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
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"
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"
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!");
42 gColorTable
= new nsStaticCaseInsensitiveNameTable();
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
]);
51 NS_ASSERTION(temp1
.Equals(temp2
), "upper case char in table");
55 gColorTable
->Init(kColorNames
, eColorName_COUNT
);
60 void nsColorNames::ReleaseTable(void)
64 gColorTable
= nullptr;
68 static int ComponentValue(const char16_t
* aColorSpec
, int aLen
, int color
, int dpc
)
71 int index
= (color
* dpc
);
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);
91 NS_GFX_(bool) NS_HexToRGB(const nsAString
& aColorSpec
,
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'))) {
107 // Whoops. Illegal character.
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
);
118 // Scale single digit component to an 8 bit value. Replicate the
119 // single digit to compute the new value.
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
);
131 // Improperly formatted color value
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")) {
143 int nameLen
= aColorSpec
.Length();
144 const char16_t
* colorSpec
= aColorSpec
.get();
149 if ('#' == colorSpec
[0]) {
154 // digits per component
155 int dpc
= (nameLen
+ 2) / 3;
158 // Use only the rightmost 8 characters of each component.
160 nameLen
-= newdpc
- 8;
161 colorSpec
+= 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
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')) {
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
);
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");
210 *aResult
= kColors
[id
];
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
);
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))
232 NS_ComposeColors(nscolor aBG
, nscolor aFG
)
234 // This function uses colors that are non premultiplied alpha.
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
));
246 // In this case the blended color is totally trasparent,
247 // we preserve the color information of the foreground color.
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
264 HSL_HueToRGB(float m1
, float m2
, float h
)
270 if (h
< (float)(1.0/6.0))
271 return m1
+ (m2
- m1
)*h
*6.0f
;
272 if (h
< (float)(1.0/2.0))
274 if (h
< (float)(2.0/3.0))
275 return m1
+ (m2
- m1
)*((float)(2.0/3.0) - h
)*6.0f
;
279 // The float parameters are all expected to be in the range 0-1
281 NS_HSL2RGB(float h
, float s
, float l
)
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
);
298 NS_RGBToColorName(nscolor aColor
)
300 for (size_t idx
= 0; idx
< ArrayLength(kColors
); ++idx
) {
301 if (kColors
[idx
] == aColor
) {
302 return kColorNames
[idx
];