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