Bug 1299741 part 7 - Support storing ComplexColor in nsCSSValue and StyleAnimationValue. r=heycam draft
authorXidorn Quan <me@upsuper.org>
Fri, 16 Sep 2016 15:30:35 +1000
changeset 415366 722d2aee06e59cdf061d0daae43d8dbc0a9641b4
parent 415365 2e914c26fac4613c25d5f1381693617a9bbbe412
child 415367 2582ce0e1a665701958f3647d871d8febe7f93fb
push id29862
push userxquan@mozilla.com
push dateTue, 20 Sep 2016 08:44:59 +0000
reviewersheycam
bugs1299741
milestone52.0a1
Bug 1299741 part 7 - Support storing ComplexColor in nsCSSValue and StyleAnimationValue. r=heycam This is a complete rewrite of the original part 8. Instead of storing the ratio in mValueExtra, all values are stored in a struct in heap, so that we support range outside [0.0, 1.0] in computation. MozReview-Commit-ID: 7xUZSgQE5vA
layout/style/StyleAnimationValue.cpp
layout/style/StyleAnimationValue.h
layout/style/nsCSSValue.cpp
layout/style/nsCSSValue.h
--- a/layout/style/StyleAnimationValue.cpp
+++ b/layout/style/StyleAnimationValue.cpp
@@ -3206,16 +3206,21 @@ StyleAnimationValue::UncomputeValue(nsCS
                  (unit == eUnit_ObjectPosition &&
                   val->GetUnit() == eCSSUnit_Array) ||
                  (unit == eUnit_URL && val->GetUnit() == eCSSUnit_URL) ||
                  unit == eUnit_DiscreteCSSValue,
                  "unexpected unit");
       aSpecifiedValue = *val;
       break;
     }
