LCOV - code coverage report
Current view: top level - gfx/src - nsColor.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 92 177 52.0 %
Date: 2017-07-14 16:53:18 Functions: 8 13 61.5 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13