Backed out changeset cb6165af87e7 (bug 929011) for Android Build Bustage
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Tue, 29 Oct 2013 15:59:50 +0100
changeset 152886 e6428d3d7313c9a25ba7bef9b77296a33895a71c
parent 152885 5c3c2060a7237d66f94a6a982196d14d1821f0e6
child 152887 f31dc2d87066888dbde9b9ae7848ec8519266ba8
push id25562
push userkwierso@gmail.com
push dateFri, 01 Nov 2013 01:00:51 +0000
treeherdermozilla-central@4813677c42bf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs929011
milestone28.0a1
backs outcb6165af87e7cbcacc305b03d62f6f0a000d289f
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
Backed out changeset cb6165af87e7 (bug 929011) for Android Build Bustage
content/svg/content/src/SVGContentUtils.cpp
content/svg/content/src/SVGContentUtils.h
content/svg/content/src/SVGLength.cpp
content/svg/content/src/SVGMotionSMILAnimationFunction.cpp
content/svg/content/src/SVGPathData.cpp
content/svg/content/src/SVGPathData.h
content/svg/content/src/SVGPointList.cpp
content/svg/content/src/SVGTransformList.cpp
content/svg/content/src/SVGTransformListParser.cpp
content/svg/content/src/SVGTransformListParser.h
content/svg/content/src/nsSVGAngle.cpp
content/svg/content/src/nsSVGDataParser.cpp
content/svg/content/src/nsSVGDataParser.h
content/svg/content/src/nsSVGLength2.cpp
content/svg/content/src/nsSVGNumber2.cpp
content/svg/content/src/nsSVGPathDataParser.cpp
content/svg/content/src/nsSVGPathDataParser.h
--- a/content/svg/content/src/SVGContentUtils.cpp
+++ b/content/svg/content/src/SVGContentUtils.cpp
@@ -5,16 +5,17 @@
 
 // Main header first:
 // This is also necessary to ensure our definition of M_SQRT1_2 is picked up
 #include "SVGContentUtils.h"
 
 // Keep others in (case-insensitive) order:
 #include "gfxMatrix.h"
 #include "mozilla/dom/SVGSVGElement.h"
+#include "mozilla/RangedPtr.h"
 #include "nsComputedDOMStyle.h"
 #include "nsFontMetrics.h"
 #include "nsIFrame.h"
 #include "nsIScriptError.h"
 #include "nsLayoutUtils.h"
 #include "SVGAnimationElement.h"
 #include "SVGAnimatedPreserveAspectRatio.h"
 #include "nsContentUtils.h"
@@ -384,152 +385,151 @@ static inline uint32_t
 DecimalDigitValue(PRUnichar aCh)
 {
   MOZ_ASSERT(IsDigit(aCh), "Digit expected");
   return aCh - '0';
 }
 
 template<class floatType>
 bool
