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/bootstrapfixture.hxx>
15 #include <unotest/macros_test.hxx>
16 #include <rtl/ustring.hxx>
17 #include <editeng/unoprnms.hxx>
18 #include <basegfx/polygon/b2dpolypolygon.hxx>
19 #include <basegfx/polygon/b2dpolygon.hxx>
20 #include <basegfx/point/b2dpoint.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/svdoashp.hxx>
28 #include <svx/svdopath.hxx>
29 #include <svx/svdview.hxx>
30 #include <svx/svxids.hrc>
31 #include <svx/unoapi.hxx>
32 #include <unotools/mediadescriptor.hxx>
33 #include <unotools/tempfile.hxx>
35 #include <cppunit/TestAssert.h>
37 #include <com/sun/star/beans/XPropertySet.hpp>
38 #include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
39 #include <com/sun/star/drawing/XDrawPage.hpp>
40 #include <com/sun/star/awt/Rectangle.hpp>
41 #include <com/sun/star/frame/Desktop.hpp>
42 #include <com/sun/star/frame/XStorable.hpp>
44 using namespace ::com::sun::star
;
48 constexpr OUStringLiteral
sDataDirectory(u
"svx/qa/unit/data/");
50 /// Tests for svx/source/customshapes/ code.
51 class CustomshapesTest
: public test::BootstrapFixture
, public unotest::MacrosTest
54 uno::Reference
<lang::XComponent
> mxComponent
;
55 // get shape nShapeIndex from page 0
56 uno::Reference
<drawing::XShape
> getShape(sal_uInt8 nShapeIndex
);
57 sal_uInt8
countShapes();
60 virtual void setUp() override
62 test::BootstrapFixture::setUp();
63 mxDesktop
.set(frame::Desktop::create(m_xContext
));
66 virtual void tearDown() override
70 mxComponent
->dispose();
72 test::BootstrapFixture::tearDown();
76 uno::Reference
<drawing::XShape
> CustomshapesTest::getShape(sal_uInt8 nShapeIndex
)
78 uno::Reference
<drawing::XDrawPagesSupplier
> xDrawPagesSupplier(mxComponent
,
79 uno::UNO_QUERY_THROW
);
80 CPPUNIT_ASSERT_MESSAGE("Could not get XDrawPagesSupplier", xDrawPagesSupplier
.is());
81 uno::Reference
<drawing::XDrawPages
> xDrawPages(xDrawPagesSupplier
->getDrawPages());
82 uno::Reference
<drawing::XDrawPage
> xDrawPage(xDrawPages
->getByIndex(0), uno::UNO_QUERY_THROW
);
83 CPPUNIT_ASSERT_MESSAGE("Could not get xDrawPage", xDrawPage
.is());
84 uno::Reference
<drawing::XShape
> xShape(xDrawPage
->getByIndex(nShapeIndex
), uno::UNO_QUERY
);
85 CPPUNIT_ASSERT_MESSAGE("Could not get xShape", xShape
.is());
89 sal_uInt8
CustomshapesTest::countShapes()
91 uno::Reference
<drawing::XDrawPagesSupplier
> xDrawPagesSupplier(mxComponent
,
92 uno::UNO_QUERY_THROW
);
93 CPPUNIT_ASSERT_MESSAGE("Could not get XDrawPagesSupplier", xDrawPagesSupplier
.is());
94 uno::Reference
<drawing::XDrawPages
> xDrawPages(xDrawPagesSupplier
->getDrawPages());
95 uno::Reference
<drawing::XDrawPage
> xDrawPage(xDrawPages
->getByIndex(0), uno::UNO_QUERY_THROW
);
96 CPPUNIT_ASSERT_MESSAGE("Could not get xDrawPage", xDrawPage
.is());
97 return xDrawPage
->getCount();
100 void lcl_AssertRectEqualWithTolerance(std::string_view sInfo
, const tools::Rectangle
& rExpected
,
101 const tools::Rectangle
& rActual
, const sal_Int32 nTolerance
)
104 OString sMsg
= OString::Concat(sInfo
) + " Left expected " + OString::number(rExpected
.Left())
105 + " actual " + OString::number(rActual
.Left()) + " Tolerance "
106 + OString::number(nTolerance
);
107 CPPUNIT_ASSERT_MESSAGE(sMsg
.getStr(),
108 std::abs(rExpected
.Left() - rActual
.Left()) <= nTolerance
);
111 sMsg
= OString::Concat(sInfo
) + " Top expected " + OString::number(rExpected
.Top()) + " actual "
112 + OString::number(rActual
.Top()) + " Tolerance " + OString::number(nTolerance
);
113 CPPUNIT_ASSERT_MESSAGE(sMsg
.getStr(), std::abs(rExpected
.Top() - rActual
.Top()) <= nTolerance
);
116 sMsg
= OString::Concat(sInfo
) + " Width expected " + OString::number(rExpected
.GetWidth())
117 + " actual " + OString::number(rActual
.GetWidth()) + " Tolerance "
118 + OString::number(nTolerance
);
119 CPPUNIT_ASSERT_MESSAGE(sMsg
.getStr(),
120 std::abs(rExpected
.GetWidth() - rActual
.GetWidth()) <= nTolerance
);
123 sMsg
= OString::Concat(sInfo
) + " Height expected " + OString::number(rExpected
.GetHeight())
124 + " actual " + OString::number(rActual
.GetHeight()) + " Tolerance "
125 + OString::number(nTolerance
);
126 CPPUNIT_ASSERT_MESSAGE(sMsg
.getStr(),
127 std::abs(rExpected
.GetHeight() - rActual
.GetHeight()) <= nTolerance
);
130 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testTdf145004_gap_by_ScaleX
)
134 // tdf#145004 In case property ScaleX=true was set in property 'TextPath' an additional
135 // padding was added to the scaling factor. That results in a gap at start or/and end of
136 // the text. Such gap should not be there.
138 // Load document and get shape. It is a custom shape from pptx import of a WordArt of
139 // kind 'Follow Path'.
140 OUString aURL
= m_directories
.getURLFromSrc(sDataDirectory
) + "tdf145004_gap_by_ScaleX.pptx";
141 mxComponent
= loadFromDesktop(aURL
, "com.sun.star.comp.presentation.PresentationDocument");
142 uno::Reference
<drawing::XShape
> xShape(getShape(0));
143 SdrObjCustomShape
& rSdrCustomShape(
144 static_cast<SdrObjCustomShape
&>(*SdrObject::getSdrObjectFromXShape(xShape
)));
146 // Verify width. Without the fix in place the width was 8231, but should be 8496 for 96dpi.
147 // Was 8328, should be 8527 for 120dpi.
148 tools::Rectangle
aBoundRect(rSdrCustomShape
.GetCurrentBoundRect());
149 CPPUNIT_ASSERT_DOUBLES_EQUAL(tools::Long(8496), aBoundRect
.GetWidth(), 5);
152 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testTdf141021ExtrusionNorth
)
154 // tdf#141021 Setting extrusion direction in projection method 'perspective' to
155 // 'Extrusion North' had used a wrong origin for the ViewPoint and thus the
156 // side faces were wrong calculated.
158 // Load document and get shape. It is a custom shape in 3D mode.
159 OUString aURL
= m_directories
.getURLFromSrc(sDataDirectory
) + "tdf141021_ExtrusionNorth.odp";
160 mxComponent
= loadFromDesktop(aURL
, "com.sun.star.comp.presentation.PresentationDocument");
161 uno::Reference
<drawing::XShape
> xShape(getShape(0));
162 SdrObjCustomShape
& rSdrCustomShape(
163 static_cast<SdrObjCustomShape
&>(*SdrObject::getSdrObjectFromXShape(xShape
)));
166 SfxViewShell
* pViewShell
= SfxViewShell::Current();
167 SdrView
* pSdrView
= pViewShell
->GetDrawView();
168 pSdrView
->MarkObj(&rSdrCustomShape
, pSdrView
->GetSdrPageView());
171 SfxRequest
aReq(pViewShell
->GetViewFrame(), SID_EXTRUSION_DIRECTION
);
172 SfxInt32Item
aItem(SID_EXTRUSION_DIRECTION
, 90);
173 aReq
.AppendItem(aItem
);
174 svx::ExtrusionBar::execute(pSdrView
, aReq
, SfxViewFrame::Current()->GetBindings());
176 // Verify height. Without the fix in place the height would 4001.
177 tools::Rectangle
aBoundRect(rSdrCustomShape
.GetCurrentBoundRect());
178 CPPUNIT_ASSERT_EQUAL(tools::Long(5895), aBoundRect
.GetHeight());
181 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testResizeRotatedShape
)
183 // tdf#138945 Setting width or height for a rotated or sheared shape in the Position&Size dialog
184 // had resulted in a mismatch of handle position and shape outline. That becomes visible in object
185 // properties as mismatch of frame rectangle and bound rectangle.
186 // Problem was, that fObjectRotation was not updated.
188 // Load document and get shape. It is a rectangle custom shape with 45° shear and 330° rotation.
190 = m_directories
.getURLFromSrc(sDataDirectory
) + "tdf138945_resizeRotatedShape.odg";
191 mxComponent
= loadFromDesktop(aURL
, "com.sun.star.comp.presentation.PresentationDocument");
192 uno::Reference
<drawing::XShape
> xShape(getShape(0));
194 // Change height and mirror vertical
196 SdrObjCustomShape
& rSdrShape(
197 static_cast<SdrObjCustomShape
&>(*SdrObject::getSdrObjectFromXShape(xShape
)));
198 rSdrShape
.NbcResize(rSdrShape
.GetRelativePos(), Fraction(1.0), Fraction(-0.5));
199 tools::Rectangle
aSnapRect(rSdrShape
.GetSnapRect());
200 tools::Rectangle
aBoundRect(rSdrShape
.GetCurrentBoundRect());
201 lcl_AssertRectEqualWithTolerance("height changed, mirror vert", aSnapRect
, aBoundRect
, 3);
206 SdrObjCustomShape
& rSdrShape(
207 static_cast<SdrObjCustomShape
&>(*SdrObject::getSdrObjectFromXShape(xShape
)));
208 rSdrShape
.NbcResize(rSdrShape
.GetRelativePos(), Fraction(1.0), Fraction(2.0));
209 tools::Rectangle
aSnapRect(rSdrShape
.GetSnapRect());
210 tools::Rectangle
aBoundRect(rSdrShape
.GetCurrentBoundRect());
211 lcl_AssertRectEqualWithTolerance("height changed", aSnapRect
, aBoundRect
, 3);
216 SdrObjCustomShape
& rSdrShape(
217 static_cast<SdrObjCustomShape
&>(*SdrObject::getSdrObjectFromXShape(xShape
)));
218 rSdrShape
.NbcResize(rSdrShape
.GetRelativePos(), Fraction(2.0), Fraction(1.0));
219 tools::Rectangle
aSnapRect(rSdrShape
.GetSnapRect());
220 tools::Rectangle
aBoundRect(rSdrShape
.GetCurrentBoundRect());
221 lcl_AssertRectEqualWithTolerance("width changed", aSnapRect
, aBoundRect
, 3);
224 // Change width and mirror horizontal
226 SdrObjCustomShape
& rSdrShape(
227 static_cast<SdrObjCustomShape
&>(*SdrObject::getSdrObjectFromXShape(xShape
)));
228 rSdrShape
.NbcResize(rSdrShape
.GetRelativePos(), Fraction(-0.5), Fraction(1.0));
229 tools::Rectangle
aSnapRect(rSdrShape
.GetSnapRect());
230 tools::Rectangle
aBoundRect(rSdrShape
.GetCurrentBoundRect());
231 lcl_AssertRectEqualWithTolerance("width changed, mirror hori", aSnapRect
, aBoundRect
, 3);
235 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testViewBoxLeftTop
)
237 // tdf#121890 formula values "left" and "top" are wrongly calculated
238 // Load a document with two custom shapes of type "non-primitive"
240 = m_directories
.getURLFromSrc(sDataDirectory
) + "viewBox_positive_twolines_strict.odp";
241 mxComponent
= loadFromDesktop(aURL
, "com.sun.star.comp.presentation.PresentationDocument");
242 // Get the shape "leftright". Error was, that the identifier "left" was always set to zero, thus
243 // the path was outside the frame rectangle for a viewBox having a positive "left" value.
244 uno::Reference
<drawing::XShape
> xShapeLR(getShape(0));
245 uno::Reference
<beans::XPropertySet
> xShapeLRProps(xShapeLR
, uno::UNO_QUERY
);
246 CPPUNIT_ASSERT_MESSAGE("Could not get the shape 'leftright' properties", xShapeLRProps
.is());
247 awt::Rectangle aFrameRectLR
;
248 xShapeLRProps
->getPropertyValue(UNO_NAME_MISC_OBJ_FRAMERECT
) >>= aFrameRectLR
;
249 awt::Rectangle aBoundRectLR
;
250 xShapeLRProps
->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT
) >>= aBoundRectLR
;
251 // difference should be zero, but allow some rounding errors
252 CPPUNIT_ASSERT_LESS(sal_Int32(3), std::abs(aFrameRectLR
.X
- aBoundRectLR
.X
));
254 // Get the shape "topbottom". Error was, that the identifier "top" was always set to zero, thus
255 // the path was outside the frame rectangle for a viewBox having a positive "top" value.
256 uno::Reference
<drawing::XShape
> xShapeTB(getShape(1));
257 uno::Reference
<beans::XPropertySet
> xShapeTBProps(xShapeTB
, uno::UNO_QUERY
);
258 CPPUNIT_ASSERT_MESSAGE("Could not get the shape 'topbottom' properties", xShapeTBProps
.is());
259 awt::Rectangle aFrameRectTB
;
260 xShapeTBProps
->getPropertyValue(UNO_NAME_MISC_OBJ_FRAMERECT
) >>= aFrameRectTB
;
261 awt::Rectangle aBoundRectTB
;
262 xShapeTBProps
->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT
) >>= aBoundRectTB
;
263 // difference should be zero, but allow some rounding errors
264 CPPUNIT_ASSERT_LESS(sal_Int32(3), std::abs(aFrameRectTB
.Y
- aBoundRectTB
.Y
));
267 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testAccuracyCommandX
)
269 // 121761 Increase accuracy of quarter circles drawn by command X or Y
270 // The loaded document has a quarter circle with radius 10000 (unit 1/100 mm)
271 // which is rotated by 45deg. The test considers the segment.
273 = m_directories
.getURLFromSrc(sDataDirectory
) + "tdf121761_Accuracy_command_X.odp";
274 mxComponent
= loadFromDesktop(aURL
, "com.sun.star.comp.presentation.PresentationDocument");
275 // Get the shape "arc_45deg_rotated". Error was, that a Bezier curve with bad parameters
276 // was used, thus the segment height was obviously smaller than for a true circle.
277 // Math: segment height approx 10000 * ( 1 - sqrt(0.5)) + line width
278 uno::Reference
<drawing::XShape
> xShape(getShape(0));
279 uno::Reference
<beans::XPropertySet
> xShapeProps(xShape
, uno::UNO_QUERY
);
280 CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShapeProps
.is());
281 awt::Rectangle aBoundRect
;
282 xShapeProps
->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT
) >>= aBoundRect
;
283 double fHeight
= static_cast<double>(aBoundRect
.Height
);
284 // The tolerance is a guess, might be smaller.
285 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("segment height out of tolerance", 2942.0, fHeight
, 8.0);
288 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testToggleCommandXY
)
290 // 121952 Toggle x- and y-direction if command X has several parameters
291 // The loaded document has a shape with command X and two parameter placed on a diagonal.
292 // The radius of the quarter circles are both 10000 (unit 1/100 mm).
293 // The shape is rotated by 45deg, so you get two segments, one up and one down.
295 = m_directories
.getURLFromSrc(sDataDirectory
) + "tdf121952_Toggle_direction_command_X.odp";
296 mxComponent
= loadFromDesktop(aURL
, "com.sun.star.comp.presentation.PresentationDocument");
297 // Error was, that the second segment was drawn with same direction as first one. If drawn
298 // correctly, the bounding box height of the segments together is about twice the single
299 // segment height. Math: segment height approx 10000 * ( 1 - sqrt(0.5)) + line width
300 uno::Reference
<drawing::XShape
> xShape(getShape(0));
301 uno::Reference
<beans::XPropertySet
> xShapeProps(xShape
, uno::UNO_QUERY
);
302 CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShapeProps
.is());
303 awt::Rectangle aBoundRect
;
304 xShapeProps
->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT
) >>= aBoundRect
;
305 double fHeight
= static_cast<double>(aBoundRect
.Height
);
306 // The tolerance is a guess, might be smaller.
307 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("segment height out of tolerance", 5871.0, fHeight
, 16.0);
310 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testMultipleMoveTo
)
312 // tdf122964 Multiple moveTo has to be treated as lineTo in draw:enhanced-path
313 // Load a document with path "M 0 0 5 10 10 0 N"
314 OUString aURL
= m_directories
.getURLFromSrc(sDataDirectory
) + "tdf122964_MultipleMoveTo.odg";
315 mxComponent
= loadFromDesktop(aURL
, "com.sun.star.comp.drawing.DrawingDocument");
316 // Error was, that the second and further parameter pairs were treated as moveTo,
317 // and so the generated path was empty, resulting in zero width and height of the
318 // bounding box. It has to be treated same as "M 0 0 L 5 10 10 0 N".
319 uno::Reference
<drawing::XShape
> xShape(getShape(0));
320 uno::Reference
<beans::XPropertySet
> xShapeProps(xShape
, uno::UNO_QUERY
);
321 CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShapeProps
.is());
322 awt::Rectangle aBoundRect
;
323 xShapeProps
->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT
) >>= aBoundRect
;
324 bool bIsZero(aBoundRect
.Height
== 0 && aBoundRect
.Width
== 0);
325 CPPUNIT_ASSERT_MESSAGE("Path is empty", !bIsZero
);
328 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testWidthOrientationCommandU
)
330 // tdf121845 custom shape with command U (angleellipse) is wrongly drawn
331 // Load a document with path "M 750 0 L 750 500 250 500 250 0 U 500 0 500 500 0 180 N"
332 // in viewBox="0 0 1000 500" and width="10cm", height="5cm".
334 = m_directories
.getURLFromSrc(sDataDirectory
) + "tdf121845_WidthOrientation_command_U.odg";
335 mxComponent
= loadFromDesktop(sURL
, "com.sun.star.comp.drawing.DrawingDocument");
336 // Error was, that the width and height of the ellipse was halved and that the ellipse
337 // was not drawn clockwise but counter clockwise.
338 uno::Reference
<drawing::XShape
> xShape(getShape(0));
339 uno::Reference
<beans::XPropertySet
> xShapeProps(xShape
, uno::UNO_QUERY
);
340 CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShapeProps
.is());
341 awt::Rectangle aBoundRect
;
342 xShapeProps
->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT
) >>= aBoundRect
;
343 const double fWidth
= static_cast<double>(aBoundRect
.Width
);
344 // Need some tolerance for line width
345 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("wrong width", 10000.0, fWidth
, 40.0);
346 const double fHeight
= static_cast<double>(aBoundRect
.Height
);
347 // Wrong orientation draws segment above the top of the viewBox and so increases 'Height'.
348 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("wrong orientation", 5000.0, fHeight
, 40.0);
351 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testHalfEllipseVML
)
353 // tdf121845 custom shape with command U (angleellipse) is wrongly drawn
354 // Load a document which was converted from VML to doc by Word. It had a VML
355 // path="m750,al500,,500,500,,-11796480e" resulting in a lower half circle.
357 = m_directories
.getURLFromSrc(sDataDirectory
) + "tdf121845_HalfEllipseVML.doc";
358 mxComponent
= loadFromDesktop(sURL
, "com.sun.star.comp.text.TextDocument");
359 // Error was, that a full circle instead of the half circle was draw.
360 uno::Reference
<drawing::XShape
> xShape(getShape(0));
361 uno::Reference
<beans::XPropertySet
> xShapeProps(xShape
, uno::UNO_QUERY
);
362 CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShapeProps
.is());
363 awt::Rectangle aBoundRect
;
364 xShapeProps
->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT
) >>= aBoundRect
;
365 const double fDiff2HmW
= static_cast<double>(2 * aBoundRect
.Height
- aBoundRect
.Width
);
366 // Need some tolerance for line width
367 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("not a half circle", 0.0, fDiff2HmW
, 40.0);
370 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testLargeSwingAngleVML
)
372 // tdf121845 custom shape with command U (angleellipse) is wrongly drawn
373 // Load a document which was converted from VML to doc by Word. It had a VML
374 // path="al50,50,45,45,2621440,31457280e" resulting in a full circle plus 120 deg segment.
376 = m_directories
.getURLFromSrc(sDataDirectory
) + "tdf121845_start40_swing480.doc";
377 mxComponent
= loadFromDesktop(sURL
, "com.sun.star.comp.text.TextDocument");
378 // Error was, that only the 120 deg segment was drawn.
379 uno::Reference
<drawing::XShape
> xShape(getShape(0));
380 uno::Reference
<beans::XPropertySet
> xShapeProps(xShape
, uno::UNO_QUERY
);
381 CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShapeProps
.is());
382 awt::Rectangle aBoundRect
;
383 xShapeProps
->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT
) >>= aBoundRect
;
384 const double fDiffWmH
= static_cast<double>(aBoundRect
.Width
- aBoundRect
.Height
);
385 // Need some tolerance for line width
386 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Full circle plus segment expected", 0.0, fDiffWmH
, 10.0);
388 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testTdf121845_two_commands_U
)
390 // tdf121845 custom shape with command U (angleellipse) is wrongly drawn
391 // Load a document with path "U 950 250 200 200 90 180 250 250 200 200 180 270 N"
392 // Error was, that the second ellipse segment was interpreted as command T and
393 // thus a line from first to second segment was drawn.
394 OUString sURL
= m_directories
.getURLFromSrc(sDataDirectory
) + "tdf121845_Two_commands_U.odg";
395 mxComponent
= loadFromDesktop(sURL
, "com.sun.star.comp.drawing.DrawingDocument");
396 uno::Reference
<drawing::XShape
> xShape(getShape(0));
397 // In case no line is drawn, two polygons are generated; with line only one polygon
398 SdrObjCustomShape
& rSdrObjCustomShape(
399 static_cast<SdrObjCustomShape
&>(*SdrObject::getSdrObjectFromXShape(xShape
)));
400 EnhancedCustomShape2d
aCustomShape2d(rSdrObjCustomShape
);
401 SdrPathObjUniquePtr
pPathObj(
402 static_cast<SdrPathObj
*>(aCustomShape2d
.CreateLineGeometry().release()));
403 CPPUNIT_ASSERT_MESSAGE("Could not convert to SdrPathObj", pPathObj
);
404 const basegfx::B2DPolyPolygon
aPolyPolygon(pPathObj
->GetPathPoly());
405 CPPUNIT_ASSERT_EQUAL_MESSAGE("count polygons", static_cast<sal_uInt32
>(2),
406 aPolyPolygon
.count());
409 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testTdf124212_handle_position
)
411 // tdf124212 Adjustment handle reacts wrongly, if custom shape has a non
412 // default viewBox. Load a document with svg:viewBox="10800 0 10800 21600"
413 // Error was, that moving the controller results in a handle position that
414 // does not reflect the movement.
415 OUString sURL
= m_directories
.getURLFromSrc(sDataDirectory
) + "tdf124212_handle_position.odg";
416 mxComponent
= loadFromDesktop(sURL
, "com.sun.star.comp.drawing.DrawingDocument");
417 uno::Reference
<drawing::XShape
> xShape(getShape(0));
418 // The shape has one, horizontal adjust handle.
419 SdrObjCustomShape
& rSdrObjCustomShape(
420 static_cast<SdrObjCustomShape
&>(*SdrObject::getSdrObjectFromXShape(xShape
)));
421 EnhancedCustomShape2d
aCustomShape2d(rSdrObjCustomShape
);
422 Point aInitialPosition
;
423 aCustomShape2d
.GetHandlePosition(0, aInitialPosition
);
424 css::awt::Point
aDesiredPosition(aInitialPosition
.X() + 1000, aInitialPosition
.Y());
425 aCustomShape2d
.SetHandleControllerPosition(0, aDesiredPosition
);
426 Point aObservedPosition
;
427 aCustomShape2d
.GetHandlePosition(0, aObservedPosition
);
428 sal_Int32
nDesiredX(aDesiredPosition
.X
); // awt::Point
429 sal_Int32
nObservedX(aObservedPosition
.X()); // tools::Point
430 CPPUNIT_ASSERT_EQUAL_MESSAGE("handle X coordinate", nDesiredX
, nObservedX
);
433 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testTdf124029_arc_position
)
435 // tdf121029 MS binary custom shape mso_sptArc has wrong position
436 // MS uses the sector for position reference. Error was, that
437 // LibreOffice has used the underlying ellipse.
438 OUString sURL
= m_directories
.getURLFromSrc(sDataDirectory
) + "tdf124029_Arc_position.doc";
439 mxComponent
= loadFromDesktop(sURL
, "com.sun.star.comp.text.TextDocument");
440 uno::Reference
<drawing::XShape
> xShape(getShape(0));
441 // The visual wrong position is due to a wrong shape width.
442 uno::Reference
<beans::XPropertySet
> xShapeProps(xShape
, uno::UNO_QUERY
);
443 CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShapeProps
.is());
444 awt::Rectangle aFrameRect
;
445 xShapeProps
->getPropertyValue(UNO_NAME_MISC_OBJ_FRAMERECT
) >>= aFrameRect
;
446 CPPUNIT_ASSERT_EQUAL_MESSAGE("shape width", static_cast<sal_uInt32
>(1610),
447 static_cast<sal_uInt32
>(aFrameRect
.Width
));
450 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testTdf124740_handle_path_coordsystem
)
452 // tdf124740 OOXML shape with handle and w and h attribute on path has wrong
454 // The handle position was scaled erroneously twice.
456 = m_directories
.getURLFromSrc(sDataDirectory
) + "tdf124740_HandleInOOXMLUserShape.pptx";
457 mxComponent
= loadFromDesktop(sURL
, "com.sun.star.comp.drawing.DrawingDocument");
458 uno::Reference
<drawing::XShape
> xShape(getShape(0));
459 // The shape has one, horizontal adjust handle. It is about 1/5 of 10cm from left
460 // shape edge, shape is 6cm from left . That results in a position
461 // of 8cm from left page edge, which is 8000 in 1/100 mm unit.
462 SdrObjCustomShape
& rSdrObjCustomShape(
463 static_cast<SdrObjCustomShape
&>(*SdrObject::getSdrObjectFromXShape(xShape
)));
464 EnhancedCustomShape2d
aCustomShape2d(rSdrObjCustomShape
);
466 aCustomShape2d
.GetHandlePosition(0, aPosition
);
467 double fX(aPosition
.X());
468 // tolerance for rounding to integer
469 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("handle X coordinate", 8000.0, fX
, 2.0);
472 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testTdf115813_OOXML_XY_handle
)
474 // The test covers all preset shapes with handles. Only these ones are
475 // excluded: arc, blockArc, chord, circularArrow, gear6, gear9, mathNotEqual, pie,
476 // leftCircularArrow, leftRightCircularArrow, swooshArrow.
477 // Connectors are included as ordinary shapes to prevent converting.
478 // Error was, that the handle movement and the changes to the shape did not follow
479 // the mouse movement.
480 OUString sURL
= m_directories
.getURLFromSrc(sDataDirectory
)
481 + "tdf115813_HandleMovementOOXMLPresetShapes.pptx";
482 mxComponent
= loadFromDesktop(sURL
, "com.sun.star.comp.drawing.DrawingDocument");
485 // values in vector InteractionsHandles are in 1/100 mm and refer to page
486 for (sal_uInt8 i
= 0; i
< countShapes(); i
++)
488 uno::Reference
<drawing::XShape
> xShape(getShape(i
));
489 SdrObjCustomShape
& rSdrObjCustomShape(
490 static_cast<SdrObjCustomShape
&>(*SdrObject::getSdrObjectFromXShape(xShape
)));
491 OUString
sShapeType("non-primitive"); // default for ODF
492 const SdrCustomShapeGeometryItem
& rGeometryItem(
493 rSdrObjCustomShape
.GetMergedItem(SDRATTR_CUSTOMSHAPE_GEOMETRY
));
494 const uno::Any
* pAny
= rGeometryItem
.GetPropertyValueByName("Type");
496 *pAny
>>= sShapeType
;
498 sal_uInt8 nHandlesCount
= rSdrObjCustomShape
.GetInteractionHandles().size();
499 for (sal_uInt8 j
= 0; j
< nHandlesCount
; j
++)
501 css::awt::Point
aInitialPosition(
502 rSdrObjCustomShape
.GetInteractionHandles()[j
].aPosition
);
503 // The handles are initialized in the test document, so that if the handle is moveable in
504 // that direction at all, then it can move at least with an amount of 100.
505 Point
aDesiredPosition(aInitialPosition
.X
+ 100, aInitialPosition
.Y
+ 100);
506 rSdrObjCustomShape
.DragMoveCustomShapeHdl(aDesiredPosition
, j
, false);
507 css::awt::Point
aObservedPosition(
508 rSdrObjCustomShape
.GetInteractionHandles()[j
].aPosition
);
509 sal_Int32
nDesiredX(aDesiredPosition
.X()); // tools::Point
510 sal_Int32
nDesiredY(aDesiredPosition
.Y());
511 sal_Int32
nObservedX(aObservedPosition
.X
); // css::awt::Point
512 sal_Int32
nObservedY(aObservedPosition
.Y
);
513 // If a handle only moves in one direction, the difference is 100 for the other direction.
514 // There exists some rounding differences, therefore '<= 1' instead of '== 0'.
515 // The condition has the form '!(good cases)'.
516 if (!((abs(nDesiredX
- nObservedX
) <= 1 && abs(nDesiredY
- nObservedY
) == 100)
517 || (abs(nDesiredX
- nObservedX
) == 100 && abs(nDesiredY
- nObservedY
) <= 1)
518 || (abs(nDesiredX
- nObservedX
) <= 1 && abs(nDesiredY
- nObservedY
) <= 1)))
521 //sErrors += OUString(sal_Unicode(10));
522 OUString::number(i
) + " " + sShapeType
+ ": " + OUString::number(j
)
523 + " X " + OUString::number(nDesiredX
) + "|"
524 + OUString::number(nObservedX
) + " Y " + OUString::number(nDesiredY
)
525 + "|" + OUString::number(nObservedY
);
529 CPPUNIT_ASSERT_EQUAL(OUString(), sErrors
);
532 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testQuadraticCurveTo
)
534 // tdf125782 command Q (quadraticcurveto) uses wrong 'current point'.
535 // When converting to cubic Bezier curve, this had resulted in a wrong first control point.
536 // The quadraticcurveto segment starts in shape center in the test file. The first control
537 // point should produce a horizontal tangent in the start point.
539 = m_directories
.getURLFromSrc(sDataDirectory
) + "tdf125782_QuadraticCurveTo.odg";
540 mxComponent
= loadFromDesktop(sURL
, "com.sun.star.comp.drawing.DrawingDocument");
541 uno::Reference
<drawing::XShape
> xShape(getShape(0));
542 uno::Reference
<beans::XPropertySet
> xShapeProps(xShape
, uno::UNO_QUERY
);
543 CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShapeProps
.is());
544 awt::Rectangle aBoundRect
;
545 xShapeProps
->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT
) >>= aBoundRect
;
546 const double fHeight
= static_cast<double>(aBoundRect
.Height
);
548 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("bad height of quadraticcurveto", 3004, fHeight
, 10.0);
551 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testTdf126512_OOXML_handle_in_ODP
)
553 // The test covers all preset shapes with handles. Connectors are included as ordinary
554 // shapes to prevent converting. The file was created in PowerPoint 365 and then
555 // opened and exported to ODF format by LibreOffice.
556 // Error was, that for shapes, which were originally imported from OOXML, the handles
557 // could not be moved at all.
559 = m_directories
.getURLFromSrc(sDataDirectory
) + "tdf126512_OOXMLHandleMovementInODF.odp";
560 mxComponent
= loadFromDesktop(sURL
, "com.sun.star.comp.drawing.DrawingDocument");
562 OUString sErrors
; // sErrors collects shape type and handle index for failing cases
563 for (sal_uInt8 i
= 0; i
< countShapes(); i
++)
565 uno::Reference
<drawing::XShape
> xShape(getShape(i
));
566 SdrObjCustomShape
& rSdrObjCustomShape(
567 static_cast<SdrObjCustomShape
&>(*SdrObject::getSdrObjectFromXShape(xShape
)));
568 OUString
sShapeType("non-primitive"); // only to initialize, value not used here
569 const SdrCustomShapeGeometryItem
& rGeometryItem(
570 rSdrObjCustomShape
.GetMergedItem(SDRATTR_CUSTOMSHAPE_GEOMETRY
));
571 const uno::Any
* pAny
= rGeometryItem
.GetPropertyValueByName("Type");
573 *pAny
>>= sShapeType
;
575 sal_uInt8 nHandlesCount
= rSdrObjCustomShape
.GetInteractionHandles().size();
576 for (sal_uInt8 j
= 0; j
< nHandlesCount
; j
++)
578 css::awt::Point
aInitialPosition(
579 rSdrObjCustomShape
.GetInteractionHandles()[j
].aPosition
);
580 // The handles are initialized in the test document, so that if the handle is moveable
581 // in that direction at all, then it can move at least with an amount of 100.
582 Point
aDesiredPosition(aInitialPosition
.X
+ 100, aInitialPosition
.Y
+ 100);
583 rSdrObjCustomShape
.DragMoveCustomShapeHdl(aDesiredPosition
, j
, false);
584 css::awt::Point
aObservedPosition(
585 rSdrObjCustomShape
.GetInteractionHandles()[j
].aPosition
);
586 if (aInitialPosition
.X
== aObservedPosition
.X
587 && aInitialPosition
.Y
== aObservedPosition
.Y
)
590 += "\n" + OUString::number(i
) + " " + sShapeType
+ " " + OUString::number(j
);
594 CPPUNIT_ASSERT_EQUAL(OUString(), sErrors
);
597 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testTdf127785_Mirror
)
599 // The document contains two shapes, one with horizontal flip, the other with vertical
600 // flip. They are diamonds, so their text frame is symmetric to the center of the shape.
601 // The shapes have not stroke and no fill, so that the bounding box surrounds the text
602 // and therefore equals approximately the text frame.
603 // Error was, that because of wrong calculation, the flipped shapes do not use the
604 // text frame but the frame rectangle for their text.
605 OUString sURL
= m_directories
.getURLFromSrc(sDataDirectory
) + "tdf127785_Mirror.odp";
606 mxComponent
= loadFromDesktop(sURL
, "com.sun.star.comp.drawing.DrawingDocument");
607 OUString sErrors
; // sErrors collects the errors and should be empty in case all is OK.
609 uno::Reference
<drawing::XShape
> xShapeV(getShape(0));
610 uno::Reference
<beans::XPropertySet
> xShapeVProps(xShapeV
, uno::UNO_QUERY
);
611 CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShapeVProps
.is());
612 awt::Rectangle aBoundRectV
;
613 xShapeVProps
->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT
) >>= aBoundRectV
;
614 const sal_Int32 nHeightV
= aBoundRectV
.Height
;
615 const sal_Int32 nWidthV
= aBoundRectV
.Width
;
616 const sal_Int32 nLeftV
= aBoundRectV
.X
;
617 const sal_Int32 nTopV
= aBoundRectV
.Y
;
618 if (abs(nHeightV
- 8000) > 10 || abs(nWidthV
- 8000) > 10)
619 sErrors
+= "Flip vertical wrong size.";
620 if (abs(nLeftV
- 1000) > 10 || abs(nTopV
- 2000) > 10)
621 sErrors
+= " Flip vertical wrong position.";
623 uno::Reference
<drawing::XShape
> xShapeH(getShape(1));
624 uno::Reference
<beans::XPropertySet
> xShapeHProps(xShapeH
, uno::UNO_QUERY
);
625 CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShapeHProps
.is());
626 awt::Rectangle aBoundRectH
;
627 xShapeHProps
->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT
) >>= aBoundRectH
;
628 const sal_Int32 nHeightH
= aBoundRectH
.Height
;
629 const sal_Int32 nWidthH
= aBoundRectH
.Width
;
630 const sal_Int32 nLeftH
= aBoundRectH
.X
;
631 const sal_Int32 nTopH
= aBoundRectH
.Y
;
632 if (abs(nHeightH
- 8000) > 10 || abs(nWidthH
- 8000) > 10)
633 sErrors
+= " Flip horizontal wrong size.";
634 if (abs(nLeftH
- 13000) > 10 || abs(nTopH
- 2000) > 10)
635 sErrors
+= " Flip horizontal wrong position.";
637 CPPUNIT_ASSERT_EQUAL(OUString(), sErrors
);
640 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testTdf126060_3D_Z_Rotation
)
642 // The document contains one textbox with inside overflowed text
643 // and the text has 3D z rotation. When we open the document we
644 // should see the text vertically and rotated from text bound center not text box.
646 OUString sURL
= m_directories
.getURLFromSrc(sDataDirectory
) + "tdf126060_3D_Z_Rotation.pptx";
647 mxComponent
= loadFromDesktop(sURL
, "com.sun.star.comp.drawing.DrawingDocument");
649 uno::Reference
<drawing::XShape
> xShape(getShape(0));
650 SdrObjCustomShape
& rSdrObjCustomShape(
651 static_cast<SdrObjCustomShape
&>(*SdrObject::getSdrObjectFromXShape(xShape
)));
653 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong text camera Z rotation", 90.0,
654 rSdrObjCustomShape
.GetCameraZRotation());
656 basegfx::B2DHomMatrix aObjectTransform
;
657 basegfx::B2DPolyPolygon aObjectPolyPolygon
;
658 rSdrObjCustomShape
.TRGetBaseGeometry(aObjectTransform
, aObjectPolyPolygon
);
660 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong transformation at 0,0 position", 1492.0,
661 aObjectTransform
.get(0, 0));
662 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong transformation at 0,1 position", 0.0,
663 aObjectTransform
.get(0, 1));
664 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong transformation at 0,2 position", 1129.0,
665 aObjectTransform
.get(0, 2));
666 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong transformation at 1,0 position", 0.0,
667 aObjectTransform
.get(1, 0));
668 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong transformation at 1,1 position", 2500.0,
669 aObjectTransform
.get(1, 1));
670 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong transformation at 1,2 position", 5846.0,
671 aObjectTransform
.get(1, 2));
674 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testTdf127785_Asymmetric
)
676 // The document contains a shapes with vertical flip and text frame asymmetrical
677 // to shape. The shape has not stroke and no fill, so that the bounding box surrounds
678 // the text and therefore equals approximately the text frame.
679 // Error was, that the 180deg text rotation was not compensated for the position of
680 // the flipped text box.
682 = m_directories
.getURLFromSrc(sDataDirectory
) + "tdf127785_asymmetricTextBoxFlipV.odg";
683 mxComponent
= loadFromDesktop(sURL
, "com.sun.star.comp.drawing.DrawingDocument");
684 OUString sErrors
; // sErrors collects the errors and should be empty in case all is OK.
686 uno::Reference
<drawing::XShape
> xShape(getShape(0));
687 uno::Reference
<beans::XPropertySet
> xShapeProps(xShape
, uno::UNO_QUERY
);
688 CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShapeProps
.is());
689 awt::Rectangle aBoundRect
;
690 xShapeProps
->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT
) >>= aBoundRect
;
691 const sal_Int32 nLeft
= aBoundRect
.X
;
692 const sal_Int32 nTop
= aBoundRect
.Y
;
693 const sal_Int32 nRight
= aBoundRect
.X
+ aBoundRect
.Width
- 1;
694 const sal_Int32 nBottom
= aBoundRect
.Y
+ aBoundRect
.Height
- 1;
695 if (abs(nLeft
- 9000) > 10)
696 sErrors
+= "wrong left";
697 if (abs(nRight
- 19000) > 10)
698 sErrors
+= " wrong right";
699 if (abs(nTop
- 3000) > 10)
700 sErrors
+= " wrong top";
701 if (abs(nBottom
- 18000) > 10)
702 sErrors
+= " wrong bottom";
704 CPPUNIT_ASSERT_EQUAL(OUString(), sErrors
);
707 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testTdf127785_TextRotateAngle
)
709 // The document contains a shapes with vertical flip and a text frame with own
710 // rotate angle. The shape has not stroke and no fill, so that the bounding box
711 // surrounds the text and therefore equals approximately the text frame.
712 // Error was, that the compensation for the 180° rotation added for vertical
713 // flip were not made to the text box position but to the text matrix.
714 OUString sURL
= m_directories
.getURLFromSrc(sDataDirectory
) + "tdf127785_TextRotateAngle.odp";
715 mxComponent
= loadFromDesktop(sURL
, "com.sun.star.comp.drawing.DrawingDocument");
716 OUString sErrors
; // sErrors collects the errors and should be empty in case all is OK.
718 uno::Reference
<drawing::XShape
> xShape(getShape(0));
719 uno::Reference
<beans::XPropertySet
> xShapeProps(xShape
, uno::UNO_QUERY
);
720 CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShapeProps
.is());
721 awt::Rectangle aBoundRect
;
722 xShapeProps
->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT
) >>= aBoundRect
;
723 const sal_Int32 nLeft
= aBoundRect
.X
;
724 const sal_Int32 nTop
= aBoundRect
.Y
;
725 const sal_Int32 nRight
= aBoundRect
.X
+ aBoundRect
.Width
- 1;
726 const sal_Int32 nBottom
= aBoundRect
.Y
+ aBoundRect
.Height
- 1;
727 if (abs(nLeft
- 2000) > 10)
728 sErrors
+= "wrong left";
729 if (abs(nRight
- 14000) > 10)
730 sErrors
+= " wrong right";
731 if (abs(nTop
- 3000) > 10)
732 sErrors
+= " wrong top";
733 if (abs(nBottom
- 9000) > 10)
734 sErrors
+= " wrong bottom";
736 CPPUNIT_ASSERT_EQUAL(OUString(), sErrors
);
739 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testTdf128413_tbrlOnOff
)
741 // The document contains a rotated shape with text. The error was, that switching
742 // tb-rl writing-mode on, changed the shape size and position.
744 OUString sURL
= m_directories
.getURLFromSrc(sDataDirectory
) + "tdf128413_tbrl_OnOff.odp";
745 mxComponent
= loadFromDesktop(sURL
, "com.sun.star.comp.drawing.DrawingDocument");
746 uno::Reference
<drawing::XShape
> xShape(getShape(0));
747 uno::Reference
<beans::XPropertySet
> xShapeProps(xShape
, uno::UNO_QUERY
);
748 CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShapeProps
.is());
749 awt::Rectangle aOrigRect
;
750 xShapeProps
->getPropertyValue(UNO_NAME_MISC_OBJ_FRAMERECT
) >>= aOrigRect
;
752 SdrObjCustomShape
& rSdrObjCustomShape(
753 static_cast<SdrObjCustomShape
&>(*SdrObject::getSdrObjectFromXShape(xShape
)));
754 rSdrObjCustomShape
.SetVerticalWriting(true);
756 awt::Rectangle aObservedRect
;
757 xShapeProps
->getPropertyValue(UNO_NAME_MISC_OBJ_FRAMERECT
) >>= aObservedRect
;
759 CPPUNIT_ASSERT_EQUAL_MESSAGE("Shape has wrong width", aOrigRect
.Width
, aObservedRect
.Width
);
760 CPPUNIT_ASSERT_EQUAL_MESSAGE("Shape has wrong height", aOrigRect
.Height
, aObservedRect
.Height
);
761 CPPUNIT_ASSERT_EQUAL_MESSAGE("Shape has wrong X position", aOrigRect
.X
, aObservedRect
.X
);
762 CPPUNIT_ASSERT_EQUAL_MESSAGE("Shape has wrong Y position", aOrigRect
.Y
, aObservedRect
.Y
);
765 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testTdf129532_MatrixFlipV
)
767 // The document contains two rotated shapes with the same geometry. For one of them
768 // "matrix(1 0 0 -1 0cm 0cm)" was manually added to the value of the draw:transform
769 // attribute. That should result in mirroring on the x-axis. Error was, that the lines
770 // which are drawn on the shape rectangle were mirrored, but not the rectangle itself.
771 // The rectangle was only shifted.
772 OUString sURL
= m_directories
.getURLFromSrc(sDataDirectory
) + "tdf129532_MatrixFlipV.odg";
773 mxComponent
= loadFromDesktop(sURL
, "com.sun.star.comp.drawing.DrawingDocument");
774 OUString sErrors
; // sErrors collects the errors and should be empty in case all is OK.
776 uno::Reference
<drawing::XShape
> xShape0(getShape(0));
777 uno::Reference
<beans::XPropertySet
> xShape0Props(xShape0
, uno::UNO_QUERY
);
778 CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShape0Props
.is());
779 awt::Rectangle aBoundRect0
;
780 xShape0Props
->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT
) >>= aBoundRect0
;
782 uno::Reference
<drawing::XShape
> xShape1(getShape(1));
783 uno::Reference
<beans::XPropertySet
> xShape1Props(xShape1
, uno::UNO_QUERY
);
784 CPPUNIT_ASSERT_MESSAGE("Could not get the shape properties", xShape1Props
.is());
785 awt::Rectangle aBoundRect1
;
786 xShape1Props
->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT
) >>= aBoundRect1
;
788 // The size of the two BoundRect rectangles are the same in case of correct
789 // vertical mirroring.
790 if (aBoundRect0
.Width
!= aBoundRect1
.Width
)
792 sErrors
+= "\n Width expected: " + OUString::number(aBoundRect1
.Width
)
793 + " actual: " + OUString::number(aBoundRect0
.Width
);
795 if (aBoundRect0
.Height
!= aBoundRect1
.Height
)
797 sErrors
+= "\n Height expected: " + OUString::number(aBoundRect1
.Height
)
798 + " actual: " + OUString::number(aBoundRect0
.Height
);
800 CPPUNIT_ASSERT_EQUAL(OUString(), sErrors
);
803 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testTdf103474_commandT_CaseZeroHeight
)
805 // tdf103474 custom shape with command T to create quarter ellipses in a bracket,
806 // corner case where the ellipse has zero height.
807 // Error was, that the calculation of the circle angle from the ellipse
808 // angle results in a wrong angle for the case 180° and height zero.
810 = m_directories
.getURLFromSrc(sDataDirectory
) + "tdf103474_commandT_CaseZeroHeight.odp";
811 mxComponent
= loadFromDesktop(sURL
, "com.sun.star.comp.presentation.PresentationDocument");
812 uno::Reference
<drawing::XShape
> xShape(getShape(0));
813 // The end points of the straight line segment should have the same x-coordinate of left
814 // of shape, and different y-coordinates, one top and the other bottom of the shape.
815 SdrObjCustomShape
& rSdrObjCustomShape(
816 static_cast<SdrObjCustomShape
&>(*SdrObject::getSdrObjectFromXShape(xShape
)));
817 EnhancedCustomShape2d
aCustomShape2d(rSdrObjCustomShape
);
818 SdrPathObjUniquePtr
pPathObj(
819 static_cast<SdrPathObj
*>(aCustomShape2d
.CreateLineGeometry().release()));
820 CPPUNIT_ASSERT_MESSAGE("Could not convert to SdrPathObj", pPathObj
);
821 const basegfx::B2DPolyPolygon
aPolyPolygon(pPathObj
->GetPathPoly());
822 CPPUNIT_ASSERT_EQUAL_MESSAGE("count polygons", static_cast<sal_uInt32
>(1),
823 aPolyPolygon
.count());
824 const basegfx::B2DPolygon
aPolygon(aPolyPolygon
.getB2DPolygon(0));
825 // Get the middle points of the polygon. They are the endpoints of the
826 // straight line segment regardless of the quarter ellipse parts, because
827 // the shape is symmetric.
828 const basegfx::B2DPoint
aStart(aPolygon
.getB2DPoint(aPolygon
.count() / 2 - 1));
829 const basegfx::B2DPoint
aEnd(aPolygon
.getB2DPoint(aPolygon
.count() / 2));
830 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("aStart x-coordinate", 13999.0, aStart
.getX(), 1.0);
831 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("aEnd x-coordinate", 13999.0, aEnd
.getX(), 1.0);
832 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("aStart y-coordinate", 9999.0, aStart
.getY(), 1.0);
833 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("aEnd y-coordinate", 1999.0, aEnd
.getY(), 1.0);
836 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testTdf103474_commandG_CaseZeroHeight
)
838 // Some as above, but with shape with command G.
840 = m_directories
.getURLFromSrc(sDataDirectory
) + "tdf103474_commandG_CaseZeroHeight.odp";
841 mxComponent
= loadFromDesktop(sURL
, "com.sun.star.comp.presentation.PresentationDocument");
842 uno::Reference
<drawing::XShape
> xShape(getShape(0));
843 // The end points of the straight line segment should have the same x-coordinate of left
844 // of shape, and different y-coordinates, one top and the other bottom of the shape.
845 SdrObjCustomShape
& rSdrObjCustomShape(
846 static_cast<SdrObjCustomShape
&>(*SdrObject::getSdrObjectFromXShape(xShape
)));
847 EnhancedCustomShape2d
aCustomShape2d(rSdrObjCustomShape
);
848 SdrPathObjUniquePtr
pPathObj(
849 static_cast<SdrPathObj
*>(aCustomShape2d
.CreateLineGeometry().release()));
850 CPPUNIT_ASSERT_MESSAGE("Could not convert to SdrPathObj", pPathObj
);
851 const basegfx::B2DPolyPolygon
aPolyPolygon(pPathObj
->GetPathPoly());
852 CPPUNIT_ASSERT_EQUAL_MESSAGE("count polygons", static_cast<sal_uInt32
>(1),
853 aPolyPolygon
.count());
854 const basegfx::B2DPolygon
aPolygon(aPolyPolygon
.getB2DPolygon(0));
855 // Get the middle points of the polygon. They are the endpoints of the
856 // straight line segment regardless of the quarter ellipse parts, because
857 // the shape is symmetric.
858 const basegfx::B2DPoint
aStart(aPolygon
.getB2DPoint(aPolygon
.count() / 2 - 1));
859 const basegfx::B2DPoint
aEnd(aPolygon
.getB2DPoint(aPolygon
.count() / 2));
860 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("aStart x-coordinate", 1999.0, aStart
.getX(), 1.0);
861 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("aEnd x-coordinate", 1999.0, aEnd
.getX(), 1.0);
862 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("aStart y-coordinate", 9999.0, aStart
.getY(), 1.0);
863 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("aEnd y-coordinate", 1999.0, aEnd
.getY(), 1.0);
866 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testTdf122323_largeSwingAngle
)
868 // SwingAngles are clamped to [-360;360] in MS Office. Error was, that LO calculated
869 // the end angle and used it modulo 360, no full ellipse was drawn.
871 = m_directories
.getURLFromSrc(sDataDirectory
) + "tdf122323_swingAngle_larger360deg.pptx";
872 mxComponent
= loadFromDesktop(sURL
, "com.sun.star.comp.presentation.PresentationDocument");
873 uno::Reference
<drawing::XShape
> xShape(getShape(0));
874 uno::Reference
<beans::XPropertySet
> xShapeProps(xShape
, uno::UNO_QUERY
);
875 SdrObjCustomShape
& rSdrObjCustomShape(
876 static_cast<SdrObjCustomShape
&>(*SdrObject::getSdrObjectFromXShape(xShape
)));
877 EnhancedCustomShape2d
aCustomShape2d(rSdrObjCustomShape
);
878 SdrPathObjUniquePtr
pPathObj(
879 static_cast<SdrPathObj
*>(aCustomShape2d
.CreateLineGeometry().release()));
880 CPPUNIT_ASSERT_MESSAGE("Could not convert to SdrPathObj", pPathObj
);
881 const basegfx::B2DPolyPolygon
aPolyPolygon(pPathObj
->GetPathPoly());
882 const basegfx::B2DPolygon
aPolygon(aPolyPolygon
.getB2DPolygon(0));
883 const basegfx::B2DPoint
aStart(aPolygon
.getB2DPoint(0));
884 // last point comes from line to center, therefore -2 instead of -1
885 const basegfx::B2DPoint
aEnd(aPolygon
.getB2DPoint(aPolygon
.count() - 2));
886 CPPUNIT_ASSERT_EQUAL_MESSAGE("Start <> End", aStart
, aEnd
);
889 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testTdf141268
)
891 OUString sURL
= m_directories
.getURLFromSrc(sDataDirectory
) + "tdf141268.odp";
892 mxComponent
= loadFromDesktop(sURL
, "com.sun.star.comp.presentation.PresentationDocument");
893 uno::Reference
<drawing::XShape
> xShape(getShape(0));
894 SdrObjCustomShape
& rSdrCustomShape(
895 static_cast<SdrObjCustomShape
&>(*SdrObject::getSdrObjectFromXShape(xShape
)));
897 // Check left/bottom of bound rect. Without fix it would be left=6722, bottom=9483.
898 tools::Rectangle
aBoundRect(rSdrCustomShape
.GetCurrentBoundRect());
899 CPPUNIT_ASSERT_EQUAL(tools::Long(7620), aBoundRect
.Left());
900 CPPUNIT_ASSERT_EQUAL(tools::Long(8585), aBoundRect
.Bottom());
903 CPPUNIT_TEST_FIXTURE(CustomshapesTest
, testTdf136176
)
905 // Error was, that fObjectRotation was not correctly updated after shearing.
906 // The problem becomes visible after save and reload.
907 OUString sURL
= m_directories
.getURLFromSrc(sDataDirectory
) + "tdf136176_rot30_flip.odg";
908 mxComponent
= loadFromDesktop(sURL
, "com.sun.star.comp.drawing.DrawingDocument");
910 for (sal_uInt16 i
= 0; i
< 3; i
++)
913 uno::Reference
<drawing::XShape
> xShape(getShape(i
));
914 SdrObjCustomShape
& rSdrObjCustomShape(
915 static_cast<SdrObjCustomShape
&>(*SdrObject::getSdrObjectFromXShape(xShape
)));
916 // apply shearing 20deg
917 const Point aCenter
= rSdrObjCustomShape
.GetSnapRect().Center();
918 rSdrObjCustomShape
.Shear(aCenter
, 2000_deg100
, tan(basegfx::deg2rad(20.0)), false);
922 uno::Reference
<frame::XStorable
> xStorable(mxComponent
, uno::UNO_QUERY
);
923 utl::TempFile aTempFile
;
924 aTempFile
.EnableKillingFile();
925 utl::MediaDescriptor aMediaDescriptor
;
926 aMediaDescriptor
["FilterName"] <<= OUString("draw8");
927 xStorable
->storeToURL(aTempFile
.GetURL(), aMediaDescriptor
.getAsConstPropertyValueList());
928 mxComponent
->dispose();
929 mxComponent
= loadFromDesktop(aTempFile
.GetURL());
931 // Expected values of point 4 of the shape polygon
932 const OString sTestCase
[] = { "FlipH", "FlipV", "FlipHV" };
933 const double fX
[] = { 14981.0, 3849.0, 15214.0 };
934 const double fY
[] = { 9366.0, 16464.0, 23463.0 };
936 // Verify correct positions
937 for (sal_uInt16 i
= 0; i
< 3; i
++)
940 const uno::Reference
<drawing::XShape
> xShape(getShape(i
));
941 const SdrObjCustomShape
& rSdrObjCustomShape(
942 static_cast<SdrObjCustomShape
&>(*SdrObject::getSdrObjectFromXShape(xShape
)));
943 // Create polygon from shape and examine point 4 of the polygon
944 const basegfx::B2DPolyPolygon aLineGeometry
= rSdrObjCustomShape
.GetLineGeometry(false);
945 const basegfx::B2DPoint
aPoint(aLineGeometry
.getB2DPolygon(0).getB2DPoint(4));
946 // Allow some tolerance for rounding errors
947 if (fabs(aPoint
.getX() - fX
[i
]) > 2.0 || fabs(aPoint
.getY() - fY
[i
]) > 2.0)
949 CPPUNIT_ASSERT_EQUAL_MESSAGE(sTestCase
[i
].getStr(), aPoint
,
950 basegfx::B2DPoint(fX
[i
], fY
[i
]));
956 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */