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