Bug 1776680 [wpt PR 34603] - [@container] Test invalidation of font-relative units...
[gecko.git] / gfx / src / nsColor.cpp
blob841b187438680211adb8c4d5fa58db43c8c9eaf6
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/. */
7 #include "mozilla/ArrayUtils.h" // for ArrayLength
8 #include "mozilla/mozalloc.h" // for operator delete, etc
9 #include "mozilla/MathAlgorithms.h"
11 #include "nsColor.h"
12 #include <sys/types.h> // for int32_t
13 #include "nsColorNames.h" // for nsColorNames
14 #include "nsDebug.h" // for NS_ASSERTION, etc
15 #include "nsStaticNameTable.h"
16 #include "nsString.h" // for nsAutoCString, nsString, etc
17 #include "nscore.h" // for nsAString, etc
18 #include "prtypes.h" // for PR_BEGIN_MACRO, etc
20 using namespace mozilla;
22 // define an array of all color names
23 #define GFX_COLOR(_name, _value) #_name,
24 static const char* const kColorNames[] = {
25 #include "nsColorNameList.h"
27 #undef GFX_COLOR
29 // define an array of all color name values
30 #define GFX_COLOR(_name, _value) _value,
31 static const nscolor kColors[] = {
32 #include "nsColorNameList.h"
34 #undef GFX_COLOR
36 #define eColorName_COUNT (ArrayLength(kColorNames))
37 #define eColorName_UNKNOWN (-1)
39 static nsStaticCaseInsensitiveNameTable* gColorTable = nullptr;
41 void nsColorNames::AddRefTable(void) {
42 NS_ASSERTION(!gColorTable, "pre existing array!");
43 if (!gColorTable) {
44 gColorTable =
45 new nsStaticCaseInsensitiveNameTable(kColorNames, eColorName_COUNT);
49 void nsColorNames::ReleaseTable(void) {
50 if (gColorTable) {
51 delete gColorTable;
52 gColorTable = nullptr;
56 static int ComponentValue(const char16_t* aColorSpec, int aLen, int color,
57 int dpc) {
58 int component = 0;
59 int index = (color * dpc);
60 if (2 < dpc) {
61 dpc = 2;
63 while (--dpc >= 0) {
64 char16_t ch = ((index < aLen) ? aColorSpec[index++] : '0');
65 if (('0' <= ch) && (ch <= '9')) {
66 component = (component * 16) + (ch - '0');
67 } else if ((('a' <= ch) && (ch <= 'f')) || (('A' <= ch) && (ch <= 'F'))) {
68 // "ch&7" handles lower and uppercase hex alphabetics
69 component = (component * 16) + (ch & 7) + 9;
70 } else { // not a hex digit, treat it like 0
71 component = (component * 16);
74 return component;
77 bool NS_HexToRGBA(const nsAString& aColorSpec, nsHexColorType aType,
78 nscolor* aResult) {
79 const char16_t* buffer = aColorSpec.BeginReading();
81 int nameLen = aColorSpec.Length();
82 bool hasAlpha = false;
83 if (nameLen != 3 && nameLen != 6) {
84 if ((nameLen != 4 && nameLen != 8) || aType == nsHexColorType::NoAlpha) {
85 // Improperly formatted color value
86 return false;
88 hasAlpha = true;
91 // Make sure the digits are legal
92 for (int i = 0; i < nameLen; i++) {
93 char16_t ch = buffer[i];
94 if (((ch >= '0') && (ch <= '9')) || ((ch >= 'a') && (ch <= 'f')) ||
95 ((ch >= 'A') && (ch <= 'F'))) {
96 // Legal character
97 continue;
99 // Whoops. Illegal character.
100 return false;
103 // Convert the ascii to binary
104 int dpc = ((nameLen <= 4) ? 1 : 2);
105 // Translate components from hex to binary
106 int r = ComponentValue(buffer, nameLen, 0, dpc);
107 int g = ComponentValue(buffer, nameLen, 1, dpc);
108 int b = ComponentValue(buffer, nameLen, 2, dpc);
109 int a;
110 if (hasAlpha) {
111 a = ComponentValue(buffer, nameLen, 3, dpc);
112 } else {
113 a = (dpc == 1) ? 0xf : 0xff;
115 if (dpc == 1) {
116 // Scale single digit component to an 8 bit value. Replicate the
117 // single digit to compute the new value.
118 r = (r << 4) | r;
119 g = (g << 4) | g;
120 b = (b << 4) | b;
121 a = (a << 4) | a;
123 NS_ASSERTION((r >= 0) && (r <= 255), "bad r");
124 NS_ASSERTION((g >= 0) && (g <= 255), "bad g");
125 NS_ASSERTION((b >= 0) && (b <= 255), "bad b");
126 NS_ASSERTION((a >= 0) && (a <= 255), "bad a");
127 *aResult = NS_RGBA(r, g, b, a);
128 return true;
131 // This implements part of the algorithm for legacy behavior described in
132 // http://www.whatwg.org/specs/web-apps/current-work/complete/common-microsyntaxes.html#rules-for-parsing-a-legacy-color-value
133 bool NS_LooseHexToRGB(const nsString& aColorSpec, nscolor* aResult) {
134 if (aColorSpec.EqualsLiteral("transparent")) {
135 return false;
138 int nameLen = aColorSpec.Length();
139 const char16_t* colorSpec = aColorSpec.get();
140 if (nameLen > 128) {
141 nameLen = 128;
144 if ('#' == colorSpec[0]) {
145 ++colorSpec;
146 --nameLen;
149 // digits per component
150 int dpc = (nameLen + 2) / 3;
151 int newdpc = dpc;
153 // Use only the rightmost 8 characters of each component.
154 if (newdpc > 8) {
155 nameLen -= newdpc - 8;
156 colorSpec += newdpc - 8;
157 newdpc = 8;
160 // And then keep trimming characters at the left until we'd trim one
161 // that would leave a nonzero value, but not past 2 characters per
162 // component.
163 while (newdpc > 2) {
164 bool haveNonzero = false;
165 for (int c = 0; c < 3; ++c) {
166 MOZ_ASSERT(c * dpc < nameLen,
167 "should not pass end of string while newdpc > 2");
168 char16_t ch = colorSpec[c * dpc];
169 if (('1' <= ch && ch <= '9') || ('A' <= ch && ch <= 'F') ||
170 ('a' <= ch && ch <= 'f')) {
171 haveNonzero = true;
172 break;
175 if (haveNonzero) {
176 break;
178 --newdpc;
179 --nameLen;
180 ++colorSpec;
183 // Translate components from hex to binary
184 int r = ComponentValue(colorSpec, nameLen, 0, dpc);
185 int g = ComponentValue(colorSpec, nameLen, 1, dpc);
186 int b = ComponentValue(colorSpec, nameLen, 2, dpc);
187 NS_ASSERTION((r >= 0) && (r <= 255), "bad r");
188 NS_ASSERTION((g >= 0) && (g <= 255), "bad g");
189 NS_ASSERTION((b >= 0) && (b <= 255), "bad b");
191 *aResult = NS_RGB(r, g, b);
192 return true;
195 bool NS_ColorNameToRGB(const nsAString& aColorName, nscolor* aResult) {
196 if (!gColorTable) return false;
198 int32_t id = gColorTable->Lookup(aColorName);
199 if (eColorName_UNKNOWN < id) {
200 NS_ASSERTION(uint32_t(id) < eColorName_COUNT,
201 "gColorTable->Lookup messed up");
202 if (aResult) {
203 *aResult = kColors[id];
205 return true;
207 return false;
210 // Fast approximate division by 255. It has the property that
211 // for all 0 <= n <= 255*255, FAST_DIVIDE_BY_255(n) == n/255.
212 // But it only uses two adds and two shifts instead of an
213 // integer division (which is expensive on many processors).
215 // equivalent to target=v/255
216 #define FAST_DIVIDE_BY_255(target, v) \
217 PR_BEGIN_MACRO \
218 unsigned tmp_ = v; \
219 target = ((tmp_ << 8) + tmp_ + 255) >> 16; \
220 PR_END_MACRO
222 // Macro to blend two colors
224 // equivalent to target = (bg*(255-fgalpha) + fg*fgalpha)/255
225 #define MOZ_BLEND(target, bg, fg, fgalpha) \
226 FAST_DIVIDE_BY_255(target, (bg) * (255 - fgalpha) + (fg) * (fgalpha))
228 nscolor NS_ComposeColors(nscolor aBG, nscolor aFG) {
229 // This function uses colors that are non premultiplied alpha.
230 int r, g, b, a;
232 int bgAlpha = NS_GET_A(aBG);
233 int fgAlpha = NS_GET_A(aFG);
235 // Compute the final alpha of the blended color
236 // a = fgAlpha + bgAlpha*(255 - fgAlpha)/255;
237 FAST_DIVIDE_BY_255(a, bgAlpha * (255 - fgAlpha));
238 a = fgAlpha + a;
239 int blendAlpha;
240 if (a == 0) {
241 // In this case the blended color is totally trasparent,
242 // we preserve the color information of the foreground color.
243 blendAlpha = 255;
244 } else {
245 blendAlpha = (fgAlpha * 255) / a;
247 MOZ_BLEND(r, NS_GET_R(aBG), NS_GET_R(aFG), blendAlpha);
248 MOZ_BLEND(g, NS_GET_G(aBG), NS_GET_G(aFG), blendAlpha);
249 MOZ_BLEND(b, NS_GET_B(aBG), NS_GET_B(aFG), blendAlpha);
251 return NS_RGBA(r, g, b, a);
254 const char* NS_RGBToColorName(nscolor aColor) {
255 for (size_t idx = 0; idx < ArrayLength(kColors); ++idx) {
256 if (kColors[idx] == aColor) {
257 return kColorNames[idx];
261 return nullptr;