+    case eUnit_ComplexColor: {
+      aSpecifiedValue.SetComplexColorValue(
+        do_AddRef(aComputedValue.mValue.mComplexColor));
+      break;
+    }
     case eUnit_CSSValuePair: {
       // Rule node processing expects pair values to be collapsed to a
       // single value if both halves would be equal, for most but not
       // all properties.  At present, all animatable properties that
       // use pairs do expect collapsing.
       const nsCSSValuePair* pair = aComputedValue.GetCSSValuePairValue();
       if (pair->mXValue == pair->mYValue) {
         aSpecifiedValue = pair->mXValue;
@@ -4512,16 +4517,21 @@ StyleAnimationValue::operator=(const Sty
                  "value pair lists may not be null");
       mValue.mCSSValuePairList = aOther.mValue.mCSSValuePairList->Clone();
       break;
     case eUnit_UnparsedString:
       MOZ_ASSERT(aOther.mValue.mString, "expecting non-null string");
       mValue.mString = aOther.mValue.mString;
       mValue.mString->AddRef();
       break;
+    case eUnit_ComplexColor:
+      MOZ_ASSERT(aOther.mValue.mComplexColor);
+      mValue.mComplexColor = aOther.mValue.mComplexColor;
+      mValue.mComplexColor->AddRef();
+      break;
   }
 
   return *this;
 }
 
 void
 StyleAnimationValue::SetNormalValue()
 {
@@ -4590,16 +4600,37 @@ StyleAnimationValue::SetColorValue(nscol
 void
 StyleAnimationValue::SetCurrentColorValue()
 {
   FreeValue();
   mUnit = eUnit_CurrentColor;
 }
 
 void
+StyleAnimationValue::SetComplexColorValue(const StyleComplexColor& aColor)
+{
+  if (aColor.IsCurrentColor()) {
+    SetCurrentColorValue();
+  } else if (aColor.IsNumericColor()) {
+    SetColorValue(aColor.mColor);
+  } else {
+    SetComplexColorValue(do_AddRef(new ComplexColorValue(aColor)));
+  }
+}
+
+void
+StyleAnimationValue::SetComplexColorValue(
+  already_AddRefed<ComplexColorValue> aValue)
+{
+  FreeValue();
+  mUnit = eUnit_ComplexColor;
+  mValue.mComplexColor = aValue.take();
+}
+
+void
 StyleAnimationValue::SetUnparsedStringValue(const nsString& aString)
 {
   FreeValue();
   mUnit = eUnit_UnparsedString;
   mValue.mString = nsCSSValue::BufferFromString(aString).take();
 }
 
 void
@@ -4707,16 +4738,18 @@ StyleAnimationValue::FreeValue()
     delete mValue.mCSSRect;
   } else if (IsCSSValuePairListUnit(mUnit)) {
     delete mValue.mCSSValuePairList;
   } else if (IsCSSValueArrayUnit(mUnit)) {
     mValue.mCSSValueArray->Release();
   } else if (IsStringUnit(mUnit)) {
     MOZ_ASSERT(mValue.mString, "expecting non-null string");
     mValue.mString->Release();
+  } else if (mUnit == eUnit_ComplexColor) {
+    mValue.mComplexColor->Release();
   }
 }
 
 bool
 StyleAnimationValue::operator==(const StyleAnimationValue& aOther) const
 {
   if (mUnit != aOther.mUnit) {
     return false;
@@ -4763,13 +4796,15 @@ StyleAnimationValue::operator==(const St
     case eUnit_Transform:
       return *mValue.mCSSValueSharedList == *aOther.mValue.mCSSValueSharedList;
     case eUnit_CSSValuePairList:
       return nsCSSValuePairList::Equal(mValue.mCSSValuePairList,
                                        aOther.mValue.mCSSValuePairList);
     case eUnit_UnparsedString:
       return (NS_strcmp(GetStringBufferValue(),
                         aOther.GetStringBufferValue()) == 0);
+    case eUnit_ComplexColor:
+      return *mValue.mComplexColor == *aOther.mValue.mComplexColor;
   }
 
   NS_NOTREACHED("incomplete case");
   return false;
 }
--- a/layout/style/StyleAnimationValue.h
+++ b/layout/style/StyleAnimationValue.h
@@ -315,16 +315,17 @@ public:
                       // Enumerated to Visibility as needed)
     eUnit_Integer,
     eUnit_Coord,
     eUnit_Percent,
     eUnit_Float,
     eUnit_Color, // nsCSSValue* (never null), always with an nscolor or
                  // an nsCSSValueFloatColor
     eUnit_CurrentColor,
+    eUnit_ComplexColor, // ComplexColorValue* (never null)
     eUnit_Calc, // nsCSSValue* (never null), always with a single
                 // calc() expression that's either length or length+percent
     eUnit_ObjectPosition, // nsCSSValue* (never null), always with a
                           // 4-entry nsCSSValue::Array
     eUnit_URL, // nsCSSValue* (never null), always with a css::URLValue
     eUnit_DiscreteCSSValue, // nsCSSValue* (never null)
     eUnit_CSSValuePair, // nsCSSValuePair* (never null)
     eUnit_CSSValueTriplet, // nsCSSValueTriplet* (never null)
@@ -349,16 +350,17 @@ private:
     nsCSSValuePair* mCSSValuePair;
     nsCSSValueTriplet* mCSSValueTriplet;
     nsCSSRect* mCSSRect;
     nsCSSValue::Array* mCSSValueArray;
     nsCSSValueList* mCSSValueList;
     nsCSSValueSharedList* mCSSValueSharedList;
     nsCSSValuePairList* mCSSValuePairList;
     nsStringBuffer* mString;
+    css::ComplexColorValue* mComplexColor;
   } mValue;
 
 public:
   Unit GetUnit() const {
     NS_ASSERTION(mUnit != eUnit_Null, "uninitialized");
     return mUnit;
   }
 
@@ -426,16 +428,24 @@ public:
     aBuffer.Truncate();
     uint32_t len = NS_strlen(GetBufferValue(mValue.mString));
     mValue.mString->ToString(len, aBuffer);
   }
 
   /// @return the scale for this value, calculated with reference to @aForFrame.
   gfxSize GetScaleValue(const nsIFrame* aForFrame) const;
 
+  const css::ComplexColorData& GetComplexColorData() const {
+    MOZ_ASSERT(mUnit == eUnit_ComplexColor, "unit mismatch");
+    return *mValue.mComplexColor;
+  }
+  StyleComplexColor GetStyleComplexColorValue() const {
+    return GetComplexColorData().ToComplexColor();
+  }
+
   UniquePtr<nsCSSValueList> TakeCSSValueListValue() {
     nsCSSValueList* list = GetCSSValueListValue();
     mValue.mCSSValueList = nullptr;
     mUnit = eUnit_Null;
     return UniquePtr<nsCSSValueList>(list);
   }
   UniquePtr<nsCSSValuePairList> TakeCSSValuePairListValue() {
     nsCSSValuePairList* list = GetCSSValuePairListValue();
@@ -482,16 +492,18 @@ public:
                   "aValue must be an enum that fits within mValue.mInt");
     SetIntValue(static_cast<int32_t>(aInt), aUnit);
   }
   void SetCoordValue(nscoord aCoord);
   void SetPercentValue(float aPercent);
   void SetFloatValue(float aFloat);
   void SetColorValue(nscolor aColor);
   void SetCurrentColorValue();
+  void SetComplexColorValue(const StyleComplexColor& aColor);
+  void SetComplexColorValue(already_AddRefed<css::ComplexColorValue> aValue);
   void SetUnparsedStringValue(const nsString& aString);
   void SetCSSValueArrayValue(nsCSSValue::Array* aValue, Unit aUnit);
 
   // These setters take ownership of |aValue|, and are therefore named
   // "SetAndAdopt*".
   void SetAndAdoptCSSValueValue(nsCSSValue *aValue, Unit aUnit);
   void SetAndAdoptCSSValuePairValue(nsCSSValuePair *aValue, Unit aUnit);
   void SetAndAdoptCSSValueTripletValue(nsCSSValueTriplet *aValue, Unit aUnit);
--- a/layout/style/nsCSSValue.cpp
+++ b/layout/style/nsCSSValue.cpp
@@ -156,16 +156,20 @@ nsCSSValue::nsCSSValue(const nsCSSValue&
   }
   else if (IsIntegerColorUnit()) {
     mValue.mColor = aCopy.mValue.mColor;
   }
   else if (IsFloatColorUnit()) {
     mValue.mFloatColor = aCopy.mValue.mFloatColor;
     mValue.mFloatColor->AddRef();
   }
+  else if (eCSSUnit_ComplexColor == mUnit) {
+    mValue.mComplexColor = aCopy.mValue.mComplexColor;
+    mValue.mComplexColor->AddRef();
+  }
   else if (UnitHasArrayValue()) {
     mValue.mArray = aCopy.mValue.mArray;
     mValue.mArray->AddRef();
   }
   else if (eCSSUnit_URL == mUnit) {
     mValue.mURL = aCopy.mValue.mURL;
     mValue.mURL->AddRef();
   }
@@ -266,16 +270,19 @@ bool nsCSSValue::operator==(const nsCSSV
       return mValue.mInt == aOther.mValue.mInt;
     }
     else if (IsIntegerColorUnit()) {
       return mValue.mColor == aOther.mValue.mColor;
     }
     else if (IsFloatColorUnit()) {
       return *mValue.mFloatColor == *aOther.mValue.mFloatColor;
     }
