gfx/src/nsColor.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #include "mozilla/ArrayUtils.h" // for ArrayLength
michael@0 7 #include "mozilla/mozalloc.h" // for operator delete, etc
michael@0 8
michael@0 9 #include "nsColor.h"
michael@0 10 #include <sys/types.h> // for int32_t
michael@0 11 #include "nsColorNames.h" // for nsColorNames
michael@0 12 #include "nsDebug.h" // for NS_ASSERTION, etc
michael@0 13 #include "nsStaticNameTable.h"
michael@0 14 #include "nsString.h" // for nsAutoCString, nsString, etc
michael@0 15 #include "nscore.h" // for nsAString, etc
michael@0 16
michael@0 17 using namespace mozilla;
michael@0 18
michael@0 19 // define an array of all color names
michael@0 20 #define GFX_COLOR(_name, _value) #_name,
michael@0 21 static const char* const kColorNames[] = {
michael@0 22 #include "nsColorNameList.h"
michael@0 23 };
michael@0 24 #undef GFX_COLOR
michael@0 25
michael@0 26 // define an array of all color name values
michael@0 27 #define GFX_COLOR(_name, _value) _value,
michael@0 28 static const nscolor kColors[] = {
michael@0 29 #include "nsColorNameList.h"
michael@0 30 };
michael@0 31 #undef GFX_COLOR
michael@0 32
michael@0 33 #define eColorName_COUNT (ArrayLength(kColorNames))
michael@0 34 #define eColorName_UNKNOWN (-1)
michael@0 35
michael@0 36 static nsStaticCaseInsensitiveNameTable* gColorTable = nullptr;
michael@0 37
michael@0 38 void nsColorNames::AddRefTable(void)
michael@0 39 {
michael@0 40 NS_ASSERTION(!gColorTable, "pre existing array!");
michael@0 41 if (!gColorTable) {
michael@0 42 gColorTable = new nsStaticCaseInsensitiveNameTable();
michael@0 43 if (gColorTable) {
michael@0 44 #ifdef DEBUG
michael@0 45 {
michael@0 46 // let's verify the table...
michael@0 47 for (uint32_t index = 0; index < eColorName_COUNT; ++index) {
michael@0 48 nsAutoCString temp1(kColorNames[index]);
michael@0 49 nsAutoCString temp2(kColorNames[index]);
michael@0 50 ToLowerCase(temp1);
michael@0 51 NS_ASSERTION(temp1.Equals(temp2), "upper case char in table");
michael@0 52 }
michael@0 53 }
michael@0 54 #endif
michael@0 55 gColorTable->Init(kColorNames, eColorName_COUNT);
michael@0 56 }
michael@0 57 }
michael@0 58 }
michael@0 59
michael@0 60 void nsColorNames::ReleaseTable(void)
michael@0 61 {
michael@0 62 if (gColorTable) {
michael@0 63 delete gColorTable;
michael@0 64 gColorTable = nullptr;
michael@0 65 }
michael@0 66 }
michael@0 67
michael@0 68 static int ComponentValue(const char16_t* aColorSpec, int aLen, int color, int dpc)
michael@0 69 {
michael@0 70 int component = 0;
michael@0 71 int index = (color * dpc);
michael@0 72 if (2 < dpc) {
michael@0 73 dpc = 2;
michael@0 74 }
michael@0 75 while (--dpc >= 0) {
michael@0 76 char16_t ch = ((index < aLen) ? aColorSpec[index++] : '0');
michael@0 77 if (('0' <= ch) && (ch <= '9')) {
michael@0 78 component = (component * 16) + (ch - '0');
michael@0 79 } else if ((('a' <= ch) && (ch <= 'f')) ||
michael@0 80 (('A' <= ch) && (ch <= 'F'))) {
michael@0 81 // "ch&7" handles lower and uppercase hex alphabetics
michael@0 82 component = (component * 16) + (ch & 7) + 9;
michael@0 83 }
michael@0 84 else { // not a hex digit, treat it like 0
michael@0 85 component = (component * 16);
michael@0 86 }
michael@0 87 }
michael@0 88 return component;
michael@0 89 }
michael@0 90
michael@0 91 NS_GFX_(bool) NS_HexToRGB(const nsAString& aColorSpec,
michael@0 92 nscolor* aResult)
michael@0 93 {
michael@0 94 const char16_t* buffer = aColorSpec.BeginReading();
michael@0 95
michael@0 96 int nameLen = aColorSpec.Length();
michael@0 97 if ((nameLen == 3) || (nameLen == 6)) {
michael@0 98 // Make sure the digits are legal
michael@0 99 for (int i = 0; i < nameLen; i++) {
michael@0 100 char16_t ch = buffer[i];
michael@0 101 if (((ch >= '0') && (ch <= '9')) ||
michael@0 102 ((ch >= 'a') && (ch <= 'f')) ||
michael@0 103 ((ch >= 'A') && (ch <= 'F'))) {
michael@0 104 // Legal character
michael@0 105 continue;
michael@0 106 }
michael@0 107 // Whoops. Illegal character.
michael@0 108 return false;
michael@0 109 }
michael@0 110
michael@0 111 // Convert the ascii to binary
michael@0 112 int dpc = ((3 == nameLen) ? 1 : 2);
michael@0 113 // Translate components from hex to binary
michael@0 114 int r = ComponentValue(buffer, nameLen, 0, dpc);
michael@0 115 int g = ComponentValue(buffer, nameLen, 1, dpc);
michael@0 116 int b = ComponentValue(buffer, nameLen, 2, dpc);
michael@0 117 if (dpc == 1) {
michael@0 118 // Scale single digit component to an 8 bit value. Replicate the
michael@0 119 // single digit to compute the new value.
michael@0 120 r = (r << 4) | r;
michael@0 121 g = (g << 4) | g;
michael@0 122 b = (b << 4) | b;
michael@0 123 }
michael@0 124 NS_ASSERTION((r >= 0) && (r <= 255), "bad r");
michael@0 125 NS_ASSERTION((g >= 0) && (g <= 255), "bad g");
michael@0 126 NS_ASSERTION((b >= 0) && (b <= 255), "bad b");
michael@0 127 *aResult = NS_RGB(r, g, b);
michael@0 128 return true;
michael@0 129 }
michael@0 130
michael@0 131 // Improperly formatted color value
michael@0 132 return false;
michael@0 133 }
michael@0 134
michael@0 135 // This implements part of the algorithm for legacy behavior described in
michael@0 136 // http://www.whatwg.org/specs/web-apps/current-work/complete/common-microsyntaxes.html#rules-for-parsing-a-legacy-color-value
michael@0 137 NS_GFX_(bool) NS_LooseHexToRGB(const nsString& aColorSpec, nscolor* aResult)
michael@0 138 {
michael@0 139 if (aColorSpec.EqualsLiteral("transparent")) {
michael@0 140 return false;
michael@0 141 }
michael@0 142
michael@0 143 int nameLen = aColorSpec.Length();
michael@0 144 const char16_t* colorSpec = aColorSpec.get();
michael@0 145 if (nameLen > 128) {
michael@0 146 nameLen = 128;
michael@0 147 }
michael@0 148
michael@0 149 if ('#' == colorSpec[0]) {
michael@0 150 ++colorSpec;
michael@0 151 --nameLen;
michael@0 152 }
michael@0 153
michael@0 154 // digits per component
michael@0 155 int dpc = (nameLen + 2) / 3;
michael@0 156 int newdpc = dpc;
michael@0 157
michael@0 158 // Use only the rightmost 8 characters of each component.
michael@0 159 if (newdpc > 8) {
michael@0 160 nameLen -= newdpc - 8;
michael@0 161 colorSpec += newdpc - 8;
michael@0 162 newdpc = 8;
michael@0 163 }
michael@0 164
michael@0 165 // And then keep trimming characters at the left until we'd trim one
michael@0 166 // that would leave a nonzero value, but not past 2 characters per
michael@0 167 // component.
michael@0 168 while (newdpc > 2) {
michael@0 169 bool haveNonzero = false;
michael@0 170 for (int c = 0; c < 3; ++c) {
michael@0 171 NS_ABORT_IF_FALSE(c * dpc < nameLen,
michael@0 172 "should not pass end of string while newdpc > 2");
michael@0 173 char16_t ch = colorSpec[c * dpc];
michael@0 174 if (('1' <= ch && ch <= '9') ||
michael@0 175 ('A' <= ch && ch <= 'F') ||
michael@0 176 ('a' <= ch && ch <= 'f')) {
michael@0 177 haveNonzero = true;
michael@0 178 break;
michael@0 179 }
michael@0 180 }
michael@0 181 if (haveNonzero) {
michael@0 182 break;
michael@0 183 }
michael@0 184 --newdpc;
michael@0 185 --nameLen;
michael@0 186 ++colorSpec;
michael@0 187 }
michael@0 188
michael@0 189 // Translate components from hex to binary
michael@0 190 int r = ComponentValue(colorSpec, nameLen, 0, dpc);
michael@0 191 int g = ComponentValue(colorSpec, nameLen, 1, dpc);
michael@0 192 int b = ComponentValue(colorSpec, nameLen, 2, dpc);
michael@0 193 NS_ASSERTION((r >= 0) && (r <= 255), "bad r");
michael@0 194 NS_ASSERTION((g >= 0) && (g <= 255), "bad g");
michael@0 195 NS_ASSERTION((b >= 0) && (b <= 255), "bad b");
michael@0 196
michael@0 197 *aResult = NS_RGB(r, g, b);
michael@0 198 return true;
michael@0 199 }
michael@0 200
michael@0 201 NS_GFX_(bool) NS_ColorNameToRGB(const nsAString& aColorName, nscolor* aResult)
michael@0 202 {
michael@0 203 if (!gColorTable) return false;
michael@0 204
michael@0 205 int32_t id = gColorTable->Lookup(aColorName);
michael@0 206 if (eColorName_UNKNOWN < id) {
michael@0 207 NS_ASSERTION(uint32_t(id) < eColorName_COUNT,
michael@0 208 "gColorTable->Lookup messed up");
michael@0 209 if (aResult) {
michael@0 210 *aResult = kColors[id];
michael@0 211 }
michael@0 212 return true;
michael@0 213 }
michael@0 214 return false;
michael@0 215 }
michael@0 216
michael@0 217 // Returns kColorNames, an array of all possible color names, and sets
michael@0 218 // *aSizeArray to the size of that array. Do NOT call free() on this array.
michael@0 219 NS_GFX_(const char * const *) NS_AllColorNames(size_t *aSizeArray)
michael@0 220 {
michael@0 221 *aSizeArray = ArrayLength(kColorNames);
michael@0 222 return kColorNames;
michael@0 223 }
michael@0 224
michael@0 225 // Macro to blend two colors
michael@0 226 //
michael@0 227 // equivalent to target = (bg*(255-fgalpha) + fg*fgalpha)/255
michael@0 228 #define MOZ_BLEND(target, bg, fg, fgalpha) \
michael@0 229 FAST_DIVIDE_BY_255(target, (bg)*(255-fgalpha) + (fg)*(fgalpha))
michael@0 230
michael@0 231 NS_GFX_(nscolor)
michael@0 232 NS_ComposeColors(nscolor aBG, nscolor aFG)
michael@0 233 {
michael@0 234 // This function uses colors that are non premultiplied alpha.
michael@0 235 int r, g, b, a;
michael@0 236
michael@0 237 int bgAlpha = NS_GET_A(aBG);
michael@0 238 int fgAlpha = NS_GET_A(aFG);
michael@0 239
michael@0 240 // Compute the final alpha of the blended color
michael@0 241 // a = fgAlpha + bgAlpha*(255 - fgAlpha)/255;
michael@0 242 FAST_DIVIDE_BY_255(a, bgAlpha*(255-fgAlpha));
michael@0 243 a = fgAlpha + a;
michael@0 244 int blendAlpha;
michael@0 245 if (a == 0) {
michael@0 246 // In this case the blended color is totally trasparent,
michael@0 247 // we preserve the color information of the foreground color.
michael@0 248 blendAlpha = 255;
michael@0 249 } else {
michael@0 250 blendAlpha = (fgAlpha*255)/a;
michael@0 251 }
michael@0 252 MOZ_BLEND(r, NS_GET_R(aBG), NS_GET_R(aFG), blendAlpha);
michael@0 253 MOZ_BLEND(g, NS_GET_G(aBG), NS_GET_G(aFG), blendAlpha);
michael@0 254 MOZ_BLEND(b, NS_GET_B(aBG), NS_GET_B(aFG), blendAlpha);
michael@0 255
michael@0 256 return NS_RGBA(r, g, b, a);
michael@0 257 }
michael@0 258
michael@0 259 // Functions to convert from HSL color space to RGB color space.
michael@0 260 // This is the algorithm described in the CSS3 specification
michael@0 261
michael@0 262 // helper
michael@0 263 static float
michael@0 264 HSL_HueToRGB(float m1, float m2, float h)
michael@0 265 {
michael@0 266 if (h < 0.0f)
michael@0 267 h += 1.0f;
michael@0 268 if (h > 1.0f)
michael@0 269 h -= 1.0f;
michael@0 270 if (h < (float)(1.0/6.0))
michael@0 271 return m1 + (m2 - m1)*h*6.0f;
michael@0 272 if (h < (float)(1.0/2.0))
michael@0 273 return m2;
michael@0 274 if (h < (float)(2.0/3.0))
michael@0 275 return m1 + (m2 - m1)*((float)(2.0/3.0) - h)*6.0f;
michael@0 276 return m1;
michael@0 277 }
michael@0 278
michael@0 279 // The float parameters are all expected to be in the range 0-1
michael@0 280 NS_GFX_(nscolor)
michael@0 281 NS_HSL2RGB(float h, float s, float l)
michael@0 282 {
michael@0 283 uint8_t r, g, b;
michael@0 284 float m1, m2;
michael@0 285 if (l <= 0.5f) {
michael@0 286 m2 = l*(s+1);
michael@0 287 } else {
michael@0 288 m2 = l + s - l*s;
michael@0 289 }
michael@0 290 m1 = l*2 - m2;
michael@0 291 r = uint8_t(255 * HSL_HueToRGB(m1, m2, h + 1.0f/3.0f));
michael@0 292 g = uint8_t(255 * HSL_HueToRGB(m1, m2, h));
michael@0 293 b = uint8_t(255 * HSL_HueToRGB(m1, m2, h - 1.0f/3.0f));
michael@0 294 return NS_RGB(r, g, b);
michael@0 295 }
michael@0 296
michael@0 297 NS_GFX_(const char*)
michael@0 298 NS_RGBToColorName(nscolor aColor)
michael@0 299 {
michael@0 300 for (size_t idx = 0; idx < ArrayLength(kColors); ++idx) {
michael@0 301 if (kColors[idx] == aColor) {
michael@0 302 return kColorNames[idx];
michael@0 303 }
michael@0 304 }
michael@0 305
michael@0 306 return nullptr;
michael@0 307 }

mercurial