Bug 1512745 - Use nsWhitespaceTokenizer to ignore leading and trailing whitespace r=longsonr
authorviolet <violet.bugreport@gmail.com>
Wed, 27 Mar 2019 08:52:33 +0000
changeset 466313 c887f70fb725b6379c1504742eb973b51b087610
parent 466312 526c37cbcb1f39aca62ab3171e0d7ee8b4581dd6
child 466314 d6e162d3efdc67c7f4d51589382d2c4c4db27778
push id35764
push useraciure@mozilla.com
push dateWed, 27 Mar 2019 16:35:35 +0000
treeherdermozilla-central@16f19322ec76 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerslongsonr
bugs1512745
milestone68.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 1512745 - Use nsWhitespaceTokenizer to ignore leading and trailing whitespace r=longsonr Length attribute should allow leading and trailing whitespace per SVG2. Differential Revision: https://phabricator.services.mozilla.com/D23628
dom/smil/test/smilAnimateMotionValueLists.js
dom/svg/SVGContentUtils.cpp
dom/svg/SVGContentUtils.h
dom/svg/SVGInteger.cpp
dom/svg/SVGLength.cpp
dom/svg/SVGOrient.cpp
dom/svg/nsSVGLength2.cpp
dom/svg/nsSVGNumber2.cpp
dom/svg/test/test_lengthParsing.html
--- a/dom/smil/test/smilAnimateMotionValueLists.js
+++ b/dom/smil/test/smilAnimateMotionValueLists.js
@@ -32,27 +32,27 @@ const gInvalidValues = [
 ];
 
 const gValidRotate = [
   "10",
   "20.1",
   "30.5deg",
   "0.5rad",
   "auto",
-  "auto-reverse"
+  "auto-reverse",
+  " 10 ",
+  "  10deg",
+  "10deg ",
+  " 10.1 "
 ];
 
 const gInvalidRotate = [
-  " 10 ",
-  "  10deg",
   "10 deg",
-  "10deg ",
   "10 rad    ",
-  "aaa",
-  " 10.1 ",
+  "aaa"
 ];
 
 const gValidToBy = [
  "0 0",
  "1em,2",
  "50.3em 0.2in",
  " 1,2",
  "1 2 "
--- a/dom/svg/SVGContentUtils.cpp
+++ b/dom/svg/SVGContentUtils.cpp
@@ -18,16 +18,17 @@
 #include "mozilla/SVGContextPaint.h"
 #include "mozilla/TextUtils.h"
 #include "nsComputedDOMStyle.h"
 #include "nsFontMetrics.h"
 #include "nsIFrame.h"
 #include "nsIScriptError.h"
 #include "nsLayoutUtils.h"
 #include "nsMathUtils.h"
+#include "nsWhitespaceTokenizer.h"
 #include "SVGAnimationElement.h"
 #include "SVGAnimatedPreserveAspectRatio.h"
 #include "nsContentUtils.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/gfx/Types.h"
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/ComputedStyle.h"
 #include "SVGPathDataParser.h"
@@ -793,9 +794,27 @@ already_AddRefed<gfx::Path> SVGContentUt
   return pathData.BuildPath(builder, NS_STYLE_STROKE_LINECAP_BUTT, 1);
 }
 
 bool SVGContentUtils::ShapeTypeHasNoCorners(const nsIContent* aContent) {
   return aContent &&
          aContent->IsAnyOfSVGElements(nsGkAtoms::circle, nsGkAtoms::ellipse);
 }
 
+nsDependentSubstring SVGContentUtils::GetAndEnsureOneToken(
+    const nsAString& aString, bool& aSuccess) {
+  nsWhitespaceTokenizerTemplate<nsContentUtils::IsHTMLWhitespace> tokenizer(
+      aString);
+
+  aSuccess = false;
+  if (!tokenizer.hasMoreTokens()) {
+    return {};
+  }
+  auto token = tokenizer.nextToken();
+  if (tokenizer.hasMoreTokens()) {
+    return {};
+  }
+
+  aSuccess = true;
+  return token;
+}
+
 }  // namespace mozilla
--- a/dom/svg/SVGContentUtils.h
+++ b/dom/svg/SVGContentUtils.h
@@ -12,16 +12,17 @@
 
 #include "mozilla/gfx/2D.h"  // for StrokeOptions
 #include "mozilla/gfx/Matrix.h"
 #include "mozilla/RangedPtr.h"
 #include "nsStyleCoord.h"
 #include "nsError.h"
 #include "nsStringFwd.h"
 #include "gfx2DGlue.h"
