Bug 574778 - Fix win widget's ConstrainPosition so that it supports full screen windo...
[mozilla-central.git] / gfx / src / nsColor.cpp
blob2a509f1a5b583652edb6de5ec7dfbc29c43c65b8
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
13 * License.
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.
22 * Contributor(s):
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 ***** */
38 #include "plstr.h"
39 #include "nsColor.h"
40 #include "nsColorNames.h"
41 #include "nsString.h"
42 #include "nscore.h"
43 #include "nsCoord.h"
44 #include "nsCOMPtr.h"
45 #include "nsIServiceManager.h"
46 #include <math.h>
47 #include "prprf.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"
55 #undef GFX_COLOR
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"
62 #undef GFX_COLOR
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!");
72 if (!gColorTable) {
73 gColorTable = new nsStaticCaseInsensitiveNameTable();
74 if (gColorTable) {
75 #ifdef DEBUG
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]);
81 ToLowerCase(temp1);
82 NS_ASSERTION(temp1.Equals(temp2), "upper case char in table");
85 #endif
86 gColorTable->Init(kColorNames, eColorName_COUNT);
91 void nsColorNames::ReleaseTable(void)
93 if (gColorTable) {
94 delete gColorTable;
95 gColorTable = nsnull;
99 static int ComponentValue(const PRUnichar* aColorSpec, int aLen, int color, int dpc)
101 int component = 0;
102 int index = (color * dpc);
103 if (2 < dpc) {
104 dpc = 2;
106 while (--dpc >= 0) {
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);
119 return component;
122 NS_GFX_(PRBool) NS_HexToRGB(const nsString& aColorSpec,
123 nscolor* aResult)
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'))) {
135 // Legal character
136 continue;
138 // Whoops. Illegal character.
139 return PR_FALSE;
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);
148 if (dpc == 1) {
149 // Scale single digit component to an 8 bit value. Replicate the
150 // single digit to compute the new value.
151 r = (r << 4) | r;
152 g = (g << 4) | g;
153 b = (b << 4) | b;
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);
159 return PR_TRUE;
162 // Improperly formatted color value
163 return PR_FALSE;
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")) {
171 return PR_FALSE;
174 int nameLen = aColorSpec.Length();
175 const PRUnichar* colorSpec = aColorSpec.get();
176 if (nameLen > 128) {
177 nameLen = 128;
180 if ('#' == colorSpec[0]) {
181 ++colorSpec;
182 --nameLen;
185 // digits per component
186 int dpc = (nameLen + 2) / 3;
187 int newdpc = dpc;
189 // Use only the rightmost 8 characters of each component.
190 if (newdpc > 8) {
191 nameLen -= newdpc - 8;
192 colorSpec += newdpc - 8;
193 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
198 // component.
199 while (newdpc > 2) {
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;
209 break;
212 if (haveNonzero) {
213 break;
215 --newdpc;
216 --nameLen;
217 ++colorSpec;
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);
229 return PR_TRUE;
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");
240 if (aResult) {
241 *aResult = kColors[id];
243 return PR_TRUE;
245 return PR_FALSE;
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))
254 NS_GFX_(nscolor)
255 NS_ComposeColors(nscolor aBG, nscolor aFG)
257 // This function uses colors that are non premultiplied alpha.
258 PRIntn r, g, b, a;
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));
266 a = fgAlpha + a;
267 PRIntn blendAlpha;
268 if (a == 0) {
269 // In this case the blended color is totally trasparent,
270 // we preserve the color information of the foreground color.
271 blendAlpha = 255;
272 } else {
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
285 // helper
286 static float
287 HSL_HueToRGB(float m1, float m2, float h)
289 if (h < 0.0f)
290 h += 1.0f;
291 if (h > 1.0f)
292 h -= 1.0f;
293 if (h < (float)(1.0/6.0))
294 return m1 + (m2 - m1)*h*6.0f;
295 if (h < (float)(1.0/2.0))
296 return m2;
297 if (h < (float)(2.0/3.0))
298 return m1 + (m2 - m1)*((float)(2.0/3.0) - h)*6.0f;
299 return m1;
302 // The float parameters are all expected to be in the range 0-1
303 NS_GFX_(nscolor)
304 NS_HSL2RGB(float h, float s, float l)
306 PRUint8 r, g, b;
307 float m1, m2;
308 if (l <= 0.5f) {
309 m2 = l*(s+1);
310 } else {
311 m2 = l + s - l*s;
313 m1 = l*2 - m2;
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);