Bug 1272475 - Part 1: Clamp max/min float value in the parser of CSS Transform function. r=heycam
authorBoris Chiou <boris.chiou@gmail.com>
Wed, 20 Jul 2016 15:14:05 +0800
changeset 348630 5598fd36f3d444e91938dbbfe0c150cd49f9cb28
parent 348629 6bb2750914173c6c7a54818cd62b88d6b4101695
child 348631 538b3f9574b73c4d445b4c424c24bbacdae35178
push id1230
push userjlund@mozilla.com
push dateMon, 31 Oct 2016 18:13:35 +0000
treeherdermozilla-release@5e06e3766db2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersheycam
bugs1272475
milestone50.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1272475 - Part 1: Clamp max/min float value in the parser of CSS Transform function. r=heycam To avoid calculate +/-infinite function value, we clamp it in the parser level. Also, we use EnsureNotNan while calculating the interpolation for translate function, so it's also better to do EnsureNotNan before call SetFloatValue() while calculating the interpolation for rotate (AddCSSValueAngle) and scale functions. MozReview-Commit-ID: 1k19ytyNG1N
layout/style/StyleAnimationValue.cpp
layout/style/nsCSSParser.cpp
layout/style/nsCSSValue.cpp
layout/style/nsCSSValue.h
--- a/layout/style/StyleAnimationValue.cpp
+++ b/layout/style/StyleAnimationValue.cpp
@@ -1077,23 +1077,25 @@ AddCSSValueCanonicalCalc(double aCoeff1,
 
 static void
 AddCSSValueAngle(double aCoeff1, const nsCSSValue &aValue1,
                  double aCoeff2, const nsCSSValue &aValue2,
                  nsCSSValue &aResult)
 {
   if (aValue1.GetUnit() == aValue2.GetUnit()) {
     // To avoid floating point error, if the units match, maintain the unit.
-    aResult.SetFloatValue(aCoeff1 * aValue1.GetFloatValue() +
-                          aCoeff2 * aValue2.GetFloatValue(),
-                          aValue1.GetUnit());
+    aResult.SetFloatValue(
+      EnsureNotNan(aCoeff1 * aValue1.GetFloatValue() +
+                   aCoeff2 * aValue2.GetFloatValue()),
+      aValue1.GetUnit());
   } else {
-    aResult.SetFloatValue(aCoeff1 * aValue1.GetAngleValueInRadians() +
-                          aCoeff2 * aValue2.GetAngleValueInRadians(),
-                          eCSSUnit_Radian);
+    aResult.SetFloatValue(
+      EnsureNotNan(aCoeff1 * aValue1.GetAngleValueInRadians() +
+                   aCoeff2 * aValue2.GetAngleValueInRadians()),
+      eCSSUnit_Radian);
   }
 }
 
 static bool
 AddCSSValuePixelPercentCalc(const uint32_t aValueRestrictions,
                             const nsCSSUnit aCommonUnit,
                             double aCoeff1, const nsCSSValue &aValue1,
                             double aCoeff2, const nsCSSValue &aValue2,
@@ -1249,17 +1251,17 @@ AddTransformScale(double aCoeff1, const 
   // back.  This gets the right AddWeighted behavior and gets us the
   // interpolation-against-identity behavior for free.
   MOZ_ASSERT(aValue1.GetUnit() == eCSSUnit_Number, "unexpected unit");
   MOZ_ASSERT(aValue2.GetUnit() == eCSSUnit_Number, "unexpected unit");
 
   float v1 = aValue1.GetFloatValue() - 1.0f,
         v2 = aValue2.GetFloatValue() - 1.0f;
   float result = v1 * aCoeff1 + v2 * aCoeff2;
-  aResult.SetFloatValue(result + 1.0f, eCSSUnit_Number);
+  aResult.SetFloatValue(EnsureNotNan(result + 1.0f), eCSSUnit_Number);
 }
 
 /* static */ already_AddRefed<nsCSSValue::Array>
 StyleAnimationValue::AppendTransformFunction(nsCSSKeyword aTransformFunction,
                                              nsCSSValueList**& aListTail)
 {
   RefPtr<nsCSSValue::Array> arr = AppendFunction(aTransformFunction);
   nsCSSValueList *item = new nsCSSValueList;
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -15412,16 +15412,26 @@ CSSParserImpl::ParseFunctionInternals(co
 
   for (uint16_t index = 0; index < aMaxElems; ++index) {
     nsCSSValue newValue;
     uint32_t m = aVariantMaskAll ? aVariantMaskAll : aVariantMask[index];
     if (ParseVariant(newValue, m, nullptr) != CSSParseResult::Ok) {
       break;
     }
 
+    if (nsCSSValue::IsFloatUnit(newValue.GetUnit())) {
+      // Clamp infinity or -infinity values to max float or -max float to avoid
+      // calculations with infinity.
+      newValue.SetFloatValue(
+        mozilla::clamped(newValue.GetFloatValue(),
+                         -std::numeric_limits<float>::max(),
+                          std::numeric_limits<float>::max()),
+        newValue.GetUnit());
+    }
+
     aOutput.AppendElement(newValue);
 
     if (ExpectSymbol(',', true)) {
       // Move on to the next argument if we see a comma.
       continue;
     }
 
     if (ExpectSymbol(')', true)) {
--- a/layout/style/nsCSSValue.cpp
+++ b/layout/style/nsCSSValue.cpp
@@ -408,19 +408,19 @@ void nsCSSValue::SetPercentValue(float a
   Reset();
   mUnit = eCSSUnit_Percent;
   mValue.mFloat = aValue;
   MOZ_ASSERT(!mozilla::IsNaN(mValue.mFloat));
 }
 
 void nsCSSValue::SetFloatValue(float aValue, nsCSSUnit aUnit)
 {
-  MOZ_ASSERT(eCSSUnit_Number <= aUnit, "not a float value");
+  MOZ_ASSERT(IsFloatUnit(aUnit), "not a float value");
   Reset();
-  if (eCSSUnit_Number <= aUnit) {
+  if (IsFloatUnit(aUnit)) {
     mUnit = aUnit;
     mValue.mFloat = aValue;
     MOZ_ASSERT(!mozilla::IsNaN(mValue.mFloat));
   }
 }
 
 void nsCSSValue::SetStringValue(const nsString& aValue,
                                 nsCSSUnit aUnit)
--- a/layout/style/nsCSSValue.h
+++ b/layout/style/nsCSSValue.h
@@ -511,16 +511,18 @@ public:
     { return eCSSUnit_EM <= mUnit && mUnit <= eCSSUnit_RootEM; }
   /**
    * A "pixel" length unit is a some multiple of CSS pixels.
    */
   static bool IsPixelLengthUnit(nsCSSUnit aUnit)
     { return eCSSUnit_Point <= aUnit && aUnit <= eCSSUnit_Pixel; }
   bool      IsPixelLengthUnit() const
     { return IsPixelLengthUnit(mUnit); }
+  static bool IsFloatUnit(nsCSSUnit aUnit)
+    { return eCSSUnit_Number <= aUnit; }
   bool      IsAngularUnit() const  
     { return eCSSUnit_Degree <= mUnit && mUnit <= eCSSUnit_Turn; }
   bool      IsFrequencyUnit() const  
     { return eCSSUnit_Hertz <= mUnit && mUnit <= eCSSUnit_Kilohertz; }
   bool      IsTimeUnit() const  
     { return eCSSUnit_Seconds <= mUnit && mUnit <= eCSSUnit_Milliseconds; }
   bool      IsCalcUnit() const
     { return eCSSUnit_Calc <= mUnit && mUnit <= eCSSUnit_Calc_Divided; }