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 <test/unoapixml_test.hxx>
12 #include <com/sun/star/beans/XPropertySet.hpp>
13 #include <com/sun/star/drawing/XDrawPageSupplier.hpp>
14 #include <com/sun/star/drawing/EnhancedCustomShapeMetalType.hpp>
15 #include <com/sun/star/drawing/EnhancedCustomShapeSegment.hpp>
16 #include <com/sun/star/drawing/EnhancedCustomShapeSegmentCommand.hpp>
17 #include <com/sun/star/drawing/FillStyle.hpp>
18 #include <com/sun/star/drawing/Hatch.hpp>
19 #include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
20 #include <com/sun/star/drawing/XMasterPageTarget.hpp>
21 #include <com/sun/star/text/XTextRange.hpp>
22 #include <com/sun/star/text/XTextTable.hpp>
23 #include <com/sun/star/text/GraphicCrop.hpp>
25 #include <comphelper/propertyvalue.hxx>
26 #include <comphelper/sequence.hxx>
27 #include <comphelper/sequenceashashmap.hxx>
28 #include <unotools/tempfile.hxx>
29 #include <unotools/saveopt.hxx>
30 #include <svx/unopage.hxx>
31 #include <svx/svdpage.hxx>
32 #include <svx/svdomedia.hxx>
33 #include <docmodel/uno/UnoComplexColor.hxx>
34 #include <docmodel/uno/UnoTheme.hxx>
35 #include <docmodel/theme/Theme.hxx>
37 using namespace ::com::sun::star
;
39 /// Covers xmloff/source/draw/ fixes.
40 class XmloffDrawTest
: public UnoApiXmlTest
44 uno::Reference
<drawing::XShape
> getShape(sal_uInt8 nShapeIndex
);
46 uno::Reference
<beans::XPropertySet
>
47 getShapeTextPortion(sal_uInt32 nIndex
, uno::Reference
<drawing::XShape
> const& xShape
)
49 uno::Reference
<beans::XPropertySet
> xPortion
;
51 uno::Reference
<container::XEnumerationAccess
> xEnumAccess(xShape
, uno::UNO_QUERY
);
52 if (!xEnumAccess
->hasElements())
54 uno::Reference
<container::XEnumeration
> xEnum(xEnumAccess
->createEnumeration());
55 uno::Reference
<text::XTextContent
> xTextContent
;
56 xEnum
->nextElement() >>= xTextContent
;
57 if (!xTextContent
.is())
60 uno::Reference
<container::XEnumerationAccess
> xParaEnumAccess(xTextContent
, uno::UNO_QUERY
);
61 uno::Reference
<container::XEnumeration
> xParaEnum(xParaEnumAccess
->createEnumeration());
62 sal_uInt32 nCurrent
= 0;
63 xPortion
= uno::Reference
<beans::XPropertySet
>(xParaEnum
->nextElement(), uno::UNO_QUERY
);
64 while (nIndex
!= nCurrent
)
68 = uno::Reference
<beans::XPropertySet
>(xParaEnum
->nextElement(), uno::UNO_QUERY
);
74 XmloffDrawTest::XmloffDrawTest()
75 : UnoApiXmlTest(u
"/xmloff/qa/unit/data/"_ustr
)
79 uno::Reference
<drawing::XShape
> XmloffDrawTest::getShape(sal_uInt8 nShapeIndex
)
81 uno::Reference
<drawing::XDrawPagesSupplier
> xDrawPagesSupplier(mxComponent
,
82 uno::UNO_QUERY_THROW
);
83 uno::Reference
<drawing::XDrawPages
> xDrawPages(xDrawPagesSupplier
->getDrawPages());
84 uno::Reference
<drawing::XDrawPage
> xDrawPage(xDrawPages
->getByIndex(0), uno::UNO_QUERY_THROW
);
85 uno::Reference
<drawing::XShape
> xShape(xDrawPage
->getByIndex(nShapeIndex
),
86 uno::UNO_QUERY_THROW
);
90 CPPUNIT_TEST_FIXTURE(XmloffDrawTest
, testTextBoxLoss
)
92 // Load a document that has a shape with a textbox in it. Save it to ODF and reload.
93 loadFromFile(u
"textbox-loss.docx");
94 saveAndReload(u
"impress8"_ustr
);
96 // Make sure that the shape is still a textbox.
97 uno::Reference
<drawing::XDrawPageSupplier
> xDrawPageSupplier(mxComponent
, uno::UNO_QUERY
);
98 uno::Reference
<drawing::XDrawPage
> xDrawPage
= xDrawPageSupplier
->getDrawPage();
99 uno::Reference
<beans::XPropertySet
> xShape(xDrawPage
->getByIndex(1), uno::UNO_QUERY
);
100 bool bTextBox
= false;
101 xShape
->getPropertyValue(u
"TextBox"_ustr
) >>= bTextBox
;
103 // Without the accompanying fix in place, this test would have failed, as the shape only had
104 // editeng text, losing the image part of the shape text.
105 CPPUNIT_ASSERT(bTextBox
);
108 CPPUNIT_TEST_FIXTURE(XmloffDrawTest
, testTdf141301_Extrusion_Angle
)
110 // Load a document that has a custom shape with extrusion direction as set by LO as its default.
111 loadFromFile(u
"tdf141301_Extrusion_Skew.odg");
113 // Prepare use of XPath
115 xmlDocUniquePtr pXmlDoc
= parseExport(u
"content.xml"_ustr
);
117 // Without fix draw:extrusion-skew="50 -135" was not written to file although "50 -135" is not
118 // default in ODF, but only default inside LO.
119 assertXPath(pXmlDoc
, "//draw:enhanced-geometry", "extrusion-skew", u
"50 -135");
122 CPPUNIT_TEST_FIXTURE(XmloffDrawTest
, testThemeExport
)
124 // Create an Impress document which has a master page which has a theme associated with it.
125 loadFromURL(u
"private:factory/simpress"_ustr
);
126 uno::Reference
<drawing::XDrawPagesSupplier
> xDrawPagesSupplier(mxComponent
, uno::UNO_QUERY
);
127 uno::Reference
<drawing::XMasterPageTarget
> xDrawPage(
128 xDrawPagesSupplier
->getDrawPages()->getByIndex(0), uno::UNO_QUERY
);
129 uno::Reference
<beans::XPropertySet
> xMasterPage(xDrawPage
->getMasterPage(), uno::UNO_QUERY
);
131 auto pTheme
= std::make_shared
<model::Theme
>("mytheme");
132 auto pColorSet
= std::make_shared
<model::ColorSet
>("mycolorscheme");
133 pColorSet
->add(model::ThemeColorType::Dark1
, 0x0);
134 pColorSet
->add(model::ThemeColorType::Light1
, 0x1);
135 pColorSet
->add(model::ThemeColorType::Dark2
, 0x2);
136 pColorSet
->add(model::ThemeColorType::Light2
, 0x3);
137 pColorSet
->add(model::ThemeColorType::Accent1
, 0x4);
138 pColorSet
->add(model::ThemeColorType::Accent2
, 0x5);
139 pColorSet
->add(model::ThemeColorType::Accent3
, 0x6);
140 pColorSet
->add(model::ThemeColorType::Accent4
, 0x7);
141 pColorSet
->add(model::ThemeColorType::Accent5
, 0x8);
142 pColorSet
->add(model::ThemeColorType::Accent6
, 0x9);
143 pColorSet
->add(model::ThemeColorType::Hyperlink
, 0xa);
144 pColorSet
->add(model::ThemeColorType::FollowedHyperlink
, 0xb);
145 pTheme
->setColorSet(pColorSet
);
147 uno::Reference
<util::XTheme
> xTheme
= model::theme::createXTheme(pTheme
);
148 xMasterPage
->setPropertyValue(u
"Theme"_ustr
, uno::Any(xTheme
));
151 save(u
"impress8"_ustr
);
153 // Check if the 12 colors are written in the XML:
154 xmlDocUniquePtr pXmlDoc
= parseExport(u
"styles.xml"_ustr
);
155 // Without the accompanying fix in place, this test would have failed with:
158 // - XPath '//style:master-page/loext:theme/loext:color-table/loext:color' number of nodes is incorrect
159 // i.e. the theme was lost on exporting to ODF.
160 assertXPath(pXmlDoc
, "//style:master-page/loext:theme/loext:theme-colors/loext:color", 12);
163 CPPUNIT_TEST_FIXTURE(XmloffDrawTest
, testVideoSnapshot
)
165 // Execute ODP import:
166 loadFromFile(u
"video-snapshot.odp");
167 uno::Reference
<drawing::XDrawPagesSupplier
> xDrawPagesSupplier(mxComponent
,
168 uno::UNO_QUERY_THROW
);
169 CPPUNIT_ASSERT(xDrawPagesSupplier
.is());
170 uno::Reference
<drawing::XDrawPages
> xDrawPages(xDrawPagesSupplier
->getDrawPages());
171 uno::Reference
<drawing::XDrawPage
> xDrawPage(xDrawPages
->getByIndex(0), uno::UNO_QUERY_THROW
);
172 CPPUNIT_ASSERT(xDrawPage
.is());
173 auto pUnoPage
= dynamic_cast<SvxDrawPage
*>(xDrawPage
.get());
174 SdrPage
* pSdrPage
= pUnoPage
->GetSdrPage();
175 auto pMedia
= dynamic_cast<SdrMediaObj
*>(pSdrPage
->GetObj(0));
177 // Check that the preview was imported:
178 const avmedia::MediaItem
& rItem
= pMedia
->getMediaProperties();
179 const Graphic
& rGraphic
= rItem
.getGraphic();
180 CPPUNIT_ASSERT(!rGraphic
.IsNone());
182 // Check that the crop was imported:
183 const text::GraphicCrop
& rCrop
= rItem
.getCrop();
184 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(0), rCrop
.Top
);
185 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(0), rCrop
.Bottom
);
186 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(1356), rCrop
.Left
);
187 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(1356), rCrop
.Right
);
189 // Execute ODP export:
190 save(u
"impress8"_ustr
);
192 xmlDocUniquePtr pXmlDoc
= parseExport(u
"content.xml"_ustr
);
193 // Check that the preview was exported:
194 // Without the accompanying fix in place, this test would have failed with:
197 // - XPath '//draw:frame[@draw:style-name='gr1']/draw:image' number of nodes is incorrect
198 // i.e. the preview wasn't exported to ODP.
199 assertXPath(pXmlDoc
, "//draw:frame[@draw:style-name='gr1']/draw:image", "href",
200 u
"Pictures/MediaPreview1.png");
201 // Check that the crop was exported:
202 assertXPath(pXmlDoc
, "//style:style[@style:name='gr1']/style:graphic-properties", "clip",
203 u
"rect(0cm, 1.356cm, 0cm, 1.356cm)");
206 CPPUNIT_TEST_FIXTURE(XmloffDrawTest
, testThemeImport
)
208 // Given a document that has a master page with a theme associated:
209 loadFromFile(u
"theme.fodp");
211 // Then make sure the doc model has a master page with a theme:
212 uno::Reference
<drawing::XDrawPagesSupplier
> xDrawPagesSupplier(mxComponent
, uno::UNO_QUERY
);
213 uno::Reference
<drawing::XMasterPageTarget
> xDrawPage(
214 xDrawPagesSupplier
->getDrawPages()->getByIndex(0), uno::UNO_QUERY
);
215 uno::Reference
<beans::XPropertySet
> xMasterpage(xDrawPage
->getMasterPage(), uno::UNO_QUERY
);
217 uno::Reference
<util::XTheme
> xTheme
;
218 xMasterpage
->getPropertyValue(u
"Theme"_ustr
) >>= xTheme
;
220 // We expect the theme to be set on the master page
221 CPPUNIT_ASSERT(xTheme
.is());
222 auto* pUnoTheme
= dynamic_cast<UnoTheme
*>(xTheme
.get());
223 CPPUNIT_ASSERT(pUnoTheme
);
224 auto pTheme
= pUnoTheme
->getTheme();
225 CPPUNIT_ASSERT(pTheme
);
227 CPPUNIT_ASSERT_EQUAL(u
"Office Theme"_ustr
, pTheme
->GetName());
228 auto pColorSet
= pTheme
->getColorSet();
229 CPPUNIT_ASSERT(pColorSet
);
230 CPPUNIT_ASSERT_EQUAL(u
"Office"_ustr
, pColorSet
->getName());
232 CPPUNIT_ASSERT_EQUAL(Color(0x954F72),
233 pColorSet
->getColor(model::ThemeColorType::FollowedHyperlink
));
238 void checkFillAndLineComplexColors(uno::Reference
<drawing::XShape
> const& xShape
)
240 CPPUNIT_ASSERT(xShape
.is());
241 uno::Reference
<beans::XPropertySet
> xShapeProperties(xShape
, uno::UNO_QUERY
);
243 uno::Reference
<util::XComplexColor
> xComplexColor
;
244 xShapeProperties
->getPropertyValue(u
"FillComplexColor"_ustr
) >>= xComplexColor
;
245 CPPUNIT_ASSERT(xComplexColor
.is());
246 auto aComplexColor
= model::color::getFromXComplexColor(xComplexColor
);
247 CPPUNIT_ASSERT_EQUAL(model::ThemeColorType::Accent3
, aComplexColor
.getThemeColorType());
248 CPPUNIT_ASSERT_EQUAL(size_t(2), aComplexColor
.getTransformations().size());
249 auto const& rTrans1
= aComplexColor
.getTransformations()[0];
250 CPPUNIT_ASSERT_EQUAL(model::TransformationType::LumMod
, rTrans1
.meType
);
251 CPPUNIT_ASSERT_EQUAL(sal_Int16(4000), rTrans1
.mnValue
);
252 auto const& rTrans2
= aComplexColor
.getTransformations()[1];
253 CPPUNIT_ASSERT_EQUAL(model::TransformationType::LumOff
, rTrans2
.meType
);
254 CPPUNIT_ASSERT_EQUAL(sal_Int16(6000), rTrans2
.mnValue
);
257 uno::Reference
<util::XComplexColor
> xComplexColor
;
258 xShapeProperties
->getPropertyValue(u
"LineComplexColor"_ustr
) >>= xComplexColor
;
259 CPPUNIT_ASSERT(xComplexColor
.is());
260 auto aComplexColor
= model::color::getFromXComplexColor(xComplexColor
);
261 CPPUNIT_ASSERT_EQUAL(model::ThemeColorType::Accent3
, aComplexColor
.getThemeColorType());
262 CPPUNIT_ASSERT_EQUAL(size_t(2), aComplexColor
.getTransformations().size());
263 auto const& rTrans1
= aComplexColor
.getTransformations()[0];
264 CPPUNIT_ASSERT_EQUAL(model::TransformationType::LumMod
, rTrans1
.meType
);
265 CPPUNIT_ASSERT_EQUAL(sal_Int16(6000), rTrans1
.mnValue
);
266 auto const& rTrans2
= aComplexColor
.getTransformations()[1];
267 CPPUNIT_ASSERT_EQUAL(model::TransformationType::LumOff
, rTrans2
.meType
);
268 CPPUNIT_ASSERT_EQUAL(sal_Int16(4000), rTrans2
.mnValue
);
272 } // end anonymous ns
274 CPPUNIT_TEST_FIXTURE(XmloffDrawTest
, testFillAndLineThemeColorExportImport
)
276 loadFromFile(u
"FillAndStrokeThemeColorTest.fodp");
278 checkFillAndLineComplexColors(getShape(0));
280 save(u
"impress8"_ustr
);
282 loadFromURL(maTempFile
.GetURL());
284 checkFillAndLineComplexColors(getShape(0));
287 CPPUNIT_TEST_FIXTURE(XmloffDrawTest
, testTextAndFillThemeColorExportImport
)
289 // Given a document that refers to a theme color:
290 loadFromFile(u
"Reference-ThemeColors-TextAndFill.pptx");
291 saveAndReload(u
"impress8"_ustr
);
293 // Make sure the export result has the theme reference:
294 xmlDocUniquePtr pXmlDoc
= parseExport(u
"content.xml"_ustr
);
298 "//style:style[@style:name='T2']/style:text-properties/loext:char-complex-color"_ostr
);
299 assertXPath(pXmlDoc
, aStyle1
, "color-type", u
"theme");
300 assertXPath(pXmlDoc
, aStyle1
, "theme-type", u
"accent3");
301 assertXPath(pXmlDoc
, aStyle1
+ "/loext:transformation[1]", "type", u
"lummod");
302 assertXPath(pXmlDoc
, aStyle1
+ "/loext:transformation[1]", "value", u
"2000");
303 assertXPath(pXmlDoc
, aStyle1
+ "/loext:transformation[2]", "type", u
"lumoff");
304 assertXPath(pXmlDoc
, aStyle1
+ "/loext:transformation[2]", "value", u
"8000");
307 "//style:style[@style:name='T3']/style:text-properties/loext:char-complex-color"_ostr
);
308 assertXPath(pXmlDoc
, aStyle1
, "color-type", u
"theme");
309 assertXPath(pXmlDoc
, aStyle2
, "theme-type", u
"accent3");
310 assertXPath(pXmlDoc
, aStyle2
+ "/loext:transformation[1]", "type", u
"lummod");
311 assertXPath(pXmlDoc
, aStyle2
+ "/loext:transformation[1]", "value", u
"6000");
312 assertXPath(pXmlDoc
, aStyle2
+ "/loext:transformation[2]", "type", u
"lumoff");
313 assertXPath(pXmlDoc
, aStyle2
+ "/loext:transformation[2]", "value", u
"4000");
316 "//style:style[@style:name='T4']/style:text-properties/loext:char-complex-color"_ostr
);
317 assertXPath(pXmlDoc
, aStyle1
, "color-type", u
"theme");
318 assertXPath(pXmlDoc
, aStyle3
, "theme-type", u
"accent3");
319 assertXPath(pXmlDoc
, aStyle3
+ "/loext:transformation[1]", "type", u
"lummod");
320 assertXPath(pXmlDoc
, aStyle3
+ "/loext:transformation[1]", "value", u
"5000");
323 OString
aShape1("//style:style[@style:name='gr1']/style:graphic-properties/"
324 "loext:fill-complex-color"_ostr
);
325 assertXPath(pXmlDoc
, aStyle1
, "color-type", u
"theme");
326 assertXPath(pXmlDoc
, aShape1
, "theme-type", u
"accent2");
327 assertXPath(pXmlDoc
, aShape1
+ "/loext:transformation[1]", "type", u
"lummod");
328 assertXPath(pXmlDoc
, aShape1
+ "/loext:transformation[1]", "value", u
"2000");
329 assertXPath(pXmlDoc
, aShape1
+ "/loext:transformation[2]", "type", u
"lumoff");
330 assertXPath(pXmlDoc
, aShape1
+ "/loext:transformation[2]", "value", u
"8000");
332 OString
aShape2("//style:style[@style:name='gr2']/style:graphic-properties/"
333 "loext:fill-complex-color"_ostr
);
334 assertXPath(pXmlDoc
, aStyle1
, "color-type", u
"theme");
335 assertXPath(pXmlDoc
, aShape2
, "theme-type", u
"accent2");
336 assertXPath(pXmlDoc
, aShape2
+ "/loext:transformation[1]", "type", u
"lummod");
337 assertXPath(pXmlDoc
, aShape2
+ "/loext:transformation[1]", "value", u
"6000");
338 assertXPath(pXmlDoc
, aShape2
+ "/loext:transformation[2]", "type", u
"lumoff");
339 assertXPath(pXmlDoc
, aShape2
+ "/loext:transformation[2]", "value", u
"4000");
341 OString
aShape3("//style:style[@style:name='gr3']/style:graphic-properties/"
342 "loext:fill-complex-color"_ostr
);
343 assertXPath(pXmlDoc
, aStyle1
, "color-type", u
"theme");
344 assertXPath(pXmlDoc
, aShape3
, "theme-type", u
"accent2");
345 assertXPath(pXmlDoc
, aShape3
+ "/loext:transformation[1]", "type", u
"lummod");
346 assertXPath(pXmlDoc
, aShape3
+ "/loext:transformation[1]", "value", u
"5000");
348 // check fill color theme
350 uno::Reference
<drawing::XShape
> xShape(getShape(0));
351 CPPUNIT_ASSERT(xShape
.is());
352 uno::Reference
<beans::XPropertySet
> xShapeProperties(xShape
, uno::UNO_QUERY
);
353 uno::Reference
<util::XComplexColor
> xComplexColor
;
354 xShapeProperties
->getPropertyValue(u
"FillComplexColor"_ustr
) >>= xComplexColor
;
355 CPPUNIT_ASSERT(xComplexColor
.is());
356 auto aComplexColor
= model::color::getFromXComplexColor(xComplexColor
);
357 CPPUNIT_ASSERT_EQUAL(model::ThemeColorType::Accent2
, aComplexColor
.getThemeColorType());
358 CPPUNIT_ASSERT_EQUAL(size_t(2), aComplexColor
.getTransformations().size());
359 auto const& rTrans1
= aComplexColor
.getTransformations()[0];
360 CPPUNIT_ASSERT_EQUAL(model::TransformationType::LumMod
, rTrans1
.meType
);
361 CPPUNIT_ASSERT_EQUAL(sal_Int16(2000), rTrans1
.mnValue
);
362 auto const& rTrans2
= aComplexColor
.getTransformations()[1];
363 CPPUNIT_ASSERT_EQUAL(model::TransformationType::LumOff
, rTrans2
.meType
);
364 CPPUNIT_ASSERT_EQUAL(sal_Int16(8000), rTrans2
.mnValue
);
367 uno::Reference
<drawing::XShape
> xShape(getShape(1));
368 CPPUNIT_ASSERT(xShape
.is());
369 uno::Reference
<beans::XPropertySet
> xShapeProperties(xShape
, uno::UNO_QUERY
);
370 uno::Reference
<util::XComplexColor
> xComplexColor
;
371 xShapeProperties
->getPropertyValue(u
"FillComplexColor"_ustr
) >>= xComplexColor
;
372 CPPUNIT_ASSERT(xComplexColor
.is());
373 auto aComplexColor
= model::color::getFromXComplexColor(xComplexColor
);
374 CPPUNIT_ASSERT_EQUAL(model::ThemeColorType::Accent2
, aComplexColor
.getThemeColorType());
375 CPPUNIT_ASSERT_EQUAL(size_t(2), aComplexColor
.getTransformations().size());
376 auto const& rTrans1
= aComplexColor
.getTransformations()[0];
377 CPPUNIT_ASSERT_EQUAL(model::TransformationType::LumMod
, rTrans1
.meType
);
378 CPPUNIT_ASSERT_EQUAL(sal_Int16(6000), rTrans1
.mnValue
);
379 auto const& rTrans2
= aComplexColor
.getTransformations()[1];
380 CPPUNIT_ASSERT_EQUAL(model::TransformationType::LumOff
, rTrans2
.meType
);
381 CPPUNIT_ASSERT_EQUAL(sal_Int16(4000), rTrans2
.mnValue
);
384 uno::Reference
<drawing::XShape
> xShape(getShape(2));
385 CPPUNIT_ASSERT(xShape
.is());
386 uno::Reference
<beans::XPropertySet
> xShapeProperties(xShape
, uno::UNO_QUERY
);
387 uno::Reference
<util::XComplexColor
> xComplexColor
;
388 xShapeProperties
->getPropertyValue(u
"FillComplexColor"_ustr
) >>= xComplexColor
;
389 CPPUNIT_ASSERT(xComplexColor
.is());
390 auto aComplexColor
= model::color::getFromXComplexColor(xComplexColor
);
391 CPPUNIT_ASSERT_EQUAL(model::ThemeColorType::Accent2
, aComplexColor
.getThemeColorType());
392 CPPUNIT_ASSERT_EQUAL(size_t(1), aComplexColor
.getTransformations().size());
393 auto const& rTrans1
= aComplexColor
.getTransformations()[0];
394 CPPUNIT_ASSERT_EQUAL(model::TransformationType::LumMod
, rTrans1
.meType
);
395 CPPUNIT_ASSERT_EQUAL(sal_Int16(5000), rTrans1
.mnValue
);
401 // Check the first text portion properties
402 uno::Reference
<drawing::XShape
> xShape(getShape(3));
403 CPPUNIT_ASSERT(xShape
.is());
404 uno::Reference
<beans::XPropertySet
> xPortion
= getShapeTextPortion(0, xShape
);
405 CPPUNIT_ASSERT(xPortion
.is());
406 uno::Reference
<util::XComplexColor
> xComplexColor
;
407 xPortion
->getPropertyValue(u
"CharComplexColor"_ustr
) >>= xComplexColor
;
408 CPPUNIT_ASSERT(xComplexColor
.is());
409 auto aComplexColor
= model::color::getFromXComplexColor(xComplexColor
);
410 CPPUNIT_ASSERT_EQUAL(model::ThemeColorType::Accent3
, aComplexColor
.getThemeColorType());
411 auto const& rTransforms
= aComplexColor
.getTransformations();
412 CPPUNIT_ASSERT_EQUAL(size_t(2), rTransforms
.size());
413 auto const& rTrans1
= rTransforms
[0];
414 CPPUNIT_ASSERT_EQUAL(model::TransformationType::LumMod
, rTrans1
.meType
);
415 CPPUNIT_ASSERT_EQUAL(sal_Int16(2000), rTrans1
.mnValue
);
416 auto const& rTrans2
= rTransforms
[1];
417 CPPUNIT_ASSERT_EQUAL(model::TransformationType::LumOff
, rTrans2
.meType
);
418 CPPUNIT_ASSERT_EQUAL(sal_Int16(8000), rTrans2
.mnValue
);
422 // Check the first text portion properties
423 uno::Reference
<drawing::XShape
> xShape(getShape(4));
424 CPPUNIT_ASSERT(xShape
.is());
425 uno::Reference
<beans::XPropertySet
> xPortion
= getShapeTextPortion(0, xShape
);
426 CPPUNIT_ASSERT(xPortion
.is());
427 uno::Reference
<util::XComplexColor
> xComplexColor
;
428 xPortion
->getPropertyValue(u
"CharComplexColor"_ustr
) >>= xComplexColor
;
429 CPPUNIT_ASSERT(xComplexColor
.is());
430 auto aComplexColor
= model::color::getFromXComplexColor(xComplexColor
);
431 CPPUNIT_ASSERT_EQUAL(model::ThemeColorType::Accent3
, aComplexColor
.getThemeColorType());
432 auto const& rTransforms
= aComplexColor
.getTransformations();
433 CPPUNIT_ASSERT_EQUAL(size_t(2), rTransforms
.size());
434 auto const& rTrans1
= rTransforms
[0];
435 CPPUNIT_ASSERT_EQUAL(model::TransformationType::LumMod
, rTrans1
.meType
);
436 CPPUNIT_ASSERT_EQUAL(sal_Int16(6000), rTrans1
.mnValue
);
437 auto const& rTrans2
= rTransforms
[1];
438 CPPUNIT_ASSERT_EQUAL(model::TransformationType::LumOff
, rTrans2
.meType
);
439 CPPUNIT_ASSERT_EQUAL(sal_Int16(4000), rTrans2
.mnValue
);
443 // Check the first text portion properties
444 uno::Reference
<drawing::XShape
> xShape(getShape(5));
445 CPPUNIT_ASSERT(xShape
.is());
446 uno::Reference
<beans::XPropertySet
> xPortion
= getShapeTextPortion(0, xShape
);
447 CPPUNIT_ASSERT(xPortion
.is());
448 uno::Reference
<util::XComplexColor
> xComplexColor
;
449 xPortion
->getPropertyValue(u
"CharComplexColor"_ustr
) >>= xComplexColor
;
450 CPPUNIT_ASSERT(xComplexColor
.is());
451 auto aComplexColor
= model::color::getFromXComplexColor(xComplexColor
);
452 CPPUNIT_ASSERT_EQUAL(model::ThemeColorType::Accent3
, aComplexColor
.getThemeColorType());
453 CPPUNIT_ASSERT_EQUAL(size_t(1), aComplexColor
.getTransformations().size());
454 auto const& rTrans1
= aComplexColor
.getTransformations()[0];
455 CPPUNIT_ASSERT_EQUAL(model::TransformationType::LumMod
, rTrans1
.meType
);
456 CPPUNIT_ASSERT_EQUAL(sal_Int16(5000), rTrans1
.mnValue
);
460 CPPUNIT_TEST_FIXTURE(XmloffDrawTest
, testThemeColor_ShapeFill
)
462 loadFromFile(u
"ReferenceShapeFill.pptx");
463 saveAndReload(u
"impress8"_ustr
);
465 // check fill color theme
466 uno::Reference
<drawing::XShape
> xShape(getShape(0));
467 CPPUNIT_ASSERT(xShape
.is());
468 uno::Reference
<beans::XPropertySet
> xShapeProperties(xShape
, uno::UNO_QUERY
);
469 uno::Reference
<util::XComplexColor
> xComplexColor
;
470 xShapeProperties
->getPropertyValue(u
"FillComplexColor"_ustr
) >>= xComplexColor
;
471 CPPUNIT_ASSERT(xComplexColor
.is());
472 auto aComplexColor
= model::color::getFromXComplexColor(xComplexColor
);
473 CPPUNIT_ASSERT_EQUAL(model::ThemeColorType::Accent6
, aComplexColor
.getThemeColorType());
474 CPPUNIT_ASSERT_EQUAL(size_t(1), aComplexColor
.getTransformations().size());
475 CPPUNIT_ASSERT_EQUAL(model::TransformationType::LumMod
,
476 aComplexColor
.getTransformations()[0].meType
);
477 CPPUNIT_ASSERT_EQUAL(sal_Int16(7500), aComplexColor
.getTransformations()[0].mnValue
);
480 CPPUNIT_TEST_FIXTURE(XmloffDrawTest
, testTableInShape
)
482 // Given a document with a shape with a "FrameX" parent style (starts with Frame, but is not
484 loadFromFile(u
"table-in-shape.fodt");
486 // Then make sure the table inside the shape is not lost:
487 uno::Reference
<drawing::XDrawPageSupplier
> xDrawPageSupplier(mxComponent
, uno::UNO_QUERY
);
488 uno::Reference
<drawing::XDrawPage
> xDrawPage
= xDrawPageSupplier
->getDrawPage();
489 uno::Reference
<text::XTextRange
> xShape(xDrawPage
->getByIndex(0), uno::UNO_QUERY
);
490 uno::Reference
<container::XEnumerationAccess
> xText(xShape
->getText(), uno::UNO_QUERY
);
491 uno::Reference
<container::XEnumeration
> xEnum
= xText
->createEnumeration();
492 uno::Reference
<text::XTextTable
> xTable(xEnum
->nextElement(), uno::UNO_QUERY
);
493 // Without the accompanying fix in place, this test would have crashed, as xTable was an empty
494 // reference, i.e. the table inside the shape was lost.
495 uno::Reference
<text::XTextRange
> xCell(xTable
->getCellByName(u
"A1"_ustr
), uno::UNO_QUERY
);
496 CPPUNIT_ASSERT_EQUAL(u
"A1"_ustr
, xCell
->getString());
499 // Tests for save/load of new (LO 7.4) attribute loext:extrusion-metal-type
500 // Since ODF 1.4 it is available as draw:extrusion-metal-type in the standard.
503 void lcl_assertMetalProperties(std::string_view sInfo
, uno::Reference
<drawing::XShape
>& rxShape
,
504 sal_Int16 nExpectedMetalType
)
506 uno::Reference
<beans::XPropertySet
> xShapeProps(rxShape
, uno::UNO_QUERY
);
507 uno::Sequence
<beans::PropertyValue
> aGeoPropSeq
;
508 xShapeProps
->getPropertyValue(u
"CustomShapeGeometry"_ustr
) >>= aGeoPropSeq
;
509 comphelper::SequenceAsHashMap
aGeoPropMap(aGeoPropSeq
);
510 uno::Sequence
<beans::PropertyValue
> aExtrusionSeq
;
511 aGeoPropMap
.getValue(u
"Extrusion"_ustr
) >>= aExtrusionSeq
;
512 comphelper::SequenceAsHashMap
aExtrusionPropMap(aExtrusionSeq
);
514 bool bIsMetal(false);
515 aExtrusionPropMap
.getValue(u
"Metal"_ustr
) >>= bIsMetal
;
516 OString sMsg
= OString::Concat(sInfo
) + " Metal";
517 CPPUNIT_ASSERT_MESSAGE(sMsg
.getStr(), bIsMetal
);
519 sal_Int16
nMetalType(-1);
520 aExtrusionPropMap
.getValue(u
"MetalType"_ustr
) >>= nMetalType
;
521 sMsg
= OString::Concat(sInfo
) + " MetalType";
522 CPPUNIT_ASSERT_EQUAL_MESSAGE(sMsg
.getStr(), nExpectedMetalType
, nMetalType
);
526 CPPUNIT_TEST_FIXTURE(XmloffDrawTest
, testExtrusionMetalTypeExtended
)
528 Resetter
resetter([]() { SetODFDefaultVersion(SvtSaveOptions::ODFVER_LATEST
); });
529 loadFromFile(u
"tdf145700_3D_metal_type_MSCompatible.doc");
531 uno::Reference
<drawing::XShape
> xShape(getShape(0));
532 lcl_assertMetalProperties("from doc", xShape
,
533 css::drawing::EnhancedCustomShapeMetalType::MetalMSCompatible
);
535 // Test, that attribute is written with 'draw' namespace in ODF version LATEST
536 saveAndReload(u
"writer8"_ustr
);
539 xmlDocUniquePtr pXmlDoc
= parseExport(u
"content.xml"_ustr
);
540 assertXPath(pXmlDoc
, "//draw:enhanced-geometry", "extrusion-metal", u
"true");
542 "//draw:enhanced-geometry[@draw:extrusion-metal-type='loext:MetalMSCompatible']");
545 uno::Reference
<drawing::XShape
> xShapeReload(getShape(0));
546 lcl_assertMetalProperties("from LATEST", xShapeReload
,
547 css::drawing::EnhancedCustomShapeMetalType::MetalMSCompatible
);
549 // Test, that attribute is written with 'loext' namespace in extended version before ODF 1.4
550 SetODFDefaultVersion(SvtSaveOptions::ODFVER_013_EXTENDED
);
551 // As of Nov 2024, validating against a version other than LATEST is not implemented.
553 saveAndReload(u
"writer8"_ustr
);
556 pXmlDoc
= parseExport(u
"content.xml"_ustr
);
557 assertXPath(pXmlDoc
, "//draw:enhanced-geometry", "extrusion-metal", u
"true");
559 "//draw:enhanced-geometry[@loext:extrusion-metal-type='loext:MetalMSCompatible']");
562 uno::Reference
<drawing::XShape
> xShapeReload2(getShape(0));
563 lcl_assertMetalProperties("from ODF 1.3 extended", xShapeReload2
,
564 css::drawing::EnhancedCustomShapeMetalType::MetalMSCompatible
);
567 CPPUNIT_TEST_FIXTURE(XmloffDrawTest
, testExtrusionMetalTypeStrict
)
569 Resetter
resetter([]() { SetODFDefaultVersion(SvtSaveOptions::ODFVER_LATEST
); });
570 loadFromFile(u
"tdf145700_3D_metal_type_MSCompatible.doc");
572 // save in ODF 1.4 strict and test that new attribute is written.
573 SetODFDefaultVersion(SvtSaveOptions::ODFVER_014
);
574 save(u
"writer8"_ustr
);
575 xmlDocUniquePtr pXmlDoc
= parseExport(u
"content.xml"_ustr
);
576 assertXPath(pXmlDoc
, "//draw:enhanced-geometry", "extrusion-metal", u
"true");
578 "//draw:enhanced-geometry[@draw:extrusion-metal-type='loext:MetalMSCompatible']");
580 // save in ODF 1.3 strict and test that new attribute is not written.
581 SetODFDefaultVersion(SvtSaveOptions::ODFVER_013
);
582 // As of Nov 2024, validating against a version other than LATEST is not implemented.
584 save(u
"writer8"_ustr
);
585 pXmlDoc
= parseExport(u
"content.xml"_ustr
);
586 assertXPath(pXmlDoc
, "//draw:enhanced-geometry", "extrusion-metal", u
"true");
587 assertXPathNoAttribute(pXmlDoc
, "//draw:enhanced-geometry", "extrusion-metal-type");
590 CPPUNIT_TEST_FIXTURE(XmloffDrawTest
, testExtrusionMetalTypeODF
)
592 Resetter
resetter([]() { SetODFDefaultVersion(SvtSaveOptions::ODFVER_LATEST
); });
593 loadFromFile(u
"tdf162686_3D_metal_type_ODF.fods");
595 uno::Reference
<drawing::XShape
> xShape(getShape(0));
596 lcl_assertMetalProperties("from doc", xShape
,
597 css::drawing::EnhancedCustomShapeMetalType::MetalODF
);
599 // Test, that attribute is written with 'draw' namespace in ODF version LATEST
600 saveAndReload(u
"calc8"_ustr
);
603 xmlDocUniquePtr pXmlDoc
= parseExport(u
"content.xml"_ustr
);
604 assertXPath(pXmlDoc
, "//draw:enhanced-geometry", "extrusion-metal", u
"true");
605 assertXPath(pXmlDoc
, "//draw:enhanced-geometry[@draw:extrusion-metal-type='draw:MetalODF']");
608 uno::Reference
<drawing::XShape
> xShapeReload(getShape(0));
609 lcl_assertMetalProperties("from LATEST", xShapeReload
,
610 css::drawing::EnhancedCustomShapeMetalType::MetalODF
);
612 // Test, that export in ODFVER_014 is valid. Needs adaption, when ODF 1.5 comes out.
613 SetODFDefaultVersion(SvtSaveOptions::ODFVER_014
);
614 saveAndReload(u
"calc8"_ustr
);
616 // Test, that attribute is written with 'loext' namespace in extended version before ODF 1.4
617 SetODFDefaultVersion(SvtSaveOptions::ODFVER_013_EXTENDED
);
618 // As of Nov 2024, validating against a version other than LATEST is not implemented.
620 saveAndReload(u
"calc8"_ustr
);
623 pXmlDoc
= parseExport(u
"content.xml"_ustr
);
624 assertXPath(pXmlDoc
, "//draw:enhanced-geometry[@loext:extrusion-metal-type='draw:MetalODF']");
627 uno::Reference
<drawing::XShape
> xShapeReload2(getShape(0));
628 lcl_assertMetalProperties("from ODF 1.3 extended", xShapeReload2
,
629 css::drawing::EnhancedCustomShapeMetalType::MetalODF
);
631 // Test, that attribute is not written at all in strict version before ODF 1.4
632 SetODFDefaultVersion(SvtSaveOptions::ODFVER_013
);
634 pXmlDoc
= parseExport(u
"content.xml"_ustr
);
635 assertXPathNoAttribute(pXmlDoc
, "//draw:enhanced-geometry", "extrusion-metal-type");
638 CPPUNIT_TEST_FIXTURE(XmloffDrawTest
, testHandlePosition
)
640 Resetter
resetter([]() { SetODFDefaultVersion(SvtSaveOptions::ODFVER_LATEST
); });
641 loadFromFile(u
"tdf162691_handle_position.fodt");
643 save(u
"writer8"_ustr
);
644 static constexpr OString
sXPath("/office:document-content/office:body/office:text/text:p/"
645 "draw:custom-shape/draw:enhanced-geometry/draw:handle"_ostr
);
647 xmlDocUniquePtr pXmlDoc
= parseExport(u
"content.xml"_ustr
);
649 assertXPath(pXmlDoc
, sXPath
, "handle-position", u
"$0 10800");
650 assertXPath(pXmlDoc
, sXPath
, "handle-position-x", u
"$0");
651 assertXPath(pXmlDoc
, sXPath
, "handle-position-y", u
"10800");
653 // assert that new attributes are not written in older ODF versions and old one is written.
654 SetODFDefaultVersion(SvtSaveOptions::ODFVER_013_EXTENDED
);
655 // As of Nov 2024, validating against a version other than LATEST is not implemented.
657 save(u
"writer8"_ustr
);
658 pXmlDoc
= parseExport(u
"content.xml"_ustr
);
659 assertXPath(pXmlDoc
, sXPath
, "handle-position", u
"$0 10800");
660 assertXPathNoAttribute(pXmlDoc
, sXPath
, "handle-position-x");
661 assertXPathNoAttribute(pXmlDoc
, sXPath
, "handle-position-y");
664 CPPUNIT_TEST_FIXTURE(XmloffDrawTest
, testHandlePolar
)
666 Resetter
resetter([]() { SetODFDefaultVersion(SvtSaveOptions::ODFVER_LATEST
); });
667 loadFromFile(u
"tdf162691_handle_polar.fodt");
669 save(u
"writer8"_ustr
);
672 xmlDocUniquePtr pXmlDoc
= parseExport(u
"content.xml"_ustr
);
673 static constexpr OString
sXPath("/office:document-content/office:body/office:text/text:p/"
674 "draw:custom-shape/draw:enhanced-geometry/draw:handle"_ostr
);
675 assertXPath(pXmlDoc
, sXPath
, "handle-position", u
"9000 $0");
676 assertXPath(pXmlDoc
, sXPath
, "handle-polar", u
"10800 1000");
677 assertXPath(pXmlDoc
, sXPath
, "handle-polar-angle", u
"$0");
678 assertXPath(pXmlDoc
, sXPath
, "handle-polar-radius", u
"9000");
679 assertXPath(pXmlDoc
, sXPath
, "handle-polar-pole-x", u
"10800");
680 assertXPath(pXmlDoc
, sXPath
, "handle-polar-pole-y", u
"1000");
682 // assert that new attributes are not written in older ODF versions and old ones are written.
683 SetODFDefaultVersion(SvtSaveOptions::ODFVER_013_EXTENDED
);
684 // As of Nov 2024, validating against a version other than LATEST is not implemented.
686 save(u
"writer8"_ustr
);
687 pXmlDoc
= parseExport(u
"content.xml"_ustr
);
688 assertXPath(pXmlDoc
, sXPath
, "handle-position", u
"9000 $0");
689 assertXPath(pXmlDoc
, sXPath
, "handle-polar", u
"10800 1000");
690 assertXPathNoAttribute(pXmlDoc
, sXPath
, "handle-polar-pole-x");
691 assertXPathNoAttribute(pXmlDoc
, sXPath
, "handle-polar-pole-y");
692 assertXPathNoAttribute(pXmlDoc
, sXPath
, "handle-polar-angle");
693 assertXPathNoAttribute(pXmlDoc
, sXPath
, "handle-polar-radius");
698 void lcl_assertSpecularityProperty(std::string_view sInfo
, uno::Reference
<drawing::XShape
>& rxShape
)
700 uno::Reference
<beans::XPropertySet
> xShapeProps(rxShape
, uno::UNO_QUERY
);
701 uno::Sequence
<beans::PropertyValue
> aGeoPropSeq
;
702 xShapeProps
->getPropertyValue(u
"CustomShapeGeometry"_ustr
) >>= aGeoPropSeq
;
703 comphelper::SequenceAsHashMap
aGeoPropMap(aGeoPropSeq
);
704 uno::Sequence
<beans::PropertyValue
> aExtrusionSeq
;
705 aGeoPropMap
.getValue(u
"Extrusion"_ustr
) >>= aExtrusionSeq
;
706 comphelper::SequenceAsHashMap
aExtrusionPropMap(aExtrusionSeq
);
708 double fSpecularity(-1.0);
709 aExtrusionPropMap
.getValue(u
"Specularity"_ustr
) >>= fSpecularity
;
710 OString sMsg
= OString::Concat(sInfo
) + "Specularity";
711 CPPUNIT_ASSERT_EQUAL_MESSAGE(sMsg
.getStr(), 122.0703125, fSpecularity
);
715 CPPUNIT_TEST_FIXTURE(XmloffDrawTest
, testExtrusionSpecularityExtended
)
717 Resetter
resetter([]() { SetODFDefaultVersion(SvtSaveOptions::ODFVER_LATEST
); });
718 loadFromFile(u
"tdf147580_extrusion-specularity.doc");
720 uno::Reference
<drawing::XShape
> xShape(getShape(0));
721 lcl_assertSpecularityProperty("from doc", xShape
);
723 // Test, that attribute is written in draw namespace with value 100% and in loext namespace with
724 // value 122.0703125%.
725 SetODFDefaultVersion(SvtSaveOptions::ODFVER_013_EXTENDED
);
726 // As of Nov 2024, validating against a version other than LATEST is not implemented.
728 saveAndReload(u
"writer8"_ustr
);
731 xmlDocUniquePtr pXmlDoc
= parseExport(u
"content.xml"_ustr
);
732 assertXPath(pXmlDoc
, "//draw:enhanced-geometry[@draw:extrusion-specularity='100%']");
734 "//draw:enhanced-geometry[@loext:extrusion-specularity-loext='122.0703125%']");
737 uno::Reference
<drawing::XShape
> xShapeReload(getShape(0));
738 lcl_assertSpecularityProperty("from ODF 1.3 extended", xShapeReload
);
741 CPPUNIT_TEST_FIXTURE(XmloffDrawTest
, testExtrusionSpecularity
)
743 loadFromFile(u
"tdf147580_extrusion-specularity.doc");
745 uno::Reference
<drawing::XShape
> xShape(getShape(0));
746 lcl_assertSpecularityProperty("from doc", xShape
);
748 saveAndReload(u
"writer8"_ustr
);
751 xmlDocUniquePtr pXmlDoc
= parseExport(u
"content.xml"_ustr
);
752 assertXPath(pXmlDoc
, "//draw:enhanced-geometry[@draw:extrusion-specularity='122.0703125%']");
755 uno::Reference
<drawing::XShape
> xShapeReload(getShape(0));
756 lcl_assertSpecularityProperty("from ODF 1.4", xShapeReload
);
759 CPPUNIT_TEST_FIXTURE(XmloffDrawTest
, testExtrusionSpecularityStrict
)
761 Resetter
resetter([]() { SetODFDefaultVersion(SvtSaveOptions::ODFVER_LATEST
); });
762 loadFromFile(u
"tdf147580_extrusion-specularity.doc");
764 // The file has c3DSpecularAmt="80000" which results internally in specularity=122%.
765 SetODFDefaultVersion(SvtSaveOptions::ODFVER_014
);
766 save(u
"writer8"_ustr
);
767 xmlDocUniquePtr pXmlDoc
= parseExport(u
"content.xml"_ustr
);
768 assertXPath(pXmlDoc
, "//draw:enhanced-geometry[@draw:extrusion-specularity='122.0703125%']");
770 // Save to ODF 1.3 strict and make sure draw:extrusion-specularity="100%" is written and
771 // loext:extrusion-specularity is not written.
772 // As of Nov 2024, validating against a version other than LATEST is not implemented.
774 SetODFDefaultVersion(SvtSaveOptions::ODFVER_013
);
775 save(u
"writer8"_ustr
);
776 pXmlDoc
= parseExport(u
"content.xml"_ustr
);
777 assertXPath(pXmlDoc
, "//draw:enhanced-geometry[@loext:extrusion-specularity]", 0);
778 assertXPath(pXmlDoc
, "//draw:enhanced-geometry[@draw:extrusion-specularity='100%']");
783 bool lcl_getShapeSegments(uno::Sequence
<drawing::EnhancedCustomShapeSegment
>& rSegments
,
784 const uno::Reference
<drawing::XShape
>& xShape
)
786 uno::Reference
<beans::XPropertySet
> xShapeProps(xShape
, uno::UNO_QUERY_THROW
);
787 uno::Any anotherAny
= xShapeProps
->getPropertyValue(u
"CustomShapeGeometry"_ustr
);
788 uno::Sequence
<beans::PropertyValue
> aCustomShapeGeometry
;
789 if (!(anotherAny
>>= aCustomShapeGeometry
))
791 uno::Sequence
<beans::PropertyValue
> aPathProps
;
792 for (beans::PropertyValue
const& rProp
: aCustomShapeGeometry
)
794 if (rProp
.Name
== "Path")
796 rProp
.Value
>>= aPathProps
;
801 for (beans::PropertyValue
const& rProp
: aPathProps
)
803 if (rProp
.Name
== "Segments")
805 rProp
.Value
>>= rSegments
;
809 if (rSegments
.getLength() > 2)
816 CPPUNIT_TEST_FIXTURE(XmloffDrawTest
, testTdf148714_CurvedArrowsOld
)
818 // Load a document with CurveArrow shapes with faulty path as written by older LO versions.
819 loadFromFile(u
"tdf148714_CurvedArrowsOld.odp");
821 // Make sure, that the error has been corrected on opening.
822 for (sal_Int32 nShapeIndex
= 0; nShapeIndex
< 4; nShapeIndex
++)
824 uno::Reference
<drawing::XShape
> xShape(getShape(nShapeIndex
));
825 uno::Sequence
<drawing::EnhancedCustomShapeSegment
> aSegments
;
826 CPPUNIT_ASSERT(lcl_getShapeSegments(aSegments
, xShape
));
828 if (nShapeIndex
== 0 || nShapeIndex
== 3)
830 // curvedDownArrow or curvedLeftArrow. Segments should start with VW. Without fix it was
831 // V with count 2, which means VV.
832 CPPUNIT_ASSERT_EQUAL(
833 sal_Int16(drawing::EnhancedCustomShapeSegmentCommand::CLOCKWISEARC
),
834 aSegments
[0].Command
);
835 CPPUNIT_ASSERT_EQUAL(sal_Int16(1), aSegments
[0].Count
);
836 CPPUNIT_ASSERT_EQUAL(
837 sal_Int16(drawing::EnhancedCustomShapeSegmentCommand::CLOCKWISEARCTO
),
838 aSegments
[1].Command
);
839 CPPUNIT_ASSERT_EQUAL(sal_Int16(1), aSegments
[1].Count
);
843 // curvedUpArrow or curvedRightArrow. Segments should start with BA. Without fix is was
844 // B with count 2, which means BB.
845 CPPUNIT_ASSERT_EQUAL(sal_Int16(drawing::EnhancedCustomShapeSegmentCommand::ARC
),
846 aSegments
[0].Command
);
847 CPPUNIT_ASSERT_EQUAL(sal_Int16(1), aSegments
[0].Count
);
848 CPPUNIT_ASSERT_EQUAL(sal_Int16(drawing::EnhancedCustomShapeSegmentCommand::ARCTO
),
849 aSegments
[1].Command
);
850 CPPUNIT_ASSERT_EQUAL(sal_Int16(1), aSegments
[1].Count
);
855 CPPUNIT_TEST_FIXTURE(XmloffDrawTest
, testTextRotationPlusPre
)
857 loadFromFile(u
"tdf149551_verticalText.pptx");
858 // The file has a shape with attribute vert="vert" in <bodyPr> element. That generates a
859 // TextPreRotateAngle attribute in CustomShapeGeometry.
861 // Add a TextRotateAngle attribute.
862 uno::Reference
<drawing::XShape
> xShape(getShape(0));
863 uno::Reference
<beans::XPropertySet
> xShapeProps(xShape
, uno::UNO_QUERY
);
864 uno::Sequence
<beans::PropertyValue
> aGeomSeq
;
865 xShapeProps
->getPropertyValue(u
"CustomShapeGeometry"_ustr
) >>= aGeomSeq
;
866 auto aGeomVec(comphelper::sequenceToContainer
<std::vector
<beans::PropertyValue
>>(aGeomSeq
));
867 aGeomVec
.push_back(comphelper::makePropertyValue(u
"TextRotateAngle"_ustr
, sal_Int32(45)));
868 aGeomSeq
= comphelper::containerToSequence(aGeomVec
);
869 xShapeProps
->setPropertyValue(u
"CustomShapeGeometry"_ustr
, uno::Any(aGeomSeq
));
871 // Save to ODF. Without the fix, a file format error was produced, because attribute
872 // draw:text-rotate-angle was written twice, one from TextPreRotateAngle and the other from
874 // This should already catch the format error, but does not, see tdf#149567
875 // But reload catches it.
876 saveAndReload(u
"writer8"_ustr
);
879 CPPUNIT_TEST_FIXTURE(XmloffDrawTest
, testTdf156975_ThemeExport
)
881 // It tests, that a theme is written to master page in Draw documents.
882 // Without fix for tdf#156975 it was not written at all.
883 // The test needs to be adapted, when themes are available in ODF.
885 loadFromURL(u
"private:factory/sdraw"_ustr
);
886 // generate a theme to be sure we have got one and know the values
887 uno::Reference
<drawing::XDrawPagesSupplier
> xDrawPagesSupplier(mxComponent
, uno::UNO_QUERY
);
888 uno::Reference
<drawing::XMasterPageTarget
> xDrawPage(
889 xDrawPagesSupplier
->getDrawPages()->getByIndex(0), uno::UNO_QUERY
);
890 uno::Reference
<beans::XPropertySet
> xMasterPageProps(xDrawPage
->getMasterPage(),
893 auto pTheme
= std::make_shared
<model::Theme
>("Custom");
894 auto pColorSet
= std::make_shared
<model::ColorSet
>("My Colors");
895 pColorSet
->add(model::ThemeColorType::Dark1
, 0x000000);
896 pColorSet
->add(model::ThemeColorType::Light1
, 0xffff11);
897 pColorSet
->add(model::ThemeColorType::Dark2
, 0x002200);
898 pColorSet
->add(model::ThemeColorType::Light2
, 0xff33ff);
899 pColorSet
->add(model::ThemeColorType::Accent1
, 0x440000);
900 pColorSet
->add(model::ThemeColorType::Accent2
, 0x005500);
901 pColorSet
->add(model::ThemeColorType::Accent3
, 0x000066);
902 pColorSet
->add(model::ThemeColorType::Accent4
, 0x777700);
903 pColorSet
->add(model::ThemeColorType::Accent5
, 0x880088);
904 pColorSet
->add(model::ThemeColorType::Accent6
, 0x009999);
905 pColorSet
->add(model::ThemeColorType::Hyperlink
, 0x0a0a0a);
906 pColorSet
->add(model::ThemeColorType::FollowedHyperlink
, 0xb0b0b0);
907 pTheme
->setColorSet(pColorSet
);
909 uno::Reference
<util::XTheme
> xTheme
= model::theme::createXTheme(pTheme
);
910 xMasterPageProps
->setPropertyValue(u
"Theme"_ustr
, uno::Any(xTheme
));
915 // and check the markup.
916 xmlDocUniquePtr pXmlDoc
= parseExport(u
"styles.xml"_ustr
);
917 static constexpr OString sThemePath
918 = "//office:master-styles/style:master-page/loext:theme"_ostr
;
919 assertXPath(pXmlDoc
, sThemePath
, 1);
920 assertXPath(pXmlDoc
, sThemePath
+ "[@loext:name='Custom']");
922 const OString sThemeColorsPath
= sThemePath
+ "/loext:theme-colors";
923 assertXPath(pXmlDoc
, sThemeColorsPath
, 1);
924 assertXPath(pXmlDoc
, sThemeColorsPath
+ "[@loext:name='My Colors']");
926 const OString sThemeColorPath
= sThemeColorsPath
+ "/loext:color";
927 assertXPath(pXmlDoc
, sThemeColorPath
, 12);
928 assertXPath(pXmlDoc
, sThemeColorPath
+ "[3]", "name", u
"dark2");
929 assertXPath(pXmlDoc
, sThemeColorPath
+ "[3]", "color", u
"#002200");
930 assertXPath(pXmlDoc
, sThemeColorPath
+ "[9]", "name", u
"accent5");
931 assertXPath(pXmlDoc
, sThemeColorPath
+ "[9]", "color", u
"#880088");
932 assertXPath(pXmlDoc
, sThemeColorPath
+ "[12]", "name", u
"followed-hyperlink");
933 assertXPath(pXmlDoc
, sThemeColorPath
+ "[12]", "color", u
"#b0b0b0");
936 CPPUNIT_TEST_FIXTURE(XmloffDrawTest
, testTdf157018_ThemeImportDraw
)
938 // Similar to testThemeImport but for Draw.
939 // Load document with custom color theme
940 loadFromFile(u
"tdf157018_CustomTheme.fodg");
942 // First make sure the doc model has a master page with a theme:
943 uno::Reference
<drawing::XDrawPagesSupplier
> xDrawPagesSupplier(mxComponent
, uno::UNO_QUERY
);
944 uno::Reference
<drawing::XMasterPageTarget
> xDrawPage(
945 xDrawPagesSupplier
->getDrawPages()->getByIndex(0), uno::UNO_QUERY
);
946 uno::Reference
<beans::XPropertySet
> xMasterpage(xDrawPage
->getMasterPage(), uno::UNO_QUERY
);
948 uno::Reference
<util::XTheme
> xTheme
;
949 xMasterpage
->getPropertyValue(u
"Theme"_ustr
) >>= xTheme
;
950 CPPUNIT_ASSERT(xTheme
.is());
952 // Then make sure it is the custom color theme
953 auto* pUnoTheme
= dynamic_cast<UnoTheme
*>(xTheme
.get());
954 CPPUNIT_ASSERT(pUnoTheme
);
955 auto pTheme
= pUnoTheme
->getTheme();
956 CPPUNIT_ASSERT(pTheme
);
958 CPPUNIT_ASSERT_EQUAL(u
"Custom"_ustr
, pTheme
->GetName());
959 auto pColorSet
= pTheme
->getColorSet();
960 CPPUNIT_ASSERT(pColorSet
);
961 CPPUNIT_ASSERT_EQUAL(u
"My Colors"_ustr
, pColorSet
->getName());
963 // and test some colors
964 CPPUNIT_ASSERT_EQUAL(Color(0xFFFF11), pColorSet
->getColor(model::ThemeColorType::Light1
));
965 CPPUNIT_ASSERT_EQUAL(Color(0x0A0A0A), pColorSet
->getColor(model::ThemeColorType::Hyperlink
));
966 CPPUNIT_ASSERT_EQUAL(Color(0x440000), pColorSet
->getColor(model::ThemeColorType::Accent1
));
969 CPPUNIT_TEST_FIXTURE(XmloffDrawTest
, test_scene3d_ooxml_light
)
971 // The document has a shape in 3D mode. The import of ooxml light rigs can produce light
972 // levels outside the 0..100 range allowed in ODF. Such high levels are needed for rendering
973 // similar to MS Office.
974 loadFromFile(u
"Scene3d_LightRig_threePt.pptx");
976 // Without fix this would have failed with validation error.
977 save(u
"impress8"_ustr
);
980 CPPUNIT_TEST_FIXTURE(XmloffDrawTest
, testTdf161327_LatheEndAngle
)
982 // Load document with 3D-Scene with 4 rotation objects
983 loadFromFile(u
"tdf161327_LatheEndAngle.fodg");
986 uno::Reference
<drawing::XShape
> xSceneShape(getShape(0));
987 static constexpr OUString
sExpected(u
"com.sun.star.drawing.Shape3DSceneObject"_ustr
);
988 CPPUNIT_ASSERT_EQUAL(sExpected
, xSceneShape
->getShapeType());
990 // Examine child objects
991 // [0] dr3d:end-angle="1512"
992 // [1] dr3d:end-angle="151.2deg"
993 // [2] dr3d:end-angle="168.0grad"
994 // [3] dr3d:end-angle="2.638937829015430rad"
995 // All cases should result in D3DEndAngle = 1512. Without fix, cases [1], [2] and [3]
996 // could not be read and default 3600 was used, although the values are valid in ODF.
997 for (size_t i
= 0; i
< 4; ++i
)
999 uno::Reference
<container::XIndexAccess
> xGroup(xSceneShape
, uno::UNO_QUERY
);
1000 uno::Reference
<drawing::XShape
> xShape(xGroup
->getByIndex(i
), uno::UNO_QUERY
);
1001 uno::Reference
<beans::XPropertySet
> xShapeProps(xShape
, uno::UNO_QUERY
);
1002 sal_Int16 nEndAngle
;
1003 xShapeProps
->getPropertyValue(u
"D3DEndAngle"_ustr
) >>= nEndAngle
;
1004 CPPUNIT_ASSERT_EQUAL(sal_Int16(1512), nEndAngle
);
1008 CPPUNIT_TEST_FIXTURE(XmloffDrawTest
, testTdf161327_HatchAngle
)
1010 // Load document with four rectangles with linear hatch background fill
1011 loadFromFile(u
"tdf161327_HatchAngle.fodg");
1013 // The hatch angle is given in file as
1014 // [0] 585 unit less
1017 // [3] 1.01201761241668rad
1018 // The resulting angle should be 585 (meaning 1/10 of a degree) in all cases.
1019 // Cases [1], [2] and [3] had angle 0 without fix.
1020 for (size_t i
= 0; i
< 4; ++i
)
1022 uno::Reference
<drawing::XShape
> xShape(getShape(i
));
1023 uno::Reference
<beans::XPropertySet
> xShapeProps(xShape
, uno::UNO_QUERY
);
1024 constexpr css::drawing::FillStyle eExpectedStyle
= css::drawing::FillStyle_HATCH
;
1025 css::drawing::FillStyle aActualStyle
;
1026 xShapeProps
->getPropertyValue(u
"FillStyle"_ustr
) >>= aActualStyle
;
1027 CPPUNIT_ASSERT_EQUAL(eExpectedStyle
, aActualStyle
);
1028 sal_Int32 nExpectedAngle
= 585; // FillHatch.Angle has data type 'long'
1029 css::drawing::Hatch aActualHatch
;
1030 xShapeProps
->getPropertyValue(u
"FillHatch"_ustr
) >>= aActualHatch
;
1031 CPPUNIT_ASSERT_EQUAL(nExpectedAngle
, aActualHatch
.Angle
);
1035 CPPUNIT_TEST_FIXTURE(XmloffDrawTest
, testTdf161483_ShadowSlant
)
1037 // Load document with four 3D-scenes, that differ in the draw:shadow-slant value
1038 loadFromFile(u
"tdf161483_ShadowSlant.fodg");
1040 // The shadow-slant angle is given in file as
1044 // [3] 1.628318530717959rad
1045 // The resulting angle should be 36 in all cases.
1046 // Cases [1], [2] and [3] had angle 0 without fix.
1048 constexpr sal_Int16 nExpectedAngle
= 36; // D3DSceneShadowSlant has data type 'short'
1049 for (size_t i
= 0; i
< 4; ++i
)
1051 uno::Reference
<drawing::XShape
> xShape(getShape(i
));
1052 uno::Reference
<beans::XPropertySet
> xShapeProps(xShape
, uno::UNO_QUERY
);
1053 sal_Int16 nActualAngle
;
1054 xShapeProps
->getPropertyValue(u
"D3DSceneShadowSlant"_ustr
) >>= nActualAngle
;
1055 CPPUNIT_ASSERT_EQUAL(nExpectedAngle
, nActualAngle
);
1059 CPPUNIT_TEST_FIXTURE(XmloffDrawTest
, testTdf161483_CircleStartEndAngle
)
1061 // Load document with four 'Arc' shapes, which differ in the type of start and end angles
1062 loadFromFile(u
"tdf161483_CircleStartEndAngle.fodg");
1064 // The start and end angles are given in file as
1065 // [0] unitless: start 337.5 end 306
1066 // [1] deg: start 337.5deg end 306deg
1067 // [2] grad: start 375grad end 340grad
1068 // [3] rad: start 5.89048622548086rad end 5.34070751110265rad
1069 // The resulting angle should be 33750 and 30600 in all cases.
1071 // CircleStartAngle and CircleEndAngle have data type 'long', meaning Degree100
1072 constexpr sal_Int32 nExpectedStartAngle
= 33750;
1073 constexpr sal_Int32 nExpectedEndAngle
= 30600;
1074 for (size_t i
= 0; i
< 4; ++i
)
1076 uno::Reference
<drawing::XShape
> xShape(getShape(i
));
1077 uno::Reference
<beans::XPropertySet
> xShapeProps(xShape
, uno::UNO_QUERY
);
1078 sal_Int32 nActualStartAngle
;
1079 xShapeProps
->getPropertyValue(u
"CircleStartAngle"_ustr
) >>= nActualStartAngle
;
1080 CPPUNIT_ASSERT_EQUAL(nExpectedStartAngle
, nActualStartAngle
);
1081 sal_Int32 nActualEndAngle
;
1082 xShapeProps
->getPropertyValue(u
"CircleEndAngle"_ustr
) >>= nActualEndAngle
;
1083 CPPUNIT_ASSERT_EQUAL(nExpectedEndAngle
, nActualEndAngle
);
1087 CPPUNIT_PLUGIN_IMPLEMENT();
1089 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */