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 <sal/config.h>
14 #include <test/unoapi_test.hxx>
15 #include <rtl/ustring.hxx>
16 #include <basegfx/polygon/b2dpolypolygon.hxx>
17 #include <basegfx/polygon/b2dpolygon.hxx>
18 #include <basegfx/point/b2dpoint.hxx>
19 #include <comphelper/propertyvalue.hxx>
20 #include <editeng/unoprnms.hxx>
21 #include <sfx2/request.hxx>
22 #include <sfx2/viewfrm.hxx>
23 #include <sfx2/viewsh.hxx>
24 #include <svl/intitem.hxx>
25 #include <svx/EnhancedCustomShape2d.hxx>
26 #include <svx/extrusionbar.hxx>
27 #include <svx/graphichelper.hxx>
28 #include <svx/svdoashp.hxx>
29 #include <svx/svdopath.hxx>
30 #include <svx/svdview.hxx>
31 #include <svx/svxids.hrc>
32 #include <unotools/mediadescriptor.hxx>
33 #include <unotools/tempfile.hxx>
34 #include <vcl/filter/PngImageReader.hxx>
35 #include <vcl/BitmapReadAccess.hxx>
37 #include <cppunit/TestAssert.h>
39 #include <com/sun/star/awt/Rectangle.hpp>
40 #include <com/sun/star/beans/XPropertySet.hpp>
41 #include <com/sun/star/drawing/EnhancedCustomShapeSegment.hpp>
42 #include <com/sun/star/drawing/EnhancedCustomShapeSegmentCommand.hpp>
43 #include <com/sun/star/drawing/GraphicExportFilter.hpp>
44 #include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
45 #include <com/sun/star/drawing/XDrawPage.hpp>
46 #include <com/sun/star/frame/Desktop.hpp>
47 #include <com/sun/star/frame/XStorable.hpp>
49 using namespace ::com::sun::star
;
53 /// Tests for svx/source/customshapes/ code.
54 class CustomshapesTest
: public UnoApiTest
58 : UnoApiTest("svx/qa/unit/data/")
63 // get shape nShapeIndex from page 0
64 uno::Reference
<drawing::XShape
> getShape(sal_uInt8 nShapeIndex
);
65 sal_uInt8
countShapes();
68 uno::Reference
<drawing::XShape
> CustomshapesTest::getShape(sal_uInt8 nShapeIndex
)
70 uno::Reference
<drawing::XDrawPagesSupplier
> xDrawPagesSupplier(mxComponent
,
71 uno::UNO_QUERY_THROW
);
72 CPPUNIT_ASSERT_MESSAGE("Could not get XDrawPagesSupplier", xDrawPagesSupplier
.is());
73 uno::Reference
<drawing::XDrawPages
> xDrawPages(xDrawPagesSupplier
->getDrawPages());
74 uno::Reference
<drawing::XDrawPage
> xDrawPage(xDrawPages
->getByIndex(0), uno::UNO_QUERY_THROW
);
75 CPPUNIT_ASSERT_MESSAGE("Could not get xDrawPage", xDrawPage
.is());
76 uno::Reference
<drawing::XShape
> xShape(xDrawPage
->getByIndex(nShapeIndex
), uno::UNO_QUERY
);
77 CPPUNIT_ASSERT_MESSAGE("Could not get xShape", xShape
.is());
81 sal_uInt8
CustomshapesTest::countShapes()
83 uno::Reference
<drawing::XDrawPagesSupplier
> xDrawPagesSupplier(mxComponent
,
84 uno::UNO_QUERY_THROW
);
85 CPPUNIT_ASSERT_MESSAGE("Could not get XDrawPagesSupplier", xDrawPagesSupplier
.is());
86 uno::Reference
<drawing::XDrawPages
> xDrawPages(xDrawPagesSupplier
->getDrawPages());
87 uno::Reference
<drawing::XDrawPage
> xDrawPage(xDrawPages
->getByIndex(0), uno::UNO_QUERY_THROW
);
88 CPPUNIT_ASSERT_MESSAGE("Could not get xDrawPage", xDrawPage
.is());
89 return xDrawPage
->getCount();
92 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testTdf147409_GeomItemHash
)
94 loadFromURL(u
"tdf147409_GeomItemHash.odg");
95 uno::Reference
<drawing::XShape
> xShape(getShape(0));
96 SdrObjCustomShape
* pSdrCustomShape(
97 static_cast<SdrObjCustomShape
*>(SdrObject::getSdrObjectFromXShape(xShape
)));
100 SfxViewShell
* pViewShell
= SfxViewShell::Current();
101 SdrView
* pSdrView
= pViewShell
->GetDrawView();
102 pSdrView
->MarkObj(pSdrCustomShape
, pSdrView
->GetSdrPageView());
104 // Apply FontworkSameLetterHeights toggle
105 // Without patch a debug build fails assert in SfxItemPool::PutImpl and so crashes.
106 dispatchCommand(mxComponent
, ".uno:FontworkSameLetterHeights", {});
109 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testTdf146866_GeomItemHash
)
111 loadFromURL(u
"tdf147409_GeomItemHash.odg");
112 uno::Reference
<drawing::XShape
> xShape(getShape(0));
113 SdrObjCustomShape
* pSdrCustomShape(
114 static_cast<SdrObjCustomShape
*>(SdrObject::getSdrObjectFromXShape(xShape
)));
117 SfxViewShell
* pViewShell
= SfxViewShell::Current();
118 SdrView
* pSdrView
= pViewShell
->GetDrawView();
119 pSdrView
->MarkObj(pSdrCustomShape
, pSdrView
->GetSdrPageView());
121 // Apply extrusion toggle
122 // Without patch a debug build fails assert in SfxItemPool::PutImpl and so crashes.
123 dispatchCommand(mxComponent
, ".uno:ExtrusionToggle", {});
126 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testTdf145700_3D_NonUI
)
128 // The document contains first light soft, no ambient color, no second light and shininess 6.
129 // Such settings are not available in the UI. It tests the actual color, not the geometry.
131 loadFromURL(u
"tdf145700_3D_NonUI.doc");
133 // Generate bitmap from shape
134 uno::Reference
<drawing::XShape
> xShape
= getShape(0);
135 GraphicHelper::SaveShapeAsGraphicToPath(mxComponent
, xShape
, "image/png", maTempFile
.GetURL());
137 // Read bitmap and test color
138 // The expected values are taken from an image generated by Word
139 // Without the changed methods the colors were in range RGB(17,11,17) to RGB(87,55,89).
140 SvFileStream
aFileStream(maTempFile
.GetURL(), StreamMode::READ
);
141 vcl::PngImageReader
aPNGReader(aFileStream
);
142 BitmapEx aBMPEx
= aPNGReader
.read();
143 Bitmap aBMP
= aBMPEx
.GetBitmap();
144 Bitmap::ScopedReadAccess
pRead(aBMP
);
145 Size aSize
= aBMP
.GetSizePixel();
147 Color aActualColor
= pRead
->GetColor(aSize
.Height() / 2, aSize
.Width() * 0.125);
148 Color
aExpectedColor(107, 67, 109);
149 sal_uInt16 nColorDistance
= aExpectedColor
.GetColorError(aActualColor
);
150 CPPUNIT_ASSERT_LESS(sal_uInt16(6), nColorDistance
);
151 // The current solution for soft light still can be improved. nColorDistance is high.
152 aActualColor
= pRead
->GetColor(aSize
.Height() / 2, aSize
.Width() * 0.45);
153 aExpectedColor
= Color(179, 113, 183);
154 nColorDistance
= aExpectedColor
.GetColorError(aActualColor
);
155 CPPUNIT_ASSERT_LESS(sal_uInt16(54), nColorDistance
);
156 // This point tests whether shininess is read and used. With default shininess it would be white.
157 aActualColor
= pRead
->GetColor(aSize
.Height() / 2, aSize
.Width() * 0.72);
158 aExpectedColor
= Color(255, 231, 255);
159 nColorDistance
= aExpectedColor
.GetColorError(aActualColor
);
160 CPPUNIT_ASSERT_LESS(sal_uInt16(14), nColorDistance
);
163 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testTdf145700_3D_FrontLightDim
)
165 // This tests the actual color, not the geometry.
167 loadFromURL(u
"tdf145700_3D_FrontLightDim.doc");
169 // Generate bitmap from shape
170 uno::Reference
<drawing::XShape
> xShape
= getShape(0);
171 GraphicHelper::SaveShapeAsGraphicToPath(mxComponent
, xShape
, "image/png", maTempFile
.GetURL());
173 // Read bitmap and test color
174 // The expected values are taken from an image generated by Word
175 // Without the changed methods the nColorDistance was 476 and 173 respectively.
176 SvFileStream
aFileStream(maTempFile
.GetURL(), StreamMode::READ
);
177 vcl::PngImageReader
aPNGReader(aFileStream
);
178 BitmapEx aBMPEx
= aPNGReader
.read();
179 Bitmap aBMP
= aBMPEx
.GetBitmap();
180 Bitmap::ScopedReadAccess
pRead(aBMP
);
181 Size aSize
= aBMP
.GetSizePixel();
183 Color aActualColor
= pRead
->GetColor(aSize
.Height() / 2, aSize
.Width() * 0.4);
184 Color
aExpectedColor(240, 224, 229);
185 sal_uInt16 nColorDistance
= aExpectedColor
.GetColorError(aActualColor
);
186 CPPUNIT_ASSERT_LESS(sal_uInt16(9), nColorDistance
);
187 aActualColor
= pRead
->GetColor(aSize
.Height() / 2, aSize
.Width() * 0.9);
188 aExpectedColor
= Color(96, 90, 92);
189 nColorDistance
= aExpectedColor
.GetColorError(aActualColor
);
190 CPPUNIT_ASSERT_LESS(sal_uInt16(6), nColorDistance
);
193 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testTdf145700_3D_FirstLightHarsh
)
196 loadFromURL(u
"tdf145700_3D_FirstLightHarsh.doc");
198 // Generate bitmap from shape
199 uno::Reference
<drawing::XShape
> xShape
= getShape(0);
200 GraphicHelper::SaveShapeAsGraphicToPath(mxComponent
, xShape
, "image/png", maTempFile
.GetURL());
202 // Read bitmap and test color in center
203 SvFileStream
aFileStream(maTempFile
.GetURL(), StreamMode::READ
);
204 vcl::PngImageReader
aPNGReader(aFileStream
);
205 BitmapEx aBMPEx
= aPNGReader
.read();
206 Bitmap aBMP
= aBMPEx
.GetBitmap();
207 Bitmap::ScopedReadAccess
pRead(aBMP
);
208 Size aSize
= aBMP
.GetSizePixel();
210 const Color aActualColor
= pRead
->GetColor(aSize
.Height() / 2, aSize
.Width() / 2);
211 const Color
aExpectedColor(211, 247, 255); // from image generated by Word
212 sal_uInt16 nColorDistance
= aExpectedColor
.GetColorError(aActualColor
);
213 CPPUNIT_ASSERT_LESS(sal_uInt16(3), nColorDistance
);
216 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testTdf145956_Origin_Relative_BoundRect
)
218 // The ViewPoint is relative to point Origin. The coordinates of point Origin are fractions of
219 // the actual (2D) bounding rectangle of the shape, including rotation around z-axis and flip.
220 // Error (among others) was, that the unrotated snap rectangle was used.
223 loadFromURL(u
"tdf145956_Origin.odp");
225 // The shape is extruded with 10cm. viewpoint="(0cm 0cm 25cm)", origin="0 0".
226 uno::Reference
<drawing::XShape
> xShape(getShape(0));
227 uno::Reference
<beans::XPropertySet
> xPropSet(xShape
, uno::UNO_QUERY
);
228 CPPUNIT_ASSERT_MESSAGE("Could not get the properties", xPropSet
.is());
229 awt::Rectangle aBoundRect
;
230 xPropSet
->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT
) >>= aBoundRect
;
231 sal_Int32 nActualTop
= aBoundRect
.Y
;
233 // Without the fix it would have failed with top = 9462.
234 // The tolerance 10 is estimated and can be adjusted if required for HiDPI.
235 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("top", 10448, nActualTop
, 10);
238 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testTdf145904_Extrusion_CenterZ_odt
)
240 // The Z-component of the extrusion rotation center specifies the position in Hmm.
241 // Error (among others) was, that the value was interpreted as Twips.
244 loadFromURL(u
"tdf145904_center_Zminus2000.odt");
246 // The shape is extruded and tilt left 60deg. The rotation center is at -2000Hmm on the z-axis.
247 // That is a position behind the back face of the extruded shape.
248 uno::Reference
<drawing::XShape
> xShape(getShape(0));
249 uno::Reference
<beans::XPropertySet
> xPropSet(xShape
, uno::UNO_QUERY
);
250 CPPUNIT_ASSERT_MESSAGE("Could not get the properties", xPropSet
.is());
251 awt::Rectangle aBoundRect
;
252 xPropSet
->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT
) >>= aBoundRect
;
253 awt::Point aAnchorPosition
;
254 xPropSet
->getPropertyValue("AnchorPosition") >>= aAnchorPosition
;
255 sal_Int32 nActualLeft
= aBoundRect
.X
- aAnchorPosition
.X
;
257 // Without the fix it would have failed with left = 7731.
258 // The tolerance 10 is estimated and can be adjusted if required for HiDPI.
259 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("left", 3501, nActualLeft
, 10);
262 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testTdf145904_Extrusion_CenterY_odt
)
264 // The X- and Y-component of the extrusion rotation center specify the position as fraction of
265 // shape size. Error was, that the relative fraction was handled as absolute value in Hmm.
268 loadFromURL(u
"tdf145904_center_Y0dot25.odt");
270 // The shape is extruded and tilt down 90deg. The rotation center is in the middle between shape
271 // center and bottom shape edge. The bottom edge of the projected solid has roughly the
272 // y-coordinate of the rotation center.
273 uno::Reference
<drawing::XShape
> xShape(getShape(0));
274 uno::Reference
<beans::XPropertySet
> xPropSet(xShape
, uno::UNO_QUERY
);
275 CPPUNIT_ASSERT_MESSAGE("Could not get the properties", xPropSet
.is());
276 awt::Rectangle aBoundRect
;
277 xPropSet
->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT
) >>= aBoundRect
;
278 awt::Point aAnchorPosition
;
279 xPropSet
->getPropertyValue("AnchorPosition") >>= aAnchorPosition
;
280 sal_Int32 nActualTop
= aBoundRect
.Y
- aAnchorPosition
.Y
;
282 // Without the fix it would have failed with top = 2252.
283 // The tolerance 10 is estimated and can be adjusted if required for HiDPI.
284 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("top", 3208, nActualTop
, 10);
287 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testTdf145904_Extrusion_CenterY_doc
)
289 // The X- and Y-component of the extrusion rotation center specify the position as fraction of
290 // shape size. Error was, that the relative fraction was handled as absolute value in EMU.
293 loadFromURL(u
"tdf145904_center_Y0dot25.doc");
295 // The shape is extruded and tilt down 90deg. The rotation center is in the middle between shape
296 // center and bottom shape edge. The bottom edge of the projected solid has roughly the
297 // y-coordinate of the center.
298 uno::Reference
<drawing::XShape
> xShape(getShape(0));
299 uno::Reference
<beans::XPropertySet
> xPropSet(xShape
, uno::UNO_QUERY
);
300 CPPUNIT_ASSERT_MESSAGE("Could not get the properties", xPropSet
.is());
301 awt::Rectangle aBoundRect
;
302 xPropSet
->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT
) >>= aBoundRect
;
303 awt::Point aAnchorPosition
;
304 xPropSet
->getPropertyValue("AnchorPosition") >>= aAnchorPosition
;
305 sal_Int32 nActualTop
= aBoundRect
.Y
- aAnchorPosition
.Y
;
307 // Without the fix it would have failed with top = 2330
308 // The tolerance 10 is estimated and can be adjusted if required for HiDPI.
309 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("top", 3208, nActualTop
, 10);
312 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testTdf145245_ExtrusionPosition
)
314 // The second parameter of the extrusion-depth property specifies how much of the extrusion
315 // lies before the shape. The file contains three shapes which have the values 0, 0.5 and 1.
316 // They are rotated around the x-axis so that the extrusion becomes visible. The extrusion
317 // depth itself is 5cm. Y-coordinate of shape is 6cm.
320 loadFromURL(u
"tdf145245_ExtrusionPosition.odp");
322 // The tolerance 40 is estimated and can be adjusted if required for HiDPI.
324 // First shape has extrusion behind the shape.
325 uno::Reference
<drawing::XShape
> xShape0(getShape(0));
326 SdrObjCustomShape
& rSdrCustomShape(
327 static_cast<SdrObjCustomShape
&>(*SdrObject::getSdrObjectFromXShape(xShape0
)));
328 tools::Rectangle
aBoundRect(rSdrCustomShape
.GetCurrentBoundRect());
329 tools::Rectangle
aExpected(Point(1000, 1000), Size(6002, 5001));
330 CPPUNIT_ASSERT_RECTANGLE_EQUAL_WITH_TOLERANCE(aExpected
, aBoundRect
, 40);
333 // Second shape has half of extrusion behind the shape.
334 uno::Reference
<drawing::XShape
> xShape(getShape(1));
335 SdrObjCustomShape
& rSdrCustomShape(
336 static_cast<SdrObjCustomShape
&>(*SdrObject::getSdrObjectFromXShape(xShape
)));
337 // Without the fix the height was 1 instead of 5001.
338 tools::Rectangle
aBoundRect(rSdrCustomShape
.GetCurrentBoundRect());
339 tools::Rectangle
aExpected(Point(9000, 3500), Size(6002, 5001));
340 CPPUNIT_ASSERT_RECTANGLE_EQUAL_WITH_TOLERANCE(aExpected
, aBoundRect
, 40);
343 // Third shape has extrusion before the shape.
344 uno::Reference
<drawing::XShape
> xShape(getShape(2));
345 SdrObjCustomShape
& rSdrCustomShape(
346 static_cast<SdrObjCustomShape
&>(*SdrObject::getSdrObjectFromXShape(xShape
)));
347 // Without the fix the y-coordinate was 1000 instead of 6000.
348 tools::Rectangle
aBoundRect(rSdrCustomShape
.GetCurrentBoundRect());
349 tools::Rectangle
aExpected(Point(18000, 6000), Size(6002, 5001));
350 CPPUNIT_ASSERT_RECTANGLE_EQUAL_WITH_TOLERANCE(aExpected
, aBoundRect
, 40);
354 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testTdf145111_Fontwork_rendering_font_size
)
356 // The tested position and height depend on dpi.
360 // tdf#144988 In case ScaleX is true in property TextPath, the rendering font size should be
361 // reduced in case any of the paragraphs would be longer as its sub-path. That was wrong, if
362 // the first paragraph was too long and the second would fit. It resulted in wrong position
363 // and height and overlapping characters.
365 loadFromURL(u
"tdf144988_Fontwork_FontSize.odp");
366 uno::Reference
<drawing::XShape
> xShape(getShape(0));
367 SdrObjCustomShape
& rSdrCustomShape(
368 static_cast<SdrObjCustomShape
&>(*SdrObject::getSdrObjectFromXShape(xShape
)));
370 // Without the fix in place left|top, width x height was 1279|1279, 2815 x 2448.
371 // The expected values 1501|1777, 3941 x 1446 are only valid for 96dpi.
372 tools::Rectangle
aBoundRect(rSdrCustomShape
.GetCurrentBoundRect());
373 tools::Rectangle
aExpected(Point(1501, 1777), Size(3941, 1446));
374 CPPUNIT_ASSERT_RECTANGLE_EQUAL_WITH_TOLERANCE(aExpected
, aBoundRect
, 5);
377 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testTdf145111_anchor_in_Fontwork
)
379 // The tested positions depend on dpi.
383 // tdf#145004 In case ScaleX is true in property TextPath, SDRTEXTVERTADJUST is
384 // evaluated and should shift the Fontwork text. That did not work for
385 // 'Top-Left' and 'Bottom-Left'.
388 loadFromURL(u
"tdf145111_TL_BL_Fontwork.odp");
391 // First shape has anchor set to Top-Left, which shifts Fontwork text down.
392 uno::Reference
<drawing::XShape
> xShape(getShape(0));
393 SdrObjCustomShape
& rSdrCustomShape(
394 static_cast<SdrObjCustomShape
&>(*SdrObject::getSdrObjectFromXShape(xShape
)));
396 // Without the fix in place top was 2295, but should be 2916 for 96dpi.
397 // Was 2184, should be 2886 for 120dpi.
398 tools::Rectangle
aBoundRect(rSdrCustomShape
.GetCurrentBoundRect());
399 CPPUNIT_ASSERT_DOUBLES_EQUAL(tools::Long(2916), aBoundRect
.Top(), 5);
402 // Second shape has anchor set to Bottom-Left, which shifts Fontwork text up.
403 uno::Reference
<drawing::XShape
> xShape(getShape(1));
404 SdrObjCustomShape
& rSdrCustomShape(
405 static_cast<SdrObjCustomShape
&>(*SdrObject::getSdrObjectFromXShape(xShape
)));
407 // Without the fix in place top was 10294, but should be 9519 for 96dpi.
408 // Was 10184, should be 9481 for 120dpi.
409 tools::Rectangle
aBoundRect(rSdrCustomShape
.GetCurrentBoundRect());
410 CPPUNIT_ASSERT_DOUBLES_EQUAL(tools::Long(9519), aBoundRect
.Top(), 5);
414 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testTdf145004_gap_by_ScaleX
)
418 // tdf#145004 In case property ScaleX=true was set in property 'TextPath' an additional
419 // padding was added to the scaling factor. That results in a gap at start or/and end of
420 // the text. Such gap should not be there.
422 // Load document and get shape. It is a custom shape from pptx import of a WordArt of
423 // kind 'Follow Path'.
424 loadFromURL(u
"tdf145004_gap_by_ScaleX.pptx");
425 uno::Reference
<drawing::XShape
> xShape(getShape(0));
426 SdrObjCustomShape
& rSdrCustomShape(
427 static_cast<SdrObjCustomShape
&>(*SdrObject::getSdrObjectFromXShape(xShape
)));
429 // Verify width. Without the fix in place the width was 8231, but should be 8496 for 96dpi.
430 // Was 8328, should be 8527 for 120dpi.
431 tools::Rectangle
aBoundRect(rSdrCustomShape
.GetCurrentBoundRect());
432 CPPUNIT_ASSERT_DOUBLES_EQUAL(tools::Long(8496), aBoundRect
.GetWidth(), 5);
435 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testTdf141021ExtrusionNorth
)
437 // tdf#141021 Setting extrusion direction in projection method 'perspective' to
438 // 'Extrusion North' had used a wrong origin for the ViewPoint and thus the
439 // side faces were wrong calculated.
441 // Load document and get shape. It is a custom shape in 3D mode.
442 loadFromURL(u
"tdf141021_ExtrusionNorth.odp");
443 uno::Reference
<drawing::XShape
> xShape(getShape(0));
444 SdrObjCustomShape
& rSdrCustomShape(
445 static_cast<SdrObjCustomShape
&>(*SdrObject::getSdrObjectFromXShape(xShape
)));
448 SfxViewShell
* pViewShell
= SfxViewShell::Current();
449 SdrView
* pSdrView
= pViewShell
->GetDrawView();
450 pSdrView
->MarkObj(&rSdrCustomShape
, pSdrView
->GetSdrPageView());
453 SfxRequest
aReq(pViewShell
->GetViewFrame(), SID_EXTRUSION_DIRECTION
);
454 SfxInt32Item
aItem(SID_EXTRUSION_DIRECTION
, 90);
455 aReq
.AppendItem(aItem
);
456 svx::ExtrusionBar::execute(pSdrView
, aReq
, SfxViewFrame::Current()->GetBindings());
458 // Verify height. Without the fix in place the height would 4001.
459 tools::Rectangle
aBoundRect(rSdrCustomShape
.GetCurrentBoundRect());
460 CPPUNIT_ASSERT_EQUAL(tools::Long(5895), aBoundRect
.GetHeight());
463 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testResizeRotatedShape
)
465 // tdf#138945 Setting width or height for a rotated or sheared shape in the Position&Size dialog
466 // had resulted in a mismatch of handle position and shape outline. That becomes visible in object
467 // properties as mismatch of frame rectangle and bound rectangle.
468 // Problem was, that fObjectRotation was not updated.
470 // Load document and get shape. It is a rectangle custom shape with 45° shear and 330° rotation.
471 loadFromURL(u
"tdf138945_resizeRotatedShape.odg");
472 uno::Reference
<drawing::XShape
> xShape(getShape(0));
474 // Change height and mirror vertical
476 SdrObjCustomShape
& rSdrShape(
477 static_cast<SdrObjCustomShape
&>(*SdrObject::getSdrObjectFromXShape(xShape
)));
478 rSdrShape
.NbcResize(rSdrShape
.GetRelativePos(), Fraction(1.0), Fraction(-0.5));
479 tools::Rectangle
aSnapRect(rSdrShape
.GetSnapRect());
480 tools::Rectangle
aBoundRect(rSdrShape
.GetCurrentBoundRect());
481 CPPUNIT_ASSERT_RECTANGLE_EQUAL_WITH_TOLERANCE(aSnapRect
, aBoundRect
, 3);
486 SdrObjCustomShape
& rSdrShape(
487 static_cast<SdrObjCustomShape
&>(*SdrObject::getSdrObjectFromXShape(xShape
)));
488 rSdrShape
.NbcResize(rSdrShape
.GetRelativePos(), Fraction(1.0), Fraction(2.0));
489 tools::Rectangle
aSnapRect(rSdrShape
.GetSnapRect());
490 tools::Rectangle
aBoundRect(rSdrShape
.GetCurrentBoundRect());
491 CPPUNIT_ASSERT_RECTANGLE_EQUAL_WITH_TOLERANCE(aSnapRect
, aBoundRect
, 3);
496 SdrObjCustomShape
& rSdrShape(
497 static_cast<SdrObjCustomShape
&>(*SdrObject::getSdrObjectFromXShape(xShape
)));
498 rSdrShape
.NbcResize(rSdrShape
.GetRelativePos(), Fraction(2.0), Fraction(1.0));
499 tools::Rectangle
aSnapRect(rSdrShape
.GetSnapRect());
500 tools::Rectangle
aBoundRect(rSdrShape
.GetCurrentBoundRect());
501 CPPUNIT_ASSERT_RECTANGLE_EQUAL_WITH_TOLERANCE(aSnapRect
, aBoundRect
, 3);
504 // Change width and mirror horizontal
506 SdrObjCustomShape
& rSdrShape(
507 static_cast<SdrObjCustomShape
&>(*SdrObject::getSdrObjectFromXShape(xShape
)));
508 rSdrShape
.NbcResize(rSdrShape
.GetRelativePos(), Fraction(-0.5), Fraction(1.0));
509 tools::Rectangle
aSnapRect(rSdrShape
.GetSnapRect());
510 tools::Rectangle
aBoundRect(rSdrShape
.GetCurrentBoundRect());
511 CPPUNIT_ASSERT_RECTANGLE_EQUAL_WITH_TOLERANCE(aSnapRect
, aBoundRect
, 3);
515 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testViewBoxLeftTop
)
517 // tdf#121890 formula values "left" and "top" are wrongly calculated
518 // Load a document with two custom shapes of type "non-primitive"
519 loadFromURL(u
"viewBox_positive_twolines_strict.odp");
520 // Get the shape "leftright". Error was, that the identifier "left" was always set to zero, thus
521 // the path was outside the frame rectangle for a viewBox having a positive "left" value.
522 uno::Reference
<drawing::XShape
> xShapeLR(getShape(0));
523 uno::Reference
<beans::XPropertySet
> xShapeLRProps(xShapeLR
, uno::UNO_QUERY
);
524 CPPUNIT_ASSERT_MESSAGE("Could not get the shape 'leftright' properties", xShapeLRProps
.is());
525 awt::Rectangle aFrameRectLR
;
526 xShapeLRProps
->getPropertyValue(UNO_NAME_MISC_OBJ_FRAMERECT
) >>= aFrameRectLR
;
527 awt::Rectangle aBoundRectLR
;
528 xShapeLRProps
->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT
) >>= aBoundRectLR
;
529 // difference should be zero, but allow some rounding errors
530 CPPUNIT_ASSERT_LESS(sal_Int32(3), std::abs(aFrameRectLR
.X
- aBoundRectLR
.X
));
532 // Get the shape "topbottom". Error was, that the identifier "top" was always set to zero, thus
533 // the path was outside the frame rectangle for a viewBox having a positive "top" value.
534 uno::Reference
<drawing::XShape
> xShapeTB(getShape(1));
535 uno::Reference
<beans::XPropertySet
> xShapeTBProps(xShapeTB
, uno::UNO_QUERY
);
536 CPPUNIT_ASSERT_MESSAGE("Could not get the shape 'topbottom' properties", xShapeTBProps
.is());
537 awt::Rectangle aFrameRectTB
;
538 xShapeTBProps
->getPropertyValue(UNO_NAME_MISC_OBJ_FRAMERECT
) >>= aFrameRectTB
;
539 awt::Rectangle aBoundRectTB
;
540 xShapeTBProps
->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT
) >>= aBoundRectTB
;
541 // difference should be zero, but allow some rounding errors
542 CPPUNIT_ASSERT_LESS(sal_Int32(3), std::abs(aFrameRectTB
.Y
- aBoundRectTB
.Y
));
545 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testAccuracyCommandX
)
547 // 121761 Increase accuracy of quarter circles drawn by command X or Y
548 // The loaded document has a quarter circle with radius 10000 (unit 1/100 mm)
549 // which is rotated by 45deg. The test considers the segment.
550 loadFromURL(u
"tdf121761_Accuracy_command_X.odp");
551 // Get the shape "arc_45deg_rotated". Error was, that a Bezier curve with bad parameters
552 // was used, thus the segment height was obviously smaller than for a true circle.
553 // Math: segment height approx 10000 * ( 1 - sqrt(0.5)) + line width
554 uno::Reference
<drawing::XShape
> xShape(getShape(0));
555 uno::Reference
<beans::XPropertySet
> xShapeProps(xShape
, uno::UNO_QUERY
);
556 CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShapeProps
.is());
557 awt::Rectangle aBoundRect
;
558 xShapeProps
->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT
) >>= aBoundRect
;
559 double fHeight
= static_cast<double>(aBoundRect
.Height
);
560 // The tolerance is a guess, might be smaller.
561 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("segment height out of tolerance", 2942.0, fHeight
, 8.0);
564 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testToggleCommandXY
)
566 // 121952 Toggle x- and y-direction if command X has several parameters
567 // The loaded document has a shape with command X and two parameter placed on a diagonal.
568 // The radius of the quarter circles are both 10000 (unit 1/100 mm).
569 // The shape is rotated by 45deg, so you get two segments, one up and one down.
570 loadFromURL(u
"tdf121952_Toggle_direction_command_X.odp");
571 // Error was, that the second segment was drawn with same direction as first one. If drawn
572 // correctly, the bounding box height of the segments together is about twice the single
573 // segment height. Math: segment height approx 10000 * ( 1 - sqrt(0.5)) + line width
574 uno::Reference
<drawing::XShape
> xShape(getShape(0));
575 uno::Reference
<beans::XPropertySet
> xShapeProps(xShape
, uno::UNO_QUERY
);
576 CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShapeProps
.is());
577 awt::Rectangle aBoundRect
;
578 xShapeProps
->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT
) >>= aBoundRect
;
579 double fHeight
= static_cast<double>(aBoundRect
.Height
);
580 // The tolerance is a guess, might be smaller.
581 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("segment height out of tolerance", 5871.0, fHeight
, 16.0);
584 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testMultipleMoveTo
)
586 // tdf122964 Multiple moveTo has to be treated as lineTo in draw:enhanced-path
587 // Load a document with path "M 0 0 5 10 10 0 N"
588 loadFromURL(u
"tdf122964_MultipleMoveTo.odg");
589 // Error was, that the second and further parameter pairs were treated as moveTo,
590 // and so the generated path was empty, resulting in zero width and height of the
591 // bounding box. It has to be treated same as "M 0 0 L 5 10 10 0 N".
592 uno::Reference
<drawing::XShape
> xShape(getShape(0));
593 uno::Reference
<beans::XPropertySet
> xShapeProps(xShape
, uno::UNO_QUERY
);
594 CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShapeProps
.is());
595 awt::Rectangle aBoundRect
;
596 xShapeProps
->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT
) >>= aBoundRect
;
597 bool bIsZero(aBoundRect
.Height
== 0 && aBoundRect
.Width
== 0);
598 CPPUNIT_ASSERT_MESSAGE("Path is empty", !bIsZero
);
601 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testWidthOrientationCommandU
)
603 // tdf121845 custom shape with command U (angleellipse) is wrongly drawn
604 // Load a document with path "M 750 0 L 750 500 250 500 250 0 U 500 0 500 500 0 180 N"
605 // in viewBox="0 0 1000 500" and width="10cm", height="5cm".
606 loadFromURL(u
"tdf121845_WidthOrientation_command_U.odg");
607 // Error was, that the width and height of the ellipse was halved and that the ellipse
608 // was not drawn clockwise but counter clockwise.
609 uno::Reference
<drawing::XShape
> xShape(getShape(0));
610 uno::Reference
<beans::XPropertySet
> xShapeProps(xShape
, uno::UNO_QUERY
);
611 CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShapeProps
.is());
612 awt::Rectangle aBoundRect
;
613 xShapeProps
->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT
) >>= aBoundRect
;
614 const double fWidth
= static_cast<double>(aBoundRect
.Width
);
615 // Need some tolerance for line width
616 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("wrong width", 10000.0, fWidth
, 40.0);
617 const double fHeight
= static_cast<double>(aBoundRect
.Height
);
618 // Wrong orientation draws segment above the top of the viewBox and so increases 'Height'.
619 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("wrong orientation", 5000.0, fHeight
, 40.0);
622 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testHalfEllipseVML
)
624 // tdf121845 custom shape with command U (angleellipse) is wrongly drawn
625 // Load a document which was converted from VML to doc by Word. It had a VML
626 // path="m750,al500,,500,500,,-11796480e" resulting in a lower half circle.
627 loadFromURL(u
"tdf121845_HalfEllipseVML.doc");
628 // Error was, that a full circle instead of the half circle was draw.
629 uno::Reference
<drawing::XShape
> xShape(getShape(0));
630 uno::Reference
<beans::XPropertySet
> xShapeProps(xShape
, uno::UNO_QUERY
);
631 CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShapeProps
.is());
632 awt::Rectangle aBoundRect
;
633 xShapeProps
->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT
) >>= aBoundRect
;
634 const double fDiff2HmW
= static_cast<double>(2 * aBoundRect
.Height
- aBoundRect
.Width
);
635 // Need some tolerance for line width
636 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("not a half circle", 0.0, fDiff2HmW
, 40.0);
639 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testLargeSwingAngleVML
)
641 // tdf121845 custom shape with command U (angleellipse) is wrongly drawn
642 // Load a document which was converted from VML to doc by Word. It had a VML
643 // path="al50,50,45,45,2621440,31457280e" resulting in a full circle plus 120 deg segment.
644 loadFromURL(u
"tdf121845_start40_swing480.doc");
645 // Error was, that only the 120 deg segment was drawn.
646 uno::Reference
<drawing::XShape
> xShape(getShape(0));
647 uno::Reference
<beans::XPropertySet
> xShapeProps(xShape
, uno::UNO_QUERY
);
648 CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShapeProps
.is());
649 awt::Rectangle aBoundRect
;
650 xShapeProps
->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT
) >>= aBoundRect
;
651 const double fDiffWmH
= static_cast<double>(aBoundRect
.Width
- aBoundRect
.Height
);
652 // Need some tolerance for line width
653 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Full circle plus segment expected", 0.0, fDiffWmH
, 10.0);
655 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testTdf121845_two_commands_U
)
657 // tdf121845 custom shape with command U (angleellipse) is wrongly drawn
658 // Load a document with path "U 950 250 200 200 90 180 250 250 200 200 180 270 N"
659 // Error was, that the second ellipse segment was interpreted as command T and
660 // thus a line from first to second segment was drawn.
661 loadFromURL(u
"tdf121845_Two_commands_U.odg");
662 uno::Reference
<drawing::XShape
> xShape(getShape(0));
663 // In case no line is drawn, two polygons are generated; with line only one polygon
664 SdrObjCustomShape
& rSdrObjCustomShape(
665 static_cast<SdrObjCustomShape
&>(*SdrObject::getSdrObjectFromXShape(xShape
)));
666 EnhancedCustomShape2d
aCustomShape2d(rSdrObjCustomShape
);
667 rtl::Reference
<SdrPathObj
> pPathObj(
668 static_cast<SdrPathObj
*>(aCustomShape2d
.CreateLineGeometry().get()));
669 CPPUNIT_ASSERT_MESSAGE("Could not convert to SdrPathObj", pPathObj
);
670 const basegfx::B2DPolyPolygon
aPolyPolygon(pPathObj
->GetPathPoly());
671 CPPUNIT_ASSERT_EQUAL_MESSAGE("count polygons", static_cast<sal_uInt32
>(2),
672 aPolyPolygon
.count());
675 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testTdf124212_handle_position
)
677 // tdf124212 Adjustment handle reacts wrongly, if custom shape has a non
678 // default viewBox. Load a document with svg:viewBox="10800 0 10800 21600"
679 // Error was, that moving the controller results in a handle position that
680 // does not reflect the movement.
681 loadFromURL(u
"tdf124212_handle_position.odg");
682 uno::Reference
<drawing::XShape
> xShape(getShape(0));
683 // The shape has one, horizontal adjust handle.
684 SdrObjCustomShape
& rSdrObjCustomShape(
685 static_cast<SdrObjCustomShape
&>(*SdrObject::getSdrObjectFromXShape(xShape
)));
686 EnhancedCustomShape2d
aCustomShape2d(rSdrObjCustomShape
);
687 Point aInitialPosition
;
688 aCustomShape2d
.GetHandlePosition(0, aInitialPosition
);
689 css::awt::Point
aDesiredPosition(aInitialPosition
.X() + 1000, aInitialPosition
.Y());
690 aCustomShape2d
.SetHandleControllerPosition(0, aDesiredPosition
);
691 Point aObservedPosition
;
692 aCustomShape2d
.GetHandlePosition(0, aObservedPosition
);
693 sal_Int32
nDesiredX(aDesiredPosition
.X
); // awt::Point
694 sal_Int32
nObservedX(aObservedPosition
.X()); // tools::Point
695 CPPUNIT_ASSERT_EQUAL_MESSAGE("handle X coordinate", nDesiredX
, nObservedX
);
698 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testTdf124029_arc_position
)
700 // tdf121029 MS binary custom shape mso_sptArc has wrong position
701 // MS uses the sector for position reference. Error was, that
702 // LibreOffice has used the underlying ellipse.
703 loadFromURL(u
"tdf124029_Arc_position.doc");
704 uno::Reference
<drawing::XShape
> xShape(getShape(0));
705 // The visual wrong position is due to a wrong shape width.
706 uno::Reference
<beans::XPropertySet
> xShapeProps(xShape
, uno::UNO_QUERY
);
707 CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShapeProps
.is());
708 awt::Rectangle aFrameRect
;
709 xShapeProps
->getPropertyValue(UNO_NAME_MISC_OBJ_FRAMERECT
) >>= aFrameRect
;
710 CPPUNIT_ASSERT_EQUAL_MESSAGE("shape width", static_cast<sal_uInt32
>(1610),
711 static_cast<sal_uInt32
>(aFrameRect
.Width
));
714 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testTdf124740_handle_path_coordsystem
)
716 // tdf124740 OOXML shape with handle and w and h attribute on path has wrong
718 // The handle position was scaled erroneously twice.
719 loadFromURL(u
"tdf124740_HandleInOOXMLUserShape.pptx");
720 uno::Reference
<drawing::XShape
> xShape(getShape(0));
721 // The shape has one, horizontal adjust handle. It is about 1/5 of 10cm from left
722 // shape edge, shape is 6cm from left . That results in a position
723 // of 8cm from left page edge, which is 8000 in 1/100 mm unit.
724 SdrObjCustomShape
& rSdrObjCustomShape(
725 static_cast<SdrObjCustomShape
&>(*SdrObject::getSdrObjectFromXShape(xShape
)));
726 EnhancedCustomShape2d
aCustomShape2d(rSdrObjCustomShape
);
728 aCustomShape2d
.GetHandlePosition(0, aPosition
);
729 double fX(aPosition
.X());
730 // tolerance for rounding to integer
731 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("handle X coordinate", 8000.0, fX
, 2.0);
734 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testTdf115813_OOXML_XY_handle
)
736 // The test covers all preset shapes with handles. Only these ones are
737 // excluded: arc, blockArc, chord, circularArrow, gear6, gear9, mathNotEqual, pie,
738 // leftCircularArrow, leftRightCircularArrow, swooshArrow.
739 // Connectors are included as ordinary shapes to prevent converting.
740 // Error was, that the handle movement and the changes to the shape did not follow
741 // the mouse movement.
742 loadFromURL(u
"tdf115813_HandleMovementOOXMLPresetShapes.pptx");
744 // values in vector InteractionsHandles are in 1/100 mm and refer to page
745 for (sal_uInt8 i
= 0; i
< countShapes(); i
++)
747 uno::Reference
<drawing::XShape
> xShape(getShape(i
));
748 SdrObjCustomShape
& rSdrObjCustomShape(
749 static_cast<SdrObjCustomShape
&>(*SdrObject::getSdrObjectFromXShape(xShape
)));
750 OUString
sShapeType("non-primitive"); // default for ODF
751 const SdrCustomShapeGeometryItem
& rGeometryItem(
752 rSdrObjCustomShape
.GetMergedItem(SDRATTR_CUSTOMSHAPE_GEOMETRY
));
753 const uno::Any
* pAny
= rGeometryItem
.GetPropertyValueByName("Type");
755 *pAny
>>= sShapeType
;
757 sal_uInt8 nHandlesCount
= rSdrObjCustomShape
.GetInteractionHandles().size();
758 for (sal_uInt8 j
= 0; j
< nHandlesCount
; j
++)
760 css::awt::Point
aInitialPosition(
761 rSdrObjCustomShape
.GetInteractionHandles()[j
].aPosition
);
762 // The handles are initialized in the test document, so that if the handle is moveable in
763 // that direction at all, then it can move at least with an amount of 100.
764 Point
aDesiredPosition(aInitialPosition
.X
+ 100, aInitialPosition
.Y
+ 100);
765 rSdrObjCustomShape
.DragMoveCustomShapeHdl(aDesiredPosition
, j
, false);
766 css::awt::Point
aObservedPosition(
767 rSdrObjCustomShape
.GetInteractionHandles()[j
].aPosition
);
768 sal_Int32
nDesiredX(aDesiredPosition
.X()); // tools::Point
769 sal_Int32
nDesiredY(aDesiredPosition
.Y());
770 sal_Int32
nObservedX(aObservedPosition
.X
); // css::awt::Point
771 sal_Int32
nObservedY(aObservedPosition
.Y
);
772 // If a handle only moves in one direction, the difference is 100 for the other direction.
773 // There exists some rounding differences, therefore '<= 1' instead of '== 0'.
774 // The condition has the form '!(good cases)'.
775 if (!((abs(nDesiredX
- nObservedX
) <= 1 && abs(nDesiredY
- nObservedY
) == 100)
776 || (abs(nDesiredX
- nObservedX
) == 100 && abs(nDesiredY
- nObservedY
) <= 1)
777 || (abs(nDesiredX
- nObservedX
) <= 1 && abs(nDesiredY
- nObservedY
) <= 1)))
780 = OUString::number(i
) + " " + sShapeType
+ ": " + OUString::number(j
) + " X "
781 + OUString::number(nDesiredX
) + "|" + OUString::number(nObservedX
) + " Y "
782 + OUString::number(nDesiredY
) + "|" + OUString::number(nObservedY
);
783 CPPUNIT_FAIL(sError
.toUtf8().getStr());
789 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testQuadraticCurveTo
)
791 // tdf125782 command Q (quadraticcurveto) uses wrong 'current point'.
792 // When converting to cubic Bezier curve, this had resulted in a wrong first control point.
793 // The quadraticcurveto segment starts in shape center in the test file. The first control
794 // point should produce a horizontal tangent in the start point.
795 loadFromURL(u
"tdf125782_QuadraticCurveTo.odg");
796 uno::Reference
<drawing::XShape
> xShape(getShape(0));
797 uno::Reference
<beans::XPropertySet
> xShapeProps(xShape
, uno::UNO_QUERY
);
798 CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShapeProps
.is());
799 awt::Rectangle aBoundRect
;
800 xShapeProps
->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT
) >>= aBoundRect
;
801 const double fHeight
= static_cast<double>(aBoundRect
.Height
);
803 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("bad height of quadraticcurveto", 3004, fHeight
, 10.0);
806 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testTdf126512_OOXML_handle_in_ODP
)
808 // The test covers all preset shapes with handles. Connectors are included as ordinary
809 // shapes to prevent converting. The file was created in PowerPoint 365 and then
810 // opened and exported to ODF format by LibreOffice.
811 // Error was, that for shapes, which were originally imported from OOXML, the handles
812 // could not be moved at all.
813 loadFromURL(u
"tdf126512_OOXMLHandleMovementInODF.odp");
815 for (sal_uInt8 i
= 0; i
< countShapes(); i
++)
817 uno::Reference
<drawing::XShape
> xShape(getShape(i
));
818 SdrObjCustomShape
& rSdrObjCustomShape(
819 static_cast<SdrObjCustomShape
&>(*SdrObject::getSdrObjectFromXShape(xShape
)));
820 OUString
sShapeType("non-primitive"); // only to initialize, value not used here
821 const SdrCustomShapeGeometryItem
& rGeometryItem(
822 rSdrObjCustomShape
.GetMergedItem(SDRATTR_CUSTOMSHAPE_GEOMETRY
));
823 const uno::Any
* pAny
= rGeometryItem
.GetPropertyValueByName("Type");
825 *pAny
>>= sShapeType
;
827 sal_uInt8 nHandlesCount
= rSdrObjCustomShape
.GetInteractionHandles().size();
828 for (sal_uInt8 j
= 0; j
< nHandlesCount
; j
++)
830 css::awt::Point
aInitialPosition(
831 rSdrObjCustomShape
.GetInteractionHandles()[j
].aPosition
);
832 // The handles are initialized in the test document, so that if the handle is moveable
833 // in that direction at all, then it can move at least with an amount of 100.
834 Point
aDesiredPosition(aInitialPosition
.X
+ 100, aInitialPosition
.Y
+ 100);
835 rSdrObjCustomShape
.DragMoveCustomShapeHdl(aDesiredPosition
, j
, false);
836 css::awt::Point
aObservedPosition(
837 rSdrObjCustomShape
.GetInteractionHandles()[j
].aPosition
);
838 if (aInitialPosition
.X
== aObservedPosition
.X
839 && aInitialPosition
.Y
== aObservedPosition
.Y
)
842 = OUString::number(i
) + " " + sShapeType
+ " " + OUString::number(j
);
843 CPPUNIT_FAIL(sError
.toUtf8().getStr());
849 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testTdf127785_Mirror
)
851 // The document contains two shapes, one with horizontal flip, the other with vertical
852 // flip. They are diamonds, so their text frame is symmetric to the center of the shape.
853 // The shapes have not stroke and no fill, so that the bounding box surrounds the text
854 // and therefore equals approximately the text frame.
855 // Error was, that because of wrong calculation, the flipped shapes do not use the
856 // text frame but the frame rectangle for their text.
857 loadFromURL(u
"tdf127785_Mirror.odp");
859 uno::Reference
<drawing::XShape
> xShapeV(getShape(0));
860 uno::Reference
<beans::XPropertySet
> xShapeVProps(xShapeV
, uno::UNO_QUERY
);
861 CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShapeVProps
.is());
862 awt::Rectangle aBoundRectV
;
863 xShapeVProps
->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT
) >>= aBoundRectV
;
864 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Flip vertical wrong size.", 8000.0, aBoundRectV
.Height
,
866 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Flip vertical wrong size.", 8000.0, aBoundRectV
.Width
,
868 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Flip vertical wrong position.", 1000.0, aBoundRectV
.X
,
870 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Flip vertical wrong position.", 2000.0, aBoundRectV
.Y
,
873 uno::Reference
<drawing::XShape
> xShapeH(getShape(1));
874 uno::Reference
<beans::XPropertySet
> xShapeHProps(xShapeH
, uno::UNO_QUERY
);
875 CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShapeHProps
.is());
876 awt::Rectangle aBoundRectH
;
877 xShapeHProps
->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT
) >>= aBoundRectH
;
878 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Flip horizontal wrong size.", 8000.0, aBoundRectH
.Height
,
880 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Flip horizontal wrong size.", 8000.0, aBoundRectH
.Width
,
882 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Flip horizontal wrong position.", 13000.0, aBoundRectH
.X
,
884 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Flip horizontal wrong position.", 2000.0, aBoundRectH
.Y
,
888 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testTdf126060_3D_Z_Rotation
)
890 // The document contains one textbox with inside overflowed text
891 // and the text has 3D z rotation. When we open the document we
892 // should see the text vertically and rotated from text bound center not text box.
894 loadFromURL(u
"tdf126060_3D_Z_Rotation.pptx");
896 uno::Reference
<drawing::XShape
> xShape(getShape(0));
897 SdrObjCustomShape
& rSdrObjCustomShape(
898 static_cast<SdrObjCustomShape
&>(*SdrObject::getSdrObjectFromXShape(xShape
)));
900 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong text camera Z rotation", 90.0,
901 rSdrObjCustomShape
.GetCameraZRotation());
903 basegfx::B2DHomMatrix aObjectTransform
;
904 basegfx::B2DPolyPolygon aObjectPolyPolygon
;
905 rSdrObjCustomShape
.TRGetBaseGeometry(aObjectTransform
, aObjectPolyPolygon
);
907 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong transformation at 0,0 position", 1492.0,
908 aObjectTransform
.get(0, 0));
909 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong transformation at 0,1 position", 0.0,
910 aObjectTransform
.get(0, 1));
911 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong transformation at 0,2 position", 1129.0,
912 aObjectTransform
.get(0, 2));
913 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong transformation at 1,0 position", 0.0,
914 aObjectTransform
.get(1, 0));
915 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong transformation at 1,1 position", 2500.0,
916 aObjectTransform
.get(1, 1));
917 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong transformation at 1,2 position", 5846.0,
918 aObjectTransform
.get(1, 2));
921 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testTdf127785_Asymmetric
)
923 // The document contains a shapes with vertical flip and text frame asymmetrical
924 // to shape. The shape has not stroke and no fill, so that the bounding box surrounds
925 // the text and therefore equals approximately the text frame.
926 // Error was, that the 180deg text rotation was not compensated for the position of
927 // the flipped text box.
928 loadFromURL(u
"tdf127785_asymmetricTextBoxFlipV.odg");
930 uno::Reference
<drawing::XShape
> xShape(getShape(0));
931 uno::Reference
<beans::XPropertySet
> xShapeProps(xShape
, uno::UNO_QUERY
);
932 CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShapeProps
.is());
933 awt::Rectangle aBoundRect
;
934 xShapeProps
->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT
) >>= aBoundRect
;
936 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("wrong left", 9000.0, aBoundRect
.X
, 10.0);
937 const double nRight
= aBoundRect
.X
+ aBoundRect
.Width
- 1;
938 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("wrong right", 19000.0, nRight
, 10.0);
939 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("wrong top", 3000.0, aBoundRect
.Y
, 10.0);
940 const double nBottom
= aBoundRect
.Y
+ aBoundRect
.Height
- 1;
941 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("wrong bottom", 18000.0, nBottom
, 10.0);
944 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testTdf127785_TextRotateAngle
)
946 // The document contains a shapes with vertical flip and a text frame with own
947 // rotate angle. The shape has not stroke and no fill, so that the bounding box
948 // surrounds the text and therefore equals approximately the text frame.
949 // Error was, that the compensation for the 180° rotation added for vertical
950 // flip were not made to the text box position but to the text matrix.
951 loadFromURL(u
"tdf127785_TextRotateAngle.odp");
953 uno::Reference
<drawing::XShape
> xShape(getShape(0));
954 uno::Reference
<beans::XPropertySet
> xShapeProps(xShape
, uno::UNO_QUERY
);
955 CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShapeProps
.is());
956 awt::Rectangle aBoundRect
;
957 xShapeProps
->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT
) >>= aBoundRect
;
959 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("wrong left", 2000.0, aBoundRect
.X
, 10.0);
960 const double nRight
= aBoundRect
.X
+ aBoundRect
.Width
- 1;
961 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("wrong right", 14000.0, nRight
, 10.0);
962 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("wrong top", 3000.0, aBoundRect
.Y
, 10.0);
963 const double nBottom
= aBoundRect
.Y
+ aBoundRect
.Height
- 1;
964 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("wrong bottom", 9000.0, nBottom
, 10.0);
967 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testTdf128413_tbrlOnOff
)
969 // The document contains a rotated shape with text. The error was, that switching
970 // tb-rl writing-mode on, changed the shape size and position.
972 loadFromURL(u
"tdf128413_tbrl_OnOff.odp");
973 uno::Reference
<drawing::XShape
> xShape(getShape(0));
974 uno::Reference
<beans::XPropertySet
> xShapeProps(xShape
, uno::UNO_QUERY
);
975 CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShapeProps
.is());
976 awt::Rectangle aOrigRect
;
977 xShapeProps
->getPropertyValue(UNO_NAME_MISC_OBJ_FRAMERECT
) >>= aOrigRect
;
979 SdrObjCustomShape
& rSdrObjCustomShape(
980 static_cast<SdrObjCustomShape
&>(*SdrObject::getSdrObjectFromXShape(xShape
)));
981 rSdrObjCustomShape
.SetVerticalWriting(true);
983 awt::Rectangle aObservedRect
;
984 xShapeProps
->getPropertyValue(UNO_NAME_MISC_OBJ_FRAMERECT
) >>= aObservedRect
;
986 CPPUNIT_ASSERT_EQUAL_MESSAGE("Shape has wrong width", aOrigRect
.Width
, aObservedRect
.Width
);
987 CPPUNIT_ASSERT_EQUAL_MESSAGE("Shape has wrong height", aOrigRect
.Height
, aObservedRect
.Height
);
988 CPPUNIT_ASSERT_EQUAL_MESSAGE("Shape has wrong X position", aOrigRect
.X
, aObservedRect
.X
);
989 CPPUNIT_ASSERT_EQUAL_MESSAGE("Shape has wrong Y position", aOrigRect
.Y
, aObservedRect
.Y
);
992 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testTdf129532_MatrixFlipV
)
994 // The document contains two rotated shapes with the same geometry. For one of them
995 // "matrix(1 0 0 -1 0cm 0cm)" was manually added to the value of the draw:transform
996 // attribute. That should result in mirroring on the x-axis. Error was, that the lines
997 // which are drawn on the shape rectangle were mirrored, but not the rectangle itself.
998 // The rectangle was only shifted.
999 loadFromURL(u
"tdf129532_MatrixFlipV.odg");
1001 uno::Reference
<drawing::XShape
> xShape0(getShape(0));
1002 uno::Reference
<beans::XPropertySet
> xShape0Props(xShape0
, uno::UNO_QUERY
);
1003 CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShape0Props
.is());
1004 awt::Rectangle aBoundRect0
;
1005 xShape0Props
->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT
) >>= aBoundRect0
;
1007 uno::Reference
<drawing::XShape
> xShape1(getShape(1));
1008 uno::Reference
<beans::XPropertySet
> xShape1Props(xShape1
, uno::UNO_QUERY
);
1009 CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShape1Props
.is());
1010 awt::Rectangle aBoundRect1
;
1011 xShape1Props
->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT
) >>= aBoundRect1
;
1013 // The size of the two BoundRect rectangles are the same in case of correct
1014 // vertical mirroring.
1015 CPPUNIT_ASSERT_EQUAL_MESSAGE("Incorrect width", aBoundRect0
.Width
, aBoundRect1
.Width
);
1016 CPPUNIT_ASSERT_EQUAL_MESSAGE("Incorrect height", aBoundRect0
.Height
, aBoundRect1
.Height
);
1019 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testTdf103474_commandT_CaseZeroHeight
)
1021 // tdf103474 custom shape with command T to create quarter ellipses in a bracket,
1022 // corner case where the ellipse has zero height.
1023 // Error was, that the calculation of the circle angle from the ellipse
1024 // angle results in a wrong angle for the case 180° and height zero.
1025 loadFromURL(u
"tdf103474_commandT_CaseZeroHeight.odp");
1026 uno::Reference
<drawing::XShape
> xShape(getShape(0));
1027 // The end points of the straight line segment should have the same x-coordinate of left
1028 // of shape, and different y-coordinates, one top and the other bottom of the shape.
1029 SdrObjCustomShape
& rSdrObjCustomShape(
1030 static_cast<SdrObjCustomShape
&>(*SdrObject::getSdrObjectFromXShape(xShape
)));
1031 EnhancedCustomShape2d
aCustomShape2d(rSdrObjCustomShape
);
1032 rtl::Reference
<SdrPathObj
> pPathObj(
1033 static_cast<SdrPathObj
*>(aCustomShape2d
.CreateLineGeometry().get()));
1034 CPPUNIT_ASSERT_MESSAGE("Could not convert to SdrPathObj", pPathObj
);
1035 const basegfx::B2DPolyPolygon
aPolyPolygon(pPathObj
->GetPathPoly());
1036 CPPUNIT_ASSERT_EQUAL_MESSAGE("count polygons", static_cast<sal_uInt32
>(1),
1037 aPolyPolygon
.count());
1038 const basegfx::B2DPolygon
aPolygon(aPolyPolygon
.getB2DPolygon(0));
1039 // Get the middle points of the polygon. They are the endpoints of the
1040 // straight line segment regardless of the quarter ellipse parts, because
1041 // the shape is symmetric.
1042 const basegfx::B2DPoint
aStart(aPolygon
.getB2DPoint(aPolygon
.count() / 2 - 1));
1043 const basegfx::B2DPoint
aEnd(aPolygon
.getB2DPoint(aPolygon
.count() / 2));
1044 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("aStart x-coordinate", 13999.0, aStart
.getX(), 1.0);
1045 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("aEnd x-coordinate", 13999.0, aEnd
.getX(), 1.0);
1046 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("aStart y-coordinate", 9999.0, aStart
.getY(), 1.0);
1047 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("aEnd y-coordinate", 1999.0, aEnd
.getY(), 1.0);
1050 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testTdf103474_commandG_CaseZeroHeight
)
1052 // Some as above, but with shape with command G.
1053 loadFromURL(u
"tdf103474_commandG_CaseZeroHeight.odp");
1054 uno::Reference
<drawing::XShape
> xShape(getShape(0));
1055 // The end points of the straight line segment should have the same x-coordinate of left
1056 // of shape, and different y-coordinates, one top and the other bottom of the shape.
1057 SdrObjCustomShape
& rSdrObjCustomShape(
1058 static_cast<SdrObjCustomShape
&>(*SdrObject::getSdrObjectFromXShape(xShape
)));
1059 EnhancedCustomShape2d
aCustomShape2d(rSdrObjCustomShape
);
1060 rtl::Reference
<SdrPathObj
> pPathObj(
1061 static_cast<SdrPathObj
*>(aCustomShape2d
.CreateLineGeometry().get()));
1062 CPPUNIT_ASSERT_MESSAGE("Could not convert to SdrPathObj", pPathObj
);
1063 const basegfx::B2DPolyPolygon
aPolyPolygon(pPathObj
->GetPathPoly());
1064 CPPUNIT_ASSERT_EQUAL_MESSAGE("count polygons", static_cast<sal_uInt32
>(1),
1065 aPolyPolygon
.count());
1066 const basegfx::B2DPolygon
aPolygon(aPolyPolygon
.getB2DPolygon(0));
1067 // Get the middle points of the polygon. They are the endpoints of the
1068 // straight line segment regardless of the quarter ellipse parts, because
1069 // the shape is symmetric.
1070 const basegfx::B2DPoint
aStart(aPolygon
.getB2DPoint(aPolygon
.count() / 2 - 1));
1071 const basegfx::B2DPoint
aEnd(aPolygon
.getB2DPoint(aPolygon
.count() / 2));
1072 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("aStart x-coordinate", 1999.0, aStart
.getX(), 1.0);
1073 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("aEnd x-coordinate", 1999.0, aEnd
.getX(), 1.0);
1074 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("aStart y-coordinate", 9999.0, aStart
.getY(), 1.0);
1075 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("aEnd y-coordinate", 1999.0, aEnd
.getY(), 1.0);
1078 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testTdf122323_largeSwingAngle
)
1080 // SwingAngles are clamped to [-360;360] in MS Office. Error was, that LO calculated
1081 // the end angle and used it modulo 360, no full ellipse was drawn.
1082 loadFromURL(u
"tdf122323_swingAngle_larger360deg.pptx");
1083 uno::Reference
<drawing::XShape
> xShape(getShape(0));
1084 SdrObjCustomShape
& rSdrObjCustomShape(
1085 static_cast<SdrObjCustomShape
&>(*SdrObject::getSdrObjectFromXShape(xShape
)));
1086 EnhancedCustomShape2d
aCustomShape2d(rSdrObjCustomShape
);
1087 rtl::Reference
<SdrPathObj
> pPathObj(
1088 static_cast<SdrPathObj
*>(aCustomShape2d
.CreateLineGeometry().get()));
1089 CPPUNIT_ASSERT_MESSAGE("Could not convert to SdrPathObj", pPathObj
);
1090 const basegfx::B2DPolyPolygon
aPolyPolygon(pPathObj
->GetPathPoly());
1091 const basegfx::B2DPolygon
aPolygon(aPolyPolygon
.getB2DPolygon(0));
1092 const basegfx::B2DPoint
aStart(aPolygon
.getB2DPoint(0));
1093 // last point comes from line to center, therefore -2 instead of -1
1094 const basegfx::B2DPoint
aEnd(aPolygon
.getB2DPoint(aPolygon
.count() - 2));
1095 CPPUNIT_ASSERT_EQUAL_MESSAGE("Start <> End", aStart
, aEnd
);
1098 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testTdf141268
)
1100 loadFromURL(u
"tdf141268.odp");
1101 uno::Reference
<drawing::XShape
> xShape(getShape(0));
1102 SdrObjCustomShape
& rSdrCustomShape(
1103 static_cast<SdrObjCustomShape
&>(*SdrObject::getSdrObjectFromXShape(xShape
)));
1105 // Check left/bottom of bound rect. Without fix it would be left=6722, bottom=9483.
1106 tools::Rectangle
aBoundRect(rSdrCustomShape
.GetCurrentBoundRect());
1107 CPPUNIT_ASSERT_EQUAL(tools::Long(7620), aBoundRect
.Left());
1108 CPPUNIT_ASSERT_EQUAL(tools::Long(8584), aBoundRect
.Bottom());
1111 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testTdf136176
)
1113 // Error was, that fObjectRotation was not correctly updated after shearing.
1114 // The problem becomes visible after save and reload.
1115 loadFromURL(u
"tdf136176_rot30_flip.odg");
1117 for (sal_uInt16 i
= 0; i
< 3; i
++)
1120 uno::Reference
<drawing::XShape
> xShape(getShape(i
));
1121 SdrObjCustomShape
& rSdrObjCustomShape(
1122 static_cast<SdrObjCustomShape
&>(*SdrObject::getSdrObjectFromXShape(xShape
)));
1123 // apply shearing 20deg
1124 const Point aCenter
= rSdrObjCustomShape
.GetSnapRect().Center();
1125 rSdrObjCustomShape
.Shear(aCenter
, 2000_deg100
, tan(basegfx::deg2rad(20.0)), false);
1129 saveAndReload("draw8");
1131 // Expected values of point 4 of the shape polygon
1132 const OString sTestCase
[] = { "FlipH", "FlipV", "FlipHV" };
1133 const double fX
[] = { 14981.0, 3849.0, 15214.0 };
1134 const double fY
[] = { 9366.0, 16464.0, 23463.0 };
1136 // Verify correct positions
1137 for (sal_uInt16 i
= 0; i
< 3; i
++)
1140 const uno::Reference
<drawing::XShape
> xShape(getShape(i
));
1141 const SdrObjCustomShape
& rSdrObjCustomShape(
1142 static_cast<SdrObjCustomShape
&>(*SdrObject::getSdrObjectFromXShape(xShape
)));
1143 // Create polygon from shape and examine point 4 of the polygon
1144 const basegfx::B2DPolyPolygon aLineGeometry
= rSdrObjCustomShape
.GetLineGeometry(false);
1145 const basegfx::B2DPoint
aPoint(aLineGeometry
.getB2DPolygon(0).getB2DPoint(4));
1146 // Allow some tolerance for rounding errors
1147 if (fabs(aPoint
.getX() - fX
[i
]) > 2.0 || fabs(aPoint
.getY() - fY
[i
]) > 2.0)
1149 CPPUNIT_ASSERT_EQUAL_MESSAGE(sTestCase
[i
].getStr(), aPoint
,
1150 basegfx::B2DPoint(fX
[i
], fY
[i
]));
1155 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testTdf148501_OctagonBevel
)
1157 // The document contains a shape "Octagon Bevel". It should use shadings 40%, 20%, -20%, -40%
1158 // from left-top to bottom-right. The test examines actual color, not the geometry.
1160 loadFromURL(u
"tdf148501_OctagonBevel.odp");
1162 // Generate bitmap from shape
1163 uno::Reference
<drawing::XShape
> xShape
= getShape(0);
1164 GraphicHelper::SaveShapeAsGraphicToPath(mxComponent
, xShape
, "image/png", maTempFile
.GetURL());
1166 // Read bitmap and test color
1167 // expected in order top-left, top, top-right, right, bottom-right:
1168 // RGB(165|195|266), RGB(139|176|217), RGB(91|127|166), RGB(68|95|124), RGB(68|95|124)
1169 // Without applied patch the colors were:
1170 // RGB(193|214,236), RGB(193|214,236), RGB(80|111|145), RGB(23|32|41), RGB(193|214|236)
1171 // So we test segments top, right and bottom-right.
1172 SvFileStream
aFileStream(maTempFile
.GetURL(), StreamMode::READ
);
1173 vcl::PngImageReader
aPNGReader(aFileStream
);
1174 BitmapEx aBMPEx
= aPNGReader
.read();
1175 Bitmap aBMP
= aBMPEx
.GetBitmap();
1176 Bitmap::ScopedReadAccess
pRead(aBMP
);
1177 Size aSize
= aBMP
.GetSizePixel();
1179 // GetColor(Y,X). The chosen threshold for the ColorDistance can be adapted if necessary.
1180 Color aActualColor
= pRead
->GetColor(aSize
.Height() * 0.17, aSize
.Width() * 0.5); // top
1181 Color
aExpectedColor(139, 176, 217);
1182 sal_uInt16 nColorDistance
= aExpectedColor
.GetColorError(aActualColor
);
1183 CPPUNIT_ASSERT_LESS(sal_uInt16(6), nColorDistance
);
1184 aActualColor
= pRead
->GetColor(aSize
.Height() * 0.5, aSize
.Width() * 0.83); // right
1185 aExpectedColor
= Color(68, 95, 124); // same for right and bottom-right
1186 nColorDistance
= aExpectedColor
.GetColorError(aActualColor
);
1187 CPPUNIT_ASSERT_LESS(sal_uInt16(6), nColorDistance
);
1188 aActualColor
= pRead
->GetColor(aSize
.Height() * 0.75, aSize
.Width() * 0.75); // bottom-right
1189 nColorDistance
= aExpectedColor
.GetColorError(aActualColor
);
1190 CPPUNIT_ASSERT_LESS(sal_uInt16(6), nColorDistance
);
1193 bool lcl_getShapeSegments(uno::Sequence
<drawing::EnhancedCustomShapeSegment
>& rSegments
,
1194 const uno::Reference
<drawing::XShape
>& xShape
)
1196 uno::Reference
<beans::XPropertySet
> xShapeProps(xShape
, uno::UNO_QUERY_THROW
);
1197 uno::Any anotherAny
= xShapeProps
->getPropertyValue("CustomShapeGeometry");
1198 uno::Sequence
<beans::PropertyValue
> aCustomShapeGeometry
;
1199 if (!(anotherAny
>>= aCustomShapeGeometry
))
1201 uno::Sequence
<beans::PropertyValue
> aPathProps
;
1202 for (beans::PropertyValue
const& rProp
: std::as_const(aCustomShapeGeometry
))
1204 if (rProp
.Name
== "Path")
1206 rProp
.Value
>>= aPathProps
;
1211 for (beans::PropertyValue
const& rProp
: std::as_const(aPathProps
))
1213 if (rProp
.Name
== "Segments")
1215 rProp
.Value
>>= rSegments
;
1219 if (rSegments
.getLength() > 1)
1225 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testTdf148714_CurvedArrows
)
1227 // Error was, that the line between 1. and 2. arc was missing.
1228 loadFromURL(u
"tdf148714_CurvedArrows.ppt");
1230 for (sal_Int32 nShapeIndex
= 0; nShapeIndex
< 4; nShapeIndex
++)
1232 uno::Reference
<drawing::XShape
> xShape(getShape(nShapeIndex
));
1233 uno::Sequence
<drawing::EnhancedCustomShapeSegment
> aSegments
;
1234 CPPUNIT_ASSERT(lcl_getShapeSegments(aSegments
, xShape
));
1236 if (nShapeIndex
== 0 || nShapeIndex
== 3)
1238 // curvedDownArrow or curvedLeftArrow. Segments should start with VW. Without fix it was
1239 // V with count 2, which means VV.
1240 CPPUNIT_ASSERT_EQUAL(
1241 sal_Int16(drawing::EnhancedCustomShapeSegmentCommand::CLOCKWISEARC
),
1242 aSegments
[0].Command
);
1243 CPPUNIT_ASSERT_EQUAL(sal_Int16(1), aSegments
[0].Count
);
1244 CPPUNIT_ASSERT_EQUAL(
1245 sal_Int16(drawing::EnhancedCustomShapeSegmentCommand::CLOCKWISEARCTO
),
1246 aSegments
[1].Command
);
1247 CPPUNIT_ASSERT_EQUAL(sal_Int16(1), aSegments
[1].Count
);
1251 // curvedUpArrow or curvedRightArrow. Segments should start with BA. Without fix is was
1252 // B with count 2, which means BB.
1253 CPPUNIT_ASSERT_EQUAL(sal_Int16(drawing::EnhancedCustomShapeSegmentCommand::ARC
),
1254 aSegments
[0].Command
);
1255 CPPUNIT_ASSERT_EQUAL(sal_Int16(1), aSegments
[0].Count
);
1256 CPPUNIT_ASSERT_EQUAL(sal_Int16(drawing::EnhancedCustomShapeSegmentCommand::ARCTO
),
1257 aSegments
[1].Command
);
1258 CPPUNIT_ASSERT_EQUAL(sal_Int16(1), aSegments
[1].Count
);
1263 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testTdf148707_two_commands_B_V
)
1265 // tdf148707 custom shape with multiple command B or multiple command V were drawn with a line
1266 // between the arcs as if the second command was a A or W respectively.
1267 // The test document has a shape with path "V 0 0 50 100 0 50 25 0 50 0 100 100 75 0 100 50 N"
1268 // and a shape with path "B 0 0 50 100 0 50 25 100 50 0 100 100 75 100 100 50 N".
1269 loadFromURL(u
"tdf148707_two_commands_B_V.odp");
1270 for (sal_uInt8 i
= 0; i
< 2; i
++)
1272 uno::Reference
<drawing::XShape
> xShape(getShape(i
));
1273 // In case no line is drawn, two polygons are generated; with line only one polygon
1274 SdrObjCustomShape
& rSdrObjCustomShape(
1275 static_cast<SdrObjCustomShape
&>(*SdrObject::getSdrObjectFromXShape(xShape
)));
1276 EnhancedCustomShape2d
aCustomShape2d(rSdrObjCustomShape
);
1277 rtl::Reference
<SdrPathObj
> pPathObj(
1278 static_cast<SdrPathObj
*>(aCustomShape2d
.CreateLineGeometry().get()));
1279 CPPUNIT_ASSERT_MESSAGE("Could not convert to SdrPathObj", pPathObj
);
1280 const basegfx::B2DPolyPolygon
aPolyPolygon(pPathObj
->GetPathPoly());
1281 CPPUNIT_ASSERT_EQUAL_MESSAGE("count polygons", sal_uInt32(2), aPolyPolygon
.count());
1285 bool lcl_getShapeCoordinates(uno::Sequence
<drawing::EnhancedCustomShapeParameterPair
>& rCoordinates
,
1286 const uno::Reference
<drawing::XShape
>& xShape
)
1288 uno::Reference
<beans::XPropertySet
> xShapeProps(xShape
, uno::UNO_QUERY_THROW
);
1289 uno::Any anotherAny
= xShapeProps
->getPropertyValue("CustomShapeGeometry");
1290 uno::Sequence
<beans::PropertyValue
> aCustomShapeGeometry
;
1291 if (!(anotherAny
>>= aCustomShapeGeometry
))
1293 uno::Sequence
<beans::PropertyValue
> aPathProps
;
1294 for (beans::PropertyValue
const& rProp
: std::as_const(aCustomShapeGeometry
))
1296 if (rProp
.Name
== "Path")
1298 rProp
.Value
>>= aPathProps
;
1303 for (beans::PropertyValue
const& rProp
: std::as_const(aPathProps
))
1305 if (rProp
.Name
== "Coordinates")
1307 rProp
.Value
>>= rCoordinates
;
1311 if (rCoordinates
.getLength() > 0)
1317 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testTdf153000_MS0_SPT_25_31
)
1319 // The shapes MSO_SPT=25 to MSO_SPT=31 are currently rendered as rectangle. They should be
1320 // rendered same way as in Word. More info in bug 153000.
1321 loadFromURL(u
"tdf153000_WordArt_type_25_to_31.docx");
1322 // The wrong rendering becomes visible in properties "Coordinates" and "Segments". To simplify
1323 // the test we do not compare the values themselves but only the amount of values.
1324 // Without fix there were always 5 pairs in "Coordinates" and "Segments" did not exist.
1325 sal_Int32 aExpected
[] = { 8, 5, 14, 8, 8, 14, 4 };
1326 for (sal_uInt8 i
= 0; i
< 7; i
++)
1328 uno::Reference
<drawing::XShape
> xShape(getShape(i
));
1329 uno::Sequence
<drawing::EnhancedCustomShapeSegment
> aSegments
;
1330 CPPUNIT_ASSERT(lcl_getShapeSegments(aSegments
, xShape
));
1331 uno::Sequence
<drawing::EnhancedCustomShapeParameterPair
> aCoordinates
;
1332 CPPUNIT_ASSERT(lcl_getShapeCoordinates(aCoordinates
, xShape
));
1333 CPPUNIT_ASSERT_EQUAL(aExpected
[i
], aCoordinates
.getLength());
1338 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */