sd: de-duplicate masters on save to pptx follow-up
After commit 2d9c808d1952c18daa007b41e70fc7e63f6c5712 "sd: de-duplicate slide masters on save to pptx", there was some loss of data on save since when saving only the layouts for de-duplicated masters, not enough of the shape tree was being saved. Ideally we may want a clever algorithm that best separates the shape tree between master and layout, but just saving all the shape tree on the layout files when de-duplicating masters also works. Change-Id: I8b932708ef9212a4d5034713066299065083da8d Reviewed-on: https://gerrit.libreoffice.org/c/core/+/179861 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice@gmail.com> Reviewed-by: Miklos Vajna <vmiklos@collabora.com> (cherry picked from commit 3c8c537b3cfc4cf812e8728f6e6e46c0596ba7f6) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/180546 Tested-by: Jenkins Reviewed-by: Jaume Pujantell <jaume.pujantell@collabora.com>
This commit is contained in:
Binary file not shown.
@@ -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"14");
|
||||
"spid", u"59");
|
||||
}
|
||||
|
||||
CPPUNIT_TEST_FIXTURE(SdOOXMLExportTest2, testTdf112280)
|
||||
@@ -1889,10 +1889,10 @@ CPPUNIT_TEST_FIXTURE(SdOOXMLExportTest2, testTdf59323_slideFooters)
|
||||
}
|
||||
|
||||
// Test placeholder indexes
|
||||
xmlDocUniquePtr pXmlDocMaster = parseExport(u"ppt/slideMasters/slideMaster1.xml"_ustr);
|
||||
assertXPath(pXmlDocMaster, "//p:ph [@type='dt']", "idx", u"1");
|
||||
assertXPath(pXmlDocMaster, "//p:ph [@type='ftr']", "idx", u"2");
|
||||
assertXPath(pXmlDocMaster, "//p:ph [@type='sldNum']", "idx", u"3");
|
||||
xmlDocUniquePtr pXmlDocLayout = parseExport(u"ppt/slideLayouts/slideLayout1.xml"_ustr);
|
||||
assertXPath(pXmlDocLayout, "//p:ph [@type='dt']", "idx", u"1");
|
||||
assertXPath(pXmlDocLayout, "//p:ph [@type='ftr']", "idx", u"2");
|
||||
assertXPath(pXmlDocLayout, "//p:ph [@type='sldNum']", "idx", u"3");
|
||||
|
||||
xmlDocUniquePtr pXmlDocSlide1 = parseExport(u"ppt/slides/slide1.xml"_ustr);
|
||||
assertXPath(pXmlDocSlide1, "//p:ph [@type='dt']", "idx", u"1");
|
||||
|
||||
@@ -1274,6 +1274,43 @@ CPPUNIT_TEST_FIXTURE(SdOOXMLExportTest4, testPlaceHolderFitHeightToText)
|
||||
CPPUNIT_ASSERT_MESSAGE("PlaceHolder Fit height to text should be true.", bTextAutoGrowHeight);
|
||||
}
|
||||
|
||||
CPPUNIT_TEST_FIXTURE(SdOOXMLExportTest4, testDeduplicateMasters)
|
||||
{
|
||||
createSdImpressDoc("pptx/onemaster-twolayouts.pptx");
|
||||
saveAndReload("Impress Office Open XML");
|
||||
|
||||
// Check that the document still has one master and two layouts
|
||||
xmlDocUniquePtr pXmlDocContent = parseExport("ppt/presentation.xml");
|
||||
assertXPath(pXmlDocContent, "/p:presentation/p:sldMasterIdLst/p:sldMasterId"_ostr, 1);
|
||||
pXmlDocContent = parseExport("ppt/slideMasters/slideMaster1.xml");
|
||||
assertXPath(pXmlDocContent, "/p:sldMaster/p:sldLayoutIdLst/p:sldLayoutId"_ostr, 2);
|
||||
|
||||
// Check that both background colors have been preserved
|
||||
uno::Reference<drawing::XMasterPagesSupplier> xDoc(mxComponent, uno::UNO_QUERY);
|
||||
CPPUNIT_ASSERT(xDoc.is());
|
||||
CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xDoc->getMasterPages()->getCount());
|
||||
|
||||
uno::Reference<drawing::XDrawPage> xPage(xDoc->getMasterPages()->getByIndex(0),
|
||||
uno::UNO_QUERY_THROW);
|
||||
uno::Reference<beans::XPropertySet> xPropSet(xPage, uno::UNO_QUERY);
|
||||
uno::Any aAny = xPropSet->getPropertyValue("Background");
|
||||
CPPUNIT_ASSERT(aAny.hasValue());
|
||||
uno::Reference<beans::XPropertySet> aXBackgroundPropSet;
|
||||
aAny >>= aXBackgroundPropSet;
|
||||
Color nColor;
|
||||
CPPUNIT_ASSERT(aXBackgroundPropSet->getPropertyValue("FillColor") >>= nColor);
|
||||
CPPUNIT_ASSERT_EQUAL(Color(0x0E2841), nColor);
|
||||
|
||||
uno::Reference<drawing::XDrawPage> xPage1(xDoc->getMasterPages()->getByIndex(1),
|
||||
uno::UNO_QUERY_THROW);
|
||||
uno::Reference<beans::XPropertySet> xPropSet1(xPage1, uno::UNO_QUERY);
|
||||
aAny = xPropSet1->getPropertyValue("Background");
|
||||
CPPUNIT_ASSERT(aAny.hasValue());
|
||||
aAny >>= aXBackgroundPropSet;
|
||||
CPPUNIT_ASSERT(aXBackgroundPropSet->getPropertyValue("FillColor") >>= nColor);
|
||||
CPPUNIT_ASSERT_EQUAL(Color(0x000000), nColor);
|
||||
}
|
||||
|
||||
CPPUNIT_PLUGIN_IMPLEMENT();
|
||||
|
||||
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|
||||
|
||||
@@ -90,6 +90,9 @@ private:
|
||||
virtual void ImplWriteNotes( sal_uInt32 nPageNum ) override;
|
||||
virtual void ImplWriteSlideMaster( sal_uInt32 nPageNum, css::uno::Reference< css::beans::XPropertySet > const & aXBackgroundPropSet ) override;
|
||||
void ImplWritePPTXLayout( sal_Int32 nOffset, sal_uInt32 nMasterNum, const OUString& aSlideName );
|
||||
void ImplWritePPTXLayoutWithContent(
|
||||
sal_Int32 nOffset, sal_uInt32 nMasterNum, const OUString& aSlideName,
|
||||
css::uno::Reference<css::beans::XPropertySet> const& aXBackgroundPropSet);
|
||||
static void WriteDefaultColorSchemes(const FSHelperPtr& pFS);
|
||||
void WriteTheme( sal_Int32 nThemeNum, model::Theme* pTheme );
|
||||
|
||||
@@ -145,7 +148,7 @@ private:
|
||||
LayoutInfo mLayoutInfo[OOXML_LAYOUT_SIZE];
|
||||
// Pairs of masters and layouts as used by Impress
|
||||
std::vector<std::pair<SdrPage*, sal_Int32>> maMastersLayouts;
|
||||
// For each Impress master, which master will represent it on the exported file (themselves by default)
|
||||
// For each Impress master, which master will represent it on the exported file (SAL_MAX_UINT32 if not in an equivalency group)
|
||||
std::vector<sal_uInt32> maEquivalentMasters;
|
||||
std::unique_ptr<SvtSecurityMapPersonalInfo> mpAuthorIDs; // map authors to remove personal info
|
||||
std::vector< ::sax_fastparser::FSHelperPtr > mpSlidesFSArray;
|
||||
|
||||
@@ -1513,10 +1513,9 @@ void PowerPointExport::FindEquivalentMasterPages()
|
||||
css::uno::Reference<css::drawing::XDrawPages> xDrawPages(
|
||||
mXMasterPagesSupplier->getMasterPages());
|
||||
maMastersLayouts.resize(mnMasterPages);
|
||||
maEquivalentMasters.resize(mnMasterPages);
|
||||
maEquivalentMasters.resize(mnMasterPages, SAL_MAX_UINT32);
|
||||
for (sal_uInt32 i = 0; i < mnMasterPages; i++)
|
||||
{
|
||||
maEquivalentMasters[i] = i;
|
||||
css::uno::Reference<css::drawing::XDrawPage> xDrawPage;
|
||||
uno::Any aAny(xDrawPages->getByIndex(i));
|
||||
aAny >>= xDrawPage;
|
||||
@@ -1537,11 +1536,11 @@ void PowerPointExport::FindEquivalentMasterPages()
|
||||
|
||||
for (sal_uInt32 i = 0; i < mnMasterPages; i++)
|
||||
{
|
||||
if (!maMastersLayouts[i].first || maEquivalentMasters[i] != i)
|
||||
if (!maMastersLayouts[i].first || maEquivalentMasters[i] != SAL_MAX_UINT32)
|
||||
continue;
|
||||
for (sal_uInt32 j = i + 1; j < mnMasterPages; j++)
|
||||
{
|
||||
if (!maMastersLayouts[j].first || maEquivalentMasters[j] != j)
|
||||
if (!maMastersLayouts[j].first || maEquivalentMasters[j] != SAL_MAX_UINT32)
|
||||
continue;
|
||||
|
||||
if (lcl_ComparePageProperties(maMastersLayouts[i].first, maMastersLayouts[j].first)
|
||||
@@ -1550,6 +1549,7 @@ void PowerPointExport::FindEquivalentMasterPages()
|
||||
// If both masters have the same properties and objects,
|
||||
// we assume they are the same and only export the first one
|
||||
maEquivalentMasters[j] = i;
|
||||
maEquivalentMasters[i] = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1564,9 +1564,22 @@ sal_uInt32 PowerPointExport::GetEquivalentMasterPage(sal_uInt32 nMasterPage)
|
||||
|
||||
void PowerPointExport::ImplWriteSlideMaster(sal_uInt32 nPageNum, Reference< XPropertySet > const& aXBackgroundPropSet)
|
||||
{
|
||||
if (nPageNum != GetEquivalentMasterPage(nPageNum))
|
||||
SAL_INFO("sd.eppt", "write master slide: " << nPageNum << "\n--------------");
|
||||
|
||||
if (nPageNum != GetEquivalentMasterPage(nPageNum)
|
||||
&& GetEquivalentMasterPage(nPageNum) != SAL_MAX_UINT32)
|
||||
{
|
||||
// We already exported it's layout on an equivalent master so do nothing
|
||||
// It's equivalent to an already written master, write only the layout file
|
||||
if (maMastersLayouts[nPageNum].second != -1)
|
||||
{
|
||||
OUString aSlideName;
|
||||
Reference<XNamed> xNamed(mXDrawPage, UNO_QUERY);
|
||||
if (xNamed.is())
|
||||
aSlideName = xNamed->getName();
|
||||
ImplWritePPTXLayoutWithContent(maMastersLayouts[nPageNum].second, nPageNum, aSlideName,
|
||||
aXBackgroundPropSet);
|
||||
}
|
||||
|
||||
// Close the list tag if it was the last one
|
||||
if (nPageNum == mnMasterPages - 1)
|
||||
mPresentationFS->endElementNS(XML_p, XML_sldMasterIdLst);
|
||||
@@ -1574,8 +1587,6 @@ void PowerPointExport::ImplWriteSlideMaster(sal_uInt32 nPageNum, Reference< XPro
|
||||
return;
|
||||
}
|
||||
|
||||
SAL_INFO("sd.eppt", "write master slide: " << nPageNum << "\n--------------");
|
||||
|
||||
// slides list
|
||||
if (nPageNum == 0)
|
||||
mPresentationFS->startElementNS(XML_p, XML_sldMasterIdLst);
|
||||
@@ -1614,9 +1625,19 @@ void PowerPointExport::ImplWriteSlideMaster(sal_uInt32 nPageNum, Reference< XPro
|
||||
|
||||
pFS->startElementNS(XML_p, XML_cSld);
|
||||
|
||||
if (aXBackgroundPropSet)
|
||||
ImplWriteBackground(pFS, aXBackgroundPropSet);
|
||||
WriteShapeTree(pFS, MASTER, true);
|
||||
if (GetEquivalentMasterPage(nPageNum) != nPageNum)
|
||||
{
|
||||
if (aXBackgroundPropSet)
|
||||
ImplWriteBackground(pFS, aXBackgroundPropSet);
|
||||
WriteShapeTree(pFS, MASTER, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Minimal shape tree, the actual one will be written in the layout file.
|
||||
pFS->startElementNS(XML_p, XML_spTree);
|
||||
pFS->write(MAIN_GROUP);
|
||||
pFS->endElementNS(XML_p, XML_spTree);
|
||||
}
|
||||
|
||||
pFS->endElementNS(XML_p, XML_cSld);
|
||||
|
||||
@@ -1733,16 +1754,24 @@ void PowerPointExport::ImplWriteSlideMaster(sal_uInt32 nPageNum, Reference< XPro
|
||||
|
||||
for (auto nLayout : aLayouts)
|
||||
{
|
||||
ImplWritePPTXLayout(nLayout, nPageNum, aSlideName);
|
||||
if (GetEquivalentMasterPage(nPageNum) == nPageNum)
|
||||
ImplWritePPTXLayoutWithContent(nLayout, nPageNum, aSlideName, aXBackgroundPropSet);
|
||||
else
|
||||
ImplWritePPTXLayout(nLayout, nPageNum, aSlideName);
|
||||
AddLayoutIdAndRelation(pFS, GetLayoutFileId(nLayout, nPageNum));
|
||||
}
|
||||
|
||||
// Export layouts of other Impress masters that came from a sinlge pptx master with multiple layouts
|
||||
// Add layouts of other Impress masters that came from a single 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);
|
||||
// Reserve layout file Id to be writen later
|
||||
if (mLayoutInfo[maMastersLayouts[i].second].mnFileIdArray.size() < mnMasterPages)
|
||||
mLayoutInfo[maMastersLayouts[i].second].mnFileIdArray.resize(mnMasterPages);
|
||||
mLayoutInfo[maMastersLayouts[i].second].mnFileIdArray[i] = mnLayoutFileIdMax;
|
||||
mnLayoutFileIdMax++;
|
||||
|
||||
AddLayoutIdAndRelation(pFS, GetLayoutFileId(maMastersLayouts[i].second, i));
|
||||
}
|
||||
}
|
||||
@@ -1800,9 +1829,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(GetEquivalentMasterPage(nMasterNum) + 1) + ".xml"));
|
||||
addRelation(
|
||||
pFS->getOutputStream(), oox::getRelationship(Relationship::SLIDEMASTER),
|
||||
Concat2View("../slideMasters/slideMaster" + OUString::number(nMasterNum + 1) + ".xml"));
|
||||
|
||||
pFS->startElementNS(XML_p, XML_sldLayout,
|
||||
PNMSS,
|
||||
@@ -1835,6 +1864,57 @@ void PowerPointExport::ImplWritePPTXLayout(sal_Int32 nOffset, sal_uInt32 nMaster
|
||||
pFS->endDocument();
|
||||
}
|
||||
|
||||
void PowerPointExport::ImplWritePPTXLayoutWithContent(
|
||||
sal_Int32 nOffset, sal_uInt32 nMasterNum, const OUString& aSlideName,
|
||||
Reference<XPropertySet> const& aXBackgroundPropSet)
|
||||
{
|
||||
SAL_INFO("sd.eppt", "write layout: " << nOffset);
|
||||
|
||||
if (mLayoutInfo[nOffset].mnFileIdArray.size() < mnMasterPages)
|
||||
{
|
||||
mLayoutInfo[nOffset].mnFileIdArray.resize(mnMasterPages);
|
||||
}
|
||||
|
||||
if (mLayoutInfo[nOffset].mnFileIdArray[nMasterNum] == 0)
|
||||
{
|
||||
mLayoutInfo[nOffset].mnFileIdArray[nMasterNum] = mnLayoutFileIdMax;
|
||||
mnLayoutFileIdMax++;
|
||||
}
|
||||
sal_Int32 nLayoutFileId = mLayoutInfo[nOffset].mnFileIdArray[nMasterNum];
|
||||
|
||||
FSHelperPtr pFS = openFragmentStreamWithSerializer(
|
||||
"ppt/slideLayouts/slideLayout" + OUString::number(nLayoutFileId) + ".xml",
|
||||
"application/vnd.openxmlformats-officedocument.presentationml.slideLayout+xml");
|
||||
|
||||
// add implicit relation of slide layout to slide master
|
||||
addRelation(pFS->getOutputStream(), oox::getRelationship(Relationship::SLIDEMASTER),
|
||||
Concat2View("../slideMasters/slideMaster"
|
||||
+ OUString::number(GetEquivalentMasterPage(nMasterNum) + 1) + ".xml"));
|
||||
|
||||
pFS->startElementNS(XML_p, XML_sldLayout, PNMSS, XML_type, aLayoutInfo[nOffset].sType,
|
||||
XML_preserve, "1");
|
||||
|
||||
if (!aSlideName.isEmpty())
|
||||
{
|
||||
pFS->startElementNS(XML_p, XML_cSld, XML_name, aSlideName);
|
||||
}
|
||||
else
|
||||
{
|
||||
pFS->startElementNS(XML_p, XML_cSld, XML_name, aLayoutInfo[nOffset].sName);
|
||||
}
|
||||
|
||||
if (aXBackgroundPropSet)
|
||||
ImplWriteBackground(pFS, aXBackgroundPropSet);
|
||||
|
||||
WriteShapeTree(pFS, MASTER, true);
|
||||
|
||||
pFS->endElementNS(XML_p, XML_cSld);
|
||||
|
||||
pFS->endElementNS(XML_p, XML_sldLayout);
|
||||
|
||||
pFS->endDocument();
|
||||
}
|
||||
|
||||
void PowerPointExport::WriteShapeTree(const FSHelperPtr& pFS, PageType ePageType, bool bMaster)
|
||||
{
|
||||
PowerPointShapeExport aDML(pFS, &maShapeMap, this);
|
||||
@@ -2457,25 +2537,26 @@ Reference<XShape> PowerPointExport::GetReferencedPlaceholderXShape(const Placeho
|
||||
}
|
||||
if (ePresObjKind != PresObjKind::NONE)
|
||||
{
|
||||
SdPage* pMasterPage;
|
||||
SdrPage* pPage;
|
||||
if (ePageType == LAYOUT)
|
||||
{
|
||||
// since Layout pages do not have drawpages themselves - mXDrawPage is still the master they reference to..
|
||||
pMasterPage = SdPage::getImplementation(mXDrawPage);
|
||||
pPage = SdPage::getImplementation(mXDrawPage);
|
||||
}
|
||||
else
|
||||
{
|
||||
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<SdPage*>(pPage);
|
||||
pPage = &SdPage::getImplementation(mXDrawPage)->TRG_GetMasterPage();
|
||||
}
|
||||
for (sal_uInt32 i = 0; i < mnMasterPages; i++)
|
||||
{
|
||||
if (maMastersLayouts[i].first == pPage)
|
||||
{
|
||||
if (maEquivalentMasters[i] < mnMasterPages)
|
||||
pPage = maMastersLayouts[maEquivalentMasters[i]].first;
|
||||
break;
|
||||
}
|
||||
}
|
||||
SdPage* pMasterPage = dynamic_cast<SdPage*>(pPage);
|
||||
if (SdrObject* pMasterFooter
|
||||
= (pMasterPage ? pMasterPage->GetPresObj(ePresObjKind) : nullptr))
|
||||
return GetXShapeForSdrObject(pMasterFooter);
|
||||
|
||||
Reference in New Issue
Block a user