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