Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / sw / qa / extras / layout / layout3.cxx
blob9815c72adbd3480a3e2e751ec61359fc27a3dd0f
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/WrapTextMode.hpp>
14 #include <vcl/event.hxx>
15 #include <vcl/scheduler.hxx>
16 #include <editeng/fontitem.hxx>
17 #include <editeng/fhgtitem.hxx>
18 #include <editeng/postitem.hxx>
19 #include <editeng/unolingu.hxx>
20 #include <editeng/editobj.hxx>
21 #include <comphelper/sequence.hxx>
23 #include <fmtfsize.hxx>
24 #include <wrtsh.hxx>
25 #include <edtwin.hxx>
26 #include <view.hxx>
27 #include <txtfrm.hxx>
28 #include <pagefrm.hxx>
29 #include <bodyfrm.hxx>
30 #include <sortedobjs.hxx>
31 #include <ndtxt.hxx>
32 #include <frmatr.hxx>
33 #include <IDocumentSettingAccess.hxx>
34 #include <unotxdoc.hxx>
35 #include <rootfrm.hxx>
36 #include <IDocumentLayoutAccess.hxx>
37 #include <IDocumentDrawModelAccess.hxx>
38 #include <unoframe.hxx>
39 #include <drawdoc.hxx>
40 #include <svx/svdpage.hxx>
41 #include <svx/svdotext.hxx>
42 #include <dcontact.hxx>
43 #include <frameformats.hxx>
45 /// Test to assert layout / rendering result of Writer.
46 class SwLayoutWriter3 : public SwModelTestBase
48 public:
49 SwLayoutWriter3()
50 : SwModelTestBase("/sw/qa/extras/layout/data/")
55 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf134463)
57 createSwDoc("tdf134463.docx");
58 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
59 // This was 621. The previous paragraph must have zero bottom border.
60 assertXPath(pXmlDoc, "/root/page/body/txt[3]/infos/prtBounds", "top", "21");
63 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf117188)
65 createSwDoc("tdf117188.docx");
66 saveAndReload("writer8");
67 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
68 OUString sWidth = getXPath(pXmlDoc, "/root/page/body/txt/anchored/fly/infos/bounds", "width");
69 OUString sHeight = getXPath(pXmlDoc, "/root/page/body/txt/anchored/fly/infos/bounds", "height");
70 // The text box must have zero border distances
71 assertXPath(pXmlDoc, "/root/page/body/txt/anchored/fly/infos/prtBounds", "left", "0");
72 assertXPath(pXmlDoc, "/root/page/body/txt/anchored/fly/infos/prtBounds", "top", "0");
73 assertXPath(pXmlDoc, "/root/page/body/txt/anchored/fly/infos/prtBounds", "width", sWidth);
74 assertXPath(pXmlDoc, "/root/page/body/txt/anchored/fly/infos/prtBounds", "height", sHeight);
77 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf117187)
79 createSwDoc("tdf117187.odt");
80 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
82 // there should be no fly portions
83 assertXPath(
84 pXmlDoc,
85 "/root/page/body/txt/SwParaPortion/SwLineLayout/child::*[@nType='PortionType::Fly']", 0);
88 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf119875)
90 createSwDoc("tdf119875.odt");
91 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
92 sal_Int32 nFirstTop
93 = getXPath(pXmlDoc, "/root/page[2]/body/section[1]/infos/bounds", "top").toInt32();
94 sal_Int32 nSecondTop
95 = getXPath(pXmlDoc, "/root/page[2]/body/section[2]/infos/bounds", "top").toInt32();
96 // The first section had the same top value as the second one, so they
97 // overlapped.
98 CPPUNIT_ASSERT_LESS(nSecondTop, nFirstTop);
101 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf137523)
103 createSwDoc("tdf137523-1-min.fodt");
104 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
105 // the problem was that in the footer, the text frames below the table
106 // had wrong height and were not visible
107 assertXPath(pXmlDoc, "/root/page/footer/txt[1]/infos/bounds", "height", "304");
108 assertXPath(pXmlDoc, "/root/page/footer/txt[2]/infos/bounds", "height", "191");
109 assertXPath(pXmlDoc, "/root/page/footer/txt[3]/infos/bounds", "height", "219");
110 assertXPath(pXmlDoc, "/root/page/footer/tab/infos/bounds", "height", "1378");
113 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf120287)
115 createSwDoc("tdf120287.fodt");
116 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
117 // This was 2, TabOverMargin Word-specific compat flag did not imply
118 // default-in-Word printer-independent layout, resulting in an additional
119 // line break.
120 assertXPath(pXmlDoc, "/root/page/body/txt[1]/SwParaPortion/SwLineLayout", 1);
123 static auto getXPathIntAttributeValue(xmlXPathContextPtr pXmlXpathCtx, char const* const pXPath)
124 -> sal_Int32
126 xmlXPathObjectPtr pXmlXpathObj = xmlXPathEvalExpression(BAD_CAST(pXPath), pXmlXpathCtx);
127 CPPUNIT_ASSERT(pXmlXpathObj->nodesetval);
128 CPPUNIT_ASSERT_EQUAL(1, xmlXPathNodeSetGetLength(pXmlXpathObj->nodesetval));
129 auto ret
130 = sal_Int32(xmlXPathCastNodeToNumber(xmlXPathNodeSetItem(pXmlXpathObj->nodesetval, 0)));
131 xmlXPathFreeObject(pXmlXpathObj);
132 return ret;
135 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf128966)
137 createSwDoc("tdf128966-2-min.odt");
139 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
141 xmlXPathObjectPtr pXmlObj
142 = getXPathNode(pXmlDoc, "/root/page/body/tab/row/cell[@rowspan > 0][child::txt]");
143 xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
144 CPPUNIT_ASSERT(pXmlNodes);
145 CPPUNIT_ASSERT_GREATER(300, xmlXPathNodeSetGetLength(pXmlNodes)); // many...
147 xmlXPathContextPtr pXmlXpathCtx = xmlXPathNewContext(pXmlDoc.get());
148 registerNamespaces(pXmlXpathCtx);
150 for (int i = 0; i < xmlXPathNodeSetGetLength(pXmlNodes); ++i)
152 xmlNodePtr pNode = xmlXPathNodeSetItem(pXmlNodes, i);
153 xmlXPathSetContextNode(pNode, pXmlXpathCtx);
155 OString msg("Cell nr.: " + OString::number(i)
156 + " id=" + OString::number(getXPathIntAttributeValue(pXmlXpathCtx, "@id")));
158 auto nCellTop = getXPathIntAttributeValue(pXmlXpathCtx, "infos/bounds/@top");
159 auto nCellHeight = getXPathIntAttributeValue(pXmlXpathCtx, "infos/bounds/@height");
160 auto nCellCenter = nCellTop + (nCellHeight / 2);
162 auto nContentTop
163 = getXPathIntAttributeValue(pXmlXpathCtx, "txt[position()=1]/infos/bounds/@top");
164 auto nContentBottom = getXPathIntAttributeValue(
165 pXmlXpathCtx, "txt[position()=last()]/infos/bounds/@bottom");
167 CPPUNIT_ASSERT_MESSAGE(msg.getStr(), nContentTop < nCellCenter);
168 CPPUNIT_ASSERT_MESSAGE(msg.getStr(), nContentBottom > nCellCenter);
171 xmlXPathFreeContext(pXmlXpathCtx);
172 xmlXPathFreeObject(pXmlObj);
175 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf106234)
177 createSwDoc("tdf106234.fodt");
178 // Ensure that all text portions are calculated before testing.
179 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
180 CPPUNIT_ASSERT(pTextDoc);
181 SwViewShell* pViewShell
182 = pTextDoc->GetDocShell()->GetDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
183 CPPUNIT_ASSERT(pViewShell);
184 pViewShell->Reformat();
186 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
187 // In justified paragraphs, there is justification between left tabulators and manual line breaks
188 assertXPath(pXmlDoc, "/root/page/body/txt[1]/SwParaPortion/SwLineLayout[1]/SwGluePortion",
189 "type", "PortionType::Margin");
190 assertXPath(pXmlDoc, "/root/page/body/txt[1]/SwParaPortion/SwLineLayout[1]/SwGluePortion",
191 "width", "0");
192 // but not after centered, right and decimal tabulators
193 assertXPath(pXmlDoc, "/root/page/body/txt[2]/SwParaPortion/SwLineLayout[1]/SwGluePortion",
194 "type", "PortionType::Margin");
195 // This was a justified line, without width
196 assertXPath(pXmlDoc, "/root/page/body/txt[2]/SwParaPortion/SwLineLayout[1]/SwGluePortion",
197 "width", "7881");
200 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf155324)
202 createSwDoc("tox-update-wrong-pages.odt");
204 dispatchCommand(mxComponent, ".uno:UpdateAllIndexes", {});
206 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
208 // the problem was that the first entry was on page 7, 2nd on page 9 etc.
209 assertXPath(pXmlDoc,
210 "/root/page[1]/body/section[2]/txt[1]/SwParaPortion/SwLineLayout/SwLinePortion[1]",
211 "portion", "Foo");
212 assertXPath(pXmlDoc,
213 "/root/page[1]/body/section[2]/txt[1]/SwParaPortion/SwLineLayout/SwLinePortion[2]",
214 "portion", "5");
215 assertXPath(pXmlDoc,
216 "/root/page[1]/body/section[2]/txt[2]/SwParaPortion/SwLineLayout/SwLinePortion[1]",
217 "portion", "bar");
218 assertXPath(pXmlDoc,
219 "/root/page[1]/body/section[2]/txt[2]/SwParaPortion/SwLineLayout/SwLinePortion[2]",
220 "portion", "7");
221 assertXPath(pXmlDoc,
222 "/root/page[1]/body/section[2]/txt[3]/SwParaPortion/SwLineLayout/SwLinePortion[1]",
223 "portion", "Three");
224 assertXPath(pXmlDoc,
225 "/root/page[1]/body/section[2]/txt[3]/SwParaPortion/SwLineLayout/SwLinePortion[2]",
226 "portion", "7");
228 // check first content page has the footnotes
229 assertXPath(pXmlDoc, "/root/page[5]/body/txt[1]/SwParaPortion/SwLineLayout", "portion", "Foo");
230 assertXPath(pXmlDoc, "/root/page[4]/ftncont", 0);
231 assertXPath(pXmlDoc, "/root/page[5]/ftncont/ftn", 5);
234 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf120287b)
236 createSwDoc("tdf120287b.fodt");
237 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
238 // This was 1418, TabOverMargin did the right split of the paragraph to two
239 // lines, but then calculated a too large tab portion size on the first
240 // line.
241 assertXPath(
242 pXmlDoc,
243 "/root/page/body/txt[1]/SwParaPortion/SwLineLayout/child::*[@type='PortionType::TabRight']",
244 "width", "17");
247 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf120287c)
249 createSwDoc("tdf120287c.fodt");
250 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
251 // This was 2, the second line was not broken into a 2nd and a 3rd one,
252 // rendering text outside the paragraph frame.
253 assertXPath(pXmlDoc, "/root/page/body/txt[1]/SwParaPortion/SwLineLayout", 3);
256 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf155177)
258 createSwDoc("tdf155177-1-min.odt");
260 uno::Reference<beans::XPropertySet> xStyle(getStyles("ParagraphStyles")->getByName("Body Text"),
261 uno::UNO_QUERY_THROW);
262 CPPUNIT_ASSERT_EQUAL(sal_Int32(210), getProperty<sal_Int32>(xStyle, "ParaTopMargin"));
265 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
266 assertXPath(pXmlDoc, "/root/page[2]/body/txt", 6);
267 assertXPath(pXmlDoc, "/root/page[2]/body/txt[6]/SwParaPortion/SwLineLayout", 2);
268 assertXPath(pXmlDoc, "/root/page[2]/body/txt[6]/SwParaPortion/SwLineLayout[2]", "portion",
269 "long as two lines.");
270 assertXPath(pXmlDoc, "/root/page[3]/body/txt[1]/SwParaPortion/SwLineLayout", 3);
271 assertXPath(pXmlDoc, "/root/page[3]/body/txt[1]/SwParaPortion/SwLineLayout[1]", "portion",
272 "This paragraph is even longer so that ");
273 discardDumpedLayout();
276 // this should bring one line back
277 xStyle->setPropertyValue("ParaTopMargin", uno::Any(sal_Int32(200)));
279 Scheduler::ProcessEventsToIdle();
282 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
283 assertXPath(pXmlDoc, "/root/page[2]/body/txt", 7);
284 assertXPath(pXmlDoc, "/root/page[2]/body/txt[7]/SwParaPortion/SwLineLayout", 1);
285 assertXPath(pXmlDoc, "/root/page[2]/body/txt[7]/SwParaPortion/SwLineLayout[1]", "portion",
286 "This paragraph is even longer so that ");
287 assertXPath(pXmlDoc, "/root/page[3]/body/txt[1]/SwParaPortion/SwLineLayout", 2);
288 assertXPath(pXmlDoc, "/root/page[3]/body/txt[1]/SwParaPortion/SwLineLayout[1]", "portion",
289 "it is now three lines long though ");
290 discardDumpedLayout();
293 // this should bring second line back
294 xStyle->setPropertyValue("ParaTopMargin", uno::Any(sal_Int32(120)));
296 Scheduler::ProcessEventsToIdle();
299 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
300 assertXPath(pXmlDoc, "/root/page[2]/body/txt", 7);
301 assertXPath(pXmlDoc, "/root/page[2]/body/txt[7]/SwParaPortion/SwLineLayout", 2);
302 assertXPath(pXmlDoc, "/root/page[2]/body/txt[7]/SwParaPortion/SwLineLayout[1]", "portion",
303 "This paragraph is even longer so that ");
304 assertXPath(pXmlDoc, "/root/page[2]/body/txt[7]/SwParaPortion/SwLineLayout[2]", "portion",
305 "it is now three lines long though ");
306 assertXPath(pXmlDoc, "/root/page[3]/body/txt[1]/SwParaPortion/SwLineLayout", 1);
307 assertXPath(pXmlDoc, "/root/page[3]/body/txt[1]/SwParaPortion/SwLineLayout[1]", "portion",
308 "containing a single sentence.");
309 discardDumpedLayout();
313 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf122878)
315 createSwDoc("tdf122878.docx");
316 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
317 const sal_Int32 nTblTop
318 = getXPath(pXmlDoc, "/root/page[1]/footer/txt/anchored/fly/tab/infos/bounds", "top")
319 .toInt32();
320 SwDoc* pDoc = getSwDoc();
321 SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
322 auto pPage1 = dynamic_cast<SwPageFrame*>(pLayout->Lower());
323 CPPUNIT_ASSERT(pPage1);
324 SwFrame* pBody = pPage1->FindBodyCont();
325 for (SwFrame* pFrame = pBody->GetLower(); pFrame; pFrame = pFrame->GetNext())
327 const sal_Int32 nTxtBottom = pFrame->getFrameArea().Bottom();
328 // No body paragraphs should overlap the table in the footer
329 CPPUNIT_ASSERT_MESSAGE(
330 OString("testing paragraph #" + OString::number(pFrame->GetFrameId())).getStr(),
331 nTxtBottom <= nTblTop);
335 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf115094)
337 createSwDoc("tdf115094.docx");
338 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
340 sal_Int32 nTopOfD1
341 = getXPath(pXmlDoc, "/root/page/body/txt/anchored/fly/tab/row[1]/cell[4]/infos/bounds",
342 "top")
343 .toInt32();
344 sal_Int32 nTopOfD1Anchored = getXPath(pXmlDoc,
345 "/root/page/body/txt/anchored/fly/tab/row[1]/cell[4]/"
346 "txt[2]/anchored/fly/infos/bounds",
347 "top")
348 .toInt32();
349 CPPUNIT_ASSERT_LESS(nTopOfD1Anchored, nTopOfD1);
350 sal_Int32 nTopOfB2
351 = getXPath(pXmlDoc, "/root/page/body/txt/anchored/fly/tab/row[2]/cell[2]/infos/bounds",
352 "top")
353 .toInt32();
354 sal_Int32 nTopOfB2Anchored = getXPath(pXmlDoc,
355 "/root/page/body/txt/anchored/fly/tab/row[2]/cell[2]/"
356 "txt[1]/anchored/fly/infos/bounds",
357 "top")
358 .toInt32();
359 CPPUNIT_ASSERT_LESS(nTopOfB2Anchored, nTopOfB2);
362 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf112290)
364 createSwDoc("tdf112290.docx");
365 SwDoc* pDoc = getSwDoc();
366 CPPUNIT_ASSERT(pDoc);
367 auto pXml = parseLayoutDump();
368 assertXPath(pXml, "/root/page/body/txt/SwParaPortion/SwLineLayout[2]", "portion", "Xxxx Xxxx");
371 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testKeepWithNextPlusFlyFollowTextFlow)
373 createSwDoc("keep-with-next-fly.fodt");
376 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
377 // 3 text frames on page 1
378 assertXPath(pXmlDoc, "/root/page[1]/body/infos/bounds", "bottom", "7540");
379 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/infos/bounds", "height", "276");
380 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/infos/bounds", "height", "276");
381 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly", 1);
382 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly/infos/bounds", "top", "1694");
383 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/infos/bounds", "height", "276");
384 assertXPath(pXmlDoc, "/root/page", 1);
385 discardDumpedLayout();
388 dispatchCommand(mxComponent, ".uno:Fieldnames", {});
391 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
392 // 1 text frame on page 1, and some empty space
393 assertXPath(pXmlDoc, "/root/page[1]/body/infos/bounds", "bottom", "7540");
394 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/infos/bounds", "height", "5796");
395 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/infos/bounds", "bottom", "7213");
396 // 2 text frames on page 2
397 assertXPath(pXmlDoc, "/root/page[2]/body/txt[1]/infos/bounds", "height", "276");
398 assertXPath(pXmlDoc, "/root/page[2]/body/txt[1]/anchored/fly", 1);
399 assertXPath(pXmlDoc, "/root/page[2]/body/txt[1]/anchored/fly/infos/bounds", "top", "10093");
400 assertXPath(pXmlDoc, "/root/page[2]/body/txt[2]/infos/bounds", "height", "276");
401 assertXPath(pXmlDoc, "/root/page", 2);
402 discardDumpedLayout();
405 dispatchCommand(mxComponent, ".uno:Fieldnames", {});
408 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
409 // 3 text frames on page 1
410 assertXPath(pXmlDoc, "/root/page[1]/body/infos/bounds", "bottom", "7540");
411 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/infos/bounds", "height", "276");
412 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/infos/bounds", "height", "276");
413 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly", 1);
414 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly/infos/bounds", "top", "1694");
415 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/infos/bounds", "height", "276");
416 assertXPath(pXmlDoc, "/root/page", 1);
417 discardDumpedLayout();
421 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf122607)
423 createSwDoc("tdf122607.odt");
424 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
425 assertXPath(pXmlDoc,
426 "/root/page[1]/anchored/fly/txt[1]/anchored/fly/tab/row[2]/cell/txt[7]/anchored/"
427 "fly/txt/SwParaPortion/SwLineLayout/child::*[1]",
428 "height", "253");
429 assertXPath(pXmlDoc,
430 "/root/page[1]/anchored/fly/txt[1]/anchored/fly/tab/row[2]/cell/txt[7]/anchored/"
431 "fly/txt/SwParaPortion/SwLineLayout/child::*[1]",
432 "width", "428");
433 assertXPath(pXmlDoc,
434 "/root/page[1]/anchored/fly/txt[1]/anchored/fly/tab/row[2]/cell/txt[7]/anchored/"
435 "fly/txt/SwParaPortion/SwLineLayout/child::*[1]",
436 "portion", "Fax:");
439 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf122607_regression)
441 discardDumpedLayout();
442 if (mxComponent.is())
443 mxComponent->dispose();
445 OUString const url(createFileURL(u"tdf122607_leerzeile.odt"));
447 // note: must set Hidden property, so that SfxFrameViewWindow_Impl::Resize()
448 // does *not* forward initial VCL Window Resize and thereby triggers a
449 // layout which does not happen on soffice --convert-to pdf.
450 std::vector<beans::PropertyValue> aFilterOptions = {
451 { beans::PropertyValue("Hidden", -1, uno::Any(true), beans::PropertyState_DIRECT_VALUE) },
454 // inline the loading because currently properties can't be passed...
455 mxComponent = loadFromDesktop(url, "com.sun.star.text.TextDocument",
456 comphelper::containerToSequence(aFilterOptions));
457 uno::Sequence<beans::PropertyValue> props(comphelper::InitPropertySequence({
458 { "FilterName", uno::Any(OUString("writer_pdf_Export")) },
459 }));
460 utl::TempFileNamed aTempFile;
461 uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
462 xStorable->storeToURL(aTempFile.GetURL(), props);
464 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
465 // somehow these 2 rows overlapped in the PDF unless CalcLayout() runs
466 assertXPath(pXmlDoc, "/root/page[1]/anchored/fly/tab[1]/row[1]/infos/bounds", "mbFixSize",
467 "false");
468 assertXPath(pXmlDoc, "/root/page[1]/anchored/fly/tab[1]/row[1]/infos/bounds", "top", "2977");
469 assertXPath(pXmlDoc, "/root/page[1]/anchored/fly/tab[1]/row[1]/infos/bounds", "height", "241");
470 assertXPath(pXmlDoc, "/root/page[1]/anchored/fly/tab[1]/row[2]/infos/bounds", "mbFixSize",
471 "true");
472 // this was 3034, causing the overlap
473 assertXPath(pXmlDoc, "/root/page[1]/anchored/fly/tab[1]/row[2]/infos/bounds", "top", "3218");
474 assertXPath(pXmlDoc, "/root/page[1]/anchored/fly/tab[1]/row[2]/infos/bounds", "height", "164");
476 aTempFile.EnableKillingFile();
479 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, TestTdf150616)
481 discardDumpedLayout();
482 if (mxComponent.is())
483 mxComponent->dispose();
485 OUString const url(createFileURL(u"in_056132_mod.odt"));
487 // note: must set Hidden property, so that SfxFrameViewWindow_Impl::Resize()
488 // does *not* forward initial VCL Window Resize and thereby triggers a
489 // layout which does not happen on soffice --convert-to pdf.
490 std::vector<beans::PropertyValue> aFilterOptions = {
491 { beans::PropertyValue("Hidden", -1, uno::Any(true), beans::PropertyState_DIRECT_VALUE) },
494 // inline the loading because currently properties can't be passed...
495 mxComponent = loadFromDesktop(url, "com.sun.star.text.TextDocument",
496 comphelper::containerToSequence(aFilterOptions));
497 uno::Sequence<beans::PropertyValue> props(comphelper::InitPropertySequence({
498 { "FilterName", uno::Any(OUString("writer_pdf_Export")) },
499 }));
500 utl::TempFileNamed aTempFile;
501 uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
502 xStorable->storeToURL(aTempFile.GetURL(), props);
504 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
505 CPPUNIT_ASSERT(pXmlDoc);
507 // this one was 0 height
508 assertXPath(pXmlDoc,
509 "/root/page[1]/body/tab[3]/row[2]/cell[2]/txt[2]/SwParaPortion/SwLineLayout",
510 "portion", "Important information here!");
511 assertXPath(pXmlDoc, "/root/page[1]/body/tab[3]/row[2]/cell[2]/txt[2]/infos/bounds", "height",
512 "253");
513 assertXPath(pXmlDoc, "/root/page[1]/body/tab[3]/row[2]/cell[2]/txt[2]/infos/bounds", "top",
514 "7925");
515 assertXPath(pXmlDoc,
516 "/root/page[1]/body/tab[3]/row[2]/cell[2]/txt[3]/SwParaPortion/SwLineLayout",
517 "portion", "xxx 111 ");
518 assertXPath(pXmlDoc, "/root/page[1]/body/tab[3]/row[2]/cell[2]/txt[3]/infos/bounds", "height",
519 "697");
520 assertXPath(pXmlDoc, "/root/page[1]/body/tab[3]/row[2]/cell[2]/txt[3]/infos/bounds", "top",
521 "8178");
523 aTempFile.EnableKillingFile();
526 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testBtlrCell)
528 createSwDoc("btlr-cell.odt");
529 SwDoc* pDoc = getSwDoc();
530 SwDocShell* pShell = pDoc->GetDocShell();
532 // Dump the rendering of the first page as an XML file.
533 std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
534 MetafileXmlDump dumper;
535 xmlDocUniquePtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
536 CPPUNIT_ASSERT(pXmlDoc);
538 // Without the accompanying fix in place, this test would have failed, as
539 // the orientation was 0 (layout did not take btlr direction request from
540 // doc model).
541 assertXPath(pXmlDoc, "//font[1]", "orientation", "900");
543 #if !defined(MACOSX) && !defined(_WIN32) // macOS fails with x == 2662 for some reason.
544 // Without the accompanying fix in place, this test would have failed with 'Expected: 1915;
545 // Actual : 1756', i.e. the AAA1 text was too close to the left cell border due to an ascent vs
546 // descent mismatch when calculating the baseline offset of the text portion.
547 assertXPath(pXmlDoc, "//textarray[1]", "x", "1915");
548 assertXPath(pXmlDoc, "//textarray[1]", "y", "2707");
550 // Without the accompanying fix in place, this test would have failed with 'Expected: 1979;
551 // Actual : 2129', i.e. the gray background of the "AAA2." text was too close to the right edge
552 // of the text portion. Now it's exactly behind the text portion.
553 assertXPath(pXmlDoc, "(//rect)[2]", "left", "1979");
555 // Without the accompanying fix in place, this test would have failed with 'Expected: 269;
556 // Actual : 0', i.e. the AAA2 frame was not visible due to 0 width.
557 pXmlDoc = parseLayoutDump();
558 assertXPath(pXmlDoc, "/root/page/body/tab/row/cell[1]/txt[2]/infos/bounds", "width", "269");
560 // Test the position of the cursor after doc load.
561 // We expect that it's inside the first text frame in the first cell.
562 // More precisely, this is a bottom to top vertical frame, so we expect it's at the start, which
563 // means it's at the lower half of the text frame rectangle (vertically).
564 SwWrtShell* pWrtShell = pShell->GetWrtShell();
565 CPPUNIT_ASSERT(pWrtShell);
567 const SwRect& rCharRect = pWrtShell->GetCharRect();
568 SwTwips nFirstParaTop
569 = getXPath(pXmlDoc, "/root/page/body/tab/row/cell[1]/txt[1]/infos/bounds", "top").toInt32();
570 SwTwips nFirstParaHeight
571 = getXPath(pXmlDoc, "/root/page/body/tab/row/cell[1]/txt[1]/infos/bounds", "height")
572 .toInt32();
573 SwTwips nFirstParaMiddle = nFirstParaTop + nFirstParaHeight / 2;
574 SwTwips nFirstParaBottom = nFirstParaTop + nFirstParaHeight;
575 // Without the accompanying fix in place, this test would have failed: the lower half (vertical)
576 // range was 2273 -> 2835, the good vertical position is 2730, the bad one was 1830.
577 CPPUNIT_ASSERT_GREATER(nFirstParaMiddle, rCharRect.Top());
578 CPPUNIT_ASSERT_LESS(nFirstParaBottom, rCharRect.Top());
580 // Save initial cursor position.
581 SwPosition aCellStart = *pWrtShell->GetCursor()->Start();
583 // Test that pressing "up" at the start of the cell goes to the next character position.
584 SwNodeOffset nNodeIndex = pWrtShell->GetCursor()->Start()->GetNodeIndex();
585 sal_Int32 nIndex = pWrtShell->GetCursor()->Start()->GetContentIndex();
586 KeyEvent aKeyEvent(0, KEY_UP);
587 SwEditWin& rEditWin = pShell->GetView()->GetEditWin();
588 rEditWin.KeyInput(aKeyEvent);
589 Scheduler::ProcessEventsToIdle();
590 // Without the accompanying fix in place, this test would have failed: "up" was interpreted as
591 // logical "left", which does nothing if you're at the start of the text anyway.
592 CPPUNIT_ASSERT_EQUAL(nIndex + 1, pWrtShell->GetCursor()->Start()->GetContentIndex());
594 // Test that pressing "right" goes to the next paragraph (logical "down").
595 sal_Int32 nContentIndex = pWrtShell->GetCursor()->Start()->GetContentIndex();
596 aKeyEvent = KeyEvent(0, KEY_RIGHT);
597 rEditWin.KeyInput(aKeyEvent);
598 Scheduler::ProcessEventsToIdle();
599 // Without the accompanying fix in place, this test would have failed: the cursor went to the
600 // paragraph after the table.
601 CPPUNIT_ASSERT_EQUAL(nNodeIndex + 1, pWrtShell->GetCursor()->Start()->GetNodeIndex());
603 // Test that we have the correct character index after traveling to the next paragraph.
604 // Without the accompanying fix in place, this test would have failed: char position was 5, i.e.
605 // the cursor jumped to the end of the paragraph for no reason.
606 CPPUNIT_ASSERT_EQUAL(nContentIndex, pWrtShell->GetCursor()->Start()->GetContentIndex());
608 // Test that clicking "below" the second paragraph positions the cursor at the start of the
609 // second paragraph.
610 SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
611 SwPosition aPosition(aCellStart);
612 SwTwips nSecondParaLeft
613 = getXPath(pXmlDoc, "/root/page/body/tab/row/cell[1]/txt[2]/infos/bounds", "left")
614 .toInt32();
615 SwTwips nSecondParaWidth
616 = getXPath(pXmlDoc, "/root/page/body/tab/row/cell[1]/txt[2]/infos/bounds", "width")
617 .toInt32();
618 SwTwips nSecondParaTop
619 = getXPath(pXmlDoc, "/root/page/body/tab/row/cell[1]/txt[2]/infos/bounds", "top").toInt32();
620 SwTwips nSecondParaHeight
621 = getXPath(pXmlDoc, "/root/page/body/tab/row/cell[1]/txt[2]/infos/bounds", "height")
622 .toInt32();
623 Point aPoint;
624 aPoint.setX(nSecondParaLeft + nSecondParaWidth / 2);
625 aPoint.setY(nSecondParaTop + nSecondParaHeight - 100);
626 SwCursorMoveState aState(CursorMoveState::NONE);
627 pLayout->GetModelPositionForViewPoint(&aPosition, aPoint, &aState);
628 CPPUNIT_ASSERT_EQUAL(aCellStart.GetNodeIndex() + 1, aPosition.GetNodeIndex());
629 // Without the accompanying fix in place, this test would have failed: character position was 5,
630 // i.e. cursor was at the end of the paragraph.
631 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0), aPosition.GetContentIndex());
633 // Test that the selection rectangles are inside the cell frame if we select all the cell
634 // content.
635 SwTwips nCellLeft
636 = getXPath(pXmlDoc, "/root/page/body/tab/row/cell[1]/infos/bounds", "left").toInt32();
637 SwTwips nCellWidth
638 = getXPath(pXmlDoc, "/root/page/body/tab/row/cell[1]/infos/bounds", "width").toInt32();
639 SwTwips nCellTop
640 = getXPath(pXmlDoc, "/root/page/body/tab/row/cell[1]/infos/bounds", "top").toInt32();
641 SwTwips nCellHeight
642 = getXPath(pXmlDoc, "/root/page/body/tab/row/cell[1]/infos/bounds", "height").toInt32();
643 SwRect aCellRect(Point(nCellLeft, nCellTop), Size(nCellWidth, nCellHeight));
644 pWrtShell->SelAll();
645 SwShellCursor* pShellCursor = pWrtShell->getShellCursor(/*bBlock=*/false);
646 CPPUNIT_ASSERT(!pShellCursor->empty());
647 // Without the accompanying fix in place, this test would have failed with:
648 // selection rectangle 269x2573@(1970,2172) is not inside cell rectangle 3207x1134@(1593,1701)
649 // i.e. the selection went past the bottom border of the cell frame.
650 for (const auto& rRect : *pShellCursor)
652 std::stringstream ss;
653 ss << "selection rectangle " << rRect << " is not inside cell rectangle " << aCellRect;
654 CPPUNIT_ASSERT_MESSAGE(ss.str(), aCellRect.Contains(rRect));
657 // Make sure that the correct rectangle gets repainted on scroll.
658 SwFrame* pPageFrame = pLayout->GetLower();
659 CPPUNIT_ASSERT(pPageFrame->IsPageFrame());
661 SwFrame* pBodyFrame = pPageFrame->GetLower();
662 CPPUNIT_ASSERT(pBodyFrame->IsBodyFrame());
664 SwFrame* pTabFrame = pBodyFrame->GetLower();
665 CPPUNIT_ASSERT(pTabFrame->IsTabFrame());
667 SwFrame* pRowFrame = pTabFrame->GetLower();
668 CPPUNIT_ASSERT(pRowFrame->IsRowFrame());
670 SwFrame* pCellFrame = pRowFrame->GetLower();
671 CPPUNIT_ASSERT(pCellFrame->IsCellFrame());
673 SwFrame* pFrame = pCellFrame->GetLower();
674 CPPUNIT_ASSERT(pFrame->IsTextFrame());
676 SwTextFrame* pTextFrame = static_cast<SwTextFrame*>(pFrame);
677 pTextFrame->SwapWidthAndHeight();
678 // Mimic what normally SwTextFrame::PaintSwFrame() does:
679 SwRect aRect(4207, 2273, 269, 572);
680 pTextFrame->SwitchVerticalToHorizontal(aRect);
681 // Without the accompanying fix in place, this test would have failed with:
682 // Expected: 572x269@(1691,4217)
683 // Actual : 572x269@(2263,4217)
684 // i.e. the paint rectangle position was incorrect, text was not painted on scrolling up.
685 CPPUNIT_ASSERT_EQUAL(SwRect(1691, 4217, 572, 269), aRect);
686 #endif
689 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf123898)
691 createSwDoc("tdf123898.odt");
693 // Make sure spellchecker has done its job already
694 Scheduler::ProcessEventsToIdle();
696 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
697 // Make sure that the arrow on the left is not there (the first portion's type is
698 // PortionType::Arrow if it's there)
699 assertXPath(pXmlDoc,
700 "/root/page/body/txt/anchored/fly/txt/SwParaPortion/SwLineLayout[1]/child::*[1]",
701 "type", "PortionType::Para");
704 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf123651)
706 createSwDoc("tdf123651.docx");
707 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
708 // Without the accompanying fix in place, this test would have failed with 'Expected: 7639;
709 // Actual: 12926'. The shape was below the second "Lorem ipsum" text, not above it.
710 const sal_Int32 nTopValue
711 = getXPath(pXmlDoc, "//anchored/SwAnchoredDrawObject/bounds", "top").toInt32();
712 CPPUNIT_ASSERT_DOUBLES_EQUAL(7639, nTopValue, 10);
715 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf116501)
717 //just care it doesn't freeze
718 createSwDoc("tdf116501.odt");
721 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf123163)
723 //just care it doesn't assert
724 createSwDoc("tdf123163-1.docx");
727 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testAbi11870)
729 //just care it doesn't assert
730 createSwDoc("abi11870-2.odt");
733 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf118719)
735 // Insert a page break.
736 createSwDoc();
737 SwDoc* pDoc = getSwDoc();
738 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
740 // Enable hide whitespace mode.
741 SwViewOption aViewOptions(*pWrtShell->GetViewOptions());
742 aViewOptions.SetHideWhitespaceMode(true);
743 pWrtShell->ApplyViewOptions(aViewOptions);
745 pWrtShell->Insert("first");
746 pWrtShell->InsertPageBreak();
747 pWrtShell->Insert("second");
749 // Without the accompanying fix in place, this test would have failed, as the height of the
750 // first page was 15840 twips, instead of the much smaller 276.
751 sal_Int32 nOther = parseDump("/root/page[1]/infos/bounds", "height").toInt32();
752 sal_Int32 nLast = parseDump("/root/page[2]/infos/bounds", "height").toInt32();
753 CPPUNIT_ASSERT_GREATER(nOther, nLast);
756 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTabOverMargin)
758 createSwDoc("tab-over-margin.odt");
759 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
761 // 2nd paragraph has a tab over the right margin, and with the TabOverMargin compat option,
762 // there is enough space to have all content in a single line.
763 // Without the accompanying fix in place, this test would have failed, there were 2 lines.
764 assertXPath(pXmlDoc, "/root/page/body/txt[2]/SwParaPortion/SwLineLayout", 1);
767 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testImageComment)
769 // Load a document that has "aaa" in it, then a commented image (4th char is the as-char image,
770 // 5th char is the comment anchor).
771 createSwDoc("image-comment.odt");
772 SwDoc* pDoc = getSwDoc();
773 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
775 // Look up a layout position which is on the right of the image.
776 SwRootFrame* pRoot = pWrtShell->GetLayout();
777 CPPUNIT_ASSERT(pRoot->GetLower()->IsPageFrame());
778 SwPageFrame* pPage = static_cast<SwPageFrame*>(pRoot->GetLower());
779 CPPUNIT_ASSERT(pPage->GetLower()->IsBodyFrame());
780 SwBodyFrame* pBody = static_cast<SwBodyFrame*>(pPage->GetLower());
781 CPPUNIT_ASSERT(pBody->GetLower()->IsTextFrame());
782 SwTextFrame* pTextFrame = static_cast<SwTextFrame*>(pBody->GetLower());
783 CPPUNIT_ASSERT(pTextFrame->GetDrawObjs());
784 SwSortedObjs& rDrawObjs = *pTextFrame->GetDrawObjs();
785 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rDrawObjs.size());
786 SwAnchoredObject* pDrawObj = rDrawObjs[0];
787 const SwRect& rDrawObjRect = pDrawObj->GetObjRect();
788 Point aPoint = rDrawObjRect.Center();
789 aPoint.setX(aPoint.getX() + rDrawObjRect.Width() / 2);
791 // Ask for the doc model pos of this layout point.
792 SwPosition aPosition(*pTextFrame->GetTextNodeForFirstText());
793 pTextFrame->GetModelPositionForViewPoint(&aPosition, aPoint);
795 // Without the accompanying fix in place, this test would have failed with:
796 // - Expected: 5
797 // - Actual : 4
798 // i.e. the cursor got positioned between the image and its comment, so typing extended the
799 // comment, instead of adding content after the commented image.
800 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(5), aPosition.GetContentIndex());
803 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testScriptField)
805 // Test clicking script field inside table ( tdf#141079 )
806 createSwDoc("tdf141079.odt");
807 SwDoc* pDoc = getSwDoc();
808 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
810 // Look up layout position which is the first cell in the table
811 SwRootFrame* pRoot = pWrtShell->GetLayout();
812 CPPUNIT_ASSERT(pRoot->GetLower()->IsPageFrame());
813 SwPageFrame* pPage = static_cast<SwPageFrame*>(pRoot->GetLower());
814 CPPUNIT_ASSERT(pPage->GetLower()->IsBodyFrame());
815 SwBodyFrame* pBody = static_cast<SwBodyFrame*>(pPage->GetLower());
816 CPPUNIT_ASSERT(pBody->GetLower()->IsTextFrame());
817 SwTextFrame* pTextFrame = static_cast<SwTextFrame*>(pBody->GetLower());
818 CPPUNIT_ASSERT(pTextFrame->GetNext()->IsTabFrame());
819 SwFrame* pTable = pTextFrame->GetNext();
820 SwFrame* pRow1 = pTable->GetLower();
821 CPPUNIT_ASSERT(pRow1->GetLower()->IsCellFrame());
822 SwFrame* pCell1 = pRow1->GetLower();
823 CPPUNIT_ASSERT(pCell1->GetLower()->IsTextFrame());
824 SwTextFrame* pCellTextFrame = static_cast<SwTextFrame*>(pCell1->GetLower());
825 const SwRect& rCellRect = pCell1->getFrameArea();
826 Point aPoint = rCellRect.Center();
827 aPoint.setX(aPoint.getX() - rCellRect.Width() / 2);
829 // Ask for the doc model pos of this layout point.
830 SwPosition aPosition(*pCellTextFrame->GetTextNodeForFirstText());
831 pCellTextFrame->GetModelPositionForViewPoint(&aPosition, aPoint);
833 // Position was 1 without the fix from tdf#141079
834 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0), aPosition.GetContentIndex());
837 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testCommentCursorPosition)
839 // Load a document that has "aaa" in it, followed by three comments.
840 createSwDoc("endOfLineComments.odt");
841 SwDoc* pDoc = getSwDoc();
842 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
844 SwRootFrame* pRoot = pWrtShell->GetLayout();
845 CPPUNIT_ASSERT(pRoot->GetLower()->IsPageFrame());
846 SwPageFrame* pPage = static_cast<SwPageFrame*>(pRoot->GetLower());
847 CPPUNIT_ASSERT(pPage->GetLower()->IsBodyFrame());
848 SwBodyFrame* pBody = static_cast<SwBodyFrame*>(pPage->GetLower());
849 CPPUNIT_ASSERT(pBody->GetLower()->IsTextFrame());
850 SwTextFrame* pTextFrame = static_cast<SwTextFrame*>(pBody->GetLower());
852 // Set a point in the whitespace past the end of the first line.
853 Point aPoint = pWrtShell->getShellCursor(false)->GetSttPos();
854 aPoint.setX(aPoint.getX() + 10000);
856 // Ask for the doc model pos of this layout point.
857 SwPosition aPosition(*pTextFrame->GetTextNodeForFirstText());
858 pTextFrame->GetModelPositionForViewPoint(&aPosition, aPoint);
860 // Without the accompanying fix in place, this test would have failed with:
861 // - Expected: 6
862 // - Actual : 3 or 4
863 // i.e. the cursor got positioned before the comments,
864 // so typing extended the first comment instead of adding content after the comments.
865 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(6), aPosition.GetContentIndex());
866 // The second line is also important, but can't be auto-tested
867 // since the failing situation depends on GetViewWidth which is zero in the headless tests.
868 // bb<comment>| - the cursor should move behind the |, not before it.
871 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testCombiningCharacterCursorPosition)
873 // Load a document that has "a" in it, followed by a combining acute in a separate rext span
874 createSwDoc("tdf138592-a-acute.fodt");
875 SwDoc* pDoc = getSwDoc();
876 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
878 SwRootFrame* pRoot = pWrtShell->GetLayout();
879 CPPUNIT_ASSERT(pRoot->GetLower()->IsPageFrame());
880 SwPageFrame* pPage = static_cast<SwPageFrame*>(pRoot->GetLower());
881 CPPUNIT_ASSERT(pPage->GetLower()->IsBodyFrame());
882 SwBodyFrame* pBody = static_cast<SwBodyFrame*>(pPage->GetLower());
883 CPPUNIT_ASSERT(pBody->GetLower()->IsTextFrame());
884 SwTextFrame* pTextFrame = static_cast<SwTextFrame*>(pBody->GetLower());
886 // Set a point in the whitespace past the end of the first line.
887 Point aPoint = pWrtShell->getShellCursor(false)->GetSttPos();
888 aPoint.AdjustX(10000);
890 // Ask for the doc model pos of this layout point.
891 SwPosition aPosition(*pTextFrame->GetTextNodeForFirstText());
892 pTextFrame->GetModelPositionForViewPoint(&aPosition, aPoint);
894 // Without the accompanying fix in place, this test would have failed with:
895 // - Expected: 2
896 // - Actual : 1
897 // i.e. the cursor got positioned before the acute, so typing shifted the acute (applying it
898 // to newly typed characters) instead of adding content after it.
899 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), aPosition.GetContentIndex());
902 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf64222)
904 createSwDoc("tdf64222.docx");
905 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
906 assertXPath(pXmlDoc,
907 "/root/page/body/txt[2]/SwParaPortion/SwLineLayout/"
908 "child::*[@type='PortionType::Number']/SwFont",
909 "height", "560");
912 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf113014)
914 createSwDoc("tdf113014.fodt");
915 SwDoc* pDoc = getSwDoc();
916 SwDocShell* pShell = pDoc->GetDocShell();
918 // Dump the rendering of the first page as an XML file.
919 std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
920 MetafileXmlDump dumper;
921 xmlDocUniquePtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
922 CPPUNIT_ASSERT(pXmlDoc);
924 // This failed, if numbering of cell A1 is missing
925 // (A1: left indent: 3 cm, first line indent: -3 cm
926 // A2: left indent: 0 cm, first line indent: 0 cm)
927 assertXPathContent(pXmlDoc, "/metafile/push[1]/push[1]/push[1]/textarray[1]/text", "1.");
928 assertXPathContent(pXmlDoc, "/metafile/push[1]/push[1]/push[1]/textarray[3]/text", "2.");
929 assertXPathContent(pXmlDoc, "/metafile/push[1]/push[1]/push[1]/textarray[5]/text", "3.");
932 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf130218)
934 createSwDoc("tdf130218.fodt");
935 SwDoc* pDoc = getSwDoc();
936 SwDocShell* pShell = pDoc->GetDocShell();
938 // Dump the rendering of the first page as an XML file.
939 std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
940 MetafileXmlDump dumper;
942 xmlDocUniquePtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
943 CPPUNIT_ASSERT(pXmlDoc);
945 // This failed, if hanging first line was hidden
946 assertXPathContent(pXmlDoc, "/metafile/push[1]/push[1]/push[1]/textarray[1]/text", "Text");
949 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf127235)
951 createSwDoc("tdf127235.odt");
952 SwDoc* pDoc = getSwDoc();
953 // This resulted in a layout loop.
954 pDoc->getIDocumentLayoutAccess().GetCurrentViewShell()->CalcLayout();
957 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf138039)
959 createSwDoc("tdf138039.odt");
961 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
963 // there are 3 pages
964 assertXPath(pXmlDoc, "/root/page", 3);
965 // table on first page
966 assertXPath(pXmlDoc, "/root/page[1]/body/tab", 1);
967 assertXPath(pXmlDoc, "/root/page[1]/body/txt", 0);
968 // paragraph with large fly on second page
969 assertXPath(pXmlDoc, "/root/page[2]/body/tab", 0);
970 assertXPath(pXmlDoc, "/root/page[2]/body/txt", 1);
971 assertXPath(pXmlDoc, "/root/page[2]/body/txt[1]/anchored/fly", 1);
972 assertXPath(pXmlDoc, "/root/page[2]/body/txt[1]/anchored/fly[1]/infos/bounds", "top", "17915");
973 assertXPath(pXmlDoc, "/root/page[2]/body/txt[1]/anchored/fly[1]/infos/bounds", "height",
974 "15819");
975 // paragraph on third page
976 assertXPath(pXmlDoc, "/root/page[3]/body/tab", 0);
977 assertXPath(pXmlDoc, "/root/page[3]/body/txt", 1);
978 assertXPath(pXmlDoc, "/root/page[3]/body/txt[1]/anchored", 0);
981 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf134298)
983 createSwDoc("tdf134298.ott");
985 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
987 // there are 2 pages
988 assertXPath(pXmlDoc, "/root/page", 2);
989 // table and first para on first page
990 assertXPath(pXmlDoc, "/root/page[1]/body/tab", 1);
991 assertXPath(pXmlDoc, "/root/page[1]/body/txt", 1);
992 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored", 0);
993 // paragraph with large fly on second page
994 assertXPath(pXmlDoc, "/root/page[2]/body/tab", 0);
995 assertXPath(pXmlDoc, "/root/page[2]/body/txt", 1);
996 assertXPath(pXmlDoc, "/root/page[2]/body/txt[1]/anchored/fly", 1);
997 assertXPath(pXmlDoc, "/root/page[2]/body/txt[1]/anchored/fly[1]/infos/bounds", "top", "17897");
998 assertXPath(pXmlDoc, "/root/page[2]/body/txt[1]/anchored/fly[1]/infos/bounds", "height",
999 "15819");
1002 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testShapeAllowOverlap)
1004 // Need to find out why this fails on macOS and why this is unstable on Windows.
1005 #if !defined(MACOSX) && !defined(_WIN32)
1006 // Create an empty document with two, intentionally overlapping shapes.
1007 // Set their AllowOverlap property to false.
1008 createSwDoc();
1009 uno::Reference<lang::XMultiServiceFactory> xDocument(mxComponent, uno::UNO_QUERY);
1010 awt::Point aPoint(1000, 1000);
1011 awt::Size aSize(2000, 2000);
1012 uno::Reference<drawing::XShape> xShape(
1013 xDocument->createInstance("com.sun.star.drawing.RectangleShape"), uno::UNO_QUERY);
1014 xShape->setPosition(aPoint);
1015 xShape->setSize(aSize);
1016 uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(xDocument, uno::UNO_QUERY);
1017 uno::Reference<beans::XPropertySet> xShapeProperties(xShape, uno::UNO_QUERY);
1018 xShapeProperties->setPropertyValue("AllowOverlap", uno::Any(false));
1019 xShapeProperties->setPropertyValue("AnchorType",
1020 uno::Any(text::TextContentAnchorType_AT_CHARACTER));
1021 xDrawPageSupplier->getDrawPage()->add(xShape);
1023 aPoint = awt::Point(2000, 2000);
1024 xShape.set(xDocument->createInstance("com.sun.star.drawing.RectangleShape"), uno::UNO_QUERY);
1025 xShape->setPosition(aPoint);
1026 xShape->setSize(aSize);
1027 xShapeProperties.set(xShape, uno::UNO_QUERY);
1028 xShapeProperties->setPropertyValue("AllowOverlap", uno::Any(false));
1029 xShapeProperties->setPropertyValue("AnchorType",
1030 uno::Any(text::TextContentAnchorType_AT_CHARACTER));
1031 xDrawPageSupplier->getDrawPage()->add(xShape);
1033 // Now verify that the rectangle of the anchored objects don't overlap.
1034 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
1035 CPPUNIT_ASSERT(pTextDoc);
1036 SwDoc* pDoc = pTextDoc->GetDocShell()->GetDoc();
1037 SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
1038 SwFrame* pPageFrame = pLayout->GetLower();
1039 SwFrame* pBodyFrame = pPageFrame->GetLower();
1040 SwFrame* pTextFrame = pBodyFrame->GetLower();
1041 CPPUNIT_ASSERT(pTextFrame->GetDrawObjs());
1042 SwSortedObjs& rObjs = *pTextFrame->GetDrawObjs();
1043 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), rObjs.size());
1044 SwAnchoredObject* pFirst = rObjs[0];
1045 SwAnchoredObject* pSecond = rObjs[1];
1046 // Without the accompanying fix in place, this test would have failed: the layout dump was
1047 // <bounds left="1984" top="1984" width="1137" height="1137"/>
1048 // <bounds left="2551" top="2551" width="1137" height="1137"/>
1049 // so there was a clear vertical overlap. (Allow for 1px tolerance.)
1050 OString aMessage = "Unexpected overlap: first shape's bottom is "
1051 + OString::number(pFirst->GetObjRect().Bottom()) + ", second shape's top is "
1052 + OString::number(pSecond->GetObjRect().Top());
1053 CPPUNIT_ASSERT_MESSAGE(aMessage.getStr(),
1054 std::abs(pFirst->GetObjRect().Bottom() - pSecond->GetObjRect().Top())
1055 < 15);
1056 #endif
1059 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testShapeAllowOverlapWrap)
1061 // Create an empty document with two, intentionally overlapping shapes.
1062 // Set their AllowOverlap property to false and their wrap to through.
1063 createSwDoc();
1064 uno::Reference<lang::XMultiServiceFactory> xDocument(mxComponent, uno::UNO_QUERY);
1065 awt::Point aPoint(1000, 1000);
1066 awt::Size aSize(2000, 2000);
1067 uno::Reference<drawing::XShape> xShape(
1068 xDocument->createInstance("com.sun.star.drawing.RectangleShape"), uno::UNO_QUERY);
1069 xShape->setPosition(aPoint);
1070 xShape->setSize(aSize);
1071 uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(xDocument, uno::UNO_QUERY);
1072 uno::Reference<beans::XPropertySet> xShapeProperties(xShape, uno::UNO_QUERY);
1073 xShapeProperties->setPropertyValue("AllowOverlap", uno::Any(false));
1074 xShapeProperties->setPropertyValue("AnchorType",
1075 uno::Any(text::TextContentAnchorType_AT_CHARACTER));
1076 xShapeProperties->setPropertyValue("Surround", uno::Any(text::WrapTextMode_THROUGH));
1077 xDrawPageSupplier->getDrawPage()->add(xShape);
1079 aPoint = awt::Point(2000, 2000);
1080 xShape.set(xDocument->createInstance("com.sun.star.drawing.RectangleShape"), uno::UNO_QUERY);
1081 xShape->setPosition(aPoint);
1082 xShape->setSize(aSize);
1083 xShapeProperties.set(xShape, uno::UNO_QUERY);
1084 xShapeProperties->setPropertyValue("AllowOverlap", uno::Any(false));
1085 xShapeProperties->setPropertyValue("AnchorType",
1086 uno::Any(text::TextContentAnchorType_AT_CHARACTER));
1087 xShapeProperties->setPropertyValue("Surround", uno::Any(text::WrapTextMode_THROUGH));
1088 xDrawPageSupplier->getDrawPage()->add(xShape);
1090 // Now verify that the rectangle of the anchored objects do overlap.
1091 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
1092 CPPUNIT_ASSERT(pTextDoc);
1093 SwDoc* pDoc = pTextDoc->GetDocShell()->GetDoc();
1094 SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
1095 SwFrame* pPageFrame = pLayout->GetLower();
1096 SwFrame* pBodyFrame = pPageFrame->GetLower();
1097 SwFrame* pTextFrame = pBodyFrame->GetLower();
1098 CPPUNIT_ASSERT(pTextFrame->GetDrawObjs());
1099 SwSortedObjs& rObjs = *pTextFrame->GetDrawObjs();
1100 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), rObjs.size());
1101 SwAnchoredObject* pFirst = rObjs[0];
1102 SwAnchoredObject* pSecond = rObjs[1];
1103 // Without the accompanying fix in place, this test would have failed: AllowOverlap=no had
1104 // priority over Surround=through (which is bad for Word compat).
1105 CPPUNIT_ASSERT(pSecond->GetObjRect().Overlaps(pFirst->GetObjRect()));
1108 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf124600)
1110 createSwDoc("tdf124600.docx");
1111 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1113 // Without the accompanying fix in place, this test would have failed with:
1114 // - Expected: 1
1115 // - Actual : 2
1116 // i.e. the last line in the body text had 2 lines, while it should have 1, as Word does (as the
1117 // fly frame does not intersect with the print area of the paragraph.)
1118 assertXPath(pXmlDoc, "/root/page/body/txt[2]/SwParaPortion/SwLineLayout", 1);
1121 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf124601)
1123 // This is a testcase for the ContinuousEndnotes compat flag.
1124 // The document has 2 pages, the endnote anchor is on the first page.
1125 // The endnote should be on the 2nd page together with the last page content.
1126 createSwDoc("tdf124601.doc");
1127 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1129 // Without the accompanying fix in place, this test would have failed with:
1130 // - Expected: 2
1131 // - Actual : 3
1132 // i.e. there was a separate endnote page, even when the ContinuousEndnotes compat option was
1133 // on.
1134 assertXPath(pXmlDoc, "/root/page", 2);
1135 assertXPath(pXmlDoc, "/root/page[2]/ftncont", 1);
1138 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf124601b)
1140 // Table has an image, which is anchored in the first row, but its vertical position is large
1141 // enough to be rendered in the second row.
1142 // The shape has layoutInCell=1, so should match what Word does here.
1143 // Also the horizontal position should be in the last column, even if the anchor is in the
1144 // last-but-one column.
1145 createSwDoc("tdf124601b.doc");
1146 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1148 sal_Int32 nFlyTop = getXPath(pXmlDoc, "//anchored/fly/infos/bounds", "top").toInt32();
1149 sal_Int32 nFlyLeft = getXPath(pXmlDoc, "//anchored/fly/infos/bounds", "left").toInt32();
1150 sal_Int32 nFlyRight
1151 = nFlyLeft + getXPath(pXmlDoc, "//anchored/fly/infos/bounds", "width").toInt32();
1152 sal_Int32 nSecondRowTop = getXPath(pXmlDoc, "//tab/row[2]/infos/bounds", "top").toInt32();
1153 sal_Int32 nLastCellLeft
1154 = getXPath(pXmlDoc, "//tab/row[1]/cell[5]/infos/bounds", "left").toInt32();
1155 sal_Int32 nLastCellRight
1156 = nLastCellLeft + getXPath(pXmlDoc, "//tab/row[1]/cell[5]/infos/bounds", "width").toInt32();
1157 // Without the accompanying fix in place, this test would have failed with:
1158 // - Expected greater than: 3736
1159 // - Actual : 2852
1160 // i.e. the image was still inside the first row.
1161 CPPUNIT_ASSERT_GREATER(nSecondRowTop, nFlyTop);
1163 // Without the accompanying fix in place, this test would have failed with:
1164 // - Expected greater than: 9640
1165 // - Actual : 9639
1166 // i.e. the right edge of the image was not within the bounds of the last column, the right edge
1167 // was in the last-but-one column.
1168 CPPUNIT_ASSERT_GREATER(nLastCellLeft, nFlyRight);
1169 CPPUNIT_ASSERT_LESS(nLastCellRight, nFlyRight);
1172 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf124770)
1174 // Enable content over margin.
1175 createSwDoc();
1176 SwDoc* pDoc = getSwDoc();
1177 pDoc->getIDocumentSettingAccess().set(DocumentSettingId::TAB_OVER_MARGIN, true);
1179 // Set page width.
1180 SwPageDesc& rPageDesc = pDoc->GetPageDesc(0);
1181 SwFrameFormat& rPageFormat = rPageDesc.GetMaster();
1182 const SwAttrSet& rPageSet = rPageFormat.GetAttrSet();
1183 SwFormatFrameSize aPageSize = rPageSet.GetFrameSize();
1184 aPageSize.SetWidth(3703);
1185 rPageFormat.SetFormatAttr(aPageSize);
1187 // Set left and right margin.
1188 SvxLRSpaceItem aLRSpace = rPageSet.GetLRSpace();
1189 aLRSpace.SetLeft(1418);
1190 aLRSpace.SetRight(1418);
1191 rPageFormat.SetFormatAttr(aLRSpace);
1192 pDoc->ChgPageDesc(0, rPageDesc);
1194 // Set font to italic 20pt Liberation Serif.
1195 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
1196 SfxItemSet aTextSet(pWrtShell->GetView().GetPool(),
1197 svl::Items<RES_CHRATR_BEGIN, RES_CHRATR_END - 1>);
1198 SvxFontItem aFont(RES_CHRATR_FONT);
1199 aFont.SetFamilyName("Liberation Serif");
1200 aTextSet.Put(aFont);
1201 SvxFontHeightItem aHeight(400, 100, RES_CHRATR_FONTSIZE);
1202 aTextSet.Put(aHeight);
1203 SvxPostureItem aItalic(ITALIC_NORMAL, RES_CHRATR_POSTURE);
1204 aTextSet.Put(aItalic);
1205 pWrtShell->SetAttrSet(aTextSet);
1207 // Insert the text.
1208 pWrtShell->Insert2("HHH");
1210 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1211 // Without the accompanying fix in place, this test would have failed with:
1212 // - Expected: 1
1213 // - Actual : 2
1214 // i.e. the italic string was broken into 2 lines, while Word kept it in a single line.
1215 assertXPath(pXmlDoc, "/root/page/body/txt[1]/SwParaPortion/SwLineLayout", 1);
1218 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testContinuousEndnotesInsertPageAtStart)
1220 // Create a new document with CONTINUOUS_ENDNOTES enabled.
1221 createSwDoc();
1222 SwDoc* pDoc = getSwDoc();
1223 pDoc->getIDocumentSettingAccess().set(DocumentSettingId::CONTINUOUS_ENDNOTES, true);
1225 // Insert a second page, and an endnote on the 2nd page (both the anchor and the endnote is on
1226 // the 2nd page).
1227 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
1228 pWrtShell->InsertPageBreak();
1229 pWrtShell->InsertFootnote("endnote", /*bEndNote=*/true, /*bEdit=*/false);
1231 // Add a new page at the start of the document.
1232 pWrtShell->SttEndDoc(/*bStart=*/true);
1233 pWrtShell->InsertPageBreak();
1235 // Make sure that the endnote is moved from the 2nd page to the 3rd one.
1236 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1237 assertXPath(pXmlDoc, "/root/page", 3);
1238 // Without the accompanying fix in place, this test would have failed with:
1239 // - Expected: 1
1240 // - Actual : 0
1241 // i.e. the footnote container remained on page 2.
1242 assertXPath(pXmlDoc, "/root/page[3]/ftncont", 1);
1245 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testContinuousEndnotesDeletePageAtStart)
1247 // Create a new document with CONTINUOUS_ENDNOTES enabled.
1248 createSwDoc();
1249 SwDoc* pDoc = getSwDoc();
1250 pDoc->getIDocumentSettingAccess().set(DocumentSettingId::CONTINUOUS_ENDNOTES, true);
1252 // Insert a second page, and an endnote on the 2nd page (both the anchor and the endnote is on
1253 // the 2nd page).
1254 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
1255 pWrtShell->InsertPageBreak();
1256 pWrtShell->InsertFootnote("endnote", /*bEndNote=*/true, /*bEdit=*/false);
1258 // Remove the empty page at the start of the document.
1259 pWrtShell->SttEndDoc(/*bStart=*/true);
1260 pWrtShell->DelRight();
1262 // Make sure that the endnote is moved from the 2nd page to the 1st one.
1263 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1264 // Without the accompanying fix in place, this test would have failed with:
1265 // - Expected: 1
1266 // - Actual : 2
1267 // i.e. the endnote remained on an (otherwise) empty 2nd page.
1268 assertXPath(pXmlDoc, "/root/page", 1);
1269 assertXPath(pXmlDoc, "/root/page[1]/ftncont", 1);
1272 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf128399)
1274 createSwDoc("tdf128399.docx");
1275 SwDoc* pDoc = getSwDoc();
1276 SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
1277 SwFrame* pPage = pLayout->GetLower();
1278 SwFrame* pBody = pPage->GetLower();
1279 SwFrame* pTable = pBody->GetLower();
1280 SwFrame* pRow1 = pTable->GetLower();
1281 SwFrame* pRow2 = pRow1->GetNext();
1282 const SwRect& rRow2Rect = pRow2->getFrameArea();
1283 Point aPoint = rRow2Rect.Center();
1285 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
1286 SwPosition aPosition = *pWrtShell->GetCursor()->Start();
1287 SwPosition aFirstRow(aPosition);
1288 SwCursorMoveState aState(CursorMoveState::NONE);
1289 pLayout->GetModelPositionForViewPoint(&aPosition, aPoint, &aState);
1290 // Second row is +3: end node, start node and the first text node in the 2nd row.
1291 SwNodeOffset nExpected = aFirstRow.GetNodeIndex() + 3;
1293 // Without the accompanying fix in place, this test would have failed with:
1294 // - Expected: 14
1295 // - Actual : 11
1296 // i.e. clicking on the center of the 2nd row placed the cursor in the 1st row.
1297 CPPUNIT_ASSERT_EQUAL(nExpected, aPosition.GetNodeIndex());
1300 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf156724)
1302 discardDumpedLayout();
1303 if (mxComponent.is())
1304 mxComponent->dispose();
1306 OUString const url(createFileURL(u"fdo56797-2-min.odt"));
1308 // note: must set Hidden property, so that SfxFrameViewWindow_Impl::Resize()
1309 // does *not* forward initial VCL Window Resize and thereby triggers a
1310 // layout which does not happen on soffice --convert-to pdf.
1311 std::vector<beans::PropertyValue> aFilterOptions = {
1312 { beans::PropertyValue("Hidden", -1, uno::Any(true), beans::PropertyState_DIRECT_VALUE) },
1315 // inline the loading because currently properties can't be passed...
1316 mxComponent = loadFromDesktop(url, "com.sun.star.text.TextDocument",
1317 comphelper::containerToSequence(aFilterOptions));
1318 save("writer_pdf_Export");
1320 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1321 // both pages have a tab frame and one footnote
1322 assertXPath(pXmlDoc, "/root/page[1]/body/tab", 1);
1323 assertXPath(pXmlDoc, "/root/page[1]/ftncont", 1);
1324 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn", 1);
1325 assertXPath(pXmlDoc, "/root/page[2]/body/tab", 1);
1326 assertXPath(pXmlDoc, "/root/page[2]/ftncont", 1);
1327 assertXPath(pXmlDoc, "/root/page[2]/ftncont/ftn", 1);
1328 assertXPath(pXmlDoc, "/root/page", 2);
1331 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf156725)
1333 createSwDoc("tdf156725.fodt");
1335 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1336 assertXPath(pXmlDoc, "/root/page", 2);
1337 // the fly has 2 columns, the section in it has 2 columns, and is split
1338 // across the fly columns => 4 columns with 1 text frame each
1339 assertXPath(pXmlDoc, "/root/page[2]/body/txt/anchored/fly/column", 2);
1340 assertXPath(pXmlDoc, "/root/page[2]/body/txt/anchored/fly/column[1]/body/section/column", 2);
1341 assertXPath(pXmlDoc,
1342 "/root/page[2]/body/txt/anchored/fly/column[1]/body/section/column[1]/body/txt", 1);
1343 assertXPath(pXmlDoc,
1344 "/root/page[2]/body/txt/anchored/fly/column[1]/body/section/column[2]/body/txt", 1);
1345 assertXPath(pXmlDoc, "/root/page[2]/body/txt/anchored/fly/column[2]/body/section/column", 2);
1346 assertXPath(pXmlDoc,
1347 "/root/page[2]/body/txt/anchored/fly/column[2]/body/section/column[1]/body/txt", 1);
1348 assertXPath(pXmlDoc,
1349 "/root/page[2]/body/txt/anchored/fly/column[2]/body/section/column[2]/body/txt", 1);
1352 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf156419)
1354 createSwDoc("linked_frames_section_bug.odt");
1356 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1357 assertXPath(pXmlDoc, "/root/page", 2);
1358 // there are 2 flys on page 1, and 1 on page 2, all linked
1359 assertXPath(pXmlDoc, "/root/page[1]/body/txt/anchored/fly[1]/section/column", 2);
1360 assertXPath(pXmlDoc, "/root/page[1]/body/txt/anchored/fly[1]/section/column[1]/body/txt", 11);
1361 assertXPath(pXmlDoc, "/root/page[1]/body/txt/anchored/fly[1]/section/column[2]/body/txt", 11);
1362 assertXPath(pXmlDoc, "/root/page[1]/body/txt/anchored/fly[2]/section/column", 2);
1363 assertXPath(pXmlDoc, "/root/page[1]/body/txt/anchored/fly[2]/section/column[1]/body/txt", 12);
1364 assertXPath(pXmlDoc, "/root/page[1]/body/txt/anchored/fly[2]/section/column[2]/body/txt", 12);
1365 assertXPath(pXmlDoc, "/root/page[2]/body/txt/anchored/fly[1]/section/column", 2);
1366 assertXPath(pXmlDoc, "/root/page[2]/body/txt/anchored/fly[1]/section/column[1]/body/txt", 2);
1367 assertXPath(pXmlDoc, "/root/page[2]/body/txt/anchored/fly[1]/section/column[2]/body/txt", 1);
1370 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf145826)
1372 createSwDoc("tdf145826.odt");
1373 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1374 CPPUNIT_ASSERT(pXmlDoc);
1376 assertXPath(pXmlDoc, "/root/page/body/section/column", 2);
1378 // Without the fix in place, this test would have failed with
1379 // - Expected: 1
1380 // - Actual : 0
1381 assertXPath(pXmlDoc, "/root/page/body/section/column[1]/ftncont", 1);
1382 assertXPath(pXmlDoc, "/root/page/body/section/column[2]/ftncont", 1);
1383 assertXPath(pXmlDoc, "/root/page/body/section/column[1]/ftncont/ftn", 3);
1384 assertXPath(pXmlDoc, "/root/page/body/section/column[2]/ftncont/ftn", 3);
1387 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf105481)
1389 createSwDoc("tdf105481.odt");
1390 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1391 CPPUNIT_ASSERT(pXmlDoc);
1393 // Without the accompanying fix in place, this test would have failed
1394 // because the vertical position of the as-char shape object and the
1395 // as-char math object will be wrong (below/beyond the text frame's bottom).
1397 SwTwips nTxtTop = getXPath(pXmlDoc,
1398 "/root/page/anchored/fly/txt[2]"
1399 "/infos/bounds",
1400 "top")
1401 .toInt32();
1402 SwTwips nTxtBottom = nTxtTop
1403 + getXPath(pXmlDoc,
1404 "/root/page/anchored/fly/txt[2]"
1405 "/infos/bounds",
1406 "height")
1407 .toInt32();
1409 SwTwips nFormula1Top = getXPath(pXmlDoc,
1410 "/root/page/anchored/fly/txt[2]"
1411 "/anchored/fly[1]/infos/bounds",
1412 "top")
1413 .toInt32();
1414 SwTwips nFormula1Bottom = nFormula1Top
1415 + getXPath(pXmlDoc,
1416 "/root/page/anchored/fly/txt[2]"
1417 "/anchored/fly[1]/infos/bounds",
1418 "height")
1419 .toInt32();
1421 SwTwips nFormula2Top = getXPath(pXmlDoc,
1422 "/root/page/anchored/fly/txt[2]"
1423 "/anchored/fly[2]/infos/bounds",
1424 "top")
1425 .toInt32();
1426 SwTwips nFormula2Bottom = nFormula2Top
1427 + getXPath(pXmlDoc,
1428 "/root/page/anchored/fly/txt[2]"
1429 "/anchored/fly[2]/infos/bounds",
1430 "height")
1431 .toInt32();
1433 // Ensure that the two formula positions are at least between top and bottom of the text frame.
1434 // The below two are satisfied even without the fix.
1435 CPPUNIT_ASSERT_GREATEREQUAL(nTxtTop, nFormula1Top);
1436 CPPUNIT_ASSERT_GREATEREQUAL(nTxtTop, nFormula2Top);
1438 // Without the accompanying fix in place, this test would have failed with:
1439 // - Expected less than or equal to : 14423
1440 // - Actual : 14828
1441 // that is, the formula is below the text-frame's y bound.
1442 CPPUNIT_ASSERT_LESSEQUAL(nTxtBottom, nFormula1Bottom);
1443 // Similarly for formula # 2 :
1444 // - Expected less than or equal to : 14423
1445 // - Actual : 15035
1446 // that is, the formula is below the text-frame's y bound.
1447 CPPUNIT_ASSERT_LESSEQUAL(nTxtBottom, nFormula2Bottom);
1450 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf117982)
1452 createSwDoc("tdf117982.docx");
1453 SwDoc* pDocument = getSwDoc();
1454 SwDocShell* pShell = pDocument->GetDocShell();
1455 std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
1456 MetafileXmlDump dumper;
1457 xmlDocUniquePtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
1458 assertXPathContent(pXmlDoc, "/metafile/push[1]/push[1]/push[1]/textarray[1]/text", "FOO AAA");
1459 //The first cell must be "FOO AAA". If not, this means the first cell content not visible in
1460 //the source document.
1463 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf128959)
1465 // no orphan/widow control in table cells
1466 createSwDoc("tdf128959.docx");
1467 SwDoc* pDocument = getSwDoc();
1468 CPPUNIT_ASSERT(pDocument);
1469 discardDumpedLayout();
1470 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1472 // first two lines of the paragraph in the split table cell on the first page
1473 // (these lines were completely lost)
1474 assertXPath(
1475 pXmlDoc, "/root/page[1]/body/tab[1]/row[1]/cell[1]/txt[1]/SwParaPortion/SwLineLayout[1]",
1476 "portion",
1477 "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas porttitor congue ");
1478 assertXPath(
1479 pXmlDoc, "/root/page[1]/body/tab[1]/row[1]/cell[1]/txt[1]/SwParaPortion/SwLineLayout[2]",
1480 "portion",
1481 "massa. Fusce posuere, magna sed pulvinar ultricies, purus lectus malesuada libero, sit ");
1482 // last line of the paragraph in the split table cell on the second page
1483 assertXPath(pXmlDoc,
1484 "/root/page[2]/body/tab[1]/row[1]/cell[1]/txt[1]/SwParaPortion/SwLineLayout[1]",
1485 "portion", "amet commodo magna eros quis urna.");
1487 // Also check that the widow control for the paragraph is not turned off:
1488 sw::TableFrameFormats& rTableFormats = *pDocument->GetTableFrameFormats();
1489 SwFrameFormat* pTableFormat = rTableFormats[0];
1490 SwTable* pTable = SwTable::FindTable(pTableFormat);
1491 const SwTableBox* pCell = pTable->GetTableBox("A1");
1492 const SwStartNode* pStartNode = pCell->GetSttNd();
1493 SwNodeIndex aNodeIndex(*pStartNode);
1494 ++aNodeIndex;
1495 const SwTextNode* pTextNode = aNodeIndex.GetNode().GetTextNode();
1496 // Without the accompanying fix in place, this test would have failed with:
1497 // - Expected: 2
1498 // - Actual : 0
1499 // i.e. the original fix only worked as the entire widow / orphan control was switched off.
1500 CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(pTextNode->GetSwAttrSet().GetWidows().GetValue()));
1503 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf121658)
1505 uno::Reference<linguistic2::XHyphenator> xHyphenator = LinguMgr::GetHyphenator();
1506 if (!xHyphenator->hasLocale(lang::Locale("en", "US", OUString())))
1507 return;
1509 createSwDoc("tdf121658.odt");
1510 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1512 // Only 2 hyphenated words should appear in the document (in the lowercase words).
1513 // Uppercase words should not be hyphenated.
1514 assertXPath(pXmlDoc, "//SwLineLayout/child::*[@type='PortionType::Hyphen']", 2);
1517 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf149420)
1519 uno::Reference<linguistic2::XHyphenator> xHyphenator = LinguMgr::GetHyphenator();
1520 if (!xHyphenator->hasLocale(lang::Locale("en", "US", OUString())))
1521 return;
1523 createSwDoc("tdf149420.odt");
1524 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1526 // Only 3 hyphenated words should appear in the document (last paragraph
1527 // has got a 1 cm hyphenation zone, removing two hyphenations, which visible
1528 // in the second paragraph).
1529 assertXPath(pXmlDoc, "//SwLineLayout/child::*[@type='PortionType::Hyphen']", 8);
1532 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf149324)
1534 uno::Reference<linguistic2::XHyphenator> xHyphenator = LinguMgr::GetHyphenator();
1535 if (!xHyphenator->hasLocale(lang::Locale("en", "US", OUString())))
1536 return;
1538 createSwDoc("tdf149324.odt");
1539 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1541 // Only 3 hyphenated words should appear in the document (last paragraph
1542 // has got a 7-character word limit for hyphenation, removing the
1543 // hyphenation "ex-cept".
1544 assertXPath(pXmlDoc, "//SwLineLayout/child::*[@type='PortionType::Hyphen']", 3);
1547 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf149248)
1549 uno::Reference<linguistic2::XHyphenator> xHyphenator = LinguMgr::GetHyphenator();
1550 if (!xHyphenator->hasLocale(lang::Locale("en", "US", OUString())))
1551 return;
1553 createSwDoc("tdf149248.odt");
1554 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1556 // Only 1 hyphenated word should appear in the document (last word of the second
1557 // paragraph). Last word should not be hyphenated for the fourth paragraph
1558 // (the same paragraph, but with forbidden hyphenation of the last word).
1559 assertXPath(pXmlDoc, "//SwLineLayout/child::*[@type='PortionType::Hyphen']", 1);
1562 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testWriterImageNoCapture)
1564 createSwDoc("writer-image-no-capture.docx");
1565 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1566 CPPUNIT_ASSERT(pXmlDoc);
1567 sal_Int32 nPageLeft = getXPath(pXmlDoc, "//page/infos/bounds", "left").toInt32();
1568 sal_Int32 nImageLeft = getXPath(pXmlDoc, "//anchored/fly/infos/bounds", "left").toInt32();
1569 // Without the accompanying fix in place, this test would have failed with:
1570 // - Expected less than: 284
1571 // - Actual : 284
1572 // i.e. the image position was modified to be inside the page frame ("captured"), even if Word
1573 // does not do that.
1574 CPPUNIT_ASSERT_LESS(nPageLeft, nImageLeft);
1577 static SwRect lcl_getVisibleFlyObjRect(SwWrtShell* pWrtShell)
1579 SwRootFrame* pRoot = pWrtShell->GetLayout();
1580 SwPageFrame* pPage = static_cast<SwPageFrame*>(pRoot->GetLower());
1581 pPage = static_cast<SwPageFrame*>(pPage->GetNext());
1582 pPage = static_cast<SwPageFrame*>(pPage->GetNext());
1583 SwSortedObjs* pDrawObjs = pPage->GetDrawObjs();
1584 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pDrawObjs->size());
1585 SwAnchoredObject* pDrawObj = (*pDrawObjs)[0];
1586 CPPUNIT_ASSERT_EQUAL(OUString("Rahmen8"), pDrawObj->GetFrameFormat().GetName());
1587 pPage = static_cast<SwPageFrame*>(pPage->GetNext());
1588 pDrawObjs = pPage->GetDrawObjs();
1589 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pDrawObjs->size());
1590 pDrawObj = (*pDrawObjs)[0];
1591 CPPUNIT_ASSERT_EQUAL(OUString("Rahmen123"), pDrawObj->GetFrameFormat().GetName());
1592 SwRect aFlyRect = pDrawObj->GetObjRect();
1593 CPPUNIT_ASSERT(pPage->getFrameArea().Contains(aFlyRect));
1594 return aFlyRect;
1597 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testStableAtPageAnchoredFlyPosition)
1599 // this doc has two page-anchored frames: one tiny on page 3 and one large on page 4.
1600 // it also has a style:master-page named "StandardEntwurf", which contains some fields.
1601 // if you add a break to page 2, or append some text to page 4 (or just toggle display field names),
1602 // the page anchored frame on page 4 vanishes, as it is incorrectly moved out of the page bounds.
1603 createSwDoc("stable-at-page-anchored-fly-position.odt");
1604 SwDoc* pDoc = getSwDoc();
1605 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
1607 // look up the layout position of the page-bound frame on page four
1608 SwRect aOrigRect = lcl_getVisibleFlyObjRect(pWrtShell);
1610 // append some text to the document to trigger bug / relayout
1611 pWrtShell->SttEndDoc(false);
1612 pWrtShell->Insert("foo");
1614 // get the current position of the frame on page four
1615 SwRect aRelayoutRect = lcl_getVisibleFlyObjRect(pWrtShell);
1617 // the anchored frame should not have moved
1618 CPPUNIT_ASSERT_EQUAL(aOrigRect, aRelayoutRect);
1621 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf134548)
1623 createSwDoc("tdf134548.odt");
1624 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1626 // Second paragraph has two non zero width tabs in beginning of line
1628 OUString sNodeType = parseDump(
1629 "/root/page/body/txt[2]/SwParaPortion/SwLineLayout/SwFixPortion[1]", "type");
1630 CPPUNIT_ASSERT_EQUAL(OUString("PortionType::TabLeft"), sNodeType);
1631 sal_Int32 nWidth
1632 = parseDump("/root/page/body/txt[2]/SwParaPortion/SwLineLayout/SwFixPortion[1]",
1633 "width")
1634 .toInt32();
1635 CPPUNIT_ASSERT_GREATER(sal_Int32(0), nWidth);
1638 OUString sNodeType = parseDump(
1639 "/root/page/body/txt[2]/SwParaPortion/SwLineLayout/SwFixPortion[2]", "type");
1640 CPPUNIT_ASSERT_EQUAL(OUString("PortionType::TabLeft"), sNodeType);
1641 sal_Int32 nWidth
1642 = parseDump("/root/page/body/txt[2]/SwParaPortion/SwLineLayout/SwFixPortion[2]",
1643 "width")
1644 .toInt32();
1645 CPPUNIT_ASSERT_GREATER(sal_Int32(0), nWidth);
1649 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf124423)
1651 createSwDoc("tdf124423.docx");
1652 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1653 sal_Int32 nFly1Width
1654 = getXPath(pXmlDoc, "(//anchored/fly)[1]/infos/prtBounds", "width").toInt32();
1655 sal_Int32 nFly2Width
1656 = getXPath(pXmlDoc, "(//anchored/fly)[2]/infos/prtBounds", "width").toInt32();
1657 sal_Int32 nPageWidth = getXPath(pXmlDoc, "//page/infos/prtBounds", "width").toInt32();
1658 CPPUNIT_ASSERT_EQUAL(nPageWidth, nFly2Width);
1659 CPPUNIT_ASSERT_LESS(nPageWidth / 2, nFly1Width);
1661 createSwDoc("tdf124423.odt");
1662 pXmlDoc = parseLayoutDump();
1663 nFly1Width = getXPath(pXmlDoc, "(//anchored/fly)[1]/infos/prtBounds", "width").toInt32();
1664 nFly2Width = getXPath(pXmlDoc, "(//anchored/fly)[2]/infos/prtBounds", "width").toInt32();
1665 nPageWidth = getXPath(pXmlDoc, "//page/infos/prtBounds", "width").toInt32();
1666 CPPUNIT_ASSERT_LESS(nPageWidth / 2, nFly2Width);
1667 CPPUNIT_ASSERT_LESS(nPageWidth / 2, nFly1Width);
1670 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf137185)
1672 // First load the sample bugdoc
1673 createSwDoc("tdf137185.odt");
1674 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
1675 CPPUNIT_ASSERT(pTextDoc);
1676 // Get the doc shell
1677 SwDoc* pDoc(pTextDoc->GetDocShell()->GetDoc());
1679 // Get the DrawObject from page
1680 auto pModel = pDoc->getIDocumentDrawModelAccess().GetDrawModel();
1681 CPPUNIT_ASSERT(pModel);
1682 auto pPage = pModel->GetPage(0);
1683 CPPUNIT_ASSERT(pPage);
1684 auto pObj = pPage->GetObj(0);
1685 CPPUNIT_ASSERT(pObj);
1687 // Get the format of the draw object
1688 auto pShape = FindFrameFormat(pObj);
1689 CPPUNIT_ASSERT(pShape);
1691 // Check the text of the shape
1692 uno::Reference<text::XText> xTxt(getShape(1), uno::UNO_QUERY);
1693 CPPUNIT_ASSERT_EQUAL(OUString("Align me!"), xTxt->getText()->getString());
1695 // Add a textbox to the shape
1696 SwTextBoxHelper::create(pShape, pShape->FindRealSdrObject(), true);
1698 // Check if the text moved from the shape to the frame
1699 auto pFormat = SwTextBoxHelper::getOtherTextBoxFormat(getShape(1));
1700 auto xTextFrame = SwXTextFrame::CreateXTextFrame(*pFormat->GetDoc(), pFormat);
1702 CPPUNIT_ASSERT_EQUAL(OUString("Align me!"), xTextFrame->getText()->getString());
1703 SdrTextObj* pTextObj = DynCastSdrTextObj(pObj);
1704 CPPUNIT_ASSERT(pTextObj);
1705 const auto& aOutStr = pTextObj->GetOutlinerParaObject()->GetTextObject();
1707 CPPUNIT_ASSERT(aOutStr.GetText(0).isEmpty());
1708 // Before the patch it failed, because the text appeared 2 times on each other.
1711 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf138782)
1713 createSwDoc("tdf138782.docx");
1714 auto pXml = parseLayoutDump();
1715 CPPUNIT_ASSERT(pXml);
1717 // Without the fix it failed because the 3rd shape was outside the page:
1718 // - Expected less than: 13327
1719 // - Actual : 14469
1721 CPPUNIT_ASSERT_LESS(
1722 getXPath(pXml, "/root/page/infos/bounds", "right").toInt32(),
1723 getXPath(pXml, "/root/page/body/txt[8]/anchored/SwAnchoredDrawObject/bounds", "right")
1724 .toInt32());
1727 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf135035)
1729 createSwDoc("tdf135035.docx");
1730 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1731 sal_Int32 nFly1Width
1732 = getXPath(pXmlDoc, "(//anchored/fly)[1]/infos/prtBounds", "width").toInt32();
1733 sal_Int32 nFly2Width
1734 = getXPath(pXmlDoc, "(//anchored/fly)[2]/infos/prtBounds", "width").toInt32();
1735 sal_Int32 nFly3Width
1736 = getXPath(pXmlDoc, "(//anchored/fly)[3]/infos/prtBounds", "width").toInt32();
1737 sal_Int32 nParentWidth = getXPath(pXmlDoc, "(//txt)[1]/infos/prtBounds", "width").toInt32();
1738 CPPUNIT_ASSERT_EQUAL(nParentWidth, nFly2Width);
1739 CPPUNIT_ASSERT_EQUAL(nParentWidth, nFly3Width);
1740 CPPUNIT_ASSERT_LESS(nParentWidth / 2, nFly1Width);
1742 createSwDoc("tdf135035.odt");
1743 pXmlDoc = parseLayoutDump();
1744 nFly1Width = getXPath(pXmlDoc, "(//anchored/fly)[1]/infos/prtBounds", "width").toInt32();
1745 nFly2Width = getXPath(pXmlDoc, "(//anchored/fly)[2]/infos/prtBounds", "width").toInt32();
1746 nFly3Width = getXPath(pXmlDoc, "(//anchored/fly)[3]/infos/prtBounds", "width").toInt32();
1747 nParentWidth = getXPath(pXmlDoc, "(//txt)[1]/infos/prtBounds", "width").toInt32();
1748 CPPUNIT_ASSERT_LESS(nParentWidth / 2, nFly2Width);
1749 CPPUNIT_ASSERT_LESS(nParentWidth / 2, nFly1Width);
1750 CPPUNIT_ASSERT_GREATER(nParentWidth, nFly3Width);
1753 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf146704_EndnoteInSection)
1755 createSwDoc("tdf146704_EndnoteInSection.odt");
1756 SwDoc* pDoc = getSwDoc();
1757 CPPUNIT_ASSERT(pDoc);
1758 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1759 // Without the fix, the endnote placed to 2. page
1760 assertXPath(pXmlDoc, "/root/page", 1);
1763 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf139336_ColumnsWithFootnoteDoNotOccupyEntirePage)
1765 createSwDoc("tdf139336_ColumnsWithFootnoteDoNotOccupyEntirePage.docx");
1766 SwDoc* pDoc = getSwDoc();
1767 CPPUNIT_ASSERT(pDoc);
1768 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1769 // Without the fix, it would be 5 pages, but with the fix the whole document
1770 // would fit into 1 page, but it will be 2 pages right now, because
1771 // when writer import (from docx) the last section with columns, then it does not set
1772 // the evenly distributed settings, and this settings is required for the fix now, to
1773 // avoid some regression.
1774 assertXPath(pXmlDoc, "/root/page", 2);
1777 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf54465_ColumnsWithFootnoteDoNotOccupyEntirePage)
1779 // Old odt files should keep their original layout, as it was before Tdf139336 fix.
1780 // The new odt file is only 1 page long, while the old odt file (with the same content)
1781 // was more than 1 page long.
1782 // Note: Somewhy this test miscalculates the layout of the old odt file.
1783 // It will be 4 pages long, while opened in Writer it is 5 pages long.
1784 createSwDoc("tdf54465_ColumnsWithFootnoteDoNotOccupyEntirePage_Old.odt");
1785 SwDoc* pDoc = getSwDoc();
1786 CPPUNIT_ASSERT(pDoc);
1787 Scheduler::ProcessEventsToIdle();
1788 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1789 xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "/root/page");
1790 xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
1791 CPPUNIT_ASSERT_GREATER(1, xmlXPathNodeSetGetLength(pXmlNodes));
1792 xmlXPathFreeObject(pXmlObj);
1794 discardDumpedLayout();
1795 createSwDoc("tdf54465_ColumnsWithFootnoteDoNotOccupyEntirePage_New.odt");
1796 pDoc = getSwDoc();
1797 CPPUNIT_ASSERT(pDoc);
1798 pXmlDoc = parseLayoutDump();
1799 assertXPath(pXmlDoc, "/root/page", 1);
1802 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf138124)
1804 // When the only portion after the footnote number is a FlyCnt, and it doesn't fit into
1805 // the page width, it should be moved to the next line without the footnote number, and
1806 // not loop, nor OOM, nor fail assertions.
1808 createSwDoc("wideBoxInFootnote.fodt");
1809 Scheduler::ProcessEventsToIdle();
1811 // Without the fix in place, the layout would loop, creating new FootnoteNum portions
1812 // indefinitely, until OOM.
1813 // If the footnote paragraph had no orphan control, then the loop would finally end,
1814 // but an assertion in SwTextPainter::DrawTextLine would fail during paint.
1816 xmlDocUniquePtr pXml = parseLayoutDump();
1817 assertXPath(pXml, "/root/page", 1);
1818 assertXPath(pXml, "/root/page/ftncont/ftn/txt/anchored", 1);
1820 // And finally, if there were no assertion in SwTextPainter::DrawTextLine, it would have
1821 // produced multiple lines with FootnoteNum portions, failing the following check like
1822 // - Expected: 1
1823 // - Actual : 49
1825 assertXPath(pXml,
1826 "/root/page/ftncont/ftn/txt//SwFieldPortion[@type='PortionType::FootnoteNum']", 1);
1827 assertXPath(pXml, "/root/page/ftncont/ftn/txt//SwLinePortion[@type='PortionType::FlyCnt']", 1);
1830 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf154113)
1832 createSwDoc("three_sections.fodt");
1833 Scheduler::ProcessEventsToIdle();
1835 dispatchCommand(mxComponent, ".uno:GoToStartOfDoc", {});
1836 dispatchCommand(mxComponent, ".uno:GoToNextPara", {});
1837 dispatchCommand(mxComponent, ".uno:EndOfDocumentSel", {}); // to the end of current section!
1838 dispatchCommand(mxComponent, ".uno:EndOfDocumentSel", {}); // to the end of the document.
1840 auto xModel = mxComponent.queryThrow<frame::XModel>();
1841 auto xSelected = xModel->getCurrentSelection().queryThrow<container::XIndexAccess>();
1842 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xSelected->getCount());
1843 auto xRange = xSelected->getByIndex(0).queryThrow<text::XTextRange>();
1844 CPPUNIT_ASSERT_EQUAL(OUString("<-- Start selection here. Section1" SAL_NEWLINE_STRING
1845 "Section2" SAL_NEWLINE_STRING "Section3. End selection here -->"),
1846 xRange->getString());
1848 dispatchCommand(mxComponent, ".uno:Cut", {});
1850 xSelected = xModel->getCurrentSelection().queryThrow<container::XIndexAccess>();
1851 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xSelected->getCount());
1852 xRange = xSelected->getByIndex(0).queryThrow<text::XTextRange>();
1853 CPPUNIT_ASSERT_EQUAL(OUString(), xRange->getString());
1855 dispatchCommand(mxComponent, ".uno:Paste", {});
1857 xmlDocUniquePtr pXml = parseLayoutDump();
1859 // Without the fix in place, this would fail with
1860 // - Expected: 3
1861 // - Actual : 2
1862 assertXPath(pXml, "/root/page/body/section", 3);
1863 assertXPath(pXml, "/root/page/body/section[1]/txt/SwParaPortion/SwLineLayout", "portion",
1864 "<-- Start selection here. Section1");
1865 assertXPath(pXml, "/root/page/body/section[2]/txt/SwParaPortion/SwLineLayout", "portion",
1866 "Section2");
1867 assertXPath(pXml, "/root/page/body/section[3]/txt/SwParaPortion/SwLineLayout", "portion",
1868 "Section3. End selection here -->");
1871 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf155611)
1873 createSwDoc("tdf155611_table_and_nested_section.fodt");
1874 Scheduler::ProcessEventsToIdle();
1876 xmlDocUniquePtr pXml = parseLayoutDump();
1877 CPPUNIT_ASSERT(pXml);
1879 // Check the layout: single page, two section frames (no section frames after the one for Inner
1880 // section), correct table structure and content in the first section frame, including nested
1881 // table in the last cell, and the last section text.
1882 assertXPath(pXml, "/root/page");
1883 // Without the fix in place, this would fail with
1884 // - Expected: 2
1885 // - Actual : 3
1886 assertXPath(pXml, "/root/page/body/section", 2);
1887 assertXPath(pXml, "/root/page/body/section[1]/tab");
1888 assertXPath(pXml, "/root/page/body/section[1]/tab/row");
1889 assertXPath(pXml, "/root/page/body/section[1]/tab/row/cell", 2);
1890 assertXPath(pXml, "/root/page/body/section[1]/tab/row/cell[1]/txt/SwParaPortion/SwLineLayout/"
1891 "SwParaPortion[@portion='foo']");
1892 assertXPath(pXml, "/root/page/body/section[1]/tab/row/cell[2]/txt/SwParaPortion/SwLineLayout/"
1893 "SwParaPortion[@portion='bar']");
1894 assertXPath(pXml, "/root/page/body/section[1]/tab/row/cell[2]/tab/row/cell/txt/SwParaPortion/"
1895 "SwLineLayout/SwParaPortion[@portion='baz']");
1896 assertXPath(pXml, "/root/page/body/section[2]/txt[1]/SwParaPortion/SwLineLayout/"
1897 "SwParaPortion[@portion='abc']");
1899 // Also must not crash on close because of a frame that accidentally fell off of the layout
1902 CPPUNIT_PLUGIN_IMPLEMENT();
1904 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */