| @@ -62,15 +62,15 @@ public: | |||
| { | |||
| const String viewBoxAtt (xml.getStringAttribute ("viewBox")); | |||
| String::CharPointerType viewParams (viewBoxAtt.getCharPointer()); | |||
| float vx, vy, vw, vh; | |||
| Point<float> vxy, vwh; | |||
| if (parseCoords (viewParams, vx, vy, true) | |||
| && parseCoords (viewParams, vw, vh, true) | |||
| && vw > 0 | |||
| && vh > 0) | |||
| if (parseCoords (viewParams, vxy, true) | |||
| && parseCoords (viewParams, vwh, true) | |||
| && vwh.x > 0 | |||
| && vwh.y > 0) | |||
| { | |||
| newState.viewBoxW = vw; | |||
| newState.viewBoxH = vh; | |||
| newState.viewBoxW = vwh.x; | |||
| newState.viewBoxH = vwh.y; | |||
| int placementFlags = 0; | |||
| @@ -103,8 +103,8 @@ public: | |||
| const RectanglePlacement placement (placementFlags); | |||
| newState.transform | |||
| = placement.getTransformToFit (Rectangle<float> (vx, vy, vw, vh), | |||
| Rectangle<float> (0.0f, 0.0f, newState.width, newState.height)) | |||
| = placement.getTransformToFit (Rectangle<float> (vxy.x, vxy.y, vwh.x, vwh.y), | |||
| Rectangle<float> (newState.width, newState.height)) | |||
| .followedBy (newState.transform); | |||
| } | |||
| } | |||
| @@ -196,8 +196,7 @@ private: | |||
| if (getStyleAttribute (&xml, "fill-rule").trim().equalsIgnoreCase ("evenodd")) | |||
| path.setUsingNonZeroWinding (false); | |||
| float lastX = 0, lastY = 0; | |||
| float lastX2 = 0, lastY2 = 0; | |||
| Point<float> subpathStart, last, last2, p1, p2, p3; | |||
| juce_wchar lastCommandChar = 0; | |||
| bool isRelative = true; | |||
| bool carryOn = true; | |||
| @@ -206,8 +205,6 @@ private: | |||
| while (! d.isEmpty()) | |||
| { | |||
| float x, y, x2, y2, x3, y3; | |||
| if (validCommandChars.indexOf (*d) >= 0) | |||
| { | |||
| lastCommandChar = d.getAndAdvance(); | |||
| @@ -220,45 +217,36 @@ private: | |||
| case 'm': | |||
| case 'L': | |||
| case 'l': | |||
| if (parseCoords (d, x, y, false)) | |||
| if (parseCoordsOrSkip (d, p1, false)) | |||
| { | |||
| if (isRelative) | |||
| { | |||
| x += lastX; | |||
| y += lastY; | |||
| } | |||
| p1 += last; | |||
| if (lastCommandChar == 'M' || lastCommandChar == 'm') | |||
| { | |||
| path.startNewSubPath (x, y); | |||
| subpathStart = p1; | |||
| path.startNewSubPath (p1); | |||
| lastCommandChar = 'l'; | |||
| } | |||
| else | |||
| path.lineTo (x, y); | |||
| path.lineTo (p1); | |||
| lastX2 = lastX; | |||
| lastY2 = lastY; | |||
| lastX = x; | |||
| lastY = y; | |||
| } | |||
| else | |||
| { | |||
| ++d; | |||
| last2 = last; | |||
| last = p1; | |||
| } | |||
| break; | |||
| case 'H': | |||
| case 'h': | |||
| if (parseCoord (d, x, false, true)) | |||
| if (parseCoord (d, p1.x, false, true)) | |||
| { | |||
| if (isRelative) | |||
| x += lastX; | |||
| p1.x += last.x; | |||
| path.lineTo (x, lastY); | |||
| path.lineTo (p1.x, last.y); | |||
| lastX2 = lastX; | |||
| lastX = x; | |||
| last2.x = last.x; | |||
| last.x = p1.x; | |||
| } | |||
| else | |||
| { | |||
| @@ -268,15 +256,15 @@ private: | |||
| case 'V': | |||
| case 'v': | |||
| if (parseCoord (d, y, false, false)) | |||
| if (parseCoord (d, p1.y, false, false)) | |||
| { | |||
| if (isRelative) | |||
| y += lastY; | |||
| p1.y += last.y; | |||
| path.lineTo (lastX, y); | |||
| path.lineTo (last.x, p1.y); | |||
| lastY2 = lastY; | |||
| lastY = y; | |||
| last2.y = last.y; | |||
| last.y = p1.y; | |||
| } | |||
| else | |||
| { | |||
| @@ -286,115 +274,79 @@ private: | |||
| case 'C': | |||
| case 'c': | |||
| if (parseCoords (d, x, y, false) | |||
| && parseCoords (d, x2, y2, false) | |||
| && parseCoords (d, x3, y3, false)) | |||
| if (parseCoordsOrSkip (d, p1, false) | |||
| && parseCoordsOrSkip (d, p2, false) | |||
| && parseCoordsOrSkip (d, p3, false)) | |||
| { | |||
| if (isRelative) | |||
| { | |||
| x += lastX; | |||
| y += lastY; | |||
| x2 += lastX; | |||
| y2 += lastY; | |||
| x3 += lastX; | |||
| y3 += lastY; | |||
| p1 += last; | |||
| p2 += last; | |||
| p3 += last; | |||
| } | |||
| path.cubicTo (x, y, x2, y2, x3, y3); | |||
| path.cubicTo (p1, p2, p3); | |||
| lastX2 = x2; | |||
| lastY2 = y2; | |||
| lastX = x3; | |||
| lastY = y3; | |||
| } | |||
| else | |||
| { | |||
| ++d; | |||
| last2 = p2; | |||
| last = p3; | |||
| } | |||
| break; | |||
| case 'S': | |||
| case 's': | |||
| if (parseCoords (d, x, y, false) | |||
| && parseCoords (d, x3, y3, false)) | |||
| if (parseCoordsOrSkip (d, p1, false) | |||
| && parseCoordsOrSkip (d, p3, false)) | |||
| { | |||
| if (isRelative) | |||
| { | |||
| x += lastX; | |||
| y += lastY; | |||
| x3 += lastX; | |||
| y3 += lastY; | |||
| p1 += last; | |||
| p3 += last; | |||
| } | |||
| x2 = lastX + (lastX - lastX2); | |||
| y2 = lastY + (lastY - lastY2); | |||
| path.cubicTo (x2, y2, x, y, x3, y3); | |||
| p2 = last + (last - last2); | |||
| path.cubicTo (p2, p1, p3); | |||
| lastX2 = x; | |||
| lastY2 = y; | |||
| lastX = x3; | |||
| lastY = y3; | |||
| } | |||
| else | |||
| { | |||
| ++d; | |||
| last2 = p1; | |||
| last = p3; | |||
| } | |||
| break; | |||
| case 'Q': | |||
| case 'q': | |||
| if (parseCoords (d, x, y, false) | |||
| && parseCoords (d, x2, y2, false)) | |||
| if (parseCoordsOrSkip (d, p1, false) | |||
| && parseCoordsOrSkip (d, p2, false)) | |||
| { | |||
| if (isRelative) | |||
| { | |||
| x += lastX; | |||
| y += lastY; | |||
| x2 += lastX; | |||
| y2 += lastY; | |||
| p1 += last; | |||
| p2 += last; | |||
| } | |||
| path.quadraticTo (x, y, x2, y2); | |||
| path.quadraticTo (p1, p2); | |||
| lastX2 = x; | |||
| lastY2 = y; | |||
| lastX = x2; | |||
| lastY = y2; | |||
| } | |||
| else | |||
| { | |||
| ++d; | |||
| last2 = p1; | |||
| last = p2; | |||
| } | |||
| break; | |||
| case 'T': | |||
| case 't': | |||
| if (parseCoords (d, x, y, false)) | |||
| if (parseCoordsOrSkip (d, p1, false)) | |||
| { | |||
| if (isRelative) | |||
| { | |||
| x += lastX; | |||
| y += lastY; | |||
| } | |||
| p1 += last; | |||
| x2 = lastX + (lastX - lastX2); | |||
| y2 = lastY + (lastY - lastY2); | |||
| path.quadraticTo (x2, y2, x, y); | |||
| p2 = last + (last - last2); | |||
| path.quadraticTo (p2, p1); | |||
| lastX2 = x2; | |||
| lastY2 = y2; | |||
| lastX = x; | |||
| lastY = y; | |||
| } | |||
| else | |||
| { | |||
| ++d; | |||
| last2 = p2; | |||
| last = p1; | |||
| } | |||
| break; | |||
| case 'A': | |||
| case 'a': | |||
| if (parseCoords (d, x, y, false)) | |||
| if (parseCoordsOrSkip (d, p1, false)) | |||
| { | |||
| String num; | |||
| @@ -410,20 +362,17 @@ private: | |||
| { | |||
| const bool sweep = num.getIntValue() != 0; | |||
| if (parseCoords (d, x2, y2, false)) | |||
| if (parseCoordsOrSkip (d, p2, false)) | |||
| { | |||
| if (isRelative) | |||
| { | |||
| x2 += lastX; | |||
| y2 += lastY; | |||
| } | |||
| p2 += last; | |||
| if (lastX != x2 || lastY != y2) | |||
| if (last != p2) | |||
| { | |||
| double centreX, centreY, startAngle, deltaAngle; | |||
| double rx = x, ry = y; | |||
| double rx = p1.x, ry = p1.y; | |||
| endpointToCentreParameters (lastX, lastY, x2, y2, | |||
| endpointToCentreParameters (last.x, last.y, p2.x, p2.y, | |||
| angle, largeArc, sweep, | |||
| rx, ry, centreX, centreY, | |||
| startAngle, deltaAngle); | |||
| @@ -433,28 +382,23 @@ private: | |||
| angle, (float) startAngle, (float) (startAngle + deltaAngle), | |||
| false); | |||
| path.lineTo (x2, y2); | |||
| path.lineTo (p2); | |||
| } | |||
| lastX2 = lastX; | |||
| lastY2 = lastY; | |||
| lastX = x2; | |||
| lastY = y2; | |||
| last2 = last; | |||
| last = p2; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| else | |||
| { | |||
| ++d; | |||
| } | |||
| break; | |||
| case 'Z': | |||
| case 'z': | |||
| path.closeSubPath(); | |||
| last = last2 = subpathStart; | |||
| d = d.findEndOfWhitespace(); | |||
| break; | |||
| @@ -551,24 +495,21 @@ private: | |||
| const String pointsAtt (xml.getStringAttribute ("points")); | |||
| String::CharPointerType points (pointsAtt.getCharPointer()); | |||
| Path path; | |||
| float x, y; | |||
| Point<float> p; | |||
| if (parseCoords (points, x, y, true)) | |||
| if (parseCoords (points, p, true)) | |||
| { | |||
| float firstX = x; | |||
| float firstY = y; | |||
| float lastX = 0, lastY = 0; | |||
| Point<float> first (p), last; | |||
| path.startNewSubPath (x, y); | |||
| path.startNewSubPath (first); | |||
| while (parseCoords (points, x, y, true)) | |||
| while (parseCoords (points, p, true)) | |||
| { | |||
| lastX = x; | |||
| lastY = y; | |||
| path.lineTo (x, y); | |||
| last = p; | |||
| path.lineTo (p); | |||
| } | |||
| if ((! isPolyline) || (firstX == lastX && firstY == lastY)) | |||
| if ((! isPolyline) || first == last) | |||
| path.closeSubPath(); | |||
| } | |||
| @@ -865,10 +806,19 @@ private: | |||
| return true; | |||
| } | |||
| bool parseCoords (String::CharPointerType& s, float& x, float& y, const bool allowUnits) const | |||
| bool parseCoords (String::CharPointerType& s, Point<float>& p, const bool allowUnits) const | |||
| { | |||
| return parseCoord (s, x, allowUnits, true) | |||
| && parseCoord (s, y, allowUnits, false); | |||
| return parseCoord (s, p.x, allowUnits, true) | |||
| && parseCoord (s, p.y, allowUnits, false); | |||
| } | |||
| bool parseCoordsOrSkip (String::CharPointerType& s, Point<float>& p, const bool allowUnits) const | |||
| { | |||
| const bool b = parseCoords (s, p, allowUnits); | |||
| if (! b) | |||
| ++s; | |||
| return b; | |||
| } | |||
| float getCoordLength (const String& s, const float sizeForProportions) const | |||