1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 #include <swmodeltestbase.hxx>
12 #include <comphelper/processfactory.hxx>
13 #include <svx/svddef.hxx>
14 #include <svx/sdmetitm.hxx>
15 #include <svx/svdobj.hxx>
17 #include <com/sun/star/drawing/FillStyle.hpp>
18 #include <com/sun/star/lang/Locale.hpp>
19 #include <com/sun/star/packages/zip/ZipFileAccess.hpp>
20 #include <com/sun/star/text/XChapterNumberingSupplier.hpp>
21 #include <com/sun/star/text/XEndnotesSupplier.hpp>
22 #include <com/sun/star/text/XFootnotesSupplier.hpp>
23 #include <com/sun/star/text/XTextFieldsSupplier.hpp>
24 #include <com/sun/star/text/XTextFrame.hpp>
25 #include <com/sun/star/text/XTextFramesSupplier.hpp>
26 #include <com/sun/star/text/XTextTablesSupplier.hpp>
27 #include <com/sun/star/text/XTextViewCursorSupplier.hpp>
28 #include <com/sun/star/view/XViewCursor.hpp>
29 #include <comphelper/sequenceashashmap.hxx>
30 #include <unoprnms.hxx>
31 #include <o3tl/string_view.hxx>
32 #include <comphelper/scopeguard.hxx>
33 #include <officecfg/Office/Common.hxx>
35 class Test
: public SwModelTestBase
38 Test() : SwModelTestBase(u
"/sw/qa/extras/ooxmlexport/data/"_ustr
, u
"Office Open XML Text"_ustr
) {}
41 CPPUNIT_TEST_FIXTURE(Test
, testTdf143860NonPrimitiveCustomShape
)
43 loadAndReload("tdf143860_NonPrimitiveCustomShape.odt");
44 CPPUNIT_ASSERT_EQUAL(1, getShapes());
45 CPPUNIT_ASSERT_EQUAL(1, getPages());
46 // The document has a custom shape of type non-primitive without handles. Make sure that the shape
47 // is not exported with preset but with custom geometry.
48 xmlDocUniquePtr pXmlDocument
= parseExport(u
"word/document.xml"_ustr
);
49 CPPUNIT_ASSERT(pXmlDocument
);
50 assertXPath(pXmlDocument
, "//a:prstGeom", 0);
51 assertXPath(pXmlDocument
, "//a:custGeom", 1);
54 CPPUNIT_TEST_FIXTURE(Test
, testWrapPolygonCurve
)
56 loadAndSave("tdf136386_WrapPolygonCurve.odt");
57 CPPUNIT_ASSERT_EQUAL(1, getShapes());
58 CPPUNIT_ASSERT_EQUAL(1, getPages());
59 // Document has a curve with contour wrap and 'outside only'. Error was, that type 'square' was
60 // written and no wrap polygon. Make sure we write wrapTight and a wrapPolygon.
61 xmlDocUniquePtr pXmlDocument
= parseExport(u
"word/document.xml"_ustr
);
62 CPPUNIT_ASSERT(pXmlDocument
);
63 assertXPath(pXmlDocument
, "//wp:wrapTight", 1);
64 assertXPath(pXmlDocument
, "//wp:wrapPolygon", 1);
65 assertXPath(pXmlDocument
, "//wp:start", 1);
66 xmlXPathObjectPtr pXmlObj
= getXPathNode(pXmlDocument
, "//wp:lineTo");
67 CPPUNIT_ASSERT_GREATER(sal_Int32(2),
68 static_cast<sal_Int32
>(xmlXPathNodeSetGetLength(pXmlObj
->nodesetval
)));
69 xmlXPathFreeObject(pXmlObj
);
72 CPPUNIT_TEST_FIXTURE(Test
, testWrapPolygonLineShape
)
74 loadAndSave("tdf136386_WrapPolygonLineShape.odt");
75 CPPUNIT_ASSERT_EQUAL(1, getShapes());
76 CPPUNIT_ASSERT_EQUAL(1, getPages());
77 // Document has a sloping line with contour wrap. Error was, that type 'square' was written and
78 // no wrap polygon. Now we write 'through' and use wrap polygon 0|0, 21600|21600, 0|0.
79 xmlDocUniquePtr pXmlDocument
= parseExport(u
"word/document.xml"_ustr
);
80 CPPUNIT_ASSERT(pXmlDocument
);
81 assertXPath(pXmlDocument
, "//wp:wrapThrough", 1);
82 assertXPath(pXmlDocument
, "//wp:lineTo", 2);
83 sal_Int32 nYCoord
= getXPath(pXmlDocument
, "(//wp:lineTo)[1]", "y").toInt32();
84 CPPUNIT_ASSERT_EQUAL(sal_Int32(21600), nYCoord
);
85 sal_Int32 nXCoord
= getXPath(pXmlDocument
, "(//wp:lineTo)[2]", "x").toInt32();
86 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), nXCoord
);
89 CPPUNIT_TEST_FIXTURE(Test
, testWrapPolygonCustomShape
)
91 loadAndReload("tdf142433_WrapPolygonCustomShape.odt");
92 CPPUNIT_ASSERT_EQUAL(1, getShapes());
93 CPPUNIT_ASSERT_EQUAL(1, getPages());
94 // Document has 4-point star with contour wrap. Error was, that the enhanced path was written
95 // literally as wrap polygon. But that does not work, because path might have links to equations
96 // and handles and not only numbers.
97 xmlDocUniquePtr pXmlDocument
= parseExport(u
"word/document.xml"_ustr
);
98 CPPUNIT_ASSERT(pXmlDocument
);
99 // Expected coordinates are 0|10800, 8936|8936, 10800|0, 12664|8936, 21600|10800, 12664|12664,
100 // 10800|21600, 8936|12664, 0|10800. Assert forth point, which comes from equations. Allow some
102 sal_Int32 nXCoord
= getXPath(pXmlDocument
, "(//wp:lineTo)[3]", "x").toInt32();
103 // Without fix it would fail with expected 12664, actual 3
104 CPPUNIT_ASSERT_DOUBLES_EQUAL(12664, nXCoord
, 10);
105 // Without fix it would fail with expected 8936, actual 4
106 sal_Int32 nYCoord
= getXPath(pXmlDocument
, "(//wp:lineTo)[3]", "y").toInt32();
107 CPPUNIT_ASSERT_DOUBLES_EQUAL(8936, nYCoord
, 10);
110 CPPUNIT_TEST_FIXTURE(Test
, testFrameWrapTextMode
)
112 loadAndSave("tdf143432_Frame_WrapTextMode.odt");
113 CPPUNIT_ASSERT_EQUAL(2, getShapes());
114 CPPUNIT_ASSERT_EQUAL(1, getPages());
115 xmlDocUniquePtr pXmlDocument
= parseExport(u
"word/document.xml"_ustr
);
116 CPPUNIT_ASSERT(pXmlDocument
);
117 // Without the fix the value "largest" was written to file in both cases.
118 assertXPath(pXmlDocument
, "(//wp:wrapSquare)[1]", "wrapText", u
"right");
119 assertXPath(pXmlDocument
, "(//wp:wrapSquare)[2]", "wrapText", u
"left");
122 CPPUNIT_TEST_FIXTURE(Test
, testTdf134219ContourWrap_glow_rotate
)
124 auto verify
= [this]() {
125 CPPUNIT_ASSERT_DOUBLES_EQUAL(sal_Int32(1461),
126 getProperty
<sal_Int32
>(getShape(1), u
"LeftMargin"_ustr
), 2);
127 CPPUNIT_ASSERT_DOUBLES_EQUAL(sal_Int32(1302),
128 getProperty
<sal_Int32
>(getShape(1), u
"RightMargin"_ustr
), 1);
129 CPPUNIT_ASSERT_DOUBLES_EQUAL(sal_Int32(1522),
130 getProperty
<sal_Int32
>(getShape(1), u
"TopMargin"_ustr
), 1);
131 CPPUNIT_ASSERT_DOUBLES_EQUAL(sal_Int32(1296),
132 getProperty
<sal_Int32
>(getShape(1), u
"BottomMargin"_ustr
), 1);
134 // Given a document with a shape with contour wrap, that has glow effect and rotation.
135 createSwDoc("tdf143219ContourWrap_glow_rotate.docx");
137 // Error was, that the margins, which were added on import to approximate Word's rendering of
138 // contour wrap, contained the effect extent for rotation. But LibreOffice extents the wrap
139 // distance automatically. The distance was too large on first load and because the extent was
140 // not removed on export, much larger on reload.
141 // Test fails on reload without fix with left: expected 1461 actual 2455; right: expected 1302
142 // actual 4177; top: expected 1522 actual 2457; bottom: expected 1296, actual 4179
144 saveAndReload(u
"Office Open XML Text"_ustr
);
148 CPPUNIT_TEST_FIXTURE(Test
, testTdf134219ContourWrap_stroke_shadow
)
150 auto verify
= [this]() {
151 CPPUNIT_ASSERT_DOUBLES_EQUAL(sal_Int32(318),
152 getProperty
<sal_Int32
>(getShape(1), u
"LeftMargin"_ustr
), 1);
153 CPPUNIT_ASSERT_DOUBLES_EQUAL(sal_Int32(1164),
154 getProperty
<sal_Int32
>(getShape(1), u
"RightMargin"_ustr
), 1);
155 CPPUNIT_ASSERT_DOUBLES_EQUAL(sal_Int32(318),
156 getProperty
<sal_Int32
>(getShape(1), u
"TopMargin"_ustr
), 1);
157 CPPUNIT_ASSERT_DOUBLES_EQUAL(sal_Int32(1164),
158 getProperty
<sal_Int32
>(getShape(1), u
"BottomMargin"_ustr
), 1);
160 // Given a document with a shape with contour wrap, that has a fat stroke and large shadow.
161 createSwDoc("tdf143219ContourWrap_stroke_shadow.docx");
163 // Error was, that the margins, which were added on import to approximate Word's rendering of
164 // contour wrap, were not removed on export and so used twice on reload.
165 // Test after reload would fail without fix with
166 // left, top: expected 318 actual 635; right, bottom: expected 1164 actual 2434
168 saveAndReload(u
"Office Open XML Text"_ustr
);
172 CPPUNIT_TEST_FIXTURE(Test
, testTdf123569_rotWriterImage
)
174 loadAndReload("tdf123569_rotWriterImage_46deg.odt");
175 CPPUNIT_ASSERT_EQUAL(1, getShapes());
176 CPPUNIT_ASSERT_EQUAL(2, getPages());
177 uno::Reference
<beans::XPropertySet
> xFrame(getShape(1), uno::UNO_QUERY
);
178 // Error was, that position of logical rectangle was treated as position of snap rectangle.
179 // Thus a wrong position was calculated.
180 // Without fix this would have failed with expected 4798, actual 4860
181 CPPUNIT_ASSERT_DOUBLES_EQUAL(sal_Int32(4798),
182 getProperty
<sal_Int32
>(xFrame
, u
"HoriOrientPosition"_ustr
), 1);
183 // Without fix this would have failed with expected 1438, actual 4062
184 CPPUNIT_ASSERT_DOUBLES_EQUAL(sal_Int32(1438),
185 getProperty
<sal_Int32
>(xFrame
, u
"VertOrientPosition"_ustr
), 1);
188 DECLARE_OOXMLEXPORT_TEST(testTdf142486_LeftMarginShadowLeft
, "tdf142486_LeftMarginShadowLeft.docx")
190 uno::Reference
<beans::XPropertySet
> xFrame(getShape(1), uno::UNO_QUERY
);
191 // Error was, that the shadow distance appeared as additional margin.
192 // Without fix this would have failed with expected 953, actual 2822
193 // Margin is 36px (= 952.5Hmm) in Word.
194 CPPUNIT_ASSERT_DOUBLES_EQUAL(sal_Int32(953), getProperty
<sal_Int32
>(xFrame
, u
"LeftMargin"_ustr
), 1);
197 DECLARE_OOXMLEXPORT_TEST(testTdf151384Hyperlink
, "151384Hyperlink.odt")
199 loadAndSave("151384Hyperlink.odt");
200 xmlDocUniquePtr pXmlDoc
= parseExport(u
"word/document.xml"_ustr
);
201 xmlDocUniquePtr pXmlStyles
= parseExport(u
"word/styles.xml"_ustr
);
202 assertXPath(pXmlDoc
, "/w:document/w:body/w:p/w:hyperlink/w:r/w:rPr/w:rStyle", "val", u
"Hyperlink");
203 assertXPath(pXmlStyles
, "/w:styles/w:style[@w:styleId='Hyperlink']/w:name", "val", u
"Hyperlink");
206 DECLARE_OOXMLEXPORT_TEST(testTdf66039
, "tdf66039.docx")
208 // This bugdoc has a groupshape (WPG) with a table inside its each member shape.
209 // Before there was no table after import at all. From now, there must be 2 tables.
210 uno::Reference
<text::XTextTablesSupplier
> xTablesSupplier(mxComponent
, uno::UNO_QUERY
);
211 uno::Reference
<container::XIndexAccess
> xTables(xTablesSupplier
->getTextTables(),
213 // This was 0 before:
214 CPPUNIT_ASSERT_EQUAL_MESSAGE("Where are the tables?!", static_cast<sal_Int32
>(2),
215 xTables
->getCount());
218 CPPUNIT_TEST_FIXTURE(Test
, testTdf142486_FrameShadow
)
220 loadAndReload("tdf142486_FrameShadow.odt");
221 CPPUNIT_ASSERT_EQUAL(1, getShapes());
222 CPPUNIT_ASSERT_EQUAL(1, getPages());
223 uno::Reference
<frame::XModel
> xModel(mxComponent
, uno::UNO_QUERY
);
224 uno::Reference
<text::XTextViewCursorSupplier
> xTextViewCursorSupplier(
225 xModel
->getCurrentController(), uno::UNO_QUERY_THROW
);
226 uno::Reference
<text::XTextViewCursor
> xViewCursor(xTextViewCursorSupplier
->getViewCursor());
227 xViewCursor
->gotoStart(/*bExpand=*/false);
228 uno::Reference
<view::XViewCursor
> xCursor(xViewCursor
, uno::UNO_QUERY
);
229 xCursor
->goDown(/*nCount=*/3, /*bExpand=*/false);
230 xViewCursor
->goRight(/*nCount=*/1, /*bExpand=*/true);
231 OUString sText
= xViewCursor
->getString();
232 // Without fix in place, the frame size including shadow width was exported as object size. On
233 // import the shadow width was added as wrap "distance from text". That results in totally
234 // different wrapping of the surrounding text.
235 // Here line started with "x" instead of expected "e".
236 CPPUNIT_ASSERT(sText
.startsWith("e"));
239 CPPUNIT_TEST_FIXTURE(Test
, testTdf136059
)
241 loadAndReload("tdf136059.odt");
242 CPPUNIT_ASSERT_EQUAL(1, getShapes());
243 CPPUNIT_ASSERT_EQUAL(1, getPages());
244 CPPUNIT_ASSERT_EQUAL_MESSAGE("Contour has not been exported!", true,
245 getProperty
<bool>(getShape(1), u
"SurroundContour"_ustr
));
246 // With the fix this shall pass, see tdf136059.
249 DECLARE_OOXMLEXPORT_TEST(testTdf138892_noNumbering
, "tdf138892_noNumbering.docx")
251 CPPUNIT_ASSERT_MESSAGE("Para1: Bullet point", !getProperty
<OUString
>(getParagraph(1), u
"NumberingStyleName"_ustr
).isEmpty());
252 CPPUNIT_ASSERT_MESSAGE("Para2: <blank line>", getProperty
<OUString
>(getParagraph(2), u
"NumberingStyleName"_ustr
).isEmpty());
253 CPPUNIT_ASSERT_MESSAGE("Para3: <blank line>", getProperty
<OUString
>(getParagraph(3), u
"NumberingStyleName"_ustr
).isEmpty());
256 DECLARE_OOXMLEXPORT_TEST(testTdf44278
, "tdf44278.docx")
258 // Without the fix in place, this test would have failed with
261 CPPUNIT_ASSERT_EQUAL(1, getShapes());
262 CPPUNIT_ASSERT_EQUAL(1, getPages());
265 DECLARE_OOXMLEXPORT_TEST(testTdf137742
, "tdf137742.docx")
268 getProperty
<lang::Locale
>(getParagraph(1), u
"CharLocale"_ustr
));
269 CPPUNIT_ASSERT_EQUAL(u
"en"_ustr
, locale
.Language
);
271 // Without the fix in place, this test would have failed with
274 CPPUNIT_ASSERT_EQUAL(u
"US"_ustr
, locale
.Country
);
277 DECLARE_OOXMLEXPORT_TEST(testTdf141231_arabicHebrewNumbering
, "tdf141231_arabicHebrewNumbering.docx")
279 // The page's numbering type: instead of Hebrew, this was default style::NumberingType::ARABIC (4).
280 auto nActual
= getProperty
<sal_Int16
>(getStyles(u
"PageStyles"_ustr
)->getByName(u
"Standard"_ustr
), u
"NumberingType"_ustr
);
281 CPPUNIT_ASSERT_EQUAL(style::NumberingType::NUMBER_HEBREW
, nActual
);
283 // The footnote numbering type: instead of arabicAbjad, this was the default style::NumberingType::ARABIC.
284 uno::Reference
<text::XFootnotesSupplier
> xFootnotesSupplier(mxComponent
, uno::UNO_QUERY
);
285 uno::Reference
<beans::XPropertySet
> xFootnoteSettings
= xFootnotesSupplier
->getFootnoteSettings();
286 nActual
= getProperty
<sal_Int16
>(xFootnotesSupplier
->getFootnoteSettings(), u
"NumberingType"_ustr
);
287 CPPUNIT_ASSERT_EQUAL(style::NumberingType::CHARS_ARABIC_ABJAD
, nActual
);
290 DECLARE_OOXMLEXPORT_TEST(testTdf141966_chapterNumbering
, "tdf141966_chapterNumbering.docx")
292 uno::Reference
<text::XChapterNumberingSupplier
> xNumberingSupplier(mxComponent
, uno::UNO_QUERY
);
293 uno::Reference
<container::XIndexAccess
> xNumberingRules
= xNumberingSupplier
->getChapterNumberingRules();
294 comphelper::SequenceAsHashMap
hashMap(xNumberingRules
->getByIndex(0));
296 CPPUNIT_ASSERT(hashMap
[u
"HeadingStyleName"_ustr
].get
<OUString
>().match("CN1"));
298 uno::Reference
<beans::XPropertySet
> xPara(getParagraph(7, u
"Direct formatting with \"Outline\" numbering."_ustr
), uno::UNO_QUERY
);
299 CPPUNIT_ASSERT_EQUAL(u
"2nd"_ustr
, getProperty
<OUString
>(xPara
, u
"ListLabelString"_ustr
));
302 DECLARE_OOXMLEXPORT_TEST(testTdf141966_chapterNumberTortureTest
, "tdf141966_chapterNumberTortureTest.docx")
304 // There is no point in identifying what the wrong values where in this test,
305 //because EVERYTHING was wrong, and MANY different fixes are required to solve the problems.
306 uno::Reference
<beans::XPropertySet
> xPara(getParagraph(1, u
"No numId in style or paragraph"_ustr
), uno::UNO_QUERY
);
307 CPPUNIT_ASSERT_EQUAL(u
""_ustr
, getProperty
<OUString
>(xPara
, u
"ListLabelString"_ustr
));
309 xPara
.set(getParagraph(2, u
"Paragraph cancels numbering(0)"_ustr
), uno::UNO_QUERY
);
310 CPPUNIT_ASSERT_EQUAL(u
""_ustr
, getProperty
<OUString
>(xPara
, u
"ListLabelString"_ustr
));
312 xPara
.set(getParagraph(3, u
"First numbered line"_ustr
), uno::UNO_QUERY
);
313 CPPUNIT_ASSERT_EQUAL(u
"1st.i.a.1.I"_ustr
, getProperty
<OUString
>(xPara
, u
"ListLabelString"_ustr
));
315 xPara
.set(getParagraph(5, u
"Outline with listLvl 5"_ustr
), uno::UNO_QUERY
);
316 CPPUNIT_ASSERT_EQUAL(u
""_ustr
, getProperty
<OUString
>(xPara
, u
"ListLabelString"_ustr
));
318 xPara
.set(getParagraph(7, u
"inheritOnly: inherit outlineLvl and listLvl."_ustr
), uno::UNO_QUERY
);
319 // 2nd.iii in MS Word 2003. 2nd.ii in MS Word 2010/2016 where para5 is not numbered.
320 CPPUNIT_ASSERT_EQUAL(u
"2nd.ii"_ustr
, getProperty
<OUString
>(xPara
, u
"ListLabelString"_ustr
));
321 CPPUNIT_ASSERT_EQUAL(sal_Int16(1), getProperty
<sal_Int16
>(xPara
, u
"NumberingLevel"_ustr
)); // Level 2
323 xPara
.set(getParagraph(9, u
"outline with Body listLvl(9)."_ustr
), uno::UNO_QUERY
);
324 CPPUNIT_ASSERT_EQUAL(u
""_ustr
, getProperty
<OUString
>(xPara
, u
"ListLabelString"_ustr
));
326 xPara
.set(getParagraph(10, u
"outline with Body listLvl(9) #2."_ustr
), uno::UNO_QUERY
);
327 CPPUNIT_ASSERT_EQUAL(u
""_ustr
, getProperty
<OUString
>(xPara
, u
"ListLabelString"_ustr
));
329 xPara
.set(getParagraph(11, u
"direct formatting - Body listLvl(9)."_ustr
), uno::UNO_QUERY
);
330 CPPUNIT_ASSERT_EQUAL(u
""_ustr
, getProperty
<OUString
>(xPara
, u
"ListLabelString"_ustr
));
332 xPara
.set(getParagraph(12, u
"direct numId, inherit listLvl."_ustr
), uno::UNO_QUERY
);
333 CPPUNIT_ASSERT_EQUAL(u
"2nd.ii.a.1.I"_ustr
, getProperty
<OUString
>(xPara
, u
"ListLabelString"_ustr
));
334 CPPUNIT_ASSERT_EQUAL(sal_Int16(4), getProperty
<sal_Int16
>(xPara
, u
"NumberingLevel"_ustr
)); // Level 5
336 xPara
.set(getParagraph(13, u
"Style numId0 cancels inherited numbering."_ustr
), uno::UNO_QUERY
);
337 CPPUNIT_ASSERT_EQUAL(u
""_ustr
, getProperty
<OUString
>(xPara
, u
"ListLabelString"_ustr
));
340 DECLARE_OOXMLEXPORT_TEST(testTdf143692_outlineLevelTortureTest
, "tdf143692_outlineLevelTortureTest.docx")
342 uno::Reference
<beans::XPropertySet
> xPara(getParagraph(1, u
"Head non Toc style"_ustr
), uno::UNO_QUERY
);
343 // fixed missing inherit from Heading 1
344 CPPUNIT_ASSERT_EQUAL(sal_Int16(1), getProperty
<sal_Int16
>(xPara
, u
"OutlineLevel"_ustr
));
346 xPara
.set(getParagraph(2, u
"noInheritHeading1"_ustr
), uno::UNO_QUERY
);
347 // fixed body level not cancelling inherited level
348 CPPUNIT_ASSERT_EQUAL(sal_Int16(0), getProperty
<sal_Int16
>(xPara
, u
"OutlineLevel"_ustr
));
350 xPara
.set(getParagraph(4, u
"illegal -3"_ustr
), uno::UNO_QUERY
);
351 // illegal value is ignored, so inherit from Heading 1
352 CPPUNIT_ASSERT_EQUAL(sal_Int16(1), getProperty
<sal_Int16
>(xPara
, u
"OutlineLevel"_ustr
));
354 xPara
.set(getParagraph(5, u
"Heading 1 with invalid direct -2"_ustr
), uno::UNO_QUERY
);
355 // fixed illegal does not mean body level, it means inherit from style.
356 CPPUNIT_ASSERT_EQUAL(sal_Int16(1), getProperty
<sal_Int16
>(xPara
, u
"OutlineLevel"_ustr
));
358 xPara
.set(getParagraph(7, u
"InheritCN3"_ustr
), uno::UNO_QUERY
);
359 // fixed Chapter Numbering cancelling inheritance
360 CPPUNIT_ASSERT_EQUAL(sal_Int16(3), getProperty
<sal_Int16
>(xPara
, u
"OutlineLevel"_ustr
));
362 xPara
.set(getParagraph(8, u
"noInheritCN3"_ustr
), uno::UNO_QUERY
);
363 CPPUNIT_ASSERT_EQUAL(sal_Int16(0), getProperty
<sal_Int16
>(xPara
, u
"OutlineLevel"_ustr
));
365 xPara
.set(getParagraph(9, u
"override6CN3"_ustr
), uno::UNO_QUERY
);
366 // fixed body level not cancelling inherited level
367 CPPUNIT_ASSERT_EQUAL(sal_Int16(6), getProperty
<sal_Int16
>(xPara
, u
"OutlineLevel"_ustr
));
369 xPara
.set(getParagraph(10, u
"illegal 25"_ustr
), uno::UNO_QUERY
);
370 // fixed illegal value is ignored, so inherit from List Level (Chapter Numbering)
371 CPPUNIT_ASSERT_EQUAL(sal_Int16(3), getProperty
<sal_Int16
>(xPara
, u
"OutlineLevel"_ustr
));
374 DECLARE_OOXMLEXPORT_TEST(testTdf132752
, "tdf132752.docx")
376 uno::Reference
<beans::XPropertySet
> xPara1(getParagraph(1), uno::UNO_QUERY
);
377 CPPUNIT_ASSERT_EQUAL(sal_Int32(1801), getProperty
<sal_Int32
>(xPara1
, u
"ParaLeftMargin"_ustr
));
378 CPPUNIT_ASSERT_EQUAL(sal_Int32(1000), getProperty
<sal_Int32
>(xPara1
, u
"ParaRightMargin"_ustr
));
379 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty
<sal_Int32
>(xPara1
, u
"ParaFirstLineIndent"_ustr
));
381 uno::Reference
<beans::XPropertySet
> xPara2(getParagraph(2), uno::UNO_QUERY
);
382 CPPUNIT_ASSERT_EQUAL(sal_Int32(1801), getProperty
<sal_Int32
>(xPara2
, u
"ParaLeftMargin"_ustr
));
383 CPPUNIT_ASSERT_EQUAL(sal_Int32(1000), getProperty
<sal_Int32
>(xPara2
, u
"ParaRightMargin"_ustr
));
384 CPPUNIT_ASSERT_EQUAL(sal_Int32(-630), getProperty
<sal_Int32
>(xPara2
, u
"ParaFirstLineIndent"_ustr
));
386 uno::Reference
<beans::XPropertySet
> xPara3(getParagraph(3), uno::UNO_QUERY
);
387 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty
<sal_Int32
>(xPara3
, u
"ParaLeftMargin"_ustr
));
388 CPPUNIT_ASSERT_EQUAL(sal_Int32(5891), getProperty
<sal_Int32
>(xPara3
, u
"ParaRightMargin"_ustr
));
389 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty
<sal_Int32
>(xPara3
, u
"ParaFirstLineIndent"_ustr
));
391 uno::Reference
<beans::XPropertySet
> xPara4(getParagraph(4), uno::UNO_QUERY
);
392 CPPUNIT_ASSERT_EQUAL(sal_Int32(1801), getProperty
<sal_Int32
>(xPara4
, u
"ParaLeftMargin"_ustr
));
393 CPPUNIT_ASSERT_EQUAL(sal_Int32(1000), getProperty
<sal_Int32
>(xPara4
, u
"ParaRightMargin"_ustr
));
394 CPPUNIT_ASSERT_EQUAL(sal_Int32(4157), getProperty
<sal_Int32
>(xPara4
, u
"ParaFirstLineIndent"_ustr
));
396 uno::Reference
<beans::XPropertySet
> xPara5(getParagraph(5), uno::UNO_QUERY
);
397 CPPUNIT_ASSERT_EQUAL(sal_Int32(1801), getProperty
<sal_Int32
>(xPara5
, u
"ParaLeftMargin"_ustr
));
398 CPPUNIT_ASSERT_EQUAL(sal_Int32(1000), getProperty
<sal_Int32
>(xPara5
, u
"ParaRightMargin"_ustr
));
399 CPPUNIT_ASSERT_EQUAL(sal_Int32(-630), getProperty
<sal_Int32
>(xPara5
, u
"ParaFirstLineIndent"_ustr
));
401 uno::Reference
<beans::XPropertySet
> xPara6(getParagraph(6), uno::UNO_QUERY
);
402 CPPUNIT_ASSERT_EQUAL(sal_Int32(3565), getProperty
<sal_Int32
>(xPara6
, u
"ParaLeftMargin"_ustr
));
403 CPPUNIT_ASSERT_EQUAL(sal_Int32(2764), getProperty
<sal_Int32
>(xPara6
, u
"ParaRightMargin"_ustr
));
404 CPPUNIT_ASSERT_EQUAL(sal_Int32(-2394), getProperty
<sal_Int32
>(xPara6
, u
"ParaFirstLineIndent"_ustr
));
407 DECLARE_OOXMLEXPORT_TEST(testGutterLeft
, "gutter-left.docx")
409 uno::Reference
<beans::XPropertySet
> xPageStyle
;
410 getStyles(u
"PageStyles"_ustr
)->getByName(u
"Standard"_ustr
) >>= xPageStyle
;
411 sal_Int32 nGutterMargin
{};
412 xPageStyle
->getPropertyValue(u
"GutterMargin"_ustr
) >>= nGutterMargin
;
413 // Without the accompanying fix in place, this test would have failed with:
416 // i.e. gutter margin was lost.
417 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(1270), nGutterMargin
);
420 CPPUNIT_TEST_FIXTURE(Test
, testGutterTop
)
422 loadAndSave("gutter-top.docx");
423 xmlDocUniquePtr pXmlSettings
= parseExport(u
"word/settings.xml"_ustr
);
424 CPPUNIT_ASSERT(pXmlSettings
);
425 // Without the accompanying fix in place, this test would have failed with:
428 // i.e. <w:gutterAtTop> was lost.
429 assertXPath(pXmlSettings
, "/w:settings/w:gutterAtTop", 1);
432 CPPUNIT_TEST_FIXTURE(Test
, testCustomShapePresetExport
)
434 loadAndReload("testCustomShapePresetExport.odt");
435 // Check if the load failed.
436 CPPUNIT_ASSERT(getPages());
438 // Check all shapes of the file
440 for (int i
= 1; i
<= getShapes(); i
++)
442 uno::Reference
<beans::XPropertySet
> xProperties(getShape(i
), uno::UNO_QUERY
);
443 if (!xProperties
->getPropertySetInfo()->hasPropertyByName(u
"CustomShapeGeometry"_ustr
))
445 // Get the custom shape property
446 auto aCustomShapeGeometry
= xProperties
->getPropertyValue(u
"CustomShapeGeometry"_ustr
)
447 .get
<uno::Sequence
<beans::PropertyValue
>>();
448 // Find for shape type
449 for (const auto& aCustomGeometryIterator
: aCustomShapeGeometry
)
451 if (aCustomGeometryIterator
.Name
== "Type")
452 CPPUNIT_ASSERT_MESSAGE(
453 "This is an ooxml preset shape with custom geometry! Shape type lost!",
454 aCustomGeometryIterator
.Value
.get
<OUString
>() != "ooxml-non-primitive");
455 // Without the fix, all shapes have ooxml-non-primitive type, and lost their
456 // real type (like triangle) with the textbox padding.
460 // Without the fix the count does not match.
461 CPPUNIT_ASSERT_EQUAL(17, nCount
);
464 CPPUNIT_TEST_FIXTURE(Test
, testTdf148671
)
466 loadAndSave("tdf148671.docx");
467 // Don't assert with 'pFieldMark' failed when document is opened
468 CPPUNIT_ASSERT_EQUAL(1, getPages());
470 // Preserve tag on SDT blocks. (Before the fix, these were all lost)
471 xmlDocUniquePtr pXmlDoc
= parseExport(u
"word/document.xml"_ustr
);
472 assertXPath(pXmlDoc
, "//w:sdt/w:sdtPr/w:tag", 3);
475 DECLARE_OOXMLEXPORT_TEST(testTdf140668
, "tdf140668.docx")
477 // Don't crash when document is opened
478 CPPUNIT_ASSERT_EQUAL(1, getPages());
481 DECLARE_OOXMLEXPORT_TEST(testTdf149649
, "tdf149649.docx")
483 // Don't crash when document is opened
484 CPPUNIT_ASSERT_EQUAL(2, getPages());
487 DECLARE_OOXMLEXPORT_TEST(testTdf138771
, "tdf138771.docx")
489 // Don't crash when document is imported
490 CPPUNIT_ASSERT_EQUAL(1, getPages());
493 DECLARE_OOXMLEXPORT_TEST(testTdf125936_numberingSuperscript
, "tdf125936_numberingSuperscript.docx")
495 // Without the fix, the first character run was superscripted.
496 CPPUNIT_ASSERT_EQUAL( sal_Int16(0), getProperty
<sal_Int16
>(getRun(getParagraph(1), 1, u
"A-570-108"_ustr
), u
"CharEscapement"_ustr
) );
499 CPPUNIT_TEST_FIXTURE(Test
, testTdf134619_numberingProps
)
501 loadAndReload("tdf134619_numberingProps.doc");
502 // Get the third paragraph's numbering style's 1st level's bullet size
503 uno::Reference
<text::XTextRange
> xParagraph
= getParagraph(3);
504 auto xLevels
= getProperty
< uno::Reference
<container::XIndexAccess
> >(xParagraph
, u
"NumberingRules"_ustr
);
505 uno::Sequence
<beans::PropertyValue
> aLevel
;
506 xLevels
->getByIndex(0) >>= aLevel
; // 1st level
507 OUString aCharStyleName
= std::find_if(std::cbegin(aLevel
), std::cend(aLevel
), [](const beans::PropertyValue
& rValue
) { return rValue
.Name
== "CharStyleName"; })->Value
.get
<OUString
>();
509 // Make sure that the blue bullet's font size is 72 points, not 12 points.
510 uno::Reference
<beans::XPropertySet
> xStyle(getStyles(u
"CharacterStyles"_ustr
)->getByName(aCharStyleName
), uno::UNO_QUERY
);
511 CPPUNIT_ASSERT_EQUAL(72.f
, getProperty
<float>(xStyle
, u
"CharHeight"_ustr
));
514 CPPUNIT_TEST_FIXTURE(Test
, testTdf134951_duplicates
)
516 loadAndReload("tdf134951_duplicates.odt");
517 CPPUNIT_ASSERT_EQUAL(3, getShapes());
518 CPPUNIT_ASSERT_EQUAL(1, getPages());
519 uno::Reference
<text::XEndnotesSupplier
> xEndnotesSupplier(mxComponent
, uno::UNO_QUERY
);
520 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(1), xEndnotesSupplier
->getEndnotes()->getCount());
522 getParagraph(5, u
"Duplicate fields: 1"_ustr
);
525 CPPUNIT_TEST_FIXTURE(Test
, testTdf135773_numberingShading
)
527 bool bIsExportAsShading
= !officecfg::Office::Common::Filter::Microsoft::Export::CharBackgroundToHighlighting::get();
528 auto batch
= comphelper::ConfigurationChanges::create();
530 // This function is run at the end of the test - returning the filter options to normal.
531 comphelper::ScopeGuard
g(
532 [bIsExportAsShading
, batch
]
534 if (bIsExportAsShading
)
536 officecfg::Office::Common::Filter::Microsoft::Export::CharBackgroundToHighlighting::set(false, batch
);
540 // For these test, ensure exporting CharBackground as w:highlight.
541 officecfg::Office::Common::Filter::Microsoft::Export::CharBackgroundToHighlighting::set(true, batch
);
544 loadAndSave("tdf135774_numberingShading.docx");
545 // This test uses a custom setting to export CharBackground as Highlight instead of the 7.0 default of Shading.
547 // Before the fix, the imported shading was converted into a red highlight.
548 xmlDocUniquePtr pXmlStyles
= parseExport(u
"word/numbering.xml"_ustr
);
549 assertXPath(pXmlStyles
, "/w:numbering/w:abstractNum[@w:abstractNumId='1']/w:lvl[@w:ilvl='0']/w:rPr/w:shd", "fill", u
"ED4C05");
552 CPPUNIT_TEST_FIXTURE(Test
, testTdf140336_paraNoneShading
)
554 loadAndReload("tdf140336_paraNoneShading.odt");
555 CPPUNIT_ASSERT_EQUAL(1, getPages());
556 // Before the fix, the background from a style was exported to dis-inheriting paragraphs/styles.
557 CPPUNIT_ASSERT_EQUAL(sal_uInt32(COL_AUTO
), getProperty
<sal_uInt32
>(getParagraph(1), u
"ParaBackColor"_ustr
));
558 uno::Reference
<beans::XPropertySet
> xStyle(getStyles(u
"ParagraphStyles"_ustr
)->getByName(u
"CanclledBackground"_ustr
), uno::UNO_QUERY
);
559 CPPUNIT_ASSERT_EQUAL(drawing::FillStyle_NONE
, getProperty
<drawing::FillStyle
>(xStyle
, u
"FillStyle"_ustr
));
561 // sanity check: backgroundColor paragraph style has a golden color(FF7F50), which para2 inherits
562 CPPUNIT_ASSERT_EQUAL(sal_uInt32(16744272), getProperty
<sal_uInt32
>(getParagraph(2), u
"ParaBackColor"_ustr
));
565 CPPUNIT_TEST_FIXTURE(Test
, testTdf141173_missingFrames
)
567 loadAndReload("tdf141173_missingFrames.rtf");
568 // Without the fix in place, almost all of the text and textboxes were missing.
569 // Without the fix, there were only 2 shapes (mostly unseen).
570 CPPUNIT_ASSERT_EQUAL(13, getShapes());
573 DECLARE_OOXMLEXPORT_TEST(testTdf142404_tabSpacing
, "tdf142404_tabSpacing.docx")
575 // The tabstops should be laid out as triple-spaced when the paragraph takes multiple lines.
576 CPPUNIT_ASSERT_EQUAL_MESSAGE("too big for one page", 2, getPages());
579 DECLARE_OOXMLEXPORT_TEST(testTdf142404_tabOverMarginC15
, "tdf142404_tabOverMarginC15.docx")
581 // TabOverMargin no longer applies to compatibilityMode 15 DOCX files. In Word 2016 this is 3pg.
582 // One page long if tabOverMargin is true. Two pages long if tabOverflow is true.
583 // Really should be 3 pages long, when tabOverflow is also false, but inadequate implementation.
584 CPPUNIT_ASSERT_EQUAL_MESSAGE("too big for one page", 2, getPages());
587 CPPUNIT_TEST_FIXTURE(Test
, testTdf142404_tabOverSpacingC15
)
589 loadAndReload("tdf142404_tabOverSpacingC15.odt");
590 // Although TabOverMargin no longer applies to compatibilityMode 15 DOCX files,
591 // it still applies to a tab over the paragraph end (inside text boundaries).
592 // The original 3-page ODT saved as DOCX would fit on one page in MS Word 2010, but 3 in Word 2013.
593 CPPUNIT_ASSERT_EQUAL_MESSAGE("too big for two pages", 3, getPages());
594 // The tab goes over the paragraph margin
595 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
596 assertXPath(pXmlDoc
, "//page[1]/body/txt[2]/SwParaPortion/SwLineLayout[1]/SwLinePortion[1]", "portion", u
"A left tab positioned at");
597 sal_Int32 nTextLen
= getXPath(pXmlDoc
, "//page[1]/body/txt[2]/SwParaPortion/SwLineLayout[1]/SwLinePortion[1]", "width").toInt32();
598 assertXPath(pXmlDoc
, "//page[1]/body/txt[2]/SwParaPortion/SwLineLayout[1]/SwFixPortion[1]", "portion", u
"*");
599 sal_Int32 nTabLen
= getXPath(pXmlDoc
, "//page[1]/body/txt[2]/SwParaPortion/SwLineLayout[1]/SwFixPortion[1]", "width").toInt32();
600 CPPUNIT_ASSERT_MESSAGE("Large left tab", nTextLen
< nTabLen
);
601 // Not 1 line high (Word 2010 DOCX), or 3 lines high (LO DOCX) or 5 lines high (ODT), but 4 lines high
602 sal_Int32 nHeight
= getXPath(pXmlDoc
, "//page[1]/body/txt[2]/infos/bounds", "height").toInt32();
603 CPPUNIT_ASSERT_MESSAGE("4 lines high", 1100 < nHeight
);
604 CPPUNIT_ASSERT_MESSAGE("4 lines high", nHeight
< 1300);
606 assertXPath(pXmlDoc
, "//page[1]/body/txt[7]/SwParaPortion/SwLineLayout[1]/SwLinePortion[1]", "portion", u
"TabOverflow does what?");
607 // Not 1 line high (Word 2010 DOCX), or 4 lines high (prev LO DOCX) or 8 lines high (ODT).
608 // but two lines high. (3 in Word 2016 because it pulls down "what?" to the second line - weird)
609 nHeight
= getXPath(pXmlDoc
, "//page[1]/body/txt[7]/infos/bounds", "height").toInt32();
610 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("2 lines high (but 3 in Word)", 242*2.5, nHeight
, 242);
612 assertXPath(pXmlDoc
, "//page[1]/body/txt[3]/SwParaPortion/SwLineLayout[1]/SwLinePortion[1]", "portion", u
"A centered tab positioned at");
613 sal_Int32 nLineWidth
= getXPath(pXmlDoc
, "//page[1]/body/txt[3]/SwParaPortion/SwLineLayout[1]/SwFixPortion[1]", "width").toInt32();
614 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Big tab: full paragraph area used", 737, nLineWidth
, 100);
616 // Pages 2/3 are TabOverMargin - in this particular case tabs should not go over margin.
617 assertXPath(pXmlDoc
, "//page[2]/body/txt[6]/SwParaPortion/SwLineLayout[1]/SwLinePortion[1]", "portion", u
"A right tab positioned at");
618 sal_Int32 nParaWidth
= getXPath(pXmlDoc
, "//page[2]/body/txt[6]/infos/prtBounds", "width").toInt32();
619 // the clearest non-first-line visual example is this second tab in the right-tab paragraph.
620 nLineWidth
= getXPath(pXmlDoc
, "//page[2]/body/txt[6]/SwParaPortion/SwLineLayout[4]", "width").toInt32();
621 CPPUNIT_ASSERT_EQUAL_MESSAGE("Full paragraph area used", nLineWidth
, nParaWidth
);
623 assertXPath(pXmlDoc
, "//page[3]/body/txt[2]/SwParaPortion/SwLineLayout[1]/SwLinePortion[1]", "portion", u
"TabOverflow does what?");
624 // Not 1 line high (Word 2010 DOCX and ODT), or 4 lines high (prev LO DOCX),
626 nHeight
= getXPath(pXmlDoc
, "//page[3]/body/txt[2]/infos/bounds", "height").toInt32();
627 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("8 lines high", 242*8, nHeight
, 121);
630 DECLARE_OOXMLEXPORT_TEST(testShapeHyperlink
, "hyperlinkshape.docx")
632 // Test import/export of hyperlink property on shapes
633 auto xShape(getShape(1));
634 CPPUNIT_ASSERT_EQUAL(u
"https://libreoffice.org/"_ustr
, getProperty
<OUString
>(xShape
, u
"Hyperlink"_ustr
));
637 CPPUNIT_TEST_FIXTURE(Test
, testTextframeHyperlink
)
639 // Make sure hyperlink is imported correctly
640 createSwDoc("docxopenhyperlinkbox.docx");
641 uno::Reference
<text::XTextFramesSupplier
> xTextFramesSupplier(mxComponent
, uno::UNO_QUERY
);
642 uno::Reference
<container::XIndexAccess
> xIndexAccess(xTextFramesSupplier
->getTextFrames(), uno::UNO_QUERY
);
643 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xIndexAccess
->getCount());
645 uno::Reference
<beans::XPropertySet
> xFrame(xIndexAccess
->getByIndex(0), uno::UNO_QUERY
);
646 CPPUNIT_ASSERT_EQUAL(u
"https://libreoffice.org/"_ustr
, getProperty
<OUString
>(xFrame
, u
"HyperLinkURL"_ustr
));
648 // FIXME: After save&reload, the text frame should still be a text frame, and the above test should still work.
649 // (Currently the Writer text frame becomes a text box (shape based)). See tdf#140961
650 saveAndReload(u
"Office Open XML Text"_ustr
);
652 xmlDocUniquePtr pXmlDoc
= parseExport(u
"word/document.xml"_ustr
);
654 assertXPath(pXmlDoc
, "//w:drawing/wp:anchor/wp:docPr/a:hlinkClick", 1);
656 assertXPath(pXmlDoc
, "//w:pict/v:rect", "href", u
"https://libreoffice.org/");
659 CPPUNIT_TEST_FIXTURE(Test
, testTdf146171_invalid_change_date
)
661 createSwDoc("tdf146171.docx");
662 // false alarm? during ODF roundtrip:
663 // 'Error: "1970-01-01" does not satisfy the "dateTime" type'
664 // disable and check only the conversion of the invalid (zeroed) change date
665 // 0000-00-00T00:00:00Z, resulting loss of change tracking during ODF roundtrip
666 // reload("writer8", "tdf146171.odt");
667 saveAndReload(u
"Office Open XML Text"_ustr
);
669 xmlDocUniquePtr pXmlDoc
= parseExport(u
"word/document.xml"_ustr
);
671 assertXPath(pXmlDoc
, "//w:ins", 5);
673 assertXPath(pXmlDoc
, "//w:del", 2);
674 // no date (anonymized change)
675 // This failed, date was exported as w:date="1970-01-01T00:00:00Z" before fixing tdf#147760
676 assertXPathNoAttribute(pXmlDoc
, "//w:del[1]", "date");
677 assertXPathNoAttribute(pXmlDoc
, "//w:del[2]", "date");
680 CPPUNIT_TEST_FIXTURE(Test
, testTdf139580
)
682 loadAndReload("tdf139580.odt");
683 // Without the fix in place, this test would have crashed at export time
684 CPPUNIT_ASSERT_EQUAL(2, getShapes());
685 CPPUNIT_ASSERT_EQUAL(1, getPages());
688 DECLARE_OOXMLEXPORT_TEST(testTdf149198
, "tdf149198.docx")
690 // Without the fix in place, this test would have crashed at export time
691 CPPUNIT_ASSERT_EQUAL(1, getPages());
692 CPPUNIT_ASSERT_EQUAL(u
"Documentation"_ustr
, getParagraph(1)->getString());
695 CPPUNIT_TEST_FIXTURE(Test
, testFooterMarginLost
)
697 loadAndSave("footer-margin-lost.docx");
698 xmlDocUniquePtr pXmlDoc
= parseExport(u
"word/document.xml"_ustr
);
699 // Without the accompanying fix in place, this test would have failed with:
702 // i.e. import + export lost the footer margin value.
703 assertXPath(pXmlDoc
, "/w:document/w:body/w:sectPr/w:pgMar", "footer", u
"709");
706 CPPUNIT_TEST_FIXTURE(Test
, testEffectExtentLineWidth
)
708 auto verify
= [this]() {
709 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(506),
710 getProperty
<sal_Int32
>(getShape(1), u
"TopMargin"_ustr
));
713 // Given a document with a shape that has a non-zero line width and effect extent:
714 // When loading the document:
715 createSwDoc("effect-extent-line-width.docx");
716 // Then make sure that the line width is not taken twice (once as part of the margin, and then
717 // also as the line width):
718 // Without the accompanying fix in place, this test would have failed with:
721 // i.e. the upper spacing was too large, the last line of the text moved below the shape.
723 saveAndReload(u
"Office Open XML Text"_ustr
);
727 CPPUNIT_TEST_FIXTURE(Test
, testRtlGutter
)
729 // Given a document with RTL gutter:
730 createSwDoc("rtl-gutter.docx");
731 uno::Reference
<beans::XPropertySet
> xStandard(getStyles(u
"PageStyles"_ustr
)->getByName(u
"Standard"_ustr
),
733 CPPUNIT_ASSERT(getProperty
<bool>(xStandard
, u
"RtlGutter"_ustr
));
735 // When saving back to DOCX:
736 saveAndReload(u
"Office Open XML Text"_ustr
);
738 // Then make sure the section's gutter is still RTL:
739 xmlDocUniquePtr pXmlDoc
= parseExport(u
"word/document.xml"_ustr
);
740 // Without the accompanying fix in place, this test would have failed as the XML element was
742 assertXPath(pXmlDoc
, "/w:document/w:body/w:sectPr/w:rtlGutter", 1);
745 CPPUNIT_TEST_FIXTURE(Test
, testTdf140572_docDefault_superscript
)
747 loadAndReload("tdf140572_docDefault_superscript.docx");
748 // A round-trip was crashing.
750 // Without the fix, everything was DFLT_ESC_AUTO_SUPER (default superscript)
751 CPPUNIT_ASSERT_EQUAL( sal_Int16(0), getProperty
<sal_Int16
>(getRun(getParagraph(1), 1), u
"CharEscapement"_ustr
) );
754 DECLARE_OOXMLEXPORT_TEST(testTdf136841
, "tdf136841.docx")
758 uno::Reference
<drawing::XShape
> image
= getShape(1);
759 uno::Reference
<beans::XPropertySet
> imageProperties(image
, uno::UNO_QUERY
);
760 uno::Reference
<graphic::XGraphic
> graphic
;
761 imageProperties
->getPropertyValue( u
"Graphic"_ustr
) >>= graphic
;
762 Graphic
vclGraphic(graphic
);
763 BitmapEx
bitmap(vclGraphic
.GetBitmapEx());
764 CPPUNIT_ASSERT_EQUAL( tools::Long(76), bitmap
.GetSizePixel().Width());
765 CPPUNIT_ASSERT_EQUAL( tools::Long(76), bitmap
.GetSizePixel().Height());
767 // Without the fix in place, this test would have failed with
768 // - Expected: Color: R:228 G:71 B:69 A:0
769 // - Actual : Color: R:0 G:0 B:0 A:0
771 #if defined(_WIN32) || defined(MACOSX)
772 CPPUNIT_ASSERT_EQUAL( Color(228,71,69), bitmap
.GetPixelColor(38,38));
774 // NOTE: For CairoSDPR the Color changes slightly from (228,71,69)
775 CPPUNIT_ASSERT_EQUAL( Color(229,71,70), bitmap
.GetPixelColor(38,38));
779 CPPUNIT_TEST_FIXTURE(Test
, testTdf138953
)
781 loadAndReload("croppedAndRotated.odt");
782 CPPUNIT_ASSERT_EQUAL(1, getShapes());
783 CPPUNIT_ASSERT_EQUAL(1, getPages());
784 // Make sure the rotation is exported correctly, and size not distorted
785 auto xShape(getShape(1));
786 CPPUNIT_ASSERT_EQUAL(27000.0, getProperty
<double>(xShape
, u
"RotateAngle"_ustr
));
787 auto frameRect
= getProperty
<css::awt::Rectangle
>(xShape
, u
"FrameRect"_ustr
);
788 // Before the fix, original object size (i.e., before cropping) was written to spPr in OOXML,
789 // and the resulting object size was much larger than should be.
790 CPPUNIT_ASSERT_EQUAL(sal_Int32(12961), frameRect
.Height
);
791 CPPUNIT_ASSERT_EQUAL(sal_Int32(8664), frameRect
.Width
);
794 CPPUNIT_TEST_FIXTURE(Test
, testTdf118535
)
796 loadAndReload("tdf118535.odt");
797 CPPUNIT_ASSERT_EQUAL(2, getShapes());
798 CPPUNIT_ASSERT_EQUAL(2, getPages());
799 uno::Reference
<packages::zip::XZipFileAccess2
> xNameAccess
= packages::zip::ZipFileAccess::createWithURL(comphelper::getComponentContext(m_xSFactory
), maTempFile
.GetURL());
800 CPPUNIT_ASSERT_EQUAL(true, bool(xNameAccess
->hasByName(u
"word/media/image1.jpeg"_ustr
)));
801 // Without the accompanying fix in place, this test would have failed with:
804 // i.e. the embedded picture would have been saved twice.
805 CPPUNIT_ASSERT_EQUAL(false, bool(xNameAccess
->hasByName(u
"word/media/image2.jpeg"_ustr
)));
808 DECLARE_OOXMLEXPORT_TEST(testTdf133473_shadowSize
, "tdf133473.docx")
810 uno::Reference
<drawing::XShape
> xShape
= getShape(1);
812 SdrObject
* pObj(SdrObject::getSdrObjectFromXShape(xShape
));
813 const SfxItemSet
& rSet
= pObj
->GetMergedItemSet();
814 sal_Int32 nSize1
= rSet
.Get(SDRATTR_SHADOWSIZEX
).GetValue();
816 // Without the accompanying fix in place, this test would have failed with:
817 // - Expected: 200000
819 // I.e. Shadow size will be smaller than actual.
821 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(200000), nSize1
);
824 DECLARE_OOXMLEXPORT_TEST(testTdf153874
, "image_through_shape.docx")
826 uno::Reference
<beans::XPropertySet
> const xShape1(getShapeByName(u
"Test1"), uno::UNO_QUERY
);
827 uno::Reference
<beans::XPropertySet
> const xShape2(getShapeByName(u
"Rectangle 1"), uno::UNO_QUERY
);
828 CPPUNIT_ASSERT_EQUAL(text::TextContentAnchorType_AS_CHARACTER
, xShape1
->getPropertyValue(u
"AnchorType"_ustr
).get
<text::TextContentAnchorType
>());
829 CPPUNIT_ASSERT_EQUAL(text::TextContentAnchorType_AT_CHARACTER
, xShape2
->getPropertyValue(u
"AnchorType"_ustr
).get
<text::TextContentAnchorType
>());
830 CPPUNIT_ASSERT_LESS(xShape2
->getPropertyValue(u
"ZOrder"_ustr
).get
<sal_uInt64
>(), xShape1
->getPropertyValue(u
"ZOrder"_ustr
).get
<sal_uInt64
>());
831 CPPUNIT_ASSERT(xShape1
->getPropertyValue(u
"Decorative"_ustr
).get
<bool>());
832 // not implemented on shape yet
833 //CPPUNIT_ASSERT(xShape2->getPropertyValue("Decorative").get<bool>());
836 DECLARE_OOXMLEXPORT_TEST(testTextBoxZOrder
, "testTextBoxZOrder.docx")
838 // Collect the z-order values of the textboxes
839 std::vector
<sal_uInt64
> ShapeZorders
;
840 std::vector
<sal_uInt64
> FrameZorders
;
841 for (int i
= 1; i
< 4; i
++)
843 uno::Reference
<drawing::XShape
> xShape(getShape(i
));
844 CPPUNIT_ASSERT(xShape
);
845 uno::Reference
<beans::XPropertySet
> xShapeProperties(xShape
, uno::UNO_QUERY
);
846 CPPUNIT_ASSERT(xShapeProperties
);
847 uno::Reference
<text::XTextFrame
> xFrame
= SwTextBoxHelper::getUnoTextFrame(xShape
);
848 CPPUNIT_ASSERT(xFrame
.is());
849 uno::Reference
<beans::XPropertySet
> const xFrameProperties(xFrame
, uno::UNO_QUERY
);
850 CPPUNIT_ASSERT(xFrameProperties
);
851 ShapeZorders
.push_back(xShapeProperties
->getPropertyValue(u
"ZOrder"_ustr
).get
<sal_uInt64
>());
852 FrameZorders
.push_back(xFrameProperties
->getPropertyValue(u
"ZOrder"_ustr
).get
<sal_uInt64
>());
854 // Check the z-order values.
855 for (int i
= 1; i
< 3; i
++)
857 CPPUNIT_ASSERT_GREATER(ShapeZorders
[i
- 1], ShapeZorders
[i
]);
858 CPPUNIT_ASSERT_GREATER(FrameZorders
[i
- 1], FrameZorders
[i
]);
859 CPPUNIT_ASSERT_GREATER(ShapeZorders
[i
- 1], FrameZorders
[i
- 1]);
861 // Without the fix it failed, because the z-order was wrong.
864 DECLARE_OOXMLEXPORT_TEST(testTdf141550
, "tdf141550.docx")
866 uno::Reference
<drawing::XShape
> xShape(getShape(1));
867 uno::Reference
<text::XTextFrame
> xFrame
= SwTextBoxHelper::getUnoTextFrame(xShape
);
869 CPPUNIT_ASSERT(xShape
);
870 CPPUNIT_ASSERT(xFrame
);
872 const sal_uInt16 nShapeRelOri
= getProperty
<sal_uInt16
>(xShape
, UNO_NAME_HORI_ORIENT_RELATION
);
873 const sal_uInt16 nFrameRelOri
= getProperty
<sal_uInt16
>(xFrame
, UNO_NAME_HORI_ORIENT_RELATION
);
875 CPPUNIT_ASSERT_EQUAL_MESSAGE("Textbox fallen apart!", nShapeRelOri
, nFrameRelOri
);
876 // Without the fix in place it fails with difference.
879 DECLARE_OOXMLEXPORT_TEST(testTdf140137
, "tdf140137.docx")
881 // Don't throw exception during load
882 CPPUNIT_ASSERT_EQUAL(1, getPages());
885 DECLARE_OOXMLEXPORT_TEST(testTdf105688
, "tdf105688.docx")
887 // Don't throw exception during load
888 CPPUNIT_ASSERT_EQUAL(2, getPages());
891 CPPUNIT_TEST_FIXTURE(Test
, testCommentReply
)
893 loadAndSave("CommentReply.docx");
894 xmlDocUniquePtr pXmlComm
= parseExport(u
"word/comments.xml"_ustr
);
895 xmlDocUniquePtr pXmlCommExt
= parseExport(u
"word/commentsExtended.xml"_ustr
);
896 CPPUNIT_ASSERT(pXmlComm
);
897 CPPUNIT_ASSERT(pXmlCommExt
);
898 OUString sParentId
= getXPath(pXmlComm
, "/w:comments/w:comment[1]/w:p[1]", "paraId");
899 OUString sChildId
= getXPath(pXmlComm
, "/w:comments/w:comment[2]/w:p[1]", "paraId");
900 OUString sChildIdEx
= getXPath(pXmlCommExt
, "/w15:commentsEx/w15:commentEx", "paraId");
901 OUString sChildParentId
= getXPath(pXmlCommExt
,
902 "/w15:commentsEx/w15:commentEx", "paraIdParent");
903 // Make sure exported extended paraId matches the one in comments.xml
904 CPPUNIT_ASSERT_EQUAL(sChildId
, sChildIdEx
);
905 // Make sure the paraIdParent matches the id of its parent
906 CPPUNIT_ASSERT_EQUAL(sParentId
, sChildParentId
);
909 CPPUNIT_TEST_FIXTURE(Test
, testCommentDone
)
911 loadAndSave("CommentDone.docx");
912 xmlDocUniquePtr pXmlComm
= parseExport(u
"word/comments.xml"_ustr
);
913 assertXPath(pXmlComm
, "/w:comments/w:comment[1]/w:p", 2);
914 OUString idLastPara
= getXPath(pXmlComm
, "/w:comments/w:comment[1]/w:p[2]", "paraId");
915 xmlDocUniquePtr pXmlCommExt
= parseExport(u
"word/commentsExtended.xml"_ustr
);
916 assertXPath(pXmlCommExt
, "/w15:commentsEx", "Ignorable", u
"w15");
917 assertXPath(pXmlCommExt
, "/w15:commentsEx/w15:commentEx", 1);
918 OUString idLastParaEx
= getXPath(pXmlCommExt
, "/w15:commentsEx/w15:commentEx", "paraId");
919 CPPUNIT_ASSERT_EQUAL(idLastPara
, idLastParaEx
);
920 assertXPath(pXmlCommExt
, "/w15:commentsEx/w15:commentEx", "done", u
"1");
923 DECLARE_OOXMLEXPORT_TEST(testTableWidth
, "frame_size_export.docx")
925 // after exporting: table width was overwritten in the doc model
926 uno::Reference
<text::XTextTablesSupplier
> xTablesSupplier(mxComponent
, uno::UNO_QUERY
);
927 uno::Reference
<container::XIndexAccess
> xTables(xTablesSupplier
->getTextTables(),
929 CPPUNIT_ASSERT_EQUAL(sal_Int16(100),
930 getProperty
<sal_Int16
>(xTables
->getByIndex(0), u
"RelativeWidth"_ustr
));
934 CPPUNIT_TEST_FIXTURE(Test
, testCommentDoneModel
)
936 auto verify
= [this](bool bIsExport
= false) {
937 css::uno::Reference
<css::text::XTextFieldsSupplier
> xTextFieldsSupplier(
938 mxComponent
, css::uno::UNO_QUERY_THROW
);
939 auto xFields(xTextFieldsSupplier
->getTextFields()->createEnumeration());
941 // First comment: initially resolved, toggled to unresolved on import, unresolved on roundtrip
942 CPPUNIT_ASSERT(xFields
->hasMoreElements());
943 css::uno::Any aComment
= xFields
->nextElement();
944 css::uno::Reference
<css::beans::XPropertySet
> xComment(aComment
, css::uno::UNO_QUERY_THROW
);
948 // Check that it's resolved when initially read
949 CPPUNIT_ASSERT_EQUAL(true, xComment
->getPropertyValue(u
"Resolved"_ustr
).get
<bool>());
951 xComment
->setPropertyValue(u
"Resolved"_ustr
, css::uno::Any(false));
955 // After the roundtrip, it keeps the "unresolved" state set above
956 CPPUNIT_ASSERT_EQUAL(false, xComment
->getPropertyValue(u
"Resolved"_ustr
).get
<bool>());
959 // Second comment: initially unresolved, toggled to resolved on import, resolved on roundtrip
960 CPPUNIT_ASSERT(xFields
->hasMoreElements());
961 aComment
= xFields
->nextElement();
962 xComment
.set(aComment
, css::uno::UNO_QUERY_THROW
);
966 // Check that it's unresolved when initially read
967 CPPUNIT_ASSERT_EQUAL(false, xComment
->getPropertyValue(u
"Resolved"_ustr
).get
<bool>());
969 xComment
->setPropertyValue(u
"Resolved"_ustr
, css::uno::Any(true));
973 // After the roundtrip, it keeps the "resolved" state set above
974 CPPUNIT_ASSERT_EQUAL(true, xComment
->getPropertyValue(u
"Resolved"_ustr
).get
<bool>());
978 createSwDoc("CommentDone.docx");
980 saveAndReload(mpFilter
);
981 verify(/*bIsExport*/ true);
984 CPPUNIT_TEST_FIXTURE(Test
, Test_ShadowDirection
)
986 loadAndSave("tdf142361ShadowDirection.odt");
987 CPPUNIT_ASSERT_EQUAL(1, getShapes());
988 CPPUNIT_ASSERT_EQUAL(1, getPages());
989 // The attribute 'rotWithShape' has the default value 'true' in OOXML, so Words interprets a
990 // missing attribute as 'true'. That means that Word rotates the shadow if the shape is
991 // rotated. Because in LibreOffice a shadow is never rotated, we must not omit this
993 xmlDocUniquePtr pXmlDoc
= parseExport(u
"word/document.xml"_ustr
);
995 "/w:document/w:body/w:p[1]/w:r[1]/mc:AlternateContent/mc:Choice/w:drawing/"
996 "wp:anchor/a:graphic/a:graphicData/wps:wsp/wps:spPr/a:effectLst/a:outerShdw",
997 "rotWithShape", u
"0");
1000 CPPUNIT_TEST_FIXTURE(Test
, testTdf150542
)
1002 loadAndSave("tdf150542.docx");
1004 xmlDocUniquePtr pSettingsDoc
= parseExport(u
"word/settings.xml"_ustr
);
1005 // Ensure that all docvars from input are written back and with correct values.
1006 // Order of document variables is not checked. So this can fail at some time if order is changed.
1007 assertXPath(pSettingsDoc
,
1008 "/w:settings/w:docVars/w:docVar[1]", "name", u
"LocalChars\u00C1\u0072\u0076\u00ED\u007A\u0074\u0075\u0072\u006F\u0054\u00FC\u006B\u00F6\u0072\u0066\u00FA\u0072\u00F3\u0067\u00E9\u0070");
1009 assertXPath(pSettingsDoc
,
1010 "/w:settings/w:docVars/w:docVar[1]", "val", u
"Correct value (\u00E1\u0072\u0076\u00ED\u007A\u0074\u0075\u0072\u006F\u0020\u0074\u00FC\u006B\u00F6\u0072\u0066\u00FA\u0072\u00F3\u0067\u00E9\u0070)");
1011 assertXPath(pSettingsDoc
,
1012 "/w:settings/w:docVars/w:docVar[2]", "name", u
"DocVar1");
1013 assertXPath(pSettingsDoc
,
1014 "/w:settings/w:docVars/w:docVar[2]", "val", u
"DocVar1 Value");
1015 assertXPath(pSettingsDoc
,
1016 "/w:settings/w:docVars/w:docVar[3]", "name", u
"DocVar3");
1017 assertXPath(pSettingsDoc
,
1018 "/w:settings/w:docVars/w:docVar[3]", "val", u
"DocVar3 Value");
1021 CPPUNIT_TEST_FIXTURE(Test
, testTdf139549
)
1023 loadAndSave("tdf139549.docx");
1024 // Document contains a VML textbox, the position of the textbox was incorrect.
1025 xmlDocUniquePtr pXmlDoc
= parseExport(u
"word/document.xml"_ustr
);
1026 OUString aStyle
= getXPath(pXmlDoc
, "//w:pict/v:shape", "style");
1027 /* original is: "position:absolute;margin-left:138.5pt;margin-top:40.1pt;width:183pt;
1028 height:68pt;z-index:251675648;mso-position-horizontal:absolute;
1029 mso-position-horizontal-relative:page;mso-position-vertical:absolute;
1030 mso-position-vertical-relative:page" */
1031 CPPUNIT_ASSERT(!aStyle
.isEmpty());
1033 sal_Int32 nextTokenPos
= 0;
1034 OUString aStyleCommand
= aStyle
.getToken(0, ';', nextTokenPos
);
1035 CPPUNIT_ASSERT(!aStyleCommand
.isEmpty());
1037 OUString aStyleCommandName
= aStyleCommand
.getToken(0, ':');
1038 OUString aStyleCommandValue
= aStyleCommand
.getToken(1, ':');
1039 CPPUNIT_ASSERT_EQUAL(u
"position"_ustr
, aStyleCommandName
);
1040 CPPUNIT_ASSERT_EQUAL(u
"absolute"_ustr
, aStyleCommandValue
);
1042 aStyleCommand
= aStyle
.getToken(0, ';', nextTokenPos
);
1043 CPPUNIT_ASSERT(!aStyleCommand
.isEmpty());
1045 aStyleCommandName
= aStyleCommand
.getToken(0, ':');
1046 aStyleCommandValue
= aStyleCommand
.getToken(1, ':');
1047 CPPUNIT_ASSERT_EQUAL(u
"margin-left"_ustr
, aStyleCommandName
);
1048 // Without the fix it failed, because the margin-left was 171.85pt.
1049 CPPUNIT_ASSERT_DOUBLES_EQUAL(138.5, aStyleCommandValue
.toFloat(), 0.1);
1051 aStyleCommand
= aStyle
.getToken(0, ';', nextTokenPos
);
1052 CPPUNIT_ASSERT(!aStyleCommand
.isEmpty());
1054 aStyleCommandName
= aStyleCommand
.getToken(0, ':');
1055 aStyleCommandValue
= aStyleCommand
.getToken(1, ':');
1056 CPPUNIT_ASSERT_EQUAL(u
"margin-top"_ustr
, aStyleCommandName
);
1057 // Without the fix it failed, because the margin-top was 55.45pt.
1058 CPPUNIT_ASSERT_DOUBLES_EQUAL(40.1, aStyleCommandValue
.toFloat(), 0.1);
1062 CPPUNIT_TEST_FIXTURE(Test
, testTdf143726
)
1064 loadAndReload("Simple-TOC.odt");
1065 CPPUNIT_ASSERT_EQUAL(1, getPages());
1066 xmlDocUniquePtr pXmlStyles
= parseExport(u
"word/styles.xml"_ustr
);
1067 CPPUNIT_ASSERT(pXmlStyles
);
1068 // Without the fix this was "TOA Heading" which belongs to the "Table of Authorities" index in Word
1069 // TOC's heading style should be exported as "TOC Heading" as that's the default Word style name
1070 assertXPath(pXmlStyles
, "/w:styles/w:style[@w:styleId='TOCHeading']/w:name", "val", u
"TOC Heading");
1073 CPPUNIT_TEST_FIXTURE(Test
, testTdf152153
)
1075 loadAndReload("embedded_images.odt");
1077 uno::Reference
<packages::zip::XZipFileAccess2
> xNameAccess
1078 = packages::zip::ZipFileAccess::createWithURL(comphelper::getComponentContext(m_xSFactory
),
1079 maTempFile
.GetURL());
1080 const uno::Sequence
<OUString
> aNames(xNameAccess
->getElementNames());
1081 int nImageFiles
= 0;
1082 for (const auto& rElementName
: aNames
)
1083 if (rElementName
.startsWith("word/media/image"))
1086 // Without the accompanying fix in place, this test would have failed with:
1089 // i.e. the once embedded picture wouldn't have been saved.
1090 CPPUNIT_ASSERT_EQUAL(4, nImageFiles
);
1093 CPPUNIT_TEST_FIXTURE(Test
, testTdf152152
)
1095 loadAndReload("artistic_effects.docx");
1097 uno::Reference
<packages::zip::XZipFileAccess2
> xNameAccess
1098 = packages::zip::ZipFileAccess::createWithURL(comphelper::getComponentContext(m_xSFactory
),
1099 maTempFile
.GetURL());
1100 const uno::Sequence
<OUString
> aNames(xNameAccess
->getElementNames());
1101 int nImageFiles
= 0;
1102 for (const auto& rElementName
: aNames
)
1103 if (rElementName
.startsWith("word/media/hdphoto"))
1106 // Without the accompanying fix in place, this test would have failed with:
1109 // i.e. the once WDP picture wouldn't have been saved.
1110 CPPUNIT_ASSERT_EQUAL(2, nImageFiles
);
1113 CPPUNIT_PLUGIN_IMPLEMENT();
1115 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */