From 014b91b5311ed28ff68e6d35ea338191cdb6947d Mon Sep 17 00:00:00 2001 From: gloriousjob Date: Mon, 7 Sep 2020 12:18:46 -0400 Subject: [PATCH] fix(fabric.utils): ISSUE-6566 Fix SVGs for special Arc lines (#6571) --- .gitignore | 1 + HEADER.js | 1 + src/parser.js | 2 +- src/util/path.js | 28 ++++++++++++++++++++++------ test/fixtures/f_blue.svg | 4 ++++ test/unit/path_utils.js | 8 ++++++++ 6 files changed, 37 insertions(+), 7 deletions(-) create mode 100644 test/fixtures/f_blue.svg diff --git a/.gitignore b/.gitignore index d705ddb4f97..8f5ff108b23 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ .DS_Store *.iml /.nyc_output/ +/.vscode/ /node_modules/ /npm-debug.log before_commit diff --git a/HEADER.js b/HEADER.js index 14adebd735f..819b8fb8be5 100644 --- a/HEADER.js +++ b/HEADER.js @@ -73,6 +73,7 @@ fabric.SHARED_ATTRIBUTES = [ */ fabric.DPI = 96; fabric.reNum = '(?:[-+]?(?:\\d+|\\d*\\.\\d+)(?:[eE][-+]?\\d+)?)'; +fabric.commaWsp = '(?:\\s+,?\\s*|,\\s*)' fabric.rePathCommand = /([-+]?((\d+\.\d+)|((\d+)|(\.\d+)))(?:[eE][-+]?\d+)?)/ig; fabric.reNonWord = /[ \n\.,;!\?\-]/; fabric.fontPaths = { }; diff --git a/src/parser.js b/src/parser.js index a8ded9cedda..ee0cbf29ab9 100644 --- a/src/parser.js +++ b/src/parser.js @@ -246,7 +246,7 @@ // == begin transform regexp number = fabric.reNum, - commaWsp = '(?:\\s+,?\\s*|,\\s*)', + commaWsp = fabric.commaWsp, skewX = '(?:(skewX)\\s*\\(\\s*(' + number + ')\\s*\\))', diff --git a/src/util/path.js b/src/util/path.js index f46cf489da5..21f8fed2948 100644 --- a/src/util/path.js +++ b/src/util/path.js @@ -590,6 +590,12 @@ currentPath, parsed, re = fabric.rePathCommand, + rNumber = '[-+]?(?:\\d*\\.\\d+|\\d+\\.?)(?:[eE][-+]?\\d+)?\\s*', + rNumberCommaWsp = '(' + rNumber + ')' + fabric.commaWsp, + rFlagCommaWsp = '([01])' + fabric.commaWsp + '?', + rArcSeq = rNumberCommaWsp + '?' + rNumberCommaWsp + '?' + rNumberCommaWsp + rFlagCommaWsp + rFlagCommaWsp + + rNumberCommaWsp + '?(' + rNumber + ')', + regArcArgumentSequence = new RegExp(rArcSeq, 'g'), match, coordsStr, // one of commands (m,M,l,L,q,Q,c,C,etc.) followed by non-command characters (i.e. command values) @@ -605,11 +611,22 @@ coordsStr = currentPath.slice(1).trim(); coords.length = 0; - while ((match = re.exec(coordsStr))) { - coords.push(match[0]); - } + var command = currentPath.charAt(0); + coordsParsed = [command]; - coordsParsed = [currentPath.charAt(0)]; + if (command.toLowerCase() === 'a') { + // arcs have special flags that apparently don't require spaces so handle special + for (var args; (args = regArcArgumentSequence.exec(coordsStr));) { + for (var j = 1; j < args.length; j++) { + coords.push(args[j]); + } + } + } + else { + while ((match = re.exec(coordsStr))) { + coords.push(match[0]); + } + } for (var j = 0, jlen = coords.length; j < jlen; j++) { parsed = parseFloat(coords[j]); @@ -618,8 +635,7 @@ } } - var command = coordsParsed[0], - commandLength = commandLengths[command.toLowerCase()], + var commandLength = commandLengths[command.toLowerCase()], repeatedCommand = repeatedCommands[command] || command; if (coordsParsed.length - 1 > commandLength) { diff --git a/test/fixtures/f_blue.svg b/test/fixtures/f_blue.svg new file mode 100644 index 00000000000..8c868a068f5 --- /dev/null +++ b/test/fixtures/f_blue.svg @@ -0,0 +1,4 @@ + + + + diff --git a/test/unit/path_utils.js b/test/unit/path_utils.js index a58cb751edb..c058dbe04d2 100644 --- a/test/unit/path_utils.js +++ b/test/unit/path_utils.js @@ -22,6 +22,14 @@ assert.deepEqual(command, expectedSimplified[index], 'should contain a subset of equivalent commands ' + index); }); }); + QUnit.test('fabric.util.parsePath can parse arcs correctly when no spaces between flags', function(assert) { + // eslint-disable-next-line max-len + var pathWithWeirdArc = 'a10.56 10.56 0 00-1.484-.133'; + var expected = ['a', 10.56, 10.56, 0, 0, 0, -1.484, -0.133]; + var parsed = fabric.util.parsePath(pathWithWeirdArc); + var command = parsed[0]; + assert.deepEqual(command, expected, 'Arc should be parsed correctly.'); + }); QUnit.test('fabric.util.getPathSegmentsInfo', function(assert) { assert.ok(typeof fabric.util.getPathSegmentsInfo === 'function'); var parsed = fabric.util.makePathSimpler(fabric.util.parsePath(path));