From 2a9ecaa6e60f3e565b47912837a40fa55d8d2ba4 Mon Sep 17 00:00:00 2001 From: Robert Longson Date: Tue, 29 Oct 2013 17:15:39 +0000 Subject: [PATCH] Bug 929011 - Simplify path and transform parsing. r=dholbert --- content/svg/content/src/SVGContentUtils.cpp | 87 +- content/svg/content/src/SVGContentUtils.h | 15 +- content/svg/content/src/SVGLength.cpp | 11 +- .../src/SVGMotionSMILAnimationFunction.cpp | 4 +- content/svg/content/src/SVGPathData.cpp | 4 +- content/svg/content/src/SVGPathData.h | 6 +- content/svg/content/src/SVGPointList.cpp | 13 +- content/svg/content/src/SVGTransformList.cpp | 6 +- .../content/src/SVGTransformListParser.cpp | 371 +++--- .../svg/content/src/SVGTransformListParser.h | 44 +- content/svg/content/src/nsSVGAngle.cpp | 10 +- content/svg/content/src/nsSVGDataParser.cpp | 301 +---- content/svg/content/src/nsSVGDataParser.h | 51 +- content/svg/content/src/nsSVGLength2.cpp | 11 +- content/svg/content/src/nsSVGNumber2.cpp | 20 +- .../svg/content/src/nsSVGPathDataParser.cpp | 1060 +++++------------ content/svg/content/src/nsSVGPathDataParser.h | 142 +-- 17 files changed, 613 insertions(+), 1543 deletions(-) diff --git a/content/svg/content/src/SVGContentUtils.cpp b/content/svg/content/src/SVGContentUtils.cpp index 6ca71737270e..4bd8b2c39516 100644 --- a/content/svg/content/src/SVGContentUtils.cpp +++ b/content/svg/content/src/SVGContentUtils.cpp @@ -10,7 +10,6 @@ // 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" @@ -390,24 +389,22 @@ DecimalDigitValue(PRUnichar aCh) template bool -SVGContentUtils::ParseNumber(const nsAString& aString, - floatType& aValue, - nsAString& aLeftOver) +SVGContentUtils::ParseNumber(RangedPtr& aIter, + const RangedPtr& aEnd, + floatType& aValue) { - mozilla::RangedPtr iter(aString.Data(), aString.Length()); - const mozilla::RangedPtr end(aString.Data() + aString.Length(), - aString.Data(), aString.Length()); - - if (iter == end) { + if (aIter == aEnd) { return false; } + RangedPtr iter(aIter); + // Sign of the mantissa (-1 or 1). int32_t sign = *iter == '-' ? -1 : 1; if (*iter == '-' || *iter == '+') { ++iter; - if (iter == end) { + if (iter == aEnd) { return false; } } @@ -424,9 +421,9 @@ SVGContentUtils::ParseNumber(const nsAString& aString, do { intPart = floatType(10) * intPart + DecimalDigitValue(*iter); ++iter; - } while (iter != end && IsDigit(*iter)); + } while (iter != aEnd && IsDigit(*iter)); - if (iter != end) { + if (iter != aEnd) { gotDot = *iter == '.'; } } @@ -436,7 +433,7 @@ SVGContentUtils::ParseNumber(const nsAString& aString, if (gotDot) { ++iter; - if (iter == end || !IsDigit(*iter)) { + if (iter == aEnd || !IsDigit(*iter)) { return false; } // Power of ten by which we need to divide our next digit @@ -445,23 +442,23 @@ SVGContentUtils::ParseNumber(const nsAString& aString, fracPart += DecimalDigitValue(*iter) / divisor; divisor *= 10; ++iter; - } while (iter != end && IsDigit(*iter)); + } while (iter != aEnd && IsDigit(*iter)); } bool gotE = false; int32_t exponent = 0; int32_t expSign; - if (iter != end && (*iter == 'e' || *iter == 'E')) { + if (iter != aEnd && (*iter == 'e' || *iter == 'E')) { - mozilla::RangedPtr expIter(iter); + RangedPtr expIter(iter); ++expIter; - if (expIter != end) { + if (expIter != aEnd) { expSign = *expIter == '-' ? -1 : 1; if (*expIter == '-' || *expIter == '+') { ++expIter; - if (expIter != end && IsDigit(*expIter)) { + if (expIter != aEnd && 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; @@ -474,41 +471,54 @@ SVGContentUtils::ParseNumber(const nsAString& aString, do { exponent = 10 * exponent + DecimalDigitValue(*iter); ++iter; - } while (iter != end && IsDigit(*iter)); + } while (iter != aEnd && IsDigit(*iter)); } } // Assemble the number - aValue = sign * (intPart + fracPart); + floatType value = sign * (intPart + fracPart); if (gotE) { - aValue *= pow(floatType(10), floatType(expSign * exponent)); + value *= pow(floatType(10), floatType(expSign * exponent)); } - - aLeftOver = Substring(iter.get(), end.get()); - return NS_finite(aValue); + if (!NS_finite(value)) { + return false; + } + aIter = iter; + aValue = value; + return true; } template bool -SVGContentUtils::ParseNumber(const nsAString& aString, - float& aValue, - nsAString& aLeftOver); +SVGContentUtils::ParseNumber(RangedPtr& aIter, + const RangedPtr& aEnd, + float& aValue); template bool -SVGContentUtils::ParseNumber(const nsAString& aString, - double& aValue, - nsAString& aLeftOver); +SVGContentUtils::ParseNumber(RangedPtr& aIter, + const RangedPtr& aEnd, + double& aValue); + +RangedPtr +SVGContentUtils::GetStartRangedPtr(const nsAString& aString) +{ + return RangedPtr(aString.Data(), aString.Length()); +} + +RangedPtr +SVGContentUtils::GetEndRangedPtr(const nsAString& aString) +{ + return RangedPtr(aString.Data() + aString.Length(), + aString.Data(), aString.Length()); +} template bool SVGContentUtils::ParseNumber(const nsAString& aString, floatType& aValue) { - nsAutoString leftOver; + RangedPtr iter = GetStartRangedPtr(aString); + const RangedPtr end = GetEndRangedPtr(aString); - if (!ParseNumber(aString, aValue, leftOver)) { - return false; - } - - return leftOver.IsEmpty(); + return ParseNumber(iter, end, aValue) && iter == end; } template bool @@ -522,9 +532,8 @@ bool SVGContentUtils::ParseInteger(const nsAString& aString, int32_t& aValue) { - mozilla::RangedPtr iter(aString.Data(), aString.Length()); - const mozilla::RangedPtr end(aString.Data() + aString.Length(), - aString.Data(), aString.Length()); + RangedPtr iter = GetStartRangedPtr(aString); + const RangedPtr end = GetEndRangedPtr(aString); if (iter == end) { return false; diff --git a/content/svg/content/src/SVGContentUtils.h b/content/svg/content/src/SVGContentUtils.h index 5e5ff7926ebc..656796b37334 100644 --- a/content/svg/content/src/SVGContentUtils.h +++ b/content/svg/content/src/SVGContentUtils.h @@ -11,6 +11,7 @@ #include #include "gfxMatrix.h" +#include "mozilla/RangedPtr.h" class nsIContent; class nsIDocument; @@ -132,16 +133,24 @@ public: float aViewboxWidth, float aViewboxHeight, const SVGPreserveAspectRatio &aPreserveAspectRatio); + static mozilla::RangedPtr + GetStartRangedPtr(const nsAString& aString); + + static mozilla::RangedPtr + 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. - * Anything after the number is returned in aLeftOver. + * If parsing succeeds, aIter is updated so that it points to the character + * after the end of the number, otherwise it is left unchanged */ template static bool - ParseNumber(const nsAString& aString, floatType& aValue, - nsAString& aLeftOver); + ParseNumber(mozilla::RangedPtr& aIter, + const mozilla::RangedPtr& aEnd, + floatType& aValue); /** * Parse a number of the form: diff --git a/content/svg/content/src/SVGLength.cpp b/content/svg/content/src/SVGLength.cpp index 868138909d07..fe4c566517a4 100644 --- a/content/svg/content/src/SVGLength.cpp +++ b/content/svg/content/src/SVGLength.cpp @@ -34,15 +34,20 @@ SVGLength::GetValueAsString(nsAString &aValue) const } bool -SVGLength::SetValueFromString(const nsAString &aValueAsString) +SVGLength::SetValueFromString(const nsAString &aString) { - nsAutoString units; + RangedPtr iter = + SVGContentUtils::GetStartRangedPtr(aString); + const RangedPtr end = + SVGContentUtils::GetEndRangedPtr(aString); + float value; - if (!SVGContentUtils::ParseNumber(aValueAsString, value, units)) { + if (!SVGContentUtils::ParseNumber(iter, end, value)) { return false; } + const nsAString& units = Substring(iter.get(), end.get()); uint16_t unitType = GetUnitTypeForString(units); if (!IsValidUnitType(unitType)) { return false; diff --git a/content/svg/content/src/SVGMotionSMILAnimationFunction.cpp b/content/svg/content/src/SVGMotionSMILAnimationFunction.cpp index 7549fffa180a..61cc42c13913 100644 --- a/content/svg/content/src/SVGMotionSMILAnimationFunction.cpp +++ b/content/svg/content/src/SVGMotionSMILAnimationFunction.cpp @@ -241,13 +241,13 @@ SVGMotionSMILAnimationFunction::RebuildPathAndVerticesFromPathAttr() // Generate gfxPath from |path| attr SVGPathData path; - nsSVGPathDataParserToInternal pathParser(&path); + nsSVGPathDataParser pathParser(pathSpec, &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(pathSpec); + pathParser.Parse(); if (!path.Length()) { return; } diff --git a/content/svg/content/src/SVGPathData.cpp b/content/svg/content/src/SVGPathData.cpp index 701b7105cd1f..7ea1907abac4 100644 --- a/content/svg/content/src/SVGPathData.cpp +++ b/content/svg/content/src/SVGPathData.cpp @@ -71,8 +71,8 @@ SVGPathData::SetValueFromString(const nsAString& aValue) // the first error. We still return any error though so that callers know if // there's a problem. - nsSVGPathDataParserToInternal pathParser(this); - return pathParser.Parse(aValue); + nsSVGPathDataParser pathParser(aValue, this); + return pathParser.Parse() ? NS_OK : NS_ERROR_DOM_SYNTAX_ERR; } nsresult diff --git a/content/svg/content/src/SVGPathData.h b/content/svg/content/src/SVGPathData.h index b3fef168671e..fdc5966b4e4d 100644 --- a/content/svg/content/src/SVGPathData.h +++ b/content/svg/content/src/SVGPathData.h @@ -20,7 +20,7 @@ class gfxContext; class gfxPath; -class nsSVGPathDataParserToInternal; // IWYU pragma: keep +class nsSVGPathDataParser; // IWYU pragma: keep struct gfxMatrix; struct nsSVGMark; @@ -78,8 +78,8 @@ class SVGPathData friend class SVGAnimatedPathSegList; friend class DOMSVGPathSegList; friend class DOMSVGPathSeg; - friend class ::nsSVGPathDataParserToInternal; - // nsSVGPathDataParserToInternal will not keep wrappers in sync, so consumers + friend class ::nsSVGPathDataParser; + // nsSVGPathDataParser will not keep wrappers in sync, so consumers // are responsible for that! typedef gfx::DrawTarget DrawTarget; diff --git a/content/svg/content/src/SVGPointList.cpp b/content/svg/content/src/SVGPointList.cpp index bb78cc3cead6..40519a79e239 100644 --- a/content/svg/content/src/SVGPointList.cpp +++ b/content/svg/content/src/SVGPointList.cpp @@ -60,15 +60,21 @@ SVGPointList::SetValueFromString(const nsAString& aValue) while (tokenizer.hasMoreTokens()) { + const nsAString& token = tokenizer.nextToken(); + + RangedPtr iter = + SVGContentUtils::GetStartRangedPtr(token); + const RangedPtr end = + SVGContentUtils::GetEndRangedPtr(token); + float x; - nsAutoString leftOver; - if (!SVGContentUtils::ParseNumber(tokenizer.nextToken(), x, leftOver)) { + if (!SVGContentUtils::ParseNumber(iter, end, x)) { rv = NS_ERROR_DOM_SYNTAX_ERR; break; } float y; - if (leftOver.IsEmpty()) { + if (iter == end) { if (!tokenizer.hasMoreTokens() || !SVGContentUtils::ParseNumber(tokenizer.nextToken(), y)) { rv = NS_ERROR_DOM_SYNTAX_ERR; @@ -77,6 +83,7 @@ SVGPointList::SetValueFromString(const nsAString& aValue) } 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; diff --git a/content/svg/content/src/SVGTransformList.cpp b/content/svg/content/src/SVGTransformList.cpp index 15e928c39a1e..8b080bc2fa3c 100644 --- a/content/svg/content/src/SVGTransformList.cpp +++ b/content/svg/content/src/SVGTransformList.cpp @@ -70,10 +70,8 @@ SVGTransformList::GetValueAsString(nsAString& aValue) const nsresult SVGTransformList::SetValueFromString(const nsAString& aValue) { - SVGTransformListParser parser; - nsresult rv = parser.Parse(aValue); - - if (NS_FAILED(rv)) { + SVGTransformListParser parser(aValue); + if (!parser.Parse()) { // there was a parse error. return NS_ERROR_DOM_SYNTAX_ERR; } diff --git a/content/svg/content/src/SVGTransformListParser.cpp b/content/svg/content/src/SVGTransformListParser.cpp index 4a30c45182cb..cbd9702b2584 100644 --- a/content/svg/content/src/SVGTransformListParser.cpp +++ b/content/svg/content/src/SVGTransformListParser.cpp @@ -7,201 +7,138 @@ #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 -nsresult -SVGTransformListParser::Match() +bool +SVGTransformListParser::Parse() { mTransforms.Clear(); - return MatchTransformList(); + return ParseTransforms(); } - -nsresult -SVGTransformListParser::MatchTransformList() -{ - MatchWsp(); - - if (IsTokenTransformStarter()) { - ENSURE_MATCHED(MatchTransforms()); - } - - 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 (IsTokenTransformStarter()) { - ENSURE_MATCHED(MatchTransform()); - } else { - if (pos != mTokenPos) RewindTo(pos); - break; - } - } - - 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; - } - - return rv; -} - - -nsresult -SVGTransformListParser::MatchTransform() -{ - nsCOMPtr keyatom; - - nsresult rv = GetTransformToken(getter_AddRefs(keyatom), true); - if (NS_FAILED(rv)) { - return rv; - } - - 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() +SVGTransformListParser::ParseTransforms() { - nsCOMPtr keyatom; - - nsresult rv = GetTransformToken(getter_AddRefs(keyatom), false); - if (NS_FAILED(rv)) { - return false; - } - - if (keyatom == nsGkAtoms::translate || - keyatom == nsGkAtoms::scale || - keyatom == nsGkAtoms::rotate || - keyatom == nsGkAtoms::skewX || - keyatom == nsGkAtoms::skewY || - keyatom == nsGkAtoms::matrix) { + if (!SkipWsp()) { return true; } + if (!ParseTransform()) { + return false; + } + + while (SkipWsp()) { + // The SVG BNF allows multiple comma-wsp between transforms + while (*mIter == ',') { + ++mIter; + if (!SkipWsp()) { + return false; + } + } + + if (!ParseTransform()) { + return false; + } + } + return true; +} + +bool +SVGTransformListParser::ParseTransform() +{ + RangedPtr start(mIter); + while (IsAlpha(*mIter)) { + ++mIter; + if (mIter == mEnd) { + return false; + } + } + + if (start == mIter) { + // Didn't read anything + return false; + } + + const nsAString& transform = Substring(start.get(), mIter.get()); + nsIAtom* keyAtom = NS_GetStaticAtom(transform); + + if (!keyAtom || !SkipWsp()) { + return false; + } + + if (keyAtom == nsGkAtoms::translate) { + return ParseTranslate(); + } + if (keyAtom == nsGkAtoms::scale) { + return ParseScale(); + } + if (keyAtom == nsGkAtoms::rotate) { + return ParseRotate(); + } + if (keyAtom == nsGkAtoms::skewX) { + return ParseSkewX(); + } + if (keyAtom == nsGkAtoms::skewY) { + return ParseSkewY(); + } + if (keyAtom == nsGkAtoms::matrix) { + return ParseMatrix(); + } return false; } -nsresult -SVGTransformListParser::MatchNumberArguments(float *aResult, - uint32_t aMaxNum, - uint32_t *aParsedNum) +bool +SVGTransformListParser::ParseArguments(float* aResult, + uint32_t aMaxCount, + uint32_t* aParsedCount) { - *aParsedNum = 0; + if (*mIter != '(') { + return false; + } + ++mIter; - MatchWsp(); - - ENSURE_MATCHED(MatchLeftParen()); - - MatchWsp(); - - ENSURE_MATCHED(MatchNumber(&aResult[0])); - *aParsedNum = 1; - - while (IsTokenCommaWspStarter()) { - MatchWsp(); - if (mTokenType == RIGHT_PAREN) { - break; - } - if (*aParsedNum == aMaxNum) { - return NS_ERROR_FAILURE; - } - if (IsTokenCommaWspStarter()) { - MatchCommaWsp(); - } - ENSURE_MATCHED(MatchNumber(&aResult[(*aParsedNum)++])); + if (!SkipWsp()) { + return false; } - MatchWsp(); + if (!SVGContentUtils::ParseNumber(mIter, mEnd, aResult[0])) { + return false; + } + *aParsedCount = 1; - ENSURE_MATCHED(MatchRightParen()); - - return NS_OK; + while (SkipWsp()) { + if (*mIter == ')') { + ++mIter; + return true; + } + if (*aParsedCount == aMaxCount) { + return false; + } + SkipCommaWsp(); + if (!SVGContentUtils::ParseNumber(mIter, mEnd, aResult[(*aParsedCount)++])) { + return false; + } + } + return false; } -nsresult -SVGTransformListParser::MatchTranslate() +bool +SVGTransformListParser::ParseTranslate() { - GetNextToken(); - float t[2]; uint32_t count; - ENSURE_MATCHED(MatchNumberArguments(t, ArrayLength(t), &count)); + if (!ParseArguments(t, ArrayLength(t), &count)) { + return false; + } switch (count) { case 1: @@ -210,27 +147,26 @@ SVGTransformListParser::MatchTranslate() case 2: { nsSVGTransform* transform = mTransforms.AppendElement(); - NS_ENSURE_TRUE(transform, NS_ERROR_OUT_OF_MEMORY); + if (!transform) { + return false; + } transform->SetTranslate(t[0], t[1]); - break; + return true; } - default: - return NS_ERROR_FAILURE; } - return NS_OK; + return false; } - -nsresult -SVGTransformListParser::MatchScale() +bool +SVGTransformListParser::ParseScale() { - GetNextToken(); - float s[2]; uint32_t count; - ENSURE_MATCHED(MatchNumberArguments(s, ArrayLength(s), &count)); + if (!ParseArguments(s, ArrayLength(s), &count)) { + return false; + } switch (count) { case 1: @@ -239,27 +175,27 @@ SVGTransformListParser::MatchScale() case 2: { nsSVGTransform* transform = mTransforms.AppendElement(); - NS_ENSURE_TRUE(transform, NS_ERROR_OUT_OF_MEMORY); + if (!transform) { + return false; + } transform->SetScale(s[0], s[1]); - break; + return true; } - default: - return NS_ERROR_FAILURE; } - return NS_OK; + return false; } -nsresult -SVGTransformListParser::MatchRotate() +bool +SVGTransformListParser::ParseRotate() { - GetNextToken(); - float r[3]; uint32_t count; - ENSURE_MATCHED(MatchNumberArguments(r, ArrayLength(r), &count)); + if (!ParseArguments(r, ArrayLength(r), &count)) { + return false; + } switch (count) { case 1: @@ -268,79 +204,70 @@ SVGTransformListParser::MatchRotate() case 3: { nsSVGTransform* transform = mTransforms.AppendElement(); - NS_ENSURE_TRUE(transform, NS_ERROR_OUT_OF_MEMORY); + if (!transform) { + return false; + } transform->SetRotate(r[0], r[1], r[2]); - break; + return true; } - default: - return NS_ERROR_FAILURE; } - return NS_OK; + return false; } - -nsresult -SVGTransformListParser::MatchSkewX() +bool +SVGTransformListParser::ParseSkewX() { - GetNextToken(); - float skew; uint32_t count; - ENSURE_MATCHED(MatchNumberArguments(&skew, 1, &count)); - - if (count != 1) { - return NS_ERROR_FAILURE; + if (!ParseArguments(&skew, 1, &count) || count != 1) { + return false; } nsSVGTransform* transform = mTransforms.AppendElement(); - NS_ENSURE_TRUE(transform, NS_ERROR_OUT_OF_MEMORY); + if (!transform) { + return false; + } transform->SetSkewX(skew); - return NS_OK; + return true; } - -nsresult -SVGTransformListParser::MatchSkewY() +bool +SVGTransformListParser::ParseSkewY() { - GetNextToken(); - float skew; uint32_t count; - ENSURE_MATCHED(MatchNumberArguments(&skew, 1, &count)); - - if (count != 1) { - return NS_ERROR_FAILURE; + if (!ParseArguments(&skew, 1, &count) || count != 1) { + return false; } nsSVGTransform* transform = mTransforms.AppendElement(); - NS_ENSURE_TRUE(transform, NS_ERROR_OUT_OF_MEMORY); + if (!transform) { + return false; + } transform->SetSkewY(skew); - return NS_OK; + return true; } - -nsresult -SVGTransformListParser::MatchMatrix() +bool +SVGTransformListParser::ParseMatrix() { - GetNextToken(); - float m[6]; uint32_t count; - ENSURE_MATCHED(MatchNumberArguments(m, ArrayLength(m), &count)); - - if (count != 6) { - return NS_ERROR_FAILURE; + if (!ParseArguments(m, ArrayLength(m), &count) || count != 6) { + return false; } nsSVGTransform* transform = mTransforms.AppendElement(); - NS_ENSURE_TRUE(transform, NS_ERROR_OUT_OF_MEMORY); + if (!transform) { + return false; + } transform->SetMatrix(gfxMatrix(m[0], m[1], m[2], m[3], m[4], m[5])); - return NS_OK; + return true; } diff --git a/content/svg/content/src/SVGTransformListParser.h b/content/svg/content/src/SVGTransformListParser.h index 3537653161b3..d980c5fa812d 100644 --- a/content/svg/content/src/SVGTransformListParser.h +++ b/content/svg/content/src/SVGTransformListParser.h @@ -12,14 +12,11 @@ #include "nsTArray.h" //////////////////////////////////////////////////////////////////////// -// SVGTransformListParser: taken from nsSVGPathDataParser, a simple -// recursive descent parser that builds the transform lists from the -// transform attributes. The grammar for path data +// SVGTransformListParser: A simple recursive descent parser that builds +// transform lists from 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; @@ -27,36 +24,33 @@ class nsSVGTransform; class SVGTransformListParser : public nsSVGDataParser { public: + SVGTransformListParser(const nsAString& aValue) + : nsSVGDataParser(aValue) {} + + bool Parse(); + const nsTArray& GetTransformList() const { return mTransforms; } private: - nsTArray mTransforms; - // helpers - virtual nsresult Match() MOZ_OVERRIDE; + bool ParseArguments(float *aResult, + uint32_t aMaxCount, + uint32_t *aParsedCount); - nsresult MatchNumberArguments(float *aResult, - uint32_t aMaxNum, - uint32_t *aParsedNum); + bool ParseTransforms(); - nsresult MatchTransformList(); + bool ParseTransform(); - nsresult GetTransformToken(nsIAtom** aKeyatom, bool aAdvancePos); - nsresult MatchTransforms(); + bool ParseTranslate(); + bool ParseScale(); + bool ParseRotate(); + bool ParseSkewX(); + bool ParseSkewY(); + bool ParseMatrix(); - nsresult MatchTransform(); - - bool IsTokenTransformStarter(); - - nsresult MatchTranslate(); - - nsresult MatchScale(); - nsresult MatchRotate(); - nsresult MatchSkewX(); - nsresult MatchSkewY(); - nsresult MatchMatrix(); + FallibleTArray mTransforms; }; } // namespace mozilla diff --git a/content/svg/content/src/nsSVGAngle.cpp b/content/svg/content/src/nsSVGAngle.cpp index 16084dd07b6c..adc9c2f81046 100644 --- a/content/svg/content/src/nsSVGAngle.cpp +++ b/content/svg/content/src/nsSVGAngle.cpp @@ -94,16 +94,20 @@ GetValueString(nsAString &aValueAsString, float aValue, uint16_t aUnitType) } static bool -GetValueFromString(const nsAString& aValueAsString, +GetValueFromString(const nsAString& aString, float& aValue, uint16_t* aUnitType) { - nsAutoString units; + RangedPtr iter = + SVGContentUtils::GetStartRangedPtr(aString); + const RangedPtr end = + SVGContentUtils::GetEndRangedPtr(aString); - if (!SVGContentUtils::ParseNumber(aValueAsString, aValue, units)) { + if (!SVGContentUtils::ParseNumber(iter, end, aValue)) { return false; } + const nsAString& units = Substring(iter.get(), end.get()); *aUnitType = GetUnitTypeForString(units); return IsValidUnitType(*aUnitType); } diff --git a/content/svg/content/src/nsSVGDataParser.cpp b/content/svg/content/src/nsSVGDataParser.cpp index 0c1f6d01cd67..575669abd23c 100644 --- a/content/svg/content/src/nsSVGDataParser.cpp +++ b/content/svg/content/src/nsSVGDataParser.cpp @@ -3,298 +3,37 @@ * 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 "prdtoa.h" -#include "nsMathUtils.h" -#include "nsMemory.h" -#include "nsReadableUtils.h" -#include -#include +#include "SVGContentUtils.h" -//---------------------------------------------------------------------- -// public interface - -nsresult -nsSVGDataParser::Parse(const nsAString &aValue) +nsSVGDataParser::nsSVGDataParser(const nsAString& aValue) + : mIter(SVGContentUtils::GetStartRangedPtr(aValue)), + mEnd(SVGContentUtils::GetEndRangedPtr(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 - -void nsSVGDataParser::GetNextToken() +bool +nsSVGDataParser::SkipCommaWsp() { - 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 (!SkipWsp()) { + // end of string + return false; } - - if (*mInputPos != '\0') { - ++mInputPos; + if (*mIter != ',') { + return true; } + ++mIter; + return SkipWsp(); } -void nsSVGDataParser::RewindTo(const char* aPos) +bool +nsSVGDataParser::SkipWsp() { - 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); -} - - -//---------------------------------------------------------------------- - -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() -{ - 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()); - } - - return NS_OK; -} - -//---------------------------------------------------------------------- - -nsresult nsSVGDataParser::MatchFractConst() -{ - if (mTokenType == POINT) { - GetNextToken(); - ENSURE_MATCHED(MatchDigitSeq()); - } - else { - ENSURE_MATCHED(MatchDigitSeq()); - if (mTokenType == POINT) { - GetNextToken(); - if (IsTokenDigitSeqStarter()) { - ENSURE_MATCHED(MatchDigitSeq()); - } + while (mIter != mEnd) { + if (!IsSVGWhitespace(*mIter)) { + return true; } + ++mIter; } - return NS_OK; + return false; } - -//---------------------------------------------------------------------- - -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() -{ - 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 NS_OK; -} - -nsresult nsSVGDataParser::MatchRightParen() -{ - switch (mTokenType) { - case RIGHT_PAREN: - GetNextToken(); - break; - default: - return NS_ERROR_FAILURE; - } - - return NS_OK; -} - diff --git a/content/svg/content/src/nsSVGDataParser.h b/content/svg/content/src/nsSVGDataParser.h index 497d35b52c15..0dc87ce6b8a3 100644 --- a/content/svg/content/src/nsSVGDataParser.h +++ b/content/svg/content/src/nsSVGDataParser.h @@ -6,57 +6,32 @@ #ifndef __NS_SVGDATAPARSER_H__ #define __NS_SVGDATAPARSER_H__ -#include "nsError.h" +#include "mozilla/RangedPtr.h" #include "nsString.h" -//---------------------------------------------------------------------- -// helper macros -#define ENSURE_MATCHED(exp) { nsresult rv = exp; if (NS_FAILED(rv)) return rv; } - //////////////////////////////////////////////////////////////////////// -// nsSVGDataParser: a simple abstract class for parsing values +// nsSVGDataParser: a simple base class for parsing values // for path and transform values. // class nsSVGDataParser { public: - nsresult Parse(const nsAString &aValue); + nsSVGDataParser(const nsAString& aValue); protected: - const char* mInputPos; - - const char* mTokenPos; - enum { DIGIT, WSP, COMMA, POINT, SIGN, LEFT_PAREN, RIGHT_PAREN, OTHER, END } mTokenType; - char mTokenVal; + static bool IsAlpha(PRUnichar aCh) { + // Exclude non-ascii characters before calling isalpha + return (aCh & 0x7f) == aCh && isalpha(aCh); + } - // 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(); - nsresult MatchLeftParen(); - nsresult MatchRightParen(); + mozilla::RangedPtr mIter; + const mozilla::RangedPtr mEnd; }; diff --git a/content/svg/content/src/nsSVGLength2.cpp b/content/svg/content/src/nsSVGLength2.cpp index f81535006efd..9c69341cffcc 100644 --- a/content/svg/content/src/nsSVGLength2.cpp +++ b/content/svg/content/src/nsSVGLength2.cpp @@ -122,14 +122,19 @@ GetValueString(nsAString &aValueAsString, float aValue, uint16_t aUnitType) } static bool -GetValueFromString(const nsAString& aValueAsString, +GetValueFromString(const nsAString& aString, float& aValue, uint16_t* aUnitType) { - nsAutoString units; - if (!SVGContentUtils::ParseNumber(aValueAsString, aValue, units)) { + RangedPtr iter = + SVGContentUtils::GetStartRangedPtr(aString); + const RangedPtr end = + SVGContentUtils::GetEndRangedPtr(aString); + + if (!SVGContentUtils::ParseNumber(iter, end, aValue)) { return false; } + const nsAString& units = Substring(iter.get(), end.get()); *aUnitType = GetUnitTypeForString(units); return IsValidUnitType(*aUnitType); } diff --git a/content/svg/content/src/nsSVGNumber2.cpp b/content/svg/content/src/nsSVGNumber2.cpp index 347cd90f8ade..908de10d9f44 100644 --- a/content/svg/content/src/nsSVGNumber2.cpp +++ b/content/svg/content/src/nsSVGNumber2.cpp @@ -49,22 +49,28 @@ static nsSVGAttrTearoffTable sSVGAnimatedNumberTearoffTable; static bool -GetValueFromString(const nsAString& aValueAsString, +GetValueFromString(const nsAString& aString, bool aPercentagesAllowed, float& aValue) { - nsAutoString units; + RangedPtr iter = + SVGContentUtils::GetStartRangedPtr(aString); + const RangedPtr end = + SVGContentUtils::GetEndRangedPtr(aString); - if (!SVGContentUtils::ParseNumber(aValueAsString, aValue, units)) { + if (!SVGContentUtils::ParseNumber(iter, end, aValue)) { return false; } - if (aPercentagesAllowed && units.EqualsLiteral("%")) { - aValue /= 100; - return true; + if (aPercentagesAllowed) { + const nsAString& units = Substring(iter.get(), end.get()); + if (units.EqualsLiteral("%")) { + aValue /= 100; + return true; + } } - return units.IsEmpty(); + return iter == end; } nsresult diff --git a/content/svg/content/src/nsSVGPathDataParser.cpp b/content/svg/content/src/nsSVGPathDataParser.cpp index 36a295790b72..dfcb7310f13a 100644 --- a/content/svg/content/src/nsSVGPathDataParser.cpp +++ b/content/svg/content/src/nsSVGPathDataParser.cpp @@ -7,828 +7,392 @@ #include "mozilla/gfx/Point.h" #include "nsSVGDataParser.h" +#include "SVGContentUtils.h" #include "SVGPathData.h" #include "SVGPathSegUtils.h" -#include -#include using namespace mozilla; using namespace mozilla::gfx; -nsresult nsSVGPathDataParser::Match() +static inline PRUnichar ToUpper(PRUnichar aCh) { - return MatchSvgPath(); + return aCh >= 'a' && aCh <= 'z' ? aCh - 'a' + 'A' : aCh; +} + +bool +nsSVGPathDataParser::Parse() +{ + mPathSegList->Clear(); + return ParsePath(); } //---------------------------------------------------------------------- -nsresult nsSVGPathDataParser::MatchCoordPair(float* aX, float* aY) +bool +nsSVGPathDataParser::ParseCoordPair(float& aX, float& aY) { - ENSURE_MATCHED(MatchCoord(aX)); - - if (IsTokenCommaWspStarter()) { - ENSURE_MATCHED(MatchCommaWsp()); - } - - ENSURE_MATCHED(MatchCoord(aY)); - - return NS_OK; + return SVGContentUtils::ParseNumber(mIter, mEnd, aX) && + SkipCommaWsp() && + SVGContentUtils::ParseNumber(mIter, mEnd, aY); } -bool nsSVGPathDataParser::IsTokenCoordPairStarter() +bool +nsSVGPathDataParser::ParseFlag(bool& aFlag) { - return IsTokenCoordStarter(); + if (mIter == mEnd || (*mIter != '0' && *mIter != '1')) { + return false; + } + aFlag = (*mIter == '1'); + + ++mIter; + return true; } //---------------------------------------------------------------------- -nsresult nsSVGPathDataParser::MatchCoord(float* aX) +bool +nsSVGPathDataParser::ParsePath() { - ENSURE_MATCHED(MatchNumber(aX)); - - return NS_OK; -} - -bool nsSVGPathDataParser::IsTokenCoordStarter() -{ - 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; -} - -//---------------------------------------------------------------------- - -nsresult nsSVGPathDataParser::MatchSvgPath() -{ - while (IsTokenWspStarter()) { - ENSURE_MATCHED(MatchWsp()); - } - - if (IsTokenSubPathsStarter()) { - ENSURE_MATCHED(MatchSubPaths()); - } - - while (IsTokenWspStarter()) { - ENSURE_MATCHED(MatchWsp()); - } - - return NS_OK; -} - -//---------------------------------------------------------------------- - -nsresult nsSVGPathDataParser::MatchSubPaths() -{ - 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; - } - } - - return NS_OK; -} - -bool nsSVGPathDataParser::IsTokenSubPathsStarter() -{ - return IsTokenSubPathStarter(); -} - -//---------------------------------------------------------------------- - -nsresult nsSVGPathDataParser::MatchSubPath() -{ - ENSURE_MATCHED(MatchMoveto()); - - while (IsTokenWspStarter()) { - ENSURE_MATCHED(MatchWsp()); - } - - if (IsTokenSubPathElementsStarter()) - ENSURE_MATCHED(MatchSubPathElements()); - - return NS_OK; -} - -bool nsSVGPathDataParser::IsTokenSubPathStarter() -{ - 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; -} - -bool nsSVGPathDataParser::IsTokenSubPathElementsStarter() -{ - return IsTokenSubPathElementStarter(); -} - -//---------------------------------------------------------------------- - -nsresult nsSVGPathDataParser::MatchSubPathElement() -{ - 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 NS_OK; -} - -bool nsSVGPathDataParser::IsTokenSubPathElementStarter() -{ - 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: + while (SkipWsp()) { + if (!ParseSubPath()) { return false; - break; + } + } + + return true; +} + +//---------------------------------------------------------------------- + +bool +nsSVGPathDataParser::ParseSubPath() +{ + return ParseMoveto() && ParseSubPathElements(); +} + +bool +nsSVGPathDataParser::ParseSubPathElements() +{ + 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; + } + } + return true; +} + +bool +nsSVGPathDataParser::ParseSubPathElement(PRUnichar aCommandType, + bool aAbsCoords) +{ + 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); } return false; -} +} + +bool +nsSVGPathDataParser::IsStartOfSubPath() const +{ + return *mIter == 'm' || *mIter == 'M'; +} //---------------------------------------------------------------------- -nsresult nsSVGPathDataParser::MatchMoveto() +bool +nsSVGPathDataParser::ParseMoveto() { - bool absCoords; - - switch (mTokenVal) { - case 'M': - absCoords = true; - break; - case 'm': - absCoords = false; - break; - default: - return NS_ERROR_FAILURE; + if (!IsStartOfSubPath()) { + return false; } - GetNextToken(); + bool absCoords = (*mIter == 'M'); - while (IsTokenWspStarter()) { - ENSURE_MATCHED(MatchWsp()); - } + ++mIter; + SkipWsp(); - ENSURE_MATCHED(MatchMovetoArgSeq(absCoords)); - - return NS_OK; -} - -nsresult nsSVGPathDataParser::MatchMovetoArgSeq(bool absCoords) -{ - 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 (!ParseCoordPair(x, y)) { + return false; } - if (IsTokenLinetoArgSeqStarter()) { - ENSURE_MATCHED(MatchLinetoArgSeq(absCoords)); + if (NS_FAILED(mPathSegList->AppendSeg( + absCoords ? PATHSEG_MOVETO_ABS : PATHSEG_MOVETO_REL, + x, y))) { + return false; } - else { - if (pos != mTokenPos) RewindTo(pos); + + if (!SkipWsp() || IsAlpha(*mIter)) { + // End of data, or start of a new command + return true; } - - return NS_OK; + + // 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); } //---------------------------------------------------------------------- -nsresult nsSVGPathDataParser::MatchClosePath() +bool +nsSVGPathDataParser::ParseClosePath() { - switch (mTokenVal) { - case 'Z': - case 'z': - GetNextToken(); - break; - default: - return NS_ERROR_FAILURE; - } - - return StoreClosePath(); + return NS_SUCCEEDED(mPathSegList->AppendSeg(PATHSEG_CLOSEPATH)); } //---------------------------------------------------------------------- - -nsresult nsSVGPathDataParser::MatchLineto() + +bool +nsSVGPathDataParser::ParseLineto(bool aAbsCoords) { - bool absCoords; - - switch (mTokenVal) { - case 'L': - absCoords = true; - break; - case 'l': - absCoords = false; - break; - default: - return NS_ERROR_FAILURE; - } - - GetNextToken(); - - while (IsTokenWspStarter()) { - ENSURE_MATCHED(MatchWsp()); - } - - ENSURE_MATCHED(MatchLinetoArgSeq(absCoords)); - - return NS_OK; -} - -nsresult nsSVGPathDataParser::MatchLinetoArgSeq(bool absCoords) -{ - while(1) { + while (true) { float x, y; - ENSURE_MATCHED(MatchCoordPair(&x, &y)); - - nsresult rv = StoreLineTo(absCoords, x, y); - NS_ENSURE_SUCCESS(rv, rv); - - const char* pos = mTokenPos; - - if (IsTokenCommaWspStarter()) { - ENSURE_MATCHED(MatchCommaWsp()); + if (!ParseCoordPair(x, y)) { + return false; } - if (!IsTokenCoordPairStarter()) { - if (pos != mTokenPos) RewindTo(pos); - return NS_OK; + if (NS_FAILED(mPathSegList->AppendSeg( + aAbsCoords ? PATHSEG_LINETO_ABS : PATHSEG_LINETO_REL, + x, y))) { + return false; } + + if (!SkipWsp() || IsAlpha(*mIter)) { + // End of data, or start of a new command + return true; + } + SkipCommaWsp(); } - - return NS_OK; -} - -bool nsSVGPathDataParser::IsTokenLinetoArgSeqStarter() -{ - return IsTokenCoordPairStarter(); } //---------------------------------------------------------------------- -nsresult nsSVGPathDataParser::MatchHorizontalLineto() +bool +nsSVGPathDataParser::ParseHorizontalLineto(bool aAbsCoords) { - bool absCoords; - - switch (mTokenVal) { - case 'H': - absCoords = true; - break; - case 'h': - absCoords = false; - break; - default: - return NS_ERROR_FAILURE; - } - - GetNextToken(); - - while (IsTokenWspStarter()) { - ENSURE_MATCHED(MatchWsp()); - } - - ENSURE_MATCHED(MatchHorizontalLinetoArgSeq(absCoords)); - - return NS_OK; -} - -nsresult nsSVGPathDataParser::MatchHorizontalLinetoArgSeq(bool absCoords) -{ - while(1) { + while (true) { 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 (!SVGContentUtils::ParseNumber(mIter, mEnd, x)) { + return false; } - if (!IsTokenCoordStarter()) { - if (pos != mTokenPos) RewindTo(pos); - return NS_OK; + if (NS_FAILED(mPathSegList->AppendSeg( + aAbsCoords ? PATHSEG_LINETO_HORIZONTAL_ABS : PATHSEG_LINETO_HORIZONTAL_REL, + x))) { + return false; } + + if (!SkipWsp() || IsAlpha(*mIter)) { + // End of data, or start of a new command + return true; + } + SkipCommaWsp(); } - - return NS_OK; } //---------------------------------------------------------------------- -nsresult nsSVGPathDataParser::MatchVerticalLineto() +bool +nsSVGPathDataParser::ParseVerticalLineto(bool aAbsCoords) { - 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) { + while (true) { 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 (!SVGContentUtils::ParseNumber(mIter, mEnd, y)) { + return false; } - if (!IsTokenCoordStarter()) { - if (pos != mTokenPos) RewindTo(pos); - return NS_OK; + if (NS_FAILED(mPathSegList->AppendSeg( + aAbsCoords ? PATHSEG_LINETO_VERTICAL_ABS : PATHSEG_LINETO_VERTICAL_REL, + y))) { + return false; } + + if (!SkipWsp() || IsAlpha(*mIter)) { + // End of data, or start of a new command + return true; + } + SkipCommaWsp(); } - - return NS_OK; } //---------------------------------------------------------------------- -nsresult nsSVGPathDataParser::MatchCurveto() +bool +nsSVGPathDataParser::ParseCurveto(bool aAbsCoords) { - bool absCoords; - - switch (mTokenVal) { - case 'C': - absCoords = true; - break; - case 'c': - absCoords = false; - break; - default: - return NS_ERROR_FAILURE; - } + while (true) { + float x1, y1, x2, y2, x, y; - 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 (!(ParseCoordPair(x1, y1) && + SkipCommaWsp() && + ParseCoordPair(x2, y2) && + SkipCommaWsp() && + ParseCoordPair(x, y))) { + return false; } - if (!IsTokenCurvetoArgStarter()) { - if (pos != mTokenPos) RewindTo(pos); - return NS_OK; + if (NS_FAILED(mPathSegList->AppendSeg( + aAbsCoords ? PATHSEG_CURVETO_CUBIC_ABS : PATHSEG_CURVETO_CUBIC_REL, + x1, y1, x2, y2, x, y))) { + return false; } + + if (!SkipWsp() || IsAlpha(*mIter)) { + // End of data, or start of a new command + return true; + } + SkipCommaWsp(); } - - return NS_OK; -} - -nsresult -nsSVGPathDataParser::MatchCurvetoArg(float* x, float* y, float* x1, - float* y1, float* x2, float* y2) -{ - ENSURE_MATCHED(MatchCoordPair(x1, y1)); - - 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(); } //---------------------------------------------------------------------- -nsresult nsSVGPathDataParser::MatchSmoothCurveto() +bool +nsSVGPathDataParser::ParseSmoothCurveto(bool aAbsCoords) { - bool absCoords; - - switch (mTokenVal) { - case 'S': - absCoords = true; - break; - case 's': - absCoords = false; - break; - default: - return NS_ERROR_FAILURE; - } - - GetNextToken(); - - 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()); + while (true) { + float x2, y2, x, y; + if (!(ParseCoordPair(x2, y2) && + SkipCommaWsp() && + ParseCoordPair(x, y))) { + return false; } - if (!IsTokenSmoothCurvetoArgStarter()) { - if (pos != mTokenPos) RewindTo(pos); - return NS_OK; + if (NS_FAILED(mPathSegList->AppendSeg( + aAbsCoords ? PATHSEG_CURVETO_CUBIC_SMOOTH_ABS : PATHSEG_CURVETO_CUBIC_SMOOTH_REL, + x2, y2, x, y))) { + return false; } + + if (!SkipWsp() || IsAlpha(*mIter)) { + // End of data, or start of a new command + return true; + } + SkipCommaWsp(); } - - return NS_OK; -} - -nsresult nsSVGPathDataParser::MatchSmoothCurvetoArg(float* x, float* y, float* x2, float* y2) -{ - ENSURE_MATCHED(MatchCoordPair(x2, y2)); - - if (IsTokenCommaWspStarter()) { - ENSURE_MATCHED(MatchCommaWsp()); - } - - ENSURE_MATCHED(MatchCoordPair(x, y)); - - return NS_OK; -} - -bool nsSVGPathDataParser::IsTokenSmoothCurvetoArgStarter() -{ - return IsTokenCoordPairStarter(); } //---------------------------------------------------------------------- -nsresult nsSVGPathDataParser::MatchQuadBezierCurveto() +bool +nsSVGPathDataParser::ParseQuadBezierCurveto(bool aAbsCoords) { - bool absCoords; - - switch (mTokenVal) { - case 'Q': - absCoords = true; - break; - case 'q': - absCoords = false; - break; - default: - return NS_ERROR_FAILURE; - } - - GetNextToken(); - - while (IsTokenWspStarter()) { - ENSURE_MATCHED(MatchWsp()); - } - - ENSURE_MATCHED(MatchQuadBezierCurvetoArgSeq(absCoords)); - - return NS_OK; -} - -nsresult nsSVGPathDataParser::MatchQuadBezierCurvetoArgSeq(bool absCoords) -{ - 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()); + while (true) { + float x1, y1, x, y; + if (!(ParseCoordPair(x1, y1) && + SkipCommaWsp() && + ParseCoordPair(x, y))) { + return false; } - if (!IsTokenQuadBezierCurvetoArgStarter()) { - if (pos != mTokenPos) RewindTo(pos); - return NS_OK; + if (NS_FAILED(mPathSegList->AppendSeg( + aAbsCoords ? PATHSEG_CURVETO_QUADRATIC_ABS : PATHSEG_CURVETO_QUADRATIC_REL, + x1, y1, x, y))) { + return false; } + + if (!SkipWsp() || IsAlpha(*mIter)) { + // Start of a new command + return true; + } + SkipCommaWsp(); } - - return NS_OK; -} - -nsresult nsSVGPathDataParser::MatchQuadBezierCurvetoArg(float* x, float* y, float* x1, float* y1) -{ - ENSURE_MATCHED(MatchCoordPair(x1, y1)); - - if (IsTokenCommaWspStarter()) { - ENSURE_MATCHED(MatchCommaWsp()); - } - - ENSURE_MATCHED(MatchCoordPair(x, y)); - - return NS_OK; -} - -bool nsSVGPathDataParser::IsTokenQuadBezierCurvetoArgStarter() -{ - return IsTokenCoordPairStarter(); } //---------------------------------------------------------------------- -nsresult nsSVGPathDataParser::MatchSmoothQuadBezierCurveto() +bool +nsSVGPathDataParser::ParseSmoothQuadBezierCurveto(bool aAbsCoords) { - 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) { + while (true) { float x, y; - 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 (!ParseCoordPair(x, y)) { + return false; } - if (!IsTokenCoordPairStarter()) { - if (pos != mTokenPos) RewindTo(pos); - return NS_OK; + if (NS_FAILED(mPathSegList->AppendSeg( + aAbsCoords ? PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS : PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL, + x, y))) { + return false; } + + if (!SkipWsp() || IsAlpha(*mIter)) { + // End of data, or start of a new command + return true; + } + SkipCommaWsp(); } - - return NS_OK; } //---------------------------------------------------------------------- -nsresult nsSVGPathDataParser::MatchEllipticalArc() +bool +nsSVGPathDataParser::ParseEllipticalArc(bool aAbsCoords) { - 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()); - } - - ENSURE_MATCHED(MatchEllipticalArcArgSeq(absCoords)); - - return NS_OK; -} - - -nsresult nsSVGPathDataParser::MatchEllipticalArcArgSeq(bool absCoords) -{ - while(1) { - float x, y, r1, r2, angle; + while (true) { + float r1, r2, angle, x, y; 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()); + 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; } - if (!IsTokenEllipticalArcArgStarter()) { - if (pos != mTokenPos) RewindTo(pos); - return NS_OK; + // 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 (!SkipWsp() || IsAlpha(*mIter)) { + // End of data, or start of a new command + return true; + } + SkipCommaWsp(); } - - return NS_OK; } -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(); -} - - //----------------------------------------------------------------------- @@ -947,97 +511,3 @@ nsSVGArcConverter::GetNextSegment(Point* cp1, Point* cp2, Point* to) 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); -} - diff --git a/content/svg/content/src/nsSVGPathDataParser.h b/content/svg/content/src/nsSVGPathDataParser.h index f06d35a39cd3..f295964e0fc8 100644 --- a/content/svg/content/src/nsSVGPathDataParser.h +++ b/content/svg/content/src/nsSVGPathDataParser.h @@ -22,91 +22,43 @@ class SVGPathData; class nsSVGPathDataParser : public nsSVGDataParser { -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(); +public: + nsSVGPathDataParser(const nsAString& aValue, + mozilla::SVGPathData* aList) + : nsSVGDataParser(aValue), + mPathSegList(aList) + { + MOZ_ASSERT(aList, "null path data"); + } - nsresult MatchCoord(float* aX); - bool IsTokenCoordStarter(); + bool Parse(); - 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(); + + bool ParseSubPathElements(); + bool ParseSubPathElement(PRUnichar aCommandType, + bool aAbsCoords); - 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(); - - 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(); - - }; + 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; +}; class nsSVGArcConverter { @@ -128,34 +80,4 @@ protected: 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__