diff options
Diffstat (limited to 'filter/source/svg/svgexport.cxx')
-rw-r--r-- | filter/source/svg/svgexport.cxx | 802 |
1 files changed, 601 insertions, 201 deletions
diff --git a/filter/source/svg/svgexport.cxx b/filter/source/svg/svgexport.cxx index eb5da674e6c3..c6325f282a2e 100644 --- a/filter/source/svg/svgexport.cxx +++ b/filter/source/svg/svgexport.cxx @@ -17,6 +17,7 @@ * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ +#include <strings.hrc> #include "svgwriter.hxx" #include "svgfontexport.hxx" #include "svgfilter.hxx" @@ -43,14 +44,17 @@ #include <editeng/outliner.hxx> #include <editeng/flditem.hxx> #include <comphelper/processfactory.hxx> +#include <comphelper/propertyvalue.hxx> +#include <comphelper/scopeguard.hxx> #include <comphelper/sequenceashashmap.hxx> #include <i18nlangtag/lang.h> -#include <svl/zforlist.hxx> +#include <svl/numformat.hxx> #include <tools/debug.hxx> #include <tools/urlobj.hxx> #include <unotools/streamwrap.hxx> #include <unotools/tempfile.hxx> #include <unotools/ucbstreamhelper.hxx> +#include <vcl/filter/SvmReader.hxx> #include <xmloff/unointerfacetouniqueidentifiermapper.hxx> #include <xmloff/namespacemap.hxx> #include <xmloff/xmlnamespace.hxx> @@ -60,7 +64,9 @@ #include <svx/svdmodel.hxx> #include <svx/svdxcgv.hxx> #include <sal/log.hxx> -#include <tools/diagnose_ex.h> +#include <comphelper/diagnose_ex.hxx> +#include <tools/zcodec.hxx> +#include <rtl/crc.h> #include <memory> #include <string_view> @@ -68,39 +74,41 @@ using namespace css::animations; using namespace css::presentation; using namespace ::com::sun::star::graphic; -using namespace ::com::sun::star::geometry; +using namespace ::com::sun::star::style; using namespace ::com::sun::star; using namespace ::xmloff::token; // - ooo elements and attributes - -#define NSPREFIX "ooo:" +#define NSPREFIX u"ooo:" -#define SVG_PROP_TINYPROFILE "TinyMode" -#define SVG_PROP_DTDSTRING "DTDString" -#define SVG_PROP_EMBEDFONTS "EmbedFonts" -#define SVG_PROP_NATIVEDECORATION "UseNativeTextDecoration" -#define SVG_PROP_OPACITY "Opacity" -#define SVG_PROP_POSITIONED_CHARACTERS "UsePositionedCharacters" +constexpr OUStringLiteral SVG_PROP_TINYPROFILE = u"TinyMode"; +constexpr OUStringLiteral SVG_PROP_DTDSTRING = u"DTDString"; +constexpr OUStringLiteral SVG_PROP_EMBEDFONTS = u"EmbedFonts"; +constexpr OUStringLiteral SVG_PROP_NATIVEDECORATION = u"UseNativeTextDecoration"; +constexpr OUStringLiteral SVG_PROP_OPACITY = u"Opacity"; +constexpr OUStringLiteral SVG_PROP_POSITIONED_CHARACTERS = u"UsePositionedCharacters"; // ooo xml elements -constexpr OUStringLiteral aOOOElemTextField = u"" NSPREFIX "text_field"; +constexpr OUString aOOOElemTextField = NSPREFIX "text_field"_ustr; // ooo xml attributes for meta_slide -const char aOOOAttrSlide[] = NSPREFIX "slide"; -const char aOOOAttrMaster[] = NSPREFIX "master"; -const char aOOOAttrBackgroundVisibility[] = NSPREFIX "background-visibility"; -const char aOOOAttrMasterObjectsVisibility[] = NSPREFIX "master-objects-visibility"; -const char aOOOAttrSlideDuration[] = NSPREFIX "slide-duration"; -const OUString aOOOAttrDateTimeField = NSPREFIX "date-time-field"; -constexpr OUStringLiteral aOOOAttrFooterField = u"" NSPREFIX "footer-field"; -const char aOOOAttrHasTransition[] = NSPREFIX "has-transition"; +constexpr OUString aOOOAttrSlide = NSPREFIX "slide"_ustr; +constexpr OUString aOOOAttrMaster = NSPREFIX "master"_ustr; +constexpr OUStringLiteral aOOOAttrHasCustomBackground = NSPREFIX "has-custom-background"; +constexpr OUStringLiteral aOOOAttrDisplayName = NSPREFIX "display-name"; +constexpr OUString aOOOAttrBackgroundVisibility = NSPREFIX "background-visibility"_ustr; +constexpr OUString aOOOAttrMasterObjectsVisibility = NSPREFIX "master-objects-visibility"_ustr; +constexpr OUStringLiteral aOOOAttrSlideDuration = NSPREFIX "slide-duration"; +constexpr OUString aOOOAttrDateTimeField = NSPREFIX "date-time-field"_ustr; +constexpr OUString aOOOAttrFooterField = NSPREFIX "footer-field"_ustr; +constexpr OUString aOOOAttrHasTransition = NSPREFIX "has-transition"_ustr; // ooo xml attributes for pages and shapes -const char aOOOAttrName[] = NSPREFIX "name"; +constexpr OUString aOOOAttrName = NSPREFIX "name"_ustr; -constexpr OUStringLiteral constSvgNamespace = u"http://www.w3.org/2000/svg"; +constexpr OUString constSvgNamespace = u"http://www.w3.org/2000/svg"_ustr; /** Text Field Class Hierarchy @@ -203,7 +211,7 @@ public: } virtual void growCharSet( SVGFilter::UCharSetMapMap & aTextFieldCharSets ) const override { - static const OUString sFieldId = aOOOAttrFooterField; + static constexpr OUString sFieldId = aOOOAttrFooterField; implGrowCharSet( aTextFieldCharSets, text, sFieldId ); } }; @@ -300,7 +308,7 @@ public: OUString sDateTimeFormat = sDateFormat + " " + sTimeFormat; - pSVGExport->AddAttribute( XML_NAMESPACE_NONE, NSPREFIX "date-time-format", sDateTimeFormat ); + pSVGExport->AddAttribute( XML_NAMESPACE_NONE, NSPREFIX "date-time-format"_ustr, sDateTimeFormat ); SvXMLElementExport aExp( *pSVGExport, XML_NAMESPACE_NONE, "g", true, true ); } virtual void growCharSet( SVGFilter::UCharSetMapMap & aTextFieldCharSets ) const override @@ -368,6 +376,11 @@ SVGExport::SVGExport( // add namespaces GetNamespaceMap_().Add( + GetXMLToken(XML_NP_SVG), + GetXMLToken(XML_N_SVG_COMPAT), + XML_NAMESPACE_SVG); + + GetNamespaceMap_().Add( GetXMLToken(XML_NP_PRESENTATION), GetXMLToken(XML_N_PRESENTATION), XML_NAMESPACE_PRESENTATION); @@ -423,6 +436,12 @@ namespace BitmapChecksum GetBitmapChecksum( const MetaAction* pAction ) { + if( !pAction ) + { + OSL_FAIL( "GetBitmapChecksum: passed MetaAction pointer is null." ); + return 0; + } + BitmapChecksum nChecksum = 0; const MetaActionType nType = pAction->GetType(); @@ -431,19 +450,16 @@ BitmapChecksum GetBitmapChecksum( const MetaAction* pAction ) case MetaActionType::BMPSCALE: { const MetaBmpScaleAction* pA = static_cast<const MetaBmpScaleAction*>(pAction); - if( pA ) - nChecksum = pA->GetBitmap().GetChecksum(); - else - OSL_FAIL( "GetBitmapChecksum: MetaBmpScaleAction pointer is null." ); + // The conversion to BitmapEx is needed since a Bitmap object is + // converted to BitmapEx before passing it to SVGActionWriter::ImplWriteBmp + // where the checksum is checked for matching. + nChecksum = BitmapEx( pA->GetBitmap() ).GetChecksum(); } break; case MetaActionType::BMPEXSCALE: { const MetaBmpExScaleAction* pA = static_cast<const MetaBmpExScaleAction*>(pAction); - if( pA ) - nChecksum = pA->GetBitmapEx().GetChecksum(); - else - OSL_FAIL( "GetBitmapChecksum: MetaBmpExScaleAction pointer is null." ); + nChecksum = pA->GetBitmapEx().GetChecksum(); } break; default: break; @@ -451,37 +467,131 @@ BitmapChecksum GetBitmapChecksum( const MetaAction* pAction ) return nChecksum; } -} // end anonymous namespace +MetaAction* CreateMetaBitmapAction( const MetaAction* pAction, const Point& rPt, const Size& rSz ) +{ + if( !pAction ) + { + OSL_FAIL( "CreateMetaBitmapAction: passed MetaAction pointer is null." ); + return nullptr; + } + MetaAction* pResAction = nullptr; + const MetaActionType nType = pAction->GetType(); + switch( nType ) + { + case MetaActionType::BMPSCALE: + { + const MetaBmpScaleAction* pA = static_cast<const MetaBmpScaleAction*>(pAction); + pResAction = new MetaBmpScaleAction( rPt, rSz, pA->GetBitmap() ); + } + break; + case MetaActionType::BMPEXSCALE: + { + const MetaBmpExScaleAction* pA = static_cast<const MetaBmpExScaleAction*>(pAction); + pResAction = new MetaBmpExScaleAction( rPt, rSz, pA->GetBitmapEx() ); + } + break; + default: break; + } + return pResAction; +} -static void MetaBitmapActionGetPoint( const MetaAction* pAction, Point& rPt ) +void MetaBitmapActionGetPoint( const MetaAction* pAction, Point& rPt ) { + if( !pAction ) + { + OSL_FAIL( "MetaBitmapActionGetPoint: passed MetaAction pointer is null." ); + return; + } const MetaActionType nType = pAction->GetType(); switch( nType ) { case MetaActionType::BMPSCALE: { const MetaBmpScaleAction* pA = static_cast<const MetaBmpScaleAction*>(pAction); - if( pA ) - rPt = pA->GetPoint(); - else - OSL_FAIL( "MetaBitmapActionGetPoint: MetaBmpScaleAction pointer is null." ); + rPt = pA->GetPoint(); } break; case MetaActionType::BMPEXSCALE: { const MetaBmpExScaleAction* pA = static_cast<const MetaBmpExScaleAction*>(pAction); - if( pA ) - rPt = pA->GetPoint(); - else - OSL_FAIL( "MetaBitmapActionGetPoint: MetaBmpExScaleAction pointer is null." ); + rPt = pA->GetPoint(); + } + break; + default: break; + } +} + +void MetaBitmapActionGetSize( const MetaAction* pAction, Size& rSz ) +{ + if( !pAction ) + { + OSL_FAIL( "MetaBitmapActionGetSize: passed MetaAction pointer is null." ); + return; + } + const MetaActionType nType = pAction->GetType(); + switch( nType ) + { + case MetaActionType::BMPSCALE: + { + const MetaBmpScaleAction* pA = static_cast<const MetaBmpScaleAction*>(pAction); + rSz = pA->GetSize(); + } + break; + case MetaActionType::BMPEXSCALE: + { + const MetaBmpExScaleAction* pA = static_cast<const MetaBmpExScaleAction*>(pAction); + rSz = pA->GetSize(); + } + break; + default: break; + } +} + +void MetaBitmapActionGetOrigSize( const MetaAction* pAction, Size& rSz ) +{ + if( !pAction ) + { + OSL_FAIL( "MetaBitmapActionGetOrigSize: passed MetaAction pointer is null." ); + return; + } + + const MetaActionType nType = pAction->GetType(); + MapMode aSourceMode( MapUnit::MapPixel ); + MapMode aTargetMode( MapUnit::Map100thMM ); + + switch( nType ) + { + case MetaActionType::BMPSCALE: + { + const MetaBmpScaleAction* pA = static_cast<const MetaBmpScaleAction*>(pAction); + const Bitmap& rBitmap = pA->GetBitmap(); + rSz = rBitmap.GetSizePixel(); + } + break; + case MetaActionType::BMPEXSCALE: + { + const MetaBmpExScaleAction* pA = static_cast<const MetaBmpExScaleAction*>(pAction); + const BitmapEx& rBitmap = pA->GetBitmapEx(); + rSz = rBitmap.GetSizePixel(); } break; default: break; } + rSz = OutputDevice::LogicToLogic( rSz, aSourceMode, aTargetMode ); +} +OUString getPatternIdForTiledBackground( std::u16string_view sSlideId, BitmapChecksum nChecksum ) +{ + return OUString::Concat("bg-pattern.") + sSlideId + "." + OUString::number( nChecksum ); } +OUString getIdForTiledBackground( std::u16string_view sSlideId, BitmapChecksum nChecksum ) +{ + return OUString::Concat("bg-") + sSlideId + "." + OUString::number( nChecksum ); +} + +} // end anonymous namespace size_t HashBitmap::operator()( const ObjectRepresentation& rObjRep ) const { @@ -544,6 +654,8 @@ bool SVGFilter::implExport( const Sequence< PropertyValue >& rDescriptor ) { pValue[ i ].Value >>= maFilterData; } + else if (pValue[i].Name == "StatusIndicator") + pValue[i].Value >>= mxStatusIndicator; } if(mbWriterFilter || mbCalcFilter) @@ -556,12 +668,16 @@ bool SVGFilter::implExportImpressOrDraw( const Reference< XOutputStream >& rxOSt { Reference< XComponentContext > xContext( ::comphelper::getProcessComponentContext() ) ; bool bRet = false; + // Instead of writing to rxOStm directly, we write here in case we need + // to compress the output later + SvMemoryStream aTempStm; if( rxOStm.is() ) { - if( !mSelectedPages.empty() && !mMasterPageTargets.empty() ) + if (!mSelectedPages.empty()) { - Reference< XDocumentHandler > xDocHandler = implCreateExportDocumentHandler( rxOStm ); + ::rtl::Reference< ::utl::OStreamWrapper > aTempStmWrapper = new ::utl::OStreamWrapper( aTempStm ); + Reference< XDocumentHandler > xDocHandler = implCreateExportDocumentHandler( aTempStmWrapper ); if( xDocHandler.is() ) { @@ -571,10 +687,6 @@ bool SVGFilter::implExportImpressOrDraw( const Reference< XOutputStream >& rxOSt // mpSVGExport = new SVGExport( xDocHandler ); mpSVGExport = new SVGExport( xContext, xDocHandler, maFilterData ); - // xKeepAlive is set up only to manage the life-time of the object pointed by mpSVGExport, - // and in order to prevent that it is destroyed when passed to AnimationExporter. - Reference< XInterface > xKeepAlive = static_cast< css::document::XFilter* >( mpSVGExport ); - // create an id for each draw page for( const auto& rPage : mSelectedPages ) implRegisterInterface( rPage ); @@ -591,7 +703,7 @@ bool SVGFilter::implExportImpressOrDraw( const Reference< XOutputStream >& rxOSt if( mxDefaultPage.is() ) { - SvxDrawPage* pSvxDrawPage = comphelper::getUnoTunnelImplementation<SvxDrawPage>( mxDefaultPage ); + SvxDrawPage* pSvxDrawPage = comphelper::getFromUnoTunnel<SvxDrawPage>( mxDefaultPage ); if( pSvxDrawPage ) { @@ -640,6 +752,38 @@ bool SVGFilter::implExportImpressOrDraw( const Reference< XOutputStream >& rxOSt } } } + if ( bRet ) + { + const sal_Int8* aDataPtr = static_cast< const sal_Int8* >( aTempStm.GetData() ); + sal_uInt32 aDataSize = aTempStm.GetSize(); + SvMemoryStream aCompressedStm; + if ( mbShouldCompress ) + { + sal_uInt32 nUncompressedCRC32 + = rtl_crc32( 0, aTempStm.GetData(), aTempStm.GetSize() ); + ZCodec aCodec; + aTempStm.Seek( 0 ); + aCodec.BeginCompression( ZCODEC_DEFAULT_COMPRESSION, /*gzLib*/true ); + // the inner modify time/filename doesn't really matter in this context because + // compressed graphic formats are meant to be opened as is - not to be extracted + aCodec.SetCompressionMetadata( "inner"_ostr, 0, nUncompressedCRC32 ); + aCodec.Compress( aTempStm, aCompressedStm ); + sal_uInt32 nTotalIn = static_cast< sal_uInt32 >( aCodec.EndCompression() ); + if ( aCompressedStm.GetError() || nTotalIn != aDataSize ) + { + bRet = false; + return bRet; + } + else + { + aDataPtr = static_cast< const sal_Int8* >( aCompressedStm.GetData() ); + aDataSize = aCompressedStm.GetSize(); + } + } + + Sequence< sal_Int8 > aTempSeq( aDataPtr, aDataSize ); + rxOStm->writeBytes( aTempSeq ); + } return bRet; } @@ -660,10 +804,6 @@ bool SVGFilter::implExportWriterOrCalc( const Reference< XOutputStream >& rxOStm // mpSVGExport = new SVGExport( xDocHandler ); mpSVGExport = new SVGExport( xContext, xDocHandler, maFilterData ); - // xKeepAlive is set up only to manage the life-time of the object pointed by mpSVGExport, - // and in order to prevent that it is destroyed when passed to AnimationExporter. - Reference< XInterface > xKeepAlive = static_cast< css::document::XFilter* >( mpSVGExport ); - try { mxDefaultPage = mSelectedPages[0]; @@ -693,42 +833,54 @@ bool SVGFilter::implExportWriterTextGraphic( const Reference< view::XSelectionSu Any selection = xSelectionSupplier->getSelection(); uno::Reference<lang::XServiceInfo> xSelection; selection >>= xSelection; - if (xSelection.is() && xSelection->supportsService("com.sun.star.text.TextGraphicObject")) - { - uno::Reference<beans::XPropertySet> xPropertySet(xSelection, uno::UNO_QUERY); + if (!xSelection || !xSelection->supportsService("com.sun.star.text.TextGraphicObject")) + return true; - uno::Reference<graphic::XGraphic> xOriginalGraphic; - xPropertySet->getPropertyValue("Graphic") >>= xOriginalGraphic; - const Graphic aOriginalGraphic(xOriginalGraphic); + uno::Reference<beans::XPropertySet> xPropertySet(xSelection, uno::UNO_QUERY); - uno::Reference<graphic::XGraphic> xTransformedGraphic; - xPropertySet->getPropertyValue("TransformedGraphic") >>= xTransformedGraphic; + uno::Reference<graphic::XGraphic> xOriginalGraphic; + xPropertySet->getPropertyValue("Graphic") >>= xOriginalGraphic; + const Graphic aOriginalGraphic(xOriginalGraphic); - if (!xTransformedGraphic.is()) - return false; - const Graphic aTransformedGraphic(xTransformedGraphic); - bool bSameGraphic = aTransformedGraphic == aOriginalGraphic || - aOriginalGraphic.GetChecksum() == aTransformedGraphic.GetChecksum(); - const Graphic aGraphic = bSameGraphic ? aOriginalGraphic : aTransformedGraphic; - uno::Reference<graphic::XGraphic> xGraphic = bSameGraphic ? xOriginalGraphic : xTransformedGraphic; + uno::Reference<graphic::XGraphic> xTransformedGraphic; + xPropertySet->getPropertyValue( + mbIsPreview ? OUString("GraphicPreview") : OUString("TransformedGraphic")) + >>= xTransformedGraphic; - // Calculate size from Graphic - Point aPos( OutputDevice::LogicToLogic(aGraphic.GetPrefMapMode().GetOrigin(), aGraphic.GetPrefMapMode(), MapMode(MapUnit::Map100thMM)) ); - Size aSize( OutputDevice::LogicToLogic(aGraphic.GetPrefSize(), aGraphic.GetPrefMapMode(), MapMode(MapUnit::Map100thMM)) ); + if (!xTransformedGraphic.is()) + return false; + const Graphic aTransformedGraphic(xTransformedGraphic); + bool bSameGraphic = aTransformedGraphic == aOriginalGraphic || + aOriginalGraphic.GetChecksum() == aTransformedGraphic.GetChecksum(); + const Graphic aGraphic = bSameGraphic ? aOriginalGraphic : aTransformedGraphic; + uno::Reference<graphic::XGraphic> xGraphic = bSameGraphic ? xOriginalGraphic : xTransformedGraphic; + + // Calculate size from Graphic + Point aPos( OutputDevice::LogicToLogic(aGraphic.GetPrefMapMode().GetOrigin(), aGraphic.GetPrefMapMode(), MapMode(MapUnit::Map100thMM)) ); + Size aSize( OutputDevice::LogicToLogic(aGraphic.GetPrefSize(), aGraphic.GetPrefMapMode(), MapMode(MapUnit::Map100thMM)) ); + + assert(mSelectedPages.size() == 1); + SvxDrawPage* pSvxDrawPage(comphelper::getFromUnoTunnel<SvxDrawPage>(mSelectedPages[0])); + if(pSvxDrawPage == nullptr || pSvxDrawPage->GetSdrPage() == nullptr) + return false; - assert(mSelectedPages.size() == 1); - SvxDrawPage* pSvxDrawPage(comphelper::getUnoTunnelImplementation<SvxDrawPage>(mSelectedPages[0])); - if(pSvxDrawPage == nullptr || pSvxDrawPage->GetSdrPage() == nullptr) - return false; + SdrModel& rModel = pSvxDrawPage->GetSdrPage()->getSdrModelFromSdrPage(); + const bool bUndoEnable = rModel.IsUndoEnabled(); + if (bUndoEnable) + rModel.EnableUndo(false); + comphelper::ScopeGuard guard([bUndoEnable, &rModel]() { + // restore when leaving + if (bUndoEnable) + rModel.EnableUndo(false); + }); - SdrGrafObj* pGraphicObj = new SdrGrafObj(pSvxDrawPage->GetSdrPage()->getSdrModelFromSdrPage(), aGraphic, tools::Rectangle( aPos, aSize )); - uno::Reference< drawing::XShape > xShape = GetXShapeForSdrObject(pGraphicObj); - uno::Reference< XPropertySet > xShapePropSet(xShape, uno::UNO_QUERY); - xShapePropSet->setPropertyValue("Graphic", uno::Any(xGraphic)); + rtl::Reference<SdrGrafObj> pGraphicObj = new SdrGrafObj(rModel, aGraphic, tools::Rectangle( aPos, aSize )); + uno::Reference< drawing::XShape > xShape = GetXShapeForSdrObject(pGraphicObj.get()); + uno::Reference< XPropertySet > xShapePropSet(xShape, uno::UNO_QUERY); + xShapePropSet->setPropertyValue("Graphic", uno::Any(xGraphic)); - maShapeSelection = drawing::ShapeCollection::create(comphelper::getProcessComponentContext()); - maShapeSelection->add(xShape); - } + maShapeSelection = drawing::ShapeCollection::create(comphelper::getProcessComponentContext()); + maShapeSelection->add(xShape); return true; } @@ -797,10 +949,14 @@ bool SVGFilter::implExportDocument() // #i124608# mbExportShapeSelection = mbSinglePage && maShapeSelection.is() && maShapeSelection->getCount(); - if(xDefaultPagePropertySet.is()) + if (xDefaultPagePropertySet.is()) { - xDefaultPagePropertySet->getPropertyValue( "Width" ) >>= nDocWidth; - xDefaultPagePropertySet->getPropertyValue( "Height" ) >>= nDocHeight; + sal_Int32 nWidth = 0; + sal_Int32 nHeight = 0; + if (xDefaultPagePropertySet->getPropertyValue("Width") >>= nWidth) + nDocWidth = nWidth; + if (xDefaultPagePropertySet->getPropertyValue("Height") >>= nHeight) + nDocHeight = nHeight; } if(mbExportShapeSelection) @@ -862,7 +1018,7 @@ bool SVGFilter::implExportDocument() aObjects[ nPos++ ] = elem.second; } - mpSVGFontExport = new SVGFontExport( *mpSVGExport, aObjects ); + mpSVGFontExport = new SVGFontExport( *mpSVGExport, std::move(aObjects) ); mpSVGWriter = new SVGActionWriter( *mpSVGExport, *mpSVGFontExport ); if( mpSVGExport->IsEmbedFonts() ) @@ -874,10 +1030,15 @@ bool SVGFilter::implExportDocument() implExportTextShapeIndex(); implEmbedBulletGlyphs(); implExportTextEmbeddedBitmaps(); + implExportBackgroundBitmaps(); + mpSVGWriter->SetEmbeddedBitmapRefs( &maBitmapActionMap ); + implExportTiledBackground(); } + if( mbIsPreview ) + mpSVGWriter->SetPreviewMode(); // #i124608# export a given object selection, so no MasterPage export at all - if (!mbExportShapeSelection) + if (!mbExportShapeSelection && !mMasterPageTargets.empty()) implExportMasterPages( mMasterPageTargets, 0, mMasterPageTargets.size() - 1 ); implExportDrawPages( mSelectedPages, 0, nLastPage ); @@ -947,6 +1108,7 @@ void SVGFilter::implExportDocumentHeaderImpressOrDraw(sal_Int32 nDocX, sal_Int32 mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "xmlns:presentation", "http://sun.com/xmlns/staroffice/presentation" ); mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "xmlns:smil", "http://www.w3.org/2001/SMIL20/" ); mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "xmlns:anim", "urn:oasis:names:tc:opendocument:xmlns:animation:1.0" ); + mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "xmlns:svg", "urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" ); mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "xml:space", "preserve" ); mpSVGDoc = new SvXMLElementExport( *mpSVGExport, XML_NAMESPACE_NONE, "svg", true, true ); @@ -1058,20 +1220,20 @@ void SVGFilter::implGenerateMetaData() // we wrap all meta presentation info into a svg:defs element SvXMLElementExport aDefsElem( *mpSVGExport, XML_NAMESPACE_NONE, "defs", true, true ); - mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "id", NSPREFIX "meta_slides" ); - mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, NSPREFIX "number-of-slides", OUString::number( nCount ) ); - mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, NSPREFIX "start-slide-number", OUString::number( mnVisiblePage ) ); + mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "id", NSPREFIX "meta_slides"_ustr ); + mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, NSPREFIX "number-of-slides"_ustr, OUString::number( nCount ) ); + mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, NSPREFIX "start-slide-number"_ustr, OUString::number( mnVisiblePage ) ); if( mpSVGExport->IsUsePositionedCharacters() ) { - mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, NSPREFIX "use-positioned-chars", "true" ); + mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, NSPREFIX "use-positioned-chars"_ustr, "true" ); } // Add a (global) Page Numbering Type attribute for the document // NOTE: at present pSdrModel->GetPageNumType() returns always css::style::NumberingType::ARABIC // so the following code fragment is pretty useless sal_Int32 nPageNumberingType = css::style::NumberingType::ARABIC; - SvxDrawPage* pSvxDrawPage = comphelper::getUnoTunnelImplementation<SvxDrawPage>( mSelectedPages[0] ); + SvxDrawPage* pSvxDrawPage = comphelper::getFromUnoTunnel<SvxDrawPage>( mSelectedPages[0] ); if( pSvxDrawPage ) { SdrPage* pSdrPage = pSvxDrawPage->GetSdrPage(); @@ -1105,20 +1267,20 @@ void SVGFilter::implGenerateMetaData() break; } if( !sNumberingType.isEmpty() ) - mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, NSPREFIX "page-numbering-type", sNumberingType ); + mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, NSPREFIX "page-numbering-type"_ustr, sNumberingType ); } { SvXMLElementExport aExp( *mpSVGExport, XML_NAMESPACE_NONE, "g", true, true ); - const OUString aId( NSPREFIX "meta_slide" ); + const OUString aId( NSPREFIX "meta_slide"_ustr ); const OUString aElemTextFieldId( aOOOElemTextField ); std::vector< std::unique_ptr<TextField> > aFieldSet; // dummy slide - used as leaving slide for transition on the first slide if( mbPresentation ) { - mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "id", NSPREFIX "meta_dummy_slide" ); + mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "id", NSPREFIX "meta_dummy_slide"_ustr ); mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, aOOOAttrSlide, "dummy-slide" ); mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, aOOOAttrMaster, "dummy-master-page" ); mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, aOOOAttrBackgroundVisibility, "hidden" ); @@ -1131,6 +1293,8 @@ void SVGFilter::implGenerateMetaData() { const Reference< css::drawing::XDrawPage > & xDrawPage = mSelectedPages[i]; Reference< css::drawing::XMasterPageTarget > xMasterPageTarget( xDrawPage, UNO_QUERY ); + if (!xMasterPageTarget.is()) + continue; Reference< css::drawing::XDrawPage > xMasterPage = xMasterPageTarget->getMasterPage(); OUString aSlideId(aId + "_" + OUString::number( i )); @@ -1145,6 +1309,12 @@ void SVGFilter::implGenerateMetaData() if( xPropSet.is() ) { + OUString sDisplayName; + if (xPropSet->getPropertyValue("LinkDisplayName") >>= sDisplayName) + { + mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, aOOOAttrDisplayName, sDisplayName); + } + bool bBackgroundVisibility = true; // default: visible bool bBackgroundObjectsVisibility = true; // default: visible @@ -1152,12 +1322,24 @@ void SVGFilter::implGenerateMetaData() VariableDateTimeField aVariableDateTimeField; FooterField aFooterField; + // check if the slide has a custom background which overlaps the master page background + Reference< XPropertySet > xBackground; + xPropSet->getPropertyValue( "Background" ) >>= xBackground; + if( xBackground.is() ) + { + drawing::FillStyle aFillStyle; + bool assigned = ( xBackground->getPropertyValue( "FillStyle" ) >>= aFillStyle ); + // has a custom background ? + if( assigned && aFillStyle != drawing::FillStyle_NONE ) + mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, aOOOAttrHasCustomBackground, "true" ); + } + xPropSet->getPropertyValue( "IsBackgroundVisible" ) >>= bBackgroundVisibility; // in case the attribute is set to its default value it is not appended to the meta-slide element if( !bBackgroundVisibility ) // visibility default value: 'visible' mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, aOOOAttrBackgroundVisibility, "hidden" ); - // Page Number, Date/Time, Footer and Header Fields are regarded as background objects. + // Page Number, DateTime, Footer and Header Fields are regarded as background objects. // So bBackgroundObjectsVisibility overrides visibility of master page text fields. xPropSet->getPropertyValue( "IsBackgroundObjectsVisible" ) >>= bBackgroundObjectsVisibility; if( bBackgroundObjectsVisibility ) // visibility default value: 'visible' @@ -1171,50 +1353,44 @@ void SVGFilter::implGenerateMetaData() bPageNumberVisibility = bPageNumberVisibility && ( nPageNumberingType != css::style::NumberingType::NUMBER_NONE ); if( bPageNumberVisibility ) // visibility default value: 'hidden' { - mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, NSPREFIX "page-number-visibility", "visible" ); + mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, NSPREFIX "page-number-visibility"_ustr, "visible" ); } - // Date/Time Field - xPropSet->getPropertyValue( "IsDateTimeVisible" ) >>= bDateTimeVisibility; - if( bDateTimeVisibility ) // visibility default value: 'visible' + // DateTime Field + bool bDateTimeFixed = true; // default: fixed + xPropSet->getPropertyValue( "IsDateTimeFixed" ) >>= bDateTimeFixed; + if( bDateTimeFixed ) // we are interested only in the field text not in the date/time format { - bool bDateTimeFixed = true; // default: fixed - xPropSet->getPropertyValue( "IsDateTimeFixed" ) >>= bDateTimeFixed; - if( bDateTimeFixed ) // we are interested only in the field text not in the date/time format + xPropSet->getPropertyValue( "DateTimeText" ) >>= aFixedDateTimeField.text; + if( !aFixedDateTimeField.text.isEmpty() ) { - xPropSet->getPropertyValue( "DateTimeText" ) >>= aFixedDateTimeField.text; - if( !aFixedDateTimeField.text.isEmpty() ) - { - OUString sFieldId = implGenerateFieldId( aFieldSet, aFixedDateTimeField, aElemTextFieldId, xMasterPage ); - mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, aOOOAttrDateTimeField, sFieldId ); - } - } - else // the inverse applies: we are interested only in the date/time format not in the field text - { - xPropSet->getPropertyValue( "DateTimeFormat" ) >>= aVariableDateTimeField.format; - OUString sFieldId = implGenerateFieldId( aFieldSet, aVariableDateTimeField, aElemTextFieldId, xMasterPage ); + OUString sFieldId = implGenerateFieldId( aFieldSet, aFixedDateTimeField, aElemTextFieldId, xMasterPage ); mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, aOOOAttrDateTimeField, sFieldId ); } } - else + else // the inverse applies: we are interested only in the date/time format not in the field text { - mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, NSPREFIX "date-time-visibility", "hidden" ); + xPropSet->getPropertyValue( "DateTimeFormat" ) >>= aVariableDateTimeField.format; + OUString sFieldId = implGenerateFieldId( aFieldSet, aVariableDateTimeField, aElemTextFieldId, xMasterPage ); + mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, aOOOAttrDateTimeField, sFieldId ); + } + xPropSet->getPropertyValue( "IsDateTimeVisible" ) >>= bDateTimeVisibility; + if( !bDateTimeVisibility ) // visibility default value: 'visible' + { + mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, NSPREFIX "date-time-visibility"_ustr, "hidden" ); } // Footer Field - xPropSet->getPropertyValue( "IsFooterVisible" ) >>= bFooterVisibility; - if( bFooterVisibility ) // visibility default value: 'visible' + xPropSet->getPropertyValue( "FooterText" ) >>= aFooterField.text; + if( !aFooterField.text.isEmpty() ) { - xPropSet->getPropertyValue( "FooterText" ) >>= aFooterField.text; - if( !aFooterField.text.isEmpty() ) - { - OUString sFieldId = implGenerateFieldId( aFieldSet, aFooterField, aElemTextFieldId, xMasterPage ); - mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, aOOOAttrFooterField, sFieldId ); - } + OUString sFieldId = implGenerateFieldId( aFieldSet, aFooterField, aElemTextFieldId, xMasterPage ); + mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, aOOOAttrFooterField, sFieldId ); } - else + xPropSet->getPropertyValue( "IsFooterVisible" ) >>= bFooterVisibility; + if( !bFooterVisibility ) // visibility default value: 'visible' { - mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, NSPREFIX "footer-visibility", "hidden" ); + mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, NSPREFIX "footer-visibility"_ustr, "hidden" ); } } else @@ -1260,9 +1436,9 @@ void SVGFilter::implGenerateMetaData() { for( sal_Int32 i = 0, nSize = aFieldSet.size(); i < nSize; ++i ) { - OUString sElemId = OUStringLiteral(aOOOElemTextField) + "_" + OUString::number( i ); + OUString sElemId = OUString::Concat(aOOOElemTextField) + "_" + OUString::number( i ); mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "id", sElemId ); - aFieldSet[i]->elementExport( mpSVGExport ); + aFieldSet[i]->elementExport( mpSVGExport.get() ); } if( mpSVGExport->IsEmbedFonts() && mpSVGExport->IsUsePositionedCharacters() ) { @@ -1350,7 +1526,7 @@ void SVGFilter::implExportTextShapeIndex() for( sal_Int32 i = 0; i < nCount; ++i ) { const Reference< css::drawing::XDrawPage > & xDrawPage = mSelectedPages[i]; - if( mTextShapeIdListMap.find( xDrawPage ) != mTextShapeIdListMap.end() ) + if( mTextShapeIdListMap.contains(xDrawPage) ) { OUString sTextShapeIdList = mTextShapeIdListMap[xDrawPage].trim(); @@ -1358,7 +1534,7 @@ void SVGFilter::implExportTextShapeIndex() if( !rPageId.isEmpty() && !sTextShapeIdList.isEmpty() ) { mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, aOOOAttrSlide, rPageId ); - mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, NSPREFIX "id-list", sTextShapeIdList ); + mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, NSPREFIX "id-list"_ustr, sTextShapeIdList ); SvXMLElementExport aGElem( *mpSVGExport, XML_NAMESPACE_NONE, "g", true, true ); } } @@ -1408,8 +1584,105 @@ void SVGFilter::implEmbedBulletGlyph( sal_Unicode cBullet, const OUString & sPat mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "d", sPathData ); SvXMLElementExport aPathElem( *mpSVGExport, XML_NAMESPACE_NONE, "path", true, true ); + mpSVGExport->SetEmbeddedBulletGlyph(cBullet); +} + +void SVGFilter::implExportBackgroundBitmaps() +{ + if (maBitmapActionMap.empty()) + return; + + mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "class", "BackgroundBitmaps" ); + SvXMLElementExport aDefsContainerElem( *mpSVGExport, XML_NAMESPACE_NONE, "defs", true, true ); + + OUString sId; + for( const auto& rItem : maBitmapActionMap ) + { + BitmapChecksum nChecksum = rItem.first; + const GDIMetaFile& aEmbeddedBitmapMtf = *(rItem.second); + MetaAction* pBitmapAction = aEmbeddedBitmapMtf.GetAction( 0 ); + if( pBitmapAction ) + { + sId = "bitmap(" + OUString::number( nChecksum ) + ")"; + mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "id", sId ); + + const Point aPos; // (0, 0) + const Size aSize = aEmbeddedBitmapMtf.GetPrefSize(); + mpSVGWriter->WriteMetaFile( aPos, aSize, aEmbeddedBitmapMtf, 0xffffffff ); + } + } } +void SVGFilter::implExportTiledBackground() +{ + if( maPatterProps.empty() ) + return; + + mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "class", "BackgroundPatterns" ); + SvXMLElementExport aDefsContainerElem( *mpSVGExport, XML_NAMESPACE_NONE, "defs", true, true ); + + for( const auto& [ rSlideId, rData ] : maPatterProps ) + { + auto aBitmapActionIt = maBitmapActionMap.find( rData.aBitmapChecksum ); + if( aBitmapActionIt != maBitmapActionMap.end() ) + { + // pattern element attributes + const OUString sPatternId = getPatternIdForTiledBackground( rSlideId, rData.aBitmapChecksum ); + // <pattern> <use> + { + // pattern element attributes + mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "id", sPatternId ); + + mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "x", OUString::number( rData.aPos.X() ) ); + mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "y", OUString::number( rData.aPos.Y() ) ); + mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "width", OUString::number( rData.aSize.Width() ) ); + mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "height", OUString::number( rData.aSize.Height() ) ); + mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "patternUnits", "userSpaceOnUse" ); + + SvXMLElementExport aPatternElem( *mpSVGExport, XML_NAMESPACE_NONE, "pattern", true, true ); + + // use element attributes + const Size& aOrigSize = aBitmapActionIt->second->GetPrefSize(); + OUString sTransform; + Fraction aFractionX( rData.aSize.Width(), aOrigSize.Width() ); + Fraction aFractionY( rData.aSize.Height(), aOrigSize.Height() ); + double scaleX = rtl_math_round( double(aFractionX), 3, rtl_math_RoundingMode::rtl_math_RoundingMode_Corrected ); + double scaleY = rtl_math_round( double(aFractionY), 3, rtl_math_RoundingMode::rtl_math_RoundingMode_Corrected ); + if( !rtl_math_approxEqual( scaleX, 1.0 ) || !rtl_math_approxEqual( scaleY, 1.0 ) ) + sTransform += " scale(" + OUString::number( double(aFractionX) ) + ", " + OUString::number( double(aFractionY) ) + ")"; + + if( !sTransform.isEmpty() ) + mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "transform", sTransform ); + + // referenced bitmap + OUString sRefId = "#bitmap(" + OUString::number( rData.aBitmapChecksum ) + ")"; + mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "xlink:href", sRefId ); + + SvXMLElementExport aUseElem( *mpSVGExport, XML_NAMESPACE_NONE, "use", true, true ); + } // </use> </pattern> + + // <g> <rect> + { + // group + const OUString sBgId = getIdForTiledBackground( rSlideId, rData.aBitmapChecksum ); + mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "id", sBgId ); + + SvXMLElementExport aGroupElem( *mpSVGExport, XML_NAMESPACE_NONE, "g", true, true ); + + // rectangle + const OUString sUrl = "url(#" + sPatternId + ")"; + mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "x", "0" ); + mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "y", "0" ); + mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "width", OUString::number( rData.aSlideSize.Width() ) ); + mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "height", OUString::number( rData.aSlideSize.Height() ) ); + mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "stroke", "none" ); + mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "fill", sUrl ); + + SvXMLElementExport aRectElem( *mpSVGExport, XML_NAMESPACE_NONE, "rect", true, true ); + } // </g> </rect> + } + } +} /** SVGFilter::implExportTextEmbeddedBitmaps We export bitmaps embedded into text shapes, such as those used by list @@ -1549,7 +1822,7 @@ void SVGFilter::implGetPagePropSet( const Reference< css::drawing::XDrawPage > & if( mVisiblePagePropSet.bIsPageNumberFieldVisible ) { - SvxDrawPage* pSvxDrawPage = comphelper::getUnoTunnelImplementation<SvxDrawPage>( rxPage ); + SvxDrawPage* pSvxDrawPage = comphelper::getFromUnoTunnel<SvxDrawPage>( rxPage ); if( pSvxDrawPage ) { SdrPage* pSdrPage = pSvxDrawPage->GetSdrPage(); @@ -1636,25 +1909,21 @@ void SVGFilter::implExportDrawPages( const std::vector< Reference< css::drawing: } } - if(!mbExportShapeSelection) + if (!mbExportShapeSelection) { // We wrap all slide in a group element with class name "SlideGroup". mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "class", "SlideGroup" ); SvXMLElementExport aExp( *mpSVGExport, XML_NAMESPACE_NONE, "g", true, true ); + if (mxStatusIndicator) + mxStatusIndicator->start(FilterResId(STR_FILTER_DOC_SAVING), nLastPage - nFirstPage + 1); + for( sal_Int32 i = nFirstPage; i <= nLastPage; ++i ) { - Reference< css::drawing::XShapes > xShapes; + if (mxStatusIndicator.is()) + mxStatusIndicator->setValue(i - nFirstPage); - if (mbExportShapeSelection) - { - // #i124608# export a given object selection - xShapes = maShapeSelection; - } - else - { - xShapes = rxPages[i]; - } + Reference<css::drawing::XShapes> xShapes = rxPages[i]; if( xShapes.is() ) { @@ -1697,6 +1966,9 @@ void SVGFilter::implExportDrawPages( const std::vector< Reference< css::drawing: } // append the </g> closing tag related to inserted elements } // append the </g> closing tag related to the svg element handling the slide visibility } + + if (mxStatusIndicator) + mxStatusIndicator->end(); } else { @@ -1746,34 +2018,47 @@ bool SVGFilter::implExportPage( std::u16string_view sPageId, const GDIMetaFile& rMtf = (*mpObjects)[ rxPage ].GetRepresentation(); if( rMtf.GetActionSize() ) { - // background id = "bg-" + page id - OUString sBackgroundId = OUString::Concat("bg-") + sPageId; - mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "id", sBackgroundId ); - - // At present (LibreOffice 3.4.0) the 'IsBackgroundVisible' property is not handled - // by Impress; anyway we handle this property as referring only to the visibility - // of the master page background. So if a slide has its own background object, - // the visibility of such a background object is always inherited from the visibility - // of the parent slide regardless of the value of the 'IsBackgroundVisible' property. - // This means that we need to set up the visibility attribute only for the background - // element of a master page. - if( !mbPresentation && bMaster ) + // If this is not a master page wrap the slide custom background + // by a <defs> element. + // Slide custom background, if any, is referenced at a different position + // in order to not overlap background objects. + std::unique_ptr<SvXMLElementExport> xDefsExp; + if (!bMaster) // insert the <defs> open tag related to the slide background + { + mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "class", "SlideBackground" ); + xDefsExp.reset( new SvXMLElementExport( *mpSVGExport, XML_NAMESPACE_NONE, "defs", true, true ) ); + } { - if( !mVisiblePagePropSet.bIsBackgroundVisible ) + // background id = "bg-" + page id + OUString sBackgroundId = OUString::Concat("bg-") + sPageId; + mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "id", sBackgroundId ); + + // At present (LibreOffice 3.4.0) the 'IsBackgroundVisible' property is not handled + // by Impress; anyway we handle this property as referring only to the visibility + // of the master page background. So if a slide has its own background object, + // the visibility of such a background object is always inherited from the visibility + // of the parent slide regardless of the value of the 'IsBackgroundVisible' property. + // This means that we need to set up the visibility attribute only for the background + // element of a master page. + if( !mbPresentation && bMaster ) { - mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "visibility", "hidden" ); + if( !mVisiblePagePropSet.bIsBackgroundVisible ) + { + mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "visibility", "hidden" ); + } } - } - mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "class", "Background" ); + mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "class", "Background" ); - // insert the <g> open tag related to the Background - SvXMLElementExport aExp2( *mpSVGExport, XML_NAMESPACE_NONE, "g", true, true ); + // insert the <g> open tag related to the Background + SvXMLElementExport aExp2( *mpSVGExport, XML_NAMESPACE_NONE, "g", true, true ); + + // append all elements that make up the Background + const Point aNullPt; + mpSVGWriter->WriteMetaFile( aNullPt, rMtf.GetPrefSize(), rMtf, SVGWRITER_WRITE_FILL ); + } // insert the </g> closing tag related to the Background - // append all elements that make up the Background - const Point aNullPt; - mpSVGWriter->WriteMetaFile( aNullPt, rMtf.GetPrefSize(), rMtf, SVGWRITER_WRITE_FILL ); - } // insert the </g> closing tag related to the Background + } // insert the </defs> closing tag related to the slide background } // In case we are dealing with a master page we need to group all its shapes @@ -1881,20 +2166,25 @@ bool SVGFilter::implExportShape( const Reference< css::drawing::XShape >& rxShap if( rMtf.GetActionSize() ) { // for text field shapes we set up text-adjust attributes // and set visibility to hidden - const OUString* pElementId = nullptr; + OUString aElementId; + if( mbPresentation ) { - bool bIsPageNumber = ( aShapeClass == "Slide_Number" ); + bool bIsPageNumber = ( aShapeClass == "PageNumber" ); bool bIsFooter = ( aShapeClass == "Footer" ); - bool bIsDateTime = ( aShapeClass == "Date/Time" ); - if( bIsPageNumber || bIsDateTime || bIsFooter ) + bool bIsDateTime = ( aShapeClass == "DateTime" ); + bool bTextField = bIsPageNumber || bIsFooter || bIsDateTime; + if( bTextField ) { // to notify to the SVGActionWriter::ImplWriteActions method // that we are dealing with a placeholder shape - pElementId = &sPlaceholderTag; + aElementId = sPlaceholderTag; mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "visibility", "hidden" ); + } + if( bTextField || ( aShapeClass == "TextShape" ) ) + { sal_uInt16 nTextAdjust = sal_uInt16(ParagraphAdjust_LEFT); OUString sTextAdjust; xShapePropSet->getPropertyValue( "ParaAdjust" ) >>= nTextAdjust; @@ -1913,7 +2203,7 @@ bool SVGFilter::implExportShape( const Reference< css::drawing::XShape >& rxShap default: break; } - mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, NSPREFIX "text-adjust", sTextAdjust ); + mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, NSPREFIX "text-adjust"_ustr, sTextAdjust ); } } mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "class", aShapeClass ); @@ -1982,7 +2272,7 @@ bool SVGFilter::implExportShape( const Reference< css::drawing::XShape >& rxShap SvXMLElementExport alinkA( *mpSVGExport, XML_NAMESPACE_NONE, "a", true, true ); mpSVGWriter->WriteMetaFile( aTopLeft, aSize, rMtf, 0xffffffff, - pElementId, + aElementId, &rxShape, pEmbeddedBitmapsMtf ); } @@ -1991,7 +2281,7 @@ bool SVGFilter::implExportShape( const Reference< css::drawing::XShape >& rxShap { mpSVGWriter->WriteMetaFile( aTopLeft, aSize, rMtf, 0xffffffff, - pElementId, + aElementId, &rxShape, pEmbeddedBitmapsMtf ); } @@ -2046,21 +2336,19 @@ bool SVGFilter::implCreateObjects() // implementation status: // - hatch stroke color is set to 'none' so the hatch is not visible, why? // - gradient look is not really awesome, too few colors are used; - // - stretched bitmap, gradient and hatch are not exported only once + // - gradient and hatch are not exported only once // and then referenced in case more than one slide uses them. - // - tiled bitmap: an image element is exported for each tile, - // this is really too expensive! Reference< XPropertySet > xPropSet( xDrawPage, UNO_QUERY ); if( xPropSet.is() ) { Reference< XPropertySet > xBackground; - xPropSet->getPropertyValue( "Background" ) >>= xBackground; + if (xPropSet->getPropertySetInfo()->hasPropertyByName("Background")) + xPropSet->getPropertyValue( "Background" ) >>= xBackground; if( xBackground.is() ) { drawing::FillStyle aFillStyle; bool assigned = ( xBackground->getPropertyValue( "FillStyle" ) >>= aFillStyle ); - if( assigned && aFillStyle != drawing::FillStyle_NONE - && aFillStyle != drawing::FillStyle_BITMAP ) + if( assigned && aFillStyle != drawing::FillStyle_NONE ) { implCreateObjectsFromBackground( xDrawPage ); } @@ -2102,11 +2390,12 @@ bool SVGFilter::implCreateObjectsFromShape( const Reference< css::drawing::XDraw } else { - SdrObject* pObj = GetSdrObjectFromXShape( rxShape ); + SdrObject* pObj = SdrObject::getSdrObjectFromXShape(rxShape); if( pObj ) { - Graphic aGraphic(SdrExchangeView::GetObjGraphic(*pObj)); + // tdf#155479 need to signal SVG export + Graphic aGraphic(SdrExchangeView::GetObjGraphic(*pObj, true)); // Writer graphic shapes are handled differently if( mbWriterFilter && aGraphic.GetType() == GraphicType::NONE ) @@ -2175,8 +2464,8 @@ bool SVGFilter::implCreateObjectsFromShape( const Reference< css::drawing::XDraw MetaAction* pAction; bool bIsTextShapeStarted = false; const GDIMetaFile& rMtf = aGraphic.GetGDIMetaFile(); - sal_uLong nCount = rMtf.GetActionSize(); - for( sal_uLong nCurAction = 0; nCurAction < nCount; ++nCurAction ) + size_t nCount = rMtf.GetActionSize(); + for( size_t nCurAction = 0; nCurAction < nCount; ++nCurAction ) { pAction = rMtf.GetAction( nCurAction ); const MetaActionType nType = pAction->GetType(); @@ -2227,24 +2516,122 @@ void SVGFilter::implCreateObjectsFromBackground( const Reference< css::drawing:: GDIMetaFile aMtf; - utl::TempFile aFile; - aFile.EnableKillingFile(); + utl::TempFileFast aFile; + SvStream* pStream = aFile.GetStream(StreamMode::READWRITE); - Sequence< PropertyValue > aDescriptor( 3 ); - aDescriptor[0].Name = "FilterName"; - aDescriptor[0].Value <<= OUString( "SVM" ); - aDescriptor[1].Name = "URL"; - aDescriptor[1].Value <<= aFile.GetURL(); - aDescriptor[2].Name = "ExportOnlyBackground"; - aDescriptor[2].Value <<= true; + Sequence< PropertyValue > aDescriptor{ + comphelper::makePropertyValue("FilterName", OUString( "SVM" )), + comphelper::makePropertyValue("OutputStream", uno::Reference<XOutputStream>(new utl::OOutputStreamWrapper(*pStream))), + comphelper::makePropertyValue("ExportOnlyBackground", true) + }; xExporter->setSourceDocument( Reference< XComponent >( rxDrawPage, UNO_QUERY ) ); xExporter->filter( aDescriptor ); - aMtf.Read( *aFile.GetStream( StreamMode::READ ) ); + pStream->Seek(0); + SvmReader aReader( *pStream ); + aReader.Read( aMtf ); - (*mpObjects)[ rxDrawPage ] = ObjectRepresentation( rxDrawPage, aMtf ); -} + bool bIsBitmap = false; + bool bIsTiled = false; + + // look for background type + Reference< XPropertySet > xPropSet( rxDrawPage, UNO_QUERY ); + if( xPropSet.is() ) + { + Reference< XPropertySet > xBackground; + xPropSet->getPropertyValue( "Background" ) >>= xBackground; + if( xBackground.is() ) + { + drawing::FillStyle aFillStyle; + if( xBackground->getPropertyValue( "FillStyle" ) >>= aFillStyle ) + { + if( aFillStyle == drawing::FillStyle::FillStyle_BITMAP ) + { + bIsBitmap = true; + xBackground->getPropertyValue( "FillBitmapTile" ) >>= bIsTiled; + + // we do not handle tiled background with a row or column offset + sal_Int32 nFillBitmapOffsetX = 0, nFillBitmapOffsetY = 0; + xBackground->getPropertyValue( "FillBitmapOffsetX" ) >>= nFillBitmapOffsetX; + xBackground->getPropertyValue( "FillBitmapOffsetY" ) >>= nFillBitmapOffsetY; + bIsTiled = bIsTiled && ( nFillBitmapOffsetX == 0 && nFillBitmapOffsetY == 0 ); + } + } + } + } + + if( !bIsBitmap ) + { + (*mpObjects)[ rxDrawPage ] = ObjectRepresentation( rxDrawPage, aMtf ); + return; + } + + GDIMetaFile aTiledMtf; + bool bBitmapFound = false; + MetaAction* pAction; + size_t nCount = aMtf.GetActionSize(); + for( size_t nCurAction = 0; nCurAction < nCount; ++nCurAction ) + { + pAction = aMtf.GetAction( nCurAction ); + const MetaActionType nType = pAction->GetType(); + // collect bitmap + if( nType == MetaActionType::BMPSCALE || nType == MetaActionType::BMPEXSCALE ) + { + if( bBitmapFound ) + continue; + bBitmapFound = true; // the subsequent bitmaps are still the same just translated + + BitmapChecksum nChecksum = GetBitmapChecksum( pAction ); + if( maBitmapActionMap.find( nChecksum ) == maBitmapActionMap.end() ) + { + Point aPos; // (0, 0) + Size aSize; + MetaBitmapActionGetOrigSize( pAction, aSize ); + MetaAction* pBitmapAction = CreateMetaBitmapAction( pAction, aPos, aSize ); + if( pBitmapAction ) + { + GDIMetaFile* pEmbeddedBitmapMtf = new GDIMetaFile(); + pEmbeddedBitmapMtf->AddAction( pBitmapAction ); + pEmbeddedBitmapMtf->SetPrefSize( aSize ); + pEmbeddedBitmapMtf->SetPrefMapMode( MapMode(MapUnit::Map100thMM) ); + + maBitmapActionMap[ nChecksum ].reset( pEmbeddedBitmapMtf ); + } + } + + if( bIsTiled ) + { + // collect data for <pattern> and <rect> + const OUString & sPageId = implGetValidIDFromInterface( rxDrawPage ); + Point aPos; + MetaBitmapActionGetPoint( pAction, aPos ); + Size aSize; + MetaBitmapActionGetSize( pAction, aSize ); + + sal_Int32 nSlideWidth = 0, nSlideHeight = 0; + xPropSet->getPropertyValue( "Width" ) >>= nSlideWidth; + xPropSet->getPropertyValue( "Height" ) >>= nSlideHeight; + + maPatterProps[ sPageId ] = { nChecksum, aPos, aSize, { nSlideWidth, nSlideHeight } }; + + // create meta comment action that is used to exporting + // a <use> element which points to the group element representing the background + const OUString sBgId = getIdForTiledBackground( sPageId, nChecksum ); + OString sComment = sTiledBackgroundTag + " " + sBgId.toUtf8(); + MetaCommentAction* pCommentAction = new MetaCommentAction( sComment ); + if( pCommentAction ) + aTiledMtf.AddAction( pCommentAction ); + } + } + else if( bIsTiled && nType != MetaActionType::CLIPREGION ) + { + aTiledMtf.AddAction( pAction ); + } + } + + (*mpObjects)[ rxDrawPage ] = ObjectRepresentation( rxDrawPage, bIsTiled ? aTiledMtf : aMtf ); +} OUString SVGFilter::implGetClassFromShape( const Reference< css::drawing::XShape >& rxShape ) { @@ -2257,14 +2644,16 @@ OUString SVGFilter::implGetClassFromShape( const Reference< css::drawing::XShape aRet = "Graphic"; else if( aShapeType.lastIndexOf( "drawing.OLE2Shape" ) != -1 ) aRet = "OLE2"; + else if( aShapeType.lastIndexOf( "drawing.TextShape" ) != -1 ) + aRet = "TextShape"; else if( aShapeType.lastIndexOf( "presentation.HeaderShape" ) != -1 ) aRet = "Header"; else if( aShapeType.lastIndexOf( "presentation.FooterShape" ) != -1 ) aRet = "Footer"; else if( aShapeType.lastIndexOf( "presentation.DateTimeShape" ) != -1 ) - aRet = "Date/Time"; + aRet = "DateTime"; else if( aShapeType.lastIndexOf( "presentation.SlideNumberShape" ) != -1 ) - aRet = "Slide_Number"; + aRet = "PageNumber"; else if( aShapeType.lastIndexOf( "presentation.TitleTextShape" ) != -1 ) aRet = "TitleText"; else if( aShapeType.lastIndexOf( "presentation.OutlinerShape" ) != -1 ) @@ -2311,7 +2700,7 @@ IMPL_LINK( SVGFilter, CalcFieldHdl, EditFieldInfo*, pInfo, void ) { // to notify to the SVGActionWriter::ImplWriteText method // that we are dealing with a placeholder shape - OUStringBuffer aRepresentation = sPlaceholderTag; + OUStringBuffer aRepresentation(sPlaceholderTag); if( !mCreateOjectsCurrentMasterPage.is() ) { @@ -2320,9 +2709,9 @@ IMPL_LINK( SVGFilter, CalcFieldHdl, EditFieldInfo*, pInfo, void ) } bool bHasCharSetMap = mTextFieldCharSets.find( mCreateOjectsCurrentMasterPage ) != mTextFieldCharSets.end(); - static const OUString aHeaderId( NSPREFIX "header-field" ); - static const OUString aFooterId( aOOOAttrFooterField ); - static const OUString aDateTimeId( aOOOAttrDateTimeField ); + static constexpr OUString aHeaderId( NSPREFIX "header-field"_ustr ); + static constexpr OUString aFooterId( aOOOAttrFooterField ); + static constexpr OUString aDateTimeId( aOOOAttrDateTimeField ); static const OUString aVariableDateTimeId( aOOOAttrDateTimeField + "-variable" ); const UCharSet * pCharSet = nullptr; @@ -2429,7 +2818,7 @@ IMPL_LINK( SVGFilter, CalcFieldHdl, EditFieldInfo*, pInfo, void ) // nothing to do here, we always collect the characters needed for these cases. break; } - aRepresentation.append( sDate.makeStringAndClear() ); + aRepresentation.append( sDate ); } } } @@ -2521,7 +2910,7 @@ void SVGExport::writeMtf( const GDIMetaFile& rMtf ) std::vector< ObjectRepresentation > aObjects; aObjects.emplace_back( Reference< XInterface >(), rMtf ); - SVGFontExport aSVGFontExport( *this, aObjects ); + SVGFontExport aSVGFontExport( *this, std::move(aObjects) ); Point aPoint100thmm( OutputDevice::LogicToLogic(rMtf.GetPrefMapMode().GetOrigin(), rMtf.GetPrefMapMode(), MapMode(MapUnit::Map100thMM)) ); Size aSize100thmm( OutputDevice::LogicToLogic(rMtf.GetPrefSize(), rMtf.GetPrefMapMode(), MapMode(MapUnit::Map100thMM)) ); @@ -2532,4 +2921,15 @@ void SVGExport::writeMtf( const GDIMetaFile& rMtf ) } } +void SVGExport::SetEmbeddedBulletGlyph(sal_Unicode cBullet) +{ + maEmbeddedBulletGlyphs.insert(cBullet); +} + +bool SVGExport::IsEmbeddedBulletGlyph(sal_Unicode cBullet) const +{ + auto it = maEmbeddedBulletGlyphs.find(cBullet); + return it != maEmbeddedBulletGlyphs.end(); +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |