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 #include "oox/drawingml/fillproperties.hxx" 29 30 #include <com/sun/star/lang/XMultiServiceFactory.hpp> 31 #include <com/sun/star/beans/XPropertySet.hpp> 32 #include <com/sun/star/awt/Gradient.hpp> 33 #include <com/sun/star/text/GraphicCrop.hpp> 34 #include <com/sun/star/awt/Size.hpp> 35 #include <com/sun/star/drawing/BitmapMode.hpp> 36 #include <com/sun/star/drawing/ColorMode.hpp> 37 #include <com/sun/star/drawing/FillStyle.hpp> 38 #include <com/sun/star/drawing/RectanglePoint.hpp> 39 #include <com/sun/star/graphic/XGraphicTransformer.hpp> 40 #include "oox/helper/graphichelper.hxx" 41 #include "oox/drawingml/drawingmltypes.hxx" 42 #include "oox/drawingml/shapepropertymap.hxx" 43 #include "oox/token/tokens.hxx" 44 45 using namespace ::com::sun::star; 46 using namespace ::com::sun::star::drawing; 47 using namespace ::com::sun::star::graphic; 48 49 using ::rtl::OUString; 50 using ::com::sun::star::uno::Reference; 51 using ::com::sun::star::uno::Exception; 52 using ::com::sun::star::uno::UNO_QUERY; 53 using ::com::sun::star::uno::UNO_QUERY_THROW; 54 using ::com::sun::star::geometry::IntegerRectangle2D; 55 56 namespace oox { 57 namespace drawingml { 58 59 // ============================================================================ 60 61 namespace { 62 63 BitmapMode lclGetBitmapMode( sal_Int32 nToken ) 64 { 65 switch( nToken ) 66 { 67 case XML_tile: return BitmapMode_REPEAT; 68 case XML_stretch: return BitmapMode_STRETCH; 69 } 70 return BitmapMode_NO_REPEAT; 71 } 72 73 RectanglePoint lclGetRectanglePoint( sal_Int32 nToken ) 74 { 75 switch( nToken ) 76 { 77 case XML_tl: return RectanglePoint_LEFT_TOP; 78 case XML_t: return RectanglePoint_MIDDLE_TOP; 79 case XML_tr: return RectanglePoint_RIGHT_TOP; 80 case XML_l: return RectanglePoint_LEFT_MIDDLE; 81 case XML_ctr: return RectanglePoint_MIDDLE_MIDDLE; 82 case XML_r: return RectanglePoint_RIGHT_MIDDLE; 83 case XML_bl: return RectanglePoint_LEFT_BOTTOM; 84 case XML_b: return RectanglePoint_MIDDLE_BOTTOM; 85 case XML_br: return RectanglePoint_RIGHT_BOTTOM; 86 } 87 return RectanglePoint_LEFT_TOP; 88 } 89 90 const awt::Size lclGetOriginalSize( const GraphicHelper& rGraphicHelper, const Reference< XGraphic >& rxGraphic ) 91 { 92 awt::Size aSizeHmm( 0, 0 ); 93 try 94 { 95 Reference< beans::XPropertySet > xGraphicPropertySet( rxGraphic, UNO_QUERY_THROW ); 96 if( xGraphicPropertySet->getPropertyValue( CREATE_OUSTRING( "Size100thMM" ) ) >>= aSizeHmm ) 97 { 98 if( !aSizeHmm.Width && !aSizeHmm.Height ) 99 { // MAPMODE_PIXEL USED :-( 100 awt::Size aSourceSizePixel( 0, 0 ); 101 if( xGraphicPropertySet->getPropertyValue( CREATE_OUSTRING( "SizePixel" ) ) >>= aSourceSizePixel ) 102 aSizeHmm = rGraphicHelper.convertScreenPixelToHmm( aSourceSizePixel ); 103 } 104 } 105 } 106 catch( Exception& ) 107 { 108 } 109 return aSizeHmm; 110 } 111 112 } // namespace 113 114 // ============================================================================ 115 116 void GradientFillProperties::assignUsed( const GradientFillProperties& rSourceProps ) 117 { 118 if( !rSourceProps.maGradientStops.empty() ) 119 maGradientStops = rSourceProps.maGradientStops; 120 moFillToRect.assignIfUsed( rSourceProps.moFillToRect ); 121 moTileRect.assignIfUsed( rSourceProps.moTileRect ); 122 moGradientPath.assignIfUsed( rSourceProps.moGradientPath ); 123 moShadeAngle.assignIfUsed( rSourceProps.moShadeAngle ); 124 moShadeFlip.assignIfUsed( rSourceProps.moShadeFlip ); 125 moShadeScaled.assignIfUsed( rSourceProps.moShadeScaled ); 126 moRotateWithShape.assignIfUsed( rSourceProps.moRotateWithShape ); 127 } 128 129 // ============================================================================ 130 131 void PatternFillProperties::assignUsed( const PatternFillProperties& rSourceProps ) 132 { 133 maPattFgColor.assignIfUsed( rSourceProps.maPattFgColor ); 134 maPattBgColor.assignIfUsed( rSourceProps.maPattBgColor ); 135 moPattPreset.assignIfUsed( rSourceProps.moPattPreset ); 136 } 137 138 // ============================================================================ 139 140 void BlipFillProperties::assignUsed( const BlipFillProperties& rSourceProps ) 141 { 142 if( rSourceProps.mxGraphic.is() ) 143 mxGraphic = rSourceProps.mxGraphic; 144 moBitmapMode.assignIfUsed( rSourceProps.moBitmapMode ); 145 moFillRect.assignIfUsed( rSourceProps.moFillRect ); 146 moTileOffsetX.assignIfUsed( rSourceProps.moTileOffsetX ); 147 moTileOffsetY.assignIfUsed( rSourceProps.moTileOffsetY ); 148 moTileScaleX.assignIfUsed( rSourceProps.moTileScaleX ); 149 moTileScaleY.assignIfUsed( rSourceProps.moTileScaleY ); 150 moTileAlign.assignIfUsed( rSourceProps.moTileAlign ); 151 moTileFlip.assignIfUsed( rSourceProps.moTileFlip ); 152 moRotateWithShape.assignIfUsed( rSourceProps.moRotateWithShape ); 153 moColorEffect.assignIfUsed( rSourceProps.moColorEffect ); 154 moBrightness.assignIfUsed( rSourceProps.moBrightness ); 155 moContrast.assignIfUsed( rSourceProps.moContrast ); 156 maColorChangeFrom.assignIfUsed( rSourceProps.maColorChangeFrom ); 157 maColorChangeTo.assignIfUsed( rSourceProps.maColorChangeTo ); 158 } 159 160 // ============================================================================ 161 162 void FillProperties::assignUsed( const FillProperties& rSourceProps ) 163 { 164 moFillType.assignIfUsed( rSourceProps.moFillType ); 165 maFillColor.assignIfUsed( rSourceProps.maFillColor ); 166 maGradientProps.assignUsed( rSourceProps.maGradientProps ); 167 maPatternProps.assignUsed( rSourceProps.maPatternProps ); 168 maBlipProps.assignUsed( rSourceProps.maBlipProps ); 169 } 170 171 Color FillProperties::getBestSolidColor() const 172 { 173 Color aSolidColor; 174 if( moFillType.has() ) switch( moFillType.get() ) 175 { 176 case XML_solidFill: 177 aSolidColor = maFillColor; 178 break; 179 case XML_gradFill: 180 if( !maGradientProps.maGradientStops.empty() ) 181 aSolidColor = maGradientProps.maGradientStops.begin()->second; 182 break; 183 case XML_pattFill: 184 aSolidColor = maPatternProps.maPattBgColor.isUsed() ? maPatternProps.maPattBgColor : maPatternProps.maPattFgColor; 185 break; 186 } 187 return aSolidColor; 188 } 189 190 void FillProperties::pushToPropMap( ShapePropertyMap& rPropMap, 191 const GraphicHelper& rGraphicHelper, sal_Int32 nShapeRotation, sal_Int32 nPhClr ) const 192 { 193 if( moFillType.has() ) 194 { 195 FillStyle eFillStyle = FillStyle_NONE; 196 switch( moFillType.get() ) 197 { 198 case XML_noFill: 199 eFillStyle = FillStyle_NONE; 200 break; 201 202 case XML_solidFill: 203 if( maFillColor.isUsed() ) 204 { 205 rPropMap.setProperty( SHAPEPROP_FillColor, maFillColor.getColor( rGraphicHelper, nPhClr ) ); 206 if( maFillColor.hasTransparency() ) 207 rPropMap.setProperty( SHAPEPROP_FillTransparency, maFillColor.getTransparency() ); 208 eFillStyle = FillStyle_SOLID; 209 } 210 break; 211 212 case XML_gradFill: 213 // do not create gradient struct if property is not supported... 214 if( rPropMap.supportsProperty( SHAPEPROP_FillGradient ) ) 215 { 216 awt::Gradient aGradient; 217 aGradient.Angle = 900; 218 aGradient.StartIntensity = 100; 219 aGradient.EndIntensity = 100; 220 221 size_t nColorCount = maGradientProps.maGradientStops.size(); 222 if( nColorCount > 1 ) 223 { 224 aGradient.StartColor = maGradientProps.maGradientStops.begin()->second.getColor( rGraphicHelper, nPhClr ); 225 aGradient.EndColor = maGradientProps.maGradientStops.rbegin()->second.getColor( rGraphicHelper, nPhClr ); 226 } 227 228 // "rotate with shape" not set, or set to false -> do not rotate 229 if ( !maGradientProps.moRotateWithShape.get( false ) ) 230 nShapeRotation = 0; 231 232 sal_Int32 nDmlAngle = 0; 233 if( maGradientProps.moGradientPath.has() ) 234 { 235 aGradient.Style = (maGradientProps.moGradientPath.get() == XML_circle) ? awt::GradientStyle_ELLIPTICAL : awt::GradientStyle_RECT; 236 // position of gradient center (limited to [30%;70%], otherwise gradient is too hidden) 237 IntegerRectangle2D aFillToRect = maGradientProps.moFillToRect.get( IntegerRectangle2D( 0, 0, MAX_PERCENT, MAX_PERCENT ) ); 238 sal_Int32 nCenterX = (MAX_PERCENT + aFillToRect.X1 - aFillToRect.X2) / 2; 239 aGradient.XOffset = getLimitedValue< sal_Int16, sal_Int32 >( nCenterX / PER_PERCENT, 30, 70 ); 240 sal_Int32 nCenterY = (MAX_PERCENT + aFillToRect.Y1 - aFillToRect.Y2) / 2; 241 aGradient.YOffset = getLimitedValue< sal_Int16, sal_Int32 >( nCenterY / PER_PERCENT, 30, 70 ); 242 ::std::swap( aGradient.StartColor, aGradient.EndColor ); 243 nDmlAngle = nShapeRotation; 244 } 245 else 246 { 247 /* Try to detect a VML axial gradient. This type of 248 gradient is simulated by a 3-point linear gradient 249 with equal start and end color. */ 250 bool bAxial = (nColorCount == 3) && (aGradient.StartColor == aGradient.EndColor); 251 aGradient.Style = bAxial ? awt::GradientStyle_AXIAL : awt::GradientStyle_LINEAR; 252 if( bAxial ) 253 { 254 GradientFillProperties::GradientStopMap::const_iterator aIt = maGradientProps.maGradientStops.begin(); 255 // API StartColor is inner color in axial gradient 256 aGradient.StartColor = (++aIt)->second.getColor( rGraphicHelper, nPhClr ); 257 } 258 nDmlAngle = maGradientProps.moShadeAngle.get( 0 ) - nShapeRotation; 259 } 260 // convert DrawingML angle (in 1/60000 degrees) to API angle (in 1/10 degrees) 261 aGradient.Angle = static_cast< sal_Int16 >( (4500 - (nDmlAngle / (PER_DEGREE / 10))) % 3600 ); 262 263 // push gradient or named gradient to property map 264 if( rPropMap.setProperty( SHAPEPROP_FillGradient, aGradient ) ) 265 eFillStyle = FillStyle_GRADIENT; 266 } 267 break; 268 269 case XML_blipFill: 270 // do not start complex graphic transformation if property is not supported... 271 if( maBlipProps.mxGraphic.is() && rPropMap.supportsProperty( SHAPEPROP_FillBitmapUrl ) ) 272 { 273 // TODO: "rotate with shape" is not possible with our current core 274 275 OUString aGraphicUrl = rGraphicHelper.createGraphicObject( maBlipProps.mxGraphic ); 276 // push bitmap or named bitmap to property map 277 if( (aGraphicUrl.getLength() > 0) && rPropMap.setProperty( SHAPEPROP_FillBitmapUrl, aGraphicUrl ) ) 278 eFillStyle = FillStyle_BITMAP; 279 280 // set other bitmap properties, if bitmap has been inserted into the map 281 if( eFillStyle == FillStyle_BITMAP ) 282 { 283 // bitmap mode (single, repeat, stretch) 284 BitmapMode eBitmapMode = lclGetBitmapMode( maBlipProps.moBitmapMode.get( XML_TOKEN_INVALID ) ); 285 rPropMap.setProperty( SHAPEPROP_FillBitmapMode, eBitmapMode ); 286 287 // additional settings for repeated bitmap 288 if( eBitmapMode == BitmapMode_REPEAT ) 289 { 290 // anchor position inside bitmap 291 RectanglePoint eRectPoint = lclGetRectanglePoint( maBlipProps.moTileAlign.get( XML_tl ) ); 292 rPropMap.setProperty( SHAPEPROP_FillBitmapRectanglePoint, eRectPoint ); 293 294 awt::Size aOriginalSize = lclGetOriginalSize( rGraphicHelper, maBlipProps.mxGraphic ); 295 if( (aOriginalSize.Width > 0) && (aOriginalSize.Height > 0) ) 296 { 297 // size of one bitmap tile (given as 1/1000 percent of bitmap size), convert to 1/100 mm 298 double fScaleX = maBlipProps.moTileScaleX.get( MAX_PERCENT ) / static_cast< double >( MAX_PERCENT ); 299 sal_Int32 nFillBmpSizeX = getLimitedValue< sal_Int32, double >( aOriginalSize.Width * fScaleX, 1, SAL_MAX_INT32 ); 300 rPropMap.setProperty( SHAPEPROP_FillBitmapSizeX, nFillBmpSizeX ); 301 double fScaleY = maBlipProps.moTileScaleY.get( MAX_PERCENT ) / static_cast< double >( MAX_PERCENT ); 302 sal_Int32 nFillBmpSizeY = getLimitedValue< sal_Int32, double >( aOriginalSize.Height * fScaleY, 1, SAL_MAX_INT32 ); 303 rPropMap.setProperty( SHAPEPROP_FillBitmapSizeY, nFillBmpSizeY ); 304 305 // offset of the first bitmap tile (given as EMUs), convert to percent 306 sal_Int16 nTileOffsetX = getDoubleIntervalValue< sal_Int16 >( maBlipProps.moTileOffsetX.get( 0 ) / 3.6 / aOriginalSize.Width, 0, 100 ); 307 rPropMap.setProperty( SHAPEPROP_FillBitmapOffsetX, nTileOffsetX ); 308 sal_Int16 nTileOffsetY = getDoubleIntervalValue< sal_Int16 >( maBlipProps.moTileOffsetY.get( 0 ) / 3.6 / aOriginalSize.Height, 0, 100 ); 309 rPropMap.setProperty( SHAPEPROP_FillBitmapOffsetY, nTileOffsetY ); 310 } 311 } 312 } 313 } 314 break; 315 316 case XML_pattFill: 317 { 318 // todo 319 Color aColor = getBestSolidColor(); 320 if( aColor.isUsed() ) 321 { 322 rPropMap.setProperty( SHAPEPROP_FillColor, aColor.getColor( rGraphicHelper, nPhClr ) ); 323 if( aColor.hasTransparency() ) 324 rPropMap.setProperty( SHAPEPROP_FillTransparency, aColor.getTransparency() ); 325 eFillStyle = FillStyle_SOLID; 326 } 327 } 328 break; 329 330 case XML_grpFill: 331 // todo 332 eFillStyle = FillStyle_NONE; 333 break; 334 } 335 336 // set final fill style property 337 rPropMap.setProperty( SHAPEPROP_FillStyle, eFillStyle ); 338 } 339 } 340 341 // ============================================================================ 342 343 void GraphicProperties::assignUsed( const GraphicProperties& rSourceProps ) 344 { 345 maBlipProps.assignUsed( rSourceProps.maBlipProps ); 346 } 347 348 void GraphicProperties::pushToPropMap( PropertyMap& rPropMap, const GraphicHelper& rGraphicHelper, sal_Int32 nPhClr ) const 349 { 350 if( maBlipProps.mxGraphic.is() ) 351 { 352 // created transformed graphic 353 Reference< XGraphic > xGraphic = maBlipProps.mxGraphic; 354 if( maBlipProps.maColorChangeFrom.isUsed() && maBlipProps.maColorChangeTo.isUsed() ) 355 { 356 sal_Int32 nFromColor = maBlipProps.maColorChangeFrom.getColor( rGraphicHelper, nPhClr ); 357 sal_Int32 nToColor = maBlipProps.maColorChangeTo.getColor( rGraphicHelper, nPhClr ); 358 if ( (nFromColor != nToColor) || maBlipProps.maColorChangeTo.hasTransparency() ) try 359 { 360 sal_Int16 nToTransparence = maBlipProps.maColorChangeTo.getTransparency(); 361 sal_Int8 nToAlpha = static_cast< sal_Int8 >( (100 - nToTransparence) / 39.062 ); // ?!? correct ?!? 362 Reference< XGraphicTransformer > xTransformer( maBlipProps.mxGraphic, UNO_QUERY_THROW ); 363 xGraphic = xTransformer->colorChange( maBlipProps.mxGraphic, nFromColor, 9, nToColor, nToAlpha ); 364 } 365 catch( Exception& ) 366 { 367 } 368 } 369 370 OUString aGraphicUrl = rGraphicHelper.createGraphicObject( xGraphic ); 371 if( aGraphicUrl.getLength() > 0 ) 372 rPropMap[ PROP_GraphicURL ] <<= aGraphicUrl; 373 374 // cropping 375 if ( maBlipProps.moClipRect.has() ) 376 { 377 geometry::IntegerRectangle2D oClipRect( maBlipProps.moClipRect.get() ); 378 awt::Size aOriginalSize( rGraphicHelper.getOriginalSize( xGraphic ) ); 379 if ( aOriginalSize.Width && aOriginalSize.Height ) 380 { 381 text::GraphicCrop aGraphCrop( 0, 0, 0, 0 ); 382 if ( oClipRect.X1 ) 383 aGraphCrop.Left = static_cast< sal_Int32 >( ( static_cast< double >( aOriginalSize.Width ) * oClipRect.X1 ) / 100000 ); 384 if ( oClipRect.Y1 ) 385 aGraphCrop.Top = static_cast< sal_Int32 >( ( static_cast< double >( aOriginalSize.Height ) * oClipRect.Y1 ) / 100000 ); 386 if ( oClipRect.X2 ) 387 aGraphCrop.Right = static_cast< sal_Int32 >( ( static_cast< double >( aOriginalSize.Width ) * oClipRect.X2 ) / 100000 ); 388 if ( oClipRect.Y2 ) 389 aGraphCrop.Bottom = static_cast< sal_Int32 >( ( static_cast< double >( aOriginalSize.Height ) * oClipRect.Y2 ) / 100000 ); 390 rPropMap[ PROP_GraphicCrop ] <<= aGraphCrop; 391 } 392 } 393 } 394 395 // color effect 396 ColorMode eColorMode = ColorMode_STANDARD; 397 switch( maBlipProps.moColorEffect.get( XML_TOKEN_INVALID ) ) 398 { 399 case XML_biLevel: eColorMode = ColorMode_MONO; break; 400 case XML_grayscl: eColorMode = ColorMode_GREYS; break; 401 } 402 rPropMap[ PROP_GraphicColorMode ] <<= eColorMode; 403 404 // brightness and contrast 405 sal_Int16 nBrightness = getLimitedValue< sal_Int16, sal_Int32 >( maBlipProps.moBrightness.get( 0 ) / PER_PERCENT, -100, 100 ); 406 if( nBrightness != 0 ) 407 rPropMap[ PROP_AdjustLuminance ] <<= nBrightness; 408 sal_Int16 nContrast = getLimitedValue< sal_Int16, sal_Int32 >( maBlipProps.moContrast.get( 0 ) / PER_PERCENT, -100, 100 ); 409 if( nContrast != 0 ) 410 rPropMap[ PROP_AdjustContrast ] <<= nContrast; 411 } 412 413 // ============================================================================ 414 415 } // namespace drawingml 416 } // namespace oox 417 418