1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 #include <test/unoapixml_test.hxx>
12 #include <docmodel/color/ComplexColor.hxx>
13 #include <docmodel/uno/UnoComplexColor.hxx>
14 #include <editeng/unoprnms.hxx>
16 #include <com/sun/star/awt/Gradient2.hpp>
17 #include <com/sun/star/awt/Rectangle.hpp>
18 #include <com/sun/star/beans/XPropertySet.hpp>
19 #include <com/sun/star/drawing/ConnectorType.hpp>
20 #include <com/sun/star/drawing/PolyPolygonBezierCoords.hpp>
21 #include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
22 #include <com/sun/star/drawing/XShape.hpp>
23 #include <com/sun/star/lang/XServiceInfo.hpp>
24 #include <com/sun/star/text/XTextDocument.hpp>
25 #include <com/sun/star/text/XTextFrame.hpp>
26 #include <com/sun/star/text/XTextRange.hpp>
27 #include <com/sun/star/text/XTextTable.hpp>
28 #include <com/sun/star/text/XTextTablesSupplier.hpp>
29 #include <com/sun/star/util/XComplexColor.hpp>
30 using namespace ::com::sun::star
;
34 /// The test suite covers tests for import of Word drawing canvas (wpc), available since LO 24.2.
35 /// Before its implementation the VML fallback was used. That lost properties because VML is not able
36 /// to describe them or the VML import of LO has deficits.
37 class TestWPC
: public UnoApiXmlTest
41 : UnoApiXmlTest("/oox/qa/unit/data/")
46 CPPUNIT_TEST_FIXTURE(TestWPC
, WPC_Table_inside_Textbox
)
48 // The document has a table inside a text box on a drawing canvas.
49 loadFromFile(u
"WPC_tdf48610_Textbox_with_table_inside.docx");
51 // Make sure the table exists. Without import of drawing canvas, the table was lost.
52 uno::Reference
<text::XTextTablesSupplier
> xTextDocument(mxComponent
, uno::UNO_QUERY
);
53 uno::Reference
<container::XIndexAccess
> xTables(xTextDocument
->getTextTables(), uno::UNO_QUERY
);
54 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTables
->getCount());
57 CPPUNIT_TEST_FIXTURE(TestWPC
, WPC_Text_in_ellipse
)
59 // The document has text in an ellipse on a drawing canvas.
60 loadFromFile(u
"WPC_Textwrap_in_ellipse.docx");
62 // The VML import creates for an ellipse not a custom shape but a legacy ellipse and that has no
63 // word wrap. Thus the text was in one line and overflows the shape. This overflow becomes visible
64 // in the bounding box. Without fix the rectangle width was 9398 Hmm.
65 uno::Reference
<drawing::XDrawPagesSupplier
> xDrawPagesSupplier(mxComponent
, uno::UNO_QUERY
);
66 uno::Reference
<drawing::XDrawPage
> xDrawPage(xDrawPagesSupplier
->getDrawPages()->getByIndex(0),
68 uno::Reference
<drawing::XShapes
> xGroup(xDrawPage
->getByIndex(0), uno::UNO_QUERY
);
69 // getByIndex(0) gives the background shape, the ellipse is at index 1
70 uno::Reference
<beans::XPropertySet
> xShapeProps(xGroup
->getByIndex(1), uno::UNO_QUERY
);
71 awt::Rectangle aBoundRect
;
72 xShapeProps
->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT
) >>= aBoundRect
;
73 // The tolerance 10 is estimated and can be adjusted if required for HiDPI.
74 CPPUNIT_ASSERT_DOUBLES_EQUAL(4740, aBoundRect
.Width
, 10);
77 CPPUNIT_TEST_FIXTURE(TestWPC
, WPC_MulticolorGradient
)
79 // The document has a shape with multi color gradient fill on a drawing canvas.
80 loadFromFile(u
"WPC_MulticolorGradient.docx");
82 // The VML import was not able to import multicolor gradients. Thus only start and end color
83 // were imported, ColorStops had only two elements.
84 uno::Reference
<drawing::XDrawPagesSupplier
> xDrawPagesSupplier(mxComponent
, uno::UNO_QUERY
);
85 uno::Reference
<drawing::XDrawPage
> xDrawPage(xDrawPagesSupplier
->getDrawPages()->getByIndex(0),
87 uno::Reference
<drawing::XShapes
> xGroup(xDrawPage
->getByIndex(0), uno::UNO_QUERY
);
88 uno::Reference
<beans::XPropertySet
> xShapeProps(xGroup
->getByIndex(1), uno::UNO_QUERY
);
89 awt::Gradient2 aGradient
;
90 xShapeProps
->getPropertyValue(UNO_NAME_FILLGRADIENT
) >>= aGradient
;
91 CPPUNIT_ASSERT_EQUAL(sal_Int32(4), aGradient
.ColorStops
.getLength());
94 CPPUNIT_TEST_FIXTURE(TestWPC
, WPC_CanvasBackground
)
96 // The document has a drawing canvas with color fill.
97 loadFromFile(u
"WPC_CanvasBackground.docx");
99 // The VML import displayed the background as if it was transparent. Thus the BoundRect
100 // of the shape which represents the background was zero.
101 uno::Reference
<drawing::XDrawPagesSupplier
> xDrawPagesSupplier(mxComponent
, uno::UNO_QUERY
);
102 uno::Reference
<drawing::XDrawPage
> xDrawPage(xDrawPagesSupplier
->getDrawPages()->getByIndex(0),
104 uno::Reference
<drawing::XShapes
> xGroup(xDrawPage
->getByIndex(0), uno::UNO_QUERY
);
105 uno::Reference
<beans::XPropertySet
> xShapeProps(xGroup
->getByIndex(0), uno::UNO_QUERY
);
106 awt::Rectangle aBoundRect
;
107 xShapeProps
->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT
) >>= aBoundRect
;
108 CPPUNIT_ASSERT(aBoundRect
.Width
> 0);
109 CPPUNIT_ASSERT(aBoundRect
.Height
> 0);
112 CPPUNIT_TEST_FIXTURE(TestWPC
, WPC_Glow
)
114 // The document has a shape with glow effect.
115 loadFromFile(u
"WPC_Glow.docx");
117 // VML does not know any glow effect. Thus it was lost on import.
118 uno::Reference
<drawing::XDrawPagesSupplier
> xDrawPagesSupplier(mxComponent
, uno::UNO_QUERY
);
119 uno::Reference
<drawing::XDrawPage
> xDrawPage(xDrawPagesSupplier
->getDrawPages()->getByIndex(0),
121 uno::Reference
<drawing::XShapes
> xGroup(xDrawPage
->getByIndex(0), uno::UNO_QUERY
);
122 uno::Reference
<beans::XPropertySet
> xShapeProps(xGroup
->getByIndex(1), uno::UNO_QUERY
);
124 // Check glow properties
125 sal_Int32 nGlowEffectRad
= 0;
126 xShapeProps
->getPropertyValue(u
"GlowEffectRadius"_ustr
) >>= nGlowEffectRad
;
127 CPPUNIT_ASSERT_EQUAL(sal_Int32(564), nGlowEffectRad
); // 16 pt = 564.444... mm/100
128 Color nGlowEffectColor
;
129 xShapeProps
->getPropertyValue(u
"GlowEffectColor"_ustr
) >>= nGlowEffectColor
;
130 CPPUNIT_ASSERT_EQUAL(Color(0xFFFF00), nGlowEffectColor
); // "Yellow"
131 sal_Int16 nGlowEffectTransparency
= 0;
132 xShapeProps
->getPropertyValue(u
"GlowEffectTransparency"_ustr
) >>= nGlowEffectTransparency
;
133 CPPUNIT_ASSERT_EQUAL(sal_Int16(10), nGlowEffectTransparency
); // 10%
136 CPPUNIT_TEST_FIXTURE(TestWPC
, WPC_BentConnector
)
138 // The document has two shapes connected with a bentConnector on a drawing canvas.
139 loadFromFile(u
"WPC_BentConnector.docx");
141 // VML has no information about the target shapes of the connector. The connector was imported as
142 // custom shape, not as connector shape
143 uno::Reference
<drawing::XDrawPagesSupplier
> xDrawPagesSupplier(mxComponent
, uno::UNO_QUERY
);
144 uno::Reference
<drawing::XDrawPage
> xDrawPage(xDrawPagesSupplier
->getDrawPages()->getByIndex(0),
146 uno::Reference
<drawing::XShapes
> xGroup(xDrawPage
->getByIndex(0), uno::UNO_QUERY
);
147 uno::Reference
<lang::XServiceInfo
> xInfo(xGroup
->getByIndex(2), uno::UNO_QUERY
);
148 CPPUNIT_ASSERT(xInfo
->supportsService("com.sun.star.drawing.ConnectorShape"));
150 uno::Reference
<beans::XPropertySet
> xShapeProps(xGroup
->getByIndex(2), uno::UNO_QUERY
);
151 com::sun::star::drawing::ConnectorType eEdgeKind
;
152 xShapeProps
->getPropertyValue(UNO_NAME_EDGEKIND
) >>= eEdgeKind
;
153 CPPUNIT_ASSERT_EQUAL(drawing::ConnectorType::ConnectorType_STANDARD
, eEdgeKind
);
155 sal_Int32 nEdgeLineDelta
;
156 xShapeProps
->getPropertyValue(UNO_NAME_EDGELINE1DELTA
) >>= nEdgeLineDelta
;
157 CPPUNIT_ASSERT_EQUAL(sal_Int32(-635), nEdgeLineDelta
);
158 xShapeProps
->getPropertyValue(UNO_NAME_EDGELINE2DELTA
) >>= nEdgeLineDelta
;
159 CPPUNIT_ASSERT_EQUAL(sal_Int32(1949), nEdgeLineDelta
);
160 xShapeProps
->getPropertyValue(UNO_NAME_EDGELINE3DELTA
) >>= nEdgeLineDelta
;
161 CPPUNIT_ASSERT_EQUAL(sal_Int32(887), nEdgeLineDelta
);
164 CPPUNIT_TEST_FIXTURE(TestWPC
, WPC_ThemeColor
)
166 // The document has a shape with color fill used as pseudo background and a 'heart' shape with
167 // color fill and colored line. All colors are theme colors.
168 loadFromFile(u
"WPC_ThemeColor.docx");
170 // VML has no information about theme colors. Thus ThemeColorType was always 'Unknown'.
171 uno::Reference
<drawing::XDrawPagesSupplier
> xDrawPagesSupplier(mxComponent
, uno::UNO_QUERY
);
172 uno::Reference
<drawing::XDrawPage
> xDrawPage(xDrawPagesSupplier
->getDrawPages()->getByIndex(0),
174 uno::Reference
<drawing::XShapes
> xGroup(xDrawPage
->getByIndex(0), uno::UNO_QUERY
);
176 // Check color of shape used for pseudo background
178 uno::Reference
<beans::XPropertySet
> xShapeProps(xGroup
->getByIndex(0), uno::UNO_QUERY
);
179 uno::Reference
<util::XComplexColor
> xComplexColor
;
180 CPPUNIT_ASSERT(xShapeProps
->getPropertyValue(UNO_NAME_FILL_COMPLEX_COLOR
)
182 CPPUNIT_ASSERT(xComplexColor
.is());
183 auto aComplexColor
= model::color::getFromXComplexColor(xComplexColor
);
184 CPPUNIT_ASSERT_EQUAL(model::ThemeColorType::Dark2
, aComplexColor
.getThemeColorType());
186 auto const& rTrans
= aComplexColor
.getTransformations();
187 CPPUNIT_ASSERT_EQUAL(size_t(2), rTrans
.size());
188 CPPUNIT_ASSERT_EQUAL(model::TransformationType::LumMod
, rTrans
[0].meType
);
189 CPPUNIT_ASSERT_EQUAL(sal_Int16(7500), rTrans
[1].mnValue
);
190 CPPUNIT_ASSERT_EQUAL(model::TransformationType::LumOff
, rTrans
[1].meType
);
191 CPPUNIT_ASSERT_EQUAL(sal_Int16(2500), rTrans
[0].mnValue
);
194 // Check colors of 'heart' shape
196 uno::Reference
<beans::XPropertySet
> xShapeProps(xGroup
->getByIndex(1), uno::UNO_QUERY
);
197 uno::Reference
<util::XComplexColor
> xComplexColor
;
198 CPPUNIT_ASSERT(xShapeProps
->getPropertyValue(UNO_NAME_FILL_COMPLEX_COLOR
)
200 CPPUNIT_ASSERT(xComplexColor
.is());
201 auto aComplexColor
= model::color::getFromXComplexColor(xComplexColor
);
202 CPPUNIT_ASSERT_EQUAL(model::ThemeColorType::Accent5
, aComplexColor
.getThemeColorType());
205 uno::Reference
<beans::XPropertySet
> xShapeProps(xGroup
->getByIndex(1), uno::UNO_QUERY
);
206 uno::Reference
<util::XComplexColor
> xComplexColor
;
207 CPPUNIT_ASSERT(xShapeProps
->getPropertyValue(UNO_NAME_LINE_COMPLEX_COLOR
)
209 CPPUNIT_ASSERT(xComplexColor
.is());
210 auto aComplexColor
= model::color::getFromXComplexColor(xComplexColor
);
211 CPPUNIT_ASSERT_EQUAL(model::ThemeColorType::Accent4
, aComplexColor
.getThemeColorType());
215 CPPUNIT_TEST_FIXTURE(TestWPC
, WPC_tdf104671_Cloud
)
217 // The document has 'cloud' shape on a drawing canvas.
218 loadFromFile(u
"WPC_tdf104671_Cloud.docx");
220 // MS Office writes the 'cloud' shape without type to the VML fallback. Thus the VLM import uses
221 // ClosedBezierShape with several closed polygons. That produces holes because of the even-odd
222 // rule, and inner lines. The fix uses the mc:Choice alternative which provides the type for a
224 uno::Reference
<drawing::XDrawPagesSupplier
> xDrawPagesSupplier(mxComponent
, uno::UNO_QUERY
);
225 uno::Reference
<drawing::XDrawPage
> xDrawPage(xDrawPagesSupplier
->getDrawPages()->getByIndex(0),
227 uno::Reference
<drawing::XShapes
> xGroup(xDrawPage
->getByIndex(0), uno::UNO_QUERY
);
228 uno::Reference
<lang::XServiceInfo
> xInfo(xGroup
->getByIndex(1), uno::UNO_QUERY
);
229 CPPUNIT_ASSERT(xInfo
->supportsService("com.sun.star.drawing.CustomShape"));
232 CPPUNIT_TEST_FIXTURE(TestWPC
, WPC_Shadow
)
234 // The document has a shape with blur shadow on a drawing canvas.
235 loadFromFile(u
"WPC_Shadow.docx");
237 // The VML fallback contains a block shadow. Blur is not available in VML. The VML import does not
238 // import shadow at all.
239 uno::Reference
<drawing::XDrawPagesSupplier
> xDrawPagesSupplier(mxComponent
, uno::UNO_QUERY
);
240 uno::Reference
<drawing::XDrawPage
> xDrawPage(xDrawPagesSupplier
->getDrawPages()->getByIndex(0),
242 uno::Reference
<drawing::XShapes
> xGroup(xDrawPage
->getByIndex(0), uno::UNO_QUERY
);
243 uno::Reference
<beans::XPropertySet
> xShapeProps(xGroup
->getByIndex(1), uno::UNO_QUERY
);
244 bool bHasShadow
= false;
245 xShapeProps
->getPropertyValue(UNO_NAME_SHADOW
) >>= bHasShadow
;
246 CPPUNIT_ASSERT(bHasShadow
);
248 xShapeProps
->getPropertyValue(UNO_NAME_SHADOWBLUR
) >>= nValue
;
249 CPPUNIT_ASSERT_EQUAL(sal_Int32(282), nValue
);
250 xShapeProps
->getPropertyValue(UNO_NAME_SHADOWXDIST
) >>= nValue
;
251 CPPUNIT_ASSERT_EQUAL(sal_Int32(224), nValue
);
252 xShapeProps
->getPropertyValue(UNO_NAME_SHADOWYDIST
) >>= nValue
;
253 CPPUNIT_ASSERT_EQUAL(sal_Int32(224), nValue
);
255 xShapeProps
->getPropertyValue(UNO_NAME_SHADOWCOLOR
) >>= nColor
;
256 CPPUNIT_ASSERT_EQUAL(Color(0x808080), nColor
);
259 CPPUNIT_TEST_FIXTURE(TestWPC
, WPC_tdf158339_shape_text_in_group
)
261 // The document has a group of two shapes with text. This group is child of a drawing canvas.
262 // Without fix the text of the shapes were imported as separate text boxes.
263 loadFromFile(u
"WPC_tdf158339_shape_text_in_group.docx");
265 uno::Reference
<drawing::XDrawPagesSupplier
> xDrawPagesSupplier(mxComponent
, uno::UNO_QUERY
);
266 uno::Reference
<drawing::XDrawPage
> xDrawPage(xDrawPagesSupplier
->getDrawPages()->getByIndex(0),
268 // Make sure there is only one object on that page. Without fix there were three objects.
269 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xDrawPage
->getCount());
270 // Get the group which represents the drawing canvas and the group object inside.
271 uno::Reference
<drawing::XShapes
> xCanvas(xDrawPage
->getByIndex(0), uno::UNO_QUERY
);
272 uno::Reference
<drawing::XShapes
> xGroup(xCanvas
->getByIndex(1), uno::UNO_QUERY
);
273 // Get the properties of the second shape inside the group
274 uno::Reference
<beans::XPropertySet
> xShapeProps(xGroup
->getByIndex(1), uno::UNO_QUERY
);
275 // and make sure the shape has text.
276 uno::Reference
<css::text::XTextFrame
> xTextFrame
;
277 xShapeProps
->getPropertyValue(u
"TextBoxContent"_ustr
) >>= xTextFrame
;
278 CPPUNIT_ASSERT(xTextFrame
.is());
279 CPPUNIT_ASSERT_EQUAL(OUString("Group"), xTextFrame
->getText()->getString());
282 CPPUNIT_TEST_FIXTURE(TestWPC
, WPC_tdf158348_shape_text_in_table_cell
)
284 // The document has a shape with text on a drawing canvas in a table cell.
285 // Without fix the text of the shape becomes part of the paragraph of the table cell.
286 loadFromFile(u
"WPC_tdf158348_shape_text_in_table_cell.docx");
288 uno::Reference
<drawing::XDrawPagesSupplier
> xDrawPagesSupplier(mxComponent
, uno::UNO_QUERY
);
289 uno::Reference
<drawing::XDrawPage
> xDrawPage(xDrawPagesSupplier
->getDrawPages()->getByIndex(0),
292 // Get the shape and make sure it has text.
293 uno::Reference
<drawing::XShapes
> xCanvas(xDrawPage
->getByIndex(0), uno::UNO_QUERY
);
294 uno::Reference
<beans::XPropertySet
> xShapeProps(xCanvas
->getByIndex(1), uno::UNO_QUERY
);
295 uno::Reference
<css::text::XTextFrame
> xTextFrame
;
296 xShapeProps
->getPropertyValue(u
"TextBoxContent"_ustr
) >>= xTextFrame
;
297 CPPUNIT_ASSERT(xTextFrame
.is());
298 // The string was empty without fix.
299 CPPUNIT_ASSERT_EQUAL(u
"Inside shape"_ustr
, xTextFrame
->getText()->getString());
301 // Get the table and make sure the cell has only its own text.
302 uno::Reference
<text::XTextTablesSupplier
> xTablesSupplier(mxComponent
, uno::UNO_QUERY
);
303 uno::Reference
<text::XTextTable
> xTextTable(
304 xTablesSupplier
->getTextTables()->getByName(u
"Table1"_ustr
), uno::UNO_QUERY
);
305 uno::Reference
<text::XTextRange
> xCellA1(xTextTable
->getCellByName("A1"), uno::UNO_QUERY
);
306 // The string had started with "Inside shape" without fix.
307 CPPUNIT_ASSERT(xCellA1
->getString().startsWith("Inside table"));
310 CPPUNIT_TEST_FIXTURE(TestWPC
, WPC_CurvedConnector2
)
312 // The document has two shapes connected with a curvedConnector2 on a drawing canvas.
313 // This connector is a single Bezier segment without handles.
314 loadFromFile(u
"WPC_CurvedConnector2.docx");
316 // LO and OOXML differ in the position of the control points. LibreOffice uses 2/3 but OOXML
317 // uses 1/2 of width or height. The path by LO looks more round.
318 uno::Reference
<drawing::XDrawPagesSupplier
> xDrawPagesSupplier(mxComponent
, uno::UNO_QUERY
);
319 uno::Reference
<drawing::XDrawPage
> xDrawPage(xDrawPagesSupplier
->getDrawPages()->getByIndex(0),
321 uno::Reference
<drawing::XShapes
> xGroup(xDrawPage
->getByIndex(0), uno::UNO_QUERY
);
322 uno::Reference
<lang::XServiceInfo
> xInfo(xGroup
->getByIndex(3), uno::UNO_QUERY
);
323 CPPUNIT_ASSERT(xInfo
->supportsService("com.sun.star.drawing.ConnectorShape"));
325 uno::Reference
<beans::XPropertySet
> xShapeProps(xGroup
->getByIndex(3), uno::UNO_QUERY
);
326 com::sun::star::drawing::ConnectorType eEdgeKind
;
327 xShapeProps
->getPropertyValue(UNO_NAME_EDGEKIND
) >>= eEdgeKind
;
328 CPPUNIT_ASSERT_EQUAL(drawing::ConnectorType::ConnectorType_CURVE
, eEdgeKind
);
330 // Make sure the path is OOXML compatible
331 drawing::PolyPolygonBezierCoords aPolyPolygonBezierCoords
;
332 xShapeProps
->getPropertyValue("PolyPolygonBezier") >>= aPolyPolygonBezierCoords
;
333 drawing::PointSequence aPolygon
= aPolyPolygonBezierCoords
.Coordinates
[0];
334 // First control point. LO routing would generate point (4372|5584).
335 CPPUNIT_ASSERT_EQUAL(sal_Int32(5149), aPolygon
[1].Y
);
336 // Second control point. LO routing would generate point (5887|6458).
337 CPPUNIT_ASSERT_EQUAL(sal_Int32(6645), aPolygon
[2].X
);
341 CPPUNIT_PLUGIN_IMPLEMENT();
343 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */