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/xmlfilterbase.hxx"
49 using namespace ::com::sun::star
;
50 using namespace ::com::sun::star::drawing
;
51 using namespace ::com::sun::star::graphic
;
53 using ::rtl::OUString
;
54 using ::com::sun::star::uno::Reference
;
55 using ::com::sun::star::uno::Exception
;
56 using ::com::sun::star::uno::UNO_QUERY
;
57 using ::com::sun::star::uno::UNO_QUERY_THROW
;
58 using ::oox::core::XmlFilterBase
;
63 // ============================================================================
67 static const sal_Int32 spnDefaultFillIds
[ FillId_END
] =
71 PROP_FillTransparence
,
77 PROP_FillBitmapPositionOffsetX
,
78 PROP_FillBitmapPositionOffsetY
,
79 PROP_FillBitmapRectanglePoint
82 BitmapMode
lclGetBitmapMode( sal_Int32 nToken
)
86 case XML_tile
: return BitmapMode_REPEAT
;
87 case XML_stretch
: return BitmapMode_STRETCH
;
89 return BitmapMode_NO_REPEAT
;
92 RectanglePoint
lclGetRectanglePoint( sal_Int32 nToken
)
96 case XML_tl
: return RectanglePoint_LEFT_TOP
;
97 case XML_t
: return RectanglePoint_MIDDLE_TOP
;
98 case XML_tr
: return RectanglePoint_RIGHT_TOP
;
99 case XML_l
: return RectanglePoint_LEFT_MIDDLE
;
100 case XML_ctr
: return RectanglePoint_MIDDLE_MIDDLE
;
101 case XML_r
: return RectanglePoint_RIGHT_MIDDLE
;
102 case XML_bl
: return RectanglePoint_LEFT_BOTTOM
;
103 case XML_b
: return RectanglePoint_MIDDLE_BOTTOM
;
104 case XML_br
: return RectanglePoint_RIGHT_BOTTOM
;
106 return RectanglePoint_LEFT_TOP
;
109 const awt::Size
lclGetOriginalSize( const XmlFilterBase
& rFilter
, const Reference
< XGraphic
>& rxGraphic
)
111 awt::Size
aSize100thMM( 0, 0 );
114 Reference
< beans::XPropertySet
> xGraphicPropertySet( rxGraphic
, UNO_QUERY_THROW
);
115 if( xGraphicPropertySet
->getPropertyValue( CREATE_OUSTRING( "Size100thMM" ) ) >>= aSize100thMM
)
117 if( !aSize100thMM
.Width
&& !aSize100thMM
.Height
)
118 { // MAPMODE_PIXEL USED :-(
119 awt::Size
aSourceSizePixel( 0, 0 );
120 if( xGraphicPropertySet
->getPropertyValue( CREATE_OUSTRING( "SizePixel" ) ) >>= aSourceSizePixel
)
122 aSize100thMM
= awt::Size(
123 rFilter
.convertScreenPixelX( aSourceSizePixel
.Width
),
124 rFilter
.convertScreenPixelY( aSourceSizePixel
.Height
) );
137 // ============================================================================
139 FillPropertyIds::FillPropertyIds( const sal_Int32
* pnPropertyIds
, bool bNamedFillGradient
, bool bNamedFillBitmap
) :
140 mpnPropertyIds( pnPropertyIds
),
141 mbNamedFillGradient( bNamedFillGradient
),
142 mbNamedFillBitmap( bNamedFillBitmap
)
144 OSL_ENSURE( mpnPropertyIds
!= 0, "FillPropertyIds::FillPropertyIds - missing property identifiers" );
147 // ============================================================================
149 void GradientFillProperties::assignUsed( const GradientFillProperties
& rSourceProps
)
151 if( !rSourceProps
.maGradientStops
.empty() )
152 maGradientStops
= rSourceProps
.maGradientStops
;
153 moFillToRect
.assignIfUsed( rSourceProps
.moFillToRect
);
154 moTileRect
.assignIfUsed( rSourceProps
.moTileRect
);
155 moGradientPath
.assignIfUsed( rSourceProps
.moGradientPath
);
156 moShadeAngle
.assignIfUsed( rSourceProps
.moShadeAngle
);
157 moShadeFlip
.assignIfUsed( rSourceProps
.moShadeFlip
);
158 moShadeScaled
.assignIfUsed( rSourceProps
.moShadeScaled
);
159 moRotateWithShape
.assignIfUsed( rSourceProps
.moRotateWithShape
);
162 // ============================================================================
164 void PatternFillProperties::assignUsed( const PatternFillProperties
& rSourceProps
)
166 maPattFgColor
.assignIfUsed( rSourceProps
.maPattFgColor
);
167 maPattBgColor
.assignIfUsed( rSourceProps
.maPattBgColor
);
168 moPattPreset
.assignIfUsed( rSourceProps
.moPattPreset
);
171 // ============================================================================
173 void BlipFillProperties::assignUsed( const BlipFillProperties
& rSourceProps
)
175 if( rSourceProps
.mxGraphic
.is() )
176 mxGraphic
= rSourceProps
.mxGraphic
;
177 moBitmapMode
.assignIfUsed( rSourceProps
.moBitmapMode
);
178 moFillRect
.assignIfUsed( rSourceProps
.moFillRect
);
179 moTileOffsetX
.assignIfUsed( rSourceProps
.moTileOffsetX
);
180 moTileOffsetY
.assignIfUsed( rSourceProps
.moTileOffsetY
);
181 moTileScaleX
.assignIfUsed( rSourceProps
.moTileScaleX
);
182 moTileScaleY
.assignIfUsed( rSourceProps
.moTileScaleY
);
183 moTileAlign
.assignIfUsed( rSourceProps
.moTileAlign
);
184 moTileFlip
.assignIfUsed( rSourceProps
.moTileFlip
);
185 moRotateWithShape
.assignIfUsed( rSourceProps
.moRotateWithShape
);
186 moColorEffect
.assignIfUsed( rSourceProps
.moColorEffect
);
187 moBrightness
.assignIfUsed( rSourceProps
.moBrightness
);
188 moContrast
.assignIfUsed( rSourceProps
.moContrast
);
189 maColorChangeFrom
.assignIfUsed( rSourceProps
.maColorChangeFrom
);
190 maColorChangeTo
.assignIfUsed( rSourceProps
.maColorChangeTo
);
193 // ============================================================================
195 FillPropertyIds
FillProperties::DEFAULT_IDS( spnDefaultFillIds
, false, false );
197 void FillProperties::assignUsed( const FillProperties
& rSourceProps
)
199 moFillType
.assignIfUsed( rSourceProps
.moFillType
);
200 maFillColor
.assignIfUsed( rSourceProps
.maFillColor
);
201 maGradientProps
.assignUsed( rSourceProps
.maGradientProps
);
202 maPatternProps
.assignUsed( rSourceProps
.maPatternProps
);
203 maBlipProps
.assignUsed( rSourceProps
.maBlipProps
);
206 Color
FillProperties::getBestSolidColor() const
209 if( moFillType
.has() ) switch( moFillType
.get() )
212 aSolidColor
= maFillColor
;
215 if( !maGradientProps
.maGradientStops
.empty() )
216 aSolidColor
= maGradientProps
.maGradientStops
.begin()->second
;
219 aSolidColor
= maPatternProps
.maPattBgColor
.isUsed() ? maPatternProps
.maPattBgColor
: maPatternProps
.maPattFgColor
;
225 void FillProperties::pushToPropMap( PropertyMap
& rPropMap
, const FillPropertyIds
& rPropIds
,
226 const XmlFilterBase
& rFilter
, ModelObjectHelper
& rModelObjHelper
,
227 sal_Int32 nShapeRotation
, sal_Int32 nPhClr
) const
229 if( moFillType
.has() )
231 FillStyle eFillStyle
= FillStyle_NONE
;
232 switch( moFillType
.get() )
235 eFillStyle
= FillStyle_NONE
;
239 if( maFillColor
.isUsed() )
241 rPropMap
.setProperty( rPropIds
[ FillColorId
], maFillColor
.getColor( rFilter
, nPhClr
) );
242 if( maFillColor
.hasTransparence() )
243 rPropMap
.setProperty( rPropIds
[ FillTransparenceId
], maFillColor
.getTransparence() );
244 eFillStyle
= FillStyle_SOLID
;
249 // do not create gradient struct if property is not supported...
250 if( rPropIds
.has( FillGradientId
) )
252 awt::Gradient aGradient
;
253 aGradient
.Angle
= 900;
254 aGradient
.StartIntensity
= 100;
255 aGradient
.EndIntensity
= 100;
257 if( maGradientProps
.maGradientStops
.size() > 1 )
259 aGradient
.StartColor
= maGradientProps
.maGradientStops
.begin()->second
.getColor( rFilter
, nPhClr
);
260 aGradient
.EndColor
= maGradientProps
.maGradientStops
.rbegin()->second
.getColor( rFilter
, nPhClr
);
263 // "rotate with shape" not set, or set to false -> do not rotate
264 if ( !maGradientProps
.moRotateWithShape
.get( false ) )
267 if( maGradientProps
.moGradientPath
.has() )
269 aGradient
.Style
= (maGradientProps
.moGradientPath
.get() == XML_circle
) ? awt::GradientStyle_ELLIPTICAL
: awt::GradientStyle_RECT
;
270 aGradient
.Angle
= static_cast< sal_Int16
>( (900 - (nShapeRotation
/ 6000)) % 3600 );
271 aGradient
.XOffset
= maGradientProps
.moFillToRect
.has() ? getLimitedValue
< sal_Int16
, sal_Int32
>( maGradientProps
.moFillToRect
.get().X1
/ 1000, 30, 70 ) : 50;
272 aGradient
.YOffset
= maGradientProps
.moFillToRect
.has() ? getLimitedValue
< sal_Int16
, sal_Int32
>( maGradientProps
.moFillToRect
.get().Y1
/ 1000, 30, 70 ) : 50;
273 ::std::swap( aGradient
.StartColor
, aGradient
.EndColor
);
277 aGradient
.Style
= awt::GradientStyle_LINEAR
;
278 aGradient
.Angle
= static_cast< sal_Int16
>( (4500 - ((maGradientProps
.moShadeAngle
.get( 0 ) - nShapeRotation
) / 6000)) % 3600 );
281 // push gradient or named gradient to property map
282 if( rPropIds
.mbNamedFillGradient
)
284 OUString aGradientName
= rModelObjHelper
.insertFillGradient( aGradient
);
285 if( aGradientName
.getLength() > 0 )
287 rPropMap
.setProperty( rPropIds
[ FillGradientId
], aGradientName
);
288 eFillStyle
= FillStyle_GRADIENT
;
293 rPropMap
.setProperty( rPropIds
[ FillGradientId
], aGradient
);
294 eFillStyle
= FillStyle_GRADIENT
;
300 // do not start complex graphic transformation if property is not supported...
301 if( maBlipProps
.mxGraphic
.is() && rPropIds
.has( FillBitmapUrlId
) )
303 // TODO: "rotate with shape" is not possible with our current core
305 OUString aGraphicUrl
= rFilter
.getGraphicHelper().createGraphicObject( maBlipProps
.mxGraphic
);
306 if( aGraphicUrl
.getLength() > 0 )
308 // push bitmap or named bitmap to property map
309 if( rPropIds
.mbNamedFillBitmap
)
311 OUString aBitmapName
= rModelObjHelper
.insertFillBitmap( aGraphicUrl
);
312 if( aBitmapName
.getLength() > 0 )
314 rPropMap
.setProperty( rPropIds
[ FillBitmapUrlId
], aBitmapName
);
315 eFillStyle
= FillStyle_BITMAP
;
320 rPropMap
.setProperty( rPropIds
[ FillBitmapUrlId
], aGraphicUrl
);
321 eFillStyle
= FillStyle_BITMAP
;
325 // set other bitmap properties, if bitmap has been inserted into the map
326 if( eFillStyle
== FillStyle_BITMAP
)
328 // bitmap mode (single, repeat, stretch)
329 BitmapMode eBitmapMode
= lclGetBitmapMode( maBlipProps
.moBitmapMode
.get( XML_TOKEN_INVALID
) );
330 rPropMap
.setProperty( rPropIds
[ FillBitmapModeId
], eBitmapMode
);
332 // additional settings for repeated bitmap
333 if( eBitmapMode
== BitmapMode_REPEAT
)
335 // anchor position inside bitmap
336 RectanglePoint eRectPoint
= lclGetRectanglePoint( maBlipProps
.moTileAlign
.get( XML_tl
) );
337 rPropMap
.setProperty( rPropIds
[ FillBitmapRectanglePointId
], eRectPoint
);
339 awt::Size aOriginalSize
= lclGetOriginalSize( rFilter
, maBlipProps
.mxGraphic
);
340 if( (aOriginalSize
.Width
> 0) && (aOriginalSize
.Height
> 0) )
342 // size of one bitmap tile (given as 1/1000 percent of bitmap size), convert to 1/100 mm
343 double fScaleX
= maBlipProps
.moTileScaleX
.get( 100000 ) / 100000.0;
344 sal_Int32 nFillBmpSizeX
= getLimitedValue
< sal_Int32
, double >( aOriginalSize
.Width
* fScaleX
, 1, SAL_MAX_INT32
);
345 rPropMap
.setProperty( rPropIds
[ FillBitmapSizeXId
], nFillBmpSizeX
);
346 double fScaleY
= maBlipProps
.moTileScaleY
.get( 100000 ) / 100000.0;
347 sal_Int32 nFillBmpSizeY
= getLimitedValue
< sal_Int32
, double >( aOriginalSize
.Height
* fScaleY
, 1, SAL_MAX_INT32
);
348 rPropMap
.setProperty( rPropIds
[ FillBitmapSizeYId
], nFillBmpSizeY
);
350 // offset of the first bitmap tile (given as EMUs), convert to percent
351 sal_Int16 nTileOffsetX
= getDoubleIntervalValue
< sal_Int16
>( maBlipProps
.moTileOffsetX
.get( 0 ) / 3.6 / aOriginalSize
.Width
, 0, 100 );
352 rPropMap
.setProperty( rPropIds
[ FillBitmapOffsetXId
], nTileOffsetX
);
353 sal_Int16 nTileOffsetY
= getDoubleIntervalValue
< sal_Int16
>( maBlipProps
.moTileOffsetY
.get( 0 ) / 3.6 / aOriginalSize
.Height
, 0, 100 );
354 rPropMap
.setProperty( rPropIds
[ FillBitmapOffsetYId
], nTileOffsetY
);
364 Color aColor
= getBestSolidColor();
365 if( aColor
.isUsed() )
367 rPropMap
.setProperty( rPropIds
[ FillColorId
], aColor
.getColor( rFilter
, nPhClr
) );
368 if( aColor
.hasTransparence() )
369 rPropMap
.setProperty( rPropIds
[ FillTransparenceId
], aColor
.getTransparence() );
370 eFillStyle
= FillStyle_SOLID
;
377 eFillStyle
= FillStyle_NONE
;
381 // set final fill style property
382 rPropMap
.setProperty( rPropIds
[ FillStyleId
], eFillStyle
);
386 void FillProperties::pushToPropSet( PropertySet
& rPropSet
, const FillPropertyIds
& rPropIds
,
387 const XmlFilterBase
& rFilter
, ModelObjectHelper
& rModelObjHelper
,
388 sal_Int32 nShapeRotation
, sal_Int32 nPhClr
) const
390 PropertyMap aPropMap
;
391 pushToPropMap( aPropMap
, rPropIds
, rFilter
, rModelObjHelper
, nShapeRotation
, nPhClr
);
392 rPropSet
.setProperties( aPropMap
);
395 // ============================================================================
397 void GraphicProperties::assignUsed( const GraphicProperties
& rSourceProps
)
399 maBlipProps
.assignUsed( rSourceProps
.maBlipProps
);
402 void GraphicProperties::pushToPropMap( PropertyMap
& rPropMap
, const XmlFilterBase
& rFilter
, sal_Int32 nPhClr
) const
404 if( maBlipProps
.mxGraphic
.is() )
406 // created transformed graphic
407 Reference
< XGraphic
> xGraphic
= maBlipProps
.mxGraphic
;
408 if( maBlipProps
.maColorChangeFrom
.isUsed() && maBlipProps
.maColorChangeTo
.isUsed() )
410 sal_Int32 nFromColor
= maBlipProps
.maColorChangeFrom
.getColor( rFilter
, nPhClr
);
411 sal_Int32 nToColor
= maBlipProps
.maColorChangeTo
.getColor( rFilter
, nPhClr
);
412 if ( (nFromColor
!= nToColor
) || maBlipProps
.maColorChangeTo
.hasTransparence() ) try
414 sal_Int16 nToTransparence
= maBlipProps
.maColorChangeTo
.getTransparence();
415 sal_Int8 nToAlpha
= static_cast< sal_Int8
>( (100 - nToTransparence
) / 39.062 ); // ?!? correct ?!?
416 Reference
< XGraphicTransformer
> xTransformer( maBlipProps
.mxGraphic
, UNO_QUERY_THROW
);
417 xGraphic
= xTransformer
->colorChange( maBlipProps
.mxGraphic
, nFromColor
, 9, nToColor
, nToAlpha
);
424 OUString aGraphicUrl
= rFilter
.getGraphicHelper().createGraphicObject( xGraphic
);
425 if( aGraphicUrl
.getLength() > 0 )
426 rPropMap
[ PROP_GraphicURL
] <<= aGraphicUrl
;
430 ColorMode eColorMode
= ColorMode_STANDARD
;
431 switch( maBlipProps
.moColorEffect
.get( XML_TOKEN_INVALID
) )
433 case XML_biLevel
: eColorMode
= ColorMode_MONO
; break;
434 case XML_grayscl
: eColorMode
= ColorMode_GREYS
; break;
436 rPropMap
[ PROP_GraphicColorMode
] <<= eColorMode
;
438 // brightness and contrast
439 sal_Int16 nBrightness
= getLimitedValue
< sal_Int16
, sal_Int32
>( maBlipProps
.moBrightness
.get( 0 ) / 1000, -100, 100 );
440 if( nBrightness
!= 0 )
441 rPropMap
[ PROP_AdjustLuminance
] <<= nBrightness
;
442 sal_Int16 nContrast
= getLimitedValue
< sal_Int16
, sal_Int32
>( maBlipProps
.moContrast
.get( 0 ) / 1000, -100, 100 );
444 rPropMap
[ PROP_AdjustContrast
] <<= nContrast
;
447 void GraphicProperties::pushToPropSet( PropertySet
& rPropSet
, const XmlFilterBase
& rFilter
, sal_Int32 nPhClr
) const
449 PropertyMap aPropMap
;
450 pushToPropMap( aPropMap
, rFilter
, nPhClr
);
451 rPropSet
.setProperties( aPropMap
);
454 // ============================================================================
456 } // namespace drawingml