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