CSSPrimitiveValue.m 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. #import "CSSPrimitiveValue.h"
  2. #import "CSSValue_ForSubclasses.h"
  3. #import "CSSPrimitiveValue_ConfigurablePixelsPerInch.h"
  4. #import "DOMGlobalSettings.h"
  5. #define INCHES_PER_CENTIMETRE ( 0.393700787f )
  6. #define INCHES_PER_MILLIMETER ( 0.0393701f )
  7. @interface CSSPrimitiveValue()
  8. @property(nonatomic) float internalValue;
  9. @property(nonatomic,strong) NSString* internalString;
  10. @end
  11. @implementation CSSPrimitiveValue
  12. @synthesize pixelsPerInch;
  13. @synthesize internalValue;
  14. @synthesize internalString;
  15. @synthesize primitiveType;
  16. - (id)init
  17. {
  18. self = [super initWithUnitType:CSS_PRIMITIVE_VALUE];
  19. if (self) {
  20. self.pixelsPerInch = 1.0f; // this can be overridden by classes that import the CSSPrimitiveValue_ConfigurablePixelsPerInch.h header
  21. }
  22. return self;
  23. }
  24. -(void) setFloatValue:(CSSPrimitiveType) unitType floatValue:(float) floatValue
  25. {
  26. self.primitiveType = unitType;
  27. self.internalValue = floatValue;
  28. self.internalString = nil;
  29. }
  30. -(float) getFloatValue:(CSSPrimitiveType) unitType
  31. {
  32. /** Easy case: you're asking for the same unit as the originally stored units */
  33. if( unitType == self.primitiveType )
  34. return self.internalValue;
  35. switch( self.primitiveType )
  36. {
  37. case CSS_UNKNOWN:
  38. {
  39. if( self.internalValue == 0.0f )
  40. return self.internalValue;
  41. else
  42. {
  43. NSAssert( FALSE, @"Asked to convert a UNKNOWN value to a different type (%i)", unitType );
  44. }
  45. }
  46. case CSS_CM:
  47. case CSS_IN:
  48. case CSS_MM:
  49. case CSS_PT:
  50. case CSS_PC:
  51. {
  52. float valueAsInches;
  53. switch( self.primitiveType )
  54. {
  55. case CSS_CM:
  56. {
  57. valueAsInches = self.internalValue * INCHES_PER_CENTIMETRE;
  58. }break;
  59. case CSS_MM:
  60. {
  61. valueAsInches = self.internalValue * INCHES_PER_MILLIMETER;
  62. }break;
  63. case CSS_PT:
  64. {
  65. valueAsInches = self.internalValue / 72.0f;
  66. }break;
  67. case CSS_PC:
  68. {
  69. valueAsInches = self.internalValue * 12.0f / 72.0f;
  70. }break;
  71. case CSS_IN:
  72. {
  73. valueAsInches = self.internalValue;
  74. }break;
  75. default:
  76. {
  77. valueAsInches = 0;
  78. NSAssert( FALSE, @"This line is impossible but Apple's compiler is crap" );
  79. }
  80. }
  81. switch( unitType )
  82. {
  83. case CSS_CM:
  84. {
  85. return valueAsInches / INCHES_PER_CENTIMETRE;
  86. }break;
  87. case CSS_MM:
  88. {
  89. return valueAsInches / INCHES_PER_MILLIMETER;
  90. }break;
  91. case CSS_PT:
  92. {
  93. return valueAsInches * 72.0f;
  94. }break;
  95. case CSS_PC:
  96. {
  97. return valueAsInches / 12.0f * 72.0f;
  98. }break;
  99. case CSS_PX:
  100. {
  101. return valueAsInches * self.pixelsPerInch;
  102. }break;
  103. default:
  104. {
  105. NSAssert( FALSE, @"Asked to convert a value in centimetres to an incompatible unit type (%i)", unitType );
  106. }
  107. }
  108. } break;
  109. case CSS_DEG:
  110. case CSS_GRAD:
  111. case CSS_RAD:
  112. {
  113. NSAssert( FALSE, @"Asked to convert an Angle value to a different type (NO conversions for this type are currently supported) (%i)", unitType );
  114. } break;
  115. case CSS_COUNTER:
  116. {
  117. NSAssert( FALSE, @"Asked to convert a Counter value to a different type (NO conversions for this type are currently supported) (%i)", unitType );
  118. } break;
  119. case CSS_DIMENSION:
  120. {
  121. NSAssert( FALSE, @"Asked to convert a Dimension value to a different type (NO conversions for this type are currently supported) (%i)", unitType );
  122. } break;
  123. case CSS_EMS:
  124. case CSS_EXS:
  125. case CSS_PX:
  126. {
  127. NSAssert( FALSE, @"Asked to convert a Relative Length value to a different type (NO conversions for this type are currently supported) (%i)", unitType );
  128. }break;
  129. case CSS_HZ:
  130. case CSS_MS:
  131. case CSS_KHZ:
  132. case CSS_S:
  133. {
  134. NSAssert( FALSE, @"Asked to convert a Time or Frequency value to a different type (NO conversions for this type are currently supported) (%i)", unitType );
  135. }break;
  136. case CSS_NUMBER:
  137. {
  138. if( unitType == CSS_PX ) /** Dom 1 spec allows this, SVG Spec says "this is correct by spec", and DOM 2 spec says this is illegal. Most CSS interpreters do it... */
  139. {
  140. return self.internalValue;
  141. }
  142. else
  143. {
  144. NSAssert( FALSE, @"Asked to convert a Number to a different type (NO conversions for this type are currently supported) (%i)", unitType );
  145. }
  146. }break;
  147. case CSS_PERCENTAGE:
  148. {
  149. if( unitType == CSS_NUMBER )
  150. {
  151. return self.internalValue / 100.0f; // convert percentages to values from 0.0 - 1.0
  152. }
  153. else
  154. NSAssert( FALSE, @"Asked to convert a Percentage value to a different type (%i)", unitType );
  155. }break;
  156. default:
  157. {
  158. NSAssert( FALSE, @"Asked to convert a (%i) value to a (%i) (couldn't find a valid conversion route). Float (4 d.p.) = %2.4f, String = %@", self.primitiveType, unitType, self.internalValue, self.internalString );
  159. }
  160. }
  161. return 0.0f; // this will never happen. you should have Asserted by now, or else returned early with the correct value
  162. }
  163. -(void) setStringValue:(CSSPrimitiveType) stringType stringValue:(NSString*) stringValue
  164. {
  165. self.primitiveType = stringType;
  166. self.internalString = stringValue;
  167. self.internalValue = 0.0f;
  168. }
  169. -(NSString*) getStringValue
  170. {
  171. return self.internalString;
  172. }
  173. -(/* FIXME: have to add this type: Counter*/ void) getCounterValue
  174. {
  175. NSAssert(FALSE, @"This method not supported");
  176. }
  177. -(/* FIXME: have to add this type: Rect*/ void) getRectValue
  178. {
  179. NSAssert(FALSE, @"This method not supported");
  180. }
  181. -(/* FIXME: have to add this type: RGBColor*/ void) getRGBColorValue
  182. {
  183. NSAssert(FALSE, @"This method not supported");
  184. }
  185. #pragma mark - non DOM spec methods needed to implement Objective-C code for this class
  186. -(void)setCssText:(NSString *)newCssText
  187. {
  188. _cssText = newCssText;
  189. /** the css text value has been set, so we need to split the elements up and save them in the internal array */
  190. if( _cssText == nil
  191. || _cssText.length == 0 )
  192. {
  193. self.internalValue = 0.0f;
  194. self.internalString = @"";
  195. self.primitiveType = CSS_UNKNOWN;
  196. }
  197. else if( [_cssText hasSuffix:@"%"])
  198. [self setFloatValue:CSS_PERCENTAGE floatValue:[_cssText floatValue]];
  199. else if( [_cssText hasSuffix:@"em"])
  200. [self setFloatValue:CSS_EMS floatValue:[_cssText floatValue]];
  201. else if( [_cssText hasSuffix:@"ex"])
  202. [self setFloatValue:CSS_EXS floatValue:[_cssText floatValue]];
  203. else if( [_cssText hasSuffix:@"px"])
  204. [self setFloatValue:CSS_PX floatValue:[_cssText floatValue]];
  205. else if( [_cssText hasSuffix:@"cm"])
  206. [self setFloatValue:CSS_CM floatValue:[_cssText floatValue]];
  207. else if( [_cssText hasSuffix:@"mm"])
  208. [self setFloatValue:CSS_MM floatValue:[_cssText floatValue]];
  209. else if( [_cssText hasSuffix:@"in"])
  210. [self setFloatValue:CSS_IN floatValue:[_cssText floatValue]];
  211. else if( [_cssText hasSuffix:@"pt"])
  212. [self setFloatValue:CSS_PT floatValue:[_cssText floatValue]];
  213. else if( [_cssText hasSuffix:@"pc"])
  214. [self setFloatValue:CSS_PC floatValue:[_cssText floatValue]];
  215. else if( [_cssText hasSuffix:@"deg"])
  216. [self setFloatValue:CSS_DEG floatValue:[_cssText floatValue]];
  217. else if( [_cssText hasSuffix:@"rad"])
  218. [self setFloatValue:CSS_RAD floatValue:[_cssText floatValue]];
  219. else if( [_cssText hasSuffix:@"grad"])
  220. [self setFloatValue:CSS_GRAD floatValue:[_cssText floatValue]];
  221. else if( [_cssText hasSuffix:@"ms"])
  222. [self setFloatValue:CSS_MS floatValue:[_cssText floatValue]];
  223. else if( [_cssText hasSuffix:@"s"])
  224. [self setFloatValue:CSS_S floatValue:[_cssText floatValue]];
  225. else if( [_cssText hasSuffix:@"khz"]) // -----------NB: check this before checking HZ !
  226. [self setFloatValue:CSS_KHZ floatValue:[_cssText floatValue]];
  227. else if( [_cssText hasSuffix:@"hz"])
  228. [self setFloatValue:CSS_HZ floatValue:[_cssText floatValue]];
  229. else
  230. {
  231. /**
  232. Three possible outcomes left:
  233. 1. It's a pure number, no units (in CSS, that's rare - but in SVG it's common, and defined by Spec to be "the same as PX")
  234. 2. It's a string, one of many different CSS string types
  235. 3. It's a corrupt file
  236. */
  237. /**
  238. NSScaner is an Apple class that SPECIFICALLY will refuse to return a number if there are any non-numberic characters in the string */
  239. NSScanner *scanner = [NSScanner scannerWithString: _cssText];
  240. float floatToHoldTheOutput;
  241. if( [scanner scanFloat:&floatToHoldTheOutput])
  242. {
  243. /* Option 1: it's a pure number */
  244. [self setFloatValue:CSS_NUMBER floatValue:floatToHoldTheOutput];
  245. }
  246. else
  247. {
  248. /* Option 2: it's a string - or corrupt, which we're not going to handle here */
  249. #if DEBUG_DOM_PARSING
  250. SVGKitLogVerbose(@"[%@] WARNING: not bothering to work out 'what kind of CSS string' this string is. CSS is stupid. String = %@", [self class], _cssText );
  251. #endif
  252. [self setStringValue:CSS_STRING stringValue:_cssText]; // -------- NB: we allow any string-to-string conversion, so it's not a huge problem that we dont correctly detect "url" versus "other kind of string". I hate CSS Parsing...
  253. }
  254. }
  255. }
  256. @end