/src/libreoffice/xmloff/source/draw/XMLImageMapExport.cxx
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | /* |
3 | | * This file is part of the LibreOffice project. |
4 | | * |
5 | | * This Source Code Form is subject to the terms of the Mozilla Public |
6 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
7 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
8 | | * |
9 | | * This file incorporates work covered by the following license notice: |
10 | | * |
11 | | * Licensed to the Apache Software Foundation (ASF) under one or more |
12 | | * contributor license agreements. See the NOTICE file distributed |
13 | | * with this work for additional information regarding copyright |
14 | | * ownership. The ASF licenses this file to you under the Apache |
15 | | * License, Version 2.0 (the "License"); you may not use this file |
16 | | * except in compliance with the License. You may obtain a copy of |
17 | | * the License at http://www.apache.org/licenses/LICENSE-2.0 . |
18 | | */ |
19 | | |
20 | | #include <XMLImageMapExport.hxx> |
21 | | #include <o3tl/any.hxx> |
22 | | #include <rtl/ustring.hxx> |
23 | | #include <rtl/ustrbuf.hxx> |
24 | | #include <tools/debug.hxx> |
25 | | #include <com/sun/star/uno/Reference.h> |
26 | | #include <com/sun/star/uno/Sequence.h> |
27 | | #include <com/sun/star/beans/XPropertySet.hpp> |
28 | | #include <com/sun/star/lang/XServiceInfo.hpp> |
29 | | #include <com/sun/star/container/XIndexContainer.hpp> |
30 | | #include <com/sun/star/document/XEventsSupplier.hpp> |
31 | | #include <com/sun/star/awt/Rectangle.hpp> |
32 | | #include <com/sun/star/awt/Point.hpp> |
33 | | #include <com/sun/star/drawing/PointSequence.hpp> |
34 | | #include <xmloff/xmlexp.hxx> |
35 | | #include <xmloff/xmlnamespace.hxx> |
36 | | #include <xmloff/xmltoken.hxx> |
37 | | #include <xmloff/XMLEventExport.hxx> |
38 | | #include <xmloff/xmluconv.hxx> |
39 | | #include <xexptran.hxx> |
40 | | #include <basegfx/polygon/b2dpolygon.hxx> |
41 | | #include <basegfx/polygon/b2dpolygontools.hxx> |
42 | | |
43 | | using namespace ::com::sun::star; |
44 | | using namespace ::xmloff::token; |
45 | | |
46 | | using ::com::sun::star::uno::Any; |
47 | | using ::com::sun::star::uno::UNO_QUERY; |
48 | | using ::com::sun::star::uno::Sequence; |
49 | | using ::com::sun::star::uno::Reference; |
50 | | using ::com::sun::star::beans::XPropertySet; |
51 | | using ::com::sun::star::container::XIndexContainer; |
52 | | using ::com::sun::star::document::XEventsSupplier; |
53 | | using ::com::sun::star::lang::XServiceInfo; |
54 | | using ::com::sun::star::drawing::PointSequence; |
55 | | |
56 | | constexpr OUStringLiteral gsBoundary(u"Boundary"); |
57 | | constexpr OUStringLiteral gsCenter(u"Center"); |
58 | | constexpr OUStringLiteral gsDescription(u"Description"); |
59 | | constexpr OUString gsImageMap(u"ImageMap"_ustr); |
60 | | constexpr OUStringLiteral gsIsActive(u"IsActive"); |
61 | | constexpr OUStringLiteral gsName(u"Name"); |
62 | | constexpr OUStringLiteral gsPolygon(u"Polygon"); |
63 | | constexpr OUStringLiteral gsRadius(u"Radius"); |
64 | | constexpr OUStringLiteral gsTarget(u"Target"); |
65 | | constexpr OUStringLiteral gsURL(u"URL"); |
66 | | constexpr OUStringLiteral gsTitle(u"Title"); |
67 | | |
68 | | XMLImageMapExport::XMLImageMapExport(SvXMLExport& rExp) : |
69 | 6 | mrExport(rExp) |
70 | 6 | { |
71 | 6 | } |
72 | | |
73 | | void XMLImageMapExport::Export( |
74 | | const Reference<XPropertySet> & rPropertySet) |
75 | 199 | { |
76 | 199 | if (rPropertySet->getPropertySetInfo()->hasPropertyByName(gsImageMap)) |
77 | 199 | { |
78 | 199 | Any aAny = rPropertySet->getPropertyValue(gsImageMap); |
79 | 199 | Reference<XIndexContainer> aContainer; |
80 | 199 | aAny >>= aContainer; |
81 | | |
82 | 199 | Export(aContainer); |
83 | 199 | } |
84 | | // else: no ImageMap property -> nothing to do |
85 | 199 | } |
86 | | |
87 | | void XMLImageMapExport::Export( |
88 | | const Reference<XIndexContainer> & rContainer) |
89 | 199 | { |
90 | 199 | if (!rContainer.is()) |
91 | 0 | return; |
92 | | |
93 | 199 | if (!rContainer->hasElements()) |
94 | 199 | return; |
95 | | |
96 | | // image map container element |
97 | 0 | SvXMLElementExport aImageMapElement( |
98 | 0 | mrExport, XML_NAMESPACE_DRAW, XML_IMAGE_MAP, |
99 | 0 | true/*bWhiteSpace*/, true/*bWhiteSpace*/); |
100 | | |
101 | | // iterate over image map elements and call ExportMapEntry(...) |
102 | | // for each |
103 | 0 | sal_Int32 nLength = rContainer->getCount(); |
104 | 0 | for(sal_Int32 i = 0; i < nLength; i++) |
105 | 0 | { |
106 | 0 | Any aAny = rContainer->getByIndex(i); |
107 | 0 | Reference<XPropertySet> rElement; |
108 | 0 | aAny >>= rElement; |
109 | |
|
110 | 0 | DBG_ASSERT(rElement.is(), "Image map element is empty!"); |
111 | 0 | if (rElement.is()) |
112 | 0 | { |
113 | 0 | ExportMapEntry(rElement); |
114 | 0 | } |
115 | 0 | } |
116 | | // else: container is empty -> nothing to do |
117 | | // else: no container -> nothing to do |
118 | 0 | } |
119 | | |
120 | | |
121 | | void XMLImageMapExport::ExportMapEntry( |
122 | | const Reference<XPropertySet> & rPropertySet) |
123 | 0 | { |
124 | 0 | Reference<XServiceInfo> xServiceInfo(rPropertySet, UNO_QUERY); |
125 | 0 | if (!xServiceInfo.is()) |
126 | 0 | return; |
127 | | |
128 | 0 | enum XMLTokenEnum eType = XML_TOKEN_INVALID; |
129 | | |
130 | | // distinguish map entries by their service name |
131 | 0 | const Sequence<OUString> sServiceNames = |
132 | 0 | xServiceInfo->getSupportedServiceNames(); |
133 | 0 | for( const OUString& rName : sServiceNames ) |
134 | 0 | { |
135 | 0 | if ( rName == "com.sun.star.image.ImageMapRectangleObject" ) |
136 | 0 | { |
137 | 0 | eType = XML_AREA_RECTANGLE; |
138 | 0 | break; |
139 | 0 | } |
140 | 0 | else if ( rName == "com.sun.star.image.ImageMapCircleObject" ) |
141 | 0 | { |
142 | 0 | eType = XML_AREA_CIRCLE; |
143 | 0 | break; |
144 | 0 | } |
145 | 0 | else if ( rName == "com.sun.star.image.ImageMapPolygonObject" ) |
146 | 0 | { |
147 | 0 | eType = XML_AREA_POLYGON; |
148 | 0 | break; |
149 | 0 | } |
150 | 0 | } |
151 | | |
152 | | // return from method if no proper service is found! |
153 | 0 | DBG_ASSERT(XML_TOKEN_INVALID != eType, |
154 | 0 | "Image map element doesn't support appropriate service!"); |
155 | 0 | if (XML_TOKEN_INVALID == eType) |
156 | 0 | return; |
157 | | |
158 | | // now: handle ImageMapObject properties (those for all types) |
159 | | |
160 | | // XLINK (URL property) |
161 | 0 | Any aAny = rPropertySet->getPropertyValue(gsURL); |
162 | 0 | OUString sHref; |
163 | 0 | aAny >>= sHref; |
164 | 0 | if (!sHref.isEmpty()) |
165 | 0 | { |
166 | 0 | mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, mrExport.GetRelativeReference(sHref)); |
167 | 0 | } |
168 | 0 | mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE ); |
169 | | |
170 | | // Target property (and xlink:show) |
171 | 0 | aAny = rPropertySet->getPropertyValue(gsTarget); |
172 | 0 | OUString sTargt; |
173 | 0 | aAny >>= sTargt; |
174 | 0 | if (!sTargt.isEmpty()) |
175 | 0 | { |
176 | 0 | mrExport.AddAttribute( |
177 | 0 | XML_NAMESPACE_OFFICE, XML_TARGET_FRAME_NAME, sTargt); |
178 | |
|
179 | 0 | mrExport.AddAttribute( |
180 | 0 | XML_NAMESPACE_XLINK, XML_SHOW, |
181 | 0 | sTargt == "_blank" ? XML_NEW : XML_REPLACE ); |
182 | 0 | } |
183 | | |
184 | | // name |
185 | 0 | aAny = rPropertySet->getPropertyValue(gsName); |
186 | 0 | OUString sItemName; |
187 | 0 | aAny >>= sItemName; |
188 | 0 | if (!sItemName.isEmpty()) |
189 | 0 | { |
190 | 0 | mrExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_NAME, sItemName); |
191 | 0 | } |
192 | | |
193 | | // is-active |
194 | 0 | aAny = rPropertySet->getPropertyValue(gsIsActive); |
195 | 0 | if (! *o3tl::doAccess<bool>(aAny)) |
196 | 0 | { |
197 | 0 | mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_NOHREF, XML_NOHREF); |
198 | 0 | } |
199 | | |
200 | | // call specific rectangle/circle/... method |
201 | | // also prepare element name |
202 | 0 | switch (eType) |
203 | 0 | { |
204 | 0 | case XML_AREA_RECTANGLE: |
205 | 0 | ExportRectangle(rPropertySet); |
206 | 0 | break; |
207 | 0 | case XML_AREA_CIRCLE: |
208 | 0 | ExportCircle(rPropertySet); |
209 | 0 | break; |
210 | 0 | case XML_AREA_POLYGON: |
211 | 0 | ExportPolygon(rPropertySet); |
212 | 0 | break; |
213 | 0 | default: |
214 | 0 | break; |
215 | 0 | } |
216 | | |
217 | | // write element |
218 | 0 | DBG_ASSERT(XML_TOKEN_INVALID != eType, |
219 | 0 | "No name?! How did this happen?"); |
220 | 0 | SvXMLElementExport aAreaElement(mrExport, XML_NAMESPACE_DRAW, eType, |
221 | 0 | true/*bWhiteSpace*/, true/*bWhiteSpace*/); |
222 | | |
223 | | // title property (as <svg:title> element) |
224 | 0 | OUString sTitle; |
225 | 0 | rPropertySet->getPropertyValue(gsTitle) >>= sTitle; |
226 | 0 | if(!sTitle.isEmpty()) |
227 | 0 | { |
228 | 0 | SvXMLElementExport aEventElemt(mrExport, XML_NAMESPACE_SVG, XML_TITLE, true/*bWhiteSpace*/, false); |
229 | 0 | mrExport.Characters(sTitle); |
230 | 0 | } |
231 | | |
232 | | // description property (as <svg:desc> element) |
233 | 0 | OUString sDescription; |
234 | 0 | rPropertySet->getPropertyValue(gsDescription) >>= sDescription; |
235 | 0 | if (!sDescription.isEmpty()) |
236 | 0 | { |
237 | 0 | SvXMLElementExport aDesc(mrExport, XML_NAMESPACE_SVG, XML_DESC, true/*bWhiteSpace*/, false); |
238 | 0 | mrExport.Characters(sDescription); |
239 | 0 | } |
240 | | |
241 | | // export events attached to this |
242 | 0 | Reference<XEventsSupplier> xSupplier(rPropertySet, UNO_QUERY); |
243 | 0 | mrExport.GetEventExport().Export(xSupplier); |
244 | | |
245 | | // else: no service info -> can't determine type -> ignore entry |
246 | 0 | } |
247 | | |
248 | | void XMLImageMapExport::ExportRectangle( |
249 | | const Reference<XPropertySet> & rPropertySet) |
250 | 0 | { |
251 | | // get boundary rectangle |
252 | 0 | Any aAny = rPropertySet->getPropertyValue(gsBoundary); |
253 | 0 | awt::Rectangle aRectangle; |
254 | 0 | aAny >>= aRectangle; |
255 | | |
256 | | // parameters svg:x, svg:y, svg:width, svg:height |
257 | 0 | OUStringBuffer aBuffer; |
258 | 0 | mrExport.GetMM100UnitConverter().convertMeasureToXML(aBuffer, aRectangle.X); |
259 | 0 | mrExport.AddAttribute( XML_NAMESPACE_SVG, XML_X, |
260 | 0 | aBuffer.makeStringAndClear() ); |
261 | 0 | mrExport.GetMM100UnitConverter().convertMeasureToXML(aBuffer, aRectangle.Y); |
262 | 0 | mrExport.AddAttribute( XML_NAMESPACE_SVG, XML_Y, |
263 | 0 | aBuffer.makeStringAndClear() ); |
264 | 0 | mrExport.GetMM100UnitConverter().convertMeasureToXML(aBuffer, |
265 | 0 | aRectangle.Width); |
266 | 0 | mrExport.AddAttribute( XML_NAMESPACE_SVG, XML_WIDTH, |
267 | 0 | aBuffer.makeStringAndClear() ); |
268 | 0 | mrExport.GetMM100UnitConverter().convertMeasureToXML(aBuffer, |
269 | 0 | aRectangle.Height); |
270 | 0 | mrExport.AddAttribute( XML_NAMESPACE_SVG, XML_HEIGHT, |
271 | 0 | aBuffer.makeStringAndClear() ); |
272 | 0 | } |
273 | | |
274 | | void XMLImageMapExport::ExportCircle( |
275 | | const Reference<XPropertySet> & rPropertySet) |
276 | 0 | { |
277 | | // get boundary rectangle |
278 | 0 | Any aAny = rPropertySet->getPropertyValue(gsCenter); |
279 | 0 | awt::Point aCenter; |
280 | 0 | aAny >>= aCenter; |
281 | | |
282 | | // parameters svg:cx, svg:cy |
283 | 0 | OUStringBuffer aBuffer; |
284 | 0 | mrExport.GetMM100UnitConverter().convertMeasureToXML(aBuffer, aCenter.X); |
285 | 0 | mrExport.AddAttribute( XML_NAMESPACE_SVG, XML_CX, |
286 | 0 | aBuffer.makeStringAndClear() ); |
287 | 0 | mrExport.GetMM100UnitConverter().convertMeasureToXML(aBuffer, aCenter.Y); |
288 | 0 | mrExport.AddAttribute( XML_NAMESPACE_SVG, XML_CY, |
289 | 0 | aBuffer.makeStringAndClear() ); |
290 | | |
291 | | // radius |
292 | 0 | aAny = rPropertySet->getPropertyValue(gsRadius); |
293 | 0 | sal_Int32 nRadius = 0; |
294 | 0 | aAny >>= nRadius; |
295 | 0 | mrExport.GetMM100UnitConverter().convertMeasureToXML(aBuffer, nRadius); |
296 | 0 | mrExport.AddAttribute( XML_NAMESPACE_SVG, XML_R, |
297 | 0 | aBuffer.makeStringAndClear() ); |
298 | 0 | } |
299 | | |
300 | | void XMLImageMapExport::ExportPolygon(const Reference<XPropertySet> & rPropertySet) |
301 | 0 | { |
302 | | // polygons get exported as bounding box, viewbox, and coordinate |
303 | | // pair sequence. The bounding box is always the entire image. |
304 | | |
305 | | // get polygon point sequence |
306 | 0 | Any aAny = rPropertySet->getPropertyValue(gsPolygon); |
307 | 0 | PointSequence aPoly; |
308 | 0 | aAny >>= aPoly; |
309 | |
|
310 | 0 | const basegfx::B2DPolygon aPolygon( |
311 | 0 | basegfx::utils::UnoPointSequenceToB2DPolygon( |
312 | 0 | aPoly)); |
313 | 0 | const basegfx::B2DRange aPolygonRange(aPolygon.getB2DRange()); |
314 | | |
315 | | // parameters svg:x, svg:y, svg:width, svg:height |
316 | 0 | OUStringBuffer aBuffer; |
317 | |
|
318 | 0 | mrExport.GetMM100UnitConverter().convertMeasureToXML(aBuffer, 0); |
319 | 0 | mrExport.AddAttribute( XML_NAMESPACE_SVG, XML_X, aBuffer.makeStringAndClear() ); |
320 | 0 | mrExport.GetMM100UnitConverter().convertMeasureToXML(aBuffer, 0); |
321 | 0 | mrExport.AddAttribute( XML_NAMESPACE_SVG, XML_Y, aBuffer.makeStringAndClear() ); |
322 | 0 | mrExport.GetMM100UnitConverter().convertMeasureToXML(aBuffer, basegfx::fround(aPolygonRange.getWidth())); |
323 | 0 | mrExport.AddAttribute( XML_NAMESPACE_SVG, XML_WIDTH, aBuffer.makeStringAndClear() ); |
324 | 0 | mrExport.GetMM100UnitConverter().convertMeasureToXML(aBuffer, basegfx::fround(aPolygonRange.getHeight())); |
325 | 0 | mrExport.AddAttribute( XML_NAMESPACE_SVG, XML_HEIGHT, aBuffer.makeStringAndClear() ); |
326 | | |
327 | | // svg:viewbox |
328 | 0 | SdXMLImExViewBox aViewBox(0.0, 0.0, aPolygonRange.getWidth(), aPolygonRange.getHeight()); |
329 | 0 | mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_VIEWBOX, aViewBox.GetExportString()); |
330 | | |
331 | | // export point sequence |
332 | 0 | const OUString aPointString( |
333 | 0 | basegfx::utils::exportToSvgPoints( |
334 | 0 | aPolygon)); |
335 | |
|
336 | 0 | mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_POINTS, aPointString); |
337 | 0 | } |
338 | | |
339 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |