SVGKParserSVG.m 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. #import "SVGKParserSVG.h"
  2. #import "SVGSVGElement.h"
  3. #import "SVGCircleElement.h"
  4. #import "SVGClipPathElement.h"
  5. #import "SVGDefsElement.h"
  6. #import "SVGDescriptionElement.h"
  7. //#import "SVGKSource.h"
  8. #import "SVGEllipseElement.h"
  9. #import "SVGGElement.h"
  10. #import "SVGImageElement.h"
  11. #import "SVGLineElement.h"
  12. #import "SVGPathElement.h"
  13. #import "SVGPolygonElement.h"
  14. #import "SVGPolylineElement.h"
  15. #import "SVGRectElement.h"
  16. #import "SVGSwitchElement.h"
  17. #import "SVGTitleElement.h"
  18. #import "SVGTextElement.h"
  19. #import "TinySVGTextAreaElement.h"
  20. #import "SVGDocument_Mutable.h"
  21. @interface SVGKParserSVG ()
  22. @property (nonatomic) NSArray *supportedNamespaces;
  23. @property (nonatomic) NSDictionary *elementMap;
  24. @end
  25. @implementation SVGKParserSVG
  26. - (NSDictionary *)elementMap {
  27. if (!_elementMap) {
  28. _elementMap = [NSDictionary dictionaryWithObjectsAndKeys:
  29. [SVGSVGElement class], @"svg",
  30. [SVGCircleElement class], @"circle",
  31. [SVGDescriptionElement class], @"description",
  32. [SVGEllipseElement class], @"ellipse",
  33. [SVGGElement class], @"g",
  34. [SVGClipPathElement class], @"clipPath",
  35. [SVGImageElement class], @"image",
  36. [SVGLineElement class], @"line",
  37. [SVGPathElement class], @"path",
  38. [SVGPolygonElement class], @"polygon",
  39. [SVGPolylineElement class], @"polyline",
  40. [SVGRectElement class], @"rect",
  41. [SVGSwitchElement class], @"switch",
  42. [SVGTitleElement class], @"title",
  43. [SVGTextElement class], @"text",
  44. [TinySVGTextAreaElement class], @"textArea",
  45. nil];
  46. }
  47. return _elementMap;
  48. }
  49. -(NSArray *)supportedNamespaces
  50. {
  51. if( _supportedNamespaces == nil )
  52. _supportedNamespaces = @[@"http://www.w3.org/2000/svg"];
  53. return _supportedNamespaces;
  54. }
  55. /** "tags supported" is exactly the set of all SVGElement subclasses that already exist */
  56. -(NSArray*) supportedTags
  57. {
  58. return [self.elementMap allKeys];
  59. }
  60. - (Node*) handleStartElement:(NSString *)name document:(SVGKSource*) SVGKSource namePrefix:(NSString*)prefix namespaceURI:(NSString*) XMLNSURI attributes:(NSMutableDictionary *)attributes parseResult:(SVGKParseResult *)parseResult parentNode:(Node*) parentNode
  61. {
  62. if( [[self supportedNamespaces] containsObject:XMLNSURI] )
  63. {
  64. Class elementClass = [self.elementMap objectForKey:name];
  65. if (!elementClass) {
  66. elementClass = [SVGElement class];
  67. SVGKitLogWarn(@"Support for '%@' element has not been implemented", name);
  68. }
  69. /**
  70. NB: following the SVG Spec, it's critical that we ONLY use the DOM methods for creating
  71. basic 'Element' nodes.
  72. Our SVGElement root class has an implementation of init that delegates to the same
  73. private methods that the DOM methods use, so it's safe...
  74. FIXME: ...but in reality we ought to be using the DOMDocument createElement/NS methods, although "good luck" trying to find a DOMDocument if your SVG is embedded inside a larger XML document :(
  75. */
  76. NSString* qualifiedName = (prefix == nil) ? name : [NSString stringWithFormat:@"%@:%@", prefix, name];
  77. /** NB: must supply a NON-qualified name if we have no specific prefix here ! */
  78. SVGElement *element = [[elementClass alloc] initWithQualifiedName:qualifiedName inNameSpaceURI:XMLNSURI attributes:attributes];
  79. /** NB: all the interesting handling of shared / generic attributes - e.g. the whole of CSS styling etc - takes place in this method: */
  80. [element postProcessAttributesAddingErrorsTo:parseResult];
  81. /** special case: <svg:svg ... version="XXX"> */
  82. if( [@"svg" isEqualToString:name] )
  83. {
  84. ((SVGSVGElement *) element).source = SVGKSource;
  85. NSString* svgVersion = nil;
  86. /** According to spec, if the first XML node is an SVG node, then it
  87. becomes TWO THINGS:
  88. - An SVGSVGElement
  89. *and*
  90. - An SVGDocument
  91. - ...and that becomes "the root SVGDocument"
  92. If it's NOT the first XML node, but it's the first SVG node, then it ONLY becomes:
  93. - An SVGSVGElement
  94. If it's NOT the first SVG node, then it becomes:
  95. - An SVGSVGElement
  96. *and*
  97. - An SVGDocument
  98. Yes. It's Very confusing! Go read the SVG Spec!
  99. */
  100. BOOL generateAnSVGDocument = FALSE;
  101. BOOL overwriteRootSVGDocument = FALSE;
  102. BOOL overwriteRootOfTree = FALSE;
  103. if( parentNode == nil )
  104. {
  105. /** This start element is the first item in the document
  106. PS: xcode has a new bug for Lion: it can't format single-line comments with two asterisks. This line added because Xcode sucks.
  107. */
  108. generateAnSVGDocument = overwriteRootSVGDocument = overwriteRootOfTree = TRUE;
  109. }
  110. else if( parseResult.rootOfSVGTree == nil )
  111. {
  112. /** It's not the first XML, but it's the first SVG node */
  113. overwriteRootOfTree = TRUE;
  114. }
  115. else
  116. {
  117. /** It's not the first SVG node */
  118. // ... so: do nothing special
  119. }
  120. /**
  121. Handle the complex stuff above about SVGDocument and SVG node
  122. */
  123. if( overwriteRootOfTree )
  124. {
  125. parseResult.rootOfSVGTree = (SVGSVGElement*) element;
  126. /** Post-processing of the ROOT SVG ONLY (doesn't apply to embedded SVG's )
  127. */
  128. if ((svgVersion = [attributes objectForKey:@"version"])) {
  129. SVGKSource.svgLanguageVersion = svgVersion;
  130. }
  131. }
  132. if( generateAnSVGDocument )
  133. {
  134. NSAssert( [element isKindOfClass:[SVGSVGElement class]], @"Trying to create a new internal SVGDocument from a Node that is NOT of type SVGSVGElement (tag: svg). Node was of type: %@", NSStringFromClass([element class]));
  135. SVGDocument* newDocument = [[SVGDocument alloc] init];
  136. newDocument.rootElement = (SVGSVGElement*) element;
  137. if( overwriteRootSVGDocument )
  138. {
  139. parseResult.parsedDocument = newDocument;
  140. }
  141. else
  142. {
  143. NSAssert( FALSE, @"Currently not supported: multiple SVG Document nodes in a single SVG file" );
  144. }
  145. }
  146. }
  147. return element;
  148. }
  149. return nil;
  150. }
  151. -(void)handleEndElement:(Node *)newNode document:(SVGKSource *)document parseResult:(SVGKParseResult *)parseResult
  152. {
  153. }
  154. @end