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 23 24 #include "oox/vml/vmlshape.hxx" 25 26 #include <com/sun/star/beans/PropertyValues.hpp> 27 #include <com/sun/star/awt/XControlModel.hpp> 28 #include <com/sun/star/drawing/PointSequenceSequence.hpp> 29 #include <com/sun/star/drawing/XEnhancedCustomShapeDefaulter.hpp> 30 #include <com/sun/star/drawing/XShapes.hpp> 31 #include <com/sun/star/graphic/XGraphic.hpp> 32 #include <rtl/math.hxx> 33 #include <rtl/ustrbuf.hxx> 34 #include "oox/core/xmlfilterbase.hxx" 35 #include "oox/drawingml/shapepropertymap.hxx" 36 #include "oox/helper/containerhelper.hxx" 37 #include "oox/helper/graphichelper.hxx" 38 #include "oox/helper/propertyset.hxx" 39 #include "oox/ole/axcontrol.hxx" 40 #include "oox/ole/axcontrolfragment.hxx" 41 #include "oox/ole/oleobjecthelper.hxx" 42 #include "oox/vml/vmldrawing.hxx" 43 #include "oox/vml/vmlshapecontainer.hxx" 44 #include "oox/vml/vmltextbox.hxx" 45 46 namespace oox { 47 namespace vml { 48 49 // ============================================================================ 50 51 using namespace ::com::sun::star::awt; 52 using namespace ::com::sun::star::drawing; 53 using namespace ::com::sun::star::graphic; 54 using namespace ::com::sun::star::uno; 55 56 using ::oox::core::XmlFilterBase; 57 using ::rtl::OUString; 58 using ::rtl::OUStringBuffer; 59 60 // ============================================================================ 61 62 namespace { 63 64 const sal_Int32 VML_SHAPETYPE_PICTUREFRAME = 75; 65 const sal_Int32 VML_SHAPETYPE_HOSTCONTROL = 201; 66 67 // ---------------------------------------------------------------------------- 68 69 Point lclGetAbsPoint( const Point& rRelPoint, const Rectangle& rShapeRect, const Rectangle& rCoordSys ) 70 { 71 double fWidthRatio = static_cast< double >( rShapeRect.Width ) / rCoordSys.Width; 72 double fHeightRatio = static_cast< double >( rShapeRect.Height ) / rCoordSys.Height; 73 Point aAbsPoint; 74 aAbsPoint.X = static_cast< sal_Int32 >( rShapeRect.X + fWidthRatio * (rRelPoint.X - rCoordSys.X) + 0.5 ); 75 aAbsPoint.Y = static_cast< sal_Int32 >( rShapeRect.Y + fHeightRatio * (rRelPoint.Y - rCoordSys.Y) + 0.5 ); 76 return aAbsPoint; 77 } 78 79 Rectangle lclGetAbsRect( const Rectangle& rRelRect, const Rectangle& rShapeRect, const Rectangle& rCoordSys ) 80 { 81 double fWidthRatio = static_cast< double >( rShapeRect.Width ) / rCoordSys.Width; 82 double fHeightRatio = static_cast< double >( rShapeRect.Height ) / rCoordSys.Height; 83 Rectangle aAbsRect; 84 aAbsRect.X = static_cast< sal_Int32 >( rShapeRect.X + fWidthRatio * (rRelRect.X - rCoordSys.X) + 0.5 ); 85 aAbsRect.Y = static_cast< sal_Int32 >( rShapeRect.Y + fHeightRatio * (rRelRect.Y - rCoordSys.Y) + 0.5 ); 86 aAbsRect.Width = static_cast< sal_Int32 >( fWidthRatio * rRelRect.Width + 0.5 ); 87 aAbsRect.Height = static_cast< sal_Int32 >( fHeightRatio * rRelRect.Height + 0.5 ); 88 return aAbsRect; 89 } 90 91 } // namespace 92 93 // ============================================================================ 94 95 ShapeTypeModel::ShapeTypeModel() 96 { 97 } 98 99 void ShapeTypeModel::assignUsed( const ShapeTypeModel& rSource ) 100 { 101 moShapeType.assignIfUsed( rSource.moShapeType ); 102 moCoordPos.assignIfUsed( rSource.moCoordPos ); 103 moCoordSize.assignIfUsed( rSource.moCoordSize ); 104 /* The style properties position, left, top, width, height, margin-left, 105 margin-top are not derived from shape template to shape. */ 106 maStrokeModel.assignUsed( rSource.maStrokeModel ); 107 maFillModel.assignUsed( rSource.maFillModel ); 108 moGraphicPath.assignIfUsed( rSource.moGraphicPath ); 109 moGraphicTitle.assignIfUsed( rSource.moGraphicTitle ); 110 } 111 112 // ---------------------------------------------------------------------------- 113 114 ShapeType::ShapeType( Drawing& rDrawing ) : 115 mrDrawing( rDrawing ) 116 { 117 } 118 119 ShapeType::~ShapeType() 120 { 121 } 122 123 sal_Int32 ShapeType::getShapeType() const 124 { 125 return maTypeModel.moShapeType.get( 0 ); 126 } 127 128 OUString ShapeType::getGraphicPath() const 129 { 130 return maTypeModel.moGraphicPath.get( OUString() ); 131 } 132 133 Rectangle ShapeType::getCoordSystem() const 134 { 135 Int32Pair aCoordPos = maTypeModel.moCoordPos.get( Int32Pair( 0, 0 ) ); 136 Int32Pair aCoordSize = maTypeModel.moCoordSize.get( Int32Pair( 1000, 1000 ) ); 137 return Rectangle( aCoordPos.first, aCoordPos.second, aCoordSize.first, aCoordSize.second ); 138 } 139 140 Rectangle ShapeType::getRectangle( const ShapeParentAnchor* pParentAnchor ) const 141 { 142 return pParentAnchor ? 143 lclGetAbsRect( getRelRectangle(), pParentAnchor->maShapeRect, pParentAnchor->maCoordSys ) : 144 getAbsRectangle(); 145 } 146 147 Rectangle ShapeType::getAbsRectangle() const 148 { 149 const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper(); 150 return Rectangle( 151 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maTypeModel.maLeft, 0, true, true ) + ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maTypeModel.maMarginLeft, 0, true, true ), 152 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maTypeModel.maTop, 0, false, true ) + ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maTypeModel.maMarginTop, 0, false, true ), 153 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maTypeModel.maWidth, 0, true, true ), 154 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maTypeModel.maHeight, 0, false, true ) ); 155 } 156 157 Rectangle ShapeType::getRelRectangle() const 158 { 159 return Rectangle( 160 maTypeModel.maLeft.toInt32(), 161 maTypeModel.maTop.toInt32(), 162 maTypeModel.maWidth.toInt32(), 163 maTypeModel.maHeight.toInt32() ); 164 } 165 166 // ============================================================================ 167 168 ClientData::ClientData() : 169 mnObjType( XML_TOKEN_INVALID ), 170 mnTextHAlign( XML_Left ), 171 mnTextVAlign( XML_Top ), 172 mnCol( -1 ), 173 mnRow( -1 ), 174 mnChecked( VML_CLIENTDATA_UNCHECKED ), 175 mnDropStyle( XML_Combo ), 176 mnDropLines( 1 ), 177 mnVal( 0 ), 178 mnMin( 0 ), 179 mnMax( 0 ), 180 mnInc( 0 ), 181 mnPage( 0 ), 182 mnSelType( XML_Single ), 183 mnVTEdit( VML_CLIENTDATA_TEXT ), 184 mbPrintObject( true ), 185 mbVisible( false ), 186 mbDde( false ), 187 mbNo3D( false ), 188 mbNo3D2( false ), 189 mbMultiLine( false ), 190 mbVScroll( false ), 191 mbSecretEdit( false ) 192 { 193 } 194 195 // ---------------------------------------------------------------------------- 196 197 ShapeModel::ShapeModel() 198 { 199 } 200 201 ShapeModel::~ShapeModel() 202 { 203 } 204 205 TextBox& ShapeModel::createTextBox() 206 { 207 mxTextBox.reset( new TextBox ); 208 return *mxTextBox; 209 } 210 211 ClientData& ShapeModel::createClientData() 212 { 213 mxClientData.reset( new ClientData ); 214 return *mxClientData; 215 } 216 217 // ---------------------------------------------------------------------------- 218 219 ShapeBase::ShapeBase( Drawing& rDrawing ) : 220 ShapeType( rDrawing ) 221 { 222 } 223 224 void ShapeBase::finalizeFragmentImport() 225 { 226 // resolve shape template reference 227 if( (maShapeModel.maType.getLength() > 1) && (maShapeModel.maType[ 0 ] == '#') ) 228 if( const ShapeType* pShapeType = mrDrawing.getShapes().getShapeTypeById( maShapeModel.maType.copy( 1 ), true ) ) 229 maTypeModel.assignUsed( pShapeType->getTypeModel() ); 230 } 231 232 OUString ShapeBase::getShapeName() const 233 { 234 if( maTypeModel.maShapeName.getLength() > 0 ) 235 return maTypeModel.maShapeName; 236 237 OUString aBaseName = mrDrawing.getShapeBaseName( *this ); 238 if( aBaseName.getLength() > 0 ) 239 { 240 sal_Int32 nShapeIdx = mrDrawing.getLocalShapeIndex( getShapeId() ); 241 if( nShapeIdx > 0 ) 242 return OUStringBuffer( aBaseName ).append( sal_Unicode( ' ' ) ).append( nShapeIdx ).makeStringAndClear(); 243 } 244 245 return OUString(); 246 } 247 248 const ShapeType* ShapeBase::getChildTypeById( const OUString& ) const 249 { 250 return 0; 251 } 252 253 const ShapeBase* ShapeBase::getChildById( const OUString& ) const 254 { 255 return 0; 256 } 257 258 Reference< XShape > ShapeBase::convertAndInsert( const Reference< XShapes >& rxShapes, const ShapeParentAnchor* pParentAnchor ) const 259 { 260 Reference< XShape > xShape; 261 if( mrDrawing.isShapeSupported( *this ) ) 262 { 263 /* Calculate shape rectangle. Applications may do something special 264 according to some imported shape client data (e.g. Excel cell anchor). */ 265 Rectangle aShapeRect = calcShapeRectangle( pParentAnchor ); 266 267 // convert the shape, if the calculated rectangle is not empty 268 if( ((aShapeRect.Width > 0) || (aShapeRect.Height > 0)) && rxShapes.is() ) 269 { 270 xShape = implConvertAndInsert( rxShapes, aShapeRect ); 271 if( xShape.is() ) 272 { 273 // set imported or generated shape name (not supported by form controls) 274 PropertySet aShapeProp( xShape ); 275 if( aShapeProp.hasProperty( PROP_Name ) ) 276 aShapeProp.setProperty( PROP_Name, getShapeName() ); 277 278 /* Notify the drawing that a new shape has been inserted. For 279 convenience, pass the rectangle that contains position and 280 size of the shape. */ 281 bool bGroupChild = pParentAnchor != 0; 282 mrDrawing.notifyXShapeInserted( xShape, aShapeRect, *this, bGroupChild ); 283 } 284 } 285 } 286 return xShape; 287 } 288 289 void ShapeBase::convertFormatting( const Reference< XShape >& rxShape, const ShapeParentAnchor* pParentAnchor ) const 290 { 291 if( rxShape.is() ) 292 { 293 /* Calculate shape rectangle. Applications may do something special 294 according to some imported shape client data (e.g. Excel cell anchor). */ 295 Rectangle aShapeRect = calcShapeRectangle( pParentAnchor ); 296 297 // convert the shape, if the calculated rectangle is not empty 298 if( (aShapeRect.Width > 0) || (aShapeRect.Height > 0) ) 299 { 300 rxShape->setPosition( Point( aShapeRect.X, aShapeRect.Y ) ); 301 rxShape->setSize( Size( aShapeRect.Width, aShapeRect.Height ) ); 302 convertShapeProperties( rxShape ); 303 } 304 } 305 } 306 307 // protected ------------------------------------------------------------------ 308 309 Rectangle ShapeBase::calcShapeRectangle( const ShapeParentAnchor* pParentAnchor ) const 310 { 311 /* Calculate shape rectangle. Applications may do something special 312 according to some imported shape client data (e.g. Excel cell anchor). */ 313 Rectangle aShapeRect; 314 const ClientData* pClientData = getClientData(); 315 if( !pClientData || !mrDrawing.convertClientAnchor( aShapeRect, pClientData->maAnchor ) ) 316 aShapeRect = getRectangle( pParentAnchor ); 317 return aShapeRect; 318 } 319 320 void ShapeBase::convertShapeProperties( const Reference< XShape >& rxShape ) const 321 { 322 ::oox::drawingml::ShapePropertyMap aPropMap( mrDrawing.getFilter().getModelObjectHelper() ); 323 const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper(); 324 maTypeModel.maStrokeModel.pushToPropMap( aPropMap, rGraphicHelper ); 325 maTypeModel.maFillModel.pushToPropMap( aPropMap, rGraphicHelper ); 326 PropertySet( rxShape ).setProperties( aPropMap ); 327 } 328 329 // ============================================================================ 330 331 SimpleShape::SimpleShape( Drawing& rDrawing, const OUString& rService ) : 332 ShapeBase( rDrawing ), 333 maService( rService ) 334 { 335 } 336 337 Reference< XShape > SimpleShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const Rectangle& rShapeRect ) const 338 { 339 Reference< XShape > xShape = mrDrawing.createAndInsertXShape( maService, rxShapes, rShapeRect ); 340 convertShapeProperties( xShape ); 341 return xShape; 342 } 343 344 // ============================================================================ 345 346 RectangleShape::RectangleShape( Drawing& rDrawing ) : 347 SimpleShape( rDrawing, CREATE_OUSTRING( "com.sun.star.drawing.RectangleShape" ) ) 348 { 349 } 350 351 // ============================================================================ 352 353 EllipseShape::EllipseShape( Drawing& rDrawing ) : 354 SimpleShape( rDrawing, CREATE_OUSTRING( "com.sun.star.drawing.EllipseShape" ) ) 355 { 356 } 357 358 // ============================================================================ 359 360 PolyLineShape::PolyLineShape( Drawing& rDrawing ) : 361 SimpleShape( rDrawing, CREATE_OUSTRING( "com.sun.star.drawing.PolyLineShape" ) ) 362 { 363 } 364 365 Reference< XShape > PolyLineShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const Rectangle& rShapeRect ) const 366 { 367 Reference< XShape > xShape = SimpleShape::implConvertAndInsert( rxShapes, rShapeRect ); 368 // polygon path 369 Rectangle aCoordSys = getCoordSystem(); 370 if( !maShapeModel.maPoints.empty() && (aCoordSys.Width > 0) && (aCoordSys.Height > 0) ) 371 { 372 ::std::vector< Point > aAbsPoints; 373 for( ShapeModel::PointVector::const_iterator aIt = maShapeModel.maPoints.begin(), aEnd = maShapeModel.maPoints.end(); aIt != aEnd; ++aIt ) 374 aAbsPoints.push_back( lclGetAbsPoint( *aIt, rShapeRect, aCoordSys ) ); 375 PointSequenceSequence aPointSeq( 1 ); 376 aPointSeq[ 0 ] = ContainerHelper::vectorToSequence( aAbsPoints ); 377 PropertySet aPropSet( xShape ); 378 aPropSet.setProperty( PROP_PolyPolygon, aPointSeq ); 379 } 380 return xShape; 381 } 382 383 // ============================================================================ 384 385 CustomShape::CustomShape( Drawing& rDrawing ) : 386 SimpleShape( rDrawing, CREATE_OUSTRING( "com.sun.star.drawing.CustomShape" ) ) 387 { 388 } 389 390 Reference< XShape > CustomShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const Rectangle& rShapeRect ) const 391 { 392 // try to create a custom shape 393 Reference< XShape > xShape = SimpleShape::implConvertAndInsert( rxShapes, rShapeRect ); 394 if( xShape.is() ) try 395 { 396 // create the custom shape geometry 397 Reference< XEnhancedCustomShapeDefaulter > xDefaulter( xShape, UNO_QUERY_THROW ); 398 xDefaulter->createCustomShapeDefaults( OUString::valueOf( getShapeType() ) ); 399 // convert common properties 400 convertShapeProperties( xShape ); 401 } 402 catch( Exception& ) 403 { 404 } 405 return xShape; 406 } 407 408 // ============================================================================ 409 410 ComplexShape::ComplexShape( Drawing& rDrawing ) : 411 CustomShape( rDrawing ) 412 { 413 } 414 415 Reference< XShape > ComplexShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const Rectangle& rShapeRect ) const 416 { 417 XmlFilterBase& rFilter = mrDrawing.getFilter(); 418 sal_Int32 nShapeType = getShapeType(); 419 OUString aGraphicPath = getGraphicPath(); 420 421 // try to find registered OLE object info 422 if( const OleObjectInfo* pOleObjectInfo = mrDrawing.getOleObjectInfo( maTypeModel.maShapeId ) ) 423 { 424 OSL_ENSURE( nShapeType == VML_SHAPETYPE_PICTUREFRAME, "ComplexShape::implConvertAndInsert - unexpected shape type" ); 425 426 // if OLE object is embedded into a DrawingML shape (PPTX), do not create it here 427 if( pOleObjectInfo->mbDmlShape ) 428 return Reference< XShape >(); 429 430 PropertyMap aOleProps; 431 Size aOleSize( rShapeRect.Width, rShapeRect.Height ); 432 if( rFilter.getOleObjectHelper().importOleObject( aOleProps, *pOleObjectInfo, aOleSize ) ) 433 { 434 Reference< XShape > xShape = mrDrawing.createAndInsertXShape( CREATE_OUSTRING( "com.sun.star.drawing.OLE2Shape" ), rxShapes, rShapeRect ); 435 if( xShape.is() ) 436 { 437 // set the replacement graphic 438 if( aGraphicPath.getLength() > 0 ) 439 { 440 Reference< XGraphic > xGraphic = rFilter.getGraphicHelper().importEmbeddedGraphic( aGraphicPath ); 441 if( xGraphic.is() ) 442 aOleProps[ PROP_Graphic ] <<= xGraphic; 443 } 444 445 PropertySet aPropSet( xShape ); 446 aPropSet.setProperties( aOleProps ); 447 448 return xShape; 449 } 450 } 451 } 452 453 // try to find registered form control info 454 const ControlInfo* pControlInfo = mrDrawing.getControlInfo( maTypeModel.maShapeId ); 455 if( pControlInfo && (pControlInfo->maFragmentPath.getLength() > 0) ) 456 { 457 OSL_ENSURE( nShapeType == VML_SHAPETYPE_HOSTCONTROL, "ComplexShape::implConvertAndInsert - unexpected shape type" ); 458 OUString aShapeName = getShapeName(); 459 if( aShapeName.getLength() > 0 ) 460 { 461 OSL_ENSURE( aShapeName == pControlInfo->maName, "ComplexShape::implConvertAndInsert - control name mismatch" ); 462 // load the control properties from fragment 463 ::oox::ole::EmbeddedControl aControl( aShapeName ); 464 if( rFilter.importFragment( new ::oox::ole::AxControlFragment( rFilter, pControlInfo->maFragmentPath, aControl ) ) ) 465 { 466 // create and return the control shape (including control model) 467 sal_Int32 nCtrlIndex = -1; 468 Reference< XShape > xShape = mrDrawing.createAndInsertXControlShape( aControl, rxShapes, rShapeRect, nCtrlIndex ); 469 // on error, proceed and try to create picture from replacement image 470 if( xShape.is() ) 471 return xShape; 472 } 473 } 474 } 475 476 // host application wants to create the shape (do not try failed OLE controls again) 477 if( (nShapeType == VML_SHAPETYPE_HOSTCONTROL) && !pControlInfo ) 478 { 479 OSL_ENSURE( getClientData(), "ComplexShape::implConvertAndInsert - missing client data" ); 480 Reference< XShape > xShape = mrDrawing.createAndInsertClientXShape( *this, rxShapes, rShapeRect ); 481 if( xShape.is() ) 482 return xShape; 483 } 484 485 // try to create a picture object 486 if( aGraphicPath.getLength() > 0 ) 487 { 488 Reference< XShape > xShape = mrDrawing.createAndInsertXShape( CREATE_OUSTRING( "com.sun.star.drawing.GraphicObjectShape" ), rxShapes, rShapeRect ); 489 if( xShape.is() ) 490 { 491 OUString aGraphicUrl = rFilter.getGraphicHelper().importEmbeddedGraphicObject( aGraphicPath ); 492 if( aGraphicUrl.getLength() > 0 ) 493 { 494 PropertySet aPropSet( xShape ); 495 aPropSet.setProperty( PROP_GraphicURL, aGraphicUrl ); 496 } 497 } 498 return xShape; 499 } 500 501 // default: try to create a custom shape 502 return CustomShape::implConvertAndInsert( rxShapes, rShapeRect ); 503 } 504 505 // ============================================================================ 506 507 GroupShape::GroupShape( Drawing& rDrawing ) : 508 ShapeBase( rDrawing ), 509 mxChildren( new ShapeContainer( rDrawing ) ) 510 { 511 } 512 513 GroupShape::~GroupShape() 514 { 515 } 516 517 void GroupShape::finalizeFragmentImport() 518 { 519 // basic shape processing 520 ShapeBase::finalizeFragmentImport(); 521 // finalize all child shapes 522 mxChildren->finalizeFragmentImport(); 523 } 524 525 const ShapeType* GroupShape::getChildTypeById( const OUString& rShapeId ) const 526 { 527 return mxChildren->getShapeTypeById( rShapeId, true ); 528 } 529 530 const ShapeBase* GroupShape::getChildById( const OUString& rShapeId ) const 531 { 532 return mxChildren->getShapeById( rShapeId, true ); 533 } 534 535 Reference< XShape > GroupShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const Rectangle& rShapeRect ) const 536 { 537 Reference< XShape > xGroupShape; 538 // check that this shape contains children and a valid coordinate system 539 ShapeParentAnchor aParentAnchor; 540 aParentAnchor.maShapeRect = rShapeRect; 541 aParentAnchor.maCoordSys = getCoordSystem(); 542 if( !mxChildren->empty() && (aParentAnchor.maCoordSys.Width > 0) && (aParentAnchor.maCoordSys.Height > 0) ) try 543 { 544 xGroupShape = mrDrawing.createAndInsertXShape( CREATE_OUSTRING( "com.sun.star.drawing.GroupShape" ), rxShapes, rShapeRect ); 545 Reference< XShapes > xChildShapes( xGroupShape, UNO_QUERY_THROW ); 546 mxChildren->convertAndInsert( xChildShapes, &aParentAnchor ); 547 // no child shape has been created - delete the group shape 548 if( !xChildShapes->hasElements() ) 549 { 550 rxShapes->remove( xGroupShape ); 551 xGroupShape.clear(); 552 } 553 } 554 catch( Exception& ) 555 { 556 } 557 return xGroupShape; 558 } 559 560 // ============================================================================ 561 562 } // namespace vml 563 } // namespace oox 564