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"
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
;
65 // ============================================================================
69 static const sal_Int32 spnDefaultFillIds
[ FillId_END
] =
73 PROP_FillTransparence
,
79 PROP_FillBitmapPositionOffsetX
,
80 PROP_FillBitmapPositionOffsetY
,
81 PROP_FillBitmapRectanglePoint
84 BitmapMode
lclGetBitmapMode( sal_Int32 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
)
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
) );
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
211 if( moFillType
.has() ) switch( moFillType
.get() )
214 aSolidColor
= maFillColor
;
217 if( !maGradientProps
.maGradientStops
.empty() )
218 aSolidColor
= maGradientProps
.maGradientStops
.begin()->second
;
221 aSolidColor
= maPatternProps
.maPattBgColor
.isUsed() ? maPatternProps
.maPattBgColor
: maPatternProps
.maPattFgColor
;
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() )
237 eFillStyle
= FillStyle_NONE
;
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
;
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 ) )
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
;
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
;
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
;
313 rPropMap
.setProperty( rPropIds
[ FillGradientId
], aGradient
);
314 eFillStyle
= FillStyle_GRADIENT
;
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
;
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
);
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
;
397 eFillStyle
= FillStyle_NONE
;
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
);
444 OUString aGraphicUrl
= rFilter
.getGraphicHelper().createGraphicObject( xGraphic
);
445 if( aGraphicUrl
.getLength() > 0 )
446 rPropMap
[ PROP_GraphicURL
] <<= aGraphicUrl
;
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 );
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