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