1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 #include <swmodeltestbase.hxx>
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>
20 #include <pagefrm.hxx>
21 #include <sortedobjs.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>
35 /// Test to assert layout / rendering result of Writer.
36 class SwLayoutWriter4
: public SwModelTestBase
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
69 assertXPath(pXmlDoc
, "/root/page[2]/body/section[1]/infos/bounds", "height", u
"552");
71 assertXPath(pXmlDoc
, "/root/page[2]/body/section[1]/infos/bounds", "height", u
"532");
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
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
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
99 assertXPath(pXmlDoc
, "/root/page[3]/body/section[1]/infos/bounds", "height", u
"552");
101 assertXPath(pXmlDoc
, "/root/page[3]/body/section[1]/infos/bounds", "height", u
"532");
103 assertXPath(pXmlDoc
, "/root/page[3]", "formatName", u
"RueckantwortRechts");
106 // toggle one section hidden and other visible
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
121 assertXPath(pXmlDoc
, "/root/page[2]/body/section[1]/infos/bounds", "height", u
"552");
123 assertXPath(pXmlDoc
, "/root/page[2]/body/section[1]/infos/bounds", "height", u
"532");
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",
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",
155 assertXPath(pXmlDoc
, "/root/page[3]/body/section[2]/column", 2);
156 assertXPath(pXmlDoc
, "/root/page[3]/body/section[2]/column/body/txt", 2);
158 "/root/page[3]/body/section[2]/column/body/txt[2]/SwParaPortion/SwLineLayout",
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);
165 "/root/page[4]/body/section[1]/column[1]/body/txt[1]/SwParaPortion/SwLineLayout",
169 "/root/page[4]/body/section[1]/column[2]/body/txt[1]/SwParaPortion/SwLineLayout",
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",
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",
211 assertXPath(pXmlDoc
, "/root/page[3]/body/section[2]/column", 2);
212 assertXPath(pXmlDoc
, "/root/page[3]/body/section[2]/column/body/txt", 2);
214 "/root/page[3]/body/section[2]/column/body/txt[2]/SwParaPortion/SwLineLayout",
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);
221 "/root/page[4]/body/section[1]/column[1]/body/txt[1]/SwParaPortion/SwLineLayout",
225 "/root/page[4]/body/section[1]/column[2]/body/txt[1]/SwParaPortion/SwLineLayout",
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",
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",
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",
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",
274 assertXPath(pXmlDoc
, "/root/page[3]/body/section[2]/column", 2);
275 assertXPath(pXmlDoc
, "/root/page[3]/body/section[2]/column/body/txt", 2);
277 "/root/page[3]/body/section[2]/column/body/txt[2]/SwParaPortion/SwLineLayout",
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);
284 "/root/page[4]/body/section[1]/column[1]/body/txt[1]/SwParaPortion/SwLineLayout",
288 "/root/page[4]/body/section[1]/column[2]/body/txt[1]/SwParaPortion/SwLineLayout",
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);
309 "/root/page[2]/body/txt/anchored/fly/column[1]/body/section/column[1]/body/txt", 1);
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);
314 "/root/page[2]/body/txt/anchored/fly/column[2]/body/section/column[1]/body/txt", 1);
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
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]"
383 SwTwips nTxtBottom
= nTxtTop
385 "/root/page/anchored/fly/txt[2]"
390 SwTwips nFormula1Top
= getXPath(pXmlDoc
,
391 "/root/page/anchored/fly/txt[2]"
392 "/anchored/fly[1]/infos/bounds",
395 SwTwips nFormula1Bottom
= nFormula1Top
397 "/root/page/anchored/fly/txt[2]"
398 "/anchored/fly[1]/infos/bounds",
402 SwTwips nFormula2Top
= getXPath(pXmlDoc
,
403 "/root/page/anchored/fly/txt[2]"
404 "/anchored/fly[2]/infos/bounds",
407 SwTwips nFormula2Bottom
= nFormula2Top
409 "/root/page/anchored/fly/txt[2]"
410 "/anchored/fly[2]/infos/bounds",
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
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
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)
453 pXmlDoc
, "/root/page[1]/body/tab[1]/row[1]/cell[1]/txt[1]/SwParaPortion/SwLineLayout[1]",
455 u
"Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas porttitor congue ");
457 pXmlDoc
, "/root/page[1]/body/tab[1]/row[1]/cell[1]/txt[1]/SwParaPortion/SwLineLayout[2]",
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
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
);
473 const SwTextNode
* pTextNode
= aNodeIndex
.GetNode().GetTextNode();
474 // Without the accompanying fix in place, this test would have failed with:
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())))
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())))
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())))
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())))
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
550 // i.e. the image position was modified to be inside the page frame ("captured"), even if Word
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
));
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
);
609 = getXPath(pXmlDoc
, "/root/page/body/txt[2]/SwParaPortion/SwLineLayout/SwFixPortion[1]",
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
);
619 = getXPath(pXmlDoc
, "/root/page/body/txt[2]/SwParaPortion/SwLineLayout/SwFixPortion[2]",
622 CPPUNIT_ASSERT_GREATER(sal_Int32(0), nWidth
);
626 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4
, testTdf124423
)
628 createSwDoc("tdf124423.docx");
629 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
631 = getXPath(pXmlDoc
, "(//anchored/fly)[1]/infos/prtBounds", "width").toInt32();
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");
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
697 getXPath(pXml
, "/root/page/infos/bounds", "right").toInt32(),
698 getXPath(pXml
, "/root/page/body/txt[8]/anchored/SwAnchoredDrawObject/bounds", "right")
702 CPPUNIT_TEST_FIXTURE(SwLayoutWriter4
, testTdf135035
)
704 createSwDoc("tdf135035.docx");
705 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
707 = getXPath(pXmlDoc
, "(//anchored/fly)[1]/infos/prtBounds", "width").toInt32();
709 = getXPath(pXmlDoc
, "(//anchored/fly)[2]/infos/prtBounds", "width").toInt32();
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
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
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",
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
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.
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:
902 // How much tables do we have? How much rows does the last table have?
904 = countXPathNodes(pXmlDoc
, "/root/page[" + OString::number(nPage
) + "]/body/section/tab");
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",
915 // Where does the footer start (footer/info/bounds/top)?
917 = getXPath(pXmlDoc
, "/root/page[" + OString::number(nPage
) + "]/footer/infos/bounds", "top")
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",
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']")
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']")
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:
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
1149 "/metafile/push[1]/push[1]/push[1]/push[3]/push[1]/push[1]/push[1]/push[47]/textarray/text",
1153 "/metafile/push[1]/push[1]/push[1]/push[3]/push[1]/push[1]/push[1]/push[49]/textarray/text",
1157 "/metafile/push[1]/push[1]/push[1]/push[3]/push[1]/push[1]/push[1]/push[51]/textarray/text",
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
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]",
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]",
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]",
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:
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",
1214 assertXPathContent(pXmlDoc
,
1215 "/metafile/push[1]/push[1]/push[1]/push[3]/push[1]/push[1]/push[1]/"
1216 "push[104]/textarray/text",
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);
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));
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
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);
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));
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
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")
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]",
1458 CPPUNIT_ASSERT_GREATER(sal_Int32(55), nPor1Width
);
1460 sal_Int32 nPor2Width
1462 "/root/page[1]/body/txt[1]/SwParaPortion/SwLineLayout/SwFieldPortion[1]",
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]",
1471 CPPUNIT_ASSERT_GREATER(sal_Int32(2870), nPor3Width
);
1473 sal_Int32 nPor4Width
1475 "/root/page[1]/body/txt[1]/SwParaPortion/SwLineLayout/SwFieldPortion[2]",
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]",
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",
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",
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",
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();
1580 = getXPath(pXmlDoc
, "/root/page/body/txt/SwParaPortion/SwLineLayout[1]", "height")
1583 = getXPath(pXmlDoc
, "/root/page/body/txt/SwParaPortion/SwLineLayout[2]", "height")
1586 = getXPath(pXmlDoc
, "/root/page/body/txt/SwParaPortion/SwLineLayout[3]", "height")
1589 = getXPath(pXmlDoc
, "/root/page/body/txt/SwParaPortion/SwLineLayout[4]", "height")
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",
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",
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",
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)
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);
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");
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);
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"));
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");
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
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.)");
1745 assertXPath(pXmlDoc
, "//page[2]/body/tab[1]/row/cell/tab/row[2]/cell", 2);
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
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");
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")
1788 = getXPath(pXmlDoc
, "/root/page/body/txt[2]/anchored/fly/txt/infos/bounds", "right")
1792 = getXPath(pXmlDoc
, "/root/page/body/txt[2]/anchored/SwAnchoredDrawObject/bounds", "left")
1795 = getXPath(pXmlDoc
, "/root/page/body/txt[2]/anchored/SwAnchoredDrawObject/bounds", "right")
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")
1815 = getXPath(pXmlDoc
, "/root/page/body/txt[2]/anchored/fly/txt/infos/bounds", "right")
1819 = getXPath(pXmlDoc
, "/root/page/body/txt[2]/anchored/SwAnchoredDrawObject/bounds", "left")
1822 = getXPath(pXmlDoc
, "/root/page/body/txt[2]/anchored/SwAnchoredDrawObject/bounds", "right")
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();
1884 = getXPath(pXmlDoc
, "/root/page[1]/body/tab[1]/row[1]/cell[2]/txt/infos/bounds", "height")
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: */