2019-12-26 15:55:27 +04:00

242 lines
6.8 KiB
Objective-C

#import "SVGLength.h"
#import "CSSPrimitiveValue.h"
#import "CSSPrimitiveValue_ConfigurablePixelsPerInch.h"
#import "SVGUtils.h"
#include <sys/types.h>
#include <sys/sysctl.h>
@interface SVGLength()
@property(nonatomic,strong) CSSPrimitiveValue* internalCSSPrimitiveValue;
@end
@implementation SVGLength
@synthesize unitType;
@synthesize value;
@synthesize valueInSpecifiedUnits;
@synthesize valueAsString;
@synthesize internalCSSPrimitiveValue;
- (id)init
{
NSAssert(FALSE, @"This class must not be init'd. Use the static hepler methods to instantiate it instead");
return nil;
}
- (id)initWithCSSPrimitiveValue:(CSSPrimitiveValue*) pv
{
self = [super init];
if (self) {
self.internalCSSPrimitiveValue = pv;
}
return self;
}
-(float)value
{
return [self.internalCSSPrimitiveValue getFloatValue:self.internalCSSPrimitiveValue.primitiveType];
}
-(SVG_LENGTH_TYPE)unitType
{
switch( self.internalCSSPrimitiveValue.primitiveType )
{
case CSS_CM:
return SVG_LENGTHTYPE_CM;
case CSS_EMS:
return SVG_LENGTHTYPE_EMS;
case CSS_EXS:
return SVG_LENGTHTYPE_EXS;
case CSS_IN:
return SVG_LENGTHTYPE_IN;
case CSS_MM:
return SVG_LENGTHTYPE_MM;
case CSS_PC:
return SVG_LENGTHTYPE_PC;
case CSS_PERCENTAGE:
return SVG_LENGTHTYPE_PERCENTAGE;
case CSS_PT:
return SVG_LENGTHTYPE_PT;
case CSS_PX:
return SVG_LENGTHTYPE_PX;
case CSS_NUMBER:
case CSS_DIMENSION:
return SVG_LENGTHTYPE_NUMBER;
default:
return SVG_LENGTHTYPE_UNKNOWN;
}
}
-(void) newValueSpecifiedUnits:(SVG_LENGTH_TYPE) unitType valueInSpecifiedUnits:(float) valueInSpecifiedUnits
{
NSAssert(FALSE, @"Not supported yet");
}
-(void) convertToSpecifiedUnits:(SVG_LENGTH_TYPE) unitType
{
NSAssert(FALSE, @"Not supported yet");
}
/** Apple calls this method when the class is loaded; that's as good a time as any to calculate the device / screen's PPI */
+(void)initialize
{
cachedDevicePixelsPerInch = [self pixelsPerInchForCurrentDevice];
}
+(SVGLength*) svgLengthZero
{
SVGLength* result = [[SVGLength alloc] initWithCSSPrimitiveValue:nil];
return result;
}
static float cachedDevicePixelsPerInch;
+(SVGLength*) svgLengthFromNSString:(NSString*) s
{
CSSPrimitiveValue* pv = [[CSSPrimitiveValue alloc] init];
pv.pixelsPerInch = cachedDevicePixelsPerInch;
pv.cssText = s;
SVGLength* result = [[SVGLength alloc] initWithCSSPrimitiveValue:pv];
return result;
}
-(float) pixelsValue
{
return [self.internalCSSPrimitiveValue getFloatValue:CSS_PX];
}
-(float) pixelsValueWithDimension:(float)dimension
{
if (self.internalCSSPrimitiveValue.primitiveType == CSS_PERCENTAGE)
return dimension * self.value / 100.0;
return [self pixelsValue];
}
-(float) pixelsValueWithGradientDimension:(float)dimension
{
if (self.internalCSSPrimitiveValue.primitiveType == CSS_PERCENTAGE) {
return dimension * self.value / 100.0;
} else if (self.internalCSSPrimitiveValue.primitiveType == CSS_NUMBER) {
if (self.value >= 0 && self.value <= 1) {
return dimension * self.value;
}
}
return [self pixelsValue];
}
-(float) numberValue
{
return [self.internalCSSPrimitiveValue getFloatValue:CSS_NUMBER];
}
#pragma mark - secret methods needed to provide an implementation on ObjectiveC
+(float) pixelsPerInchForCurrentDevice
{
/** Using this as reference: http://en.wikipedia.org/wiki/Retina_Display and https://www.theiphonewiki.com/wiki/Models
*/
size_t size;
sysctlbyname("hw.machine", NULL, &size, NULL, 0);
char *machine = malloc(size);
sysctlbyname("hw.machine", machine, &size, NULL, 0);
NSString *platform = [NSString stringWithUTF8String:machine];
free(machine);
if( [platform hasPrefix:@"iPhone1"]
|| [platform hasPrefix:@"iPhone2"]
|| [platform hasPrefix:@"iPhone3"])
return 163.0f;
if( [platform hasPrefix:@"iPhone4"]
|| [platform hasPrefix:@"iPhone5"]
|| [platform hasPrefix:@"iPhone6"]
|| [platform hasPrefix:@"iPhone7,2"]
|| [platform hasPrefix:@"iPhone8,1"]
|| [platform hasPrefix:@"iPhone8,4"]
|| [platform hasPrefix:@"iPhone9,1"]
|| [platform hasPrefix:@"iPhone9,3"]) {
return 326.0f;
}
if ( [platform hasPrefix:@"iPhone7,1"]
|| [platform hasPrefix:@"iPhone8,2"]
|| [platform hasPrefix:@"iPhone9,2"]
|| [platform hasPrefix:@"iPhone9,4"]) {
return 401.0f;
}
if( [platform hasPrefix:@"iPhone"]) // catch-all for higher-end devices not yet existing
{
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!");
return 401.0f;
}
if( [platform hasPrefix:@"iPod1"]
|| [platform hasPrefix:@"iPod2"]
|| [platform hasPrefix:@"iPod3"])
return 163.0f;
if( [platform hasPrefix:@"iPod4"]
|| [platform hasPrefix:@"iPod5"]
|| [platform hasPrefix:@"iPod7"])
return 326.0f;
if( [platform hasPrefix:@"iPod"]) // catch-all for higher-end devices not yet existing
{
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!");
return 326.0f;
}
if( [platform hasPrefix:@"iPad5,1"]
|| [platform hasPrefix:@"iPad5,2"])
return 326.0f;
if( [platform hasPrefix:@"iPad1"]
|| [platform hasPrefix:@"iPad2"])
return 132.0f;
if( [platform hasPrefix:@"iPad3"]
|| [platform hasPrefix:@"iPad4"]
|| [platform hasPrefix:@"iPad5,3"]
|| [platform hasPrefix:@"iPad5,4"]
|| [platform hasPrefix:@"iPad6"]
|| [platform hasPrefix:@"iPad7"]
|| [platform hasPrefix:@"iPad8"])
return 264.0f;
if( [platform hasPrefix:@"iPad"]) // catch-all for higher-end devices not yet existing
{
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!");
return 264.0f;
}
if( [platform hasPrefix:@"iWatch1"])
return 326.0f;
if( [platform hasPrefix:@"iWatch"]) // catch-all for higher-end devices not yet existing
{
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!");
return 326.0f;
}
if( [platform hasPrefix:@"x86_64"])
{
SVGKitLogWarn(@"[%@] WARNING: you are running on the simulator; it's impossible for us to calculate centimeter/millimeter/inches units correctly", [self class]);
return 132.0f; // Simulator, running on desktop machine
}
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)" );
return 0.0f; // Bet you'll get a divide by zero here...
}
@end