Update ooo320-m1
[ooovba.git] / oox / source / drawingml / fillproperties.cxx
blobf6a72c3aafcee13bd898f8d8b26e6ec12fb05046
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: fillproperties.cxx,v $
10 * $Revision: 1.7.6.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 #include "oox/drawingml/fillproperties.hxx"
32 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
33 #include <com/sun/star/beans/XPropertySet.hpp>
34 #include <com/sun/star/awt/Gradient.hpp>
35 #include <com/sun/star/awt/Size.hpp>
36 #include <com/sun/star/drawing/BitmapMode.hpp>
37 #include <com/sun/star/drawing/ColorMode.hpp>
38 #include <com/sun/star/drawing/FillStyle.hpp>
39 #include <com/sun/star/drawing/RectanglePoint.hpp>
40 #include <com/sun/star/graphic/XGraphicTransformer.hpp>
41 #include "properties.hxx"
42 #include "tokens.hxx"
43 #include "oox/helper/graphichelper.hxx"
44 #include "oox/helper/modelobjecthelper.hxx"
45 #include "oox/helper/propertymap.hxx"
46 #include "oox/helper/propertyset.hxx"
47 #include "oox/core/filterbase.hxx"
48 #include "oox/drawingml/drawingmltypes.hxx"
50 using namespace ::com::sun::star;
51 using namespace ::com::sun::star::drawing;
52 using namespace ::com::sun::star::graphic;
54 using ::rtl::OUString;
55 using ::com::sun::star::uno::Reference;
56 using ::com::sun::star::uno::Exception;
57 using ::com::sun::star::uno::UNO_QUERY;
58 using ::com::sun::star::uno::UNO_QUERY_THROW;
59 using ::com::sun::star::geometry::IntegerRectangle2D;
60 using ::oox::core::FilterBase;
62 namespace oox {
63 namespace drawingml {
65 // ============================================================================
67 namespace {
69 static const sal_Int32 spnDefaultFillIds[ FillId_END ] =
71 PROP_FillStyle,
72 PROP_FillColor,
73 PROP_FillTransparence,
74 PROP_FillGradient,
75 PROP_FillBitmapURL,
76 PROP_FillBitmapMode,
77 PROP_FillBitmapSizeX,
78 PROP_FillBitmapSizeY,
79 PROP_FillBitmapPositionOffsetX,
80 PROP_FillBitmapPositionOffsetY,
81 PROP_FillBitmapRectanglePoint
84 BitmapMode lclGetBitmapMode( sal_Int32 nToken )
86 switch( nToken )
88 case XML_tile: return BitmapMode_REPEAT;
89 case XML_stretch: return BitmapMode_STRETCH;
91 return BitmapMode_NO_REPEAT;
94 RectanglePoint lclGetRectanglePoint( sal_Int32 nToken )
96 switch( nToken )
98 case XML_tl: return RectanglePoint_LEFT_TOP;
99 case XML_t: return RectanglePoint_MIDDLE_TOP;
100 case XML_tr: return RectanglePoint_RIGHT_TOP;
101 case XML_l: return RectanglePoint_LEFT_MIDDLE;
102 case XML_ctr: return RectanglePoint_MIDDLE_MIDDLE;
103 case XML_r: return RectanglePoint_RIGHT_MIDDLE;
104 case XML_bl: return RectanglePoint_LEFT_BOTTOM;
105 case XML_b: return RectanglePoint_MIDDLE_BOTTOM;
106 case XML_br: return RectanglePoint_RIGHT_BOTTOM;
108 return RectanglePoint_LEFT_TOP;
111 const awt::Size lclGetOriginalSize( const FilterBase& rFilter, const Reference< XGraphic >& rxGraphic )
113 awt::Size aSize100thMM( 0, 0 );
116 Reference< beans::XPropertySet > xGraphicPropertySet( rxGraphic, UNO_QUERY_THROW );
117 if( xGraphicPropertySet->getPropertyValue( CREATE_OUSTRING( "Size100thMM" ) ) >>= aSize100thMM )
119 if( !aSize100thMM.Width && !aSize100thMM.Height )
120 { // MAPMODE_PIXEL USED :-(
121 awt::Size aSourceSizePixel( 0, 0 );
122 if( xGraphicPropertySet->getPropertyValue( CREATE_OUSTRING( "SizePixel" ) ) >>= aSourceSizePixel )
124 aSize100thMM = awt::Size(
125 rFilter.convertScreenPixelX( aSourceSizePixel.Width ),
126 rFilter.convertScreenPixelY( aSourceSizePixel.Height ) );
131 catch( Exception& )
134 return aSize100thMM;
137 } // namespace
139 // ============================================================================
141 FillPropertyIds::FillPropertyIds( const sal_Int32* pnPropertyIds, bool bNamedFillGradient, bool bNamedFillBitmap ) :
142 mpnPropertyIds( pnPropertyIds ),
143 mbNamedFillGradient( bNamedFillGradient ),
144 mbNamedFillBitmap( bNamedFillBitmap )
146 OSL_ENSURE( mpnPropertyIds != 0, "FillPropertyIds::FillPropertyIds - missing property identifiers" );
149 // ============================================================================
151 void GradientFillProperties::assignUsed( const GradientFillProperties& rSourceProps )
153 if( !rSourceProps.maGradientStops.empty() )
154 maGradientStops = rSourceProps.maGradientStops;
155 moFillToRect.assignIfUsed( rSourceProps.moFillToRect );
156 moTileRect.assignIfUsed( rSourceProps.moTileRect );
157 moGradientPath.assignIfUsed( rSourceProps.moGradientPath );
158 moShadeAngle.assignIfUsed( rSourceProps.moShadeAngle );
159 moShadeFlip.assignIfUsed( rSourceProps.moShadeFlip );
160 moShadeScaled.assignIfUsed( rSourceProps.moShadeScaled );
161 moRotateWithShape.assignIfUsed( rSourceProps.moRotateWithShape );
164 // ============================================================================
166 void PatternFillProperties::assignUsed( const PatternFillProperties& rSourceProps )
168 maPattFgColor.assignIfUsed( rSourceProps.maPattFgColor );
169 maPattBgColor.assignIfUsed( rSourceProps.maPattBgColor );
170 moPattPreset.assignIfUsed( rSourceProps.moPattPreset );
173 // ============================================================================
175 void BlipFillProperties::assignUsed( const BlipFillProperties& rSourceProps )
177 if( rSourceProps.mxGraphic.is() )
178 mxGraphic = rSourceProps.mxGraphic;
179 moBitmapMode.assignIfUsed( rSourceProps.moBitmapMode );
180 moFillRect.assignIfUsed( rSourceProps.moFillRect );
181 moTileOffsetX.assignIfUsed( rSourceProps.moTileOffsetX );
182 moTileOffsetY.assignIfUsed( rSourceProps.moTileOffsetY );
183 moTileScaleX.assignIfUsed( rSourceProps.moTileScaleX );
184 moTileScaleY.assignIfUsed( rSourceProps.moTileScaleY );
185 moTileAlign.assignIfUsed( rSourceProps.moTileAlign );
186 moTileFlip.assignIfUsed( rSourceProps.moTileFlip );
187 moRotateWithShape.assignIfUsed( rSourceProps.moRotateWithShape );
188 moColorEffect.assignIfUsed( rSourceProps.moColorEffect );
189 moBrightness.assignIfUsed( rSourceProps.moBrightness );
190 moContrast.assignIfUsed( rSourceProps.moContrast );
191 maColorChangeFrom.assignIfUsed( rSourceProps.maColorChangeFrom );
192 maColorChangeTo.assignIfUsed( rSourceProps.maColorChangeTo );
195 // ============================================================================
197 FillPropertyIds FillProperties::DEFAULT_IDS( spnDefaultFillIds, false, false );
199 void FillProperties::assignUsed( const FillProperties& rSourceProps )
201 moFillType.assignIfUsed( rSourceProps.moFillType );
202 maFillColor.assignIfUsed( rSourceProps.maFillColor );
203 maGradientProps.assignUsed( rSourceProps.maGradientProps );
204 maPatternProps.assignUsed( rSourceProps.maPatternProps );
205 maBlipProps.assignUsed( rSourceProps.maBlipProps );
208 Color FillProperties::getBestSolidColor() const
210 Color aSolidColor;
211 if( moFillType.has() ) switch( moFillType.get() )
213 case XML_solidFill:
214 aSolidColor = maFillColor;
215 break;
216 case XML_gradFill:
217 if( !maGradientProps.maGradientStops.empty() )
218 aSolidColor = maGradientProps.maGradientStops.begin()->second;
219 break;
220 case XML_pattFill:
221 aSolidColor = maPatternProps.maPattBgColor.isUsed() ? maPatternProps.maPattBgColor : maPatternProps.maPattFgColor;
222 break;
224 return aSolidColor;
227 void FillProperties::pushToPropMap( PropertyMap& rPropMap, const FilterBase& rFilter,
228 ModelObjectHelper& rModelObjHelper, const FillPropertyIds& rPropIds,
229 sal_Int32 nShapeRotation, sal_Int32 nPhClr ) const
231 if( moFillType.has() )
233 FillStyle eFillStyle = FillStyle_NONE;
234 switch( moFillType.get() )
236 case XML_noFill:
237 eFillStyle = FillStyle_NONE;
238 break;
240 case XML_solidFill:
241 if( maFillColor.isUsed() )
243 rPropMap.setProperty( rPropIds[ FillColorId ], maFillColor.getColor( rFilter, nPhClr ) );
244 if( maFillColor.hasTransparence() )
245 rPropMap.setProperty( rPropIds[ FillTransparenceId ], maFillColor.getTransparence() );
246 eFillStyle = FillStyle_SOLID;
248 break;
250 case XML_gradFill:
251 // do not create gradient struct if property is not supported...
252 if( rPropIds.has( FillGradientId ) )
254 awt::Gradient aGradient;
255 aGradient.Angle = 900;
256 aGradient.StartIntensity = 100;
257 aGradient.EndIntensity = 100;
259 size_t nColorCount = maGradientProps.maGradientStops.size();
260 if( nColorCount > 1 )
262 aGradient.StartColor = maGradientProps.maGradientStops.begin()->second.getColor( rFilter, nPhClr );
263 aGradient.EndColor = maGradientProps.maGradientStops.rbegin()->second.getColor( rFilter, nPhClr );
266 // "rotate with shape" not set, or set to false -> do not rotate
267 if ( !maGradientProps.moRotateWithShape.get( false ) )
268 nShapeRotation = 0;
270 sal_Int32 nDmlAngle = 0;
271 if( maGradientProps.moGradientPath.has() )
273 aGradient.Style = (maGradientProps.moGradientPath.get() == XML_circle) ? awt::GradientStyle_ELLIPTICAL : awt::GradientStyle_RECT;
274 // position of gradient center (limited to [30%;70%], otherwise gradient is too hidden)
275 IntegerRectangle2D aFillToRect = maGradientProps.moFillToRect.get( IntegerRectangle2D( 0, 0, MAX_PERCENT, MAX_PERCENT ) );
276 sal_Int32 nCenterX = (MAX_PERCENT + aFillToRect.X1 - aFillToRect.X2) / 2;
277 aGradient.XOffset = getLimitedValue< sal_Int16, sal_Int32 >( nCenterX / PER_PERCENT, 30, 70 );
278 sal_Int32 nCenterY = (MAX_PERCENT + aFillToRect.Y1 - aFillToRect.Y2) / 2;
279 aGradient.YOffset = getLimitedValue< sal_Int16, sal_Int32 >( nCenterY / PER_PERCENT, 30, 70 );
280 ::std::swap( aGradient.StartColor, aGradient.EndColor );
281 nDmlAngle = nShapeRotation;
283 else
285 /* Try to detect a VML axial gradient. This type of
286 gradient is simulated by a 3-point linear gradient
287 with equal start and end color. */
288 bool bAxial = (nColorCount == 3) && (aGradient.StartColor == aGradient.EndColor);
289 aGradient.Style = bAxial ? awt::GradientStyle_AXIAL : awt::GradientStyle_LINEAR;
290 if( bAxial )
292 GradientFillProperties::GradientStopMap::const_iterator aIt = maGradientProps.maGradientStops.begin();
293 // API StartColor is inner color in axial gradient
294 aGradient.StartColor = (++aIt)->second.getColor( rFilter, nPhClr );
296 nDmlAngle = maGradientProps.moShadeAngle.get( 0 ) - nShapeRotation;
298 // convert DrawingML angle (in 1/60000 degrees) to API angle (in 1/10 degrees)
299 aGradient.Angle = static_cast< sal_Int16 >( (4500 - (nDmlAngle / (PER_DEGREE / 10))) % 3600 );
301 // push gradient or named gradient to property map
302 if( rPropIds.mbNamedFillGradient )
304 OUString aGradientName = rModelObjHelper.insertFillGradient( aGradient );
305 if( aGradientName.getLength() > 0 )
307 rPropMap.setProperty( rPropIds[ FillGradientId ], aGradientName );
308 eFillStyle = FillStyle_GRADIENT;
311 else
313 rPropMap.setProperty( rPropIds[ FillGradientId ], aGradient );
314 eFillStyle = FillStyle_GRADIENT;
317 break;
319 case XML_blipFill:
320 // do not start complex graphic transformation if property is not supported...
321 if( maBlipProps.mxGraphic.is() && rPropIds.has( FillBitmapUrlId ) )
323 // TODO: "rotate with shape" is not possible with our current core
325 OUString aGraphicUrl = rFilter.getGraphicHelper().createGraphicObject( maBlipProps.mxGraphic );
326 if( aGraphicUrl.getLength() > 0 )
328 // push bitmap or named bitmap to property map
329 if( rPropIds.mbNamedFillBitmap )
331 OUString aBitmapName = rModelObjHelper.insertFillBitmap( aGraphicUrl );
332 if( aBitmapName.getLength() > 0 )
334 rPropMap.setProperty( rPropIds[ FillBitmapUrlId ], aBitmapName );
335 eFillStyle = FillStyle_BITMAP;
338 else
340 rPropMap.setProperty( rPropIds[ FillBitmapUrlId ], aGraphicUrl );
341 eFillStyle = FillStyle_BITMAP;
345 // set other bitmap properties, if bitmap has been inserted into the map
346 if( eFillStyle == FillStyle_BITMAP )
348 // bitmap mode (single, repeat, stretch)
349 BitmapMode eBitmapMode = lclGetBitmapMode( maBlipProps.moBitmapMode.get( XML_TOKEN_INVALID ) );
350 rPropMap.setProperty( rPropIds[ FillBitmapModeId ], eBitmapMode );
352 // additional settings for repeated bitmap
353 if( eBitmapMode == BitmapMode_REPEAT )
355 // anchor position inside bitmap
356 RectanglePoint eRectPoint = lclGetRectanglePoint( maBlipProps.moTileAlign.get( XML_tl ) );
357 rPropMap.setProperty( rPropIds[ FillBitmapRectanglePointId ], eRectPoint );
359 awt::Size aOriginalSize = lclGetOriginalSize( rFilter, maBlipProps.mxGraphic );
360 if( (aOriginalSize.Width > 0) && (aOriginalSize.Height > 0) )
362 // size of one bitmap tile (given as 1/1000 percent of bitmap size), convert to 1/100 mm
363 double fScaleX = maBlipProps.moTileScaleX.get( MAX_PERCENT ) / static_cast< double >( MAX_PERCENT );
364 sal_Int32 nFillBmpSizeX = getLimitedValue< sal_Int32, double >( aOriginalSize.Width * fScaleX, 1, SAL_MAX_INT32 );
365 rPropMap.setProperty( rPropIds[ FillBitmapSizeXId ], nFillBmpSizeX );
366 double fScaleY = maBlipProps.moTileScaleY.get( MAX_PERCENT ) / static_cast< double >( MAX_PERCENT );
367 sal_Int32 nFillBmpSizeY = getLimitedValue< sal_Int32, double >( aOriginalSize.Height * fScaleY, 1, SAL_MAX_INT32 );
368 rPropMap.setProperty( rPropIds[ FillBitmapSizeYId ], nFillBmpSizeY );
370 // offset of the first bitmap tile (given as EMUs), convert to percent
371 sal_Int16 nTileOffsetX = getDoubleIntervalValue< sal_Int16 >( maBlipProps.moTileOffsetX.get( 0 ) / 3.6 / aOriginalSize.Width, 0, 100 );
372 rPropMap.setProperty( rPropIds[ FillBitmapOffsetXId ], nTileOffsetX );
373 sal_Int16 nTileOffsetY = getDoubleIntervalValue< sal_Int16 >( maBlipProps.moTileOffsetY.get( 0 ) / 3.6 / aOriginalSize.Height, 0, 100 );
374 rPropMap.setProperty( rPropIds[ FillBitmapOffsetYId ], nTileOffsetY );
379 break;
381 case XML_pattFill:
383 // todo
384 Color aColor = getBestSolidColor();
385 if( aColor.isUsed() )
387 rPropMap.setProperty( rPropIds[ FillColorId ], aColor.getColor( rFilter, nPhClr ) );
388 if( aColor.hasTransparence() )
389 rPropMap.setProperty( rPropIds[ FillTransparenceId ], aColor.getTransparence() );
390 eFillStyle = FillStyle_SOLID;
393 break;
395 case XML_grpFill:
396 // todo
397 eFillStyle = FillStyle_NONE;
398 break;
401 // set final fill style property
402 rPropMap.setProperty( rPropIds[ FillStyleId ], eFillStyle );
406 void FillProperties::pushToPropSet( PropertySet& rPropSet, const FilterBase& rFilter,
407 ModelObjectHelper& rModelObjHelper, const FillPropertyIds& rPropIds,
408 sal_Int32 nShapeRotation, sal_Int32 nPhClr ) const
410 PropertyMap aPropMap;
411 pushToPropMap( aPropMap, rFilter, rModelObjHelper, rPropIds, nShapeRotation, nPhClr );
412 rPropSet.setProperties( aPropMap );
415 // ============================================================================
417 void GraphicProperties::assignUsed( const GraphicProperties& rSourceProps )
419 maBlipProps.assignUsed( rSourceProps.maBlipProps );
422 void GraphicProperties::pushToPropMap( PropertyMap& rPropMap, const FilterBase& rFilter, sal_Int32 nPhClr ) const
424 if( maBlipProps.mxGraphic.is() )
426 // created transformed graphic
427 Reference< XGraphic > xGraphic = maBlipProps.mxGraphic;
428 if( maBlipProps.maColorChangeFrom.isUsed() && maBlipProps.maColorChangeTo.isUsed() )
430 sal_Int32 nFromColor = maBlipProps.maColorChangeFrom.getColor( rFilter, nPhClr );
431 sal_Int32 nToColor = maBlipProps.maColorChangeTo.getColor( rFilter, nPhClr );
432 if ( (nFromColor != nToColor) || maBlipProps.maColorChangeTo.hasTransparence() ) try
434 sal_Int16 nToTransparence = maBlipProps.maColorChangeTo.getTransparence();
435 sal_Int8 nToAlpha = static_cast< sal_Int8 >( (100 - nToTransparence) / 39.062 ); // ?!? correct ?!?
436 Reference< XGraphicTransformer > xTransformer( maBlipProps.mxGraphic, UNO_QUERY_THROW );
437 xGraphic = xTransformer->colorChange( maBlipProps.mxGraphic, nFromColor, 9, nToColor, nToAlpha );
439 catch( Exception& )
444 OUString aGraphicUrl = rFilter.getGraphicHelper().createGraphicObject( xGraphic );
445 if( aGraphicUrl.getLength() > 0 )
446 rPropMap[ PROP_GraphicURL ] <<= aGraphicUrl;
449 // color effect
450 ColorMode eColorMode = ColorMode_STANDARD;
451 switch( maBlipProps.moColorEffect.get( XML_TOKEN_INVALID ) )
453 case XML_biLevel: eColorMode = ColorMode_MONO; break;
454 case XML_grayscl: eColorMode = ColorMode_GREYS; break;
456 rPropMap[ PROP_GraphicColorMode ] <<= eColorMode;
458 // brightness and contrast
459 sal_Int16 nBrightness = getLimitedValue< sal_Int16, sal_Int32 >( maBlipProps.moBrightness.get( 0 ) / PER_PERCENT, -100, 100 );
460 if( nBrightness != 0 )
461 rPropMap[ PROP_AdjustLuminance ] <<= nBrightness;
462 sal_Int16 nContrast = getLimitedValue< sal_Int16, sal_Int32 >( maBlipProps.moContrast.get( 0 ) / PER_PERCENT, -100, 100 );
463 if( nContrast != 0 )
464 rPropMap[ PROP_AdjustContrast ] <<= nContrast;
467 void GraphicProperties::pushToPropSet( PropertySet& rPropSet, const FilterBase& rFilter, sal_Int32 nPhClr ) const
469 PropertyMap aPropMap;
470 pushToPropMap( aPropMap, rFilter, nPhClr );
471 rPropSet.setProperties( aPropMap );
474 // ============================================================================
476 } // namespace drawingml
477 } // namespace oox