| <!DOCTYPE html> |
| <html> |
| <head> |
| <script src="../../resources/testharness.js"></script> |
| <script src="../../resources/testharnessreport.js"></script> |
| </head> |
| <body> |
| <svg id="testcontainer"><path id="path"></path></svg> |
| <script> |
| var pathElement = document.getElementById("path"); |
| |
| var pathProperties = { |
| "M": [ "x", "y" ], |
| "m": [ "x", "y" ], |
| "L": [ "x", "y" ], |
| "l": [ "x", "y" ], |
| "H": [ "x" ], |
| "h": [ "x" ], |
| "V": [ "y" ], |
| "v": [ "y" ], |
| "Z": [ ], |
| "z": [ ], |
| "C": [ "x1", "y1", "x2", "y2", "x", "y" ], |
| "c": [ "x1", "y1", "x2", "y2", "x", "y" ], |
| "S": [ "x2", "y2", "x", "y" ], |
| "s": [ "x2", "y2", "x", "y" ], |
| "Q": [ "x1", "y1", "x", "y" ], |
| "q": [ "x1", "y1", "x", "y" ], |
| "T": [ "x", "y" ], |
| "t": [ "x", "y" ], |
| "A": [ "r1", "r2", "angle", "largeArcFlag", "sweepFlag", "x", "y" ], |
| "a": [ "r1", "r2", "angle", "largeArcFlag", "sweepFlag", "x", "y" ] |
| }; |
| |
| function printSegment(segment) |
| { |
| var letter = segment.pathSegTypeAsLetter; |
| var names = pathProperties[letter]; |
| if (!names) |
| return letter + "?"; |
| var string = letter; |
| for (var i = 0; i < names.length; ++i) { |
| if (i) |
| string += ","; |
| var value = segment[names[i]]; |
| if (value == undefined) { |
| string += "?"; |
| continue; |
| } |
| if (typeof(value) === "boolean") { |
| string += value ? 1 : 0; |
| continue; |
| } |
| string += value.toFixed(1).replace(/\.0$/, ""); |
| } |
| return string; |
| } |
| |
| function parsePath(string) |
| { |
| pathElement.setAttributeNS(null, "d", string); |
| |
| var pathSegList = pathElement.pathSegList; |
| var numberOfItems = pathSegList.numberOfItems; |
| |
| var pathCommands = ""; |
| for (var i = 0; i < numberOfItems; i++) { |
| if (i) |
| pathCommands += " "; |
| pathCommands += printSegment(pathSegList.getItem(i)); |
| } |
| |
| return pathCommands; |
| } |
| |
| // Basic commands. |
| test(function() { assert_equals(parsePath("M1,2"), "M1,2"); }, "M command"); |
| test(function() { assert_equals(parsePath("m1,2"), "m1,2"); }, "m command"); |
| test(function() { assert_equals(parsePath("M100,200 m3,4"), "M100,200 m3,4"); }, "M followed by m"); |
| test(function() { assert_equals(parsePath("M100,200 L3,4"), "M100,200 L3,4"); }, "L command"); |
| test(function() { assert_equals(parsePath("M100,200 l3,4"), "M100,200 l3,4"); }, "l command"); |
| test(function() { assert_equals(parsePath("M100,200 H3"), "M100,200 H3"); }, "H command"); |
| test(function() { assert_equals(parsePath("M100,200 h3"), "M100,200 h3"); }, "h command"); |
| test(function() { assert_equals(parsePath("M100,200 V3"), "M100,200 V3"); }, "V command"); |
| test(function() { assert_equals(parsePath("M100,200 v3"), "M100,200 v3"); }, "v command"); |
| test(function() { assert_equals(parsePath("M100,200 Z"), "M100,200 Z"); }, "Z command"); |
| test(function() { assert_equals(parsePath("M100,200 z"), "M100,200 Z"); }, "z command"); |
| test(function() { assert_equals(parsePath("M100,200 C3,4,5,6,7,8"), "M100,200 C3,4,5,6,7,8"); }, "C command"); |
| test(function() { assert_equals(parsePath("M100,200 c3,4,5,6,7,8"), "M100,200 c3,4,5,6,7,8"); }, "c command"); |
| test(function() { assert_equals(parsePath("M100,200 S3,4,5,6"), "M100,200 S3,4,5,6"); }, "S command"); |
| test(function() { assert_equals(parsePath("M100,200 s3,4,5,6"), "M100,200 s3,4,5,6"); }, "s command"); |
| test(function() { assert_equals(parsePath("M100,200 Q3,4,5,6"), "M100,200 Q3,4,5,6"); }, "Q command"); |
| test(function() { assert_equals(parsePath("M100,200 q3,4,5,6"), "M100,200 q3,4,5,6"); }, "q command"); |
| test(function() { assert_equals(parsePath("M100,200 T3,4"), "M100,200 T3,4"); }, "T command"); |
| test(function() { assert_equals(parsePath("M100,200 t3,4"), "M100,200 t3,4"); }, "t command"); |
| |
| // Arc commands. |
| test(function() { assert_equals(parsePath("M100,200 A3,4,5,0,0,6,7"), "M100,200 A3,4,5,0,0,6,7"); }, "A command flags 0,0"); |
| test(function() { assert_equals(parsePath("M100,200 A3,4,5,1,0,6,7"), "M100,200 A3,4,5,1,0,6,7"); }, "A command flags 1,0"); |
| test(function() { assert_equals(parsePath("M100,200 A3,4,5,0,1,6,7"), "M100,200 A3,4,5,0,1,6,7"); }, "A command flags 0,1"); |
| test(function() { assert_equals(parsePath("M100,200 A3,4,5,1,1,6,7"), "M100,200 A3,4,5,1,1,6,7"); }, "A command flags 1,1"); |
| test(function() { assert_equals(parsePath("M100,200 a3,4,5,0,0,6,7"), "M100,200 a3,4,5,0,0,6,7"); }, "a command flags 0,0"); |
| test(function() { assert_equals(parsePath("M100,200 a3,4,5,0,1,6,7"), "M100,200 a3,4,5,0,1,6,7"); }, "a command flags 0,1"); |
| test(function() { assert_equals(parsePath("M100,200 a3,4,5,1,0,6,7"), "M100,200 a3,4,5,1,0,6,7"); }, "a command flags 1,0"); |
| test(function() { assert_equals(parsePath("M100,200 a3,4,5,1,1,6,7"), "M100,200 a3,4,5,1,1,6,7"); }, "a command flags 1,1"); |
| test(function() { assert_equals(parsePath("M100,200 a3,4,5,006,7"), "M100,200 a3,4,5,0,0,6,7"); }, "arc flag compression 00"); |
| test(function() { assert_equals(parsePath("M100,200 a3,4,5,016,7"), "M100,200 a3,4,5,0,1,6,7"); }, "arc flag compression 01"); |
| test(function() { assert_equals(parsePath("M100,200 a3,4,5,106,7"), "M100,200 a3,4,5,1,0,6,7"); }, "arc flag compression 10"); |
| test(function() { assert_equals(parsePath("M100,200 a3,4,5,116,7"), "M100,200 a3,4,5,1,1,6,7"); }, "arc flag compression 11"); |
| test(function() { assert_equals(parsePath("M100,200 a3,4,5,2,1,6,7"), "M100,200"); }, "malformed: invalid large-arc-flag 2"); |
| test(function() { assert_equals(parsePath("M100,200 a3,4,5,1,2,6,7"), "M100,200"); }, "malformed: invalid sweep-flag 2"); |
| test(function() { assert_equals(parsePath("M100,200 a0,4,5,0,0,10,0 a4,0,5,0,0,0,10 a0,0,5,0,0,-10,0 z"), "M100,200 l10,0 l0,10 l-10,0 Z"); }, "zero radius arcs become lineto"); |
| |
| // Implicit lineto after moveto. |
| test(function() { assert_equals(parsePath("M1,2,3,4"), "M1,2 L3,4"); }, "implicit L after M"); |
| test(function() { assert_equals(parsePath("m100,200,3,4"), "m100,200 l3,4"); }, "implicit l after m"); |
| |
| // Number parsing. |
| test(function() { assert_equals(parsePath("M 100-200"), "M100,-200"); }, "negative number without separator"); |
| test(function() { assert_equals(parsePath("M 0.6.5"), "M0.6,0.5"); }, "dot starts new number"); |
| |
| // Leading whitespace. |
| test(function() { assert_equals(parsePath(" M1,2"), "M1,2"); }, "leading space"); |
| test(function() { assert_equals(parsePath(" M1,2"), "M1,2"); }, "leading double space"); |
| test(function() { assert_equals(parsePath("\tM1,2"), "M1,2"); }, "leading tab"); |
| test(function() { assert_equals(parsePath("\nM1,2"), "M1,2"); }, "leading newline"); |
| test(function() { assert_equals(parsePath("\rM1,2"), "M1,2"); }, "leading carriage return"); |
| test(function() { assert_equals(parsePath("\vM1,2"), ""); }, "malformed: leading vertical tab"); |
| test(function() { assert_equals(parsePath("xM1,2"), ""); }, "malformed: leading x"); |
| |
| // Trailing whitespace and junk. |
| test(function() { assert_equals(parsePath("M1,2 "), "M1,2"); }, "trailing space"); |
| test(function() { assert_equals(parsePath("M1,2\t"), "M1,2"); }, "trailing tab"); |
| test(function() { assert_equals(parsePath("M1,2\n"), "M1,2"); }, "trailing newline"); |
| test(function() { assert_equals(parsePath("M1,2\r"), "M1,2"); }, "trailing carriage return"); |
| test(function() { assert_equals(parsePath("M1,2\v"), "M1,2"); }, "trailing vertical tab"); |
| test(function() { assert_equals(parsePath("M1,2x"), "M1,2"); }, "malformed: trailing x"); |
| test(function() { assert_equals(parsePath("M1,2 L40,0#90"), "M1,2 L40,0"); }, "malformed: hash in number"); |
| |
| // Empty and invalid. |
| test(function() { assert_equals(parsePath(""), ""); }, "empty string"); |
| test(function() { assert_equals(parsePath(" "), ""); }, "only space"); |
| test(function() { assert_equals(parsePath("x"), ""); }, "malformed: only x"); |
| test(function() { assert_equals(parsePath("L1,2"), ""); }, "malformed: missing initial moveto"); |
| test(function() { assert_equals(parsePath("M.1 .2 L.3 .4 .5 .6"), "M0.1,0.2 L0.3,0.4 L0.5,0.6"); }, "leading dot numbers with implicit L"); |
| |
| // Scientific notation. |
| test(function() { assert_equals(parsePath("M1e2,10e1"), "M100,100"); }, "scientific notation basic"); |
| test(function() { assert_equals(parsePath("M100e0,100"), "M100,100"); }, "scientific notation e0"); |
| test(function() { assert_equals(parsePath("M1e+2,1000e-1"), "M100,100"); }, "scientific notation with signs"); |
| test(function() { assert_equals(parsePath("M1e2.5"), "M100,0.5"); }, "dot ends exponent"); |
| test(function() { assert_equals(parsePath("M0.00000001e10 100"), "M100,100"); }, "scientific notation small base"); |
| test(function() { assert_equals(parsePath("M1e-46,50 h1e38"), "M0,50 h9.999999680285692e+37"); }, "scientific notation large valid exponent"); |
| test(function() { assert_equals(parsePath("M0,50 h1e-123456789123456789123"), "M0,50 h0"); }, "negative exponent overflow to zero"); |
| test(function() { assert_equals(parsePath("M0,50 h1e-1234567891234567891238"), "M0,50 h0"); }, "negative exponent overflow to zero (variant)"); |
| test(function() { assert_equals(parsePath("M0,50 h1e39"), "M0,50"); }, "malformed: positive exponent overflow"); |
| test(function() { assert_equals(parsePath("M0,50 h1e123456789123456789123"), "M0,50"); }, "malformed: large positive exponent overflow"); |
| test(function() { assert_equals(parsePath("M0,50 h1e-.5"), "M0,50"); }, "malformed: fractional negative exponent"); |
| test(function() { assert_equals(parsePath("M0,50 h1e+.5"), "M0,50"); }, "malformed: fractional positive exponent"); |
| |
| // Incomplete commands. |
| test(function() { assert_equals(parsePath("M"), ""); }, "malformed: M with no coordinates"); |
| |
| // Trailing content after close. |
| test(function() { assert_equals(parsePath("M1,1Z0"), "M1,1 Z"); }, "malformed: trailing digit after Z"); |
| test(function() { assert_equals(parsePath("M1,1z0"), "M1,1 Z"); }, "malformed: trailing digit after z"); |
| |
| // Repeated h/H/v/V commands. |
| test(function() { assert_equals(parsePath("M1,1h2,3"), "M1,1 h2 h3"); }, "repeated h"); |
| test(function() { assert_equals(parsePath("M1,1H2,3"), "M1,1 H2 H3"); }, "repeated H"); |
| test(function() { assert_equals(parsePath("M1,1v2,3"), "M1,1 v2 v3"); }, "repeated v"); |
| test(function() { assert_equals(parsePath("M1,1V2,3"), "M1,1 V2 V3"); }, "repeated V"); |
| |
| // Repeated cubic bezier commands. |
| test(function() { assert_equals(parsePath("M1,1c2,3 4,5 6,7 8"), "M1,1 c2,3,4,5,6,7"); }, "malformed: incomplete repeated c"); |
| test(function() { assert_equals(parsePath("M1,1c2,3 4,5 6,7 8,9 10,11 12,13"), "M1,1 c2,3,4,5,6,7 c8,9,10,11,12,13"); }, "repeated c"); |
| test(function() { assert_equals(parsePath("M1,1C2,3 4,5 6,7 8"), "M1,1 C2,3,4,5,6,7"); }, "malformed: incomplete repeated C"); |
| test(function() { assert_equals(parsePath("M1,1C2,3 4,5 6,7 8,9 10,11 12,13"), "M1,1 C2,3,4,5,6,7 C8,9,10,11,12,13"); }, "repeated C"); |
| |
| // Repeated smooth cubic bezier commands. |
| test(function() { assert_equals(parsePath("M1,1s2,3 4,5 6"), "M1,1 s2,3,4,5"); }, "malformed: incomplete repeated s"); |
| test(function() { assert_equals(parsePath("M1,1s2,3 4,5 6,7 8,9"), "M1,1 s2,3,4,5 s6,7,8,9"); }, "repeated s"); |
| test(function() { assert_equals(parsePath("M1,1S2,3 4,5 6"), "M1,1 S2,3,4,5"); }, "malformed: incomplete repeated S"); |
| test(function() { assert_equals(parsePath("M1,1S2,3 4,5 6,7 8,9"), "M1,1 S2,3,4,5 S6,7,8,9"); }, "repeated S"); |
| |
| // Repeated quadratic bezier commands. |
| test(function() { assert_equals(parsePath("M1,1q2,3 4,5 6"), "M1,1 q2,3,4,5"); }, "malformed: incomplete repeated q"); |
| test(function() { assert_equals(parsePath("M1,1q2,3 4,5 6,7 8,9"), "M1,1 q2,3,4,5 q6,7,8,9"); }, "repeated q"); |
| test(function() { assert_equals(parsePath("M1,1Q2,3 4,5 6"), "M1,1 Q2,3,4,5"); }, "malformed: incomplete repeated Q"); |
| test(function() { assert_equals(parsePath("M1,1Q2,3 4,5 6,7 8,9"), "M1,1 Q2,3,4,5 Q6,7,8,9"); }, "repeated Q"); |
| |
| // Repeated smooth quadratic bezier commands. |
| test(function() { assert_equals(parsePath("M1,1t2,3 4"), "M1,1 t2,3"); }, "malformed: incomplete repeated t"); |
| test(function() { assert_equals(parsePath("M1,1t2,3 4,5"), "M1,1 t2,3 t4,5"); }, "repeated t"); |
| test(function() { assert_equals(parsePath("M1,1T2,3 4"), "M1,1 T2,3"); }, "malformed: incomplete repeated T"); |
| test(function() { assert_equals(parsePath("M1,1T2,3 4,5"), "M1,1 T2,3 T4,5"); }, "repeated T"); |
| |
| // Repeated arc commands. |
| test(function() { assert_equals(parsePath("M1,1a2,3,4,0,0,5,6 7"), "M1,1 a2,3,4,0,0,5,6"); }, "malformed: incomplete repeated a"); |
| test(function() { assert_equals(parsePath("M1,1a2,3,4,0,0,5,6 7,8,9,0,0,10,11"), "M1,1 a2,3,4,0,0,5,6 a7,8,9,0,0,10,11"); }, "repeated a"); |
| test(function() { assert_equals(parsePath("M1,1A2,3,4,0,0,5,6 7"), "M1,1 A2,3,4,0,0,5,6"); }, "malformed: incomplete repeated A"); |
| test(function() { assert_equals(parsePath("M1,1A2,3,4,0,0,5,6 7,8,9,0,0,10,11"), "M1,1 A2,3,4,0,0,5,6 A7,8,9,0,0,10,11"); }, "repeated A"); |
| </script> |
| </body> |
| </html> |