+    else if (eCSSUnit_ComplexColor == mUnit) {
+      return *mValue.mComplexColor == *aOther.mValue.mComplexColor;
+    }
     else if (UnitHasArrayValue()) {
       return *mValue.mArray == *aOther.mValue.mArray;
     }
     else if (eCSSUnit_URL == mUnit) {
       return *mValue.mURL == *aOther.mValue.mURL;
     }
     else if (eCSSUnit_Image == mUnit) {
       return *mValue.mImage == *aOther.mValue.mImage;
@@ -372,16 +379,18 @@ nscoord nsCSSValue::GetPixelLength() con
 }
 
 void nsCSSValue::DoReset()
 {
   if (UnitHasStringValue()) {
     mValue.mString->Release();
   } else if (IsFloatColorUnit()) {
     mValue.mFloatColor->Release();
+  } else if (eCSSUnit_ComplexColor == mUnit) {
+    mValue.mComplexColor->Release();
   } else if (UnitHasArrayValue()) {
     mValue.mArray->Release();
   } else if (eCSSUnit_URL == mUnit) {
     mValue.mURL->Release();
   } else if (eCSSUnit_Image == mUnit) {
     mValue.mImage->Release();
   } else if (eCSSUnit_Gradient == mUnit) {
     mValue.mGradient->Release();
@@ -480,16 +489,24 @@ void nsCSSValue::SetFloatColorValue(floa
 
 void
 nsCSSValue::SetRGBAColorValue(const RGBAColorData& aValue)
 {
   SetFloatColorValue(aValue.mR, aValue.mG, aValue.mB,
                      aValue.mA, eCSSUnit_PercentageRGBAColor);
 }
 
+void
+nsCSSValue::SetComplexColorValue(already_AddRefed<ComplexColorValue> aValue)
+{
+  Reset();
+  mUnit = eCSSUnit_ComplexColor;
+  mValue.mComplexColor = aValue.take();
+}
+
 void nsCSSValue::SetArrayValue(nsCSSValue::Array* aValue, nsCSSUnit aUnit)
 {
   Reset();
   mUnit = aUnit;
   MOZ_ASSERT(UnitHasArrayValue(), "bad unit");
   mValue.mArray = aValue;
   mValue.mArray->AddRef();
 }
@@ -1568,16 +1585,28 @@ nsCSSValue::AppendToString(nsCSSProperty
       if (eCSSUnit_ShortHexColorAlpha == unit) {
         aResult.AppendInt(NS_GET_A(color) / 0x11, 16);
       }
     } else {
       MOZ_ASSERT(IsFloatColorUnit());
       mValue.mFloatColor->AppendToString(unit, aResult);
     }
   }
+  else if (eCSSUnit_ComplexColor == unit) {
+    StyleComplexColor color = GetStyleComplexColorValue();
+    nsCSSValue serializable;
+    if (color.IsCurrentColor()) {
+      serializable.SetIntValue(NS_COLOR_CURRENTCOLOR, eCSSUnit_EnumColor);
+    } else if (color.IsNumericColor()) {
+      serializable.SetColorValue(color.mColor);
+    } else {
+      MOZ_ASSERT_UNREACHABLE("Cannot serialize a complex color");
+    }
+    serializable.AppendToString(aProperty, aResult, aSerialization);
+  }
   else if (eCSSUnit_URL == unit || eCSSUnit_Image == unit) {
     aResult.AppendLiteral("url(");
     nsStyleUtil::AppendEscapedCSSString(
       nsDependentString(GetOriginalURLValue()), aResult);
     aResult.Append(')');
   }
   else if (eCSSUnit_Element == unit) {
     aResult.AppendLiteral("-moz-element(#");
@@ -1864,16 +1893,17 @@ nsCSSValue::AppendToString(nsCSSProperty
     case eCSSUnit_HexColor:              break;
     case eCSSUnit_ShortHexColor:         break;
     case eCSSUnit_HexColorAlpha:         break;
     case eCSSUnit_ShortHexColorAlpha:    break;
     case eCSSUnit_PercentageRGBColor:    break;
     case eCSSUnit_PercentageRGBAColor:   break;
     case eCSSUnit_HSLColor:              break;
     case eCSSUnit_HSLAColor:             break;
+    case eCSSUnit_ComplexColor:          break;
     case eCSSUnit_Percent:      aResult.Append(char16_t('%'));    break;
     case eCSSUnit_Number:       break;
     case eCSSUnit_Gradient:     break;
     case eCSSUnit_TokenStream:  break;
     case eCSSUnit_Pair:         break;
     case eCSSUnit_Triplet:      break;
     case eCSSUnit_Rect:         break;
     case eCSSUnit_List:         break;
@@ -2051,16 +2081,21 @@ nsCSSValue::SizeOfExcludingThis(mozilla:
     // Float Color
     case eCSSUnit_PercentageRGBColor:
     case eCSSUnit_PercentageRGBAColor:
     case eCSSUnit_HSLColor:
     case eCSSUnit_HSLAColor:
       n += mValue.mFloatColor->SizeOfIncludingThis(aMallocSizeOf);
       break;
 
+    // Complex Color
+    case eCSSUnit_ComplexColor:
+      n += mValue.mComplexColor->SizeOfIncludingThis(aMallocSizeOf);
+      break;
+
     // Float: nothing extra to measure.
     case eCSSUnit_Percent:
     case eCSSUnit_Number:
     case eCSSUnit_PhysicalMillimeter:
     case eCSSUnit_ViewportWidth:
     case eCSSUnit_ViewportHeight:
     case eCSSUnit_ViewportMin:
     case eCSSUnit_ViewportMax:
@@ -2779,16 +2814,27 @@ css::ImageValue::~ImageValue()
     if (proxy) {
       proxy->CancelAndForgetObserver(NS_BINDING_ABORTED);
     }
 
     iter.Remove();
   }
 }
 
+size_t
+css::ComplexColorValue::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
+{
+  // Only measure it if it's unshared, to avoid double-counting.
+  size_t n = 0;
+  if (mRefCnt <= 1) {
+    n += aMallocSizeOf(this);
+  }
+  return n;
+}
+
 nsCSSValueGradientStop::nsCSSValueGradientStop()
   : mLocation(eCSSUnit_None),
     mColor(eCSSUnit_Null),
     mIsInterpolationHint(false)
 {
   MOZ_COUNT_CTOR(nsCSSValueGradientStop);
 }
 
--- a/layout/style/nsCSSValue.h
+++ b/layout/style/nsCSSValue.h
@@ -8,16 +8,17 @@
 #ifndef nsCSSValue_h___
 #define nsCSSValue_h___
 
 #include <type_traits>
 
 #include "mozilla/Attributes.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/SheetType.h"
+#include "mozilla/StyleComplexColor.h"
 #include "mozilla/UniquePtr.h"
 
 #include "nsIPrincipal.h"
 #include "nsIURI.h"
 #include "nsCOMPtr.h"
 #include "nsCSSKeywords.h"
 #include "nsCSSPropertyID.h"
 #include "nsCSSProps.h"
@@ -340,16 +341,66 @@ struct RGBAColorData
   RGBAColorData WithAlpha(float aAlpha) const
   {
     RGBAColorData result = *this;
     result.mA = aAlpha;
     return result;
   }
 };
 
+struct ComplexColorData
+{
+  RGBAColorData mColor;
+  float mForegroundRatio;
+
+  ComplexColorData() = default;
+  ComplexColorData(const RGBAColorData& aColor, float aForegroundRatio)
+    : mColor(aColor), mForegroundRatio(aForegroundRatio) {}
+  ComplexColorData(nscolor aColor, float aForegroundRatio)
+    : mColor(aColor), mForegroundRatio(aForegroundRatio) {}
+  explicit ComplexColorData(const StyleComplexColor& aColor)
+    : mColor(aColor.mColor)
+    , mForegroundRatio(aColor.mForegroundRatio * (1.0f / 255.0f)) {}
+
+  bool operator==(const ComplexColorData& aOther) const
+  {
+    return mForegroundRatio == aOther.mForegroundRatio &&
+           (IsCurrentColor() || mColor == aOther.mColor);
+  }
+  bool operator!=(const ComplexColorData& aOther) const
+  {
+    return !(*this == aOther);
+  }
+
+  bool IsCurrentColor() const { return mForegroundRatio >= 1.0f; }
+  bool IsNumericColor() const { return mForegroundRatio <= 0.0f; }
+
+  StyleComplexColor ToComplexColor() const
+  {
+    return StyleComplexColor(
+      mColor.ToColor(), ClampColor(mForegroundRatio * 255.0f));
+  }
+};
+
+struct ComplexColorValue final : public ComplexColorData
+{
+  // Just redirect any parameter to the data struct.
+  template<typename... Args>
+  explicit ComplexColorValue(Args&&... aArgs)
+    : ComplexColorData(Forward<Args>(aArgs)...) {}
+  ComplexColorValue(const ComplexColorValue&) = delete;
+
+  NS_INLINE_DECL_REFCOUNTING(ComplexColorValue)
+
+  size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
+
+private:
+  ~ComplexColorValue() {}
+};
+
 } // namespace css
 } // namespace mozilla
 
 enum nsCSSUnit {
   eCSSUnit_Null         = 0,      // (n/a) null unit, value is not specified
   eCSSUnit_Auto         = 1,      // (n/a) value is algorithmic
   eCSSUnit_Inherit      = 2,      // (n/a) value is inherited
   eCSSUnit_Initial      = 3,      // (n/a) value is default UA value
@@ -434,16 +485,17 @@ enum nsCSSUnit {
                                        // percentage components. Values over
                                        // 100% are allowed.
   eCSSUnit_PercentageRGBAColor = 88,   // (nsCSSValueFloatColor*) an RGBA value
                                        // specified as rgba() with percentage
                                        // components. Values over 100% are
                                        // allowed.
   eCSSUnit_HSLColor            = 89,   // (nsCSSValueFloatColor*)
   eCSSUnit_HSLAColor           = 90,   // (nsCSSValueFloatColor*)
+  eCSSUnit_ComplexColor        = 91,   // (ComplexColorValue*)
 
   eCSSUnit_Percent      = 100,     // (float) 1.0 == 100%) value is percentage of something
   eCSSUnit_Number       = 101,     // (float) value is numeric (usually multiplier, different behavior than percent)
 
   // Physical length units
   eCSSUnit_PhysicalMillimeter = 200,   // (float) 1/25.4 inch
 
   // Length units - relative
@@ -682,16 +734,21 @@ public:
   const char16_t* GetStringBufferValue() const
   {
     MOZ_ASSERT(UnitHasStringValue(), "not a string value");
     return GetBufferValue(mValue.mString);
   }
 
   nscolor GetColorValue() const;
   bool IsNonTransparentColor() const;
+  mozilla::StyleComplexColor GetStyleComplexColorValue() const
+  {
+    MOZ_ASSERT(mUnit == eCSSUnit_ComplexColor);
+    return mValue.mComplexColor->ToComplexColor();
+  }
 
   Array* GetArrayValue() const
   {
     MOZ_ASSERT(UnitHasArrayValue(), "not an array value");
     return mValue.mArray;
   }
 
   nsIURI* GetURLValue() const
@@ -813,16 +870,18 @@ public:
   void SetStringValue(const nsString& aValue, nsCSSUnit aUnit);
   void SetColorValue(nscolor aValue);
   void SetIntegerColorValue(nscolor aValue, nsCSSUnit aUnit);
   void SetFloatColorValue(float aComponent1,
                           float aComponent2,
                           float aComponent3,
                           float aAlpha, nsCSSUnit aUnit);
   void SetRGBAColorValue(const mozilla::css::RGBAColorData& aValue);
+  void SetComplexColorValue(
+    already_AddRefed<mozilla::css::ComplexColorValue> aValue);
   void SetArrayValue(nsCSSValue::Array* aArray, nsCSSUnit aUnit);
   void SetURLValue(mozilla::css::URLValue* aURI);
   void SetImageValue(mozilla::css::ImageValue* aImage);
   void SetGradientValue(nsCSSValueGradient* aGradient);
   void SetTokenStreamValue(nsCSSValueTokenStream* aTokenStream);
   void SetGridTemplateAreas(mozilla::css::GridTemplateAreasValue* aValue);
   void SetFontFamilyListValue(mozilla::css::FontFamilyListRefCnt* aFontListValue);
   void SetPairValue(const nsCSSValuePair* aPair);
@@ -920,16 +979,17 @@ protected:
     nsCSSValueTriplet_heap* MOZ_OWNING_REF mTriplet;
     nsCSSValueList_heap* MOZ_OWNING_REF mList;
     nsCSSValueList* mListDependent;
     nsCSSValueSharedList* MOZ_OWNING_REF mSharedList;
     nsCSSValuePairList_heap* MOZ_OWNING_REF mPairList;
     nsCSSValuePairList* mPairListDependent;
     nsCSSValueFloatColor* MOZ_OWNING_REF mFloatColor;
     mozilla::css::FontFamilyListRefCnt* MOZ_OWNING_REF mFontFamilyList;
+    mozilla::css::ComplexColorValue* MOZ_OWNING_REF mComplexColor;
   } mValue;
 };
 
 struct nsCSSValue::Array final {
 
   // return |Array| with reference count of zero
   static Array* Create(size_t aItemCount) {
     return new (aItemCount) Array(aItemCount);