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 "sdmodeltestbase.hxx"
12 #include <com/sun/star/uno/Reference.hxx>
14 #include <com/sun/star/drawing/XShapes.hpp>
16 #include <svx/svdpage.hxx>
17 #include <svx/svdotext.hxx>
21 /// Shape / SdrObject import and export tests
22 class ShapeImportExportTest
: public SdModelTestBase
25 ShapeImportExportTest()
26 : SdModelTestBase("/sd/qa/unit/data/")
30 void testTextDistancesOOXML();
31 void testTextDistancesOOXML_LargerThanTextAreaSpecialCase();
32 void testTextDistancesOOXML_Export();
33 void testTextDistancesODP_OOXML_Export();
35 CPPUNIT_TEST_SUITE(ShapeImportExportTest
);
36 CPPUNIT_TEST(testTextDistancesOOXML
);
37 CPPUNIT_TEST(testTextDistancesOOXML_LargerThanTextAreaSpecialCase
);
38 CPPUNIT_TEST(testTextDistancesOOXML_Export
);
39 CPPUNIT_TEST(testTextDistancesODP_OOXML_Export
);
40 CPPUNIT_TEST_SUITE_END();
45 SdrObject
* searchObject(SdrPage
const* pPage
, std::u16string_view rName
)
47 for (size_t i
= 0; i
< pPage
->GetObjCount(); ++i
)
49 SdrObject
* pCurrent
= pPage
->GetObj(i
);
50 if (pCurrent
->GetName() == rName
)
57 /* Test text distances (insets) */
58 void ShapeImportExportTest::testTextDistancesOOXML()
60 createSdImpressDoc("TextDistancesInsets1.pptx");
62 SdrPage
const* pPage
= GetPage(1);
63 // Bottom Margin = 4cm
65 std::array
<std::u16string_view
, 3> aObjectDesc
= {
71 for (auto const& rString
: aObjectDesc
)
73 auto* pTextObj
= DynCastSdrTextObj(searchObject(pPage
, rString
));
74 CPPUNIT_ASSERT(pTextObj
);
75 CPPUNIT_ASSERT_EQUAL(tools::Long(-1292), pTextObj
->GetTextUpperDistance());
76 CPPUNIT_ASSERT_EQUAL(tools::Long(2708), pTextObj
->GetTextLowerDistance());
80 // Bottom Margin = 1cm
82 std::array
<std::u16string_view
, 3> aObjectDesc
= {
88 for (auto const& rString
: aObjectDesc
)
90 auto* pTextObj
= DynCastSdrTextObj(searchObject(pPage
, rString
));
91 CPPUNIT_ASSERT(pTextObj
);
92 CPPUNIT_ASSERT_EQUAL(tools::Long(0), pTextObj
->GetTextUpperDistance());
93 CPPUNIT_ASSERT_EQUAL(tools::Long(1000), pTextObj
->GetTextLowerDistance());
97 // Top + Bottom Margin = 1cm
99 std::array
<std::u16string_view
, 3> aObjectDesc
= {
105 for (auto const& rString
: aObjectDesc
)
107 auto* pTextObj
= DynCastSdrTextObj(searchObject(pPage
, rString
));
108 CPPUNIT_ASSERT(pTextObj
);
109 CPPUNIT_ASSERT_EQUAL(tools::Long(708), pTextObj
->GetTextUpperDistance());
110 CPPUNIT_ASSERT_EQUAL(tools::Long(708), pTextObj
->GetTextLowerDistance());
114 // No margin - Top + Bottom = 0cm
116 std::array
<std::u16string_view
, 3> aObjectDesc
= {
122 for (auto const& rString
: aObjectDesc
)
124 auto* pTextObj
= DynCastSdrTextObj(searchObject(pPage
, rString
));
125 CPPUNIT_ASSERT(pTextObj
);
126 CPPUNIT_ASSERT_EQUAL(tools::Long(0), pTextObj
->GetTextUpperDistance());
127 CPPUNIT_ASSERT_EQUAL(tools::Long(0), pTextObj
->GetTextLowerDistance());
133 std::array
<std::u16string_view
, 3> aObjectDesc
= {
139 for (auto const& rString
: aObjectDesc
)
141 auto* pTextObj
= DynCastSdrTextObj(searchObject(pPage
, rString
));
142 CPPUNIT_ASSERT(pTextObj
);
143 CPPUNIT_ASSERT_EQUAL(tools::Long(1000), pTextObj
->GetTextUpperDistance());
144 CPPUNIT_ASSERT_EQUAL(tools::Long(0), pTextObj
->GetTextLowerDistance());
150 std::array
<std::u16string_view
, 3> aObjectDesc
= {
156 for (auto const& rString
: aObjectDesc
)
158 auto* pTextObj
= DynCastSdrTextObj(searchObject(pPage
, rString
));
159 CPPUNIT_ASSERT(pTextObj
);
160 CPPUNIT_ASSERT_EQUAL(tools::Long(2708), pTextObj
->GetTextUpperDistance());
161 CPPUNIT_ASSERT_EQUAL(tools::Long(-1292), pTextObj
->GetTextLowerDistance());
166 /* Test text distances (insets) variants where top+bottom margin > text area*/
167 void ShapeImportExportTest::testTextDistancesOOXML_LargerThanTextAreaSpecialCase()
169 createSdImpressDoc("TextDistancesInsets2.pptx");
171 SdrPage
const* pPage
= GetPage(1);
173 // Top/Bottom 0cm/3cm, 1cm/4cm, 4cm/7cm - all should be converted to the same value in LO
175 std::array
<std::u16string_view
, 9> aObjectNames
= {
176 u
"T_0_3", u
"M_0_3", u
"B_0_3", u
"T_1_4", u
"M_1_4",
177 u
"B_1_4", u
"T_4_7", u
"M_4_7", u
"B_4_7",
180 for (auto const& rName
: aObjectNames
)
182 auto* pTextObj
= DynCastSdrTextObj(searchObject(pPage
, rName
));
183 CPPUNIT_ASSERT(pTextObj
);
184 CPPUNIT_ASSERT_EQUAL(tools::Long(-792), pTextObj
->GetTextUpperDistance());
185 CPPUNIT_ASSERT_EQUAL(tools::Long(2208), pTextObj
->GetTextLowerDistance());
189 // Top/Bottom 0cm/2cm, 1cm/3cm, 4cm/6cm - all should be converted to the same value in LO
191 std::array
<std::u16string_view
, 9> aObjectNames
= {
192 u
"T_0_2", u
"M_0_2", u
"B_0_2", u
"T_1_3", u
"M_1_3",
193 u
"B_1_3", u
"T_4_6", u
"M_4_6", u
"B_4_6",
196 for (auto const& rName
: aObjectNames
)
198 auto* pTextObj
= DynCastSdrTextObj(searchObject(pPage
, rName
));
199 CPPUNIT_ASSERT(pTextObj
);
200 CPPUNIT_ASSERT_EQUAL(tools::Long(-292), pTextObj
->GetTextUpperDistance());
201 CPPUNIT_ASSERT_EQUAL(tools::Long(1708), pTextObj
->GetTextLowerDistance());
205 // Top/Bottom 2cm/2cm, 3cm/3cm, 4cm/4cm - all should be converted to the same value in LO
207 std::array
<std::u16string_view
, 9> aObjectNames
= {
208 u
"T_2_2", u
"M_2_2", u
"B_2_2", u
"T_3_3", u
"M_3_3",
209 u
"B_3_3", u
"T_4_4", u
"M_4_4", u
"B_4_4",
212 for (auto const& rName
: aObjectNames
)
214 auto* pTextObj
= DynCastSdrTextObj(searchObject(pPage
, rName
));
215 CPPUNIT_ASSERT(pTextObj
);
216 CPPUNIT_ASSERT_EQUAL(tools::Long(708), pTextObj
->GetTextUpperDistance());
217 CPPUNIT_ASSERT_EQUAL(tools::Long(708), pTextObj
->GetTextLowerDistance());
221 // Top/Bottom 2cm/0cm, 3cm/1cm, 6cm/4cm - all should be converted to the same value in LO
223 std::array
<std::u16string_view
, 9> aObjectNames
= {
224 u
"T_2_0", u
"M_2_0", u
"B_2_0", u
"T_3_1", u
"M_3_1",
225 u
"B_3_1", u
"T_6_4", u
"M_6_4", u
"B_6_4",
228 for (auto const& rName
: aObjectNames
)
230 auto* pTextObj
= DynCastSdrTextObj(searchObject(pPage
, rName
));
231 CPPUNIT_ASSERT(pTextObj
);
232 CPPUNIT_ASSERT_EQUAL(tools::Long(1708), pTextObj
->GetTextUpperDistance());
233 CPPUNIT_ASSERT_EQUAL(tools::Long(-292), pTextObj
->GetTextLowerDistance());
237 // Top/Bottom 3cm/0cm, 4cm/1cm, 7cm/4cm - all should be converted to the same value in LO
239 std::array
<std::u16string_view
, 9> aObjectNames
= {
240 u
"T_3_0", u
"M_3_0", u
"B_3_0", u
"T_4_1", u
"M_4_1",
241 u
"B_4_1", u
"T_7_4", u
"M_7_4", u
"B_7_4",
244 for (auto const& rName
: aObjectNames
)
246 auto* pTextObj
= DynCastSdrTextObj(searchObject(pPage
, rName
));
247 CPPUNIT_ASSERT(pTextObj
);
248 CPPUNIT_ASSERT_EQUAL(tools::Long(2208), pTextObj
->GetTextUpperDistance());
249 CPPUNIT_ASSERT_EQUAL(tools::Long(-792), pTextObj
->GetTextLowerDistance());
254 /* Test export of text distances (insets) - conversion back of special case */
255 void ShapeImportExportTest::testTextDistancesOOXML_Export()
257 createSdImpressDoc("TextDistancesInsets3.pptx");
259 save("Impress Office Open XML");
260 xmlDocUniquePtr pXmlDoc
= parseExport("ppt/slides/slide1.xml");
261 CPPUNIT_ASSERT(pXmlDoc
);
263 //Check shape Top/Bottom - 0cm, 4cm
264 assertXPath(pXmlDoc
, "/p:sld/p:cSld/p:spTree/p:sp[1]/p:nvSpPr/p:cNvPr", "name", "Text_TB_0_4");
265 assertXPathAttrs(pXmlDoc
, "/p:sld/p:cSld/p:spTree/p:sp[1]/p:txBody/a:bodyPr",
266 { { "tIns", "-360000" }, { "bIns", "1079640" } });
268 //Check shape Top/Bottom - 4cm, 0cm
269 assertXPath(pXmlDoc
, "/p:sld/p:cSld/p:spTree/p:sp[2]/p:nvSpPr/p:cNvPr", "name", "Text_TB_4_0");
270 assertXPathAttrs(pXmlDoc
, "/p:sld/p:cSld/p:spTree/p:sp[2]/p:txBody/a:bodyPr",
271 { { "tIns", "1079640" }, { "bIns", "-360000" } });
273 //Check shape Top/Bottom - 0cm, 3cm
274 assertXPath(pXmlDoc
, "/p:sld/p:cSld/p:spTree/p:sp[3]/p:nvSpPr/p:cNvPr", "name", "Text_TB_0_3");
275 assertXPathAttrs(pXmlDoc
, "/p:sld/p:cSld/p:spTree/p:sp[3]/p:txBody/a:bodyPr",
276 { { "tIns", "-180000" }, { "bIns", "899640" } });
278 //Check shape Top/Bottom - 2cm, 1cm
279 assertXPath(pXmlDoc
, "/p:sld/p:cSld/p:spTree/p:sp[4]/p:nvSpPr/p:cNvPr", "name", "Text_TB_2_1");
280 assertXPathAttrs(pXmlDoc
, "/p:sld/p:cSld/p:spTree/p:sp[4]/p:txBody/a:bodyPr",
281 { { "tIns", "540000" }, { "bIns", "180000" } });
283 //Check shape Top/Bottom - 0cm, 2.5cm
284 assertXPath(pXmlDoc
, "/p:sld/p:cSld/p:spTree/p:sp[5]/p:nvSpPr/p:cNvPr", "name",
286 assertXPathAttrs(pXmlDoc
, "/p:sld/p:cSld/p:spTree/p:sp[5]/p:txBody/a:bodyPr",
287 { { "tIns", "-90000" }, { "bIns", "809640" } });
289 //Check shape Top/Bottom - 0cm, 2cm
290 assertXPath(pXmlDoc
, "/p:sld/p:cSld/p:spTree/p:sp[6]/p:nvSpPr/p:cNvPr", "name", "Text_TB_0_2");
291 assertXPathAttrs(pXmlDoc
, "/p:sld/p:cSld/p:spTree/p:sp[6]/p:txBody/a:bodyPr",
292 { { "tIns", "0" }, { "bIns", "720000" } });
294 //Check shape Top/Bottom - 0cm, 1.5cm
295 assertXPath(pXmlDoc
, "/p:sld/p:cSld/p:spTree/p:sp[7]/p:nvSpPr/p:cNvPr", "name",
297 assertXPathAttrs(pXmlDoc
, "/p:sld/p:cSld/p:spTree/p:sp[7]/p:txBody/a:bodyPr",
298 { { "tIns", "0" }, { "bIns", "540000" } });
300 //Check shape Top/Bottom - 3cm, 0cm
301 assertXPath(pXmlDoc
, "/p:sld/p:cSld/p:spTree/p:sp[8]/p:nvSpPr/p:cNvPr", "name", "Text_TB_3_0");
302 assertXPathAttrs(pXmlDoc
, "/p:sld/p:cSld/p:spTree/p:sp[8]/p:txBody/a:bodyPr",
303 { { "tIns", "899640" }, { "bIns", "-180000" } });
305 //Check shape Top/Bottom - 2.5cm, 0cm
306 assertXPath(pXmlDoc
, "/p:sld/p:cSld/p:spTree/p:sp[9]/p:nvSpPr/p:cNvPr", "name",
308 assertXPathAttrs(pXmlDoc
, "/p:sld/p:cSld/p:spTree/p:sp[9]/p:txBody/a:bodyPr",
309 { { "tIns", "809640" }, { "bIns", "-90000" } });
311 //Check shape Top/Bottom - 2cm, 0cm
312 assertXPath(pXmlDoc
, "/p:sld/p:cSld/p:spTree/p:sp[10]/p:nvSpPr/p:cNvPr", "name", "Text_TB_2_0");
313 assertXPathAttrs(pXmlDoc
, "/p:sld/p:cSld/p:spTree/p:sp[10]/p:txBody/a:bodyPr",
314 { { "tIns", "720000" }, { "bIns", "0" } });
316 //Check shape Top/Bottom - 1.5cm, 0cm
317 assertXPath(pXmlDoc
, "/p:sld/p:cSld/p:spTree/p:sp[11]/p:nvSpPr/p:cNvPr", "name",
319 assertXPathAttrs(pXmlDoc
, "/p:sld/p:cSld/p:spTree/p:sp[11]/p:txBody/a:bodyPr",
320 { { "tIns", "540000" }, { "bIns", "0" } });
322 //Check shape Top/Bottom - 1cm, 2cm
323 assertXPath(pXmlDoc
, "/p:sld/p:cSld/p:spTree/p:sp[12]/p:nvSpPr/p:cNvPr", "name", "Text_TB_1_2");
324 assertXPathAttrs(pXmlDoc
, "/p:sld/p:cSld/p:spTree/p:sp[12]/p:txBody/a:bodyPr",
325 { { "tIns", "180000" }, { "bIns", "540000" } });
327 //Check shape Top/Bottom - 2cm, 1.5cm
328 assertXPath(pXmlDoc
, "/p:sld/p:cSld/p:spTree/p:sp[13]/p:nvSpPr/p:cNvPr", "name",
330 assertXPathAttrs(pXmlDoc
, "/p:sld/p:cSld/p:spTree/p:sp[13]/p:txBody/a:bodyPr",
331 { { "tIns", "450000" }, { "bIns", "270000" } });
333 //Check shape Top/Bottom - 1.5cm, 2cm
334 assertXPath(pXmlDoc
, "/p:sld/p:cSld/p:spTree/p:sp[14]/p:nvSpPr/p:cNvPr", "name",
336 assertXPathAttrs(pXmlDoc
, "/p:sld/p:cSld/p:spTree/p:sp[14]/p:txBody/a:bodyPr",
337 { { "tIns", "270000" }, { "bIns", "450000" } });
339 //Check shape Top/Bottom - 2cm, 1.75cm
340 assertXPath(pXmlDoc
, "/p:sld/p:cSld/p:spTree/p:sp[15]/p:nvSpPr/p:cNvPr", "name",
342 assertXPathAttrs(pXmlDoc
, "/p:sld/p:cSld/p:spTree/p:sp[15]/p:txBody/a:bodyPr",
343 { { "tIns", "405000" }, { "bIns", "315000" } });
345 //Check shape Top/Bottom - 1.75cm, 2cm
346 assertXPath(pXmlDoc
, "/p:sld/p:cSld/p:spTree/p:sp[16]/p:nvSpPr/p:cNvPr", "name",
348 assertXPathAttrs(pXmlDoc
, "/p:sld/p:cSld/p:spTree/p:sp[16]/p:txBody/a:bodyPr",
349 { { "tIns", "315000" }, { "bIns", "405000" } });
351 //Check shape Top/Bottom - 2cm, 2cm
352 assertXPath(pXmlDoc
, "/p:sld/p:cSld/p:spTree/p:sp[17]/p:nvSpPr/p:cNvPr", "name", "Text_TB_2_2");
353 assertXPathAttrs(pXmlDoc
, "/p:sld/p:cSld/p:spTree/p:sp[17]/p:txBody/a:bodyPr",
354 { { "tIns", "360000" }, { "bIns", "360000" } });
356 //Check shape Top/Bottom - 1cm, 1cm
357 assertXPath(pXmlDoc
, "/p:sld/p:cSld/p:spTree/p:sp[18]/p:nvSpPr/p:cNvPr", "name", "Text_TB_1_1");
358 assertXPathAttrs(pXmlDoc
, "/p:sld/p:cSld/p:spTree/p:sp[18]/p:txBody/a:bodyPr",
359 { { "tIns", "360000" }, { "bIns", "360000" } });
361 //Check shape Top/Bottom - 0.5cm, 0.5cm
362 assertXPath(pXmlDoc
, "/p:sld/p:cSld/p:spTree/p:sp[19]/p:nvSpPr/p:cNvPr", "name",
364 assertXPathAttrs(pXmlDoc
, "/p:sld/p:cSld/p:spTree/p:sp[19]/p:txBody/a:bodyPr",
365 { { "tIns", "180000" }, { "bIns", "180000" } });
368 void ShapeImportExportTest::testTextDistancesODP_OOXML_Export()
370 createSdImpressDoc("odp/tdf150966_hugeInset.odp");
371 save("Impress Office Open XML");
372 xmlDocUniquePtr pXmlDoc
= parseExport("ppt/slides/slide1.xml");
373 CPPUNIT_ASSERT(pXmlDoc
);
375 // The text ends 5cm below the top edge of the shape.
376 // Without the fix we exported tIns="3600000" and bIns="5400000".
377 // The text had ended about 3.3cm below the top edge in PowerPoint.
378 assertXPathAttrs(pXmlDoc
, "/p:sld/p:cSld/p:spTree/p:sp[1]/p:txBody/a:bodyPr",
379 { { "tIns", "720000" }, { "bIns", "2520000" } });
382 CPPUNIT_TEST_SUITE_REGISTRATION(ShapeImportExportTest
);
384 CPPUNIT_PLUGIN_IMPLEMENT();
386 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */