summaryrefslogtreecommitdiff
path: root/filter/source/svg/presentation_engine.js
diff options
context:
space:
mode:
authorfxwan <wanliyou@gmail.com>2017-05-15 18:41:08 +0800
committerThorsten Behrens <Thorsten.Behrens@CIB.de>2017-09-03 01:46:52 +0200
commit9d4fc496d498f2f5c7fedba94f656ef3189b85dd (patch)
tree1cadf7461cbb683cf51fa1c5e364395e8031cda8 /filter/source/svg/presentation_engine.js
parentba0a94a914260c38abd8dc5af1104ba14734b8ef (diff)
svg.js: lift Source & Builder Class outta _parsePath func for less GC
Change-Id: Id45021a7a7aa4c60d59afa86363d0bd54a7948ff Reviewed-on: https://gerrit.libreoffice.org/37638 Reviewed-by: Thorsten Behrens <Thorsten.Behrens@CIB.de> Tested-by: Thorsten Behrens <Thorsten.Behrens@CIB.de>
Diffstat (limited to 'filter/source/svg/presentation_engine.js')
-rw-r--r--filter/source/svg/presentation_engine.js556
1 files changed, 278 insertions, 278 deletions
diff --git a/filter/source/svg/presentation_engine.js b/filter/source/svg/presentation_engine.js
index f7912c351349..f6db576a898b 100644
--- a/filter/source/svg/presentation_engine.js
+++ b/filter/source/svg/presentation_engine.js
@@ -1317,326 +1317,326 @@ function configureDetectionTools()
return string;
};
- // This closely follows SVGPathParser::parsePath from Source/core/svg/SVGPathParser.cpp.
- SVGPathSegList.prototype._parsePath = function(string) {
- if (!string || string.length == 0)
- return [];
+ var Source = function(string) {
+ this._string = string;
+ this._currentIndex = 0;
+ this._endIndex = this._string.length;
+ this._previousCommand = SVGPathSeg.PATHSEG_UNKNOWN;
- var owningPathSegList = this;
-
- var Builder = function() {
- this.pathSegList = [];
- };
+ this._skipOptionalSpaces();
+ };
- Builder.prototype.appendSegment = function(pathSeg) {
- this.pathSegList.push(pathSeg);
- };
+ Source.prototype._isCurrentSpace = function() {
+ var character = this._string[this._currentIndex];
+ return character <= ' ' && (character == ' ' || character == '\n' || character == '\t' || character == '\r' || character == '\f');
+ };
- var Source = function(string) {
- this._string = string;
- this._currentIndex = 0;
- this._endIndex = this._string.length;
- this._previousCommand = SVGPathSeg.PATHSEG_UNKNOWN;
+ Source.prototype._skipOptionalSpaces = function() {
+ while (this._currentIndex < this._endIndex && this._isCurrentSpace())
+ this._currentIndex++;
+ return this._currentIndex < this._endIndex;
+ };
- this._skipOptionalSpaces();
- };
+ Source.prototype._skipOptionalSpacesOrDelimiter = function() {
+ if (this._currentIndex < this._endIndex && !this._isCurrentSpace() && this._string.charAt(this._currentIndex) != ',')
+ return false;
+ if (this._skipOptionalSpaces()) {
+ if (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) == ',') {
+ this._currentIndex++;
+ this._skipOptionalSpaces();
+ }
+ }
+ return this._currentIndex < this._endIndex;
+ };
- Source.prototype._isCurrentSpace = function() {
- var character = this._string[this._currentIndex];
- return character <= ' ' && (character == ' ' || character == '\n' || character == '\t' || character == '\r' || character == '\f');
- };
+ Source.prototype.hasMoreData = function() {
+ return this._currentIndex < this._endIndex;
+ };
- Source.prototype._skipOptionalSpaces = function() {
- while (this._currentIndex < this._endIndex && this._isCurrentSpace())
- this._currentIndex++;
- return this._currentIndex < this._endIndex;
- };
+ Source.prototype.peekSegmentType = function() {
+ var lookahead = this._string[this._currentIndex];
+ return this._pathSegTypeFromChar(lookahead);
+ };
- Source.prototype._skipOptionalSpacesOrDelimiter = function() {
- if (this._currentIndex < this._endIndex && !this._isCurrentSpace() && this._string.charAt(this._currentIndex) != ',')
- return false;
- if (this._skipOptionalSpaces()) {
- if (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) == ',') {
- this._currentIndex++;
- this._skipOptionalSpaces();
- }
- }
- return this._currentIndex < this._endIndex;
- };
+ Source.prototype._pathSegTypeFromChar = function(lookahead) {
+ switch (lookahead) {
+ case 'Z':
+ case 'z':
+ return SVGPathSeg.PATHSEG_CLOSEPATH;
+ case 'M':
+ return SVGPathSeg.PATHSEG_MOVETO_ABS;
+ case 'm':
+ return SVGPathSeg.PATHSEG_MOVETO_REL;
+ case 'L':
+ return SVGPathSeg.PATHSEG_LINETO_ABS;
+ case 'l':
+ return SVGPathSeg.PATHSEG_LINETO_REL;
+ case 'C':
+ return SVGPathSeg.PATHSEG_CURVETO_CUBIC_ABS;
+ case 'c':
+ return SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL;
+ case 'Q':
+ return SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS;
+ case 'q':
+ return SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL;
+ case 'A':
+ return SVGPathSeg.PATHSEG_ARC_ABS;
+ case 'a':
+ return SVGPathSeg.PATHSEG_ARC_REL;
+ case 'H':
+ return SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS;
+ case 'h':
+ return SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL;
+ case 'V':
+ return SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS;
+ case 'v':
+ return SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL;
+ case 'S':
+ return SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS;
+ case 's':
+ return SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL;
+ case 'T':
+ return SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS;
+ case 't':
+ return SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL;
+ default:
+ return SVGPathSeg.PATHSEG_UNKNOWN;
+ }
+ };
- Source.prototype.hasMoreData = function() {
- return this._currentIndex < this._endIndex;
- };
+ Source.prototype._nextCommandHelper = function(lookahead, previousCommand) {
+ // Check for remaining coordinates in the current command.
+ if ((lookahead == '+' || lookahead == '-' || lookahead == '.' || (lookahead >= '0' && lookahead <= '9')) && previousCommand != SVGPathSeg.PATHSEG_CLOSEPATH) {
+ if (previousCommand == SVGPathSeg.PATHSEG_MOVETO_ABS)
+ return SVGPathSeg.PATHSEG_LINETO_ABS;
+ if (previousCommand == SVGPathSeg.PATHSEG_MOVETO_REL)
+ return SVGPathSeg.PATHSEG_LINETO_REL;
+ return previousCommand;
+ }
+ return SVGPathSeg.PATHSEG_UNKNOWN;
+ };
- Source.prototype.peekSegmentType = function() {
- var lookahead = this._string[this._currentIndex];
- return this._pathSegTypeFromChar(lookahead);
- };
+ Source.prototype.initialCommandIsMoveTo = function() {
+ // If the path is empty it is still valid, so return true.
+ if (!this.hasMoreData())
+ return true;
+ var command = this.peekSegmentType();
+ // Path must start with moveTo.
+ return command == SVGPathSeg.PATHSEG_MOVETO_ABS || command == SVGPathSeg.PATHSEG_MOVETO_REL;
+ };
- Source.prototype._pathSegTypeFromChar = function(lookahead) {
- switch (lookahead) {
- case 'Z':
- case 'z':
- return SVGPathSeg.PATHSEG_CLOSEPATH;
- case 'M':
- return SVGPathSeg.PATHSEG_MOVETO_ABS;
- case 'm':
- return SVGPathSeg.PATHSEG_MOVETO_REL;
- case 'L':
- return SVGPathSeg.PATHSEG_LINETO_ABS;
- case 'l':
- return SVGPathSeg.PATHSEG_LINETO_REL;
- case 'C':
- return SVGPathSeg.PATHSEG_CURVETO_CUBIC_ABS;
- case 'c':
- return SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL;
- case 'Q':
- return SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS;
- case 'q':
- return SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL;
- case 'A':
- return SVGPathSeg.PATHSEG_ARC_ABS;
- case 'a':
- return SVGPathSeg.PATHSEG_ARC_REL;
- case 'H':
- return SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS;
- case 'h':
- return SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL;
- case 'V':
- return SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS;
- case 'v':
- return SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL;
- case 'S':
- return SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS;
- case 's':
- return SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL;
- case 'T':
- return SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS;
- case 't':
- return SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL;
- default:
- return SVGPathSeg.PATHSEG_UNKNOWN;
- }
- };
+ // Parse a number from an SVG path. This very closely follows genericParseNumber(...) from Source/core/svg/SVGParserUtilities.cpp.
+ // Spec: http://www.w3.org/TR/SVG11/single-page.html#paths-PathDataBNF
+ Source.prototype._parseNumber = function() {
+ var exponent = 0;
+ var integer = 0;
+ var frac = 1;
+ var decimal = 0;
+ var sign = 1;
+ var expsign = 1;
+
+ var startIndex = this._currentIndex;
+
+ this._skipOptionalSpaces();
+
+ // Read the sign.
+ if (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) == '+')
+ this._currentIndex++;
+ else if (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) == '-') {
+ this._currentIndex++;
+ sign = -1;
+ }
- Source.prototype._nextCommandHelper = function(lookahead, previousCommand) {
- // Check for remaining coordinates in the current command.
- if ((lookahead == '+' || lookahead == '-' || lookahead == '.' || (lookahead >= '0' && lookahead <= '9')) && previousCommand != SVGPathSeg.PATHSEG_CLOSEPATH) {
- if (previousCommand == SVGPathSeg.PATHSEG_MOVETO_ABS)
- return SVGPathSeg.PATHSEG_LINETO_ABS;
- if (previousCommand == SVGPathSeg.PATHSEG_MOVETO_REL)
- return SVGPathSeg.PATHSEG_LINETO_REL;
- return previousCommand;
+ if (this._currentIndex == this._endIndex || ((this._string.charAt(this._currentIndex) < '0' || this._string.charAt(this._currentIndex) > '9') && this._string.charAt(this._currentIndex) != '.'))
+ // The first character of a number must be one of [0-9+-.].
+ return undefined;
+
+ // Read the integer part, build right-to-left.
+ var startIntPartIndex = this._currentIndex;
+ while (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) >= '0' && this._string.charAt(this._currentIndex) <= '9')
+ this._currentIndex++; // Advance to first non-digit.
+
+ if (this._currentIndex != startIntPartIndex) {
+ var scanIntPartIndex = this._currentIndex - 1;
+ var multiplier = 1;
+ while (scanIntPartIndex >= startIntPartIndex) {
+ integer += multiplier * (this._string.charAt(scanIntPartIndex--) - '0');
+ multiplier *= 10;
}
- return SVGPathSeg.PATHSEG_UNKNOWN;
- };
-
- Source.prototype.initialCommandIsMoveTo = function() {
- // If the path is empty it is still valid, so return true.
- if (!this.hasMoreData())
- return true;
- var command = this.peekSegmentType();
- // Path must start with moveTo.
- return command == SVGPathSeg.PATHSEG_MOVETO_ABS || command == SVGPathSeg.PATHSEG_MOVETO_REL;
- };
+ }
- // Parse a number from an SVG path. This very closely follows genericParseNumber(...) from Source/core/svg/SVGParserUtilities.cpp.
- // Spec: http://www.w3.org/TR/SVG11/single-page.html#paths-PathDataBNF
- Source.prototype._parseNumber = function() {
- var exponent = 0;
- var integer = 0;
- var frac = 1;
- var decimal = 0;
- var sign = 1;
- var expsign = 1;
+ // Read the decimals.
+ if (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) == '.') {
+ this._currentIndex++;
- var startIndex = this._currentIndex;
+ // There must be a least one digit following the .
+ if (this._currentIndex >= this._endIndex || this._string.charAt(this._currentIndex) < '0' || this._string.charAt(this._currentIndex) > '9')
+ return undefined;
+ while (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) >= '0' && this._string.charAt(this._currentIndex) <= '9') {
+ frac *= 10;
+ decimal += (this._string.charAt(this._currentIndex) - '0') / frac;
+ this._currentIndex += 1;
+ }
+ }
- this._skipOptionalSpaces();
+ // Read the exponent part.
+ if (this._currentIndex != startIndex && this._currentIndex + 1 < this._endIndex && (this._string.charAt(this._currentIndex) == 'e' || this._string.charAt(this._currentIndex) == 'E') && (this._string.charAt(this._currentIndex + 1) != 'x' && this._string.charAt(this._currentIndex + 1) != 'm')) {
+ this._currentIndex++;
- // Read the sign.
- if (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) == '+')
+ // Read the sign of the exponent.
+ if (this._string.charAt(this._currentIndex) == '+') {
this._currentIndex++;
- else if (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) == '-') {
+ } else if (this._string.charAt(this._currentIndex) == '-') {
this._currentIndex++;
- sign = -1;
+ expsign = -1;
}
- if (this._currentIndex == this._endIndex || ((this._string.charAt(this._currentIndex) < '0' || this._string.charAt(this._currentIndex) > '9') && this._string.charAt(this._currentIndex) != '.'))
- // The first character of a number must be one of [0-9+-.].
+ // There must be an exponent.
+ if (this._currentIndex >= this._endIndex || this._string.charAt(this._currentIndex) < '0' || this._string.charAt(this._currentIndex) > '9')
return undefined;
- // Read the integer part, build right-to-left.
- var startIntPartIndex = this._currentIndex;
- while (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) >= '0' && this._string.charAt(this._currentIndex) <= '9')
- this._currentIndex++; // Advance to first non-digit.
-
- if (this._currentIndex != startIntPartIndex) {
- var scanIntPartIndex = this._currentIndex - 1;
- var multiplier = 1;
- while (scanIntPartIndex >= startIntPartIndex) {
- integer += multiplier * (this._string.charAt(scanIntPartIndex--) - '0');
- multiplier *= 10;
- }
- }
-
- // Read the decimals.
- if (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) == '.') {
+ while (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) >= '0' && this._string.charAt(this._currentIndex) <= '9') {
+ exponent *= 10;
+ exponent += (this._string.charAt(this._currentIndex) - '0');
this._currentIndex++;
-
- // There must be a least one digit following the .
- if (this._currentIndex >= this._endIndex || this._string.charAt(this._currentIndex) < '0' || this._string.charAt(this._currentIndex) > '9')
- return undefined;
- while (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) >= '0' && this._string.charAt(this._currentIndex) <= '9') {
- frac *= 10;
- decimal += (this._string.charAt(this._currentIndex) - '0') / frac;
- this._currentIndex += 1;
- }
}
+ }
- // Read the exponent part.
- if (this._currentIndex != startIndex && this._currentIndex + 1 < this._endIndex && (this._string.charAt(this._currentIndex) == 'e' || this._string.charAt(this._currentIndex) == 'E') && (this._string.charAt(this._currentIndex + 1) != 'x' && this._string.charAt(this._currentIndex + 1) != 'm')) {
- this._currentIndex++;
+ var number = integer + decimal;
+ number *= sign;
- // Read the sign of the exponent.
- if (this._string.charAt(this._currentIndex) == '+') {
- this._currentIndex++;
- } else if (this._string.charAt(this._currentIndex) == '-') {
- this._currentIndex++;
- expsign = -1;
- }
+ if (exponent)
+ number *= Math.pow(10, expsign * exponent);
- // There must be an exponent.
- if (this._currentIndex >= this._endIndex || this._string.charAt(this._currentIndex) < '0' || this._string.charAt(this._currentIndex) > '9')
- return undefined;
+ if (startIndex == this._currentIndex)
+ return undefined;
- while (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) >= '0' && this._string.charAt(this._currentIndex) <= '9') {
- exponent *= 10;
- exponent += (this._string.charAt(this._currentIndex) - '0');
- this._currentIndex++;
- }
- }
+ this._skipOptionalSpacesOrDelimiter();
- var number = integer + decimal;
- number *= sign;
+ return number;
+ };
- if (exponent)
- number *= Math.pow(10, expsign * exponent);
+ Source.prototype._parseArcFlag = function() {
+ if (this._currentIndex >= this._endIndex)
+ return undefined;
+ var flag = false;
+ var flagChar = this._string.charAt(this._currentIndex++);
+ if (flagChar == '0')
+ flag = false;
+ else if (flagChar == '1')
+ flag = true;
+ else
+ return undefined;
- if (startIndex == this._currentIndex)
- return undefined;
+ this._skipOptionalSpacesOrDelimiter();
+ return flag;
+ };
- this._skipOptionalSpacesOrDelimiter();
+ Source.prototype.parseSegment = function() {
+ var lookahead = this._string[this._currentIndex];
+ var command = this._pathSegTypeFromChar(lookahead);
+ if (command == SVGPathSeg.PATHSEG_UNKNOWN) {
+ // Possibly an implicit command. Not allowed if this is the first command.
+ if (this._previousCommand == SVGPathSeg.PATHSEG_UNKNOWN)
+ return null;
+ command = this._nextCommandHelper(lookahead, this._previousCommand);
+ if (command == SVGPathSeg.PATHSEG_UNKNOWN)
+ return null;
+ } else {
+ this._currentIndex++;
+ }
- return number;
- };
+ this._previousCommand = command;
+
+ switch (command) {
+ case SVGPathSeg.PATHSEG_MOVETO_REL:
+ return new SVGPathSegMovetoRel(owningPathSegList, this._parseNumber(), this._parseNumber());
+ case SVGPathSeg.PATHSEG_MOVETO_ABS:
+ return new SVGPathSegMovetoAbs(owningPathSegList, this._parseNumber(), this._parseNumber());
+ case SVGPathSeg.PATHSEG_LINETO_REL:
+ return new SVGPathSegLinetoRel(owningPathSegList, this._parseNumber(), this._parseNumber());
+ case SVGPathSeg.PATHSEG_LINETO_ABS:
+ return new SVGPathSegLinetoAbs(owningPathSegList, this._parseNumber(), this._parseNumber());
+ case SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL:
+ return new SVGPathSegLinetoHorizontalRel(owningPathSegList, this._parseNumber());
+ case SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS:
+ return new SVGPathSegLinetoHorizontalAbs(owningPathSegList, this._parseNumber());
+ case SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL:
+ return new SVGPathSegLinetoVerticalRel(owningPathSegList, this._parseNumber());
+ case SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS:
+ return new SVGPathSegLinetoVerticalAbs(owningPathSegList, this._parseNumber());
+ case SVGPathSeg.PATHSEG_CLOSEPATH:
+ this._skipOptionalSpaces();
+ return new SVGPathSegClosePath(owningPathSegList);
+ case SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL:
+ {
+ const points = {x1: this._parseNumber(), y1: this._parseNumber(), x2: this._parseNumber(), y2: this._parseNumber(), x: this._parseNumber(), y: this._parseNumber()};
+ return new SVGPathSegCurvetoCubicRel(owningPathSegList, points.x, points.y, points.x1, points.y1, points.x2, points.y2);
+ }
+ case SVGPathSeg.PATHSEG_CURVETO_CUBIC_ABS:
+ {
+ const points = {x1: this._parseNumber(), y1: this._parseNumber(), x2: this._parseNumber(), y2: this._parseNumber(), x: this._parseNumber(), y: this._parseNumber()};
+ return new SVGPathSegCurvetoCubicAbs(owningPathSegList, points.x, points.y, points.x1, points.y1, points.x2, points.y2);
+ }
+ case SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL:
+ {
+ const points = {x2: this._parseNumber(), y2: this._parseNumber(), x: this._parseNumber(), y: this._parseNumber()};
+ return new SVGPathSegCurvetoCubicSmoothRel(owningPathSegList, points.x, points.y, points.x2, points.y2);
+ }
+ case SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS:
+ {
+ const points = {x2: this._parseNumber(), y2: this._parseNumber(), x: this._parseNumber(), y: this._parseNumber()};
+ return new SVGPathSegCurvetoCubicSmoothAbs(owningPathSegList, points.x, points.y, points.x2, points.y2);
+ }
+ case SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL:
+ {
+ const points = {x1: this._parseNumber(), y1: this._parseNumber(), x: this._parseNumber(), y: this._parseNumber()};
+ return new SVGPathSegCurvetoQuadraticRel(owningPathSegList, points.x, points.y, points.x1, points.y1);
+ }
+ case SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS:
+ {
+ const points = {x1: this._parseNumber(), y1: this._parseNumber(), x: this._parseNumber(), y: this._parseNumber()};
+ return new SVGPathSegCurvetoQuadraticAbs(owningPathSegList, points.x, points.y, points.x1, points.y1);
+ }
+ case SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL:
+ return new SVGPathSegCurvetoQuadraticSmoothRel(owningPathSegList, this._parseNumber(), this._parseNumber());
+ case SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS:
+ return new SVGPathSegCurvetoQuadraticSmoothAbs(owningPathSegList, this._parseNumber(), this._parseNumber());
+ case SVGPathSeg.PATHSEG_ARC_REL:
+ {
+ const points = {x1: this._parseNumber(), y1: this._parseNumber(), arcAngle: this._parseNumber(), arcLarge: this._parseArcFlag(), arcSweep: this._parseArcFlag(), x: this._parseNumber(), y: this._parseNumber()};
+ return new SVGPathSegArcRel(owningPathSegList, points.x, points.y, points.x1, points.y1, points.arcAngle, points.arcLarge, points.arcSweep);
+ }
+ case SVGPathSeg.PATHSEG_ARC_ABS:
+ {
+ const points = {x1: this._parseNumber(), y1: this._parseNumber(), arcAngle: this._parseNumber(), arcLarge: this._parseArcFlag(), arcSweep: this._parseArcFlag(), x: this._parseNumber(), y: this._parseNumber()};
+ return new SVGPathSegArcAbs(owningPathSegList, points.x, points.y, points.x1, points.y1, points.arcAngle, points.arcLarge, points.arcSweep);
+ }
+ default:
+ throw 'Unknown path seg type.'
+ }
+ };
- Source.prototype._parseArcFlag = function() {
- if (this._currentIndex >= this._endIndex)
- return undefined;
- var flag = false;
- var flagChar = this._string.charAt(this._currentIndex++);
- if (flagChar == '0')
- flag = false;
- else if (flagChar == '1')
- flag = true;
- else
- return undefined;
+ var Builder = function() {
+ this.pathSegList = [];
+ };
- this._skipOptionalSpacesOrDelimiter();
- return flag;
- };
+ Builder.prototype.appendSegment = function(pathSeg) {
+ this.pathSegList.push(pathSeg);
+ };
- Source.prototype.parseSegment = function() {
- var lookahead = this._string[this._currentIndex];
- var command = this._pathSegTypeFromChar(lookahead);
- if (command == SVGPathSeg.PATHSEG_UNKNOWN) {
- // Possibly an implicit command. Not allowed if this is the first command.
- if (this._previousCommand == SVGPathSeg.PATHSEG_UNKNOWN)
- return null;
- command = this._nextCommandHelper(lookahead, this._previousCommand);
- if (command == SVGPathSeg.PATHSEG_UNKNOWN)
- return null;
- } else {
- this._currentIndex++;
- }
+ // This closely follows SVGPathParser::parsePath from Source/core/svg/SVGPathParser.cpp.
+ SVGPathSegList.prototype._parsePath = function(string) {
+ if (!string || string.length == 0)
+ return [];
- this._previousCommand = command;
-
- switch (command) {
- case SVGPathSeg.PATHSEG_MOVETO_REL:
- return new SVGPathSegMovetoRel(owningPathSegList, this._parseNumber(), this._parseNumber());
- case SVGPathSeg.PATHSEG_MOVETO_ABS:
- return new SVGPathSegMovetoAbs(owningPathSegList, this._parseNumber(), this._parseNumber());
- case SVGPathSeg.PATHSEG_LINETO_REL:
- return new SVGPathSegLinetoRel(owningPathSegList, this._parseNumber(), this._parseNumber());
- case SVGPathSeg.PATHSEG_LINETO_ABS:
- return new SVGPathSegLinetoAbs(owningPathSegList, this._parseNumber(), this._parseNumber());
- case SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL:
- return new SVGPathSegLinetoHorizontalRel(owningPathSegList, this._parseNumber());
- case SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS:
- return new SVGPathSegLinetoHorizontalAbs(owningPathSegList, this._parseNumber());
- case SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL:
- return new SVGPathSegLinetoVerticalRel(owningPathSegList, this._parseNumber());
- case SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS:
- return new SVGPathSegLinetoVerticalAbs(owningPathSegList, this._parseNumber());
- case SVGPathSeg.PATHSEG_CLOSEPATH:
- this._skipOptionalSpaces();
- return new SVGPathSegClosePath(owningPathSegList);
- case SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL:
- {
- const points = {x1: this._parseNumber(), y1: this._parseNumber(), x2: this._parseNumber(), y2: this._parseNumber(), x: this._parseNumber(), y: this._parseNumber()};
- return new SVGPathSegCurvetoCubicRel(owningPathSegList, points.x, points.y, points.x1, points.y1, points.x2, points.y2);
- }
- case SVGPathSeg.PATHSEG_CURVETO_CUBIC_ABS:
- {
- const points = {x1: this._parseNumber(), y1: this._parseNumber(), x2: this._parseNumber(), y2: this._parseNumber(), x: this._parseNumber(), y: this._parseNumber()};
- return new SVGPathSegCurvetoCubicAbs(owningPathSegList, points.x, points.y, points.x1, points.y1, points.x2, points.y2);
- }
- case SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL:
- {
- const points = {x2: this._parseNumber(), y2: this._parseNumber(), x: this._parseNumber(), y: this._parseNumber()};
- return new SVGPathSegCurvetoCubicSmoothRel(owningPathSegList, points.x, points.y, points.x2, points.y2);
- }
- case SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS:
- {
- const points = {x2: this._parseNumber(), y2: this._parseNumber(), x: this._parseNumber(), y: this._parseNumber()};
- return new SVGPathSegCurvetoCubicSmoothAbs(owningPathSegList, points.x, points.y, points.x2, points.y2);
- }
- case SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL:
- {
- const points = {x1: this._parseNumber(), y1: this._parseNumber(), x: this._parseNumber(), y: this._parseNumber()};
- return new SVGPathSegCurvetoQuadraticRel(owningPathSegList, points.x, points.y, points.x1, points.y1);
- }
- case SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS:
- {
- const points = {x1: this._parseNumber(), y1: this._parseNumber(), x: this._parseNumber(), y: this._parseNumber()};
- return new SVGPathSegCurvetoQuadraticAbs(owningPathSegList, points.x, points.y, points.x1, points.y1);
- }
- case SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL:
- return new SVGPathSegCurvetoQuadraticSmoothRel(owningPathSegList, this._parseNumber(), this._parseNumber());
- case SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS:
- return new SVGPathSegCurvetoQuadraticSmoothAbs(owningPathSegList, this._parseNumber(), this._parseNumber());
- case SVGPathSeg.PATHSEG_ARC_REL:
- {
- const points = {x1: this._parseNumber(), y1: this._parseNumber(), arcAngle: this._parseNumber(), arcLarge: this._parseArcFlag(), arcSweep: this._parseArcFlag(), x: this._parseNumber(), y: this._parseNumber()};
- return new SVGPathSegArcRel(owningPathSegList, points.x, points.y, points.x1, points.y1, points.arcAngle, points.arcLarge, points.arcSweep);
- }
- case SVGPathSeg.PATHSEG_ARC_ABS:
- {
- const points = {x1: this._parseNumber(), y1: this._parseNumber(), arcAngle: this._parseNumber(), arcLarge: this._parseArcFlag(), arcSweep: this._parseArcFlag(), x: this._parseNumber(), y: this._parseNumber()};
- return new SVGPathSegArcAbs(owningPathSegList, points.x, points.y, points.x1, points.y1, points.arcAngle, points.arcLarge, points.arcSweep);
- }
- default:
- throw 'Unknown path seg type.'
- }
- };
+ var owningPathSegList = this;
- var builder = new Builder();
var source = new Source(string);
if (!source.initialCommandIsMoveTo())
return [];
+ var builder = new Builder();
while (source.hasMoreData()) {
var pathSeg = source.parseSegment();
if (!pathSeg)