Bug 1891710: part 2) Enable <Element-outerHTML.html> WPT for Trusted Types. r=smaug
[gecko.git] / gfx / src / nsColor.cpp
blob82a86c28db3b64c74a543cc47c52ce5062fbef77
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 "nsDebug.h" // for NS_ASSERTION, etc
14 #include "nsStaticNameTable.h"
15 #include "nsString.h" // for nsAutoCString, nsString, etc
16 #include "nscore.h" // for nsAString, etc
17 #include "prtypes.h" // for PR_BEGIN_MACRO, etc
19 using namespace mozilla;
21 static int ComponentValue(const char16_t* aColorSpec, int aLen, int color,
22 int dpc) {
23 int component = 0;
24 int index = (color * dpc);
25 if (2 < dpc) {
26 dpc = 2;
28 while (--dpc >= 0) {
29 char16_t ch = ((index < aLen) ? aColorSpec[index++] : '0');
30 if (('0' <= ch) && (ch <= '9')) {
31 component = (component * 16) + (ch - '0');
32 } else if ((('a' <= ch) && (ch <= 'f')) || (('A' <= ch) && (ch <= 'F'))) {
33 // "ch&7" handles lower and uppercase hex alphabetics
34 component = (component * 16) + (ch & 7) + 9;
35 } else { // not a hex digit, treat it like 0
36 component = (component * 16);
39 return component;
42 bool NS_HexToRGBA(const nsAString& aColorSpec, nsHexColorType aType,
43 nscolor* aResult) {
44 const char16_t* buffer = aColorSpec.BeginReading();
46 int nameLen = aColorSpec.Length();
47 bool hasAlpha = false;
48 if (nameLen != 3 && nameLen != 6) {
49 if ((nameLen != 4 && nameLen != 8) || aType == nsHexColorType::NoAlpha) {
50 // Improperly formatted color value
51 return false;
53 hasAlpha = true;
56 // Make sure the digits are legal
57 for (int i = 0; i < nameLen; i++) {
58 char16_t ch = buffer[i];
59 if (((ch >= '0') && (ch <= '9')) || ((ch >= 'a') && (ch <= 'f')) ||
60 ((ch >= 'A') && (ch <= 'F'))) {
61 // Legal character
62 continue;
64 // Whoops. Illegal character.
65 return false;
68 // Convert the ascii to binary
69 int dpc = ((nameLen <= 4) ? 1 : 2);
70 // Translate components from hex to binary
71 int r = ComponentValue(buffer, nameLen, 0, dpc);
72 int g = ComponentValue(buffer, nameLen, 1, dpc);
73 int b = ComponentValue(buffer, nameLen, 2, dpc);
74 int a;
75 if (hasAlpha) {
76 a = ComponentValue(buffer, nameLen, 3, dpc);
77 } else {
78 a = (dpc == 1) ? 0xf : 0xff;
80 if (dpc == 1) {
81 // Scale single digit component to an 8 bit value. Replicate the
82 // single digit to compute the new value.
83 r = (r << 4) | r;
84 g = (g << 4) | g;
85 b = (b << 4) | b;
86 a = (a << 4) | a;
88 NS_ASSERTION((r >= 0) && (r <= 255), "bad r");
89 NS_ASSERTION((g >= 0) && (g <= 255), "bad g");
90 NS_ASSERTION((b >= 0) && (b <= 255), "bad b");
91 NS_ASSERTION((a >= 0) && (a <= 255), "bad a");
92 *aResult = NS_RGBA(r, g, b, a);
93 return true;
96 // This implements part of the algorithm for legacy behavior described in
97 // http://www.whatwg.org/specs/web-apps/current-work/complete/common-microsyntaxes.html#rules-for-parsing-a-legacy-color-value
98 bool NS_LooseHexToRGB(const nsString& aColorSpec, nscolor* aResult) {
99 if (aColorSpec.EqualsLiteral("transparent")) {
100 return false;
103 int nameLen = aColorSpec.Length();
104 const char16_t* colorSpec = aColorSpec.get();
105 if (nameLen > 128) {
106 nameLen = 128;
109 if ('#' == colorSpec[0]) {
110 ++colorSpec;
111 --nameLen;
114 // digits per component
115 int dpc = (nameLen + 2) / 3;
116 int newdpc = dpc;
118 // Use only the rightmost 8 characters of each component.
119 if (newdpc > 8) {
120 nameLen -= newdpc - 8;
121 colorSpec += newdpc - 8;
122 newdpc = 8;
125 // And then keep trimming characters at the left until we'd trim one
126 // that would leave a nonzero value, but not past 2 characters per
127 // component.
128 while (newdpc > 2) {
129 bool haveNonzero = false;
130 for (int c = 0; c < 3; ++c) {
131 MOZ_ASSERT(c * dpc < nameLen,
132 "should not pass end of string while newdpc > 2");
133 char16_t ch = colorSpec[c * dpc];
134 if (('1' <= ch && ch <= '9') || ('A' <= ch && ch <= 'F') ||
135 ('a' <= ch && ch <= 'f')) {
136 haveNonzero = true;
137 break;
140 if (haveNonzero) {
141 break;
143 --newdpc;
144 --nameLen;
145 ++colorSpec;
148 // Translate components from hex to binary
149 int r = ComponentValue(colorSpec, nameLen, 0, dpc);
150 int g = ComponentValue(colorSpec, nameLen, 1, dpc);
151 int b = ComponentValue(colorSpec, nameLen, 2, dpc);
152 NS_ASSERTION((r >= 0) && (r <= 255), "bad r");
153 NS_ASSERTION((g >= 0) && (g <= 255), "bad g");
154 NS_ASSERTION((b >= 0) && (b <= 255), "bad b");
156 *aResult = NS_RGB(r, g, b);
157 return true;
160 // Fast approximate division by 255. It has the property that
161 // for all 0 <= n <= 255*255, FAST_DIVIDE_BY_255(n) == n/255.
162 // But it only uses two adds and two shifts instead of an
163 // integer division (which is expensive on many processors).
165 // equivalent to target=v/255
166 #define FAST_DIVIDE_BY_255(target, v) \
167 PR_BEGIN_MACRO \
168 unsigned tmp_ = v; \
169 target = ((tmp_ << 8) + tmp_ + 255) >> 16; \
170 PR_END_MACRO
172 // Macro to blend two colors
174 // equivalent to target = (bg*(255-fgalpha) + fg*fgalpha)/255
175 #define MOZ_BLEND(target, bg, fg, fgalpha) \
176 FAST_DIVIDE_BY_255(target, (bg) * (255 - fgalpha) + (fg) * (fgalpha))
178 nscolor NS_ComposeColors(nscolor aBG, nscolor aFG) {
179 // This function uses colors that are non premultiplied alpha.
180 int r, g, b, a;
182 int bgAlpha = NS_GET_A(aBG);
183 int fgAlpha = NS_GET_A(aFG);
185 // Compute the final alpha of the blended color
186 // a = fgAlpha + bgAlpha*(255 - fgAlpha)/255;
187 FAST_DIVIDE_BY_255(a, bgAlpha * (255 - fgAlpha));
188 a = fgAlpha + a;
189 int blendAlpha;
190 if (a == 0) {
191 // In this case the blended color is totally trasparent,
192 // we preserve the color information of the foreground color.
193 blendAlpha = 255;
194 } else {
195 blendAlpha = (fgAlpha * 255) / a;
197 MOZ_BLEND(r, NS_GET_R(aBG), NS_GET_R(aFG), blendAlpha);
198 MOZ_BLEND(g, NS_GET_G(aBG), NS_GET_G(aFG), blendAlpha);
199 MOZ_BLEND(b, NS_GET_B(aBG), NS_GET_B(aFG), blendAlpha);
201 return NS_RGBA(r, g, b, a);