forcepoint#93 fix crash on layout of specific rtf
[LibreOffice.git] / sw / qa / extras / layout / layout.cxx
blob4122d3725b889f66f13043123781b52527a90d9e
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 <com/sun/star/linguistic2/LinguServiceManager.hpp>
12 #include <comphelper/propertysequence.hxx>
13 #include <com/sun/star/linguistic2/XHyphenator.hpp>
14 #include <com/sun/star/text/WrapTextMode.hpp>
15 #include <comphelper/scopeguard.hxx>
16 #include <vcl/event.hxx>
17 #include <vcl/scheduler.hxx>
18 #include <editeng/lrspitem.hxx>
19 #include <editeng/fontitem.hxx>
20 #include <editeng/fhgtitem.hxx>
21 #include <editeng/postitem.hxx>
22 #include <editeng/unolingu.hxx>
23 #include <editeng/outlobj.hxx>
24 #include <editeng/editobj.hxx>
25 #include <comphelper/sequence.hxx>
27 #include <fmtanchr.hxx>
28 #include <fmtfsize.hxx>
29 #include <fmtcntnt.hxx>
30 #include <wrtsh.hxx>
31 #include <edtwin.hxx>
32 #include <view.hxx>
33 #include <txtfrm.hxx>
34 #include <pagefrm.hxx>
35 #include <bodyfrm.hxx>
36 #include <sortedobjs.hxx>
37 #include <anchoredobject.hxx>
38 #include <ndtxt.hxx>
39 #include <frmatr.hxx>
40 #include <IDocumentSettingAccess.hxx>
41 #include <unotxdoc.hxx>
42 #include <rootfrm.hxx>
43 #include <docsh.hxx>
44 #include <IDocumentLayoutAccess.hxx>
45 #include <IDocumentDrawModelAccess.hxx>
46 #include <IDocumentRedlineAccess.hxx>
47 #include <textboxhelper.hxx>
48 #include <unoframe.hxx>
49 #include <drawdoc.hxx>
50 #include <svx/svdpage.hxx>
51 #include <svx/svdotext.hxx>
52 #include <dcontact.hxx>
54 constexpr OUStringLiteral DATA_DIRECTORY = u"/sw/qa/extras/layout/data/";
56 /// Test to assert layout / rendering result of Writer.
57 class SwLayoutWriter : public SwModelTestBase
59 protected:
60 void CheckRedlineFootnotesHidden();
61 void CheckRedlineSectionsHidden();
64 // this is a member because our test classes have protected members :(
65 void SwLayoutWriter::CheckRedlineFootnotesHidden()
67 discardDumpedLayout();
68 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
69 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/merged", "paraPropsNodeIndex", "24");
70 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[1]", "nType", "PortionType::Footnote");
71 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[1]", "rText", "1");
72 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Text");
73 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "foaz");
74 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[2]", "nType", "PortionType::Footnote");
75 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[2]", "rText", "2");
76 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/merged", "paraPropsNodeIndex", "13");
77 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/Special[1]", "nType",
78 "PortionType::FootnoteNum");
79 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/Special[1]", "rText", "1");
80 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/Text[1]", "nType",
81 "PortionType::Text");
82 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/Text[1]", "Portion", "ac");
83 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/merged", "paraPropsNodeIndex", "16");
84 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Special[1]", "nType",
85 "PortionType::FootnoteNum");
86 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Special[1]", "rText", "2");
87 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Text[1]", "nType",
88 "PortionType::Text");
89 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Text[1]", "Portion", "mo");
92 void SwLayoutWriter::CheckRedlineSectionsHidden()
94 discardDumpedLayout();
95 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
96 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/merged", "paraPropsNodeIndex", "12");
97 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Para");
98 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "folah");
99 assertXPath(pXmlDoc, "/root/page[1]/body/section[1]/txt[1]/merged", "paraPropsNodeIndex", "20");
100 assertXPath(pXmlDoc, "/root/page[1]/body/section[1]/txt[1]/Text[1]", "nType",
101 "PortionType::Para");
102 assertXPath(pXmlDoc, "/root/page[1]/body/section[1]/txt[1]/Text[1]", "Portion", "folah");
105 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testRedlineFootnotes)
107 createSwDoc(DATA_DIRECTORY, "redline_footnotes.odt");
108 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
109 CPPUNIT_ASSERT(pTextDoc);
110 SwDoc* pDoc(pTextDoc->GetDocShell()->GetDoc());
111 SwRootFrame* pLayout(pDoc->getIDocumentLayoutAccess().GetCurrentLayout());
112 CPPUNIT_ASSERT(pLayout->IsHideRedlines());
114 // verify after load
115 CheckRedlineFootnotesHidden();
117 dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
118 CPPUNIT_ASSERT(!pLayout->IsHideRedlines());
119 discardDumpedLayout();
120 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
122 // show: nothing is merged
123 xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "//merged");
124 xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
125 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes));
126 xmlXPathFreeObject(pXmlObj);
127 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[1]", "nType", "PortionType::Footnote");
128 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[1]", "rText", "1");
129 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Text");
130 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "fo");
131 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[2]", "nType", "PortionType::Text");
132 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[2]", "Portion", "o");
133 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[2]", "nType", "PortionType::Footnote");
134 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[2]", "rText", "2");
136 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/Special[1]", "nType",
137 "PortionType::FootnoteNum");
138 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/Special[1]", "rText", "1");
139 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/Text[1]", "nType",
140 "PortionType::Text");
141 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/Text[1]", "Portion", "a");
142 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/Text[2]", "nType",
143 "PortionType::Text");
144 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/Text[2]", "Portion", "b");
145 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/Text[3]", "nType",
146 "PortionType::Text");
147 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/Text[3]", "Portion", "c");
148 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Special[1]", "nType",
149 "PortionType::FootnoteNum");
150 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Special[1]", "rText", "2");
151 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Text[1]", "nType",
152 "PortionType::Text");
153 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Text[1]", "Portion", "def");
154 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[1]", "nType", "PortionType::Text");
155 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[1]", "Portion", "b");
156 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Special[1]", "nType", "PortionType::Footnote");
157 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Special[1]", "rText", "3");
158 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[2]", "nType", "PortionType::Text");
159 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[2]", "Portion", "ar");
160 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[3]/txt[1]/Special[1]", "nType",
161 "PortionType::FootnoteNum");
162 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[3]/txt[1]/Special[1]", "rText", "3");
163 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[3]/txt[1]/Text[1]", "nType",
164 "PortionType::Text");
165 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[3]/txt[1]/Text[1]", "Portion", "ghi");
166 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Special[1]", "nType", "PortionType::Footnote");
167 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Special[1]", "rText", "4");
168 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[1]", "nType", "PortionType::Text");
169 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[1]", "Portion", "b");
170 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[2]", "nType", "PortionType::Text");
171 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[2]", "Portion", "az");
172 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Special[2]", "nType", "PortionType::Footnote");
173 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Special[2]", "rText", "5");
175 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[4]/txt[1]/Special[1]", "nType",
176 "PortionType::FootnoteNum");
177 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[4]/txt[1]/Special[1]", "rText", "4");
178 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[4]/txt[1]/Text[1]", "nType",
179 "PortionType::Text");
180 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[4]/txt[1]/Text[1]", "Portion", "jkl");
181 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[5]/txt[1]/Special[1]", "nType",
182 "PortionType::FootnoteNum");
183 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[5]/txt[1]/Special[1]", "rText", "5");
184 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[5]/txt[1]/Text[1]", "nType",
185 "PortionType::Text");
186 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[5]/txt[1]/Text[1]", "Portion", "m");
187 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[5]/txt[1]/Text[2]", "nType",
188 "PortionType::Text");
189 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[5]/txt[1]/Text[2]", "Portion", "n");
190 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[5]/txt[1]/Text[3]", "nType",
191 "PortionType::Text");
192 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[5]/txt[1]/Text[3]", "Portion", "o");
194 // verify after hide
195 dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
196 CPPUNIT_ASSERT(pLayout->IsHideRedlines());
197 discardDumpedLayout();
198 CheckRedlineFootnotesHidden();
201 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, TestTdf136588)
203 load(DATA_DIRECTORY, "tdf136588.docx");
204 auto pXMLLayoutDump = parseLayoutDump();
205 CPPUNIT_ASSERT(pXMLLayoutDump);
207 //there was a bad line break before, the correct break layout is this:
208 assertXPath(pXMLLayoutDump, "/root/page/body/txt[2]/LineBreak[2]", "Line",
209 "effectively by modern-day small to ");
212 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testRedlineFlysInBody)
214 loadURL("private:factory/swriter", nullptr);
215 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
216 CPPUNIT_ASSERT(pTextDoc);
217 SwDoc* pDoc(pTextDoc->GetDocShell()->GetDoc());
218 SwWrtShell* pWrtShell = pTextDoc->GetDocShell()->GetWrtShell();
219 SwRootFrame* pLayout(pWrtShell->GetLayout());
220 CPPUNIT_ASSERT(!pLayout->IsHideRedlines());
221 pWrtShell->Insert("foo");
222 pWrtShell->SplitNode(false);
223 pWrtShell->Insert("bar");
224 pWrtShell->SplitNode(false);
225 pWrtShell->Insert("baz");
226 SfxItemSet flySet(pDoc->GetAttrPool(),
227 svl::Items<RES_FRM_SIZE, RES_FRM_SIZE, RES_ANCHOR, RES_ANCHOR>);
228 SwFormatAnchor anchor(RndStdIds::FLY_AT_CHAR);
229 pWrtShell->StartOfSection(false);
230 pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 1, /*bBasicCall=*/false);
231 anchor.SetAnchor(pWrtShell->GetCursor()->GetPoint());
232 flySet.Put(anchor);
233 SwFormatFrameSize size(SwFrameSize::Minimum, 1000, 1000);
234 flySet.Put(size); // set a size, else we get 1 char per line...
235 SwFrameFormat const* pFly = pWrtShell->NewFlyFrame(flySet, /*bAnchValid=*/true);
236 CPPUNIT_ASSERT(pFly != nullptr);
237 // move inside fly
238 pWrtShell->GotoFly(pFly->GetName(), FLYCNTTYPE_FRM, /*bSelFrame=*/false);
239 pWrtShell->Insert("abc");
240 pWrtShell->SplitNode(false);
241 pWrtShell->Insert("def");
242 pWrtShell->SplitNode(false);
243 pWrtShell->Insert("ghi");
245 dispatchCommand(mxComponent, ".uno:TrackChanges", {});
246 // delete redline inside fly
247 pWrtShell->Left(CRSR_SKIP_CHARS, /*bSelect=*/false, 2, /*bBasicCall=*/false);
248 pWrtShell->Left(CRSR_SKIP_CHARS, /*bSelect=*/true, 8, /*bBasicCall=*/false);
249 pWrtShell->Delete();
251 pWrtShell->SttEndDoc(true); // note: SttDoc actually moves to start of fly?
252 pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 2, /*bBasicCall=*/false);
253 pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/true, 7, /*bBasicCall=*/false);
254 pWrtShell->Delete();
256 for (int i = 0; i < 2; ++i)
258 if (i == 1) // secondly, try with different anchor type
260 anchor.SetType(RndStdIds::FLY_AT_PARA);
261 SwPosition pos(*anchor.GetContentAnchor());
262 pos.nContent.Assign(nullptr, 0);
263 anchor.SetAnchor(&pos);
264 pDoc->SetAttr(anchor, *const_cast<SwFrameFormat*>(pFly));
267 dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
268 CPPUNIT_ASSERT(pLayout->IsHideRedlines());
269 discardDumpedLayout();
270 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
271 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/merged", "paraPropsNodeIndex", "14");
272 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Para");
273 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "foaz");
274 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/merged",
275 "paraPropsNodeIndex", "6");
276 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "nType",
277 "PortionType::Para");
278 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "Portion",
279 "ahi");
281 dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
282 CPPUNIT_ASSERT(!pLayout->IsHideRedlines());
283 discardDumpedLayout();
284 pXmlDoc = parseLayoutDump();
286 { // show: nothing is merged
287 xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "//merged");
288 xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
289 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes));
290 xmlXPathFreeObject(pXmlObj);
293 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Text");
294 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "fo");
295 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[2]", "nType", "PortionType::Text");
296 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[2]", "Portion", "o");
297 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "nType",
298 "PortionType::Text");
299 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "Portion",
300 "a");
301 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[2]", "nType",
302 "PortionType::Text");
303 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[2]", "Portion",
304 "bc");
305 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[2]/Text[1]", "nType",
306 "PortionType::Para");
307 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[2]/Text[1]", "Portion",
308 "def");
309 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[3]/Text[1]", "nType",
310 "PortionType::Text");
311 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[3]/Text[1]", "Portion",
312 "g");
313 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[3]/Text[2]", "nType",
314 "PortionType::Text");
315 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[3]/Text[2]", "Portion",
316 "hi");
317 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[1]", "nType", "PortionType::Para");
318 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[1]", "Portion", "bar");
319 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[1]", "nType", "PortionType::Text");
320 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[1]", "Portion", "b");
321 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[2]", "nType", "PortionType::Text");
322 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[2]", "Portion", "az");
325 // anchor to 2nd (deleted) paragraph
326 pWrtShell->StartOfSection();
327 pWrtShell->Down(false, 1);
328 anchor.SetType(RndStdIds::FLY_AT_CHAR);
329 anchor.SetAnchor(pWrtShell->GetCursor()->GetPoint());
330 pDoc->SetAttr(anchor, *const_cast<SwFrameFormat*>(pFly));
332 for (int i = 0; i < 2; ++i)
334 if (i == 1) // secondly, try with different anchor type
336 anchor.SetType(RndStdIds::FLY_AT_PARA);
337 SwPosition pos(*anchor.GetContentAnchor());
338 pos.nContent.Assign(nullptr, 0);
339 anchor.SetAnchor(&pos);
340 pDoc->SetAttr(anchor, *const_cast<SwFrameFormat*>(pFly));
343 dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
344 CPPUNIT_ASSERT(pLayout->IsHideRedlines());
345 discardDumpedLayout();
346 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
347 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/merged", "paraPropsNodeIndex", "14");
348 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Para");
349 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "foaz");
351 { // hide: no anchored object shown
352 xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "//anchored");
353 xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
354 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes));
355 xmlXPathFreeObject(pXmlObj);
358 dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
359 CPPUNIT_ASSERT(!pLayout->IsHideRedlines());
360 discardDumpedLayout();
361 pXmlDoc = parseLayoutDump();
363 { // show: nothing is merged
364 xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "//merged");
365 xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
366 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes));
367 xmlXPathFreeObject(pXmlObj);
370 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Text");
371 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "fo");
372 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[2]", "nType", "PortionType::Text");
373 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[2]", "Portion", "o");
374 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[1]", "nType", "PortionType::Para");
375 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[1]", "Portion", "bar");
376 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[1]/Text[1]", "nType",
377 "PortionType::Text");
378 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[1]/Text[1]", "Portion",
379 "a");
380 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[1]/Text[2]", "nType",
381 "PortionType::Text");
382 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[1]/Text[2]", "Portion",
383 "bc");
384 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[2]/Text[1]", "nType",
385 "PortionType::Para");
386 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[2]/Text[1]", "Portion",
387 "def");
388 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[3]/Text[1]", "nType",
389 "PortionType::Text");
390 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[3]/Text[1]", "Portion",
391 "g");
392 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[3]/Text[2]", "nType",
393 "PortionType::Text");
394 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[3]/Text[2]", "Portion",
395 "hi");
396 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[1]", "nType", "PortionType::Text");
397 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[1]", "Portion", "b");
398 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[2]", "nType", "PortionType::Text");
399 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[2]", "Portion", "az");
402 // anchor to 3rd paragraph
403 pWrtShell->EndOfSection();
404 anchor.SetType(RndStdIds::FLY_AT_CHAR);
405 anchor.SetAnchor(pWrtShell->GetCursor()->GetPoint());
406 pDoc->SetAttr(anchor, *const_cast<SwFrameFormat*>(pFly));
408 for (int i = 0; i < 2; ++i)
410 if (i == 1) // secondly, try with different anchor type
412 anchor.SetType(RndStdIds::FLY_AT_PARA);
413 SwPosition pos(*anchor.GetContentAnchor());
414 pos.nContent.Assign(nullptr, 0);
415 anchor.SetAnchor(&pos);
416 pDoc->SetAttr(anchor, *const_cast<SwFrameFormat*>(pFly));
419 dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
420 CPPUNIT_ASSERT(pLayout->IsHideRedlines());
421 discardDumpedLayout();
422 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
423 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/merged", "paraPropsNodeIndex", "14");
424 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Para");
425 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "foaz");
426 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/merged",
427 "paraPropsNodeIndex", "6");
428 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "nType",
429 "PortionType::Para");
430 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "Portion",
431 "ahi");
433 dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
434 CPPUNIT_ASSERT(!pLayout->IsHideRedlines());
435 discardDumpedLayout();
436 pXmlDoc = parseLayoutDump();
438 { // show: nothing is merged
439 xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "//merged");
440 xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
441 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes));
442 xmlXPathFreeObject(pXmlObj);
445 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Text");
446 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "fo");
447 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[2]", "nType", "PortionType::Text");
448 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[2]", "Portion", "o");
449 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[1]", "nType", "PortionType::Para");
450 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[1]", "Portion", "bar");
451 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[1]", "nType", "PortionType::Text");
452 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[1]", "Portion", "b");
453 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[2]", "nType", "PortionType::Text");
454 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[2]", "Portion", "az");
455 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[1]/Text[1]", "nType",
456 "PortionType::Text");
457 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[1]/Text[1]", "Portion",
458 "a");
459 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[1]/Text[2]", "nType",
460 "PortionType::Text");
461 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[1]/Text[2]", "Portion",
462 "bc");
463 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[2]/Text[1]", "nType",
464 "PortionType::Para");
465 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[2]/Text[1]", "Portion",
466 "def");
467 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[3]/Text[1]", "nType",
468 "PortionType::Text");
469 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[3]/Text[1]", "Portion",
470 "g");
471 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[3]/Text[2]", "nType",
472 "PortionType::Text");
473 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[3]/Text[2]", "Portion",
474 "hi");
478 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, TestTdf134272)
480 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "tdf134472.odt");
481 CPPUNIT_ASSERT(pDoc);
482 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
483 assertXPath(pXmlDoc, "/root/page[1]/header/txt[2]/infos/bounds", "height", "843");
484 assertXPath(pXmlDoc, "/root/page[1]/header/txt[2]/infos/bounds", "bottom", "2819");
487 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, TestNestedTableMoveFwd)
489 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "tabellen_test_windows_1.odt");
490 CPPUNIT_ASSERT(pDoc);
491 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
492 // the row with the nested table should not be split but be the first row on page 2
493 assertXPath(pXmlDoc, "/root/page[1]/body/tab[1]/row[last()]/cell[1]/txt[1]/Text", "Portion",
494 "Tabelle 1");
495 assertXPath(pXmlDoc, "/root/page[2]/body/tab[1]/row[1]/cell[1]/tab[1]/row[1]/cell[1]/txt/Text",
496 "Portion", "Tabelle 2");
499 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, TestTdf136613)
501 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "tdf136613.docx");
502 CPPUNIT_ASSERT(pDoc);
504 //get the flys and the root frame
505 const auto vFlyFormats = pDoc->GetFlyFrameFormats(FLYCNTTYPE_ALL, true);
506 const auto vFrames = pDoc->GetAllLayouts();
508 CPPUNIT_ASSERT(!vFrames.empty());
509 CPPUNIT_ASSERT(!vFlyFormats.empty());
511 //get the page frame from the root
512 SwFrame* pPageFrame = vFrames[0]->Lower();
513 CPPUNIT_ASSERT(pPageFrame);
515 //get the rectangle of the page
516 const SwRect& rPageRect = pPageFrame->getFrameArea();
518 //check the flys and...
519 for (auto pFlyFormat : vFlyFormats)
521 //...the rectangle of the fly location...
522 const SwRect& rRect = pFlyFormat->FindLayoutRect();
523 CPPUNIT_ASSERT(!rRect.IsEmpty());
525 //...if it is on the page. This will fail if not.
526 CPPUNIT_ASSERT_MESSAGE("The pictures are outside the page!", rPageRect.Contains(rRect));
530 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf88496)
532 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "tdf88496.docx");
533 CPPUNIT_ASSERT(pDoc);
534 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
535 // This was 4, table fallback "switch off repeating header" started on a new page
536 assertXPath(pXmlDoc, "/root/page", 3);
539 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testRedlineFlysInHeader)
541 loadURL("private:factory/swriter", nullptr);
542 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
543 CPPUNIT_ASSERT(pTextDoc);
544 SwDoc* pDoc(pTextDoc->GetDocShell()->GetDoc());
545 SwWrtShell* pWrtShell = pTextDoc->GetDocShell()->GetWrtShell();
546 SwRootFrame* pLayout(pWrtShell->GetLayout());
547 CPPUNIT_ASSERT(!pLayout->IsHideRedlines());
548 pWrtShell->ChangeHeaderOrFooter(u"Default Page Style", /*bHeader*/ true, /*bOn*/ true, false);
549 CPPUNIT_ASSERT(
550 pWrtShell
551 ->IsInHeaderFooter()); // assume this is supposed to put cursor in the new header...
552 pWrtShell->Insert("foo");
553 pWrtShell->SplitNode(false);
554 pWrtShell->Insert("bar");
555 pWrtShell->SplitNode(false);
556 pWrtShell->Insert("baz");
557 SfxItemSet flySet(pDoc->GetAttrPool(),
558 svl::Items<RES_FRM_SIZE, RES_FRM_SIZE, RES_ANCHOR, RES_ANCHOR>);
559 SwFormatAnchor anchor(RndStdIds::FLY_AT_CHAR);
560 pWrtShell->StartOfSection(false);
561 pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 1, /*bBasicCall=*/false);
562 anchor.SetAnchor(pWrtShell->GetCursor()->GetPoint());
563 flySet.Put(anchor);
564 SwFormatFrameSize size(SwFrameSize::Minimum, 1000, 1000);
565 flySet.Put(size); // set a size, else we get 1 char per line...
566 SwFrameFormat const* pFly = pWrtShell->NewFlyFrame(flySet, /*bAnchValid=*/true);
567 CPPUNIT_ASSERT(pFly != nullptr);
568 // move inside fly
569 pWrtShell->GotoFly(pFly->GetName(), FLYCNTTYPE_FRM, /*bSelFrame=*/false);
570 pWrtShell->Insert("abc");
571 pWrtShell->SplitNode(false);
572 pWrtShell->Insert("def");
573 pWrtShell->SplitNode(false);
574 pWrtShell->Insert("ghi");
576 dispatchCommand(mxComponent, ".uno:TrackChanges", {});
577 // delete redline inside fly
578 pWrtShell->Left(CRSR_SKIP_CHARS, /*bSelect=*/false, 2, /*bBasicCall=*/false);
579 pWrtShell->Left(CRSR_SKIP_CHARS, /*bSelect=*/true, 8, /*bBasicCall=*/false);
580 pWrtShell->Delete();
582 pWrtShell->GotoHeaderText();
583 pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 2, /*bBasicCall=*/false);
584 pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/true, 7, /*bBasicCall=*/false);
585 pWrtShell->Delete();
587 for (int i = 0; i < 2; ++i)
589 if (i == 1) // secondly, try with different anchor type
591 anchor.SetType(RndStdIds::FLY_AT_PARA);
592 SwPosition pos(*anchor.GetContentAnchor());
593 pos.nContent.Assign(nullptr, 0);
594 anchor.SetAnchor(&pos);
595 pDoc->SetAttr(anchor, *const_cast<SwFrameFormat*>(pFly));
598 dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
599 CPPUNIT_ASSERT(pLayout->IsHideRedlines());
600 discardDumpedLayout();
601 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
602 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Para");
603 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nLength", "0");
604 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/merged", "paraPropsNodeIndex", "6");
605 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/Text[1]", "nType", "PortionType::Para");
606 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/Text[1]", "Portion", "foaz");
607 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[1]/merged",
608 "paraPropsNodeIndex", "11");
609 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "nType",
610 "PortionType::Para");
611 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
612 "Portion", "ahi");
614 dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
615 CPPUNIT_ASSERT(!pLayout->IsHideRedlines());
616 discardDumpedLayout();
617 pXmlDoc = parseLayoutDump();
619 { // show: nothing is merged
620 xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "//merged");
621 xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
622 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes));
623 xmlXPathFreeObject(pXmlObj);
626 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Para");
627 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nLength", "0");
628 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/Text[1]", "nType", "PortionType::Text");
629 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/Text[1]", "Portion", "fo");
630 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/Text[2]", "nType", "PortionType::Text");
631 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/Text[2]", "Portion", "o");
632 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "nType",
633 "PortionType::Text");
634 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
635 "Portion", "a");
636 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[1]/Text[2]", "nType",
637 "PortionType::Text");
638 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[1]/Text[2]",
639 "Portion", "bc");
640 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[2]/Text[1]", "nType",
641 "PortionType::Para");
642 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[2]/Text[1]",
643 "Portion", "def");
644 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[3]/Text[1]", "nType",
645 "PortionType::Text");
646 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[3]/Text[1]",
647 "Portion", "g");
648 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[3]/Text[2]", "nType",
649 "PortionType::Text");
650 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[3]/Text[2]",
651 "Portion", "hi");
652 assertXPath(pXmlDoc, "/root/page[1]/header/txt[2]/Text[1]", "nType", "PortionType::Para");
653 assertXPath(pXmlDoc, "/root/page[1]/header/txt[2]/Text[1]", "Portion", "bar");
654 assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/Text[1]", "nType", "PortionType::Text");
655 assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/Text[1]", "Portion", "b");
656 assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/Text[2]", "nType", "PortionType::Text");
657 assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/Text[2]", "Portion", "az");
660 // anchor to 2nd (deleted) paragraph
661 pWrtShell->StartOfSection();
662 pWrtShell->Down(false, 1);
663 anchor.SetType(RndStdIds::FLY_AT_CHAR);
664 anchor.SetAnchor(pWrtShell->GetCursor()->GetPoint());
665 pDoc->SetAttr(anchor, *const_cast<SwFrameFormat*>(pFly));
667 for (int i = 0; i < 2; ++i)
669 if (i == 1) // secondly, try with different anchor type
671 anchor.SetType(RndStdIds::FLY_AT_PARA);
672 SwPosition pos(*anchor.GetContentAnchor());
673 pos.nContent.Assign(nullptr, 0);
674 anchor.SetAnchor(&pos);
675 pDoc->SetAttr(anchor, *const_cast<SwFrameFormat*>(pFly));
678 dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
679 CPPUNIT_ASSERT(pLayout->IsHideRedlines());
680 discardDumpedLayout();
681 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
682 // now the frame has no Text portion? not sure why it's a 0-length one first and now none?
683 // assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Para");
684 // assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nLength", "0");
685 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/merged", "paraPropsNodeIndex", "6");
686 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/Text[1]", "nType", "PortionType::Para");
687 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/Text[1]", "Portion", "foaz");
689 { // hide: no anchored object shown
690 xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "//anchored");
691 xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
692 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes));
693 xmlXPathFreeObject(pXmlObj);
696 dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
697 CPPUNIT_ASSERT(!pLayout->IsHideRedlines());
698 discardDumpedLayout();
699 pXmlDoc = parseLayoutDump();
701 { // show: nothing is merged
702 xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "//merged");
703 xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
704 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes));
705 xmlXPathFreeObject(pXmlObj);
708 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Para");
709 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nLength", "0");
710 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/Text[1]", "nType", "PortionType::Text");
711 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/Text[1]", "Portion", "fo");
712 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/Text[2]", "nType", "PortionType::Text");
713 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/Text[2]", "Portion", "o");
714 assertXPath(pXmlDoc, "/root/page[1]/header/txt[2]/Text[1]", "nType", "PortionType::Para");
715 assertXPath(pXmlDoc, "/root/page[1]/header/txt[2]/Text[1]", "Portion", "bar");
716 assertXPath(pXmlDoc, "/root/page[1]/header/txt[2]/anchored/fly[1]/txt[1]/Text[1]", "nType",
717 "PortionType::Text");
718 assertXPath(pXmlDoc, "/root/page[1]/header/txt[2]/anchored/fly[1]/txt[1]/Text[1]",
719 "Portion", "a");
720 assertXPath(pXmlDoc, "/root/page[1]/header/txt[2]/anchored/fly[1]/txt[1]/Text[2]", "nType",
721 "PortionType::Text");
722 assertXPath(pXmlDoc, "/root/page[1]/header/txt[2]/anchored/fly[1]/txt[1]/Text[2]",
723 "Portion", "bc");
724 assertXPath(pXmlDoc, "/root/page[1]/header/txt[2]/anchored/fly[1]/txt[2]/Text[1]", "nType",
725 "PortionType::Para");
726 assertXPath(pXmlDoc, "/root/page[1]/header/txt[2]/anchored/fly[1]/txt[2]/Text[1]",
727 "Portion", "def");
728 assertXPath(pXmlDoc, "/root/page[1]/header/txt[2]/anchored/fly[1]/txt[3]/Text[1]", "nType",
729 "PortionType::Text");
730 assertXPath(pXmlDoc, "/root/page[1]/header/txt[2]/anchored/fly[1]/txt[3]/Text[1]",
731 "Portion", "g");
732 assertXPath(pXmlDoc, "/root/page[1]/header/txt[2]/anchored/fly[1]/txt[3]/Text[2]", "nType",
733 "PortionType::Text");
734 assertXPath(pXmlDoc, "/root/page[1]/header/txt[2]/anchored/fly[1]/txt[3]/Text[2]",
735 "Portion", "hi");
736 assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/Text[1]", "nType", "PortionType::Text");
737 assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/Text[1]", "Portion", "b");
738 assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/Text[2]", "nType", "PortionType::Text");
739 assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/Text[2]", "Portion", "az");
742 // anchor to 3rd paragraph
743 pWrtShell->EndOfSection();
744 anchor.SetType(RndStdIds::FLY_AT_CHAR);
745 anchor.SetAnchor(pWrtShell->GetCursor()->GetPoint());
746 pDoc->SetAttr(anchor, *const_cast<SwFrameFormat*>(pFly));
748 for (int i = 0; i < 2; ++i)
750 if (i == 1) // secondly, try with different anchor type
752 anchor.SetType(RndStdIds::FLY_AT_PARA);
753 SwPosition pos(*anchor.GetContentAnchor());
754 pos.nContent.Assign(nullptr, 0);
755 anchor.SetAnchor(&pos);
756 pDoc->SetAttr(anchor, *const_cast<SwFrameFormat*>(pFly));
759 dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
760 CPPUNIT_ASSERT(pLayout->IsHideRedlines());
761 discardDumpedLayout();
762 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
763 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Para");
764 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nLength", "0");
765 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/merged", "paraPropsNodeIndex", "6");
766 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/Text[1]", "nType", "PortionType::Para");
767 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/Text[1]", "Portion", "foaz");
768 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[1]/merged",
769 "paraPropsNodeIndex", "11");
770 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "nType",
771 "PortionType::Para");
772 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
773 "Portion", "ahi");
775 dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
776 CPPUNIT_ASSERT(!pLayout->IsHideRedlines());
777 discardDumpedLayout();
778 pXmlDoc = parseLayoutDump();
780 { // show: nothing is merged
781 xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "//merged");
782 xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
783 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes));
784 xmlXPathFreeObject(pXmlObj);
787 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Para");
788 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nLength", "0");
789 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/Text[1]", "nType", "PortionType::Text");
790 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/Text[1]", "Portion", "fo");
791 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/Text[2]", "nType", "PortionType::Text");
792 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/Text[2]", "Portion", "o");
793 assertXPath(pXmlDoc, "/root/page[1]/header/txt[2]/Text[1]", "nType", "PortionType::Para");
794 assertXPath(pXmlDoc, "/root/page[1]/header/txt[2]/Text[1]", "Portion", "bar");
795 assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/Text[1]", "nType", "PortionType::Text");
796 assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/Text[1]", "Portion", "b");
797 assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/Text[2]", "nType", "PortionType::Text");
798 assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/Text[2]", "Portion", "az");
799 assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/anchored/fly[1]/txt[1]/Text[1]", "nType",
800 "PortionType::Text");
801 assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/anchored/fly[1]/txt[1]/Text[1]",
802 "Portion", "a");
803 assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/anchored/fly[1]/txt[1]/Text[2]", "nType",
804 "PortionType::Text");
805 assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/anchored/fly[1]/txt[1]/Text[2]",
806 "Portion", "bc");
807 assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/anchored/fly[1]/txt[2]/Text[1]", "nType",
808 "PortionType::Para");
809 assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/anchored/fly[1]/txt[2]/Text[1]",
810 "Portion", "def");
811 assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/anchored/fly[1]/txt[3]/Text[1]", "nType",
812 "PortionType::Text");
813 assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/anchored/fly[1]/txt[3]/Text[1]",
814 "Portion", "g");
815 assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/anchored/fly[1]/txt[3]/Text[2]", "nType",
816 "PortionType::Text");
817 assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/anchored/fly[1]/txt[3]/Text[2]",
818 "Portion", "hi");
822 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, TestTdf137025)
824 // Check the padding of the textbox
825 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "tdf137025.docx");
826 CPPUNIT_ASSERT(pDoc);
827 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
828 CPPUNIT_ASSERT(pXmlDoc);
830 // Check the layout xml
831 // SDRATTR_TEXT_LEFTDIST
832 assertXPath(pXmlDoc,
833 "/root/page/body/txt/anchored/SwAnchoredDrawObject/SdrObject"
834 "/DefaultProperties/SfxItemSet/SdrMetricItem/SfxInt32Item[@whichId='1071']",
835 "value", "567");
836 // SDRATTR_TEXT_RIGHTDIST
837 assertXPath(pXmlDoc,
838 "/root/page/body/txt/anchored/SwAnchoredDrawObject/SdrObject"
839 "/DefaultProperties/SfxItemSet/SdrMetricItem/SfxInt32Item[@whichId='1072']",
840 "value", "1134");
841 // SDRATTR_TEXT_UPPERDIST
842 assertXPath(pXmlDoc,
843 "/root/page/body/txt/anchored/SwAnchoredDrawObject/SdrObject"
844 "/DefaultProperties/SfxItemSet/SdrMetricItem/SfxInt32Item[@whichId='1073']",
845 "value", "1701");
846 // SDRATTR_TEXT_LOWERDIST
847 assertXPath(pXmlDoc,
848 "/root/page/body/txt/anchored/SwAnchoredDrawObject/SdrObject"
849 "/DefaultProperties/SfxItemSet/SdrMetricItem/SfxInt32Item[@whichId='1074']",
850 "value", "2268");
852 // Check the textbox-shape import too
853 auto xShp = getShape(1);
854 CPPUNIT_ASSERT(xShp);
856 uno::Reference<beans::XPropertySet> xShapeProps(xShp, uno::UNO_QUERY);
858 SwFrameFormat* pFrameFormat = SwTextBoxHelper::getOtherTextBoxFormat(xShp);
859 CPPUNIT_ASSERT(pFrameFormat);
861 // The shape has these values to copy to the associated text frame after modification::
862 const tools::Long nLPaddng
863 = xShapeProps->getPropertyValue("TextLeftDistance").get<tools::Long>();
864 const tools::Long nRPaddng
865 = xShapeProps->getPropertyValue("TextRightDistance").get<tools::Long>();
866 const tools::Long nTPaddng
867 = xShapeProps->getPropertyValue("TextUpperDistance").get<tools::Long>();
868 const tools::Long nBPaddng
869 = xShapeProps->getPropertyValue("TextLowerDistance").get<tools::Long>();
871 CPPUNIT_ASSERT_EQUAL(tools::Long(1000), nLPaddng);
872 CPPUNIT_ASSERT_EQUAL(tools::Long(2000), nRPaddng);
873 CPPUNIT_ASSERT_EQUAL(tools::Long(3000), nTPaddng);
874 CPPUNIT_ASSERT_EQUAL(tools::Long(4001), nBPaddng);
876 // TODO: modify shape distance via UNO with text frame synchronization
877 // Check the textbox as well:
878 auto xTxFrm = SwXTextFrame::CreateXTextFrame(*pFrameFormat->GetDoc(), pFrameFormat);
879 CPPUNIT_ASSERT(xTxFrm);
880 uno::Reference<beans::XPropertySet> xFrameProps(xTxFrm, uno::UNO_QUERY);
882 const tools::Long nFrameLeftPaddng
883 = xFrameProps->getPropertyValue("LeftBorderDistance").get<tools::Long>();
884 const tools::Long nFrameRightPaddng
885 = xFrameProps->getPropertyValue("RightBorderDistance").get<tools::Long>();
886 const tools::Long nFrameTopPaddng
887 = xFrameProps->getPropertyValue("TopBorderDistance").get<tools::Long>();
888 const tools::Long nFrameBottomPaddng
889 = xFrameProps->getPropertyValue("BottomBorderDistance").get<tools::Long>();
891 // Check if the shape and frame have different setting
892 CPPUNIT_ASSERT_EQUAL(nLPaddng, nFrameLeftPaddng);
893 CPPUNIT_ASSERT_EQUAL(nRPaddng, nFrameRightPaddng);
894 CPPUNIT_ASSERT_EQUAL(nTPaddng, nFrameTopPaddng);
895 CPPUNIT_ASSERT_EQUAL(nBPaddng, nFrameBottomPaddng);
898 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testRedlineFlysInFootnote)
900 loadURL("private:factory/swriter", nullptr);
901 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
902 CPPUNIT_ASSERT(pTextDoc);
903 SwDoc* pDoc(pTextDoc->GetDocShell()->GetDoc());
904 SwWrtShell* pWrtShell = pTextDoc->GetDocShell()->GetWrtShell();
905 SwRootFrame* pLayout(pWrtShell->GetLayout());
906 CPPUNIT_ASSERT(!pLayout->IsHideRedlines());
907 pWrtShell->InsertFootnote("");
908 CPPUNIT_ASSERT(pWrtShell->IsCursorInFootnote());
910 SfxItemSet flySet(pDoc->GetAttrPool(),
911 svl::Items<RES_FRM_SIZE, RES_FRM_SIZE, RES_ANCHOR, RES_ANCHOR>);
912 SwFormatFrameSize size(SwFrameSize::Minimum, 1000, 1000);
913 flySet.Put(size); // set a size, else we get 1 char per line...
914 SwFormatAnchor anchor(RndStdIds::FLY_AT_CHAR);
915 anchor.SetAnchor(pWrtShell->GetCursor()->GetPoint());
916 flySet.Put(anchor);
917 // first fly is in first footnote that will be deleted
918 /* SwFrameFormat const* pFly1 =*/pWrtShell->NewFlyFrame(flySet, /*bAnchValid=*/true);
919 pWrtShell->Insert("quux");
921 pWrtShell->SttEndDoc(false);
923 pWrtShell->InsertFootnote("");
924 CPPUNIT_ASSERT(pWrtShell->IsCursorInFootnote());
925 pWrtShell->Insert("foo");
926 pWrtShell->SplitNode(false);
927 pWrtShell->Insert("bar");
928 pWrtShell->SplitNode(false);
929 pWrtShell->Insert("baz");
931 pWrtShell->StartOfSection(false);
932 CPPUNIT_ASSERT(pWrtShell->IsCursorInFootnote());
933 pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 1, /*bBasicCall=*/false);
934 anchor.SetAnchor(pWrtShell->GetCursor()->GetPoint());
935 flySet.Put(anchor);
936 // second fly is in second footnote that is not deleted
937 SwFrameFormat const* pFly = pWrtShell->NewFlyFrame(flySet, /*bAnchValid=*/true);
938 CPPUNIT_ASSERT(pFly != nullptr);
939 // move inside fly
940 pWrtShell->GotoFly(pFly->GetName(), FLYCNTTYPE_FRM, /*bSelFrame=*/false);
941 pWrtShell->Insert("abc");
942 pWrtShell->SplitNode(false);
943 pWrtShell->Insert("def");
944 pWrtShell->SplitNode(false);
945 pWrtShell->Insert("ghi");
947 dispatchCommand(mxComponent, ".uno:TrackChanges", {});
948 // delete redline inside fly
949 pWrtShell->Left(CRSR_SKIP_CHARS, /*bSelect=*/false, 2, /*bBasicCall=*/false);
950 pWrtShell->Left(CRSR_SKIP_CHARS, /*bSelect=*/true, 8, /*bBasicCall=*/false);
951 pWrtShell->Delete();
953 // pWrtShell->GotoFlyAnchor(); // sigh... why, now we're in the body...
954 pWrtShell->SttEndDoc(false);
955 pWrtShell->Left(CRSR_SKIP_CHARS, /*bSelect=*/false, 1, /*bBasicCall=*/false);
956 pWrtShell->GotoFootnoteText();
957 pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 2, /*bBasicCall=*/false);
958 pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/true, 7, /*bBasicCall=*/false);
959 pWrtShell->Delete();
960 pWrtShell->EndSelect(); // ?
961 // delete first footnote
962 pWrtShell->SttEndDoc(true);
963 pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/true, 1, /*bBasicCall=*/false);
964 pWrtShell->Delete();
966 for (int i = 0; i < 2; ++i)
968 if (i == 1) // secondly, try with different anchor type
970 anchor.SetType(RndStdIds::FLY_AT_PARA);
971 SwPosition pos(*anchor.GetContentAnchor());
972 pos.nContent.Assign(nullptr, 0);
973 anchor.SetAnchor(&pos);
974 pDoc->SetAttr(anchor, *const_cast<SwFrameFormat*>(pFly));
977 dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
978 CPPUNIT_ASSERT(pLayout->IsHideRedlines());
979 discardDumpedLayout();
980 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
981 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/merged", "paraPropsNodeIndex", "25");
982 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[1]", "nType",
983 "PortionType::Footnote");
984 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[1]", "rText", "1");
985 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/merged", "paraPropsNodeIndex",
986 "7");
987 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/anchored/fly[1]/txt[1]/merged",
988 "paraPropsNodeIndex", "17");
989 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
990 "nType", "PortionType::Para");
991 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
992 "Portion", "ahi");
993 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/Special[1]", "nType",
994 "PortionType::FootnoteNum");
995 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/Special[1]", "rText", "1");
997 dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
998 CPPUNIT_ASSERT(!pLayout->IsHideRedlines());
999 discardDumpedLayout();
1000 pXmlDoc = parseLayoutDump();
1002 { // show: nothing is merged
1003 xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "//merged");
1004 xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
1005 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes));
1006 xmlXPathFreeObject(pXmlObj);
1009 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[1]", "nType",
1010 "PortionType::Footnote");
1011 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[1]", "rText", "1");
1012 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[2]", "nType",
1013 "PortionType::Footnote");
1014 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[2]", "rText", "2");
1015 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
1016 "nType", "PortionType::Para");
1017 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
1018 "Portion", "quux");
1019 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/Special[1]", "nType",
1020 "PortionType::FootnoteNum");
1021 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/Special[1]", "rText", "1");
1022 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
1023 "nType", "PortionType::Text");
1024 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
1025 "Portion", "a");
1026 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/anchored/fly[1]/txt[1]/Text[2]",
1027 "nType", "PortionType::Text");
1028 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/anchored/fly[1]/txt[1]/Text[2]",
1029 "Portion", "bc");
1030 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/anchored/fly[1]/txt[2]/Text[1]",
1031 "nType", "PortionType::Para");
1032 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/anchored/fly[1]/txt[2]/Text[1]",
1033 "Portion", "def");
1034 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/anchored/fly[1]/txt[3]/Text[1]",
1035 "nType", "PortionType::Text");
1036 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/anchored/fly[1]/txt[3]/Text[1]",
1037 "Portion", "g");
1038 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/anchored/fly[1]/txt[3]/Text[2]",
1039 "nType", "PortionType::Text");
1040 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/anchored/fly[1]/txt[3]/Text[2]",
1041 "Portion", "hi");
1042 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Special[1]", "nType",
1043 "PortionType::FootnoteNum");
1044 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Special[1]", "rText", "2");
1045 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Text[1]", "nType",
1046 "PortionType::Text");
1047 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Text[1]", "Portion", "fo");
1048 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Text[2]", "nType",
1049 "PortionType::Text");
1050 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Text[2]", "Portion", "o");
1051 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[2]/Text[1]", "nType",
1052 "PortionType::Para");
1053 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[2]/Text[1]", "Portion", "bar");
1054 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/Text[1]", "nType",
1055 "PortionType::Text");
1056 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/Text[1]", "Portion", "b");
1057 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/Text[2]", "nType",
1058 "PortionType::Text");
1059 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/Text[2]", "Portion", "az");
1062 // anchor to 2nd (deleted) paragraph
1063 pWrtShell->SttEndDoc(false);
1064 pWrtShell->Left(CRSR_SKIP_CHARS, /*bSelect=*/false, 1, /*bBasicCall=*/false);
1065 pWrtShell->GotoFootnoteText();
1066 pWrtShell->Down(false, 1);
1067 anchor.SetType(RndStdIds::FLY_AT_CHAR);
1068 anchor.SetAnchor(pWrtShell->GetCursor()->GetPoint());
1069 pDoc->SetAttr(anchor, *const_cast<SwFrameFormat*>(pFly));
1071 for (int i = 0; i < 2; ++i)
1073 if (i == 1) // secondly, try with different anchor type
1075 anchor.SetType(RndStdIds::FLY_AT_PARA);
1076 SwPosition pos(*anchor.GetContentAnchor());
1077 pos.nContent.Assign(nullptr, 0);
1078 anchor.SetAnchor(&pos);
1079 pDoc->SetAttr(anchor, *const_cast<SwFrameFormat*>(pFly));
1082 dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
1083 CPPUNIT_ASSERT(pLayout->IsHideRedlines());
1084 discardDumpedLayout();
1085 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1087 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/merged", "paraPropsNodeIndex", "25");
1088 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[1]", "nType",
1089 "PortionType::Footnote");
1090 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[1]", "rText", "1");
1091 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/merged", "paraPropsNodeIndex",
1092 "7");
1093 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/Special[1]", "nType",
1094 "PortionType::FootnoteNum");
1095 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/Special[1]", "rText", "1");
1097 { // hide: no anchored object shown
1098 xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "//anchored");
1099 xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
1100 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes));
1101 xmlXPathFreeObject(pXmlObj);
1104 dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
1105 CPPUNIT_ASSERT(!pLayout->IsHideRedlines());
1106 discardDumpedLayout();
1107 pXmlDoc = parseLayoutDump();
1109 { // show: nothing is merged
1110 xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "//merged");
1111 xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
1112 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes));
1113 xmlXPathFreeObject(pXmlObj);
1116 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[1]", "nType",
1117 "PortionType::Footnote");
1118 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[1]", "rText", "1");
1119 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[2]", "nType",
1120 "PortionType::Footnote");
1121 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[2]", "rText", "2");
1122 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
1123 "nType", "PortionType::Para");
1124 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
1125 "Portion", "quux");
1126 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/Special[1]", "nType",
1127 "PortionType::FootnoteNum");
1128 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/Special[1]", "rText", "1");
1129 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Special[1]", "nType",
1130 "PortionType::FootnoteNum");
1131 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Special[1]", "rText", "2");
1132 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Text[1]", "nType",
1133 "PortionType::Text");
1134 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Text[1]", "Portion", "fo");
1135 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Text[2]", "nType",
1136 "PortionType::Text");
1137 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Text[2]", "Portion", "o");
1138 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[2]/anchored/fly[1]/txt[1]/Text[1]",
1139 "nType", "PortionType::Text");
1140 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[2]/anchored/fly[1]/txt[1]/Text[1]",
1141 "Portion", "a");
1142 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[2]/anchored/fly[1]/txt[1]/Text[2]",
1143 "nType", "PortionType::Text");
1144 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[2]/anchored/fly[1]/txt[1]/Text[2]",
1145 "Portion", "bc");
1146 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[2]/anchored/fly[1]/txt[2]/Text[1]",
1147 "nType", "PortionType::Para");
1148 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[2]/anchored/fly[1]/txt[2]/Text[1]",
1149 "Portion", "def");
1150 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[2]/anchored/fly[1]/txt[3]/Text[1]",
1151 "nType", "PortionType::Text");
1152 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[2]/anchored/fly[1]/txt[3]/Text[1]",
1153 "Portion", "g");
1154 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[2]/anchored/fly[1]/txt[3]/Text[2]",
1155 "nType", "PortionType::Text");
1156 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[2]/anchored/fly[1]/txt[3]/Text[2]",
1157 "Portion", "hi");
1158 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[2]/Text[1]", "nType",
1159 "PortionType::Para");
1160 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[2]/Text[1]", "Portion", "bar");
1161 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/Text[1]", "nType",
1162 "PortionType::Text");
1163 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/Text[1]", "Portion", "b");
1164 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/Text[2]", "nType",
1165 "PortionType::Text");
1166 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/Text[2]", "Portion", "az");
1169 // anchor to 3rd paragraph
1170 pWrtShell->EndOfSection();
1171 pWrtShell->SttEndDoc(false);
1172 pWrtShell->Left(CRSR_SKIP_CHARS, /*bSelect=*/false, 1, /*bBasicCall=*/false);
1173 pWrtShell->GotoFootnoteText();
1174 pWrtShell->EndOfSection();
1175 anchor.SetType(RndStdIds::FLY_AT_CHAR);
1176 anchor.SetAnchor(pWrtShell->GetCursor()->GetPoint());
1177 pDoc->SetAttr(anchor, *const_cast<SwFrameFormat*>(pFly));
1179 for (int i = 0; i < 2; ++i)
1181 if (i == 1) // secondly, try with different anchor type
1183 anchor.SetType(RndStdIds::FLY_AT_PARA);
1184 SwPosition pos(*anchor.GetContentAnchor());
1185 pos.nContent.Assign(nullptr, 0);
1186 anchor.SetAnchor(&pos);
1187 pDoc->SetAttr(anchor, *const_cast<SwFrameFormat*>(pFly));
1190 dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
1191 CPPUNIT_ASSERT(pLayout->IsHideRedlines());
1192 discardDumpedLayout();
1193 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1194 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/merged", "paraPropsNodeIndex", "25");
1195 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[1]", "nType",
1196 "PortionType::Footnote");
1197 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[1]", "rText", "1");
1198 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/merged", "paraPropsNodeIndex",
1199 "7");
1200 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/anchored/fly[1]/txt[1]/merged",
1201 "paraPropsNodeIndex", "17");
1202 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
1203 "nType", "PortionType::Para");
1204 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
1205 "Portion", "ahi");
1206 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/Special[1]", "nType",
1207 "PortionType::FootnoteNum");
1208 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/Special[1]", "rText", "1");
1210 dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
1211 CPPUNIT_ASSERT(!pLayout->IsHideRedlines());
1212 discardDumpedLayout();
1213 pXmlDoc = parseLayoutDump();
1215 { // show: nothing is merged
1216 xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "//merged");
1217 xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
1218 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes));
1219 xmlXPathFreeObject(pXmlObj);
1222 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[1]", "nType",
1223 "PortionType::Footnote");
1224 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[1]", "rText", "1");
1225 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[2]", "nType",
1226 "PortionType::Footnote");
1227 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[2]", "rText", "2");
1228 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
1229 "nType", "PortionType::Para");
1230 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
1231 "Portion", "quux");
1232 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/Special[1]", "nType",
1233 "PortionType::FootnoteNum");
1234 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/Special[1]", "rText", "1");
1235 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Special[1]", "nType",
1236 "PortionType::FootnoteNum");
1237 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Special[1]", "rText", "2");
1238 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Text[1]", "nType",
1239 "PortionType::Text");
1240 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Text[1]", "Portion", "fo");
1241 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Text[2]", "nType",
1242 "PortionType::Text");
1243 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Text[2]", "Portion", "o");
1244 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[2]/Text[1]", "nType",
1245 "PortionType::Para");
1246 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[2]/Text[1]", "Portion", "bar");
1247 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/anchored/fly[1]/txt[1]/Text[1]",
1248 "nType", "PortionType::Text");
1249 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/anchored/fly[1]/txt[1]/Text[1]",
1250 "Portion", "a");
1251 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/anchored/fly[1]/txt[1]/Text[2]",
1252 "nType", "PortionType::Text");
1253 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/anchored/fly[1]/txt[1]/Text[2]",
1254 "Portion", "bc");
1255 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/anchored/fly[1]/txt[2]/Text[1]",
1256 "nType", "PortionType::Para");
1257 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/anchored/fly[1]/txt[2]/Text[1]",
1258 "Portion", "def");
1259 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/anchored/fly[1]/txt[3]/Text[1]",
1260 "nType", "PortionType::Text");
1261 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/anchored/fly[1]/txt[3]/Text[1]",
1262 "Portion", "g");
1263 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/anchored/fly[1]/txt[3]/Text[2]",
1264 "nType", "PortionType::Text");
1265 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/anchored/fly[1]/txt[3]/Text[2]",
1266 "Portion", "hi");
1267 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/Text[1]", "nType",
1268 "PortionType::Text");
1269 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/Text[1]", "Portion", "b");
1270 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/Text[2]", "nType",
1271 "PortionType::Text");
1272 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/Text[2]", "Portion", "az");
1276 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf143239)
1278 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "tdf143239-1-min.odt");
1279 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
1281 // These are unstable on macOS and Win64 builds,
1282 // so only test that they restore original values for now
1283 OUString p2txt1Left, p2txt2Left, p3txt1Left;
1286 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1287 assertXPath(pXmlDoc, "/root/page[2]/body/txt[1]/anchored/fly", 1);
1288 assertXPath(pXmlDoc, "/root/page[2]/body/txt[1]/anchored/fly[1]/infos/bounds", "top",
1289 "18540");
1290 p2txt1Left
1291 = getXPath(pXmlDoc, "/root/page[2]/body/txt[1]/anchored/fly[1]/infos/bounds", "left");
1292 assertXPath(pXmlDoc, "/root/page[2]/body/txt[2]/anchored/fly", 1);
1293 assertXPath(pXmlDoc, "/root/page[2]/body/txt[2]/anchored/fly[1]/infos/bounds", "top",
1294 "23894");
1295 p2txt2Left
1296 = getXPath(pXmlDoc, "/root/page[2]/body/txt[2]/anchored/fly[1]/infos/bounds", "left");
1297 assertXPath(pXmlDoc, "/root/page[3]/body/txt[1]/anchored/fly", 1);
1298 assertXPath(pXmlDoc, "/root/page[3]/body/txt[1]/anchored/fly[1]/infos/bounds", "top",
1299 "35662");
1300 p3txt1Left
1301 = getXPath(pXmlDoc, "/root/page[3]/body/txt[1]/anchored/fly[1]/infos/bounds", "left");
1302 assertXPath(pXmlDoc, "/root/page", 3);
1303 discardDumpedLayout();
1306 pWrtShell->SelAll();
1307 pWrtShell->Delete();
1308 pWrtShell->Undo();
1309 Scheduler::ProcessEventsToIdle();
1312 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1313 // now the 1st fly was on page 1, and the fly on page 2 was the 2nd one
1314 assertXPath(pXmlDoc, "/root/page[2]/body/txt[1]/anchored/fly", 1);
1315 assertXPath(pXmlDoc, "/root/page[2]/body/txt[1]/anchored/fly[1]/infos/bounds", "top",
1316 "18540");
1317 assertXPath(pXmlDoc, "/root/page[2]/body/txt[1]/anchored/fly[1]/infos/bounds", "left",
1318 p2txt1Left);
1319 assertXPath(pXmlDoc, "/root/page[2]/body/txt[2]/anchored/fly", 1);
1320 assertXPath(pXmlDoc, "/root/page[2]/body/txt[2]/anchored/fly[1]/infos/bounds", "top",
1321 "23894");
1322 assertXPath(pXmlDoc, "/root/page[2]/body/txt[2]/anchored/fly[1]/infos/bounds", "left",
1323 p2txt2Left);
1324 assertXPath(pXmlDoc, "/root/page[3]/body/txt[1]/anchored/fly", 1);
1325 assertXPath(pXmlDoc, "/root/page[3]/body/txt[1]/anchored/fly[1]/infos/bounds", "top",
1326 "35662");
1327 assertXPath(pXmlDoc, "/root/page[3]/body/txt[1]/anchored/fly[1]/infos/bounds", "left",
1328 p3txt1Left);
1329 assertXPath(pXmlDoc, "/root/page", 3);
1330 discardDumpedLayout();
1334 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTableOverlapFooterFly)
1336 // Load a document that has a fly anchored in the footer.
1337 // It also has a table which initially overlaps with the fly, but then moves to the next page.
1338 load(DATA_DIRECTORY, "footer-fly-table.fodt");
1339 xmlDocUniquePtr pLayout = parseLayoutDump();
1340 // no fly portions, was: 8
1341 assertXPath(
1342 pLayout,
1343 "/root/page[2]/body/tab[1]/row[5]/cell[5]/txt[1]/Special[@nType='PortionType::Fly']", 0);
1344 // one line break, was: 5
1345 assertXPath(pLayout, "/root/page[2]/body/tab[1]/row[5]/cell[5]/txt[1]/LineBreak", 1);
1346 // one text portion, was: 1
1347 assertXPath(pLayout, "/root/page[2]/body/tab[1]/row[5]/cell[5]/txt[1]/Text", 1);
1348 assertXPath(pLayout, "/root/page[2]/body/tab[1]/row[5]/cell[5]/txt[1]/Text", "Portion",
1349 "Abc def ghi jkl mno pqr stu vwx yz.");
1350 // height was: 1517
1351 // tdf#134782 height was: 379
1352 assertXPath(pLayout, "/root/page[2]/body/tab[1]/row[5]/cell[5]/txt[1]/infos/bounds", "height",
1353 "253");
1356 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, TestTdf134277)
1358 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "tdf134277.docx");
1359 CPPUNIT_ASSERT(pDoc);
1360 SwDocShell* pShell = pDoc->GetDocShell();
1362 std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
1363 MetafileXmlDump dumper;
1365 xmlDocUniquePtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
1366 CPPUNIT_ASSERT(pXmlDoc);
1368 xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "/metafile/push/push/push/layoutmode[2]");
1369 xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
1370 CPPUNIT_ASSERT_EQUAL_MESSAGE("Bad position of shape in page break!", 0,
1371 xmlXPathNodeSetGetLength(pXmlNodes));
1374 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf116486)
1376 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "tdf116486.docx");
1377 CPPUNIT_ASSERT(pDoc);
1378 OUString aTop = parseDump("/root/page/body/txt/Special[1]", "nHeight");
1379 CPPUNIT_ASSERT_EQUAL(OUString("4006"), aTop);
1382 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, TestTdf142080)
1384 // this caused an infinite loop
1385 load(DATA_DIRECTORY, "fdo43573-2-min.docx");
1387 xmlDocUniquePtr pLayout = parseLayoutDump();
1388 // check the first paragraph on page 9 with its fly; the column was empty too
1389 assertXPath(pLayout, "/root/page[9]/body/section[1]/column[1]/body/txt[1]/Text[1]", "Portion",
1390 "De kleur u (rood) in het rechtervlak (R), de kleur r (wit) beneden (D),");
1391 SwTwips nPage9Top = getXPath(pLayout, "/root/page[9]/infos/bounds", "top").toInt32();
1392 assertXPath(
1393 pLayout,
1394 "/root/page[9]/body/section[1]/column[1]/body/txt[1]/anchored/fly[1]/notxt/infos/bounds",
1395 "top", OUString::number(nPage9Top + 1460));
1398 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf128198)
1400 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "tdf128198-1.docx");
1401 CPPUNIT_ASSERT(pDoc);
1402 xmlDocUniquePtr pLayout = parseLayoutDump();
1403 // the problem was that line 5 was truncated at "this "
1404 // due to the fly anchored in previous paragraph
1405 assertXPath(pLayout, "/root/page/body/txt[2]/LineBreak[5]", "Line",
1406 "to access any service, any time, anywhere. From this perspective, satellite "
1407 "boasts some ");
1408 assertXPath(pLayout, "/root/page/body/txt[2]/LineBreak[6]", "Line", "significant advantages. ");
1411 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testNoLineBreakAtSlash)
1413 load(DATA_DIRECTORY, "no-line-break-at-slash.fodt");
1414 xmlDocUniquePtr pLayout = parseLayoutDump();
1416 // the line break was between "Foostrasse 13/c/" and "2"
1417 xmlXPathObjectPtr pXmlObj = getXPathNode(pLayout, "/root/page[1]/body/txt[1]/child::*[2]");
1418 CPPUNIT_ASSERT_EQUAL(std::string("Text"), std::string(reinterpret_cast<char const*>(
1419 pXmlObj->nodesetval->nodeTab[0]->name)));
1420 xmlXPathFreeObject(pXmlObj);
1421 pXmlObj = getXPathNode(pLayout, "/root/page[1]/body/txt[1]/child::*[3]");
1422 CPPUNIT_ASSERT_EQUAL(std::string("LineBreak"), std::string(reinterpret_cast<char const*>(
1423 pXmlObj->nodesetval->nodeTab[0]->name)));
1424 xmlXPathFreeObject(pXmlObj);
1425 pXmlObj = getXPathNode(pLayout, "/root/page[1]/body/txt[1]/child::*[4]");
1426 CPPUNIT_ASSERT_EQUAL(std::string("Text"), std::string(reinterpret_cast<char const*>(
1427 pXmlObj->nodesetval->nodeTab[0]->name)));
1428 xmlXPathFreeObject(pXmlObj);
1429 pXmlObj = getXPathNode(pLayout, "/root/page[1]/body/txt[1]/child::*[5]");
1430 CPPUNIT_ASSERT_EQUAL(std::string("Special"), std::string(reinterpret_cast<char const*>(
1431 pXmlObj->nodesetval->nodeTab[0]->name)));
1432 xmlXPathFreeObject(pXmlObj);
1433 pXmlObj = getXPathNode(pLayout, "/root/page[1]/body/txt[1]/child::*[6]");
1434 CPPUNIT_ASSERT_EQUAL(std::string("Text"), std::string(reinterpret_cast<char const*>(
1435 pXmlObj->nodesetval->nodeTab[0]->name)));
1436 xmlXPathFreeObject(pXmlObj);
1437 pXmlObj = getXPathNode(pLayout, "/root/page[1]/body/txt[1]/child::*[7]");
1438 CPPUNIT_ASSERT_EQUAL(std::string("LineBreak"), std::string(reinterpret_cast<char const*>(
1439 pXmlObj->nodesetval->nodeTab[0]->name)));
1440 xmlXPathFreeObject(pXmlObj);
1441 pXmlObj = getXPathNode(pLayout, "/root/page[1]/body/txt[1]/child::*[8]");
1442 CPPUNIT_ASSERT_EQUAL(std::string("Finish"), std::string(reinterpret_cast<char const*>(
1443 pXmlObj->nodesetval->nodeTab[0]->name)));
1444 xmlXPathFreeObject(pXmlObj);
1446 assertXPath(pLayout, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "Blah blah bla bla bla ");
1447 assertXPath(pLayout, "/root/page[1]/body/txt[1]/Text[2]", "Portion", "Foostrasse");
1448 assertXPath(pLayout, "/root/page[1]/body/txt[1]/Text[3]", "Portion", "13/c/2, etc.");
1451 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf106153)
1453 load(DATA_DIRECTORY, "tdf106153.docx");
1454 xmlDocUniquePtr pDump = parseLayoutDump();
1456 const sal_Int64 nPageValLeft = getXPath(pDump, "/root/page/infos/bounds", "left").toInt64();
1457 const sal_Int64 nPageValTop = getXPath(pDump, "/root/page/infos/bounds", "top").toInt64();
1458 const sal_Int64 nPageValRight = getXPath(pDump, "/root/page/infos/bounds", "right").toInt64();
1459 const sal_Int64 nPageValBottom = getXPath(pDump, "/root/page/infos/bounds", "bottom").toInt64();
1461 const sal_Int64 nShape1ValTop
1462 = getXPath(pDump, "/root/page/body/txt/anchored/fly[1]/infos/bounds", "top").toInt64();
1463 const sal_Int64 nShape2ValLeft
1464 = getXPath(pDump, "/root/page/body/txt/anchored/fly[2]/infos/bounds", "left").toInt64();
1465 const sal_Int64 nShape3ValRight
1466 = getXPath(pDump, "/root/page/body/txt/anchored/fly[3]/infos/bounds", "right").toInt64();
1467 const sal_Int64 nShape4ValBottom
1468 = getXPath(pDump, "/root/page/body/txt/anchored/fly[4]/infos/bounds", "bottom").toInt64();
1470 CPPUNIT_ASSERT_MESSAGE("The whole top textbox is inside the page!",
1471 nPageValTop > nShape1ValTop);
1472 CPPUNIT_ASSERT_MESSAGE("The whole left textbox is inside the page!",
1473 nPageValLeft > nShape2ValLeft);
1474 CPPUNIT_ASSERT_MESSAGE("The whole right textbox is inside the page!",
1475 nPageValRight < nShape3ValRight);
1476 CPPUNIT_ASSERT_MESSAGE("The whole bottom textbox is inside the page!",
1477 nPageValBottom < nShape4ValBottom);
1480 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testRedlineFlysInFlys)
1482 loadURL("private:factory/swriter", nullptr);
1483 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
1484 CPPUNIT_ASSERT(pTextDoc);
1485 SwDoc* pDoc(pTextDoc->GetDocShell()->GetDoc());
1486 SwWrtShell* pWrtShell = pTextDoc->GetDocShell()->GetWrtShell();
1487 SwRootFrame* pLayout(pWrtShell->GetLayout());
1488 CPPUNIT_ASSERT(!pLayout->IsHideRedlines());
1489 pWrtShell->Insert("foo");
1490 pWrtShell->SplitNode(false);
1491 pWrtShell->Insert("bar");
1492 pWrtShell->SplitNode(false);
1493 pWrtShell->Insert("baz");
1494 SfxItemSet flySet(pDoc->GetAttrPool(),
1495 svl::Items<RES_FRM_SIZE, RES_FRM_SIZE, RES_ANCHOR, RES_ANCHOR>);
1496 SwFormatFrameSize size(SwFrameSize::Minimum, 1000, 1000);
1497 flySet.Put(size); // set a size, else we get 1 char per line...
1498 pWrtShell->StartOfSection(false);
1499 pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 1, /*bBasicCall=*/false);
1500 SwFormatAnchor anchor1(RndStdIds::FLY_AT_CHAR);
1501 anchor1.SetAnchor(pWrtShell->GetCursor()->GetPoint());
1502 flySet.Put(anchor1);
1503 SwFrameFormat const* pFly1 = pWrtShell->NewFlyFrame(flySet, /*bAnchValid=*/true);
1504 CPPUNIT_ASSERT(pFly1 != nullptr);
1505 // move inside fly1
1506 pWrtShell->GotoFly(pFly1->GetName(), FLYCNTTYPE_FRM, /*bSelFrame=*/false);
1507 pWrtShell->Insert("abc");
1508 pWrtShell->SplitNode(false);
1509 pWrtShell->Insert("def");
1510 pWrtShell->SplitNode(false);
1511 pWrtShell->Insert("ghi");
1513 SwFormatAnchor anchor2(RndStdIds::FLY_AT_CHAR);
1514 pWrtShell->StartOfSection(false); // start of fly...
1515 anchor2.SetAnchor(pWrtShell->GetCursor()->GetPoint());
1516 flySet.Put(anchor2);
1517 SwFrameFormat const* pFly2 = pWrtShell->NewFlyFrame(flySet, /*bAnchValid=*/true);
1518 CPPUNIT_ASSERT(pFly2 != nullptr);
1519 // move inside fly2
1520 pWrtShell->GotoFly(pFly2->GetName(), FLYCNTTYPE_FRM, /*bSelFrame=*/false);
1521 pWrtShell->Insert("jkl");
1522 pWrtShell->SplitNode(false);
1523 pWrtShell->Insert("mno");
1524 pWrtShell->SplitNode(false);
1525 pWrtShell->Insert("pqr");
1527 dispatchCommand(mxComponent, ".uno:TrackChanges", {});
1528 // delete redline inside fly2
1529 pWrtShell->Left(CRSR_SKIP_CHARS, /*bSelect=*/false, 2, /*bBasicCall=*/false);
1530 pWrtShell->Left(CRSR_SKIP_CHARS, /*bSelect=*/true, 8, /*bBasicCall=*/false);
1531 pWrtShell->Delete();
1533 // delete redline inside fly1
1534 pWrtShell->GotoFly(pFly1->GetName(), FLYCNTTYPE_FRM, /*bSelFrame=*/false);
1535 pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 2, /*bBasicCall=*/false);
1536 pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/true, 7, /*bBasicCall=*/false);
1537 pWrtShell->Delete();
1539 pWrtShell->ClearMark(); // otherwise it refuses to leave the fly...
1540 pWrtShell->SttEndDoc(true); // note: SttDoc actually moves to start of fly?
1541 pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 2, /*bBasicCall=*/false);
1542 pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/true, 7, /*bBasicCall=*/false);
1543 pWrtShell->Delete();
1545 for (int i = 0; i < 2; ++i)
1547 if (i == 1) // secondly, try with different anchor type
1549 anchor1.SetType(RndStdIds::FLY_AT_PARA);
1550 SwPosition pos(*anchor1.GetContentAnchor());
1551 pos.nContent.Assign(nullptr, 0);
1552 anchor1.SetAnchor(&pos);
1553 pDoc->SetAttr(anchor1, *const_cast<SwFrameFormat*>(pFly1));
1554 anchor2.SetType(RndStdIds::FLY_AT_PARA);
1555 pos.nNode = anchor2.GetContentAnchor()->nNode;
1556 anchor2.SetAnchor(&pos);
1557 pDoc->SetAttr(anchor2, *const_cast<SwFrameFormat*>(pFly2));
1560 dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
1561 CPPUNIT_ASSERT(pLayout->IsHideRedlines());
1562 discardDumpedLayout();
1563 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1564 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/merged", "paraPropsNodeIndex", "19");
1565 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/merged",
1566 "paraPropsNodeIndex", "6");
1567 assertXPath(
1568 pXmlDoc,
1569 "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/anchored[1]/fly[1]/txt[1]/merged",
1570 "paraPropsNodeIndex", "11");
1571 assertXPath(
1572 pXmlDoc,
1573 "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/anchored[1]/fly[1]/txt[1]/Text[1]",
1574 "nType", "PortionType::Para");
1575 assertXPath(
1576 pXmlDoc,
1577 "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/anchored[1]/fly[1]/txt[1]/Text[1]",
1578 "Portion", "jqr");
1579 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Special[1]", "nType",
1580 "PortionType::Fly"); // remove???
1581 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "nType",
1582 "PortionType::Lay");
1583 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "Portion",
1584 "abhi");
1585 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Para");
1586 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "foaz");
1588 dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
1589 CPPUNIT_ASSERT(!pLayout->IsHideRedlines());
1590 discardDumpedLayout();
1591 pXmlDoc = parseLayoutDump();
1593 { // show: nothing is merged
1594 xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "//merged");
1595 xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
1596 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes));
1597 xmlXPathFreeObject(pXmlObj);
1600 assertXPath(
1601 pXmlDoc,
1602 "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/anchored[1]/fly[1]/txt[1]/Text[1]",
1603 "nType", "PortionType::Text");
1604 assertXPath(
1605 pXmlDoc,
1606 "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/anchored[1]/fly[1]/txt[1]/Text[1]",
1607 "Portion", "j");
1608 assertXPath(
1609 pXmlDoc,
1610 "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/anchored[1]/fly[1]/txt[1]/Text[2]",
1611 "nType", "PortionType::Text");
1612 assertXPath(
1613 pXmlDoc,
1614 "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/anchored[1]/fly[1]/txt[1]/Text[2]",
1615 "Portion", "kl");
1616 assertXPath(
1617 pXmlDoc,
1618 "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/anchored[1]/fly[1]/txt[2]/Text[1]",
1619 "nType", "PortionType::Para");
1620 assertXPath(
1621 pXmlDoc,
1622 "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/anchored[1]/fly[1]/txt[2]/Text[1]",
1623 "Portion", "mno");
1624 assertXPath(
1625 pXmlDoc,
1626 "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/anchored[1]/fly[1]/txt[3]/Text[1]",
1627 "nType", "PortionType::Text");
1628 assertXPath(
1629 pXmlDoc,
1630 "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/anchored[1]/fly[1]/txt[3]/Text[1]",
1631 "Portion", "p");
1632 assertXPath(
1633 pXmlDoc,
1634 "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/anchored[1]/fly[1]/txt[3]/Text[2]",
1635 "nType", "PortionType::Text");
1636 assertXPath(
1637 pXmlDoc,
1638 "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/anchored[1]/fly[1]/txt[3]/Text[2]",
1639 "Portion", "qr");
1640 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Special[1]", "nType",
1641 "PortionType::Fly"); // remove???
1642 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "nType",
1643 "PortionType::Text");
1644 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "Portion",
1645 "ab");
1646 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[2]", "nType",
1647 "PortionType::Text");
1648 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[2]", "Portion",
1649 "c");
1650 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[2]/Text[1]", "nType",
1651 "PortionType::Para");
1652 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[2]/Text[1]", "Portion",
1653 "def");
1654 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[3]/Text[1]", "nType",
1655 "PortionType::Text");
1656 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[3]/Text[1]", "Portion",
1657 "g");
1658 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[3]/Text[2]", "nType",
1659 "PortionType::Text");
1660 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[3]/Text[2]", "Portion",
1661 "hi");
1662 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Text");
1663 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "fo");
1664 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[2]", "nType", "PortionType::Text");
1665 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[2]", "Portion", "o");
1666 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[1]", "nType", "PortionType::Para");
1667 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[1]", "Portion", "bar");
1668 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[1]", "nType", "PortionType::Text");
1669 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[1]", "Portion", "b");
1670 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[2]", "nType", "PortionType::Text");
1671 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[2]", "Portion", "az");
1674 // anchor to 2nd (deleted) paragraph
1675 // also, switch the in-fly anchoring to the other fly, for additional fun!
1676 pWrtShell->StartOfSection();
1677 pWrtShell->Down(false, 1);
1678 anchor2.SetType(RndStdIds::FLY_AT_CHAR);
1679 anchor2.SetAnchor(pWrtShell->GetCursor()->GetPoint());
1680 pDoc->SetAttr(anchor2, *const_cast<SwFrameFormat*>(pFly2));
1681 pWrtShell->GotoFly(pFly2->GetName(), FLYCNTTYPE_FRM, /*bSelFrame=*/false);
1682 pWrtShell->Down(false, 1);
1683 anchor1.SetType(RndStdIds::FLY_AT_CHAR);
1684 anchor1.SetAnchor(pWrtShell->GetCursor()->GetPoint());
1685 pDoc->SetAttr(anchor1, *const_cast<SwFrameFormat*>(pFly1));
1687 for (int i = 0; i < 2; ++i)
1689 if (i == 1) // secondly, try with different anchor type
1691 anchor1.SetType(RndStdIds::FLY_AT_PARA);
1692 SwPosition pos(*anchor1.GetContentAnchor());
1693 pos.nContent.Assign(nullptr, 0);
1694 anchor1.SetAnchor(&pos);
1695 pDoc->SetAttr(anchor1, *const_cast<SwFrameFormat*>(pFly1));
1696 anchor2.SetType(RndStdIds::FLY_AT_PARA);
1697 pos.nNode = anchor2.GetContentAnchor()->nNode;
1698 anchor2.SetAnchor(&pos);
1699 pDoc->SetAttr(anchor2, *const_cast<SwFrameFormat*>(pFly2));
1702 dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
1703 CPPUNIT_ASSERT(pLayout->IsHideRedlines());
1704 discardDumpedLayout();
1705 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1706 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/merged", "paraPropsNodeIndex", "19");
1707 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Para");
1708 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "foaz");
1710 { // hide: no anchored object shown
1711 xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "//anchored");
1712 xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
1713 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes));
1714 xmlXPathFreeObject(pXmlObj);
1717 dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
1718 CPPUNIT_ASSERT(!pLayout->IsHideRedlines());
1719 discardDumpedLayout();
1720 pXmlDoc = parseLayoutDump();
1722 { // show: nothing is merged
1723 xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "//merged");
1724 xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
1725 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes));
1726 xmlXPathFreeObject(pXmlObj);
1729 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Text");
1730 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "fo");
1731 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[2]", "nType", "PortionType::Text");
1732 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[2]", "Portion", "o");
1733 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[1]/Text[1]", "nType",
1734 "PortionType::Text");
1735 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[1]/Text[1]", "Portion",
1736 "j");
1737 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[1]/Text[2]", "nType",
1738 "PortionType::Text");
1739 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[1]/Text[2]", "Portion",
1740 "kl");
1741 assertXPath(
1742 pXmlDoc,
1743 "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[2]/anchored[1]/fly[1]/txt[1]/Text[1]",
1744 "nType", "PortionType::Text");
1745 assertXPath(
1746 pXmlDoc,
1747 "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[2]/anchored[1]/fly[1]/txt[1]/Text[1]",
1748 "Portion", "ab");
1749 assertXPath(
1750 pXmlDoc,
1751 "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[2]/anchored[1]/fly[1]/txt[1]/Text[2]",
1752 "nType", "PortionType::Text");
1753 assertXPath(
1754 pXmlDoc,
1755 "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[2]/anchored[1]/fly[1]/txt[1]/Text[2]",
1756 "Portion", "c");
1757 assertXPath(
1758 pXmlDoc,
1759 "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[2]/anchored[1]/fly[1]/txt[2]/Text[1]",
1760 "nType", "PortionType::Para");
1761 assertXPath(
1762 pXmlDoc,
1763 "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[2]/anchored[1]/fly[1]/txt[2]/Text[1]",
1764 "Portion", "def");
1765 assertXPath(
1766 pXmlDoc,
1767 "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[2]/anchored[1]/fly[1]/txt[3]/Text[1]",
1768 "nType", "PortionType::Text");
1769 assertXPath(
1770 pXmlDoc,
1771 "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[2]/anchored[1]/fly[1]/txt[3]/Text[1]",
1772 "Portion", "g");
1773 assertXPath(
1774 pXmlDoc,
1775 "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[2]/anchored[1]/fly[1]/txt[3]/Text[2]",
1776 "nType", "PortionType::Text");
1777 assertXPath(
1778 pXmlDoc,
1779 "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[2]/anchored[1]/fly[1]/txt[3]/Text[2]",
1780 "Portion", "hi");
1781 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[2]/Special[1]", "nType",
1782 "PortionType::Fly"); // remove???
1783 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[2]/Text[1]", "nType",
1784 "PortionType::Lay");
1785 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[2]/Text[1]", "Portion",
1786 "mno");
1787 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[3]/Text[1]", "nType",
1788 "PortionType::Text");
1789 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[3]/Text[1]", "Portion",
1790 "p");
1791 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[3]/Text[2]", "nType",
1792 "PortionType::Text");
1793 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[3]/Text[2]", "Portion",
1794 "qr");
1795 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[1]", "nType", "PortionType::Para");
1796 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[1]", "Portion", "bar");
1797 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[1]", "nType", "PortionType::Text");
1798 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[1]", "Portion", "b");
1799 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[2]", "nType", "PortionType::Text");
1800 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[2]", "Portion", "az");
1803 // anchor to 3rd paragraph
1804 pWrtShell->SttEndDoc(false);
1805 anchor1.SetType(RndStdIds::FLY_AT_CHAR);
1806 anchor1.SetAnchor(pWrtShell->GetCursor()->GetPoint());
1807 pDoc->SetAttr(anchor1, *const_cast<SwFrameFormat*>(pFly1));
1808 pWrtShell->GotoFly(pFly1->GetName(), FLYCNTTYPE_FRM, /*bSelFrame=*/false);
1809 pWrtShell->EndOfSection();
1810 anchor2.SetType(RndStdIds::FLY_AT_CHAR);
1811 anchor2.SetAnchor(pWrtShell->GetCursor()->GetPoint());
1812 pDoc->SetAttr(anchor2, *const_cast<SwFrameFormat*>(pFly2));
1814 for (int i = 0; i < 2; ++i)
1816 if (i == 1) // secondly, try with different anchor type
1818 anchor1.SetType(RndStdIds::FLY_AT_PARA);
1819 SwPosition pos(*anchor1.GetContentAnchor());
1820 pos.nContent.Assign(nullptr, 0);
1821 anchor1.SetAnchor(&pos);
1822 pDoc->SetAttr(anchor1, *const_cast<SwFrameFormat*>(pFly1));
1823 anchor2.SetType(RndStdIds::FLY_AT_PARA);
1824 pos.nNode = anchor2.GetContentAnchor()->nNode;
1825 anchor2.SetAnchor(&pos);
1826 pDoc->SetAttr(anchor2, *const_cast<SwFrameFormat*>(pFly2));
1829 dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
1830 CPPUNIT_ASSERT(pLayout->IsHideRedlines());
1831 discardDumpedLayout();
1832 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1833 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/merged", "paraPropsNodeIndex", "19");
1834 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/merged",
1835 "paraPropsNodeIndex", "6");
1836 assertXPath(
1837 pXmlDoc,
1838 "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/anchored[1]/fly[1]/txt[1]/merged",
1839 "paraPropsNodeIndex", "11");
1840 assertXPath(
1841 pXmlDoc,
1842 "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/anchored[1]/fly[1]/txt[1]/Text[1]",
1843 "nType", "PortionType::Para");
1844 assertXPath(
1845 pXmlDoc,
1846 "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/anchored[1]/fly[1]/txt[1]/Text[1]",
1847 "Portion", "jqr");
1848 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Special[1]", "nType",
1849 "PortionType::Fly"); // remove???
1850 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "nType",
1851 "PortionType::Lay");
1852 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "Portion",
1853 "abhi");
1854 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Para");
1855 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "foaz");
1857 dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
1858 CPPUNIT_ASSERT(!pLayout->IsHideRedlines());
1859 discardDumpedLayout();
1860 pXmlDoc = parseLayoutDump();
1862 { // show: nothing is merged
1863 xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "//merged");
1864 xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
1865 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes));
1866 xmlXPathFreeObject(pXmlObj);
1869 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Text");
1870 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "fo");
1871 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[2]", "nType", "PortionType::Text");
1872 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[2]", "Portion", "o");
1873 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[1]", "nType", "PortionType::Para");
1874 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[1]", "Portion", "bar");
1875 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[1]/Text[1]", "nType",
1876 "PortionType::Text");
1877 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[1]/Text[1]", "Portion",
1878 "ab");
1879 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[1]/Text[2]", "nType",
1880 "PortionType::Text");
1881 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[1]/Text[2]", "Portion",
1882 "c");
1883 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[2]/Text[1]", "nType",
1884 "PortionType::Para");
1885 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[2]/Text[1]", "Portion",
1886 "def");
1887 assertXPath(
1888 pXmlDoc,
1889 "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[3]/anchored[1]/fly[1]/txt[1]/Text[1]",
1890 "nType", "PortionType::Text");
1891 assertXPath(
1892 pXmlDoc,
1893 "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[3]/anchored[1]/fly[1]/txt[1]/Text[1]",
1894 "Portion", "j");
1895 assertXPath(
1896 pXmlDoc,
1897 "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[3]/anchored[1]/fly[1]/txt[1]/Text[2]",
1898 "nType", "PortionType::Text");
1899 assertXPath(
1900 pXmlDoc,
1901 "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[3]/anchored[1]/fly[1]/txt[1]/Text[2]",
1902 "Portion", "kl");
1903 assertXPath(
1904 pXmlDoc,
1905 "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[3]/anchored[1]/fly[1]/txt[2]/Text[1]",
1906 "nType", "PortionType::Para");
1907 assertXPath(
1908 pXmlDoc,
1909 "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[3]/anchored[1]/fly[1]/txt[2]/Text[1]",
1910 "Portion", "mno");
1911 assertXPath(
1912 pXmlDoc,
1913 "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[3]/anchored[1]/fly[1]/txt[3]/Text[1]",
1914 "nType", "PortionType::Text");
1915 assertXPath(
1916 pXmlDoc,
1917 "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[3]/anchored[1]/fly[1]/txt[3]/Text[1]",
1918 "Portion", "p");
1919 assertXPath(
1920 pXmlDoc,
1921 "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[3]/anchored[1]/fly[1]/txt[3]/Text[2]",
1922 "nType", "PortionType::Text");
1923 assertXPath(
1924 pXmlDoc,
1925 "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[3]/anchored[1]/fly[1]/txt[3]/Text[2]",
1926 "Portion", "qr");
1927 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[3]/Text[1]", "nType",
1928 "PortionType::Text");
1929 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[3]/Special[1]", "nType",
1930 "PortionType::Fly"); // remove???
1931 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[3]/Text[1]", "Portion",
1932 "g");
1933 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[3]/Text[2]", "nType",
1934 "PortionType::Text");
1935 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[3]/Text[2]", "Portion",
1936 "hi");
1937 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[1]", "nType", "PortionType::Text");
1938 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[1]", "Portion", "b");
1939 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[2]", "nType", "PortionType::Text");
1940 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[2]", "Portion", "az");
1944 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testRedlineFlysAtFlys)
1946 loadURL("private:factory/swriter", nullptr);
1947 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
1948 CPPUNIT_ASSERT(pTextDoc);
1949 SwDoc* pDoc(pTextDoc->GetDocShell()->GetDoc());
1950 SwWrtShell* pWrtShell = pTextDoc->GetDocShell()->GetWrtShell();
1951 SwRootFrame* pLayout(pWrtShell->GetLayout());
1952 CPPUNIT_ASSERT(!pLayout->IsHideRedlines());
1953 pWrtShell->Insert("foo");
1954 pWrtShell->SplitNode(false);
1955 pWrtShell->Insert("bar");
1956 pWrtShell->SplitNode(false);
1957 pWrtShell->Insert("baz");
1958 SfxItemSet flySet(pDoc->GetAttrPool(),
1959 svl::Items<RES_FRM_SIZE, RES_FRM_SIZE, RES_ANCHOR, RES_ANCHOR>);
1960 SwFormatFrameSize size(SwFrameSize::Minimum, 1000, 1000);
1961 flySet.Put(size); // set a size, else we get 1 char per line...
1962 pWrtShell->StartOfSection(false);
1963 pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 1, /*bBasicCall=*/false);
1964 SwFormatAnchor anchor1(RndStdIds::FLY_AT_CHAR);
1965 anchor1.SetAnchor(pWrtShell->GetCursor()->GetPoint());
1966 flySet.Put(anchor1);
1967 SwFrameFormat const* pFly1 = pWrtShell->NewFlyFrame(flySet, /*bAnchValid=*/true);
1968 CPPUNIT_ASSERT(pFly1 != nullptr);
1969 // move inside fly1
1970 pWrtShell->GotoFly(pFly1->GetName(), FLYCNTTYPE_FRM, /*bSelFrame=*/false);
1971 pWrtShell->Insert("abc");
1972 pWrtShell->SplitNode(false);
1973 pWrtShell->Insert("def");
1974 pWrtShell->SplitNode(false);
1975 pWrtShell->Insert("ghi");
1977 SwFormatAnchor anchor2(RndStdIds::FLY_AT_FLY);
1978 SwPosition pos(*pFly1->GetContent().GetContentIdx());
1979 anchor2.SetAnchor(&pos);
1980 flySet.Put(anchor2);
1981 SwFrameFormat const* pFly2 = pWrtShell->NewFlyFrame(flySet, /*bAnchValid=*/true);
1982 CPPUNIT_ASSERT(pFly2 != nullptr);
1983 // move inside fly2
1984 pWrtShell->GotoFly(pFly2->GetName(), FLYCNTTYPE_FRM, /*bSelFrame=*/false);
1985 pWrtShell->Insert("jkl");
1986 pWrtShell->SplitNode(false);
1987 pWrtShell->Insert("mno");
1988 pWrtShell->SplitNode(false);
1989 pWrtShell->Insert("pqr");
1991 dispatchCommand(mxComponent, ".uno:TrackChanges", {});
1992 // delete redline inside fly2
1993 pWrtShell->Left(CRSR_SKIP_CHARS, /*bSelect=*/false, 2, /*bBasicCall=*/false);
1994 pWrtShell->Left(CRSR_SKIP_CHARS, /*bSelect=*/true, 8, /*bBasicCall=*/false);
1995 pWrtShell->Delete();
1997 // delete redline inside fly1
1998 pWrtShell->GotoFly(pFly1->GetName(), FLYCNTTYPE_FRM, /*bSelFrame=*/false);
1999 pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 2, /*bBasicCall=*/false);
2000 pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/true, 7, /*bBasicCall=*/false);
2001 pWrtShell->Delete();
2003 pWrtShell->ClearMark(); // otherwise it refuses to leave the fly...
2004 pWrtShell->SttEndDoc(true); // note: SttDoc actually moves to start of fly?
2005 pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 2, /*bBasicCall=*/false);
2006 pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/true, 7, /*bBasicCall=*/false);
2007 pWrtShell->Delete();
2009 dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
2010 CPPUNIT_ASSERT(pLayout->IsHideRedlines());
2011 discardDumpedLayout();
2012 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
2013 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/merged", "paraPropsNodeIndex", "19");
2014 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/merged",
2015 "paraPropsNodeIndex", "6");
2016 assertXPath(pXmlDoc,
2017 "/root/page[1]/body/txt[1]/anchored/fly[1]/anchored[1]/fly[1]/txt[1]/merged",
2018 "paraPropsNodeIndex", "11");
2019 assertXPath(pXmlDoc,
2020 "/root/page[1]/body/txt[1]/anchored/fly[1]/anchored[1]/fly[1]/txt[1]/Text[1]",
2021 "nType", "PortionType::Para");
2022 assertXPath(pXmlDoc,
2023 "/root/page[1]/body/txt[1]/anchored/fly[1]/anchored[1]/fly[1]/txt[1]/Text[1]",
2024 "Portion", "jqr");
2025 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Special[1]", "nType",
2026 "PortionType::Fly"); // remove???
2027 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "nType",
2028 "PortionType::Lay");
2029 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "Portion",
2030 "abhi");
2031 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Para");
2032 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "foaz");
2034 dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
2035 CPPUNIT_ASSERT(!pLayout->IsHideRedlines());
2036 discardDumpedLayout();
2037 pXmlDoc = parseLayoutDump();
2039 { // show: nothing is merged
2040 xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "//merged");
2041 xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
2042 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes));
2043 xmlXPathFreeObject(pXmlObj);
2046 assertXPath(pXmlDoc,
2047 "/root/page[1]/body/txt[1]/anchored/fly[1]/anchored[1]/fly[1]/txt[1]/Text[1]",
2048 "nType", "PortionType::Text");
2049 assertXPath(pXmlDoc,
2050 "/root/page[1]/body/txt[1]/anchored/fly[1]/anchored[1]/fly[1]/txt[1]/Text[1]",
2051 "Portion", "j");
2052 assertXPath(pXmlDoc,
2053 "/root/page[1]/body/txt[1]/anchored/fly[1]/anchored[1]/fly[1]/txt[1]/Text[2]",
2054 "nType", "PortionType::Text");
2055 assertXPath(pXmlDoc,
2056 "/root/page[1]/body/txt[1]/anchored/fly[1]/anchored[1]/fly[1]/txt[1]/Text[2]",
2057 "Portion", "kl");
2058 assertXPath(pXmlDoc,
2059 "/root/page[1]/body/txt[1]/anchored/fly[1]/anchored[1]/fly[1]/txt[2]/Text[1]",
2060 "nType", "PortionType::Para");
2061 assertXPath(pXmlDoc,
2062 "/root/page[1]/body/txt[1]/anchored/fly[1]/anchored[1]/fly[1]/txt[2]/Text[1]",
2063 "Portion", "mno");
2064 assertXPath(pXmlDoc,
2065 "/root/page[1]/body/txt[1]/anchored/fly[1]/anchored[1]/fly[1]/txt[3]/Text[1]",
2066 "nType", "PortionType::Text");
2067 assertXPath(pXmlDoc,
2068 "/root/page[1]/body/txt[1]/anchored/fly[1]/anchored[1]/fly[1]/txt[3]/Text[1]",
2069 "Portion", "p");
2070 assertXPath(pXmlDoc,
2071 "/root/page[1]/body/txt[1]/anchored/fly[1]/anchored[1]/fly[1]/txt[3]/Text[2]",
2072 "nType", "PortionType::Text");
2073 assertXPath(pXmlDoc,
2074 "/root/page[1]/body/txt[1]/anchored/fly[1]/anchored[1]/fly[1]/txt[3]/Text[2]",
2075 "Portion", "qr");
2076 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Special[1]", "nType",
2077 "PortionType::Fly"); // remove???
2078 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "nType",
2079 "PortionType::Text");
2080 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "Portion",
2081 "ab");
2082 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[2]", "nType",
2083 "PortionType::Text");
2084 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[2]", "Portion",
2085 "c");
2086 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[2]/Text[1]", "nType",
2087 "PortionType::Para");
2088 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[2]/Text[1]", "Portion",
2089 "def");
2090 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[3]/Text[1]", "nType",
2091 "PortionType::Text");
2092 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[3]/Text[1]", "Portion",
2093 "g");
2094 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[3]/Text[2]", "nType",
2095 "PortionType::Text");
2096 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[3]/Text[2]", "Portion",
2097 "hi");
2098 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Text");
2099 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "fo");
2100 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[2]", "nType", "PortionType::Text");
2101 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[2]", "Portion", "o");
2102 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[1]", "nType", "PortionType::Para");
2103 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[1]", "Portion", "bar");
2104 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[1]", "nType", "PortionType::Text");
2105 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[1]", "Portion", "b");
2106 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[2]", "nType", "PortionType::Text");
2107 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[2]", "Portion", "az");
2109 // anchor to 2nd (deleted) paragraph
2110 pWrtShell->StartOfSection();
2111 pWrtShell->Down(false, 1);
2112 anchor1.SetType(RndStdIds::FLY_AT_CHAR);
2113 anchor1.SetAnchor(pWrtShell->GetCursor()->GetPoint());
2114 pDoc->SetAttr(anchor1, *const_cast<SwFrameFormat*>(pFly1));
2116 dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
2117 CPPUNIT_ASSERT(pLayout->IsHideRedlines());
2118 discardDumpedLayout();
2119 pXmlDoc = parseLayoutDump();
2120 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/merged", "paraPropsNodeIndex", "19");
2121 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Para");
2122 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "foaz");
2124 { // hide: no anchored object shown
2125 xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "//anchored");
2126 xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
2127 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes));
2128 xmlXPathFreeObject(pXmlObj);
2131 dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
2132 CPPUNIT_ASSERT(!pLayout->IsHideRedlines());
2133 discardDumpedLayout();
2134 pXmlDoc = parseLayoutDump();
2136 { // show: nothing is merged
2137 xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "//merged");
2138 xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
2139 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes));
2140 xmlXPathFreeObject(pXmlObj);
2143 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Text");
2144 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "fo");
2145 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[2]", "nType", "PortionType::Text");
2146 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[2]", "Portion", "o");
2147 assertXPath(pXmlDoc,
2148 "/root/page[1]/body/txt[2]/anchored/fly[1]/anchored[1]/fly[1]/txt[1]/Text[1]",
2149 "nType", "PortionType::Text");
2150 assertXPath(pXmlDoc,
2151 "/root/page[1]/body/txt[2]/anchored/fly[1]/anchored[1]/fly[1]/txt[1]/Text[1]",
2152 "Portion", "j");
2153 assertXPath(pXmlDoc,
2154 "/root/page[1]/body/txt[2]/anchored/fly[1]/anchored[1]/fly[1]/txt[1]/Text[2]",
2155 "nType", "PortionType::Text");
2156 assertXPath(pXmlDoc,
2157 "/root/page[1]/body/txt[2]/anchored/fly[1]/anchored[1]/fly[1]/txt[1]/Text[2]",
2158 "Portion", "kl");
2159 assertXPath(pXmlDoc,
2160 "/root/page[1]/body/txt[2]/anchored/fly[1]/anchored[1]/fly[1]/txt[2]/Text[1]",
2161 "nType", "PortionType::Para");
2162 assertXPath(pXmlDoc,
2163 "/root/page[1]/body/txt[2]/anchored/fly[1]/anchored[1]/fly[1]/txt[2]/Text[1]",
2164 "Portion", "mno");
2165 assertXPath(pXmlDoc,
2166 "/root/page[1]/body/txt[2]/anchored/fly[1]/anchored[1]/fly[1]/txt[3]/Text[1]",
2167 "nType", "PortionType::Text");
2168 assertXPath(pXmlDoc,
2169 "/root/page[1]/body/txt[2]/anchored/fly[1]/anchored[1]/fly[1]/txt[3]/Text[1]",
2170 "Portion", "p");
2171 assertXPath(pXmlDoc,
2172 "/root/page[1]/body/txt[2]/anchored/fly[1]/anchored[1]/fly[1]/txt[3]/Text[2]",
2173 "nType", "PortionType::Text");
2174 assertXPath(pXmlDoc,
2175 "/root/page[1]/body/txt[2]/anchored/fly[1]/anchored[1]/fly[1]/txt[3]/Text[2]",
2176 "Portion", "qr");
2177 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[1]/Text[1]", "nType",
2178 "PortionType::Text");
2179 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[1]/Special[1]", "nType",
2180 "PortionType::Fly"); // remove???
2181 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[1]/Text[1]", "Portion",
2182 "ab");
2183 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[1]/Text[2]", "nType",
2184 "PortionType::Text");
2185 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[1]/Text[2]", "Portion",
2186 "c");
2187 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[2]/Text[1]", "nType",
2188 "PortionType::Para");
2189 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[2]/Text[1]", "Portion",
2190 "def");
2191 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[3]/Text[1]", "nType",
2192 "PortionType::Text");
2193 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[3]/Text[1]", "Portion",
2194 "g");
2195 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[3]/Text[2]", "nType",
2196 "PortionType::Text");
2197 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[3]/Text[2]", "Portion",
2198 "hi");
2199 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[1]", "nType", "PortionType::Para");
2200 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[1]", "Portion", "bar");
2201 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[1]", "nType", "PortionType::Text");
2202 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[1]", "Portion", "b");
2203 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[2]", "nType", "PortionType::Text");
2204 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[2]", "Portion", "az");
2207 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testRedlineSections)
2209 createSwDoc(DATA_DIRECTORY, "redline_sections.fodt");
2210 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
2211 CPPUNIT_ASSERT(pTextDoc);
2212 SwDoc* pDoc(pTextDoc->GetDocShell()->GetDoc());
2213 SwRootFrame* pLayout(pDoc->getIDocumentLayoutAccess().GetCurrentLayout());
2214 CPPUNIT_ASSERT(pLayout->IsHideRedlines());
2216 // verify after load
2217 CheckRedlineSectionsHidden();
2219 dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
2220 CPPUNIT_ASSERT(!pLayout->IsHideRedlines());
2221 // why is this needed explicitly?
2222 pDoc->getIDocumentLayoutAccess().GetCurrentViewShell()->CalcLayout();
2223 discardDumpedLayout();
2224 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
2226 // show: nothing is merged
2227 xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "//merged");
2228 xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
2229 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes));
2230 xmlXPathFreeObject(pXmlObj);
2231 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Text");
2232 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "fo");
2233 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[2]", "nType", "PortionType::Text");
2234 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[2]", "Portion", "o");
2236 assertXPath(pXmlDoc, "/root/page[1]/body/section[1]/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
2237 "nType", "PortionType::Para");
2238 assertXPath(pXmlDoc, "/root/page[1]/body/section[1]/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
2239 "Portion", "FRAME");
2240 assertXPath(pXmlDoc, "/root/page[1]/body/section[1]/txt[1]/Text[1]", "nType",
2241 "PortionType::Para");
2242 assertXPath(pXmlDoc, "/root/page[1]/body/section[1]/txt[1]/Text[1]", "Portion", "bar");
2243 assertXPath(pXmlDoc, "/root/page[1]/body/section[1]/txt[2]/Text[1]", "nType",
2244 "PortionType::Para");
2245 assertXPath(pXmlDoc, "/root/page[1]/body/section[1]/txt[2]/Text[1]", "Portion", "baz");
2246 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[1]", "nType", "PortionType::Text");
2247 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[1]", "Portion", "b");
2248 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[2]", "nType", "PortionType::Text");
2249 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[2]", "Portion", "lah");
2250 assertXPath(pXmlDoc, "/root/page[1]/body/section[2]/txt[1]/Text[1]", "nType",
2251 "PortionType::Text");
2252 assertXPath(pXmlDoc, "/root/page[1]/body/section[2]/txt[1]/Text[1]", "Portion", "fo");
2253 assertXPath(pXmlDoc, "/root/page[1]/body/section[2]/txt[1]/Text[2]", "nType",
2254 "PortionType::Text");
2255 assertXPath(pXmlDoc, "/root/page[1]/body/section[2]/txt[1]/Text[2]", "Portion", "o");
2256 assertXPath(pXmlDoc, "/root/page[1]/body/section[2]/txt[2]/Text[1]", "nType",
2257 "PortionType::Para");
2258 assertXPath(pXmlDoc, "/root/page[1]/body/section[2]/txt[2]/Text[1]", "Portion", "bar");
2259 assertXPath(pXmlDoc, "/root/page[1]/body/section[2]/txt[3]/Text[1]", "nType",
2260 "PortionType::Text");
2261 assertXPath(pXmlDoc, "/root/page[1]/body/section[2]/txt[3]/Text[1]", "Portion", "b");
2262 assertXPath(pXmlDoc, "/root/page[1]/body/section[2]/txt[3]/Text[2]", "nType",
2263 "PortionType::Text");
2264 assertXPath(pXmlDoc, "/root/page[1]/body/section[2]/txt[3]/Text[2]", "Portion", "lah");
2266 // verify after hide
2267 dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
2268 CPPUNIT_ASSERT(pLayout->IsHideRedlines());
2269 // why is this needed explicitly?
2270 pDoc->getIDocumentLayoutAccess().GetCurrentViewShell()->CalcLayout();
2271 discardDumpedLayout();
2272 CheckRedlineSectionsHidden();
2275 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, TDF69647_images)
2277 createSwDoc(DATA_DIRECTORY, "tdf69647_images.odt");
2278 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
2279 CPPUNIT_ASSERT(pTextDoc);
2280 CPPUNIT_ASSERT_EQUAL_MESSAGE("Number of pages does not match!", 2, getPages());
2283 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, TDF69647_text)
2285 createSwDoc(DATA_DIRECTORY, "tdf69647_text.docx");
2286 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
2287 CPPUNIT_ASSERT(pTextDoc);
2288 CPPUNIT_ASSERT_EQUAL_MESSAGE("Number of pages does not match!", 2, getPages());
2291 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testRedlineTables)
2293 createSwDoc(DATA_DIRECTORY, "redline_table.fodt");
2294 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
2295 CPPUNIT_ASSERT(pTextDoc);
2296 SwDoc* pDoc(pTextDoc->GetDocShell()->GetDoc());
2297 SwRootFrame* pLayout(pDoc->getIDocumentLayoutAccess().GetCurrentLayout());
2298 CPPUNIT_ASSERT(pLayout->IsHideRedlines());
2300 // verify after load
2301 discardDumpedLayout();
2302 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
2303 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/merged", "paraPropsNodeIndex", "12");
2304 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Para");
2305 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "foar");
2307 dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
2308 CPPUNIT_ASSERT(!pLayout->IsHideRedlines());
2309 // why is this needed explicitly?
2310 pDoc->getIDocumentLayoutAccess().GetCurrentViewShell()->CalcLayout();
2311 discardDumpedLayout();
2312 pXmlDoc = parseLayoutDump();
2314 // show: nothing is merged
2315 xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "//merged");
2316 xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
2317 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes));
2318 xmlXPathFreeObject(pXmlObj);
2319 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Text");
2320 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "fo");
2321 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[2]", "nType", "PortionType::Text");
2322 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[2]", "Portion", "o");
2324 assertXPath(pXmlDoc,
2325 "/root/page[1]/body/tab[1]/row[1]/cell[1]/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
2326 "nType", "PortionType::Para");
2327 assertXPath(pXmlDoc,
2328 "/root/page[1]/body/tab[1]/row[1]/cell[1]/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
2329 "Portion", "FRAME");
2330 assertXPath(pXmlDoc, "/root/page[1]/body/tab[1]/row[1]/cell[1]/txt[1]/Text[1]", "nType",
2331 "PortionType::Para");
2332 assertXPath(pXmlDoc, "/root/page[1]/body/tab[1]/row[1]/cell[1]/txt[1]/Text[1]", "Portion",
2333 "aaa");
2334 assertXPath(pXmlDoc, "/root/page[1]/body/tab[1]/row[2]/cell[2]/txt[1]/Text[1]", "nType",
2335 "PortionType::Para");
2336 assertXPath(pXmlDoc, "/root/page[1]/body/tab[1]/row[2]/cell[2]/txt[1]/Text[1]", "Portion",
2337 "ddd");
2338 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[1]", "nType", "PortionType::Text");
2339 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[1]", "Portion", "b");
2340 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[2]", "nType", "PortionType::Text");
2341 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[2]", "Portion", "ar");
2343 // verify after hide
2344 dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
2345 CPPUNIT_ASSERT(pLayout->IsHideRedlines());
2346 // why is this needed explicitly?
2347 pDoc->getIDocumentLayoutAccess().GetCurrentViewShell()->CalcLayout();
2348 discardDumpedLayout();
2349 pXmlDoc = parseLayoutDump();
2350 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/merged", "paraPropsNodeIndex", "12");
2351 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Para");
2352 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "foar");
2355 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf144057)
2357 createSwDoc(DATA_DIRECTORY, "tdf144057.fodt");
2358 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
2359 CPPUNIT_ASSERT(pTextDoc);
2360 SwDoc* pDoc(pTextDoc->GetDocShell()->GetDoc());
2361 SwRootFrame* pLayout(pDoc->getIDocumentLayoutAccess().GetCurrentLayout());
2362 CPPUNIT_ASSERT(!pLayout->IsHideRedlines());
2363 discardDumpedLayout();
2364 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
2365 // show tracked row deletions
2366 assertXPath(pXmlDoc, "/root/page", 4);
2367 assertXPath(pXmlDoc, "/root/page[1]/body/tab/row[6]/cell/txt/Text", "Portion", "A6");
2368 assertXPath(pXmlDoc, "/root/page[2]/body/tab/row[6]/cell/txt/Text", "Portion", "A12");
2369 assertXPath(pXmlDoc, "/root/page[3]/body/tab/row[6]/cell/txt/Text", "Portion", "B6");
2370 assertXPath(pXmlDoc, "/root/page[4]/body/tab/row[6]/cell/txt/Text", "Portion", "B12");
2372 // hide tracked table and table row deletions
2373 dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
2374 CPPUNIT_ASSERT(pLayout->IsHideRedlines());
2375 pDoc->getIDocumentLayoutAccess().GetCurrentViewShell()->CalcLayout();
2376 discardDumpedLayout();
2377 pXmlDoc = parseLayoutDump();
2379 // This was 4 (unhidden tracked table and table row deletions)
2380 assertXPath(pXmlDoc, "/root/page", 1);
2381 assertXPath(pXmlDoc, "/root/page[1]/body/tab", 1);
2382 assertXPath(pXmlDoc, "/root/page[1]/body/tab/row", 5);
2383 assertXPath(pXmlDoc, "/root/page[1]/body/tab/row[5]/cell/txt/Text", "Portion", "B12");
2385 // show tracked table and table row deletions again
2386 dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
2387 CPPUNIT_ASSERT(!pLayout->IsHideRedlines());
2388 pDoc->getIDocumentLayoutAccess().GetCurrentViewShell()->CalcLayout();
2389 discardDumpedLayout();
2390 pXmlDoc = parseLayoutDump();
2391 assertXPath(pXmlDoc, "/root/page", 4);
2392 assertXPath(pXmlDoc, "/root/page[1]/body/tab/row[6]/cell/txt/Text", "Portion", "A6");
2393 assertXPath(pXmlDoc, "/root/page[2]/body/tab/row[6]/cell/txt/Text", "Portion", "A12");
2394 assertXPath(pXmlDoc, "/root/page[3]/body/tab/row[6]/cell/txt/Text", "Portion", "B6");
2395 assertXPath(pXmlDoc, "/root/page[4]/body/tab/row[6]/cell/txt/Text", "Portion", "B12");
2398 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf144347)
2400 createSwDoc(DATA_DIRECTORY, "tdf144057.fodt");
2401 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
2402 CPPUNIT_ASSERT(pTextDoc);
2403 SwDoc* pDoc(pTextDoc->GetDocShell()->GetDoc());
2404 SwRootFrame* pLayout(pDoc->getIDocumentLayoutAccess().GetCurrentLayout());
2406 // enable redlining
2407 dispatchCommand(mxComponent, ".uno:TrackChanges", {});
2408 CPPUNIT_ASSERT_MESSAGE("redlining should be on",
2409 pDoc->getIDocumentRedlineAccess().IsRedlineOn());
2410 CPPUNIT_ASSERT(!pLayout->IsHideRedlines());
2412 // remove first table
2413 SwEditShell* const pEditShell(pDoc->GetEditShell());
2414 for (int i = 0; i < 12; ++i)
2415 pEditShell->AcceptRedline(0);
2417 pDoc->getIDocumentLayoutAccess().GetCurrentViewShell()->CalcLayout();
2418 discardDumpedLayout();
2419 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
2420 // show tracked row deletions
2421 assertXPath(pXmlDoc, "/root/page", 2);
2422 assertXPath(pXmlDoc, "/root/page[1]/body/tab", 1);
2424 // select all the text, including the texts before and after the table
2425 // Note: this table contains tracked changes, which was a
2426 // problem for the original OOo implementation of track changes,
2427 // resulting empty tables after accepting the deletion of these tables.
2428 dispatchCommand(mxComponent, ".uno:SelectAll", {});
2429 dispatchCommand(mxComponent, ".uno:SelectAll", {});
2430 dispatchCommand(mxComponent, ".uno:Delete", {});
2431 pDoc->getIDocumentLayoutAccess().GetCurrentViewShell()->CalcLayout();
2432 discardDumpedLayout();
2433 pXmlDoc = parseLayoutDump();
2435 // table is deleted with change tracking: it still exists
2436 assertXPath(pXmlDoc, "/root/page", 2);
2437 assertXPath(pXmlDoc, "/root/page[1]/body/tab", 1);
2439 // accept all deletions, removing the table completely
2440 while (pEditShell->GetRedlineCount() > 0)
2441 pEditShell->AcceptRedline(0);
2443 pDoc->getIDocumentLayoutAccess().GetCurrentViewShell()->CalcLayout();
2444 discardDumpedLayout();
2445 pXmlDoc = parseLayoutDump();
2447 assertXPath(pXmlDoc, "/root/page", 1);
2448 // This was 1 (bad empty table)
2449 assertXPath(pXmlDoc, "/root/page[1]/body/tab", 0);
2452 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf109137)
2454 createSwDoc(DATA_DIRECTORY, "tdf109137.docx");
2455 uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
2456 utl::TempFile aTempFile;
2457 aTempFile.EnableKillingFile();
2458 uno::Sequence<beans::PropertyValue> aDescriptor(comphelper::InitPropertySequence({
2459 { "FilterName", uno::Any(OUString("writer8")) },
2460 }));
2461 xStorable->storeToURL(aTempFile.GetURL(), aDescriptor);
2462 loadURL(aTempFile.GetURL(), "tdf109137.odt");
2463 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
2464 // This was 0, the blue rectangle moved from the 1st to the 2nd page.
2465 assertXPath(pXmlDoc, "/root/page[1]/body/txt/anchored/fly/notxt",
2466 /*nNumberOfNodes=*/1);
2469 //just care it doesn't crash/assert
2470 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testForcepoint72)
2472 createSwDoc(DATA_DIRECTORY, "forcepoint72-1.rtf");
2475 //just care it doesn't crash/assert
2476 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testForcepoint75)
2478 createSwDoc(DATA_DIRECTORY, "forcepoint75-1.rtf");
2481 // FIXME: apparently infinite loop on Mac
2482 #ifndef MACOSX
2483 //just care it doesn't crash/assert
2484 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testUXTSOREL)
2486 createSwDoc(DATA_DIRECTORY, "LIBREOFFICE-UXTSOREL.rtf");
2488 #endif
2490 //just care it doesn't crash/assert
2491 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testForcepointFootnoteFrame)
2493 createSwDoc(DATA_DIRECTORY, "forcepoint-swfootnoteframe-1.rtf");
2496 //just care it doesn't crash/assert
2497 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testForcepoint76)
2499 createSwDoc(DATA_DIRECTORY, "forcepoint76-1.rtf");
2502 //just care it doesn't crash/assert
2503 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testForcepoint89)
2505 createSwWebDoc(DATA_DIRECTORY, "forcepoint89.html");
2508 //just care it doesn't crash/assert
2509 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testForcepoint90)
2511 createSwDoc(DATA_DIRECTORY, "forcepoint90.rtf");
2514 //just care it doesn't crash/assert
2515 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testForcepoint91)
2517 createSwWebDoc(DATA_DIRECTORY, "forcepoint91.html");
2520 //just care it doesn't crash/assert
2521 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testForcepoint92)
2523 createSwDoc(DATA_DIRECTORY, "forcepoint92.doc");
2526 //just care it doesn't crash/assert
2527 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testForcepoint93)
2529 createSwDoc(DATA_DIRECTORY, "forcepoint93-1.rtf");
2530 createSwDoc(DATA_DIRECTORY, "forcepoint93-2.rtf");
2533 //just care it doesn't crash/assert
2534 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testForcepoint94)
2536 createSwWebDoc(DATA_DIRECTORY, "forcepoint94.html");
2539 //just care it doesn't crash/assert
2540 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testForcepoint98)
2542 createSwWebDoc(DATA_DIRECTORY, "forcepoint98.html");
2545 //just care it doesn't crash/assert
2546 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testForcepoint100)
2548 createSwWebDoc(DATA_DIRECTORY, "forcepoint100.html");
2551 //just care it doesn't crash/assert
2552 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testForcepoint102)
2554 createSwDoc(DATA_DIRECTORY, "forcepoint102.rtf");
2557 //just care it doesn't crash/assert
2558 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testForcepoint103)
2560 createSwWebDoc(DATA_DIRECTORY, "forcepoint103.html");
2563 //just care it doesn't crash/assert
2564 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf147485Forcepoint)
2566 createSwDoc(DATA_DIRECTORY, "tdf147485-forcepoint.doc");
2569 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf118058)
2571 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "tdf118058.fodt");
2572 // This resulted in a layout loop.
2573 pDoc->getIDocumentLayoutAccess().GetCurrentViewShell()->CalcLayout();
2576 //just care it doesn't crash/assert
2577 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testForcepoint99)
2579 createSwWebDoc(DATA_DIRECTORY, "forcepoint99.html");
2582 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf128611)
2584 createSwDoc(DATA_DIRECTORY, "tdf128611.fodt");
2585 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
2586 CPPUNIT_ASSERT(pXmlDoc);
2587 // Without the accompanying fix in place, this test would have failed with:
2588 // - Expected: 1
2589 // - Actual : 14
2590 // i.e. there were multiple portions in the first paragraph of the A1 cell, which means that the
2591 // rotated text was broken into multiple lines without a good reason.
2592 assertXPath(pXmlDoc, "//tab/row/cell[1]/txt/Text", "Portion", "Abcd efghijkl");
2595 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf125893)
2597 createSwDoc(DATA_DIRECTORY, "tdf125893.docx");
2598 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
2599 // This was 400. The paragraph must have zero top border.
2600 assertXPath(pXmlDoc, "/root/page/body/txt[4]/infos/prtBounds", "top", "0");
2603 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf134463)
2605 createSwDoc(DATA_DIRECTORY, "tdf134463.docx");
2606 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
2607 // This was 621. The previous paragraph must have zero bottom border.
2608 assertXPath(pXmlDoc, "/root/page/body/txt[3]/infos/prtBounds", "top", "21");
2611 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf117188)
2613 createSwDoc(DATA_DIRECTORY, "tdf117188.docx");
2614 uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
2615 utl::TempFile aTempFile;
2616 aTempFile.EnableKillingFile();
2617 uno::Sequence<beans::PropertyValue> aDescriptor(comphelper::InitPropertySequence({
2618 { "FilterName", uno::Any(OUString("writer8")) },
2619 }));
2620 xStorable->storeToURL(aTempFile.GetURL(), aDescriptor);
2621 loadURL(aTempFile.GetURL(), "tdf117188.odt");
2622 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
2623 OUString sWidth = getXPath(pXmlDoc, "/root/page/body/txt/anchored/fly/infos/bounds", "width");
2624 OUString sHeight = getXPath(pXmlDoc, "/root/page/body/txt/anchored/fly/infos/bounds", "height");
2625 // The text box must have zero border distances
2626 assertXPath(pXmlDoc, "/root/page/body/txt/anchored/fly/infos/prtBounds", "left", "0");
2627 assertXPath(pXmlDoc, "/root/page/body/txt/anchored/fly/infos/prtBounds", "top", "0");
2628 assertXPath(pXmlDoc, "/root/page/body/txt/anchored/fly/infos/prtBounds", "width", sWidth);
2629 assertXPath(pXmlDoc, "/root/page/body/txt/anchored/fly/infos/prtBounds", "height", sHeight);
2632 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf117187)
2634 createSwDoc(DATA_DIRECTORY, "tdf117187.odt");
2635 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
2637 // there should be no fly portions
2638 assertXPath(pXmlDoc, "/root/page/body/txt/Special[@nType='PortionType::Fly']", 0);
2641 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf119875)
2643 createSwDoc(DATA_DIRECTORY, "tdf119875.odt");
2644 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
2645 sal_Int32 nFirstTop
2646 = getXPath(pXmlDoc, "/root/page[2]/body/section[1]/infos/bounds", "top").toInt32();
2647 sal_Int32 nSecondTop
2648 = getXPath(pXmlDoc, "/root/page[2]/body/section[2]/infos/bounds", "top").toInt32();
2649 // The first section had the same top value as the second one, so they
2650 // overlapped.
2651 CPPUNIT_ASSERT_LESS(nSecondTop, nFirstTop);
2654 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf120287)
2656 createSwDoc(DATA_DIRECTORY, "tdf120287.fodt");
2657 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
2658 // This was 2, TabOverMargin Word-specific compat flag did not imply
2659 // default-in-Word printer-independent layout, resulting in an additional
2660 // line break.
2661 assertXPath(pXmlDoc, "/root/page/body/txt[1]/LineBreak", 1);
2664 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf106234)
2666 createSwDoc(DATA_DIRECTORY, "tdf106234.fodt");
2667 // Ensure that all text portions are calculated before testing.
2668 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
2669 CPPUNIT_ASSERT(pTextDoc);
2670 SwViewShell* pViewShell
2671 = pTextDoc->GetDocShell()->GetDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
2672 CPPUNIT_ASSERT(pViewShell);
2673 pViewShell->Reformat();
2675 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
2676 // In justified paragraphs, there is justification between left tabulators and manual line breaks
2677 assertXPath(pXmlDoc, "/root/page/body/txt[1]/Special", "nType", "PortionType::Margin");
2678 assertXPathNoAttribute(pXmlDoc, "/root/page/body/txt[1]/Special", "nWidth");
2679 // but not after centered, right and decimal tabulators
2680 assertXPath(pXmlDoc, "/root/page/body/txt[2]/Special", "nType", "PortionType::Margin");
2681 // This was a justified line, without nWidth
2682 assertXPath(pXmlDoc, "/root/page/body/txt[2]/Special", "nWidth", "7881");
2685 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf120287b)
2687 createSwDoc(DATA_DIRECTORY, "tdf120287b.fodt");
2688 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
2689 // This was 1418, TabOverMargin did the right split of the paragraph to two
2690 // lines, but then calculated a too large tab portion size on the first
2691 // line.
2692 assertXPath(pXmlDoc, "/root/page/body/txt[1]/Text[@nType='PortionType::TabRight']", "nWidth",
2693 "17");
2696 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf120287c)
2698 createSwDoc(DATA_DIRECTORY, "tdf120287c.fodt");
2699 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
2700 // This was 2, the second line was not broken into a 2nd and a 3rd one,
2701 // rendering text outside the paragraph frame.
2702 assertXPath(pXmlDoc, "/root/page/body/txt[1]/LineBreak", 3);
2705 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf122878)
2707 createSwDoc(DATA_DIRECTORY, "tdf122878.docx");
2708 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
2709 // FIXME: the XPath should be adjusted when the proper floating table would be imported
2710 const sal_Int32 nTblTop
2711 = getXPath(pXmlDoc, "/root/page[1]/footer/txt/anchored/fly/tab/infos/bounds", "top")
2712 .toInt32();
2713 const sal_Int32 nFirstPageParaCount
2714 = getXPathContent(pXmlDoc, "count(/root/page[1]/body/txt)").toInt32();
2715 CPPUNIT_ASSERT_EQUAL(sal_Int32(30), nFirstPageParaCount);
2716 for (sal_Int32 i = 1; i <= nFirstPageParaCount; ++i)
2718 const OString xPath = "/root/page[1]/body/txt[" + OString::number(i) + "]/infos/bounds";
2719 const sal_Int32 nTxtBottom = getXPath(pXmlDoc, xPath.getStr(), "top").toInt32()
2720 + getXPath(pXmlDoc, xPath.getStr(), "height").toInt32();
2721 // No body paragraphs should overlap the table in the footer
2722 CPPUNIT_ASSERT_MESSAGE(OString("testing paragraph #" + OString::number(i)).getStr(),
2723 nTxtBottom <= nTblTop);
2727 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf115094)
2729 createSwDoc(DATA_DIRECTORY, "tdf115094.docx");
2730 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
2732 sal_Int32 nTopOfD1
2733 = getXPath(pXmlDoc, "/root/page/body/txt/anchored/fly/tab/row[1]/cell[4]/infos/bounds",
2734 "top")
2735 .toInt32();
2736 sal_Int32 nTopOfD1Anchored = getXPath(pXmlDoc,
2737 "/root/page/body/txt/anchored/fly/tab/row[1]/cell[4]/"
2738 "txt[2]/anchored/fly/infos/bounds",
2739 "top")
2740 .toInt32();
2741 CPPUNIT_ASSERT_LESS(nTopOfD1Anchored, nTopOfD1);
2742 sal_Int32 nTopOfB2
2743 = getXPath(pXmlDoc, "/root/page/body/txt/anchored/fly/tab/row[2]/cell[2]/infos/bounds",
2744 "top")
2745 .toInt32();
2746 sal_Int32 nTopOfB2Anchored = getXPath(pXmlDoc,
2747 "/root/page/body/txt/anchored/fly/tab/row[2]/cell[2]/"
2748 "txt[1]/anchored/fly/infos/bounds",
2749 "top")
2750 .toInt32();
2751 CPPUNIT_ASSERT_LESS(nTopOfB2Anchored, nTopOfB2);
2754 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf112290)
2756 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "tdf112290.docx");
2757 CPPUNIT_ASSERT(pDoc);
2758 auto pXml = parseLayoutDump();
2759 assertXPath(pXml, "/root/page/body/txt/LineBreak[2]", "Line", "Xxxx Xxxx");
2762 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testKeepWithNextPlusFlyFollowTextFlow)
2764 createSwDoc(DATA_DIRECTORY, "keep-with-next-fly.fodt");
2767 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
2768 // 3 text frames on page 1
2769 assertXPath(pXmlDoc, "/root/page[1]/body/infos/bounds", "bottom", "7540");
2770 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/infos/bounds", "height", "276");
2771 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/infos/bounds", "height", "276");
2772 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly", 1);
2773 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly/infos/bounds", "top", "1694");
2774 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/infos/bounds", "height", "276");
2775 assertXPath(pXmlDoc, "/root/page", 1);
2776 discardDumpedLayout();
2779 dispatchCommand(mxComponent, ".uno:Fieldnames", {});
2780 Scheduler::ProcessEventsToIdle();
2783 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
2784 // 1 text frame on page 1, and some empty space
2785 assertXPath(pXmlDoc, "/root/page[1]/body/infos/bounds", "bottom", "7540");
2786 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/infos/bounds", "height", "5796");
2787 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/infos/bounds", "bottom", "7213");
2788 // 2 text frames on page 2
2789 assertXPath(pXmlDoc, "/root/page[2]/body/txt[1]/infos/bounds", "height", "276");
2790 assertXPath(pXmlDoc, "/root/page[2]/body/txt[1]/anchored/fly", 1);
2791 assertXPath(pXmlDoc, "/root/page[2]/body/txt[1]/anchored/fly/infos/bounds", "top", "10093");
2792 assertXPath(pXmlDoc, "/root/page[2]/body/txt[2]/infos/bounds", "height", "276");
2793 assertXPath(pXmlDoc, "/root/page", 2);
2794 discardDumpedLayout();
2797 dispatchCommand(mxComponent, ".uno:Fieldnames", {});
2798 Scheduler::ProcessEventsToIdle();
2801 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
2802 // 3 text frames on page 1
2803 assertXPath(pXmlDoc, "/root/page[1]/body/infos/bounds", "bottom", "7540");
2804 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/infos/bounds", "height", "276");
2805 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/infos/bounds", "height", "276");
2806 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly", 1);
2807 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly/infos/bounds", "top", "1694");
2808 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/infos/bounds", "height", "276");
2809 assertXPath(pXmlDoc, "/root/page", 1);
2810 discardDumpedLayout();
2814 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf122607)
2816 createSwDoc(DATA_DIRECTORY, "tdf122607.odt");
2817 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
2818 assertXPath(pXmlDoc,
2819 "/root/page[1]/anchored/fly/txt[1]/anchored/fly/tab/row[2]/cell/txt[7]/anchored/"
2820 "fly/txt/Text[1]",
2821 "nHeight", "253");
2822 assertXPath(pXmlDoc,
2823 "/root/page[1]/anchored/fly/txt[1]/anchored/fly/tab/row[2]/cell/txt[7]/anchored/"
2824 "fly/txt/Text[1]",
2825 "nWidth", "428");
2826 assertXPath(pXmlDoc,
2827 "/root/page[1]/anchored/fly/txt[1]/anchored/fly/tab/row[2]/cell/txt[7]/anchored/"
2828 "fly/txt/Text[1]",
2829 "Portion", "Fax:");
2832 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf122607_regression)
2834 discardDumpedLayout();
2835 if (mxComponent.is())
2836 mxComponent->dispose();
2838 OUString const pName("tdf122607_leerzeile.odt");
2840 OUString const url(m_directories.getURLFromSrc(DATA_DIRECTORY) + pName);
2842 // note: must set Hidden property, so that SfxFrameViewWindow_Impl::Resize()
2843 // does *not* forward initial VCL Window Resize and thereby triggers a
2844 // layout which does not happen on soffice --convert-to pdf.
2845 std::vector<beans::PropertyValue> aFilterOptions = {
2846 { beans::PropertyValue("Hidden", -1, uno::Any(true), beans::PropertyState_DIRECT_VALUE) },
2849 std::cout << pName << ":\n";
2851 // inline the loading because currently properties can't be passed...
2852 mxComponent = loadFromDesktop(url, "com.sun.star.text.TextDocument",
2853 comphelper::containerToSequence(aFilterOptions));
2854 uno::Sequence<beans::PropertyValue> props(comphelper::InitPropertySequence({
2855 { "FilterName", uno::Any(OUString("writer_pdf_Export")) },
2856 }));
2857 utl::TempFile aTempFile;
2858 uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
2859 xStorable->storeToURL(aTempFile.GetURL(), props);
2861 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
2862 // somehow these 2 rows overlapped in the PDF unless CalcLayout() runs
2863 assertXPath(pXmlDoc, "/root/page[1]/anchored/fly/tab[1]/row[1]/infos/bounds", "mbFixSize",
2864 "false");
2865 assertXPath(pXmlDoc, "/root/page[1]/anchored/fly/tab[1]/row[1]/infos/bounds", "top", "2977");
2866 assertXPath(pXmlDoc, "/root/page[1]/anchored/fly/tab[1]/row[1]/infos/bounds", "height", "241");
2867 assertXPath(pXmlDoc, "/root/page[1]/anchored/fly/tab[1]/row[2]/infos/bounds", "mbFixSize",
2868 "true");
2869 // this was 3034, causing the overlap
2870 assertXPath(pXmlDoc, "/root/page[1]/anchored/fly/tab[1]/row[2]/infos/bounds", "top", "3218");
2871 assertXPath(pXmlDoc, "/root/page[1]/anchored/fly/tab[1]/row[2]/infos/bounds", "height", "164");
2873 aTempFile.EnableKillingFile();
2876 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testBtlrCell)
2878 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "btlr-cell.odt");
2879 SwDocShell* pShell = pDoc->GetDocShell();
2881 // Dump the rendering of the first page as an XML file.
2882 std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
2883 MetafileXmlDump dumper;
2884 xmlDocUniquePtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
2885 CPPUNIT_ASSERT(pXmlDoc);
2887 // Without the accompanying fix in place, this test would have failed, as
2888 // the orientation was 0 (layout did not take btlr direction request from
2889 // doc model).
2890 assertXPath(pXmlDoc, "//font[1]", "orientation", "900");
2892 #if !defined(MACOSX) && !defined(_WIN32) // macOS fails with x == 2662 for some reason.
2893 // Without the accompanying fix in place, this test would have failed with 'Expected: 1915;
2894 // Actual : 1756', i.e. the AAA1 text was too close to the left cell border due to an ascent vs
2895 // descent mismatch when calculating the baseline offset of the text portion.
2896 assertXPath(pXmlDoc, "//textarray[1]", "x", "1915");
2897 assertXPath(pXmlDoc, "//textarray[1]", "y", "2707");
2899 // Without the accompanying fix in place, this test would have failed with 'Expected: 1979;
2900 // Actual : 2129', i.e. the gray background of the "AAA2." text was too close to the right edge
2901 // of the text portion. Now it's exactly behind the text portion.
2902 assertXPath(pXmlDoc, "//rect[@top='2159']", "left", "1979");
2904 // Without the accompanying fix in place, this test would have failed with 'Expected: 269;
2905 // Actual : 0', i.e. the AAA2 frame was not visible due to 0 width.
2906 pXmlDoc = parseLayoutDump();
2907 assertXPath(pXmlDoc, "/root/page/body/tab/row/cell[1]/txt[2]/infos/bounds", "width", "269");
2909 // Test the position of the cursor after doc load.
2910 // We expect that it's inside the first text frame in the first cell.
2911 // More precisely, this is a bottom to top vertical frame, so we expect it's at the start, which
2912 // means it's at the lower half of the text frame rectangle (vertically).
2913 SwWrtShell* pWrtShell = pShell->GetWrtShell();
2914 CPPUNIT_ASSERT(pWrtShell);
2916 const SwRect& rCharRect = pWrtShell->GetCharRect();
2917 SwTwips nFirstParaTop
2918 = getXPath(pXmlDoc, "/root/page/body/tab/row/cell[1]/txt[1]/infos/bounds", "top").toInt32();
2919 SwTwips nFirstParaHeight
2920 = getXPath(pXmlDoc, "/root/page/body/tab/row/cell[1]/txt[1]/infos/bounds", "height")
2921 .toInt32();
2922 SwTwips nFirstParaMiddle = nFirstParaTop + nFirstParaHeight / 2;
2923 SwTwips nFirstParaBottom = nFirstParaTop + nFirstParaHeight;
2924 // Without the accompanying fix in place, this test would have failed: the lower half (vertical)
2925 // range was 2273 -> 2835, the good vertical position is 2730, the bad one was 1830.
2926 CPPUNIT_ASSERT_GREATER(nFirstParaMiddle, rCharRect.Top());
2927 CPPUNIT_ASSERT_LESS(nFirstParaBottom, rCharRect.Top());
2929 // Save initial cursor position.
2930 SwPosition aCellStart = *pWrtShell->GetCursor()->Start();
2932 // Test that pressing "up" at the start of the cell goes to the next character position.
2933 SwNodeOffset nNodeIndex = pWrtShell->GetCursor()->Start()->nNode.GetIndex();
2934 sal_Int32 nIndex = pWrtShell->GetCursor()->Start()->nContent.GetIndex();
2935 KeyEvent aKeyEvent(0, KEY_UP);
2936 SwEditWin& rEditWin = pShell->GetView()->GetEditWin();
2937 rEditWin.KeyInput(aKeyEvent);
2938 Scheduler::ProcessEventsToIdle();
2939 // Without the accompanying fix in place, this test would have failed: "up" was interpreted as
2940 // logical "left", which does nothing if you're at the start of the text anyway.
2941 CPPUNIT_ASSERT_EQUAL(nIndex + 1, pWrtShell->GetCursor()->Start()->nContent.GetIndex());
2943 // Test that pressing "right" goes to the next paragraph (logical "down").
2944 sal_Int32 nContentIndex = pWrtShell->GetCursor()->Start()->nContent.GetIndex();
2945 aKeyEvent = KeyEvent(0, KEY_RIGHT);
2946 rEditWin.KeyInput(aKeyEvent);
2947 Scheduler::ProcessEventsToIdle();
2948 // Without the accompanying fix in place, this test would have failed: the cursor went to the
2949 // paragraph after the table.
2950 CPPUNIT_ASSERT_EQUAL(nNodeIndex + 1, pWrtShell->GetCursor()->Start()->nNode.GetIndex());
2952 // Test that we have the correct character index after traveling to the next paragraph.
2953 // Without the accompanying fix in place, this test would have failed: char position was 5, i.e.
2954 // the cursor jumped to the end of the paragraph for no reason.
2955 CPPUNIT_ASSERT_EQUAL(nContentIndex, pWrtShell->GetCursor()->Start()->nContent.GetIndex());
2957 // Test that clicking "below" the second paragraph positions the cursor at the start of the
2958 // second paragraph.
2959 SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
2960 SwPosition aPosition(aCellStart);
2961 SwTwips nSecondParaLeft
2962 = getXPath(pXmlDoc, "/root/page/body/tab/row/cell[1]/txt[2]/infos/bounds", "left")
2963 .toInt32();
2964 SwTwips nSecondParaWidth
2965 = getXPath(pXmlDoc, "/root/page/body/tab/row/cell[1]/txt[2]/infos/bounds", "width")
2966 .toInt32();
2967 SwTwips nSecondParaTop
2968 = getXPath(pXmlDoc, "/root/page/body/tab/row/cell[1]/txt[2]/infos/bounds", "top").toInt32();
2969 SwTwips nSecondParaHeight
2970 = getXPath(pXmlDoc, "/root/page/body/tab/row/cell[1]/txt[2]/infos/bounds", "height")
2971 .toInt32();
2972 Point aPoint;
2973 aPoint.setX(nSecondParaLeft + nSecondParaWidth / 2);
2974 aPoint.setY(nSecondParaTop + nSecondParaHeight - 100);
2975 SwCursorMoveState aState(CursorMoveState::NONE);
2976 pLayout->GetModelPositionForViewPoint(&aPosition, aPoint, &aState);
2977 CPPUNIT_ASSERT_EQUAL(aCellStart.nNode.GetIndex() + 1, aPosition.nNode.GetIndex());
2978 // Without the accompanying fix in place, this test would have failed: character position was 5,
2979 // i.e. cursor was at the end of the paragraph.
2980 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0), aPosition.nContent.GetIndex());
2982 // Test that the selection rectangles are inside the cell frame if we select all the cell
2983 // content.
2984 SwTwips nCellLeft
2985 = getXPath(pXmlDoc, "/root/page/body/tab/row/cell[1]/infos/bounds", "left").toInt32();
2986 SwTwips nCellWidth
2987 = getXPath(pXmlDoc, "/root/page/body/tab/row/cell[1]/infos/bounds", "width").toInt32();
2988 SwTwips nCellTop
2989 = getXPath(pXmlDoc, "/root/page/body/tab/row/cell[1]/infos/bounds", "top").toInt32();
2990 SwTwips nCellHeight
2991 = getXPath(pXmlDoc, "/root/page/body/tab/row/cell[1]/infos/bounds", "height").toInt32();
2992 SwRect aCellRect(Point(nCellLeft, nCellTop), Size(nCellWidth, nCellHeight));
2993 pWrtShell->SelAll();
2994 SwShellCursor* pShellCursor = pWrtShell->getShellCursor(/*bBlock=*/false);
2995 CPPUNIT_ASSERT(!pShellCursor->empty());
2996 // Without the accompanying fix in place, this test would have failed with:
2997 // selection rectangle 269x2573@(1970,2172) is not inside cell rectangle 3207x1134@(1593,1701)
2998 // i.e. the selection went past the bottom border of the cell frame.
2999 for (const auto& rRect : *pShellCursor)
3001 std::stringstream ss;
3002 ss << "selection rectangle " << rRect << " is not inside cell rectangle " << aCellRect;
3003 CPPUNIT_ASSERT_MESSAGE(ss.str(), aCellRect.Contains(rRect));
3006 // Make sure that the correct rectangle gets repainted on scroll.
3007 SwFrame* pPageFrame = pLayout->GetLower();
3008 CPPUNIT_ASSERT(pPageFrame->IsPageFrame());
3010 SwFrame* pBodyFrame = pPageFrame->GetLower();
3011 CPPUNIT_ASSERT(pBodyFrame->IsBodyFrame());
3013 SwFrame* pTabFrame = pBodyFrame->GetLower();
3014 CPPUNIT_ASSERT(pTabFrame->IsTabFrame());
3016 SwFrame* pRowFrame = pTabFrame->GetLower();
3017 CPPUNIT_ASSERT(pRowFrame->IsRowFrame());
3019 SwFrame* pCellFrame = pRowFrame->GetLower();
3020 CPPUNIT_ASSERT(pCellFrame->IsCellFrame());
3022 SwFrame* pFrame = pCellFrame->GetLower();
3023 CPPUNIT_ASSERT(pFrame->IsTextFrame());
3025 SwTextFrame* pTextFrame = static_cast<SwTextFrame*>(pFrame);
3026 pTextFrame->SwapWidthAndHeight();
3027 // Mimic what normally SwTextFrame::PaintSwFrame() does:
3028 SwRect aRect(4207, 2273, 269, 572);
3029 pTextFrame->SwitchVerticalToHorizontal(aRect);
3030 // Without the accompanying fix in place, this test would have failed with:
3031 // Expected: 572x269@(1691,4217)
3032 // Actual : 572x269@(2263,4217)
3033 // i.e. the paint rectangle position was incorrect, text was not painted on scrolling up.
3034 CPPUNIT_ASSERT_EQUAL(SwRect(1691, 4217, 572, 269), aRect);
3035 #endif
3038 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf123898)
3040 createSwDoc(DATA_DIRECTORY, "tdf123898.odt");
3042 // Make sure spellchecker has done its job already
3043 Scheduler::ProcessEventsToIdle();
3045 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
3046 // Make sure that the arrow on the left is not there (there are 44 children if it's there)
3047 assertXPathChildren(pXmlDoc, "/root/page/body/txt/anchored/fly/txt", 43);
3050 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf123651)
3052 createSwDoc(DATA_DIRECTORY, "tdf123651.docx");
3053 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
3054 // Without the accompanying fix in place, this test would have failed with 'Expected: 7639;
3055 // Actual: 12926'. The shape was below the second "Lorem ipsum" text, not above it.
3056 const sal_Int32 nTopValue
3057 = getXPath(pXmlDoc, "//anchored/SwAnchoredDrawObject/bounds", "top").toInt32();
3058 CPPUNIT_ASSERT_DOUBLES_EQUAL(7639, nTopValue, 10);
3061 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf116501)
3063 //just care it doesn't freeze
3064 createSwDoc(DATA_DIRECTORY, "tdf116501.odt");
3067 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testAbi11870)
3069 //just care it doesn't assert
3070 createSwDoc(DATA_DIRECTORY, "abi11870-2.odt");
3073 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf118719)
3075 // Insert a page break.
3076 SwDoc* pDoc = createSwDoc();
3077 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
3079 // Enable hide whitespace mode.
3080 SwViewOption aViewOptions(*pWrtShell->GetViewOptions());
3081 aViewOptions.SetHideWhitespaceMode(true);
3082 pWrtShell->ApplyViewOptions(aViewOptions);
3084 pWrtShell->Insert("first");
3085 pWrtShell->InsertPageBreak();
3086 pWrtShell->Insert("second");
3088 // Without the accompanying fix in place, this test would have failed, as the height of the
3089 // first page was 15840 twips, instead of the much smaller 276.
3090 sal_Int32 nOther = parseDump("/root/page[1]/infos/bounds", "height").toInt32();
3091 sal_Int32 nLast = parseDump("/root/page[2]/infos/bounds", "height").toInt32();
3092 CPPUNIT_ASSERT_GREATER(nOther, nLast);
3095 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTabOverMargin)
3097 createSwDoc(DATA_DIRECTORY, "tab-over-margin.odt");
3098 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
3100 // 2nd paragraph has a tab over the right margin, and with the TabOverMargin compat option,
3101 // there is enough space to have all content in a single line.
3102 // Without the accompanying fix in place, this test would have failed, there were 2 lines.
3103 assertXPath(pXmlDoc, "/root/page/body/txt[2]/LineBreak", 1);
3106 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testImageComment)
3108 // Load a document that has "aaa" in it, then a commented image (4th char is the as-char image,
3109 // 5th char is the comment anchor).
3110 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "image-comment.odt");
3111 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
3113 // Look up a layout position which is on the right of the image.
3114 SwRootFrame* pRoot = pWrtShell->GetLayout();
3115 CPPUNIT_ASSERT(pRoot->GetLower()->IsPageFrame());
3116 SwPageFrame* pPage = static_cast<SwPageFrame*>(pRoot->GetLower());
3117 CPPUNIT_ASSERT(pPage->GetLower()->IsBodyFrame());
3118 SwBodyFrame* pBody = static_cast<SwBodyFrame*>(pPage->GetLower());
3119 CPPUNIT_ASSERT(pBody->GetLower()->IsTextFrame());
3120 SwTextFrame* pTextFrame = static_cast<SwTextFrame*>(pBody->GetLower());
3121 CPPUNIT_ASSERT(pTextFrame->GetDrawObjs());
3122 SwSortedObjs& rDrawObjs = *pTextFrame->GetDrawObjs();
3123 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rDrawObjs.size());
3124 SwAnchoredObject* pDrawObj = rDrawObjs[0];
3125 const SwRect& rDrawObjRect = pDrawObj->GetObjRect();
3126 Point aPoint = rDrawObjRect.Center();
3127 aPoint.setX(aPoint.getX() + rDrawObjRect.Width() / 2);
3129 // Ask for the doc model pos of this layout point.
3130 SwPosition aPosition(*pTextFrame->GetTextNodeForFirstText());
3131 pTextFrame->GetModelPositionForViewPoint(&aPosition, aPoint);
3133 // Without the accompanying fix in place, this test would have failed with:
3134 // - Expected: 5
3135 // - Actual : 4
3136 // i.e. the cursor got positioned between the image and its comment, so typing extended the
3137 // comment, instead of adding content after the commented image.
3138 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(5), aPosition.nContent.GetIndex());
3141 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testScriptField)
3143 // Test clicking script field inside table ( tdf#141079 )
3144 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "tdf141079.odt");
3145 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
3147 // Look up layout position which is the first cell in the table
3148 SwRootFrame* pRoot = pWrtShell->GetLayout();
3149 CPPUNIT_ASSERT(pRoot->GetLower()->IsPageFrame());
3150 SwPageFrame* pPage = static_cast<SwPageFrame*>(pRoot->GetLower());
3151 CPPUNIT_ASSERT(pPage->GetLower()->IsBodyFrame());
3152 SwBodyFrame* pBody = static_cast<SwBodyFrame*>(pPage->GetLower());
3153 CPPUNIT_ASSERT(pBody->GetLower()->IsTextFrame());
3154 SwTextFrame* pTextFrame = static_cast<SwTextFrame*>(pBody->GetLower());
3155 CPPUNIT_ASSERT(pTextFrame->GetNext()->IsTabFrame());
3156 SwFrame* pTable = pTextFrame->GetNext();
3157 SwFrame* pRow1 = pTable->GetLower();
3158 CPPUNIT_ASSERT(pRow1->GetLower()->IsCellFrame());
3159 SwFrame* pCell1 = pRow1->GetLower();
3160 CPPUNIT_ASSERT(pCell1->GetLower()->IsTextFrame());
3161 SwTextFrame* pCellTextFrame = static_cast<SwTextFrame*>(pCell1->GetLower());
3162 const SwRect& rCellRect = pCell1->getFrameArea();
3163 Point aPoint = rCellRect.Center();
3164 aPoint.setX(aPoint.getX() - rCellRect.Width() / 2);
3166 // Ask for the doc model pos of this layout point.
3167 SwPosition aPosition(*pCellTextFrame->GetTextNodeForFirstText());
3168 pCellTextFrame->GetModelPositionForViewPoint(&aPosition, aPoint);
3170 // Position was 1 without the fix from tdf#141079
3171 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0), aPosition.nContent.GetIndex());
3174 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testCommentCursorPosition)
3176 // Load a document that has "aaa" in it, followed by three comments.
3177 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "endOfLineComments.odt");
3178 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
3180 SwRootFrame* pRoot = pWrtShell->GetLayout();
3181 CPPUNIT_ASSERT(pRoot->GetLower()->IsPageFrame());
3182 SwPageFrame* pPage = static_cast<SwPageFrame*>(pRoot->GetLower());
3183 CPPUNIT_ASSERT(pPage->GetLower()->IsBodyFrame());
3184 SwBodyFrame* pBody = static_cast<SwBodyFrame*>(pPage->GetLower());
3185 CPPUNIT_ASSERT(pBody->GetLower()->IsTextFrame());
3186 SwTextFrame* pTextFrame = static_cast<SwTextFrame*>(pBody->GetLower());
3188 // Set a point in the whitespace past the end of the first line.
3189 Point aPoint = pWrtShell->getShellCursor(false)->GetSttPos();
3190 aPoint.setX(aPoint.getX() + 10000);
3192 // Ask for the doc model pos of this layout point.
3193 SwPosition aPosition(*pTextFrame->GetTextNodeForFirstText());
3194 pTextFrame->GetModelPositionForViewPoint(&aPosition, aPoint);
3196 // Without the accompanying fix in place, this test would have failed with:
3197 // - Expected: 6
3198 // - Actual : 3 or 4
3199 // i.e. the cursor got positioned before the comments,
3200 // so typing extended the first comment instead of adding content after the comments.
3201 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(6), aPosition.nContent.GetIndex());
3202 // The second line is also important, but can't be auto-tested
3203 // since the failing situation depends on GetViewWidth which is zero in the headless tests.
3204 // bb<comment>| - the cursor should move behind the |, not before it.
3207 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testCombiningCharacterCursorPosition)
3209 // Load a document that has "a" in it, followed by a combining acute in a separate rext span
3210 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "tdf138592-a-acute.fodt");
3211 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
3213 SwRootFrame* pRoot = pWrtShell->GetLayout();
3214 CPPUNIT_ASSERT(pRoot->GetLower()->IsPageFrame());
3215 SwPageFrame* pPage = static_cast<SwPageFrame*>(pRoot->GetLower());
3216 CPPUNIT_ASSERT(pPage->GetLower()->IsBodyFrame());
3217 SwBodyFrame* pBody = static_cast<SwBodyFrame*>(pPage->GetLower());
3218 CPPUNIT_ASSERT(pBody->GetLower()->IsTextFrame());
3219 SwTextFrame* pTextFrame = static_cast<SwTextFrame*>(pBody->GetLower());
3221 // Set a point in the whitespace past the end of the first line.
3222 Point aPoint = pWrtShell->getShellCursor(false)->GetSttPos();
3223 aPoint.AdjustX(10000);
3225 // Ask for the doc model pos of this layout point.
3226 SwPosition aPosition(*pTextFrame->GetTextNodeForFirstText());
3227 pTextFrame->GetModelPositionForViewPoint(&aPosition, aPoint);
3229 // Without the accompanying fix in place, this test would have failed with:
3230 // - Expected: 2
3231 // - Actual : 1
3232 // i.e. the cursor got positioned before the acute, so typing shifted the acute (applying it
3233 // to newly typed characters) instead of adding content after it.
3234 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), aPosition.nContent.GetIndex());
3237 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf64222)
3239 createSwDoc(DATA_DIRECTORY, "tdf64222.docx");
3240 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
3241 assertXPath(pXmlDoc, "/root/page/body/txt[2]/Special", "nHeight", "560");
3244 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf113014)
3246 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "tdf113014.fodt");
3247 SwDocShell* pShell = pDoc->GetDocShell();
3249 // Dump the rendering of the first page as an XML file.
3250 std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
3251 MetafileXmlDump dumper;
3252 xmlDocUniquePtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
3253 CPPUNIT_ASSERT(pXmlDoc);
3255 // This failed, if numbering of cell A1 is missing
3256 // (A1: left indent: 3 cm, first line indent: -3 cm
3257 // A2: left indent: 0 cm, first line indent: 0 cm)
3258 assertXPathContent(pXmlDoc, "/metafile/push[1]/push[1]/push[1]/textarray[1]/text", "1.");
3259 assertXPathContent(pXmlDoc, "/metafile/push[1]/push[1]/push[1]/textarray[3]/text", "2.");
3260 assertXPathContent(pXmlDoc, "/metafile/push[1]/push[1]/push[1]/textarray[5]/text", "3.");
3263 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf130218)
3265 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "tdf130218.fodt");
3266 SwDocShell* pShell = pDoc->GetDocShell();
3268 // Dump the rendering of the first page as an XML file.
3269 std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
3270 MetafileXmlDump dumper;
3272 xmlDocUniquePtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
3273 CPPUNIT_ASSERT(pXmlDoc);
3275 // This failed, if hanging first line was hidden
3276 assertXPathContent(pXmlDoc, "/metafile/push[1]/push[1]/push[1]/textarray[1]/text", "Text");
3279 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf127235)
3281 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "tdf127235.odt");
3282 // This resulted in a layout loop.
3283 pDoc->getIDocumentLayoutAccess().GetCurrentViewShell()->CalcLayout();
3286 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf138039)
3288 createSwDoc(DATA_DIRECTORY, "tdf138039.odt");
3290 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
3292 // there are 3 pages
3293 assertXPath(pXmlDoc, "/root/page", 3);
3294 // table on first page
3295 assertXPath(pXmlDoc, "/root/page[1]/body/tab", 1);
3296 assertXPath(pXmlDoc, "/root/page[1]/body/txt", 0);
3297 // paragraph with large fly on second page
3298 assertXPath(pXmlDoc, "/root/page[2]/body/tab", 0);
3299 assertXPath(pXmlDoc, "/root/page[2]/body/txt", 1);
3300 assertXPath(pXmlDoc, "/root/page[2]/body/txt[1]/anchored/fly", 1);
3301 assertXPath(pXmlDoc, "/root/page[2]/body/txt[1]/anchored/fly[1]/infos/bounds", "top", "17915");
3302 assertXPath(pXmlDoc, "/root/page[2]/body/txt[1]/anchored/fly[1]/infos/bounds", "height",
3303 "15819");
3304 // paragraph on third page
3305 assertXPath(pXmlDoc, "/root/page[3]/body/tab", 0);
3306 assertXPath(pXmlDoc, "/root/page[3]/body/txt", 1);
3307 assertXPath(pXmlDoc, "/root/page[3]/body/txt[1]/anchored", 0);
3310 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf134298)
3312 createSwDoc(DATA_DIRECTORY, "tdf134298.ott");
3314 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
3316 // there are 2 pages
3317 assertXPath(pXmlDoc, "/root/page", 2);
3318 // table and first para on first page
3319 assertXPath(pXmlDoc, "/root/page[1]/body/tab", 1);
3320 assertXPath(pXmlDoc, "/root/page[1]/body/txt", 1);
3321 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored", 0);
3322 // paragraph with large fly on second page
3323 assertXPath(pXmlDoc, "/root/page[2]/body/tab", 0);
3324 assertXPath(pXmlDoc, "/root/page[2]/body/txt", 1);
3325 assertXPath(pXmlDoc, "/root/page[2]/body/txt[1]/anchored/fly", 1);
3326 assertXPath(pXmlDoc, "/root/page[2]/body/txt[1]/anchored/fly[1]/infos/bounds", "top", "17897");
3327 assertXPath(pXmlDoc, "/root/page[2]/body/txt[1]/anchored/fly[1]/infos/bounds", "height",
3328 "15819");
3331 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testShapeAllowOverlap)
3333 // Need to find out why this fails on macOS and why this is unstable on Windows.
3334 #if !defined(MACOSX) && !defined(_WIN32)
3335 // Create an empty document with two, intentionally overlapping shapes.
3336 // Set their AllowOverlap property to false.
3337 loadURL("private:factory/swriter", nullptr);
3338 uno::Reference<lang::XMultiServiceFactory> xDocument(mxComponent, uno::UNO_QUERY);
3339 awt::Point aPoint(1000, 1000);
3340 awt::Size aSize(2000, 2000);
3341 uno::Reference<drawing::XShape> xShape(
3342 xDocument->createInstance("com.sun.star.drawing.RectangleShape"), uno::UNO_QUERY);
3343 xShape->setPosition(aPoint);
3344 xShape->setSize(aSize);
3345 uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(xDocument, uno::UNO_QUERY);
3346 uno::Reference<beans::XPropertySet> xShapeProperties(xShape, uno::UNO_QUERY);
3347 xShapeProperties->setPropertyValue("AllowOverlap", uno::makeAny(false));
3348 xShapeProperties->setPropertyValue("AnchorType",
3349 uno::makeAny(text::TextContentAnchorType_AT_CHARACTER));
3350 xDrawPageSupplier->getDrawPage()->add(xShape);
3352 aPoint = awt::Point(2000, 2000);
3353 xShape.set(xDocument->createInstance("com.sun.star.drawing.RectangleShape"), uno::UNO_QUERY);
3354 xShape->setPosition(aPoint);
3355 xShape->setSize(aSize);
3356 xShapeProperties.set(xShape, uno::UNO_QUERY);
3357 xShapeProperties->setPropertyValue("AllowOverlap", uno::makeAny(false));
3358 xShapeProperties->setPropertyValue("AnchorType",
3359 uno::makeAny(text::TextContentAnchorType_AT_CHARACTER));
3360 xDrawPageSupplier->getDrawPage()->add(xShape);
3362 // Now verify that the rectangle of the anchored objects don't overlap.
3363 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
3364 CPPUNIT_ASSERT(pTextDoc);
3365 SwDoc* pDoc = pTextDoc->GetDocShell()->GetDoc();
3366 SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
3367 SwFrame* pPageFrame = pLayout->GetLower();
3368 SwFrame* pBodyFrame = pPageFrame->GetLower();
3369 SwFrame* pTextFrame = pBodyFrame->GetLower();
3370 CPPUNIT_ASSERT(pTextFrame->GetDrawObjs());
3371 SwSortedObjs& rObjs = *pTextFrame->GetDrawObjs();
3372 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), rObjs.size());
3373 SwAnchoredObject* pFirst = rObjs[0];
3374 SwAnchoredObject* pSecond = rObjs[1];
3375 // Without the accompanying fix in place, this test would have failed: the layout dump was
3376 // <bounds left="1984" top="1984" width="1137" height="1137"/>
3377 // <bounds left="2551" top="2551" width="1137" height="1137"/>
3378 // so there was a clear vertical overlap. (Allow for 1px tolerance.)
3379 OString aMessage = "Unexpected overlap: first shape's bottom is "
3380 + OString::number(pFirst->GetObjRect().Bottom()) + ", second shape's top is "
3381 + OString::number(pSecond->GetObjRect().Top());
3382 CPPUNIT_ASSERT_MESSAGE(aMessage.getStr(),
3383 std::abs(pFirst->GetObjRect().Bottom() - pSecond->GetObjRect().Top())
3384 < 15);
3385 #endif
3388 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testShapeAllowOverlapWrap)
3390 // Create an empty document with two, intentionally overlapping shapes.
3391 // Set their AllowOverlap property to false and their wrap to through.
3392 loadURL("private:factory/swriter", nullptr);
3393 uno::Reference<lang::XMultiServiceFactory> xDocument(mxComponent, uno::UNO_QUERY);
3394 awt::Point aPoint(1000, 1000);
3395 awt::Size aSize(2000, 2000);
3396 uno::Reference<drawing::XShape> xShape(
3397 xDocument->createInstance("com.sun.star.drawing.RectangleShape"), uno::UNO_QUERY);
3398 xShape->setPosition(aPoint);
3399 xShape->setSize(aSize);
3400 uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(xDocument, uno::UNO_QUERY);
3401 uno::Reference<beans::XPropertySet> xShapeProperties(xShape, uno::UNO_QUERY);
3402 xShapeProperties->setPropertyValue("AllowOverlap", uno::makeAny(false));
3403 xShapeProperties->setPropertyValue("AnchorType",
3404 uno::makeAny(text::TextContentAnchorType_AT_CHARACTER));
3405 xShapeProperties->setPropertyValue("Surround", uno::makeAny(text::WrapTextMode_THROUGH));
3406 xDrawPageSupplier->getDrawPage()->add(xShape);
3408 aPoint = awt::Point(2000, 2000);
3409 xShape.set(xDocument->createInstance("com.sun.star.drawing.RectangleShape"), uno::UNO_QUERY);
3410 xShape->setPosition(aPoint);
3411 xShape->setSize(aSize);
3412 xShapeProperties.set(xShape, uno::UNO_QUERY);
3413 xShapeProperties->setPropertyValue("AllowOverlap", uno::makeAny(false));
3414 xShapeProperties->setPropertyValue("AnchorType",
3415 uno::makeAny(text::TextContentAnchorType_AT_CHARACTER));
3416 xShapeProperties->setPropertyValue("Surround", uno::makeAny(text::WrapTextMode_THROUGH));
3417 xDrawPageSupplier->getDrawPage()->add(xShape);
3419 // Now verify that the rectangle of the anchored objects do overlap.
3420 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
3421 CPPUNIT_ASSERT(pTextDoc);
3422 SwDoc* pDoc = pTextDoc->GetDocShell()->GetDoc();
3423 SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
3424 SwFrame* pPageFrame = pLayout->GetLower();
3425 SwFrame* pBodyFrame = pPageFrame->GetLower();
3426 SwFrame* pTextFrame = pBodyFrame->GetLower();
3427 CPPUNIT_ASSERT(pTextFrame->GetDrawObjs());
3428 SwSortedObjs& rObjs = *pTextFrame->GetDrawObjs();
3429 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), rObjs.size());
3430 SwAnchoredObject* pFirst = rObjs[0];
3431 SwAnchoredObject* pSecond = rObjs[1];
3432 // Without the accompanying fix in place, this test would have failed: AllowOverlap=no had
3433 // priority over Surround=through (which is bad for Word compat).
3434 CPPUNIT_ASSERT(pSecond->GetObjRect().Overlaps(pFirst->GetObjRect()));
3437 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf124600)
3439 createSwDoc(DATA_DIRECTORY, "tdf124600.docx");
3440 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
3442 // Without the accompanying fix in place, this test would have failed with:
3443 // - Expected: 1
3444 // - Actual : 2
3445 // i.e. the last line in the body text had 2 lines, while it should have 1, as Word does (as the
3446 // fly frame does not intersect with the print area of the paragraph.)
3447 assertXPath(pXmlDoc, "/root/page/body/txt[2]/LineBreak", 1);
3450 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf124601)
3452 // This is a testcase for the ContinuousEndnotes compat flag.
3453 // The document has 2 pages, the endnote anchor is on the first page.
3454 // The endnote should be on the 2nd page together with the last page content.
3455 createSwDoc(DATA_DIRECTORY, "tdf124601.doc");
3456 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
3458 // Without the accompanying fix in place, this test would have failed with:
3459 // - Expected: 2
3460 // - Actual : 3
3461 // i.e. there was a separate endnote page, even when the ContinuousEndnotes compat option was
3462 // on.
3463 assertXPath(pXmlDoc, "/root/page", 2);
3464 assertXPath(pXmlDoc, "/root/page[2]/ftncont", 1);
3467 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf124601b)
3469 // Table has an image, which is anchored in the first row, but its vertical position is large
3470 // enough to be rendered in the second row.
3471 // The shape has layoutInCell=1, so should match what Word does here.
3472 // Also the horizontal position should be in the last column, even if the anchor is in the
3473 // last-but-one column.
3474 createSwDoc(DATA_DIRECTORY, "tdf124601b.doc");
3475 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
3477 sal_Int32 nFlyTop = getXPath(pXmlDoc, "//anchored/fly/infos/bounds", "top").toInt32();
3478 sal_Int32 nFlyLeft = getXPath(pXmlDoc, "//anchored/fly/infos/bounds", "left").toInt32();
3479 sal_Int32 nFlyRight
3480 = nFlyLeft + getXPath(pXmlDoc, "//anchored/fly/infos/bounds", "width").toInt32();
3481 sal_Int32 nSecondRowTop = getXPath(pXmlDoc, "//tab/row[2]/infos/bounds", "top").toInt32();
3482 sal_Int32 nLastCellLeft
3483 = getXPath(pXmlDoc, "//tab/row[1]/cell[5]/infos/bounds", "left").toInt32();
3484 sal_Int32 nLastCellRight
3485 = nLastCellLeft + getXPath(pXmlDoc, "//tab/row[1]/cell[5]/infos/bounds", "width").toInt32();
3486 // Without the accompanying fix in place, this test would have failed with:
3487 // - Expected greater than: 3736
3488 // - Actual : 2852
3489 // i.e. the image was still inside the first row.
3490 CPPUNIT_ASSERT_GREATER(nSecondRowTop, nFlyTop);
3492 // Without the accompanying fix in place, this test would have failed with:
3493 // - Expected greater than: 9640
3494 // - Actual : 9639
3495 // i.e. the right edge of the image was not within the bounds of the last column, the right edge
3496 // was in the last-but-one column.
3497 CPPUNIT_ASSERT_GREATER(nLastCellLeft, nFlyRight);
3498 CPPUNIT_ASSERT_LESS(nLastCellRight, nFlyRight);
3501 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf124770)
3503 // Enable content over margin.
3504 SwDoc* pDoc = createSwDoc();
3505 pDoc->getIDocumentSettingAccess().set(DocumentSettingId::TAB_OVER_MARGIN, true);
3507 // Set page width.
3508 SwPageDesc& rPageDesc = pDoc->GetPageDesc(0);
3509 SwFrameFormat& rPageFormat = rPageDesc.GetMaster();
3510 const SwAttrSet& rPageSet = rPageFormat.GetAttrSet();
3511 SwFormatFrameSize aPageSize = rPageSet.GetFrameSize();
3512 aPageSize.SetWidth(3703);
3513 rPageFormat.SetFormatAttr(aPageSize);
3515 // Set left and right margin.
3516 SvxLRSpaceItem aLRSpace = rPageSet.GetLRSpace();
3517 aLRSpace.SetLeft(1418);
3518 aLRSpace.SetRight(1418);
3519 rPageFormat.SetFormatAttr(aLRSpace);
3520 pDoc->ChgPageDesc(0, rPageDesc);
3522 // Set font to italic 20pt Liberation Serif.
3523 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
3524 SfxItemSet aTextSet(pWrtShell->GetView().GetPool(),
3525 svl::Items<RES_CHRATR_BEGIN, RES_CHRATR_END - 1>);
3526 SvxFontItem aFont(RES_CHRATR_FONT);
3527 aFont.SetFamilyName("Liberation Serif");
3528 aTextSet.Put(aFont);
3529 SvxFontHeightItem aHeight(400, 100, RES_CHRATR_FONTSIZE);
3530 aTextSet.Put(aHeight);
3531 SvxPostureItem aItalic(ITALIC_NORMAL, RES_CHRATR_POSTURE);
3532 aTextSet.Put(aItalic);
3533 pWrtShell->SetAttrSet(aTextSet);
3535 // Insert the text.
3536 pWrtShell->Insert2("HHH");
3538 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
3539 // Without the accompanying fix in place, this test would have failed with:
3540 // - Expected: 1
3541 // - Actual : 2
3542 // i.e. the italic string was broken into 2 lines, while Word kept it in a single line.
3543 assertXPath(pXmlDoc, "/root/page/body/txt[1]/LineBreak", 1);
3546 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testContinuousEndnotesInsertPageAtStart)
3548 // Create a new document with CONTINUOUS_ENDNOTES enabled.
3549 SwDoc* pDoc = createSwDoc();
3550 pDoc->getIDocumentSettingAccess().set(DocumentSettingId::CONTINUOUS_ENDNOTES, true);
3552 // Insert a second page, and an endnote on the 2nd page (both the anchor and the endnote is on
3553 // the 2nd page).
3554 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
3555 pWrtShell->InsertPageBreak();
3556 pWrtShell->InsertFootnote("endnote", /*bEndNote=*/true, /*bEdit=*/false);
3558 // Add a new page at the start of the document.
3559 pWrtShell->SttEndDoc(/*bStart=*/true);
3560 pWrtShell->InsertPageBreak();
3562 // Make sure that the endnote is moved from the 2nd page to the 3rd one.
3563 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
3564 assertXPath(pXmlDoc, "/root/page", 3);
3565 // Without the accompanying fix in place, this test would have failed with:
3566 // - Expected: 1
3567 // - Actual : 0
3568 // i.e. the footnote container remained on page 2.
3569 assertXPath(pXmlDoc, "/root/page[3]/ftncont", 1);
3572 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testContinuousEndnotesDeletePageAtStart)
3574 // Create a new document with CONTINUOUS_ENDNOTES enabled.
3575 SwDoc* pDoc = createSwDoc();
3576 pDoc->getIDocumentSettingAccess().set(DocumentSettingId::CONTINUOUS_ENDNOTES, true);
3578 // Insert a second page, and an endnote on the 2nd page (both the anchor and the endnote is on
3579 // the 2nd page).
3580 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
3581 pWrtShell->InsertPageBreak();
3582 pWrtShell->InsertFootnote("endnote", /*bEndNote=*/true, /*bEdit=*/false);
3584 // Remove the empty page at the start of the document.
3585 pWrtShell->SttEndDoc(/*bStart=*/true);
3586 pWrtShell->DelRight();
3588 // Make sure that the endnote is moved from the 2nd page to the 1st one.
3589 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
3590 // Without the accompanying fix in place, this test would have failed with:
3591 // - Expected: 1
3592 // - Actual : 2
3593 // i.e. the endnote remained on an (otherwise) empty 2nd page.
3594 assertXPath(pXmlDoc, "/root/page", 1);
3595 assertXPath(pXmlDoc, "/root/page[1]/ftncont", 1);
3598 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf128399)
3600 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "tdf128399.docx");
3601 SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
3602 SwFrame* pPage = pLayout->GetLower();
3603 SwFrame* pBody = pPage->GetLower();
3604 SwFrame* pTable = pBody->GetLower();
3605 SwFrame* pRow1 = pTable->GetLower();
3606 SwFrame* pRow2 = pRow1->GetNext();
3607 const SwRect& rRow2Rect = pRow2->getFrameArea();
3608 Point aPoint = rRow2Rect.Center();
3610 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
3611 SwPosition aPosition = *pWrtShell->GetCursor()->Start();
3612 SwPosition aFirstRow(aPosition);
3613 SwCursorMoveState aState(CursorMoveState::NONE);
3614 pLayout->GetModelPositionForViewPoint(&aPosition, aPoint, &aState);
3615 // Second row is +3: end node, start node and the first text node in the 2nd row.
3616 SwNodeOffset nExpected = aFirstRow.nNode.GetIndex() + 3;
3618 // Without the accompanying fix in place, this test would have failed with:
3619 // - Expected: 14
3620 // - Actual : 11
3621 // i.e. clicking on the center of the 2nd row placed the cursor in the 1st row.
3622 CPPUNIT_ASSERT_EQUAL(nExpected, aPosition.nNode.GetIndex());
3625 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf105481)
3627 createSwDoc(DATA_DIRECTORY, "tdf105481.odt");
3628 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
3629 CPPUNIT_ASSERT(pXmlDoc);
3631 // Without the accompanying fix in place, this test would have failed
3632 // because the vertical position of the as-char shape object and the
3633 // as-char math object will be wrong (below/beyond the text frame's bottom).
3635 SwTwips nTxtTop = getXPath(pXmlDoc,
3636 "/root/page/anchored/fly/txt[2]"
3637 "/infos/bounds",
3638 "top")
3639 .toInt32();
3640 SwTwips nTxtBottom = nTxtTop
3641 + getXPath(pXmlDoc,
3642 "/root/page/anchored/fly/txt[2]"
3643 "/infos/bounds",
3644 "height")
3645 .toInt32();
3647 SwTwips nFormula1Top = getXPath(pXmlDoc,
3648 "/root/page/anchored/fly/txt[2]"
3649 "/anchored/fly[1]/infos/bounds",
3650 "top")
3651 .toInt32();
3652 SwTwips nFormula1Bottom = nFormula1Top
3653 + getXPath(pXmlDoc,
3654 "/root/page/anchored/fly/txt[2]"
3655 "/anchored/fly[1]/infos/bounds",
3656 "height")
3657 .toInt32();
3659 SwTwips nFormula2Top = getXPath(pXmlDoc,
3660 "/root/page/anchored/fly/txt[2]"
3661 "/anchored/fly[2]/infos/bounds",
3662 "top")
3663 .toInt32();
3664 SwTwips nFormula2Bottom = nFormula2Top
3665 + getXPath(pXmlDoc,
3666 "/root/page/anchored/fly/txt[2]"
3667 "/anchored/fly[2]/infos/bounds",
3668 "height")
3669 .toInt32();
3671 // Ensure that the two formula positions are at least between top and bottom of the text frame.
3672 // The below two are satisfied even without the fix.
3673 CPPUNIT_ASSERT_GREATEREQUAL(nTxtTop, nFormula1Top);
3674 CPPUNIT_ASSERT_GREATEREQUAL(nTxtTop, nFormula2Top);
3676 // Without the accompanying fix in place, this test would have failed with:
3677 // - Expected less than or equal to : 14423
3678 // - Actual : 14828
3679 // that is, the formula is below the text-frame's y bound.
3680 CPPUNIT_ASSERT_LESSEQUAL(nTxtBottom, nFormula1Bottom);
3681 // Similarly for formula # 2 :
3682 // - Expected less than or equal to : 14423
3683 // - Actual : 15035
3684 // that is, the formula is below the text-frame's y bound.
3685 CPPUNIT_ASSERT_LESSEQUAL(nTxtBottom, nFormula2Bottom);
3688 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf117982)
3690 SwDoc* pDocument = createSwDoc(DATA_DIRECTORY, "tdf117982.docx");
3691 SwDocShell* pShell = pDocument->GetDocShell();
3692 std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
3693 MetafileXmlDump dumper;
3694 xmlDocUniquePtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
3695 assertXPathContent(pXmlDoc, "/metafile/push[1]/push[1]/push[1]/textarray[1]/text", "FOO AAA");
3696 //The first cell must be "FOO AAA". If not, this means the first cell content not visible in
3697 //the source document.
3700 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf128959)
3702 // no orphan/widow control in table cells
3703 SwDoc* pDocument = createSwDoc(DATA_DIRECTORY, "tdf128959.docx");
3704 CPPUNIT_ASSERT(pDocument);
3705 discardDumpedLayout();
3706 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
3708 // first two lines of the paragraph in the split table cell on the first page
3709 // (these lines were completely lost)
3710 assertXPath(
3711 pXmlDoc, "/root/page[1]/body/tab[1]/row[1]/cell[1]/txt[1]/LineBreak[1]", "Line",
3712 "a)Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas porttitor congue ");
3713 assertXPath(
3714 pXmlDoc, "/root/page[1]/body/tab[1]/row[1]/cell[1]/txt[1]/LineBreak[2]", "Line",
3715 "massa. Fusce posuere, magna sed pulvinar ultricies, purus lectus malesuada libero, sit ");
3716 // last line of the paragraph in the split table cell on the second page
3717 assertXPath(pXmlDoc, "/root/page[2]/body/tab[1]/row[1]/cell[1]/txt[1]/LineBreak[1]", "Line",
3718 "amet commodo magna eros quis urna.");
3721 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf121658)
3723 uno::Reference<linguistic2::XHyphenator> xHyphenator = LinguMgr::GetHyphenator();
3724 if (!xHyphenator->hasLocale(lang::Locale("en", "US", OUString())))
3725 return;
3727 createSwDoc(DATA_DIRECTORY, "tdf121658.odt");
3728 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
3730 // Only 2 hyphenated words should appear in the document (in the lowercase words).
3731 // Uppercase words should not be hyphenated.
3732 assertXPath(pXmlDoc, "//Special[@nType='PortionType::Hyphen']", 2);
3735 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testWriterImageNoCapture)
3737 createSwDoc(DATA_DIRECTORY, "writer-image-no-capture.docx");
3738 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
3739 CPPUNIT_ASSERT(pXmlDoc);
3740 sal_Int32 nPageLeft = getXPath(pXmlDoc, "//page/infos/bounds", "left").toInt32();
3741 sal_Int32 nImageLeft = getXPath(pXmlDoc, "//anchored/fly/infos/bounds", "left").toInt32();
3742 // Without the accompanying fix in place, this test would have failed with:
3743 // - Expected less than: 284
3744 // - Actual : 284
3745 // i.e. the image position was modified to be inside the page frame ("captured"), even if Word
3746 // does not do that.
3747 CPPUNIT_ASSERT_LESS(nPageLeft, nImageLeft);
3750 static SwRect lcl_getVisibleFlyObjRect(SwWrtShell* pWrtShell)
3752 SwRootFrame* pRoot = pWrtShell->GetLayout();
3753 SwPageFrame* pPage = static_cast<SwPageFrame*>(pRoot->GetLower());
3754 pPage = static_cast<SwPageFrame*>(pPage->GetNext());
3755 pPage = static_cast<SwPageFrame*>(pPage->GetNext());
3756 SwSortedObjs* pDrawObjs = pPage->GetDrawObjs();
3757 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pDrawObjs->size());
3758 SwAnchoredObject* pDrawObj = (*pDrawObjs)[0];
3759 CPPUNIT_ASSERT_EQUAL(OUString("Rahmen8"), pDrawObj->GetFrameFormat().GetName());
3760 pPage = static_cast<SwPageFrame*>(pPage->GetNext());
3761 pDrawObjs = pPage->GetDrawObjs();
3762 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pDrawObjs->size());
3763 pDrawObj = (*pDrawObjs)[0];
3764 CPPUNIT_ASSERT_EQUAL(OUString("Rahmen123"), pDrawObj->GetFrameFormat().GetName());
3765 SwRect aFlyRect = pDrawObj->GetObjRect();
3766 CPPUNIT_ASSERT(pPage->getFrameArea().Contains(aFlyRect));
3767 return aFlyRect;
3770 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testStableAtPageAnchoredFlyPosition)
3772 // this doc has two page-anchored frames: one tiny on page 3 and one large on page 4.
3773 // it also has a style:master-page named "StandardEntwurf", which contains some fields.
3774 // if you add a break to page 2, or append some text to page 4 (or just toggle display field names),
3775 // the page anchored frame on page 4 vanishes, as it is incorrectly moved out of the page bounds.
3776 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "stable-at-page-anchored-fly-position.odt");
3777 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
3779 // look up the layout position of the page-bound frame on page four
3780 SwRect aOrigRect = lcl_getVisibleFlyObjRect(pWrtShell);
3782 // append some text to the document to trigger bug / relayout
3783 pWrtShell->SttEndDoc(false);
3784 pWrtShell->Insert("foo");
3786 // get the current position of the frame on page four
3787 SwRect aRelayoutRect = lcl_getVisibleFlyObjRect(pWrtShell);
3789 // the anchored frame should not have moved
3790 CPPUNIT_ASSERT_EQUAL(aOrigRect, aRelayoutRect);
3793 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf134548)
3795 createSwDoc(DATA_DIRECTORY, "tdf134548.odt");
3796 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
3798 // Second paragraph has two non zero width tabs in beginning of line
3800 OUString sNodeType = parseDump("/root/page/body/txt[2]/Text[1]", "nType");
3801 CPPUNIT_ASSERT_EQUAL(OUString("PortionType::TabLeft"), sNodeType);
3802 sal_Int32 nWidth = parseDump("/root/page/body/txt[2]/Text[1]", "nWidth").toInt32();
3803 CPPUNIT_ASSERT_GREATER(sal_Int32(0), nWidth);
3806 OUString sNodeType = parseDump("/root/page/body/txt[2]/Text[2]", "nType");
3807 CPPUNIT_ASSERT_EQUAL(OUString("PortionType::TabLeft"), sNodeType);
3808 sal_Int32 nWidth = parseDump("/root/page/body/txt[2]/Text[2]", "nWidth").toInt32();
3809 CPPUNIT_ASSERT_GREATER(sal_Int32(0), nWidth);
3813 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf124423)
3815 createSwDoc(DATA_DIRECTORY, "tdf124423.docx");
3816 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
3817 sal_Int32 nFly1Width
3818 = getXPath(pXmlDoc, "(//anchored/fly)[1]/infos/prtBounds", "width").toInt32();
3819 sal_Int32 nFly2Width
3820 = getXPath(pXmlDoc, "(//anchored/fly)[2]/infos/prtBounds", "width").toInt32();
3821 sal_Int32 nPageWidth = getXPath(pXmlDoc, "//page/infos/prtBounds", "width").toInt32();
3822 CPPUNIT_ASSERT_EQUAL(nPageWidth, nFly2Width);
3823 CPPUNIT_ASSERT_LESS(nPageWidth / 2, nFly1Width);
3825 createSwDoc(DATA_DIRECTORY, "tdf124423.odt");
3826 pXmlDoc = parseLayoutDump();
3827 nFly1Width = getXPath(pXmlDoc, "(//anchored/fly)[1]/infos/prtBounds", "width").toInt32();
3828 nFly2Width = getXPath(pXmlDoc, "(//anchored/fly)[2]/infos/prtBounds", "width").toInt32();
3829 nPageWidth = getXPath(pXmlDoc, "//page/infos/prtBounds", "width").toInt32();
3830 CPPUNIT_ASSERT_LESS(nPageWidth / 2, nFly2Width);
3831 CPPUNIT_ASSERT_LESS(nPageWidth / 2, nFly1Width);
3834 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf137185)
3836 // First load the sample bugdoc
3837 load(DATA_DIRECTORY, "tdf137185.odt");
3838 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
3839 CPPUNIT_ASSERT(pTextDoc);
3840 // Get the doc shell
3841 SwDoc* pDoc(pTextDoc->GetDocShell()->GetDoc());
3843 // Get the DrawObject from page
3844 auto pModel = pDoc->getIDocumentDrawModelAccess().GetDrawModel();
3845 CPPUNIT_ASSERT(pModel);
3846 auto pPage = pModel->GetPage(0);
3847 CPPUNIT_ASSERT(pPage);
3848 auto pObj = pPage->GetObj(0);
3849 CPPUNIT_ASSERT(pObj);
3851 // Get the format of the draw object
3852 auto pShape = FindFrameFormat(pObj);
3853 CPPUNIT_ASSERT(pShape);
3855 // Check the text of the shape
3856 uno::Reference<text::XText> xTxt(getShape(1), uno::UNO_QUERY);
3857 CPPUNIT_ASSERT_EQUAL(OUString("Align me!"), xTxt->getText()->getString());
3859 // Add a textbox to the shape
3860 SwTextBoxHelper::create(pShape, pShape->FindRealSdrObject(), true);
3862 // Check if the text moved from the shape to the frame
3863 auto pFormat = SwTextBoxHelper::getOtherTextBoxFormat(getShape(1));
3864 auto xTextFrame = SwXTextFrame::CreateXTextFrame(*pFormat->GetDoc(), pFormat);
3866 CPPUNIT_ASSERT_EQUAL(OUString("Align me!"), xTextFrame->getText()->getString());
3867 SdrTextObj* pTextObj = dynamic_cast<SdrTextObj*>(pObj);
3868 CPPUNIT_ASSERT(pTextObj);
3869 const auto& aOutStr = pTextObj->GetOutlinerParaObject()->GetTextObject();
3871 CPPUNIT_ASSERT(aOutStr.GetText(0).isEmpty());
3872 // Before the patch it failed, because the text appeared 2 times on each other.
3875 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf138782)
3877 CPPUNIT_ASSERT(createSwDoc(DATA_DIRECTORY, "tdf138782.docx"));
3878 auto pXml = parseLayoutDump();
3879 CPPUNIT_ASSERT(pXml);
3881 // Without the fix it failed because the 3rd shape was outside the page:
3882 // - Expected less than: 13327
3883 // - Actual : 14469
3885 CPPUNIT_ASSERT_LESS(
3886 getXPath(pXml, "/root/page/infos/bounds", "right").toInt32(),
3887 getXPath(pXml, "/root/page/body/txt[8]/anchored/SwAnchoredDrawObject/bounds", "right")
3888 .toInt32());
3891 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf135035)
3893 createSwDoc(DATA_DIRECTORY, "tdf135035.docx");
3894 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
3895 sal_Int32 nFly1Width
3896 = getXPath(pXmlDoc, "(//anchored/fly)[1]/infos/prtBounds", "width").toInt32();
3897 sal_Int32 nFly2Width
3898 = getXPath(pXmlDoc, "(//anchored/fly)[2]/infos/prtBounds", "width").toInt32();
3899 sal_Int32 nFly3Width
3900 = getXPath(pXmlDoc, "(//anchored/fly)[3]/infos/prtBounds", "width").toInt32();
3901 sal_Int32 nParentWidth = getXPath(pXmlDoc, "(//txt)[1]/infos/prtBounds", "width").toInt32();
3902 CPPUNIT_ASSERT_EQUAL(nParentWidth, nFly2Width);
3903 CPPUNIT_ASSERT_EQUAL(nParentWidth, nFly3Width);
3904 CPPUNIT_ASSERT_LESS(nParentWidth / 2, nFly1Width);
3906 createSwDoc(DATA_DIRECTORY, "tdf135035.odt");
3907 pXmlDoc = parseLayoutDump();
3908 nFly1Width = getXPath(pXmlDoc, "(//anchored/fly)[1]/infos/prtBounds", "width").toInt32();
3909 nFly2Width = getXPath(pXmlDoc, "(//anchored/fly)[2]/infos/prtBounds", "width").toInt32();
3910 nFly3Width = getXPath(pXmlDoc, "(//anchored/fly)[3]/infos/prtBounds", "width").toInt32();
3911 nParentWidth = getXPath(pXmlDoc, "(//txt)[1]/infos/prtBounds", "width").toInt32();
3912 CPPUNIT_ASSERT_LESS(nParentWidth / 2, nFly2Width);
3913 CPPUNIT_ASSERT_LESS(nParentWidth / 2, nFly1Width);
3914 CPPUNIT_ASSERT_GREATER(nParentWidth, nFly3Width);
3917 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf146704_EndnoteInSection)
3919 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "tdf146704_EndnoteInSection.odt");
3920 CPPUNIT_ASSERT(pDoc);
3921 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
3922 // Without the fix, the endnote placed to 2. page
3923 assertXPath(pXmlDoc, "/root/page", 1);
3926 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf139336_ColumnsWithFootnoteDoNotOccupyEntirePage)
3928 SwDoc* pDoc
3929 = createSwDoc(DATA_DIRECTORY, "tdf139336_ColumnsWithFootnoteDoNotOccupyEntirePage.docx");
3930 CPPUNIT_ASSERT(pDoc);
3931 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
3932 // Without the fix, it would be 5 pages, but with the fix the whole document
3933 // would fit into 1 page, but it will be 2 pages right now, because
3934 // when writer import (from docx) the last section with columns, then it does not set
3935 // the evenly distributed settings, and this settings is required for the fix now, to
3936 // avoid some regression.
3937 assertXPath(pXmlDoc, "/root/page", 2);
3940 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf54465_ColumnsWithFootnoteDoNotOccupyEntirePage)
3942 // Old odt files should keep their original layout, as it was before Tdf139336 fix.
3943 // The new odt file is only 1 page long, while the old odt file (with the same content)
3944 // was more then 1 page long.
3945 // Note: Somewhy this test miscalculates the layout of the old odt file.
3946 // It will be 4 pages long, while opened in Writer it is 5 pages long.
3947 SwDoc* pDoc
3948 = createSwDoc(DATA_DIRECTORY, "tdf54465_ColumnsWithFootnoteDoNotOccupyEntirePage_Old.odt");
3949 CPPUNIT_ASSERT(pDoc);
3950 Scheduler::ProcessEventsToIdle();
3951 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
3952 xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "/root/page");
3953 xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
3954 CPPUNIT_ASSERT_GREATER(1, xmlXPathNodeSetGetLength(pXmlNodes));
3955 xmlXPathFreeObject(pXmlObj);
3957 discardDumpedLayout();
3958 pDoc = createSwDoc(DATA_DIRECTORY, "tdf54465_ColumnsWithFootnoteDoNotOccupyEntirePage_New.odt");
3959 CPPUNIT_ASSERT(pDoc);
3960 pXmlDoc = parseLayoutDump();
3961 assertXPath(pXmlDoc, "/root/page", 1);
3964 CPPUNIT_PLUGIN_IMPLEMENT();
3966 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */