SVGRectElement.m 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. #import "SVGRectElement.h"
  2. #import "SVGElement_ForParser.h" // to resolve Xcode circular dependencies; in long term, parsing SHOULD NOT HAPPEN inside any class whose name starts "SVG" (because those are reserved classes for the SVG Spec)
  3. #import "SVGHelperUtilities.h"
  4. @interface SVGRectElement ()
  5. #if SVGKIT_UIKIT && __IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_7_0
  6. void CGPathAddRoundedRect (CGMutablePathRef path, CGRect rect, CGFloat radiusX, CGFloat radiusY);
  7. #endif
  8. @end
  9. @implementation SVGRectElement
  10. @synthesize transform; // each SVGElement subclass that conforms to protocol "SVGTransformable" has to re-synthesize this to work around bugs in Apple's Objective-C 2.0 design that don't allow @properties to be extended by categories / protocols
  11. @synthesize x = _x;
  12. @synthesize y = _y;
  13. @synthesize width = _width;
  14. @synthesize height = _height;
  15. @synthesize rx = _rx;
  16. @synthesize ry = _ry;
  17. #if SVGKIT_UIKIT && __IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_7_0
  18. // adapted from http://www.cocoanetics.com/2010/02/drawing-rounded-rectangles/
  19. void CGPathAddRoundedRect (CGMutablePathRef path, CGRect rect, CGFloat radiusX, CGFloat radiusY) {
  20. CGRect innerRect = CGRectInset(rect, radiusX, radiusY);
  21. CGFloat innerRight = innerRect.origin.x + innerRect.size.width;
  22. CGFloat right = rect.origin.x + rect.size.width;
  23. CGFloat innerBottom = innerRect.origin.y + innerRect.size.height;
  24. CGFloat bottom = rect.origin.y + rect.size.height;
  25. CGFloat innerTop = innerRect.origin.y;
  26. CGFloat top = rect.origin.y;
  27. CGFloat innerLeft = innerRect.origin.x;
  28. CGFloat left = rect.origin.x;
  29. CGPathMoveToPoint(path, NULL, innerLeft, top);
  30. CGPathAddLineToPoint(path, NULL, innerRight, top);
  31. /** c.f http://stackoverflow.com/a/12152442/153422 */
  32. CGAffineTransform t = CGAffineTransformConcat( CGAffineTransformMakeScale(1.0, radiusY/radiusX), CGAffineTransformMakeTranslation(innerRight, innerTop));
  33. CGPathAddArc(path, &t, 0, 0, radiusX, -M_PI_2, 0, false);
  34. CGPathAddLineToPoint(path, NULL, right, innerBottom);
  35. /** c.f http://stackoverflow.com/a/12152442/153422 */
  36. t = CGAffineTransformConcat( CGAffineTransformMakeScale(1.0, radiusY/radiusX), CGAffineTransformMakeTranslation(innerRight, innerBottom));
  37. CGPathAddArc(path, &t, 0, 0, radiusX, 0, M_PI_2, false);
  38. CGPathAddLineToPoint(path, NULL, innerLeft, bottom);
  39. /** c.f http://stackoverflow.com/a/12152442/153422 */
  40. t = CGAffineTransformConcat( CGAffineTransformMakeScale(1.0, radiusY/radiusX), CGAffineTransformMakeTranslation(innerLeft, innerBottom));
  41. CGPathAddArc(path, &t, 0, 0, radiusX, M_PI_2, M_PI, false);
  42. CGPathAddLineToPoint(path, NULL, left, innerTop);
  43. /** c.f http://stackoverflow.com/a/12152442/153422 */
  44. t = CGAffineTransformConcat( CGAffineTransformMakeScale(1.0, radiusY/radiusX), CGAffineTransformMakeTranslation(innerLeft, innerTop));
  45. CGPathAddArc(path, &t, 0, 0, radiusX, M_PI, 3*M_PI_2, false);
  46. CGPathCloseSubpath(path);
  47. }
  48. #endif
  49. - (void)postProcessAttributesAddingErrorsTo:(SVGKParseResult *)parseResult {
  50. [super postProcessAttributesAddingErrorsTo:parseResult];
  51. if( [[self getAttribute:@"x"] length] > 0 )
  52. _x = [SVGLength svgLengthFromNSString:[self getAttribute:@"x"]];
  53. if( [[self getAttribute:@"y"] length] > 0 )
  54. _y = [SVGLength svgLengthFromNSString:[self getAttribute:@"y"]];
  55. if( [[self getAttribute:@"width"] length] > 0 )
  56. _width = [SVGLength svgLengthFromNSString:[self getAttribute:@"width"]];
  57. if( [[self getAttribute:@"height"] length] > 0 )
  58. _height = [SVGLength svgLengthFromNSString:[self getAttribute:@"height"]];
  59. if( [[self getAttribute:@"rx"] length] > 0 )
  60. _rx = [SVGLength svgLengthFromNSString:[self getAttribute:@"rx"]];
  61. if( [[self getAttribute:@"ry"] length] > 0 )
  62. _ry = [SVGLength svgLengthFromNSString:[self getAttribute:@"ry"]];
  63. /**
  64. Create a square OR rounded rectangle as a CGPath
  65. */
  66. SVGRect r = parseResult.rootOfSVGTree.viewport;
  67. CGMutablePathRef path = CGPathCreateMutable();
  68. CGRect rect = CGRectMake([_x pixelsValueWithDimension:r.x], [_y pixelsValueWithDimension:r.y],
  69. [_width pixelsValueWithDimension:r.width], [_height pixelsValueWithDimension:r.height]);
  70. CGFloat radiusXPixels = _rx != nil ? [_rx pixelsValue] : 0;
  71. CGFloat radiusYPixels = _ry != nil ? [_ry pixelsValue] : 0;
  72. if( radiusXPixels == 0 && radiusYPixels == 0 )
  73. {
  74. CGPathAddRect(path, NULL, rect);
  75. }
  76. else
  77. {
  78. if( radiusXPixels > 0 && radiusYPixels == 0 ) // if RY unspecified, make it equal to RX
  79. radiusYPixels = radiusXPixels;
  80. else if( radiusXPixels == 0 && radiusYPixels > 0 ) // if RX unspecified, make it equal to RY
  81. radiusXPixels = radiusYPixels;
  82. if( radiusXPixels > CGRectGetWidth(rect) / 2 ) // give RX max value of half rect width
  83. radiusXPixels = CGRectGetWidth(rect) / 2;
  84. if( radiusYPixels > CGRectGetHeight(rect) / 2 ) // give RY max value of half rect height
  85. radiusYPixels = CGRectGetHeight(rect) / 2;
  86. CGPathAddRoundedRect(path,
  87. #if !(SVGKIT_UIKIT && __IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_7_0)
  88. nil,
  89. #endif
  90. rect, radiusXPixels, radiusYPixels);
  91. }
  92. self.pathForShapeInRelativeCoords = path;
  93. CGPathRelease(path);
  94. }
  95. @end