1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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  */
9 
10 #include <swmodeltestbase.hxx>
11 
12 #include <com/sun/star/text/XTextColumns.hpp>
13 #include <com/sun/star/text/XTextTablesSupplier.hpp>
14 #include <com/sun/star/text/XTextSectionsSupplier.hpp>
15 #include <com/sun/star/graphic/XGraphic.hpp>
16 
17 #include <editeng/boxitem.hxx>
18 #include <editeng/lrspitem.hxx>
19 #include <editeng/ulspitem.hxx>
20 #include <sfx2/docfile.hxx>
21 #include <sfx2/docfilt.hxx>
22 
23 #include <ndgrf.hxx>
24 #include <docsh.hxx>
25 #include <unotxdoc.hxx>
26 #include <viewsh.hxx>
27 #include <IDocumentLayoutAccess.hxx>
28 
29 // tests should only be added to ww8IMPORT *if* they fail round-tripping in ww8EXPORT
30 
31 class Test : public SwModelTestBase
32 {
33 public:
Test()34     Test() : SwModelTestBase("/sw/qa/extras/ww8import/data/", "MS Word 97")
35     {
36     }
37 };
38 
39 #define DECLARE_WW8IMPORT_TEST(TestName, filename) DECLARE_SW_IMPORT_TEST(TestName, filename, nullptr, Test)
40 
41 DECLARE_WW8IMPORT_TEST(testFloatingTableSectionMargins, "floating-table-section-margins.doc")
42 {
43     sal_Int32 pageLeft = parseDump("/root/page[2]/infos/bounds", "left").toInt32();
44     sal_Int32 pageWidth = parseDump("/root/page[2]/infos/bounds", "width").toInt32();
45     sal_Int32 tableLeft = parseDump("//tab/infos/bounds", "left").toInt32();
46     sal_Int32 tableWidth = parseDump("//tab/infos/bounds", "width").toInt32();
47     CPPUNIT_ASSERT( pageWidth > 0 );
48     CPPUNIT_ASSERT( tableWidth > 0 );
49     // The table's resulting position should be roughly centered.
50     CPPUNIT_ASSERT( abs(( pageLeft + pageWidth / 2 ) - ( tableLeft + tableWidth / 2 )) < 20 );
51 
52     uno::Reference<beans::XPropertySet> xTextSection = getProperty< uno::Reference<beans::XPropertySet> >(getParagraph(2), "TextSection");
53     CPPUNIT_ASSERT(xTextSection.is());
54     uno::Reference<text::XTextColumns> xTextColumns = getProperty< uno::Reference<text::XTextColumns> >(xTextSection, "TextColumns");
55     OUString pageStyleName = getProperty<OUString>(getParagraph(2), "PageStyleName");
56     uno::Reference<style::XStyle> pageStyle( getStyles("PageStyles")->getByName(pageStyleName), uno::UNO_QUERY);
57     uno::Reference<beans::XPropertySet> xPageStyle(getStyles("PageStyles")->getByName(pageStyleName), uno::UNO_QUERY);
58     uno::Reference<text::XTextColumns> xPageColumns = getProperty< uno::Reference<text::XTextColumns> >(xPageStyle, "TextColumns");
59 
60     //either one or the other should get the column's, not both.
61     CPPUNIT_ASSERT( xTextColumns->getColumnCount() != xPageColumns->getColumnCount());
62 }
63 
64 DECLARE_WW8IMPORT_TEST(testN816593, "n816593.doc")
65 {
66     uno::Reference<text::XTextTablesSupplier> xTextTablesSupplier(mxComponent, uno::UNO_QUERY);
67     uno::Reference<container::XIndexAccess> xIndexAccess(xTextTablesSupplier->getTextTables(), uno::UNO_QUERY);
68     // Make sure that even if we import the two tables as non-floating, we
69     // still consider them different, and not merge them.
70     CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xIndexAccess->getCount());
71 }
72 
73 DECLARE_WW8IMPORT_TEST(testBnc875715, "bnc875715.doc")
74 {
75     uno::Reference<text::XTextSectionsSupplier> xTextSectionsSupplier(mxComponent, uno::UNO_QUERY);
76     uno::Reference<container::XIndexAccess> xSections(xTextSectionsSupplier->getTextSections(), uno::UNO_QUERY);
77     // Was incorrectly set as -1270.
78     CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty<sal_Int32>(xSections->getByIndex(0), "SectionLeftMargin"));
79 }
80 
81 DECLARE_WW8IMPORT_TEST(testFloatingTableSectionColumns, "floating-table-section-columns.doc")
82 {
83     OUString tableWidth = parseDump("/root/page[1]/body/section/column[2]/body/txt/anchored/fly/tab/infos/bounds", "width");
84     // table width was restricted by a column
85     CPPUNIT_ASSERT( tableWidth.toInt32() > 10000 );
86 }
87 
88 DECLARE_WW8IMPORT_TEST(testTdf124601, "tdf124601.doc")
89 {
90     // Without the accompanying fix in place, this test would have failed, as the importer lost the
91     // fLayoutInCell shape property for wrap-though shapes.
92     CPPUNIT_ASSERT(getProperty<bool>(getShapeByName(u"Grafik 18"), "IsFollowingTextFlow"));
93     CPPUNIT_ASSERT(getProperty<bool>(getShapeByName(u"Grafik 19"), "IsFollowingTextFlow"));
94 }
95 
96 DECLARE_WW8IMPORT_TEST(testImageLazyRead, "image-lazy-read.doc")
97 {
98     auto xGraphic = getProperty<uno::Reference<graphic::XGraphic>>(getShape(1), "Graphic");
99     Graphic aGraphic(xGraphic);
100     // This failed, import loaded the graphic, it wasn't lazy-read.
101     CPPUNIT_ASSERT(!aGraphic.isAvailable());
102 }
103 
104 DECLARE_WW8IMPORT_TEST(testImageLazyRead0size, "image-lazy-read-0size.doc")
105 {
106     // Load a document with a single bitmap in it: it's declared as a WMF one, but actually a TGA
107     // bitmap.
108     SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
109     SwDoc* pDoc = pTextDoc->GetDocShell()->GetDoc();
110     SwNode* pNode = pDoc->GetNodes()[6];
111     SwGrfNode* pGrfNode = pNode->GetGrfNode();
112     CPPUNIT_ASSERT(pGrfNode);
113     // Without the accompanying fix in place, this test would have failed with:
114     // - Expected: 7590x10440
115     // - Actual  : 0x0
116     // i.e. the size was 0, even if the actual bitmap had a non-0 size.
117     CPPUNIT_ASSERT_EQUAL(Size(7590, 10440), pGrfNode->GetTwipSize());
118 }
119 
120 DECLARE_WW8IMPORT_TEST(testTdf106799, "tdf106799.doc")
121 {
122     // Ensure that all text portions are calculated before testing.
123     SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
124     CPPUNIT_ASSERT(pTextDoc);
125     SwViewShell* pViewShell
126         = pTextDoc->GetDocShell()->GetDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
127     CPPUNIT_ASSERT(pViewShell);
128     pViewShell->Reformat();
129 
130     sal_Int32 const nCellWidths[3][4] = { { 9528, 0, 0, 0 },{ 2382, 2382, 2382, 2382 },{ 2382, 2382, 2382, 2382 } };
131     sal_Int32 const nCellTxtLns[3][4] = { { 1, 0, 0, 0 },{ 1, 0, 0, 0},{ 1, 1, 1, 1 } };
132     // Table was distorted because of missing sprmPFInnerTableCell at paragraph marks (0x0D) with sprmPFInnerTtp
133     for (sal_Int32 nRow : { 0, 1, 2 })
134         for (sal_Int32 nCell : { 0, 1, 2, 3 })
135         {
136             OString cellXPath("/root/page/body/tab/row/cell/tab/row[" + OString::number(nRow+1) + "]/cell[" + OString::number(nCell+1) + "]/");
137             CPPUNIT_ASSERT_EQUAL_MESSAGE(cellXPath.getStr(), nCellWidths[nRow][nCell], parseDump(cellXPath + "infos/bounds", "width").toInt32());
138             if (nCellTxtLns[nRow][nCell] != 0)
139                 CPPUNIT_ASSERT_EQUAL_MESSAGE(cellXPath.getStr(), nCellTxtLns[nRow][nCell], parseDump(cellXPath + "txt/Text", "nLength").toInt32());
140         }
141 }
142 
143 DECLARE_WW8IMPORT_TEST(testTdf121734, "tdf121734.doc")
144 {
145     SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
146     CPPUNIT_ASSERT(pTextDoc);
147     SwDoc* pDoc = pTextDoc->GetDocShell()->GetDoc();
148     SwPosFlyFrames aPosFlyFrames = pDoc->GetAllFlyFormats(nullptr, false);
149     // There is only one fly frame in the document: the one with the imported floating table
150     CPPUNIT_ASSERT_EQUAL(size_t(1), aPosFlyFrames.size());
151     for (const auto& rPosFlyFrame : aPosFlyFrames)
152     {
153         const SwFrameFormat& rFormat = rPosFlyFrame->GetFormat();
154         const SfxPoolItem* pItem = nullptr;
155 
156         // The LR and UL spacings and borders must all be set explicitly;
157         // spacings and border distances must be 0; borders must be absent.
158 
159         CPPUNIT_ASSERT_EQUAL(SfxItemState::SET, rFormat.GetItemState(RES_LR_SPACE, false, &pItem));
160         auto pLR = static_cast<const SvxLRSpaceItem*>(pItem);
161         CPPUNIT_ASSERT(pLR);
162         CPPUNIT_ASSERT_EQUAL(tools::Long(0), pLR->GetLeft());
163         CPPUNIT_ASSERT_EQUAL(tools::Long(0), pLR->GetRight());
164 
165         CPPUNIT_ASSERT_EQUAL(SfxItemState::SET, rFormat.GetItemState(RES_UL_SPACE, false, &pItem));
166         auto pUL = static_cast<const SvxULSpaceItem*>(pItem);
167         CPPUNIT_ASSERT(pUL);
168         CPPUNIT_ASSERT_EQUAL(sal_uInt16(0), pUL->GetUpper());
169         CPPUNIT_ASSERT_EQUAL(sal_uInt16(0), pUL->GetLower());
170 
171         CPPUNIT_ASSERT_EQUAL(SfxItemState::SET, rFormat.GetItemState(RES_BOX, false, &pItem));
172         auto pBox = static_cast<const SvxBoxItem*>(pItem);
173         CPPUNIT_ASSERT(pBox);
174         for (auto eLine : { SvxBoxItemLine::TOP, SvxBoxItemLine::BOTTOM,
175                             SvxBoxItemLine::LEFT, SvxBoxItemLine::RIGHT })
176         {
177             CPPUNIT_ASSERT_EQUAL(sal_uInt16(0), pBox->GetDistance(eLine));
178             CPPUNIT_ASSERT(!pBox->GetLine(eLine));
179         }
180     }
181 }
182 
183 DECLARE_WW8IMPORT_TEST(testTdf125281, "tdf125281.doc")
184 {
185 #if !defined(_WIN32)
186     // Windows fails with actual == 26171 for some reason; also lazy load isn't lazy in Windows
187     // debug builds, reason is not known at the moment.
188 
189     // Load a .doc file which has an embedded .emf image.
190     SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
191     SwDoc* pDoc = pTextDoc->GetDocShell()->GetDoc();
192     SwNode* pNode = pDoc->GetNodes()[6];
193     CPPUNIT_ASSERT(pNode->IsGrfNode());
194     SwGrfNode* pGrfNode = pNode->GetGrfNode();
195     const Graphic& rGraphic = pGrfNode->GetGrf();
196 
197     // Without the accompanying fix in place, this test would have failed, as pref size was 0 till
198     // an actual Paint() was performed (and even then, it was wrong).
199     tools::Long nExpected = 25664;
200     CPPUNIT_ASSERT_EQUAL(nExpected, rGraphic.GetPrefSize().getWidth());
201 
202     // Without the accompanying fix in place, this test would have failed, as setting the pref size
203     // swapped the image in.
204     CPPUNIT_ASSERT(!rGraphic.isAvailable());
205 #endif
206 }
207 
208 DECLARE_WW8IMPORT_TEST(testTdf122425_1, "tdf122425_1.doc")
209 {
210     // This is for header text in case we use a hack for fixed-height headers
211     // (see SwWW8ImplReader::Read_HdFtTextAsHackedFrame)
212     SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
213     CPPUNIT_ASSERT(pTextDoc);
214     SwDoc* pDoc = pTextDoc->GetDocShell()->GetDoc();
215     SwPosFlyFrames aPosFlyFrames = pDoc->GetAllFlyFormats(nullptr, false);
216     // There are two fly frames in the document: for first page's header, and for other pages'
217     CPPUNIT_ASSERT_EQUAL(size_t(2), aPosFlyFrames.size());
218     for (const auto& rPosFlyFrame : aPosFlyFrames)
219     {
220         const SwFrameFormat& rFormat = rPosFlyFrame->GetFormat();
221         const SfxPoolItem* pItem = nullptr;
222 
223         // The LR and UL spacings and borders must all be set explicitly;
224         // spacings and border distances must be 0; borders must be absent
225 
226         CPPUNIT_ASSERT_EQUAL(SfxItemState::SET, rFormat.GetItemState(RES_LR_SPACE, false, &pItem));
227         auto pLR = static_cast<const SvxLRSpaceItem*>(pItem);
228         CPPUNIT_ASSERT(pLR);
229         CPPUNIT_ASSERT_EQUAL(tools::Long(0), pLR->GetLeft());
230         CPPUNIT_ASSERT_EQUAL(tools::Long(0), pLR->GetRight());
231 
232         CPPUNIT_ASSERT_EQUAL(SfxItemState::SET, rFormat.GetItemState(RES_UL_SPACE, false, &pItem));
233         auto pUL = static_cast<const SvxULSpaceItem*>(pItem);
234         CPPUNIT_ASSERT(pUL);
235         CPPUNIT_ASSERT_EQUAL(sal_uInt16(0), pUL->GetUpper());
236         CPPUNIT_ASSERT_EQUAL(sal_uInt16(0), pUL->GetLower());
237 
238         CPPUNIT_ASSERT_EQUAL(SfxItemState::SET, rFormat.GetItemState(RES_BOX, false, &pItem));
239         auto pBox = static_cast<const SvxBoxItem*>(pItem);
240         CPPUNIT_ASSERT(pBox);
241         for (auto eLine : { SvxBoxItemLine::TOP, SvxBoxItemLine::BOTTOM,
242                             SvxBoxItemLine::LEFT, SvxBoxItemLine::RIGHT })
243         {
244             CPPUNIT_ASSERT_EQUAL(sal_uInt16(0), pBox->GetDistance(eLine));
245             CPPUNIT_ASSERT(!pBox->GetLine(eLine));
246         }
247     }
248 
249     //tdf#139495: without the fix, a negative number was converted into a uInt16, overflowing to 115501
250     auto nDist = getProperty<sal_uInt32>(getStyles("PageStyles")->getByName("Standard"), "HeaderBodyDistance");
251     CPPUNIT_ASSERT_EQUAL(sal_uInt32(0), nDist);
252 }
253 
254 DECLARE_WW8IMPORT_TEST(testTdf110987, "tdf110987")
255 {
256     // The input document is an empty .doc, but without file name
257     // extension. Check that it was loaded as a normal .doc document,
258     // and not a template.
259     SwXTextDocument* pTextDoc     = dynamic_cast<SwXTextDocument*>(mxComponent.get());
260     CPPUNIT_ASSERT(pTextDoc);
261     OUString sFilterName = pTextDoc->GetDocShell()->GetMedium()->GetFilter()->GetFilterName();
262     CPPUNIT_ASSERT(sFilterName != "MS Word 97 Vorlage");
263 }
264 
265 DECLARE_WW8IMPORT_TEST(testTdf120761_zOrder, "tdf120761_zOrder.doc")
266 {
267     //The blue shape was covering everything (highest zorder = 2) instead of the lowest(0)
268     uno::Reference<drawing::XShape> xShape(getShapeByName(u"Picture 2"), uno::UNO_QUERY);
269     CPPUNIT_ASSERT_EQUAL(sal_uInt32(0), getProperty<sal_uInt32>(xShape, "ZOrder"));
270 }
271 
272 
273 // tests should only be added to ww8IMPORT *if* they fail round-tripping in ww8EXPORT
274 
275 CPPUNIT_PLUGIN_IMPLEMENT();
276 
277 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
278