summaryrefslogtreecommitdiffstats
path: root/core/java/android/util/PathParser.java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java/android/util/PathParser.java')
-rw-r--r--core/java/android/util/PathParser.java75
1 files changed, 57 insertions, 18 deletions
diff --git a/core/java/android/util/PathParser.java b/core/java/android/util/PathParser.java
index 6820f77..92b19be 100644
--- a/core/java/android/util/PathParser.java
+++ b/core/java/android/util/PathParser.java
@@ -34,7 +34,11 @@ public class PathParser {
Path path = new Path();
PathDataNode[] nodes = createNodesFromPathData(pathData);
if (nodes != null) {
- PathDataNode.nodesToPath(nodes, path);
+ try {
+ PathDataNode.nodesToPath(nodes, path);
+ } catch (RuntimeException e) {
+ throw new RuntimeException("Error in parsing " + pathData, e);
+ }
return path;
}
return null;
@@ -128,7 +132,12 @@ public class PathParser {
while (end < s.length()) {
c = s.charAt(end);
- if (((c - 'A') * (c - 'Z') <= 0) || (((c - 'a') * (c - 'z') <= 0))) {
+ // Note that 'e' or 'E' are not valid path commands, but could be
+ // used for floating point numbers' scientific notation.
+ // Therefore, when searching for next command, we should ignore 'e'
+ // and 'E'.
+ if ((((c - 'A') * (c - 'Z') <= 0) || ((c - 'a') * (c - 'z') <= 0))
+ && c != 'e' && c != 'E') {
return end;
}
end++;
@@ -142,9 +151,9 @@ public class PathParser {
private static class ExtractFloatResult {
// We need to return the position of the next separator and whether the
- // next float starts with a '-'.
+ // next float starts with a '-' or a '.'.
int mEndPosition;
- boolean mEndWithNegSign;
+ boolean mEndWithNegOrDot;
}
/**
@@ -179,8 +188,8 @@ public class PathParser {
s.substring(startPosition, endPosition));
}
- if (result.mEndWithNegSign) {
- // Keep the '-' sign with next number.
+ if (result.mEndWithNegOrDot) {
+ // Keep the '-' or '.' sign with next number.
startPosition = endPosition;
} else {
startPosition = endPosition + 1;
@@ -188,8 +197,7 @@ public class PathParser {
}
return Arrays.copyOf(results, count);
} catch (NumberFormatException e) {
- Log.e(LOGTAG, "error in parsing \"" + s + "\"");
- throw e;
+ throw new RuntimeException("error in parsing \"" + s + "\"", e);
}
}
@@ -201,11 +209,15 @@ public class PathParser {
* the starting position of next number, whether it is ending with a '-'.
*/
private static void extract(String s, int start, ExtractFloatResult result) {
- // Now looking for ' ', ',' or '-' from the start.
+ // Now looking for ' ', ',', '.' or '-' from the start.
int currentIndex = start;
boolean foundSeparator = false;
- result.mEndWithNegSign = false;
+ result.mEndWithNegOrDot = false;
+ boolean secondDot = false;
+ boolean isExponential = false;
for (; currentIndex < s.length(); currentIndex++) {
+ boolean isPrevExponential = isExponential;
+ isExponential = false;
char currentChar = s.charAt(currentIndex);
switch (currentChar) {
case ' ':
@@ -213,11 +225,25 @@ public class PathParser {
foundSeparator = true;
break;
case '-':
- if (currentIndex != start) {
+ // The negative sign following a 'e' or 'E' is not a separator.
+ if (currentIndex != start && !isPrevExponential) {
+ foundSeparator = true;
+ result.mEndWithNegOrDot = true;
+ }
+ break;
+ case '.':
+ if (!secondDot) {
+ secondDot = true;
+ } else {
+ // This is the second dot, and it is considered as a separator.
foundSeparator = true;
- result.mEndWithNegSign = true;
+ result.mEndWithNegOrDot = true;
}
break;
+ case 'e':
+ case 'E':
+ isExponential = true;
+ break;
}
if (foundSeparator) {
break;
@@ -254,7 +280,7 @@ public class PathParser {
* @param path The target Path object.
*/
public static void nodesToPath(PathDataNode[] node, Path path) {
- float[] current = new float[4];
+ float[] current = new float[6];
char previousCommand = 'm';
for (int i = 0; i < node.length; i++) {
addCommand(path, current, previousCommand, node[i].mType, node[i].mParams);
@@ -287,6 +313,8 @@ public class PathParser {
float currentY = current[1];
float ctrlPointX = current[2];
float ctrlPointY = current[3];
+ float currentSegmentStartX = current[4];
+ float currentSegmentStartY = current[5];
float reflectiveCtrlPointX;
float reflectiveCtrlPointY;
@@ -294,7 +322,15 @@ public class PathParser {
case 'z':
case 'Z':
path.close();
- return;
+ // Path is closed here, but we need to move the pen to the
+ // closed position. So we cache the segment's starting position,
+ // and restore it here.
+ currentX = currentSegmentStartX;
+ currentY = currentSegmentStartY;
+ ctrlPointX = currentSegmentStartX;
+ ctrlPointY = currentSegmentStartY;
+ path.moveTo(currentX, currentY);
+ break;
case 'm':
case 'M':
case 'l':
@@ -324,17 +360,22 @@ public class PathParser {
incr = 7;
break;
}
+
for (int k = 0; k < val.length; k += incr) {
switch (cmd) {
case 'm': // moveto - Start a new sub-path (relative)
path.rMoveTo(val[k + 0], val[k + 1]);
currentX += val[k + 0];
currentY += val[k + 1];
+ currentSegmentStartX = currentX;
+ currentSegmentStartY = currentY;
break;
case 'M': // moveto - Start a new sub-path
path.moveTo(val[k + 0], val[k + 1]);
currentX = val[k + 0];
currentY = val[k + 1];
+ currentSegmentStartX = currentX;
+ currentSegmentStartY = currentY;
break;
case 'l': // lineto - Draw a line from the current point (relative)
path.rLineTo(val[k + 0], val[k + 1]);
@@ -346,10 +387,6 @@ public class PathParser {
currentX = val[k + 0];
currentY = val[k + 1];
break;
- case 'z': // closepath - Close the current subpath
- case 'Z': // closepath - Close the current subpath
- path.close();
- break;
case 'h': // horizontal lineto - Draws a horizontal line (relative)
path.rLineTo(val[k + 0], 0);
currentX += val[k + 0];
@@ -500,6 +537,8 @@ public class PathParser {
current[1] = currentY;
current[2] = ctrlPointX;
current[3] = ctrlPointY;
+ current[4] = currentSegmentStartX;
+ current[5] = currentSegmentStartY;
}
private static void drawArc(Path p,