-SVGContentUtils::ParseNumber(RangedPtr<const PRUnichar>& aIter,
-                             const RangedPtr<const PRUnichar>& aEnd,
-                             floatType& aValue)
+SVGContentUtils::ParseNumber(const nsAString& aString, 
+                             floatType& aValue,
+                             nsAString& aLeftOver)
 {
-  if (aIter == aEnd) {
+  mozilla::RangedPtr<const PRUnichar> iter(aString.Data(), aString.Length());
+  const mozilla::RangedPtr<const PRUnichar> end(aString.Data() + aString.Length(),
+                                                aString.Data(), aString.Length());
+
+  if (iter == end) {
     return false;
   }
 
-  RangedPtr<const PRUnichar> iter(aIter);
-
   // Sign of the mantissa (-1 or 1).
   int32_t sign = *iter == '-' ? -1 : 1;
 
   if (*iter == '-' || *iter == '+') {
     ++iter;
-    if (iter == aEnd) {
+    if (iter == end) {
       return false;
     }
   }
 
   // Absolute value of the integer part of the mantissa.
   floatType intPart = floatType(0);
 
   bool gotDot = *iter == '.';
 
   if (!gotDot) {
     if (!IsDigit(*iter)) {
       return false;
     }
     do {
       intPart = floatType(10) * intPart + DecimalDigitValue(*iter);
       ++iter;
-    } while (iter != aEnd && IsDigit(*iter));
+    } while (iter != end && IsDigit(*iter));
 
-    if (iter != aEnd) {
+    if (iter != end) {
       gotDot = *iter == '.';
     }
   }
 
   // Fractional part of the mantissa.
   floatType fracPart = floatType(0);
 
   if (gotDot) {
     ++iter;
-    if (iter == aEnd || !IsDigit(*iter)) {
+    if (iter == end || !IsDigit(*iter)) {
       return false;
     }
     // Power of ten by which we need to divide our next digit
     floatType divisor = floatType(10);
     do {
       fracPart += DecimalDigitValue(*iter) / divisor;
       divisor *= 10;
       ++iter;
-    } while (iter != aEnd && IsDigit(*iter));
+    } while (iter != end && IsDigit(*iter));
   }
 
   bool gotE = false;
   int32_t exponent = 0;
   int32_t expSign;
 
-  if (iter != aEnd && (*iter == 'e' || *iter == 'E')) {
+  if (iter != end && (*iter == 'e' || *iter == 'E')) {
 
-    RangedPtr<const PRUnichar> expIter(iter);
+    mozilla::RangedPtr<const PRUnichar> expIter(iter);
 
     ++expIter;
-    if (expIter != aEnd) {
+    if (expIter != end) {
       expSign = *expIter == '-' ? -1 : 1;
       if (*expIter == '-' || *expIter == '+') {
         ++expIter;
-        if (expIter != aEnd && IsDigit(*expIter)) {
+        if (expIter != end && IsDigit(*expIter)) {
           // At this point we're sure this is an exponent
           // and not the start of a unit such as em or ex.
           gotE = true;
         }
       }
     }
 
     if (gotE) {
       iter = expIter;
       do {
         exponent = 10 * exponent + DecimalDigitValue(*iter);
         ++iter;
-      } while (iter != aEnd && IsDigit(*iter));
+      } while (iter != end && IsDigit(*iter));
     }
   }
 
   // Assemble the number
-  floatType value = sign * (intPart + fracPart);
+  aValue = sign * (intPart + fracPart);
   if (gotE) {
-    value *= pow(floatType(10), floatType(expSign * exponent));
+    aValue *= pow(floatType(10), floatType(expSign * exponent));
   }
-  if (!NS_finite(value)) {
-    return false;
-  }
-  aIter = iter;
-  aValue = value;
-  return true;
+  
+  aLeftOver = Substring(iter.get(), end.get());
+  return NS_finite(aValue);
 }
 
-RangedPtr<const PRUnichar>
-SVGContentUtils::GetStartRangedPtr(const nsAString& aString)
-{
-  return RangedPtr<const PRUnichar>(aString.Data(), aString.Length());
-}
-
-RangedPtr<const PRUnichar>
-SVGContentUtils::GetEndRangedPtr(const nsAString& aString)
-{
-  return RangedPtr<const PRUnichar>(aString.Data() + aString.Length(),
-                                    aString.Data(), aString.Length());
-}
+template bool
+SVGContentUtils::ParseNumber<float>(const nsAString& aString, 
+                                    float& aValue,
+                                    nsAString& aLeftOver);
+template bool
+SVGContentUtils::ParseNumber<double>(const nsAString& aString, 
+                                     double& aValue,
+                                     nsAString& aLeftOver);
 
 template<class floatType>
 bool
 SVGContentUtils::ParseNumber(const nsAString& aString, 
                              floatType& aValue)
 {
-  RangedPtr<const PRUnichar> iter = GetStartRangedPtr(aString);
-  const RangedPtr<const PRUnichar> end = GetEndRangedPtr(aString);
+  nsAutoString leftOver;
 
-  return ParseNumber(iter, end, aValue) && iter == end;
+  if (!ParseNumber(aString, aValue, leftOver)) {
+    return false;
+  }
+
+  return leftOver.IsEmpty();
 }
 
 template bool
 SVGContentUtils::ParseNumber<float>(const nsAString& aString, 
                                     float& aValue);
 template bool
 SVGContentUtils::ParseNumber<double>(const nsAString& aString, 
                                      double& aValue);
 
 bool
 SVGContentUtils::ParseInteger(const nsAString& aString,
                               int32_t& aValue)
 {
-  RangedPtr<const PRUnichar> iter = GetStartRangedPtr(aString);
-  const RangedPtr<const PRUnichar> end = GetEndRangedPtr(aString);
+  mozilla::RangedPtr<const PRUnichar> iter(aString.Data(), aString.Length());
+  const mozilla::RangedPtr<const PRUnichar> end(aString.Data() + aString.Length(),
+                                                aString.Data(), aString.Length());
 
   if (iter == end) {
     return false;
   }
 
   int32_t sign = *iter == '-' ? -1 : 1;
 
   if (*iter == '-' || *iter == '+') {
--- a/content/svg/content/src/SVGContentUtils.h
+++ b/content/svg/content/src/SVGContentUtils.h
@@ -6,17 +6,16 @@
 #ifndef MOZILLA_SVGCONTENTUTILS_H
 #define MOZILLA_SVGCONTENTUTILS_H
 
 // include math.h to pick up definition of M_ maths defines e.g. M_PI
 #define _USE_MATH_DEFINES
 #include <math.h>
 
 #include "gfxMatrix.h"
-#include "mozilla/RangedPtr.h"
 
 class nsIContent;
 class nsIDocument;
 class nsIFrame;
 class nsStyleContext;
 class nsSVGElement;
 
 namespace mozilla {
@@ -128,34 +127,26 @@ public:
                       const SVGAnimatedPreserveAspectRatio &aPreserveAspectRatio);
 
   static gfxMatrix
   GetViewBoxTransform(float aViewportWidth, float aViewportHeight,
                       float aViewboxX, float aViewboxY,
                       float aViewboxWidth, float aViewboxHeight,
                       const SVGPreserveAspectRatio &aPreserveAspectRatio);
 
-  static mozilla::RangedPtr<const PRUnichar>
-  GetStartRangedPtr(const nsAString& aString);
-
-  static mozilla::RangedPtr<const PRUnichar>
-  GetEndRangedPtr(const nsAString& aString);
-
   /**
    * Parse a number of the form:
    * number ::= integer ([Ee] integer)? | [+-]? [0-9]* "." [0-9]+ ([Ee] integer)?
    * Parsing fails if the number cannot be represented by a floatType.
-   * If parsing succeeds, aIter is updated so that it points to the character
-   * after the end of the number, otherwise it is left unchanged
+   * Anything after the number is returned in aLeftOver.
    */
   template<class floatType>
   static bool
-  ParseNumber(mozilla::RangedPtr<const PRUnichar>& aIter,
-              const mozilla::RangedPtr<const PRUnichar>& aEnd,
-              floatType& aValue);
+  ParseNumber(const nsAString& aString, floatType& aValue,
+              nsAString& aLeftOver);
 
   /**
    * Parse a number of the form:
    * number ::= integer ([Ee] integer)? | [+-]? [0-9]* "." [0-9]+ ([Ee] integer)?
    * Parsing fails if there is anything left over after the number,
    * or the number cannot be represented by a floatType.
    */
   template<class floatType>
--- a/content/svg/content/src/SVGLength.cpp
+++ b/content/svg/content/src/SVGLength.cpp
@@ -29,30 +29,25 @@ SVGLength::GetValueAsString(nsAString &a
   aValue.Assign(buf);
 
   nsAutoString unitString;
   GetUnitString(unitString, mUnit);
   aValue.Append(unitString);
 }
 
 bool
-SVGLength::SetValueFromString(const nsAString &aString)
+SVGLength::SetValueFromString(const nsAString &aValueAsString)
 {
-  RangedPtr<const PRUnichar> iter =
-    SVGContentUtils::GetStartRangedPtr(aString);
-  const RangedPtr<const PRUnichar> end =
-    SVGContentUtils::GetEndRangedPtr(aString);
-
+  nsAutoString units;
   float value;
 
-  if (!SVGContentUtils::ParseNumber(iter, end, value)) {
+  if (!SVGContentUtils::ParseNumber(aValueAsString, value, units)) {
     return false;
   }
 
-  const nsAString& units = Substring(iter.get(), end.get());
   uint16_t unitType = GetUnitTypeForString(units);
   if (!IsValidUnitType(unitType)) {
     return false;
   }
   mValue = value;
   mUnit = uint8_t(unitType);
   return true;
 }
--- a/content/svg/content/src/SVGMotionSMILAnimationFunction.cpp
+++ b/content/svg/content/src/SVGMotionSMILAnimationFunction.cpp
@@ -236,23 +236,23 @@ SVGMotionSMILAnimationFunction::
 void
 SVGMotionSMILAnimationFunction::RebuildPathAndVerticesFromPathAttr()
 {
   const nsAString& pathSpec = GetAttr(nsGkAtoms::path)->GetStringValue();
   mPathSourceType = ePathSourceType_PathAttr;
 
   // Generate gfxPath from |path| attr
   SVGPathData path;
-  nsSVGPathDataParser pathParser(pathSpec, &path);
+  nsSVGPathDataParserToInternal pathParser(&path);
 
   // We ignore any failure returned from Parse() since the SVG spec says to
   // accept all segments up to the first invalid token. Instead we must
   // explicitly check that the parse produces at least one path segment (if
   // the path data doesn't begin with a valid "M", then it's invalid).
-  pathParser.Parse();
+  pathParser.Parse(pathSpec);
   if (!path.Length()) {
     return;
   }
 
   mPath = path.ToPath(gfxMatrix());
   bool ok = path.GetDistancesFromOriginToEndsOfVisibleSegments(&mPathVertices);
   if (!ok || !mPathVertices.Length()) {
     mPath = nullptr;
--- a/content/svg/content/src/SVGPathData.cpp
+++ b/content/svg/content/src/SVGPathData.cpp
@@ -66,18 +66,18 @@ SVGPathData::GetValueAsString(nsAString&
 
 nsresult
 SVGPathData::SetValueFromString(const nsAString& aValue)
 {
   // We don't use a temp variable since the spec says to parse everything up to
   // the first error. We still return any error though so that callers know if
   // there's a problem.
 
-  nsSVGPathDataParser pathParser(aValue, this);
-  return pathParser.Parse() ? NS_OK : NS_ERROR_DOM_SYNTAX_ERR;
+  nsSVGPathDataParserToInternal pathParser(this);
+  return pathParser.Parse(aValue);
 }
 
 nsresult
 SVGPathData::AppendSeg(uint32_t aType, ...)
 {
   uint32_t oldLength = mData.Length();
   uint32_t newLength = oldLength + 1 + SVGPathSegUtils::ArgCountForType(aType);
   if (!mData.SetLength(newLength)) {
--- a/content/svg/content/src/SVGPathData.h
+++ b/content/svg/content/src/SVGPathData.h
@@ -15,17 +15,17 @@
 #include "mozilla/RefPtr.h"
 #include "nsSVGElement.h"
 #include "nsTArray.h"
 
 #include <string.h>
 
 class gfxContext;
 class gfxPath;
-class nsSVGPathDataParser; // IWYU pragma: keep
+class nsSVGPathDataParserToInternal; // IWYU pragma: keep
 
 struct gfxMatrix;
 struct nsSVGMark;
 
 namespace mozilla {
 
 /**
  * ATTENTION! WARNING! WATCH OUT!!
@@ -73,18 +73,18 @@ namespace mozilla {
  * there are (if any), and thus where the current encoded segment ends, and
  * where the next segment (if any) begins.
  */
 class SVGPathData
 {
   friend class SVGAnimatedPathSegList;
   friend class DOMSVGPathSegList;
   friend class DOMSVGPathSeg;
-  friend class ::nsSVGPathDataParser;
-  // nsSVGPathDataParser will not keep wrappers in sync, so consumers
+  friend class ::nsSVGPathDataParserToInternal;
+  // nsSVGPathDataParserToInternal will not keep wrappers in sync, so consumers
   // are responsible for that!
 
   typedef gfx::DrawTarget DrawTarget;
   typedef gfx::Path Path;
   typedef gfx::FillRule FillRule;
   typedef gfx::CapStyle CapStyle;
 
 public:
--- a/content/svg/content/src/SVGPointList.cpp
+++ b/content/svg/content/src/SVGPointList.cpp
@@ -55,40 +55,33 @@ SVGPointList::SetValueFromString(const n
 
   SVGPointList temp;
 
   nsCharSeparatedTokenizerTemplate<IsSVGWhitespace>
     tokenizer(aValue, ',', nsCharSeparatedTokenizer::SEPARATOR_OPTIONAL);
 
   while (tokenizer.hasMoreTokens()) {
 
-    const nsAString& token = tokenizer.nextToken();
-
-    RangedPtr<const PRUnichar> iter =
-      SVGContentUtils::GetStartRangedPtr(token);
-    const RangedPtr<const PRUnichar> end =
-      SVGContentUtils::GetEndRangedPtr(token);
-
     float x;
-    if (!SVGContentUtils::ParseNumber(iter, end, x)) {
+    nsAutoString leftOver;
+    if (!SVGContentUtils::ParseNumber(tokenizer.nextToken(), x, leftOver)) {
       rv = NS_ERROR_DOM_SYNTAX_ERR;
       break;
     }
 
     float y;
-    if (iter == end) {
+    if (leftOver.IsEmpty()) {
       if (!tokenizer.hasMoreTokens() ||
           !SVGContentUtils::ParseNumber(tokenizer.nextToken(), y)) {
         rv = NS_ERROR_DOM_SYNTAX_ERR;
         break;
       }
     } else {
       // It's possible for the token to be 10-30 which has
       // no separator but needs to be parsed as 10, -30
-      const nsAString& leftOver = Substring(iter.get(), end.get());
       if (leftOver[0] != '-' || !SVGContentUtils::ParseNumber(leftOver, y)) {
         rv = NS_ERROR_DOM_SYNTAX_ERR;
         break;
       }
     }
     temp.AppendItem(SVGPoint(x, y));
   }
   if (tokenizer.separatorAfterCurrentToken()) {
--- a/content/svg/content/src/SVGTransformList.cpp
+++ b/content/svg/content/src/SVGTransformList.cpp
@@ -65,18 +65,20 @@ SVGTransformList::GetValueAsString(nsASt
       aValue.Append(' ');
     }
   }
 }
 
 nsresult
 SVGTransformList::SetValueFromString(const nsAString& aValue)
 {
-  SVGTransformListParser parser(aValue);
-  if (!parser.Parse()) {
+  SVGTransformListParser parser;
+  nsresult rv = parser.Parse(aValue);
+
+  if (NS_FAILED(rv)) {
     // there was a parse error.
     return NS_ERROR_DOM_SYNTAX_ERR;
   }
 
   return CopyFrom(parser.GetTransformList());
 }
 
 } // namespace mozilla
--- a/content/svg/content/src/SVGTransformListParser.cpp
+++ b/content/svg/content/src/SVGTransformListParser.cpp
@@ -2,272 +2,345 @@
  * vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/Util.h"
 
 #include "SVGTransformListParser.h"
-#include "SVGContentUtils.h"
 #include "nsSVGTransform.h"
+#include "nsError.h"
 #include "nsGkAtoms.h"
 #include "nsIAtom.h"
+#include "plstr.h"
 
 using namespace mozilla;
 
 //----------------------------------------------------------------------
 // private methods
 
-bool
-SVGTransformListParser::Parse()
+nsresult
+SVGTransformListParser::Match()
 {
   mTransforms.Clear();
-  return ParseTransforms();
+  return MatchTransformList();
 }
 
-bool
-SVGTransformListParser::ParseTransforms()
+
+nsresult
+SVGTransformListParser::MatchTransformList()
 {
-  if (!SkipWsp()) {
-    return true;
-  }
+  MatchWsp();
 
-  if (!ParseTransform()) {
-    return false;
+  if (IsTokenTransformStarter()) {
+    ENSURE_MATCHED(MatchTransforms());
   }
 
-  while (SkipWsp()) {
-    // The SVG BNF allows multiple comma-wsp between transforms
-    while (*mIter == ',') {
-      ++mIter;
-      if (!SkipWsp()) {
-        return false;
-      }
+  MatchWsp();
+
+  return NS_OK;
+}
+
+
+nsresult
+SVGTransformListParser::MatchTransforms()
+{
+  ENSURE_MATCHED(MatchTransform());
+
+  while (mTokenType != END) {
+    const char* pos = mTokenPos;
+
+    /* Curiously the SVG BNF allows multiple comma-wsp between transforms */
+    while (IsTokenCommaWspStarter()) {
+      ENSURE_MATCHED(MatchCommaWsp());
     }
 
-    if (!ParseTransform()) {
-      return false;
-    }
-  }
-  return true;
-}
-
-bool
-SVGTransformListParser::ParseTransform()
-{
-  RangedPtr<const PRUnichar> start(mIter);
-  while (IsAlpha(*mIter)) {
-    ++mIter;
-    if (mIter == mEnd) {
-      return false;
+    if (IsTokenTransformStarter()) {
+      ENSURE_MATCHED(MatchTransform());
+    } else {
+      if (pos != mTokenPos) RewindTo(pos);
+      break;
     }
   }
 
-  if (start == mIter) {
-    // Didn't read anything
-    return false;
+  return NS_OK;
+}
+
+
+nsresult
+SVGTransformListParser::GetTransformToken(nsIAtom** aKeyAtom,
+                                          bool aAdvancePos)
+{
+  if (mTokenType != OTHER || *mTokenPos == '\0') {
+    return NS_ERROR_FAILURE;
+  }
+
+  nsresult rv = NS_OK;
+
+  const char* delimiters = "\x20\x9\xD\xA,(";
+  char* delimiterStart = PL_strnpbrk(mTokenPos, delimiters, 11);
+  if (delimiterStart != 0) {
+    /* save this character and null it out */
+    char holdingChar = *delimiterStart;
+    *delimiterStart = '\0';
+
+    uint32_t len;
+    if ((len = strlen(mTokenPos)) > 0) {
+      *aKeyAtom = NS_NewAtom(Substring(mTokenPos, mTokenPos + len)).get();
+
+      if (aAdvancePos) {
+         mInputPos = mTokenPos + len;
+         mTokenPos = mInputPos;
+      }
+    } else {
+      rv = NS_ERROR_FAILURE;
+    }
+    /* reset character back to original */
+    *delimiterStart = holdingChar;
+  } else {
+    rv = NS_ERROR_FAILURE;
   }
 
-  const nsAString& transform = Substring(start.get(), mIter.get());
-  nsIAtom* keyAtom = NS_GetStaticAtom(transform);
+  return rv;
+}
+
+
+nsresult
+SVGTransformListParser::MatchTransform()
+{
+  nsCOMPtr<nsIAtom> keyatom;
+
+  nsresult rv = GetTransformToken(getter_AddRefs(keyatom), true);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
 
-  if (!keyAtom || !SkipWsp()) {
+  if (keyatom == nsGkAtoms::translate) {
+    ENSURE_MATCHED(MatchTranslate());
+  } else if (keyatom == nsGkAtoms::scale) {
+    ENSURE_MATCHED(MatchScale());
+  } else if (keyatom == nsGkAtoms::rotate) {
+    ENSURE_MATCHED(MatchRotate());
+  } else if (keyatom == nsGkAtoms::skewX) {
+    ENSURE_MATCHED(MatchSkewX());
+  } else if (keyatom == nsGkAtoms::skewY) {
+    ENSURE_MATCHED(MatchSkewY());
+  } else if (keyatom == nsGkAtoms::matrix) {
+    ENSURE_MATCHED(MatchMatrix());
+  } else {
+    return NS_ERROR_FAILURE;
+  }
+
+  return NS_OK;
+}
+
+
+bool
+SVGTransformListParser::IsTokenTransformStarter()
+{
+  nsCOMPtr<nsIAtom> keyatom;
+
+  nsresult rv = GetTransformToken(getter_AddRefs(keyatom), false);
+  if (NS_FAILED(rv)) {
     return false;
   }
 
-  if (keyAtom == nsGkAtoms::translate) {
-    return ParseTranslate();
-  }
-  if (keyAtom == nsGkAtoms::scale) {
-    return ParseScale();
-  }
-  if (keyAtom == nsGkAtoms::rotate) {
-    return ParseRotate();
+  if (keyatom == nsGkAtoms::translate ||
+      keyatom == nsGkAtoms::scale     ||
+      keyatom == nsGkAtoms::rotate    ||
+      keyatom == nsGkAtoms::skewX     ||
+      keyatom == nsGkAtoms::skewY     ||
+      keyatom == nsGkAtoms::matrix) {
+    return true;
   }
-  if (keyAtom == nsGkAtoms::skewX) {
-    return ParseSkewX();
-  }
-  if (keyAtom == nsGkAtoms::skewY) {
-    return ParseSkewY();
-  }
-  if (keyAtom == nsGkAtoms::matrix) {
-    return ParseMatrix();
-  }
+
   return false;
 }
 
-bool
-SVGTransformListParser::ParseArguments(float* aResult,
-                                       uint32_t aMaxCount,
-                                       uint32_t* aParsedCount)
+nsresult
+SVGTransformListParser::MatchNumberArguments(float *aResult,
+                                             uint32_t aMaxNum,
+                                             uint32_t *aParsedNum)
 {
-  if (*mIter != '(') {
-    return false;
-  }
-  ++mIter;
+  *aParsedNum = 0;
+
+  MatchWsp();
+
+  ENSURE_MATCHED(MatchLeftParen());
+
+  MatchWsp();
+
+  ENSURE_MATCHED(MatchNumber(&aResult[0]));
+  *aParsedNum = 1;
 
-  if (!SkipWsp()) {
-    return false;
+  while (IsTokenCommaWspStarter()) {
+    MatchWsp();
+    if (mTokenType == RIGHT_PAREN) {
+      break;
+    }
+    if (*aParsedNum == aMaxNum) {
+      return NS_ERROR_FAILURE;
+    }
+    if (IsTokenCommaWspStarter()) {
+      MatchCommaWsp();
+    }
+    ENSURE_MATCHED(MatchNumber(&aResult[(*aParsedNum)++]));
   }
 
-  if (!SVGContentUtils::ParseNumber(mIter, mEnd, aResult[0])) {
-    return false;
-  }
-  *aParsedCount = 1;
+  MatchWsp();
 
-  while (SkipWsp()) {
-    if (*mIter == ')') {
-      ++mIter;
-      return true;
-    }
-    if (*aParsedCount == aMaxCount) {
-      return false;
-    }
-    SkipCommaWsp();
-    if (!SVGContentUtils::ParseNumber(mIter, mEnd, aResult[(*aParsedCount)++])) {
-      return false;
-    }
-  }
-  return false;
+  ENSURE_MATCHED(MatchRightParen());
+
+  return NS_OK;
 }
 
-bool
-SVGTransformListParser::ParseTranslate()
+nsresult
+SVGTransformListParser::MatchTranslate()
 {
+  GetNextToken();
+
   float t[2];
   uint32_t count;
 
-  if (!ParseArguments(t, ArrayLength(t), &count)) {
-    return false;
-  }
+  ENSURE_MATCHED(MatchNumberArguments(t, ArrayLength(t), &count));
 
   switch (count) {
     case 1:
       t[1] = 0.f;
       // fall-through
     case 2:
     {
       nsSVGTransform* transform = mTransforms.AppendElement();
-      if (!transform) {
-        return false;
-      }
+      NS_ENSURE_TRUE(transform, NS_ERROR_OUT_OF_MEMORY);
       transform->SetTranslate(t[0], t[1]);
-      return true;
+      break;
     }
+    default:
+      return NS_ERROR_FAILURE;
   }
 
-  return false;
+  return NS_OK;
 }
 
-bool
-SVGTransformListParser::ParseScale()
+
+nsresult
+SVGTransformListParser::MatchScale()
 {
+  GetNextToken();
+
   float s[2];
   uint32_t count;
 
-  if (!ParseArguments(s, ArrayLength(s), &count)) {
-    return false;
-  }
+  ENSURE_MATCHED(MatchNumberArguments(s, ArrayLength(s), &count));
 
   switch (count) {
     case 1:
       s[1] = s[0];
       // fall-through
     case 2:
     {
       nsSVGTransform* transform = mTransforms.AppendElement();
-      if (!transform) {
-        return false;
-      }
+      NS_ENSURE_TRUE(transform, NS_ERROR_OUT_OF_MEMORY);
       transform->SetScale(s[0], s[1]);
-      return true;
+      break;
     }
+    default:
+      return NS_ERROR_FAILURE;
   }
 
-  return false;
+  return NS_OK;
 }
 
 
-bool
-SVGTransformListParser::ParseRotate()
+nsresult
+SVGTransformListParser::MatchRotate()
 {
+  GetNextToken();
+
   float r[3];
   uint32_t count;
 
-  if (!ParseArguments(r, ArrayLength(r), &count)) {
-    return false;
-  }
+  ENSURE_MATCHED(MatchNumberArguments(r, ArrayLength(r), &count));
 
   switch (count) {
     case 1:
       r[1] = r[2] = 0.f;
       // fall-through
     case 3:
     {
       nsSVGTransform* transform = mTransforms.AppendElement();
-      if (!transform) {
-        return false;
-      }
+      NS_ENSURE_TRUE(transform, NS_ERROR_OUT_OF_MEMORY);
       transform->SetRotate(r[0], r[1], r[2]);
-      return true;
+      break;
     }
+    default:
+      return NS_ERROR_FAILURE;
   }
 
-  return false;
+  return NS_OK;
 }
 
-bool
-SVGTransformListParser::ParseSkewX()
+
+nsresult
+SVGTransformListParser::MatchSkewX()
 {
+  GetNextToken();
+
   float skew;
   uint32_t count;
 
-  if (!ParseArguments(&skew, 1, &count) || count != 1) {
-    return false;
+  ENSURE_MATCHED(MatchNumberArguments(&skew, 1, &count));
+
+  if (count != 1) {
+    return NS_ERROR_FAILURE;
   }
 
   nsSVGTransform* transform = mTransforms.AppendElement();
-  if (!transform) {
-    return false;
-  }
+  NS_ENSURE_TRUE(transform, NS_ERROR_OUT_OF_MEMORY);
   transform->SetSkewX(skew);
 
-  return true;
+  return NS_OK;
 }
 
-bool
-SVGTransformListParser::ParseSkewY()
+
+nsresult
+SVGTransformListParser::MatchSkewY()
 {
+  GetNextToken();
+
   float skew;
   uint32_t count;
 
-  if (!ParseArguments(&skew, 1, &count) || count != 1) {
-    return false;
+  ENSURE_MATCHED(MatchNumberArguments(&skew, 1, &count));
+
+  if (count != 1) {
+    return NS_ERROR_FAILURE;
   }
 
   nsSVGTransform* transform = mTransforms.AppendElement();
-  if (!transform) {
-    return false;
-  }
+  NS_ENSURE_TRUE(transform, NS_ERROR_OUT_OF_MEMORY);
   transform->SetSkewY(skew);
 
-  return true;
+  return NS_OK;
 }
 
-bool
-SVGTransformListParser::ParseMatrix()
+
+nsresult
+SVGTransformListParser::MatchMatrix()
 {
+  GetNextToken();
+
   float m[6];
   uint32_t count;
 
-  if (!ParseArguments(m, ArrayLength(m), &count) || count != 6) {
-    return false;
+  ENSURE_MATCHED(MatchNumberArguments(m, ArrayLength(m), &count));
+
+  if (count != 6) {
+    return NS_ERROR_FAILURE;
   }
 
   nsSVGTransform* transform = mTransforms.AppendElement();
-  if (!transform) {
-    return false;
-  }
+  NS_ENSURE_TRUE(transform, NS_ERROR_OUT_OF_MEMORY);
   transform->SetMatrix(gfxMatrix(m[0], m[1], m[2], m[3], m[4], m[5]));
 
-  return true;
+  return NS_OK;
 }
--- a/content/svg/content/src/SVGTransformListParser.h
+++ b/content/svg/content/src/SVGTransformListParser.h
@@ -7,52 +7,58 @@
 #ifndef MOZILLA_SVGTRANSFORMLISTPARSER_H__
 #define MOZILLA_SVGTRANSFORMLISTPARSER_H__
 
 #include "mozilla/Attributes.h"
 #include "nsSVGDataParser.h"
 #include "nsTArray.h"
 
 ////////////////////////////////////////////////////////////////////////
-// SVGTransformListParser: A simple recursive descent parser that builds
-// transform lists from transform attributes. The grammar for path data
+// SVGTransformListParser: taken from nsSVGPathDataParser, a simple
+//  recursive descent parser that builds the transform lists from the
+//  transform attributes. The grammar for path data
 // can be found in SVG 1.1,  chapter 7.
 // http://www.w3.org/TR/SVG11/coords.html#TransformAttribute
 
+class nsIAtom;
+
 namespace mozilla {
 
 class nsSVGTransform;
 
 class SVGTransformListParser : public nsSVGDataParser
 {
 public:
-  SVGTransformListParser(const nsAString& aValue)
-    : nsSVGDataParser(aValue) {}
-  
-  bool Parse();
-
   const nsTArray<nsSVGTransform>& GetTransformList() const {
     return mTransforms;
   }
 
 private:
+  nsTArray<nsSVGTransform> mTransforms;
+
   // helpers
-  bool ParseArguments(float *aResult,
-                      uint32_t aMaxCount,
-                      uint32_t *aParsedCount);
+  virtual nsresult Match() MOZ_OVERRIDE;
 
-  bool ParseTransforms();
+  nsresult MatchNumberArguments(float *aResult,
+                                uint32_t aMaxNum,
+                                uint32_t *aParsedNum);
 
-  bool ParseTransform();
+  nsresult MatchTransformList();
 
-  bool ParseTranslate();
-  bool ParseScale();
-  bool ParseRotate();
-  bool ParseSkewX();
-  bool ParseSkewY();
-  bool ParseMatrix();
+  nsresult GetTransformToken(nsIAtom** aKeyatom, bool aAdvancePos);
+  nsresult MatchTransforms();
+
+  nsresult MatchTransform();
+
+  bool IsTokenTransformStarter();
 
-  FallibleTArray<nsSVGTransform> mTransforms;
+  nsresult MatchTranslate();
+
+  nsresult MatchScale();
+  nsresult MatchRotate();
+  nsresult MatchSkewX();
+  nsresult MatchSkewY();
+  nsresult MatchMatrix();
 };
 
 } // namespace mozilla
 
 #endif // MOZILLA_SVGTRANSFORMLISTPARSER_H__
--- a/content/svg/content/src/nsSVGAngle.cpp
+++ b/content/svg/content/src/nsSVGAngle.cpp
@@ -89,30 +89,26 @@ GetValueString(nsAString &aValueAsString
   aValueAsString.Assign(buf);
 
   nsAutoString unitString;
   GetUnitString(unitString, aUnitType);
   aValueAsString.Append(unitString);
 }
 
 static bool
-GetValueFromString(const nsAString& aString,
+GetValueFromString(const nsAString& aValueAsString,
                    float& aValue,
                    uint16_t* aUnitType)
 {
-  RangedPtr<const PRUnichar> iter =
-    SVGContentUtils::GetStartRangedPtr(aString);
-  const RangedPtr<const PRUnichar> end =
-    SVGContentUtils::GetEndRangedPtr(aString);
+  nsAutoString units;
 
-  if (!SVGContentUtils::ParseNumber(iter, end, aValue)) {
+  if (!SVGContentUtils::ParseNumber(aValueAsString, aValue, units)) {
     return false;
   }
 
-  const nsAString& units = Substring(iter.get(), end.get());
   *aUnitType = GetUnitTypeForString(units);
   return IsValidUnitType(*aUnitType);
 }
 
 /* static */ float
 nsSVGAngle::GetDegreesPerUnit(uint8_t aUnit)
 {
   switch (aUnit) {
--- a/content/svg/content/src/nsSVGDataParser.cpp
+++ b/content/svg/content/src/nsSVGDataParser.cpp
@@ -1,39 +1,300 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+ /**
+  * NOTE:
+  *
+  *   How should subclasses use this class?
+  *   This class was separated from the nsSVGPathDataParser class to share
+  *   functionality found to be common in other descent parsers in this component.
+  *
+  *   A subclass should implement a Match method which gets invoked from the
+  *   Parse method.  The Parse method can be overridden, as required.
+  *
+  */
+
+
 #include "nsSVGDataParser.h"
-#include "SVGContentUtils.h"
+#include "prdtoa.h"
+#include "nsMathUtils.h"
+#include "nsMemory.h"
+#include "nsReadableUtils.h"
+#include <stdlib.h>
+#include <math.h>
+
+//----------------------------------------------------------------------
+// public interface
+
+nsresult
+nsSVGDataParser::Parse(const nsAString &aValue)
+{
+  char *str = ToNewUTF8String(aValue);
+  if (!str)
+    return NS_ERROR_OUT_OF_MEMORY;
+
+  mInputPos = str;
+
+  GetNextToken();
+  nsresult rv = Match();
+  if (mTokenType != END)
+    rv = NS_ERROR_FAILURE; // not all tokens were consumed
+
+  mInputPos = nullptr;
+  nsMemory::Free(str);
+
+  return rv;
+}
+
+//----------------------------------------------------------------------
+// helpers
 
-nsSVGDataParser::nsSVGDataParser(const nsAString& aValue)
-  : mIter(SVGContentUtils::GetStartRangedPtr(aValue)),
-    mEnd(SVGContentUtils::GetEndRangedPtr(aValue))
+void nsSVGDataParser::GetNextToken()
 {
+  mTokenPos = mInputPos;
+  mTokenVal = *mInputPos;
+  
+  switch (mTokenVal) {
+    case '0': case '1': case '2': case '3': case '4':
+    case '5': case '6': case '7': case '8': case '9':
+      mTokenType = DIGIT;
+      break;
+    case '\x20': case '\x9': case '\xd': case '\xa':
+      mTokenType = WSP;
+      break;
+    case ',':
+      mTokenType = COMMA;
+      break;
+    case '+': case '-':
+      mTokenType = SIGN;
+      break;
+    case '.':
+      mTokenType = POINT;
+      break;
+    case '(':
+      mTokenType = LEFT_PAREN;
+      break;
+    case ')':
+      mTokenType = RIGHT_PAREN;
+      break;
+    case '\0':
+      mTokenType = END;
+      break;
+    default:
+      mTokenType = OTHER;
+  }
+  
+  if (*mInputPos != '\0') {
+    ++mInputPos;
+  }
+}
+
+void nsSVGDataParser::RewindTo(const char* aPos)
+{
+  mInputPos = aPos;
+  GetNextToken();
+}
+
+//----------------------------------------------------------------------
+
+nsresult nsSVGDataParser::MatchNumber(float* aX)
+{
+  const char* pos = mTokenPos;
+  
+  if (mTokenType == SIGN)
+    GetNextToken();
+
+  const char* pos2 = mTokenPos;
+
+  nsresult rv = MatchFloatingPointConst();
+
+  if (NS_FAILED(rv)) {
+    RewindTo(pos2);
+    ENSURE_MATCHED(MatchIntegerConst());
+  }
+
+  char* end;
+  /* PR_strtod is not particularily fast. We only need a float and not a double so
+   * we could probably use something faster here if needed. The CSS parser uses
+   * nsCSSScanner::ParseNumber() instead of PR_strtod. See bug 516396 for some
+   * additional info. */
+  *aX = float(PR_strtod(pos, &end));
+  if (pos != end && NS_finite(*aX)) {
+    return NS_OK;
+  }
+  
+  return NS_ERROR_FAILURE;
+}
+
+bool nsSVGDataParser::IsTokenNumberStarter()
+{
+  return (mTokenType == DIGIT || mTokenType == POINT || mTokenType == SIGN);
 }
 
-bool
-nsSVGDataParser::SkipCommaWsp()
+
+//----------------------------------------------------------------------
+
+nsresult nsSVGDataParser::MatchCommaWsp()
+{
+  switch (mTokenType) {
+    case WSP:
+      ENSURE_MATCHED(MatchWsp());
+      if (mTokenType == COMMA)
+        GetNextToken();
+      break;
+    case COMMA:
+      GetNextToken();
+      break;
+    default:
+      return NS_ERROR_FAILURE;
+  }
+
+  while (IsTokenWspStarter()) {
+    ENSURE_MATCHED(MatchWsp());
+  }
+  return NS_OK;
+}
+  
+bool nsSVGDataParser::IsTokenCommaWspStarter()
+{
+  return (IsTokenWspStarter() || mTokenType == COMMA);
+}
+
+//----------------------------------------------------------------------
+
+nsresult nsSVGDataParser::MatchIntegerConst()
 {
-  if (!SkipWsp()) {
-    // end of string
-    return false;
+  ENSURE_MATCHED(MatchDigitSeq());
+  return NS_OK;
+}
+
+//----------------------------------------------------------------------
+
+nsresult nsSVGDataParser::MatchFloatingPointConst()
+{
+  // XXX inefficient implementation. It would be nice if we could make
+  // this predictive and wouldn't have to backtrack...
+  
+  const char* pos = mTokenPos;
+
+  nsresult rv = MatchFractConst();
+  if (NS_SUCCEEDED(rv)) {
+    if (IsTokenExponentStarter())
+      ENSURE_MATCHED(MatchExponent());
+  }
+  else {
+    RewindTo(pos);
+    ENSURE_MATCHED(MatchDigitSeq());
+    ENSURE_MATCHED(MatchExponent());    
   }
-  if (*mIter != ',') {
-    return true;
+
+  return NS_OK;  
+}
+
+//----------------------------------------------------------------------
+
+nsresult nsSVGDataParser::MatchFractConst()
+{
+  if (mTokenType == POINT) {
+    GetNextToken();
+    ENSURE_MATCHED(MatchDigitSeq());
   }
-  ++mIter;
-  return SkipWsp();
+  else {
+    ENSURE_MATCHED(MatchDigitSeq());
+    if (mTokenType == POINT) {
+      GetNextToken();
+      if (IsTokenDigitSeqStarter()) {
+        ENSURE_MATCHED(MatchDigitSeq());
+      }
+    }
+  }
+  return NS_OK;
 }
 
-bool
-nsSVGDataParser::SkipWsp()
+//----------------------------------------------------------------------
+
+nsresult nsSVGDataParser::MatchExponent()
+{
+  if (!(tolower(mTokenVal) == 'e')) return NS_ERROR_FAILURE;
+
+  GetNextToken();
+
+  if (mTokenType == SIGN)
+    GetNextToken();
+
+  ENSURE_MATCHED(MatchDigitSeq());
+
+  return NS_OK;  
+}
+
+bool nsSVGDataParser::IsTokenExponentStarter()
+{
+  return (tolower(mTokenVal) == 'e');
+}
+
+//----------------------------------------------------------------------
+
+nsresult nsSVGDataParser::MatchDigitSeq()
+{
+  if (!(mTokenType == DIGIT)) return NS_ERROR_FAILURE;
+
+  do {
+    GetNextToken();
+  } while (mTokenType == DIGIT);
+
+  return NS_OK;
+}
+
+bool nsSVGDataParser::IsTokenDigitSeqStarter()
+{
+  return (mTokenType == DIGIT);
+}
+
+//----------------------------------------------------------------------
+
+nsresult nsSVGDataParser::MatchWsp()
 {
-  while (mIter != mEnd) {
-    if (!IsSVGWhitespace(*mIter)) {
-      return true;
-    }
-    ++mIter;
+  if (!(mTokenType == WSP)) return NS_ERROR_FAILURE;
+
+  do {
+    GetNextToken();
+  } while (mTokenType == WSP);
+
+  return NS_OK;  
+}
+
+bool nsSVGDataParser::IsTokenWspStarter()
+{
+  return (mTokenType == WSP);
+}  
+
+//----------------------------------------------------------------------
+
+nsresult nsSVGDataParser::MatchLeftParen()
+{
+  switch (mTokenType) {
+    case LEFT_PAREN:
+      GetNextToken();
+      break;
+    default:
+      return NS_ERROR_FAILURE;
   }
-  return false;
+
+ 
+  return NS_OK;
 }
+
+nsresult nsSVGDataParser::MatchRightParen()
+{
+  switch (mTokenType) {
+    case RIGHT_PAREN:
+       GetNextToken();
+      break;
+    default:
+      return NS_ERROR_FAILURE;
+  }
+
+  return NS_OK;
+}
+
--- a/content/svg/content/src/nsSVGDataParser.h
+++ b/content/svg/content/src/nsSVGDataParser.h
@@ -1,38 +1,63 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef __NS_SVGDATAPARSER_H__
 #define __NS_SVGDATAPARSER_H__
 
-#include "mozilla/RangedPtr.h"
+#include "nsError.h"
 #include "nsString.h"
 
+//----------------------------------------------------------------------
+// helper macros
+#define ENSURE_MATCHED(exp) { nsresult rv = exp; if (NS_FAILED(rv)) return rv; }
+
 ////////////////////////////////////////////////////////////////////////
-// nsSVGDataParser: a simple base class for parsing values
+// nsSVGDataParser: a simple abstract class for parsing values
 // for path and transform values.
 // 
 class nsSVGDataParser
 {
 public:
-  nsSVGDataParser(const nsAString& aValue);
+  nsresult Parse(const nsAString &aValue);
 
 protected:
-  static bool IsAlpha(PRUnichar aCh) {
-    // Exclude non-ascii characters before calling isalpha
-    return (aCh & 0x7f) == aCh && isalpha(aCh);
-  }
+  const char* mInputPos;
+  
+  const char* mTokenPos;
+  enum { DIGIT, WSP, COMMA, POINT, SIGN, LEFT_PAREN, RIGHT_PAREN, OTHER, END } mTokenType;
+  char mTokenVal;
+
+  // helpers
+  void GetNextToken();
+  void RewindTo(const char* aPos);
+  virtual nsresult Match()=0;
 
-  // Returns true if there are more characters to read, false otherwise.
-  bool SkipCommaWsp();
+  nsresult MatchNumber(float* x);
+  bool IsTokenNumberStarter();
+  
+  nsresult MatchCommaWsp();
+  bool IsTokenCommaWspStarter();
+  
+  nsresult MatchIntegerConst();
+  
+  nsresult MatchFloatingPointConst();
+  
+  nsresult MatchFractConst();
+  
+  nsresult MatchExponent();
+  bool IsTokenExponentStarter();
+  
+  nsresult MatchDigitSeq();
+  bool IsTokenDigitSeqStarter();
+  
+  nsresult MatchWsp();
+  bool IsTokenWspStarter();
 
-  // Returns true if there are more characters to read, false otherwise.
-  bool SkipWsp();
-
-  mozilla::RangedPtr<const PRUnichar> mIter;
-  const mozilla::RangedPtr<const PRUnichar> mEnd;
+  nsresult MatchLeftParen();
+  nsresult MatchRightParen();
 };
 
 
 #endif // __NS_SVGDATAPARSER_H__
--- a/content/svg/content/src/nsSVGLength2.cpp
+++ b/content/svg/content/src/nsSVGLength2.cpp
@@ -117,29 +117,24 @@ GetValueString(nsAString &aValueAsString
   aValueAsString.Assign(buf);
 
   nsAutoString unitString;
   GetUnitString(unitString, aUnitType);
   aValueAsString.Append(unitString);
 }
 
 static bool
-GetValueFromString(const nsAString& aString,
+GetValueFromString(const nsAString& aValueAsString,
                    float& aValue,
                    uint16_t* aUnitType)
 {
-  RangedPtr<const PRUnichar> iter =
-    SVGContentUtils::GetStartRangedPtr(aString);
-  const RangedPtr<const PRUnichar> end =
-    SVGContentUtils::GetEndRangedPtr(aString);
-
-  if (!SVGContentUtils::ParseNumber(iter, end, aValue)) {
+  nsAutoString units;
+  if (!SVGContentUtils::ParseNumber(aValueAsString, aValue, units)) {
     return false;
   }
-  const nsAString& units = Substring(iter.get(), end.get());
   *aUnitType = GetUnitTypeForString(units);
   return IsValidUnitType(*aUnitType);
 }
 
 static float
 FixAxisLength(float aLength)
 {
   if (aLength == 0.0f) {
--- a/content/svg/content/src/nsSVGNumber2.cpp
+++ b/content/svg/content/src/nsSVGNumber2.cpp
@@ -44,38 +44,32 @@ NS_INTERFACE_MAP_BEGIN(DOMSVGNumber)
 NS_INTERFACE_MAP_END
 
 /* Implementation */
 
 static nsSVGAttrTearoffTable<nsSVGNumber2, nsSVGNumber2::DOMAnimatedNumber>
   sSVGAnimatedNumberTearoffTable;
 
 static bool
-GetValueFromString(const nsAString& aString,
+GetValueFromString(const nsAString& aValueAsString,
                    bool aPercentagesAllowed,
                    float& aValue)
 {
-  RangedPtr<const PRUnichar> iter =
-    SVGContentUtils::GetStartRangedPtr(aString);
-  const RangedPtr<const PRUnichar> end =
-    SVGContentUtils::GetEndRangedPtr(aString);
+  nsAutoString units;
 
-  if (!SVGContentUtils::ParseNumber(iter, end, aValue)) {
+  if (!SVGContentUtils::ParseNumber(aValueAsString, aValue, units)) {
     return false;
   }
 
-  if (aPercentagesAllowed) {
-    const nsAString& units = Substring(iter.get(), end.get());
-    if (units.EqualsLiteral("%")) {
-      aValue /= 100;
-      return true;
-    }
+  if (aPercentagesAllowed && units.EqualsLiteral("%")) {
+    aValue /= 100;
+    return true;
   }
 
-  return iter == end;
+  return units.IsEmpty();
 }
 
 nsresult
 nsSVGNumber2::SetBaseValueString(const nsAString &aValueAsString,
                                  nsSVGElement *aSVGElement)
 {
   float val;
 
--- a/content/svg/content/src/nsSVGPathDataParser.cpp
+++ b/content/svg/content/src/nsSVGPathDataParser.cpp
@@ -2,402 +2,838 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsSVGPathDataParser.h"
 
 #include "mozilla/gfx/Point.h"
 #include "nsSVGDataParser.h"
-#include "SVGContentUtils.h"
 #include "SVGPathData.h"
 #include "SVGPathSegUtils.h"
+#include <stdlib.h>
+#include <math.h>
 
 using namespace mozilla;
 using namespace mozilla::gfx;
 
-static inline PRUnichar ToUpper(PRUnichar aCh)
+nsresult nsSVGPathDataParser::Match()
+{
+  return MatchSvgPath();
+}
+
+//----------------------------------------------------------------------
+
+nsresult nsSVGPathDataParser::MatchCoordPair(float* aX, float* aY)
 {
-  return aCh >= 'a' && aCh <= 'z' ? aCh - 'a' + 'A' : aCh;
+  ENSURE_MATCHED(MatchCoord(aX));
+
+  if (IsTokenCommaWspStarter()) {
+    ENSURE_MATCHED(MatchCommaWsp());
+  }
+
+  ENSURE_MATCHED(MatchCoord(aY));
+
+  return NS_OK;
+}
+
+bool nsSVGPathDataParser::IsTokenCoordPairStarter()
+{
+  return IsTokenCoordStarter();
 }
 
-bool
-nsSVGPathDataParser::Parse()
+//----------------------------------------------------------------------
+
+nsresult nsSVGPathDataParser::MatchCoord(float* aX)
+{
+  ENSURE_MATCHED(MatchNumber(aX));
+
+  return NS_OK;
+}
+
+bool nsSVGPathDataParser::IsTokenCoordStarter()
 {
-  mPathSegList->Clear();
-  return ParsePath();
+  return IsTokenNumberStarter();
+}
+
+//----------------------------------------------------------------------
+
+nsresult nsSVGPathDataParser::MatchFlag(bool* f)
+{
+  switch (mTokenVal) {
+    case '0':
+      *f = false;
+      break;
+    case '1':
+      *f = true;
+      break;
+    default:
+      return NS_ERROR_FAILURE;
+  }
+  GetNextToken();
+  return NS_OK;
 }
 
 //----------------------------------------------------------------------
 
-bool
-nsSVGPathDataParser::ParseCoordPair(float& aX, float& aY)
+nsresult nsSVGPathDataParser::MatchSvgPath()
 {
-  return SVGContentUtils::ParseNumber(mIter, mEnd, aX) &&
-         SkipCommaWsp() &&
-         SVGContentUtils::ParseNumber(mIter, mEnd, aY);
+  while (IsTokenWspStarter()) {
+    ENSURE_MATCHED(MatchWsp());
+  }
+
+  if (IsTokenSubPathsStarter()) {
+    ENSURE_MATCHED(MatchSubPaths());
+  }
+
+  while (IsTokenWspStarter()) {
+    ENSURE_MATCHED(MatchWsp());
+  }
+  
+  return NS_OK;
 }
 
-bool
-nsSVGPathDataParser::ParseFlag(bool& aFlag)
+//----------------------------------------------------------------------
+
+nsresult nsSVGPathDataParser::MatchSubPaths()
 {
-  if (mIter == mEnd || (*mIter != '0' && *mIter != '1')) {
-    return false;
+  ENSURE_MATCHED(MatchSubPath());
+
+  while (1) {
+    const char* pos = mTokenPos;
+
+    while (IsTokenWspStarter()) {
+      ENSURE_MATCHED(MatchWsp());
+    }
+
+    if (IsTokenSubPathStarter()) {
+      ENSURE_MATCHED(MatchSubPath());
+    }
+    else {
+      if (pos != mTokenPos) RewindTo(pos);
+      break;
+    }
   }
-  aFlag = (*mIter == '1');
+  
+  return NS_OK;
+}
 
-  ++mIter;
-  return true;
+bool nsSVGPathDataParser::IsTokenSubPathsStarter()
+{
+  return IsTokenSubPathStarter();
 }
 
 //----------------------------------------------------------------------
 
-bool
-nsSVGPathDataParser::ParsePath()
+nsresult nsSVGPathDataParser::MatchSubPath()
+{
+  ENSURE_MATCHED(MatchMoveto());
+
+  while (IsTokenWspStarter()) {
+    ENSURE_MATCHED(MatchWsp());
+  }
+
+  if (IsTokenSubPathElementsStarter())
+    ENSURE_MATCHED(MatchSubPathElements());
+  
+  return NS_OK;
+}
+
+bool nsSVGPathDataParser::IsTokenSubPathStarter()
 {
-  while (SkipWsp()) {
-    if (!ParseSubPath()) {
-      return false;
+  return (tolower(mTokenVal) == 'm');
+}
+
+//----------------------------------------------------------------------
+
+nsresult nsSVGPathDataParser::MatchSubPathElements()
+{
+  ENSURE_MATCHED(MatchSubPathElement());
+
+  while (1) {
+    const char* pos = mTokenPos;
+
+    while (IsTokenWspStarter()) {
+      ENSURE_MATCHED(MatchWsp());
+    }
+
+
+    if (IsTokenSubPathElementStarter()) {
+        ENSURE_MATCHED(MatchSubPathElement());
+    }
+    else {
+      if (pos != mTokenPos) RewindTo(pos);
+      return NS_OK;
     }
   }
+  
+  return NS_OK;
+}
 
-  return true;
+bool nsSVGPathDataParser::IsTokenSubPathElementsStarter()
+{
+  return IsTokenSubPathElementStarter();
 }
 
 //----------------------------------------------------------------------
 
-bool
-nsSVGPathDataParser::ParseSubPath()
-{
-  return ParseMoveto() && ParseSubPathElements();
-}
-
-bool
-nsSVGPathDataParser::ParseSubPathElements()
+nsresult nsSVGPathDataParser::MatchSubPathElement()
 {
-  while (SkipWsp() && !IsStartOfSubPath()) {
-    PRUnichar commandType = ToUpper(*mIter);
-
-    // Upper case commands have absolute co-ordinates,
-    // lower case commands have relative co-ordinates.
-    bool absCoords = commandType == *mIter;
-
-    ++mIter;
-    SkipWsp();
-
-    if (!ParseSubPathElement(commandType, absCoords)) {
-      return false;
-    }
+  switch (tolower(mTokenVal)) {
+    case 'z':
+      ENSURE_MATCHED(MatchClosePath());
+      break;
+    case 'l':
+      ENSURE_MATCHED(MatchLineto());
+      break;      
+    case 'h':
+      ENSURE_MATCHED(MatchHorizontalLineto());
+      break;
+    case 'v':
+      ENSURE_MATCHED(MatchVerticalLineto());
+      break;
+    case 'c':
+      ENSURE_MATCHED(MatchCurveto());
+      break;      
+    case 's':
+      ENSURE_MATCHED(MatchSmoothCurveto());
+      break;
+    case 'q':
+      ENSURE_MATCHED(MatchQuadBezierCurveto());
+      break;
+    case 't':
+      ENSURE_MATCHED(MatchSmoothQuadBezierCurveto());
+      break;
+    case 'a':
+      ENSURE_MATCHED(MatchEllipticalArc());
+      break;
+    default:
+      return NS_ERROR_FAILURE;
+      break;
   }
-  return true;
+  return NS_OK;
 }
 
-bool
-nsSVGPathDataParser::ParseSubPathElement(PRUnichar aCommandType,
-                                         bool aAbsCoords)
+bool nsSVGPathDataParser::IsTokenSubPathElementStarter()
 {
-  switch (aCommandType) {
-    case 'Z':
-      return ParseClosePath();
-    case 'L':
-      return ParseLineto(aAbsCoords);
-    case 'H':
-      return ParseHorizontalLineto(aAbsCoords);
-    case 'V':
-      return ParseVerticalLineto(aAbsCoords);
-    case 'C':
-      return ParseCurveto(aAbsCoords);
-    case 'S':
-      return ParseSmoothCurveto(aAbsCoords);
-    case 'Q':
-      return ParseQuadBezierCurveto(aAbsCoords);
-    case 'T':
-      return ParseSmoothQuadBezierCurveto(aAbsCoords);
-    case 'A':
-      return ParseEllipticalArc(aAbsCoords);
+  switch (tolower(mTokenVal)) {
+    case 'z': case 'l': case 'h': case 'v': case 'c':
+    case 's': case 'q': case 't': case 'a':
+      return true;
+      break;
+    default:
+      return false;
+      break;
   }
   return false;
+}  
+
+//----------------------------------------------------------------------
+
+nsresult nsSVGPathDataParser::MatchMoveto()
+{
+  bool absCoords;
+  
+  switch (mTokenVal) {
+    case 'M':
+      absCoords = true;
+      break;
+    case 'm':
+      absCoords = false;
+      break;
+    default:
+      return NS_ERROR_FAILURE;
+  }
+
+  GetNextToken();
+
+  while (IsTokenWspStarter()) {
+    ENSURE_MATCHED(MatchWsp());
+  }
+
+  ENSURE_MATCHED(MatchMovetoArgSeq(absCoords));
+  
+  return NS_OK;
 }
 
-bool
-nsSVGPathDataParser::IsStartOfSubPath() const
+nsresult nsSVGPathDataParser::MatchMovetoArgSeq(bool absCoords)
 {
-  return *mIter == 'm' || *mIter == 'M';
+  
+  float x, y;
+  ENSURE_MATCHED(MatchCoordPair(&x, &y));
+
+  nsresult rv = StoreMoveTo(absCoords, x, y);
+  NS_ENSURE_SUCCESS(rv, rv);
+    
+  const char* pos = mTokenPos;
+
+  if (IsTokenCommaWspStarter()) {
+    ENSURE_MATCHED(MatchCommaWsp());
+  }
+
+  if (IsTokenLinetoArgSeqStarter()) {
+    ENSURE_MATCHED(MatchLinetoArgSeq(absCoords));
+  }
+  else {
+    if (pos != mTokenPos) RewindTo(pos);
+  }
+  
+  return NS_OK;
 }
 
 //----------------------------------------------------------------------
 
-bool
-nsSVGPathDataParser::ParseMoveto()
+nsresult nsSVGPathDataParser::MatchClosePath()
 {
-  if (!IsStartOfSubPath()) {
-    return false;
+  switch (mTokenVal) {
+    case 'Z':
+    case 'z':
+      GetNextToken();
+      break;
+    default:
+      return NS_ERROR_FAILURE;
+  }
+
+  return StoreClosePath();
+}
+
+//----------------------------------------------------------------------
+  
+nsresult nsSVGPathDataParser::MatchLineto()
+{
+  bool absCoords;
+  
+  switch (mTokenVal) {
+    case 'L':
+      absCoords = true;
+      break;
+    case 'l':
+      absCoords = false;
+      break;
+    default:
+      return NS_ERROR_FAILURE;
   }
 
-  bool absCoords = (*mIter == 'M');
+  GetNextToken();
 
-  ++mIter;
-  SkipWsp();
-
-  float x, y;
-  if (!ParseCoordPair(x, y)) {
-    return false;
+  while (IsTokenWspStarter()) {
+    ENSURE_MATCHED(MatchWsp());
   }
 
-  if (NS_FAILED(mPathSegList->AppendSeg(
-                  absCoords ? PATHSEG_MOVETO_ABS : PATHSEG_MOVETO_REL,
-                  x, y))) {
-    return false;
-  }
+  ENSURE_MATCHED(MatchLinetoArgSeq(absCoords));
+  
+  return NS_OK;
+}
+
+nsresult nsSVGPathDataParser::MatchLinetoArgSeq(bool absCoords)
+{
+  while(1) {
+    float x, y;
+    ENSURE_MATCHED(MatchCoordPair(&x, &y));
+    
+    nsresult rv = StoreLineTo(absCoords, x, y);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    const char* pos = mTokenPos;
 
-  if (!SkipWsp() || IsAlpha(*mIter)) {
-    // End of data, or start of a new command
-    return true;
-  }
+    if (IsTokenCommaWspStarter()) {
+      ENSURE_MATCHED(MatchCommaWsp());
+    }
 
-  // Per SVG 1.1 Section 8.3.2
-  // If a moveto is followed by multiple pairs of coordinates,
-  // the subsequent pairs are treated as implicit lineto commands
-  return ParseLineto(absCoords);
+    if (!IsTokenCoordPairStarter()) {
+      if (pos != mTokenPos) RewindTo(pos);
+      return NS_OK;
+    }
+  }
+  
+  return NS_OK;  
+}
+
+bool nsSVGPathDataParser::IsTokenLinetoArgSeqStarter()
+{
+  return IsTokenCoordPairStarter();
 }
 
 //----------------------------------------------------------------------
 
-bool
-nsSVGPathDataParser::ParseClosePath()
+nsresult nsSVGPathDataParser::MatchHorizontalLineto()
 {
-  return NS_SUCCEEDED(mPathSegList->AppendSeg(PATHSEG_CLOSEPATH));
-}
+  bool absCoords;
+  
+  switch (mTokenVal) {
+    case 'H':
+      absCoords = true;
+      break;
+    case 'h':
+      absCoords = false;
+      break;
+    default:
+      return NS_ERROR_FAILURE;
+  }
 
-//----------------------------------------------------------------------
+  GetNextToken();
 
-bool
-nsSVGPathDataParser::ParseLineto(bool aAbsCoords)
+  while (IsTokenWspStarter()) {
+    ENSURE_MATCHED(MatchWsp());
+  }
+
+  ENSURE_MATCHED(MatchHorizontalLinetoArgSeq(absCoords));
+  
+  return NS_OK;
+}
+  
+nsresult nsSVGPathDataParser::MatchHorizontalLinetoArgSeq(bool absCoords)
 {
-  while (true) {
-    float x, y;
-    if (!ParseCoordPair(x, y)) {
-      return false;
+  while(1) {
+    float x;
+    ENSURE_MATCHED(MatchCoord(&x));
+    
+    nsresult rv = StoreHLineTo(absCoords, x);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    const char* pos = mTokenPos;
+
+    if (IsTokenCommaWspStarter()) {
+      ENSURE_MATCHED(MatchCommaWsp());
     }
 
-    if (NS_FAILED(mPathSegList->AppendSeg(
-                   aAbsCoords ? PATHSEG_LINETO_ABS : PATHSEG_LINETO_REL,
-                   x, y))) {
-      return false;
+    if (!IsTokenCoordStarter()) {
+      if (pos != mTokenPos) RewindTo(pos);
+      return NS_OK;
     }
-
-    if (!SkipWsp() || IsAlpha(*mIter)) {
-      // End of data, or start of a new command
-      return true;
-    }
-    SkipCommaWsp();
   }
+  
+  return NS_OK;    
 }
 
 //----------------------------------------------------------------------
 
-bool
-nsSVGPathDataParser::ParseHorizontalLineto(bool aAbsCoords)
+nsresult nsSVGPathDataParser::MatchVerticalLineto()
 {
-  while (true) {
-    float x;
-    if (!SVGContentUtils::ParseNumber(mIter, mEnd, x)) {
-      return false;
+  bool absCoords;
+  
+  switch (mTokenVal) {
+    case 'V':
+      absCoords = true;
+      break;
+    case 'v':
+      absCoords = false;
+      break;
+    default:
+      return NS_ERROR_FAILURE;
+  }
+
+  GetNextToken();
+
+  while (IsTokenWspStarter()) {
+    ENSURE_MATCHED(MatchWsp());
+  }
+
+  ENSURE_MATCHED(MatchVerticalLinetoArgSeq(absCoords));
+  
+  return NS_OK;
+}
+
+nsresult nsSVGPathDataParser::MatchVerticalLinetoArgSeq(bool absCoords)
+{
+  while(1) {
+    float y;
+    ENSURE_MATCHED(MatchCoord(&y));
+    
+    nsresult rv = StoreVLineTo(absCoords, y);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    const char* pos = mTokenPos;
+
+    if (IsTokenCommaWspStarter()) {
+      ENSURE_MATCHED(MatchCommaWsp());
     }
 
-    if (NS_FAILED(mPathSegList->AppendSeg(
-                    aAbsCoords ? PATHSEG_LINETO_HORIZONTAL_ABS : PATHSEG_LINETO_HORIZONTAL_REL,
-                    x))) {
-      return false;
+    if (!IsTokenCoordStarter()) {
+      if (pos != mTokenPos) RewindTo(pos);
+      return NS_OK;
     }
-
-    if (!SkipWsp() || IsAlpha(*mIter)) {
-      // End of data, or start of a new command
-      return true;
-    }
-    SkipCommaWsp();
   }
+  
+  return NS_OK;      
 }
 
 //----------------------------------------------------------------------
 
-bool
-nsSVGPathDataParser::ParseVerticalLineto(bool aAbsCoords)
+nsresult nsSVGPathDataParser::MatchCurveto()
 {
-  while (true) {
-    float y;
-    if (!SVGContentUtils::ParseNumber(mIter, mEnd, y)) {
-      return false;
+  bool absCoords;
+  
+  switch (mTokenVal) {
+    case 'C':
+      absCoords = true;
+      break;
+    case 'c':
+      absCoords = false;
+      break;
+    default:
+      return NS_ERROR_FAILURE;
+  }
+
+  GetNextToken();
+
+  while (IsTokenWspStarter()) {
+    ENSURE_MATCHED(MatchWsp());
+  }
+
+  ENSURE_MATCHED(MatchCurvetoArgSeq(absCoords));
+  
+  return NS_OK;
+}
+
+
+nsresult nsSVGPathDataParser::MatchCurvetoArgSeq(bool absCoords)
+{
+  while(1) {
+    float x, y, x1, y1, x2, y2;
+    ENSURE_MATCHED(MatchCurvetoArg(&x, &y, &x1, &y1, &x2, &y2));
+
+    nsresult rv = StoreCurveTo(absCoords, x, y, x1, y1, x2, y2);
+    NS_ENSURE_SUCCESS(rv, rv);
+    
+    const char* pos = mTokenPos;
+
+    if (IsTokenCommaWspStarter()) {
+      ENSURE_MATCHED(MatchCommaWsp());
     }
 
-    if (NS_FAILED(mPathSegList->AppendSeg(
-                    aAbsCoords ? PATHSEG_LINETO_VERTICAL_ABS : PATHSEG_LINETO_VERTICAL_REL,
-                    y))) {
-      return false;
+    if (!IsTokenCurvetoArgStarter()) {
+      if (pos != mTokenPos) RewindTo(pos);
+      return NS_OK;
     }
+  }
+  
+  return NS_OK;      
+}
+
+nsresult
+nsSVGPathDataParser::MatchCurvetoArg(float* x, float* y, float* x1,
+                                     float* y1, float* x2, float* y2)
+{
+  ENSURE_MATCHED(MatchCoordPair(x1, y1));
 
-    if (!SkipWsp() || IsAlpha(*mIter)) {
-      // End of data, or start of a new command
-      return true;
-    }
-    SkipCommaWsp();
+  if (IsTokenCommaWspStarter()) {
+    ENSURE_MATCHED(MatchCommaWsp());
+  }
+
+  ENSURE_MATCHED(MatchCoordPair(x2, y2));
+
+  if (IsTokenCommaWspStarter()) {
+    ENSURE_MATCHED(MatchCommaWsp());
   }
+
+  ENSURE_MATCHED(MatchCoordPair(x, y));
+
+  return NS_OK;
+}
+
+bool nsSVGPathDataParser::IsTokenCurvetoArgStarter()
+{
+  return IsTokenCoordPairStarter();
 }
 
 //----------------------------------------------------------------------
 
-bool
-nsSVGPathDataParser::ParseCurveto(bool aAbsCoords)
+nsresult nsSVGPathDataParser::MatchSmoothCurveto()
 {
-  while (true) {
-    float x1, y1, x2, y2, x, y;
+  bool absCoords;
+  
+  switch (mTokenVal) {
+    case 'S':
+      absCoords = true;
+      break;
+    case 's':
+      absCoords = false;
+      break;
+    default:
+      return NS_ERROR_FAILURE;
+  }
+
+  GetNextToken();
 
-    if (!(ParseCoordPair(x1, y1) &&
-          SkipCommaWsp() &&
-          ParseCoordPair(x2, y2) &&
-          SkipCommaWsp() &&
-          ParseCoordPair(x, y))) {
-      return false;
+  while (IsTokenWspStarter()) {
+    ENSURE_MATCHED(MatchWsp());
+  }
+
+  ENSURE_MATCHED(MatchSmoothCurvetoArgSeq(absCoords));
+  
+  return NS_OK;
+}
+
+nsresult nsSVGPathDataParser::MatchSmoothCurvetoArgSeq(bool absCoords)
+{
+  while(1) {
+    float x, y, x2, y2;
+    ENSURE_MATCHED(MatchSmoothCurvetoArg(&x, &y, &x2, &y2));
+    
+    nsresult rv = StoreSmoothCurveTo(absCoords, x, y, x2, y2);
+    NS_ENSURE_SUCCESS(rv, rv);
+    
+    const char* pos = mTokenPos;
+
+    if (IsTokenCommaWspStarter()) {
+      ENSURE_MATCHED(MatchCommaWsp());
     }
 
-    if (NS_FAILED(mPathSegList->AppendSeg(
-                    aAbsCoords ? PATHSEG_CURVETO_CUBIC_ABS : PATHSEG_CURVETO_CUBIC_REL,
-                    x1, y1, x2, y2, x, y))) {
-      return false;
+    if (!IsTokenSmoothCurvetoArgStarter()) {
+      if (pos != mTokenPos) RewindTo(pos);
+      return NS_OK;
     }
+  }
+  
+  return NS_OK;        
+}
+
+nsresult nsSVGPathDataParser::MatchSmoothCurvetoArg(float* x, float* y, float* x2, float* y2)
+{
+  ENSURE_MATCHED(MatchCoordPair(x2, y2));
 
-    if (!SkipWsp() || IsAlpha(*mIter)) {
-      // End of data, or start of a new command
-      return true;
-    }
-    SkipCommaWsp();
+  if (IsTokenCommaWspStarter()) {
+    ENSURE_MATCHED(MatchCommaWsp());
   }
+
+  ENSURE_MATCHED(MatchCoordPair(x, y));
+
+  return NS_OK;
+}
+
+bool nsSVGPathDataParser::IsTokenSmoothCurvetoArgStarter()
+{
+  return IsTokenCoordPairStarter();
 }
 
 //----------------------------------------------------------------------
 
-bool
-nsSVGPathDataParser::ParseSmoothCurveto(bool aAbsCoords)
+nsresult nsSVGPathDataParser::MatchQuadBezierCurveto()
 {
-  while (true) {
-    float x2, y2, x, y;
-    if (!(ParseCoordPair(x2, y2) &&
-          SkipCommaWsp() &&
-          ParseCoordPair(x, y))) {
-      return false;
-    }
+  bool absCoords;
+  
+  switch (mTokenVal) {
+    case 'Q':
+      absCoords = true;
+      break;
+    case 'q':
+      absCoords = false;
+      break;
+    default:
+      return NS_ERROR_FAILURE;
+  }
 
-    if (NS_FAILED(mPathSegList->AppendSeg(
-                    aAbsCoords ? PATHSEG_CURVETO_CUBIC_SMOOTH_ABS : PATHSEG_CURVETO_CUBIC_SMOOTH_REL,
-                    x2, y2, x, y))) {
-      return false;
-    }
+  GetNextToken();
 
-    if (!SkipWsp() || IsAlpha(*mIter)) {
-      // End of data, or start of a new command
-      return true;
-    }
-    SkipCommaWsp();
+  while (IsTokenWspStarter()) {
+    ENSURE_MATCHED(MatchWsp());
   }
+
+  ENSURE_MATCHED(MatchQuadBezierCurvetoArgSeq(absCoords));
+  
+  return NS_OK;
 }
 
-//----------------------------------------------------------------------
-
-bool
-nsSVGPathDataParser::ParseQuadBezierCurveto(bool aAbsCoords)
+nsresult nsSVGPathDataParser::MatchQuadBezierCurvetoArgSeq(bool absCoords)
 {
-  while (true) {
-    float x1, y1, x, y;
-    if (!(ParseCoordPair(x1, y1) &&
-         SkipCommaWsp() &&
-         ParseCoordPair(x, y))) {
-      return false;
+  while(1) {
+    float x, y, x1, y1;
+    ENSURE_MATCHED(MatchQuadBezierCurvetoArg(&x, &y, &x1, &y1));
+
+    nsresult rv = StoreQuadCurveTo(absCoords, x, y, x1, y1);
+    NS_ENSURE_SUCCESS(rv, rv);
+    
+    const char* pos = mTokenPos;
+
+    if (IsTokenCommaWspStarter()) {
+      ENSURE_MATCHED(MatchCommaWsp());
     }
 
-    if (NS_FAILED(mPathSegList->AppendSeg(
-                    aAbsCoords ? PATHSEG_CURVETO_QUADRATIC_ABS : PATHSEG_CURVETO_QUADRATIC_REL,
-                    x1, y1, x, y))) {
-      return false;
+    if (!IsTokenQuadBezierCurvetoArgStarter()) {
+      if (pos != mTokenPos) RewindTo(pos);
+      return NS_OK;
     }
+  }
+  
+  return NS_OK;        
+}
+
+nsresult nsSVGPathDataParser::MatchQuadBezierCurvetoArg(float* x, float* y, float* x1, float* y1)
+{
+  ENSURE_MATCHED(MatchCoordPair(x1, y1));
 
-    if (!SkipWsp() || IsAlpha(*mIter)) {
-      // Start of a new command
-      return true;
-    }
-    SkipCommaWsp();
+  if (IsTokenCommaWspStarter()) {
+    ENSURE_MATCHED(MatchCommaWsp());
   }
+
+  ENSURE_MATCHED(MatchCoordPair(x, y));
+
+  return NS_OK;  
+}
+
+bool nsSVGPathDataParser::IsTokenQuadBezierCurvetoArgStarter()
+{
+  return IsTokenCoordPairStarter();
 }
 
 //----------------------------------------------------------------------
 
-bool
-nsSVGPathDataParser::ParseSmoothQuadBezierCurveto(bool aAbsCoords)
+nsresult nsSVGPathDataParser::MatchSmoothQuadBezierCurveto()
 {
-  while (true) {
+  bool absCoords;
+  
+  switch (mTokenVal) {
+    case 'T':
+      absCoords = true;
+      break;
+    case 't':
+      absCoords = false;
+      break;
+    default:
+      return NS_ERROR_FAILURE;
+  }
+
+  GetNextToken();
+
+  while (IsTokenWspStarter()) {
+    ENSURE_MATCHED(MatchWsp());
+  }
+
+  ENSURE_MATCHED(MatchSmoothQuadBezierCurvetoArgSeq(absCoords));
+  
+  return NS_OK;
+}
+
+nsresult nsSVGPathDataParser::MatchSmoothQuadBezierCurvetoArgSeq(bool absCoords)
+{
+  while(1) {
     float x, y;
-    if (!ParseCoordPair(x, y)) {
-      return false;
+    ENSURE_MATCHED(MatchCoordPair(&x, &y));
+   
+    nsresult rv = StoreSmoothQuadCurveTo(absCoords, x, y);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    const char* pos = mTokenPos;
+
+    if (IsTokenCommaWspStarter()) {
+      ENSURE_MATCHED(MatchCommaWsp());
     }
 
-    if (NS_FAILED(mPathSegList->AppendSeg(
-                    aAbsCoords ? PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS : PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL,
-                    x, y))) {
-      return false;
+    if (!IsTokenCoordPairStarter()) {
+      if (pos != mTokenPos) RewindTo(pos);
+      return NS_OK;
     }
-
-    if (!SkipWsp() || IsAlpha(*mIter)) {
-      // End of data, or start of a new command
-      return true;
-    }
-    SkipCommaWsp();
   }
+  
+  return NS_OK;        
 }
 
 //----------------------------------------------------------------------
 
-bool
-nsSVGPathDataParser::ParseEllipticalArc(bool aAbsCoords)
+nsresult nsSVGPathDataParser::MatchEllipticalArc()
 {
-  while (true) {
-    float r1, r2, angle, x, y;
-    bool largeArcFlag, sweepFlag;
+  bool absCoords;
+  
+  switch (mTokenVal) {
+    case 'A':
+      absCoords = true;
+      break;
+    case 'a':
+      absCoords = false;
+      break;
+    default:
+      return NS_ERROR_FAILURE;
+  }
+
+  GetNextToken();
+
+  while (IsTokenWspStarter()) {
+    ENSURE_MATCHED(MatchWsp());
+  }
 
-    if (!(SVGContentUtils::ParseNumber(mIter, mEnd, r1) &&
-          SkipCommaWsp() &&
-          SVGContentUtils::ParseNumber(mIter, mEnd, r2) &&
-          SkipCommaWsp() &&
-          SVGContentUtils::ParseNumber(mIter, mEnd, angle)&&
-          SkipCommaWsp() &&
-          ParseFlag(largeArcFlag) &&
-          SkipCommaWsp() &&
-          ParseFlag(sweepFlag) &&
-          SkipCommaWsp() &&
-          ParseCoordPair(x, y))) {
-      return false;
+  ENSURE_MATCHED(MatchEllipticalArcArgSeq(absCoords));
+  
+  return NS_OK;
+}
+
+
+nsresult nsSVGPathDataParser::MatchEllipticalArcArgSeq(bool absCoords)
+{
+  while(1) {
+    float x, y, r1, r2, angle;
+    bool largeArcFlag, sweepFlag;
+    
+    ENSURE_MATCHED(MatchEllipticalArcArg(&x, &y, &r1, &r2, &angle, &largeArcFlag, &sweepFlag));
+
+    nsresult rv = StoreEllipticalArc(absCoords, x, y, r1, r2, angle,
+                                     largeArcFlag, sweepFlag);
+    NS_ENSURE_SUCCESS(rv, rv);
+    
+    const char* pos = mTokenPos;
+
+    if (IsTokenCommaWspStarter()) {
+      ENSURE_MATCHED(MatchCommaWsp());
     }
 
-    // We can only pass floats after 'type', and per the SVG spec for arc,
-    // non-zero args are treated at 'true'.
-    if (NS_FAILED(mPathSegList->AppendSeg(
-                    aAbsCoords ? PATHSEG_ARC_ABS : PATHSEG_ARC_REL,
-                    r1, r2, angle,
-                    largeArcFlag ? 1.0f : 0.0f,
-                    sweepFlag ? 1.0f : 0.0f,
-                    x, y))) {
-      return false;
+    if (!IsTokenEllipticalArcArgStarter()) {
+      if (pos != mTokenPos) RewindTo(pos);
+      return NS_OK;
     }
+  }
+  
+  return NS_OK;        
+}
 
-    if (!SkipWsp() || IsAlpha(*mIter)) {
-      // End of data, or start of a new command
-      return true;
-    }
-    SkipCommaWsp();
+nsresult nsSVGPathDataParser::MatchEllipticalArcArg(float* x, float* y,
+                                                    float* r1, float* r2, float* angle,
+                                                    bool* largeArcFlag, bool* sweepFlag)
+{
+  ENSURE_MATCHED(MatchNumber(r1));
+
+  if (IsTokenCommaWspStarter()) {
+    ENSURE_MATCHED(MatchCommaWsp());
+  }
+
+  ENSURE_MATCHED(MatchNumber(r2));
+
+  if (IsTokenCommaWspStarter()) {
+    ENSURE_MATCHED(MatchCommaWsp());
+  }
+
+  ENSURE_MATCHED(MatchNumber(angle));
+
+  if (IsTokenCommaWspStarter()) {
+    ENSURE_MATCHED(MatchCommaWsp());
   }
+  
+  ENSURE_MATCHED(MatchFlag(largeArcFlag));
+
+  if (IsTokenCommaWspStarter()) {
+    ENSURE_MATCHED(MatchCommaWsp());
+  }
+
+  ENSURE_MATCHED(MatchFlag(sweepFlag));
+
+  if (IsTokenCommaWspStarter()) {
+    ENSURE_MATCHED(MatchCommaWsp());
+  }
+
+  ENSURE_MATCHED(MatchCoordPair(x, y));
+  
+  return NS_OK;  
+  
 }
 
+bool nsSVGPathDataParser::IsTokenEllipticalArcArgStarter()
+{
+  return IsTokenNumberStarter();
+}
+
+
 //-----------------------------------------------------------------------
 
 
 
 
 static double
 CalcVectorAngle(double ux, double uy, double vx, double vy)
 {
@@ -506,8 +942,102 @@ nsSVGArcConverter::GetNextSegment(Point*
 
   // do next segment
   mTheta = theta2;
   mFrom = *to;
   ++mSegIndex;
 
   return true;
 }
+
+
+// ---------------------------------------------------------------
+// nsSVGPathDataParserToInternal
+
+nsresult
+nsSVGPathDataParserToInternal::Parse(const nsAString &aValue)
+{
+  mPathSegList->Clear();
+  return nsSVGPathDataParser::Parse(aValue);
+}
+
+nsresult
+nsSVGPathDataParserToInternal::StoreMoveTo(bool absCoords, float x, float y)
+{
+  return mPathSegList->AppendSeg(absCoords ? PATHSEG_MOVETO_ABS : PATHSEG_MOVETO_REL, x, y);
+}
+
+nsresult
+nsSVGPathDataParserToInternal::StoreClosePath()
+{
+  return mPathSegList->AppendSeg(PATHSEG_CLOSEPATH);
+}
+
+nsresult
+nsSVGPathDataParserToInternal::StoreLineTo(bool absCoords, float x, float y)
+{
+  return mPathSegList->AppendSeg(absCoords ? PATHSEG_LINETO_ABS : PATHSEG_LINETO_REL, x, y);
+}
+
+nsresult
+nsSVGPathDataParserToInternal::StoreHLineTo(bool absCoords, float x)
+{
+  return mPathSegList->AppendSeg(absCoords ? PATHSEG_LINETO_HORIZONTAL_ABS : PATHSEG_LINETO_HORIZONTAL_REL, x);
+}
+
+nsresult
+nsSVGPathDataParserToInternal::StoreVLineTo(bool absCoords, float y)
+{
+  return mPathSegList->AppendSeg(absCoords ? PATHSEG_LINETO_VERTICAL_ABS : PATHSEG_LINETO_VERTICAL_REL, y);
+}
+
+nsresult
+nsSVGPathDataParserToInternal::StoreCurveTo(bool absCoords,
+                                            float x, float y,
+                                            float x1, float y1,
+                                            float x2, float y2)
+{
+  return mPathSegList->AppendSeg(absCoords ? PATHSEG_CURVETO_CUBIC_ABS : PATHSEG_CURVETO_CUBIC_REL,
+                                 x1, y1, x2, y2, x, y);
+}
+
+nsresult
+nsSVGPathDataParserToInternal::StoreSmoothCurveTo(bool absCoords,
+                                                  float x, float y,
+                                                  float x2, float y2)
+{
+  return mPathSegList->AppendSeg(absCoords ? PATHSEG_CURVETO_CUBIC_SMOOTH_ABS : PATHSEG_CURVETO_CUBIC_SMOOTH_REL,
+                                 x2, y2, x, y);
+}
+
+nsresult
+nsSVGPathDataParserToInternal::StoreQuadCurveTo(bool absCoords,
+                                                float x, float y,
+                                                float x1, float y1)
+{
+  return mPathSegList->AppendSeg(absCoords ? PATHSEG_CURVETO_QUADRATIC_ABS : PATHSEG_CURVETO_QUADRATIC_REL,
+                                 x1, y1, x, y);
+}
+
+nsresult
+nsSVGPathDataParserToInternal::StoreSmoothQuadCurveTo(bool absCoords,
+                                                      float x, float y)
+{
+  return mPathSegList->AppendSeg(absCoords ? PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS : PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL, x, y);
+}
+
+nsresult
+nsSVGPathDataParserToInternal::StoreEllipticalArc(bool absCoords,
+                                                  float x, float y,
+                                                  float r1, float r2,
+                                                  float angle,
+                                                  bool largeArcFlag,
+                                                  bool sweepFlag)
+{
+  // We can only pass floats after 'type', and per the SVG spec for arc,
+  // non-zero args are treated at 'true'.
+  return mPathSegList->AppendSeg(absCoords ? PATHSEG_ARC_ABS : PATHSEG_ARC_REL,
+                                 r1, r2, angle,
+                                 largeArcFlag ? 1.0f : 0.0f,
+                                 sweepFlag ? 1.0f : 0.0f,
+                                 x, y);
+}
+
--- a/content/svg/content/src/nsSVGPathDataParser.h
+++ b/content/svg/content/src/nsSVGPathDataParser.h
@@ -17,53 +17,101 @@ class SVGPathData;
 
 ////////////////////////////////////////////////////////////////////////
 // nsSVGPathDataParser: a simple recursive descent parser that builds
 // DOMSVGPathSegs from path data strings. The grammar for path data
 // can be found in SVG CR 20001102, chapter 8.
 
 class nsSVGPathDataParser : public nsSVGDataParser
 {
-public:
-  nsSVGPathDataParser(const nsAString& aValue,
-                      mozilla::SVGPathData* aList)
-    : nsSVGDataParser(aValue),
-      mPathSegList(aList)
-  {
-    MOZ_ASSERT(aList, "null path data");
-  }
+protected:
+  // Path data storage
+  virtual nsresult StoreMoveTo(bool absCoords, float x, float y) = 0;
+  virtual nsresult StoreClosePath() = 0;
+  virtual nsresult StoreLineTo(bool absCoords, float x, float y) = 0;
+  virtual nsresult StoreHLineTo(bool absCoords, float x) = 0;
+  virtual nsresult StoreVLineTo(bool absCoords, float y) = 0;
+  virtual nsresult StoreCurveTo(bool absCoords, float x, float y,
+                                float x1, float y1, float x2, float y2) = 0;
+  virtual nsresult StoreSmoothCurveTo(bool absCoords, float x, float y,
+                                      float x2, float y2) = 0;
+  virtual nsresult StoreQuadCurveTo(bool absCoords, float x, float y,
+                                    float x1, float y1) = 0;
+  virtual nsresult StoreSmoothQuadCurveTo(bool absCoords,
+                                          float x, float y) = 0;
+  virtual nsresult StoreEllipticalArc(bool absCoords, float x, float y,
+                                      float r1, float r2, float angle,
+                                      bool largeArcFlag, bool sweepFlag) = 0;
+  virtual nsresult Match() MOZ_OVERRIDE;
+ 
+  nsresult MatchCoordPair(float* aX, float* aY);
+  bool IsTokenCoordPairStarter();
 
-  bool Parse();
+  nsresult MatchCoord(float* aX);
+  bool IsTokenCoordStarter();
+
+  nsresult MatchFlag(bool* f);
 
-private:
+  nsresult MatchSvgPath();
+  
+  nsresult MatchSubPaths();
+  bool IsTokenSubPathsStarter();
+  
+  nsresult MatchSubPath();
+  bool IsTokenSubPathStarter();
+  
+  nsresult MatchSubPathElements();
+  bool IsTokenSubPathElementsStarter();
 
-  bool ParseCoordPair(float& aX, float& aY);
-  bool ParseFlag(bool& aFlag);
+  nsresult MatchSubPathElement();
+  bool IsTokenSubPathElementStarter();
 
-  bool ParsePath();
-  bool IsStartOfSubPath() const;
-  bool ParseSubPath();
+  nsresult MatchMoveto();
+  nsresult MatchMovetoArgSeq(bool absCoords);
+  
+  nsresult MatchClosePath();
+  
+  nsresult MatchLineto();
+  
+  nsresult MatchLinetoArgSeq(bool absCoords);
+  bool IsTokenLinetoArgSeqStarter();
+  
+  nsresult MatchHorizontalLineto();
+  nsresult MatchHorizontalLinetoArgSeq(bool absCoords);
+  
+  nsresult MatchVerticalLineto();
+  nsresult MatchVerticalLinetoArgSeq(bool absCoords);
+  
+  nsresult MatchCurveto();
+  nsresult MatchCurvetoArgSeq(bool absCoords);
+  nsresult MatchCurvetoArg(float* x, float* y, float* x1,
+                           float* y1, float* x2, float* y2);
+  bool IsTokenCurvetoArgStarter();
   
-  bool ParseSubPathElements();
-  bool ParseSubPathElement(PRUnichar aCommandType,
-                           bool aAbsCoords);
-
-  bool ParseMoveto();
-  bool ParseClosePath();
-  bool ParseLineto(bool aAbsCoords);
-  bool ParseHorizontalLineto(bool aAbsCoords);
-  bool ParseVerticalLineto(bool aAbsCoords);
-  bool ParseCurveto(bool aAbsCoords);
-  bool ParseSmoothCurveto(bool aAbsCoords);
-  bool ParseQuadBezierCurveto(bool aAbsCoords);
-  bool ParseSmoothQuadBezierCurveto(bool aAbsCoords);  
-  bool ParseEllipticalArc(bool aAbsCoords);  
-
-  mozilla::SVGPathData * const mPathSegList;
-};
+  nsresult MatchSmoothCurveto();
+  nsresult MatchSmoothCurvetoArgSeq(bool absCoords);
+  nsresult MatchSmoothCurvetoArg(float* x, float* y, float* x2, float* y2);
+  bool IsTokenSmoothCurvetoArgStarter();
+  
+  nsresult MatchQuadBezierCurveto();
+  nsresult MatchQuadBezierCurvetoArgSeq(bool absCoords);  
+  nsresult MatchQuadBezierCurvetoArg(float* x, float* y, float* x1, float* y1);
+  bool IsTokenQuadBezierCurvetoArgStarter();
+  
+  nsresult MatchSmoothQuadBezierCurveto();  
+  nsresult MatchSmoothQuadBezierCurvetoArgSeq(bool absCoords);
+  
+  nsresult MatchEllipticalArc();  
+  nsresult MatchEllipticalArcArgSeq(bool absCoords);
+  nsresult MatchEllipticalArcArg(float* x, float* y,
+                                 float* r1, float* r2, float* angle,
+                                 bool* largeArcFlag, bool* sweepFlag);
+  bool IsTokenEllipticalArcArgStarter();
+  
+ };
 
 class nsSVGArcConverter
 {
   typedef mozilla::gfx::Point Point;
 
 public:
   nsSVGArcConverter(const Point& from,
                     const Point& to,
@@ -75,9 +123,39 @@ public:
 protected:
   int32_t mNumSegs, mSegIndex;
   double mTheta, mDelta, mT;
   double mSinPhi, mCosPhi;
   double mRx, mRy;
   Point mFrom, mC;
 };
 
+class nsSVGPathDataParserToInternal : public nsSVGPathDataParser
+{
+public:
+  nsSVGPathDataParserToInternal(mozilla::SVGPathData *aList)
+    : mPathSegList(aList)
+  {}
+  nsresult Parse(const nsAString &aValue);
+
+protected:
+  virtual nsresult StoreMoveTo(bool absCoords, float x, float y) MOZ_OVERRIDE;
+  virtual nsresult StoreClosePath() MOZ_OVERRIDE;
+  virtual nsresult StoreLineTo(bool absCoords, float x, float y) MOZ_OVERRIDE;
+  virtual nsresult StoreHLineTo(bool absCoords, float x) MOZ_OVERRIDE;
+  virtual nsresult StoreVLineTo(bool absCoords, float y) MOZ_OVERRIDE;
+  virtual nsresult StoreCurveTo(bool absCoords, float x, float y,
+                                float x1, float y1, float x2, float y2) MOZ_OVERRIDE;
+  virtual nsresult StoreSmoothCurveTo(bool absCoords, float x, float y,
+                                      float x2, float y2) MOZ_OVERRIDE;
+  virtual nsresult StoreQuadCurveTo(bool absCoords, float x, float y,
+                                    float x1, float y1) MOZ_OVERRIDE;
+  virtual nsresult StoreSmoothQuadCurveTo(bool absCoords,
+                                          float x, float y) MOZ_OVERRIDE;
+  virtual nsresult StoreEllipticalArc(bool absCoords, float x, float y,
+                                      float r1, float r2, float angle,
+                                      bool largeArcFlag, bool sweepFlag) MOZ_OVERRIDE;
+
+private:
+  mozilla::SVGPathData *mPathSegList;
+};
+
 #endif // __NS_SVGPATHDATAPARSER_H__