in compiler/src/main/java/org/apache/royale/compiler/internal/fxg/swf/ShapeHelper.java [609:814]
public static List<ShapeRecord> path(PathNode node, boolean fill, Collection<ICompilerProblem> problems)
{
String data = node.data;
List<ShapeRecord> shapeRecords = new ArrayList<ShapeRecord>();
if (data.length() == 0)
return shapeRecords;
// Split letter followed by number (i.e. "M3" becomes "M 3")
String temp = data.replaceAll("([A-Za-z])([0-9\\-\\.])", "$1 $2");
// Split number followed by letter (i.e. "3M" becomes "3 M")
temp = temp.replaceAll("([0-9\\.])([A-Za-z\\-])", "$1 $2");
// Split letter followed by letter (i.e. "zM" becomes "z M")
temp = temp.replaceAll("([A-Za-z\\-])([A-Za-z\\-])", "$1 $2");
//support scientific notation for floats/doubles
temp = temp.replaceAll("([0-9])( )([eE])( )([0-9\\-])", "$1$3$5");
// Replace commas with spaces
temp = temp.replace(',', ' ');
// Trim leading and trailing spaces
temp = temp.trim();
// Finally, split the string into an array
String[] args = temp.split("\\s+");
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'))
{
problems.add(new FXGInvalidPathDataProblem(node.getDocumentPath(),
node.getStartLine(), node.getStartColumn()));
return Collections.<ShapeRecord>emptyList();
}
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:
problems.add(new FXGInvalidPathDataProblem(node.getDocumentPath(),
node.getStartLine(), node.getStartColumn()));
return Collections.<ShapeRecord>emptyList();
}
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;
}