in modules/fxgutils/src/java/com/adobe/internal/fxg/swf/ShapeHelper.java [614:822]
public static List<ShapeRecord> path(PathNode node, boolean fill)
{
String data = node.data;
List<ShapeRecord> shapeRecords = new ArrayList<ShapeRecord>();
if (data.length() == 0)
return shapeRecords;
String temp = data;
// Split letter followed by number (i.e. "M3" becomes "M 3")
Matcher m = charNumberPattern.matcher(data);
if (m.find())
{
temp = m.replaceAll("$1 $2");
}
// Split number followed by letter (i.e. "3M" becomes "3 M")
m = numberCharPattern.matcher(temp);
temp = m.replaceAll("$1 $2");
// Split letter followed by letter (i.e. "zM" becomes "z M")
m = charCharPattern.matcher(temp);
temp = m.replaceAll("$1 $2");
//support scientific notation for floats/doubles
m = scientificPattern.matcher(temp);
temp = m.replaceAll("$1$3$5");
// Replace commas with spaces
m = commaPattern.matcher(temp);
temp = m.replaceAll(" ");
// Trim leading and trailing spaces
temp = temp.trim();
// Finally, split the string into an array
String[] args = spacePattern.split(temp);
char ic = 0;
char prevIc = 0;
double lastMoveX = 0.0;
double lastMoveY = 0.0;
double prevX = 0.0;
double prevY = 0.0;
double x = 0.0;
double y = 0.0;
double controlX = 0.0;
double controlY = 0.0;
double control2X = 0.0;
double control2Y = 0.0;
boolean firstMove = true;
for (int i = 0; i < args.length; )
{
boolean relative = false;
char c = args[i].toCharArray()[0];
if (c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z')
{
ic = c;
i++;
}
if ((firstMove) && (ic != 'm') && (ic != 'M'))
throw new FXGException(node.getStartLine(), node.getStartColumn(), "InvalidPathData");
switch (ic)
{
case 'm':
relative = true;
case 'M':
if (firstMove) {
x = Double.parseDouble(args[i++]);
y = Double.parseDouble(args[i++]);
shapeRecords.add(move(x, y));
firstMove = false;
}
else
{
//add an implicit closepath, if needed
if (fill && (Math.abs(prevX-lastMoveX) > AbstractFXGNode.EPSILON || Math.abs(prevY-lastMoveY) > AbstractFXGNode.EPSILON))
{
if (node.stroke == null)
shapeRecords.addAll(straightEdge(prevX, prevY, lastMoveX, lastMoveY));
else
shapeRecords.addAll(implicitClosepath(prevX, prevY, lastMoveX, lastMoveY));
}
x = Double.parseDouble(args[i++]) + (relative ? prevX : 0);
y = Double.parseDouble(args[i++]) + (relative ? prevY : 0);
shapeRecords.add(move(x, y));
}
lastMoveX = x;
lastMoveY = y;
ic = (relative) ? 'l' : 'L';
break;
case 'l':
relative = true;
case 'L':
x = Double.parseDouble(args[i++]) + (relative ? prevX : 0);
y = Double.parseDouble(args[i++]) + (relative ? prevY : 0);
shapeRecords.addAll(straightEdge(prevX, prevY, x, y));
break;
case 'h':
relative = true;
case 'H':
x = Double.parseDouble(args[i++]) + (relative ? prevX : 0);
y = prevY;
shapeRecords.addAll(straightEdge(prevX, prevY, x, y));
break;
case 'v':
relative = true;
case 'V':
x = prevX;
y = Double.parseDouble(args[i++]) + (relative ? prevY : 0);
shapeRecords.addAll(straightEdge(prevX, prevY, x, y));
break;
case 'q':
relative = true;
case 'Q':
controlX = Double.parseDouble(args[i++]) + (relative ? prevX : 0);
controlY = Double.parseDouble(args[i++]) + (relative ? prevY : 0);
x = Double.parseDouble(args[i++]) + (relative ? prevX : 0);
y = Double.parseDouble(args[i++]) + (relative ? prevY : 0);
shapeRecords.add(curvedEdge(prevX, prevY, controlX, controlY, x, y));
break;
case 't':
relative = true;
case 'T':
// control is a reflection of the previous control point
if ((prevIc == 'T') || (prevIc == 't') || (prevIc == 'q') || (prevIc == 'Q'))
{
controlX = prevX + (prevX - controlX);
controlY = prevY + (prevY - controlY);
}
else
{
controlX = prevX;
controlY = prevY;
}
x = Double.parseDouble(args[i++]) + (relative ? prevX : 0);
y = Double.parseDouble(args[i++]) + (relative ? prevY : 0);
shapeRecords.add(curvedEdge(prevX, prevY, controlX, controlY, x, y));
break;
case 'c':
relative = true;
case 'C':
controlX = Double.parseDouble(args[i++]) + (relative ? prevX : 0);
controlY = Double.parseDouble(args[i++]) + (relative ? prevY : 0);
control2X = Double.parseDouble(args[i++]) + (relative ? prevX : 0);
control2Y = Double.parseDouble(args[i++]) + (relative ? prevY : 0);
x = Double.parseDouble(args[i++]) + (relative ? prevX : 0);
y = Double.parseDouble(args[i++]) + (relative ? prevY : 0);
shapeRecords.addAll(cubicToQuadratic(prevX, prevY, controlX, controlY, control2X, control2Y, x, y));
break;
case 's':
relative = true;
case 'S':
// Control1 is a reflection of the previous control2 point
if ((prevIc == 'S') || (prevIc == 's') || (prevIc == 'c') || (prevIc == 'C'))
{
controlX = prevX + (prevX - control2X);
controlY = prevY + (prevY - control2Y);
}
else
{
controlX = prevX;
controlY = prevY;
}
control2X = Double.parseDouble(args[i++]) + (relative ? prevX : 0);
control2Y = Double.parseDouble(args[i++]) + (relative ? prevY : 0);
x = Double.parseDouble(args[i++]) + (relative ? prevX : 0);
y = Double.parseDouble(args[i++]) + (relative ? prevY : 0);
shapeRecords.addAll(cubicToQuadratic(prevX, prevY, controlX, controlY, control2X, control2Y, x, y));
break;
case 'z':
case 'Z':
shapeRecords.addAll(straightEdge(prevX, prevY, lastMoveX, lastMoveY));
x = lastMoveX;
y = lastMoveY;
break;
default:
throw new FXGException(node.getStartLine(), node.getStartColumn(), "InvalidPathData");
}
prevX = x;
prevY = y;
prevIc = ic;
}
//do an implicit closepath, if needed
if (fill && (Math.abs(prevX-lastMoveX) > AbstractFXGNode.EPSILON) || (Math.abs(prevY-lastMoveY) > AbstractFXGNode.EPSILON))
{
if (node.stroke == null)
shapeRecords.addAll(straightEdge(prevX, prevY, lastMoveX, lastMoveY));
else
shapeRecords.addAll(implicitClosepath(prevX, prevY, lastMoveX, lastMoveY));
}
return shapeRecords;
}