tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

nsColor.cpp (6330B)


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