+#include "nsDependentSubstring.h"
 
 class nsIContent;
 
 class nsIFrame;
 class nsPresContext;
 
 namespace mozilla {
 class ComputedStyle;
@@ -330,13 +331,21 @@ class SVGContentUtils {
   static already_AddRefed<mozilla::gfx::Path> GetPath(
       const nsAString& aPathString);
 
   /**
    *  Returns true if aContent is one of the elements whose stroke is guaranteed
    *  to have no corners: circle or ellipse
    */
   static bool ShapeTypeHasNoCorners(const nsIContent* aContent);
+
+  /**
+   *  Return one token in aString, aString may have leading and trailing
+   * whitespace; aSuccess will be set to false if there is no token or more than
+   * one token, otherwise it's set to true.
+   */
+  static nsDependentSubstring GetAndEnsureOneToken(const nsAString& aString,
+                                                   bool& aSuccess);
 };
 
 }  // namespace mozilla
 
 #endif
--- a/dom/svg/SVGInteger.cpp
+++ b/dom/svg/SVGInteger.cpp
@@ -18,19 +18,26 @@ namespace mozilla {
 
 /* Implementation */
 
 static SVGAttrTearoffTable<SVGInteger, SVGInteger::DOMAnimatedInteger>
     sSVGAnimatedIntegerTearoffTable;
 
 nsresult SVGInteger::SetBaseValueString(const nsAString &aValueAsString,
                                         SVGElement *aSVGElement) {
+  bool success;
+  auto token = SVGContentUtils::GetAndEnsureOneToken(aValueAsString, success);
+
+  if (!success) {
+    return NS_ERROR_DOM_SYNTAX_ERR;
+  }
+
   int32_t value;
 
-  if (!SVGContentUtils::ParseInteger(aValueAsString, value)) {
+  if (!SVGContentUtils::ParseInteger(token, value)) {
     return NS_ERROR_DOM_SYNTAX_ERR;
   }
 
   mIsBaseSet = true;
   mBaseVal = value;
   if (!mIsAnimated) {
     mAnimVal = mBaseVal;
   } else {
--- a/dom/svg/SVGLength.cpp
+++ b/dom/svg/SVGLength.cpp
@@ -27,19 +27,25 @@ void SVGLength::GetValueAsString(nsAStri
   nsTextFormatter::ssprintf(aValue, u"%g", (double)mValue);
 
   nsAutoString unitString;
   GetUnitString(unitString, mUnit);
   aValue.Append(unitString);
 }
 
 bool SVGLength::SetValueFromString(const nsAString& aString) {
-  RangedPtr<const char16_t> iter = SVGContentUtils::GetStartRangedPtr(aString);
-  const RangedPtr<const char16_t> end =
-      SVGContentUtils::GetEndRangedPtr(aString);
+  bool success;
+  auto token = SVGContentUtils::GetAndEnsureOneToken(aString, success);
+
+  if (!success) {
+    return false;
+  }
+
+  RangedPtr<const char16_t> iter = SVGContentUtils::GetStartRangedPtr(token);
+  const RangedPtr<const char16_t> end = SVGContentUtils::GetEndRangedPtr(token);
 
   float value;
 
   if (!SVGContentUtils::ParseNumber(iter, end, value)) {
     return false;
   }
 
   const nsAString& units = Substring(iter.get(), end.get());
--- a/dom/svg/SVGOrient.cpp
+++ b/dom/svg/SVGOrient.cpp
@@ -113,19 +113,25 @@ static void GetAngleValueString(nsAStrin
   nsAutoString unitString;
   GetAngleUnitString(unitString, aUnitType);
   aValueAsString.Append(unitString);
 }
 
 /* static */
 bool SVGOrient::GetValueFromString(const nsAString& aString, float& aValue,
                                    uint16_t* aUnitType) {
-  RangedPtr<const char16_t> iter = SVGContentUtils::GetStartRangedPtr(aString);
-  const RangedPtr<const char16_t> end =
-      SVGContentUtils::GetEndRangedPtr(aString);
+  bool success;
+  auto token = SVGContentUtils::GetAndEnsureOneToken(aString, success);
+
+  if (!success) {
+    return false;
+  }
+
+  RangedPtr<const char16_t> iter = SVGContentUtils::GetStartRangedPtr(token);
+  const RangedPtr<const char16_t> end = SVGContentUtils::GetEndRangedPtr(token);
 
   if (!SVGContentUtils::ParseNumber(iter, end, aValue)) {
     return false;
   }
 
   const nsAString& units = Substring(iter.get(), end.get());
   *aUnitType = GetAngleUnitTypeForString(units);
   return IsValidAngleUnitType(*aUnitType);
--- a/dom/svg/nsSVGLength2.cpp
+++ b/dom/svg/nsSVGLength2.cpp
@@ -80,19 +80,25 @@ static void GetValueString(nsAString& aV
 
   nsAutoString unitString;
   GetUnitString(unitString, aUnitType);
   aValueAsString.Append(unitString);
 }
 
 static bool GetValueFromString(const nsAString& aString, float& aValue,
                                uint16_t* aUnitType) {
-  RangedPtr<const char16_t> iter = SVGContentUtils::GetStartRangedPtr(aString);
-  const RangedPtr<const char16_t> end =
-      SVGContentUtils::GetEndRangedPtr(aString);
+  bool success;
+  auto token = SVGContentUtils::GetAndEnsureOneToken(aString, success);
+
+  if (!success) {
+    return false;
+  }
+
+  RangedPtr<const char16_t> iter = SVGContentUtils::GetStartRangedPtr(token);
+  const RangedPtr<const char16_t> end = SVGContentUtils::GetEndRangedPtr(token);
 
   if (!SVGContentUtils::ParseNumber(iter, end, aValue)) {
     return false;
   }
   const nsAString& units = Substring(iter.get(), end.get());
   *aUnitType = GetUnitTypeForString(units);
   return IsValidUnitType(*aUnitType);
 }
--- a/dom/svg/nsSVGNumber2.cpp
+++ b/dom/svg/nsSVGNumber2.cpp
@@ -18,19 +18,25 @@ using namespace mozilla::dom;
 
 /* Implementation */
 
 static SVGAttrTearoffTable<nsSVGNumber2, nsSVGNumber2::DOMAnimatedNumber>
     sSVGAnimatedNumberTearoffTable;
 
 static bool GetValueFromString(const nsAString& aString,
                                bool aPercentagesAllowed, float& aValue) {
-  RangedPtr<const char16_t> iter = SVGContentUtils::GetStartRangedPtr(aString);
-  const RangedPtr<const char16_t> end =
-      SVGContentUtils::GetEndRangedPtr(aString);
+  bool success;
+  auto token = SVGContentUtils::GetAndEnsureOneToken(aString, success);
+
+  if (!success) {
+    return false;
+  }
+
+  RangedPtr<const char16_t> iter = SVGContentUtils::GetStartRangedPtr(token);
+  const RangedPtr<const char16_t> end = SVGContentUtils::GetEndRangedPtr(token);
 
   if (!SVGContentUtils::ParseNumber(iter, end, aValue)) {
     return false;
   }
 
   if (aPercentagesAllowed) {
     const nsAString& units = Substring(iter.get(), end.get());
     if (units.EqualsLiteral("%")) {
--- a/dom/svg/test/test_lengthParsing.html
+++ b/dom/svg/test/test_lengthParsing.html
@@ -23,22 +23,27 @@ https://bugzilla.mozilla.org/show_bug.cg
 checkParseOk("", 0);
 checkParseOk("-.1", -0.1);
 checkParseOk("1e1", 10);
 checkParseOk("1em", 1, "em");
 checkParseOk("1ex", 1, "ex");
 checkParseOk("1e1em", 10, "em");
 checkParseOk("1E+2", 100);
 checkParseOk(".1e-2", 0.001);
+checkParseOk("   10", 10);
+checkParseOk("10  ", 10);
+checkParseOk("  10  ", 10);
+checkParseOk("  10em  ", 10, "em");
 
 // Fail cases
 checkParseFail("1e");
 checkParseFail("1 e");
 checkParseFail("1 em");
 checkParseFail("1ee");
+checkParseFail(" 10 20");
 
 function checkParseOk(spec, valueInUnits, units) {
   var rect = document.getElementById("rect");
 
   // Clear previous value
   rect.removeAttribute("x");
   rect.setAttribute("x", spec);