SVGPathElement.m 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. //
  2. // SVGPathElement.m
  3. // SVGKit
  4. //
  5. // Copyright Matt Rajca 2010-2011. All rights reserved.
  6. //
  7. #import "SVGPathElement.h"
  8. #import "SVGUtils.h"
  9. #import "SVGKPointsAndPathsParser.h"
  10. #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)
  11. @interface SVGPathElement ()
  12. - (void) parseData:(NSString *)data;
  13. @end
  14. @implementation SVGPathElement
  15. - (void)postProcessAttributesAddingErrorsTo:(SVGKParseResult *)parseResult
  16. {
  17. [super postProcessAttributesAddingErrorsTo:parseResult];
  18. [self parseData:[self getAttribute:@"d"]];
  19. }
  20. - (void)parseData:(NSString *)data
  21. {
  22. CGMutablePathRef path = CGPathCreateMutable();
  23. NSScanner* dataScanner = [NSScanner scannerWithString:data];
  24. SVGCurve lastCurve = [SVGKPointsAndPathsParser startingCurve];
  25. BOOL foundCmd;
  26. NSCharacterSet *knownCommands = [NSCharacterSet characterSetWithCharactersInString:@"MmLlCcVvHhAaSsQqTtZz"];
  27. NSString* command;
  28. do {
  29. command = nil;
  30. foundCmd = [dataScanner scanCharactersFromSet:knownCommands intoString:&command];
  31. if (command.length > 1) {
  32. // Take only one char (it can happen that multiple commands are consecutive, as "ZM" - so we only want to get the "Z")
  33. const NSUInteger tooManyChars = command.length-1;
  34. command = [command substringToIndex:1];
  35. [dataScanner setScanLocation:([dataScanner scanLocation] - tooManyChars)];
  36. }
  37. if (foundCmd) {
  38. if ([@"z" isEqualToString:command] || [@"Z" isEqualToString:command]) {
  39. lastCurve = [SVGKPointsAndPathsParser readCloseCommand:[NSScanner scannerWithString:command]
  40. path:path
  41. relativeTo:lastCurve.p];
  42. } else {
  43. NSString* cmdArgs = nil;
  44. BOOL foundParameters = [dataScanner scanUpToCharactersFromSet:knownCommands
  45. intoString:&cmdArgs];
  46. if (foundParameters) {
  47. NSString* commandWithParameters = [command stringByAppendingString:cmdArgs];
  48. NSScanner* commandScanner = [NSScanner scannerWithString:commandWithParameters];
  49. if ([@"m" isEqualToString:command]) {
  50. lastCurve = [SVGKPointsAndPathsParser readMovetoDrawtoCommandGroups:commandScanner
  51. path:path
  52. relativeTo:lastCurve.p
  53. isRelative:TRUE];
  54. } else if ([@"M" isEqualToString:command]) {
  55. lastCurve = [SVGKPointsAndPathsParser readMovetoDrawtoCommandGroups:commandScanner
  56. path:path
  57. relativeTo:CGPointZero
  58. isRelative:FALSE];
  59. } else if ([@"l" isEqualToString:command]) {
  60. lastCurve = [SVGKPointsAndPathsParser readLinetoCommand:commandScanner
  61. path:path
  62. relativeTo:lastCurve.p
  63. isRelative:TRUE];
  64. } else if ([@"L" isEqualToString:command]) {
  65. lastCurve = [SVGKPointsAndPathsParser readLinetoCommand:commandScanner
  66. path:path
  67. relativeTo:CGPointZero
  68. isRelative:FALSE];
  69. } else if ([@"v" isEqualToString:command]) {
  70. lastCurve = [SVGKPointsAndPathsParser readVerticalLinetoCommand:commandScanner
  71. path:path
  72. relativeTo:lastCurve.p];
  73. } else if ([@"V" isEqualToString:command]) {
  74. lastCurve = [SVGKPointsAndPathsParser readVerticalLinetoCommand:commandScanner
  75. path:path
  76. relativeTo:CGPointZero];
  77. } else if ([@"h" isEqualToString:command]) {
  78. lastCurve = [SVGKPointsAndPathsParser readHorizontalLinetoCommand:commandScanner
  79. path:path
  80. relativeTo:lastCurve.p];
  81. } else if ([@"H" isEqualToString:command]) {
  82. lastCurve = [SVGKPointsAndPathsParser readHorizontalLinetoCommand:commandScanner
  83. path:path
  84. relativeTo:CGPointZero];
  85. } else if ([@"c" isEqualToString:command]) {
  86. lastCurve = [SVGKPointsAndPathsParser readCurvetoCommand:commandScanner
  87. path:path
  88. relativeTo:lastCurve.p
  89. isRelative:TRUE];
  90. } else if ([@"C" isEqualToString:command]) {
  91. lastCurve = [SVGKPointsAndPathsParser readCurvetoCommand:commandScanner
  92. path:path
  93. relativeTo:CGPointZero
  94. isRelative:FALSE];
  95. } else if ([@"s" isEqualToString:command]) {
  96. lastCurve = [SVGKPointsAndPathsParser readSmoothCurvetoCommand:commandScanner
  97. path:path
  98. relativeTo:lastCurve.p
  99. withPrevCurve:lastCurve
  100. isRelative:TRUE];
  101. } else if ([@"S" isEqualToString:command]) {
  102. lastCurve = [SVGKPointsAndPathsParser readSmoothCurvetoCommand:commandScanner
  103. path:path
  104. relativeTo:CGPointZero
  105. withPrevCurve:lastCurve
  106. isRelative:FALSE];
  107. } else if ([@"q" isEqualToString:command]) {
  108. lastCurve = [SVGKPointsAndPathsParser readQuadraticCurvetoCommand:commandScanner
  109. path:path
  110. relativeTo:lastCurve.p
  111. isRelative:TRUE];
  112. } else if ([@"Q" isEqualToString:command]) {
  113. lastCurve = [SVGKPointsAndPathsParser readQuadraticCurvetoCommand:commandScanner
  114. path:path
  115. relativeTo:CGPointZero
  116. isRelative:FALSE];
  117. } else if ([@"t" isEqualToString:command]) {
  118. lastCurve = [SVGKPointsAndPathsParser readSmoothQuadraticCurvetoCommand:commandScanner
  119. path:path
  120. relativeTo:lastCurve.p
  121. withPrevCurve:lastCurve];
  122. } else if ([@"T" isEqualToString:command]) {
  123. lastCurve = [SVGKPointsAndPathsParser readSmoothQuadraticCurvetoCommand:commandScanner
  124. path:path
  125. relativeTo:CGPointZero
  126. withPrevCurve:lastCurve];
  127. } else if ([@"a" isEqualToString:command]) {
  128. lastCurve = [SVGKPointsAndPathsParser readEllipticalArcArguments:commandScanner
  129. path:path
  130. relativeTo:lastCurve.p
  131. isRelative:TRUE];
  132. } else if ([@"A" isEqualToString:command]) {
  133. lastCurve = [SVGKPointsAndPathsParser readEllipticalArcArguments:commandScanner
  134. path:path
  135. relativeTo:CGPointZero
  136. isRelative:FALSE];
  137. } else {
  138. SVGKitLogWarn(@"unsupported command %@", command);
  139. }
  140. }
  141. }
  142. }
  143. } while (foundCmd);
  144. self.pathForShapeInRelativeCoords = path;
  145. CGPathRelease(path);
  146. }
  147. @end