1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "oox/drawingml/color.hxx"
23 #include "oox/helper/containerhelper.hxx"
24 #include "oox/helper/graphichelper.hxx"
25 #include "oox/drawingml/drawingmltypes.hxx"
26 #include "oox/token/namespaces.hxx"
27 #include "oox/token/tokens.hxx"
32 // ============================================================================
36 /** Global storage for predefined color values used in OOXML file formats. */
37 struct PresetColorsPool
39 typedef ::std::vector
< sal_Int32
> ColorVector
;
41 ColorVector maDmlColors
; /// Predefined colors in DrawingML, indexed by XML token.
42 ColorVector maVmlColors
; /// Predefined colors in VML, indexed by XML token.
44 explicit PresetColorsPool();
47 // ----------------------------------------------------------------------------
49 PresetColorsPool::PresetColorsPool() :
50 maDmlColors( static_cast< size_t >( XML_TOKEN_COUNT
), API_RGB_TRANSPARENT
),
51 maVmlColors( static_cast< size_t >( XML_TOKEN_COUNT
), API_RGB_TRANSPARENT
)
53 // predefined colors in DrawingML (map XML token identifiers to RGB values)
54 static const sal_Int32 spnDmlColors
[] =
56 XML_aliceBlue
, 0xF0F8FF, XML_antiqueWhite
, 0xFAEBD7,
57 XML_aqua
, 0x00FFFF, XML_aquamarine
, 0x7FFFD4,
58 XML_azure
, 0xF0FFFF, XML_beige
, 0xF5F5DC,
59 XML_bisque
, 0xFFE4C4, XML_black
, 0x000000,
60 XML_blanchedAlmond
, 0xFFEBCD, XML_blue
, 0x0000FF,
61 XML_blueViolet
, 0x8A2BE2, XML_brown
, 0xA52A2A,
62 XML_burlyWood
, 0xDEB887, XML_cadetBlue
, 0x5F9EA0,
63 XML_chartreuse
, 0x7FFF00, XML_chocolate
, 0xD2691E,
64 XML_coral
, 0xFF7F50, XML_cornflowerBlue
, 0x6495ED,
65 XML_cornsilk
, 0xFFF8DC, XML_crimson
, 0xDC143C,
66 XML_cyan
, 0x00FFFF, XML_deepPink
, 0xFF1493,
67 XML_deepSkyBlue
, 0x00BFFF, XML_dimGray
, 0x696969,
68 XML_dkBlue
, 0x00008B, XML_dkCyan
, 0x008B8B,
69 XML_dkGoldenrod
, 0xB8860B, XML_dkGray
, 0xA9A9A9,
70 XML_dkGreen
, 0x006400, XML_dkKhaki
, 0xBDB76B,
71 XML_dkMagenta
, 0x8B008B, XML_dkOliveGreen
, 0x556B2F,
72 XML_dkOrange
, 0xFF8C00, XML_dkOrchid
, 0x9932CC,
73 XML_dkRed
, 0x8B0000, XML_dkSalmon
, 0xE9967A,
74 XML_dkSeaGreen
, 0x8FBC8B, XML_dkSlateBlue
, 0x483D8B,
75 XML_dkSlateGray
, 0x2F4F4F, XML_dkTurquoise
, 0x00CED1,
76 XML_dkViolet
, 0x9400D3, XML_dodgerBlue
, 0x1E90FF,
77 XML_firebrick
, 0xB22222, XML_floralWhite
, 0xFFFAF0,
78 XML_forestGreen
, 0x228B22, XML_fuchsia
, 0xFF00FF,
79 XML_gainsboro
, 0xDCDCDC, XML_ghostWhite
, 0xF8F8FF,
80 XML_gold
, 0xFFD700, XML_goldenrod
, 0xDAA520,
81 XML_gray
, 0x808080, XML_green
, 0x008000,
82 XML_greenYellow
, 0xADFF2F, XML_honeydew
, 0xF0FFF0,
83 XML_hotPink
, 0xFF69B4, XML_indianRed
, 0xCD5C5C,
84 XML_indigo
, 0x4B0082, XML_ivory
, 0xFFFFF0,
85 XML_khaki
, 0xF0E68C, XML_lavender
, 0xE6E6FA,
86 XML_lavenderBlush
, 0xFFF0F5, XML_lawnGreen
, 0x7CFC00,
87 XML_lemonChiffon
, 0xFFFACD, XML_lime
, 0x00FF00,
88 XML_limeGreen
, 0x32CD32, XML_linen
, 0xFAF0E6,
89 XML_ltBlue
, 0xADD8E6, XML_ltCoral
, 0xF08080,
90 XML_ltCyan
, 0xE0FFFF, XML_ltGoldenrodYellow
, 0xFAFA78,
91 XML_ltGray
, 0xD3D3D3, XML_ltGreen
, 0x90EE90,
92 XML_ltPink
, 0xFFB6C1, XML_ltSalmon
, 0xFFA07A,
93 XML_ltSeaGreen
, 0x20B2AA, XML_ltSkyBlue
, 0x87CEFA,
94 XML_ltSlateGray
, 0x778899, XML_ltSteelBlue
, 0xB0C4DE,
95 XML_ltYellow
, 0xFFFFE0, XML_magenta
, 0xFF00FF,
96 XML_maroon
, 0x800000, XML_medAquamarine
, 0x66CDAA,
97 XML_medBlue
, 0x0000CD, XML_medOrchid
, 0xBA55D3,
98 XML_medPurple
, 0x9370DB, XML_medSeaGreen
, 0x3CB371,
99 XML_medSlateBlue
, 0x7B68EE, XML_medSpringGreen
, 0x00FA9A,
100 XML_medTurquoise
, 0x48D1CC, XML_medVioletRed
, 0xC71585,
101 XML_midnightBlue
, 0x191970, XML_mintCream
, 0xF5FFFA,
102 XML_mistyRose
, 0xFFE4E1, XML_moccasin
, 0xFFE4B5,
103 XML_navajoWhite
, 0xFFDEAD, XML_navy
, 0x000080,
104 XML_oldLace
, 0xFDF5E6, XML_olive
, 0x808000,
105 XML_oliveDrab
, 0x6B8E23, XML_orange
, 0xFFA500,
106 XML_orangeRed
, 0xFF4500, XML_orchid
, 0xDA70D6,
107 XML_paleGoldenrod
, 0xEEE8AA, XML_paleGreen
, 0x98FB98,
108 XML_paleTurquoise
, 0xAFEEEE, XML_paleVioletRed
, 0xDB7093,
109 XML_papayaWhip
, 0xFFEFD5, XML_peachPuff
, 0xFFDAB9,
110 XML_peru
, 0xCD853F, XML_pink
, 0xFFC0CB,
111 XML_plum
, 0xDDA0DD, XML_powderBlue
, 0xB0E0E6,
112 XML_purple
, 0x800080, XML_red
, 0xFF0000,
113 XML_rosyBrown
, 0xBC8F8F, XML_royalBlue
, 0x4169E1,
114 XML_saddleBrown
, 0x8B4513, XML_salmon
, 0xFA8072,
115 XML_sandyBrown
, 0xF4A460, XML_seaGreen
, 0x2E8B57,
116 XML_seaShell
, 0xFFF5EE, XML_sienna
, 0xA0522D,
117 XML_silver
, 0xC0C0C0, XML_skyBlue
, 0x87CEEB,
118 XML_slateBlue
, 0x6A5ACD, XML_slateGray
, 0x708090,
119 XML_snow
, 0xFFFAFA, XML_springGreen
, 0x00FF7F,
120 XML_steelBlue
, 0x4682B4, XML_tan
, 0xD2B48C,
121 XML_teal
, 0x008080, XML_thistle
, 0xD8BFD8,
122 XML_tomato
, 0xFF6347, XML_turquoise
, 0x40E0D0,
123 XML_violet
, 0xEE82EE, XML_wheat
, 0xF5DEB3,
124 XML_white
, 0xFFFFFF, XML_whiteSmoke
, 0xF5F5F5,
125 XML_yellow
, 0xFFFF00, XML_yellowGreen
, 0x9ACD32
127 for( const sal_Int32
* pnEntry
= spnDmlColors
; pnEntry
< STATIC_ARRAY_END( spnDmlColors
); pnEntry
+= 2 )
128 maDmlColors
[ static_cast< size_t >( pnEntry
[ 0 ] ) ] = pnEntry
[ 1 ];
130 // predefined colors in VML (map XML token identifiers to RGB values)
131 static const sal_Int32 spnVmlColors
[] =
133 XML_aqua
, 0x00FFFF, XML_black
, 0x000000,
134 XML_blue
, 0x0000FF, XML_fuchsia
, 0xFF00FF,
135 XML_gray
, 0x808080, XML_green
, 0x008000,
136 XML_lime
, 0x00FF00, XML_maroon
, 0x800000,
137 XML_navy
, 0x000080, XML_olive
, 0x808000,
138 XML_purple
, 0x800080, XML_red
, 0xFF0000,
139 XML_silver
, 0xC0C0C0, XML_teal
, 0x008080,
140 XML_white
, 0xFFFFFF, XML_yellow
, 0xFFFF00
142 for( const sal_Int32
* pnEntry
= spnVmlColors
; pnEntry
< STATIC_ARRAY_END( spnVmlColors
); pnEntry
+= 2 )
143 maVmlColors
[ static_cast< size_t >( pnEntry
[ 0 ] ) ] = pnEntry
[ 1 ];
146 // ----------------------------------------------------------------------------
148 struct StaticPresetColorsPool
: public ::rtl::Static
< PresetColorsPool
, StaticPresetColorsPool
> {};
150 // ----------------------------------------------------------------------------
152 const double DEC_GAMMA
= 2.3;
153 const double INC_GAMMA
= 1.0 / DEC_GAMMA
;
155 // ----------------------------------------------------------------------------
157 inline void lclRgbToRgbComponents( sal_Int32
& ornR
, sal_Int32
& ornG
, sal_Int32
& ornB
, sal_Int32 nRgb
)
159 ornR
= (nRgb
>> 16) & 0xFF;
160 ornG
= (nRgb
>> 8) & 0xFF;
164 inline sal_Int32
lclRgbComponentsToRgb( sal_Int32 nR
, sal_Int32 nG
, sal_Int32 nB
)
166 return static_cast< sal_Int32
>( (nR
<< 16) | (nG
<< 8) | nB
);
169 inline sal_Int32
lclRgbCompToCrgbComp( sal_Int32 nRgbComp
)
171 return static_cast< sal_Int32
>( nRgbComp
* MAX_PERCENT
/ 255 );
174 inline sal_Int32
lclCrgbCompToRgbComp( sal_Int32 nCrgbComp
)
176 return static_cast< sal_Int32
>( nCrgbComp
* 255 / MAX_PERCENT
);
179 inline sal_Int32
lclGamma( sal_Int32 nComp
, double fGamma
)
181 return static_cast< sal_Int32
>( pow( static_cast< double >( nComp
) / MAX_PERCENT
, fGamma
) * MAX_PERCENT
+ 0.5 );
184 void lclSetValue( sal_Int32
& ornValue
, sal_Int32 nNew
, sal_Int32 nMax
= MAX_PERCENT
)
186 OSL_ENSURE( (0 <= nNew
) && (nNew
<= nMax
), "lclSetValue - invalid value" );
187 if( (0 <= nNew
) && (nNew
<= nMax
) )
191 void lclModValue( sal_Int32
& ornValue
, sal_Int32 nMod
, sal_Int32 nMax
= MAX_PERCENT
)
193 OSL_ENSURE( (0 <= nMod
), "lclModValue - invalid modificator" );
194 ornValue
= getLimitedValue
< sal_Int32
, double >( static_cast< double >( ornValue
) * nMod
/ MAX_PERCENT
, 0, nMax
);
197 void lclOffValue( sal_Int32
& ornValue
, sal_Int32 nOff
, sal_Int32 nMax
= MAX_PERCENT
)
199 OSL_ENSURE( (-nMax
<= nOff
) && (nOff
<= nMax
), "lclOffValue - invalid offset" );
200 ornValue
= getLimitedValue
< sal_Int32
, sal_Int32
>( ornValue
+ nOff
, 0, nMax
);
205 // ============================================================================
208 meMode( COLOR_UNUSED
),
212 mnAlpha( MAX_PERCENT
)
220 sal_Int32
Color::getDmlPresetColor( sal_Int32 nToken
, sal_Int32 nDefaultRgb
)
222 /* Do not pass nDefaultRgb to ContainerHelper::getVectorElement(), to be
223 able to catch the existing vector entries without corresponding XML
225 sal_Int32 nRgbValue
= ContainerHelper::getVectorElement( StaticPresetColorsPool::get().maDmlColors
, nToken
, API_RGB_TRANSPARENT
);
226 return (nRgbValue
>= 0) ? nRgbValue
: nDefaultRgb
;
229 sal_Int32
Color::getVmlPresetColor( sal_Int32 nToken
, sal_Int32 nDefaultRgb
)
231 /* Do not pass nDefaultRgb to ContainerHelper::getVectorElement(), to be
232 able to catch the existing vector entries without corresponding XML
234 sal_Int32 nRgbValue
= ContainerHelper::getVectorElement( StaticPresetColorsPool::get().maVmlColors
, nToken
, API_RGB_TRANSPARENT
);
235 return (nRgbValue
>= 0) ? nRgbValue
: nDefaultRgb
;
238 void Color::setUnused()
240 meMode
= COLOR_UNUSED
;
243 void Color::setSrgbClr( sal_Int32 nRgb
)
245 OSL_ENSURE( (0 <= nRgb
) && (nRgb
<= 0xFFFFFF), "Color::setSrgbClr - invalid RGB value" );
247 lclRgbToRgbComponents( mnC1
, mnC2
, mnC3
, nRgb
);
250 void Color::setScrgbClr( sal_Int32 nR
, sal_Int32 nG
, sal_Int32 nB
)
252 OSL_ENSURE( (0 <= nR
) && (nR
<= MAX_PERCENT
), "Color::setScrgbClr - invalid red value" );
253 OSL_ENSURE( (0 <= nG
) && (nG
<= MAX_PERCENT
), "Color::setScrgbClr - invalid green value" );
254 OSL_ENSURE( (0 <= nB
) && (nB
<= MAX_PERCENT
), "Color::setScrgbClr - invalid blue value" );
256 mnC1
= getLimitedValue
< sal_Int32
, sal_Int32
>( nR
, 0, MAX_PERCENT
);
257 mnC2
= getLimitedValue
< sal_Int32
, sal_Int32
>( nG
, 0, MAX_PERCENT
);
258 mnC3
= getLimitedValue
< sal_Int32
, sal_Int32
>( nB
, 0, MAX_PERCENT
);
261 void Color::setHslClr( sal_Int32 nHue
, sal_Int32 nSat
, sal_Int32 nLum
)
263 OSL_ENSURE( (0 <= nHue
) && (nHue
<= MAX_DEGREE
), "Color::setHslClr - invalid hue value" );
264 OSL_ENSURE( (0 <= nSat
) && (nSat
<= MAX_PERCENT
), "Color::setHslClr - invalid saturation value" );
265 OSL_ENSURE( (0 <= nLum
) && (nLum
<= MAX_PERCENT
), "Color::setHslClr - invalid luminance value" );
267 mnC1
= getLimitedValue
< sal_Int32
, sal_Int32
>( nHue
, 0, MAX_DEGREE
);
268 mnC2
= getLimitedValue
< sal_Int32
, sal_Int32
>( nSat
, 0, MAX_PERCENT
);
269 mnC3
= getLimitedValue
< sal_Int32
, sal_Int32
>( nLum
, 0, MAX_PERCENT
);
272 void Color::setPrstClr( sal_Int32 nToken
)
274 sal_Int32 nRgbValue
= getDmlPresetColor( nToken
, API_RGB_TRANSPARENT
);
275 OSL_ENSURE( nRgbValue
>= 0, "Color::setPrstClr - invalid preset color token" );
277 setSrgbClr( nRgbValue
);
280 void Color::setSchemeClr( sal_Int32 nToken
)
282 OSL_ENSURE( nToken
!= XML_TOKEN_INVALID
, "Color::setSchemeClr - invalid color token" );
283 meMode
= (nToken
== XML_phClr
) ? COLOR_PH
: COLOR_SCHEME
;
287 void Color::setPaletteClr( sal_Int32 nPaletteIdx
)
289 OSL_ENSURE( nPaletteIdx
>= 0, "Color::setPaletteClr - invalid palette index" );
290 meMode
= COLOR_PALETTE
;
294 void Color::setSysClr( sal_Int32 nToken
, sal_Int32 nLastRgb
)
296 OSL_ENSURE( (-1 <= nLastRgb
) && (nLastRgb
<= 0xFFFFFF), "Color::setSysClr - invalid RGB value" );
297 meMode
= COLOR_SYSTEM
;
302 void Color::addTransformation( sal_Int32 nElement
, sal_Int32 nValue
)
304 /* Execute alpha transformations directly, store other transformations in
305 a vector, they may depend on a scheme base color which will be resolved
306 in Color::getColor(). */
307 sal_Int32 nToken
= getBaseToken( nElement
);
310 case XML_alpha
: lclSetValue( mnAlpha
, nValue
); break;
311 case XML_alphaMod
: lclModValue( mnAlpha
, nValue
); break;
312 case XML_alphaOff
: lclOffValue( mnAlpha
, nValue
); break;
313 default: maTransforms
.push_back( Transformation( nToken
, nValue
) );
317 void Color::addChartTintTransformation( double fTint
)
319 sal_Int32 nValue
= getLimitedValue
< sal_Int32
, double >( fTint
* MAX_PERCENT
+ 0.5, -MAX_PERCENT
, MAX_PERCENT
);
321 maTransforms
.push_back( Transformation( XML_shade
, nValue
+ MAX_PERCENT
) );
322 else if( nValue
> 0 )
323 maTransforms
.push_back( Transformation( XML_tint
, MAX_PERCENT
- nValue
) );
326 void Color::addExcelTintTransformation( double fTint
)
328 sal_Int32 nValue
= getLimitedValue
< sal_Int32
, double >( fTint
* MAX_PERCENT
+ 0.5, -MAX_PERCENT
, MAX_PERCENT
);
329 maTransforms
.push_back( Transformation( XLS_TOKEN( tint
), nValue
) );
332 void Color::clearTransformations()
334 maTransforms
.clear();
338 void Color::clearTransparence()
340 mnAlpha
= MAX_PERCENT
;
343 sal_Int32
Color::getColor( const GraphicHelper
& rGraphicHelper
, sal_Int32 nPhClr
) const
345 /* Special handling for theme style list placeholder colors (state
346 COLOR_PH), Color::getColor() may be called with different placeholder
347 colors in the nPhClr parameter. Therefore, the resolved color will not
348 be stored in this object, thus the state COLOR_FINAL will not be
349 reached and the transformation container will not be cleared, but the
350 original COLOR_PH state will be restored instead. */
355 case COLOR_UNUSED
: mnC1
= API_RGB_TRANSPARENT
; break;
357 case COLOR_RGB
: break; // nothing to do
358 case COLOR_CRGB
: break; // nothing to do
359 case COLOR_HSL
: break; // nothing to do
361 case COLOR_SCHEME
: setResolvedRgb( rGraphicHelper
.getSchemeColor( mnC1
) ); break;
362 case COLOR_PALETTE
: setResolvedRgb( rGraphicHelper
.getPaletteColor( mnC1
) ); break;
363 case COLOR_SYSTEM
: setResolvedRgb( rGraphicHelper
.getSystemColor( mnC1
, mnC2
) ); break;
364 case COLOR_PH
: setResolvedRgb( nPhClr
); bIsPh
= true; break;
366 case COLOR_FINAL
: return mnC1
;
369 // if color is UNUSED or turns to UNUSED in setResolvedRgb, do not perform transformations
370 if( meMode
!= COLOR_UNUSED
)
372 for( TransformVec::const_iterator aIt
= maTransforms
.begin(), aEnd
= maTransforms
.end(); aIt
!= aEnd
; ++aIt
)
374 OSL_ASSERT((aIt
->mnToken
& sal_Int32(0xFFFF0000))==0);
375 switch( aIt
->mnToken
)
377 case XML_red
: toCrgb(); lclSetValue( mnC1
, aIt
->mnValue
); break;
378 case XML_redMod
: toCrgb(); lclModValue( mnC1
, aIt
->mnValue
); break;
379 case XML_redOff
: toCrgb(); lclOffValue( mnC1
, aIt
->mnValue
); break;
380 case XML_green
: toCrgb(); lclSetValue( mnC2
, aIt
->mnValue
); break;
381 case XML_greenMod
: toCrgb(); lclModValue( mnC2
, aIt
->mnValue
); break;
382 case XML_greenOff
: toCrgb(); lclOffValue( mnC2
, aIt
->mnValue
); break;
383 case XML_blue
: toCrgb(); lclSetValue( mnC3
, aIt
->mnValue
); break;
384 case XML_blueMod
: toCrgb(); lclModValue( mnC3
, aIt
->mnValue
); break;
385 case XML_blueOff
: toCrgb(); lclOffValue( mnC3
, aIt
->mnValue
); break;
387 case XML_hue
: toHsl(); lclSetValue( mnC1
, aIt
->mnValue
, MAX_DEGREE
); break;
388 case XML_hueMod
: toHsl(); lclModValue( mnC1
, aIt
->mnValue
, MAX_DEGREE
); break;
389 case XML_hueOff
: toHsl(); lclOffValue( mnC1
, aIt
->mnValue
, MAX_DEGREE
); break;
390 case XML_sat
: toHsl(); lclSetValue( mnC2
, aIt
->mnValue
); break;
391 case XML_satMod
: toHsl(); lclModValue( mnC2
, aIt
->mnValue
); break;
392 case XML_satOff
: toHsl(); lclOffValue( mnC2
, aIt
->mnValue
); break;
396 lclSetValue( mnC3
, aIt
->mnValue
);
397 // if color changes to black or white, it will stay gray if luminance changes again
398 if( (mnC3
== 0) || (mnC3
== MAX_PERCENT
) ) mnC2
= 0;
402 lclModValue( mnC3
, aIt
->mnValue
);
403 // if color changes to black or white, it will stay gray if luminance changes again
404 if( (mnC3
== 0) || (mnC3
== MAX_PERCENT
) ) mnC2
= 0;
408 lclOffValue( mnC3
, aIt
->mnValue
);
409 // if color changes to black or white, it will stay gray if luminance changes again
410 if( (mnC3
== 0) || (mnC3
== MAX_PERCENT
) ) mnC2
= 0;
414 // shade: 0% = black, 100% = original color
416 OSL_ENSURE( (0 <= aIt
->mnValue
) && (aIt
->mnValue
<= MAX_PERCENT
), "Color::getColor - invalid shade value" );
417 if( (0 <= aIt
->mnValue
) && (aIt
->mnValue
<= MAX_PERCENT
) )
419 double fFactor
= static_cast< double >( aIt
->mnValue
) / MAX_PERCENT
;
420 mnC1
= static_cast< sal_Int32
>( mnC1
* fFactor
);
421 mnC2
= static_cast< sal_Int32
>( mnC2
* fFactor
);
422 mnC3
= static_cast< sal_Int32
>( mnC3
* fFactor
);
426 // tint: 0% = white, 100% = original color
428 OSL_ENSURE( (0 <= aIt
->mnValue
) && (aIt
->mnValue
<= MAX_PERCENT
), "Color::getColor - invalid tint value" );
429 if( (0 <= aIt
->mnValue
) && (aIt
->mnValue
<= MAX_PERCENT
) )
431 double fFactor
= static_cast< double >( aIt
->mnValue
) / MAX_PERCENT
;
432 mnC1
= static_cast< sal_Int32
>( MAX_PERCENT
- (MAX_PERCENT
- mnC1
) * fFactor
);
433 mnC2
= static_cast< sal_Int32
>( MAX_PERCENT
- (MAX_PERCENT
- mnC2
) * fFactor
);
434 mnC3
= static_cast< sal_Int32
>( MAX_PERCENT
- (MAX_PERCENT
- mnC3
) * fFactor
);
437 case XLS_TOKEN( tint
):
438 // Excel tint: move luminance relative to current value
440 OSL_ENSURE( (-MAX_PERCENT
<= aIt
->mnValue
) && (aIt
->mnValue
<= MAX_PERCENT
), "Color::getColor - invalid tint value" );
441 if( (-MAX_PERCENT
<= aIt
->mnValue
) && (aIt
->mnValue
< 0) )
443 // negative: luminance towards 0% (black)
444 lclModValue( mnC3
, aIt
->mnValue
+ MAX_PERCENT
);
446 else if( (0 < aIt
->mnValue
) && (aIt
->mnValue
<= MAX_PERCENT
) )
448 // positive: luminance towards 100% (white)
449 mnC3
= MAX_PERCENT
- mnC3
;
450 lclModValue( mnC3
, MAX_PERCENT
- aIt
->mnValue
);
451 mnC3
= MAX_PERCENT
- mnC3
;
456 // change color to gray, weighted RGB: 22% red, 72% green, 6% blue
458 mnC1
= mnC2
= mnC3
= (mnC1
* 22 + mnC2
* 72 + mnC3
* 6) / 100;
462 // comp: rotate hue by 180 degrees, do not change lum/sat
464 (mnC1
+= 180 * PER_DEGREE
) %= MAX_DEGREE
;
467 // invert percentual RGB values
469 mnC1
= MAX_PERCENT
- mnC1
;
470 mnC2
= MAX_PERCENT
- mnC2
;
471 mnC3
= MAX_PERCENT
- mnC3
;
475 // increase gamma of color
477 mnC1
= lclGamma( mnC1
, INC_GAMMA
);
478 mnC2
= lclGamma( mnC2
, INC_GAMMA
);
479 mnC3
= lclGamma( mnC3
, INC_GAMMA
);
482 // decrease gamma of color
484 mnC1
= lclGamma( mnC1
, DEC_GAMMA
);
485 mnC2
= lclGamma( mnC2
, DEC_GAMMA
);
486 mnC3
= lclGamma( mnC3
, DEC_GAMMA
);
491 // store resulting RGB value in mnC1
493 mnC1
= lclRgbComponentsToRgb( mnC1
, mnC2
, mnC3
);
495 else // if( meMode != COLOR_UNUSED )
497 mnC1
= API_RGB_TRANSPARENT
;
500 meMode
= bIsPh
? COLOR_PH
: COLOR_FINAL
;
501 if( meMode
== COLOR_FINAL
)
502 maTransforms
.clear();
506 bool Color::hasTransparency() const
508 return mnAlpha
< MAX_PERCENT
;
511 sal_Int16
Color::getTransparency() const
513 return static_cast< sal_Int16
>( (MAX_PERCENT
- mnAlpha
) / PER_PERCENT
);
516 // private --------------------------------------------------------------------
518 void Color::setResolvedRgb( sal_Int32 nRgb
) const
520 meMode
= (nRgb
< 0) ? COLOR_UNUSED
: COLOR_RGB
;
521 lclRgbToRgbComponents( mnC1
, mnC2
, mnC3
, nRgb
);
524 void Color::toRgb() const
533 mnC1
= lclCrgbCompToRgbComp( lclGamma( mnC1
, INC_GAMMA
) );
534 mnC2
= lclCrgbCompToRgbComp( lclGamma( mnC2
, INC_GAMMA
) );
535 mnC3
= lclCrgbCompToRgbComp( lclGamma( mnC3
, INC_GAMMA
) );
540 double fR
= 0.0, fG
= 0.0, fB
= 0.0;
541 if( (mnC2
== 0) || (mnC3
== MAX_PERCENT
) )
543 fR
= fG
= fB
= static_cast< double >( mnC3
) / MAX_PERCENT
;
547 // base color from hue
548 double fHue
= static_cast< double >( mnC1
) / MAX_DEGREE
* 6.0; // interval [0.0, 6.0)
549 if( fHue
<= 1.0 ) { fR
= 1.0; fG
= fHue
; } // red...yellow
550 else if( fHue
<= 2.0 ) { fR
= 2.0 - fHue
; fG
= 1.0; } // yellow...green
551 else if( fHue
<= 3.0 ) { fG
= 1.0; fB
= fHue
- 2.0; } // green...cyan
552 else if( fHue
<= 4.0 ) { fG
= 4.0 - fHue
; fB
= 1.0; } // cyan...blue
553 else if( fHue
<= 5.0 ) { fR
= fHue
- 4.0; fB
= 1.0; } // blue...magenta
554 else { fR
= 1.0; fB
= 6.0 - fHue
; } // magenta...red
557 double fSat
= static_cast< double >( mnC2
) / MAX_PERCENT
;
558 fR
= (fR
- 0.5) * fSat
+ 0.5;
559 fG
= (fG
- 0.5) * fSat
+ 0.5;
560 fB
= (fB
- 0.5) * fSat
+ 0.5;
563 double fLum
= 2.0 * static_cast< double >( mnC3
) / MAX_PERCENT
- 1.0; // interval [-1.0, 1.0]
566 double fShade
= fLum
+ 1.0; // interval [0.0, 1.0] (black...full color)
571 else if( fLum
> 0.0 )
573 double fTint
= 1.0 - fLum
; // interval [0.0, 1.0] (white...full color)
574 fR
= 1.0 - ((1.0 - fR
) * fTint
);
575 fG
= 1.0 - ((1.0 - fG
) * fTint
);
576 fB
= 1.0 - ((1.0 - fB
) * fTint
);
579 mnC1
= static_cast< sal_Int32
>( fR
* 255.0 + 0.5 );
580 mnC2
= static_cast< sal_Int32
>( fG
* 255.0 + 0.5 );
581 mnC3
= static_cast< sal_Int32
>( fB
* 255.0 + 0.5 );
585 OSL_FAIL( "Color::toRgb - unexpected color mode" );
589 void Color::toCrgb() const
598 mnC1
= lclGamma( lclRgbCompToCrgbComp( mnC1
), DEC_GAMMA
);
599 mnC2
= lclGamma( lclRgbCompToCrgbComp( mnC2
), DEC_GAMMA
);
600 mnC3
= lclGamma( lclRgbCompToCrgbComp( mnC3
), DEC_GAMMA
);
606 OSL_FAIL( "Color::toCrgb - unexpected color mode" );
610 void Color::toHsl() const
620 double fR
= static_cast< double >( mnC1
) / 255.0; // red [0.0, 1.0]
621 double fG
= static_cast< double >( mnC2
) / 255.0; // green [0.0, 1.0]
622 double fB
= static_cast< double >( mnC3
) / 255.0; // blue [0.0, 1.0]
623 double fMin
= ::std::min( ::std::min( fR
, fG
), fB
);
624 double fMax
= ::std::max( ::std::max( fR
, fG
), fB
);
625 double fD
= fMax
- fMin
;
627 using ::rtl::math::approxEqual
;
629 // hue: 0deg = red, 120deg = green, 240deg = blue
630 if( fD
== 0.0 ) // black/gray/white
632 else if( approxEqual(fMax
, fR
, 64) ) // magenta...red...yellow
633 mnC1
= static_cast< sal_Int32
>( ((fG
- fB
) / fD
* 60.0 + 360.0) * PER_DEGREE
+ 0.5 ) % MAX_DEGREE
;
634 else if( approxEqual(fMax
, fG
, 64) ) // yellow...green...cyan
635 mnC1
= static_cast< sal_Int32
>( ((fB
- fR
) / fD
* 60.0 + 120.0) * PER_DEGREE
+ 0.5 );
636 else // cyan...blue...magenta
637 mnC1
= static_cast< sal_Int32
>( ((fR
- fG
) / fD
* 60.0 + 240.0) * PER_DEGREE
+ 0.5 );
639 // luminance: 0% = black, 50% = full color, 100% = white
640 mnC3
= static_cast< sal_Int32
>( (fMin
+ fMax
) / 2.0 * MAX_PERCENT
+ 0.5 );
642 // saturation: 0% = gray, 100% = full color
643 if( (mnC3
== 0) || (mnC3
== MAX_PERCENT
) ) // black/white
645 else if( mnC3
<= 50 * PER_PERCENT
) // dark...full color
646 mnC2
= static_cast< sal_Int32
>( fD
/ (fMin
+ fMax
) * MAX_PERCENT
+ 0.5 );
647 else // full color...light
648 mnC2
= static_cast< sal_Int32
>( fD
/ (2.0 - fMax
- fMin
) * MAX_PERCENT
+ 0.5 );
655 OSL_FAIL( "Color::toHsl - unexpected color mode" );
659 // ============================================================================
661 } // namespace drawingml
664 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */