diff --git a/sd/qa/unit/export-tests-ooxml2.cxx b/sd/qa/unit/export-tests-ooxml2.cxx index 892ce86f231a..96c94aec32c1 100644 --- a/sd/qa/unit/export-tests-ooxml2.cxx +++ b/sd/qa/unit/export-tests-ooxml2.cxx @@ -1316,7 +1316,7 @@ CPPUNIT_TEST_FIXTURE(SdOOXMLExportTest2, testTdf106867) "/p:sld/p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn/p:childTnLst/p:par/" "p:cTn/p:childTnLst/p:par/p:cTn/p:childTnLst/p:par/p:cTn/p:childTnLst/p:cmd/" "p:cBhvr/p:tgtEl/p:spTgt", - "spid", u"67"); + "spid", u"14"); } CPPUNIT_TEST_FIXTURE(SdOOXMLExportTest2, testTdf112280) @@ -1695,7 +1695,7 @@ CPPUNIT_TEST_FIXTURE(SdOOXMLExportTest2, testAccentColor) xmlDocUniquePtr pXmlDocTheme1 = parseExport(u"ppt/theme/theme1.xml"_ustr); assertXPath(pXmlDocTheme1, "/a:theme/a:themeElements/a:clrScheme/a:accent6/a:srgbClr", "val", u"70ad47"); - xmlDocUniquePtr pXmlDocTheme2 = parseExport(u"ppt/theme/theme12.xml"_ustr); + xmlDocUniquePtr pXmlDocTheme2 = parseExport(u"ppt/theme/theme2.xml"_ustr); assertXPath(pXmlDocTheme2, "/a:theme/a:themeElements/a:clrScheme/a:accent6/a:srgbClr", "val", u"deb340"); diff --git a/sd/qa/unit/export-tests-ooxml4.cxx b/sd/qa/unit/export-tests-ooxml4.cxx index 5c8085911303..29d45da07bba 100644 --- a/sd/qa/unit/export-tests-ooxml4.cxx +++ b/sd/qa/unit/export-tests-ooxml4.cxx @@ -1153,15 +1153,12 @@ CPPUNIT_TEST_FIXTURE(SdOOXMLExportTest4, testTdf157740_slideMasters) createSdImpressDoc("pptx/tdf157740.pptx"); saveAndReload(u"Impress Office Open XML"_ustr); - // Test how many slidemaster we have + // The original file has 1 slide master and 7 slide layouts in that master xmlDocUniquePtr pXmlDocContent = parseExport(u"ppt/presentation.xml"_ustr); - assertXPath(pXmlDocContent, "/p:presentation/p:sldMasterIdLst/p:sldMasterId", 7); + assertXPath(pXmlDocContent, "/p:presentation/p:sldMasterIdLst/p:sldMasterId", 1); pXmlDocContent = parseExport(u"ppt/slideMasters/slideMaster1.xml"_ustr); - assertXPath(pXmlDocContent, "/p:sldMaster/p:sldLayoutIdLst/p:sldLayoutId", 1); - - pXmlDocContent = parseExport(u"ppt/slideMasters/slideMaster7.xml"_ustr); - assertXPath(pXmlDocContent, "/p:sldMaster/p:sldLayoutIdLst/p:sldLayoutId", 1); + assertXPath(pXmlDocContent, "/p:sldMaster/p:sldLayoutIdLst/p:sldLayoutId", 7); } CPPUNIT_TEST_FIXTURE(SdOOXMLExportTest4, testTdf159931_slideLayouts) diff --git a/sd/source/filter/eppt/epptooxml.hxx b/sd/source/filter/eppt/epptooxml.hxx index f8e4eea812cf..8fcb4c0a9fbe 100644 --- a/sd/source/filter/eppt/epptooxml.hxx +++ b/sd/source/filter/eppt/epptooxml.hxx @@ -131,6 +131,9 @@ private: css::uno::Reference GetReferencedPlaceholderXShape(const PlaceholderType eType, PageType ePageType) const; void WritePlaceholderReferenceShapes(PowerPointShapeExport& rDML, PageType ePageType); + void FindEquivalentMasterPages(); + sal_uInt32 GetEquivalentMasterPage(sal_uInt32 nMasterPage); + /// Should we export as .pptm, ie. do we contain macros? bool mbPptm; @@ -140,6 +143,10 @@ private: ::sax_fastparser::FSHelperPtr mPresentationFS; LayoutInfo mLayoutInfo[OOXML_LAYOUT_SIZE]; + // Pairs of masters and layouts as used by Impress + std::vector> maMastersLayouts; + // For each Impress master, which master will represent it on the exported file (themselves by default) + std::vector maEquivalentMasters; std::unique_ptr mpAuthorIDs; // map authors to remove personal info std::vector< ::sax_fastparser::FSHelperPtr > mpSlidesFSArray; sal_Int32 mnLayoutFileIdMax; @@ -147,6 +154,7 @@ private: sal_uInt32 mnSlideIdMax; sal_uInt32 mnSlideMasterIdMax; sal_uInt32 mnAnimationNodeIdMax; + sal_uInt32 mnThemeIdMax; sal_uInt32 mnDiagramId; diff --git a/sd/source/filter/eppt/pptx-epptooxml.cxx b/sd/source/filter/eppt/pptx-epptooxml.cxx index 01174b023902..0e7b0453144b 100644 --- a/sd/source/filter/eppt/pptx-epptooxml.cxx +++ b/sd/source/filter/eppt/pptx-epptooxml.cxx @@ -25,6 +25,8 @@ #include #include "epptooxml.hxx" #include +#include +#include #include #include @@ -41,6 +43,8 @@ #include #include #include +#include +#include #include #include #include @@ -348,6 +352,7 @@ PowerPointExport::PowerPointExport(const Reference< XComponentContext >& rContex , mnSlideIdMax(1 << 8) , mnSlideMasterIdMax(1U << 31) , mnAnimationNodeIdMax(1) + , mnThemeIdMax(0) , mnDiagramId(1) , mbCreateNotes(false) , mnPlaceholderIndexMax(1) @@ -1449,8 +1454,126 @@ void PowerPointExport::AddLayoutIdAndRelation(const FSHelperPtr& pFS, sal_Int32 FSNS(XML_r, XML_id), sRelId); } +static bool lcl_ContainsEquivalentObject(SdrPage* pPage, SdrObject* pObj) +{ + bool bFound = false; + + if (!pPage || !pObj) + return bFound; + + for (size_t nObj = 0; nObj < pPage->GetObjCount(); ++nObj) + { + SdrObject* pObjNext = pPage->GetObj(nObj); + if (pObjNext && pObjNext->GetMergedItemSet().Equals(pObj->GetMergedItemSet(), false)) + { + bFound = true; + break; + } + } + + return bFound; +} + +static bool lcl_ComparePageObjects(SdrPage* pMasterPage, SdrPage* pMasterNext) +{ + if (!pMasterPage || !pMasterNext) + return false; + + SdrObject* pObjNext; + SdrLayerID aLayer = pMasterNext->GetLayerAdmin().GetLayerID(sUNO_LayerName_background_objects); + + for (size_t nObj = 0; nObj < pMasterPage->GetObjCount(); ++nObj) + { + pObjNext = pMasterPage->GetObj(nObj); + if (!pObjNext || pObjNext->GetLayer() == aLayer) + continue; + + if (!lcl_ContainsEquivalentObject(pMasterNext, pObjNext)) + return false; + } + + // No differences found + return true; +} + +static bool lcl_ComparePageProperties(SdrPage* pMasterPage, SdrPage* pMasterNext) +{ + if (!pMasterPage || !pMasterNext) + return false; + + SdrPageProperties& rProperties = pMasterPage->getSdrPageProperties(); + SdrPageProperties& rNextProperties = pMasterNext->getSdrPageProperties(); + + return rProperties.GetItemSet().Equals(rNextProperties.GetItemSet(), false) + && rProperties.getTheme().get() == rNextProperties.getTheme().get(); +} + +void PowerPointExport::FindEquivalentMasterPages() +{ + css::uno::Reference xDrawPages( + mXMasterPagesSupplier->getMasterPages()); + maMastersLayouts.resize(mnMasterPages); + maEquivalentMasters.resize(mnMasterPages); + for (sal_uInt32 i = 0; i < mnMasterPages; i++) + { + maEquivalentMasters[i] = i; + css::uno::Reference xDrawPage; + uno::Any aAny(xDrawPages->getByIndex(i)); + aAny >>= xDrawPage; + if (!xDrawPage.is()) + continue; + + maMastersLayouts[i] = std::make_pair(SdPage::getImplementation(xDrawPage), -1); + uno::Reference xPagePropSet(xDrawPage, uno::UNO_QUERY_THROW); + if (xPagePropSet.is()) + { + uno::Any aLayout = xPagePropSet->getPropertyValue("SlideLayout"); + if (aLayout.hasValue()) + { + aLayout >>= maMastersLayouts[i].second; + } + } + } + + for (sal_uInt32 i = 0; i < mnMasterPages; i++) + { + if (!maMastersLayouts[i].first || maEquivalentMasters[i] != i) + continue; + for (sal_uInt32 j = i + 1; j < mnMasterPages; j++) + { + if (!maMastersLayouts[j].first || maEquivalentMasters[j] != j) + continue; + + if (lcl_ComparePageProperties(maMastersLayouts[i].first, maMastersLayouts[j].first) + && lcl_ComparePageObjects(maMastersLayouts[i].first, maMastersLayouts[j].first)) + { + // If both masters have the same properties and objects, + // we assume they are the same and only export the first one + maEquivalentMasters[j] = i; + } + } + } +} + +sal_uInt32 PowerPointExport::GetEquivalentMasterPage(sal_uInt32 nMasterPage) +{ + if (maEquivalentMasters.size() == 0) + FindEquivalentMasterPages(); + return maEquivalentMasters[nMasterPage]; +} + void PowerPointExport::ImplWriteSlideMaster(sal_uInt32 nPageNum, Reference< XPropertySet > const& aXBackgroundPropSet) { + if (nPageNum != GetEquivalentMasterPage(nPageNum)) + { + // We already exported it's layout on an equivalent master so do nothing + // Close the list tag if it was the last one + if (nPageNum == mnMasterPages - 1) + mPresentationFS->endElementNS(XML_p, XML_sldMasterIdLst); + + return; + } + SAL_INFO("sd.eppt", "write master slide: " << nPageNum << "\n--------------"); // slides list @@ -1481,12 +1604,11 @@ void PowerPointExport::ImplWriteSlideMaster(sal_uInt32 nPageNum, Reference< XPro } // write theme per master - WriteTheme(nPageNum, pTheme); + WriteTheme(mnThemeIdMax, pTheme); // add implicit relation to the presentation theme - addRelation(pFS->getOutputStream(), - oox::getRelationship(Relationship::THEME), - Concat2View("../theme/theme" + OUString::number(nPageNum + 1) + ".xml")); + addRelation(pFS->getOutputStream(), oox::getRelationship(Relationship::THEME), + Concat2View("../theme/theme" + OUString::number(++mnThemeIdMax) + ".xml")); pFS->startElementNS(XML_p, XML_sldMaster, PNMSS); @@ -1615,6 +1737,16 @@ void PowerPointExport::ImplWriteSlideMaster(sal_uInt32 nPageNum, Reference< XPro AddLayoutIdAndRelation(pFS, GetLayoutFileId(nLayout, nPageNum)); } + // Export layouts of other Impress masters that came from a sinlge pptx master with multiple layouts + for (sal_uInt32 i = 0; i < mnMasterPages; i++) + { + if (i != nPageNum && maEquivalentMasters[i] == nPageNum && maMastersLayouts[i].second != -1) + { + ImplWritePPTXLayout(maMastersLayouts[i].second, i, aSlideName); + AddLayoutIdAndRelation(pFS, GetLayoutFileId(maMastersLayouts[i].second, i)); + } + } + pFS->endElementNS(XML_p, XML_sldLayoutIdLst); pFS->endElementNS(XML_p, XML_sldMaster); @@ -1668,9 +1800,9 @@ void PowerPointExport::ImplWritePPTXLayout(sal_Int32 nOffset, sal_uInt32 nMaster u"application/vnd.openxmlformats-officedocument.presentationml.slideLayout+xml"_ustr); // add implicit relation of slide layout to slide master - addRelation(pFS->getOutputStream(), - oox::getRelationship(Relationship::SLIDEMASTER), - Concat2View("../slideMasters/slideMaster" + OUString::number(nMasterNum + 1) + ".xml")); + addRelation(pFS->getOutputStream(), oox::getRelationship(Relationship::SLIDEMASTER), + Concat2View("../slideMasters/slideMaster" + + OUString::number(GetEquivalentMasterPage(nMasterNum) + 1) + ".xml")); pFS->startElementNS(XML_p, XML_sldLayout, PNMSS, @@ -2333,9 +2465,19 @@ Reference PowerPointExport::GetReferencedPlaceholderXShape(const Placeho } else { - pMasterPage = &static_cast(SdPage::getImplementation(mXDrawPage)->TRG_GetMasterPage()); + SdrPage* pPage = &SdPage::getImplementation(mXDrawPage)->TRG_GetMasterPage(); + for (sal_uInt32 i = 0; i < mnMasterPages; i++) + { + if (maMastersLayouts[i].first == pPage) + { + pPage = maMastersLayouts[maEquivalentMasters[i]].first; + break; + } + } + pMasterPage = dynamic_cast(pPage); } - if (SdrObject* pMasterFooter = pMasterPage->GetPresObj(ePresObjKind)) + if (SdrObject* pMasterFooter + = (pMasterPage ? pMasterPage->GetPresObj(ePresObjKind) : nullptr)) return GetXShapeForSdrObject(pMasterFooter); } return nullptr;