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