diff options
Diffstat (limited to 'core/java/android/util/PathParser.java')
-rw-r--r-- | core/java/android/util/PathParser.java | 75 |
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, |