xref: /AOO41X/main/oox/source/drawingml/color.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
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/color.hxx"
29 #include <algorithm>
30 #include <math.h>
31 #include "oox/helper/containerhelper.hxx"
32 #include "oox/helper/graphichelper.hxx"
33 #include "oox/drawingml/drawingmltypes.hxx"
34 #include "oox/token/namespaces.hxx"
35 #include "oox/token/tokens.hxx"
36 
37 using ::rtl::OUString;
38 
39 namespace oox {
40 namespace drawingml {
41 
42 // ============================================================================
43 
44 namespace {
45 
46 /** Global storage for predefined color values used in OOXML file formats. */
47 struct PresetColorsPool
48 {
49     typedef ::std::vector< sal_Int32 > ColorVector;
50 
51     ColorVector         maDmlColors;        /// Predefined colors in DrawingML, indexed by XML token.
52     ColorVector         maVmlColors;        /// Predefined colors in VML, indexed by XML token.
53 
54     explicit            PresetColorsPool();
55 };
56 
57 // ----------------------------------------------------------------------------
58 
59 PresetColorsPool::PresetColorsPool() :
60     maDmlColors( static_cast< size_t >( XML_TOKEN_COUNT ), API_RGB_TRANSPARENT ),
61     maVmlColors( static_cast< size_t >( XML_TOKEN_COUNT ), API_RGB_TRANSPARENT )
62 {
63     // predefined colors in DrawingML (map XML token identifiers to RGB values)
64     static const sal_Int32 spnDmlColors[] =
65     {
66         XML_aliceBlue,         0xF0F8FF,    XML_antiqueWhite,      0xFAEBD7,
67         XML_aqua,              0x00FFFF,    XML_aquamarine,        0x7FFFD4,
68         XML_azure,             0xF0FFFF,    XML_beige,             0xF5F5DC,
69         XML_bisque,            0xFFE4C4,    XML_black,             0x000000,
70         XML_blanchedAlmond,    0xFFEBCD,    XML_blue,              0x0000FF,
71         XML_blueViolet,        0x8A2BE2,    XML_brown,             0xA52A2A,
72         XML_burlyWood,         0xDEB887,    XML_cadetBlue,         0x5F9EA0,
73         XML_chartreuse,        0x7FFF00,    XML_chocolate,         0xD2691E,
74         XML_coral,             0xFF7F50,    XML_cornflowerBlue,    0x6495ED,
75         XML_cornsilk,          0xFFF8DC,    XML_crimson,           0xDC143C,
76         XML_cyan,              0x00FFFF,    XML_deepPink,          0xFF1493,
77         XML_deepSkyBlue,       0x00BFFF,    XML_dimGray,           0x696969,
78         XML_dkBlue,            0x00008B,    XML_dkCyan,            0x008B8B,
79         XML_dkGoldenrod,       0xB8860B,    XML_dkGray,            0xA9A9A9,
80         XML_dkGreen,           0x006400,    XML_dkKhaki,           0xBDB76B,
81         XML_dkMagenta,         0x8B008B,    XML_dkOliveGreen,      0x556B2F,
82         XML_dkOrange,          0xFF8C00,    XML_dkOrchid,          0x9932CC,
83         XML_dkRed,             0x8B0000,    XML_dkSalmon,          0xE9967A,
84         XML_dkSeaGreen,        0x8FBC8B,    XML_dkSlateBlue,       0x483D8B,
85         XML_dkSlateGray,       0x2F4F4F,    XML_dkTurquoise,       0x00CED1,
86         XML_dkViolet,          0x9400D3,    XML_dodgerBlue,        0x1E90FF,
87         XML_firebrick,         0xB22222,    XML_floralWhite,       0xFFFAF0,
88         XML_forestGreen,       0x228B22,    XML_fuchsia,           0xFF00FF,
89         XML_gainsboro,         0xDCDCDC,    XML_ghostWhite,        0xF8F8FF,
90         XML_gold,              0xFFD700,    XML_goldenrod,         0xDAA520,
91         XML_gray,              0x808080,    XML_green,             0x008000,
92         XML_greenYellow,       0xADFF2F,    XML_honeydew,          0xF0FFF0,
93         XML_hotPink,           0xFF69B4,    XML_indianRed,         0xCD5C5C,
94         XML_indigo,            0x4B0082,    XML_ivory,             0xFFFFF0,
95         XML_khaki,             0xF0E68C,    XML_lavender,          0xE6E6FA,
96         XML_lavenderBlush,     0xFFF0F5,    XML_lawnGreen,         0x7CFC00,
97         XML_lemonChiffon,      0xFFFACD,    XML_lime,              0x00FF00,
98         XML_limeGreen,         0x32CD32,    XML_linen,             0xFAF0E6,
99         XML_ltBlue,            0xADD8E6,    XML_ltCoral,           0xF08080,
100         XML_ltCyan,            0xE0FFFF,    XML_ltGoldenrodYellow, 0xFAFA78,
101         XML_ltGray,            0xD3D3D3,    XML_ltGreen,           0x90EE90,
102         XML_ltPink,            0xFFB6C1,    XML_ltSalmon,          0xFFA07A,
103         XML_ltSeaGreen,        0x20B2AA,    XML_ltSkyBlue,         0x87CEFA,
104         XML_ltSlateGray,       0x778899,    XML_ltSteelBlue,       0xB0C4DE,
105         XML_ltYellow,          0xFFFFE0,    XML_magenta,           0xFF00FF,
106         XML_maroon,            0x800000,    XML_medAquamarine,     0x66CDAA,
107         XML_medBlue,           0x0000CD,    XML_medOrchid,         0xBA55D3,
108         XML_medPurple,         0x9370DB,    XML_medSeaGreen,       0x3CB371,
109         XML_medSlateBlue,      0x7B68EE,    XML_medSpringGreen,    0x00FA9A,
110         XML_medTurquoise,      0x48D1CC,    XML_medVioletRed,      0xC71585,
111         XML_midnightBlue,      0x191970,    XML_mintCream,         0xF5FFFA,
112         XML_mistyRose,         0xFFE4E1,    XML_moccasin,          0xFFE4B5,
113         XML_navajoWhite,       0xFFDEAD,    XML_navy,              0x000080,
114         XML_oldLace,           0xFDF5E6,    XML_olive,             0x808000,
115         XML_oliveDrab,         0x6B8E23,    XML_orange,            0xFFA500,
116         XML_orangeRed,         0xFF4500,    XML_orchid,            0xDA70D6,
117         XML_paleGoldenrod,     0xEEE8AA,    XML_paleGreen,         0x98FB98,
118         XML_paleTurquoise,     0xAFEEEE,    XML_paleVioletRed,     0xDB7093,
119         XML_papayaWhip,        0xFFEFD5,    XML_peachPuff,         0xFFDAB9,
120         XML_peru,              0xCD853F,    XML_pink,              0xFFC0CB,
121         XML_plum,              0xDDA0DD,    XML_powderBlue,        0xB0E0E6,
122         XML_purple,            0x800080,    XML_red,               0xFF0000,
123         XML_rosyBrown,         0xBC8F8F,    XML_royalBlue,         0x4169E1,
124         XML_saddleBrown,       0x8B4513,    XML_salmon,            0xFA8072,
125         XML_sandyBrown,        0xF4A460,    XML_seaGreen,          0x2E8B57,
126         XML_seaShell,          0xFFF5EE,    XML_sienna,            0xA0522D,
127         XML_silver,            0xC0C0C0,    XML_skyBlue,           0x87CEEB,
128         XML_slateBlue,         0x6A5ACD,    XML_slateGray,         0x708090,
129         XML_snow,              0xFFFAFA,    XML_springGreen,       0x00FF7F,
130         XML_steelBlue,         0x4682B4,    XML_tan,               0xD2B48C,
131         XML_teal,              0x008080,    XML_thistle,           0xD8BFD8,
132         XML_tomato,            0xFF6347,    XML_turquoise,         0x40E0D0,
133         XML_violet,            0xEE82EE,    XML_wheat,             0xF5DEB3,
134         XML_white,             0xFFFFFF,    XML_whiteSmoke,        0xF5F5F5,
135         XML_yellow,            0xFFFF00,    XML_yellowGreen,       0x9ACD32
136     };
137     for( const sal_Int32* pnEntry = spnDmlColors; pnEntry < STATIC_ARRAY_END( spnDmlColors ); pnEntry += 2 )
138         maDmlColors[ static_cast< size_t >( pnEntry[ 0 ] ) ] = pnEntry[ 1 ];
139 
140     // predefined colors in VML (map XML token identifiers to RGB values)
141     static const sal_Int32 spnVmlColors[] =
142     {
143         XML_aqua,              0x00FFFF,    XML_black,             0x000000,
144         XML_blue,              0x0000FF,    XML_fuchsia,           0xFF00FF,
145         XML_gray,              0x808080,    XML_green,             0x008000,
146         XML_lime,              0x00FF00,    XML_maroon,            0x800000,
147         XML_navy,              0x000080,    XML_olive,             0x808000,
148         XML_purple,            0x800080,    XML_red,               0xFF0000,
149         XML_silver,            0xC0C0C0,    XML_teal,              0x008080,
150         XML_white,             0xFFFFFF,    XML_yellow,            0xFFFF00
151     };
152     for( const sal_Int32* pnEntry = spnVmlColors; pnEntry < STATIC_ARRAY_END( spnVmlColors ); pnEntry += 2 )
153         maVmlColors[ static_cast< size_t >( pnEntry[ 0 ] ) ] = pnEntry[ 1 ];
154 }
155 
156 // ----------------------------------------------------------------------------
157 
158 struct StaticPresetColorsPool : public ::rtl::Static< PresetColorsPool, StaticPresetColorsPool > {};
159 
160 // ----------------------------------------------------------------------------
161 
162 const double DEC_GAMMA          = 2.3;
163 const double INC_GAMMA          = 1.0 / DEC_GAMMA;
164 
165 // ----------------------------------------------------------------------------
166 
167 inline void lclRgbToRgbComponents( sal_Int32& ornR, sal_Int32& ornG, sal_Int32& ornB, sal_Int32 nRgb )
168 {
169     ornR = (nRgb >> 16) & 0xFF;
170     ornG = (nRgb >> 8) & 0xFF;
171     ornB = nRgb & 0xFF;
172 }
173 
174 inline sal_Int32 lclRgbComponentsToRgb( sal_Int32 nR, sal_Int32 nG, sal_Int32 nB )
175 {
176     return static_cast< sal_Int32 >( (nR << 16) | (nG << 8) | nB );
177 }
178 
179 inline sal_Int32 lclRgbCompToCrgbComp( sal_Int32 nRgbComp )
180 {
181     return static_cast< sal_Int32 >( nRgbComp * MAX_PERCENT / 255 );
182 }
183 
184 inline sal_Int32 lclCrgbCompToRgbComp( sal_Int32 nCrgbComp )
185 {
186     return static_cast< sal_Int32 >( nCrgbComp * 255 / MAX_PERCENT );
187 }
188 
189 inline sal_Int32 lclGamma( sal_Int32 nComp, double fGamma )
190 {
191     return static_cast< sal_Int32 >( pow( static_cast< double >( nComp ) / MAX_PERCENT, fGamma ) * MAX_PERCENT + 0.5 );
192 }
193 
194 void lclSetValue( sal_Int32& ornValue, sal_Int32 nNew, sal_Int32 nMax = MAX_PERCENT )
195 {
196     OSL_ENSURE( (0 <= nNew) && (nNew <= nMax), "lclSetValue - invalid value" );
197     if( (0 <= nNew) && (nNew <= nMax) )
198         ornValue = nNew;
199 }
200 
201 void lclModValue( sal_Int32& ornValue, sal_Int32 nMod, sal_Int32 nMax = MAX_PERCENT )
202 {
203     OSL_ENSURE( (0 <= nMod), "lclModValue - invalid modificator" );
204     ornValue = getLimitedValue< sal_Int32, double >( static_cast< double >( ornValue ) * nMod / MAX_PERCENT, 0, nMax );
205 }
206 
207 void lclOffValue( sal_Int32& ornValue, sal_Int32 nOff, sal_Int32 nMax = MAX_PERCENT )
208 {
209     OSL_ENSURE( (-nMax <= nOff) && (nOff <= nMax), "lclOffValue - invalid offset" );
210     ornValue = getLimitedValue< sal_Int32, sal_Int32 >( ornValue + nOff, 0, nMax );
211 }
212 
213 } // namespace
214 
215 // ============================================================================
216 
217 Color::Color() :
218     meMode( COLOR_UNUSED ),
219     mnC1( 0 ),
220     mnC2( 0 ),
221     mnC3( 0 ),
222     mnAlpha( MAX_PERCENT )
223 {
224 }
225 
226 Color::~Color()
227 {
228 }
229 
230 /*static*/ sal_Int32 Color::getDmlPresetColor( sal_Int32 nToken, sal_Int32 nDefaultRgb )
231 {
232     /*  Do not pass nDefaultRgb to ContainerHelper::getVectorElement(), to be
233         able to catch the existing vector entries without corresponding XML
234         token identifier. */
235     sal_Int32 nRgbValue = ContainerHelper::getVectorElement( StaticPresetColorsPool::get().maDmlColors, nToken, API_RGB_TRANSPARENT );
236     return (nRgbValue >= 0) ? nRgbValue : nDefaultRgb;
237 }
238 
239 /*static*/ sal_Int32 Color::getVmlPresetColor( sal_Int32 nToken, sal_Int32 nDefaultRgb )
240 {
241     /*  Do not pass nDefaultRgb to ContainerHelper::getVectorElement(), to be
242         able to catch the existing vector entries without corresponding XML
243         token identifier. */
244     sal_Int32 nRgbValue = ContainerHelper::getVectorElement( StaticPresetColorsPool::get().maVmlColors, nToken, API_RGB_TRANSPARENT );
245     return (nRgbValue >= 0) ? nRgbValue : nDefaultRgb;
246 }
247 
248 void Color::setUnused()
249 {
250     meMode = COLOR_UNUSED;
251 }
252 
253 void Color::setSrgbClr( sal_Int32 nRgb )
254 {
255     OSL_ENSURE( (0 <= nRgb) && (nRgb <= 0xFFFFFF), "Color::setSrgbClr - invalid RGB value" );
256     meMode = COLOR_RGB;
257     lclRgbToRgbComponents( mnC1, mnC2, mnC3, nRgb );
258 }
259 
260 void Color::setScrgbClr( sal_Int32 nR, sal_Int32 nG, sal_Int32 nB )
261 {
262     OSL_ENSURE( (0 <= nR) && (nR <= MAX_PERCENT), "Color::setScrgbClr - invalid red value" );
263     OSL_ENSURE( (0 <= nG) && (nG <= MAX_PERCENT), "Color::setScrgbClr - invalid green value" );
264     OSL_ENSURE( (0 <= nB) && (nB <= MAX_PERCENT), "Color::setScrgbClr - invalid blue value" );
265     meMode = COLOR_CRGB;
266     mnC1 = getLimitedValue< sal_Int32, sal_Int32 >( nR, 0, MAX_PERCENT );
267     mnC2 = getLimitedValue< sal_Int32, sal_Int32 >( nG, 0, MAX_PERCENT );
268     mnC3 = getLimitedValue< sal_Int32, sal_Int32 >( nB, 0, MAX_PERCENT );
269 }
270 
271 void Color::setHslClr( sal_Int32 nHue, sal_Int32 nSat, sal_Int32 nLum )
272 {
273     OSL_ENSURE( (0 <= nHue) && (nHue <= MAX_DEGREE), "Color::setHslClr - invalid hue value" );
274     OSL_ENSURE( (0 <= nSat) && (nSat <= MAX_PERCENT), "Color::setHslClr - invalid saturation value" );
275     OSL_ENSURE( (0 <= nLum) && (nLum <= MAX_PERCENT), "Color::setHslClr - invalid luminance value" );
276     meMode = COLOR_HSL;
277     mnC1 = getLimitedValue< sal_Int32, sal_Int32 >( nHue, 0, MAX_DEGREE );
278     mnC2 = getLimitedValue< sal_Int32, sal_Int32 >( nSat, 0, MAX_PERCENT );
279     mnC3 = getLimitedValue< sal_Int32, sal_Int32 >( nLum, 0, MAX_PERCENT );
280 }
281 
282 void Color::setPrstClr( sal_Int32 nToken )
283 {
284     sal_Int32 nRgbValue = getDmlPresetColor( nToken, API_RGB_TRANSPARENT );
285     OSL_ENSURE( nRgbValue >= 0, "Color::setPrstClr - invalid preset color token" );
286     if( nRgbValue >= 0 )
287         setSrgbClr( nRgbValue );
288 }
289 
290 void Color::setSchemeClr( sal_Int32 nToken )
291 {
292     OSL_ENSURE( nToken != XML_TOKEN_INVALID, "Color::setSchemeClr - invalid color token" );
293     meMode = (nToken == XML_phClr) ? COLOR_PH : COLOR_SCHEME;
294     mnC1 = nToken;
295 }
296 
297 void Color::setPaletteClr( sal_Int32 nPaletteIdx )
298 {
299     OSL_ENSURE( nPaletteIdx >= 0, "Color::setPaletteClr - invalid palette index" );
300     meMode = COLOR_PALETTE;
301     mnC1 = nPaletteIdx;
302 }
303 
304 void Color::setSysClr( sal_Int32 nToken, sal_Int32 nLastRgb )
305 {
306     OSL_ENSURE( (-1 <= nLastRgb) && (nLastRgb <= 0xFFFFFF), "Color::setSysClr - invalid RGB value" );
307     meMode = COLOR_SYSTEM;
308     mnC1 = nToken;
309     mnC2 = nLastRgb;
310 }
311 
312 void Color::addTransformation( sal_Int32 nElement, sal_Int32 nValue )
313 {
314     /*  Execute alpha transformations directly, store other transformations in
315         a vector, they may depend on a scheme base color which will be resolved
316         in Color::getColor(). */
317     sal_Int32 nToken = getBaseToken( nElement );
318     switch( nToken )
319     {
320         case XML_alpha:     lclSetValue( mnAlpha, nValue ); break;
321         case XML_alphaMod:  lclModValue( mnAlpha, nValue ); break;
322         case XML_alphaOff:  lclOffValue( mnAlpha, nValue ); break;
323         default:            maTransforms.push_back( Transformation( nToken, nValue ) );
324     }
325 }
326 
327 void Color::addChartTintTransformation( double fTint )
328 {
329     sal_Int32 nValue = getLimitedValue< sal_Int32, double >( fTint * MAX_PERCENT + 0.5, -MAX_PERCENT, MAX_PERCENT );
330     if( nValue < 0 )
331         maTransforms.push_back( Transformation( XML_shade, nValue + MAX_PERCENT ) );
332     else if( nValue > 0 )
333         maTransforms.push_back( Transformation( XML_tint, MAX_PERCENT - nValue ) );
334 }
335 
336 void Color::addExcelTintTransformation( double fTint )
337 {
338     sal_Int32 nValue = getLimitedValue< sal_Int32, double >( fTint * MAX_PERCENT + 0.5, -MAX_PERCENT, MAX_PERCENT );
339     maTransforms.push_back( Transformation( XLS_TOKEN( tint ), nValue ) );
340 }
341 
342 void Color::clearTransformations()
343 {
344     maTransforms.clear();
345     clearTransparence();
346 }
347 
348 void Color::clearTransparence()
349 {
350     mnAlpha = MAX_PERCENT;
351 }
352 
353 sal_Int32 Color::getColor( const GraphicHelper& rGraphicHelper, sal_Int32 nPhClr ) const
354 {
355     /*  Special handling for theme style list placeholder colors (state
356         COLOR_PH), Color::getColor() may be called with different placeholder
357         colors in the nPhClr parameter. Therefore, the resolved color will not
358         be stored in this object, thus the state COLOR_FINAL will not be
359         reached and the transformation container will not be cleared, but the
360         original COLOR_PH state will be restored instead. */
361     bool bIsPh = false;
362 
363     switch( meMode )
364     {
365         case COLOR_UNUSED:  mnC1 = API_RGB_TRANSPARENT; break;
366 
367         case COLOR_RGB:     break;  // nothing to do
368         case COLOR_CRGB:    break;  // nothing to do
369         case COLOR_HSL:     break;  // nothing to do
370 
371         case COLOR_SCHEME:  setResolvedRgb( rGraphicHelper.getSchemeColor( mnC1 ) );        break;
372         case COLOR_PALETTE: setResolvedRgb( rGraphicHelper.getPaletteColor( mnC1 ) );       break;
373         case COLOR_SYSTEM:  setResolvedRgb( rGraphicHelper.getSystemColor( mnC1, mnC2 ) );  break;
374         case COLOR_PH:      setResolvedRgb( nPhClr ); bIsPh = true;                         break;
375 
376         case COLOR_FINAL:   return mnC1;
377     }
378 
379     // if color is UNUSED or turns to UNUSED in setResolvedRgb, do not perform transformations
380     if( meMode != COLOR_UNUSED )
381     {
382         for( TransformVec::const_iterator aIt = maTransforms.begin(), aEnd = maTransforms.end(); aIt != aEnd; ++aIt )
383         {
384             switch( aIt->mnToken )
385             {
386                 case XML_red:       toCrgb(); lclSetValue( mnC1, aIt->mnValue );    break;
387                 case XML_redMod:    toCrgb(); lclModValue( mnC1, aIt->mnValue );    break;
388                 case XML_redOff:    toCrgb(); lclOffValue( mnC1, aIt->mnValue );    break;
389                 case XML_green:     toCrgb(); lclSetValue( mnC2, aIt->mnValue );    break;
390                 case XML_greenMod:  toCrgb(); lclModValue( mnC2, aIt->mnValue );    break;
391                 case XML_greenOff:  toCrgb(); lclOffValue( mnC2, aIt->mnValue );    break;
392                 case XML_blue:      toCrgb(); lclSetValue( mnC3, aIt->mnValue );    break;
393                 case XML_blueMod:   toCrgb(); lclModValue( mnC3, aIt->mnValue );    break;
394                 case XML_blueOff:   toCrgb(); lclOffValue( mnC3, aIt->mnValue );    break;
395 
396                 case XML_hue:       toHsl(); lclSetValue( mnC1, aIt->mnValue, MAX_DEGREE ); break;
397                 case XML_hueMod:    toHsl(); lclModValue( mnC1, aIt->mnValue, MAX_DEGREE ); break;
398                 case XML_hueOff:    toHsl(); lclOffValue( mnC1, aIt->mnValue, MAX_DEGREE ); break;
399                 case XML_sat:       toHsl(); lclSetValue( mnC2, aIt->mnValue );             break;
400                 case XML_satMod:    toHsl(); lclModValue( mnC2, aIt->mnValue );             break;
401                 case XML_satOff:    toHsl(); lclOffValue( mnC2, aIt->mnValue );             break;
402 
403                 case XML_lum:
404                     toHsl();
405                     lclSetValue( mnC3, aIt->mnValue );
406                     // if color changes to black or white, it will stay gray if luminance changes again
407                     if( (mnC3 == 0) || (mnC3 == MAX_PERCENT) ) mnC2 = 0;
408                 break;
409                 case XML_lumMod:
410                     toHsl();
411                     lclModValue( mnC3, aIt->mnValue );
412                     // if color changes to black or white, it will stay gray if luminance changes again
413                     if( (mnC3 == 0) || (mnC3 == MAX_PERCENT) ) mnC2 = 0;
414                 break;
415                 case XML_lumOff:
416                     toHsl();
417                     lclOffValue( mnC3, aIt->mnValue );
418                     // if color changes to black or white, it will stay gray if luminance changes again
419                     if( (mnC3 == 0) || (mnC3 == MAX_PERCENT) ) mnC2 = 0;
420                 break;
421 
422                 case XML_shade:
423                     // shade: 0% = black, 100% = original color
424                     toCrgb();
425                     OSL_ENSURE( (0 <= aIt->mnValue) && (aIt->mnValue <= MAX_PERCENT), "Color::getColor - invalid shade value" );
426                     if( (0 <= aIt->mnValue) && (aIt->mnValue <= MAX_PERCENT) )
427                     {
428                         double fFactor = static_cast< double >( aIt->mnValue ) / MAX_PERCENT;
429                         mnC1 = static_cast< sal_Int32 >( mnC1 * fFactor );
430                         mnC2 = static_cast< sal_Int32 >( mnC2 * fFactor );
431                         mnC3 = static_cast< sal_Int32 >( mnC3 * fFactor );
432                     }
433                 break;
434                 case XML_tint:
435                     // tint: 0% = white, 100% = original color
436                     toCrgb();
437                     OSL_ENSURE( (0 <= aIt->mnValue) && (aIt->mnValue <= MAX_PERCENT), "Color::getColor - invalid tint value" );
438                     if( (0 <= aIt->mnValue) && (aIt->mnValue <= MAX_PERCENT) )
439                     {
440                         double fFactor = static_cast< double >( aIt->mnValue ) / MAX_PERCENT;
441                         mnC1 = static_cast< sal_Int32 >( MAX_PERCENT - (MAX_PERCENT - mnC1) * fFactor );
442                         mnC2 = static_cast< sal_Int32 >( MAX_PERCENT - (MAX_PERCENT - mnC2) * fFactor );
443                         mnC3 = static_cast< sal_Int32 >( MAX_PERCENT - (MAX_PERCENT - mnC3) * fFactor );
444                     }
445                 break;
446                 case XLS_TOKEN( tint ):
447                     // Excel tint: move luminance relative to current value
448                     toHsl();
449                     OSL_ENSURE( (-MAX_PERCENT <= aIt->mnValue) && (aIt->mnValue <= MAX_PERCENT), "Color::getColor - invalid tint value" );
450                     if( (-MAX_PERCENT <= aIt->mnValue) && (aIt->mnValue < 0) )
451                     {
452                         // negative: luminance towards 0% (black)
453                         lclModValue( mnC3, aIt->mnValue + MAX_PERCENT );
454                     }
455                     else if( (0 < aIt->mnValue) && (aIt->mnValue <= MAX_PERCENT) )
456                     {
457                         // positive: luminance towards 100% (white)
458                         mnC3 = MAX_PERCENT - mnC3;
459                         lclModValue( mnC3, MAX_PERCENT - aIt->mnValue );
460                         mnC3 = MAX_PERCENT - mnC3;
461                     }
462                 break;
463 
464                 case XML_gray:
465                     // change color to gray, weighted RGB: 22% red, 72% green, 6% blue
466                     toRgb();
467                     mnC1 = mnC2 = mnC3 = (mnC1 * 22 + mnC2 * 72 + mnC3 * 6) / 100;
468                 break;
469 
470                 case XML_comp:
471                     // comp: rotate hue by 180 degrees, do not change lum/sat
472                     toHsl();
473                     (mnC1 += 180 * PER_DEGREE) %= MAX_DEGREE;
474                 break;
475                 case XML_inv:
476                     // invert percentual RGB values
477                     toCrgb();
478                     mnC1 = MAX_PERCENT - mnC1;
479                     mnC2 = MAX_PERCENT - mnC2;
480                     mnC3 = MAX_PERCENT - mnC3;
481                 break;
482 
483                 case XML_gamma:
484                     // increase gamma of color
485                     toCrgb();
486                     mnC1 = lclGamma( mnC1, INC_GAMMA );
487                     mnC2 = lclGamma( mnC2, INC_GAMMA );
488                     mnC3 = lclGamma( mnC3, INC_GAMMA );
489                 break;
490                 case XML_invGamma:
491                     // decrease gamma of color
492                     toCrgb();
493                     mnC1 = lclGamma( mnC1, DEC_GAMMA );
494                     mnC2 = lclGamma( mnC2, DEC_GAMMA );
495                     mnC3 = lclGamma( mnC3, DEC_GAMMA );
496                 break;
497             }
498         }
499 
500         // store resulting RGB value in mnC1
501         toRgb();
502         mnC1 = lclRgbComponentsToRgb( mnC1, mnC2, mnC3 );
503     }
504     else // if( meMode != COLOR_UNUSED )
505     {
506         mnC1 = API_RGB_TRANSPARENT;
507     }
508 
509     meMode = bIsPh ? COLOR_PH : COLOR_FINAL;
510     if( meMode == COLOR_FINAL )
511         maTransforms.clear();
512     return mnC1;
513 }
514 
515 bool Color::hasTransparency() const
516 {
517     return mnAlpha < MAX_PERCENT;
518 }
519 
520 sal_Int16 Color::getTransparency() const
521 {
522     return static_cast< sal_Int16 >( (MAX_PERCENT - mnAlpha) / PER_PERCENT );
523 }
524 
525 // private --------------------------------------------------------------------
526 
527 void Color::setResolvedRgb( sal_Int32 nRgb ) const
528 {
529     meMode = (nRgb < 0) ? COLOR_UNUSED : COLOR_RGB;
530     lclRgbToRgbComponents( mnC1, mnC2, mnC3, nRgb );
531 }
532 
533 void Color::toRgb() const
534 {
535     switch( meMode )
536     {
537         case COLOR_RGB:
538             // nothing to do
539         break;
540         case COLOR_CRGB:
541             meMode = COLOR_RGB;
542             mnC1 = lclCrgbCompToRgbComp( lclGamma( mnC1, INC_GAMMA ) );
543             mnC2 = lclCrgbCompToRgbComp( lclGamma( mnC2, INC_GAMMA ) );
544             mnC3 = lclCrgbCompToRgbComp( lclGamma( mnC3, INC_GAMMA ) );
545         break;
546         case COLOR_HSL:
547         {
548             meMode = COLOR_RGB;
549             double fR = 0.0, fG = 0.0, fB = 0.0;
550             if( (mnC2 == 0) || (mnC3 == MAX_PERCENT) )
551             {
552                 fR = fG = fB = static_cast< double >( mnC3 ) / MAX_PERCENT;
553             }
554             else if( mnC3 > 0 )
555             {
556                 // base color from hue
557                 double fHue = static_cast< double >( mnC1 ) / MAX_DEGREE * 6.0; // interval [0.0, 6.0)
558                 if( fHue <= 1.0 )       { fR = 1.0; fG = fHue; }        // red...yellow
559                 else if( fHue <= 2.0 )  { fR = 2.0 - fHue; fG = 1.0; }  // yellow...green
560                 else if( fHue <= 3.0 )  { fG = 1.0; fB = fHue - 2.0; }  // green...cyan
561                 else if( fHue <= 4.0 )  { fG = 4.0 - fHue; fB = 1.0; }  // cyan...blue
562                 else if( fHue <= 5.0 )  { fR = fHue - 4.0; fB = 1.0; }  // blue...magenta
563                 else                    { fR = 1.0; fB = 6.0 - fHue; }  // magenta...red
564 
565                 // apply saturation
566                 double fSat = static_cast< double >( mnC2 ) / MAX_PERCENT;
567                 fR = (fR - 0.5) * fSat + 0.5;
568                 fG = (fG - 0.5) * fSat + 0.5;
569                 fB = (fB - 0.5) * fSat + 0.5;
570 
571                 // apply luminance
572                 double fLum = 2.0 * static_cast< double >( mnC3 ) / MAX_PERCENT - 1.0;  // interval [-1.0, 1.0]
573                 if( fLum < 0.0 )
574                 {
575                     double fShade = fLum + 1.0; // interval [0.0, 1.0] (black...full color)
576                     fR *= fShade;
577                     fG *= fShade;
578                     fB *= fShade;
579                 }
580                 else if( fLum > 0.0 )
581                 {
582                     double fTint = 1.0 - fLum;  // interval [0.0, 1.0] (white...full color)
583                     fR = 1.0 - ((1.0 - fR) * fTint);
584                     fG = 1.0 - ((1.0 - fG) * fTint);
585                     fB = 1.0 - ((1.0 - fB) * fTint);
586                 }
587             }
588             mnC1 = static_cast< sal_Int32 >( fR * 255.0 + 0.5 );
589             mnC2 = static_cast< sal_Int32 >( fG * 255.0 + 0.5 );
590             mnC3 = static_cast< sal_Int32 >( fB * 255.0 + 0.5 );
591         }
592         break;
593         default:
594             OSL_ENSURE( false, "Color::toRgb - unexpected color mode" );
595     }
596 }
597 
598 void Color::toCrgb() const
599 {
600     switch( meMode )
601     {
602         case COLOR_HSL:
603             toRgb();
604             // run through!
605         case COLOR_RGB:
606             meMode = COLOR_CRGB;
607             mnC1 = lclGamma( lclRgbCompToCrgbComp( mnC1 ), DEC_GAMMA );
608             mnC2 = lclGamma( lclRgbCompToCrgbComp( mnC2 ), DEC_GAMMA );
609             mnC3 = lclGamma( lclRgbCompToCrgbComp( mnC3 ), DEC_GAMMA );
610         break;
611         case COLOR_CRGB:
612             // nothing to do
613         break;
614         default:
615             OSL_ENSURE( false, "Color::toCrgb - unexpected color mode" );
616     }
617 }
618 
619 void Color::toHsl() const
620 {
621     switch( meMode )
622     {
623         case COLOR_CRGB:
624             toRgb();
625             // run through!
626         case COLOR_RGB:
627         {
628             meMode = COLOR_HSL;
629             double fR = static_cast< double >( mnC1 ) / 255.0;  // red [0.0, 1.0]
630             double fG = static_cast< double >( mnC2 ) / 255.0;  // green [0.0, 1.0]
631             double fB = static_cast< double >( mnC3 ) / 255.0;  // blue [0.0, 1.0]
632             double fMin = ::std::min( ::std::min( fR, fG ), fB );
633             double fMax = ::std::max( ::std::max( fR, fG ), fB );
634             double fD = fMax - fMin;
635 
636             // hue: 0deg = red, 120deg = green, 240deg = blue
637             if( fD == 0.0 )         // black/gray/white
638                 mnC1 = 0;
639             else if( fMax == fR )   // magenta...red...yellow
640                 mnC1 = static_cast< sal_Int32 >( ((fG - fB) / fD * 60.0 + 360.0) * PER_DEGREE + 0.5 ) % MAX_DEGREE;
641             else if( fMax == fG )   // yellow...green...cyan
642                 mnC1 = static_cast< sal_Int32 >( ((fB - fR) / fD * 60.0 + 120.0) * PER_DEGREE + 0.5 );
643             else                    // cyan...blue...magenta
644                 mnC1 = static_cast< sal_Int32 >( ((fR - fG) / fD * 60.0 + 240.0) * PER_DEGREE + 0.5 );
645 
646             // luminance: 0% = black, 50% = full color, 100% = white
647             mnC3 = static_cast< sal_Int32 >( (fMin + fMax) / 2.0 * MAX_PERCENT + 0.5 );
648 
649             // saturation: 0% = gray, 100% = full color
650             if( (mnC3 == 0) || (mnC3 == MAX_PERCENT) )  // black/white
651                 mnC2 = 0;
652             else if( mnC3 <= 50 * PER_PERCENT )         // dark...full color
653                 mnC2 = static_cast< sal_Int32 >( fD / (fMin + fMax) * MAX_PERCENT + 0.5 );
654             else                                        // full color...light
655                 mnC2 = static_cast< sal_Int32 >( fD / (2.0 - fMax - fMin) * MAX_PERCENT + 0.5 );
656         }
657         break;
658         case COLOR_HSL:
659             // nothing to do
660         break;
661         default:
662             OSL_ENSURE( false, "Color::toHsl - unexpected color mode" );
663     }
664 }
665 
666 // ============================================================================
667 
668 } // namespace drawingml
669 } // namespace oox
670 
671