SVGPathElement.m 11 KB

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