Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 75 additions & 10 deletions core/src/processing/core/PShapeSVG.java
Original file line number Diff line number Diff line change
Expand Up @@ -961,14 +961,36 @@ else if (lexState == LexState.EXP_HEAD) {
float rx = PApplet.parseFloat(pathTokens[i + 1]);
float ry = PApplet.parseFloat(pathTokens[i + 2]);
float angle = PApplet.parseFloat(pathTokens[i + 3]);
boolean fa = PApplet.parseFloat(pathTokens[i + 4]) != 0;
boolean fs = PApplet.parseFloat(pathTokens[i + 5]) != 0;
float endX = PApplet.parseFloat(pathTokens[i + 6]);
float endY = PApplet.parseFloat(pathTokens[i + 7]);
// In compact arc notation, flags and coordinates may be concatenated.
// e.g. "013" is parsed as large-arc=0, sweep=1, x=3
String token4 = pathTokens[i + 4];
boolean fa;
boolean fs;
float endX;
float endY;
int tokenOffset = 0;
if (isCompactArcNotation(token4)) {
fa = token4.charAt(0) == '1';
fs = token4.charAt(1) == '1';
if (token4.length() > 2) {
endX = PApplet.parseFloat(token4.substring(2));
endY = PApplet.parseFloat(pathTokens[i + 5]);
tokenOffset = -2;
} else {
endX = PApplet.parseFloat(pathTokens[i + 5]);
endY = PApplet.parseFloat(pathTokens[i + 6]);
tokenOffset = -1;
}
} else {
fa = PApplet.parseFloat(token4) != 0;
fs = PApplet.parseFloat(pathTokens[i + 5]) != 0;
endX = PApplet.parseFloat(pathTokens[i + 6]);
endY = PApplet.parseFloat(pathTokens[i + 7]);
}
parsePathArcto(cx, cy, rx, ry, angle, fa, fs, endX, endY);
cx = endX;
cy = endY;
i += 8;
i += 8 + tokenOffset;
prevCurve = true;
}
break;
Expand All @@ -978,14 +1000,34 @@ else if (lexState == LexState.EXP_HEAD) {
float rx = PApplet.parseFloat(pathTokens[i + 1]);
float ry = PApplet.parseFloat(pathTokens[i + 2]);
float angle = PApplet.parseFloat(pathTokens[i + 3]);
boolean fa = PApplet.parseFloat(pathTokens[i + 4]) != 0;
boolean fs = PApplet.parseFloat(pathTokens[i + 5]) != 0;
float endX = cx + PApplet.parseFloat(pathTokens[i + 6]);
float endY = cy + PApplet.parseFloat(pathTokens[i + 7]);
String token4 = pathTokens[i + 4];
boolean fa;
boolean fs;
float endX;
float endY;
int tokenOffset = 0;
if (isCompactArcNotation(token4)) {
fa = token4.charAt(0) == '1';
fs = token4.charAt(1) == '1';
if (token4.length() > 2) {
endX = cx + PApplet.parseFloat(token4.substring(2));
endY = cy + PApplet.parseFloat(pathTokens[i + 5]);
tokenOffset = -2;
} else {
endX = cx + PApplet.parseFloat(pathTokens[i + 5]);
endY = cy + PApplet.parseFloat(pathTokens[i + 6]);
tokenOffset = -1;
}
} else {
fa = PApplet.parseFloat(token4) != 0;
fs = PApplet.parseFloat(pathTokens[i + 5]) != 0;
endX = cx + PApplet.parseFloat(pathTokens[i + 6]);
endY = cy + PApplet.parseFloat(pathTokens[i + 7]);
}
parsePathArcto(cx, cy, rx, ry, angle, fa, fs, endX, endY);
cx = endX;
cy = endY;
i += 8;
i += 8 + tokenOffset;
prevCurve = true;
}
break;
Expand Down Expand Up @@ -1054,6 +1096,29 @@ private void parsePathMoveto(float px, float py) {
}


