Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include "oox/drawingml/color.hxx"
21 : #include <algorithm>
22 : #include <math.h>
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"
28 :
29 : namespace oox {
30 : namespace drawingml {
31 :
32 : // ============================================================================
33 :
34 : namespace {
35 :
36 : /** Global storage for predefined color values used in OOXML file formats. */
37 4 : struct PresetColorsPool
38 : {
39 : typedef ::std::vector< sal_Int32 > ColorVector;
40 :
41 : ColorVector maDmlColors; /// Predefined colors in DrawingML, indexed by XML token.
42 : ColorVector maVmlColors; /// Predefined colors in VML, indexed by XML token.
43 :
44 : explicit PresetColorsPool();
45 : };
46 :
47 : // ----------------------------------------------------------------------------
48 :
49 4 : PresetColorsPool::PresetColorsPool() :
50 : maDmlColors( static_cast< size_t >( XML_TOKEN_COUNT ), API_RGB_TRANSPARENT ),
51 4 : maVmlColors( static_cast< size_t >( XML_TOKEN_COUNT ), API_RGB_TRANSPARENT )
52 : {
53 : // predefined colors in DrawingML (map XML token identifiers to RGB values)
54 : static const sal_Int32 spnDmlColors[] =
55 : {
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
126 : };
127 564 : for( const sal_Int32* pnEntry = spnDmlColors; pnEntry < STATIC_ARRAY_END( spnDmlColors ); pnEntry += 2 )
128 560 : maDmlColors[ static_cast< size_t >( pnEntry[ 0 ] ) ] = pnEntry[ 1 ];
129 :
130 : // predefined colors in VML (map XML token identifiers to RGB values)
131 : static const sal_Int32 spnVmlColors[] =
132 : {
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
141 : };
142 68 : for( const sal_Int32* pnEntry = spnVmlColors; pnEntry < STATIC_ARRAY_END( spnVmlColors ); pnEntry += 2 )
143 64 : maVmlColors[ static_cast< size_t >( pnEntry[ 0 ] ) ] = pnEntry[ 1 ];
144 4 : }
145 :
146 : // ----------------------------------------------------------------------------
147 :
148 : struct StaticPresetColorsPool : public ::rtl::Static< PresetColorsPool, StaticPresetColorsPool > {};
149 :
150 : // ----------------------------------------------------------------------------
151 :
152 : const double DEC_GAMMA = 2.3;
153 : const double INC_GAMMA = 1.0 / DEC_GAMMA;
154 :
155 : // ----------------------------------------------------------------------------
156 :
157 1095 : inline void lclRgbToRgbComponents( sal_Int32& ornR, sal_Int32& ornG, sal_Int32& ornB, sal_Int32 nRgb )
158 : {
159 1095 : ornR = (nRgb >> 16) & 0xFF;
160 1095 : ornG = (nRgb >> 8) & 0xFF;
161 1095 : ornB = nRgb & 0xFF;
162 1095 : }
163 :
164 954 : inline sal_Int32 lclRgbComponentsToRgb( sal_Int32 nR, sal_Int32 nG, sal_Int32 nB )
165 : {
166 954 : return static_cast< sal_Int32 >( (nR << 16) | (nG << 8) | nB );
167 : }
168 :
169 192 : inline sal_Int32 lclRgbCompToCrgbComp( sal_Int32 nRgbComp )
170 : {
171 192 : return static_cast< sal_Int32 >( nRgbComp * MAX_PERCENT / 255 );
172 : }
173 :
174 216 : inline sal_Int32 lclCrgbCompToRgbComp( sal_Int32 nCrgbComp )
175 : {
176 216 : return static_cast< sal_Int32 >( nCrgbComp * 255 / MAX_PERCENT );
177 : }
178 :
179 408 : inline sal_Int32 lclGamma( sal_Int32 nComp, double fGamma )
180 : {
181 408 : return static_cast< sal_Int32 >( pow( static_cast< double >( nComp ) / MAX_PERCENT, fGamma ) * MAX_PERCENT + 0.5 );
182 : }
183 :
184 66 : void lclSetValue( sal_Int32& ornValue, sal_Int32 nNew, sal_Int32 nMax = MAX_PERCENT )
185 : {
186 : OSL_ENSURE( (0 <= nNew) && (nNew <= nMax), "lclSetValue - invalid value" );
187 66 : if( (0 <= nNew) && (nNew <= nMax) )
188 66 : ornValue = nNew;
189 66 : }
190 :
191 7 : void lclModValue( sal_Int32& ornValue, sal_Int32 nMod, sal_Int32 nMax = MAX_PERCENT )
192 : {
193 : OSL_ENSURE( (0 <= nMod), "lclModValue - invalid modificator" );
194 7 : ornValue = getLimitedValue< sal_Int32, double >( static_cast< double >( ornValue ) * nMod / MAX_PERCENT, 0, nMax );
195 7 : }
196 :
197 29 : void lclOffValue( sal_Int32& ornValue, sal_Int32 nOff, sal_Int32 nMax = MAX_PERCENT )
198 : {
199 : OSL_ENSURE( (-nMax <= nOff) && (nOff <= nMax), "lclOffValue - invalid offset" );
200 29 : ornValue = getLimitedValue< sal_Int32, sal_Int32 >( ornValue + nOff, 0, nMax );
201 29 : }
202 :
203 : } // namespace
204 :
205 : // ============================================================================
206 :
207 85783 : Color::Color() :
208 : meMode( COLOR_UNUSED ),
209 : mnC1( 0 ),
210 : mnC2( 0 ),
211 : mnC3( 0 ),
212 85783 : mnAlpha( MAX_PERCENT )
213 : {
214 85783 : }
215 :
216 86820 : Color::~Color()
217 : {
218 86820 : }
219 :
220 3 : sal_Int32 Color::getDmlPresetColor( sal_Int32 nToken, sal_Int32 nDefaultRgb )
221 : {
222 : /* Do not pass nDefaultRgb to ContainerHelper::getVectorElement(), to be
223 : able to catch the existing vector entries without corresponding XML
224 : token identifier. */
225 3 : sal_Int32 nRgbValue = ContainerHelper::getVectorElement( StaticPresetColorsPool::get().maDmlColors, nToken, API_RGB_TRANSPARENT );
226 3 : return (nRgbValue >= 0) ? nRgbValue : nDefaultRgb;
227 : }
228 :
229 10 : sal_Int32 Color::getVmlPresetColor( sal_Int32 nToken, sal_Int32 nDefaultRgb )
230 : {
231 : /* Do not pass nDefaultRgb to ContainerHelper::getVectorElement(), to be
232 : able to catch the existing vector entries without corresponding XML
233 : token identifier. */
234 10 : sal_Int32 nRgbValue = ContainerHelper::getVectorElement( StaticPresetColorsPool::get().maVmlColors, nToken, API_RGB_TRANSPARENT );
235 10 : return (nRgbValue >= 0) ? nRgbValue : nDefaultRgb;
236 : }
237 :
238 0 : void Color::setUnused()
239 : {
240 0 : meMode = COLOR_UNUSED;
241 0 : }
242 :
243 421 : void Color::setSrgbClr( sal_Int32 nRgb )
244 : {
245 : OSL_ENSURE( (0 <= nRgb) && (nRgb <= 0xFFFFFF), "Color::setSrgbClr - invalid RGB value" );
246 421 : meMode = COLOR_RGB;
247 421 : lclRgbToRgbComponents( mnC1, mnC2, mnC3, nRgb );
248 421 : }
249 :
250 12 : void Color::setScrgbClr( sal_Int32 nR, sal_Int32 nG, sal_Int32 nB )
251 : {
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" );
255 12 : meMode = COLOR_CRGB;
256 12 : mnC1 = getLimitedValue< sal_Int32, sal_Int32 >( nR, 0, MAX_PERCENT );
257 12 : mnC2 = getLimitedValue< sal_Int32, sal_Int32 >( nG, 0, MAX_PERCENT );
258 12 : mnC3 = getLimitedValue< sal_Int32, sal_Int32 >( nB, 0, MAX_PERCENT );
259 12 : }
260 :
261 0 : void Color::setHslClr( sal_Int32 nHue, sal_Int32 nSat, sal_Int32 nLum )
262 : {
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" );
266 0 : meMode = COLOR_HSL;
267 0 : mnC1 = getLimitedValue< sal_Int32, sal_Int32 >( nHue, 0, MAX_DEGREE );
268 0 : mnC2 = getLimitedValue< sal_Int32, sal_Int32 >( nSat, 0, MAX_PERCENT );
269 0 : mnC3 = getLimitedValue< sal_Int32, sal_Int32 >( nLum, 0, MAX_PERCENT );
270 0 : }
271 :
272 3 : void Color::setPrstClr( sal_Int32 nToken )
273 : {
274 3 : sal_Int32 nRgbValue = getDmlPresetColor( nToken, API_RGB_TRANSPARENT );
275 : OSL_ENSURE( nRgbValue >= 0, "Color::setPrstClr - invalid preset color token" );
276 3 : if( nRgbValue >= 0 )
277 3 : setSrgbClr( nRgbValue );
278 3 : }
279 :
280 1022 : void Color::setSchemeClr( sal_Int32 nToken )
281 : {
282 : OSL_ENSURE( nToken != XML_TOKEN_INVALID, "Color::setSchemeClr - invalid color token" );
283 1022 : meMode = (nToken == XML_phClr) ? COLOR_PH : COLOR_SCHEME;
284 1022 : mnC1 = nToken;
285 1022 : }
286 :
287 319 : void Color::setPaletteClr( sal_Int32 nPaletteIdx )
288 : {
289 : OSL_ENSURE( nPaletteIdx >= 0, "Color::setPaletteClr - invalid palette index" );
290 319 : meMode = COLOR_PALETTE;
291 319 : mnC1 = nPaletteIdx;
292 319 : }
293 :
294 26 : void Color::setSysClr( sal_Int32 nToken, sal_Int32 nLastRgb )
295 : {
296 : OSL_ENSURE( (-1 <= nLastRgb) && (nLastRgb <= 0xFFFFFF), "Color::setSysClr - invalid RGB value" );
297 26 : meMode = COLOR_SYSTEM;
298 26 : mnC1 = nToken;
299 26 : mnC2 = nLastRgb;
300 26 : }
301 :
302 600 : void Color::addTransformation( sal_Int32 nElement, sal_Int32 nValue )
303 : {
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 600 : sal_Int32 nToken = getBaseToken( nElement );
308 600 : switch( nToken )
309 : {
310 66 : case XML_alpha: lclSetValue( mnAlpha, nValue ); break;
311 0 : case XML_alphaMod: lclModValue( mnAlpha, nValue ); break;
312 7 : case XML_alphaOff: lclOffValue( mnAlpha, nValue ); break;
313 527 : default: maTransforms.push_back( Transformation( nToken, nValue ) );
314 : }
315 600 : }
316 :
317 0 : void Color::addChartTintTransformation( double fTint )
318 : {
319 0 : sal_Int32 nValue = getLimitedValue< sal_Int32, double >( fTint * MAX_PERCENT + 0.5, -MAX_PERCENT, MAX_PERCENT );
320 0 : if( nValue < 0 )
321 0 : maTransforms.push_back( Transformation( XML_shade, nValue + MAX_PERCENT ) );
322 0 : else if( nValue > 0 )
323 0 : maTransforms.push_back( Transformation( XML_tint, MAX_PERCENT - nValue ) );
324 0 : }
325 :
326 0 : void Color::addExcelTintTransformation( double fTint )
327 : {
328 0 : sal_Int32 nValue = getLimitedValue< sal_Int32, double >( fTint * MAX_PERCENT + 0.5, -MAX_PERCENT, MAX_PERCENT );
329 0 : maTransforms.push_back( Transformation( XLS_TOKEN( tint ), nValue ) );
330 0 : }
331 :
332 342 : void Color::clearTransformations()
333 : {
334 342 : maTransforms.clear();
335 342 : clearTransparence();
336 342 : }
337 :
338 342 : void Color::clearTransparence()
339 : {
340 342 : mnAlpha = MAX_PERCENT;
341 342 : }
342 :
343 1300 : sal_Int32 Color::getColor( const GraphicHelper& rGraphicHelper, sal_Int32 nPhClr ) const
344 : {
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. */
351 1300 : bool bIsPh = false;
352 :
353 1300 : switch( meMode )
354 : {
355 99 : case COLOR_UNUSED: mnC1 = API_RGB_TRANSPARENT; break;
356 :
357 358 : case COLOR_RGB: break; // nothing to do
358 8 : case COLOR_CRGB: break; // nothing to do
359 0 : case COLOR_HSL: break; // nothing to do
360 :
361 439 : case COLOR_SCHEME: setResolvedRgb( rGraphicHelper.getSchemeColor( mnC1 ) ); break;
362 146 : case COLOR_PALETTE: setResolvedRgb( rGraphicHelper.getPaletteColor( mnC1 ) ); break;
363 26 : case COLOR_SYSTEM: setResolvedRgb( rGraphicHelper.getSystemColor( mnC1, mnC2 ) ); break;
364 63 : case COLOR_PH: setResolvedRgb( nPhClr ); bIsPh = true; break;
365 :
366 161 : case COLOR_FINAL: return mnC1;
367 : }
368 :
369 : // if color is UNUSED or turns to UNUSED in setResolvedRgb, do not perform transformations
370 1139 : if( meMode != COLOR_UNUSED )
371 : {
372 1047 : for( TransformVec::const_iterator aIt = maTransforms.begin(), aEnd = maTransforms.end(); aIt != aEnd; ++aIt )
373 : {
374 : OSL_ASSERT((aIt->mnToken & sal_Int32(0xFFFF0000))==0);
375 93 : switch( aIt->mnToken )
376 : {
377 0 : case XML_red: toCrgb(); lclSetValue( mnC1, aIt->mnValue ); break;
378 0 : case XML_redMod: toCrgb(); lclModValue( mnC1, aIt->mnValue ); break;
379 0 : case XML_redOff: toCrgb(); lclOffValue( mnC1, aIt->mnValue ); break;
380 0 : case XML_green: toCrgb(); lclSetValue( mnC2, aIt->mnValue ); break;
381 0 : case XML_greenMod: toCrgb(); lclModValue( mnC2, aIt->mnValue ); break;
382 0 : case XML_greenOff: toCrgb(); lclOffValue( mnC2, aIt->mnValue ); break;
383 0 : case XML_blue: toCrgb(); lclSetValue( mnC3, aIt->mnValue ); break;
384 0 : case XML_blueMod: toCrgb(); lclModValue( mnC3, aIt->mnValue ); break;
385 0 : case XML_blueOff: toCrgb(); lclOffValue( mnC3, aIt->mnValue ); break;
386 :
387 0 : case XML_hue: toHsl(); lclSetValue( mnC1, aIt->mnValue, MAX_DEGREE ); break;
388 0 : case XML_hueMod: toHsl(); lclModValue( mnC1, aIt->mnValue, MAX_DEGREE ); break;
389 7 : case XML_hueOff: toHsl(); lclOffValue( mnC1, aIt->mnValue, MAX_DEGREE ); break;
390 0 : case XML_sat: toHsl(); lclSetValue( mnC2, aIt->mnValue ); break;
391 5 : case XML_satMod: toHsl(); lclModValue( mnC2, aIt->mnValue ); break;
392 7 : case XML_satOff: toHsl(); lclOffValue( mnC2, aIt->mnValue ); break;
393 :
394 : case XML_lum:
395 0 : toHsl();
396 0 : lclSetValue( mnC3, aIt->mnValue );
397 : // if color changes to black or white, it will stay gray if luminance changes again
398 0 : if( (mnC3 == 0) || (mnC3 == MAX_PERCENT) ) mnC2 = 0;
399 0 : break;
400 : case XML_lumMod:
401 2 : toHsl();
402 2 : lclModValue( mnC3, aIt->mnValue );
403 : // if color changes to black or white, it will stay gray if luminance changes again
404 2 : if( (mnC3 == 0) || (mnC3 == MAX_PERCENT) ) mnC2 = 0;
405 2 : break;
406 : case XML_lumOff:
407 8 : toHsl();
408 8 : lclOffValue( mnC3, aIt->mnValue );
409 : // if color changes to black or white, it will stay gray if luminance changes again
410 8 : if( (mnC3 == 0) || (mnC3 == MAX_PERCENT) ) mnC2 = 0;
411 8 : break;
412 :
413 : case XML_shade:
414 : // shade: 0% = black, 100% = original color
415 55 : toCrgb();
416 : OSL_ENSURE( (0 <= aIt->mnValue) && (aIt->mnValue <= MAX_PERCENT), "Color::getColor - invalid shade value" );
417 55 : if( (0 <= aIt->mnValue) && (aIt->mnValue <= MAX_PERCENT) )
418 : {
419 55 : double fFactor = static_cast< double >( aIt->mnValue ) / MAX_PERCENT;
420 55 : mnC1 = static_cast< sal_Int32 >( mnC1 * fFactor );
421 55 : mnC2 = static_cast< sal_Int32 >( mnC2 * fFactor );
422 55 : mnC3 = static_cast< sal_Int32 >( mnC3 * fFactor );
423 : }
424 55 : break;
425 : case XML_tint:
426 : // tint: 0% = white, 100% = original color
427 9 : toCrgb();
428 : OSL_ENSURE( (0 <= aIt->mnValue) && (aIt->mnValue <= MAX_PERCENT), "Color::getColor - invalid tint value" );
429 9 : if( (0 <= aIt->mnValue) && (aIt->mnValue <= MAX_PERCENT) )
430 : {
431 9 : double fFactor = static_cast< double >( aIt->mnValue ) / MAX_PERCENT;
432 9 : mnC1 = static_cast< sal_Int32 >( MAX_PERCENT - (MAX_PERCENT - mnC1) * fFactor );
433 9 : mnC2 = static_cast< sal_Int32 >( MAX_PERCENT - (MAX_PERCENT - mnC2) * fFactor );
434 9 : mnC3 = static_cast< sal_Int32 >( MAX_PERCENT - (MAX_PERCENT - mnC3) * fFactor );
435 : }
436 9 : break;
437 : case XLS_TOKEN( tint ):
438 : // Excel tint: move luminance relative to current value
439 0 : toHsl();
440 : OSL_ENSURE( (-MAX_PERCENT <= aIt->mnValue) && (aIt->mnValue <= MAX_PERCENT), "Color::getColor - invalid tint value" );
441 0 : if( (-MAX_PERCENT <= aIt->mnValue) && (aIt->mnValue < 0) )
442 : {
443 : // negative: luminance towards 0% (black)
444 0 : lclModValue( mnC3, aIt->mnValue + MAX_PERCENT );
445 : }
446 0 : else if( (0 < aIt->mnValue) && (aIt->mnValue <= MAX_PERCENT) )
447 : {
448 : // positive: luminance towards 100% (white)
449 0 : mnC3 = MAX_PERCENT - mnC3;
450 0 : lclModValue( mnC3, MAX_PERCENT - aIt->mnValue );
451 0 : mnC3 = MAX_PERCENT - mnC3;
452 : }
453 0 : break;
454 :
455 : case XML_gray:
456 : // change color to gray, weighted RGB: 22% red, 72% green, 6% blue
457 0 : toRgb();
458 0 : mnC1 = mnC2 = mnC3 = (mnC1 * 22 + mnC2 * 72 + mnC3 * 6) / 100;
459 0 : break;
460 :
461 : case XML_comp:
462 : // comp: rotate hue by 180 degrees, do not change lum/sat
463 0 : toHsl();
464 0 : (mnC1 += 180 * PER_DEGREE) %= MAX_DEGREE;
465 0 : break;
466 : case XML_inv:
467 : // invert percentual RGB values
468 0 : toCrgb();
469 0 : mnC1 = MAX_PERCENT - mnC1;
470 0 : mnC2 = MAX_PERCENT - mnC2;
471 0 : mnC3 = MAX_PERCENT - mnC3;
472 0 : break;
473 :
474 : case XML_gamma:
475 : // increase gamma of color
476 0 : toCrgb();
477 0 : mnC1 = lclGamma( mnC1, INC_GAMMA );
478 0 : mnC2 = lclGamma( mnC2, INC_GAMMA );
479 0 : mnC3 = lclGamma( mnC3, INC_GAMMA );
480 0 : break;
481 : case XML_invGamma:
482 : // decrease gamma of color
483 0 : toCrgb();
484 0 : mnC1 = lclGamma( mnC1, DEC_GAMMA );
485 0 : mnC2 = lclGamma( mnC2, DEC_GAMMA );
486 0 : mnC3 = lclGamma( mnC3, DEC_GAMMA );
487 0 : break;
488 : }
489 : }
490 :
491 : // store resulting RGB value in mnC1
492 954 : toRgb();
493 954 : mnC1 = lclRgbComponentsToRgb( mnC1, mnC2, mnC3 );
494 : }
495 : else // if( meMode != COLOR_UNUSED )
496 : {
497 185 : mnC1 = API_RGB_TRANSPARENT;
498 : }
499 :
500 1139 : meMode = bIsPh ? COLOR_PH : COLOR_FINAL;
501 1139 : if( meMode == COLOR_FINAL )
502 1076 : maTransforms.clear();
503 1139 : return mnC1;
504 : }
505 :
506 193 : bool Color::hasTransparency() const
507 : {
508 193 : return mnAlpha < MAX_PERCENT;
509 : }
510 :
511 25 : sal_Int16 Color::getTransparency() const
512 : {
513 25 : return static_cast< sal_Int16 >( (MAX_PERCENT - mnAlpha) / PER_PERCENT );
514 : }
515 :
516 : // private --------------------------------------------------------------------
517 :
518 674 : void Color::setResolvedRgb( sal_Int32 nRgb ) const
519 : {
520 674 : meMode = (nRgb < 0) ? COLOR_UNUSED : COLOR_RGB;
521 674 : lclRgbToRgbComponents( mnC1, mnC2, mnC3, nRgb );
522 674 : }
523 :
524 960 : void Color::toRgb() const
525 : {
526 960 : switch( meMode )
527 : {
528 : case COLOR_RGB:
529 : // nothing to do
530 874 : break;
531 : case COLOR_CRGB:
532 72 : meMode = COLOR_RGB;
533 72 : mnC1 = lclCrgbCompToRgbComp( lclGamma( mnC1, INC_GAMMA ) );
534 72 : mnC2 = lclCrgbCompToRgbComp( lclGamma( mnC2, INC_GAMMA ) );
535 72 : mnC3 = lclCrgbCompToRgbComp( lclGamma( mnC3, INC_GAMMA ) );
536 72 : break;
537 : case COLOR_HSL:
538 : {
539 14 : meMode = COLOR_RGB;
540 14 : double fR = 0.0, fG = 0.0, fB = 0.0;
541 14 : if( (mnC2 == 0) || (mnC3 == MAX_PERCENT) )
542 : {
543 3 : fR = fG = fB = static_cast< double >( mnC3 ) / MAX_PERCENT;
544 : }
545 11 : else if( mnC3 > 0 )
546 : {
547 : // base color from hue
548 11 : double fHue = static_cast< double >( mnC1 ) / MAX_DEGREE * 6.0; // interval [0.0, 6.0)
549 11 : if( fHue <= 1.0 ) { fR = 1.0; fG = fHue; } // red...yellow
550 11 : else if( fHue <= 2.0 ) { fR = 2.0 - fHue; fG = 1.0; } // yellow...green
551 10 : else if( fHue <= 3.0 ) { fG = 1.0; fB = fHue - 2.0; } // green...cyan
552 10 : else if( fHue <= 4.0 ) { fG = 4.0 - fHue; fB = 1.0; } // cyan...blue
553 0 : else if( fHue <= 5.0 ) { fR = fHue - 4.0; fB = 1.0; } // blue...magenta
554 0 : else { fR = 1.0; fB = 6.0 - fHue; } // magenta...red
555 :
556 : // apply saturation
557 11 : double fSat = static_cast< double >( mnC2 ) / MAX_PERCENT;
558 11 : fR = (fR - 0.5) * fSat + 0.5;
559 11 : fG = (fG - 0.5) * fSat + 0.5;
560 11 : fB = (fB - 0.5) * fSat + 0.5;
561 :
562 : // apply luminance
563 11 : double fLum = 2.0 * static_cast< double >( mnC3 ) / MAX_PERCENT - 1.0; // interval [-1.0, 1.0]
564 11 : if( fLum < 0.0 )
565 : {
566 1 : double fShade = fLum + 1.0; // interval [0.0, 1.0] (black...full color)
567 1 : fR *= fShade;
568 1 : fG *= fShade;
569 1 : fB *= fShade;
570 : }
571 10 : else if( fLum > 0.0 )
572 : {
573 10 : double fTint = 1.0 - fLum; // interval [0.0, 1.0] (white...full color)
574 10 : fR = 1.0 - ((1.0 - fR) * fTint);
575 10 : fG = 1.0 - ((1.0 - fG) * fTint);
576 10 : fB = 1.0 - ((1.0 - fB) * fTint);
577 : }
578 : }
579 14 : mnC1 = static_cast< sal_Int32 >( fR * 255.0 + 0.5 );
580 14 : mnC2 = static_cast< sal_Int32 >( fG * 255.0 + 0.5 );
581 14 : mnC3 = static_cast< sal_Int32 >( fB * 255.0 + 0.5 );
582 : }
583 14 : break;
584 : default:
585 : OSL_FAIL( "Color::toRgb - unexpected color mode" );
586 : }
587 960 : }
588 :
589 64 : void Color::toCrgb() const
590 : {
591 64 : switch( meMode )
592 : {
593 : case COLOR_HSL:
594 0 : toRgb();
595 : // run through!
596 : case COLOR_RGB:
597 64 : meMode = COLOR_CRGB;
598 64 : mnC1 = lclGamma( lclRgbCompToCrgbComp( mnC1 ), DEC_GAMMA );
599 64 : mnC2 = lclGamma( lclRgbCompToCrgbComp( mnC2 ), DEC_GAMMA );
600 64 : mnC3 = lclGamma( lclRgbCompToCrgbComp( mnC3 ), DEC_GAMMA );
601 64 : break;
602 : case COLOR_CRGB:
603 : // nothing to do
604 0 : break;
605 : default:
606 : OSL_FAIL( "Color::toCrgb - unexpected color mode" );
607 : }
608 64 : }
609 :
610 29 : void Color::toHsl() const
611 : {
612 29 : switch( meMode )
613 : {
614 : case COLOR_CRGB:
615 6 : toRgb();
616 : // run through!
617 : case COLOR_RGB:
618 : {
619 14 : meMode = COLOR_HSL;
620 14 : double fR = static_cast< double >( mnC1 ) / 255.0; // red [0.0, 1.0]
621 14 : double fG = static_cast< double >( mnC2 ) / 255.0; // green [0.0, 1.0]
622 14 : double fB = static_cast< double >( mnC3 ) / 255.0; // blue [0.0, 1.0]
623 14 : double fMin = ::std::min( ::std::min( fR, fG ), fB );
624 14 : double fMax = ::std::max( ::std::max( fR, fG ), fB );
625 14 : double fD = fMax - fMin;
626 :
627 : using ::rtl::math::approxEqual;
628 :
629 : // hue: 0deg = red, 120deg = green, 240deg = blue
630 14 : if( fD == 0.0 ) // black/gray/white
631 3 : mnC1 = 0;
632 11 : else if( approxEqual(fMax, fR, 64) ) // magenta...red...yellow
633 0 : mnC1 = static_cast< sal_Int32 >( ((fG - fB) / fD * 60.0 + 360.0) * PER_DEGREE + 0.5 ) % MAX_DEGREE;
634 11 : else if( approxEqual(fMax, fG, 64) ) // yellow...green...cyan
635 1 : mnC1 = static_cast< sal_Int32 >( ((fB - fR) / fD * 60.0 + 120.0) * PER_DEGREE + 0.5 );
636 : else // cyan...blue...magenta
637 10 : mnC1 = static_cast< sal_Int32 >( ((fR - fG) / fD * 60.0 + 240.0) * PER_DEGREE + 0.5 );
638 :
639 : // luminance: 0% = black, 50% = full color, 100% = white
640 14 : mnC3 = static_cast< sal_Int32 >( (fMin + fMax) / 2.0 * MAX_PERCENT + 0.5 );
641 :
642 : // saturation: 0% = gray, 100% = full color
643 14 : if( (mnC3 == 0) || (mnC3 == MAX_PERCENT) ) // black/white
644 3 : mnC2 = 0;
645 11 : else if( mnC3 <= 50 * PER_PERCENT ) // dark...full color
646 0 : mnC2 = static_cast< sal_Int32 >( fD / (fMin + fMax) * MAX_PERCENT + 0.5 );
647 : else // full color...light
648 11 : mnC2 = static_cast< sal_Int32 >( fD / (2.0 - fMax - fMin) * MAX_PERCENT + 0.5 );
649 : }
650 14 : break;
651 : case COLOR_HSL:
652 : // nothing to do
653 15 : break;
654 : default:
655 : OSL_FAIL( "Color::toHsl - unexpected color mode" );
656 : }
657 29 : }
658 :
659 : // ============================================================================
660 :
661 : } // namespace drawingml
662 141 : } // namespace oox
663 :
664 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|