tdf#130857 qt weld: Implement QtInstanceWidget::get_text_height
[LibreOffice.git] / xmloff / qa / unit / draw.cxx
blob2d1a4c533f2455c8cfca9c7481cfbc5dbc6f3f5f
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 <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
42 public:
43 XmloffDrawTest();
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())
53 return xPortion;
54 uno::Reference<container::XEnumeration> xEnum(xEnumAccess->createEnumeration());
55 uno::Reference<text::XTextContent> xTextContent;
56 xEnum->nextElement() >>= xTextContent;
57 if (!xTextContent.is())
58 return xPortion;
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)
66 ++nCurrent;
67 xPortion
68 = uno::Reference<beans::XPropertySet>(xParaEnum->nextElement(), uno::UNO_QUERY);
70 return xPortion;
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);
87 return xShape;
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
114 save(u"draw8"_ustr);
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));
150 // Export to ODP:
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:
156 // - Expected: 12
157 // - Actual : 0
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:
195 // - Expected: 1
196 // - Actual : 0
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));
236 namespace
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);
296 // Text color
297 OString aStyle1(
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");
306 OString aStyle2(
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");
315 OString aStyle3(
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");
322 // Shapes fill color
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);
398 // Char color theme
399 // Shape 4
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);
420 // Shape 5
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);
441 // Shape 6
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
483 // Frame):
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.
501 namespace
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");
530 // verify properties
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);
538 // assert XML.
539 xmlDocUniquePtr pXmlDoc = parseExport(u"content.xml"_ustr);
540 assertXPath(pXmlDoc, "//draw:enhanced-geometry", "extrusion-metal", u"true");
541 assertXPath(pXmlDoc,
542 "//draw:enhanced-geometry[@draw:extrusion-metal-type='loext:MetalMSCompatible']");
544 // verify properties
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.
552 skipValidation();
553 saveAndReload(u"writer8"_ustr);
555 // assert XML.
556 pXmlDoc = parseExport(u"content.xml"_ustr);
557 assertXPath(pXmlDoc, "//draw:enhanced-geometry", "extrusion-metal", u"true");
558 assertXPath(pXmlDoc,
559 "//draw:enhanced-geometry[@loext:extrusion-metal-type='loext:MetalMSCompatible']");
561 // verify properties
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");
577 assertXPath(pXmlDoc,
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.
583 skipValidation();
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");
594 // verify properties
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);
602 // assert XML.
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']");
607 // verify properties
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.
619 skipValidation();
620 saveAndReload(u"calc8"_ustr);
622 // assert XML.
623 pXmlDoc = parseExport(u"content.xml"_ustr);
624 assertXPath(pXmlDoc, "//draw:enhanced-geometry[@loext:extrusion-metal-type='draw:MetalODF']");
626 // verify properties
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);
633 save(u"calc8"_ustr);
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);
646 // assert XML.
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.
656 skipValidation();
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);
671 // assert XML.
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.
685 skipValidation();
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");
696 namespace
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");
719 // verify property
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.
727 skipValidation();
728 saveAndReload(u"writer8"_ustr);
730 // assert XML.
731 xmlDocUniquePtr pXmlDoc = parseExport(u"content.xml"_ustr);
732 assertXPath(pXmlDoc, "//draw:enhanced-geometry[@draw:extrusion-specularity='100%']");
733 assertXPath(pXmlDoc,
734 "//draw:enhanced-geometry[@loext:extrusion-specularity-loext='122.0703125%']");
736 // verify properties
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");
744 // verify property
745 uno::Reference<drawing::XShape> xShape(getShape(0));
746 lcl_assertSpecularityProperty("from doc", xShape);
748 saveAndReload(u"writer8"_ustr);
750 // assert XML.
751 xmlDocUniquePtr pXmlDoc = parseExport(u"content.xml"_ustr);
752 assertXPath(pXmlDoc, "//draw:enhanced-geometry[@draw:extrusion-specularity='122.0703125%']");
754 // verify properties
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.
773 skipValidation();
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%']");
781 namespace
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))
790 return false;
791 uno::Sequence<beans::PropertyValue> aPathProps;
792 for (beans::PropertyValue const& rProp : aCustomShapeGeometry)
794 if (rProp.Name == "Path")
796 rProp.Value >>= aPathProps;
797 break;
801 for (beans::PropertyValue const& rProp : aPathProps)
803 if (rProp.Name == "Segments")
805 rProp.Value >>= rSegments;
806 break;
809 if (rSegments.getLength() > 2)
810 return true;
811 else
812 return false;
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);
841 else
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
873 // TextRotateAngle.
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(),
891 uno::UNO_QUERY);
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));
912 // save as odg
913 save(u"draw8"_ustr);
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");
985 // get scene object
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
1015 // [1] 58.5deg,
1016 // [2] 65grad,
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
1041 // [0] 36 unitless
1042 // [1] 36deg,
1043 // [2] 40grad,
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: */