CSSStyleDeclaration.m 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. #import "CSSStyleDeclaration.h"
  2. #import "CSSValue.h"
  3. #import "CSSValueList.h"
  4. #import "CSSPrimitiveValue.h"
  5. #import "CocoaLumberjack/DDFileLogger.h"
  6. #import "SVGKDefine_Private.h"
  7. @interface CSSStyleDeclaration()
  8. @property(nonatomic,strong) NSMutableDictionary* internalDictionaryOfStylesByCSSClass;
  9. @end
  10. @implementation CSSStyleDeclaration
  11. @synthesize internalDictionaryOfStylesByCSSClass;
  12. @synthesize cssText = _cssText;
  13. @synthesize length;
  14. @synthesize parentRule;
  15. - (id)init
  16. {
  17. self = [super init];
  18. if (self) {
  19. self.internalDictionaryOfStylesByCSSClass = [NSMutableDictionary dictionary];
  20. }
  21. return self;
  22. }
  23. #define MAX_ACCUM 256
  24. #define MAX_NAME 256
  25. /** From spec:
  26. "The parsable textual representation of the declaration block (excluding the surrounding curly braces). Setting this attribute will result in the parsing of the new value and resetting of all the properties in the declaration block including the removal or addition of properties."
  27. */
  28. -(void)setCssText:(NSString *)newCSSText
  29. {
  30. _cssText = newCSSText;
  31. /** and now post-process it, *as required by* the CSS/DOM spec... */
  32. NSMutableDictionary* processedStyles = [self NSDictionaryFromCSSAttributes:_cssText];
  33. self.internalDictionaryOfStylesByCSSClass = processedStyles;
  34. }
  35. -(NSMutableDictionary *) NSDictionaryFromCSSAttributes: (NSString *)css {
  36. NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
  37. NSCharacterSet* trimChars = [NSCharacterSet whitespaceAndNewlineCharacterSet];
  38. const char *cstr = [css UTF8String];
  39. size_t len = strlen(cstr);
  40. char name[MAX_NAME];
  41. bzero(name, MAX_NAME);
  42. char accum[MAX_ACCUM];
  43. bzero(accum, MAX_ACCUM);
  44. size_t accumIdx = 0;
  45. for (size_t n = 0; n <= len; n++) {
  46. char c = cstr[n];
  47. if (c == ':') {
  48. strncpy(name, accum, MAX_NAME);
  49. name[accumIdx] = '\0';
  50. bzero(accum, MAX_ACCUM);
  51. accumIdx = 0;
  52. continue;
  53. }
  54. else if (c == ';' || c == '\0') {
  55. if( accumIdx > 0 ) //if there is a ';' and '\0' to end the style, avoid adding an empty key-value pair
  56. {
  57. accum[accumIdx] = '\0';
  58. NSString *keyString = [[NSString stringWithUTF8String:name]
  59. stringByTrimmingCharactersInSet:trimChars];
  60. NSString *cssValueString = [[NSString stringWithUTF8String:accum]
  61. stringByTrimmingCharactersInSet:trimChars];
  62. CSSValue *cssValue;
  63. if( [cssValueString rangeOfString:@" "].length > 0 )
  64. cssValue = [[CSSValueList alloc] init];
  65. else
  66. cssValue = [[CSSPrimitiveValue alloc] init];
  67. cssValue.cssText = cssValueString; // has the side-effect of parsing, if required
  68. [dict setObject:cssValue
  69. forKey:keyString];
  70. bzero(name, MAX_NAME);
  71. bzero(accum, MAX_ACCUM);
  72. accumIdx = 0;
  73. }
  74. continue;
  75. }
  76. accum[accumIdx++] = c;
  77. if (accumIdx >= MAX_ACCUM) {
  78. SVGKitLogWarn(@"Buffer ovverun while parsing style sheet - skipping");
  79. return dict;
  80. }
  81. }
  82. return dict;
  83. }
  84. -(NSString*) getPropertyValue:(NSString*) propertyName
  85. {
  86. CSSValue* v = [self getPropertyCSSValue:propertyName];
  87. if( v == nil )
  88. return nil;
  89. else
  90. return v.cssText;
  91. }
  92. -(CSSValue*) getPropertyCSSValue:(NSString*) propertyName
  93. {
  94. return [self.internalDictionaryOfStylesByCSSClass objectForKey:propertyName];
  95. }
  96. -(NSString*) removeProperty:(NSString*) propertyName
  97. {
  98. NSString* oldValue = [self getPropertyValue:propertyName];
  99. [self.internalDictionaryOfStylesByCSSClass removeObjectForKey:propertyName];
  100. return oldValue;
  101. }
  102. -(NSString*) getPropertyPriority:(NSString*) propertyName
  103. {
  104. NSAssert(FALSE, @"CSS 'property priorities' - Not supported");
  105. return nil;
  106. }
  107. -(void) setProperty:(NSString*) propertyName value:(NSString*) value priority:(NSString*) priority
  108. {
  109. NSAssert(FALSE, @"CSS 'property priorities' - Not supported");
  110. }
  111. -(NSString*) item:(long) index
  112. {
  113. /** this is stupid slow, but until Apple *can be bothered* to add a "stable-order" dictionary to their libraries, this is the only sensibly easy way of implementing this method */
  114. NSArray* sortedKeys = [[self.internalDictionaryOfStylesByCSSClass allKeys] sortedArrayUsingSelector:@selector(compare:)];
  115. CSSValue* v = [sortedKeys objectAtIndex:index];
  116. return v.cssText;
  117. }
  118. -(NSString *)description
  119. {
  120. return [NSString stringWithFormat:@"CSSStyleDeclaration: dictionary(%@)", self.internalDictionaryOfStylesByCSSClass];
  121. }
  122. @end