SVGPathElement.m 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  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. } else if ([@"V" isEqualToString:command]) {
  75. lastCurve = [SVGKPointsAndPathsParser readVerticalLinetoCommand:commandScanner
  76. path:path
  77. relativeTo:CGPointZero];
  78. } else if ([@"h" isEqualToString:command]) {
  79. lastCurve = [SVGKPointsAndPathsParser readHorizontalLinetoCommand:commandScanner
  80. path:path
  81. relativeTo:lastCurve.p];
  82. } else if ([@"H" isEqualToString:command]) {
  83. lastCurve = [SVGKPointsAndPathsParser readHorizontalLinetoCommand:commandScanner
  84. path:path
  85. relativeTo:CGPointZero];
  86. } else if ([@"c" isEqualToString:command]) {
  87. lastCurve = [SVGKPointsAndPathsParser readCurvetoCommand:commandScanner
  88. path:path
  89. relativeTo:lastCurve.p
  90. isRelative:TRUE];
  91. } else if ([@"C" isEqualToString:command]) {
  92. lastCurve = [SVGKPointsAndPathsParser readCurvetoCommand:commandScanner
  93. path:path
  94. relativeTo:CGPointZero
  95. isRelative:FALSE];
  96. } else if ([@"s" isEqualToString:command]) {
  97. lastCurve = [SVGKPointsAndPathsParser readSmoothCurvetoCommand:commandScanner
  98. path:path
  99. relativeTo:lastCurve.p
  100. withPrevCurve:lastCurve
  101. isRelative:TRUE];
  102. } else if ([@"S" isEqualToString:command]) {
  103. lastCurve = [SVGKPointsAndPathsParser readSmoothCurvetoCommand:commandScanner
  104. path:path
  105. relativeTo:CGPointZero
  106. withPrevCurve:lastCurve
  107. isRelative:FALSE];
  108. } else if ([@"q" isEqualToString:command]) {
  109. lastCurve = [SVGKPointsAndPathsParser readQuadraticCurvetoCommand:commandScanner
  110. path:path
  111. relativeTo:lastCurve.p
  112. isRelative:TRUE];
  113. } else if ([@"Q" isEqualToString:command]) {
  114. lastCurve = [SVGKPointsAndPathsParser readQuadraticCurvetoCommand:commandScanner
  115. path:path
  116. relativeTo:CGPointZero
  117. isRelative:FALSE];
  118. } else if ([@"t" isEqualToString:command]) {
  119. lastCurve = [SVGKPointsAndPathsParser readSmoothQuadraticCurvetoCommand:commandScanner
  120. path:path
  121. relativeTo:lastCurve.p
  122. withPrevCurve:lastCurve];
  123. } else if ([@"T" isEqualToString:command]) {
  124. lastCurve = [SVGKPointsAndPathsParser readSmoothQuadraticCurvetoCommand:commandScanner
  125. path:path
  126. relativeTo:CGPointZero
  127. withPrevCurve:lastCurve];
  128. } else if ([@"a" isEqualToString:command]) {
  129. lastCurve = [SVGKPointsAndPathsParser readEllipticalArcArguments:commandScanner
  130. path:path
  131. relativeTo:lastCurve.p
  132. isRelative:TRUE];
  133. } else if ([@"A" isEqualToString:command]) {
  134. lastCurve = [SVGKPointsAndPathsParser readEllipticalArcArguments:commandScanner
  135. path:path
  136. relativeTo:CGPointZero
  137. isRelative:FALSE];
  138. } else {
  139. SVGKitLogWarn(@"unsupported command %@", command);
  140. }
  141. }
  142. }
  143. }
  144. } while (foundCmd);
  145. self.pathForShapeInRelativeCoords = path;
  146. CGPathRelease(path);
  147. }
  148. @end