SVGLength.m 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. #import "SVGLength.h"
  2. #import "CSSPrimitiveValue.h"
  3. #import "CSSPrimitiveValue_ConfigurablePixelsPerInch.h"
  4. #import "SVGUtils.h"
  5. #include <sys/types.h>
  6. #include <sys/sysctl.h>
  7. @interface SVGLength()
  8. @property(nonatomic,strong) CSSPrimitiveValue* internalCSSPrimitiveValue;
  9. @end
  10. @implementation SVGLength
  11. @synthesize unitType;
  12. @synthesize value;
  13. @synthesize valueInSpecifiedUnits;
  14. @synthesize valueAsString;
  15. @synthesize internalCSSPrimitiveValue;
  16. - (id)init
  17. {
  18. NSAssert(FALSE, @"This class must not be init'd. Use the static hepler methods to instantiate it instead");
  19. return nil;
  20. }
  21. - (id)initWithCSSPrimitiveValue:(CSSPrimitiveValue*) pv
  22. {
  23. self = [super init];
  24. if (self) {
  25. self.internalCSSPrimitiveValue = pv;
  26. }
  27. return self;
  28. }
  29. -(float)value
  30. {
  31. return [self.internalCSSPrimitiveValue getFloatValue:self.internalCSSPrimitiveValue.primitiveType];
  32. }
  33. -(SVG_LENGTH_TYPE)unitType
  34. {
  35. switch( self.internalCSSPrimitiveValue.primitiveType )
  36. {
  37. case CSS_CM:
  38. return SVG_LENGTHTYPE_CM;
  39. case CSS_EMS:
  40. return SVG_LENGTHTYPE_EMS;
  41. case CSS_EXS:
  42. return SVG_LENGTHTYPE_EXS;
  43. case CSS_IN:
  44. return SVG_LENGTHTYPE_IN;
  45. case CSS_MM:
  46. return SVG_LENGTHTYPE_MM;
  47. case CSS_PC:
  48. return SVG_LENGTHTYPE_PC;
  49. case CSS_PERCENTAGE:
  50. return SVG_LENGTHTYPE_PERCENTAGE;
  51. case CSS_PT:
  52. return SVG_LENGTHTYPE_PT;
  53. case CSS_PX:
  54. return SVG_LENGTHTYPE_PX;
  55. case CSS_NUMBER:
  56. case CSS_DIMENSION:
  57. return SVG_LENGTHTYPE_NUMBER;
  58. default:
  59. return SVG_LENGTHTYPE_UNKNOWN;
  60. }
  61. }
  62. -(void) newValueSpecifiedUnits:(SVG_LENGTH_TYPE) unitType valueInSpecifiedUnits:(float) valueInSpecifiedUnits
  63. {
  64. NSAssert(FALSE, @"Not supported yet");
  65. }
  66. -(void) convertToSpecifiedUnits:(SVG_LENGTH_TYPE) unitType
  67. {
  68. NSAssert(FALSE, @"Not supported yet");
  69. }
  70. /** Apple calls this method when the class is loaded; that's as good a time as any to calculate the device / screen's PPI */
  71. +(void)initialize
  72. {
  73. cachedDevicePixelsPerInch = [self pixelsPerInchForCurrentDevice];
  74. }
  75. +(SVGLength*) svgLengthZero
  76. {
  77. SVGLength* result = [[SVGLength alloc] initWithCSSPrimitiveValue:nil];
  78. return result;
  79. }
  80. static float cachedDevicePixelsPerInch;
  81. +(SVGLength*) svgLengthFromNSString:(NSString*) s
  82. {
  83. CSSPrimitiveValue* pv = [[CSSPrimitiveValue alloc] init];
  84. pv.pixelsPerInch = cachedDevicePixelsPerInch;
  85. pv.cssText = s;
  86. SVGLength* result = [[SVGLength alloc] initWithCSSPrimitiveValue:pv];
  87. return result;
  88. }
  89. -(float) pixelsValue
  90. {
  91. return [self.internalCSSPrimitiveValue getFloatValue:CSS_PX];
  92. }
  93. -(float) pixelsValueWithDimension:(float)dimension
  94. {
  95. if (self.internalCSSPrimitiveValue.primitiveType == CSS_PERCENTAGE)
  96. return dimension * self.value / 100.0;
  97. return [self pixelsValue];
  98. }
  99. -(float) pixelsValueWithGradientDimension:(float)dimension
  100. {
  101. if (self.internalCSSPrimitiveValue.primitiveType == CSS_PERCENTAGE) {
  102. return dimension * self.value / 100.0;
  103. } else if (self.internalCSSPrimitiveValue.primitiveType == CSS_NUMBER) {
  104. if (self.value >= 0 && self.value <= 1) {
  105. return dimension * self.value;
  106. }
  107. }
  108. return [self pixelsValue];
  109. }
  110. -(float) numberValue
  111. {
  112. return [self.internalCSSPrimitiveValue getFloatValue:CSS_NUMBER];
  113. }
  114. #pragma mark - secret methods needed to provide an implementation on ObjectiveC
  115. +(float) pixelsPerInchForCurrentDevice
  116. {
  117. /** Using this as reference: http://en.wikipedia.org/wiki/Retina_Display and https://www.theiphonewiki.com/wiki/Models
  118. */
  119. size_t size;
  120. sysctlbyname("hw.machine", NULL, &size, NULL, 0);
  121. char *machine = malloc(size);
  122. sysctlbyname("hw.machine", machine, &size, NULL, 0);
  123. NSString *platform = [NSString stringWithUTF8String:machine];
  124. free(machine);
  125. if( [platform hasPrefix:@"iPhone1"]
  126. || [platform hasPrefix:@"iPhone2"]
  127. || [platform hasPrefix:@"iPhone3"])
  128. return 163.0f;
  129. if( [platform hasPrefix:@"iPhone4"]
  130. || [platform hasPrefix:@"iPhone5"]
  131. || [platform hasPrefix:@"iPhone6"]
  132. || [platform hasPrefix:@"iPhone7,2"]
  133. || [platform hasPrefix:@"iPhone8,1"]
  134. || [platform hasPrefix:@"iPhone8,4"]
  135. || [platform hasPrefix:@"iPhone9,1"]
  136. || [platform hasPrefix:@"iPhone9,3"]) {
  137. return 326.0f;
  138. }
  139. if ( [platform hasPrefix:@"iPhone7,1"]
  140. || [platform hasPrefix:@"iPhone8,2"]
  141. || [platform hasPrefix:@"iPhone9,2"]
  142. || [platform hasPrefix:@"iPhone9,4"]) {
  143. return 401.0f;
  144. }
  145. if( [platform hasPrefix:@"iPhone"]) // catch-all for higher-end devices not yet existing
  146. {
  147. NSAssert(FALSE, @"Update your source code or disable assertions: you are using an iPhone that didn't exist when this code was written, we have no idea what the pixel count per inch is!");
  148. return 401.0f;
  149. }
  150. if( [platform hasPrefix:@"iPod1"]
  151. || [platform hasPrefix:@"iPod2"]
  152. || [platform hasPrefix:@"iPod3"])
  153. return 163.0f;
  154. if( [platform hasPrefix:@"iPod4"]
  155. || [platform hasPrefix:@"iPod5"]
  156. || [platform hasPrefix:@"iPod7"])
  157. return 326.0f;
  158. if( [platform hasPrefix:@"iPod"]) // catch-all for higher-end devices not yet existing
  159. {
  160. NSAssert(FALSE, @"Update your source code or disable assertions: you are using an iPod that didn't exist when this code was written, we have no idea what the pixel count per inch is!");
  161. return 326.0f;
  162. }
  163. if( [platform hasPrefix:@"iPad5,1"]
  164. || [platform hasPrefix:@"iPad5,2"])
  165. return 326.0f;
  166. if( [platform hasPrefix:@"iPad1"]
  167. || [platform hasPrefix:@"iPad2"])
  168. return 132.0f;
  169. if( [platform hasPrefix:@"iPad3"]
  170. || [platform hasPrefix:@"iPad4"]
  171. || [platform hasPrefix:@"iPad5,3"]
  172. || [platform hasPrefix:@"iPad5,4"]
  173. || [platform hasPrefix:@"iPad6"]
  174. || [platform hasPrefix:@"iPad7"]
  175. || [platform hasPrefix:@"iPad8"])
  176. return 264.0f;
  177. if( [platform hasPrefix:@"iPad"]) // catch-all for higher-end devices not yet existing
  178. {
  179. NSAssert(FALSE, @"Update your source code or disable assertions: you are using an iPad that didn't exist when this code was written, we have no idea what the pixel count per inch is!");
  180. return 264.0f;
  181. }
  182. if( [platform hasPrefix:@"iWatch1"])
  183. return 326.0f;
  184. if( [platform hasPrefix:@"iWatch"]) // catch-all for higher-end devices not yet existing
  185. {
  186. NSAssert(FALSE, @"Update your source code or disable assertions: you are using an iWatch that didn't exist when this code was written, we have no idea what the pixel count per inch is!");
  187. return 326.0f;
  188. }
  189. if( [platform hasPrefix:@"x86_64"])
  190. {
  191. SVGKitLogWarn(@"[%@] WARNING: you are running on the simulator; it's impossible for us to calculate centimeter/millimeter/inches units correctly", [self class]);
  192. return 132.0f; // Simulator, running on desktop machine
  193. }
  194. NSAssert(FALSE, @"Cannot determine the PPI values for current device; returning 0.0f - hopefully this will crash your code (you CANNOT run SVG's that use CM/IN/MM etc until you fix this)" );
  195. return 0.0f; // Bet you'll get a divide by zero here...
  196. }
  197. @end