Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
michael@0 | 1 | /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
michael@0 | 2 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 5 | |
michael@0 | 6 | /* functions that manipulate colors */ |
michael@0 | 7 | |
michael@0 | 8 | #include "nsCSSColorUtils.h" |
michael@0 | 9 | #include "nsDebug.h" |
michael@0 | 10 | #include <math.h> |
michael@0 | 11 | |
michael@0 | 12 | // Weird color computing code stolen from winfe which was stolen |
michael@0 | 13 | // from the xfe which was written originally by Eric Bina. So there. |
michael@0 | 14 | |
michael@0 | 15 | #define RED_LUMINOSITY 299 |
michael@0 | 16 | #define GREEN_LUMINOSITY 587 |
michael@0 | 17 | #define BLUE_LUMINOSITY 114 |
michael@0 | 18 | #define INTENSITY_FACTOR 25 |
michael@0 | 19 | #define LUMINOSITY_FACTOR 75 |
michael@0 | 20 | |
michael@0 | 21 | #define MAX_COLOR 255 |
michael@0 | 22 | #define COLOR_DARK_THRESHOLD 51 |
michael@0 | 23 | #define COLOR_LIGHT_THRESHOLD 204 |
michael@0 | 24 | |
michael@0 | 25 | #define COLOR_LITE_BS_FACTOR 45 |
michael@0 | 26 | #define COLOR_LITE_TS_FACTOR 70 |
michael@0 | 27 | |
michael@0 | 28 | #define COLOR_DARK_BS_FACTOR 30 |
michael@0 | 29 | #define COLOR_DARK_TS_FACTOR 50 |
michael@0 | 30 | |
michael@0 | 31 | #define LIGHT_GRAY NS_RGB(192, 192, 192) |
michael@0 | 32 | #define DARK_GRAY NS_RGB(96, 96, 96) |
michael@0 | 33 | |
michael@0 | 34 | #define MAX_BRIGHTNESS 254 |
michael@0 | 35 | #define MAX_DARKNESS 0 |
michael@0 | 36 | |
michael@0 | 37 | void NS_GetSpecial3DColors(nscolor aResult[2], |
michael@0 | 38 | nscolor aBackgroundColor, |
michael@0 | 39 | nscolor aBorderColor) |
michael@0 | 40 | { |
michael@0 | 41 | |
michael@0 | 42 | uint8_t f0, f1; |
michael@0 | 43 | uint8_t r, g, b; |
michael@0 | 44 | |
michael@0 | 45 | uint8_t rb = NS_GET_R(aBorderColor); |
michael@0 | 46 | uint8_t gb = NS_GET_G(aBorderColor); |
michael@0 | 47 | uint8_t bb = NS_GET_B(aBorderColor); |
michael@0 | 48 | |
michael@0 | 49 | uint8_t a = NS_GET_A(aBorderColor); |
michael@0 | 50 | |
michael@0 | 51 | // This needs to be optimized. |
michael@0 | 52 | // Calculating background brightness again and again is |
michael@0 | 53 | // a waste of time!!!. Just calculate it only once. |
michael@0 | 54 | // .....somehow!!! |
michael@0 | 55 | |
michael@0 | 56 | uint8_t red = NS_GET_R(aBackgroundColor); |
michael@0 | 57 | uint8_t green = NS_GET_G(aBackgroundColor); |
michael@0 | 58 | uint8_t blue = NS_GET_B(aBackgroundColor); |
michael@0 | 59 | |
michael@0 | 60 | uint8_t elementBrightness = NS_GetBrightness(rb,gb,bb); |
michael@0 | 61 | uint8_t backgroundBrightness = NS_GetBrightness(red, green, blue); |
michael@0 | 62 | |
michael@0 | 63 | |
michael@0 | 64 | if (backgroundBrightness < COLOR_DARK_THRESHOLD) { |
michael@0 | 65 | f0 = COLOR_DARK_BS_FACTOR; |
michael@0 | 66 | f1 = COLOR_DARK_TS_FACTOR; |
michael@0 | 67 | if(elementBrightness == MAX_DARKNESS) |
michael@0 | 68 | { |
michael@0 | 69 | rb = NS_GET_R(DARK_GRAY); |
michael@0 | 70 | gb = NS_GET_G(DARK_GRAY); |
michael@0 | 71 | bb = NS_GET_B(DARK_GRAY); |
michael@0 | 72 | } |
michael@0 | 73 | }else if (backgroundBrightness > COLOR_LIGHT_THRESHOLD) { |
michael@0 | 74 | f0 = COLOR_LITE_BS_FACTOR; |
michael@0 | 75 | f1 = COLOR_LITE_TS_FACTOR; |
michael@0 | 76 | if(elementBrightness == MAX_BRIGHTNESS) |
michael@0 | 77 | { |
michael@0 | 78 | rb = NS_GET_R(LIGHT_GRAY); |
michael@0 | 79 | gb = NS_GET_G(LIGHT_GRAY); |
michael@0 | 80 | bb = NS_GET_B(LIGHT_GRAY); |
michael@0 | 81 | } |
michael@0 | 82 | }else { |
michael@0 | 83 | f0 = COLOR_DARK_BS_FACTOR + |
michael@0 | 84 | (backgroundBrightness * |
michael@0 | 85 | (COLOR_LITE_BS_FACTOR - COLOR_DARK_BS_FACTOR) / MAX_COLOR); |
michael@0 | 86 | f1 = COLOR_DARK_TS_FACTOR + |
michael@0 | 87 | (backgroundBrightness * |
michael@0 | 88 | (COLOR_LITE_TS_FACTOR - COLOR_DARK_TS_FACTOR) / MAX_COLOR); |
michael@0 | 89 | } |
michael@0 | 90 | |
michael@0 | 91 | |
michael@0 | 92 | r = rb - (f0 * rb / 100); |
michael@0 | 93 | g = gb - (f0 * gb / 100); |
michael@0 | 94 | b = bb - (f0 * bb / 100); |
michael@0 | 95 | aResult[0] = NS_RGBA(r, g, b, a); |
michael@0 | 96 | |
michael@0 | 97 | r = rb + (f1 * (MAX_COLOR - rb) / 100); |
michael@0 | 98 | g = gb + (f1 * (MAX_COLOR - gb) / 100); |
michael@0 | 99 | b = bb + (f1 * (MAX_COLOR - bb) / 100); |
michael@0 | 100 | aResult[1] = NS_RGBA(r, g, b, a); |
michael@0 | 101 | } |
michael@0 | 102 | |
michael@0 | 103 | int NS_GetBrightness(uint8_t aRed, uint8_t aGreen, uint8_t aBlue) |
michael@0 | 104 | { |
michael@0 | 105 | |
michael@0 | 106 | uint8_t intensity = (aRed + aGreen + aBlue) / 3; |
michael@0 | 107 | |
michael@0 | 108 | uint8_t luminosity = NS_GetLuminosity(NS_RGB(aRed, aGreen, aBlue)) / 1000; |
michael@0 | 109 | |
michael@0 | 110 | return ((intensity * INTENSITY_FACTOR) + |
michael@0 | 111 | (luminosity * LUMINOSITY_FACTOR)) / 100; |
michael@0 | 112 | } |
michael@0 | 113 | |
michael@0 | 114 | int32_t NS_GetLuminosity(nscolor aColor) |
michael@0 | 115 | { |
michael@0 | 116 | // When aColor is not opaque, the perceived luminosity will depend |
michael@0 | 117 | // on what color(s) aColor is ultimately drawn on top of, which we |
michael@0 | 118 | // do not know. |
michael@0 | 119 | NS_ASSERTION(NS_GET_A(aColor) == 255, |
michael@0 | 120 | "impossible to compute luminosity of a non-opaque color"); |
michael@0 | 121 | |
michael@0 | 122 | return (NS_GET_R(aColor) * RED_LUMINOSITY + |
michael@0 | 123 | NS_GET_G(aColor) * GREEN_LUMINOSITY + |
michael@0 | 124 | NS_GET_B(aColor) * BLUE_LUMINOSITY); |
michael@0 | 125 | } |
michael@0 | 126 | |
michael@0 | 127 | // Function to convert RGB color space into the HSV colorspace |
michael@0 | 128 | // Hue is the primary color defined from 0 to 359 degrees |
michael@0 | 129 | // Saturation is defined from 0 to 255. The higher the number.. the deeper |
michael@0 | 130 | // the color Value is the brightness of the color. 0 is black, 255 is white. |
michael@0 | 131 | void NS_RGB2HSV(nscolor aColor, uint16_t &aHue, uint16_t &aSat, |
michael@0 | 132 | uint16_t &aValue, uint8_t &aAlpha) |
michael@0 | 133 | { |
michael@0 | 134 | uint8_t r, g, b; |
michael@0 | 135 | int16_t delta, min, max, r1, b1, g1; |
michael@0 | 136 | float hue; |
michael@0 | 137 | |
michael@0 | 138 | r = NS_GET_R(aColor); |
michael@0 | 139 | g = NS_GET_G(aColor); |
michael@0 | 140 | b = NS_GET_B(aColor); |
michael@0 | 141 | |
michael@0 | 142 | if (r>g) { |
michael@0 | 143 | max = r; |
michael@0 | 144 | min = g; |
michael@0 | 145 | } else { |
michael@0 | 146 | max = g; |
michael@0 | 147 | min = r; |
michael@0 | 148 | } |
michael@0 | 149 | |
michael@0 | 150 | if (b>max) { |
michael@0 | 151 | max = b; |
michael@0 | 152 | } |
michael@0 | 153 | if (b<min) { |
michael@0 | 154 | min = b; |
michael@0 | 155 | } |
michael@0 | 156 | |
michael@0 | 157 | // value or brightness will always be the max of all the colors(RGB) |
michael@0 | 158 | aValue = max; |
michael@0 | 159 | delta = max-min; |
michael@0 | 160 | aSat = (max!=0)?((delta*255)/max):0; |
michael@0 | 161 | r1 = r; |
michael@0 | 162 | b1 = b; |
michael@0 | 163 | g1 = g; |
michael@0 | 164 | |
michael@0 | 165 | if (aSat==0) { |
michael@0 | 166 | hue = 1000; |
michael@0 | 167 | } else { |
michael@0 | 168 | if(r==max){ |
michael@0 | 169 | hue=(float)(g1-b1)/(float)delta; |
michael@0 | 170 | } else if (g1==max) { |
michael@0 | 171 | hue= 2.0f+(float)(b1-r1)/(float)delta; |
michael@0 | 172 | } else { |
michael@0 | 173 | hue = 4.0f+(float)(r1-g1)/(float)delta; |
michael@0 | 174 | } |
michael@0 | 175 | } |
michael@0 | 176 | |
michael@0 | 177 | if(hue<999) { |
michael@0 | 178 | hue*=60; |
michael@0 | 179 | if(hue<0){ |
michael@0 | 180 | hue+=360; |
michael@0 | 181 | } |
michael@0 | 182 | } else { |
michael@0 | 183 | hue=0; |
michael@0 | 184 | } |
michael@0 | 185 | |
michael@0 | 186 | aHue = (uint16_t)hue; |
michael@0 | 187 | |
michael@0 | 188 | aAlpha = NS_GET_A(aColor); |
michael@0 | 189 | } |
michael@0 | 190 | |
michael@0 | 191 | // Function to convert HSV color space into the RGB colorspace |
michael@0 | 192 | // Hue is the primary color defined from 0 to 359 degrees |
michael@0 | 193 | // Saturation is defined from 0 to 255. The higher the number.. the deeper |
michael@0 | 194 | // the color Value is the brightness of the color. 0 is black, 255 is white. |
michael@0 | 195 | void NS_HSV2RGB(nscolor &aColor, uint16_t aHue, uint16_t aSat, uint16_t aValue, |
michael@0 | 196 | uint8_t aAlpha) |
michael@0 | 197 | { |
michael@0 | 198 | uint16_t r = 0, g = 0, b = 0; |
michael@0 | 199 | uint16_t i, p, q, t; |
michael@0 | 200 | double h, f, percent; |
michael@0 | 201 | |
michael@0 | 202 | if ( aSat == 0 ){ |
michael@0 | 203 | // achromatic color, no hue is defined |
michael@0 | 204 | r = aValue; |
michael@0 | 205 | g = aValue; |
michael@0 | 206 | b = aValue; |
michael@0 | 207 | } else { |
michael@0 | 208 | // hue in in degrees around the color wheel defined from |
michael@0 | 209 | // 0 to 360 degrees. |
michael@0 | 210 | if (aHue >= 360) { |
michael@0 | 211 | aHue = 0; |
michael@0 | 212 | } |
michael@0 | 213 | |
michael@0 | 214 | // we break the color wheel into 6 areas.. these |
michael@0 | 215 | // areas define how the saturation and value define the color. |
michael@0 | 216 | // reds behave differently than the blues |
michael@0 | 217 | h = (double)aHue / 60.0; |
michael@0 | 218 | i = (uint16_t) floor(h); |
michael@0 | 219 | f = h-(double)i; |
michael@0 | 220 | percent = ((double)aValue/255.0); // this needs to be a value from 0 to 1, so a percentage |
michael@0 | 221 | // can be calculated of the saturation. |
michael@0 | 222 | p = (uint16_t)(percent*(255-aSat)); |
michael@0 | 223 | q = (uint16_t)(percent*(255-(aSat*f))); |
michael@0 | 224 | t = (uint16_t)(percent*(255-(aSat*(1.0-f)))); |
michael@0 | 225 | |
michael@0 | 226 | // i is guaranteed to never be larger than 5. |
michael@0 | 227 | switch(i){ |
michael@0 | 228 | case 0: r = aValue; g = t; b = p;break; |
michael@0 | 229 | case 1: r = q; g = aValue; b = p;break; |
michael@0 | 230 | case 2: r = p; g = aValue; b = t;break; |
michael@0 | 231 | case 3: r = p; g = q; b = aValue;break; |
michael@0 | 232 | case 4: r = t; g = p; b = aValue;break; |
michael@0 | 233 | case 5: r = aValue; g = p; b = q;break; |
michael@0 | 234 | } |
michael@0 | 235 | } |
michael@0 | 236 | aColor = NS_RGBA(r, g, b, aAlpha); |
michael@0 | 237 | } |
michael@0 | 238 | |
michael@0 | 239 | #undef RED_LUMINOSITY |
michael@0 | 240 | #undef GREEN_LUMINOSITY |
michael@0 | 241 | #undef BLUE_LUMINOSITY |
michael@0 | 242 | #undef INTENSITY_FACTOR |
michael@0 | 243 | #undef LUMINOSITY_FACTOR |
michael@0 | 244 | |
michael@0 | 245 | #undef MAX_COLOR |
michael@0 | 246 | #undef COLOR_DARK_THRESHOLD |
michael@0 | 247 | #undef COLOR_LIGHT_THRESHOLD |
michael@0 | 248 | |
michael@0 | 249 | #undef COLOR_LITE_BS_FACTOR |
michael@0 | 250 | #undef COLOR_LITE_TS_FACTOR |
michael@0 | 251 | |
michael@0 | 252 | #undef COLOR_DARK_BS_FACTOR |
michael@0 | 253 | #undef COLOR_DARK_TS_FACTOR |
michael@0 | 254 | |
michael@0 | 255 | #undef LIGHT_GRAY |
michael@0 | 256 | #undef DARK_GRAY |
michael@0 | 257 | |
michael@0 | 258 | #undef MAX_BRIGHTNESS |
michael@0 | 259 | #undef MAX_DARKNESS |