1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
24 * Alternatively, the contents of this file may be used under the terms of
25 * either of the GNU General Public License Version 2 or later (the "GPL"),
26 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
40 #include "nsColorNames.h"
45 #include "nsIServiceManager.h"
48 #include "nsStaticNameTable.h"
50 // define an array of all color names
51 #define GFX_COLOR(_name, _value) #_name,
52 static const char* const kColorNames
[] = {
53 #include "nsColorNameList.h"
57 // define an array of all color name values
58 #define GFX_COLOR(_name, _value) _value,
59 static const nscolor kColors
[] = {
60 #include "nsColorNameList.h"
64 #define eColorName_COUNT (NS_ARRAY_LENGTH(kColorNames))
65 #define eColorName_UNKNOWN (-1)
67 static nsStaticCaseInsensitiveNameTable
* gColorTable
= nsnull
;
69 void nsColorNames::AddRefTable(void)
71 NS_ASSERTION(!gColorTable
, "pre existing array!");
73 gColorTable
= new nsStaticCaseInsensitiveNameTable();
77 // let's verify the table...
78 for (PRUint32 index
= 0; index
< eColorName_COUNT
; ++index
) {
79 nsCAutoString
temp1(kColorNames
[index
]);
80 nsCAutoString
temp2(kColorNames
[index
]);
82 NS_ASSERTION(temp1
.Equals(temp2
), "upper case char in table");
86 gColorTable
->Init(kColorNames
, eColorName_COUNT
);
91 void nsColorNames::ReleaseTable(void)
99 static int ComponentValue(const PRUnichar
* aColorSpec
, int aLen
, int color
, int dpc
)
102 int index
= (color
* dpc
);
107 PRUnichar ch
= ((index
< aLen
) ? aColorSpec
[index
++] : '0');
108 if (('0' <= ch
) && (ch
<= '9')) {
109 component
= (component
* 16) + (ch
- '0');
110 } else if ((('a' <= ch
) && (ch
<= 'f')) ||
111 (('A' <= ch
) && (ch
<= 'F'))) {
112 // "ch&7" handles lower and uppercase hex alphabetics
113 component
= (component
* 16) + (ch
& 7) + 9;
115 else { // not a hex digit, treat it like 0
116 component
= (component
* 16);
122 NS_GFX_(PRBool
) NS_HexToRGB(const nsString
& aColorSpec
,
125 const PRUnichar
* buffer
= aColorSpec
.get();
127 int nameLen
= aColorSpec
.Length();
128 if ((nameLen
== 3) || (nameLen
== 6)) {
129 // Make sure the digits are legal
130 for (int i
= 0; i
< nameLen
; i
++) {
131 PRUnichar ch
= buffer
[i
];
132 if (((ch
>= '0') && (ch
<= '9')) ||
133 ((ch
>= 'a') && (ch
<= 'f')) ||
134 ((ch
>= 'A') && (ch
<= 'F'))) {
138 // Whoops. Illegal character.
142 // Convert the ascii to binary
143 int dpc
= ((3 == nameLen
) ? 1 : 2);
144 // Translate components from hex to binary
145 int r
= ComponentValue(buffer
, nameLen
, 0, dpc
);
146 int g
= ComponentValue(buffer
, nameLen
, 1, dpc
);
147 int b
= ComponentValue(buffer
, nameLen
, 2, dpc
);
149 // Scale single digit component to an 8 bit value. Replicate the
150 // single digit to compute the new value.
155 NS_ASSERTION((r
>= 0) && (r
<= 255), "bad r");
156 NS_ASSERTION((g
>= 0) && (g
<= 255), "bad g");
157 NS_ASSERTION((b
>= 0) && (b
<= 255), "bad b");
158 *aResult
= NS_RGB(r
, g
, b
);
162 // Improperly formatted color value
166 // This implements part of the algorithm for legacy behavior described in
167 // http://www.whatwg.org/specs/web-apps/current-work/complete/common-microsyntaxes.html#rules-for-parsing-a-legacy-color-value
168 NS_GFX_(PRBool
) NS_LooseHexToRGB(const nsString
& aColorSpec
, nscolor
* aResult
)
170 if (aColorSpec
.EqualsLiteral("transparent")) {
174 int nameLen
= aColorSpec
.Length();
175 const PRUnichar
* colorSpec
= aColorSpec
.get();
180 if ('#' == colorSpec
[0]) {
185 // digits per component
186 int dpc
= (nameLen
+ 2) / 3;
189 // Use only the rightmost 8 characters of each component.
191 nameLen
-= newdpc
- 8;
192 colorSpec
+= newdpc
- 8;
196 // And then keep trimming characters at the left until we'd trim one
197 // that would leave a nonzero value, but not past 2 characters per
200 PRBool haveNonzero
= PR_FALSE
;
201 for (int c
= 0; c
< 3; ++c
) {
202 NS_ABORT_IF_FALSE(c
* dpc
< nameLen
,
203 "should not pass end of string while newdpc > 2");
204 PRUnichar ch
= colorSpec
[c
* dpc
];
205 if (('1' <= ch
&& ch
<= '9') ||
206 ('A' <= ch
&& ch
<= 'F') ||
207 ('a' <= ch
&& ch
<= 'f')) {
208 haveNonzero
= PR_TRUE
;
220 // Translate components from hex to binary
221 int r
= ComponentValue(colorSpec
, nameLen
, 0, dpc
);
222 int g
= ComponentValue(colorSpec
, nameLen
, 1, dpc
);
223 int b
= ComponentValue(colorSpec
, nameLen
, 2, dpc
);
224 NS_ASSERTION((r
>= 0) && (r
<= 255), "bad r");
225 NS_ASSERTION((g
>= 0) && (g
<= 255), "bad g");
226 NS_ASSERTION((b
>= 0) && (b
<= 255), "bad b");
228 *aResult
= NS_RGB(r
, g
, b
);
232 NS_GFX_(PRBool
) NS_ColorNameToRGB(const nsAString
& aColorName
, nscolor
* aResult
)
234 if (!gColorTable
) return PR_FALSE
;
236 PRInt32 id
= gColorTable
->Lookup(aColorName
);
237 if (eColorName_UNKNOWN
< id
) {
238 NS_ASSERTION(PRUint32(id
) < eColorName_COUNT
,
239 "gColorTable->Lookup messed up");
241 *aResult
= kColors
[id
];
248 // Macro to blend two colors
250 // equivalent to target = (bg*(255-fgalpha) + fg*fgalpha)/255
251 #define MOZ_BLEND(target, bg, fg, fgalpha) \
252 FAST_DIVIDE_BY_255(target, (bg)*(255-fgalpha) + (fg)*(fgalpha))
255 NS_ComposeColors(nscolor aBG
, nscolor aFG
)
257 // This function uses colors that are non premultiplied alpha.
260 PRIntn bgAlpha
= NS_GET_A(aBG
);
261 PRIntn fgAlpha
= NS_GET_A(aFG
);
263 // Compute the final alpha of the blended color
264 // a = fgAlpha + bgAlpha*(255 - fgAlpha)/255;
265 FAST_DIVIDE_BY_255(a
, bgAlpha
*(255-fgAlpha
));
269 // In this case the blended color is totally trasparent,
270 // we preserve the color information of the foreground color.
273 blendAlpha
= (fgAlpha
*255)/a
;
275 MOZ_BLEND(r
, NS_GET_R(aBG
), NS_GET_R(aFG
), blendAlpha
);
276 MOZ_BLEND(g
, NS_GET_G(aBG
), NS_GET_G(aFG
), blendAlpha
);
277 MOZ_BLEND(b
, NS_GET_B(aBG
), NS_GET_B(aFG
), blendAlpha
);
279 return NS_RGBA(r
, g
, b
, a
);
282 // Functions to convert from HSL color space to RGB color space.
283 // This is the algorithm described in the CSS3 specification
287 HSL_HueToRGB(float m1
, float m2
, float h
)
293 if (h
< (float)(1.0/6.0))
294 return m1
+ (m2
- m1
)*h
*6.0f
;
295 if (h
< (float)(1.0/2.0))
297 if (h
< (float)(2.0/3.0))
298 return m1
+ (m2
- m1
)*((float)(2.0/3.0) - h
)*6.0f
;
302 // The float parameters are all expected to be in the range 0-1
304 NS_HSL2RGB(float h
, float s
, float l
)
314 r
= PRUint8(255 * HSL_HueToRGB(m1
, m2
, h
+ 1.0f
/3.0f
));
315 g
= PRUint8(255 * HSL_HueToRGB(m1
, m2
, h
));
316 b
= PRUint8(255 * HSL_HueToRGB(m1
, m2
, h
- 1.0f
/3.0f
));
317 return NS_RGB(r
, g
, b
);