tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / sw / qa / extras / layout / layout4.cxx
blob36af7e749aae2f2fa5d17b1bd3e650703032cefa
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>
11 #include <comphelper/propertysequence.hxx>
12 #include <com/sun/star/linguistic2/XHyphenator.hpp>
13 #include <com/sun/star/text/XTextSectionsSupplier.hpp>
14 #include <vcl/scheduler.hxx>
15 #include <editeng/unolingu.hxx>
16 #include <editeng/editobj.hxx>
17 #include <comphelper/propertyvalue.hxx>
19 #include <wrtsh.hxx>
20 #include <pagefrm.hxx>
21 #include <sortedobjs.hxx>
22 #include <ndtxt.hxx>
23 #include <unotxdoc.hxx>
24 #include <rootfrm.hxx>
25 #include <IDocumentDrawModelAccess.hxx>
26 #include <unoframe.hxx>
27 #include <drawdoc.hxx>
28 #include <svx/svdpage.hxx>
29 #include <svx/svdotext.hxx>
30 #include <dcontact.hxx>
31 #include <frameformats.hxx>
33 namespace
35 /// Test to assert layout / rendering result of Writer.
36 class SwLayoutWriter4 : public SwModelTestBase
38 public:
39 SwLayoutWriter4()
40 : SwModelTestBase(u"/sw/qa/extras/layout/data/"_ustr)
45 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, testHiddenSectionPageDescs)
47 createSwDoc("hidden-sections-with-pagestyles.odt");
49 // hide these just so that the height of the section is what is expected;
50 // otherwise height depends on which tests run previously
51 uno::Sequence<beans::PropertyValue> argsSH(
52 comphelper::InitPropertySequence({ { "ShowHiddenParagraphs", uno::Any(false) } }));
53 dispatchCommand(mxComponent, ".uno:ShowHiddenParagraphs", argsSH);
54 uno::Sequence<beans::PropertyValue> args(
55 comphelper::InitPropertySequence({ { "Fieldnames", uno::Any(false) } }));
56 dispatchCommand(mxComponent, ".uno:Fieldnames", args);
57 Scheduler::ProcessEventsToIdle();
60 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
61 assertXPath(pXmlDoc, "/root/page", 2);
62 assertXPath(pXmlDoc, "/root/page[1]", "formatName", u"Hotti");
63 assertXPath(pXmlDoc, "/root/page[1]/body/section", 1);
64 assertXPath(pXmlDoc, "/root/page[1]/body/section[1]", "formatName", u"Verfügung");
65 assertXPath(pXmlDoc, "/root/page[2]/body/section", 2);
66 assertXPath(pXmlDoc, "/root/page[2]/body/section[1]", "formatName", u"Verfügung");
67 // should be > 0, no idea why it's different on Windows
68 #ifdef _WIN32
69 assertXPath(pXmlDoc, "/root/page[2]/body/section[1]/infos/bounds", "height", u"552");
70 #else
71 assertXPath(pXmlDoc, "/root/page[2]/body/section[1]/infos/bounds", "height", u"532");
72 #endif
73 assertXPath(pXmlDoc, "/root/page[2]/body/section[2]", "formatName", u"Rueckantwort");
74 assertXPath(pXmlDoc, "/root/page[2]/body/section[2]/infos/bounds", "height", u"0");
75 assertXPath(pXmlDoc, "/root/page[2]", "formatName", u"Folgeseite");
78 // toggle one section hidden and other visible
79 executeMacro(
80 u"vnd.sun.star.script:Standard.Module1.Main?language=Basic&location=document"_ustr);
81 Scheduler::ProcessEventsToIdle();
84 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
86 // tdf#152919: Without the fix in place, this test would have failed with
87 // - Expected: 3
88 // - Actual : 2
89 assertXPath(pXmlDoc, "/root/page", 3);
90 assertXPath(pXmlDoc, "/root/page[1]", "formatName", u"Hotti");
91 assertXPath(pXmlDoc, "/root/page[1]/body/section", 2);
92 assertXPath(pXmlDoc, "/root/page[1]/body/section[1]", "formatName", u"Verfügung");
93 assertXPath(pXmlDoc, "/root/page[1]/body/section[2]", "formatName", u"Rueckantwort");
94 assertXPath(pXmlDoc, "/root/page[2]", "formatName", u"Empty Page");
95 assertXPath(pXmlDoc, "/root/page[3]/body/section", 1);
96 assertXPath(pXmlDoc, "/root/page[3]/body/section[1]", "formatName", u"Rueckantwort");
97 // should be > 0, no idea why it's different on Windows
98 #ifdef _WIN32
99 assertXPath(pXmlDoc, "/root/page[3]/body/section[1]/infos/bounds", "height", u"552");
100 #else
101 assertXPath(pXmlDoc, "/root/page[3]/body/section[1]/infos/bounds", "height", u"532");
102 #endif
103 assertXPath(pXmlDoc, "/root/page[3]", "formatName", u"RueckantwortRechts");
106 // toggle one section hidden and other visible
107 executeMacro(
108 u"vnd.sun.star.script:Standard.Module1.Main?language=Basic&location=document"_ustr);
109 Scheduler::ProcessEventsToIdle();
112 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
113 assertXPath(pXmlDoc, "/root/page", 2);
114 assertXPath(pXmlDoc, "/root/page[1]", "formatName", u"Hotti");
115 assertXPath(pXmlDoc, "/root/page[1]/body/section", 1);
116 assertXPath(pXmlDoc, "/root/page[1]/body/section[1]", "formatName", u"Verfügung");
117 assertXPath(pXmlDoc, "/root/page[2]/body/section", 2);
118 assertXPath(pXmlDoc, "/root/page[2]/body/section[1]", "formatName", u"Verfügung");
119 // should be > 0, no idea why it's different on Windows
120 #ifdef _WIN32
121 assertXPath(pXmlDoc, "/root/page[2]/body/section[1]/infos/bounds", "height", u"552");
122 #else
123 assertXPath(pXmlDoc, "/root/page[2]/body/section[1]/infos/bounds", "height", u"532");
124 #endif
125 assertXPath(pXmlDoc, "/root/page[2]/body/section[2]", "formatName", u"Rueckantwort");
126 assertXPath(pXmlDoc, "/root/page[2]/body/section[2]/infos/bounds", "height", u"0");
127 assertXPath(pXmlDoc, "/root/page[2]", "formatName", u"Folgeseite");
131 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, testSectionPageBreaksWithNestedSectionWithColumns)
133 createSwDoc("section-nested-with-pagebreaks.fodt");
135 auto xTextSectionsSupplier = mxComponent.queryThrow<css::text::XTextSectionsSupplier>();
136 auto xSections = xTextSectionsSupplier->getTextSections();
137 CPPUNIT_ASSERT(xSections);
138 auto xSection1 = xSections->getByName(u"Section1"_ustr).queryThrow<css::beans::XPropertySet>();
139 auto xSection2 = xSections->getByName(u"Section2"_ustr).queryThrow<css::beans::XPropertySet>();
140 CPPUNIT_ASSERT(getProperty<bool>(xSection1, "IsVisible"));
141 CPPUNIT_ASSERT(getProperty<bool>(xSection2, "IsVisible"));
144 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
145 assertXPath(pXmlDoc, "/root/page[1]/body/section", 1);
146 assertXPath(pXmlDoc, "/root/page[1]/body/section[1]/txt", 2);
147 assertXPath(pXmlDoc, "/root/page[2]/body/section", 1);
148 assertXPath(pXmlDoc, "/root/page[2]/body/section[1]/txt", 1);
149 assertXPath(pXmlDoc, "/root/page[2]/body/section[1]/txt/SwParaPortion/SwLineLayout",
150 "portion", u"3");
151 assertXPath(pXmlDoc, "/root/page[3]/body/section", 2);
152 assertXPath(pXmlDoc, "/root/page[3]/body/section[1]/txt", 1);
153 assertXPath(pXmlDoc, "/root/page[3]/body/section[1]/txt/SwParaPortion/SwLineLayout",
154 "portion", u"4");
155 assertXPath(pXmlDoc, "/root/page[3]/body/section[2]/column", 2);
156 assertXPath(pXmlDoc, "/root/page[3]/body/section[2]/column/body/txt", 2);
157 assertXPath(pXmlDoc,
158 "/root/page[3]/body/section[2]/column/body/txt[2]/SwParaPortion/SwLineLayout",
159 "portion", u"6");
160 assertXPath(pXmlDoc, "/root/page[4]/body/section", 2);
161 assertXPath(pXmlDoc, "/root/page[4]/body/section[1]/column/body/txt", 2);
162 assertXPath(pXmlDoc, "/root/page[4]/body/section[1]/column/body/txt", 2);
163 assertXPath(
164 pXmlDoc,
165 "/root/page[4]/body/section[1]/column[1]/body/txt[1]/SwParaPortion/SwLineLayout",
166 "portion", u"7");
167 assertXPath(
168 pXmlDoc,
169 "/root/page[4]/body/section[1]/column[2]/body/txt[1]/SwParaPortion/SwLineLayout",
170 "portion", u"8");
171 assertXPath(pXmlDoc, "/root/page[4]/body/section[2]/txt", 1);
172 assertXPath(pXmlDoc, "/root/page[4]/body/section[2]/txt/SwParaPortion/SwLineLayout",
173 "portion", u"Text following inner section");
174 assertXPath(pXmlDoc, "/root/page[4]/body/txt[1]/SwParaPortion/SwLineLayout", "portion",
175 u"Text following outer section");
178 xSection1->setPropertyValue(u"IsVisible"_ustr, css::uno::Any(false));
179 Scheduler::ProcessEventsToIdle();
182 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
183 assertXPath(pXmlDoc, "/root/page[1]/body/txt", 2);
184 assertXPath(pXmlDoc, "/root/page[1]/body/section", 3);
185 assertXPath(pXmlDoc, "/root/page[1]/body/section[1]/txt", 4);
186 assertXPath(pXmlDoc, "/root/page[1]/body/section[2]/column", 2);
187 assertXPath(pXmlDoc, "/root/page[1]/body/section[2]/column/body/txt", 4);
188 assertXPath(pXmlDoc, "/root/page[1]/body/section[3]/txt", 1);
189 assertXPath(pXmlDoc, "/root/page[1]/body/section[1]/infos/bounds", "height", u"0");
190 assertXPath(pXmlDoc, "/root/page[1]/body/section[2]/infos/bounds", "height", u"0");
191 assertXPath(pXmlDoc, "/root/page[1]/body/section[3]/infos/bounds", "height", u"0");
192 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/SwParaPortion/SwLineLayout", "portion",
193 u"Text following outer section");
196 xSection1->setPropertyValue(u"IsVisible"_ustr, css::uno::Any(true));
197 Scheduler::ProcessEventsToIdle();
200 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
201 assertXPath(pXmlDoc, "/root/page[1]/body/section", 1);
202 assertXPath(pXmlDoc, "/root/page[1]/body/section[1]/txt", 2);
203 assertXPath(pXmlDoc, "/root/page[2]/body/section", 1);
204 assertXPath(pXmlDoc, "/root/page[2]/body/section[1]/txt", 1);
205 assertXPath(pXmlDoc, "/root/page[2]/body/section[1]/txt/SwParaPortion/SwLineLayout",
206 "portion", u"3");
207 assertXPath(pXmlDoc, "/root/page[3]/body/section", 2);
208 assertXPath(pXmlDoc, "/root/page[3]/body/section[1]/txt", 1);
209 assertXPath(pXmlDoc, "/root/page[3]/body/section[1]/txt/SwParaPortion/SwLineLayout",
210 "portion", u"4");
211 assertXPath(pXmlDoc, "/root/page[3]/body/section[2]/column", 2);
212 assertXPath(pXmlDoc, "/root/page[3]/body/section[2]/column/body/txt", 2);
213 assertXPath(pXmlDoc,
214 "/root/page[3]/body/section[2]/column/body/txt[2]/SwParaPortion/SwLineLayout",
215 "portion", u"6");
216 assertXPath(pXmlDoc, "/root/page[4]/body/section", 2);
217 assertXPath(pXmlDoc, "/root/page[4]/body/section[1]/column/body/txt", 2);
218 assertXPath(pXmlDoc, "/root/page[4]/body/section[1]/column/body/txt", 2);
219 assertXPath(
220 pXmlDoc,
221 "/root/page[4]/body/section[1]/column[1]/body/txt[1]/SwParaPortion/SwLineLayout",
222 "portion", u"7");
223 assertXPath(
224 pXmlDoc,
225 "/root/page[4]/body/section[1]/column[2]/body/txt[1]/SwParaPortion/SwLineLayout",
226 "portion", u"8");
227 assertXPath(pXmlDoc, "/root/page[4]/body/section[2]/txt", 1);
228 assertXPath(pXmlDoc, "/root/page[4]/body/section[2]/txt/SwParaPortion/SwLineLayout",
229 "portion", u"Text following inner section");
230 assertXPath(pXmlDoc, "/root/page[4]/body/txt[1]/SwParaPortion/SwLineLayout", "portion",
231 u"Text following outer section");
234 xSection2->setPropertyValue(u"IsVisible"_ustr, css::uno::Any(false));
235 Scheduler::ProcessEventsToIdle();
238 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
239 assertXPath(pXmlDoc, "/root/page[1]/body/section", 1);
240 assertXPath(pXmlDoc, "/root/page[1]/body/section[1]/txt", 2);
241 assertXPath(pXmlDoc, "/root/page[2]/body/section", 1);
242 assertXPath(pXmlDoc, "/root/page[2]/body/section[1]/txt", 1);
243 assertXPath(pXmlDoc, "/root/page[2]/body/section[1]/txt/SwParaPortion/SwLineLayout",
244 "portion", u"3");
245 assertXPath(pXmlDoc, "/root/page[3]/body/section", 3);
246 assertXPath(pXmlDoc, "/root/page[3]/body/section[1]/txt", 1);
247 assertXPath(pXmlDoc, "/root/page[3]/body/section[1]/txt/SwParaPortion/SwLineLayout",
248 "portion", u"4");
249 assertXPath(pXmlDoc, "/root/page[3]/body/section[2]/column", 2);
250 assertXPath(pXmlDoc, "/root/page[3]/body/section[2]/column/body/txt", 4);
251 assertXPath(pXmlDoc, "/root/page[3]/body/section[2]/infos/bounds", "height", u"0");
252 assertXPath(pXmlDoc, "/root/page[3]/body/section[3]/txt", 1);
253 assertXPath(pXmlDoc, "/root/page[3]/body/section[3]/txt/SwParaPortion/SwLineLayout",
254 "portion", u"Text following inner section");
255 assertXPath(pXmlDoc, "/root/page[3]/body/txt[1]/SwParaPortion/SwLineLayout", "portion",
256 u"Text following outer section");
259 xSection2->setPropertyValue(u"IsVisible"_ustr, css::uno::Any(true));
260 Scheduler::ProcessEventsToIdle();
263 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
264 assertXPath(pXmlDoc, "/root/page[1]/body/section", 1);
265 assertXPath(pXmlDoc, "/root/page[1]/body/section[1]/txt", 2);
266 assertXPath(pXmlDoc, "/root/page[2]/body/section", 1);
267 assertXPath(pXmlDoc, "/root/page[2]/body/section[1]/txt", 1);
268 assertXPath(pXmlDoc, "/root/page[2]/body/section[1]/txt/SwParaPortion/SwLineLayout",
269 "portion", u"3");
270 assertXPath(pXmlDoc, "/root/page[3]/body/section", 2);
271 assertXPath(pXmlDoc, "/root/page[3]/body/section[1]/txt", 1);
272 assertXPath(pXmlDoc, "/root/page[3]/body/section[1]/txt/SwParaPortion/SwLineLayout",
273 "portion", u"4");
274 assertXPath(pXmlDoc, "/root/page[3]/body/section[2]/column", 2);
275 assertXPath(pXmlDoc, "/root/page[3]/body/section[2]/column/body/txt", 2);
276 assertXPath(pXmlDoc,
277 "/root/page[3]/body/section[2]/column/body/txt[2]/SwParaPortion/SwLineLayout",
278 "portion", u"6");
279 assertXPath(pXmlDoc, "/root/page[4]/body/section", 2);
280 assertXPath(pXmlDoc, "/root/page[4]/body/section[1]/column/body/txt", 2);
281 assertXPath(pXmlDoc, "/root/page[4]/body/section[1]/column/body/txt", 2);
282 assertXPath(
283 pXmlDoc,
284 "/root/page[4]/body/section[1]/column[1]/body/txt[1]/SwParaPortion/SwLineLayout",
285 "portion", u"7");
286 assertXPath(
287 pXmlDoc,
288 "/root/page[4]/body/section[1]/column[2]/body/txt[1]/SwParaPortion/SwLineLayout",
289 "portion", u"8");
290 assertXPath(pXmlDoc, "/root/page[4]/body/section[2]/txt", 1);
291 assertXPath(pXmlDoc, "/root/page[4]/body/section[2]/txt/SwParaPortion/SwLineLayout",
292 "portion", u"Text following inner section");
293 assertXPath(pXmlDoc, "/root/page[4]/body/txt[1]/SwParaPortion/SwLineLayout", "portion",
294 u"Text following outer section");
298 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, testTdf156725)
300 createSwDoc("tdf156725.fodt");
302 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
303 assertXPath(pXmlDoc, "/root/page", 2);
304 // the fly has 2 columns, the section in it has 2 columns, and is split
305 // across the fly columns => 4 columns with 1 text frame each
306 assertXPath(pXmlDoc, "/root/page[2]/body/txt/anchored/fly/column", 2);
307 assertXPath(pXmlDoc, "/root/page[2]/body/txt/anchored/fly/column[1]/body/section/column", 2);
308 assertXPath(pXmlDoc,
309 "/root/page[2]/body/txt/anchored/fly/column[1]/body/section/column[1]/body/txt", 1);
310 assertXPath(pXmlDoc,
311 "/root/page[2]/body/txt/anchored/fly/column[1]/body/section/column[2]/body/txt", 1);
312 assertXPath(pXmlDoc, "/root/page[2]/body/txt/anchored/fly/column[2]/body/section/column", 2);
313 assertXPath(pXmlDoc,
314 "/root/page[2]/body/txt/anchored/fly/column[2]/body/section/column[1]/body/txt", 1);
315 assertXPath(pXmlDoc,
316 "/root/page[2]/body/txt/anchored/fly/column[2]/body/section/column[2]/body/txt", 1);
319 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, testTdf156419)
321 createSwDoc("linked_frames_section_bug.odt");
323 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
324 assertXPath(pXmlDoc, "/root/page", 2);
325 // there are 2 flys on page 1, and 1 on page 2, all linked
326 assertXPath(pXmlDoc, "/root/page[1]/body/txt/anchored/fly[1]/section/column", 2);
327 assertXPath(pXmlDoc, "/root/page[1]/body/txt/anchored/fly[1]/section/column[1]/body/txt", 11);
328 assertXPath(pXmlDoc, "/root/page[1]/body/txt/anchored/fly[1]/section/column[2]/body/txt", 11);
329 assertXPath(pXmlDoc, "/root/page[1]/body/txt/anchored/fly[2]/section/column", 2);
330 assertXPath(pXmlDoc, "/root/page[1]/body/txt/anchored/fly[2]/section/column[1]/body/txt", 12);
331 assertXPath(pXmlDoc, "/root/page[1]/body/txt/anchored/fly[2]/section/column[2]/body/txt", 12);
332 assertXPath(pXmlDoc, "/root/page[2]/body/txt/anchored/fly[1]/section/column", 2);
333 assertXPath(pXmlDoc, "/root/page[2]/body/txt/anchored/fly[1]/section/column[1]/body/txt", 2);
334 assertXPath(pXmlDoc, "/root/page[2]/body/txt/anchored/fly[1]/section/column[2]/body/txt", 1);
337 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, testTdf145826)
339 createSwDoc("tdf145826.odt");
340 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
341 CPPUNIT_ASSERT(pXmlDoc);
343 assertXPath(pXmlDoc, "/root/page/body/section/column", 2);
345 // Without the fix in place, this test would have failed with
346 // - Expected: 1
347 // - Actual : 0
348 assertXPath(pXmlDoc, "/root/page/body/section/column[1]/ftncont", 1);
349 assertXPath(pXmlDoc, "/root/page/body/section/column[2]/ftncont", 1);
350 assertXPath(pXmlDoc, "/root/page/body/section/column[1]/ftncont/ftn", 3);
351 assertXPath(pXmlDoc, "/root/page/body/section/column[2]/ftncont/ftn", 3);
354 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, testTable0HeightRows)
356 createSwDoc("table-0-height-rows.fodt");
358 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
359 CPPUNIT_ASSERT(pXmlDoc);
361 // the problem was that the table was erroneously split across 2 or 3 pages
362 assertXPath(pXmlDoc, "/root/page[1]/body/tab", 1);
363 assertXPath(pXmlDoc, "/root/page[1]/body/tab/row", 28);
364 assertXPath(pXmlDoc, "/root/page[1]/body/tab/row/infos/bounds[@height='0']", 25);
365 assertXPath(pXmlDoc, "/root/page", 1);
368 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, testTdf105481)
370 createSwDoc("tdf105481.odt");
371 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
372 CPPUNIT_ASSERT(pXmlDoc);
374 // Without the accompanying fix in place, this test would have failed
375 // because the vertical position of the as-char shape object and the
376 // as-char math object will be wrong (below/beyond the text frame's bottom).
378 SwTwips nTxtTop = getXPath(pXmlDoc,
379 "/root/page/anchored/fly/txt[2]"
380 "/infos/bounds",
381 "top")
382 .toInt32();
383 SwTwips nTxtBottom = nTxtTop
384 + getXPath(pXmlDoc,
385 "/root/page/anchored/fly/txt[2]"
386 "/infos/bounds",
387 "height")
388 .toInt32();
390 SwTwips nFormula1Top = getXPath(pXmlDoc,
391 "/root/page/anchored/fly/txt[2]"
392 "/anchored/fly[1]/infos/bounds",
393 "top")
394 .toInt32();
395 SwTwips nFormula1Bottom = nFormula1Top
396 + getXPath(pXmlDoc,
397 "/root/page/anchored/fly/txt[2]"
398 "/anchored/fly[1]/infos/bounds",
399 "height")
400 .toInt32();
402 SwTwips nFormula2Top = getXPath(pXmlDoc,
403 "/root/page/anchored/fly/txt[2]"
404 "/anchored/fly[2]/infos/bounds",
405 "top")
406 .toInt32();
407 SwTwips nFormula2Bottom = nFormula2Top
408 + getXPath(pXmlDoc,
409 "/root/page/anchored/fly/txt[2]"
410 "/anchored/fly[2]/infos/bounds",
411 "height")
412 .toInt32();
414 // Ensure that the two formula positions are at least between top and bottom of the text frame.
415 // The below two are satisfied even without the fix.
416 CPPUNIT_ASSERT_GREATEREQUAL(nTxtTop, nFormula1Top);
417 CPPUNIT_ASSERT_GREATEREQUAL(nTxtTop, nFormula2Top);
419 // Without the accompanying fix in place, this test would have failed with:
420 // - Expected less than or equal to : 14423
421 // - Actual : 14828
422 // that is, the formula is below the text-frame's y bound.
423 CPPUNIT_ASSERT_LESSEQUAL(nTxtBottom, nFormula1Bottom);
424 // Similarly for formula # 2 :
425 // - Expected less than or equal to : 14423
426 // - Actual : 15035
427 // that is, the formula is below the text-frame's y bound.
428 CPPUNIT_ASSERT_LESSEQUAL(nTxtBottom, nFormula2Bottom);
431 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, testTdf117982)
433 createSwDoc("tdf117982.docx");
434 SwDocShell* pShell = getSwDocShell();
435 std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
436 MetafileXmlDump dumper;
437 xmlDocUniquePtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
438 assertXPathContent(pXmlDoc, "/metafile/push[1]/push[1]/push[1]/textarray[1]/text", u"FOO AAA");
439 //The first cell must be "FOO AAA". If not, this means the first cell content not visible in
440 //the source document.
443 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, testTdf128959)
445 // no orphan/widow control in table cells
446 createSwDoc("tdf128959.docx");
447 SwDoc* pDoc = getSwDoc();
448 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
450 // first two lines of the paragraph in the split table cell on the first page
451 // (these lines were completely lost)
452 assertXPath(
453 pXmlDoc, "/root/page[1]/body/tab[1]/row[1]/cell[1]/txt[1]/SwParaPortion/SwLineLayout[1]",
454 "portion",
455 u"Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas porttitor congue ");
456 assertXPath(
457 pXmlDoc, "/root/page[1]/body/tab[1]/row[1]/cell[1]/txt[1]/SwParaPortion/SwLineLayout[2]",
458 "portion",
459 u"massa. Fusce posuere, magna sed pulvinar ultricies, purus lectus malesuada libero, sit ");
460 // last line of the paragraph in the split table cell on the second page
461 assertXPath(pXmlDoc,
462 "/root/page[2]/body/tab[1]/row[1]/cell[1]/txt[1]/SwParaPortion/SwLineLayout[1]",
463 "portion", u"amet commodo magna eros quis urna.");
465 // Also check that the widow control for the paragraph is not turned off:
466 sw::TableFrameFormats& rTableFormats = *pDoc->GetTableFrameFormats();
467 SwFrameFormat* pTableFormat = rTableFormats[0];
468 SwTable* pTable = SwTable::FindTable(pTableFormat);
469 const SwTableBox* pCell = pTable->GetTableBox(u"A1"_ustr);
470 const SwStartNode* pStartNode = pCell->GetSttNd();
471 SwNodeIndex aNodeIndex(*pStartNode);
472 ++aNodeIndex;
473 const SwTextNode* pTextNode = aNodeIndex.GetNode().GetTextNode();
474 // Without the accompanying fix in place, this test would have failed with:
475 // - Expected: 2
476 // - Actual : 0
477 // i.e. the original fix only worked as the entire widow / orphan control was switched off.
478 CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(pTextNode->GetSwAttrSet().GetWidows().GetValue()));
481 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, testTdf121658)
483 uno::Reference<linguistic2::XHyphenator> xHyphenator = LinguMgr::GetHyphenator();
484 if (!xHyphenator->hasLocale(lang::Locale(u"en"_ustr, u"US"_ustr, OUString())))
485 return;
487 createSwDoc("tdf121658.odt");
488 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
490 // Only 2 hyphenated words should appear in the document (in the lowercase words).
491 // Uppercase words should not be hyphenated.
492 assertXPath(pXmlDoc, "//SwLineLayout/child::*[@type='PortionType::Hyphen']", 2);
495 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, testTdf149420)
497 uno::Reference<linguistic2::XHyphenator> xHyphenator = LinguMgr::GetHyphenator();
498 if (!xHyphenator->hasLocale(lang::Locale(u"en"_ustr, u"US"_ustr, OUString())))
499 return;
501 createSwDoc("tdf149420.odt");
502 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
504 // Only 3 hyphenated words should appear in the document (last paragraph
505 // has got a 1 cm hyphenation zone, removing two hyphenations, which visible
506 // in the second paragraph).
507 assertXPath(pXmlDoc, "//SwLineLayout/child::*[@type='PortionType::Hyphen']", 8);
510 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, testTdf149324)
512 uno::Reference<linguistic2::XHyphenator> xHyphenator = LinguMgr::GetHyphenator();
513 if (!xHyphenator->hasLocale(lang::Locale(u"en"_ustr, u"US"_ustr, OUString())))
514 return;
516 createSwDoc("tdf149324.odt");
517 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
519 // Only 3 hyphenated words should appear in the document (last paragraph
520 // has got a 7-character word limit for hyphenation, removing the
521 // hyphenation "ex-cept".
522 assertXPath(pXmlDoc, "//SwLineLayout/child::*[@type='PortionType::Hyphen']", 3);
525 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, testTdf149248)
527 uno::Reference<linguistic2::XHyphenator> xHyphenator = LinguMgr::GetHyphenator();
528 if (!xHyphenator->hasLocale(lang::Locale(u"en"_ustr, u"US"_ustr, OUString())))
529 return;
531 createSwDoc("tdf149248.odt");
532 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
534 // Only 1 hyphenated word should appear in the document (last word of the second
535 // paragraph). Last word should not be hyphenated for the fourth paragraph
536 // (the same paragraph, but with forbidden hyphenation of the last word).
537 assertXPath(pXmlDoc, "//SwLineLayout/child::*[@type='PortionType::Hyphen']", 1);
540 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, testWriterImageNoCapture)
542 createSwDoc("writer-image-no-capture.docx");
543 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
544 CPPUNIT_ASSERT(pXmlDoc);
545 sal_Int32 nPageLeft = getXPath(pXmlDoc, "//page/infos/bounds", "left").toInt32();
546 sal_Int32 nImageLeft = getXPath(pXmlDoc, "//anchored/fly/infos/bounds", "left").toInt32();
547 // Without the accompanying fix in place, this test would have failed with:
548 // - Expected less than: 284
549 // - Actual : 284
550 // i.e. the image position was modified to be inside the page frame ("captured"), even if Word
551 // does not do that.
552 CPPUNIT_ASSERT_LESS(nPageLeft, nImageLeft);
555 SwRect lcl_getVisibleFlyObjRect(SwWrtShell* pWrtShell)
557 SwRootFrame* pRoot = pWrtShell->GetLayout();
558 SwPageFrame* pPage = static_cast<SwPageFrame*>(pRoot->GetLower());
559 pPage = static_cast<SwPageFrame*>(pPage->GetNext());
560 pPage = static_cast<SwPageFrame*>(pPage->GetNext());
561 SwSortedObjs* pDrawObjs = pPage->GetDrawObjs();
562 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pDrawObjs->size());
563 SwAnchoredObject* pDrawObj = (*pDrawObjs)[0];
564 CPPUNIT_ASSERT_EQUAL(u"Rahmen8"_ustr, pDrawObj->GetFrameFormat()->GetName());
565 pPage = static_cast<SwPageFrame*>(pPage->GetNext());
566 pDrawObjs = pPage->GetDrawObjs();
567 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pDrawObjs->size());
568 pDrawObj = (*pDrawObjs)[0];
569 CPPUNIT_ASSERT_EQUAL(u"Rahmen123"_ustr, pDrawObj->GetFrameFormat()->GetName());
570 SwRect aFlyRect = pDrawObj->GetObjRect();
571 CPPUNIT_ASSERT(pPage->getFrameArea().Contains(aFlyRect));
572 return aFlyRect;
575 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, testStableAtPageAnchoredFlyPosition)
577 // this doc has two page-anchored frames: one tiny on page 3 and one large on page 4.
578 // it also has a style:master-page named "StandardEntwurf", which contains some fields.
579 // if you add a break to page 2, or append some text to page 4 (or just toggle display field names),
580 // the page anchored frame on page 4 vanishes, as it is incorrectly moved out of the page bounds.
581 createSwDoc("stable-at-page-anchored-fly-position.odt");
582 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
584 // look up the layout position of the page-bound frame on page four
585 SwRect aOrigRect = lcl_getVisibleFlyObjRect(pWrtShell);
587 // append some text to the document to trigger bug / relayout
588 pWrtShell->SttEndDoc(false);
589 pWrtShell->Insert(u"foo"_ustr);
591 // get the current position of the frame on page four
592 SwRect aRelayoutRect = lcl_getVisibleFlyObjRect(pWrtShell);
594 // the anchored frame should not have moved
595 CPPUNIT_ASSERT_EQUAL(aOrigRect, aRelayoutRect);
598 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, testTdf134548)
600 createSwDoc("tdf134548.odt");
601 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
603 // Second paragraph has two non zero width tabs in beginning of line
605 OUString sNodeType = getXPath(
606 pXmlDoc, "/root/page/body/txt[2]/SwParaPortion/SwLineLayout/SwFixPortion[1]", "type");
607 CPPUNIT_ASSERT_EQUAL(u"PortionType::TabLeft"_ustr, sNodeType);
608 sal_Int32 nWidth
609 = getXPath(pXmlDoc, "/root/page/body/txt[2]/SwParaPortion/SwLineLayout/SwFixPortion[1]",
610 "width")
611 .toInt32();
612 CPPUNIT_ASSERT_GREATER(sal_Int32(0), nWidth);
615 OUString sNodeType = getXPath(
616 pXmlDoc, "/root/page/body/txt[2]/SwParaPortion/SwLineLayout/SwFixPortion[2]", "type");
617 CPPUNIT_ASSERT_EQUAL(u"PortionType::TabLeft"_ustr, sNodeType);
618 sal_Int32 nWidth
619 = getXPath(pXmlDoc, "/root/page/body/txt[2]/SwParaPortion/SwLineLayout/SwFixPortion[2]",
620 "width")
621 .toInt32();
622 CPPUNIT_ASSERT_GREATER(sal_Int32(0), nWidth);
626 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, testTdf124423)
628 createSwDoc("tdf124423.docx");
629 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
630 sal_Int32 nFly1Width
631 = getXPath(pXmlDoc, "(//anchored/fly)[1]/infos/prtBounds", "width").toInt32();
632 sal_Int32 nFly2Width
633 = getXPath(pXmlDoc, "(//anchored/fly)[2]/infos/prtBounds", "width").toInt32();
634 sal_Int32 nPageWidth = getXPath(pXmlDoc, "//page/infos/prtBounds", "width").toInt32();
635 CPPUNIT_ASSERT_EQUAL(nPageWidth, nFly2Width);
636 CPPUNIT_ASSERT_LESS(nPageWidth / 2, nFly1Width);
638 createSwDoc("tdf124423.odt");
639 pXmlDoc = parseLayoutDump();
640 nFly1Width = getXPath(pXmlDoc, "(//anchored/fly)[1]/infos/prtBounds", "width").toInt32();
641 nFly2Width = getXPath(pXmlDoc, "(//anchored/fly)[2]/infos/prtBounds", "width").toInt32();
642 nPageWidth = getXPath(pXmlDoc, "//page/infos/prtBounds", "width").toInt32();
643 CPPUNIT_ASSERT_LESS(nPageWidth / 2, nFly2Width);
644 CPPUNIT_ASSERT_LESS(nPageWidth / 2, nFly1Width);
647 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, testTdf137185)
649 // First load the sample bugdoc
650 createSwDoc("tdf137185.odt");
651 // Get the doc shell
652 SwDoc* pDoc(getSwDoc());
654 // Get the DrawObject from page
655 auto pModel = pDoc->getIDocumentDrawModelAccess().GetDrawModel();
656 CPPUNIT_ASSERT(pModel);
657 auto pPage = pModel->GetPage(0);
658 CPPUNIT_ASSERT(pPage);
659 auto pObj = pPage->GetObj(0);
660 CPPUNIT_ASSERT(pObj);
662 // Get the format of the draw object
663 auto pShape = FindFrameFormat(pObj);
664 CPPUNIT_ASSERT(pShape);
666 // Check the text of the shape
667 uno::Reference<text::XText> xTxt(getShape(1), uno::UNO_QUERY);
668 CPPUNIT_ASSERT_EQUAL(u"Align me!"_ustr, xTxt->getText()->getString());
670 // Add a textbox to the shape
671 SwTextBoxHelper::create(pShape, pShape->FindRealSdrObject(), true);
673 // Check if the text moved from the shape to the frame
674 auto pFormat = SwTextBoxHelper::getOtherTextBoxFormat(getShape(1));
675 auto xTextFrame = SwXTextFrame::CreateXTextFrame(*pFormat->GetDoc(), pFormat);
677 CPPUNIT_ASSERT_EQUAL(u"Align me!"_ustr, xTextFrame->getText()->getString());
678 SdrTextObj* pTextObj = DynCastSdrTextObj(pObj);
679 CPPUNIT_ASSERT(pTextObj);
680 const auto& aOutStr = pTextObj->GetOutlinerParaObject()->GetTextObject();
682 CPPUNIT_ASSERT(aOutStr.GetText(0).isEmpty());
683 // Before the patch it failed, because the text appeared 2 times on each other.
686 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, testTdf138782)
688 createSwDoc("tdf138782.docx");
689 auto pXml = parseLayoutDump();
690 CPPUNIT_ASSERT(pXml);
692 // Without the fix it failed because the 3rd shape was outside the page:
693 // - Expected less than: 13327
694 // - Actual : 14469
696 CPPUNIT_ASSERT_LESS(
697 getXPath(pXml, "/root/page/infos/bounds", "right").toInt32(),
698 getXPath(pXml, "/root/page/body/txt[8]/anchored/SwAnchoredDrawObject/bounds", "right")
699 .toInt32());
702 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, testTdf135035)
704 createSwDoc("tdf135035.docx");
705 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
706 sal_Int32 nFly1Width
707 = getXPath(pXmlDoc, "(//anchored/fly)[1]/infos/prtBounds", "width").toInt32();
708 sal_Int32 nFly2Width
709 = getXPath(pXmlDoc, "(//anchored/fly)[2]/infos/prtBounds", "width").toInt32();
710 sal_Int32 nFly3Width
711 = getXPath(pXmlDoc, "(//anchored/fly)[3]/infos/prtBounds", "width").toInt32();
712 sal_Int32 nParentWidth = getXPath(pXmlDoc, "(//txt)[1]/infos/prtBounds", "width").toInt32();
713 CPPUNIT_ASSERT_EQUAL(nParentWidth, nFly2Width);
714 CPPUNIT_ASSERT_EQUAL(nParentWidth, nFly3Width);
715 CPPUNIT_ASSERT_LESS(nParentWidth / 2, nFly1Width);
717 createSwDoc("tdf135035.odt");
718 pXmlDoc = parseLayoutDump();
719 nFly1Width = getXPath(pXmlDoc, "(//anchored/fly)[1]/infos/prtBounds", "width").toInt32();
720 nFly2Width = getXPath(pXmlDoc, "(//anchored/fly)[2]/infos/prtBounds", "width").toInt32();
721 nFly3Width = getXPath(pXmlDoc, "(//anchored/fly)[3]/infos/prtBounds", "width").toInt32();
722 nParentWidth = getXPath(pXmlDoc, "(//txt)[1]/infos/prtBounds", "width").toInt32();
723 CPPUNIT_ASSERT_LESS(nParentWidth / 2, nFly2Width);
724 CPPUNIT_ASSERT_LESS(nParentWidth / 2, nFly1Width);
725 CPPUNIT_ASSERT_GREATER(nParentWidth, nFly3Width);
728 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, testTdf146704_EndnoteInSection)
730 createSwDoc("tdf146704_EndnoteInSection.odt");
731 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
732 // Without the fix, the endnote placed to 2. page
733 assertXPath(pXmlDoc, "/root/page", 1);
736 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, testTdf139336_ColumnsWithFootnoteDoNotOccupyEntirePage)
738 createSwDoc("tdf139336_ColumnsWithFootnoteDoNotOccupyEntirePage.docx");
739 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
740 // Without the fix, it would be 5 pages, but with the fix the whole document
741 // would fit into 1 page, but it will be 2 pages right now, because
742 // when writer import (from docx) the last section with columns, then it does not set
743 // the evenly distributed settings, and this settings is required for the fix now, to
744 // avoid some regression.
745 assertXPath(pXmlDoc, "/root/page", 2);
748 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, testTdf54465_ColumnsWithFootnoteDoNotOccupyEntirePage)
750 // Old odt files should keep their original layout, as it was before Tdf139336 fix.
751 // The new odt file is only 1 page long, while the old odt file (with the same content)
752 // was more than 1 page long.
753 // Note: Somewhy this test miscalculates the layout of the old odt file.
754 // It will be 4 pages long, while opened in Writer it is 5 pages long.
755 createSwDoc("tdf54465_ColumnsWithFootnoteDoNotOccupyEntirePage_Old.odt");
756 Scheduler::ProcessEventsToIdle();
757 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
758 xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "/root/page");
759 xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
760 CPPUNIT_ASSERT_GREATER(1, xmlXPathNodeSetGetLength(pXmlNodes));
761 xmlXPathFreeObject(pXmlObj);
763 createSwDoc("tdf54465_ColumnsWithFootnoteDoNotOccupyEntirePage_New.odt");
764 pXmlDoc = parseLayoutDump();
765 assertXPath(pXmlDoc, "/root/page", 1);
768 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, testTdf138124)
770 // When the only portion after the footnote number is a FlyCnt, and it doesn't fit into
771 // the page width, it should be moved to the next line without the footnote number, and
772 // not loop, nor OOM, nor fail assertions.
774 createSwDoc("wideBoxInFootnote.fodt");
775 Scheduler::ProcessEventsToIdle();
777 // Without the fix in place, the layout would loop, creating new FootnoteNum portions
778 // indefinitely, until OOM.
779 // If the footnote paragraph had no orphan control, then the loop would finally end,
780 // but an assertion in SwTextPainter::DrawTextLine would fail during paint.
782 xmlDocUniquePtr pXml = parseLayoutDump();
783 assertXPath(pXml, "/root/page", 1);
784 assertXPath(pXml, "/root/page/ftncont/ftn/txt/anchored", 1);
786 // And finally, if there were no assertion in SwTextPainter::DrawTextLine, it would have
787 // produced multiple lines with FootnoteNum portions, failing the following check like
788 // - Expected: 1
789 // - Actual : 49
791 assertXPath(pXml,
792 "/root/page/ftncont/ftn/txt//SwFieldPortion[@type='PortionType::FootnoteNum']", 1);
793 assertXPath(pXml, "/root/page/ftncont/ftn/txt//SwLinePortion[@type='PortionType::FlyCnt']", 1);
796 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, TestTdf161348)
798 createSwDoc("fdo48718-1.docx");
800 xmlDocUniquePtr pXml = parseLayoutDump();
802 // the floating table is on page 1
803 // apparently both parts of the split table are on this text frame
804 assertXPath(pXml, "/root/page[1]/body/txt[2]/anchored/fly", 2);
805 assertXPath(pXml, "/root/page[1]/body/txt[2]/anchored/fly/tab", 2);
808 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, testTdf154113)
810 createSwDoc("three_sections.fodt");
811 Scheduler::ProcessEventsToIdle();
813 dispatchCommand(mxComponent, u".uno:GoToStartOfDoc"_ustr, {});
814 dispatchCommand(mxComponent, u".uno:GoToNextPara"_ustr, {});
815 dispatchCommand(mxComponent, u".uno:EndOfDocumentSel"_ustr,
816 {}); // to the end of current section!
817 dispatchCommand(mxComponent, u".uno:EndOfDocumentSel"_ustr, {}); // to the end of the document.
819 auto xModel = mxComponent.queryThrow<frame::XModel>();
820 auto xSelected = xModel->getCurrentSelection().queryThrow<container::XIndexAccess>();
821 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xSelected->getCount());
822 auto xRange = xSelected->getByIndex(0).queryThrow<text::XTextRange>();
823 CPPUNIT_ASSERT_EQUAL(u"<-- Start selection here. Section1" SAL_NEWLINE_STRING
824 "Section2" SAL_NEWLINE_STRING "Section3. End selection here -->"_ustr,
825 xRange->getString());
827 dispatchCommand(mxComponent, u".uno:Cut"_ustr, {});
829 xSelected = xModel->getCurrentSelection().queryThrow<container::XIndexAccess>();
830 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xSelected->getCount());
831 xRange = xSelected->getByIndex(0).queryThrow<text::XTextRange>();
832 CPPUNIT_ASSERT_EQUAL(OUString(), xRange->getString());
834 dispatchCommand(mxComponent, u".uno:Paste"_ustr, {});
836 xmlDocUniquePtr pXml = parseLayoutDump();
838 // Without the fix in place, this would fail with
839 // - Expected: 3
840 // - Actual : 2
841 assertXPath(pXml, "/root/page/body/section", 3);
842 assertXPath(pXml, "/root/page/body/section[1]/txt/SwParaPortion/SwLineLayout", "portion",
843 u"<-- Start selection here. Section1");
844 assertXPath(pXml, "/root/page/body/section[2]/txt/SwParaPortion/SwLineLayout", "portion",
845 u"Section2");
846 assertXPath(pXml, "/root/page/body/section[3]/txt/SwParaPortion/SwLineLayout", "portion",
847 u"Section3. End selection here -->");
850 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, testTdf155611)
852 createSwDoc("tdf155611_table_and_nested_section.fodt");
853 Scheduler::ProcessEventsToIdle();
855 xmlDocUniquePtr pXml = parseLayoutDump();
856 CPPUNIT_ASSERT(pXml);
858 // Check the layout: single page, two section frames (no section frames after the one for Inner
859 // section), correct table structure and content in the first section frame, including nested
860 // table in the last cell, and the last section text.
861 assertXPath(pXml, "/root/page");
862 // Without the fix in place, this would fail with
863 // - Expected: 2
864 // - Actual : 3
865 assertXPath(pXml, "/root/page/body/section", 2);
866 assertXPath(pXml, "/root/page/body/section[1]/tab");
867 assertXPath(pXml, "/root/page/body/section[1]/tab/row");
868 assertXPath(pXml, "/root/page/body/section[1]/tab/row/cell", 2);
869 assertXPath(pXml, "/root/page/body/section[1]/tab/row/cell[1]/txt/SwParaPortion/SwLineLayout/"
870 "SwParaPortion[@portion='foo']");
871 assertXPath(pXml, "/root/page/body/section[1]/tab/row/cell[2]/txt/SwParaPortion/SwLineLayout/"
872 "SwParaPortion[@portion='bar']");
873 assertXPath(pXml, "/root/page/body/section[1]/tab/row/cell[2]/tab/row/cell/txt/SwParaPortion/"
874 "SwLineLayout/SwParaPortion[@portion='baz']");
875 assertXPath(pXml, "/root/page/body/section[2]/txt[1]/SwParaPortion/SwLineLayout/"
876 "SwParaPortion[@portion='abc']");
878 // Also must not crash on close because of a frame that accidentally fell off of the layout
881 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, testTdf152307)
883 // Problem: On a given Writer document a table layout changed
884 // after doing Tools -> Update -> Update All. The last table row on page 13
885 // was bigger than the page size allowed and thus was hidden behind the footer.
887 // load the document
888 createSwDoc("tdf152307.odt");
890 // do Tools -> Update -> Update All
891 dispatchCommand(mxComponent, u".uno:UpdateAllIndexes"_ustr, {});
893 // XML dump and some basic assertions
894 sal_Int32 nPage = 7, nPages = 0;
895 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
896 nPages = countXPathNodes(pXmlDoc, "/root/page");
897 CPPUNIT_ASSERT_MESSAGE("tdf152307.odt / testTdf152307: Not enough pages.", nPage < nPages);
898 assertXPath(pXmlDoc, "/root/page[" + OString::number(nPage) + "]/body/section", 1);
900 // Actual test procedure:
901 // On page 7, check:
902 // How much tables do we have? How much rows does the last table have?
903 int nTables
904 = countXPathNodes(pXmlDoc, "/root/page[" + OString::number(nPage) + "]/body/section/tab");
905 int nRowsLastTable
906 = countXPathNodes(pXmlDoc, "/root/page[" + OString::number(nPage) + "]/body/section/tab["
907 + OString::number(nTables) + "]/row");
908 // What is the bottom value of the last table row?
909 sal_Int32 nTabBottom = getXPath(pXmlDoc,
910 "/root/page[" + OString::number(nPage) + "]/body/section/tab["
911 + OString::number(nTables) + "]/row["
912 + OString::number(nRowsLastTable) + "]/infos/bounds",
913 "bottom")
914 .toInt32();
915 // Where does the footer start (footer/info/bounds/top)?
916 sal_Int32 nFooterTop
917 = getXPath(pXmlDoc, "/root/page[" + OString::number(nPage) + "]/footer/infos/bounds", "top")
918 .toInt32();
919 // Is the bottom value of the last row above the top value of the footer?
920 OString aMsg = "tdf152307.odt / testTdf152307: Bottom value of last table row on page "
921 + OString::number(nPage) + " is below top value of footer: "
922 + OString::number(nTabBottom) + " > " + OString::number(nFooterTop);
923 CPPUNIT_ASSERT_MESSAGE(aMsg.getStr(), nTabBottom < nFooterTop);
926 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, testTdf57187_Tdf158900)
928 // Given a document with a single paragraph, having some long space runs and line breaks
929 createSwDoc("space+break.fodt");
930 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
931 // Make sure there is only one page, one paragraph, and five lines
932 assertXPath(pXmlDoc, "/root/page", 1);
933 assertXPath(pXmlDoc, "/root/page/body/txt/SwParaPortion", 1);
934 // Without the fix in place, this would fail: there used to be 6 lines
935 assertXPath(pXmlDoc, "/root/page/body/txt/SwParaPortion/SwLineLayout", 5);
937 // tdf#57187: Check that relatively short lines have spaces not participating in layout.
938 // First line has 11 spaces in the end, and then a manual line break. It is rather short:
939 // without block justification, it is narrower than the available space.
940 // It uses the "first check if everything fits to line" return path in SwTextGuess::Guess.
941 // Check that the spaces are put into a Hole portion, thus not participating in layout.
942 // Without the fix, this would fail: there were only 2 portions, no Hole nor Margin portions.
943 assertXPath(pXmlDoc, "/root/page/body/txt/SwParaPortion/SwLineLayout[1]/*", 4);
944 assertXPath(pXmlDoc, "/root/page/body/txt/SwParaPortion/SwLineLayout[1]/*[1]", "type",
945 u"PortionType::Text");
946 assertXPath(pXmlDoc, "/root/page/body/txt/SwParaPortion/SwLineLayout[1]/*[1]", "length", u"11");
947 assertXPath(pXmlDoc, "/root/page/body/txt/SwParaPortion/SwLineLayout[1]/*[2]", "type",
948 u"PortionType::Hole");
949 assertXPath(pXmlDoc, "/root/page/body/txt/SwParaPortion/SwLineLayout[1]/*[2]", "length", u"11");
950 assertXPath(pXmlDoc, "/root/page/body/txt/SwParaPortion/SwLineLayout[1]/*[3]", "type",
951 u"PortionType::Break");
952 assertXPath(pXmlDoc, "/root/page/body/txt/SwParaPortion/SwLineLayout[1]/*[4]", "type",
953 u"PortionType::Margin");
954 // Second line has 101 spaces in the end, and then a manual line break.
955 // It uses the "second check if everything fits to line" return path in SwTextGuess::Guess.
956 // Check that the spaces are put into a Hole portion, thus not participating in layout.
957 // Without the fix, this would fail: there were only 2 portions, no Hole portion.
958 assertXPath(pXmlDoc, "/root/page/body/txt/SwParaPortion/SwLineLayout[2]/*", 3);
959 assertXPath(pXmlDoc, "/root/page/body/txt/SwParaPortion/SwLineLayout[2]/*[1]", "type",
960 u"PortionType::Text");
961 assertXPath(pXmlDoc, "/root/page/body/txt/SwParaPortion/SwLineLayout[2]/*[1]", "length", u"11");
962 assertXPath(pXmlDoc, "/root/page/body/txt/SwParaPortion/SwLineLayout[2]/*[2]", "type",
963 u"PortionType::Hole");
964 assertXPath(pXmlDoc, "/root/page/body/txt/SwParaPortion/SwLineLayout[2]/*[2]", "length",
965 u"101");
966 assertXPath(pXmlDoc, "/root/page/body/txt/SwParaPortion/SwLineLayout[2]/*[3]", "type",
967 u"PortionType::Break");
969 // tdf#158900: Check that the break after a long line with trailing spaces is kept on same line.
970 // Without the fix in place, this would fail: the line had only 2 portions (text + hole),
971 // and the break was on a separate third line
972 assertXPath(pXmlDoc, "/root/page/body/txt/SwParaPortion/SwLineLayout[3]/*", 3);
973 assertXPath(pXmlDoc, "/root/page/body/txt/SwParaPortion/SwLineLayout[3]/*[1]", "type",
974 u"PortionType::Text");
975 assertXPath(pXmlDoc, "/root/page/body/txt/SwParaPortion/SwLineLayout[3]/*[2]", "type",
976 u"PortionType::Hole");
977 assertXPath(pXmlDoc, "/root/page/body/txt/SwParaPortion/SwLineLayout[3]/*[3]", "type",
978 u"PortionType::Break");
981 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, testTdf147666)
983 createSwDoc("tdf147666.odt");
985 // Move cursor into position to insert image
986 dispatchCommand(mxComponent, u".uno:GoToEndOfPara"_ustr, {});
987 dispatchCommand(mxComponent, u".uno:GoDown"_ustr, {});
989 save(u"writer8"_ustr);
990 sal_Int32 nNonInsertedViewTop = getXPathContent(parseExport(u"settings.xml"_ustr),
991 "//config:config-item[@config:name='ViewTop']")
992 .toInt32();
994 // Insert image below the end of the paragraph on page one
995 uno::Sequence<beans::PropertyValue> aArgs = {
996 comphelper::makePropertyValue(u"FileName"_ustr, createFileURL(u"tdf147666.png")),
998 dispatchCommand(mxComponent, u".uno:InsertGraphic"_ustr, aArgs);
1000 save(u"writer8"_ustr);
1001 sal_Int32 nInsertedViewTop = getXPathContent(parseExport(u"settings.xml"_ustr),
1002 "//config:config-item[@config:name='ViewTop']")
1003 .toInt32();
1005 // Without the fix in place this will fail with
1006 // nInsertedViewTop = nNonInsertedViewTop
1007 // i.e. when the image is inserted, the view doesn't
1008 // focus to the inserted graphic
1009 CPPUNIT_ASSERT_LESS(nInsertedViewTop, nNonInsertedViewTop);
1012 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, testTdf159050)
1014 // Given a document with a justified paragraph and a box with optimal wrapping
1015 createSwDoc("tdf159050-wrap-adjust.fodt");
1016 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1017 // Make sure there is only one page, one anchored object, one paragraph, and two lines
1018 assertXPath(pXmlDoc, "/root/page", 1);
1019 assertXPath(pXmlDoc, "/root/page/body/txt/anchored/SwAnchoredDrawObject", 1);
1020 assertXPath(pXmlDoc, "/root/page/body/txt/SwParaPortion", 1);
1021 assertXPath(pXmlDoc, "/root/page/body/txt/SwParaPortion/SwLineLayout", 2);
1023 // Without the fix, this would fail: there was an unexpected second fly portion.
1024 assertXPath(pXmlDoc, "/root/page/body/txt/SwParaPortion/SwLineLayout[1]/*", 4);
1025 assertXPath(pXmlDoc, "/root/page/body/txt/SwParaPortion/SwLineLayout[1]/*[1]", "type",
1026 u"PortionType::Text");
1027 assertXPath(pXmlDoc, "/root/page/body/txt/SwParaPortion/SwLineLayout[1]/*[1]", "length", u"91");
1028 assertXPath(pXmlDoc, "/root/page/body/txt/SwParaPortion/SwLineLayout[1]/*[2]", "type",
1029 u"PortionType::Hole");
1030 assertXPath(pXmlDoc, "/root/page/body/txt/SwParaPortion/SwLineLayout[1]/*[2]", "length", u"1");
1031 assertXPath(pXmlDoc, "/root/page/body/txt/SwParaPortion/SwLineLayout[1]/*[3]", "type",
1032 u"PortionType::Fly");
1033 assertXPath(pXmlDoc, "/root/page/body/txt/SwParaPortion/SwLineLayout[1]/*[4]", "type",
1034 u"PortionType::Margin");
1037 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, testTdf159271)
1039 // Given a document with a field with several spaces in a field content
1040 createSwDoc("fld-in-tbl.docx");
1041 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1042 // Make sure there is only one page, one table with one row and two cells, and one paragraph
1043 assertXPath(pXmlDoc, "/root/page", 1);
1044 assertXPath(pXmlDoc, "/root/page/body/tab", 1);
1045 assertXPath(pXmlDoc, "/root/page/body/tab/row", 1);
1046 assertXPath(pXmlDoc, "/root/page/body/tab/row/cell", 2);
1047 assertXPath(pXmlDoc, "/root/page/body/txt", 1);
1048 assertXPath(pXmlDoc, "/root/page/body/tab/row/cell[2]/txt/SwParaPortion", 1);
1050 // Without the fix, this would fail:
1051 // - Expected: 1
1052 // - Actual : 16
1053 // - In <>, XPath '/root/page/body/tab/row/cell[2]/txt//SwLineLayout' number of nodes is incorrect
1054 assertXPath(pXmlDoc, "/root/page/body/tab/row/cell[2]/txt//SwLineLayout", 1);
1055 assertXPath(pXmlDoc, "/root/page/body/tab/row/cell[2]/txt//SwFieldPortion", 1);
1058 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, testTdf159259)
1060 // Given a document with a block sdt with a single field, having framePr aligned to right
1061 createSwDoc("sdt+framePr.docx");
1062 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1063 // Make sure there is only one page and one paragraph with one line and one anchored object
1064 assertXPath(pXmlDoc, "/root/page", 1);
1065 // Without the fix, this would fail: there were two paragraphs
1066 assertXPath(pXmlDoc, "/root/page/body/txt", 1);
1067 assertXPath(pXmlDoc, "/root/page/body/txt/SwParaPortion", 1);
1068 assertXPath(pXmlDoc, "/root/page/body/txt/SwParaPortion/SwLineLayout", 1);
1069 // Without the fix, this would fail: there was a field portion in the line
1070 assertXPath(pXmlDoc, "/root/page/body/txt/SwParaPortion/SwLineLayout/SwFieldPortion", 0);
1071 // Without the fix, this would fail: there was no anchored objects
1072 assertXPath(pXmlDoc, "/root/page/body/txt/anchored", 1);
1073 assertXPath(pXmlDoc, "/root/page/body/txt/anchored/fly", 1);
1075 const sal_Int32 paraRight
1076 = getXPath(pXmlDoc, "/root/page/body/txt/infos/bounds", "right").toInt32();
1077 const sal_Int32 paraHeight
1078 = getXPath(pXmlDoc, "/root/page/body/txt/infos/bounds", "height").toInt32();
1080 CPPUNIT_ASSERT_GREATER(sal_Int32(0), paraRight);
1081 CPPUNIT_ASSERT_GREATER(sal_Int32(0), paraHeight);
1083 const sal_Int32 flyRight
1084 = getXPath(pXmlDoc, "/root/page/body/txt/anchored/fly/infos/bounds", "right").toInt32();
1085 const sal_Int32 flyHeight
1086 = getXPath(pXmlDoc, "/root/page/body/txt/anchored/fly/infos/bounds", "height").toInt32();
1088 CPPUNIT_ASSERT_EQUAL(paraRight, flyRight); // The fly is right-aligned
1089 CPPUNIT_ASSERT_EQUAL(paraHeight, flyHeight);
1092 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, testLargeTopParaMarginAfterHiddenSection)
1094 // Given a large top margin in Standard paragraph style, and the first section hidden
1095 createSwDoc("largeTopMarginAndHiddenFirstSection.fodt");
1096 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1097 // Make sure there is only one page and two sections, first hidden (zero-height)
1098 assertXPath(pXmlDoc, "//page", 1);
1099 assertXPath(pXmlDoc, "//page/body/section", 2);
1100 assertXPath(pXmlDoc, "//page/body/section[1]/infos/bounds", "height", u"0");
1101 // Check that the top margin (1 in = 1440 twip) is added to line height (12 pt = 240 twip)
1102 assertXPath(pXmlDoc, "//page/body/section[2]/infos/bounds", "height", u"1680");
1105 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, testPageBreakInHiddenSection)
1107 // Given a paragraph with page-break-before with page style and page number
1108 createSwDoc("pageBreakInHiddenSection.fodt");
1109 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1110 assertXPath(pXmlDoc, "//page", 4);
1111 assertXPath(pXmlDoc, "//section", 4);
1112 assertXPath(pXmlDoc, "//page[1]/body/txt", 1);
1113 // The page break inside the hidden section is ignored (otherwise, there would be one section
1114 // on the first page)
1115 assertXPath(pXmlDoc, "//page[1]/body/section", 2);
1116 // The first section is hidden
1117 assertXPath(pXmlDoc, "//page[1]/body/section[1]/infos/bounds", "height", u"0");
1119 // Page 2 is empty even page (generated by the next page's section with page-break-before)
1120 assertXPath(pXmlDoc, "//page[2]/body", 0);
1122 // The section on page 3 is not hidden, only text in it is, therefore its page break works
1123 assertXPath(pXmlDoc, "//page[3]/body/section", 1);
1124 assertXPath(pXmlDoc, "//page[3]/body/section/infos/bounds", "height", u"0");
1126 // The section on page 4 is hidden, thus page break in it is ignored (no further pages, where
1127 // the section would be moved to otherwise)
1128 assertXPath(pXmlDoc, "//page[4]/body/section", 1);
1129 assertXPath(pXmlDoc, "//page[4]/body/section/infos/bounds", "height", u"0");
1132 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, testTdf159443)
1134 // Given a document with chart, which have a datatable
1135 createSwDoc("tdf159443.odt");
1136 SwDocShell* pShell = getSwDocShell();
1138 // Dump the rendering of the first page as an XML file.
1139 std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
1140 MetafileXmlDump dumper;
1141 xmlDocUniquePtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
1142 CPPUNIT_ASSERT(pXmlDoc);
1143 //// Without the fix, this would fail:
1144 //// - Expected: DataSeries1
1145 //// - Actual : 1.25
1146 //// - In <>, XPath contents of child does not match
1147 assertXPathContent(
1148 pXmlDoc,
1149 "/metafile/push[1]/push[1]/push[1]/push[3]/push[1]/push[1]/push[1]/push[47]/textarray/text",
1150 u"DataSeries1");
1151 assertXPathContent(
1152 pXmlDoc,
1153 "/metafile/push[1]/push[1]/push[1]/push[3]/push[1]/push[1]/push[1]/push[49]/textarray/text",
1154 u"Category1");
1155 assertXPathContent(
1156 pXmlDoc,
1157 "/metafile/push[1]/push[1]/push[1]/push[3]/push[1]/push[1]/push[1]/push[51]/textarray/text",
1158 u"4.3");
1161 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, testTdf159422)
1163 // Given a document with chart, which have a datatable
1164 createSwDoc("charttable.odt");
1165 SwDocShell* pShell = getSwDocShell();
1167 // Dump the rendering of the first page as an XML file.
1168 std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
1169 MetafileXmlDump dumper;
1170 xmlDocUniquePtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
1171 CPPUNIT_ASSERT(pXmlDoc);
1172 //// Without the fix, this would fail:
1173 //// - Expected: 5877
1174 //// - Actual : 5649
1175 //// - Delta : 20
1176 sal_Int32 nYSymbol1 = getXPath(pXmlDoc,
1177 "/metafile/push[1]/push[1]/push[1]/push[3]/push[1]/push[1]/"
1178 "push[1]/push[99]/polypolygon/polygon/point[1]",
1179 "y")
1180 .toInt32();
1181 CPPUNIT_ASSERT_DOUBLES_EQUAL(5877, nYSymbol1, 20);
1182 sal_Int32 nYSymbol2 = getXPath(pXmlDoc,
1183 "/metafile/push[1]/push[1]/push[1]/push[3]/push[1]/push[1]/"
1184 "push[1]/push[100]/polypolygon/polygon/point[1]",
1185 "y")
1186 .toInt32();
1187 CPPUNIT_ASSERT_DOUBLES_EQUAL(6225, nYSymbol2, 20);
1188 sal_Int32 nYSymbol3 = getXPath(pXmlDoc,
1189 "/metafile/push[1]/push[1]/push[1]/push[3]/push[1]/push[1]/"
1190 "push[1]/push[101]/polypolygon/polygon/point[1]",
1191 "y")
1192 .toInt32();
1193 CPPUNIT_ASSERT_DOUBLES_EQUAL(6573, nYSymbol3, 20);
1196 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, testTdf159456)
1198 // Given a document with chart, which have a datatable
1199 createSwDoc("charttable.odt");
1200 SwDocShell* pShell = getSwDocShell();
1202 // Dump the rendering of the first page as an XML file.
1203 std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
1204 MetafileXmlDump dumper;
1205 xmlDocUniquePtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
1206 //// Without the fix, this would fail:
1207 //// - Expected: 1
1208 //// - Actual : 1.5
1209 //// - In <>, XPath contents of child does not match
1210 assertXPathContent(pXmlDoc,
1211 "/metafile/push[1]/push[1]/push[1]/push[3]/push[1]/push[1]/push[1]/"
1212 "push[103]/textarray/text",
1213 u"1");
1214 assertXPathContent(pXmlDoc,
1215 "/metafile/push[1]/push[1]/push[1]/push[3]/push[1]/push[1]/push[1]/"
1216 "push[104]/textarray/text",
1217 u"2");
1220 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, test_i84870)
1222 // Given a document with a large as-char object, alone in its paragraph, shifted down by a
1223 // header object: it must not hang in a layout loop on import
1224 createSwDoc("i84870.fodt");
1225 CPPUNIT_ASSERT_EQUAL(2, getPages());
1228 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, testTdf160549)
1230 // Given a document with a large as-char object, alone in its paragraph, shifted down by a
1231 // header object: it must not hang in a layout loop on import (similar to i84870, but not
1232 // fixed by its fix)
1233 createSwDoc("tdf160549.fodt");
1234 // The object is the first in the document; it must not move to the next page
1235 CPPUNIT_ASSERT_EQUAL(1, getPages());
1238 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, testTdf160526)
1240 // Given a document with a large as-char object, alone in its paragraph, shifted down by
1241 // another body object
1242 createSwDoc("tdf160526.fodt");
1243 // It must move to the next page
1244 CPPUNIT_ASSERT_EQUAL(2, getPages());
1245 auto pExportDump = parseLayoutDump();
1246 assertXPath(pExportDump, "//page[2]/body/txt/anchored/SwAnchoredDrawObject");
1249 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, testTdf160958_page_break)
1251 // Given a document with a section with the first paragraph having a page break
1252 createSwDoc("tdf160958_page_break.fodt");
1253 auto pExportDump = parseLayoutDump();
1254 assertXPath(pExportDump, "//page", 2);
1255 // A single paragraph on the first page, with 6 lines
1256 assertXPath(pExportDump, "//page[1]/body/txt", 1);
1257 assertXPath(pExportDump, "//page[1]/body/txt/SwParaPortion/SwLineLayout", 6);
1258 // A section with 7 paragraphs, and two more paragraphs after the section
1259 assertXPath(pExportDump, "//page[2]/body/section", 1);
1260 assertXPath(pExportDump, "//page[2]/body/section/txt", 7);
1261 assertXPath(pExportDump, "//page[2]/body/section/txt[1]/SwParaPortion", 0);
1262 assertXPath(pExportDump, "//page[2]/body/section/txt[2]/SwParaPortion", 0);
1263 assertXPath(pExportDump, "//page[2]/body/section/txt[3]/SwParaPortion", 0);
1264 assertXPath(pExportDump, "//page[2]/body/section/txt[4]/SwParaPortion/SwLineLayout", 5);
1265 assertXPath(pExportDump, "//page[2]/body/section/txt[5]/SwParaPortion", 0);
1266 assertXPath(pExportDump, "//page[2]/body/section/txt[6]/SwParaPortion", 0);
1267 assertXPath(pExportDump, "//page[2]/body/section/txt[7]/SwParaPortion", 0);
1268 assertXPath(pExportDump, "//page[2]/body/txt", 2);
1269 assertXPath(pExportDump, "//page[2]/body/txt[1]/SwParaPortion/SwLineLayout", 7);
1270 assertXPath(pExportDump, "//page[2]/body/txt[2]/SwParaPortion", 0);
1272 // Hide the section
1273 auto xTextSectionsSupplier = mxComponent.queryThrow<css::text::XTextSectionsSupplier>();
1274 auto xSections = xTextSectionsSupplier->getTextSections();
1275 CPPUNIT_ASSERT(xSections);
1276 auto xSection = xSections->getByName(u"Section1"_ustr).queryThrow<css::beans::XPropertySet>();
1277 xSection->setPropertyValue(u"IsVisible"_ustr, css::uno::Any(false));
1279 calcLayout();
1280 pExportDump = parseLayoutDump();
1281 assertXPath(pExportDump, "//page", 1);
1282 // Three paragraphs and a hidden section on the first page
1283 assertXPath(pExportDump, "//page/body/txt", 3);
1284 assertXPath(pExportDump, "//page/body/section", 1);
1286 assertXPath(pExportDump, "//page/body/section/infos/bounds", "height", u"0");
1287 assertXPath(pExportDump, "//page/body/txt[1]/SwParaPortion/SwLineLayout", 6);
1288 assertXPath(pExportDump, "//page/body/section/txt", 7);
1289 assertXPath(pExportDump, "//page/body/section/txt[1]/SwParaPortion", 0);
1290 assertXPath(pExportDump, "//page/body/section/txt[2]/SwParaPortion", 0);
1291 assertXPath(pExportDump, "//page/body/section/txt[3]/SwParaPortion", 0);
1292 assertXPath(pExportDump, "//page/body/section/txt[4]/SwParaPortion", 0);
1293 assertXPath(pExportDump, "//page/body/section/txt[5]/SwParaPortion", 0);
1294 assertXPath(pExportDump, "//page/body/section/txt[6]/SwParaPortion", 0);
1295 assertXPath(pExportDump, "//page/body/section/txt[7]/SwParaPortion", 0);
1297 assertXPath(pExportDump, "//page/body/txt[2]/SwParaPortion/SwLineLayout", 7);
1298 assertXPath(pExportDump, "//page/body/txt[3]/SwParaPortion", 0);
1300 // Show the section again
1301 xSection->setPropertyValue(u"IsVisible"_ustr, css::uno::Any(true));
1303 // Check that the layout has been restored
1304 calcLayout();
1305 pExportDump = parseLayoutDump();
1306 assertXPath(pExportDump, "//page", 2);
1307 assertXPath(pExportDump, "//page[1]/body/txt", 1);
1308 assertXPath(pExportDump, "//page[1]/body/txt/SwParaPortion/SwLineLayout", 6);
1309 assertXPath(pExportDump, "//page[2]/body/section", 1);
1310 assertXPath(pExportDump, "//page[2]/body/section/txt", 7);
1311 assertXPath(pExportDump, "//page[2]/body/section/txt[1]/SwParaPortion", 0);
1312 assertXPath(pExportDump, "//page[2]/body/section/txt[2]/SwParaPortion", 0);
1313 assertXPath(pExportDump, "//page[2]/body/section/txt[3]/SwParaPortion", 0);
1314 assertXPath(pExportDump, "//page[2]/body/section/txt[4]/SwParaPortion/SwLineLayout", 5);
1315 assertXPath(pExportDump, "//page[2]/body/section/txt[5]/SwParaPortion", 0);
1316 assertXPath(pExportDump, "//page[2]/body/section/txt[6]/SwParaPortion", 0);
1317 assertXPath(pExportDump, "//page[2]/body/section/txt[7]/SwParaPortion", 0);
1318 assertXPath(pExportDump, "//page[2]/body/txt", 2);
1319 assertXPath(pExportDump, "//page[2]/body/txt[1]/SwParaPortion/SwLineLayout", 7);
1320 assertXPath(pExportDump, "//page[2]/body/txt[2]/SwParaPortion", 0);
1323 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, testTdf160958_orphans)
1325 // Given a document with a section which moves to the next page as a whole, because of orphans
1326 createSwDoc("tdf160958_orphans_move_section.fodt");
1327 auto pExportDump = parseLayoutDump();
1328 assertXPath(pExportDump, "//page", 2);
1329 // 21 paragraphs on the first page
1330 assertXPath(pExportDump, "//page[1]/body/txt", 21);
1331 assertXPath(pExportDump, "//page[1]/body/txt[1]/SwParaPortion/SwLineLayout", 6);
1332 assertXPath(pExportDump, "//page[1]/body/txt[2]/SwParaPortion/SwLineLayout", 5);
1333 assertXPath(pExportDump, "//page[1]/body/txt[3]/SwParaPortion/SwLineLayout", 7);
1334 assertXPath(pExportDump, "//page[1]/body/txt[4]/SwParaPortion/SwLineLayout", 16);
1335 assertXPath(pExportDump, "//page[1]/body/txt[5]/SwParaPortion/SwLineLayout", 1);
1336 assertXPath(pExportDump, "//page[1]/body/txt[6]/SwParaPortion/SwLineLayout", 1);
1337 assertXPath(pExportDump, "//page[1]/body/txt[7]/SwParaPortion/SwLineLayout", 1);
1338 assertXPath(pExportDump, "//page[1]/body/txt[8]/SwParaPortion/SwLineLayout", 1);
1339 assertXPath(pExportDump, "//page[1]/body/txt[9]/SwParaPortion/SwLineLayout", 1);
1340 assertXPath(pExportDump, "//page[1]/body/txt[10]/SwParaPortion/SwLineLayout", 1);
1341 assertXPath(pExportDump, "//page[1]/body/txt[11]/SwParaPortion/SwLineLayout", 1);
1342 assertXPath(pExportDump, "//page[1]/body/txt[12]/SwParaPortion/SwLineLayout", 1);
1343 assertXPath(pExportDump, "//page[1]/body/txt[13]/SwParaPortion/SwLineLayout", 1);
1344 assertXPath(pExportDump, "//page[1]/body/txt[14]/SwParaPortion/SwLineLayout", 1);
1345 assertXPath(pExportDump, "//page[1]/body/txt[15]/SwParaPortion/SwLineLayout", 1);
1346 assertXPath(pExportDump, "//page[1]/body/txt[16]/SwParaPortion/SwLineLayout", 1);
1347 assertXPath(pExportDump, "//page[1]/body/txt[17]/SwParaPortion/SwLineLayout", 1);
1348 assertXPath(pExportDump, "//page[1]/body/txt[18]/SwParaPortion/SwLineLayout", 1);
1349 assertXPath(pExportDump, "//page[1]/body/txt[19]/SwParaPortion/SwLineLayout", 1);
1350 assertXPath(pExportDump, "//page[1]/body/txt[20]/SwParaPortion/SwLineLayout", 1);
1351 assertXPath(pExportDump, "//page[1]/body/txt[21]/SwParaPortion/SwLineLayout", 1);
1352 // A section and one more paragraph after the section
1353 assertXPath(pExportDump, "//page[2]/body/section", 1);
1354 assertXPath(pExportDump, "//page[2]/body/section/txt", 3);
1355 assertXPath(pExportDump, "//page[2]/body/section/txt[1]/SwParaPortion/SwLineLayout", 6);
1356 assertXPath(pExportDump, "//page[2]/body/section/txt[2]/SwParaPortion/SwLineLayout", 5);
1357 assertXPath(pExportDump, "//page[2]/body/section/txt[3]/SwParaPortion/SwLineLayout", 7);
1358 assertXPath(pExportDump, "//page[2]/body/txt", 1);
1359 assertXPath(pExportDump, "//page[2]/body/txt[1]/SwParaPortion/SwLineLayout", 1);
1361 // Hide the section
1362 auto xTextSectionsSupplier = mxComponent.queryThrow<css::text::XTextSectionsSupplier>();
1363 auto xSections = xTextSectionsSupplier->getTextSections();
1364 CPPUNIT_ASSERT(xSections);
1365 auto xSection = xSections->getByName(u"Section1"_ustr).queryThrow<css::beans::XPropertySet>();
1366 xSection->setPropertyValue(u"IsVisible"_ustr, css::uno::Any(false));
1368 calcLayout();
1369 pExportDump = parseLayoutDump();
1370 assertXPath(pExportDump, "//page", 1);
1371 assertXPath(pExportDump, "//page/body/txt", 22);
1372 assertXPath(pExportDump, "//page/body/section", 1);
1373 assertXPath(pExportDump, "//page/body/section/infos/bounds", "height", u"0");
1375 // Show the section again
1376 xSection->setPropertyValue(u"IsVisible"_ustr, css::uno::Any(true));
1378 // Check that the layout has been restored
1379 calcLayout();
1380 pExportDump = parseLayoutDump();
1381 assertXPath(pExportDump, "//page", 2);
1382 assertXPath(pExportDump, "//page[1]/body/txt", 21);
1383 assertXPath(pExportDump, "//page[1]/body/txt[1]/SwParaPortion/SwLineLayout", 6);
1384 assertXPath(pExportDump, "//page[1]/body/txt[2]/SwParaPortion/SwLineLayout", 5);
1385 assertXPath(pExportDump, "//page[1]/body/txt[3]/SwParaPortion/SwLineLayout", 7);
1386 assertXPath(pExportDump, "//page[1]/body/txt[4]/SwParaPortion/SwLineLayout", 16);
1387 assertXPath(pExportDump, "//page[1]/body/txt[5]/SwParaPortion/SwLineLayout", 1);
1388 assertXPath(pExportDump, "//page[1]/body/txt[6]/SwParaPortion/SwLineLayout", 1);
1389 assertXPath(pExportDump, "//page[1]/body/txt[7]/SwParaPortion/SwLineLayout", 1);
1390 assertXPath(pExportDump, "//page[1]/body/txt[8]/SwParaPortion/SwLineLayout", 1);
1391 assertXPath(pExportDump, "//page[1]/body/txt[9]/SwParaPortion/SwLineLayout", 1);
1392 assertXPath(pExportDump, "//page[1]/body/txt[10]/SwParaPortion/SwLineLayout", 1);
1393 assertXPath(pExportDump, "//page[1]/body/txt[11]/SwParaPortion/SwLineLayout", 1);
1394 assertXPath(pExportDump, "//page[1]/body/txt[12]/SwParaPortion/SwLineLayout", 1);
1395 assertXPath(pExportDump, "//page[1]/body/txt[13]/SwParaPortion/SwLineLayout", 1);
1396 assertXPath(pExportDump, "//page[1]/body/txt[14]/SwParaPortion/SwLineLayout", 1);
1397 assertXPath(pExportDump, "//page[1]/body/txt[15]/SwParaPortion/SwLineLayout", 1);
1398 assertXPath(pExportDump, "//page[1]/body/txt[16]/SwParaPortion/SwLineLayout", 1);
1399 assertXPath(pExportDump, "//page[1]/body/txt[17]/SwParaPortion/SwLineLayout", 1);
1400 assertXPath(pExportDump, "//page[1]/body/txt[18]/SwParaPortion/SwLineLayout", 1);
1401 assertXPath(pExportDump, "//page[1]/body/txt[19]/SwParaPortion/SwLineLayout", 1);
1402 assertXPath(pExportDump, "//page[1]/body/txt[20]/SwParaPortion/SwLineLayout", 1);
1403 assertXPath(pExportDump, "//page[1]/body/txt[21]/SwParaPortion/SwLineLayout", 1);
1404 assertXPath(pExportDump, "//page[2]/body/section", 1);
1405 assertXPath(pExportDump, "//page[2]/body/section/txt", 3);
1406 assertXPath(pExportDump, "//page[2]/body/section/txt[1]/SwParaPortion/SwLineLayout", 6);
1407 assertXPath(pExportDump, "//page[2]/body/section/txt[2]/SwParaPortion/SwLineLayout", 5);
1408 assertXPath(pExportDump, "//page[2]/body/section/txt[3]/SwParaPortion/SwLineLayout", 7);
1409 assertXPath(pExportDump, "//page[2]/body/txt", 1);
1410 assertXPath(pExportDump, "//page[2]/body/txt[1]/SwParaPortion/SwLineLayout", 1);
1413 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, testTdf161368)
1415 // Given a document with a text body width of 116 mm, greater than 65535 twips (115.6 mm)
1416 createSwDoc("tdf161368.fodt");
1417 auto pExportDump = parseLayoutDump();
1418 // one page, three paragraphs, each one line (it was four pages, each paragraph split into
1419 // tens of short (<= 4 mm wide) lines)
1420 assertXPath(pExportDump, "//page", 1);
1421 assertXPath(pExportDump, "//page[1]/body/txt", 3);
1422 assertXPath(pExportDump, "//page[1]/body/txt[1]/SwParaPortion/SwLineLayout", 1);
1423 assertXPath(pExportDump, "//page[1]/body/txt[2]/SwParaPortion/SwLineLayout", 1);
1424 assertXPath(pExportDump, "//page[1]/body/txt[3]/SwParaPortion/SwLineLayout", 1);
1427 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, TestCrashHyphenation)
1429 //just care it doesn't crash/assert
1430 createSwDoc("crashHyphen.fodt");
1433 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, TestTdf161508)
1435 // This document must not hang on load.
1436 createSwDoc("tdf161508.fodt");
1437 auto pExportDump = parseLayoutDump();
1438 // The table must move completely to the second page
1439 assertXPath(pExportDump, "//page[1]/body/tab", 0);
1440 assertXPath(pExportDump, "//page[2]/body/tab", 1);
1443 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, TestTdf92091)
1445 // This test verifies that RTL text following an LTR footnote is measured correctly
1446 createSwDoc("tdf92091.fodt");
1447 auto pXmlDoc = parseLayoutDump();
1449 sal_Int32 nLayoutWidth
1450 = getXPath(pXmlDoc, "/root/page[1]/body/txt[1]/SwParaPortion/SwLineLayout", "width")
1451 .toInt32();
1452 CPPUNIT_ASSERT_GREATER(sal_Int32(3210), nLayoutWidth);
1454 sal_Int32 nPor1Width
1455 = getXPath(pXmlDoc, "/root/page[1]/body/txt[1]/SwParaPortion/SwLineLayout/SwLinePortion[1]",
1456 "width")
1457 .toInt32();
1458 CPPUNIT_ASSERT_GREATER(sal_Int32(55), nPor1Width);
1460 sal_Int32 nPor2Width
1461 = getXPath(pXmlDoc,
1462 "/root/page[1]/body/txt[1]/SwParaPortion/SwLineLayout/SwFieldPortion[1]",
1463 "width")
1464 .toInt32();
1465 CPPUNIT_ASSERT_GREATER(sal_Int32(75), nPor2Width);
1467 sal_Int32 nPor3Width
1468 = getXPath(pXmlDoc, "/root/page[1]/body/txt[1]/SwParaPortion/SwLineLayout/SwLinePortion[2]",
1469 "width")
1470 .toInt32();
1471 CPPUNIT_ASSERT_GREATER(sal_Int32(2870), nPor3Width);
1473 sal_Int32 nPor4Width
1474 = getXPath(pXmlDoc,
1475 "/root/page[1]/body/txt[1]/SwParaPortion/SwLineLayout/SwFieldPortion[2]",
1476 "width")
1477 .toInt32();
1478 CPPUNIT_ASSERT_GREATER(sal_Int32(75), nPor4Width);
1480 sal_Int32 nPor5Width
1481 = getXPath(pXmlDoc, "/root/page[1]/body/txt[1]/SwParaPortion/SwLineLayout/SwLinePortion[3]",
1482 "width")
1483 .toInt32();
1484 CPPUNIT_ASSERT_GREATER(sal_Int32(110), nPor5Width);
1487 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, TestTdf104209VertLTR)
1489 // Verify that vertical left-to-right text after a fly portion will overflow to the next page.
1490 createSwDoc("tdf107209-vert-ltr.fodt");
1491 auto pXmlDoc = parseLayoutDump();
1493 assertXPath(pXmlDoc, "//page", 2);
1495 assertXPath(pXmlDoc, "/root/page[1]/body/txt[4]/SwParaPortion/SwLineLayout", "portion",
1496 u"AAAAAAAAAAAAAAAAAAA");
1497 assertXPath(pXmlDoc, "/root/page[2]/body/txt[1]/SwParaPortion/SwLineLayout[1]", "portion",
1498 u"BBBBBBBBBBBBBBBBBBBBBB");
1499 assertXPath(pXmlDoc, "/root/page[2]/body/txt[1]/SwParaPortion/SwLineLayout[2]", "portion",
1500 u"B");
1503 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, TestTdf104209VertRTL)
1505 // Verify that vertical right-to-left text after a fly portion will overflow to the next page.
1506 createSwDoc("tdf107209-vert-rtl.fodt");
1507 auto pXmlDoc = parseLayoutDump();
1509 assertXPath(pXmlDoc, "//page", 2);
1511 assertXPath(pXmlDoc, "/root/page[1]/body/txt[4]/SwParaPortion/SwLineLayout", "portion",
1512 u"AAAAAAAAAAAAAAAAAAA");
1513 assertXPath(pXmlDoc, "/root/page[2]/body/txt[1]/SwParaPortion/SwLineLayout[1]", "portion",
1514 u"BBBBBBBBBBBBBBBBBBBBBB");
1515 assertXPath(pXmlDoc, "/root/page[2]/body/txt[1]/SwParaPortion/SwLineLayout[2]", "portion",
1516 u"B");
1519 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, TestTdf56408LTR)
1521 // Verify that line breaking a first bidi portion correctly underflows in LTR text
1522 createSwDoc("tdf56408-ltr.fodt");
1523 auto pXmlDoc = parseLayoutDump();
1525 assertXPath(pXmlDoc, "//page", 1);
1527 assertXPath(pXmlDoc, "/root/page/body/txt/SwParaPortion/SwLineLayout[1]", "portion",
1528 u"English English English ");
1529 assertXPath(pXmlDoc, "/root/page/body/txt/SwParaPortion/SwLineLayout[2]", "portion",
1530 u"((((עברית)))) English");
1533 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, TestTdf56408RTL)
1535 // Verify that line breaking a first bidi portion correctly underflows in RTL text
1536 createSwDoc("tdf56408-rtl.fodt");
1537 auto pXmlDoc = parseLayoutDump();
1539 assertXPath(pXmlDoc, "//page", 1);
1541 assertXPath(pXmlDoc, "/root/page/body/txt/SwParaPortion/SwLineLayout[1]", "portion",
1542 u"עברית עברית עברית ");
1543 assertXPath(pXmlDoc, "/root/page/body/txt/SwParaPortion/SwLineLayout[2]", "portion",
1544 u"((((English)))) עברית");
1547 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, TestTdf56408NoUnderflow)
1549 // The fix for tdf#56408 introduced a change to line breaking between text with
1550 // direction changes. This test verifies behavior in the trivial case, when a
1551 // break opportunity exists at the direction change boundary.
1552 createSwDoc("tdf56408-no-underflow.fodt");
1553 auto pXmlDoc = parseLayoutDump();
1555 assertXPath(pXmlDoc, "//page", 1);
1557 assertXPath(pXmlDoc, "/root/page/body/txt/SwParaPortion/SwLineLayout[1]", "portion",
1558 u"English English English ");
1559 assertXPath(pXmlDoc, "/root/page/body/txt/SwParaPortion/SwLineLayout[2]", "portion",
1560 u"עברית English");
1563 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, TestTdf56408AfterFieldCrash)
1565 // Verify there is no crash/assertion for underflow after a number field
1566 createSwDoc("tdf56408-after-field.fodt");
1569 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, TestTdf146081)
1571 // Verifies that proportional line spacing is consistent with the
1572 // PropLineSpacingShrinksFirstLine compatibility flag set
1573 createSwDoc("tdf146081-prop-spacing.fodt");
1574 auto pXmlDoc = parseLayoutDump();
1576 SwTwips nTotalHeight
1577 = getXPath(pXmlDoc, "/root/page/body/txt/infos/bounds", "height").toInt32();
1579 SwTwips nHeight1
1580 = getXPath(pXmlDoc, "/root/page/body/txt/SwParaPortion/SwLineLayout[1]", "height")
1581 .toInt32();
1582 SwTwips nHeight2
1583 = getXPath(pXmlDoc, "/root/page/body/txt/SwParaPortion/SwLineLayout[2]", "height")
1584 .toInt32();
1585 SwTwips nHeight3
1586 = getXPath(pXmlDoc, "/root/page/body/txt/SwParaPortion/SwLineLayout[3]", "height")
1587 .toInt32();
1588 SwTwips nHeight4
1589 = getXPath(pXmlDoc, "/root/page/body/txt/SwParaPortion/SwLineLayout[4]", "height")
1590 .toInt32();
1592 // All of the lines must have the same height
1593 CPPUNIT_ASSERT_EQUAL(nHeight1, nHeight2);
1594 CPPUNIT_ASSERT_EQUAL(nHeight1, nHeight3);
1595 CPPUNIT_ASSERT_EQUAL(nHeight1, nHeight4);
1597 // The total height of the paragraph must be equal to the sum of all lines
1598 CPPUNIT_ASSERT_EQUAL(nTotalHeight, nHeight1 * 4);
1601 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, TestTdf155229RowAtLeast)
1603 createSwDoc("tdf155229_row_height_at_least.docx");
1605 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1606 sal_Int32 nTableHeight
1607 = getXPath(pXmlDoc, "/root/page[1]/body/tab[1]/row[11]/infos/bounds", "bottom").toInt32();
1609 // Without the fix, this was Actual : 14174
1610 CPPUNIT_ASSERT_EQUAL(sal_Int32(15494), nTableHeight);
1613 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, TestTdf157829LTR)
1615 // Verify that line breaking inside a bidi portion triggers underflow to previous bidi portions
1616 createSwDoc("tdf157829-ltr.fodt");
1617 auto pXmlDoc = parseLayoutDump();
1619 assertXPath(pXmlDoc, "//page", 1);
1621 assertXPath(pXmlDoc, "/root/page/body/txt/SwParaPortion/SwLineLayout[1]", "portion",
1622 u"English English English ");
1623 assertXPath(pXmlDoc, "/root/page/body/txt/SwParaPortion/SwLineLayout[2]", "portion",
1624 u"עברית English");
1627 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, TestTdf157829RTL)
1629 // Verify that line breaking inside a bidi portion triggers underflow to previous bidi portions
1630 createSwDoc("tdf157829-rtl.fodt");
1631 auto pXmlDoc = parseLayoutDump();
1633 assertXPath(pXmlDoc, "//page", 1);
1635 assertXPath(pXmlDoc, "/root/page/body/txt/SwParaPortion/SwLineLayout[1]", "portion",
1636 u"עברית עברית עברית עברית ");
1637 assertXPath(pXmlDoc, "/root/page/body/txt/SwParaPortion/SwLineLayout[2]", "portion",
1638 u"English עברית");
1641 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, TestTdf162314)
1643 // Regression test for bidi portion line breaking where the portion layout ends with underflow,
1644 // but the bidi portion should not be truncated.
1645 createSwDoc("tdf162314.fodt");
1646 auto pXmlDoc = parseLayoutDump();
1648 assertXPath(pXmlDoc, "//page", 1);
1650 assertXPath(pXmlDoc, "/root/page/body/txt/SwParaPortion/SwLineLayout[1]", "portion",
1651 u"Aa aa aaaa ﷽ ");
1652 assertXPath(pXmlDoc, "/root/page/body/txt/SwParaPortion/SwLineLayout[2]", "portion", u"aaaa");
1655 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, TestTdf162614)
1657 // Given a table inside another table, having a fixed-height last row, with a merged cell
1658 // spanning two rows, with a text (having a spacing below) wrapping inside that merged cell,
1659 // positioned so that the first line of the text in on the first page, and the second line
1660 // flows onto the second page:
1661 createSwDoc("tdf162614.fodt");
1662 auto pXmlDoc = parseLayoutDump();
1664 // Make sure that all the tables have the correct positions and sizes
1665 // I find the clang-formatted version of the following awful (it is already ugly enough)
1666 // clang-format off
1668 assertXPath(pXmlDoc, "//page", 2);
1669 // One top-level table on page 1 (Table1), with a single row and a single cell
1670 assertXPath(pXmlDoc, "//page[1]/body/tab", 1);
1671 OUString sTable1PrecedeId = getXPath(pXmlDoc, "//page[1]/body/tab", "id");
1672 OUString sTable1FollowId = getXPath(pXmlDoc, "//page[1]/body/tab", "follow");
1673 assertXPath(pXmlDoc, "//page[1]/body/tab/infos/bounds", "top", u"2261");
1674 assertXPath(pXmlDoc, "//page[1]/body/tab/infos/bounds", "height", u"810");
1675 assertXPath(pXmlDoc, "//page[1]/body/tab/row", 1);
1676 assertXPath(pXmlDoc, "//page[1]/body/tab/row/cell", 1);
1677 OUString sTable1A1PrecedeId = getXPath(pXmlDoc, "//page[1]/body/tab/row/cell", "id");
1678 OUString sTable1A1FollowId = getXPath(pXmlDoc, "//page[1]/body/tab/row/cell", "follow");
1679 // One sub-table inside it (Table2):
1680 assertXPath(pXmlDoc, "//page[1]/body/tab/row/cell/tab", 1);
1681 OUString sTable2PrecedeId = getXPath(pXmlDoc, "//page[1]/body/tab/row/cell/tab", "id");
1682 OUString sTable2FollowId = getXPath(pXmlDoc, "//page[1]/body/tab/row/cell/tab", "follow");
1683 assertXPath(pXmlDoc, "//page[1]/body/tab/row/cell/tab/infos/bounds", "top", u"2508");
1684 assertXPath(pXmlDoc, "//page[1]/body/tab/row/cell/tab/infos/bounds", "height", u"543");
1685 assertXPath(pXmlDoc, "//page[1]/body/tab/row/cell/tab/row", 1);
1686 assertXPath(pXmlDoc, "//page[1]/body/tab/row/cell/tab/row/cell", 2);
1687 // A1
1688 assertXPathNoAttribute(pXmlDoc, "//page[1]/body/tab/row/cell/tab/row/cell[1]", "follow");
1689 assertXPath(pXmlDoc, "//page[1]/body/tab/row/cell/tab/row/cell[1]", "rowspan", u"1");
1690 assertXPath(pXmlDoc, "//page[1]/body/tab/row/cell/tab/row/cell[1]/txt/SwParaPortion/SwLineLayout/*", 1);
1691 assertXPath(pXmlDoc, "//page[1]/body/tab/row/cell/tab/row/cell[1]/txt/SwParaPortion/SwLineLayout/*[1]", "type", u"PortionType::Para");
1692 assertXPath(pXmlDoc, "//page[1]/body/tab/row/cell/tab/row/cell[1]/txt/SwParaPortion/SwLineLayout/*[1]", "portion", u"Table2.A1");
1693 // B1
1694 OUString sTable2B1PrecedeId = getXPath(pXmlDoc, "//page[1]/body/tab/row/cell/tab/row/cell[2]", "id");
1695 OUString sTable2B1FollowId = getXPath(pXmlDoc, "//page[1]/body/tab/row/cell/tab/row/cell[2]", "follow");
1696 assertXPath(pXmlDoc, "//page[1]/body/tab/row/cell/tab/row/cell[2]", "rowspan", u"2");
1697 assertXPath(pXmlDoc, "//page[1]/body/tab/row/cell/tab/row/cell[2]/infos/bounds", "height", u"523");
1698 assertXPath(pXmlDoc, "//page[1]/body/tab/row/cell/tab/row/cell[2]/infos/prtBounds", "height", u"503");
1699 OUString sTable2B1TextPrecedeId = getXPath(pXmlDoc, "//page[1]/body/tab/row/cell/tab/row/cell[2]/txt", "id");
1700 OUString sTable2B1TextFollowId = getXPath(pXmlDoc, "//page[1]/body/tab/row/cell/tab/row/cell[2]/txt", "follow");
1701 assertXPath(pXmlDoc, "//page[1]/body/tab/row/cell/tab/row/cell[2]/txt", "offset", u"0");
1702 assertXPath(pXmlDoc, "//page[1]/body/tab/row/cell/tab/row/cell[2]/txt/infos/bounds", "height", u"276");
1703 assertXPath(pXmlDoc, "//page[1]/body/tab/row/cell/tab/row/cell[2]/txt/infos/prtBounds", "height", u"276");
1704 assertXPath(pXmlDoc, "//page[1]/body/tab/row/cell/tab/row/cell[2]/txt/SwParaPortion/SwLineLayout/*", 2);
1705 assertXPath(pXmlDoc, "//page[1]/body/tab/row/cell/tab/row/cell[2]/txt/SwParaPortion/SwLineLayout/*[1]", "type", u"PortionType::Text");
1706 assertXPath(pXmlDoc, "//page[1]/body/tab/row/cell/tab/row/cell[2]/txt/SwParaPortion/SwLineLayout/*[1]", "portion", u"Table2.B1");
1707 assertXPath(pXmlDoc, "//page[1]/body/tab/row/cell/tab/row/cell[2]/txt/SwParaPortion/SwLineLayout/*[2]", "type", u"PortionType::Hole");
1709 // Two top-level tables on page 2
1710 assertXPath(pXmlDoc, "//page[2]/body/tab", 2);
1711 // Table1 (follow)
1712 CPPUNIT_ASSERT_EQUAL(sTable1FollowId, getXPath(pXmlDoc, "//page[2]/body/tab[1]", "id"));
1713 CPPUNIT_ASSERT_EQUAL(sTable1PrecedeId, getXPath(pXmlDoc, "//page[2]/body/tab[1]", "precede"));
1714 assertXPath(pXmlDoc, "//page[2]/body/tab[1]/infos/bounds", "top", u"3403");
1715 assertXPath(pXmlDoc, "//page[2]/body/tab[1]/infos/bounds", "height", u"514");
1716 assertXPath(pXmlDoc, "//page[2]/body/tab[1]/row", 1);
1717 assertXPath(pXmlDoc, "//page[2]/body/tab[1]/row/cell", 1);
1718 CPPUNIT_ASSERT_EQUAL(sTable1A1FollowId, getXPath(pXmlDoc, "//page[2]/body/tab[1]/row/cell", "id"));
1719 CPPUNIT_ASSERT_EQUAL(sTable1A1PrecedeId, getXPath(pXmlDoc, "//page[2]/body/tab[1]/row/cell", "precede"));
1720 // Table2 (follow)
1721 assertXPath(pXmlDoc, "//page[2]/body/tab[1]/row/cell/tab", 1);
1722 CPPUNIT_ASSERT_EQUAL(sTable2FollowId, getXPath(pXmlDoc, "//page[2]/body/tab[1]/row/cell/tab", "id"));
1723 CPPUNIT_ASSERT_EQUAL(sTable2PrecedeId, getXPath(pXmlDoc, "//page[2]/body/tab[1]/row/cell/tab", "precede"));
1724 assertXPath(pXmlDoc, "//page[2]/body/tab[1]/row/cell/tab/infos/bounds", "top", u"3423");
1725 assertXPath(pXmlDoc, "//page[2]/body/tab[1]/row/cell/tab/infos/bounds", "height", u"474");
1726 assertXPath(pXmlDoc, "//page[2]/body/tab[1]/row/cell/tab/row", 2);
1727 // Table2 row 1 (continued)
1728 assertXPath(pXmlDoc, "//page[2]/body/tab[1]/row/cell/tab/row[1]/cell", 2);
1729 // Placeholder for the cell in column 1
1730 assertXPath(pXmlDoc, "//page[2]/body/tab[1]/row/cell/tab/row[1]/cell[1]/infos/bounds", "height", u"0");
1731 // B1 (follow)
1732 CPPUNIT_ASSERT_EQUAL(sTable2B1FollowId, getXPath(pXmlDoc, "//page[2]/body/tab[1]/row/cell/tab/row[1]/cell[2]", "id"));
1733 CPPUNIT_ASSERT_EQUAL(sTable2B1PrecedeId, getXPath(pXmlDoc, "//page[2]/body/tab[1]/row/cell/tab/row[1]/cell[2]", "precede"));
1734 assertXPath(pXmlDoc, "//page[2]/body/tab[1]/row/cell/tab/row[1]/cell[2]", "rowspan", u"2");
1735 // Without the fix, this failed with
1736 // - Expected: 1
1737 // - Actual : 2
1738 // - In <>, XPath '//page[2]/body/tab[1]/row/cell/tab/row[1]/cell[2]/txt' number of nodes is incorrect
1739 CPPUNIT_ASSERT_EQUAL(sTable2B1TextFollowId, getXPath(pXmlDoc, "//page[2]/body/tab[1]/row/cell/tab/row[1]/cell[2]/txt", "id"));
1740 CPPUNIT_ASSERT_EQUAL(sTable2B1TextPrecedeId, getXPath(pXmlDoc, "//page[2]/body/tab[1]/row/cell/tab/row[1]/cell[2]/txt", "precede"));
1741 assertXPath(pXmlDoc, "//page[2]/body/tab[1]/row/cell/tab/row[1]/cell[2]/txt/SwParaPortion/SwLineLayout/*", 1);
1742 assertXPath(pXmlDoc, "//page[2]/body/tab[1]/row/cell/tab/row[1]/cell[2]/txt/SwParaPortion/SwLineLayout/*[1]", "type", u"PortionType::Para");
1743 assertXPath(pXmlDoc, "//page[2]/body/tab[1]/row/cell/tab/row[1]/cell[2]/txt/SwParaPortion/SwLineLayout/*[1]", "portion", u"(contd.)");
1744 // Table2 row 2
1745 assertXPath(pXmlDoc, "//page[2]/body/tab[1]/row/cell/tab/row[2]/cell", 2);
1746 // A2
1747 assertXPath(pXmlDoc, "//page[2]/body/tab[1]/row/cell/tab/row[2]/cell[1]/txt/SwParaPortion/SwLineLayout/*", 1);
1748 assertXPath(pXmlDoc, "//page[2]/body/tab[1]/row/cell/tab/row[2]/cell[1]/txt/SwParaPortion/SwLineLayout/*[1]", "type", u"PortionType::Para");
1749 assertXPath(pXmlDoc, "//page[2]/body/tab[1]/row/cell/tab/row[2]/cell[1]/txt/SwParaPortion/SwLineLayout/*[1]", "portion", u"Table2.A2");
1750 // B2 (covered cell)
1751 assertXPath(pXmlDoc, "//page[2]/body/tab[1]/row/cell/tab/row[2]/cell[2]", "rowspan", u"-1");
1753 // Table3 (must not be collapsed)
1754 assertXPath(pXmlDoc, "//page[2]/body/tab[2]/infos/bounds", "top", u"4696");
1755 // Without the fix, this failed with
1756 // - Expected: 770
1757 // - Actual : 267
1758 assertXPath(pXmlDoc, "//page[2]/body/tab[2]/infos/bounds", "height", u"770");
1760 // Now a test for a case that took me some time to fix when creating the patch.
1761 // It is the greatly simplified tdf124795-5.
1763 createSwDoc("C4_must_start_on_p1.fodt");
1764 pXmlDoc = parseLayoutDump();
1766 // The first line of C4 text must start on the first page - the initial version of the fix
1767 // moved it to page 2.
1769 assertXPath(pXmlDoc, "//page[1]/body/tab/row[4]/cell[3]/txt/SwParaPortion/SwLineLayout/*", 1);
1770 assertXPath(pXmlDoc, "//page[1]/body/tab/row[4]/cell[3]/txt/SwParaPortion/SwLineLayout/*[1]", "type", u"PortionType::Para");
1771 assertXPath(pXmlDoc, "//page[1]/body/tab/row[4]/cell[3]/txt/SwParaPortion/SwLineLayout/*[1]", "portion", u"C4_xxxxxxxxxxxxxxxxxxxx");
1773 // clang-format on
1776 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, TestTdf152142)
1778 // Regression test for textbox positioning when anchored as-char in RTL context.
1779 createSwDoc("tdf152142.fodt");
1780 auto pXmlDoc = parseLayoutDump();
1782 assertXPath(pXmlDoc, "//page", 1);
1784 SwTwips nTextBoxBegin
1785 = getXPath(pXmlDoc, "/root/page/body/txt[2]/anchored/fly/txt/infos/bounds", "left")
1786 .toInt32();
1787 SwTwips nTextBoxEnd
1788 = getXPath(pXmlDoc, "/root/page/body/txt[2]/anchored/fly/txt/infos/bounds", "right")
1789 .toInt32();
1791 SwTwips nShapeBegin
1792 = getXPath(pXmlDoc, "/root/page/body/txt[2]/anchored/SwAnchoredDrawObject/bounds", "left")
1793 .toInt32();
1794 SwTwips nShapeEnd
1795 = getXPath(pXmlDoc, "/root/page/body/txt[2]/anchored/SwAnchoredDrawObject/bounds", "right")
1796 .toInt32();
1798 CPPUNIT_ASSERT_GREATER(nShapeBegin, nTextBoxBegin);
1799 CPPUNIT_ASSERT_LESS(nShapeEnd, nTextBoxEnd);
1802 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, TestTdf152142DoNotMirrorRtlDrawObjs)
1804 // Regression test for textbox positioning when anchored as-char in RTL context, with the
1805 // DoNotMirrorRtlDrawObjs compatibility flag set.
1806 createSwDoc("tdf152142-donotmirror.fodt");
1807 auto pXmlDoc = parseLayoutDump();
1809 assertXPath(pXmlDoc, "//page", 1);
1811 SwTwips nTextBoxBegin
1812 = getXPath(pXmlDoc, "/root/page/body/txt[2]/anchored/fly/txt/infos/bounds", "left")
1813 .toInt32();
1814 SwTwips nTextBoxEnd
1815 = getXPath(pXmlDoc, "/root/page/body/txt[2]/anchored/fly/txt/infos/bounds", "right")
1816 .toInt32();
1818 SwTwips nShapeBegin
1819 = getXPath(pXmlDoc, "/root/page/body/txt[2]/anchored/SwAnchoredDrawObject/bounds", "left")
1820 .toInt32();
1821 SwTwips nShapeEnd
1822 = getXPath(pXmlDoc, "/root/page/body/txt[2]/anchored/SwAnchoredDrawObject/bounds", "right")
1823 .toInt32();
1825 CPPUNIT_ASSERT_GREATER(nShapeBegin, nTextBoxBegin);
1826 CPPUNIT_ASSERT_LESS(nShapeEnd, nTextBoxEnd);
1829 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, testTdf152298)
1831 createSwDoc("tdf152298.docx");
1832 auto pDump = parseLayoutDump();
1834 assertXPath(pDump, "//page", 2);
1835 // Without the fix, this was 39
1836 assertXPath(pDump, "//page[1]/body/tab/row", 38);
1837 assertXPath(pDump, "//page[1]/body/tab/row[38]/cell[1]", "rowspan", u"4");
1838 OUString a38_id = getXPath(pDump, "//page[1]/body/tab/row[38]/cell[1]", "id");
1839 OUString follow_id = getXPath(pDump, "//page[1]/body/tab/row[38]/cell[1]", "follow");
1840 // The text of A38, that spans four rows, must be split: empty paragraph here
1841 assertXPathContent(pDump, "//page[1]/body/tab/row[38]/cell[1]/txt", u"");
1842 // First row is the repeating line
1843 assertXPathContent(pDump, "//page[2]/body/tab/row[1]/cell[1]/txt", u"1");
1844 assertXPathContent(pDump, "//page[2]/body/tab/row[1]/cell[2]/txt", u"2");
1845 assertXPathContent(pDump, "//page[2]/body/tab/row[1]/cell[3]/txt", u"3");
1846 // The text in the follow row's first cell is the second paragraph of A38, "10"
1847 assertXPath(pDump, "//page[2]/body/tab/row[2]/cell[1]", "id", follow_id);
1848 assertXPath(pDump, "//page[2]/body/tab/row[2]/cell[1]", "precede", a38_id);
1849 assertXPathContent(pDump, "//page[2]/body/tab/row[2]/cell[1]/txt", u"10");
1852 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, TestTdf163230)
1854 createSwDoc("tdf163230.fodt");
1855 auto pExportDump = parseLayoutDump();
1856 // The first row must split across pages, despite its "do not break" attribute, because it
1857 // doesn't fit on the page. Before the fix, the document had only two pages.
1858 assertXPath(pExportDump, "//page", 3);
1861 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, TestTdf163285)
1863 createSwDoc("tdf163285.fodt");
1864 auto pDump = parseLayoutDump();
1865 // The first row must split across three pages, despite its "do not break" attribute, because it
1866 // doesn't fit on the whole page.
1867 // A1 text is created such that its "pg_1", "pg_2" and "pg_3" must start the respective pages.
1868 assertXPath(pDump, "//page", 3);
1869 OUString topText1 = getXPathContent(pDump, "//page[1]/body/tab/row[1]/cell[1]/txt[1]");
1870 CPPUNIT_ASSERT(topText1.startsWith("pg_1"));
1871 OUString topText2 = getXPathContent(pDump, "//page[2]/body/tab/row[1]/cell[1]/txt[1]");
1872 CPPUNIT_ASSERT(topText2.startsWith("pg_2"));
1873 OUString topText3 = getXPathContent(pDump, "//page[3]/body/tab/row[1]/cell[1]/txt[1]");
1874 // Without the fix, this failed:
1875 CPPUNIT_ASSERT(topText3.startsWith("pg_3"));
1878 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, TestTdf152839_firstRows)
1880 createSwDoc("tdf152839_firstrows.rtf");
1882 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1883 sal_Int32 nHeight
1884 = getXPath(pXmlDoc, "/root/page[1]/body/tab[1]/row[1]/cell[2]/txt/infos/bounds", "height")
1885 .toInt32();
1886 CPPUNIT_ASSERT_EQUAL(sal_Int32(223), nHeight);
1889 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, TestTdf164098)
1891 createSwDoc("tdf164098.fodt");
1892 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
1894 pWrtShell->StartOfSection(false);
1895 pWrtShell->Right(SwCursorSkipMode::Chars, /*bSelect*/ false, 6, /*bBasicCall*/ false);
1897 // Without the fix, this line will cause a freeze:
1898 pWrtShell->Insert(u"ـ"_ustr);
1901 } // end of anonymous namespace
1903 CPPUNIT_PLUGIN_IMPLEMENT();
1905 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */