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