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