tdf#169825 AutoLayout can be incorrectly exported to PPTX
...as vertTitleAndTxOverChart, if ODP layout was
AUTOLAYOUT_NOTES, causing corruption.
PPTX export code directly matched LO's AutoLayout IDs to
PPTX layout types (OOXML spec: 19.7.15 ST_SlideLayoutType
(Slide Layout Type)) without conversion, as some don't have
direct match, and need to be matched to blank layouts. This
could result in PPTXes that can't be opened in PowerPoint.
It could also result in PPTXes with wrong layout types when
using LO's own vertical layouts. The files could still be
opened in PP in this case.
In addition, import code imported vertical PPTX layouts
with wrong IDs, matching them to notes and handout autolayouts.
Part of the mentioned behavior happened since
bff76421e2.
Change-Id: Iba7a50795979c22bc566aa2cd6ea4d82f7f9477e
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/195049
Tested-by: Jenkins
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
Reviewed-by: Aron Budea <aron.budea@collabora.com>
This commit is contained in:
@@ -88,6 +88,8 @@ SlidePersist::~SlidePersist()
|
||||
{
|
||||
}
|
||||
|
||||
// the list 'const PPTXLayoutInfo aLayoutInfo[...]' used in PowerPointExport
|
||||
// likely needs to be updated after any changes here
|
||||
sal_Int16 SlidePersist::getLayoutFromValueToken() const
|
||||
{
|
||||
sal_Int16 nLayout = 20; // 20 == blank (so many magic numbers :-( the description at com.sun.star.presentation.DrawPage.Layout does not help)
|
||||
@@ -97,7 +99,7 @@ sal_Int16 SlidePersist::getLayoutFromValueToken() const
|
||||
case XML_chart: nLayout = 2; break;
|
||||
case XML_chartAndTx: nLayout = 7; break;
|
||||
case XML_clipArtAndTx: nLayout = 9; break;
|
||||
case XML_clipArtAndVertTx: nLayout = 24; break;
|
||||
case XML_clipArtAndVertTx: nLayout = 30; break;
|
||||
case XML_fourObj: nLayout = 18; break;
|
||||
case XML_obj: nLayout = 11; break;
|
||||
case XML_objAndTx: nLayout = 13; break;
|
||||
@@ -112,15 +114,15 @@ sal_Int16 SlidePersist::getLayoutFromValueToken() const
|
||||
case XML_twoObjOverTx: nLayout = 16; break;
|
||||
case XML_tx: nLayout = 1; break;
|
||||
case XML_txAndChart: nLayout = 4; break;
|
||||
case XML_txAndClipArt: nLayout = 6; break;
|
||||
case XML_txAndClipArt:
|
||||
case XML_txAndMedia: nLayout = 6; break;
|
||||
case XML_txAndObj: nLayout = 10; break;
|
||||
case XML_objAndTwoObj:
|
||||
case XML_txAndTwoObj: nLayout = 12; break;
|
||||
case XML_txOverObj: nLayout = 17; break;
|
||||
case XML_vertTitleAndTx: nLayout = 22; break;
|
||||
case XML_vertTitleAndTxOverChart: nLayout = 21; break;
|
||||
case XML_vertTx: nLayout = 23; break;
|
||||
case XML_vertTitleAndTx: nLayout = 28; break;
|
||||
case XML_vertTitleAndTxOverChart: nLayout = 27; break;
|
||||
case XML_vertTx: nLayout = 29; break;
|
||||
case XML_objOnly: nLayout = 32; break;
|
||||
|
||||
case XML_twoTxTwoObj:
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -20,6 +20,7 @@
|
||||
#include <svx/xlndsit.hxx>
|
||||
#include <svx/svdoole2.hxx>
|
||||
#include <svx/svdotable.hxx>
|
||||
#include <xmloff/autolayout.hxx>
|
||||
|
||||
#include <com/sun/star/awt/FontUnderline.hpp>
|
||||
#include <com/sun/star/drawing/EnhancedCustomShapeParameterPair.hpp>
|
||||
@@ -1712,6 +1713,94 @@ CPPUNIT_TEST_FIXTURE(SdOOXMLExportTest4, testtdf169496_hidden_graphic)
|
||||
CPPUNIT_FAIL("Names of graphics is incorrect");
|
||||
}
|
||||
|
||||
CPPUNIT_TEST_FIXTURE(SdOOXMLExportTest4, testtdf169825_vertical_layouts)
|
||||
{
|
||||
createSdImpressDoc("pptx/tdf169825_vertical_layouts.pptx");
|
||||
save(TestFilter::PPTX);
|
||||
|
||||
xmlDocUniquePtr pXmlDocRels = parseExport(u"ppt/slides/_rels/slide1.xml.rels"_ustr);
|
||||
CPPUNIT_ASSERT(pXmlDocRels);
|
||||
// find layout XML for the slide from the relationship file
|
||||
OUString sLayoutRelRelative
|
||||
= getXPath(pXmlDocRels, "/rels:Relationships/rels:Relationship", "Target");
|
||||
OUString sLayoutRelAbs = sLayoutRelRelative.replaceFirst("..", "ppt");
|
||||
xmlDocUniquePtr pXmlDocLayout = parseExport(sLayoutRelAbs);
|
||||
CPPUNIT_ASSERT(pXmlDocLayout);
|
||||
|
||||
// without the SlidePersist::getLayoutFromValueToken() part of the patch,
|
||||
// this and the next layout types would both be exported as blank
|
||||
assertXPath(pXmlDocLayout, "/p:sldLayout", "type", u"vertTitleAndTx");
|
||||
|
||||
pXmlDocRels = parseExport(u"ppt/slides/_rels/slide2.xml.rels"_ustr);
|
||||
CPPUNIT_ASSERT(pXmlDocRels);
|
||||
sLayoutRelRelative = getXPath(pXmlDocRels, "/rels:Relationships/rels:Relationship", "Target");
|
||||
sLayoutRelAbs = sLayoutRelRelative.replaceFirst("..", "ppt");
|
||||
pXmlDocLayout = parseExport(sLayoutRelAbs);
|
||||
CPPUNIT_ASSERT(pXmlDocLayout);
|
||||
|
||||
assertXPath(pXmlDocLayout, "/p:sldLayout", "type", u"vertTx");
|
||||
}
|
||||
|
||||
CPPUNIT_TEST_FIXTURE(SdOOXMLExportTest4, testtdf169825_vertical_layouts_from_scratch)
|
||||
{
|
||||
createSdImpressDoc();
|
||||
|
||||
uno::Reference<drawing::XDrawPagesSupplier> xDoc(mxComponent, uno::UNO_QUERY_THROW);
|
||||
uno::Reference<drawing::XDrawPages> xPages = xDoc->getDrawPages();
|
||||
uno::Reference<drawing::XDrawPage> xPage(xPages->getByIndex(0), uno::UNO_QUERY);
|
||||
uno::Reference<beans::XPropertySet> xPageSet(xPage, uno::UNO_QUERY_THROW);
|
||||
xPageSet->setPropertyValue(
|
||||
"Layout",
|
||||
uno::Any(static_cast<sal_Int32>(AutoLayout::AUTOLAYOUT_VTITLE_VCONTENT_OVER_VCONTENT)));
|
||||
|
||||
uno::Reference<drawing::XDrawPage> xPage2(xPages->insertNewByIndex(1), uno::UNO_SET_THROW);
|
||||
uno::Reference<beans::XPropertySet> xPageSet2(xPage2, uno::UNO_QUERY_THROW);
|
||||
xPageSet2->setPropertyValue(
|
||||
"Layout", uno::Any(static_cast<sal_Int32>(AutoLayout::AUTOLAYOUT_VTITLE_VCONTENT)));
|
||||
save(TestFilter::PPTX);
|
||||
|
||||
xmlDocUniquePtr pXmlDocRels = parseExport(u"ppt/slides/_rels/slide1.xml.rels"_ustr);
|
||||
CPPUNIT_ASSERT(pXmlDocRels);
|
||||
// find layout XML for the slide from the relationship file
|
||||
OUString sLayoutRelRelative
|
||||
= getXPath(pXmlDocRels, "/rels:Relationships/rels:Relationship", "Target");
|
||||
OUString sLayoutRelAbs = sLayoutRelRelative.replaceFirst("..", "ppt");
|
||||
xmlDocUniquePtr pXmlDocLayout = parseExport(sLayoutRelAbs);
|
||||
CPPUNIT_ASSERT(pXmlDocLayout);
|
||||
|
||||
// without the fix in place this would be exported as "objTx"
|
||||
assertXPath(pXmlDocLayout, "/p:sldLayout", "type", u"vertTitleAndTxOverChart");
|
||||
|
||||
pXmlDocRels = parseExport(u"ppt/slides/_rels/slide2.xml.rels"_ustr);
|
||||
CPPUNIT_ASSERT(pXmlDocRels);
|
||||
sLayoutRelRelative = getXPath(pXmlDocRels, "/rels:Relationships/rels:Relationship", "Target");
|
||||
sLayoutRelAbs = sLayoutRelRelative.replaceFirst("..", "ppt");
|
||||
pXmlDocLayout = parseExport(sLayoutRelAbs);
|
||||
CPPUNIT_ASSERT(pXmlDocLayout);
|
||||
|
||||
// without the fix in place this would be exported as "picTx"
|
||||
assertXPath(pXmlDocLayout, "/p:sldLayout", "type", u"vertTitleAndTx");
|
||||
}
|
||||
|
||||
CPPUNIT_TEST_FIXTURE(SdOOXMLExportTest4, testtdf169825_layout_type)
|
||||
{
|
||||
createSdImpressDoc("odp/tdf169825_layout_type.odp");
|
||||
save(TestFilter::PPTX);
|
||||
|
||||
xmlDocUniquePtr pXmlDocRels = parseExport(u"ppt/slides/_rels/slide1.xml.rels"_ustr);
|
||||
CPPUNIT_ASSERT(pXmlDocRels);
|
||||
// find layout XML for the slide from the relationship file
|
||||
OUString sLayoutRelRelative
|
||||
= getXPath(pXmlDocRels, "/rels:Relationships/rels:Relationship", "Target");
|
||||
OUString sLayoutRelAbs = sLayoutRelRelative.replaceFirst("..", "ppt");
|
||||
xmlDocUniquePtr pXmlDocLayout = parseExport(sLayoutRelAbs);
|
||||
CPPUNIT_ASSERT(pXmlDocLayout);
|
||||
|
||||
// without the fix in place this would be exported as "vertTitleAndTxOverChart"
|
||||
// while in the original ODP this was - still possibly bogus - notes layout
|
||||
assertXPath(pXmlDocLayout, "/p:sldLayout", "type", u"blank");
|
||||
}
|
||||
|
||||
CPPUNIT_PLUGIN_IMPLEMENT();
|
||||
|
||||
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|
||||
|
||||
@@ -76,7 +76,6 @@ enum class EppLayout
|
||||
};
|
||||
|
||||
#define EPP_LAYOUT_SIZE 25
|
||||
#define OOXML_LAYOUT_SIZE 36
|
||||
|
||||
struct PHLayout
|
||||
{
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <oox/vml/vmldrawing.hxx>
|
||||
#include <oox/export/shapes.hxx>
|
||||
#include <unotools/securityoptions.hxx>
|
||||
#include <xmloff/autolayout.hxx>
|
||||
#include "epptbase.hxx"
|
||||
|
||||
using ::sax_fastparser::FSHelperPtr;
|
||||
@@ -147,7 +148,7 @@ private:
|
||||
|
||||
::sax_fastparser::FSHelperPtr mPresentationFS;
|
||||
|
||||
LayoutInfo mLayoutInfo[OOXML_LAYOUT_SIZE];
|
||||
LayoutInfo mLayoutInfo[AUTOLAYOUT_END];
|
||||
// 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 (SAL_MAX_UINT32 if not in an equivalency group)
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "epptooxml.hxx"
|
||||
#include <oox/export/shapes.hxx>
|
||||
#include <svx/svdlayer.hxx>
|
||||
#include <xmloff/autolayout.hxx>
|
||||
#include <unokywds.hxx>
|
||||
#include <osl/file.hxx>
|
||||
|
||||
@@ -234,20 +235,25 @@ struct PPTXLayoutInfo
|
||||
|
||||
}
|
||||
|
||||
const PPTXLayoutInfo aLayoutInfo[OOXML_LAYOUT_SIZE] =
|
||||
// the function 'SlidePersist::getLayoutFromValueToken()'
|
||||
// likely needs to be updated after any changes here
|
||||
// unsupported PPTX layouts: txAndMedia, twoColTx, twoTxTwoObj,
|
||||
// twoObjAndObj, objTx, picTx, secHead, objOnly, objAndTwoObj,
|
||||
// mediaAndTx, dgm, cust
|
||||
const PPTXLayoutInfo aLayoutInfo[] =
|
||||
{
|
||||
{ 0, "Title Slide", "title" },
|
||||
{ 1, "Title and text", "tx" },
|
||||
{ 2, "Title and chart", "chart" },
|
||||
{ 3, "Title, text on left, text on right", "twoObj" },
|
||||
{ 4, "Title, text on left and chart on right", "txAndChart" },
|
||||
{ 20, "Blank Slide", "blank" },
|
||||
{ 6, "Title, text on left, clip art on right", "txAndClipArt" },
|
||||
{ 6, "Title, text on left, media on right", "txAndMedia" },
|
||||
{ 7, "Title, chart on left and text on right", "chartAndTx" },
|
||||
{ 8, "Title and table", "tbl" },
|
||||
{ 9, "Title, clipart on left, text on right", "clipArtAndTx" },
|
||||
{ 10, "Title, text on left, object on right", "txAndObj" },
|
||||
{ 1, "Title and object", "obj" },
|
||||
{ 11, "Title and object", "obj" },
|
||||
{ 12, "Title, text on left, two objects on right", "txAndTwoObj" },
|
||||
{ 13, "Title, object on left, text on right", "objAndTx" },
|
||||
{ 14, "Title, object on top, text on bottom", "objOverTx" },
|
||||
@@ -257,22 +263,23 @@ const PPTXLayoutInfo aLayoutInfo[OOXML_LAYOUT_SIZE] =
|
||||
{ 18, "Title and four objects", "fourObj" },
|
||||
{ 19, "Title Only", "titleOnly" },
|
||||
{ 20, "Blank Slide", "blank" },
|
||||
{ 21, "Vertical title on right, vertical text on top, chart on bottom", "vertTitleAndTxOverChart" },
|
||||
{ 22, "Vertical title on right, vertical text on left", "vertTitleAndTx" },
|
||||
{ 23, "Title and vertical text body", "vertTx" },
|
||||
{ 24, "Title, clip art on left, vertical text on right", "clipArtAndVertTx" },
|
||||
{ 20, "Title, two objects each with text", "twoTxTwoObj" },
|
||||
{ 15, "Title, two objects on left, one object on right", "twoObjAndObj" },
|
||||
{ 20, "Title, object and caption text", "objTx" },
|
||||
{ 20, "Title, picture, and caption text", "picTx" },
|
||||
{ 20, "Section header title and subtitle text", "secHead" },
|
||||
{ 20, "Blank Slide", "blank" },
|
||||
{ 20, "Blank Slide", "blank" },
|
||||
{ 20, "Blank Slide", "blank" },
|
||||
{ 20, "Blank Slide", "blank" },
|
||||
{ 20, "Blank Slide", "blank" },
|
||||
{ 20, "Blank Slide", "blank" },
|
||||
{ 27, "Vertical title on right, vertical text on top, chart on bottom", "vertTitleAndTxOverChart" },
|
||||
{ 28, "Vertical title on right, vertical text on left", "vertTitleAndTx" },
|
||||
{ 29, "Title and vertical text body", "vertTx" },
|
||||
{ 30, "Title, clip art on left, vertical text on right", "clipArtAndVertTx" },
|
||||
{ 20, "Blank Slide", "blank" },
|
||||
{ 32, "Object only", "objOnly" },
|
||||
{ 12, "Title, one object on left, two objects on right", "objAndTwoObj" },
|
||||
{ 20, "Title, media on left, text on right", "mediaAndTx" },
|
||||
{ 34, "Title, 6 Content", "blank" }, // not defined in OOXML => blank
|
||||
{ 2, "Title and diagram", "dgm" },
|
||||
{ 0, "Custom layout defined by user", "cust" },
|
||||
{ 20, "Blank Slide", "blank" },
|
||||
{ 20, "Blank Slide", "blank" }
|
||||
};
|
||||
static_assert(std::size(aLayoutInfo) == AUTOLAYOUT_END,
|
||||
"aLayoutInfo must have a corresponding item for each AUTOLAYOUT");
|
||||
|
||||
PowerPointShapeExport::PowerPointShapeExport(FSHelperPtr pFS, ShapeHashMap* pShapeMap,
|
||||
PowerPointExport* pFB)
|
||||
@@ -1962,7 +1969,7 @@ void PowerPointExport::ImplWriteSlideMaster(sal_uInt32 nPageNum, Reference< XPro
|
||||
Reference<XNamed> xNamed(mXDrawPage, UNO_QUERY);
|
||||
if (xNamed.is())
|
||||
aSlideName = xNamed->getName();
|
||||
for (int i = 0; i < OOXML_LAYOUT_SIZE; ++i)
|
||||
for (int i = 0; i < AUTOLAYOUT_END; ++i)
|
||||
{
|
||||
if (mLayoutInfo[i].mnFileIdArray.size() > nPageNum
|
||||
&& mLayoutInfo[i].mnFileIdArray[nPageNum] > 0)
|
||||
|
||||
Reference in New Issue
Block a user