android: Update app-specific/MIME type icons
[LibreOffice.git] / sw / qa / extras / ooxmlexport / ooxmlexport16.cxx
blob502a8d9c6797cfb62bebc3ad05e4f2f60eb10906
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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/.
8 */
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 <unotools/fltrcfg.hxx>
31 #include <unoprnms.hxx>
32 #include <o3tl/string_view.hxx>
34 class Test : public SwModelTestBase
36 public:
37 Test() : SwModelTestBase("/sw/qa/extras/ooxmlexport/data/", "Office Open XML Text") {}
39 virtual std::unique_ptr<Resetter> preTest(const char* filename) override
41 if (filename == std::string_view("tdf135774_numberingShading.docx"))
43 bool bIsExportAsShading = SvtFilterOptions::Get().IsCharBackground2Shading();
44 // This function is run at the end of the test - returning the filter options to normal.
45 std::unique_ptr<Resetter> pResetter(new Resetter(
46 [bIsExportAsShading] () {
47 if (bIsExportAsShading)
48 SvtFilterOptions::Get().SetCharBackground2Shading();
49 }));
50 // For these tests, ensure exporting CharBackground as w:highlight.
51 SvtFilterOptions::Get().SetCharBackground2Highlighting();
52 return pResetter;
54 return nullptr;
58 CPPUNIT_TEST_FIXTURE(Test, testTdf143860NonPrimitiveCustomShape)
60 loadAndReload("tdf143860_NonPrimitiveCustomShape.odt");
61 CPPUNIT_ASSERT_EQUAL(1, getShapes());
62 CPPUNIT_ASSERT_EQUAL(1, getPages());
63 // The document has a custom shape of type non-primitive without handles. Make sure that the shape
64 // is not exported with preset but with custom geometry.
65 xmlDocUniquePtr pXmlDocument = parseExport("word/document.xml");
66 CPPUNIT_ASSERT(pXmlDocument);
67 assertXPath(pXmlDocument, "//a:prstGeom", 0);
68 assertXPath(pXmlDocument, "//a:custGeom", 1);
71 CPPUNIT_TEST_FIXTURE(Test, testWrapPolygonCurve)
73 loadAndSave("tdf136386_WrapPolygonCurve.odt");
74 CPPUNIT_ASSERT_EQUAL(1, getShapes());
75 CPPUNIT_ASSERT_EQUAL(1, getPages());
76 // Document has a curve with contour wrap and 'outside only'. Error was, that type 'square' was
77 // written and no wrap polygon. Make sure we write wrapTight and a wrapPolygon.
78 xmlDocUniquePtr pXmlDocument = parseExport("word/document.xml");
79 CPPUNIT_ASSERT(pXmlDocument);
80 assertXPath(pXmlDocument, "//wp:wrapTight", 1);
81 assertXPath(pXmlDocument, "//wp:wrapPolygon", 1);
82 assertXPath(pXmlDocument, "//wp:start", 1);
83 xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDocument, "//wp:lineTo");
84 CPPUNIT_ASSERT_GREATER(sal_Int32(2),
85 static_cast<sal_Int32>(xmlXPathNodeSetGetLength(pXmlObj->nodesetval)));
86 xmlXPathFreeObject(pXmlObj);
89 CPPUNIT_TEST_FIXTURE(Test, testWrapPolygonLineShape)
91 loadAndSave("tdf136386_WrapPolygonLineShape.odt");
92 CPPUNIT_ASSERT_EQUAL(1, getShapes());
93 CPPUNIT_ASSERT_EQUAL(1, getPages());
94 // Document has a sloping line with contour wrap. Error was, that type 'square' was written and
95 // no wrap polygon. Now we write 'through' and use wrap polygon 0|0, 21600|21600, 0|0.
96 xmlDocUniquePtr pXmlDocument = parseExport("word/document.xml");
97 CPPUNIT_ASSERT(pXmlDocument);
98 assertXPath(pXmlDocument, "//wp:wrapThrough", 1);
99 assertXPath(pXmlDocument, "//wp:lineTo", 2);
100 sal_Int32 nYCoord = getXPath(pXmlDocument, "(//wp:lineTo)[1]", "y").toInt32();
101 CPPUNIT_ASSERT_EQUAL(sal_Int32(21600), nYCoord);
102 sal_Int32 nXCoord = getXPath(pXmlDocument, "(//wp:lineTo)[2]", "x").toInt32();
103 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), nXCoord);
106 CPPUNIT_TEST_FIXTURE(Test, testWrapPolygonCustomShape)
108 loadAndReload("tdf142433_WrapPolygonCustomShape.odt");
109 CPPUNIT_ASSERT_EQUAL(1, getShapes());
110 CPPUNIT_ASSERT_EQUAL(1, getPages());
111 // Document has 4-point star with contour wrap. Error was, that the enhanced path was written
112 // literally as wrap polygon. But that does not work, because path might have links to equations
113 // and handles and not only numbers.
114 xmlDocUniquePtr pXmlDocument = parseExport("word/document.xml");
115 CPPUNIT_ASSERT(pXmlDocument);
116 // Expected coordinates are 0|10800, 8936|8936, 10800|0, 12664|8936, 21600|10800, 12664|12664,
117 // 10800|21600, 8936|12664, 0|10800. Assert forth point, which comes from equations. Allow some
118 // tolerance.
119 sal_Int32 nXCoord = getXPath(pXmlDocument, "(//wp:lineTo)[3]", "x").toInt32();
120 // Without fix it would fail with expected 12664, actual 3
121 CPPUNIT_ASSERT_DOUBLES_EQUAL(12664, nXCoord, 10);
122 // Without fix it would fail with expected 8936, actual 4
123 sal_Int32 nYCoord = getXPath(pXmlDocument, "(//wp:lineTo)[3]", "y").toInt32();
124 CPPUNIT_ASSERT_DOUBLES_EQUAL(8936, nYCoord, 10);
127 CPPUNIT_TEST_FIXTURE(Test, testFrameWrapTextMode)
129 loadAndSave("tdf143432_Frame_WrapTextMode.odt");
130 CPPUNIT_ASSERT_EQUAL(2, getShapes());
131 CPPUNIT_ASSERT_EQUAL(1, getPages());
132 xmlDocUniquePtr pXmlDocument = parseExport("word/document.xml");
133 CPPUNIT_ASSERT(pXmlDocument);
134 // Without the fix the value "largest" was written to file in both cases.
135 assertXPath(pXmlDocument, "(//wp:wrapSquare)[1]", "wrapText", "right");
136 assertXPath(pXmlDocument, "(//wp:wrapSquare)[2]", "wrapText", "left");
139 CPPUNIT_TEST_FIXTURE(Test, testTdf134219ContourWrap_glow_rotate)
141 auto verify = [this]() {
142 CPPUNIT_ASSERT_DOUBLES_EQUAL(sal_Int32(1461),
143 getProperty<sal_Int32>(getShape(1), "LeftMargin"), 2);
144 CPPUNIT_ASSERT_DOUBLES_EQUAL(sal_Int32(1302),
145 getProperty<sal_Int32>(getShape(1), "RightMargin"), 1);
146 CPPUNIT_ASSERT_DOUBLES_EQUAL(sal_Int32(1522),
147 getProperty<sal_Int32>(getShape(1), "TopMargin"), 1);
148 CPPUNIT_ASSERT_DOUBLES_EQUAL(sal_Int32(1296),
149 getProperty<sal_Int32>(getShape(1), "BottomMargin"), 1);
151 // Given a document with a shape with contour wrap, that has glow effect and rotation.
152 createSwDoc("tdf143219ContourWrap_glow_rotate.docx");
154 // Error was, that the margins, which were added on import to approximate Word's rendering of
155 // contour wrap, contained the effect extent for rotation. But LibreOffice extents the wrap
156 // distance automatically. The distance was too large on first load and because the extent was
157 // not removed on export, much larger on reload.
158 // Test fails on reload without fix with left: expected 1461 actual 2455; right: expected 1302
159 // actual 4177; top: expected 1522 actual 2457; bottom: expected 1296, actual 4179
160 verify();
161 saveAndReload("Office Open XML Text");
162 verify();
165 CPPUNIT_TEST_FIXTURE(Test, testTdf134219ContourWrap_stroke_shadow)
167 auto verify = [this]() {
168 CPPUNIT_ASSERT_DOUBLES_EQUAL(sal_Int32(318),
169 getProperty<sal_Int32>(getShape(1), "LeftMargin"), 1);
170 CPPUNIT_ASSERT_DOUBLES_EQUAL(sal_Int32(1164),
171 getProperty<sal_Int32>(getShape(1), "RightMargin"), 1);
172 CPPUNIT_ASSERT_DOUBLES_EQUAL(sal_Int32(318),
173 getProperty<sal_Int32>(getShape(1), "TopMargin"), 1);
174 CPPUNIT_ASSERT_DOUBLES_EQUAL(sal_Int32(1164),
175 getProperty<sal_Int32>(getShape(1), "BottomMargin"), 1);
177 // Given a document with a shape with contour wrap, that has a fat stroke and large shadow.
178 createSwDoc("tdf143219ContourWrap_stroke_shadow.docx");
180 // Error was, that the margins, which were added on import to approximate Word's rendering of
181 // contour wrap, were not removed on export and so used twice on reload.
182 // Test after reload would fail without fix with
183 // left, top: expected 318 actual 635; right, bottom: expected 1164 actual 2434
184 verify();
185 saveAndReload("Office Open XML Text");
186 verify();
189 CPPUNIT_TEST_FIXTURE(Test, testTdf123569_rotWriterImage)
191 loadAndReload("tdf123569_rotWriterImage_46deg.odt");
192 CPPUNIT_ASSERT_EQUAL(1, getShapes());
193 CPPUNIT_ASSERT_EQUAL(2, getPages());
194 uno::Reference<beans::XPropertySet> xFrame(getShape(1), uno::UNO_QUERY);
195 // Error was, that position of logical rectangle was treated as position of snap rectangle.
196 // Thus a wrong position was calculated.
197 // Without fix this would have failed with expected 4798, actual 4860
198 CPPUNIT_ASSERT_DOUBLES_EQUAL(sal_Int32(4798),
199 getProperty<sal_Int32>(xFrame, "HoriOrientPosition"), 1);
200 // Without fix this would have failed with expected 1438, actual 4062
201 CPPUNIT_ASSERT_DOUBLES_EQUAL(sal_Int32(1438),
202 getProperty<sal_Int32>(xFrame, "VertOrientPosition"), 1);
205 DECLARE_OOXMLEXPORT_TEST(testTdf142486_LeftMarginShadowLeft, "tdf142486_LeftMarginShadowLeft.docx")
207 uno::Reference<beans::XPropertySet> xFrame(getShape(1), uno::UNO_QUERY);
208 // Error was, that the shadow distance appeared as additional margin.
209 // Without fix this would have failed with expected 953, actual 2822
210 // Margin is 36px (= 952.5Hmm) in Word.
211 CPPUNIT_ASSERT_DOUBLES_EQUAL(sal_Int32(953), getProperty<sal_Int32>(xFrame, "LeftMargin"), 1);
214 DECLARE_OOXMLEXPORT_TEST(testTdf66039, "tdf66039.docx")
216 // This bugdoc has a groupshape (WPG) with a table inside its each member shape.
217 // Before there was no table after import at all. From now, there must be 2 tables.
218 uno::Reference<text::XTextTablesSupplier> xTablesSupplier(mxComponent, uno::UNO_QUERY);
219 uno::Reference<container::XIndexAccess> xTables(xTablesSupplier->getTextTables(),
220 uno::UNO_QUERY);
221 // This was 0 before:
222 CPPUNIT_ASSERT_EQUAL_MESSAGE("Where are the tables?!", static_cast<sal_Int32>(2),
223 xTables->getCount());
226 CPPUNIT_TEST_FIXTURE(Test, testTdf142486_FrameShadow)
228 loadAndReload("tdf142486_FrameShadow.odt");
229 CPPUNIT_ASSERT_EQUAL(1, getShapes());
230 CPPUNIT_ASSERT_EQUAL(1, getPages());
231 uno::Reference<frame::XModel> xModel(mxComponent, uno::UNO_QUERY);
232 uno::Reference<text::XTextViewCursorSupplier> xTextViewCursorSupplier(
233 xModel->getCurrentController(), uno::UNO_QUERY_THROW);
234 uno::Reference<text::XTextViewCursor> xViewCursor(xTextViewCursorSupplier->getViewCursor());
235 xViewCursor->gotoStart(/*bExpand=*/false);
236 uno::Reference<view::XViewCursor> xCursor(xViewCursor, uno::UNO_QUERY);
237 xCursor->goDown(/*nCount=*/3, /*bExpand=*/false);
238 xViewCursor->goRight(/*nCount=*/1, /*bExpand=*/true);
239 OUString sText = xViewCursor->getString();
240 // Without fix in place, the frame size including shadow width was exported as object size. On
241 // import the shadow width was added as wrap "distance from text". That results in totally
242 // different wrapping of the surrounding text.
243 // Here line started with "x" instead of expected "e".
244 CPPUNIT_ASSERT(sText.startsWith("e"));
247 CPPUNIT_TEST_FIXTURE(Test, testTdf136059)
249 loadAndReload("tdf136059.odt");
250 CPPUNIT_ASSERT_EQUAL(1, getShapes());
251 CPPUNIT_ASSERT_EQUAL(1, getPages());
252 CPPUNIT_ASSERT_EQUAL_MESSAGE("Contour has not been exported!", true,
253 getProperty<bool>(getShape(1), "SurroundContour"));
254 // With the fix this shall pass, see tdf136059.
257 DECLARE_OOXMLEXPORT_TEST(testTdf138892_noNumbering, "tdf138892_noNumbering.docx")
259 CPPUNIT_ASSERT_MESSAGE("Para1: Bullet point", !getProperty<OUString>(getParagraph(1), "NumberingStyleName").isEmpty());
260 CPPUNIT_ASSERT_MESSAGE("Para2: <blank line>", getProperty<OUString>(getParagraph(2), "NumberingStyleName").isEmpty());
261 CPPUNIT_ASSERT_MESSAGE("Para3: <blank line>", getProperty<OUString>(getParagraph(3), "NumberingStyleName").isEmpty());
264 DECLARE_OOXMLEXPORT_TEST(testTdf44278, "tdf44278.docx")
266 // Without the fix in place, this test would have failed with
267 // - Expected: 1
268 // - Actual : 2
269 CPPUNIT_ASSERT_EQUAL(1, getShapes());
270 CPPUNIT_ASSERT_EQUAL(1, getPages());
273 DECLARE_OOXMLEXPORT_TEST(testTdf137742, "tdf137742.docx")
275 lang::Locale locale(
276 getProperty<lang::Locale>(getParagraph(1), "CharLocale"));
277 CPPUNIT_ASSERT_EQUAL(OUString("en"), locale.Language);
279 // Without the fix in place, this test would have failed with
280 // - Expected: US
281 // - Actual :
282 CPPUNIT_ASSERT_EQUAL(OUString("US"), locale.Country);
285 DECLARE_OOXMLEXPORT_TEST(testTdf141231_arabicHebrewNumbering, "tdf141231_arabicHebrewNumbering.docx")
287 // The page's numbering type: instead of Hebrew, this was default style::NumberingType::ARABIC (4).
288 auto nActual = getProperty<sal_Int16>(getStyles("PageStyles")->getByName("Standard"), "NumberingType");
289 CPPUNIT_ASSERT_EQUAL(style::NumberingType::NUMBER_HEBREW, nActual);
291 // The footnote numbering type: instead of arabicAbjad, this was the default style::NumberingType::ARABIC.
292 uno::Reference<text::XFootnotesSupplier> xFootnotesSupplier(mxComponent, uno::UNO_QUERY);
293 uno::Reference<beans::XPropertySet> xFootnoteSettings = xFootnotesSupplier->getFootnoteSettings();
294 nActual = getProperty<sal_Int16>(xFootnotesSupplier->getFootnoteSettings(), "NumberingType");
295 CPPUNIT_ASSERT_EQUAL(style::NumberingType::CHARS_ARABIC_ABJAD, nActual);
298 DECLARE_OOXMLEXPORT_TEST(testTdf141966_chapterNumbering, "tdf141966_chapterNumbering.docx")
300 uno::Reference<text::XChapterNumberingSupplier> xNumberingSupplier(mxComponent, uno::UNO_QUERY);
301 uno::Reference<container::XIndexAccess> xNumberingRules = xNumberingSupplier->getChapterNumberingRules();
302 comphelper::SequenceAsHashMap hashMap(xNumberingRules->getByIndex(0));
304 CPPUNIT_ASSERT(hashMap["HeadingStyleName"].get<OUString>().match("CN1"));
306 uno::Reference<beans::XPropertySet> xPara(getParagraph(7, "Direct formatting with \"Outline\" numbering."), uno::UNO_QUERY);
307 CPPUNIT_ASSERT_EQUAL(OUString("2nd"), getProperty<OUString>(xPara, "ListLabelString"));
310 DECLARE_OOXMLEXPORT_TEST(testTdf141966_chapterNumberTortureTest, "tdf141966_chapterNumberTortureTest.docx")
312 // There is no point in identifying what the wrong values where in this test,
313 //because EVERYTHING was wrong, and MANY different fixes are required to solve the problems.
314 uno::Reference<beans::XPropertySet> xPara(getParagraph(1, "No numId in style or paragraph"), uno::UNO_QUERY);
315 CPPUNIT_ASSERT_EQUAL(OUString(""), getProperty<OUString>(xPara, "ListLabelString"));
317 xPara.set(getParagraph(2, "Paragraph cancels numbering(0)"), uno::UNO_QUERY);
318 CPPUNIT_ASSERT_EQUAL(OUString(""), getProperty<OUString>(xPara, "ListLabelString"));
320 xPara.set(getParagraph(3, "First numbered line"), uno::UNO_QUERY);
321 CPPUNIT_ASSERT_EQUAL(OUString("1st.i.a.1.I"), getProperty<OUString>(xPara, "ListLabelString"));
323 xPara.set(getParagraph(5, "Outline with listLvl 5"), uno::UNO_QUERY);
324 CPPUNIT_ASSERT_EQUAL(OUString(""), getProperty<OUString>(xPara, "ListLabelString"));
326 xPara.set(getParagraph(7, "inheritOnly: inherit outlineLvl and listLvl."), uno::UNO_QUERY);
327 // 2nd.iii in MS Word 2003. 2nd.ii in MS Word 2010/2016 where para5 is not numbered.
328 CPPUNIT_ASSERT_EQUAL(OUString("2nd.ii"), getProperty<OUString>(xPara, "ListLabelString"));
329 CPPUNIT_ASSERT_EQUAL(sal_Int16(1), getProperty<sal_Int16>(xPara, "NumberingLevel")); // Level 2
331 xPara.set(getParagraph(9, "outline with Body listLvl(9)."), uno::UNO_QUERY);
332 CPPUNIT_ASSERT_EQUAL(OUString(""), getProperty<OUString>(xPara, "ListLabelString"));
334 xPara.set(getParagraph(10, "outline with Body listLvl(9) #2."), uno::UNO_QUERY);
335 CPPUNIT_ASSERT_EQUAL(OUString(""), getProperty<OUString>(xPara, "ListLabelString"));
337 xPara.set(getParagraph(11, "direct formatting - Body listLvl(9)."), uno::UNO_QUERY);
338 CPPUNIT_ASSERT_EQUAL(OUString(""), getProperty<OUString>(xPara, "ListLabelString"));
340 xPara.set(getParagraph(12, "direct numId, inherit listLvl."), uno::UNO_QUERY);
341 CPPUNIT_ASSERT_EQUAL(OUString("2nd.ii.a.1.I"), getProperty<OUString>(xPara, "ListLabelString"));
342 CPPUNIT_ASSERT_EQUAL(sal_Int16(4), getProperty<sal_Int16>(xPara, "NumberingLevel")); // Level 5
344 xPara.set(getParagraph(13, "Style numId0 cancels inherited numbering."), uno::UNO_QUERY);
345 CPPUNIT_ASSERT_EQUAL(OUString(""), getProperty<OUString>(xPara, "ListLabelString"));
348 DECLARE_OOXMLEXPORT_TEST(testTdf143692_outlineLevelTortureTest, "tdf143692_outlineLevelTortureTest.docx")
350 uno::Reference<beans::XPropertySet> xPara(getParagraph(1, "Head non Toc style"), uno::UNO_QUERY);
351 // fixed missing inherit from Heading 1
352 CPPUNIT_ASSERT_EQUAL(sal_Int16(1), getProperty<sal_Int16>(xPara, "OutlineLevel"));
354 xPara.set(getParagraph(2, "noInheritHeading1"), uno::UNO_QUERY);
355 // fixed body level not cancelling inherited level
356 CPPUNIT_ASSERT_EQUAL(sal_Int16(0), getProperty<sal_Int16>(xPara, "OutlineLevel"));
358 xPara.set(getParagraph(4, "illegal -3"), uno::UNO_QUERY);
359 // illegal value is ignored, so inherit from Heading 1
360 CPPUNIT_ASSERT_EQUAL(sal_Int16(1), getProperty<sal_Int16>(xPara, "OutlineLevel"));
362 xPara.set(getParagraph(5, "Heading 1 with invalid direct -2"), uno::UNO_QUERY);
363 // fixed illegal does not mean body level, it means inherit from style.
364 CPPUNIT_ASSERT_EQUAL(sal_Int16(1), getProperty<sal_Int16>(xPara, "OutlineLevel"));
366 xPara.set(getParagraph(7, "InheritCN3"), uno::UNO_QUERY);
367 // fixed Chapter Numbering cancelling inheritance
368 CPPUNIT_ASSERT_EQUAL(sal_Int16(3), getProperty<sal_Int16>(xPara, "OutlineLevel"));
370 xPara.set(getParagraph(8, "noInheritCN3"), uno::UNO_QUERY);
371 CPPUNIT_ASSERT_EQUAL(sal_Int16(0), getProperty<sal_Int16>(xPara, "OutlineLevel"));
373 xPara.set(getParagraph(9, "override6CN3"), uno::UNO_QUERY);
374 // fixed body level not cancelling inherited level
375 CPPUNIT_ASSERT_EQUAL(sal_Int16(6), getProperty<sal_Int16>(xPara, "OutlineLevel"));
377 xPara.set(getParagraph(10, "illegal 25"), uno::UNO_QUERY);
378 // fixed illegal value is ignored, so inherit from List Level (Chapter Numbering)
379 CPPUNIT_ASSERT_EQUAL(sal_Int16(3), getProperty<sal_Int16>(xPara, "OutlineLevel"));
382 DECLARE_OOXMLEXPORT_TEST(testTdf132752, "tdf132752.docx")
384 uno::Reference<beans::XPropertySet> xPara1(getParagraph(1), uno::UNO_QUERY);
385 CPPUNIT_ASSERT_EQUAL(sal_Int32(1801), getProperty<sal_Int32>(xPara1, "ParaLeftMargin"));
386 CPPUNIT_ASSERT_EQUAL(sal_Int32(1000), getProperty<sal_Int32>(xPara1, "ParaRightMargin"));
387 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty<sal_Int32>(xPara1, "ParaFirstLineIndent"));
389 uno::Reference<beans::XPropertySet> xPara2(getParagraph(2), uno::UNO_QUERY);
390 CPPUNIT_ASSERT_EQUAL(sal_Int32(1801), getProperty<sal_Int32>(xPara2, "ParaLeftMargin"));
391 CPPUNIT_ASSERT_EQUAL(sal_Int32(1000), getProperty<sal_Int32>(xPara2, "ParaRightMargin"));
392 CPPUNIT_ASSERT_EQUAL(sal_Int32(-630), getProperty<sal_Int32>(xPara2, "ParaFirstLineIndent"));
394 uno::Reference<beans::XPropertySet> xPara3(getParagraph(3), uno::UNO_QUERY);
395 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty<sal_Int32>(xPara3, "ParaLeftMargin"));
396 CPPUNIT_ASSERT_EQUAL(sal_Int32(5891), getProperty<sal_Int32>(xPara3, "ParaRightMargin"));
397 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty<sal_Int32>(xPara3, "ParaFirstLineIndent"));
399 uno::Reference<beans::XPropertySet> xPara4(getParagraph(4), uno::UNO_QUERY);
400 CPPUNIT_ASSERT_EQUAL(sal_Int32(1801), getProperty<sal_Int32>(xPara4, "ParaLeftMargin"));
401 CPPUNIT_ASSERT_EQUAL(sal_Int32(1000), getProperty<sal_Int32>(xPara4, "ParaRightMargin"));
402 CPPUNIT_ASSERT_EQUAL(sal_Int32(4157), getProperty<sal_Int32>(xPara4, "ParaFirstLineIndent"));
404 uno::Reference<beans::XPropertySet> xPara5(getParagraph(5), uno::UNO_QUERY);
405 CPPUNIT_ASSERT_EQUAL(sal_Int32(1801), getProperty<sal_Int32>(xPara5, "ParaLeftMargin"));
406 CPPUNIT_ASSERT_EQUAL(sal_Int32(1000), getProperty<sal_Int32>(xPara5, "ParaRightMargin"));
407 CPPUNIT_ASSERT_EQUAL(sal_Int32(-630), getProperty<sal_Int32>(xPara5, "ParaFirstLineIndent"));
409 uno::Reference<beans::XPropertySet> xPara6(getParagraph(6), uno::UNO_QUERY);
410 CPPUNIT_ASSERT_EQUAL(sal_Int32(3565), getProperty<sal_Int32>(xPara6, "ParaLeftMargin"));
411 CPPUNIT_ASSERT_EQUAL(sal_Int32(2764), getProperty<sal_Int32>(xPara6, "ParaRightMargin"));
412 CPPUNIT_ASSERT_EQUAL(sal_Int32(-2394), getProperty<sal_Int32>(xPara6, "ParaFirstLineIndent"));
415 DECLARE_OOXMLEXPORT_TEST(testGutterLeft, "gutter-left.docx")
417 uno::Reference<beans::XPropertySet> xPageStyle;
418 getStyles("PageStyles")->getByName("Standard") >>= xPageStyle;
419 sal_Int32 nGutterMargin{};
420 xPageStyle->getPropertyValue("GutterMargin") >>= nGutterMargin;
421 // Without the accompanying fix in place, this test would have failed with:
422 // - Expected: 1270
423 // - Actual : 0
424 // i.e. gutter margin was lost.
425 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(1270), nGutterMargin);
428 CPPUNIT_TEST_FIXTURE(Test, testGutterTop)
430 loadAndSave("gutter-top.docx");
431 xmlDocUniquePtr pXmlSettings = parseExport("word/settings.xml");
432 CPPUNIT_ASSERT(pXmlSettings);
433 // Without the accompanying fix in place, this test would have failed with:
434 // - Expected: 1
435 // - Actual : 0
436 // i.e. <w:gutterAtTop> was lost.
437 assertXPath(pXmlSettings, "/w:settings/w:gutterAtTop", 1);
440 CPPUNIT_TEST_FIXTURE(Test, testCustomShapePresetExport)
442 loadAndReload("testCustomShapePresetExport.odt");
443 // Check if the load failed.
444 CPPUNIT_ASSERT(getPages());
446 // Check all shapes of the file
447 int nCount = 0;
448 for (int i = 1; i <= getShapes(); i++)
450 uno::Reference<beans::XPropertySet> xProperties(getShape(i), uno::UNO_QUERY);
451 if (!xProperties->getPropertySetInfo()->hasPropertyByName("CustomShapeGeometry"))
452 continue;
453 // Get the custom shape property
454 auto aCustomShapeGeometry = xProperties->getPropertyValue("CustomShapeGeometry")
455 .get<uno::Sequence<beans::PropertyValue>>();
456 // Find for shape type
457 for (const auto& aCustomGeometryIterator : std::as_const(aCustomShapeGeometry))
459 if (aCustomGeometryIterator.Name == "Type")
460 CPPUNIT_ASSERT_MESSAGE(
461 "This is an ooxml preset shape with custom geometry! Shape type lost!",
462 aCustomGeometryIterator.Value.get<OUString>() != "ooxml-non-primitive");
463 // Without the fix, all shapes have ooxml-non-primitive type, and lost their
464 // real type (like triangle) with the textbox padding.
466 nCount++;
468 // Without the fix the count does not match.
469 CPPUNIT_ASSERT_EQUAL(17, nCount);
472 CPPUNIT_TEST_FIXTURE(Test, testTdf69635)
474 loadAndSave("tdf69635.docx");
475 xmlDocUniquePtr pXmlHeader1 = parseExport("word/header1.xml");
476 xmlDocUniquePtr pXmlSettings = parseExport("word/settings.xml");
477 CPPUNIT_ASSERT(pXmlHeader1);
478 CPPUNIT_ASSERT(pXmlSettings);
480 // Without the accompanying fix in place, this test would have failed with:
481 // - Expected: "left"
482 // - Actual : "right"
483 assertXPathContent(pXmlHeader1, "/w:hdr/w:p/w:r/w:t", "left");
485 // Make sure "left" appears as a hidden header
486 assertXPath(pXmlSettings, "/w:settings/w:evenAndOddHeaders", 0);
489 DECLARE_OOXMLEXPORT_TEST(testTdf148671, "tdf148671.docx")
491 // Don't assert with 'pFieldMark' failed when document is opened
492 CPPUNIT_ASSERT_EQUAL(1, getPages());
494 if (!isExported())
495 return;
496 // Preserve tag on SDT blocks. (Before the fix, these were all lost)
497 xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml");
498 assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w:tag", 3);
501 DECLARE_OOXMLEXPORT_TEST(testTdf140668, "tdf140668.docx")
503 // Don't crash when document is opened
504 CPPUNIT_ASSERT_EQUAL(1, getPages());
507 DECLARE_OOXMLEXPORT_TEST(testTdf149649, "tdf149649.docx")
509 // Don't crash when document is opened
510 CPPUNIT_ASSERT_EQUAL(2, getPages());
513 DECLARE_OOXMLEXPORT_TEST(testTdf138771, "tdf138771.docx")
515 // Don't crash when document is imported
516 CPPUNIT_ASSERT_EQUAL(1, getPages());
519 DECLARE_OOXMLEXPORT_TEST(testTdf125936_numberingSuperscript, "tdf125936_numberingSuperscript.docx")
521 // Without the fix, the first character run was superscripted.
522 CPPUNIT_ASSERT_EQUAL( sal_Int16(0), getProperty<sal_Int16>(getRun(getParagraph(1), 1, "A-570-108"), "CharEscapement") );
525 CPPUNIT_TEST_FIXTURE(Test, testTdf134619_numberingProps)
527 loadAndReload("tdf134619_numberingProps.doc");
528 // Get the third paragraph's numbering style's 1st level's bullet size
529 uno::Reference<text::XTextRange> xParagraph = getParagraph(3);
530 auto xLevels = getProperty< uno::Reference<container::XIndexAccess> >(xParagraph, "NumberingRules");
531 uno::Sequence<beans::PropertyValue> aLevel;
532 xLevels->getByIndex(0) >>= aLevel; // 1st level
533 OUString aCharStyleName = std::find_if(std::cbegin(aLevel), std::cend(aLevel), [](const beans::PropertyValue& rValue) { return rValue.Name == "CharStyleName"; })->Value.get<OUString>();
535 // Make sure that the blue bullet's font size is 72 points, not 12 points.
536 uno::Reference<beans::XPropertySet> xStyle(getStyles("CharacterStyles")->getByName(aCharStyleName), uno::UNO_QUERY);
537 CPPUNIT_ASSERT_EQUAL(72.f, getProperty<float>(xStyle, "CharHeight"));
540 CPPUNIT_TEST_FIXTURE(Test, testTdf134951_duplicates)
542 loadAndReload("tdf134951_duplicates.odt");
543 CPPUNIT_ASSERT_EQUAL(3, getShapes());
544 CPPUNIT_ASSERT_EQUAL(1, getPages());
545 uno::Reference<text::XEndnotesSupplier> xEndnotesSupplier(mxComponent, uno::UNO_QUERY);
546 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(1), xEndnotesSupplier->getEndnotes()->getCount());
548 getParagraph(5, "Duplicate fields: 1");
551 CPPUNIT_TEST_FIXTURE(Test, testTdf135773_numberingShading)
553 loadAndSave("tdf135774_numberingShading.docx");
554 // This test uses preTest to export CharBackground as Highlight instead of the 7.0 default of Shading.
556 // Before the fix, the imported shading was converted into a red highlight.
557 xmlDocUniquePtr pXmlStyles = parseExport("word/numbering.xml");
558 assertXPath(pXmlStyles, "/w:numbering/w:abstractNum[@w:abstractNumId='1']/w:lvl[@w:ilvl='0']/w:rPr/w:shd", "fill", "ED4C05");
561 CPPUNIT_TEST_FIXTURE(Test, testTdf140336_paraNoneShading)
563 loadAndReload("tdf140336_paraNoneShading.odt");
564 CPPUNIT_ASSERT_EQUAL(1, getPages());
565 // Before the fix, the background from a style was exported to dis-inheriting paragraphs/styles.
566 CPPUNIT_ASSERT_EQUAL(sal_uInt32(COL_AUTO), getProperty<sal_uInt32>(getParagraph(1), "ParaBackColor"));
567 uno::Reference<beans::XPropertySet> xStyle(getStyles("ParagraphStyles")->getByName("CanclledBackground"), uno::UNO_QUERY);
568 CPPUNIT_ASSERT_EQUAL(drawing::FillStyle_NONE, getProperty<drawing::FillStyle>(xStyle, "FillStyle"));
570 // sanity check: backgroundColor paragraph style has a golden color(FF7F50), which para2 inherits
571 CPPUNIT_ASSERT_EQUAL(sal_uInt32(16744272), getProperty<sal_uInt32>(getParagraph(2), "ParaBackColor"));
574 CPPUNIT_TEST_FIXTURE(Test, testTdf141173_missingFrames)
576 loadAndReload("tdf141173_missingFrames.rtf");
577 // Without the fix in place, almost all of the text and textboxes were missing.
578 // Without the fix, there were only 2 shapes (mostly unseen).
579 CPPUNIT_ASSERT_EQUAL(13, getShapes());
582 DECLARE_OOXMLEXPORT_TEST(testTdf142404_tabSpacing, "tdf142404_tabSpacing.docx")
584 // The tabstops should be laid out as triple-spaced when the paragraph takes multiple lines.
585 CPPUNIT_ASSERT_EQUAL_MESSAGE("too big for one page", 2, getPages());
588 DECLARE_OOXMLEXPORT_TEST(testTdf142404_tabOverMarginC15, "tdf142404_tabOverMarginC15.docx")
590 // TabOverMargin no longer applies to compatibilityMode 15 DOCX files. In Word 2016 this is 3pg.
591 // One page long if tabOverMargin is true. Two pages long if tabOverflow is true.
592 // Really should be 3 pages long, when tabOverflow is also false, but inadequate implementation.
593 CPPUNIT_ASSERT_EQUAL_MESSAGE("too big for one page", 2, getPages());
596 CPPUNIT_TEST_FIXTURE(Test, testTdf142404_tabOverSpacingC15)
598 loadAndReload("tdf142404_tabOverSpacingC15.odt");
599 // Although TabOverMargin no longer applies to compatibilityMode 15 DOCX files,
600 // it still applies to a tab over the paragraph end (inside text boundaries).
601 // The original 3-page ODT saved as DOCX would fit on one page in MS Word 2010, but 3 in Word 2013.
602 CPPUNIT_ASSERT_EQUAL_MESSAGE("too big for two pages", 3, getPages());
603 // The tab goes over the paragraph margin
604 CPPUNIT_ASSERT_EQUAL(OUString("A left tab positioned at"), parseDump("//page[1]/body/txt[2]/SwParaPortion/SwLineLayout[1]/SwLinePortion[1]", "portion"));
605 sal_Int32 nTextLen = parseDump("//page[1]/body/txt[2]/SwParaPortion/SwLineLayout[1]/SwLinePortion[1]", "width").toInt32();
606 CPPUNIT_ASSERT_EQUAL(OUString("*"), parseDump("//page[1]/body/txt[2]/SwParaPortion/SwLineLayout[1]/SwFixPortion[1]", "portion"));
607 sal_Int32 nTabLen = parseDump("//page[1]/body/txt[2]/SwParaPortion/SwLineLayout[1]/SwFixPortion[1]", "width").toInt32();
608 CPPUNIT_ASSERT_MESSAGE("Large left tab", nTextLen < nTabLen);
609 // Not 1 line high (Word 2010 DOCX), or 3 lines high (LO DOCX) or 5 lines high (ODT), but 4 lines high
610 sal_Int32 nHeight = parseDump("//page[1]/body/txt[2]/infos/bounds", "height").toInt32();
611 CPPUNIT_ASSERT_MESSAGE("4 lines high", 1100 < nHeight);
612 CPPUNIT_ASSERT_MESSAGE("4 lines high", nHeight < 1300);
614 CPPUNIT_ASSERT_EQUAL(OUString("TabOverflow does what?"), parseDump("//page[1]/body/txt[7]/SwParaPortion/SwLineLayout[1]/SwLinePortion[1]", "portion"));
615 // Not 1 line high (Word 2010 DOCX), or 4 lines high (prev LO DOCX) or 8 lines high (ODT).
616 // but two lines high. (3 in Word 2016 because it pulls down "what?" to the second line - weird)
617 nHeight = parseDump("//page[1]/body/txt[7]/infos/bounds", "height").toInt32();
618 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("2 lines high (but 3 in Word)", 242*2.5, nHeight, 242);
620 CPPUNIT_ASSERT_EQUAL(OUString("A centered tab positioned at"), parseDump("//page[1]/body/txt[3]/SwParaPortion/SwLineLayout[1]/SwLinePortion[1]", "portion"));
621 sal_Int32 nLineWidth = parseDump("//page[1]/body/txt[3]/SwParaPortion/SwLineLayout[1]/SwFixPortion[1]", "width").toInt32();
622 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Big tab: full paragraph area used", 737, nLineWidth, 100);
624 // Pages 2/3 are TabOverMargin - in this particular case tabs should not go over margin.
625 CPPUNIT_ASSERT_EQUAL(OUString("A right tab positioned at"), parseDump("//page[2]/body/txt[6]/SwParaPortion/SwLineLayout[1]/SwLinePortion[1]", "portion"));
626 sal_Int32 nParaWidth = parseDump("//page[2]/body/txt[6]/infos/prtBounds", "width").toInt32();
627 // the clearest non-first-line visual example is this second tab in the right-tab paragraph.
628 nLineWidth = parseDump("//page[2]/body/txt[6]/SwParaPortion/SwLineLayout[4]", "width").toInt32();
629 CPPUNIT_ASSERT_EQUAL_MESSAGE("Full paragraph area used", nLineWidth, nParaWidth);
631 CPPUNIT_ASSERT_EQUAL(OUString("TabOverflow does what?"), parseDump("//page[3]/body/txt[2]/SwParaPortion/SwLineLayout[1]/SwLinePortion[1]", "portion"));
632 // Not 1 line high (Word 2010 DOCX and ODT), or 4 lines high (prev LO DOCX),
633 // but 8 lines high.
634 nHeight = parseDump("//page[3]/body/txt[2]/infos/bounds", "height").toInt32();
635 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("8 lines high", 242*8, nHeight, 121);
638 DECLARE_OOXMLEXPORT_TEST(testShapeHyperlink, "hyperlinkshape.docx")
640 // Test import/export of hyperlink property on shapes
641 auto xShape(getShape(1));
642 CPPUNIT_ASSERT_EQUAL(OUString("https://libreoffice.org/"), getProperty<OUString>(xShape, "Hyperlink"));
645 CPPUNIT_TEST_FIXTURE(Test, testTextframeHyperlink)
647 // Make sure hyperlink is imported correctly
648 createSwDoc("docxopenhyperlinkbox.docx");
649 uno::Reference<text::XTextFramesSupplier> xTextFramesSupplier(mxComponent, uno::UNO_QUERY);
650 uno::Reference<container::XIndexAccess> xIndexAccess(xTextFramesSupplier->getTextFrames(), uno::UNO_QUERY);
651 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xIndexAccess->getCount());
653 uno::Reference<beans::XPropertySet> xFrame(xIndexAccess->getByIndex(0), uno::UNO_QUERY);
654 CPPUNIT_ASSERT_EQUAL(OUString("https://libreoffice.org/"), getProperty<OUString>(xFrame, "HyperLinkURL"));
656 // FIXME: After save&reload, the text frame should still be a text frame, and the above test should still work.
657 // (Currently the Writer text frame becomes a text box (shape based)). See tdf#140961
658 saveAndReload("Office Open XML Text");
660 xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml");
661 // DML
662 assertXPath(pXmlDoc, "//w:drawing/wp:anchor/wp:docPr/a:hlinkClick", 1);
663 // VML
664 assertXPath(pXmlDoc, "//w:pict/v:rect", "href", "https://libreoffice.org/");
667 CPPUNIT_TEST_FIXTURE(Test, testTdf146171_invalid_change_date)
669 createSwDoc("tdf146171.docx");
670 // false alarm? during ODF roundtrip:
671 // 'Error: "1970-01-01" does not satisfy the "dateTime" type'
672 // disable and check only the conversion of the invalid (zeroed) change date
673 // 0000-00-00T00:00:00Z, resulting loss of change tracking during ODF roundtrip
674 // reload("writer8", "tdf146171.odt");
675 saveAndReload("Office Open XML Text");
677 xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml");
678 // This was 0
679 assertXPath(pXmlDoc, "//w:ins", 5);
680 // This was 0
681 assertXPath(pXmlDoc, "//w:del", 2);
682 // no date (anonymized change)
683 // This failed, date was exported as w:date="1970-01-01T00:00:00Z" before fixing tdf#147760
684 assertXPathNoAttribute(pXmlDoc, "//w:del[1]", "date");
685 assertXPathNoAttribute(pXmlDoc, "//w:del[2]", "date");
688 CPPUNIT_TEST_FIXTURE(Test, testTdf139580)
690 loadAndReload("tdf139580.odt");
691 // Without the fix in place, this test would have crashed at export time
692 CPPUNIT_ASSERT_EQUAL(2, getShapes());
693 CPPUNIT_ASSERT_EQUAL(1, getPages());
696 DECLARE_OOXMLEXPORT_TEST(testTdf149198, "tdf149198.docx")
698 // Without the fix in place, this test would have crashed at export time
699 CPPUNIT_ASSERT_EQUAL(1, getPages());
700 CPPUNIT_ASSERT_EQUAL(OUString("Documentation"), getParagraph(1)->getString());
703 CPPUNIT_TEST_FIXTURE(Test, testFooterMarginLost)
705 loadAndSave("footer-margin-lost.docx");
706 xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml");
707 // Without the accompanying fix in place, this test would have failed with:
708 // - Expected: 709
709 // - Actual : 0
710 // i.e. import + export lost the footer margin value.
711 assertXPath(pXmlDoc, "/w:document/w:body/w:sectPr/w:pgMar", "footer", "709");
714 CPPUNIT_TEST_FIXTURE(Test, testEffectExtentLineWidth)
716 auto verify = [this]() {
717 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(506),
718 getProperty<sal_Int32>(getShape(1), "TopMargin"));
721 // Given a document with a shape that has a non-zero line width and effect extent:
722 // When loading the document:
723 createSwDoc("effect-extent-line-width.docx");
724 // Then make sure that the line width is not taken twice (once as part of the margin, and then
725 // also as the line width):
726 // Without the accompanying fix in place, this test would have failed with:
727 // - Expected: 508
728 // - Actual : 561
729 // i.e. the upper spacing was too large, the last line of the text moved below the shape.
730 verify();
731 saveAndReload("Office Open XML Text");
732 verify();
735 CPPUNIT_TEST_FIXTURE(Test, testRtlGutter)
737 // Given a document with RTL gutter:
738 createSwDoc("rtl-gutter.docx");
739 uno::Reference<beans::XPropertySet> xStandard(getStyles("PageStyles")->getByName("Standard"),
740 uno::UNO_QUERY);
741 CPPUNIT_ASSERT(getProperty<bool>(xStandard, "RtlGutter"));
743 // When saving back to DOCX:
744 saveAndReload("Office Open XML Text");
746 // Then make sure the section's gutter is still RTL:
747 xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml");
748 // Without the accompanying fix in place, this test would have failed as the XML element was
749 // missing.
750 assertXPath(pXmlDoc, "/w:document/w:body/w:sectPr/w:rtlGutter", 1);
753 CPPUNIT_TEST_FIXTURE(Test, testTdf140572_docDefault_superscript)
755 loadAndReload("tdf140572_docDefault_superscript.docx");
756 // A round-trip was crashing.
758 // Without the fix, everything was DFLT_ESC_AUTO_SUPER (default superscript)
759 CPPUNIT_ASSERT_EQUAL( sal_Int16(0), getProperty<sal_Int16>(getRun(getParagraph(1), 1), "CharEscapement") );
762 DECLARE_OOXMLEXPORT_TEST(testTdf136841, "tdf136841.docx")
764 if (!IsDefaultDPI())
765 return;
766 uno::Reference<drawing::XShape> image = getShape(1);
767 uno::Reference<beans::XPropertySet> imageProperties(image, uno::UNO_QUERY);
768 uno::Reference<graphic::XGraphic> graphic;
769 imageProperties->getPropertyValue( "Graphic" ) >>= graphic;
770 Graphic vclGraphic(graphic);
771 BitmapEx bitmap(vclGraphic.GetBitmapEx());
772 CPPUNIT_ASSERT_EQUAL( tools::Long(76), bitmap.GetSizePixel().Width());
773 CPPUNIT_ASSERT_EQUAL( tools::Long(76), bitmap.GetSizePixel().Height());
775 // Without the fix in place, this test would have failed with
776 // - Expected: Color: R:228 G:71 B:69 A:0
777 // - Actual : Color: R:0 G:0 B:0 A:0
778 CPPUNIT_ASSERT_EQUAL( Color(228,71,69), bitmap.GetPixelColor(38,38));
781 CPPUNIT_TEST_FIXTURE(Test, testTdf138953)
783 loadAndReload("croppedAndRotated.odt");
784 CPPUNIT_ASSERT_EQUAL(1, getShapes());
785 CPPUNIT_ASSERT_EQUAL(1, getPages());
786 // Make sure the rotation is exported correctly, and size not distorted
787 auto xShape(getShape(1));
788 CPPUNIT_ASSERT_EQUAL(27000.0, getProperty<double>(xShape, "RotateAngle"));
789 auto frameRect = getProperty<css::awt::Rectangle>(xShape, "FrameRect");
790 // Before the fix, original object size (i.e., before cropping) was written to spPr in OOXML,
791 // and the resulting object size was much larger than should be.
792 CPPUNIT_ASSERT_EQUAL(sal_Int32(12961), frameRect.Height);
793 CPPUNIT_ASSERT_EQUAL(sal_Int32(8664), frameRect.Width);
796 CPPUNIT_TEST_FIXTURE(Test, testTdf118535)
798 loadAndReload("tdf118535.odt");
799 CPPUNIT_ASSERT_EQUAL(2, getShapes());
800 CPPUNIT_ASSERT_EQUAL(2, getPages());
801 uno::Reference<packages::zip::XZipFileAccess2> xNameAccess = packages::zip::ZipFileAccess::createWithURL(comphelper::getComponentContext(m_xSFactory), maTempFile.GetURL());
802 CPPUNIT_ASSERT_EQUAL(true, bool(xNameAccess->hasByName("word/media/image1.jpeg")));
803 // Without the accompanying fix in place, this test would have failed with:
804 // - Expected: false
805 // - Actual : true
806 // i.e. the embedded picture would have been saved twice.
807 CPPUNIT_ASSERT_EQUAL(false, bool(xNameAccess->hasByName("word/media/image2.jpeg")));
810 DECLARE_OOXMLEXPORT_TEST(testTdf133473_shadowSize, "tdf133473.docx")
812 uno::Reference<drawing::XShape> xShape = getShape(1);
814 SdrObject* pObj(SdrObject::getSdrObjectFromXShape(xShape));
815 const SfxItemSet& rSet = pObj->GetMergedItemSet();
816 sal_Int32 nSize1 = rSet.Get(SDRATTR_SHADOWSIZEX).GetValue();
818 // Without the accompanying fix in place, this test would have failed with:
819 // - Expected: 200000
820 // - Actual : 113386
821 // I.e. Shadow size will be smaller than actual.
823 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(200000), nSize1);
826 DECLARE_OOXMLEXPORT_TEST(testTdf153874, "image_through_shape.docx")
828 uno::Reference<beans::XPropertySet> const xShape1(getShapeByName(u"Test1"), uno::UNO_QUERY);
829 uno::Reference<beans::XPropertySet> const xShape2(getShapeByName(u"Rectangle 1"), uno::UNO_QUERY);
830 CPPUNIT_ASSERT_EQUAL(text::TextContentAnchorType_AS_CHARACTER, xShape1->getPropertyValue("AnchorType").get<text::TextContentAnchorType>());
831 CPPUNIT_ASSERT_EQUAL(text::TextContentAnchorType_AT_CHARACTER, xShape2->getPropertyValue("AnchorType").get<text::TextContentAnchorType>());
832 CPPUNIT_ASSERT_LESS(xShape2->getPropertyValue("ZOrder").get<sal_uInt64>(), xShape1->getPropertyValue("ZOrder").get<sal_uInt64>());
833 CPPUNIT_ASSERT(xShape1->getPropertyValue("Decorative").get<bool>());
834 // not implemented on shape yet
835 //CPPUNIT_ASSERT(xShape2->getPropertyValue("Decorative").get<bool>());
838 DECLARE_OOXMLEXPORT_TEST(testTextBoxZOrder, "testTextBoxZOrder.docx")
840 // Is load successful?
841 CPPUNIT_ASSERT(mxComponent);
842 // Collect the z-order values of the textboxes
843 std::vector<sal_uInt64> ShapeZorders;
844 std::vector<sal_uInt64> FrameZorders;
845 for (int i = 1; i < 4; i++)
847 uno::Reference<drawing::XShape> xShape(getShape(i));
848 CPPUNIT_ASSERT(xShape);
849 uno::Reference<beans::XPropertySet> xShapeProperties(xShape, uno::UNO_QUERY);
850 CPPUNIT_ASSERT(xShapeProperties);
851 uno::Reference<text::XTextFrame> xFrame = SwTextBoxHelper::getUnoTextFrame(xShape);
852 CPPUNIT_ASSERT(xFrame.is());
853 uno::Reference<beans::XPropertySet> const xFrameProperties(xFrame, uno::UNO_QUERY);
854 CPPUNIT_ASSERT(xFrameProperties);
855 ShapeZorders.push_back(xShapeProperties->getPropertyValue("ZOrder").get<sal_uInt64>());
856 FrameZorders.push_back(xFrameProperties->getPropertyValue("ZOrder").get<sal_uInt64>());
858 // Check the z-order values.
859 for (int i = 1; i < 3; i++)
861 CPPUNIT_ASSERT_GREATER(ShapeZorders[i - 1], ShapeZorders[i]);
862 CPPUNIT_ASSERT_GREATER(FrameZorders[i - 1], FrameZorders[i]);
863 CPPUNIT_ASSERT_GREATER(ShapeZorders[i - 1], FrameZorders[i - 1]);
865 // Without the fix it failed, because the z-order was wrong.
868 DECLARE_OOXMLEXPORT_TEST(testTdf141550, "tdf141550.docx")
870 uno::Reference<drawing::XShape> xShape(getShape(1));
871 uno::Reference<text::XTextFrame> xFrame = SwTextBoxHelper::getUnoTextFrame(xShape);
873 CPPUNIT_ASSERT(xShape);
874 CPPUNIT_ASSERT(xFrame);
876 const sal_uInt16 nShapeRelOri = getProperty<sal_uInt16>(xShape, UNO_NAME_HORI_ORIENT_RELATION);
877 const sal_uInt16 nFrameRelOri = getProperty<sal_uInt16>(xFrame, UNO_NAME_HORI_ORIENT_RELATION);
879 CPPUNIT_ASSERT_EQUAL_MESSAGE("Textbox fallen apart!", nShapeRelOri, nFrameRelOri);
880 // Without the fix in place it fails with difference.
883 DECLARE_OOXMLEXPORT_TEST(testTdf140137, "tdf140137.docx")
885 // Don't throw exception during load
886 CPPUNIT_ASSERT_EQUAL(1, getPages());
889 DECLARE_OOXMLEXPORT_TEST(testTdf105688, "tdf105688.docx")
891 // Don't throw exception during load
892 CPPUNIT_ASSERT_EQUAL(2, getPages());
895 CPPUNIT_TEST_FIXTURE(Test, testCommentReply)
897 loadAndSave("CommentReply.docx");
898 xmlDocUniquePtr pXmlComm = parseExport("word/comments.xml");
899 xmlDocUniquePtr pXmlCommExt = parseExport("word/commentsExtended.xml");
900 CPPUNIT_ASSERT(pXmlComm);
901 CPPUNIT_ASSERT(pXmlCommExt);
902 OUString sParentId = getXPath(pXmlComm, "/w:comments/w:comment[1]/w:p[1]", "paraId");
903 OUString sChildId = getXPath(pXmlComm, "/w:comments/w:comment[2]/w:p[1]", "paraId");
904 OUString sChildIdEx = getXPath(pXmlCommExt, "/w15:commentsEx/w15:commentEx", "paraId");
905 OUString sChildParentId = getXPath(pXmlCommExt,
906 "/w15:commentsEx/w15:commentEx", "paraIdParent");
907 // Make sure exported extended paraId matches the one in comments.xml
908 CPPUNIT_ASSERT_EQUAL(sChildId, sChildIdEx);
909 // Make sure the paraIdParent matches the id of its parent
910 CPPUNIT_ASSERT_EQUAL(sParentId, sChildParentId);
913 CPPUNIT_TEST_FIXTURE(Test, testCommentDone)
915 loadAndSave("CommentDone.docx");
916 xmlDocUniquePtr pXmlComm = parseExport("word/comments.xml");
917 assertXPath(pXmlComm, "/w:comments/w:comment[1]/w:p", 2);
918 OUString idLastPara = getXPath(pXmlComm, "/w:comments/w:comment[1]/w:p[2]", "paraId");
919 xmlDocUniquePtr pXmlCommExt = parseExport("word/commentsExtended.xml");
920 assertXPath(pXmlCommExt, "/w15:commentsEx", "Ignorable", "w15");
921 assertXPath(pXmlCommExt, "/w15:commentsEx/w15:commentEx", 1);
922 OUString idLastParaEx = getXPath(pXmlCommExt, "/w15:commentsEx/w15:commentEx", "paraId");
923 CPPUNIT_ASSERT_EQUAL(idLastPara, idLastParaEx);
924 assertXPath(pXmlCommExt, "/w15:commentsEx/w15:commentEx", "done", "1");
927 DECLARE_OOXMLEXPORT_TEST(testTableWidth, "frame_size_export.docx")
929 // after exporting: table width was overwritten in the doc model
930 uno::Reference<text::XTextTablesSupplier> xTablesSupplier(mxComponent, uno::UNO_QUERY);
931 uno::Reference<container::XIndexAccess> xTables(xTablesSupplier->getTextTables(),
932 uno::UNO_QUERY);
933 CPPUNIT_ASSERT_EQUAL(sal_Int16(100),
934 getProperty<sal_Int16>(xTables->getByIndex(0), "RelativeWidth"));
938 DECLARE_OOXMLEXPORT_TEST(testCommentDoneModel, "CommentDone.docx")
940 css::uno::Reference<css::text::XTextFieldsSupplier> xTextFieldsSupplier(
941 mxComponent, css::uno::UNO_QUERY_THROW);
942 auto xFields(xTextFieldsSupplier->getTextFields()->createEnumeration());
944 // First comment: initially resolved, toggled to unresolved on import, unresolved on roundtrip
945 CPPUNIT_ASSERT(xFields->hasMoreElements());
946 css::uno::Any aComment = xFields->nextElement();
947 css::uno::Reference<css::beans::XPropertySet> xComment(aComment, css::uno::UNO_QUERY_THROW);
949 if (!isExported())
951 // Check that it's resolved when initially read
952 CPPUNIT_ASSERT_EQUAL(true, xComment->getPropertyValue("Resolved").get<bool>());
953 // Set to unresolved
954 xComment->setPropertyValue("Resolved", css::uno::Any(false));
956 else
958 // After the roundtrip, it keeps the "unresolved" state set above
959 CPPUNIT_ASSERT_EQUAL(false, xComment->getPropertyValue("Resolved").get<bool>());
962 // Second comment: initially unresolved, toggled to resolved on import, resolved on roundtrip
963 CPPUNIT_ASSERT(xFields->hasMoreElements());
964 aComment = xFields->nextElement();
965 xComment.set(aComment, css::uno::UNO_QUERY_THROW);
967 if (!isExported())
969 // Check that it's unresolved when initially read
970 CPPUNIT_ASSERT_EQUAL(false, xComment->getPropertyValue("Resolved").get<bool>());
971 // Set to resolved
972 xComment->setPropertyValue("Resolved", css::uno::Any(true));
974 else
976 // After the roundtrip, it keeps the "resolved" state set above
977 CPPUNIT_ASSERT_EQUAL(true, xComment->getPropertyValue("Resolved").get<bool>());
981 CPPUNIT_TEST_FIXTURE(Test, Test_ShadowDirection)
983 loadAndSave("tdf142361ShadowDirection.odt");
984 CPPUNIT_ASSERT_EQUAL(1, getShapes());
985 CPPUNIT_ASSERT_EQUAL(1, getPages());
986 // The attribute 'rotWithShape' has the default value 'true' in OOXML, so Words interprets a
987 // missing attribute as 'true'. That means that Word rotates the shadow if the shape is
988 // rotated. Because in LibreOffice a shadow is never rotated, we must not omit this
989 // attribute.
990 xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml");
991 assertXPath(pXmlDoc,
992 "/w:document/w:body/w:p[1]/w:r[1]/mc:AlternateContent/mc:Choice/w:drawing/"
993 "wp:anchor/a:graphic/a:graphicData/wps:wsp/wps:spPr/a:effectLst/a:outerShdw",
994 "rotWithShape", "0");
997 CPPUNIT_TEST_FIXTURE(Test, testTdf150542)
999 loadAndSave("tdf150542.docx");
1001 xmlDocUniquePtr pSettingsDoc = parseExport("word/settings.xml");
1002 // Ensure that all docvars from input are written back and with correct values.
1003 // Order of document variables is not checked. So this can fail at some time if order is changed.
1004 assertXPath(pSettingsDoc,
1005 "/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");
1006 assertXPath(pSettingsDoc,
1007 "/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)");
1008 assertXPath(pSettingsDoc,
1009 "/w:settings/w:docVars/w:docVar[2]", "name", "DocVar1");
1010 assertXPath(pSettingsDoc,
1011 "/w:settings/w:docVars/w:docVar[2]", "val", "DocVar1 Value");
1012 assertXPath(pSettingsDoc,
1013 "/w:settings/w:docVars/w:docVar[3]", "name", "DocVar3");
1014 assertXPath(pSettingsDoc,
1015 "/w:settings/w:docVars/w:docVar[3]", "val", "DocVar3 Value");
1018 CPPUNIT_TEST_FIXTURE(Test, testTdf139549)
1020 loadAndSave("tdf139549.docx");
1021 // Document contains a VML textbox, the position of the textbox was incorrect.
1022 xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml");
1023 OUString aStyle = getXPath(pXmlDoc, "//w:pict/v:shape", "style");
1024 /* original is: "position:absolute;margin-left:138.5pt;margin-top:40.1pt;width:183pt;
1025 height:68pt;z-index:251675648;mso-position-horizontal:absolute;
1026 mso-position-horizontal-relative:page;mso-position-vertical:absolute;
1027 mso-position-vertical-relative:page" */
1028 CPPUNIT_ASSERT(!aStyle.isEmpty());
1030 sal_Int32 nextTokenPos = 0;
1031 OUString aStyleCommand = aStyle.getToken(0, ';', nextTokenPos);
1032 CPPUNIT_ASSERT(!aStyleCommand.isEmpty());
1034 OUString aStyleCommandName = aStyleCommand.getToken(0, ':');
1035 OUString aStyleCommandValue = aStyleCommand.getToken(1, ':');
1036 CPPUNIT_ASSERT_EQUAL(OUString("position"), aStyleCommandName);
1037 CPPUNIT_ASSERT_EQUAL(OUString("absolute"), aStyleCommandValue);
1039 aStyleCommand = aStyle.getToken(0, ';', nextTokenPos);
1040 CPPUNIT_ASSERT(!aStyleCommand.isEmpty());
1042 aStyleCommandName = aStyleCommand.getToken(0, ':');
1043 aStyleCommandValue = aStyleCommand.getToken(1, ':');
1044 CPPUNIT_ASSERT_EQUAL(OUString("margin-left"), aStyleCommandName);
1045 // Without the fix it failed, because the margin-left was 171.85pt.
1046 CPPUNIT_ASSERT_DOUBLES_EQUAL(138.5, aStyleCommandValue.toFloat(), 0.1);
1048 aStyleCommand = aStyle.getToken(0, ';', nextTokenPos);
1049 CPPUNIT_ASSERT(!aStyleCommand.isEmpty());
1051 aStyleCommandName = aStyleCommand.getToken(0, ':');
1052 aStyleCommandValue = aStyleCommand.getToken(1, ':');
1053 CPPUNIT_ASSERT_EQUAL(OUString("margin-top"), aStyleCommandName);
1054 // Without the fix it failed, because the margin-top was 55.45pt.
1055 CPPUNIT_ASSERT_DOUBLES_EQUAL(40.1, aStyleCommandValue.toFloat(), 0.1);
1059 CPPUNIT_TEST_FIXTURE(Test, testTdf143726)
1061 loadAndReload("Simple-TOC.odt");
1062 CPPUNIT_ASSERT_EQUAL(1, getPages());
1063 xmlDocUniquePtr pXmlStyles = parseExport("word/styles.xml");
1064 CPPUNIT_ASSERT(pXmlStyles);
1065 // Without the fix this was "TOA Heading" which belongs to the "Table of Authorities" index in Word
1066 // TOC's heading style should be exported as "TOC Heading" as that's the default Word style name
1067 assertXPath(pXmlStyles, "/w:styles/w:style[@w:styleId='TOCHeading']/w:name", "val", "TOC Heading");
1070 CPPUNIT_TEST_FIXTURE(Test, testTdf152153)
1072 loadAndReload("embedded_images.odt");
1074 uno::Reference<packages::zip::XZipFileAccess2> xNameAccess
1075 = packages::zip::ZipFileAccess::createWithURL(comphelper::getComponentContext(m_xSFactory),
1076 maTempFile.GetURL());
1077 const uno::Sequence<OUString> aNames(xNameAccess->getElementNames());
1078 int nImageFiles = 0;
1079 for (const auto& rElementName : aNames)
1080 if (rElementName.startsWith("word/media/image"))
1081 nImageFiles++;
1083 // Without the accompanying fix in place, this test would have failed with:
1084 // - Expected: 4
1085 // - Actual : 3
1086 // i.e. the once embedded picture wouldn't have been saved.
1087 CPPUNIT_ASSERT_EQUAL(4, nImageFiles);
1090 CPPUNIT_TEST_FIXTURE(Test, testTdf152152)
1092 loadAndReload("artistic_effects.docx");
1094 uno::Reference<packages::zip::XZipFileAccess2> xNameAccess
1095 = packages::zip::ZipFileAccess::createWithURL(comphelper::getComponentContext(m_xSFactory),
1096 maTempFile.GetURL());
1097 const uno::Sequence<OUString> aNames(xNameAccess->getElementNames());
1098 int nImageFiles = 0;
1099 for (const auto& rElementName : aNames)
1100 if (rElementName.startsWith("word/media/hdphoto"))
1101 nImageFiles++;
1103 // Without the accompanying fix in place, this test would have failed with:
1104 // - Expected: 2
1105 // - Actual : 1
1106 // i.e. the once WDP picture wouldn't have been saved.
1107 CPPUNIT_ASSERT_EQUAL(2, nImageFiles);
1110 CPPUNIT_PLUGIN_IMPLEMENT();
1112 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */