tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / sw / qa / extras / layout / layout3.cxx
blobaf6dac583f29e5e95ebac997cd3bd0ed8dc6b54e
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 <com/sun/star/text/XTextSectionsSupplier.hpp>
15 #include <vcl/event.hxx>
16 #include <vcl/metaact.hxx>
17 #include <vcl/scheduler.hxx>
18 #include <editeng/fontitem.hxx>
19 #include <editeng/fhgtitem.hxx>
20 #include <editeng/postitem.hxx>
21 #include <editeng/unolingu.hxx>
22 #include <comphelper/sequence.hxx>
24 #include <anchoredobject.hxx>
25 #include <fmtfsize.hxx>
26 #include <wrtsh.hxx>
27 #include <edtwin.hxx>
28 #include <view.hxx>
29 #include <txtfrm.hxx>
30 #include <pagefrm.hxx>
31 #include <bodyfrm.hxx>
32 #include <sortedobjs.hxx>
33 #include <ndtxt.hxx>
34 #include <frmatr.hxx>
35 #include <IDocumentSettingAccess.hxx>
36 #include <unotxdoc.hxx>
37 #include <rootfrm.hxx>
38 #include <IDocumentLayoutAccess.hxx>
39 #include <IDocumentDrawModelAccess.hxx>
40 #include <drawdoc.hxx>
41 #include <svx/svdpage.hxx>
43 namespace
45 /// Test to assert layout / rendering result of Writer.
46 class SwLayoutWriter3 : public SwModelTestBase
48 public:
49 SwLayoutWriter3()
50 : SwModelTestBase(u"/sw/qa/extras/layout/data/"_ustr)
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", u"21");
63 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf117188)
65 createSwDoc("tdf117188.docx");
66 saveAndReload(u"writer8"_ustr);
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", u"0");
72 assertXPath(pXmlDoc, "/root/page/body/txt/anchored/fly/infos/prtBounds", "top", u"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);
87 #if defined _WIN32 && defined _ARM64_
88 // skip for windows arm64 build
89 #else
90 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf119875)
92 createSwDoc("tdf119875.odt");
93 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
95 assertXPath(pXmlDoc, "//page[2]/body/section[1]", "formatName", u"S10");
96 assertXPath(pXmlDoc, "//page[2]/body/section[2]", "formatName", u"S11");
97 assertXPath(pXmlDoc, "//page[2]/body/section[3]", "formatName", u"S13");
98 assertXPath(pXmlDoc, "//page[2]/body/section[4]", "formatName", u"S14");
99 // Sections "S10" and "S13" are hidden -> their frames are zero-height
100 assertXPath(pXmlDoc, "//page[2]/body/section[1]/infos/bounds", "height", u"0");
101 assertXPath(pXmlDoc, "//page[2]/body/section[3]/infos/bounds", "height", u"0");
103 OUString S10Top = getXPath(pXmlDoc, "//page[2]/body/section[1]/infos/bounds", "top");
104 OUString S11Top = getXPath(pXmlDoc, "//page[2]/body/section[2]/infos/bounds", "top");
105 OUString S13Top = getXPath(pXmlDoc, "//page[2]/body/section[3]/infos/bounds", "top");
106 OUString S14Top = getXPath(pXmlDoc, "//page[2]/body/section[4]/infos/bounds", "top");
108 CPPUNIT_ASSERT_EQUAL(S10Top, S11Top);
109 CPPUNIT_ASSERT_EQUAL(S13Top, S14Top);
111 // Section "S11" had the same top value as section "S14", so they overlapped.
112 CPPUNIT_ASSERT_LESS(S14Top.toInt32(), S11Top.toInt32());
114 #endif
116 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf137523)
118 createSwDoc("tdf137523-1-min.fodt");
119 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
120 // the problem was that in the footer, the text frames below the table
121 // had wrong height and were not visible
122 assertXPath(pXmlDoc, "/root/page/footer/txt[1]/infos/bounds", "height", u"304");
123 assertXPath(pXmlDoc, "/root/page/footer/txt[2]/infos/bounds", "height", u"191");
124 assertXPath(pXmlDoc, "/root/page/footer/txt[3]/infos/bounds", "height", u"219");
125 assertXPath(pXmlDoc, "/root/page/footer/tab/infos/bounds", "height", u"1378");
128 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf120287)
130 createSwDoc("tdf120287.fodt");
131 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
132 // This was 2, TabOverMargin Word-specific compat flag did not imply
133 // default-in-Word printer-independent layout, resulting in an additional
134 // line break.
135 assertXPath(pXmlDoc, "/root/page/body/txt[1]/SwParaPortion/SwLineLayout", 1);
138 auto getXPathIntAttributeValue(xmlXPathContextPtr pXmlXpathCtx, char const* const pXPath)
139 -> sal_Int32
141 xmlXPathObjectPtr pXmlXpathObj = xmlXPathEvalExpression(BAD_CAST(pXPath), pXmlXpathCtx);
142 CPPUNIT_ASSERT(pXmlXpathObj->nodesetval);
143 CPPUNIT_ASSERT_EQUAL(1, xmlXPathNodeSetGetLength(pXmlXpathObj->nodesetval));
144 auto ret
145 = sal_Int32(xmlXPathCastNodeToNumber(xmlXPathNodeSetItem(pXmlXpathObj->nodesetval, 0)));
146 xmlXPathFreeObject(pXmlXpathObj);
147 return ret;
150 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf128966)
152 createSwDoc("tdf128966-2-min.odt");
154 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
156 xmlXPathObjectPtr pXmlObj
157 = getXPathNode(pXmlDoc, "/root/page/body/tab/row/cell[@rowspan > 0][child::txt]");
158 xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
159 CPPUNIT_ASSERT(pXmlNodes);
160 CPPUNIT_ASSERT_GREATER(300, xmlXPathNodeSetGetLength(pXmlNodes)); // many...
162 xmlXPathContextPtr pXmlXpathCtx = xmlXPathNewContext(pXmlDoc.get());
163 registerNamespaces(pXmlXpathCtx);
165 for (int i = 0; i < xmlXPathNodeSetGetLength(pXmlNodes); ++i)
167 xmlNodePtr pNode = xmlXPathNodeSetItem(pXmlNodes, i);
168 xmlXPathSetContextNode(pNode, pXmlXpathCtx);
170 OString msg("Cell nr.: " + OString::number(i)
171 + " id=" + OString::number(getXPathIntAttributeValue(pXmlXpathCtx, "@id")));
173 auto nCellTop = getXPathIntAttributeValue(pXmlXpathCtx, "infos/bounds/@top");
174 auto nCellHeight = getXPathIntAttributeValue(pXmlXpathCtx, "infos/bounds/@height");
175 auto nCellCenter = nCellTop + (nCellHeight / 2);
177 auto nContentTop
178 = getXPathIntAttributeValue(pXmlXpathCtx, "txt[position()=1]/infos/bounds/@top");
179 auto nContentBottom = getXPathIntAttributeValue(
180 pXmlXpathCtx, "txt[position()=last()]/infos/bounds/@bottom");
182 CPPUNIT_ASSERT_MESSAGE(msg.getStr(), nContentTop < nCellCenter);
183 CPPUNIT_ASSERT_MESSAGE(msg.getStr(), nContentBottom > nCellCenter);
186 xmlXPathFreeContext(pXmlXpathCtx);
187 xmlXPathFreeObject(pXmlObj);
190 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf161718)
192 createSwDoc("tdf161718.docx");
194 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
196 // everything on one page
197 assertXPath(pXmlDoc, "/root/page/header", 1);
198 assertXPath(pXmlDoc, "/root/page/header/txt/anchored", 1);
199 assertXPath(pXmlDoc, "/root/page/footer", 1);
200 assertXPath(pXmlDoc, "/root/page/ftncont/ftn", 1);
201 assertXPath(pXmlDoc, "/root/page/ftncont/ftn/txt", 1);
202 assertXPath(pXmlDoc, "/root/page/body/txt", 27);
203 assertXPath(pXmlDoc, "/root/page/body/txt/anchored", 1);
204 assertXPath(pXmlDoc, "/root/page", 1);
207 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf119908)
209 createSwDoc("tdf130088.docx");
210 // Ensure that all text portions are calculated before testing.
211 SwViewShell* pViewShell = getSwDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
212 CPPUNIT_ASSERT(pViewShell);
213 pViewShell->Reformat();
215 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
216 // Keep real width of the exceeding line portions to calculate shrinking
217 sal_Int32 nPortionWidth
218 = getXPath(pXmlDoc, "/root/page/body/txt[1]/SwParaPortion/SwLineLayout[2]/SwLinePortion[2]",
219 "width")
220 .toInt32();
221 // This was 5806 (not real portion width, but stripped to the line width)
222 CPPUNIT_ASSERT_GREATER(sal_Int32(5840), nPortionWidth);
225 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf158333)
227 createSwDoc("tdf130088.docx");
228 // Ensure that all text portions are calculated before testing.
229 SwViewShell* pViewShell = getSwDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
230 CPPUNIT_ASSERT(pViewShell);
231 pViewShell->Reformat();
233 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
235 // shrink line 2
236 assertXPath(
237 pXmlDoc, "/root/page/body/txt[1]/SwParaPortion/SwLineLayout[2]", "portion",
238 u"viverra odio. Donec auctor molestie sem, sit amet tristique lectus hendrerit sed. ");
240 // shrink line 7
241 assertXPath(
242 pXmlDoc, "/root/page/body/txt[1]/SwParaPortion/SwLineLayout[7]", "portion",
243 // This was "...diam ", not "...diam tempor "
244 u"laoreet vel leo nec, volutpat facilisis eros. Donec consequat arcu ut diam tempor ");
246 // shrink line 2 of paragraph 2
247 assertXPath(
248 pXmlDoc, "/root/page/body/txt[2]/SwParaPortion/SwLineLayout[2]", "portion",
249 // This was "...Cras ", not "...Cras sodales "
250 u"Donec auctor molestie sem, sit amet tristique lectus hendrerit sed. Cras sodales ");
252 // shrink line 2 of paragraph 4
253 assertXPath(pXmlDoc, "/root/page/body/txt[4]/SwParaPortion/SwLineLayout[2]", "portion",
254 // This was "...et ", not "...et magnis "
255 u"consequat arcu ut diam tempor luctus. Cum sociis natoque penatibus et magnis ");
257 // tdf#158776 don't shrink line 11 of paragraph 4
258 assertXPath(pXmlDoc, "/root/page/body/txt[4]/SwParaPortion/SwLineLayout[11]", "portion",
259 // This was "...quis curcus ", not "...quis "
260 u"venenatis, quis commodo dolor posuere. Curabitur dignissim sapien quis ");
263 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf159085)
265 createSwDoc("tdf159085.fodt");
266 // Ensure that all text portions are calculated before testing.
267 SwViewShell* pViewShell = getSwDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
268 CPPUNIT_ASSERT(pViewShell);
269 pViewShell->Reformat();
271 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
273 // This was "... cursus" instead of breaking the word at soft hyphen
274 assertXPath(pXmlDoc, "/root/page/body/txt[1]/SwParaPortion/SwLineLayout[1]", "portion",
275 u"venenatis, quis commodo dolor posuere. Curabitur dignissim sapien quis cur­");
277 // This was "... cursus" instead of breaking the word at soft hyphen
278 assertXPath(pXmlDoc, "/root/page/body/txt[2]/SwParaPortion/SwLineLayout[1]", "portion",
279 u"venenatis, quis commodo dolor posuere. Curabitur dignissim sapien quis cur­");
282 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf158419)
284 createSwDoc("tdf130088.docx");
285 SwDoc* pDoc = getSwDoc();
286 SwDocShell* pShell = getSwDocShell();
288 // Ensure that all text portions are calculated before testing.
289 SwViewShell* pViewShell = getSwDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
290 CPPUNIT_ASSERT(pViewShell);
291 pViewShell->Reformat();
293 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
295 // second paragraph.
296 SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
297 SwWrtShell* pWrtShell = pShell->GetWrtShell();
298 SwPosition aPosition(*pWrtShell->GetCursor()->Start());
299 SwTwips nSecondParaLeft
300 = getXPath(pXmlDoc, "/root/page/body/txt[2]/infos/bounds", "left").toInt32();
301 SwTwips nSecondParaWidth
302 = getXPath(pXmlDoc, "/root/page/body/txt[2]/infos/bounds", "width").toInt32();
303 SwTwips nSecondParaTop
304 = getXPath(pXmlDoc, "/root/page/body/txt[2]/infos/bounds", "top").toInt32();
305 SwTwips nSecondParaHeight
306 = getXPath(pXmlDoc, "/root/page/body/txt[2]/infos/bounds", "height").toInt32();
307 Point aPoint;
309 // click at the end of the second line of the second paragraph
310 // (a line shrunk by the new justification)
312 aPoint.setX(nSecondParaLeft + nSecondParaWidth);
313 aPoint.setY(nSecondParaTop + (nSecondParaHeight / 6) * 1.5);
314 SwCursorMoveState aState(CursorMoveState::NONE);
315 pLayout->GetModelPositionForViewPoint(&aPosition, aPoint, &aState);
316 // Without the accompanying fix in place, this test would have failed: character position was 155,
317 // i.e. cursor was before the end of the paragraph.
318 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(156), aPosition.GetContentIndex());
321 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf163042)
323 createSwDoc("tdf163042.fodt");
324 SwDoc* pDoc = getSwDoc();
325 SwDocShell* pShell = getSwDocShell();
327 // Ensure that all text portions are calculated before testing.
328 SwViewShell* pViewShell = getSwDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
329 CPPUNIT_ASSERT(pViewShell);
330 pViewShell->Reformat();
332 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
334 // 1-line paragraph
335 SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
336 SwWrtShell* pWrtShell = pShell->GetWrtShell();
337 SwPosition aPosition(*pWrtShell->GetCursor()->Start());
338 SwTwips nParaLeft = getXPath(pXmlDoc, "/root/page/body/txt[1]/infos/bounds", "left").toInt32();
339 SwTwips nParaWidth
340 = getXPath(pXmlDoc, "/root/page/body/txt[1]/infos/bounds", "width").toInt32();
341 SwTwips nParaTop = getXPath(pXmlDoc, "/root/page/body/txt[1]/infos/bounds", "top").toInt32();
342 SwTwips nParaHeight
343 = getXPath(pXmlDoc, "/root/page/body/txt[1]/infos/bounds", "height").toInt32();
344 Point aPoint;
346 // click before the last but one character of the paragraph
347 // (in a line shrunk by the new space shrinking justification)
349 aPoint.setX(nParaLeft + nParaWidth - 2 * nParaWidth / 160);
350 aPoint.setY(nParaTop + nParaHeight * 0.5);
351 SwCursorMoveState aState(CursorMoveState::NONE);
352 pLayout->GetModelPositionForViewPoint(&aPosition, aPoint, &aState);
353 // Without the accompanying fix in place, this test would have failed: character position was 160,
354 // i.e. cursor was at the end of the paragraph instead of the last but one character
355 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(158), aPosition.GetContentIndex());
358 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf163060)
360 createSwDoc("tdf163060.fodt");
362 // Ensure that all text portions are calculated before testing.
363 SwViewShell* pViewShell = getSwDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
364 CPPUNIT_ASSERT(pViewShell);
365 pViewShell->Reformat();
367 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
369 // There is only a single shrunk line 1, without breaking the last word
370 // before the last text portion "i"
372 // This ends in "dolorsi" (not "dolors", as before)
373 assertXPath(pXmlDoc, "/root/page/body/txt[1]/SwParaPortion/SwLineLayout[1]", "portion",
374 u"Quis pretium semper. Proin luctus orci a neque venenatis, quis commodo dolorsi");
376 // no second line (there was a second line with the text portion "i").
377 assertXPath(pXmlDoc, "/root/page/body/txt[1]/SwParaPortion/SwLineLayout", 1);
380 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf162109)
382 createSwDoc("tdf162109.fodt");
383 // Ensure that all text portions are calculated before testing.
384 SwViewShell* pViewShell = getSwDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
385 CPPUNIT_ASSERT(pViewShell);
386 pViewShell->Reformat();
388 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
389 // There was no SwGluePortion, because of missing justification of the last paragraph line,
390 // despite it is a full line with shrunk spaces
391 assertXPath(pXmlDoc, "/root/page/body/txt[1]/SwParaPortion/SwLineLayout[1]/SwGluePortion");
394 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf162220)
396 createSwDoc("tdf162220.fodt");
397 // Ensure that all text portions are calculated before testing.
398 SwViewShell* pViewShell = getSwDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
399 CPPUNIT_ASSERT(pViewShell);
400 pViewShell->Reformat();
402 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
403 // There was no SwGluePortion, because of missing justification of the last paragraph line,
404 // despite it is a full line with shrunk spaces
405 assertXPath(pXmlDoc, "/root/page/body/txt[1]/SwParaPortion/SwLineLayout[1]/SwGluePortion");
408 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf163720)
410 uno::Reference<linguistic2::XHyphenator> xHyphenator = LinguMgr::GetHyphenator();
411 if (!xHyphenator->hasLocale(lang::Locale(u"en"_ustr, u"US"_ustr, OUString())))
412 return;
414 createSwDoc("tdf163720.fodt");
415 // Ensure that all text portions are calculated before testing.
416 SwDocShell* pShell = getSwDocShell();
418 // Dump the rendering of the first page as an XML file.
419 std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
420 MetafileXmlDump dumper;
422 xmlDocUniquePtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
423 CPPUNIT_ASSERT(pXmlDoc);
425 // Find the first text array action
426 for (size_t nAction = 0; nAction < xMetaFile->GetActionSize(); nAction++)
428 auto pAction = xMetaFile->GetAction(nAction);
429 if (pAction->GetType() == MetaActionType::TEXTARRAY)
431 auto pTextArrayAction = static_cast<MetaTextArrayAction*>(pAction);
432 auto pDXArray = pTextArrayAction->GetDXArray();
434 // There should be 101 chars on the first line
435 CPPUNIT_ASSERT_EQUAL(size_t(101), pDXArray.size());
437 // Assert we are using the expected position for the last char
438 // This was 10093, now 10003, according to the less shrinking,
439 // than needed for the extra hyphen glyph at hyphenation
440 CPPUNIT_ASSERT_LESS(sal_Int32(10010), sal_Int32(pDXArray[100]));
441 break;
446 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf162725)
448 createSwDoc("tdf162725.fodt");
449 // Ensure that all text portions are calculated before testing.
450 SwViewShell* pViewShell = getSwDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
451 CPPUNIT_ASSERT(pViewShell);
452 pViewShell->Reformat();
454 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
455 // There was no SwGluePortion, because of missing justification of the last paragraph line,
456 // despite it is a full line with shrunk spaces
457 assertXPath(pXmlDoc, "/root/page/body/txt[1]/SwParaPortion/SwLineLayout[1]/SwGluePortion");
460 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf161810)
462 createSwDoc("tdf161810.fodt");
463 // Ensure that all text portions are calculated before testing.
464 SwDocShell* pShell = getSwDocShell();
466 // Dump the rendering of the first page as an XML file.
467 std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
468 MetafileXmlDump dumper;
470 xmlDocUniquePtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
471 CPPUNIT_ASSERT(pXmlDoc);
473 // Find the first text array action
474 for (size_t nAction = 0; nAction < xMetaFile->GetActionSize(); nAction++)
476 auto pAction = xMetaFile->GetAction(nAction);
477 if (pAction->GetType() == MetaActionType::TEXTARRAY)
479 auto pTextArrayAction = static_cast<MetaTextArrayAction*>(pAction);
480 auto pDXArray = pTextArrayAction->GetDXArray();
482 // There should be 73 chars on the first line
483 CPPUNIT_ASSERT_EQUAL(size_t(73), pDXArray.size());
485 // Assert we are using the expected position for the last char
486 // This was 9369, now 9165, according to the fixed space shrinking
487 CPPUNIT_ASSERT_LESS(sal_Int32(9300), sal_Int32(pDXArray[72]));
488 break;
493 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf163149)
495 createSwDoc("tdf163149.docx");
496 // Ensure that all text portions are calculated before testing.
497 SwDocShell* pShell = getSwDocShell();
499 // Dump the rendering of the first page as an XML file.
500 std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
501 MetafileXmlDump dumper;
503 xmlDocUniquePtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
504 CPPUNIT_ASSERT(pXmlDoc);
506 // Find the text array action for the second non-empty (shrunk) line
507 bool bFirst = true;
508 for (size_t nAction = 0; nAction < xMetaFile->GetActionSize(); nAction++)
510 auto pAction = xMetaFile->GetAction(nAction);
511 if (pAction->GetType() == MetaActionType::TEXTARRAY)
513 auto pTextArrayAction = static_cast<MetaTextArrayAction*>(pAction);
514 auto pDXArray = pTextArrayAction->GetDXArray();
516 // skip empty paragraphs
517 if (pDXArray.size() <= 1)
518 continue;
520 // skip first non-empty line
521 if (bFirst)
523 bFirst = false;
524 continue;
527 // There should be 46 chars on the second line
528 CPPUNIT_ASSERT_EQUAL(size_t(46), pDXArray.size());
530 // Assert we are using the expected position for the last char
531 // This was 4673, now 4163, according to the fixed space shrinking
532 CPPUNIT_ASSERT_LESS(sal_Int32(4200), sal_Int32(pDXArray[45]));
533 break;
538 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf132599_always)
540 uno::Reference<linguistic2::XHyphenator> xHyphenator = LinguMgr::GetHyphenator();
541 if (!xHyphenator->hasLocale(lang::Locale(u"en"_ustr, u"US"_ustr, OUString())))
542 return;
544 createSwDoc("tdf132599_always.fodt");
545 // Ensure that all text portions are calculated before testing.
546 SwViewShell* pViewShell = getSwDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
547 CPPUNIT_ASSERT(pViewShell);
548 pViewShell->Reformat();
550 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
552 // 2nd paragraph: hyphenated last full line
553 assertXPath(pXmlDoc, "/root/page/body/txt[2]/SwParaPortion/SwLineLayout[2]", "portion",
554 u"ent to any other celes");
556 // hyphenation-keep-type='always'
557 // 3rd paragraph: not hyphenated last full line of the hyphenated paragraph
558 assertXPath(pXmlDoc, "/root/page/body/txt[3]/SwParaPortion/SwLineLayout[2]", "portion",
559 u"ent to any other ");
562 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf132599_frames_on_same_page_no_hyphenation)
564 uno::Reference<linguistic2::XHyphenator> xHyphenator = LinguMgr::GetHyphenator();
565 if (!xHyphenator->hasLocale(lang::Locale(u"en"_ustr, u"US"_ustr, OUString())))
566 return;
568 createSwDoc("tdf132599_frames_on_same_page_no_hyphenation.fodt");
569 // Ensure that all text portions are calculated before testing.
570 SwViewShell* pViewShell = getSwDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
571 CPPUNIT_ASSERT(pViewShell);
572 pViewShell->Reformat();
574 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
576 // loext:hyphenation-keep-type="column"
577 // 2nd frame: shifted hyphenated line (no hyphenation at the end of the first frame)
578 assertXPath(pXmlDoc, "/root/page/body/txt/anchored/fly[2]/txt/SwParaPortion/SwLineLayout[1]",
579 "portion", u"space, ex");
582 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf132599_frames_on_same_page_hyphenation)
584 uno::Reference<linguistic2::XHyphenator> xHyphenator = LinguMgr::GetHyphenator();
585 if (!xHyphenator->hasLocale(lang::Locale(u"en"_ustr, u"US"_ustr, OUString())))
586 return;
588 createSwDoc("tdf132599_frames_on_same_page_hyphenation.fodt");
589 // Ensure that all text portions are calculated before testing.
590 SwViewShell* pViewShell = getSwDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
591 CPPUNIT_ASSERT(pViewShell);
592 pViewShell->Reformat();
594 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
596 // loext:hyphenation-keep-type="page"
597 // 2nd frame: not shifted hyphenated line (hyphenation at the end of the first frame),
598 // This was "space, ex" (bad shifting)
599 assertXPath(pXmlDoc, "/root/page/body/txt/anchored/fly[2]/txt/SwParaPortion/SwLineLayout[1]",
600 "portion", u"cept that it ");
603 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf132599_frames_on_right_pages_no_hyphenation)
605 uno::Reference<linguistic2::XHyphenator> xHyphenator = LinguMgr::GetHyphenator();
606 if (!xHyphenator->hasLocale(lang::Locale(u"en"_ustr, u"US"_ustr, OUString())))
607 return;
609 createSwDoc("tdf132599_frames_on_right_pages_no_hyphenation.fodt");
610 // Ensure that all text portions are calculated before testing.
611 SwViewShell* pViewShell = getSwDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
612 CPPUNIT_ASSERT(pViewShell);
613 pViewShell->Reformat();
615 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
617 // loext:hyphenation-keep-type="spread"
618 // 2nd frame: shifted hyphenated line
619 // This was "cept that it" (missing shifting)
620 assertXPath(pXmlDoc, "/root/page[3]/body/txt/anchored/fly/txt/SwParaPortion/SwLineLayout[1]",
621 "portion", u"space, ex");
624 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf132599_frames_on_spread_hyphenation)
626 uno::Reference<linguistic2::XHyphenator> xHyphenator = LinguMgr::GetHyphenator();
627 if (!xHyphenator->hasLocale(lang::Locale(u"en"_ustr, u"US"_ustr, OUString())))
628 return;
630 createSwDoc("tdf132599_frames_on_spread_hyphenation.fodt");
631 // Ensure that all text portions are calculated before testing.
632 SwViewShell* pViewShell = getSwDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
633 CPPUNIT_ASSERT(pViewShell);
634 pViewShell->Reformat();
636 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
638 // loext:hyphenation-keep-type="spread"
639 // 2nd frame on left page and 3rd frame on right page -> not shifted hyphenated line
640 // 2nd frame: not shifted hyphenated line (hyphenation at the end of the first frame),
641 assertXPath(pXmlDoc, "/root/page[3]/body/txt/anchored/fly/txt/SwParaPortion/SwLineLayout[1]",
642 "portion", u"cept that it ");
645 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf106234)
647 createSwDoc("tdf106234.fodt");
648 // Ensure that all text portions are calculated before testing.
649 SwViewShell* pViewShell = getSwDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
650 CPPUNIT_ASSERT(pViewShell);
651 pViewShell->Reformat();
653 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
654 // In justified paragraphs, there is justification between left tabulators and manual line breaks
655 assertXPath(pXmlDoc, "/root/page/body/txt[1]/SwParaPortion/SwLineLayout[1]/SwGluePortion",
656 "type", u"PortionType::Margin");
657 assertXPath(pXmlDoc, "/root/page/body/txt[1]/SwParaPortion/SwLineLayout[1]/SwGluePortion",
658 "width", u"0");
659 // but not after centered, right and decimal tabulators
660 assertXPath(pXmlDoc, "/root/page/body/txt[2]/SwParaPortion/SwLineLayout[1]/SwGluePortion",
661 "type", u"PortionType::Margin");
662 // This was a justified line, without width
663 assertXPath(pXmlDoc, "/root/page/body/txt[2]/SwParaPortion/SwLineLayout[1]/SwGluePortion",
664 "width", u"7882");
667 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf155324)
669 createSwDoc("tox-update-wrong-pages.odt");
671 dispatchCommand(mxComponent, u".uno:UpdateAllIndexes"_ustr, {});
673 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
675 // the problem was that the first entry was on page 7, 2nd on page 9 etc.
676 assertXPath(pXmlDoc,
677 "/root/page[1]/body/section[2]/txt[1]/SwParaPortion/SwLineLayout/SwLinePortion[1]",
678 "portion", u"Foo");
679 assertXPath(pXmlDoc,
680 "/root/page[1]/body/section[2]/txt[1]/SwParaPortion/SwLineLayout/SwLinePortion[2]",
681 "portion", u"5");
682 assertXPath(pXmlDoc,
683 "/root/page[1]/body/section[2]/txt[2]/SwParaPortion/SwLineLayout/SwLinePortion[1]",
684 "portion", u"bar");
685 assertXPath(pXmlDoc,
686 "/root/page[1]/body/section[2]/txt[2]/SwParaPortion/SwLineLayout/SwLinePortion[2]",
687 "portion", u"7");
688 assertXPath(pXmlDoc,
689 "/root/page[1]/body/section[2]/txt[3]/SwParaPortion/SwLineLayout/SwLinePortion[1]",
690 "portion", u"Three");
691 assertXPath(pXmlDoc,
692 "/root/page[1]/body/section[2]/txt[3]/SwParaPortion/SwLineLayout/SwLinePortion[2]",
693 "portion", u"7");
695 // check first content page has the footnotes
696 assertXPath(pXmlDoc, "/root/page[5]/body/txt[1]/SwParaPortion/SwLineLayout", "portion", u"Foo");
697 assertXPath(pXmlDoc, "/root/page[4]/ftncont", 0);
698 assertXPath(pXmlDoc, "/root/page[5]/ftncont/ftn", 5);
701 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf120287b)
703 createSwDoc("tdf120287b.fodt");
704 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
705 // This was 1418, TabOverMargin did the right split of the paragraph to two
706 // lines, but then calculated a too large tab portion size on the first
707 // line.
708 assertXPath(
709 pXmlDoc,
710 "/root/page/body/txt[1]/SwParaPortion/SwLineLayout/child::*[@type='PortionType::TabRight']",
711 "width", u"1");
714 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf120287c)
716 createSwDoc("tdf120287c.fodt");
717 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
718 // This was 3, the second line was broken into a 2nd and a 3rd one,
719 // not rendering text outside the paragraph frame like Word 2013 does.
720 assertXPath(pXmlDoc, "/root/page/body/txt[1]/SwParaPortion/SwLineLayout", 2);
723 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf158658a)
725 createSwDoc("tdf158658a.rtf");
726 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
728 // Word 2013 puts all tabs into one line, the last 8 of them are off the page
729 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/SwParaPortion/SwLineLayout", 1);
730 assertXPath(pXmlDoc,
731 "/root/page[1]/header/txt[1]/SwParaPortion/SwLineLayout/"
732 "child::*[@type='PortionType::TabCenter']",
734 assertXPath(pXmlDoc,
735 "/root/page[1]/header/txt[1]/SwParaPortion/SwLineLayout/"
736 "child::*[@type='PortionType::TabRight']",
738 assertXPath(pXmlDoc,
739 "/root/page[1]/header/txt[1]/SwParaPortion/SwLineLayout/"
740 "child::*[@type='PortionType::TabLeft']",
744 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf158658b)
746 createSwDoc("tdf158658b.rtf");
747 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
749 // Word 2013 puts all tabs and the field following into one line
750 // and also puts the field off the page
751 assertXPath(pXmlDoc, "/root/page[1]/footer/txt[1]/SwParaPortion/SwLineLayout", 1);
752 assertXPath(pXmlDoc,
753 "/root/page[1]/footer/txt[1]/SwParaPortion/SwLineLayout/"
754 "child::*[@type='PortionType::TabCenter']",
756 assertXPath(pXmlDoc,
757 "/root/page[1]/footer/txt[1]/SwParaPortion/SwLineLayout/"
758 "child::*[@type='PortionType::TabRight']",
760 assertXPath(pXmlDoc,
761 "/root/page[1]/footer/txt[1]/SwParaPortion/SwLineLayout/"
762 "child::*[@type='PortionType::TabRight']",
763 "width", u"4446"); // was very small: 24
764 assertXPath(pXmlDoc,
765 "/root/page[1]/footer/txt[1]/SwParaPortion/SwLineLayout/"
766 "child::*[@type='PortionType::TabLeft']",
770 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf158658c)
772 createSwDoc("tdf158658c.rtf");
773 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
775 // Word 2013 puts all tabs into one line, the last 17 of them are off the page
776 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/SwParaPortion/SwLineLayout", 1);
777 assertXPath(pXmlDoc,
778 "/root/page[1]/header/txt[1]/SwParaPortion/SwLineLayout/"
779 "child::*[@type='PortionType::TabCenter']",
781 // the right tab is exactly at the margin of the paragraph
782 assertXPath(pXmlDoc,
783 "/root/page[1]/header/txt[1]/SwParaPortion/SwLineLayout/"
784 "child::*[@type='PortionType::TabRight']",
786 assertXPath(pXmlDoc,
787 "/root/page[1]/header/txt[1]/SwParaPortion/SwLineLayout/"
788 "child::*[@type='PortionType::TabLeft']",
789 20);
792 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf155177)
794 createSwDoc("tdf155177-1-min.odt");
796 uno::Reference<beans::XPropertySet> xStyle(
797 getStyles(u"ParagraphStyles"_ustr)->getByName(u"Text body"_ustr), uno::UNO_QUERY_THROW);
798 CPPUNIT_ASSERT_EQUAL(sal_Int32(210), getProperty<sal_Int32>(xStyle, u"ParaTopMargin"_ustr));
801 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
802 assertXPath(pXmlDoc, "/root/page[2]/body/txt", 6);
803 assertXPath(pXmlDoc, "/root/page[2]/body/txt[6]/SwParaPortion/SwLineLayout", 2);
804 assertXPath(pXmlDoc, "/root/page[2]/body/txt[6]/SwParaPortion/SwLineLayout[2]", "portion",
805 u"long as two lines.");
806 assertXPath(pXmlDoc, "/root/page[3]/body/txt[1]/SwParaPortion/SwLineLayout", 3);
807 assertXPath(pXmlDoc, "/root/page[3]/body/txt[1]/SwParaPortion/SwLineLayout[1]", "portion",
808 u"This paragraph is even longer so that ");
811 // this should bring one line back
812 xStyle->setPropertyValue(u"ParaTopMargin"_ustr, uno::Any(sal_Int32(200)));
814 Scheduler::ProcessEventsToIdle();
817 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
818 assertXPath(pXmlDoc, "/root/page[2]/body/txt", 7);
819 assertXPath(pXmlDoc, "/root/page[2]/body/txt[7]/SwParaPortion/SwLineLayout", 1);
820 assertXPath(pXmlDoc, "/root/page[2]/body/txt[7]/SwParaPortion/SwLineLayout[1]", "portion",
821 u"This paragraph is even longer so that ");
822 assertXPath(pXmlDoc, "/root/page[3]/body/txt[1]/SwParaPortion/SwLineLayout", 2);
823 assertXPath(pXmlDoc, "/root/page[3]/body/txt[1]/SwParaPortion/SwLineLayout[1]", "portion",
824 u"it is now three lines long though ");
827 // this should bring second line back
828 xStyle->setPropertyValue(u"ParaTopMargin"_ustr, uno::Any(sal_Int32(120)));
830 Scheduler::ProcessEventsToIdle();
833 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
834 assertXPath(pXmlDoc, "/root/page[2]/body/txt", 7);
835 assertXPath(pXmlDoc, "/root/page[2]/body/txt[7]/SwParaPortion/SwLineLayout", 2);
836 assertXPath(pXmlDoc, "/root/page[2]/body/txt[7]/SwParaPortion/SwLineLayout[1]", "portion",
837 u"This paragraph is even longer so that ");
838 assertXPath(pXmlDoc, "/root/page[2]/body/txt[7]/SwParaPortion/SwLineLayout[2]", "portion",
839 u"it is now three lines long though ");
840 assertXPath(pXmlDoc, "/root/page[3]/body/txt[1]/SwParaPortion/SwLineLayout", 1);
841 assertXPath(pXmlDoc, "/root/page[3]/body/txt[1]/SwParaPortion/SwLineLayout[1]", "portion",
842 u"containing a single sentence.");
846 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf122878)
848 createSwDoc("tdf122878.docx");
849 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
850 const sal_Int32 nTblTop
851 = getXPath(pXmlDoc, "/root/page[1]/footer/txt/anchored/fly/tab/infos/bounds", "top")
852 .toInt32();
853 SwDoc* pDoc = getSwDoc();
854 SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
855 auto pPage1 = dynamic_cast<SwPageFrame*>(pLayout->Lower());
856 CPPUNIT_ASSERT(pPage1);
857 SwFrame* pBody = pPage1->FindBodyCont();
858 for (SwFrame* pFrame = pBody->GetLower(); pFrame; pFrame = pFrame->GetNext())
860 const sal_Int32 nTxtBottom = pFrame->getFrameArea().Bottom();
861 // No body paragraphs should overlap the table in the footer
862 CPPUNIT_ASSERT_MESSAGE(
863 OString("testing paragraph #" + OString::number(pFrame->GetFrameId())).getStr(),
864 nTxtBottom <= nTblTop);
868 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf115094)
870 createSwDoc("tdf115094.docx");
871 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
873 sal_Int32 nTopOfD1
874 = getXPath(pXmlDoc, "/root/page/body/txt/anchored/fly/tab/row[1]/cell[4]/infos/bounds",
875 "top")
876 .toInt32();
877 sal_Int32 nTopOfD1Anchored = getXPath(pXmlDoc,
878 "/root/page/body/txt/anchored/fly/tab/row[1]/cell[4]/"
879 "txt[2]/anchored/fly/infos/bounds",
880 "top")
881 .toInt32();
882 CPPUNIT_ASSERT_LESS(nTopOfD1Anchored, nTopOfD1);
883 sal_Int32 nTopOfB2
884 = getXPath(pXmlDoc, "/root/page/body/txt/anchored/fly/tab/row[2]/cell[2]/infos/bounds",
885 "top")
886 .toInt32();
887 sal_Int32 nTopOfB2Anchored = getXPath(pXmlDoc,
888 "/root/page/body/txt/anchored/fly/tab/row[2]/cell[2]/"
889 "txt[1]/anchored/fly/infos/bounds",
890 "top")
891 .toInt32();
892 CPPUNIT_ASSERT_LESS(nTopOfB2Anchored, nTopOfB2);
895 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf112290)
897 createSwDoc("tdf112290.docx");
898 auto pXml = parseLayoutDump();
899 assertXPath(pXml, "/root/page/body/txt/SwParaPortion/SwLineLayout[2]", "portion", u"Xxxx Xxxx");
902 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testKeepWithNextPlusFlyFollowTextFlow)
904 createSwDoc("keep-with-next-fly.fodt");
907 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
908 // 3 text frames on page 1
909 assertXPath(pXmlDoc, "/root/page[1]/body/infos/bounds", "bottom", u"7540");
910 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/infos/bounds", "height", u"276");
911 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/infos/bounds", "height", u"276");
912 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly", 1);
913 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly/infos/bounds", "top", u"1694");
914 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/infos/bounds", "height", u"276");
915 assertXPath(pXmlDoc, "/root/page", 1);
918 dispatchCommand(mxComponent, u".uno:Fieldnames"_ustr, {});
921 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
922 // 1 text frame on page 1, and some empty space
923 assertXPath(pXmlDoc, "/root/page[1]/body/infos/bounds", "bottom", u"7540");
924 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/infos/bounds", "height", u"5796");
925 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/infos/bounds", "bottom", u"7213");
926 // 2 text frames on page 2
927 assertXPath(pXmlDoc, "/root/page[2]/body/txt[1]/infos/bounds", "height", u"276");
928 assertXPath(pXmlDoc, "/root/page[2]/body/txt[1]/anchored/fly", 1);
929 assertXPath(pXmlDoc, "/root/page[2]/body/txt[1]/anchored/fly/infos/bounds", "top",
930 u"10093");
931 assertXPath(pXmlDoc, "/root/page[2]/body/txt[2]/infos/bounds", "height", u"276");
932 assertXPath(pXmlDoc, "/root/page", 2);
935 dispatchCommand(mxComponent, u".uno:Fieldnames"_ustr, {});
938 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
939 // 3 text frames on page 1
940 assertXPath(pXmlDoc, "/root/page[1]/body/infos/bounds", "bottom", u"7540");
941 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/infos/bounds", "height", u"276");
942 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/infos/bounds", "height", u"276");
943 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly", 1);
944 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly/infos/bounds", "top", u"1694");
945 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/infos/bounds", "height", u"276");
946 assertXPath(pXmlDoc, "/root/page", 1);
950 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf122607)
952 createSwDoc("tdf122607.odt");
953 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
954 assertXPath(pXmlDoc,
955 "/root/page[1]/anchored/fly/txt[1]/anchored/fly/tab/row[2]/cell/txt[7]/anchored/"
956 "fly/txt/SwParaPortion/SwLineLayout/child::*[1]",
957 "height", u"253");
958 assertXPath(pXmlDoc,
959 "/root/page[1]/anchored/fly/txt[1]/anchored/fly/tab/row[2]/cell/txt[7]/anchored/"
960 "fly/txt/SwParaPortion/SwLineLayout/child::*[1]",
961 "width", u"427");
962 assertXPath(pXmlDoc,
963 "/root/page[1]/anchored/fly/txt[1]/anchored/fly/tab/row[2]/cell/txt[7]/anchored/"
964 "fly/txt/SwParaPortion/SwLineLayout/child::*[1]",
965 "portion", u"Fax:");
968 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf122607_regression)
970 // note: must set Hidden property, so that SfxFrameViewWindow_Impl::Resize()
971 // does *not* forward initial VCL Window Resize and thereby triggers a
972 // layout which does not happen on soffice --convert-to pdf.
973 std::vector<beans::PropertyValue> aFilterOptions = {
974 { beans::PropertyValue(u"Hidden"_ustr, -1, uno::Any(true),
975 beans::PropertyState_DIRECT_VALUE) },
978 // inline the loading because currently properties can't be passed...
979 OUString const url(createFileURL(u"tdf122607_leerzeile.odt"));
980 loadWithParams(url, comphelper::containerToSequence(aFilterOptions));
981 save(u"writer_pdf_Export"_ustr);
983 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
984 // somehow these 2 rows overlapped in the PDF unless CalcLayout() runs
985 assertXPath(pXmlDoc, "/root/page[1]/anchored/fly/tab[1]/row[1]/infos/bounds", "mbFixSize",
986 u"false");
987 assertXPath(pXmlDoc, "/root/page[1]/anchored/fly/tab[1]/row[1]/infos/bounds", "top", u"2977");
988 assertXPath(pXmlDoc, "/root/page[1]/anchored/fly/tab[1]/row[1]/infos/bounds", "height", u"241");
989 assertXPath(pXmlDoc, "/root/page[1]/anchored/fly/tab[1]/row[2]/infos/bounds", "mbFixSize",
990 u"true");
991 // this was 3034, causing the overlap
992 assertXPath(pXmlDoc, "/root/page[1]/anchored/fly/tab[1]/row[2]/infos/bounds", "top", u"3218");
993 assertXPath(pXmlDoc, "/root/page[1]/anchored/fly/tab[1]/row[2]/infos/bounds", "height", u"164");
996 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, TestTdf150616)
998 // note: must set Hidden property, so that SfxFrameViewWindow_Impl::Resize()
999 // does *not* forward initial VCL Window Resize and thereby triggers a
1000 // layout which does not happen on soffice --convert-to pdf.
1001 std::vector<beans::PropertyValue> aFilterOptions = {
1002 { beans::PropertyValue(u"Hidden"_ustr, -1, uno::Any(true),
1003 beans::PropertyState_DIRECT_VALUE) },
1006 // inline the loading because currently properties can't be passed...
1007 OUString const url(createFileURL(u"in_056132_mod.odt"));
1008 loadWithParams(url, comphelper::containerToSequence(aFilterOptions));
1009 save(u"writer_pdf_Export"_ustr);
1011 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1012 CPPUNIT_ASSERT(pXmlDoc);
1014 // this one was 0 height
1015 assertXPath(pXmlDoc,
1016 "/root/page[1]/body/tab[3]/row[2]/cell[2]/txt[2]/SwParaPortion/SwLineLayout",
1017 "portion", u"Important information here!");
1018 assertXPath(pXmlDoc, "/root/page[1]/body/tab[3]/row[2]/cell[2]/txt[2]/infos/bounds", "height",
1019 u"253");
1020 assertXPath(pXmlDoc, "/root/page[1]/body/tab[3]/row[2]/cell[2]/txt[2]/infos/bounds", "top",
1021 u"7925");
1022 assertXPath(pXmlDoc,
1023 "/root/page[1]/body/tab[3]/row[2]/cell[2]/txt[3]/SwParaPortion/SwLineLayout",
1024 "portion", u"xxx 111 ");
1025 assertXPath(pXmlDoc, "/root/page[1]/body/tab[3]/row[2]/cell[2]/txt[3]/infos/bounds", "height",
1026 u"697");
1027 assertXPath(pXmlDoc, "/root/page[1]/body/tab[3]/row[2]/cell[2]/txt[3]/infos/bounds", "top",
1028 u"8178");
1031 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testBtlrCell)
1033 createSwDoc("btlr-cell.odt");
1034 SwDocShell* pShell = getSwDocShell();
1036 // Dump the rendering of the first page as an XML file.
1037 std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
1038 MetafileXmlDump dumper;
1039 xmlDocUniquePtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
1040 CPPUNIT_ASSERT(pXmlDoc);
1042 // Without the accompanying fix in place, this test would have failed, as
1043 // the orientation was 0 (layout did not take btlr direction request from
1044 // doc model).
1045 assertXPath(pXmlDoc, "//font[1]", "orientation", u"900");
1047 #if !defined(MACOSX) && !defined(_WIN32) // macOS fails with x == 2662 for some reason.
1048 // Without the accompanying fix in place, this test would have failed with 'Expected: 1915;
1049 // Actual : 1756', i.e. the AAA1 text was too close to the left cell border due to an ascent vs
1050 // descent mismatch when calculating the baseline offset of the text portion.
1051 assertXPath(pXmlDoc, "//textarray[1]", "x", u"1915");
1052 assertXPath(pXmlDoc, "//textarray[1]", "y", u"2707");
1054 // Without the accompanying fix in place, this test would have failed with 'Expected: 1979;
1055 // Actual : 2129', i.e. the gray background of the "AAA2." text was too close to the right edge
1056 // of the text portion. Now it's exactly behind the text portion.
1057 assertXPath(pXmlDoc, "(//rect)[2]", "left", u"1979");
1059 // Without the accompanying fix in place, this test would have failed with 'Expected: 269;
1060 // Actual : 0', i.e. the AAA2 frame was not visible due to 0 width.
1061 pXmlDoc = parseLayoutDump();
1062 assertXPath(pXmlDoc, "/root/page/body/tab/row/cell[1]/txt[2]/infos/bounds", "width", u"269");
1064 // Test the position of the cursor after doc load.
1065 // We expect that it's inside the first text frame in the first cell.
1066 // More precisely, this is a bottom to top vertical frame, so we expect it's at the start, which
1067 // means it's at the lower half of the text frame rectangle (vertically).
1068 SwWrtShell* pWrtShell = pShell->GetWrtShell();
1069 CPPUNIT_ASSERT(pWrtShell);
1071 const SwRect& rCharRect = pWrtShell->GetCharRect();
1072 SwTwips nFirstParaTop
1073 = getXPath(pXmlDoc, "/root/page/body/tab/row/cell[1]/txt[1]/infos/bounds", "top").toInt32();
1074 SwTwips nFirstParaHeight
1075 = getXPath(pXmlDoc, "/root/page/body/tab/row/cell[1]/txt[1]/infos/bounds", "height")
1076 .toInt32();
1077 SwTwips nFirstParaMiddle = nFirstParaTop + nFirstParaHeight / 2;
1078 SwTwips nFirstParaBottom = nFirstParaTop + nFirstParaHeight;
1079 // Without the accompanying fix in place, this test would have failed: the lower half (vertical)
1080 // range was 2273 -> 2835, the good vertical position is 2730, the bad one was 1830.
1081 CPPUNIT_ASSERT_GREATER(nFirstParaMiddle, rCharRect.Top());
1082 CPPUNIT_ASSERT_LESS(nFirstParaBottom, rCharRect.Top());
1084 // Save initial cursor position.
1085 SwPosition aCellStart = *pWrtShell->GetCursor()->Start();
1087 // Test that pressing "up" at the start of the cell goes to the next character position.
1088 SwNodeOffset nNodeIndex = pWrtShell->GetCursor()->Start()->GetNodeIndex();
1089 sal_Int32 nIndex = pWrtShell->GetCursor()->Start()->GetContentIndex();
1090 KeyEvent aKeyEvent(0, KEY_UP);
1091 SwEditWin& rEditWin = pShell->GetView()->GetEditWin();
1092 rEditWin.KeyInput(aKeyEvent);
1093 Scheduler::ProcessEventsToIdle();
1094 // Without the accompanying fix in place, this test would have failed: "up" was interpreted as
1095 // logical "left", which does nothing if you're at the start of the text anyway.
1096 CPPUNIT_ASSERT_EQUAL(nIndex + 1, pWrtShell->GetCursor()->Start()->GetContentIndex());
1098 // Test that pressing "right" goes to the next paragraph (logical "down").
1099 sal_Int32 nContentIndex = pWrtShell->GetCursor()->Start()->GetContentIndex();
1100 aKeyEvent = KeyEvent(0, KEY_RIGHT);
1101 rEditWin.KeyInput(aKeyEvent);
1102 Scheduler::ProcessEventsToIdle();
1103 // Without the accompanying fix in place, this test would have failed: the cursor went to the
1104 // paragraph after the table.
1105 CPPUNIT_ASSERT_EQUAL(nNodeIndex + 1, pWrtShell->GetCursor()->Start()->GetNodeIndex());
1107 // Test that we have the correct character index after traveling to the next paragraph.
1108 // Without the accompanying fix in place, this test would have failed: char position was 5, i.e.
1109 // the cursor jumped to the end of the paragraph for no reason.
1110 CPPUNIT_ASSERT_EQUAL(nContentIndex, pWrtShell->GetCursor()->Start()->GetContentIndex());
1112 // Test that clicking "below" the second paragraph positions the cursor at the start of the
1113 // second paragraph.
1114 SwDoc* pDoc = getSwDoc();
1115 SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
1116 SwPosition aPosition(aCellStart);
1117 SwTwips nSecondParaLeft
1118 = getXPath(pXmlDoc, "/root/page/body/tab/row/cell[1]/txt[2]/infos/bounds", "left")
1119 .toInt32();
1120 SwTwips nSecondParaWidth
1121 = getXPath(pXmlDoc, "/root/page/body/tab/row/cell[1]/txt[2]/infos/bounds", "width")
1122 .toInt32();
1123 SwTwips nSecondParaTop
1124 = getXPath(pXmlDoc, "/root/page/body/tab/row/cell[1]/txt[2]/infos/bounds", "top").toInt32();
1125 SwTwips nSecondParaHeight
1126 = getXPath(pXmlDoc, "/root/page/body/tab/row/cell[1]/txt[2]/infos/bounds", "height")
1127 .toInt32();
1128 Point aPoint;
1129 aPoint.setX(nSecondParaLeft + nSecondParaWidth / 2);
1130 aPoint.setY(nSecondParaTop + nSecondParaHeight - 100);
1131 SwCursorMoveState aState(CursorMoveState::NONE);
1132 pLayout->GetModelPositionForViewPoint(&aPosition, aPoint, &aState);
1133 CPPUNIT_ASSERT_EQUAL(aCellStart.GetNodeIndex() + 1, aPosition.GetNodeIndex());
1134 // Without the accompanying fix in place, this test would have failed: character position was 5,
1135 // i.e. cursor was at the end of the paragraph.
1136 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0), aPosition.GetContentIndex());
1138 // Test that the selection rectangles are inside the cell frame if we select all the cell
1139 // content.
1140 SwTwips nCellLeft
1141 = getXPath(pXmlDoc, "/root/page/body/tab/row/cell[1]/infos/bounds", "left").toInt32();
1142 SwTwips nCellWidth
1143 = getXPath(pXmlDoc, "/root/page/body/tab/row/cell[1]/infos/bounds", "width").toInt32();
1144 SwTwips nCellTop
1145 = getXPath(pXmlDoc, "/root/page/body/tab/row/cell[1]/infos/bounds", "top").toInt32();
1146 SwTwips nCellHeight
1147 = getXPath(pXmlDoc, "/root/page/body/tab/row/cell[1]/infos/bounds", "height").toInt32();
1148 SwRect aCellRect(Point(nCellLeft, nCellTop), Size(nCellWidth, nCellHeight));
1149 pWrtShell->SelAll();
1150 SwShellCursor* pShellCursor = pWrtShell->getShellCursor(/*bBlock=*/false);
1151 CPPUNIT_ASSERT(!pShellCursor->empty());
1152 // Without the accompanying fix in place, this test would have failed with:
1153 // selection rectangle 269x2573@(1970,2172) is not inside cell rectangle 3207x1134@(1593,1701)
1154 // i.e. the selection went past the bottom border of the cell frame.
1155 for (const auto& rRect : *pShellCursor)
1157 std::stringstream ss;
1158 ss << "selection rectangle " << rRect << " is not inside cell rectangle " << aCellRect;
1159 CPPUNIT_ASSERT_MESSAGE(ss.str(), aCellRect.Contains(rRect));
1162 // Make sure that the correct rectangle gets repainted on scroll.
1163 SwFrame* pPageFrame = pLayout->GetLower();
1164 CPPUNIT_ASSERT(pPageFrame->IsPageFrame());
1166 SwFrame* pBodyFrame = pPageFrame->GetLower();
1167 CPPUNIT_ASSERT(pBodyFrame->IsBodyFrame());
1169 SwFrame* pTabFrame = pBodyFrame->GetLower();
1170 CPPUNIT_ASSERT(pTabFrame->IsTabFrame());
1172 SwFrame* pRowFrame = pTabFrame->GetLower();
1173 CPPUNIT_ASSERT(pRowFrame->IsRowFrame());
1175 SwFrame* pCellFrame = pRowFrame->GetLower();
1176 CPPUNIT_ASSERT(pCellFrame->IsCellFrame());
1178 SwFrame* pFrame = pCellFrame->GetLower();
1179 CPPUNIT_ASSERT(pFrame->IsTextFrame());
1181 SwTextFrame* pTextFrame = static_cast<SwTextFrame*>(pFrame);
1182 pTextFrame->SwapWidthAndHeight();
1183 // Mimic what normally SwTextFrame::PaintSwFrame() does:
1184 SwRect aRect(4207, 2273, 269, 572);
1185 pTextFrame->SwitchVerticalToHorizontal(aRect);
1186 // Without the accompanying fix in place, this test would have failed with:
1187 // Expected: 572x269@(1691,4217)
1188 // Actual : 572x269@(2263,4217)
1189 // i.e. the paint rectangle position was incorrect, text was not painted on scrolling up.
1190 CPPUNIT_ASSERT_EQUAL(SwRect(1691, 4217, 572, 269), aRect);
1191 #endif
1194 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf123898)
1196 createSwDoc("tdf123898.odt");
1198 // Make sure spellchecker has done its job already
1199 Scheduler::ProcessEventsToIdle();
1201 uno::Reference<linguistic2::XHyphenator> xHyphenator = LinguMgr::GetHyphenator();
1202 if (!xHyphenator->hasLocale(lang::Locale("de", "DE", OUString())))
1203 return;
1205 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1206 // Make sure that the arrow on the left is not there (the first portion's type is
1207 // PortionType::Arrow if it's there)
1208 assertXPath(pXmlDoc,
1209 "/root/page/body/txt/anchored/fly/txt/SwParaPortion/SwLineLayout[1]/child::*[1]",
1210 "type", u"PortionType::Text");
1213 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf123651)
1215 createSwDoc("tdf123651.docx");
1216 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1217 // Without the accompanying fix in place, this test would have failed with 'Expected: 7639;
1218 // Actual: 12926'. The shape was below the second "Lorem ipsum" text, not above it.
1219 const sal_Int32 nTopValue
1220 = getXPath(pXmlDoc, "//anchored/SwAnchoredDrawObject/bounds", "top").toInt32();
1221 CPPUNIT_ASSERT_DOUBLES_EQUAL(7639, nTopValue, 10);
1224 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf116501)
1226 //just care it doesn't freeze
1227 createSwDoc("tdf116501.odt");
1230 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf123163)
1232 //just care it doesn't assert
1233 createSwDoc("tdf123163-1.docx");
1236 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testAbi11870)
1238 //just care it doesn't assert
1239 createSwDoc("abi11870-2.odt");
1242 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testOfz64109)
1244 //just care it doesn't assert
1245 createSwDoc("ofz64109-1.fodt");
1248 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf118719)
1250 // Insert a page break.
1251 createSwDoc();
1252 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
1254 // Enable hide whitespace mode.
1255 SwViewOption aViewOptions(*pWrtShell->GetViewOptions());
1256 aViewOptions.SetHideWhitespaceMode(true);
1257 pWrtShell->ApplyViewOptions(aViewOptions);
1259 pWrtShell->Insert(u"first"_ustr);
1260 pWrtShell->InsertPageBreak();
1261 pWrtShell->Insert(u"second"_ustr);
1263 // Without the accompanying fix in place, this test would have failed, as the height of the
1264 // first page was 15840 twips, instead of the much smaller 276.
1265 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1266 sal_Int32 nOther = getXPath(pXmlDoc, "/root/page[1]/infos/bounds", "height").toInt32();
1267 sal_Int32 nLast = getXPath(pXmlDoc, "/root/page[2]/infos/bounds", "height").toInt32();
1268 CPPUNIT_ASSERT_GREATER(nOther, nLast);
1271 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTabOverMargin)
1273 createSwDoc("tab-over-margin.odt");
1274 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1276 // 2nd paragraph has a tab over the right margin, and with the TabOverMargin compat option,
1277 // there is enough space to have all content in a single line.
1278 // Without the accompanying fix in place, this test would have failed, there were 2 lines.
1279 assertXPath(pXmlDoc, "/root/page/body/txt[2]/SwParaPortion/SwLineLayout", 1);
1282 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testImageComment)
1284 // Load a document that has "aaa" in it, then a commented image (4th char is the as-char image,
1285 // 5th char is the comment anchor).
1286 createSwDoc("image-comment.odt");
1287 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
1289 // Look up a layout position which is on the right of the image.
1290 SwRootFrame* pRoot = pWrtShell->GetLayout();
1291 CPPUNIT_ASSERT(pRoot->GetLower()->IsPageFrame());
1292 SwPageFrame* pPage = static_cast<SwPageFrame*>(pRoot->GetLower());
1293 CPPUNIT_ASSERT(pPage->GetLower()->IsBodyFrame());
1294 SwBodyFrame* pBody = static_cast<SwBodyFrame*>(pPage->GetLower());
1295 CPPUNIT_ASSERT(pBody->GetLower()->IsTextFrame());
1296 SwTextFrame* pTextFrame = static_cast<SwTextFrame*>(pBody->GetLower());
1297 CPPUNIT_ASSERT(pTextFrame->GetDrawObjs());
1298 SwSortedObjs& rDrawObjs = *pTextFrame->GetDrawObjs();
1299 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rDrawObjs.size());
1300 SwAnchoredObject* pDrawObj = rDrawObjs[0];
1301 const SwRect aDrawObjRect = pDrawObj->GetObjRect();
1302 Point aPoint = aDrawObjRect.Center();
1303 aPoint.setX(aPoint.getX() + aDrawObjRect.Width() / 2);
1305 // Ask for the doc model pos of this layout point.
1306 SwPosition aPosition(*pTextFrame->GetTextNodeForFirstText());
1307 pTextFrame->GetModelPositionForViewPoint(&aPosition, aPoint);
1309 // Without the accompanying fix in place, this test would have failed with:
1310 // - Expected: 5
1311 // - Actual : 4
1312 // i.e. the cursor got positioned between the image and its comment, so typing extended the
1313 // comment, instead of adding content after the commented image.
1314 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(5), aPosition.GetContentIndex());
1317 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testScriptField)
1319 // Test clicking script field inside table ( tdf#141079 )
1320 createSwDoc("tdf141079.odt");
1321 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
1323 // Look up layout position which is the first cell in the table
1324 SwRootFrame* pRoot = pWrtShell->GetLayout();
1325 CPPUNIT_ASSERT(pRoot->GetLower()->IsPageFrame());
1326 SwPageFrame* pPage = static_cast<SwPageFrame*>(pRoot->GetLower());
1327 CPPUNIT_ASSERT(pPage->GetLower()->IsBodyFrame());
1328 SwBodyFrame* pBody = static_cast<SwBodyFrame*>(pPage->GetLower());
1329 CPPUNIT_ASSERT(pBody->GetLower()->IsTextFrame());
1330 SwTextFrame* pTextFrame = static_cast<SwTextFrame*>(pBody->GetLower());
1331 CPPUNIT_ASSERT(pTextFrame->GetNext()->IsTabFrame());
1332 SwFrame* pTable = pTextFrame->GetNext();
1333 SwFrame* pRow1 = pTable->GetLower();
1334 CPPUNIT_ASSERT(pRow1->GetLower()->IsCellFrame());
1335 SwFrame* pCell1 = pRow1->GetLower();
1336 CPPUNIT_ASSERT(pCell1->GetLower()->IsTextFrame());
1337 SwTextFrame* pCellTextFrame = static_cast<SwTextFrame*>(pCell1->GetLower());
1338 const SwRect& rCellRect = pCell1->getFrameArea();
1339 Point aPoint = rCellRect.Center();
1340 aPoint.setX(aPoint.getX() - rCellRect.Width() / 2);
1342 // Ask for the doc model pos of this layout point.
1343 SwPosition aPosition(*pCellTextFrame->GetTextNodeForFirstText());
1344 pCellTextFrame->GetModelPositionForViewPoint(&aPosition, aPoint);
1346 // Position was 1 without the fix from tdf#141079
1347 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0), aPosition.GetContentIndex());
1350 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testCommentCursorPosition)
1352 // Load a document that has "aaa" in it, followed by three comments.
1353 createSwDoc("endOfLineComments.odt");
1354 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
1356 SwRootFrame* pRoot = pWrtShell->GetLayout();
1357 CPPUNIT_ASSERT(pRoot->GetLower()->IsPageFrame());
1358 SwPageFrame* pPage = static_cast<SwPageFrame*>(pRoot->GetLower());
1359 CPPUNIT_ASSERT(pPage->GetLower()->IsBodyFrame());
1360 SwBodyFrame* pBody = static_cast<SwBodyFrame*>(pPage->GetLower());
1361 CPPUNIT_ASSERT(pBody->GetLower()->IsTextFrame());
1362 SwTextFrame* pTextFrame = static_cast<SwTextFrame*>(pBody->GetLower());
1364 // Set a point in the whitespace past the end of the first line.
1365 Point aPoint = pWrtShell->getShellCursor(false)->GetSttPos();
1366 aPoint.setX(aPoint.getX() + 10000);
1368 // Ask for the doc model pos of this layout point.
1369 SwPosition aPosition(*pTextFrame->GetTextNodeForFirstText());
1370 pTextFrame->GetModelPositionForViewPoint(&aPosition, aPoint);
1372 // Without the accompanying fix in place, this test would have failed with:
1373 // - Expected: 6
1374 // - Actual : 3 or 4
1375 // i.e. the cursor got positioned before the comments,
1376 // so typing extended the first comment instead of adding content after the comments.
1377 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(6), aPosition.GetContentIndex());
1378 // The second line is also important, but can't be auto-tested
1379 // since the failing situation depends on GetViewWidth which is zero in the headless tests.
1380 // bb<comment>| - the cursor should move behind the |, not before it.
1383 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testCombiningCharacterCursorPosition)
1385 // Load a document that has "a" in it, followed by a combining acute in a separate rext span
1386 createSwDoc("tdf138592-a-acute.fodt");
1387 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
1389 SwRootFrame* pRoot = pWrtShell->GetLayout();
1390 CPPUNIT_ASSERT(pRoot->GetLower()->IsPageFrame());
1391 SwPageFrame* pPage = static_cast<SwPageFrame*>(pRoot->GetLower());
1392 CPPUNIT_ASSERT(pPage->GetLower()->IsBodyFrame());
1393 SwBodyFrame* pBody = static_cast<SwBodyFrame*>(pPage->GetLower());
1394 CPPUNIT_ASSERT(pBody->GetLower()->IsTextFrame());
1395 SwTextFrame* pTextFrame = static_cast<SwTextFrame*>(pBody->GetLower());
1397 // Set a point in the whitespace past the end of the first line.
1398 Point aPoint = pWrtShell->getShellCursor(false)->GetSttPos();
1399 aPoint.AdjustX(10000);
1401 // Ask for the doc model pos of this layout point.
1402 SwPosition aPosition(*pTextFrame->GetTextNodeForFirstText());
1403 pTextFrame->GetModelPositionForViewPoint(&aPosition, aPoint);
1405 // Without the accompanying fix in place, this test would have failed with:
1406 // - Expected: 2
1407 // - Actual : 1
1408 // i.e. the cursor got positioned before the acute, so typing shifted the acute (applying it
1409 // to newly typed characters) instead of adding content after it.
1410 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), aPosition.GetContentIndex());
1413 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf64222)
1415 createSwDoc("tdf64222.docx");
1416 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1417 assertXPath(pXmlDoc,
1418 "/root/page/body/txt[2]/SwParaPortion/SwLineLayout/"
1419 "child::*[@type='PortionType::Number']/SwFont",
1420 "height", u"560");
1423 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf113014)
1425 createSwDoc("tdf113014.fodt");
1426 SwDocShell* pShell = getSwDocShell();
1428 // Dump the rendering of the first page as an XML file.
1429 std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
1430 MetafileXmlDump dumper;
1431 xmlDocUniquePtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
1432 CPPUNIT_ASSERT(pXmlDoc);
1434 // This failed, if numbering of cell A1 is missing
1435 // (A1: left indent: 3 cm, first line indent: -3 cm
1436 // A2: left indent: 0 cm, first line indent: 0 cm)
1437 assertXPathContent(pXmlDoc, "/metafile/push[1]/push[1]/push[1]/textarray[1]/text", u"1.");
1438 assertXPathContent(pXmlDoc, "/metafile/push[1]/push[1]/push[1]/textarray[3]/text", u"2.");
1439 assertXPathContent(pXmlDoc, "/metafile/push[1]/push[1]/push[1]/textarray[5]/text", u"3.");
1442 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf130218)
1444 createSwDoc("tdf130218.fodt");
1445 SwDocShell* pShell = getSwDocShell();
1447 // Dump the rendering of the first page as an XML file.
1448 std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
1449 MetafileXmlDump dumper;
1451 xmlDocUniquePtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
1452 CPPUNIT_ASSERT(pXmlDoc);
1454 // This failed, if hanging first line was hidden
1455 assertXPathContent(pXmlDoc, "/metafile/push[1]/push[1]/push[1]/textarray[1]/text", u"Text");
1458 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf127235)
1460 createSwDoc("tdf127235.odt");
1461 // This resulted in a layout loop.
1462 calcLayout();
1465 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf138039)
1467 createSwDoc("tdf138039.odt");
1469 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1471 // there are 3 pages
1472 assertXPath(pXmlDoc, "/root/page", 3);
1473 // table on first page
1474 assertXPath(pXmlDoc, "/root/page[1]/body/tab", 1);
1475 assertXPath(pXmlDoc, "/root/page[1]/body/txt", 0);
1476 // paragraph with large fly on second page
1477 assertXPath(pXmlDoc, "/root/page[2]/body/tab", 0);
1478 assertXPath(pXmlDoc, "/root/page[2]/body/txt", 1);
1479 assertXPath(pXmlDoc, "/root/page[2]/body/txt[1]/anchored/fly", 1);
1480 assertXPath(pXmlDoc, "/root/page[2]/body/txt[1]/anchored/fly[1]/infos/bounds", "top", u"17915");
1481 assertXPath(pXmlDoc, "/root/page[2]/body/txt[1]/anchored/fly[1]/infos/bounds", "height",
1482 u"15819");
1483 // paragraph on third page
1484 assertXPath(pXmlDoc, "/root/page[3]/body/tab", 0);
1485 assertXPath(pXmlDoc, "/root/page[3]/body/txt", 1);
1486 assertXPath(pXmlDoc, "/root/page[3]/body/txt[1]/anchored", 0);
1489 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf134298)
1491 createSwDoc("tdf134298.ott");
1493 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1495 // there are 2 pages
1496 assertXPath(pXmlDoc, "/root/page", 2);
1497 // table and first para on first page
1498 assertXPath(pXmlDoc, "/root/page[1]/body/tab", 1);
1499 assertXPath(pXmlDoc, "/root/page[1]/body/txt", 1);
1500 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored", 0);
1501 // paragraph with large fly on second page
1502 assertXPath(pXmlDoc, "/root/page[2]/body/tab", 0);
1503 assertXPath(pXmlDoc, "/root/page[2]/body/txt", 1);
1504 assertXPath(pXmlDoc, "/root/page[2]/body/txt[1]/anchored/fly", 1);
1505 assertXPath(pXmlDoc, "/root/page[2]/body/txt[1]/anchored/fly[1]/infos/bounds", "top", u"17897");
1506 assertXPath(pXmlDoc, "/root/page[2]/body/txt[1]/anchored/fly[1]/infos/bounds", "height",
1507 u"15819");
1510 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testShapeAllowOverlap)
1512 // Need to find out why this fails on macOS and why this is unstable on Windows.
1513 #if !defined(MACOSX) && !defined(_WIN32)
1514 // Create an empty document with two, intentionally overlapping shapes.
1515 // Set their AllowOverlap property to false.
1516 createSwDoc();
1517 uno::Reference<lang::XMultiServiceFactory> xDocument(mxComponent, uno::UNO_QUERY);
1518 awt::Point aPoint(1000, 1000);
1519 awt::Size aSize(2000, 2000);
1520 uno::Reference<drawing::XShape> xShape(
1521 xDocument->createInstance(u"com.sun.star.drawing.RectangleShape"_ustr), uno::UNO_QUERY);
1522 xShape->setPosition(aPoint);
1523 xShape->setSize(aSize);
1524 uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(xDocument, uno::UNO_QUERY);
1525 uno::Reference<beans::XPropertySet> xShapeProperties(xShape, uno::UNO_QUERY);
1526 xShapeProperties->setPropertyValue(u"AllowOverlap"_ustr, uno::Any(false));
1527 xShapeProperties->setPropertyValue(u"AnchorType"_ustr,
1528 uno::Any(text::TextContentAnchorType_AT_CHARACTER));
1529 xDrawPageSupplier->getDrawPage()->add(xShape);
1531 aPoint = awt::Point(2000, 2000);
1532 xShape.set(xDocument->createInstance(u"com.sun.star.drawing.RectangleShape"_ustr),
1533 uno::UNO_QUERY);
1534 xShape->setPosition(aPoint);
1535 xShape->setSize(aSize);
1536 xShapeProperties.set(xShape, uno::UNO_QUERY);
1537 xShapeProperties->setPropertyValue(u"AllowOverlap"_ustr, uno::Any(false));
1538 xShapeProperties->setPropertyValue(u"AnchorType"_ustr,
1539 uno::Any(text::TextContentAnchorType_AT_CHARACTER));
1540 xDrawPageSupplier->getDrawPage()->add(xShape);
1542 // Now verify that the rectangle of the anchored objects don't overlap.
1543 SwDoc* pDoc = getSwDoc();
1544 SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
1545 SwFrame* pPageFrame = pLayout->GetLower();
1546 SwFrame* pBodyFrame = pPageFrame->GetLower();
1547 SwFrame* pTextFrame = pBodyFrame->GetLower();
1548 CPPUNIT_ASSERT(pTextFrame->GetDrawObjs());
1549 SwSortedObjs& rObjs = *pTextFrame->GetDrawObjs();
1550 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), rObjs.size());
1551 SwAnchoredObject* pFirst = rObjs[0];
1552 SwAnchoredObject* pSecond = rObjs[1];
1553 // Without the accompanying fix in place, this test would have failed: the layout dump was
1554 // <bounds left="1984" top="1984" width="1137" height="1137"/>
1555 // <bounds left="2551" top="2551" width="1137" height="1137"/>
1556 // so there was a clear vertical overlap. (Allow for 1px tolerance.)
1557 OString aMessage = "Unexpected overlap: first shape's bottom is "
1558 + OString::number(pFirst->GetObjRect().Bottom()) + ", second shape's top is "
1559 + OString::number(pSecond->GetObjRect().Top());
1560 CPPUNIT_ASSERT_MESSAGE(aMessage.getStr(),
1561 std::abs(pFirst->GetObjRect().Bottom() - pSecond->GetObjRect().Top())
1562 < 15);
1563 #endif
1566 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testShapeAllowOverlapWrap)
1568 // Create an empty document with two, intentionally overlapping shapes.
1569 // Set their AllowOverlap property to false and their wrap to through.
1570 createSwDoc();
1571 uno::Reference<lang::XMultiServiceFactory> xDocument(mxComponent, uno::UNO_QUERY);
1572 awt::Point aPoint(1000, 1000);
1573 awt::Size aSize(2000, 2000);
1574 uno::Reference<drawing::XShape> xShape(
1575 xDocument->createInstance(u"com.sun.star.drawing.RectangleShape"_ustr), uno::UNO_QUERY);
1576 xShape->setPosition(aPoint);
1577 xShape->setSize(aSize);
1578 uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(xDocument, uno::UNO_QUERY);
1579 uno::Reference<beans::XPropertySet> xShapeProperties(xShape, uno::UNO_QUERY);
1580 xShapeProperties->setPropertyValue(u"AllowOverlap"_ustr, uno::Any(false));
1581 xShapeProperties->setPropertyValue(u"AnchorType"_ustr,
1582 uno::Any(text::TextContentAnchorType_AT_CHARACTER));
1583 xShapeProperties->setPropertyValue(u"Surround"_ustr, uno::Any(text::WrapTextMode_THROUGH));
1584 xDrawPageSupplier->getDrawPage()->add(xShape);
1586 aPoint = awt::Point(2000, 2000);
1587 xShape.set(xDocument->createInstance(u"com.sun.star.drawing.RectangleShape"_ustr),
1588 uno::UNO_QUERY);
1589 xShape->setPosition(aPoint);
1590 xShape->setSize(aSize);
1591 xShapeProperties.set(xShape, uno::UNO_QUERY);
1592 xShapeProperties->setPropertyValue(u"AllowOverlap"_ustr, uno::Any(false));
1593 xShapeProperties->setPropertyValue(u"AnchorType"_ustr,
1594 uno::Any(text::TextContentAnchorType_AT_CHARACTER));
1595 xShapeProperties->setPropertyValue(u"Surround"_ustr, uno::Any(text::WrapTextMode_THROUGH));
1596 xDrawPageSupplier->getDrawPage()->add(xShape);
1598 // Now verify that the rectangle of the anchored objects do overlap.
1599 SwDoc* pDoc = getSwDoc();
1600 SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
1601 SwFrame* pPageFrame = pLayout->GetLower();
1602 SwFrame* pBodyFrame = pPageFrame->GetLower();
1603 SwFrame* pTextFrame = pBodyFrame->GetLower();
1604 CPPUNIT_ASSERT(pTextFrame->GetDrawObjs());
1605 SwSortedObjs& rObjs = *pTextFrame->GetDrawObjs();
1606 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), rObjs.size());
1607 SwAnchoredObject* pFirst = rObjs[0];
1608 SwAnchoredObject* pSecond = rObjs[1];
1609 // Without the accompanying fix in place, this test would have failed: AllowOverlap=no had
1610 // priority over Surround=through (which is bad for Word compat).
1611 CPPUNIT_ASSERT(pSecond->GetObjRect().Overlaps(pFirst->GetObjRect()));
1614 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf124600)
1616 createSwDoc("tdf124600.docx");
1617 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1619 // Without the accompanying fix in place, this test would have failed with:
1620 // - Expected: 1
1621 // - Actual : 2
1622 // i.e. the last line in the body text had 2 lines, while it should have 1, as Word does (as the
1623 // fly frame does not intersect with the print area of the paragraph.)
1624 assertXPath(pXmlDoc, "/root/page/body/txt[2]/SwParaPortion/SwLineLayout", 1);
1627 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf124601)
1629 // This is a testcase for the ContinuousEndnotes compat flag.
1630 // The document has 2 pages, the endnote anchor is on the first page.
1631 // The endnote should be on the 2nd page together with the last page content.
1632 createSwDoc("tdf124601.doc");
1633 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1635 // Without the accompanying fix in place, this test would have failed with:
1636 // - Expected: 2
1637 // - Actual : 3
1638 // i.e. there was a separate endnote page, even when the ContinuousEndnotes compat option was
1639 // on.
1640 assertXPath(pXmlDoc, "/root/page", 2);
1641 assertXPath(pXmlDoc, "/root/page[2]//ftncont", 1);
1644 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf124601b)
1646 // Table has an image, which is anchored in the first row, but its vertical position is large
1647 // enough to be rendered in the second row.
1648 // The shape has layoutInCell=1, so should match what Word does here.
1649 // Also the horizontal position should be in the last column, even if the anchor is in the
1650 // last-but-one column.
1651 createSwDoc("tdf124601b.doc");
1652 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1654 sal_Int32 nFlyTop = getXPath(pXmlDoc, "//anchored/fly/infos/bounds", "top").toInt32();
1655 sal_Int32 nFlyLeft = getXPath(pXmlDoc, "//anchored/fly/infos/bounds", "left").toInt32();
1656 sal_Int32 nFlyRight
1657 = nFlyLeft + getXPath(pXmlDoc, "//anchored/fly/infos/bounds", "width").toInt32();
1658 sal_Int32 nSecondRowTop = getXPath(pXmlDoc, "//tab/row[2]/infos/bounds", "top").toInt32();
1659 sal_Int32 nLastCellLeft
1660 = getXPath(pXmlDoc, "//tab/row[1]/cell[5]/infos/bounds", "left").toInt32();
1661 sal_Int32 nLastCellRight
1662 = nLastCellLeft + getXPath(pXmlDoc, "//tab/row[1]/cell[5]/infos/bounds", "width").toInt32();
1663 // Without the accompanying fix in place, this test would have failed with:
1664 // - Expected greater than: 3736
1665 // - Actual : 2852
1666 // i.e. the image was still inside the first row.
1667 CPPUNIT_ASSERT_GREATER(nSecondRowTop, nFlyTop);
1669 // Without the accompanying fix in place, this test would have failed with:
1670 // - Expected greater than: 9640
1671 // - Actual : 9639
1672 // i.e. the right edge of the image was not within the bounds of the last column, the right edge
1673 // was in the last-but-one column.
1674 CPPUNIT_ASSERT_GREATER(nLastCellLeft, nFlyRight);
1675 CPPUNIT_ASSERT_LESS(nLastCellRight, nFlyRight);
1678 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf124770)
1680 // Enable content over margin.
1681 createSwDoc();
1682 SwDoc* pDoc = getSwDoc();
1683 pDoc->getIDocumentSettingAccess().set(DocumentSettingId::TAB_OVER_MARGIN, true);
1685 // Set page width.
1686 SwPageDesc& rPageDesc = pDoc->GetPageDesc(0);
1687 SwFrameFormat& rPageFormat = rPageDesc.GetMaster();
1688 const SwAttrSet& rPageSet = rPageFormat.GetAttrSet();
1689 SwFormatFrameSize aPageSize = rPageSet.GetFrameSize();
1690 aPageSize.SetWidth(3703);
1691 rPageFormat.SetFormatAttr(aPageSize);
1693 // Set left and right margin.
1694 SvxLRSpaceItem aLRSpace = rPageSet.GetLRSpace();
1695 aLRSpace.SetLeft(SvxIndentValue::twips(1418));
1696 aLRSpace.SetRight(SvxIndentValue::twips(1418));
1697 rPageFormat.SetFormatAttr(aLRSpace);
1698 pDoc->ChgPageDesc(0, rPageDesc);
1700 // Set font to italic 20pt Liberation Serif.
1701 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
1702 SfxItemSet aTextSet(pWrtShell->GetView().GetPool(),
1703 svl::Items<RES_CHRATR_BEGIN, RES_CHRATR_END - 1>);
1704 SvxFontItem aFont(RES_CHRATR_FONT);
1705 aFont.SetFamilyName(u"Liberation Serif"_ustr);
1706 aTextSet.Put(aFont);
1707 SvxFontHeightItem aHeight(400, 100, RES_CHRATR_FONTSIZE);
1708 aTextSet.Put(aHeight);
1709 SvxPostureItem aItalic(ITALIC_NORMAL, RES_CHRATR_POSTURE);
1710 aTextSet.Put(aItalic);
1711 pWrtShell->SetAttrSet(aTextSet);
1713 // Insert the text.
1714 pWrtShell->Insert2(u"HHH"_ustr);
1716 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1717 // Without the accompanying fix in place, this test would have failed with:
1718 // - Expected: 1
1719 // - Actual : 2
1720 // i.e. the italic string was broken into 2 lines, while Word kept it in a single line.
1721 assertXPath(pXmlDoc, "/root/page/body/txt[1]/SwParaPortion/SwLineLayout", 1);
1724 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testContinuousEndnotesInsertPageAtStart)
1726 // Create a new document with CONTINUOUS_ENDNOTES enabled.
1727 createSwDoc();
1728 SwDoc* pDoc = getSwDoc();
1729 pDoc->getIDocumentSettingAccess().set(DocumentSettingId::CONTINUOUS_ENDNOTES, true);
1731 // Insert a second page, and an endnote on the 2nd page (both the anchor and the endnote is on
1732 // the 2nd page).
1733 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
1734 pWrtShell->InsertPageBreak();
1735 pWrtShell->InsertFootnote(u"endnote"_ustr, /*bEndNote=*/true, /*bEdit=*/false);
1737 // Add a new page at the start of the document.
1738 pWrtShell->SttEndDoc(/*bStart=*/true);
1739 pWrtShell->InsertPageBreak();
1741 // Make sure that the endnote is moved from the 2nd page to the 3rd one.
1742 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1743 assertXPath(pXmlDoc, "/root/page", 3);
1744 // Without the accompanying fix in place, this test would have failed with:
1745 // - Expected: 1
1746 // - Actual : 0
1747 // i.e. the footnote container remained on page 2.
1748 assertXPath(pXmlDoc, "/root/page[3]//ftncont", 1);
1751 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testContinuousEndnotesDeletePageAtStart)
1753 // Create a new document with CONTINUOUS_ENDNOTES enabled.
1754 createSwDoc();
1755 SwDoc* pDoc = getSwDoc();
1756 pDoc->getIDocumentSettingAccess().set(DocumentSettingId::CONTINUOUS_ENDNOTES, true);
1758 // Insert a second page, and an endnote on the 2nd page (both the anchor and the endnote is on
1759 // the 2nd page).
1760 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
1761 pWrtShell->InsertPageBreak();
1762 pWrtShell->InsertFootnote(u"endnote"_ustr, /*bEndNote=*/true, /*bEdit=*/false);
1764 // Remove the empty page at the start of the document.
1765 pWrtShell->SttEndDoc(/*bStart=*/true);
1766 pWrtShell->DelRight();
1768 // Make sure that the endnote is moved from the 2nd page to the 1st one.
1769 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1770 // Without the accompanying fix in place, this test would have failed with:
1771 // - Expected: 1
1772 // - Actual : 2
1773 // i.e. the endnote remained on an (otherwise) empty 2nd page.
1774 assertXPath(pXmlDoc, "/root/page", 1);
1775 assertXPath(pXmlDoc, "/root/page[1]//ftncont", 1);
1778 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf128399)
1780 createSwDoc("tdf128399.docx");
1781 SwDoc* pDoc = getSwDoc();
1782 SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
1783 SwFrame* pPage = pLayout->GetLower();
1784 SwFrame* pBody = pPage->GetLower();
1785 SwFrame* pTable = pBody->GetLower();
1786 SwFrame* pRow1 = pTable->GetLower();
1787 SwFrame* pRow2 = pRow1->GetNext();
1788 const SwRect& rRow2Rect = pRow2->getFrameArea();
1789 Point aPoint = rRow2Rect.Center();
1791 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
1792 SwPosition aPosition = *pWrtShell->GetCursor()->Start();
1793 SwPosition aFirstRow(aPosition);
1794 SwCursorMoveState aState(CursorMoveState::NONE);
1795 pLayout->GetModelPositionForViewPoint(&aPosition, aPoint, &aState);
1796 // Second row is +3: end node, start node and the first text node in the 2nd row.
1797 SwNodeOffset nExpected = aFirstRow.GetNodeIndex() + 3;
1799 // Without the accompanying fix in place, this test would have failed with:
1800 // - Expected: 14
1801 // - Actual : 11
1802 // i.e. clicking on the center of the 2nd row placed the cursor in the 1st row.
1803 CPPUNIT_ASSERT_EQUAL(nExpected, aPosition.GetNodeIndex());
1806 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf156724)
1808 // note: must set Hidden property, so that SfxFrameViewWindow_Impl::Resize()
1809 // does *not* forward initial VCL Window Resize and thereby triggers a
1810 // layout which does not happen on soffice --convert-to pdf.
1811 std::vector<beans::PropertyValue> aFilterOptions = {
1812 { beans::PropertyValue(u"Hidden"_ustr, -1, uno::Any(true),
1813 beans::PropertyState_DIRECT_VALUE) },
1816 // inline the loading because currently properties can't be passed...
1817 OUString const url(createFileURL(u"fdo56797-2-min.odt"));
1818 loadWithParams(url, comphelper::containerToSequence(aFilterOptions));
1819 save(u"writer_pdf_Export"_ustr);
1821 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1822 // both pages have a tab frame and one footnote
1823 assertXPath(pXmlDoc, "/root/page[1]/body/tab", 1);
1824 assertXPath(pXmlDoc, "/root/page[1]/ftncont", 1);
1825 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn", 1);
1826 assertXPath(pXmlDoc, "/root/page[2]/body/tab", 1);
1827 assertXPath(pXmlDoc, "/root/page[2]/ftncont", 1);
1828 assertXPath(pXmlDoc, "/root/page[2]/ftncont/ftn", 1);
1829 assertXPath(pXmlDoc, "/root/page", 2);
1832 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testHiddenParagraphFollowFrame)
1834 createSwDoc("hidden-para-follow-frame.fodt");
1836 uno::Any aOldValue{ queryDispatchStatus(mxComponent, m_xContext, ".uno:ShowHiddenParagraphs") };
1838 Resetter g([this, aOldValue] {
1839 uno::Sequence<beans::PropertyValue> argsSH(
1840 comphelper::InitPropertySequence({ { "ShowHiddenParagraphs", aOldValue } }));
1841 dispatchCommand(mxComponent, ".uno:ShowHiddenParagraphs", argsSH);
1844 uno::Sequence<beans::PropertyValue> argsSH(
1845 comphelper::InitPropertySequence({ { "ShowHiddenParagraphs", uno::Any(true) } }));
1846 dispatchCommand(mxComponent, ".uno:ShowHiddenParagraphs", argsSH);
1847 uno::Sequence<beans::PropertyValue> args(
1848 comphelper::InitPropertySequence({ { "Fieldnames", uno::Any(false) } }));
1849 dispatchCommand(mxComponent, ".uno:Fieldnames", args);
1850 Scheduler::ProcessEventsToIdle();
1853 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1854 assertXPath(pXmlDoc, "/root/page", 2);
1855 assertXPath(pXmlDoc, "/root/page[1]/body/txt", 2);
1856 assertXPath(pXmlDoc, "/root/page[2]/body/txt", 2);
1859 dispatchCommand(mxComponent, ".uno:ShowHiddenParagraphs", {});
1862 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1863 // the problem was that the 3rd paragraph didn't move to page 1
1864 assertXPath(pXmlDoc, "/root/page", 1);
1865 assertXPath(pXmlDoc, "/root/page[1]/body/txt", 3);
1868 dispatchCommand(mxComponent, ".uno:ShowHiddenParagraphs", {});
1871 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1872 assertXPath(pXmlDoc, "/root/page", 2);
1873 assertXPath(pXmlDoc, "/root/page[1]/body/txt", 2);
1874 assertXPath(pXmlDoc, "/root/page[2]/body/txt", 2);
1878 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testHiddenParagraphFlys)
1880 createSwDoc("hidden-para-as-char-fly.fodt");
1882 uno::Any aOldValue{ queryDispatchStatus(mxComponent, m_xContext, ".uno:ShowHiddenParagraphs") };
1884 Resetter g([this, aOldValue] {
1885 uno::Sequence<beans::PropertyValue> argsSH(
1886 comphelper::InitPropertySequence({ { "ShowHiddenParagraphs", aOldValue } }));
1887 dispatchCommand(mxComponent, ".uno:ShowHiddenParagraphs", argsSH);
1890 uno::Sequence<beans::PropertyValue> argsSH(
1891 comphelper::InitPropertySequence({ { "ShowHiddenParagraphs", uno::Any(true) } }));
1892 dispatchCommand(mxComponent, ".uno:ShowHiddenParagraphs", argsSH);
1893 uno::Sequence<beans::PropertyValue> args(
1894 comphelper::InitPropertySequence({ { "Fieldnames", uno::Any(false) } }));
1895 dispatchCommand(mxComponent, ".uno:Fieldnames", args);
1896 Scheduler::ProcessEventsToIdle();
1899 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1900 assertXPath(pXmlDoc, "/root/page/body/txt[3]/anchored/fly/infos/bounds", "height", u"724");
1903 dispatchCommand(mxComponent, ".uno:ShowHiddenParagraphs", {});
1906 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1907 // the problem was that this did not shrink
1908 assertXPath(pXmlDoc, "/root/page/body/txt[3]/anchored/fly/infos/bounds", "height", u"448");
1911 dispatchCommand(mxComponent, ".uno:ShowHiddenParagraphs", {});
1914 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1915 assertXPath(pXmlDoc, "/root/page/body/txt[3]/anchored/fly/infos/bounds", "height", u"724");
1919 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testSectionUnhide)
1921 createSwDoc("hiddensection.fodt");
1924 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1925 assertXPath(pXmlDoc, "/root/page/body/section/txt/infos/bounds[@height='0']", 0);
1928 // Hide the section
1929 auto xTextSectionsSupplier = mxComponent.queryThrow<css::text::XTextSectionsSupplier>();
1930 auto xSections = xTextSectionsSupplier->getTextSections();
1931 CPPUNIT_ASSERT(xSections);
1932 auto xSection = xSections->getByName(u"Section1"_ustr).queryThrow<css::beans::XPropertySet>();
1933 xSection->setPropertyValue(u"IsVisible"_ustr, css::uno::Any(false));
1934 calcLayout();
1937 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1938 assertXPath(pXmlDoc, "/root/page/body/section/txt/infos/bounds[@height='0']", 4);
1941 xSection->setPropertyValue(u"IsVisible"_ustr, css::uno::Any(true));
1942 calcLayout();
1945 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1946 // the problem was that 3 of the text frames had 0 height because Format was skipped
1947 assertXPath(pXmlDoc, "/root/page/body/section/txt/infos/bounds[@height='0']", 0);
1951 CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testHiddenSectionFlys)
1953 createSwDoc("U-min.fodt");
1955 //NO! field update job masks if the visibility was created wrong when loading.
1956 //Scheduler::ProcessEventsToIdle();
1958 SwDoc* pDoc = getSwDoc();
1959 IDocumentDrawModelAccess const& rIDMA{ pDoc->getIDocumentDrawModelAccess() };
1960 SdrPage const* pDrawPage{ rIDMA.GetDrawModel()->GetPage(0) };
1961 int invisibleHeaven{ rIDMA.GetInvisibleHeavenId().get() };
1962 int visibleHeaven{ rIDMA.GetHeavenId().get() };
1964 // these are hidden by moving to invisible layer, they're still in layout
1966 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1967 assertXPath(pXmlDoc, "//anchored/fly", 6);
1969 CPPUNIT_ASSERT_EQUAL(size_t(6), pDrawPage->GetObjCount());
1970 for (int i = 0; i < 6; ++i)
1972 CPPUNIT_ASSERT_EQUAL(invisibleHeaven, int(pDrawPage->GetObj(i)->GetLayer().get()));
1976 // Show the section
1977 auto xTextSectionsSupplier = mxComponent.queryThrow<css::text::XTextSectionsSupplier>();
1978 auto xSections = xTextSectionsSupplier->getTextSections();
1979 CPPUNIT_ASSERT(xSections);
1980 auto xSection = xSections->getByName(u"Anlage"_ustr).queryThrow<css::beans::XPropertySet>();
1981 xSection->setPropertyValue(u"IsVisible"_ustr, css::uno::Any(true));
1982 calcLayout();
1985 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1986 assertXPath(pXmlDoc, "//anchored/fly", 6);
1988 CPPUNIT_ASSERT_EQUAL(size_t(6), pDrawPage->GetObjCount());
1989 for (int i = 0; i < 6; ++i)
1991 CPPUNIT_ASSERT_EQUAL(visibleHeaven, int(pDrawPage->GetObj(i)->GetLayer().get()));
1995 xSection->setPropertyValue(u"IsVisible"_ustr, css::uno::Any(false));
1996 calcLayout();
1999 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
2000 assertXPath(pXmlDoc, "//anchored/fly", 6);
2002 CPPUNIT_ASSERT_EQUAL(size_t(6), pDrawPage->GetObjCount());
2003 for (int i = 0; i < 6; ++i)
2005 CPPUNIT_ASSERT_EQUAL(invisibleHeaven, int(pDrawPage->GetObj(i)->GetLayer().get()));
2010 } // end of anonymous namespace
2012 CPPUNIT_PLUGIN_IMPLEMENT();
2014 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */