1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 #include <swmodeltestbase.hxx>
12 #include <o3tl/string_view.hxx>
13 #include <svtools/DocumentToGraphicRenderer.hxx>
16 #include <unotxdoc.hxx>
20 /// Covers sw/source/core/layout/paintfrm.cxx fixes.
21 class Test
: public SwModelTestBase
25 : SwModelTestBase(u
"/sw/qa/core/layout/data/"_ustr
)
30 CPPUNIT_TEST_FIXTURE(Test
, testSplitTableBorder
)
32 // Given a document with a split table, table borders are defined, but cell borders are not:
33 createSwDoc("split-table-border.odt");
34 SwDocShell
* pShell
= getSwDocShell();
36 // When rendering that document:
37 std::shared_ptr
<GDIMetaFile
> xMetaFile
= pShell
->GetPreviewMetaFile();
39 // Then make sure that the master table has a bottom border and the follow table has a top
41 MetafileXmlDump aDumper
;
42 xmlDocUniquePtr pXmlDoc
= dumpAndParse(aDumper
, *xMetaFile
);
43 xmlXPathObjectPtr pXmlObj
= getXPathNode(pXmlDoc
, "//polyline[@style='solid']/point");
44 xmlNodeSetPtr pXmlNodes
= pXmlObj
->nodesetval
;
45 int nHorizontalBorders
= 0;
46 // Count the horizontal borders:
47 for (int i
= 0; i
< xmlXPathNodeSetGetLength(pXmlNodes
); i
+= 2)
49 xmlNodePtr pStart
= pXmlNodes
->nodeTab
[i
];
50 xmlNodePtr pEnd
= pXmlNodes
->nodeTab
[i
+ 1];
51 xmlChar
* pStartY
= xmlGetProp(pStart
, BAD_CAST("y"));
52 xmlChar
* pEndY
= xmlGetProp(pEnd
, BAD_CAST("y"));
53 sal_Int32 nStartY
= o3tl::toInt32(reinterpret_cast<char const*>(pStartY
));
54 sal_Int32 nEndY
= o3tl::toInt32(reinterpret_cast<char const*>(pEndY
));
63 xmlXPathFreeObject(pXmlObj
);
64 // Without the accompanying fix in place, this test would have failed with:
67 // i.e. the bottom border in the master table and the top border in the follow table were
69 CPPUNIT_ASSERT_EQUAL(4, nHorizontalBorders
);
72 CPPUNIT_TEST_FIXTURE(Test
, testRTLBorderMerge
)
74 // Given a document with an RTL table:
75 createSwDoc("rtl-table.docx");
76 SwDocShell
* pShell
= getSwDocShell();
78 // When rendering that document:
79 std::shared_ptr
<GDIMetaFile
> xMetaFile
= pShell
->GetPreviewMetaFile();
81 // Then make sure the 5 columns all have left and right vertical borders:
82 MetafileXmlDump aDumper
;
83 xmlDocUniquePtr pXmlDoc
= dumpAndParse(aDumper
, *xMetaFile
);
84 xmlXPathObjectPtr pXmlObj
= getXPathNode(pXmlDoc
, "//polyline[@style='solid']/point");
85 xmlNodeSetPtr pXmlNodes
= pXmlObj
->nodesetval
;
86 int nVerticalBorders
= 0;
87 // Count the vertical borders:
88 for (int i
= 0; i
< xmlXPathNodeSetGetLength(pXmlNodes
); i
+= 2)
90 xmlNodePtr pStart
= pXmlNodes
->nodeTab
[i
];
91 xmlNodePtr pEnd
= pXmlNodes
->nodeTab
[i
+ 1];
92 xmlChar
* pStartY
= xmlGetProp(pStart
, BAD_CAST("y"));
93 xmlChar
* pEndY
= xmlGetProp(pEnd
, BAD_CAST("y"));
94 sal_Int32 nStartY
= o3tl::toInt32(reinterpret_cast<char const*>(pStartY
));
95 sal_Int32 nEndY
= o3tl::toInt32(reinterpret_cast<char const*>(pEndY
));
104 xmlXPathFreeObject(pXmlObj
);
105 // Without the accompanying fix in place, this test would have failed with:
108 // i.e. the 2nd and 5th vertical border was missing.
109 CPPUNIT_ASSERT_EQUAL(6, nVerticalBorders
);
112 CPPUNIT_TEST_FIXTURE(Test
, testSplitTableMergedBorder
)
114 // Given a document with a split table, first row in frame 1 has merged cells:
115 createSwDoc("split-table-merged-border.odt");
116 SwDocShell
* pShell
= getSwDocShell();
118 // When rendering that document:
119 std::shared_ptr
<GDIMetaFile
> xMetaFile
= pShell
->GetPreviewMetaFile();
121 // Then make sure that the master table has a bottom border with the correct widths:
122 MetafileXmlDump aDumper
;
123 xmlDocUniquePtr pXmlDoc
= dumpAndParse(aDumper
, *xMetaFile
);
124 xmlXPathObjectPtr pXmlObj
= getXPathNode(pXmlDoc
, "//polyline[@style='solid']/point");
125 xmlNodeSetPtr pXmlNodes
= pXmlObj
->nodesetval
;
126 std::set
<int> aHorizontalBorderStarts
;
127 std::set
<int> aHorizontalBorderEnds
;
128 // Collect the horizontal borders:
129 for (int i
= 0; i
< xmlXPathNodeSetGetLength(pXmlNodes
); i
+= 2)
131 xmlNodePtr pStart
= pXmlNodes
->nodeTab
[i
];
132 xmlNodePtr pEnd
= pXmlNodes
->nodeTab
[i
+ 1];
133 xmlChar
* pStartY
= xmlGetProp(pStart
, BAD_CAST("y"));
134 xmlChar
* pEndY
= xmlGetProp(pEnd
, BAD_CAST("y"));
135 sal_Int32 nStartY
= o3tl::toInt32(reinterpret_cast<char const*>(pStartY
));
136 sal_Int32 nEndY
= o3tl::toInt32(reinterpret_cast<char const*>(pEndY
));
137 if (nStartY
!= nEndY
)
143 xmlChar
* pStartX
= xmlGetProp(pStart
, BAD_CAST("x"));
144 xmlChar
* pEndX
= xmlGetProp(pEnd
, BAD_CAST("x"));
145 sal_Int32 nStartX
= o3tl::toInt32(reinterpret_cast<char const*>(pStartX
));
146 sal_Int32 nEndX
= o3tl::toInt32(reinterpret_cast<char const*>(pEndX
));
147 aHorizontalBorderStarts
.insert(nStartX
);
148 aHorizontalBorderEnds
.insert(nEndX
);
150 xmlXPathFreeObject(pXmlObj
);
151 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), aHorizontalBorderStarts
.size());
152 // Without the accompanying fix in place, this test would have failed with:
155 // i.e. the frame 1 bottom border ended sooner than expected, resulting in a buggy, partial
157 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), aHorizontalBorderEnds
.size());
160 CPPUNIT_TEST_FIXTURE(Test
, testInlineEndnoteSeparatorPosition
)
162 // Given a document with a Word-style endnote separator:
163 createSwDoc("inline-endnote-position.docx");
164 SwDocShell
* pDocShell
= getSwDocShell();
166 // When rendering that document:
167 std::shared_ptr
<GDIMetaFile
> xMetaFile
= pDocShell
->GetPreviewMetaFile();
169 // Then make sure the separator upper spacing is 60% of all space, matching Word:
170 MetafileXmlDump aDumper
;
171 xmlDocUniquePtr pXmlDoc
= dumpAndParse(aDumper
, *xMetaFile
);
172 auto nEndnoteSeparatorY
= getXPath(pXmlDoc
, "//polygon/point[1]", "y").toInt32();
173 // Without the accompanying fix in place, this test would have failed with:
176 // i.e. the upper spacing was too low.
177 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(2164), nEndnoteSeparatorY
);
179 // Also make sure the separator length is correct:
180 auto nEndnoteSeparatorStart
= getXPath(pXmlDoc
, "//polygon/point[1]", "x").toInt32();
181 auto nEndnoteSeparatorEnd
= getXPath(pXmlDoc
, "//polygon/point[2]", "x").toInt32();
182 sal_Int32 nEndnoteSeparatorLength
= nEndnoteSeparatorEnd
- nEndnoteSeparatorStart
;
183 // Without the accompanying fix in place, this test would have failed with:
186 // i.e. the separator wasn't 2 inches long, but was shorter vs Word.
187 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(2880), nEndnoteSeparatorLength
);
190 CPPUNIT_TEST_FIXTURE(Test
, testEndnoteContSeparator
)
192 // Given a document with a Word-style endnote continuation separator:
193 createSwDoc("endnote-cont-separator.docx");
195 // When rendering page 2:
197 DocumentToGraphicRenderer
aRenderer(mxComponent
, /*bSelectionOnly=*/false);
198 Size aSize
= aRenderer
.getDocumentSizeInPixels(nPage
);
199 Graphic aGraphic
= aRenderer
.renderToGraphic(nPage
, aSize
, aSize
, COL_WHITE
,
200 /*bExtOutDevData=*/false);
201 auto& xMetaFile
= const_cast<GDIMetaFile
&>(aGraphic
.GetGDIMetaFile());
203 // Then make sure the separator length is correct:
204 MetafileXmlDump aDumper
;
205 xmlDocUniquePtr pXmlDoc
= dumpAndParse(aDumper
, xMetaFile
);
206 auto nEndnoteSeparatorStart
= getXPath(pXmlDoc
, "//polygon/point[1]", "x").toInt32();
207 auto nEndnoteSeparatorEnd
= getXPath(pXmlDoc
, "//polygon/point[2]", "x").toInt32();
208 sal_Int32 nEndnoteSeparatorLength
= nEndnoteSeparatorEnd
- nEndnoteSeparatorStart
;
209 // Without the accompanying fix in place, this test would have failed with:
210 // - Expected: 9360 (page print area width)
211 // - Actual : 2880 (2 inches)
212 // i.e. the separator was too short vs Word.
213 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(9360), nEndnoteSeparatorLength
);
217 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */