1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 #include <swmodeltestbase.hxx>
11 #include <comphelper/propertysequence.hxx>
12 #include <com/sun/star/linguistic2/XHyphenator.hpp>
13 #include <com/sun/star/text/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>
30 #include <pagefrm.hxx>
31 #include <bodyfrm.hxx>
32 #include <sortedobjs.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>
45 /// Test to assert layout / rendering result of Writer.
46 class SwLayoutWriter3
: public SwModelTestBase
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
85 "/root/page/body/txt/SwParaPortion/SwLineLayout/child::*[@nType='PortionType::Fly']", 0);
87 #if defined _WIN32 && defined _ARM64_
88 // skip for windows arm64 build
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());
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
135 assertXPath(pXmlDoc
, "/root/page/body/txt[1]/SwParaPortion/SwLineLayout", 1);
138 auto getXPathIntAttributeValue(xmlXPathContextPtr pXmlXpathCtx
, char const* const pXPath
)
141 xmlXPathObjectPtr pXmlXpathObj
= xmlXPathEvalExpression(BAD_CAST(pXPath
), pXmlXpathCtx
);
142 CPPUNIT_ASSERT(pXmlXpathObj
->nodesetval
);
143 CPPUNIT_ASSERT_EQUAL(1, xmlXPathNodeSetGetLength(pXmlXpathObj
->nodesetval
));
145 = sal_Int32(xmlXPathCastNodeToNumber(xmlXPathNodeSetItem(pXmlXpathObj
->nodesetval
, 0)));
146 xmlXPathFreeObject(pXmlXpathObj
);
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);
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]",
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();
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. ");
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
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();
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();
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();
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();
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();
343 = getXPath(pXmlDoc
, "/root/page/body/txt[1]/infos/bounds", "height").toInt32();
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())))
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]));
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]));
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
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)
520 // skip first non-empty line
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]));
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())))
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())))
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())))
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())))
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())))
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",
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",
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.
677 "/root/page[1]/body/section[2]/txt[1]/SwParaPortion/SwLineLayout/SwLinePortion[1]",
680 "/root/page[1]/body/section[2]/txt[1]/SwParaPortion/SwLineLayout/SwLinePortion[2]",
683 "/root/page[1]/body/section[2]/txt[2]/SwParaPortion/SwLineLayout/SwLinePortion[1]",
686 "/root/page[1]/body/section[2]/txt[2]/SwParaPortion/SwLineLayout/SwLinePortion[2]",
689 "/root/page[1]/body/section[2]/txt[3]/SwParaPortion/SwLineLayout/SwLinePortion[1]",
690 "portion", u
"Three");
692 "/root/page[1]/body/section[2]/txt[3]/SwParaPortion/SwLineLayout/SwLinePortion[2]",
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
710 "/root/page/body/txt[1]/SwParaPortion/SwLineLayout/child::*[@type='PortionType::TabRight']",
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);
731 "/root/page[1]/header/txt[1]/SwParaPortion/SwLineLayout/"
732 "child::*[@type='PortionType::TabCenter']",
735 "/root/page[1]/header/txt[1]/SwParaPortion/SwLineLayout/"
736 "child::*[@type='PortionType::TabRight']",
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);
753 "/root/page[1]/footer/txt[1]/SwParaPortion/SwLineLayout/"
754 "child::*[@type='PortionType::TabCenter']",
757 "/root/page[1]/footer/txt[1]/SwParaPortion/SwLineLayout/"
758 "child::*[@type='PortionType::TabRight']",
761 "/root/page[1]/footer/txt[1]/SwParaPortion/SwLineLayout/"
762 "child::*[@type='PortionType::TabRight']",
763 "width", u
"4446"); // was very small: 24
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);
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
783 "/root/page[1]/header/txt[1]/SwParaPortion/SwLineLayout/"
784 "child::*[@type='PortionType::TabRight']",
787 "/root/page[1]/header/txt[1]/SwParaPortion/SwLineLayout/"
788 "child::*[@type='PortionType::TabLeft']",
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")
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();
874 = getXPath(pXmlDoc
, "/root/page/body/txt/anchored/fly/tab/row[1]/cell[4]/infos/bounds",
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",
882 CPPUNIT_ASSERT_LESS(nTopOfD1Anchored
, nTopOfD1
);
884 = getXPath(pXmlDoc
, "/root/page/body/txt/anchored/fly/tab/row[2]/cell[2]/infos/bounds",
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",
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",
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();
955 "/root/page[1]/anchored/fly/txt[1]/anchored/fly/tab/row[2]/cell/txt[7]/anchored/"
956 "fly/txt/SwParaPortion/SwLineLayout/child::*[1]",
959 "/root/page[1]/anchored/fly/txt[1]/anchored/fly/tab/row[2]/cell/txt[7]/anchored/"
960 "fly/txt/SwParaPortion/SwLineLayout/child::*[1]",
963 "/root/page[1]/anchored/fly/txt[1]/anchored/fly/tab/row[2]/cell/txt[7]/anchored/"
964 "fly/txt/SwParaPortion/SwLineLayout/child::*[1]",
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",
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",
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",
1020 assertXPath(pXmlDoc
, "/root/page[1]/body/tab[3]/row[2]/cell[2]/txt[2]/infos/bounds", "top",
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",
1027 assertXPath(pXmlDoc
, "/root/page[1]/body/tab[3]/row[2]/cell[2]/txt[3]/infos/bounds", "top",
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
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")
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")
1120 SwTwips nSecondParaWidth
1121 = getXPath(pXmlDoc
, "/root/page/body/tab/row/cell[1]/txt[2]/infos/bounds", "width")
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")
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
1141 = getXPath(pXmlDoc
, "/root/page/body/tab/row/cell[1]/infos/bounds", "left").toInt32();
1143 = getXPath(pXmlDoc
, "/root/page/body/tab/row/cell[1]/infos/bounds", "width").toInt32();
1145 = getXPath(pXmlDoc
, "/root/page/body/tab/row/cell[1]/infos/bounds", "top").toInt32();
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
);
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())))
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.
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:
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:
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:
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",
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.
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",
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",
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.
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
),
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())
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.
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
),
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:
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:
1638 // i.e. there was a separate endnote page, even when the ContinuousEndnotes compat option was
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();
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
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
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.
1682 SwDoc
* pDoc
= getSwDoc();
1683 pDoc
->getIDocumentSettingAccess().set(DocumentSettingId::TAB_OVER_MARGIN
, true);
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
);
1714 pWrtShell
->Insert2(u
"HHH"_ustr
);
1716 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
1717 // Without the accompanying fix in place, this test would have failed with:
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.
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
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:
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.
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
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:
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:
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);
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));
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));
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()));
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));
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));
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: */