Bug 567283 patch 2 - Rename NS_HexToRGB to NS_HexToRGBA and add parameter saying whether 4 and 8 digit colors are allowed. r?xidorn draft
authorL. David Baron <dbaron@dbaron.org>
Sun, 08 May 2016 09:56:14 -0700
changeset 364684 a9743d4e625c3c0d7fb9637efff35f37ddc1e24f
parent 364683 262380dfb6f8ceb35225bc9a81d59c7408fe3b03
child 364685 3b741d5b02444ae0aed17f97f450d121d67c7420
push id17539
push userdbaron@mozilla.com
push dateSun, 08 May 2016 16:56:29 +0000
reviewersxidorn
bugs567283
milestone49.0a1
Bug 567283 patch 2 - Rename NS_HexToRGB to NS_HexToRGBA and add parameter saying whether 4 and 8 digit colors are allowed. r?xidorn This patch tells all callers to use the existing behavior, so it is intended not to change behavior. Callers that will be modified in later patches are marked with "FIXME" comments that will be removed in those later patches (patches 3 and 4). MozReview-Commit-ID: FaLryfxaeHv
dom/base/nsAttrValue.cpp
editor/libeditor/nsHTMLCSSUtils.cpp
gfx/src/nsColor.cpp
gfx/src/nsColor.h
gfx/tests/gtest/TestColorNames.cpp
layout/style/nsCSSParser.cpp
widget/gtk/nsColorPicker.cpp
widget/nsXPLookAndFeel.cpp
--- a/dom/base/nsAttrValue.cpp
+++ b/dom/base/nsAttrValue.cpp
@@ -1562,17 +1562,17 @@ nsAttrValue::ParseColor(const nsAString&
     return false;
   }
 
   nscolor color;
   // No color names begin with a '#'; in standards mode, all acceptable
   // numeric colors do.
   if (colorStr.First() == '#') {
     nsDependentString withoutHash(colorStr.get() + 1, colorStr.Length() - 1);
-    if (NS_HexToRGB(withoutHash, &color)) {
+    if (NS_HexToRGBA(withoutHash, nsHexColorType::NoAlpha, &color)) {
       SetColorValue(color, aString);
       return true;
     }
   } else {
     if (NS_ColorNameToRGB(colorStr, &color)) {
       SetColorValue(color, aString);
       return true;
     }
--- a/editor/libeditor/nsHTMLCSSUtils.cpp
+++ b/editor/libeditor/nsHTMLCSSUtils.cpp
@@ -1101,17 +1101,17 @@ nsHTMLCSSUtils::IsCSSEquivalentToHTMLInl
                 aHTMLAttribute->EqualsLiteral("bgcolor"))) {
       if (htmlValueString.IsEmpty()) {
         aIsSet = true;
       } else {
         nscolor rgba;
         nsAutoString subStr;
         htmlValueString.Right(subStr, htmlValueString.Length() - 1);
         if (NS_ColorNameToRGB(htmlValueString, &rgba) ||
-            NS_HexToRGB(subStr, &rgba)) {
+            NS_HexToRGBA(subStr, nsHexColorType::NoAlpha, &rgba)) {
           nsAutoString htmlColor, tmpStr;
 
           if (NS_GET_A(rgba) != 255) {
             // This should only be hit by the "transparent" keyword, which
             // currently serializes to "transparent" (not "rgba(0, 0, 0, 0)").
             MOZ_ASSERT(NS_GET_R(rgba) == 0 && NS_GET_G(rgba) == 0 &&
                        NS_GET_B(rgba) == 0 && NS_GET_A(rgba) == 0);
             htmlColor.AppendLiteral("transparent");
--- a/gfx/src/nsColor.cpp
+++ b/gfx/src/nsColor.cpp
@@ -70,56 +70,69 @@ static int ComponentValue(const char16_t
     }
     else {  // not a hex digit, treat it like 0
       component = (component * 16);
     }
   }
   return component;
 }
 
-bool NS_HexToRGB(const nsAString& aColorSpec, nscolor* aResult)
+bool NS_HexToRGBA(const nsAString& aColorSpec, nsHexColorType aType,
+                  nscolor* aResult)
 {
   const char16_t* buffer = aColorSpec.BeginReading();
 
   int nameLen = aColorSpec.Length();
+  bool hasAlpha = false;
   if (nameLen != 3 && nameLen != 6) {
-    // Improperly formatted color value
-    return false;
+    if ((nameLen != 4 && nameLen != 8) || aType == nsHexColorType::NoAlpha) {
+      // Improperly formatted color value
+      return false;
+    }
+    hasAlpha = true;
   }
 
   // Make sure the digits are legal
   for (int i = 0; i < nameLen; i++) {
     char16_t ch = buffer[i];
     if (((ch >= '0') && (ch <= '9')) ||
         ((ch >= 'a') && (ch <= 'f')) ||
         ((ch >= 'A') && (ch <= 'F'))) {
       // Legal character
       continue;
     }
     // Whoops. Illegal character.
     return false;
   }
 
   // Convert the ascii to binary
-  int dpc = ((3 == nameLen) ? 1 : 2);
+  int dpc = ((nameLen <= 4) ? 1 : 2);
   // Translate components from hex to binary
   int r = ComponentValue(buffer, nameLen, 0, dpc);
   int g = ComponentValue(buffer, nameLen, 1, dpc);
   int b = ComponentValue(buffer, nameLen, 2, dpc);
+  int a;
+  if (hasAlpha) {
+    a = ComponentValue(buffer, nameLen, 3, dpc);
+  } else {
+    a = (dpc == 1) ? 0xf : 0xff;
+  }
   if (dpc == 1) {
     // Scale single digit component to an 8 bit value. Replicate the
     // single digit to compute the new value.
     r = (r << 4) | r;
     g = (g << 4) | g;
     b = (b << 4) | b;
+    a = (a << 4) | a;
   }
   NS_ASSERTION((r >= 0) && (r <= 255), "bad r");
   NS_ASSERTION((g >= 0) && (g <= 255), "bad g");
   NS_ASSERTION((b >= 0) && (b <= 255), "bad b");
-  *aResult = NS_RGB(r, g, b);
+  NS_ASSERTION((a >= 0) && (a <= 255), "bad a");
+  *aResult = NS_RGBA(r, g, b, a);
   return true;
 }
 
 // This implements part of the algorithm for legacy behavior described in
 // http://www.whatwg.org/specs/web-apps/current-work/complete/common-microsyntaxes.html#rules-for-parsing-a-legacy-color-value
 bool NS_LooseHexToRGB(const nsString& aColorSpec, nscolor* aResult)
 {
   if (aColorSpec.EqualsLiteral("transparent")) {
--- a/gfx/src/nsColor.h
+++ b/gfx/src/nsColor.h
@@ -40,20 +40,26 @@ typedef uint32_t nscolor;
 //
 // equivalent to target=v/255
 #define FAST_DIVIDE_BY_255(target,v)               \
   PR_BEGIN_MACRO                                   \
     unsigned tmp_ = v;                             \
     target = ((tmp_ << 8) + tmp_ + 255) >> 16;     \
   PR_END_MACRO
 
+enum class nsHexColorType : uint8_t {
+  NoAlpha, // 3 or 6 digit hex colors only
+  AllowAlpha, // 3, 4, 6, or 8 digit hex colors
+};
+
 // Translate a hex string to a color. Return true if it parses ok,
 // otherwise return false.
-// This accepts only 3 or 6 digits
-bool NS_HexToRGB(const nsAString& aBuf, nscolor* aResult);
+// This accepts the number of digits specified by aType.
+bool
+NS_HexToRGBA(const nsAString& aBuf, nsHexColorType aType, nscolor* aResult);
 
 // Compose one NS_RGB color onto another. The result is what
 // you get if you draw aFG on top of aBG with operator OVER.
 nscolor NS_ComposeColors(nscolor aBG, nscolor aFG);
 
 // Translate a hex string to a color. Return true if it parses ok,
 // otherwise return false.
 // This version accepts 1 to 9 digits (missing digits are 0)
--- a/gfx/tests/gtest/TestColorNames.cpp
+++ b/gfx/tests/gtest/TestColorNames.cpp
@@ -62,23 +62,24 @@ void RunColorTests() {
       "failed at index " << index << " out of " << ArrayLength(kColorNames);
 
     // Check that parsing an RGB value in hex gets the right values
     uint8_t r = NS_GET_R(rgb);
     uint8_t g = NS_GET_G(rgb);
     uint8_t b = NS_GET_B(rgb);
     uint8_t a = NS_GET_A(rgb);
     if (a != UINT8_MAX) {
-      // NS_HexToRGB() can not handle a color with alpha channel
+      // FIXME: NS_HexToRGBA() now handle a color with alpha channel!
       rgb = NS_RGB(r, g, b);
     }
     char cbuf[50];
     snprintf_literal(cbuf, "%02x%02x%02x", r, g, b);
     nscolor hexrgb;
-    ASSERT_TRUE(NS_HexToRGB(NS_ConvertASCIItoUTF16(cbuf), &hexrgb)) <<
+    ASSERT_TRUE(NS_HexToRGBA(NS_ConvertASCIItoUTF16(cbuf),
+                             nsHexColorType::NoAlpha, &hexrgb)) <<
       "hex conversion to color of '" << cbuf << "'";
     ASSERT_TRUE(hexrgb == rgb);
   }
 }
 
 static
 void RunJunkColorTests() {
   nscolor rgb;
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -6607,17 +6607,18 @@ CSSParserImpl::ParseColor(nsCSSValue& aV
   }
 
   nsCSSToken* tk = &mToken;
   nscolor rgba;
   switch (tk->mType) {
     case eCSSToken_ID:
     case eCSSToken_Hash:
       // #xxyyzz
-      if (NS_HexToRGB(tk->mIdent, &rgba)) {
+      // FIXME
+      if (NS_HexToRGBA(tk->mIdent, nsHexColorType::NoAlpha, &rgba)) {
         MOZ_ASSERT(tk->mIdent.Length() == 3 || tk->mIdent.Length() == 6,
                    "unexpected hex color length");
         nsCSSUnit unit = tk->mIdent.Length() == 3 ?
                            eCSSUnit_ShortHexColor :
                            eCSSUnit_HexColor;
         aValue.SetIntegerColorValue(rgba, unit);
         return CSSParseResult::Ok;
       }
@@ -6761,17 +6762,18 @@ CSSParserImpl::ParseColor(nsCSSValue& aV
           str.Append(tk->mIdent);
         }
         break;
       default:
         // There is a whole bunch of cases that are
         // not handled by this switch.  Ignore them.
         break;
     }
-    if (NS_HexToRGB(str, &rgba)) {
+    // FIXME
+    if (NS_HexToRGBA(str, nsHexColorType::NoAlpha, &rgba)) {
       aValue.SetIntegerColorValue(rgba, eCSSUnit_HexColor);
       return CSSParseResult::Ok;
     }
   }
 
   // It's not a color
   REPORT_UNEXPECTED_TOKEN(PEColorNotColor);
   UngetToken();
--- a/widget/gtk/nsColorPicker.cpp
+++ b/widget/gtk/nsColorPicker.cpp
@@ -75,17 +75,17 @@ NS_IMETHODIMP nsColorPicker::Open(nsICol
   // Input color string should be 7 length (i.e. a string representing a valid
   // simple color)
   if (mInitialColor.Length() != 7) {
     return NS_ERROR_FAILURE;
   }
 
   const nsAString& withoutHash  = StringTail(mInitialColor, 6);
   nscolor color;
-  if (!NS_HexToRGB(withoutHash, &color)) {
+  if (!NS_HexToRGBA(withoutHash, nsHexColorType::NoAlpha, &color)) {
     return NS_ERROR_FAILURE;
   }
 
   if (mCallback) {
     // It means Open has already been called: this is not allowed
     NS_WARNING("mCallback is already set. Open called twice?");
     return NS_ERROR_FAILURE;
   }
--- a/widget/nsXPLookAndFeel.cpp
+++ b/widget/nsXPLookAndFeel.cpp
@@ -328,17 +328,18 @@ nsXPLookAndFeel::ColorPrefChanged (unsig
   nsAutoString colorStr;
   nsresult rv = Preferences::GetString(prefName, &colorStr);
   if (NS_FAILED(rv)) {
     return;
   }
   if (!colorStr.IsEmpty()) {
     nscolor thecolor;
     if (colorStr[0] == char16_t('#')) {
-      if (NS_HexToRGB(nsDependentString(colorStr, 1), &thecolor)) {
+      if (NS_HexToRGBA(nsDependentString(colorStr, 1),
+                       nsHexColorType::NoAlpha, &thecolor)) {
         int32_t id = NS_PTR_TO_INT32(index);
         CACHE_COLOR(id, thecolor);
       }
     } else if (NS_ColorNameToRGB(colorStr, &thecolor)) {
       int32_t id = NS_PTR_TO_INT32(index);
       CACHE_COLOR(id, thecolor);
 #ifdef DEBUG_akkana
       printf("====== Changed color pref %s to 0x%lx\n",
@@ -382,17 +383,17 @@ nsXPLookAndFeel::InitColorFromPref(int32
   nsresult rv = Preferences::GetString(sColorPrefs[i], &colorStr);
   if (NS_FAILED(rv) || colorStr.IsEmpty()) {
     return;
   }
   nscolor thecolor;
   if (colorStr[0] == char16_t('#')) {
     nsAutoString hexString;
     colorStr.Right(hexString, colorStr.Length() - 1);
-    if (NS_HexToRGB(hexString, &thecolor)) {
+    if (NS_HexToRGBA(hexString, nsHexColorType::NoAlpha, &thecolor)) {
       CACHE_COLOR(i, thecolor);
     }
   } else if (NS_ColorNameToRGB(colorStr, &thecolor)) {
     CACHE_COLOR(i, thecolor);
   }
 }
 
 // static