/**
* Checks if a token represents compact arc notation where flags and coordinates
* are concatenated (e.g., "013" for large-arc=0, sweep=1, x=3).
*
* @param token the token to check
* @return true if the token is in compact arc notation format
*/
private boolean isCompactArcNotation(String token) {
if (token == null) {
return false;
}
return token.length() > 1 &&
(token.charAt(0) == '0' || token.charAt(0) == '1') &&
(token.charAt(1) == '0' || token.charAt(1) == '1') &&
(token.length() == 2 ||
(token.length() > 2 && (
Character.isDigit(token.charAt(2)) ||
token.charAt(2) == '+' ||
token.charAt(2) == '-' ||
token.charAt(2) == '.')));
}


private void parsePathLineto(float px, float py) {
parsePathCode(VERTEX);
parsePathVertex(px, py);
Expand Down
79 changes: 79 additions & 0 deletions core/test/processing/core/PShapeSVGPathTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package processing.core;

import org.junit.Assert;
import org.junit.Test;
import processing.data.XML;

public class PShapeSVGPathTest {

@Test
public void testCompactPathNotation() {
// Test the failing SVG from issue #1244
String svgContent = "<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.0\" viewBox=\"0 0 29 29\">" +
"<path d=\"m0 6 3-2 15 4 7-7a2 2 0 013 3l-7 7 4 15-2 3-7-13-5 5v4l-2 2-2-5-5-2 2-2h4l5-5z\"/>" +
"</svg>";

try {
XML xml = XML.parse(svgContent);
PShapeSVG shape = new PShapeSVG(xml);
Assert.assertNotNull(shape);
} catch (Exception e) {
Assert.fail("Encountered exception " + e);
}
}

@Test
public void testWorkingPathNotation() {
// Test the working SVG (with explicit decimal points)
String svgContent = "<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.0\" viewBox=\"0 0 29 29\">" +
"<path d=\"m 0,5.9994379 2.9997,-1.9998 14.9985,3.9996 6.9993,-6.99930004 a 2.1211082,2.1211082 0 0 1 2.9997,2.99970004 l -6.9993,6.9993001 3.9996,14.9985 -1.9998,2.9997 -6.9993,-12.9987 -4.9995,4.9995 v 3.9996 l -1.9998,1.9998 -1.9998,-4.9995 -4.9995,-1.9998 1.9998,-1.9998 h 3.9996 l 4.9995,-4.9995 z\"/>" +
"</svg>";

try {
XML xml = XML.parse(svgContent);
PShapeSVG shape = new PShapeSVG(xml);
Assert.assertNotNull(shape);
} catch (Exception e) {
Assert.fail("Encountered exception " + e);
}
}

@Test
public void testCompactArcNotationVariations() {
// Test various compact arc notations
String[] testCases = {
// Flags only concatenated (e.g., "01")
"<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 100 100\"><path d=\"M10 10 A30 30 0 0110 50\"/></svg>",
// Flags and coordinate concatenated (e.g., "013")
"<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 100 100\"><path d=\"M10 10 A30 30 0 013 50\"/></svg>",
// Standard notation (should still work)
"<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 100 100\"><path d=\"M10 10 A30 30 0 0 1 10 50\"/></svg>"
};

try {
for (String svgContent : testCases) {
XML xml = XML.parse(svgContent);
PShapeSVG shape = new PShapeSVG(xml);
Assert.assertNotNull(shape);
}
} catch (Exception e) {
Assert.fail("Encountered exception " + e);
}
}

@Test
public void testCompactArcWithNegativeCoordinates() {
// Test compact arc notation with negative coordinates
String svgContent = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 100 100\">" +
"<path d=\"M50 50 a20 20 0 01-10 20\"/>" +
"</svg>";

try {
XML xml = XML.parse(svgContent);
PShapeSVG shape = new PShapeSVG(xml);
Assert.assertNotNull(shape);
} catch (Exception e) {
Assert.fail("Encountered exception " + e);
}
}
}