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