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 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 84 XMLImageMapExport::~XMLImageMapExport() 85 { 86 87 } 88 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 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 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 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 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 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