Bumping manifests a=b2g-bump
[gecko.git] / gfx / src / nsColor.cpp
blob50ca1b48a179ca4d509a90ac648100229214a7f1
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "mozilla/ArrayUtils.h" // for ArrayLength
7 #include "mozilla/mozalloc.h" // for operator delete, etc
9 #include "nsColor.h"
10 #include <sys/types.h> // for int32_t
11 #include "nsColorNames.h" // for nsColorNames
12 #include "nsDebug.h" // for NS_ASSERTION, etc
13 #include "nsStaticNameTable.h"
14 #include "nsString.h" // for nsAutoCString, nsString, etc
15 #include "nscore.h" // for nsAString, etc
17 using namespace mozilla;
19 // define an array of all color names
20 #define GFX_COLOR(_name, _value) #_name,
21 static const char* const kColorNames[] = {
22 #include "nsColorNameList.h"
24 #undef GFX_COLOR
26 // define an array of all color name values
27 #define GFX_COLOR(_name, _value) _value,
28 static const nscolor kColors[] = {
29 #include "nsColorNameList.h"
31 #undef GFX_COLOR
33 #define eColorName_COUNT (ArrayLength(kColorNames))
34 #define eColorName_UNKNOWN (-1)
36 static nsStaticCaseInsensitiveNameTable* gColorTable = nullptr;
38 void nsColorNames::AddRefTable(void)
40 NS_ASSERTION(!gColorTable, "pre existing array!");
41 if (!gColorTable) {
42 gColorTable = new nsStaticCaseInsensitiveNameTable();
43 if (gColorTable) {
44 #ifdef DEBUG
46 // let's verify the table...
47 for (uint32_t index = 0; index < eColorName_COUNT; ++index) {
48 nsAutoCString temp1(kColorNames[index]);
49 nsAutoCString temp2(kColorNames[index]);
50 ToLowerCase(temp1);
51 NS_ASSERTION(temp1.Equals(temp2), "upper case char in table");
54 #endif
55 gColorTable->Init(kColorNames, eColorName_COUNT);
60 void nsColorNames::ReleaseTable(void)
62 if (gColorTable) {
63 delete gColorTable;
64 gColorTable = nullptr;
68 static int ComponentValue(const char16_t* aColorSpec, int aLen, int color, int dpc)
70 int component = 0;
71 int index = (color * dpc);
72 if (2 < dpc) {
73 dpc = 2;
75 while (--dpc >= 0) {
76 char16_t ch = ((index < aLen) ? aColorSpec[index++] : '0');
77 if (('0' <= ch) && (ch <= '9')) {
78 component = (component * 16) + (ch - '0');
79 } else if ((('a' <= ch) && (ch <= 'f')) ||
80 (('A' <= ch) && (ch <= 'F'))) {
81 // "ch&7" handles lower and uppercase hex alphabetics
82 component = (component * 16) + (ch & 7) + 9;
84 else { // not a hex digit, treat it like 0
85 component = (component * 16);
88 return component;
91 NS_GFX_(bool) NS_HexToRGB(const nsAString& aColorSpec,
92 nscolor* aResult)
94 const char16_t* buffer = aColorSpec.BeginReading();
96 int nameLen = aColorSpec.Length();
97 if ((nameLen == 3) || (nameLen == 6)) {
98 // Make sure the digits are legal
99 for (int i = 0; i < nameLen; i++) {
100 char16_t ch = buffer[i];
101 if (((ch >= '0') && (ch <= '9')) ||
102 ((ch >= 'a') && (ch <= 'f')) ||
103 ((ch >= 'A') && (ch <= 'F'))) {
104 // Legal character
105 continue;
107 // Whoops. Illegal character.
108 return false;
111 // Convert the ascii to binary
112 int dpc = ((3 == nameLen) ? 1 : 2);
113 // Translate components from hex to binary
114 int r = ComponentValue(buffer, nameLen, 0, dpc);
115 int g = ComponentValue(buffer, nameLen, 1, dpc);
116 int b = ComponentValue(buffer, nameLen, 2, dpc);
117 if (dpc == 1) {
118 // Scale single digit component to an 8 bit value. Replicate the
119 // single digit to compute the new value.
120 r = (r << 4) | r;
121 g = (g << 4) | g;
122 b = (b << 4) | b;
124 NS_ASSERTION((r >= 0) && (r <= 255), "bad r");
125 NS_ASSERTION((g >= 0) && (g <= 255), "bad g");
126 NS_ASSERTION((b >= 0) && (b <= 255), "bad b");
127 *aResult = NS_RGB(r, g, b);
128 return true;
131 // Improperly formatted color value
132 return false;
135 // This implements part of the algorithm for legacy behavior described in
136 // http://www.whatwg.org/specs/web-apps/current-work/complete/common-microsyntaxes.html#rules-for-parsing-a-legacy-color-value
137 NS_GFX_(bool) NS_LooseHexToRGB(const nsString& aColorSpec, nscolor* aResult)
139 if (aColorSpec.EqualsLiteral("transparent")) {
140 return false;
143 int nameLen = aColorSpec.Length();
144 const char16_t* colorSpec = aColorSpec.get();
145 if (nameLen > 128) {
146 nameLen = 128;
149 if ('#' == colorSpec[0]) {
150 ++colorSpec;
151 --nameLen;
154 // digits per component
155 int dpc = (nameLen + 2) / 3;
156 int newdpc = dpc;
158 // Use only the rightmost 8 characters of each component.
159 if (newdpc > 8) {
160 nameLen -= newdpc - 8;
161 colorSpec += newdpc - 8;
162 newdpc = 8;
165 // And then keep trimming characters at the left until we'd trim one
166 // that would leave a nonzero value, but not past 2 characters per
167 // component.
168 while (newdpc > 2) {
169 bool haveNonzero = false;
170 for (int c = 0; c < 3; ++c) {
171 NS_ABORT_IF_FALSE(c * dpc < nameLen,
172 "should not pass end of string while newdpc > 2");
173 char16_t ch = colorSpec[c * dpc];
174 if (('1' <= ch && ch <= '9') ||
175 ('A' <= ch && ch <= 'F') ||
176 ('a' <= ch && ch <= 'f')) {
177 haveNonzero = true;
178 break;
181 if (haveNonzero) {
182 break;
184 --newdpc;
185 --nameLen;
186 ++colorSpec;
189 // Translate components from hex to binary
190 int r = ComponentValue(colorSpec, nameLen, 0, dpc);
191 int g = ComponentValue(colorSpec, nameLen, 1, dpc);
192 int b = ComponentValue(colorSpec, nameLen, 2, dpc);
193 NS_ASSERTION((r >= 0) && (r <= 255), "bad r");
194 NS_ASSERTION((g >= 0) && (g <= 255), "bad g");
195 NS_ASSERTION((b >= 0) && (b <= 255), "bad b");
197 *aResult = NS_RGB(r, g, b);
198 return true;
201 NS_GFX_(bool) NS_ColorNameToRGB(const nsAString& aColorName, nscolor* aResult)
203 if (!gColorTable) return false;
205 int32_t id = gColorTable->Lookup(aColorName);
206 if (eColorName_UNKNOWN < id) {
207 NS_ASSERTION(uint32_t(id) < eColorName_COUNT,
208 "gColorTable->Lookup messed up");
209 if (aResult) {
210 *aResult = kColors[id];
212 return true;
214 return false;
217 // Returns kColorNames, an array of all possible color names, and sets
218 // *aSizeArray to the size of that array. Do NOT call free() on this array.
219 NS_GFX_(const char * const *) NS_AllColorNames(size_t *aSizeArray)
221 *aSizeArray = ArrayLength(kColorNames);
222 return kColorNames;
225 // Macro to blend two colors
227 // equivalent to target = (bg*(255-fgalpha) + fg*fgalpha)/255
228 #define MOZ_BLEND(target, bg, fg, fgalpha) \
229 FAST_DIVIDE_BY_255(target, (bg)*(255-fgalpha) + (fg)*(fgalpha))
231 NS_GFX_(nscolor)
232 NS_ComposeColors(nscolor aBG, nscolor aFG)
234 // This function uses colors that are non premultiplied alpha.
235 int r, g, b, a;
237 int bgAlpha = NS_GET_A(aBG);
238 int fgAlpha = NS_GET_A(aFG);
240 // Compute the final alpha of the blended color
241 // a = fgAlpha + bgAlpha*(255 - fgAlpha)/255;
242 FAST_DIVIDE_BY_255(a, bgAlpha*(255-fgAlpha));
243 a = fgAlpha + a;
244 int blendAlpha;
245 if (a == 0) {
246 // In this case the blended color is totally trasparent,
247 // we preserve the color information of the foreground color.
248 blendAlpha = 255;
249 } else {
250 blendAlpha = (fgAlpha*255)/a;
252 MOZ_BLEND(r, NS_GET_R(aBG), NS_GET_R(aFG), blendAlpha);
253 MOZ_BLEND(g, NS_GET_G(aBG), NS_GET_G(aFG), blendAlpha);
254 MOZ_BLEND(b, NS_GET_B(aBG), NS_GET_B(aFG), blendAlpha);
256 return NS_RGBA(r, g, b, a);
259 // Functions to convert from HSL color space to RGB color space.
260 // This is the algorithm described in the CSS3 specification
262 // helper
263 static float
264 HSL_HueToRGB(float m1, float m2, float h)
266 if (h < 0.0f)
267 h += 1.0f;
268 if (h > 1.0f)
269 h -= 1.0f;
270 if (h < (float)(1.0/6.0))
271 return m1 + (m2 - m1)*h*6.0f;
272 if (h < (float)(1.0/2.0))
273 return m2;
274 if (h < (float)(2.0/3.0))
275 return m1 + (m2 - m1)*((float)(2.0/3.0) - h)*6.0f;
276 return m1;
279 // The float parameters are all expected to be in the range 0-1
280 NS_GFX_(nscolor)
281 NS_HSL2RGB(float h, float s, float l)
283 uint8_t r, g, b;
284 float m1, m2;
285 if (l <= 0.5f) {
286 m2 = l*(s+1);
287 } else {
288 m2 = l + s - l*s;
290 m1 = l*2 - m2;
291 r = uint8_t(255 * HSL_HueToRGB(m1, m2, h + 1.0f/3.0f));
292 g = uint8_t(255 * HSL_HueToRGB(m1, m2, h));
293 b = uint8_t(255 * HSL_HueToRGB(m1, m2, h - 1.0f/3.0f));
294 return NS_RGB(r, g, b);
297 NS_GFX_(const char*)
298 NS_RGBToColorName(nscolor aColor)
300 for (size_t idx = 0; idx < ArrayLength(kColors); ++idx) {
301 if (kColors[idx] == aColor) {
302 return kColorNames[idx];
306 return nullptr;