mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-08-08 08:31:13 +00:00
Remove SVGKit, fix drawing
This commit is contained in:
parent
7d686b3716
commit
7c6413ec4a
@ -8,23 +8,10 @@ static_library(
|
||||
"Sources/**/*.c",
|
||||
"Sources/**/*.cpp",
|
||||
]),
|
||||
compiler_flags = [
|
||||
"-DSVGKitLogVerbose(...)=1",
|
||||
"-DSVGKitLogWarn(...)=1",
|
||||
"-DSVGKitLogError(...)=1",
|
||||
"-DSVGKitLogInfo(...)=1",
|
||||
"-I$SDKROOT/usr/include/libxml2",
|
||||
],
|
||||
headers = glob([
|
||||
"Sources/**/*.h",
|
||||
]),
|
||||
exported_headers = glob([
|
||||
"Sources/*.h",
|
||||
]),
|
||||
exported_linker_flags = [
|
||||
"-lxml2",
|
||||
],
|
||||
deps = [
|
||||
"//submodules/GZip:GZip",
|
||||
exported_headers = [
|
||||
"Sources/Svg.h",
|
||||
],
|
||||
)
|
||||
|
@ -1,42 +0,0 @@
|
||||
/*
|
||||
PLEASE NOTE: Apple has made a PRIVATE implementation of this class, and because of their
|
||||
stupid App Store rules they ban everyone else in the world from using a class with the
|
||||
same name. Instead of making the class public, they have stolen it out of the global
|
||||
namespace. This is the wrong thing to do, but we are required to rename our classes
|
||||
because of this.
|
||||
|
||||
SVG-DOM, via Core DOM:
|
||||
|
||||
http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-102161490
|
||||
|
||||
interface DOMImplementation {
|
||||
boolean hasFeature(in DOMString feature,
|
||||
in DOMString version);
|
||||
// Introduced in DOM Level 2:
|
||||
DocumentType createDocumentType(in DOMString qualifiedName,
|
||||
in DOMString publicId,
|
||||
in DOMString systemId)
|
||||
raises(DOMException);
|
||||
// Introduced in DOM Level 2:
|
||||
Document createDocument(in DOMString namespaceURI,
|
||||
in DOMString qualifiedName,
|
||||
in DocumentType doctype)
|
||||
raises(DOMException);
|
||||
};
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "DocumentType.h"
|
||||
|
||||
@interface AppleSucksDOMImplementation : NSObject
|
||||
|
||||
-(BOOL) hasFeature:(NSString*) feature version:(NSString*) version;
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
-(DocumentType*) createDocumentType:(NSString*) qualifiedName publicId:(NSString*) publicId systemId:(NSString*) systemId;
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
-(Document*) createDocument:(NSString*) namespaceURI qualifiedName:(NSString*) qualifiedName doctype:(DocumentType*) doctype;
|
||||
|
||||
@end
|
@ -1,33 +0,0 @@
|
||||
|
||||
#import "AppleSucksDOMImplementation.h"
|
||||
|
||||
@implementation AppleSucksDOMImplementation
|
||||
|
||||
-(BOOL) hasFeature:(NSString*) feature version:(NSString*) version
|
||||
{
|
||||
NSAssert( FALSE, @"Apple has made a private class with the same name as this class - we have to rename it because ObjectiveC sucks, and Apple used a foolish name, so we CANNOT adhere to the spec now" );
|
||||
|
||||
NSAssert( FALSE, @"Not implemented yet" );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
-(DocumentType*) createDocumentType:(NSString*) qualifiedName publicId:(NSString*) publicId systemId:(NSString*) systemId
|
||||
{
|
||||
NSAssert( FALSE, @"Apple has made a private class with the same name as this class - we have to rename it because ObjectiveC sucks, and Apple used a foolish name, so we CANNOT adhere to the spec now" );
|
||||
|
||||
NSAssert( FALSE, @"Not implemented yet" );
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
-(Document*) createDocument:(NSString*) namespaceURI qualifiedName:(NSString*) qualifiedName doctype:(DocumentType*) doctype
|
||||
{
|
||||
NSAssert( FALSE, @"Apple has made a private class with the same name as this class - we have to rename it because ObjectiveC sucks, and Apple used a foolish name, so we CANNOT adhere to the spec now" );
|
||||
|
||||
NSAssert( FALSE, @"Not implemented yet" );
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
@ -1,37 +0,0 @@
|
||||
/*
|
||||
SVG-DOM, via Core DOM:
|
||||
|
||||
http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-637646024
|
||||
|
||||
interface Attr : Node {
|
||||
readonly attribute DOMString name;
|
||||
readonly attribute boolean specified;
|
||||
attribute DOMString value;
|
||||
// raises(DOMException) on setting
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
readonly attribute Element ownerElement;
|
||||
};
|
||||
*/
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
/** objc won't allow this: @class Node;*/
|
||||
#import "Node.h"
|
||||
@class Element;
|
||||
|
||||
@interface Attr : Node
|
||||
|
||||
/*! NB: The official DOM spec FAILS TO SPECIFY what the value of "name" is */
|
||||
@property(nonatomic,strong,readonly) NSString* name;
|
||||
@property(nonatomic,readonly) BOOL specified;
|
||||
@property(nonatomic,strong,readonly) NSString* value;
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
@property(nonatomic,strong,readonly) Element* ownerElement;
|
||||
|
||||
#pragma mark - ObjC methods
|
||||
|
||||
- (id)initWithName:(NSString*) n value:(NSString*) v;
|
||||
- (id)initWithNamespace:(NSString*) ns qualifiedName:(NSString*) qn value:(NSString*) v;
|
||||
|
||||
@end
|
@ -1,54 +0,0 @@
|
||||
//
|
||||
// Attr.m
|
||||
// SVGKit
|
||||
//
|
||||
// Created by adam on 22/05/2012.
|
||||
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import "Attr.h"
|
||||
|
||||
#import "Node+Mutable.h"
|
||||
|
||||
@interface Attr()
|
||||
@property(nonatomic,strong,readwrite) NSString* name;
|
||||
@property(nonatomic,readwrite) BOOL specified;
|
||||
@property(nonatomic,strong,readwrite) NSString* value;
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
@property(nonatomic,strong,readwrite) Element* ownerElement;
|
||||
@end
|
||||
|
||||
@implementation Attr
|
||||
|
||||
@synthesize name;
|
||||
@synthesize specified;
|
||||
@synthesize value;
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
@synthesize ownerElement;
|
||||
|
||||
- (id)initWithName:(NSString*) n value:(NSString*) v
|
||||
{
|
||||
self = [super initType:DOMNodeType_ATTRIBUTE_NODE name:n value:v];
|
||||
if (self)
|
||||
{
|
||||
self.name = n;
|
||||
self.value = v;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithNamespace:(NSString*) ns qualifiedName:(NSString*) qn value:(NSString *)v
|
||||
{
|
||||
self = [super initType:DOMNodeType_ATTRIBUTE_NODE name:qn value:v inNamespace:ns];
|
||||
if (self)
|
||||
{
|
||||
self.name = qn;
|
||||
self.value = v;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
@end
|
@ -1,18 +0,0 @@
|
||||
/*
|
||||
From SVG-DOM, via Core DOM:
|
||||
|
||||
http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-667469212
|
||||
|
||||
interface CDATASection : Text {
|
||||
};
|
||||
*/
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class Text;
|
||||
#import "Text.h"
|
||||
|
||||
@interface CDATASection : Text
|
||||
|
||||
- (id)initWithValue:(NSString*) v;
|
||||
|
||||
@end
|
@ -1,20 +0,0 @@
|
||||
//
|
||||
// CDATASection.m
|
||||
// SVGKit
|
||||
//
|
||||
// Created by adam on 22/05/2012.
|
||||
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import "CDATASection.h"
|
||||
|
||||
@implementation CDATASection
|
||||
|
||||
- (id)initWithValue:(NSString*) v
|
||||
{
|
||||
self = [super initType:DOMNodeType_CDATA_SECTION_NODE name:@"#cdata-section" value:v];
|
||||
if (self) {
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@end
|
@ -1,102 +0,0 @@
|
||||
/**
|
||||
http://www.w3.org/TR/2000/REC-DOM-Level-2-Style-20001113/css.html#CSS-CSSPrimitiveValue
|
||||
|
||||
interface CSSPrimitiveValue : CSSValue {
|
||||
|
||||
// UnitTypes
|
||||
const unsigned short CSS_UNKNOWN = 0;
|
||||
const unsigned short CSS_NUMBER = 1;
|
||||
const unsigned short CSS_PERCENTAGE = 2;
|
||||
const unsigned short CSS_EMS = 3;
|
||||
const unsigned short CSS_EXS = 4;
|
||||
const unsigned short CSS_PX = 5;
|
||||
const unsigned short CSS_CM = 6;
|
||||
const unsigned short CSS_MM = 7;
|
||||
const unsigned short CSS_IN = 8;
|
||||
const unsigned short CSS_PT = 9;
|
||||
const unsigned short CSS_PC = 10;
|
||||
const unsigned short CSS_DEG = 11;
|
||||
const unsigned short CSS_RAD = 12;
|
||||
const unsigned short CSS_GRAD = 13;
|
||||
const unsigned short CSS_MS = 14;
|
||||
const unsigned short CSS_S = 15;
|
||||
const unsigned short CSS_HZ = 16;
|
||||
const unsigned short CSS_KHZ = 17;
|
||||
const unsigned short CSS_DIMENSION = 18;
|
||||
const unsigned short CSS_STRING = 19;
|
||||
const unsigned short CSS_URI = 20;
|
||||
const unsigned short CSS_IDENT = 21;
|
||||
const unsigned short CSS_ATTR = 22;
|
||||
const unsigned short CSS_COUNTER = 23;
|
||||
const unsigned short CSS_RECT = 24;
|
||||
const unsigned short CSS_RGBCOLOR = 25;
|
||||
|
||||
readonly attribute unsigned short primitiveType;
|
||||
void setFloatValue(in unsigned short unitType,
|
||||
in float floatValue)
|
||||
raises(DOMException);
|
||||
float getFloatValue(in unsigned short unitType)
|
||||
raises(DOMException);
|
||||
void setStringValue(in unsigned short stringType,
|
||||
in DOMString stringValue)
|
||||
raises(DOMException);
|
||||
DOMString getStringValue()
|
||||
raises(DOMException);
|
||||
Counter getCounterValue()
|
||||
raises(DOMException);
|
||||
Rect getRectValue()
|
||||
raises(DOMException);
|
||||
RGBColor getRGBColorValue()
|
||||
raises(DOMException);
|
||||
*/
|
||||
#import "CSSValue.h"
|
||||
|
||||
typedef enum CSSPrimitiveType
|
||||
{
|
||||
CSS_UNKNOWN = 0,
|
||||
CSS_NUMBER = 1,
|
||||
CSS_PERCENTAGE = 2,
|
||||
CSS_EMS = 3,
|
||||
CSS_EXS = 4,
|
||||
CSS_PX = 5,
|
||||
CSS_CM = 6,
|
||||
CSS_MM = 7,
|
||||
CSS_IN = 8,
|
||||
CSS_PT = 9,
|
||||
CSS_PC = 10,
|
||||
CSS_DEG = 11,
|
||||
CSS_RAD = 12,
|
||||
CSS_GRAD = 13,
|
||||
CSS_MS = 14,
|
||||
CSS_S = 15,
|
||||
CSS_HZ = 16,
|
||||
CSS_KHZ = 17,
|
||||
CSS_DIMENSION = 18,
|
||||
CSS_STRING = 19,
|
||||
CSS_URI = 20,
|
||||
CSS_IDENT = 21,
|
||||
CSS_ATTR = 22,
|
||||
CSS_COUNTER = 23,
|
||||
CSS_RECT = 24,
|
||||
CSS_RGBCOLOR = 25
|
||||
} CSSPrimitiveType;
|
||||
|
||||
@interface CSSPrimitiveValue : CSSValue
|
||||
|
||||
@property(nonatomic) CSSPrimitiveType primitiveType;
|
||||
|
||||
-(void) setFloatValue:(CSSPrimitiveType) unitType floatValue:(float) floatValue;
|
||||
|
||||
-(float) getFloatValue:(CSSPrimitiveType) unitType;
|
||||
|
||||
-(void) setStringValue:(CSSPrimitiveType) stringType stringValue:(NSString*) stringValue;
|
||||
|
||||
-(NSString*) getStringValue;
|
||||
|
||||
-(/* FIXME: have to add this type: Counter*/ void) getCounterValue;
|
||||
|
||||
-(/* FIXME: have to add this type: Rect*/ void) getRectValue;
|
||||
|
||||
-(/* FIXME: have to add this type: RGBColor*/ void) getRGBColorValue;
|
||||
|
||||
@end
|
@ -1,296 +0,0 @@
|
||||
#import "CSSPrimitiveValue.h"
|
||||
#import "CSSValue_ForSubclasses.h"
|
||||
#import "CSSPrimitiveValue_ConfigurablePixelsPerInch.h"
|
||||
|
||||
#import "DOMGlobalSettings.h"
|
||||
|
||||
#define INCHES_PER_CENTIMETRE ( 0.393700787f )
|
||||
#define INCHES_PER_MILLIMETER ( 0.0393701f )
|
||||
|
||||
@interface CSSPrimitiveValue()
|
||||
|
||||
@property(nonatomic) float internalValue;
|
||||
@property(nonatomic,strong) NSString* internalString;
|
||||
|
||||
@end
|
||||
|
||||
@implementation CSSPrimitiveValue
|
||||
|
||||
@synthesize pixelsPerInch;
|
||||
|
||||
@synthesize internalValue;
|
||||
@synthesize internalString;
|
||||
|
||||
@synthesize primitiveType;
|
||||
|
||||
|
||||
- (id)init
|
||||
{
|
||||
self = [super initWithUnitType:CSS_PRIMITIVE_VALUE];
|
||||
if (self) {
|
||||
self.pixelsPerInch = 1.0f; // this can be overridden by classes that import the CSSPrimitiveValue_ConfigurablePixelsPerInch.h header
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
-(void) setFloatValue:(CSSPrimitiveType) unitType floatValue:(float) floatValue
|
||||
{
|
||||
self.primitiveType = unitType;
|
||||
self.internalValue = floatValue;
|
||||
|
||||
self.internalString = nil;
|
||||
}
|
||||
|
||||
-(float) getFloatValue:(CSSPrimitiveType) unitType
|
||||
{
|
||||
/** Easy case: you're asking for the same unit as the originally stored units */
|
||||
if( unitType == self.primitiveType )
|
||||
return self.internalValue;
|
||||
|
||||
switch( self.primitiveType )
|
||||
{
|
||||
case CSS_UNKNOWN:
|
||||
{
|
||||
if( self.internalValue == 0.0f )
|
||||
return self.internalValue;
|
||||
else
|
||||
{
|
||||
NSAssert( FALSE, @"Asked to convert a UNKNOWN value to a different type (%i)", unitType );
|
||||
}
|
||||
}
|
||||
|
||||
case CSS_CM:
|
||||
case CSS_IN:
|
||||
case CSS_MM:
|
||||
case CSS_PT:
|
||||
case CSS_PC:
|
||||
{
|
||||
float valueAsInches;
|
||||
switch( self.primitiveType )
|
||||
{
|
||||
case CSS_CM:
|
||||
{
|
||||
valueAsInches = self.internalValue * INCHES_PER_CENTIMETRE;
|
||||
}break;
|
||||
case CSS_MM:
|
||||
{
|
||||
valueAsInches = self.internalValue * INCHES_PER_MILLIMETER;
|
||||
}break;
|
||||
case CSS_PT:
|
||||
{
|
||||
valueAsInches = self.internalValue / 72.0f;
|
||||
}break;
|
||||
case CSS_PC:
|
||||
{
|
||||
valueAsInches = self.internalValue * 12.0f / 72.0f;
|
||||
}break;
|
||||
case CSS_IN:
|
||||
{
|
||||
valueAsInches = self.internalValue;
|
||||
}break;
|
||||
|
||||
default:
|
||||
{
|
||||
valueAsInches = 0;
|
||||
NSAssert( FALSE, @"This line is impossible but Apple's compiler is crap" );
|
||||
}
|
||||
}
|
||||
|
||||
switch( unitType )
|
||||
{
|
||||
case CSS_CM:
|
||||
{
|
||||
return valueAsInches / INCHES_PER_CENTIMETRE;
|
||||
}break;
|
||||
case CSS_MM:
|
||||
{
|
||||
return valueAsInches / INCHES_PER_MILLIMETER;
|
||||
}break;
|
||||
case CSS_PT:
|
||||
{
|
||||
return valueAsInches * 72.0f;
|
||||
}break;
|
||||
case CSS_PC:
|
||||
{
|
||||
return valueAsInches / 12.0f * 72.0f;
|
||||
}break;
|
||||
case CSS_PX:
|
||||
{
|
||||
return valueAsInches * self.pixelsPerInch;
|
||||
}break;
|
||||
|
||||
default:
|
||||
{
|
||||
NSAssert( FALSE, @"Asked to convert a value in centimetres to an incompatible unit type (%i)", unitType );
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
case CSS_DEG:
|
||||
case CSS_GRAD:
|
||||
case CSS_RAD:
|
||||
{
|
||||
NSAssert( FALSE, @"Asked to convert an Angle value to a different type (NO conversions for this type are currently supported) (%i)", unitType );
|
||||
} break;
|
||||
|
||||
case CSS_COUNTER:
|
||||
{
|
||||
NSAssert( FALSE, @"Asked to convert a Counter value to a different type (NO conversions for this type are currently supported) (%i)", unitType );
|
||||
} break;
|
||||
|
||||
case CSS_DIMENSION:
|
||||
{
|
||||
NSAssert( FALSE, @"Asked to convert a Dimension value to a different type (NO conversions for this type are currently supported) (%i)", unitType );
|
||||
} break;
|
||||
|
||||
case CSS_EMS:
|
||||
case CSS_EXS:
|
||||
case CSS_PX:
|
||||
{
|
||||
NSAssert( FALSE, @"Asked to convert a Relative Length value to a different type (NO conversions for this type are currently supported) (%i)", unitType );
|
||||
}break;
|
||||
|
||||
case CSS_HZ:
|
||||
case CSS_MS:
|
||||
case CSS_KHZ:
|
||||
case CSS_S:
|
||||
{
|
||||
NSAssert( FALSE, @"Asked to convert a Time or Frequency value to a different type (NO conversions for this type are currently supported) (%i)", unitType );
|
||||
}break;
|
||||
|
||||
case CSS_NUMBER:
|
||||
{
|
||||
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... */
|
||||
{
|
||||
return self.internalValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
NSAssert( FALSE, @"Asked to convert a Number to a different type (NO conversions for this type are currently supported) (%i)", unitType );
|
||||
}
|
||||
}break;
|
||||
|
||||
case CSS_PERCENTAGE:
|
||||
{
|
||||
if( unitType == CSS_NUMBER )
|
||||
{
|
||||
return self.internalValue / 100.0f; // convert percentages to values from 0.0 - 1.0
|
||||
}
|
||||
else
|
||||
NSAssert( FALSE, @"Asked to convert a Percentage value to a different type (%i)", unitType );
|
||||
}break;
|
||||
|
||||
default:
|
||||
{
|
||||
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 );
|
||||
}
|
||||
}
|
||||
|
||||
return 0.0f; // this will never happen. you should have Asserted by now, or else returned early with the correct value
|
||||
}
|
||||
|
||||
-(void) setStringValue:(CSSPrimitiveType) stringType stringValue:(NSString*) stringValue
|
||||
{
|
||||
self.primitiveType = stringType;
|
||||
self.internalString = stringValue;
|
||||
|
||||
self.internalValue = 0.0f;
|
||||
}
|
||||
|
||||
-(NSString*) getStringValue
|
||||
{
|
||||
return self.internalString;
|
||||
}
|
||||
|
||||
-(/* FIXME: have to add this type: Counter*/ void) getCounterValue
|
||||
{
|
||||
NSAssert(FALSE, @"This method not supported");
|
||||
}
|
||||
|
||||
-(/* FIXME: have to add this type: Rect*/ void) getRectValue
|
||||
{
|
||||
NSAssert(FALSE, @"This method not supported");
|
||||
}
|
||||
|
||||
-(/* FIXME: have to add this type: RGBColor*/ void) getRGBColorValue
|
||||
{
|
||||
NSAssert(FALSE, @"This method not supported");
|
||||
}
|
||||
|
||||
#pragma mark - non DOM spec methods needed to implement Objective-C code for this class
|
||||
|
||||
-(void)setCssText:(NSString *)newCssText
|
||||
{
|
||||
_cssText = newCssText;
|
||||
|
||||
/** the css text value has been set, so we need to split the elements up and save them in the internal array */
|
||||
if( _cssText == nil
|
||||
|| _cssText.length == 0 )
|
||||
{
|
||||
self.internalValue = 0.0f;
|
||||
self.internalString = @"";
|
||||
self.primitiveType = CSS_UNKNOWN;
|
||||
}
|
||||
else if( [_cssText hasSuffix:@"%"])
|
||||
[self setFloatValue:CSS_PERCENTAGE floatValue:[_cssText floatValue]];
|
||||
else if( [_cssText hasSuffix:@"em"])
|
||||
[self setFloatValue:CSS_EMS floatValue:[_cssText floatValue]];
|
||||
else if( [_cssText hasSuffix:@"ex"])
|
||||
[self setFloatValue:CSS_EXS floatValue:[_cssText floatValue]];
|
||||
else if( [_cssText hasSuffix:@"px"])
|
||||
[self setFloatValue:CSS_PX floatValue:[_cssText floatValue]];
|
||||
else if( [_cssText hasSuffix:@"cm"])
|
||||
[self setFloatValue:CSS_CM floatValue:[_cssText floatValue]];
|
||||
else if( [_cssText hasSuffix:@"mm"])
|
||||
[self setFloatValue:CSS_MM floatValue:[_cssText floatValue]];
|
||||
else if( [_cssText hasSuffix:@"in"])
|
||||
[self setFloatValue:CSS_IN floatValue:[_cssText floatValue]];
|
||||
else if( [_cssText hasSuffix:@"pt"])
|
||||
[self setFloatValue:CSS_PT floatValue:[_cssText floatValue]];
|
||||
else if( [_cssText hasSuffix:@"pc"])
|
||||
[self setFloatValue:CSS_PC floatValue:[_cssText floatValue]];
|
||||
else if( [_cssText hasSuffix:@"deg"])
|
||||
[self setFloatValue:CSS_DEG floatValue:[_cssText floatValue]];
|
||||
else if( [_cssText hasSuffix:@"rad"])
|
||||
[self setFloatValue:CSS_RAD floatValue:[_cssText floatValue]];
|
||||
else if( [_cssText hasSuffix:@"grad"])
|
||||
[self setFloatValue:CSS_GRAD floatValue:[_cssText floatValue]];
|
||||
else if( [_cssText hasSuffix:@"ms"])
|
||||
[self setFloatValue:CSS_MS floatValue:[_cssText floatValue]];
|
||||
else if( [_cssText hasSuffix:@"s"])
|
||||
[self setFloatValue:CSS_S floatValue:[_cssText floatValue]];
|
||||
else if( [_cssText hasSuffix:@"khz"]) // -----------NB: check this before checking HZ !
|
||||
[self setFloatValue:CSS_KHZ floatValue:[_cssText floatValue]];
|
||||
else if( [_cssText hasSuffix:@"hz"])
|
||||
[self setFloatValue:CSS_HZ floatValue:[_cssText floatValue]];
|
||||
else
|
||||
{
|
||||
/**
|
||||
Three possible outcomes left:
|
||||
|
||||
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")
|
||||
2. It's a string, one of many different CSS string types
|
||||
3. It's a corrupt file
|
||||
*/
|
||||
|
||||
/**
|
||||
NSScaner is an Apple class that SPECIFICALLY will refuse to return a number if there are any non-numberic characters in the string */
|
||||
NSScanner *scanner = [NSScanner scannerWithString: _cssText];
|
||||
float floatToHoldTheOutput;
|
||||
if( [scanner scanFloat:&floatToHoldTheOutput])
|
||||
{
|
||||
/* Option 1: it's a pure number */
|
||||
[self setFloatValue:CSS_NUMBER floatValue:floatToHoldTheOutput];
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Option 2: it's a string - or corrupt, which we're not going to handle here */
|
||||
#if DEBUG_DOM_PARSING
|
||||
SVGKitLogVerbose(@"[%@] WARNING: not bothering to work out 'what kind of CSS string' this string is. CSS is stupid. String = %@", [self class], _cssText );
|
||||
#endif
|
||||
[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...
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
@ -1,7 +0,0 @@
|
||||
#import "CSSPrimitiveValue.h"
|
||||
|
||||
@interface CSSPrimitiveValue ()
|
||||
|
||||
@property(nonatomic) float pixelsPerInch;
|
||||
|
||||
@end
|
@ -1,45 +0,0 @@
|
||||
/**
|
||||
http://www.w3.org/TR/2000/REC-DOM-Level-2-Style-20001113/css.html#CSS-CSSRule
|
||||
|
||||
interface CSSRule {
|
||||
|
||||
// RuleType
|
||||
const unsigned short UNKNOWN_RULE = 0;
|
||||
const unsigned short STYLE_RULE = 1;
|
||||
const unsigned short CHARSET_RULE = 2;
|
||||
const unsigned short IMPORT_RULE = 3;
|
||||
const unsigned short MEDIA_RULE = 4;
|
||||
const unsigned short FONT_FACE_RULE = 5;
|
||||
const unsigned short PAGE_RULE = 6;
|
||||
|
||||
readonly attribute unsigned short type;
|
||||
attribute DOMString cssText;
|
||||
// raises(DOMException) on setting
|
||||
|
||||
readonly attribute CSSStyleSheet parentStyleSheet;
|
||||
readonly attribute CSSRule parentRule;
|
||||
*/
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class CSSStyleSheet;
|
||||
|
||||
typedef enum CSSRuleType
|
||||
{
|
||||
UNKNOWN_RULE = 0,
|
||||
STYLE_RULE = 1,
|
||||
CHARSET_RULE = 2,
|
||||
IMPORT_RULE = 3,
|
||||
MEDIA_RULE = 4,
|
||||
FONT_FACE_RULE = 5,
|
||||
PAGE_RULE = 6
|
||||
} CSSRuleType;
|
||||
|
||||
@interface CSSRule : NSObject
|
||||
|
||||
@property(nonatomic) unsigned short type;
|
||||
@property(nonatomic,strong) NSString* cssText;
|
||||
|
||||
@property(nonatomic,strong) CSSStyleSheet* parentStyleSheet;
|
||||
@property(nonatomic,strong) CSSRule* parentRule;
|
||||
|
||||
@end
|
@ -1,12 +0,0 @@
|
||||
#import "CSSRule.h"
|
||||
|
||||
@implementation CSSRule
|
||||
|
||||
@synthesize type;
|
||||
@synthesize cssText;
|
||||
|
||||
@synthesize parentStyleSheet;
|
||||
@synthesize parentRule;
|
||||
|
||||
|
||||
@end
|
@ -1,7 +0,0 @@
|
||||
#import "CSSRuleList.h"
|
||||
|
||||
@interface CSSRuleList ()
|
||||
|
||||
@property(nonatomic,strong) NSMutableArray* internalArray;
|
||||
|
||||
@end
|
@ -1,18 +0,0 @@
|
||||
/**
|
||||
http://www.w3.org/TR/2000/REC-DOM-Level-2-Style-20001113/css.html#CSS-CSSRuleList
|
||||
|
||||
interface CSSRuleList {
|
||||
readonly attribute unsigned long length;
|
||||
CSSRule item(in unsigned long index);
|
||||
*/
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "CSSRule.h"
|
||||
|
||||
@interface CSSRuleList : NSObject
|
||||
|
||||
@property(nonatomic,readonly) unsigned long length;
|
||||
|
||||
-(CSSRule*) item:(unsigned long) index;
|
||||
|
||||
@end
|
@ -1,33 +0,0 @@
|
||||
#import "CSSRuleList.h"
|
||||
#import "CSSRuleList+Mutable.h"
|
||||
|
||||
@implementation CSSRuleList
|
||||
|
||||
@synthesize internalArray;
|
||||
|
||||
|
||||
- (id)init
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
self.internalArray = [NSMutableArray array];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
-(unsigned long)length
|
||||
{
|
||||
return self.internalArray.count;
|
||||
}
|
||||
|
||||
-(CSSRule *)item:(unsigned long)index
|
||||
{
|
||||
return [self.internalArray objectAtIndex:index];
|
||||
}
|
||||
|
||||
-(NSString *)description
|
||||
{
|
||||
return [NSString stringWithFormat:@"CSSRuleList: array(%@)", self.internalArray];
|
||||
}
|
||||
|
||||
@end
|
@ -1,49 +0,0 @@
|
||||
/**
|
||||
http://www.w3.org/TR/2000/REC-DOM-Level-2-Style-20001113/css.html#CSS-CSSStyleDeclaration
|
||||
|
||||
interface CSSStyleDeclaration {
|
||||
attribute DOMString cssText;
|
||||
// raises(DOMException) on setting
|
||||
|
||||
DOMString getPropertyValue(in DOMString propertyName);
|
||||
CSSValue getPropertyCSSValue(in DOMString propertyName);
|
||||
DOMString removeProperty(in DOMString propertyName)
|
||||
raises(DOMException);
|
||||
DOMString getPropertyPriority(in DOMString propertyName);
|
||||
void setProperty(in DOMString propertyName,
|
||||
in DOMString value,
|
||||
in DOMString priority)
|
||||
raises(DOMException);
|
||||
readonly attribute unsigned long length;
|
||||
DOMString item(in unsigned long index);
|
||||
readonly attribute CSSRule parentRule;
|
||||
*/
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "CSSValue.h"
|
||||
#import "CSSRule.h"
|
||||
|
||||
@interface CSSStyleDeclaration : NSObject
|
||||
|
||||
/** NOTE: requires special treatment!
|
||||
|
||||
From spec:
|
||||
|
||||
"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."
|
||||
*/
|
||||
@property(nonatomic,strong) NSString* cssText;
|
||||
|
||||
-(NSString*) getPropertyValue:(NSString*) propertyName;
|
||||
-(CSSValue*) getPropertyCSSValue:(NSString*) propertyName;
|
||||
-(NSString*) removeProperty:(NSString*) propertyName;
|
||||
|
||||
-(NSString*) getPropertyPriority:(NSString*) propertyName;
|
||||
-(void) setProperty:(NSString*) propertyName value:(NSString*) value priority:(NSString*) priority;
|
||||
|
||||
@property(nonatomic) unsigned long length;
|
||||
|
||||
-(NSString*) item:(long) index;
|
||||
|
||||
@property(nonatomic,strong) CSSRule* parentRule;
|
||||
|
||||
@end
|
@ -1,162 +0,0 @@
|
||||
#import "CSSStyleDeclaration.h"
|
||||
|
||||
#import "CSSValue.h"
|
||||
#import "CSSValueList.h"
|
||||
#import "CSSPrimitiveValue.h"
|
||||
|
||||
@interface CSSStyleDeclaration()
|
||||
|
||||
@property(nonatomic,strong) NSMutableDictionary* internalDictionaryOfStylesByCSSClass;
|
||||
|
||||
@end
|
||||
|
||||
@implementation CSSStyleDeclaration
|
||||
|
||||
@synthesize internalDictionaryOfStylesByCSSClass;
|
||||
|
||||
@synthesize cssText = _cssText;
|
||||
@synthesize length;
|
||||
@synthesize parentRule;
|
||||
|
||||
|
||||
- (id)init
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
self.internalDictionaryOfStylesByCSSClass = [NSMutableDictionary dictionary];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#define MAX_ACCUM 256
|
||||
#define MAX_NAME 256
|
||||
|
||||
/** From spec:
|
||||
|
||||
"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."
|
||||
*/
|
||||
-(void)setCssText:(NSString *)newCSSText
|
||||
{
|
||||
_cssText = newCSSText;
|
||||
|
||||
/** and now post-process it, *as required by* the CSS/DOM spec... */
|
||||
NSMutableDictionary* processedStyles = [self NSDictionaryFromCSSAttributes:_cssText];
|
||||
|
||||
self.internalDictionaryOfStylesByCSSClass = processedStyles;
|
||||
|
||||
}
|
||||
|
||||
-(NSMutableDictionary *) NSDictionaryFromCSSAttributes: (NSString *)css {
|
||||
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
|
||||
NSCharacterSet* trimChars = [NSCharacterSet whitespaceAndNewlineCharacterSet];
|
||||
|
||||
const char *cstr = [css UTF8String];
|
||||
size_t len = strlen(cstr);
|
||||
|
||||
char name[MAX_NAME];
|
||||
bzero(name, MAX_NAME);
|
||||
|
||||
char accum[MAX_ACCUM];
|
||||
bzero(accum, MAX_ACCUM);
|
||||
|
||||
size_t accumIdx = 0;
|
||||
|
||||
for (size_t n = 0; n <= len; n++) {
|
||||
char c = cstr[n];
|
||||
|
||||
if (c == ':') {
|
||||
strncpy(name, accum, MAX_NAME);
|
||||
name[accumIdx] = '\0';
|
||||
|
||||
bzero(accum, MAX_ACCUM);
|
||||
accumIdx = 0;
|
||||
|
||||
continue;
|
||||
}
|
||||
else if (c == ';' || c == '\0') {
|
||||
if( accumIdx > 0 ) //if there is a ';' and '\0' to end the style, avoid adding an empty key-value pair
|
||||
{
|
||||
accum[accumIdx] = '\0';
|
||||
|
||||
NSString *keyString = [[NSString stringWithUTF8String:name]
|
||||
stringByTrimmingCharactersInSet:trimChars];
|
||||
NSString *cssValueString = [[NSString stringWithUTF8String:accum]
|
||||
stringByTrimmingCharactersInSet:trimChars];
|
||||
|
||||
CSSValue *cssValue;
|
||||
if( [cssValueString rangeOfString:@" "].length > 0 )
|
||||
cssValue = [[CSSValueList alloc] init];
|
||||
else
|
||||
cssValue = [[CSSPrimitiveValue alloc] init];
|
||||
cssValue.cssText = cssValueString; // has the side-effect of parsing, if required
|
||||
|
||||
[dict setObject:cssValue
|
||||
forKey:keyString];
|
||||
|
||||
bzero(name, MAX_NAME);
|
||||
|
||||
bzero(accum, MAX_ACCUM);
|
||||
accumIdx = 0;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
accum[accumIdx++] = c;
|
||||
if (accumIdx >= MAX_ACCUM) {
|
||||
SVGKitLogWarn(@"Buffer ovverun while parsing style sheet - skipping");
|
||||
return dict;
|
||||
}
|
||||
}
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
-(NSString*) getPropertyValue:(NSString*) propertyName
|
||||
{
|
||||
CSSValue* v = [self getPropertyCSSValue:propertyName];
|
||||
|
||||
if( v == nil )
|
||||
return nil;
|
||||
else
|
||||
return v.cssText;
|
||||
}
|
||||
|
||||
-(CSSValue*) getPropertyCSSValue:(NSString*) propertyName
|
||||
{
|
||||
return [self.internalDictionaryOfStylesByCSSClass objectForKey:propertyName];
|
||||
}
|
||||
|
||||
-(NSString*) removeProperty:(NSString*) propertyName
|
||||
{
|
||||
NSString* oldValue = [self getPropertyValue:propertyName];
|
||||
[self.internalDictionaryOfStylesByCSSClass removeObjectForKey:propertyName];
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
-(NSString*) getPropertyPriority:(NSString*) propertyName
|
||||
{
|
||||
NSAssert(FALSE, @"CSS 'property priorities' - Not supported");
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
-(void) setProperty:(NSString*) propertyName value:(NSString*) value priority:(NSString*) priority
|
||||
{
|
||||
NSAssert(FALSE, @"CSS 'property priorities' - Not supported");
|
||||
}
|
||||
|
||||
-(NSString*) item:(long) index
|
||||
{
|
||||
/** 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 */
|
||||
NSArray* sortedKeys = [[self.internalDictionaryOfStylesByCSSClass allKeys] sortedArrayUsingSelector:@selector(compare:)];
|
||||
CSSValue* v = [sortedKeys objectAtIndex:index];
|
||||
return v.cssText;
|
||||
}
|
||||
|
||||
-(NSString *)description
|
||||
{
|
||||
return [NSString stringWithFormat:@"CSSStyleDeclaration: dictionary(%@)", self.internalDictionaryOfStylesByCSSClass];
|
||||
}
|
||||
|
||||
@end
|
@ -1,24 +0,0 @@
|
||||
/**
|
||||
http://www.w3.org/TR/2000/REC-DOM-Level-2-Style-20001113/css.html#CSS-CSSStyleRule
|
||||
|
||||
interface CSSStyleRule : CSSRule {
|
||||
attribute DOMString selectorText;
|
||||
// raises(DOMException) on setting
|
||||
|
||||
readonly attribute CSSStyleDeclaration style;
|
||||
*/
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "CSSRule.h"
|
||||
#import "CSSStyleDeclaration.h"
|
||||
|
||||
@interface CSSStyleRule : CSSRule
|
||||
|
||||
@property(nonatomic,strong) NSString* selectorText;
|
||||
@property(nonatomic,strong) CSSStyleDeclaration* style;
|
||||
|
||||
#pragma mark - methods needed for ObjectiveC implementation
|
||||
|
||||
- (id)initWithSelectorText:(NSString*) selector styleText:(NSString*) styleText;
|
||||
|
||||
@end
|
@ -1,37 +0,0 @@
|
||||
|
||||
#import "CSSStyleRule.h"
|
||||
|
||||
@implementation CSSStyleRule
|
||||
|
||||
@synthesize selectorText;
|
||||
@synthesize style;
|
||||
|
||||
|
||||
- (id)init
|
||||
{
|
||||
NSAssert(FALSE, @"Can't be init'd, use the right method, idiot");
|
||||
return nil;
|
||||
}
|
||||
|
||||
#pragma mark - methods needed for ObjectiveC implementation
|
||||
|
||||
- (id)initWithSelectorText:(NSString*) selector styleText:(NSString*) styleText;
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
self.selectorText = selector;
|
||||
|
||||
CSSStyleDeclaration* styleDeclaration = [[CSSStyleDeclaration alloc] init];
|
||||
styleDeclaration.cssText = styleText;
|
||||
|
||||
self.style = styleDeclaration;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
-(NSString *)description
|
||||
{
|
||||
return [NSString stringWithFormat:@"%@ : { %@ }", self.selectorText, self.style ];
|
||||
}
|
||||
|
||||
@end
|
@ -1,31 +0,0 @@
|
||||
/**
|
||||
http://www.w3.org/TR/2000/REC-DOM-Level-2-Style-20001113/css.html#CSS-CSSStyleSheet
|
||||
|
||||
interface CSSStyleSheet : stylesheets::StyleSheet {
|
||||
readonly attribute CSSRule ownerRule;
|
||||
readonly attribute CSSRuleList cssRules;
|
||||
unsigned long insertRule(in DOMString rule,
|
||||
in unsigned long index)
|
||||
raises(DOMException);
|
||||
void deleteRule(in unsigned long index)
|
||||
raises(DOMException);
|
||||
*/
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "CSSRule.h"
|
||||
#import "CSSRuleList.h"
|
||||
|
||||
@interface CSSStyleSheet : NSObject
|
||||
|
||||
|
||||
@property(nonatomic,strong) CSSRule* ownerRule;
|
||||
@property(nonatomic,strong) CSSRuleList* cssRules;
|
||||
|
||||
-(long) insertRule:(NSString*) rule index:(unsigned long) index;
|
||||
-(void) deleteRule:(unsigned long) index;
|
||||
|
||||
#pragma mark - methods needed for ObjectiveC implementation
|
||||
|
||||
- (id)initWithString:(NSString*) styleSheetBody;
|
||||
|
||||
@end
|
@ -1,92 +0,0 @@
|
||||
#import "CSSStyleSheet.h"
|
||||
|
||||
#import "CSSRuleList+Mutable.h"
|
||||
|
||||
#import "CSSStyleRule.h"
|
||||
|
||||
@implementation CSSStyleSheet
|
||||
|
||||
@synthesize ownerRule;
|
||||
@synthesize cssRules;
|
||||
|
||||
|
||||
/**
|
||||
Used to insert a new rule into the style sheet. The new rule now becomes part of the cascade.
|
||||
|
||||
Parameters
|
||||
|
||||
rule of type DOMString
|
||||
The parsable text representing the rule. For rule sets this contains both the selector and the style declaration. For at-rules, this specifies both the at-identifier and the rule content.
|
||||
index of type unsigned long
|
||||
The index within the style sheet's rule list of the rule before which to insert the specified rule. If the specified index is equal to the length of the style sheet's rule collection, the rule will be added to the end of the style sheet.
|
||||
|
||||
Return Value
|
||||
|
||||
unsigned long The index within the style sheet's rule collection of the newly inserted rule.
|
||||
*/
|
||||
-(long)insertRule:(NSString *)rule index:(unsigned long)index
|
||||
{
|
||||
if( index == self.cssRules.length )
|
||||
index = self.cssRules.length + 1; // forces it to insert "before the one that doesn't exist" (stupid API design!)
|
||||
|
||||
NSCharacterSet *whitespaceSet = [NSCharacterSet whitespaceAndNewlineCharacterSet];
|
||||
rule = [rule stringByTrimmingCharactersInSet:whitespaceSet];
|
||||
|
||||
// SVGKitLogVerbose(@"A substringie %@", idStyleString);
|
||||
|
||||
NSArray* stringSplitContainer = [rule componentsSeparatedByString:@"{"];
|
||||
if( [stringSplitContainer count] >= 2 ) //not necessary unless using shitty svgs
|
||||
{
|
||||
CSSStyleRule* newRule = [[CSSStyleRule alloc] initWithSelectorText:[stringSplitContainer objectAtIndex:0] styleText:[stringSplitContainer objectAtIndex:1]];
|
||||
|
||||
[self.cssRules.internalArray insertObject:newRule atIndex:index-1]; // CSS says you insert "BEFORE" the index, which is the opposite of most C-based programming languages
|
||||
|
||||
return index-1;
|
||||
}
|
||||
else
|
||||
NSAssert(FALSE, @"No idea what to do here");
|
||||
|
||||
|
||||
return -1; // failed, assert fired!
|
||||
}
|
||||
|
||||
-(void)deleteRule:(unsigned long)index
|
||||
{
|
||||
[self.cssRules.internalArray removeObjectAtIndex:index];
|
||||
}
|
||||
|
||||
#pragma mark - methods needed for ObjectiveC implementation
|
||||
|
||||
- (id)initWithString:(NSString*) styleSheetBody
|
||||
{
|
||||
self = [super init];
|
||||
if (self)
|
||||
{
|
||||
self.cssRules = [[CSSRuleList alloc]init];
|
||||
@autoreleasepool { //creating lots of autoreleased strings, not helpful for older devices
|
||||
|
||||
/**
|
||||
We have to manually handle the "ignore anything that is between / * and * / because those are comments"
|
||||
|
||||
NB: you NEED the NSRegularExpressionDotMatchesLineSeparators argument - which Apple DOES NOT HONOUR in NSString - hence have to use NSRegularExpression
|
||||
*/
|
||||
NSError* error;
|
||||
NSRegularExpression* regexp = [NSRegularExpression regularExpressionWithPattern:@"/\\*.*?\\*/" options: NSRegularExpressionDotMatchesLineSeparators error:&error];
|
||||
styleSheetBody = [regexp stringByReplacingMatchesInString:styleSheetBody options:0 range:NSMakeRange(0,styleSheetBody.length) withTemplate:@""];
|
||||
|
||||
NSArray *classNameAndStyleStrings = [styleSheetBody componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"}"]];
|
||||
for( NSString *idStyleString in classNameAndStyleStrings )
|
||||
{
|
||||
if( [idStyleString length] > 1 ) //not necessary unless using shitty svgs
|
||||
{
|
||||
[self insertRule:idStyleString index:self.cssRules.length];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
@ -1,35 +0,0 @@
|
||||
/**
|
||||
http://www.w3.org/TR/2000/REC-DOM-Level-2-Style-20001113/css.html#CSS-CSSValue
|
||||
|
||||
interface CSSValue {
|
||||
|
||||
// UnitTypes
|
||||
const unsigned short CSS_INHERIT = 0;
|
||||
const unsigned short CSS_PRIMITIVE_VALUE = 1;
|
||||
const unsigned short CSS_VALUE_LIST = 2;
|
||||
const unsigned short CSS_CUSTOM = 3;
|
||||
|
||||
attribute DOMString cssText;
|
||||
// raises(DOMException) on setting
|
||||
|
||||
readonly attribute unsigned short cssValueType;
|
||||
*/
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
typedef enum CSSUnitType
|
||||
{
|
||||
CSS_INHERIT = 0,
|
||||
CSS_PRIMITIVE_VALUE = 1,
|
||||
CSS_VALUE_LIST = 2,
|
||||
CSS_CUSTOM = 3
|
||||
} CSSUnitType;
|
||||
|
||||
@interface CSSValue : NSObject
|
||||
{
|
||||
NSString* _cssText; // for subclasses to manually set
|
||||
}
|
||||
|
||||
@property(nonatomic,strong) NSString* cssText;
|
||||
@property(nonatomic) CSSUnitType cssValueType;
|
||||
|
||||
@end
|
@ -1,25 +0,0 @@
|
||||
#import "CSSValue.h"
|
||||
#import "CSSValue_ForSubclasses.h"
|
||||
|
||||
@implementation CSSValue
|
||||
|
||||
@synthesize cssText = _cssText;
|
||||
@synthesize cssValueType;
|
||||
|
||||
|
||||
- (id)init
|
||||
{
|
||||
NSAssert(FALSE, @"This class cannot be init'd using init. It would break it, badly. Use the correct init call instead (if you don't know what that is, you shouldn't be init'ing this class)");
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (id)initWithUnitType:(CSSUnitType) t
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
self.cssValueType = t;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@end
|
@ -1,17 +0,0 @@
|
||||
/**
|
||||
http://www.w3.org/TR/2000/REC-DOM-Level-2-Style-20001113/css.html#CSS-CSSValueList
|
||||
|
||||
interface CSSValueList : CSSValue {
|
||||
readonly attribute unsigned long length;
|
||||
CSSValue item(in unsigned long index);
|
||||
*/
|
||||
|
||||
#import "CSSValue.h"
|
||||
|
||||
@interface CSSValueList : CSSValue
|
||||
|
||||
@property(nonatomic,readonly) unsigned long length;
|
||||
|
||||
-(CSSValue*) item:(unsigned long) index;
|
||||
|
||||
@end
|
@ -1,46 +0,0 @@
|
||||
#import "CSSValueList.h"
|
||||
#import "CSSValue_ForSubclasses.h"
|
||||
|
||||
@interface CSSValueList()
|
||||
|
||||
@property(nonatomic,strong) NSArray* internalArray;
|
||||
|
||||
@end
|
||||
|
||||
@implementation CSSValueList
|
||||
|
||||
@synthesize internalArray;
|
||||
|
||||
|
||||
- (id)init
|
||||
{
|
||||
self = [super initWithUnitType:CSS_VALUE_LIST];
|
||||
if (self) {
|
||||
self.internalArray = [NSArray array];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
-(unsigned long)length
|
||||
{
|
||||
return self.internalArray.count;
|
||||
}
|
||||
|
||||
-(CSSValue*) item:(unsigned long) index
|
||||
{
|
||||
return [self.internalArray objectAtIndex:index];
|
||||
}
|
||||
|
||||
#pragma mark - non DOM spec methods needed to implement Objective-C code for this class
|
||||
|
||||
-(void)setCssText:(NSString *)newCssText
|
||||
{
|
||||
_cssText = newCssText;
|
||||
|
||||
/** the css text value has been set, so we need to split the elements up and save them in the internal array */
|
||||
SVGKitLogVerbose(@"[%@] received new CSS Text, need to split this and save as CSSValue instances: %@", [self class], _cssText);
|
||||
|
||||
self.internalArray = [_cssText componentsSeparatedByString:@" "];
|
||||
}
|
||||
|
||||
@end
|
@ -1,7 +0,0 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface CSSValue()
|
||||
|
||||
- (id)initWithUnitType:(CSSUnitType) t;
|
||||
|
||||
@end
|
@ -1,48 +0,0 @@
|
||||
/*
|
||||
From SVG-DOM, via Core DOM:
|
||||
|
||||
http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-FF21A306
|
||||
|
||||
interface CharacterData : Node {
|
||||
attribute DOMString data;
|
||||
// raises(DOMException) on setting
|
||||
// raises(DOMException) on retrieval
|
||||
|
||||
readonly attribute unsigned long length;
|
||||
DOMString substringData(in unsigned long offset,
|
||||
in unsigned long count)
|
||||
raises(DOMException);
|
||||
void appendData(in DOMString arg)
|
||||
raises(DOMException);
|
||||
void insertData(in unsigned long offset,
|
||||
in DOMString arg)
|
||||
raises(DOMException);
|
||||
void deleteData(in unsigned long offset,
|
||||
in unsigned long count)
|
||||
raises(DOMException);
|
||||
void replaceData(in unsigned long offset,
|
||||
in unsigned long count,
|
||||
in DOMString arg)
|
||||
raises(DOMException);
|
||||
};
|
||||
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
/** objc won't allow this: @class Node;*/
|
||||
#import "Node.h"
|
||||
|
||||
@interface CharacterData : Node
|
||||
|
||||
@property(nonatomic,strong,readonly) NSString* data;
|
||||
|
||||
@property(nonatomic,readonly) unsigned long length;
|
||||
|
||||
-(NSString*) substringData:(unsigned long) offset count:(unsigned long) count;
|
||||
-(void) appendData:(NSString*) arg;
|
||||
-(void) insertData:(unsigned long) offset arg:(NSString*) arg;
|
||||
-(void) deleteData:(unsigned long) offset count:(unsigned long) count;
|
||||
-(void) replaceData:(unsigned long) offset count:(unsigned long) count arg:(NSString*) arg;
|
||||
|
||||
@end
|
@ -1,41 +0,0 @@
|
||||
//
|
||||
// CharacterData.m
|
||||
// SVGKit
|
||||
//
|
||||
// Created by adam on 22/05/2012.
|
||||
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import "CharacterData.h"
|
||||
|
||||
@implementation CharacterData
|
||||
|
||||
@synthesize data;
|
||||
|
||||
@synthesize length;
|
||||
|
||||
|
||||
-(NSString*) substringData:(unsigned long) offset count:(unsigned long) count
|
||||
{
|
||||
NSAssert( FALSE, @"Not implemented yet" );
|
||||
return nil;
|
||||
}
|
||||
|
||||
-(void) appendData:(NSString*) arg
|
||||
{
|
||||
NSAssert( FALSE, @"Not implemented yet" );
|
||||
}
|
||||
-(void) insertData:(unsigned long) offset arg:(NSString*) arg
|
||||
{
|
||||
NSAssert( FALSE, @"Not implemented yet" );
|
||||
}
|
||||
-(void) deleteData:(unsigned long) offset count:(unsigned long) count
|
||||
{
|
||||
NSAssert( FALSE, @"Not implemented yet" );
|
||||
}
|
||||
-(void) replaceData:(unsigned long) offset count:(unsigned long) count arg:(NSString*) arg
|
||||
{
|
||||
NSAssert( FALSE, @"Not implemented yet" );
|
||||
}
|
||||
|
||||
@end
|
@ -1,21 +0,0 @@
|
||||
/*
|
||||
From SVG-DOM, via Core DOM:
|
||||
|
||||
http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-1728279322
|
||||
|
||||
interface Comment : CharacterData {
|
||||
};
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "CharacterData.h"
|
||||
#ifdef __CARBONCORE__
|
||||
// macOS's out-of-date Carbon API defined the `Comment` struct and cause naming conflict, so we need re-define it and use macro to avoid changing exist API
|
||||
#define Comment SVGKComment
|
||||
#endif
|
||||
@interface Comment : CharacterData
|
||||
|
||||
- (id)initWithValue:(NSString*) v;
|
||||
|
||||
@end
|
@ -1,21 +0,0 @@
|
||||
//
|
||||
// Comment.m
|
||||
// SVGKit
|
||||
//
|
||||
// Created by adam on 22/05/2012.
|
||||
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import "Comment.h"
|
||||
|
||||
@implementation Comment
|
||||
|
||||
- (id)initWithValue:(NSString*) v
|
||||
{
|
||||
self = [super initType:DOMNodeType_COMMENT_NODE name:@"#comment" value:v];
|
||||
if (self) {
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
@ -1 +0,0 @@
|
||||
#define DEBUG_DOM_PARSING 0
|
@ -1,29 +0,0 @@
|
||||
/**
|
||||
There are some shared methods in DOM specification, where two classes have the same method, but
|
||||
are NOT subclass/superclass of each other. This is very bad from OOP design POV, because it means
|
||||
we end up with copy/paste duplicated code, very VERY likely to gain long term bugs.
|
||||
|
||||
Also, those methods REQUIRE a second, recursive, method or else you can't implement them easily.
|
||||
|
||||
So, we move their implementations into this helper class, so they can share implementation.
|
||||
|
||||
(c.f. Element vs Document - identical methods for getElementsByName)
|
||||
*/
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class Node, NodeList, Element; // avoiding #import here, to avoid C header loop problems.
|
||||
|
||||
#define DEBUG_DOM_MATCH_ELEMENTS_IDS_AND_NAMES 0 // For debugging SVGKit: causes debug output on getElementById etc
|
||||
|
||||
@interface DOMHelperUtilities : NSObject
|
||||
|
||||
/*! This useful method provides both the DOM level 1 and the DOM level 2 implementations of searching the tree for a node - because THEY ARE DIFFERENT
|
||||
yet very similar
|
||||
*/
|
||||
+(void) privateGetElementsByName:(NSString*) name inNamespace:(NSString*) namespaceURI childrenOfElement:(Node*) parent addToList:(NodeList*) accumulator;
|
||||
|
||||
/*! This is used in multiple base classes in DOM 1 and DOM 2 where they do NOT have shared superclasses, so we have to implement it here in a separate
|
||||
clas as a standalone method */
|
||||
+(Element*) privateGetElementById:(NSString*) idValue childrenOfElement:(Node*) parent;
|
||||
|
||||
@end
|
@ -1,87 +0,0 @@
|
||||
|
||||
#import "DOMHelperUtilities.h"
|
||||
|
||||
#import "Element.h"
|
||||
#import "NodeList.h"
|
||||
#import "NodeList+Mutable.h" // needed for access to underlying array, because SVG doesnt specify how lists are made mutable
|
||||
|
||||
@implementation DOMHelperUtilities
|
||||
|
||||
/*! This useful method provides both the DOM level 1 and the DOM level 2 implementations of searching the tree for a node - because THEY ARE DIFFERENT
|
||||
yet very similar
|
||||
*/
|
||||
+(void) privateGetElementsByName:(NSString*) name inNamespace:(NSString*) namespaceURI childrenOfElement:(Node*) parent addToList:(NodeList*) accumulator
|
||||
{
|
||||
/** According to spec, this is only valid for ELEMENT nodes */
|
||||
if( [parent isKindOfClass:[Element class]] )
|
||||
{
|
||||
if( namespaceURI != nil && ! [parent.namespaceURI isEqualToString:namespaceURI] )
|
||||
{
|
||||
// skip
|
||||
}
|
||||
else
|
||||
{
|
||||
Element* parentAsElement = (Element*) parent;
|
||||
|
||||
/** According to spec, "tag name" for an Element is the value of its .nodeName property; that means SOMETIMES its a qualified name! */
|
||||
BOOL includeThisNode = FALSE;
|
||||
|
||||
|
||||
if( [name isEqualToString:@"*"] )
|
||||
includeThisNode = TRUE;
|
||||
|
||||
if( !includeThisNode )
|
||||
{
|
||||
if( namespaceURI == nil ) // No namespace? then do a qualified compare
|
||||
{
|
||||
includeThisNode = [parentAsElement.tagName isEqualToString:name];
|
||||
}
|
||||
else // namespace? then do an UNqualified compare
|
||||
{
|
||||
includeThisNode = [parentAsElement.localName isEqualToString:name];
|
||||
}
|
||||
}
|
||||
|
||||
if( includeThisNode )
|
||||
{
|
||||
[accumulator.internalArray addObject:parent];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for( Node* childNode in parent.childNodes )
|
||||
{
|
||||
[self privateGetElementsByName:name inNamespace:namespaceURI childrenOfElement:childNode addToList:accumulator];
|
||||
}
|
||||
}
|
||||
|
||||
+(Element*) privateGetElementById:(NSString*) idValue childrenOfElement:(Node*) parent
|
||||
{
|
||||
/** According to spec, this is only valid for ELEMENT nodes */
|
||||
if( [parent isKindOfClass:[Element class]] )
|
||||
{
|
||||
Element* parentAsElement = (Element*) parent;
|
||||
|
||||
if( [[parentAsElement getAttribute:@"id"] isEqualToString:idValue])
|
||||
return parentAsElement;
|
||||
#if DEBUG_DOM_MATCH_ELEMENTS_IDS_AND_NAMES
|
||||
else
|
||||
{
|
||||
SVGKitLogVerbose(@"parent <%@ id='%@'..> does not match id='%@'", parentAsElement.nodeName, [parentAsElement getAttribute:@"id"], idValue );
|
||||
SVGKitLogVerbose(@"parent <%@ id='%@'..> has %li child nodes = %@", parentAsElement.nodeName, [parentAsElement getAttribute:@"id"], parent.childNodes.length, parent.childNodes );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
for( Node* childNode in parent.childNodes )
|
||||
{
|
||||
Element* childResult = [self privateGetElementById:idValue childrenOfElement:childNode];
|
||||
|
||||
if( childResult != nil )
|
||||
return childResult;
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
@ -1,7 +0,0 @@
|
||||
#import "Document.h"
|
||||
|
||||
@interface Document ()
|
||||
|
||||
@property(nonatomic,strong,readwrite) Element* documentElement;
|
||||
|
||||
@end
|
@ -1,111 +0,0 @@
|
||||
/*
|
||||
// Document.h
|
||||
|
||||
NOT a Cocoa / Apple document,
|
||||
NOT an SVG document,
|
||||
BUT INSTEAD: a DOM document (blame w3.org for the too-generic name).
|
||||
|
||||
Required for SVG-DOM
|
||||
|
||||
c.f.:
|
||||
|
||||
http://www.w3.org/TR/DOM-Level-2-Core/core.html#i-Document
|
||||
|
||||
interface Document : Node {
|
||||
readonly attribute DocumentType doctype;
|
||||
readonly attribute DOMImplementation implementation;
|
||||
readonly attribute Element documentElement;
|
||||
Element createElement(in DOMString tagName)
|
||||
raises(DOMException);
|
||||
DocumentFragment createDocumentFragment();
|
||||
Text createTextNode(in DOMString data);
|
||||
Comment createComment(in DOMString data);
|
||||
CDATASection createCDATASection(in DOMString data)
|
||||
raises(DOMException);
|
||||
ProcessingInstruction createProcessingInstruction(in DOMString target,
|
||||
in DOMString data)
|
||||
raises(DOMException);
|
||||
Attr createAttribute(in DOMString name)
|
||||
raises(DOMException);
|
||||
EntityReference createEntityReference(in DOMString name)
|
||||
raises(DOMException);
|
||||
NodeList getElementsByTagName(in DOMString tagname);
|
||||
// Introduced in DOM Level 2:
|
||||
Node importNode(in Node importedNode,
|
||||
in boolean deep)
|
||||
raises(DOMException);
|
||||
// Introduced in DOM Level 2:
|
||||
Element createElementNS(in DOMString namespaceURI,
|
||||
in DOMString qualifiedName)
|
||||
raises(DOMException);
|
||||
// Introduced in DOM Level 2:
|
||||
Attr createAttributeNS(in DOMString namespaceURI,
|
||||
in DOMString qualifiedName)
|
||||
raises(DOMException);
|
||||
// Introduced in DOM Level 2:
|
||||
NodeList getElementsByTagNameNS(in DOMString namespaceURI,
|
||||
in DOMString localName);
|
||||
// Introduced in DOM Level 2:
|
||||
Element getElementById(in DOMString elementId);
|
||||
};
|
||||
|
||||
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
/** ObjectiveC won't allow this: @class Node; */
|
||||
#import "Node.h"
|
||||
@class Element;
|
||||
#import "Element.h"
|
||||
//@class Comment;
|
||||
#import "Comment.h"
|
||||
@class CDATASection;
|
||||
#import "CDATASection.h"
|
||||
@class DocumentFragment;
|
||||
#import "DocumentFragment.h"
|
||||
@class EntityReference;
|
||||
#import "EntityReference.h"
|
||||
@class NodeList;
|
||||
#import "NodeList.h"
|
||||
@class ProcessingInstruction;
|
||||
#import "ProcessingInstruction.h"
|
||||
@class DocumentType;
|
||||
#import "DocumentType.h"
|
||||
@class AppleSucksDOMImplementation;
|
||||
#import "AppleSucksDOMImplementation.h"
|
||||
|
||||
@interface Document : Node
|
||||
|
||||
@property(nonatomic,strong,readonly) DocumentType* doctype;
|
||||
@property(nonatomic,strong,readonly) AppleSucksDOMImplementation* implementation;
|
||||
@property(nonatomic,strong,readonly) Element* documentElement;
|
||||
|
||||
|
||||
-(Element*) createElement:(NSString*) tagName __attribute__((ns_returns_retained));
|
||||
-(DocumentFragment*) createDocumentFragment __attribute__((ns_returns_retained));
|
||||
-(Text*) createTextNode:(NSString*) data __attribute__((ns_returns_retained));
|
||||
-(Comment*) createComment:(NSString*) data __attribute__((ns_returns_retained));
|
||||
-(CDATASection*) createCDATASection:(NSString*) data __attribute__((ns_returns_retained));
|
||||
-(ProcessingInstruction*) createProcessingInstruction:(NSString*) target data:(NSString*) data __attribute__((ns_returns_retained));
|
||||
-(Attr*) createAttribute:(NSString*) data __attribute__((ns_returns_retained));
|
||||
-(EntityReference*) createEntityReference:(NSString*) data __attribute__((ns_returns_retained));
|
||||
|
||||
-(NodeList*) getElementsByTagName:(NSString*) data;
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
-(Node*) importNode:(Node*) importedNode deep:(BOOL) deep;
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
-(Element*) createElementNS:(NSString*) namespaceURI qualifiedName:(NSString*) qualifiedName __attribute__((ns_returns_retained));
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
-(Attr*) createAttributeNS:(NSString*) namespaceURI qualifiedName:(NSString*) qualifiedName;
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
-(NodeList*) getElementsByTagNameNS:(NSString*) namespaceURI localName:(NSString*) localName;
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
-(Element*) getElementById:(NSString*) elementId;
|
||||
|
||||
@end
|
@ -1,109 +0,0 @@
|
||||
#import "Document.h"
|
||||
#import "Document+Mutable.h"
|
||||
|
||||
#import "DOMHelperUtilities.h"
|
||||
|
||||
#import "NodeList+Mutable.h" // needed for access to underlying array, because SVG doesnt specify how lists are made mutable
|
||||
|
||||
@implementation Document
|
||||
|
||||
@synthesize doctype;
|
||||
@synthesize implementation;
|
||||
@synthesize documentElement;
|
||||
|
||||
|
||||
|
||||
-(Element*) createElement:(NSString*) tagName
|
||||
{
|
||||
Element* newElement = [[Element alloc] initWithLocalName:tagName attributes:nil];
|
||||
|
||||
SVGKitLogVerbose( @"[%@] WARNING: SVG Spec, missing feature: if there are known attributes with default values, Attr nodes representing them SHOULD BE automatically created and attached to the element.", [self class] );
|
||||
|
||||
return newElement;
|
||||
}
|
||||
|
||||
-(DocumentFragment*) createDocumentFragment
|
||||
{
|
||||
return [[DocumentFragment alloc] init];
|
||||
}
|
||||
|
||||
-(Text*) createTextNode:(NSString*) data
|
||||
{
|
||||
return [[Text alloc] initWithValue:data];
|
||||
}
|
||||
|
||||
-(Comment*) createComment:(NSString*) data
|
||||
{
|
||||
return [[Comment alloc] initWithValue:data];
|
||||
}
|
||||
|
||||
-(CDATASection*) createCDATASection:(NSString*) data
|
||||
{
|
||||
return [[CDATASection alloc] initWithValue:data];
|
||||
}
|
||||
|
||||
-(ProcessingInstruction*) createProcessingInstruction:(NSString*) target data:(NSString*) data
|
||||
{
|
||||
return [[ProcessingInstruction alloc] initProcessingInstruction:target value:data];
|
||||
}
|
||||
|
||||
-(Attr*) createAttribute:(NSString*) n
|
||||
{
|
||||
return [[Attr alloc] initWithName:n value:@""];
|
||||
}
|
||||
|
||||
-(EntityReference*) createEntityReference:(NSString*) data
|
||||
{
|
||||
NSAssert( FALSE, @"Not implemented. According to spec: Creates an EntityReference object. In addition, if the referenced entity is known, the child list of the EntityReference node is made the same as that of the corresponding Entity node. Note: If any descendant of the Entity node has an unbound namespace prefix, the corresponding descendant of the created EntityReference node is also unbound; (its namespaceURI is null). The DOM Level 2 does not support any mechanism to resolve namespace prefixes." );
|
||||
return nil;
|
||||
}
|
||||
|
||||
-(NodeList*) getElementsByTagName:(NSString*) data
|
||||
{
|
||||
NodeList* accumulator = [[NodeList alloc] init];
|
||||
[DOMHelperUtilities privateGetElementsByName:data inNamespace:nil childrenOfElement:self.documentElement addToList:accumulator];
|
||||
|
||||
return accumulator;
|
||||
}
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
-(Node*) importNode:(Node*) importedNode deep:(BOOL) deep
|
||||
{
|
||||
NSAssert( FALSE, @"Not implemented." );
|
||||
return nil;
|
||||
}
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
-(Element*) createElementNS:(NSString*) namespaceURI qualifiedName:(NSString*) qualifiedName
|
||||
{
|
||||
Element* newElement = [[Element alloc] initWithQualifiedName:qualifiedName inNameSpaceURI:namespaceURI attributes:nil];
|
||||
|
||||
SVGKitLogVerbose( @"[%@] WARNING: SVG Spec, missing feature: if there are known attributes with default values, Attr nodes representing them SHOULD BE automatically created and attached to the element.", [self class] );
|
||||
|
||||
return newElement;
|
||||
}
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
-(Attr*) createAttributeNS:(NSString*) namespaceURI qualifiedName:(NSString*) qualifiedName
|
||||
{
|
||||
NSAssert( FALSE, @"This should be re-implemented to share code with createElementNS: method above" );
|
||||
Attr* newAttr = [[Attr alloc] initWithNamespace:namespaceURI qualifiedName:qualifiedName value:@""];
|
||||
return newAttr;
|
||||
}
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
-(NodeList*) getElementsByTagNameNS:(NSString*) namespaceURI localName:(NSString*) localName
|
||||
{
|
||||
NodeList* accumulator = [[NodeList alloc] init];
|
||||
[DOMHelperUtilities privateGetElementsByName:localName inNamespace:namespaceURI childrenOfElement:self.documentElement addToList:accumulator];
|
||||
|
||||
return accumulator;
|
||||
}
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
-(Element*) getElementById:(NSString*) elementId
|
||||
{
|
||||
return [DOMHelperUtilities privateGetElementById:elementId childrenOfElement:self.documentElement];
|
||||
}
|
||||
|
||||
@end
|
@ -1,19 +0,0 @@
|
||||
/**
|
||||
http://www.w3.org/TR/2000/REC-DOM-Level-2-Style-20001113/css.html#CSS-DocumentCSS
|
||||
|
||||
interface DocumentCSS : stylesheets::DocumentStyle {
|
||||
CSSStyleDeclaration getOverrideStyle(in Element elt,
|
||||
in DOMString pseudoElt);
|
||||
*/
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "DocumentStyle.h"
|
||||
|
||||
#import "CSSStyleDeclaration.h"
|
||||
|
||||
@class Element;
|
||||
|
||||
@protocol DocumentCSS <DocumentStyle>
|
||||
|
||||
-(CSSStyleDeclaration *)getOverrideStyle:(Element *)element pseudoElt:(NSString *)pseudoElt;
|
||||
|
||||
@end
|
@ -1,17 +0,0 @@
|
||||
/*
|
||||
From SVG-DOM, via Core DOM:
|
||||
|
||||
http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-B63ED1A3
|
||||
|
||||
interface DocumentFragment : Node {
|
||||
};
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
/** objc won't allow this: @class Node;*/
|
||||
#import "Node.h"
|
||||
|
||||
@interface DocumentFragment : Node
|
||||
|
||||
@end
|
@ -1,21 +0,0 @@
|
||||
//
|
||||
// DocumentFragment.m
|
||||
// SVGKit
|
||||
//
|
||||
// Created by adam on 22/05/2012.
|
||||
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import "DocumentFragment.h"
|
||||
|
||||
@implementation DocumentFragment
|
||||
|
||||
- (id)init
|
||||
{
|
||||
self = [super initType:DOMNodeType_DOCUMENT_FRAGMENT_NODE name:nil];
|
||||
if (self) {
|
||||
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@end
|
@ -1,17 +0,0 @@
|
||||
/**
|
||||
|
||||
http://www.w3.org/TR/2000/REC-DOM-Level-2-Style-20001113/stylesheets.html#StyleSheets-StyleSheet-DocumentStyle
|
||||
|
||||
interface DocumentStyle {
|
||||
readonly attribute StyleSheetList styleSheets;
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "StyleSheetList.h"
|
||||
|
||||
@protocol DocumentStyle <NSObject>
|
||||
|
||||
@property(nonatomic,retain) StyleSheetList* styleSheets;
|
||||
|
||||
@end
|
@ -1,39 +0,0 @@
|
||||
/*
|
||||
From SVG-DOM, via Core DOM:
|
||||
|
||||
http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-412266927
|
||||
|
||||
interface DocumentType : Node {
|
||||
readonly attribute DOMString name;
|
||||
readonly attribute NamedNodeMap entities;
|
||||
readonly attribute NamedNodeMap notations;
|
||||
// Introduced in DOM Level 2:
|
||||
readonly attribute DOMString publicId;
|
||||
// Introduced in DOM Level 2:
|
||||
readonly attribute DOMString systemId;
|
||||
// Introduced in DOM Level 2:
|
||||
readonly attribute DOMString internalSubset;
|
||||
};
|
||||
*/
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "Node.h"
|
||||
#import "NamedNodeMap.h"
|
||||
|
||||
@interface DocumentType : Node
|
||||
|
||||
@property(nonatomic,strong,readonly) NSString* name;
|
||||
@property(nonatomic,strong,readonly) NamedNodeMap* entities;
|
||||
@property(nonatomic,strong,readonly) NamedNodeMap* notations;
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
@property(nonatomic,strong,readonly) NSString* publicId;
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
@property(nonatomic,strong,readonly) NSString* systemId;
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
@property(nonatomic,strong,readonly) NSString* internalSubset;
|
||||
|
||||
|
||||
@end
|
@ -1,44 +0,0 @@
|
||||
//
|
||||
// DocumentType.m
|
||||
// SVGKit
|
||||
//
|
||||
// Created by adam on 23/05/2012.
|
||||
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import "DocumentType.h"
|
||||
|
||||
/*
|
||||
in case we need to redeclare them readwrite:
|
||||
@property(nonatomic,retain,readonly) NSString* name;
|
||||
@property(nonatomic,retain,readonly) NamedNodeMap* entities;
|
||||
@property(nonatomic,retain,readonly) NamedNodeMap* notations;
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
@property(nonatomic,retain,readonly) NSString* publicId;
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
@property(nonatomic,retain,readonly) NSString* systemId;
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
@property(nonatomic,retain,readonly) NSString* internalSubset;
|
||||
|
||||
*/
|
||||
|
||||
@implementation DocumentType
|
||||
|
||||
@synthesize name;
|
||||
@synthesize entities;
|
||||
@synthesize notations;
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
@synthesize publicId;
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
@synthesize systemId;
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
@synthesize internalSubset;
|
||||
|
||||
|
||||
@end
|
@ -1,99 +0,0 @@
|
||||
/*
|
||||
From SVG-DOM, via Core-DOM:
|
||||
|
||||
http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-745549614
|
||||
|
||||
interface Element : Node {
|
||||
readonly attribute DOMString tagName;
|
||||
DOMString getAttribute(in DOMString name);
|
||||
void setAttribute(in DOMString name,
|
||||
in DOMString value)
|
||||
raises(DOMException);
|
||||
void removeAttribute(in DOMString name)
|
||||
raises(DOMException);
|
||||
Attr getAttributeNode(in DOMString name);
|
||||
Attr setAttributeNode(in Attr newAttr)
|
||||
raises(DOMException);
|
||||
Attr removeAttributeNode(in Attr oldAttr)
|
||||
raises(DOMException);
|
||||
NodeList getElementsByTagName(in DOMString name);
|
||||
// Introduced in DOM Level 2:
|
||||
DOMString getAttributeNS(in DOMString namespaceURI,
|
||||
in DOMString localName);
|
||||
// Introduced in DOM Level 2:
|
||||
void setAttributeNS(in DOMString namespaceURI,
|
||||
in DOMString qualifiedName,
|
||||
in DOMString value)
|
||||
raises(DOMException);
|
||||
// Introduced in DOM Level 2:
|
||||
void removeAttributeNS(in DOMString namespaceURI,
|
||||
in DOMString localName)
|
||||
raises(DOMException);
|
||||
// Introduced in DOM Level 2:
|
||||
Attr getAttributeNodeNS(in DOMString namespaceURI,
|
||||
in DOMString localName);
|
||||
// Introduced in DOM Level 2:
|
||||
Attr setAttributeNodeNS(in Attr newAttr)
|
||||
raises(DOMException);
|
||||
// Introduced in DOM Level 2:
|
||||
NodeList getElementsByTagNameNS(in DOMString namespaceURI,
|
||||
in DOMString localName);
|
||||
// Introduced in DOM Level 2:
|
||||
boolean hasAttribute(in DOMString name);
|
||||
// Introduced in DOM Level 2:
|
||||
boolean hasAttributeNS(in DOMString namespaceURI,
|
||||
in DOMString localName);
|
||||
};
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
/** objc won't allow this: @class Node;*/
|
||||
#import "Node.h"
|
||||
@class Attr;
|
||||
#import "Attr.h"
|
||||
@class NodeList;
|
||||
#import "NodeList.h"
|
||||
|
||||
@interface Element : Node
|
||||
|
||||
@property(nonatomic,strong,readonly) NSString* tagName;
|
||||
|
||||
-(NSString*) getAttribute:(NSString*) name;
|
||||
-(void) setAttribute:(NSString*) name value:(NSString*) value;
|
||||
-(void) removeAttribute:(NSString*) name;
|
||||
-(Attr*) getAttributeNode:(NSString*) name;
|
||||
-(Attr*) setAttributeNode:(Attr*) newAttr;
|
||||
-(Attr*) removeAttributeNode:(Attr*) oldAttr;
|
||||
-(NodeList*) getElementsByTagName:(NSString*) name;
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
-(NSString*) getAttributeNS:(NSString*) namespaceURI localName:(NSString*) localName;
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
-(void) setAttributeNS:(NSString*) namespaceURI qualifiedName:(NSString*) qualifiedName value:(NSString*) value;
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
-(void) removeAttributeNS:(NSString*) namespaceURI localName:(NSString*) localName;
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
-(Attr*) getAttributeNodeNS:(NSString*) namespaceURI localName:(NSString*) localName;
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
-(Attr*) setAttributeNodeNS:(Attr*) newAttr;
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
-(NodeList*) getElementsByTagNameNS:(NSString*) namespaceURI localName:(NSString*) localName;
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
-(BOOL) hasAttribute:(NSString*) name;
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
-(BOOL) hasAttributeNS:(NSString*) namespaceURI localName:(NSString*) localName;
|
||||
|
||||
#pragma mark - Objective-C init methods (not in SVG Spec - you're supposed to use SVGDocument's createXXX methods instead)
|
||||
|
||||
- (id)initWithLocalName:(NSString*) n attributes:(NSMutableDictionary*) attributes;
|
||||
- (id)initWithQualifiedName:(NSString*) n inNameSpaceURI:(NSString*) nsURI attributes:(NSMutableDictionary*) attributes;
|
||||
|
||||
@end
|
@ -1,170 +0,0 @@
|
||||
#import "Element.h"
|
||||
|
||||
#import "NamedNodeMap.h"
|
||||
#import "DOMHelperUtilities.h"
|
||||
|
||||
@interface Element()
|
||||
@property(nonatomic,strong,readwrite) NSString* tagName;
|
||||
@end
|
||||
|
||||
@implementation Element
|
||||
|
||||
@synthesize tagName;
|
||||
|
||||
|
||||
- (id)initWithLocalName:(NSString*) n attributes:(NSMutableDictionary*) attributes {
|
||||
self = [super initType:DOMNodeType_ELEMENT_NODE name:n];
|
||||
if (self) {
|
||||
self.tagName = n;
|
||||
|
||||
for( NSString* attributeName in attributes.allKeys )
|
||||
{
|
||||
[self setAttribute:attributeName value:[attributes objectForKey:attributeName]];
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (id)initWithQualifiedName:(NSString*) n inNameSpaceURI:(NSString*) nsURI attributes:(NSMutableDictionary *)attributes
|
||||
{
|
||||
self = [super initType:DOMNodeType_ELEMENT_NODE name:n inNamespace:nsURI];
|
||||
if (self) {
|
||||
self.tagName = n;
|
||||
|
||||
for( Attr* attribute in attributes.allValues )
|
||||
{
|
||||
[self.attributes setNamedItemNS:attribute inNodeNamespace:nsURI];
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
-(NSString*) getAttribute:(NSString*) name
|
||||
{
|
||||
/**
|
||||
WARNING: the definition in the spec WILL CORRUPT unsuspecting Objective-C code (including a lot of the original SVGKit code!).
|
||||
|
||||
The spec - instead of defining 'nil' - defines "" (empty string) as the
|
||||
correct response.
|
||||
|
||||
But in most of the modern, C-based, (non-scripting) languages, "" means 0.
|
||||
|
||||
Very dangerous!
|
||||
*/
|
||||
Attr* result = (Attr*) [self.attributes getNamedItem:name];
|
||||
|
||||
if( result == nil || result.value == nil )
|
||||
return @""; // according to spec
|
||||
else
|
||||
return result.value;
|
||||
}
|
||||
|
||||
-(void) setAttribute:(NSString*) name value:(NSString*) value
|
||||
{
|
||||
Attr* att = [[Attr alloc] initWithName:name value:value];
|
||||
|
||||
[self.attributes setNamedItem:att];
|
||||
}
|
||||
|
||||
-(void) removeAttribute:(NSString*) name
|
||||
{
|
||||
[self.attributes removeNamedItem:name];
|
||||
|
||||
NSAssert( FALSE, @"Not fully implemented. Spec says: If the removed attribute is known to have a default value, an attribute immediately appears containing the default value as well as the corresponding namespace URI, local name, and prefix when applicable." );
|
||||
}
|
||||
|
||||
-(Attr*) getAttributeNode:(NSString*) name
|
||||
{
|
||||
return (Attr*) [self.attributes getNamedItem:name];
|
||||
}
|
||||
|
||||
-(Attr*) setAttributeNode:(Attr*) newAttr
|
||||
{
|
||||
Attr* oldAtt = (Attr*) [self.attributes getNamedItem:newAttr.nodeName];
|
||||
|
||||
[self.attributes setNamedItem:newAttr];
|
||||
|
||||
return oldAtt;
|
||||
}
|
||||
|
||||
-(Attr*) removeAttributeNode:(Attr*) oldAttr
|
||||
{
|
||||
[self.attributes removeNamedItem:oldAttr.nodeName];
|
||||
|
||||
NSAssert( FALSE, @"Not fully implemented. Spec: If the removed Attr has a default value it is immediately replaced. The replacing attribute has the same namespace URI and local name, as well as the original prefix, when applicable. " );
|
||||
|
||||
return oldAttr;
|
||||
}
|
||||
|
||||
-(NodeList*) getElementsByTagName:(NSString*) name
|
||||
{
|
||||
NodeList* accumulator = [[NodeList alloc] init];
|
||||
[DOMHelperUtilities privateGetElementsByName:name inNamespace:nil childrenOfElement:self addToList:accumulator];
|
||||
|
||||
return accumulator;
|
||||
}
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
-(NSString*) getAttributeNS:(NSString*) namespaceURI localName:(NSString*) localName
|
||||
{
|
||||
Attr* result = (Attr*) [self.attributes getNamedItemNS:namespaceURI localName:localName];
|
||||
|
||||
if( result == nil || result.value == nil )
|
||||
return @""; // according to spec
|
||||
else
|
||||
return result.value;
|
||||
}
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
-(void) setAttributeNS:(NSString*) namespaceURI qualifiedName:(NSString*) qualifiedName value:(NSString*) value
|
||||
{
|
||||
Attr* att = [[Attr alloc] initWithNamespace:namespaceURI qualifiedName:qualifiedName value:value];
|
||||
|
||||
[self.attributes setNamedItemNS:att];
|
||||
}
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
-(void) removeAttributeNS:(NSString*) namespaceURI localName:(NSString*) localName
|
||||
{
|
||||
NSAssert( FALSE, @"Not implemented yet" );
|
||||
}
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
-(Attr*) getAttributeNodeNS:(NSString*) namespaceURI localName:(NSString*) localName
|
||||
{
|
||||
Attr* result = (Attr*) [self.attributes getNamedItemNS:namespaceURI localName:localName];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
-(Attr*) setAttributeNodeNS:(Attr*) newAttr
|
||||
{
|
||||
NSAssert( FALSE, @"Not implemented yet" );
|
||||
return nil;
|
||||
}
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
-(NodeList*) getElementsByTagNameNS:(NSString*) namespaceURI localName:(NSString*) localName
|
||||
{
|
||||
NodeList* accumulator = [[NodeList alloc] init];
|
||||
[DOMHelperUtilities privateGetElementsByName:localName inNamespace:namespaceURI childrenOfElement:self addToList:accumulator];
|
||||
|
||||
return accumulator;
|
||||
}
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
-(BOOL) hasAttribute:(NSString*) name
|
||||
{
|
||||
Attr* result = (Attr*) [self.attributes getNamedItem:name];
|
||||
|
||||
return result != nil;
|
||||
}
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
-(BOOL) hasAttributeNS:(NSString*) namespaceURI localName:(NSString*) localName
|
||||
{
|
||||
NSAssert( FALSE, @"Not implemented yet" );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@end
|
@ -1,16 +0,0 @@
|
||||
/*
|
||||
From SVG-DOM, via Core DOM:
|
||||
|
||||
http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-11C98490
|
||||
|
||||
interface EntityReference : Node {
|
||||
};
|
||||
*/
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
/** objc won't allow this: @class Node; */
|
||||
#import "Node.h"
|
||||
|
||||
@interface EntityReference : Node
|
||||
|
||||
@end
|
@ -1,13 +0,0 @@
|
||||
//
|
||||
// EntityReference.m
|
||||
// SVGKit
|
||||
//
|
||||
// Created by adam on 22/05/2012.
|
||||
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import "EntityReference.h"
|
||||
|
||||
@implementation EntityReference
|
||||
|
||||
@end
|
@ -1,27 +0,0 @@
|
||||
/**
|
||||
http://www.w3.org/TR/2000/REC-DOM-Level-2-Style-20001113/stylesheets.html#StyleSheets-MediaList
|
||||
|
||||
interface MediaList {
|
||||
attribute DOMString mediaText;
|
||||
// raises(DOMException) on setting
|
||||
|
||||
readonly attribute unsigned long length;
|
||||
DOMString item(in unsigned long index);
|
||||
void deleteMedium(in DOMString oldMedium)
|
||||
raises(DOMException);
|
||||
void appendMedium(in DOMString newMedium)
|
||||
raises(DOMException);
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface MediaList : NSObject
|
||||
|
||||
@property(nonatomic,strong) NSString* mediaText;
|
||||
@property(nonatomic) unsigned long length;
|
||||
|
||||
-(NSString*) item:(unsigned long) index;
|
||||
-(void) deleteMedium:(NSString*) oldMedium;
|
||||
-(void) appendMedium:(NSString*) newMedium;
|
||||
|
||||
@end
|
@ -1,23 +0,0 @@
|
||||
#import "MediaList.h"
|
||||
|
||||
@implementation MediaList
|
||||
|
||||
@synthesize mediaText;
|
||||
@synthesize length;
|
||||
|
||||
|
||||
-(NSString*) item:(unsigned long) index
|
||||
{
|
||||
NSAssert( FALSE, @"Not implemented yet");
|
||||
return nil;
|
||||
}
|
||||
-(void) deleteMedium:(NSString*) oldMedium
|
||||
{
|
||||
NSAssert( FALSE, @"Not implemented yet");
|
||||
}
|
||||
-(void) appendMedium:(NSString*) newMedium
|
||||
{
|
||||
NSAssert( FALSE, @"Not implemented yet");
|
||||
}
|
||||
|
||||
@end
|
@ -1,55 +0,0 @@
|
||||
/*
|
||||
From SVG-DOM, via Core-DOM:
|
||||
|
||||
http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-1780488922
|
||||
|
||||
interface NamedNodeMap {
|
||||
Node getNamedItem(in DOMString name);
|
||||
Node setNamedItem(in Node arg)
|
||||
raises(DOMException);
|
||||
Node removeNamedItem(in DOMString name)
|
||||
raises(DOMException);
|
||||
Node item(in unsigned long index);
|
||||
readonly attribute unsigned long length;
|
||||
// Introduced in DOM Level 2:
|
||||
Node getNamedItemNS(in DOMString namespaceURI,
|
||||
in DOMString localName);
|
||||
// Introduced in DOM Level 2:
|
||||
Node setNamedItemNS(in Node arg)
|
||||
raises(DOMException);
|
||||
// Introduced in DOM Level 2:
|
||||
Node removeNamedItemNS(in DOMString namespaceURI,
|
||||
in DOMString localName)
|
||||
raises(DOMException);
|
||||
};
|
||||
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class Node;
|
||||
#import "Node.h"
|
||||
|
||||
@interface NamedNodeMap : NSObject </** needed so we can output SVG text in the [Node appendToXML:..] methods */ NSCopying>
|
||||
|
||||
-(Node*) getNamedItem:(NSString*) name;
|
||||
-(Node*) setNamedItem:(Node*) arg;
|
||||
-(Node*) removeNamedItem:(NSString*) name;
|
||||
-(Node*) item:(unsigned long) index;
|
||||
|
||||
@property(readonly) unsigned long length;
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
-(Node*) getNamedItemNS:(NSString*) namespaceURI localName:(NSString*) localName;
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
-(Node*) setNamedItemNS:(Node*) arg;
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
-(Node*) removeNamedItemNS:(NSString*) namespaceURI localName:(NSString*) localName;
|
||||
|
||||
#pragma mark - MISSING METHOD FROM SVG Spec, without which you cannot parse documents (don't understand how they intended you to fulfil the spec without this method)
|
||||
|
||||
-(Node*) setNamedItemNS:(Node*) arg inNodeNamespace:(NSString*) nodesNamespace;
|
||||
|
||||
@end
|
@ -1,203 +0,0 @@
|
||||
//
|
||||
// NamedNodeMap.m
|
||||
// SVGKit
|
||||
//
|
||||
// Created by adam on 22/05/2012.
|
||||
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NamedNodeMap.h"
|
||||
#import "NamedNodeMap_Iterable.h"
|
||||
|
||||
@interface NamedNodeMap()
|
||||
@property(nonatomic,strong) NSMutableDictionary* internalDictionary;
|
||||
@property(nonatomic,strong) NSMutableDictionary* internalDictionaryOfNamespaces;
|
||||
@end
|
||||
|
||||
@implementation NamedNodeMap
|
||||
|
||||
@synthesize internalDictionary;
|
||||
@synthesize internalDictionaryOfNamespaces;
|
||||
|
||||
- (id)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
self.internalDictionary = [NSMutableDictionary dictionary];
|
||||
self.internalDictionaryOfNamespaces = [NSMutableDictionary dictionary];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
-(Node*) getNamedItem:(NSString*) name
|
||||
{
|
||||
Node* simpleResult = [self.internalDictionary objectForKey:name];
|
||||
|
||||
if( simpleResult == nil )
|
||||
{
|
||||
/**
|
||||
Check the namespaces in turn, to see if we can find this node in one of them
|
||||
|
||||
NB: according to spec, this behaviour is:
|
||||
|
||||
"The result depends on the implementation"
|
||||
|
||||
I've chosen to implement it the most user-friendly way possible. It is NOT the best
|
||||
solution IMHO - the spec authors should have defined the outcome!
|
||||
*/
|
||||
|
||||
for( NSString* key in self.internalDictionaryOfNamespaces )
|
||||
{
|
||||
simpleResult = [self getNamedItemNS:key localName:name];
|
||||
if( simpleResult != nil )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return simpleResult;
|
||||
}
|
||||
|
||||
-(Node*) setNamedItem:(Node*) arg
|
||||
{
|
||||
NSAssert( [[self.internalDictionaryOfNamespaces allKeys] count] < 1, @"WARNING: you are using namespaced attributes in parallel with non-namespaced. According to the DOM Spec, this leads to UNDEFINED behaviour. This is insane - you do NOT want to be doing this! Crashing deliberately...." );
|
||||
|
||||
Node* oldNode = [self.internalDictionary objectForKey:arg.localName];
|
||||
|
||||
[self.internalDictionary setObject:arg forKey:arg.localName];
|
||||
|
||||
return oldNode;
|
||||
}
|
||||
|
||||
-(Node*) removeNamedItem:(NSString*) name
|
||||
{
|
||||
NSAssert( [[self.internalDictionaryOfNamespaces allKeys] count] < 1, @"WARNING: you are using namespaced attributes in parallel with non-namespaced. According to the DOM Spec, this leads to UNDEFINED behaviour. This is insane - you do NOT want to be doing this! Crashing deliberately...." );
|
||||
|
||||
Node* oldNode = [self.internalDictionary objectForKey:name];
|
||||
|
||||
[self.internalDictionary removeObjectForKey:name];
|
||||
|
||||
return oldNode;
|
||||
}
|
||||
|
||||
-(unsigned long)length
|
||||
{
|
||||
NSUInteger count = [self.internalDictionary count];
|
||||
|
||||
for( NSDictionary* namespaceDict in [self.internalDictionaryOfNamespaces allValues] )
|
||||
{
|
||||
count += [namespaceDict count];
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
-(Node*) item:(unsigned long) index
|
||||
{
|
||||
NSAssert(FALSE, @"This method is broken; Apple does not consistently return ordered values in dictionary.allValues. Apple DOES NOT SUPPORT ordered Maps/Hashes/Tables/Hashtables - we have to re-implement this wheel from scratch");
|
||||
|
||||
if( index < [self.internalDictionary count] )
|
||||
return [self.internalDictionary.allValues objectAtIndex:index];
|
||||
else
|
||||
{
|
||||
index -= self.internalDictionary.count;
|
||||
|
||||
for( NSDictionary* namespaceDict in [self.internalDictionaryOfNamespaces allValues] )
|
||||
{
|
||||
if( index < [namespaceDict count] )
|
||||
return [namespaceDict.allValues objectAtIndex:index];
|
||||
else
|
||||
index -= [namespaceDict count];
|
||||
}
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
-(Node*) getNamedItemNS:(NSString*) namespaceURI localName:(NSString*) localName
|
||||
{
|
||||
NSMutableDictionary* namespaceDict = [self.internalDictionaryOfNamespaces objectForKey:namespaceURI];
|
||||
|
||||
return [namespaceDict objectForKey:localName];
|
||||
}
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
-(Node*) setNamedItemNS:(Node*) arg
|
||||
{
|
||||
return [self setNamedItemNS:arg inNodeNamespace:nil];
|
||||
}
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
-(Node*) removeNamedItemNS:(NSString*) namespaceURI localName:(NSString*) localName
|
||||
{
|
||||
NSMutableDictionary* namespaceDict = [self.internalDictionaryOfNamespaces objectForKey:namespaceURI];
|
||||
Node* oldNode = [namespaceDict objectForKey:localName];
|
||||
|
||||
[namespaceDict removeObjectForKey:localName];
|
||||
|
||||
return oldNode;
|
||||
}
|
||||
|
||||
#pragma mark - MISSING METHOD FROM SVG Spec, without which you cannot parse documents (don't understand how they intended you to fulfil the spec without this method)
|
||||
|
||||
-(Node*) setNamedItemNS:(Node*) arg inNodeNamespace:(NSString*) nodesNamespace
|
||||
{
|
||||
NSString* effectiveNamespace = arg.namespaceURI != nil ? arg.namespaceURI : nodesNamespace;
|
||||
if( effectiveNamespace == nil )
|
||||
{
|
||||
return [self setNamedItem:arg]; // this should never happen, but there's a lot of malformed SVG files out in the wild
|
||||
}
|
||||
|
||||
NSMutableDictionary* namespaceDict = [self.internalDictionaryOfNamespaces objectForKey:effectiveNamespace];
|
||||
if( namespaceDict == nil )
|
||||
{
|
||||
namespaceDict = [NSMutableDictionary dictionary];
|
||||
[self.internalDictionaryOfNamespaces setObject:namespaceDict forKey:effectiveNamespace];
|
||||
}
|
||||
Node* oldNode = [namespaceDict objectForKey:arg.localName];
|
||||
|
||||
[namespaceDict setObject:arg forKey:arg.localName];
|
||||
|
||||
return oldNode;
|
||||
}
|
||||
|
||||
#pragma mark - ADDITIONAL to SVG Spec: useful debug / output / description methods
|
||||
|
||||
-(NSString *)description
|
||||
{
|
||||
/** test (and output) both the "DOM 1" and "DOM 2" dictionaries, if they're non-empty */
|
||||
|
||||
NSString* dom1 = self.internalDictionary.count > 0 ? [NSString stringWithFormat:@"DOM-v1(%@)", self.internalDictionary] : nil;
|
||||
NSString* dom2 = self.internalDictionaryOfNamespaces.count > 0 ? [NSString stringWithFormat:@"DOM-v2(%@)", self.internalDictionaryOfNamespaces] : nil;
|
||||
|
||||
return [NSString stringWithFormat:@"NamedNodeMap: %@%@%@", dom1, dom1 != nil && dom2 != nil ? @"\n" : @"", dom2 ];
|
||||
}
|
||||
|
||||
#pragma mark - Implementation of category: NamedNodeMap_Iterable
|
||||
|
||||
-(NSArray*) allNodesUnsortedDOM1
|
||||
{
|
||||
/** Using DOM1 - no namespace support */
|
||||
|
||||
return self.internalDictionary.allValues;
|
||||
}
|
||||
|
||||
-(NSDictionary*) allNodesUnsortedDOM2
|
||||
{
|
||||
/** Using DOM2 - every item has a namespace*/
|
||||
|
||||
return self.internalDictionaryOfNamespaces;
|
||||
}
|
||||
|
||||
#pragma mark - Needed to implement XML DOM effectively: ability to shallow-Clone an instance
|
||||
|
||||
-(id)copyWithZone:(NSZone *)zone
|
||||
{
|
||||
NamedNodeMap* clone = [[NamedNodeMap allocWithZone:zone] init];
|
||||
clone.internalDictionary = [self.internalDictionary copyWithZone:zone];
|
||||
clone.internalDictionaryOfNamespaces = [self.internalDictionaryOfNamespaces copyWithZone:zone];
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
@end
|
@ -1,17 +0,0 @@
|
||||
@interface NamedNodeMap ()
|
||||
|
||||
/**
|
||||
DOM1 is very basic and ignores namespaces - dangerous! It's recommended to avoid DOM1 calls throughout your apps and code!
|
||||
|
||||
@return an Array of "nodes from the nodemap (Node)"
|
||||
*/
|
||||
-(NSArray*) allNodesUnsortedDOM1;
|
||||
|
||||
/**
|
||||
DOM2 requires everything to have a namespace - much better than DOM1
|
||||
|
||||
@return a Dictionary of "namespace (string)" mapped to "node from nodemap (Node)"
|
||||
*/
|
||||
-(NSDictionary*) allNodesUnsortedDOM2;
|
||||
|
||||
@end
|
@ -1,26 +0,0 @@
|
||||
/**
|
||||
Makes the writable properties all package-private, effectively
|
||||
*/
|
||||
#import "Node.h"
|
||||
|
||||
@interface Node()
|
||||
@property(nonatomic,strong,readwrite) NSString* nodeName;
|
||||
@property(nonatomic,strong,readwrite) NSString* nodeValue;
|
||||
|
||||
@property(nonatomic,readwrite) DOMNodeType nodeType;
|
||||
@property(nonatomic,weak,readwrite) Node* parentNode;
|
||||
@property(nonatomic,strong,readwrite) NodeList* childNodes;
|
||||
@property(nonatomic,strong,readwrite) NamedNodeMap* attributes;
|
||||
|
||||
@property(nonatomic,weak,readwrite) Document* ownerDocument;
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
@property(nonatomic,strong,readwrite) NSString* namespaceURI;
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
@property(nonatomic,strong,readwrite) NSString* prefix;
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
@property(nonatomic,strong,readwrite) NSString* localName;
|
||||
|
||||
@end
|
@ -1,174 +0,0 @@
|
||||
/*
|
||||
// Node.h
|
||||
*
|
||||
http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-1950641247
|
||||
|
||||
interface Node {
|
||||
|
||||
// NodeType
|
||||
const unsigned short ELEMENT_NODE = 1;
|
||||
const unsigned short ATTRIBUTE_NODE = 2;
|
||||
const unsigned short TEXT_NODE = 3;
|
||||
const unsigned short CDATA_SECTION_NODE = 4;
|
||||
const unsigned short ENTITY_REFERENCE_NODE = 5;
|
||||
const unsigned short ENTITY_NODE = 6;
|
||||
const unsigned short PROCESSING_INSTRUCTION_NODE = 7;
|
||||
const unsigned short COMMENT_NODE = 8;
|
||||
const unsigned short DOCUMENT_NODE = 9;
|
||||
const unsigned short DOCUMENT_TYPE_NODE = 10;
|
||||
const unsigned short DOCUMENT_FRAGMENT_NODE = 11;
|
||||
const unsigned short NOTATION_NODE = 12;
|
||||
|
||||
readonly attribute DOMString nodeName;
|
||||
attribute DOMString nodeValue;
|
||||
// raises(DOMException) on setting
|
||||
// raises(DOMException) on retrieval
|
||||
|
||||
readonly attribute unsigned short nodeType;
|
||||
readonly attribute Node parentNode;
|
||||
readonly attribute NodeList childNodes;
|
||||
readonly attribute Node firstChild;
|
||||
readonly attribute Node lastChild;
|
||||
readonly attribute Node previousSibling;
|
||||
readonly attribute Node nextSibling;
|
||||
readonly attribute NamedNodeMap attributes;
|
||||
// Modified in DOM Level 2:
|
||||
readonly attribute Document ownerDocument;
|
||||
Node insertBefore(in Node newChild,
|
||||
in Node refChild)
|
||||
raises(DOMException);
|
||||
Node replaceChild(in Node newChild,
|
||||
in Node oldChild)
|
||||
raises(DOMException);
|
||||
Node removeChild(in Node oldChild)
|
||||
raises(DOMException);
|
||||
Node appendChild(in Node newChild)
|
||||
raises(DOMException);
|
||||
boolean hasChildNodes();
|
||||
Node cloneNode(in boolean deep);
|
||||
// Modified in DOM Level 2:
|
||||
void normalize();
|
||||
// Introduced in DOM Level 2:
|
||||
boolean isSupported(in DOMString feature,
|
||||
in DOMString version);
|
||||
// Introduced in DOM Level 2:
|
||||
readonly attribute DOMString namespaceURI;
|
||||
// Introduced in DOM Level 2:
|
||||
attribute DOMString prefix;
|
||||
// raises(DOMException) on setting
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
readonly attribute DOMString localName;
|
||||
// Introduced in DOM Level 2:
|
||||
boolean hasAttributes();
|
||||
};
|
||||
|
||||
-------------------------------
|
||||
|
||||
// DOM Level 3 that we *need*, partly because SVG Spec makes one brief reference to it: http://www.w3.org/TR/SVG/text.html#InterfaceSVGTextContentElement
|
||||
|
||||
http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#Node3-textContent
|
||||
|
||||
// Introduced in DOM Level 3:
|
||||
attribute DOMString textContent;
|
||||
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class Document;
|
||||
/** objc won't allow this: #import "Document.h"*/
|
||||
@class NodeList;
|
||||
/** objc won't allow this: #import "NodeList.h"*/
|
||||
@class NamedNodeMap;
|
||||
/** objc won't allow this: #import "NamedNodeMap.h"*/
|
||||
|
||||
typedef enum DOMNodeType
|
||||
{
|
||||
DOMNodeType_ELEMENT_NODE = 1,
|
||||
DOMNodeType_ATTRIBUTE_NODE = 2,
|
||||
DOMNodeType_TEXT_NODE = 3,
|
||||
DOMNodeType_CDATA_SECTION_NODE = 4,
|
||||
DOMNodeType_ENTITY_REFERENCE_NODE = 5,
|
||||
DOMNodeType_ENTITY_NODE = 6,
|
||||
DOMNodeType_PROCESSING_INSTRUCTION_NODE = 7,
|
||||
DOMNodeType_COMMENT_NODE = 8,
|
||||
DOMNodeType_DOCUMENT_NODE = 9,
|
||||
DOMNodeType_DOCUMENT_TYPE_NODE = 10,
|
||||
DOMNodeType_DOCUMENT_FRAGMENT_NODE = 11,
|
||||
DOMNodeType_NOTATION_NODE = 12
|
||||
} DOMNodeType;
|
||||
|
||||
@interface Node : NSObject
|
||||
|
||||
@property(nonatomic,strong,readonly) NSString* nodeName;
|
||||
@property(nonatomic,strong,readonly) NSString* nodeValue;
|
||||
|
||||
@property(nonatomic,readonly) DOMNodeType nodeType;
|
||||
@property(nonatomic,weak,readonly) Node* parentNode;
|
||||
@property(nonatomic,strong,readonly) NodeList* childNodes;
|
||||
@property(nonatomic,weak,readonly) Node* firstChild;
|
||||
@property(nonatomic,weak,readonly) Node* lastChild;
|
||||
@property(nonatomic,weak,readonly) Node* previousSibling;
|
||||
@property(nonatomic,weak,readonly) Node* nextSibling;
|
||||
@property(nonatomic,strong,readonly) NamedNodeMap* attributes; /**< NB: according to DOM Spec, this is null if the Node is NOT subclassed as an Element */
|
||||
|
||||
// Modified in DOM Level 2:
|
||||
@property(nonatomic,weak,readonly) Document* ownerDocument;
|
||||
|
||||
-(Node*) insertBefore:(Node*) newChild refChild:(Node*) refChild;
|
||||
|
||||
-(Node*) replaceChild:(Node*) newChild oldChild:(Node*) oldChild;
|
||||
-(Node*) removeChild:(Node*) oldChild;
|
||||
-(Node*) appendChild:(Node*) newChild;
|
||||
|
||||
@property(nonatomic) BOOL hasChildNodes;
|
||||
|
||||
-(Node*) cloneNode:(BOOL) deep;
|
||||
|
||||
// Modified in DOM Level 2:
|
||||
-(void) normalize;
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
-(BOOL) isSupportedFeature:(NSString*) feature version:(NSString*) version;
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
@property(nonatomic,strong,readonly) NSString* namespaceURI;
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
@property(nonatomic,strong,readonly) NSString* prefix;
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
@property(nonatomic,strong,readonly) NSString* localName;
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
@property(nonatomic) BOOL hasAttributes;
|
||||
|
||||
// DOM Level 3 that we *need*, partly because SVG Spec makes one brief reference to it: http://www.w3.org/TR/SVG/text.html#InterfaceSVGTextContentElement
|
||||
|
||||
// Introduced in DOM Level 3: http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#Node3-textContent
|
||||
@property(weak, nonatomic,readonly) NSString* textContent;
|
||||
|
||||
#pragma mark - Objective-C init methods (not in SVG Spec - you're supposed to use SVGDocument's createXXX methods instead)
|
||||
/** Designated initializers - 2 pairs (one for DOM 1, no namespace, the other for DOM 2, with namespace) of 2 methods (one for nodes that REQUIRE a value, the other for nodes that MUST NOT have a value) */
|
||||
- (id)initType:(DOMNodeType) nt name:(NSString*) n;
|
||||
- (id)initType:(DOMNodeType) nt name:(NSString*) n value:(NSString*) v;
|
||||
- (id)initType:(DOMNodeType) nt name:(NSString*) n inNamespace:(NSString*) nsURI;
|
||||
- (id)initType:(DOMNodeType) nt name:(NSString*) n value:(NSString*) v inNamespace:(NSString*) nsURI;
|
||||
|
||||
#pragma mark - Objective-C serialization method to serialize a DOM tree back to XML (used heavily in SVGKit's output/conversion features)
|
||||
|
||||
/** EXPERIMENTAL: not fully implemented or tested - this correctly outputs most SVG files, but is missing esoteric
|
||||
features such as EntityReferences, currently they are simply ignored
|
||||
|
||||
This method should be used hand-in-hand with the proprietary SVGDocument method "allNamespaces" and the SVGSVGElement method "
|
||||
|
||||
@param outputString an empty MUTABLE string we can accumulate with output (NB: this method uses a lot of memory, needs to accumulate data)
|
||||
|
||||
@param prefixesByKNOWNNamespace (required): a dictionary mapping "XML namespace URI" to "prefix to use inside the xml-tags", e.g. "http://w3.org/2000/svg" usually is mapped to "svg" (or to "", signifying it's the default namespace). This MUST include ALL NAMESPACES FOUND IN THE DOCUMENT (it's recommended you use SVGDocument's "allPrefixesByNamespace" method, and some post-processing, to get an accurate input here)
|
||||
|
||||
@param prefixesByACTIVENamespace (required): a mutable dictionary listing which elements of the other dictionary are active in-scope - i.e. which namespaces have been output by this node or a higher node in the tree. You pass-in an empty dictionary to the root SVG node and it fills it in as required.
|
||||
*/
|
||||
-(void) appendXMLToString:(NSMutableString*) outputString availableNamespaces:(NSDictionary*) prefixesByKNOWNNamespace activeNamespaces:(NSMutableDictionary*) prefixesByACTIVENamespace;
|
||||
|
||||
@end
|
@ -1,642 +0,0 @@
|
||||
//
|
||||
// Node.m
|
||||
// SVGKit
|
||||
//
|
||||
// Created by adam on 22/05/2012.
|
||||
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import "Node.h"
|
||||
#import "Node+Mutable.h"
|
||||
|
||||
#import "NodeList+Mutable.h"
|
||||
#import "NamedNodeMap.h"
|
||||
|
||||
#import "NamedNodeMap_Iterable.h" // Needed for the optional (non-SVG spec) "recursive toXML" method
|
||||
|
||||
@implementation Node
|
||||
|
||||
@synthesize nodeName;
|
||||
@synthesize nodeValue;
|
||||
|
||||
@synthesize nodeType;
|
||||
@synthesize parentNode;
|
||||
@synthesize childNodes;
|
||||
@synthesize attributes;
|
||||
|
||||
// Modified in DOM Level 2:
|
||||
@synthesize ownerDocument;
|
||||
|
||||
@synthesize hasAttributes, hasChildNodes;
|
||||
|
||||
@synthesize localName;
|
||||
|
||||
|
||||
- (id)init
|
||||
{
|
||||
NSAssert( FALSE, @"This class has no init method - it MUST NOT be init'd via init - you MUST use one of the multi-argument constructors instead" );
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (id)initType:(DOMNodeType) nt name:(NSString*) n value:(NSString*) v
|
||||
{
|
||||
if( [v isKindOfClass:[NSMutableString class]])
|
||||
{
|
||||
/** Apple allows this, but it breaks the whole of Obj-C / cocoa, which is damn stupid
|
||||
So we have to fix it.*/
|
||||
v = [NSString stringWithString:v];
|
||||
}
|
||||
|
||||
self = [super init];
|
||||
if (self) {
|
||||
self.nodeType = nt;
|
||||
switch( nt )
|
||||
{
|
||||
|
||||
case DOMNodeType_ATTRIBUTE_NODE:
|
||||
case DOMNodeType_CDATA_SECTION_NODE:
|
||||
case DOMNodeType_COMMENT_NODE:
|
||||
case DOMNodeType_PROCESSING_INSTRUCTION_NODE:
|
||||
case DOMNodeType_TEXT_NODE:
|
||||
{
|
||||
self.nodeName = n;
|
||||
self.nodeValue = v;
|
||||
}break;
|
||||
|
||||
|
||||
case DOMNodeType_DOCUMENT_NODE:
|
||||
case DOMNodeType_DOCUMENT_TYPE_NODE:
|
||||
case DOMNodeType_DOCUMENT_FRAGMENT_NODE:
|
||||
case DOMNodeType_ENTITY_REFERENCE_NODE:
|
||||
case DOMNodeType_ENTITY_NODE:
|
||||
case DOMNodeType_NOTATION_NODE:
|
||||
case DOMNodeType_ELEMENT_NODE:
|
||||
{
|
||||
NSAssert( FALSE, @"NodeType = %i cannot be init'd with a value; nodes of that type have no value in the DOM spec", nt);
|
||||
|
||||
self = nil;
|
||||
}break;
|
||||
}
|
||||
|
||||
self.childNodes = [[NodeList alloc] init];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initType:(DOMNodeType) nt name:(NSString*) n
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
self.nodeType = nt;
|
||||
switch( nt )
|
||||
{
|
||||
|
||||
case DOMNodeType_ATTRIBUTE_NODE:
|
||||
case DOMNodeType_CDATA_SECTION_NODE:
|
||||
case DOMNodeType_COMMENT_NODE:
|
||||
case DOMNodeType_PROCESSING_INSTRUCTION_NODE:
|
||||
case DOMNodeType_TEXT_NODE:
|
||||
{
|
||||
NSAssert( FALSE, @"NodeType = %i cannot be init'd without a value; nodes of that type MUST have a value in the DOM spec", nt);
|
||||
|
||||
self = nil;
|
||||
}break;
|
||||
|
||||
|
||||
case DOMNodeType_DOCUMENT_NODE:
|
||||
case DOMNodeType_DOCUMENT_TYPE_NODE:
|
||||
case DOMNodeType_DOCUMENT_FRAGMENT_NODE:
|
||||
case DOMNodeType_ENTITY_REFERENCE_NODE:
|
||||
case DOMNodeType_ENTITY_NODE:
|
||||
case DOMNodeType_NOTATION_NODE:
|
||||
{
|
||||
self.nodeName = n;
|
||||
}break;
|
||||
|
||||
case DOMNodeType_ELEMENT_NODE:
|
||||
{
|
||||
|
||||
self.nodeName = n;
|
||||
|
||||
self.attributes = [[NamedNodeMap alloc] init];
|
||||
}break;
|
||||
}
|
||||
|
||||
self.childNodes = [[NodeList alloc] init];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Objective-C init methods DOM LEVEL 2 (preferred init - safer/better!)
|
||||
-(void) postInitNamespaceHandling:(NSString*) nsURI
|
||||
{
|
||||
NSArray* nameSpaceParts = [self.nodeName componentsSeparatedByString:@":"];
|
||||
self.localName = [nameSpaceParts lastObject];
|
||||
if( [nameSpaceParts count] > 1 )
|
||||
self.prefix = [nameSpaceParts objectAtIndex:0];
|
||||
|
||||
self.namespaceURI = nsURI;
|
||||
}
|
||||
|
||||
- (id)initType:(DOMNodeType) nt name:(NSString*) n inNamespace:(NSString*) nsURI
|
||||
{
|
||||
self = [self initType:nt name:n];
|
||||
|
||||
if( self )
|
||||
{
|
||||
[self postInitNamespaceHandling:nsURI];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initType:(DOMNodeType) nt name:(NSString*) n value:(NSString*) v inNamespace:(NSString*) nsURI
|
||||
{
|
||||
if( [v isKindOfClass:[NSMutableString class]])
|
||||
{
|
||||
/** Apple allows this, but it breaks the whole of Obj-C / cocoa, which is damn stupid
|
||||
So we have to fix it.*/
|
||||
v = [NSString stringWithString:v];
|
||||
}
|
||||
|
||||
self = [self initType:nt name:n value:v];
|
||||
|
||||
if( self )
|
||||
{
|
||||
[self postInitNamespaceHandling:nsURI];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - Official DOM method implementations
|
||||
|
||||
-(Node *)firstChild
|
||||
{
|
||||
if( [self.childNodes length] < 1 )
|
||||
return nil;
|
||||
else
|
||||
return [self.childNodes item:0];
|
||||
}
|
||||
|
||||
-(Node *)lastChild
|
||||
{
|
||||
if( [self.childNodes length] < 1 )
|
||||
return nil;
|
||||
else
|
||||
return [self.childNodes item: [self.childNodes length] - 1];
|
||||
}
|
||||
|
||||
-(Node *)previousSibling
|
||||
{
|
||||
if( self.parentNode == nil )
|
||||
return nil;
|
||||
else
|
||||
{
|
||||
NSUInteger indexInParent = [self.parentNode.childNodes.internalArray indexOfObject:self];
|
||||
|
||||
if( indexInParent < 1 )
|
||||
return nil;
|
||||
else
|
||||
return [self.parentNode.childNodes item:indexInParent-1];
|
||||
}
|
||||
}
|
||||
|
||||
-(Node *)nextSibling
|
||||
{
|
||||
if( self.parentNode == nil )
|
||||
return nil;
|
||||
else
|
||||
{
|
||||
NSUInteger indexInParent = [self.parentNode.childNodes.internalArray indexOfObject:self];
|
||||
|
||||
if( indexInParent >= [self.parentNode.childNodes length] )
|
||||
return nil;
|
||||
else
|
||||
return [self.parentNode.childNodes item:indexInParent + 1];
|
||||
}
|
||||
}
|
||||
|
||||
-(Node*) insertBefore:(Node*) newChild refChild:(Node*) refChild
|
||||
{
|
||||
if( refChild == nil )
|
||||
{
|
||||
[self.childNodes.internalArray addObject:newChild];
|
||||
newChild.parentNode = self;
|
||||
}
|
||||
else
|
||||
{
|
||||
[self.childNodes.internalArray insertObject:newChild atIndex:[self.childNodes.internalArray indexOfObject:refChild]];
|
||||
}
|
||||
|
||||
return newChild;
|
||||
}
|
||||
|
||||
-(Node*) replaceChild:(Node*) newChild oldChild:(Node*) oldChild
|
||||
{
|
||||
if( newChild.nodeType == DOMNodeType_DOCUMENT_FRAGMENT_NODE )
|
||||
{
|
||||
/** Spec:
|
||||
|
||||
"If newChild is a DocumentFragment object, oldChild is replaced by all of the DocumentFragment children, which are inserted in the same order. If the newChild is already in the tree, it is first removed."
|
||||
*/
|
||||
|
||||
NSUInteger oldIndex = [self.childNodes.internalArray indexOfObject:oldChild];
|
||||
|
||||
NSAssert( FALSE, @"We should be recursing down the tree to find 'newChild' at any location, and removing it - required by spec - but we have no convenience method for that search, yet" );
|
||||
|
||||
for( Node* child in newChild.childNodes.internalArray )
|
||||
{
|
||||
[self.childNodes.internalArray insertObject:child atIndex:oldIndex++];
|
||||
}
|
||||
|
||||
newChild.parentNode = self;
|
||||
oldChild.parentNode = nil;
|
||||
|
||||
return oldChild;
|
||||
}
|
||||
else
|
||||
{
|
||||
[self.childNodes.internalArray replaceObjectAtIndex:[self.childNodes.internalArray indexOfObject:oldChild] withObject:newChild];
|
||||
|
||||
newChild.parentNode = self;
|
||||
oldChild.parentNode = nil;
|
||||
|
||||
return oldChild;
|
||||
}
|
||||
}
|
||||
-(Node*) removeChild:(Node*) oldChild
|
||||
{
|
||||
[self.childNodes.internalArray removeObject:oldChild];
|
||||
|
||||
oldChild.parentNode = nil;
|
||||
|
||||
return oldChild;
|
||||
}
|
||||
|
||||
-(Node*) appendChild:(Node*) newChild
|
||||
{
|
||||
[self.childNodes.internalArray removeObject:newChild]; // required by spec
|
||||
[self.childNodes.internalArray addObject:newChild];
|
||||
|
||||
newChild.parentNode = self;
|
||||
|
||||
return newChild;
|
||||
}
|
||||
|
||||
-(BOOL)hasChildNodes
|
||||
{
|
||||
return (self.childNodes.length > 0);
|
||||
}
|
||||
|
||||
-(Node*) cloneNode:(BOOL) deep
|
||||
{
|
||||
NSAssert( FALSE, @"Not implemented yet - read the spec. Sounds tricky. I'm too tired, and would probably screw it up right now" );
|
||||
return nil;
|
||||
}
|
||||
|
||||
// Modified in DOM Level 2:
|
||||
-(void) normalize
|
||||
{
|
||||
NSAssert( FALSE, @"Not implemented yet - read the spec. Sounds tricky. I'm too tired, and would probably screw it up right now" );
|
||||
}
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
-(BOOL) isSupportedFeature:(NSString*) feature version:(NSString*) version
|
||||
{
|
||||
NSAssert( FALSE, @"Not implemented yet - read the spec. I have literally no idea what this is supposed to do." );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
@synthesize namespaceURI;
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
@synthesize prefix;
|
||||
|
||||
// Introduced in DOM Level 2:
|
||||
-(BOOL)hasAttributes
|
||||
{
|
||||
if( self.attributes == nil )
|
||||
return FALSE;
|
||||
|
||||
return (self.attributes.length > 0 );
|
||||
}
|
||||
|
||||
#pragma mark - SPECIAL CASE: DOM level 3 method
|
||||
|
||||
/**
|
||||
|
||||
Note that the DOM 3 spec defines this as RECURSIVE:
|
||||
|
||||
http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#Node3-textContent
|
||||
*/
|
||||
-(NSString *)textContent
|
||||
{
|
||||
switch( self.nodeType )
|
||||
{
|
||||
case DOMNodeType_ELEMENT_NODE:
|
||||
case DOMNodeType_ATTRIBUTE_NODE:
|
||||
case DOMNodeType_ENTITY_NODE:
|
||||
case DOMNodeType_ENTITY_REFERENCE_NODE:
|
||||
case DOMNodeType_DOCUMENT_FRAGMENT_NODE:
|
||||
{
|
||||
/** DOM 3 Spec:
|
||||
"concatenation of the textContent attribute value of every child node, excluding COMMENT_NODE and PROCESSING_INSTRUCTION_NODE nodes. This is the empty string if the node has no children."
|
||||
*/
|
||||
NSMutableString* stringAccumulator = [[NSMutableString alloc] init];
|
||||
for( Node* subNode in self.childNodes.internalArray )
|
||||
{
|
||||
NSString* subText = subNode.textContent; // don't call this method twice; it's expensive to calculate!
|
||||
if( subText != nil ) // Yes, really: Apple docs require that you never append a nil substring. Sigh
|
||||
[stringAccumulator appendString:subText];
|
||||
}
|
||||
|
||||
return [NSString stringWithString:stringAccumulator];
|
||||
}
|
||||
|
||||
case DOMNodeType_TEXT_NODE:
|
||||
case DOMNodeType_CDATA_SECTION_NODE:
|
||||
case DOMNodeType_COMMENT_NODE:
|
||||
case DOMNodeType_PROCESSING_INSTRUCTION_NODE:
|
||||
{
|
||||
return self.nodeValue; // should never be nil; anything with a valid value will be at least an empty string i.e. ""
|
||||
}
|
||||
|
||||
case DOMNodeType_DOCUMENT_NODE:
|
||||
case DOMNodeType_NOTATION_NODE:
|
||||
case DOMNodeType_DOCUMENT_TYPE_NODE:
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - ADDITIONAL to SVG Spec: useful debug / output / description methods
|
||||
|
||||
-(NSString *)description
|
||||
{
|
||||
NSString* nodeTypeName;
|
||||
switch( self.nodeType )
|
||||
{
|
||||
case DOMNodeType_ELEMENT_NODE:
|
||||
nodeTypeName = @"ELEMENT";
|
||||
break;
|
||||
case DOMNodeType_TEXT_NODE:
|
||||
nodeTypeName = @"TEXT";
|
||||
break;
|
||||
case DOMNodeType_ENTITY_NODE:
|
||||
nodeTypeName = @"ENTITY";
|
||||
break;
|
||||
case DOMNodeType_COMMENT_NODE:
|
||||
nodeTypeName = @"COMMENT";
|
||||
break;
|
||||
case DOMNodeType_DOCUMENT_NODE:
|
||||
nodeTypeName = @"DOCUMENT";
|
||||
break;
|
||||
case DOMNodeType_NOTATION_NODE:
|
||||
nodeTypeName = @"NOTATION";
|
||||
break;
|
||||
case DOMNodeType_ATTRIBUTE_NODE:
|
||||
nodeTypeName = @"ATTRIBUTE";
|
||||
break;
|
||||
case DOMNodeType_CDATA_SECTION_NODE:
|
||||
nodeTypeName = @"CDATA";
|
||||
break;
|
||||
case DOMNodeType_DOCUMENT_TYPE_NODE:
|
||||
nodeTypeName = @"DOC TYPE";
|
||||
break;
|
||||
case DOMNodeType_ENTITY_REFERENCE_NODE:
|
||||
nodeTypeName = @"ENTITY REF";
|
||||
break;
|
||||
case DOMNodeType_DOCUMENT_FRAGMENT_NODE:
|
||||
nodeTypeName = @"DOC FRAGMENT";
|
||||
break;
|
||||
case DOMNodeType_PROCESSING_INSTRUCTION_NODE:
|
||||
nodeTypeName = @"PROCESSING INSTRUCTION";
|
||||
break;
|
||||
|
||||
default:
|
||||
nodeTypeName = @"N/A (DATA IS MISSING FROM NODE INSTANCE)";
|
||||
}
|
||||
return [NSString stringWithFormat:@"Node: %@ (%@) value:[%@] @@%ld attributes + %ld x children", self.nodeName, nodeTypeName, [self.nodeValue length]<11 ? self.nodeValue : [NSString stringWithFormat:@"%@...",[self.nodeValue substringToIndex:10]], self.attributes.length, (unsigned long)self.childNodes.length];
|
||||
}
|
||||
|
||||
#pragma mark - Objective-C serialization method to serialize a DOM tree back to XML (used heavily in SVGKit's output/conversion features)
|
||||
|
||||
/** EXPERIMENTAL: not fully implemented or tested - this correctly outputs most SVG files, but is missing esoteric
|
||||
features such as EntityReferences, currently they are simply ignored
|
||||
|
||||
This method should be used hand-in-hand with the proprietary SVGDocument method "allNamespaces" and the SVGSVGElement method "
|
||||
|
||||
@param outputString an empty MUTABLE string we can accumulate with output (NB: this method uses a lot of memory, needs to accumulate data)
|
||||
|
||||
@param prefixesByKNOWNNamespace (required): a dictionary mapping "XML namespace URI" to "prefix to use inside the xml-tags", e.g. "http://w3.org/2000/svg" usually is mapped to "svg" (or to "", signifying it's the default namespace). This MUST include ALL NAMESPACES FOUND IN THE DOCUMENT (it's recommended you use SVGDocument's "allPrefixesByNamespace" method, and some post-processing, to get an accurate input here)
|
||||
|
||||
@param prefixesByACTIVENamespace (required): a mutable dictionary listing which elements of the other dictionary are active in-scope - i.e. which namespaces have been output by this node or a higher node in the tree. You pass-in an empty dictionary to the root SVG node and it fills it in as required.
|
||||
*/
|
||||
-(void) appendXMLToString:(NSMutableString*) outputString availableNamespaces:(NSDictionary*) prefixesByKNOWNNamespace activeNamespaces:(NSMutableDictionary*) prefixesByACTIVENamespace
|
||||
{
|
||||
// NSAssert(namespaceShortnames != nil, @"Must supply an empty dictionary for me to fill with encountered namespaces, and the shortnames I invented for them!");
|
||||
|
||||
/** Opening */
|
||||
switch( self.nodeType )
|
||||
{
|
||||
case DOMNodeType_ATTRIBUTE_NODE:
|
||||
{
|
||||
// ?
|
||||
}break;
|
||||
|
||||
case DOMNodeType_CDATA_SECTION_NODE:
|
||||
{
|
||||
[outputString appendFormat:@"<!--"];
|
||||
}break;
|
||||
|
||||
case DOMNodeType_COMMENT_NODE:
|
||||
{
|
||||
[outputString appendFormat:@"<![CDATA["];
|
||||
}break;
|
||||
|
||||
case DOMNodeType_DOCUMENT_FRAGMENT_NODE:
|
||||
case DOMNodeType_DOCUMENT_NODE:
|
||||
case DOMNodeType_ELEMENT_NODE:
|
||||
{
|
||||
[outputString appendFormat:@"<%@", self.nodeName];
|
||||
}break;
|
||||
|
||||
case DOMNodeType_DOCUMENT_TYPE_NODE:
|
||||
case DOMNodeType_ENTITY_NODE:
|
||||
case DOMNodeType_ENTITY_REFERENCE_NODE:
|
||||
case DOMNodeType_NOTATION_NODE:
|
||||
case DOMNodeType_PROCESSING_INSTRUCTION_NODE:
|
||||
case DOMNodeType_TEXT_NODE:
|
||||
{
|
||||
// ?
|
||||
}break;
|
||||
}
|
||||
|
||||
/** ATTRIBUTES on the node (generally only applies to things of type "DOMNodeType_ELEMENT_NODE") */
|
||||
NSDictionary* nodeMapsByNamespace = [self.attributes allNodesUnsortedDOM2];
|
||||
NSMutableDictionary* newlyActivatedPrefixesByNamespace = [NSMutableDictionary dictionary];
|
||||
/**
|
||||
First, find all the attributes that declare a new Namespace at this point */
|
||||
NSString* xmlnsNamespace = @"http://www.w3.org/2000/xmlns/";
|
||||
NSDictionary* xmlnsNodemap = [nodeMapsByNamespace objectForKey:xmlnsNamespace];
|
||||
/** ... output them, making them 'active' in the output tree */
|
||||
for( NSString* xmlnsNodeName in xmlnsNodemap )
|
||||
{
|
||||
Node* attribute = [xmlnsNodemap objectForKey:xmlnsNodeName];
|
||||
|
||||
if( [prefixesByACTIVENamespace objectForKey:xmlnsNodeName] == nil )
|
||||
{
|
||||
[newlyActivatedPrefixesByNamespace setObject:xmlnsNodeName forKey:attribute.nodeValue];
|
||||
if( xmlnsNodeName.length == 0 ) // special case: the "default" namespace we encode elsewhere in SVGKit as a namespace of ""
|
||||
[outputString appendFormat:@" xmlns=\"%@\"", attribute.nodeValue];
|
||||
else
|
||||
[outputString appendFormat:@" xmlns:%@=\"%@\"", xmlnsNodeName, attribute.nodeValue];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Second, process "all" attributes, by namespace. Any time we find an attribute that "needs" a new
|
||||
namespace, we ACTIVATE it, and store it in the set of newly-activated namespaces.
|
||||
|
||||
We will later replace our current "active" set with this new "active" set before we recurse to our
|
||||
child nodes
|
||||
*/
|
||||
for( NSString* namespace in nodeMapsByNamespace )
|
||||
{
|
||||
if( [namespace isEqualToString:xmlnsNamespace] )
|
||||
continue; // we had to handle this FIRST, so we've already done it
|
||||
|
||||
NSString* localPrefix = [prefixesByACTIVENamespace objectForKey:namespace];
|
||||
if( localPrefix == nil )
|
||||
{
|
||||
/** check if it's one of our freshly-activated ones */
|
||||
localPrefix = [newlyActivatedPrefixesByNamespace objectForKey:namespace];
|
||||
}
|
||||
|
||||
if( localPrefix == nil )
|
||||
{
|
||||
/** If it STILL isn't active, (no parent Node has output it yet), we must activate it */
|
||||
|
||||
localPrefix = [prefixesByKNOWNNamespace objectForKey:namespace];
|
||||
|
||||
NSAssert( localPrefix != nil, @"Found a namespace (%@) in node (%@) which wasn't listed in the KNOWN namespaces you provided (%@); you MUST provide a COMPLETE list of known-namespaces to this method", namespace, self.nodeName, prefixesByKNOWNNamespace );
|
||||
|
||||
[newlyActivatedPrefixesByNamespace setObject:localPrefix forKey:namespace];
|
||||
[outputString appendFormat:@" xmlns:%@=\"%@\"", localPrefix, namespace];
|
||||
}
|
||||
|
||||
/** Finally: output the plain-old-attributes, overwriting their prefixes where necessary */
|
||||
NSDictionary* nodeMap = [nodeMapsByNamespace objectForKey:namespace];
|
||||
for( NSString* nodeNameFromMap in nodeMap )
|
||||
{
|
||||
Node* attribute = [nodeMap objectForKey:nodeNameFromMap];
|
||||
|
||||
attribute.prefix = localPrefix; /** Overrides any default pre-existing value */
|
||||
|
||||
[outputString appendFormat:@" %@=\"%@\"", attribute.nodeName, attribute.nodeValue];
|
||||
}
|
||||
}
|
||||
/** Post-processing: after ATTRIBUTES, we need to modify the "ACTIVE" set of namespaces we're passing-down
|
||||
to our child nodes
|
||||
|
||||
Create a NEW dictionary to pass to our descendents, so that our ancestors don't get to see it
|
||||
*/
|
||||
prefixesByACTIVENamespace = [NSMutableDictionary dictionaryWithDictionary:prefixesByACTIVENamespace];
|
||||
[prefixesByACTIVENamespace addEntriesFromDictionary:newlyActivatedPrefixesByNamespace];
|
||||
switch( self.nodeType )
|
||||
{
|
||||
case DOMNodeType_ATTRIBUTE_NODE:
|
||||
case DOMNodeType_CDATA_SECTION_NODE:
|
||||
case DOMNodeType_COMMENT_NODE:
|
||||
{
|
||||
// nothing
|
||||
}break;
|
||||
|
||||
case DOMNodeType_DOCUMENT_FRAGMENT_NODE:
|
||||
case DOMNodeType_DOCUMENT_NODE:
|
||||
case DOMNodeType_ELEMENT_NODE:
|
||||
{
|
||||
[outputString appendString:@">"];
|
||||
}break;
|
||||
|
||||
case DOMNodeType_DOCUMENT_TYPE_NODE:
|
||||
case DOMNodeType_ENTITY_NODE:
|
||||
case DOMNodeType_ENTITY_REFERENCE_NODE:
|
||||
case DOMNodeType_NOTATION_NODE:
|
||||
case DOMNodeType_PROCESSING_INSTRUCTION_NODE:
|
||||
case DOMNodeType_TEXT_NODE:
|
||||
{
|
||||
// nothing
|
||||
}break;
|
||||
}
|
||||
|
||||
/** Middle: include child nodes (only applies to some nodes - others will have values, others will have simply "zero children") */
|
||||
switch( self.nodeType )
|
||||
{
|
||||
case DOMNodeType_ATTRIBUTE_NODE:
|
||||
case DOMNodeType_CDATA_SECTION_NODE:
|
||||
case DOMNodeType_COMMENT_NODE:
|
||||
case DOMNodeType_DOCUMENT_TYPE_NODE:
|
||||
case DOMNodeType_ENTITY_NODE:
|
||||
case DOMNodeType_ENTITY_REFERENCE_NODE:
|
||||
case DOMNodeType_NOTATION_NODE:
|
||||
case DOMNodeType_PROCESSING_INSTRUCTION_NODE:
|
||||
case DOMNodeType_TEXT_NODE:
|
||||
{
|
||||
[outputString appendString:self.nodeValue];
|
||||
}break;
|
||||
|
||||
case DOMNodeType_DOCUMENT_FRAGMENT_NODE:
|
||||
case DOMNodeType_DOCUMENT_NODE:
|
||||
case DOMNodeType_ELEMENT_NODE:
|
||||
{
|
||||
for( Node* child in self.childNodes )
|
||||
{
|
||||
[child appendXMLToString:outputString availableNamespaces:prefixesByKNOWNNamespace activeNamespaces:prefixesByACTIVENamespace];
|
||||
}
|
||||
}break;
|
||||
}
|
||||
|
||||
/** End: close any nodes that opened an XML tag, or an XML comment or CDATA, during Opening */
|
||||
switch( self.nodeType )
|
||||
{
|
||||
case DOMNodeType_ATTRIBUTE_NODE:
|
||||
{
|
||||
// nothing
|
||||
}break;
|
||||
|
||||
case DOMNodeType_CDATA_SECTION_NODE:
|
||||
{
|
||||
[outputString appendFormat:@"-->"];
|
||||
}break;
|
||||
|
||||
case DOMNodeType_COMMENT_NODE:
|
||||
{
|
||||
[outputString appendFormat:@"]]>"];
|
||||
}break;
|
||||
|
||||
case DOMNodeType_DOCUMENT_FRAGMENT_NODE:
|
||||
case DOMNodeType_DOCUMENT_NODE:
|
||||
case DOMNodeType_ELEMENT_NODE:
|
||||
{
|
||||
[outputString appendFormat:@"</%@>", self.nodeName];
|
||||
}break;
|
||||
|
||||
case DOMNodeType_DOCUMENT_TYPE_NODE:
|
||||
case DOMNodeType_ENTITY_NODE:
|
||||
case DOMNodeType_ENTITY_REFERENCE_NODE:
|
||||
case DOMNodeType_NOTATION_NODE:
|
||||
case DOMNodeType_PROCESSING_INSTRUCTION_NODE:
|
||||
case DOMNodeType_TEXT_NODE:
|
||||
{
|
||||
// nothing
|
||||
}break;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
@ -1,11 +0,0 @@
|
||||
/**
|
||||
Makes the writable properties all package-private, effectively
|
||||
*/
|
||||
|
||||
#import "NodeList.h"
|
||||
|
||||
@interface NodeList()
|
||||
|
||||
@property(nonatomic,strong) NSMutableArray* internalArray;
|
||||
|
||||
@end
|
@ -1,28 +0,0 @@
|
||||
/*
|
||||
Implemented internally via an NSArray
|
||||
|
||||
NB: contains a slight "upgrade" from the SVG Spec to make it support Objective-C's
|
||||
Fast Enumeration feature
|
||||
|
||||
From SVG DOM, via CoreDOM:
|
||||
|
||||
http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-536297177
|
||||
|
||||
interface NodeList {
|
||||
Node item(in unsigned long index);
|
||||
readonly attribute unsigned long length;
|
||||
};
|
||||
|
||||
*/
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class Node;
|
||||
#import "Node.h"
|
||||
|
||||
@interface NodeList : NSObject <NSFastEnumeration>
|
||||
|
||||
@property(readonly) NSUInteger length;
|
||||
|
||||
-(Node*) item:(NSUInteger) index;
|
||||
|
||||
@end
|
@ -1,42 +0,0 @@
|
||||
#import "NodeList.h"
|
||||
#import "NodeList+Mutable.h"
|
||||
|
||||
@implementation NodeList
|
||||
|
||||
@synthesize internalArray;
|
||||
|
||||
- (id)init {
|
||||
self = [super init];
|
||||
|
||||
if (self) {
|
||||
self.internalArray = [NSMutableArray array];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
-(Node*) item:(NSUInteger) index
|
||||
{
|
||||
return [self.internalArray objectAtIndex:index];
|
||||
}
|
||||
|
||||
-(NSUInteger)length
|
||||
{
|
||||
return [self.internalArray count];
|
||||
}
|
||||
|
||||
#pragma mark - ADDITIONAL to SVG Spec: Objective-C support for fast-iteration ("for * in ..." syntax)
|
||||
|
||||
-(NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id __unsafe_unretained [])buffer count:(NSUInteger)len
|
||||
{
|
||||
return [self.internalArray countByEnumeratingWithState:state objects:buffer count:len];
|
||||
}
|
||||
|
||||
#pragma mark - ADDITIONAL to SVG Spec: useful debug / output / description methods
|
||||
|
||||
-(NSString *)description
|
||||
{
|
||||
return [NSString stringWithFormat:@"NodeList: array(%@)", self.internalArray];
|
||||
}
|
||||
|
||||
@end
|
@ -1,25 +0,0 @@
|
||||
/*
|
||||
SVG-DOM, via Core DOM:
|
||||
|
||||
http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-1004215813
|
||||
|
||||
interface ProcessingInstruction : Node {
|
||||
readonly attribute DOMString target;
|
||||
attribute DOMString data;
|
||||
// raises(DOMException) on setting
|
||||
|
||||
};
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
/** objc won't allow this: @class Node;*/
|
||||
#import "Node.h"
|
||||
|
||||
@interface ProcessingInstruction : Node
|
||||
@property(nonatomic,strong,readonly) NSString* target;
|
||||
@property(nonatomic,strong,readonly) NSString* data;
|
||||
|
||||
-(id) initProcessingInstruction:(NSString*) target value:(NSString*) data;
|
||||
|
||||
@end
|
@ -1,31 +0,0 @@
|
||||
//
|
||||
// ProcessingInstruction.m
|
||||
// SVGKit
|
||||
//
|
||||
// Created by adam on 22/05/2012.
|
||||
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ProcessingInstruction.h"
|
||||
|
||||
@interface ProcessingInstruction()
|
||||
@property(nonatomic,strong,readwrite) NSString* target;
|
||||
@property(nonatomic,strong,readwrite) NSString* data;
|
||||
@end
|
||||
|
||||
@implementation ProcessingInstruction
|
||||
|
||||
@synthesize target;
|
||||
@synthesize data;
|
||||
|
||||
-(id) initProcessingInstruction:(NSString*) t value:(NSString*) d
|
||||
{
|
||||
self = [super initType:DOMNodeType_PROCESSING_INSTRUCTION_NODE name:t value:d];
|
||||
if (self) {
|
||||
self.target = t;
|
||||
self.data = d;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
@ -1,29 +0,0 @@
|
||||
/**
|
||||
http://www.w3.org/TR/2000/REC-DOM-Level-2-Style-20001113/stylesheets.html#StyleSheets-StyleSheet
|
||||
|
||||
interface StyleSheet {
|
||||
readonly attribute DOMString type;
|
||||
attribute boolean disabled;
|
||||
readonly attribute Node ownerNode;
|
||||
readonly attribute StyleSheet parentStyleSheet;
|
||||
readonly attribute DOMString href;
|
||||
readonly attribute DOMString title;
|
||||
readonly attribute MediaList media;
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class Node;
|
||||
@class MediaList;
|
||||
|
||||
@interface StyleSheet : NSObject
|
||||
|
||||
@property(nonatomic,strong) NSString* type;
|
||||
@property(nonatomic) BOOL disabled;
|
||||
@property(nonatomic,strong) Node* ownerNode;
|
||||
@property(nonatomic,strong) StyleSheet* parentStyleSheet;
|
||||
@property(nonatomic,strong) NSString* href;
|
||||
@property(nonatomic,strong) NSString* title;
|
||||
@property(nonatomic,strong) MediaList* media;
|
||||
|
||||
@end
|
@ -1,5 +0,0 @@
|
||||
#import "StyleSheet.h"
|
||||
|
||||
@implementation StyleSheet
|
||||
|
||||
@end
|
@ -1,5 +0,0 @@
|
||||
#import "StyleSheetList.h"
|
||||
|
||||
@interface StyleSheetList()
|
||||
@property(nonatomic,strong) NSMutableArray* internalArray;
|
||||
@end
|
@ -1,19 +0,0 @@
|
||||
/**
|
||||
http://www.w3.org/TR/2000/REC-DOM-Level-2-Style-20001113/stylesheets.html#StyleSheets-StyleSheetList
|
||||
|
||||
interface StyleSheetList {
|
||||
readonly attribute unsigned long length;
|
||||
StyleSheet item(in unsigned long index);
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "StyleSheet.h"
|
||||
|
||||
@interface StyleSheetList : NSObject
|
||||
|
||||
@property(nonatomic,readonly) unsigned long length;
|
||||
|
||||
-(StyleSheet*) item:(unsigned long) index;
|
||||
|
||||
@end
|
@ -1,28 +0,0 @@
|
||||
#import "StyleSheetList.h"
|
||||
#import "StyleSheetList+Mutable.h"
|
||||
|
||||
@implementation StyleSheetList
|
||||
|
||||
@synthesize internalArray;
|
||||
|
||||
- (id)init
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
self.internalArray = [NSMutableArray array];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
-(unsigned long)length
|
||||
{
|
||||
return self.internalArray.count;
|
||||
}
|
||||
|
||||
-(StyleSheet*) item:(unsigned long) index
|
||||
{
|
||||
return [self.internalArray objectAtIndex:index];
|
||||
}
|
||||
|
||||
@end
|
@ -1,23 +0,0 @@
|
||||
/*
|
||||
SVG-DOM, via Core DOM:
|
||||
|
||||
http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-1312295772
|
||||
|
||||
interface Text : CharacterData {
|
||||
Text splitText(in unsigned long offset)
|
||||
raises(DOMException);
|
||||
};
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class CharacterData;
|
||||
#import "CharacterData.h"
|
||||
|
||||
@interface Text : CharacterData
|
||||
|
||||
- (id)initWithValue:(NSString*) v;
|
||||
|
||||
-(Text*) splitText:(unsigned long) offset;
|
||||
|
||||
@end
|
@ -1,27 +0,0 @@
|
||||
//
|
||||
// Text.m
|
||||
// SVGKit
|
||||
//
|
||||
// Created by adam on 22/05/2012.
|
||||
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import "Text.h"
|
||||
|
||||
@implementation Text
|
||||
|
||||
- (id)initWithValue:(NSString*) v
|
||||
{
|
||||
self = [super initType:DOMNodeType_TEXT_NODE name:@"#text" value:v];
|
||||
if (self) {
|
||||
|
||||
}
|
||||
return self;
|
||||
}
|
||||
-(Text*) splitText:(unsigned long) offset;
|
||||
{
|
||||
NSAssert( FALSE, @"Not implemented yet" );
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
@ -1,42 +0,0 @@
|
||||
/*!
|
||||
SVGAngle
|
||||
|
||||
http://www.w3.org/TR/SVG/types.html#InterfaceSVGAngle
|
||||
|
||||
// Angle Unit Types
|
||||
const unsigned short SVG_ANGLETYPE_UNKNOWN = 0;
|
||||
const unsigned short SVG_ANGLETYPE_UNSPECIFIED = 1;
|
||||
const unsigned short SVG_ANGLETYPE_DEG = 2;
|
||||
const unsigned short SVG_ANGLETYPE_RAD = 3;
|
||||
const unsigned short SVG_ANGLETYPE_GRAD = 4;
|
||||
|
||||
readonly attribute unsigned short unitType;
|
||||
attribute float value setraises(DOMException);
|
||||
attribute float valueInSpecifiedUnits setraises(DOMException);
|
||||
attribute DOMString valueAsString setraises(DOMException);
|
||||
|
||||
void newValueSpecifiedUnits(in unsigned short unitType, in float valueInSpecifiedUnits) raises(DOMException);
|
||||
void convertToSpecifiedUnits(in unsigned short unitType) raises(DOMException);
|
||||
*/
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface SVGAngle : NSObject
|
||||
|
||||
/*! Angle Unit Types */
|
||||
typedef enum SVGKAngleType
|
||||
{
|
||||
SVG_ANGLETYPE_UNKNOWN = 0,
|
||||
SVG_ANGLETYPE_UNSPECIFIED = 1,
|
||||
SVG_ANGLETYPE_DEG = 2,
|
||||
SVG_ANGLETYPE_RAD = 3,
|
||||
SVG_ANGLETYPE_GRAD = 4
|
||||
} SVGKAngleType;
|
||||
|
||||
@property(nonatomic, readonly) SVGKAngleType unitType;
|
||||
@property(nonatomic) float value;
|
||||
@property(nonatomic) float valueInSpecifiedUnits;
|
||||
@property(nonatomic,strong) NSString* valueAsString;
|
||||
|
||||
-(void) newValueSpecifiedUnits:(SVGKAngleType) unitType valueInSpecifiedUnits:(float) valueInSpecifiedUnits;
|
||||
-(void) convertToSpecifiedUnits:(SVGKAngleType) unitType;
|
||||
@end
|
@ -1,13 +0,0 @@
|
||||
#import "SVGAngle.h"
|
||||
|
||||
@implementation SVGAngle
|
||||
|
||||
@synthesize unitType;
|
||||
@synthesize value;
|
||||
@synthesize valueInSpecifiedUnits;
|
||||
@synthesize valueAsString;
|
||||
|
||||
-(void) newValueSpecifiedUnits:(SVGKAngleType) unitType valueInSpecifiedUnits:(float) valueInSpecifiedUnits { NSAssert( FALSE, @"Not implemented yet" ); }
|
||||
-(void) convertToSpecifiedUnits:(SVGKAngleType) unitType { NSAssert( FALSE, @"Not implemented yet" ); }
|
||||
|
||||
@end
|
@ -1,15 +0,0 @@
|
||||
/**
|
||||
http://www.w3.org/TR/SVG/coords.html#InterfaceSVGAnimatedPreserveAspectRatio
|
||||
|
||||
readonly attribute SVGPreserveAspectRatio baseVal;
|
||||
readonly attribute SVGPreserveAspectRatio animVal;
|
||||
*/
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "SVGPreserveAspectRatio.h"
|
||||
|
||||
@interface SVGAnimatedPreserveAspectRatio : NSObject
|
||||
|
||||
@property(nonatomic,strong) SVGPreserveAspectRatio* baseVal;
|
||||
@property(nonatomic,strong, readonly) SVGPreserveAspectRatio* animVal;
|
||||
|
||||
@end
|
@ -1,28 +0,0 @@
|
||||
#import "SVGAnimatedPreserveAspectRatio.h"
|
||||
|
||||
@implementation SVGAnimatedPreserveAspectRatio
|
||||
|
||||
|
||||
- (id)init
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
self.baseVal = [SVGPreserveAspectRatio new];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
/** TODO: Current implementation (animation not supported anywhere in SVGKit yet) simply returns
|
||||
a copy of self.baseVal --- NOTE: spec REQUIRES you return a copy! It is explicit on this!
|
||||
*/
|
||||
-(SVGPreserveAspectRatio *)animVal
|
||||
{
|
||||
SVGPreserveAspectRatio* cloneOfBase = [SVGPreserveAspectRatio new];
|
||||
|
||||
cloneOfBase.align = self.baseVal.align;
|
||||
cloneOfBase.meetOrSlice = self.baseVal.meetOrSlice;
|
||||
|
||||
return cloneOfBase;
|
||||
}
|
||||
|
||||
@end
|
@ -1,29 +0,0 @@
|
||||
/**
|
||||
http://www.w3.org/TR/SVG/masking.html#InterfaceSVGClipPathElement
|
||||
|
||||
interface SVGClipPathElement : SVGElement,
|
||||
SVGTests,
|
||||
SVGLangSpace,
|
||||
SVGExternalResourcesRequired,
|
||||
SVGStylable,
|
||||
SVGTransformable,
|
||||
SVGUnitTypes {
|
||||
*/
|
||||
|
||||
#import "SVGElement.h"
|
||||
#import "SVGElement_ForParser.h"
|
||||
|
||||
#import "ConverterSVGToCALayer.h"
|
||||
#import "SVGTransformable.h"
|
||||
#import "SVGUnitTypes.h"
|
||||
|
||||
|
||||
// Does NOT implement ConverterSVGToCALayer because <clipPath> elements are never rendered directly; they're only referenced via clip-path attributes in other elements
|
||||
@interface SVGClipPathElement : SVGElement <SVGTransformable, SVGStylable>
|
||||
|
||||
@property(nonatomic, readonly) SVG_UNIT_TYPE clipPathUnits;
|
||||
|
||||
- (CALayer *) newLayer;
|
||||
- (void)layoutLayer:(CALayer *)layer toMaskLayer:(CALayer *)maskThis;
|
||||
|
||||
@end
|
@ -1,81 +0,0 @@
|
||||
#import "SVGClipPathElement.h"
|
||||
|
||||
#import "CALayerWithChildHitTest.h"
|
||||
|
||||
#import "SVGHelperUtilities.h"
|
||||
|
||||
@implementation SVGClipPathElement
|
||||
|
||||
@synthesize clipPathUnits;
|
||||
@synthesize transform; // each SVGElement subclass that conforms to protocol "SVGTransformable" has to re-synthesize this to work around bugs in Apple's Objective-C 2.0 design that don't allow @properties to be extended by categories / protocols
|
||||
|
||||
- (void)postProcessAttributesAddingErrorsTo:(SVGKParseResult *)parseResult {
|
||||
[super postProcessAttributesAddingErrorsTo:parseResult];
|
||||
|
||||
NSError *error = [NSError errorWithDomain:@"SVGKit" code:1 userInfo:[NSDictionary dictionaryWithObjectsAndKeys:
|
||||
@"<clipPath> found in SVG. May render incorrectly with SVGKFastImageView due to Apple bug in CALayer .mask rendering.", NSLocalizedDescriptionKey,
|
||||
nil]];
|
||||
[parseResult addParseErrorRecoverable:error];
|
||||
|
||||
clipPathUnits = SVG_UNIT_TYPE_USERSPACEONUSE;
|
||||
|
||||
NSString *units = [self getAttribute:@"clipPathUnits"];
|
||||
if( units != nil && units.length > 0 ) {
|
||||
if( [units isEqualToString:@"userSpaceOnUse"] )
|
||||
clipPathUnits = SVG_UNIT_TYPE_USERSPACEONUSE;
|
||||
else if( [units isEqualToString:@"objectBoundingBox"] )
|
||||
clipPathUnits = SVG_UNIT_TYPE_OBJECTBOUNDINGBOX;
|
||||
else {
|
||||
SVGKitLogWarn(@"Unknown clipPathUnits value %@", units);
|
||||
NSError *error = [NSError errorWithDomain:@"SVGKit" code:1 userInfo:[NSDictionary dictionaryWithObjectsAndKeys:
|
||||
[NSString stringWithFormat:@"Unknown clipPathUnits value %@", units], NSLocalizedDescriptionKey,
|
||||
nil]];
|
||||
[parseResult addParseErrorRecoverable:error];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (CALayer *) newLayer
|
||||
{
|
||||
|
||||
CALayer* _layer = [CALayerWithChildHitTest layer];
|
||||
|
||||
[SVGHelperUtilities configureCALayer:_layer usingElement:self];
|
||||
|
||||
return _layer;
|
||||
}
|
||||
|
||||
- (void)layoutLayer:(CALayer *)layer toMaskLayer:(CALayer *)maskThis
|
||||
{
|
||||
// null rect union any other rect will return the other rect
|
||||
CGRect mainRect = CGRectNull;
|
||||
|
||||
/** make mainrect the UNION of all sublayer's frames (i.e. their individual "bounds" inside THIS layer's space) */
|
||||
for ( CALayer *currentLayer in [layer sublayers] )
|
||||
{
|
||||
mainRect = CGRectUnion(mainRect, currentLayer.frame);
|
||||
}
|
||||
|
||||
/** Changing THIS layer's frame now means all DIRECT sublayers are offset by too much (because when we change the offset
|
||||
of the parent frame (this.frame), Apple *does not* shift the sublayers around to keep them in same place.
|
||||
|
||||
NB: there are bugs in some Apple code in Interface Builder where it attempts to do exactly that (incorrectly, as the API
|
||||
is specifically designed NOT to do this), and ... Fails. But in code, thankfully, Apple *almost* never does this (there are a few method
|
||||
calls where it appears someone at Apple forgot how their API works, and tried to do the offsetting automatically. "Paved
|
||||
with good intentions...".
|
||||
*/
|
||||
if (CGRectIsNull(mainRect))
|
||||
{
|
||||
// TODO what to do when mainRect is null rect? i.e. no sublayer or all sublayers have null rect frame
|
||||
} else {
|
||||
for (CALayer *currentLayer in [layer sublayers])
|
||||
currentLayer.frame = CGRectOffset(currentLayer.frame, -mainRect.origin.x, -mainRect.origin.y);
|
||||
}
|
||||
|
||||
// unless we're working in bounding box coords, subtract the owning layer's origin
|
||||
if( self.clipPathUnits == SVG_UNIT_TYPE_USERSPACEONUSE )
|
||||
mainRect = CGRectOffset(mainRect, -maskThis.frame.origin.x, -maskThis.frame.origin.y);
|
||||
layer.frame = mainRect;
|
||||
}
|
||||
|
||||
@end
|
@ -1,9 +0,0 @@
|
||||
/*
|
||||
http://www.w3.org/TR/SVG/struct.html#InterfaceSVGDefsElement
|
||||
|
||||
*/
|
||||
#import "SVGElement.h"
|
||||
|
||||
@interface SVGDefsElement : SVGElement { }
|
||||
|
||||
@end
|
@ -1,5 +0,0 @@
|
||||
#import "SVGDefsElement.h"
|
||||
|
||||
@implementation SVGDefsElement
|
||||
|
||||
@end
|
@ -1,63 +0,0 @@
|
||||
/*
|
||||
SVG DOM, cf:
|
||||
|
||||
http://www.w3.org/TR/SVG11/struct.html#InterfaceSVGDocument
|
||||
|
||||
interface SVGDocument : Document,
|
||||
DocumentEvent {
|
||||
readonly attribute DOMString title;
|
||||
readonly attribute DOMString referrer;
|
||||
readonly attribute DOMString domain;
|
||||
readonly attribute DOMString URL;
|
||||
readonly attribute SVGSVGElement rootElement;
|
||||
};
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "Document.h"
|
||||
#import "SVGSVGElement.h"
|
||||
|
||||
@interface SVGDocument : Document
|
||||
|
||||
@property (nonatomic, strong, readonly) NSString* title;
|
||||
@property (nonatomic, strong, readonly) NSString* referrer;
|
||||
@property (nonatomic, strong, readonly) NSString* domain;
|
||||
@property (nonatomic, strong, readonly) NSString* URL;
|
||||
@property (nonatomic, strong, readonly) SVGSVGElement* rootElement;
|
||||
|
||||
#pragma mark - Objective-C init methods (not part of DOM spec, but necessary!)
|
||||
|
||||
- (id)init;
|
||||
|
||||
#pragma mark - Serialization methods that we think ought to be part of the SVG spec, as they are needed for a good implementation, but we can't find in the main Spec
|
||||
|
||||
/**
|
||||
Recursively goes through the document finding all declared namespaces in-use by any tag or attribute.
|
||||
|
||||
@return a dictionary mapping "namespace" to "ARRAY of prefix-strings"
|
||||
*/
|
||||
-(NSMutableDictionary*) allPrefixesByNamespace;
|
||||
|
||||
/**
|
||||
As per allPrefixesByNamespace, but takes the output and guarantees that:
|
||||
|
||||
1. There is AT MOST ONE namespace with no prefix
|
||||
2. The "prefixless" namespace is the SVG namespace (if possible. This should always be possible for an SVG doc!)
|
||||
3. All other namespaces have EXACTLY ONE prefix (if there are multiple, it discards excess ones)
|
||||
4. All prefixes are UNIQUE (not used by more than one Namespace)
|
||||
|
||||
This is critically important when writing-out an SVG file to disk - As far as I can tell, it's a major ommission from
|
||||
the XML Spec (which SVG sits on top of). Without this info, you can't construct the appropriate/correct "xmlns" directives
|
||||
at the start of a file.
|
||||
|
||||
USAGE INSTRUCTIONS:
|
||||
|
||||
1. Call this method to get the complete list of namespaces, including any prefixes used
|
||||
2. Invoke Node's "appendXMLToString:..." method, passing-in this output, so it can correctly output prefixes for all nodes and subnodes
|
||||
|
||||
@return a dictionary mapping "namespace" to "prefix-string or empty-string for the default namespace"
|
||||
*/
|
||||
-(NSMutableDictionary*) allPrefixesByNamespaceNormalized;
|
||||
|
||||
@end
|
@ -1,177 +0,0 @@
|
||||
/**
|
||||
SVGDocument
|
||||
|
||||
SVG spec defines this as part of the DOM version of SVG:
|
||||
|
||||
http://www.w3.org/TR/SVG11/struct.html#InterfaceSVGDocument
|
||||
*/
|
||||
|
||||
#import "Document+Mutable.h"
|
||||
|
||||
#import "SVGDocument.h"
|
||||
#import "SVGDocument_Mutable.h"
|
||||
|
||||
#import "NamedNodeMap_Iterable.h" // needed for the allPrefixesByNamespace implementation
|
||||
|
||||
@implementation SVGDocument
|
||||
|
||||
|
||||
@synthesize title;
|
||||
@synthesize referrer;
|
||||
@synthesize domain;
|
||||
@synthesize URL;
|
||||
@synthesize rootElement=_rootElement;
|
||||
|
||||
|
||||
|
||||
- (id)init
|
||||
{
|
||||
self = [super initType:DOMNodeType_DOCUMENT_NODE name:@"#document"];
|
||||
if (self) {
|
||||
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
-(void)setRootElement:(SVGSVGElement *)rootElement
|
||||
{
|
||||
_rootElement = rootElement;
|
||||
|
||||
/*! SVG spec has two variables with same name, because DOM was written to support
|
||||
weak programming languages that don't provide full OOP polymorphism.
|
||||
|
||||
So, we'd better keep the two variables in sync!
|
||||
*/
|
||||
super.documentElement = rootElement;
|
||||
}
|
||||
|
||||
-(void)setDocumentElement:(Element *)newDocumentElement
|
||||
{
|
||||
NSAssert( [newDocumentElement isKindOfClass:[SVGSVGElement class]], @"Cannot set the documentElement property on an SVG doc unless it's of type SVGSVGDocument" );
|
||||
|
||||
super.documentElement = newDocumentElement;
|
||||
|
||||
/*! SVG spec has two variables with same name, because DOM was written to support
|
||||
weak programming languages that don't provide full OOP polymorphism.
|
||||
|
||||
So, we'd better keep the two variables in sync!
|
||||
*/
|
||||
self.rootElement = (SVGSVGElement*) self.documentElement;
|
||||
}
|
||||
|
||||
#pragma mark - Serialization methods that we think ought to be part of the SVG spec, as they are needed for a good implementation, but we can't find in the main Spec
|
||||
|
||||
/**
|
||||
Recursively goes through the document finding all declared namespaces in-use by any tag or attribute.
|
||||
|
||||
@return a dictionary mapping "namespace" to "ARRAY of prefix-strings"
|
||||
*/
|
||||
-(NSMutableDictionary*) allPrefixesByNamespace
|
||||
{
|
||||
NSMutableDictionary* result = [NSMutableDictionary dictionary];
|
||||
|
||||
[SVGDocument accumulateNamespacesForNode:self.rootElement intoDictionary:result];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/** implementation of allPrefixesByNamespace - stores "namespace string" : "ARRAY of prefix strings"
|
||||
*/
|
||||
+(void) accumulateNamespacesForNode:(Node*) node intoDictionary:(NSMutableDictionary*) output
|
||||
{
|
||||
/**
|
||||
First, find all the attributes that declare a new Namespace at this point */
|
||||
NSDictionary* nodeMapsByNamespace = [node.attributes allNodesUnsortedDOM2];
|
||||
|
||||
NSString* xmlnsNamespace = @"http://www.w3.org/2000/xmlns/";
|
||||
NSDictionary* xmlnsNodemap = [nodeMapsByNamespace objectForKey:xmlnsNamespace];
|
||||
|
||||
for( NSString* xmlnsNodeName in xmlnsNodemap )
|
||||
{
|
||||
Node* namespaceDeclaration = [xmlnsNodemap objectForKey:xmlnsNodeName];
|
||||
|
||||
NSMutableArray* prefixesForNamespace = [output objectForKey:namespaceDeclaration.nodeValue];
|
||||
if( prefixesForNamespace == nil )
|
||||
{
|
||||
prefixesForNamespace = [NSMutableArray array];
|
||||
[output setObject:prefixesForNamespace forKey:namespaceDeclaration.nodeValue];
|
||||
}
|
||||
|
||||
if( ! [prefixesForNamespace containsObject:namespaceDeclaration.nodeName])
|
||||
[prefixesForNamespace addObject:namespaceDeclaration.localName];
|
||||
}
|
||||
|
||||
for( Node* childNode in node.childNodes )
|
||||
{
|
||||
[self accumulateNamespacesForNode:childNode intoDictionary:output];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
As per allPrefixesByNamespace, but takes the output and guarantees that:
|
||||
|
||||
1. There is AT MOST ONE namespace with no prefix
|
||||
2. The "prefixless" namespace is the SVG namespace (if possible. This should always be possible for an SVG doc!)
|
||||
3. All other namespaces have EXACTLY ONE prefix (if there are multiple, it discards excess ones)
|
||||
4. All prefixes are UNIQUE (not used by more than one Namespace)
|
||||
|
||||
This is critically important when writing-out an SVG file to disk - As far as I can tell, it's a major ommission from
|
||||
the XML Spec (which SVG sits on top of). Without this info, you can't construct the appropriate/correct "xmlns" directives
|
||||
at the start of a file.
|
||||
|
||||
USAGE INSTRUCTIONS:
|
||||
|
||||
1. Call this method to get the complete list of namespaces, including any prefixes used
|
||||
2. Invoke Node's "appendXMLToString:..." method, passing-in this output, so it can correctly output prefixes for all nodes and subnodes
|
||||
|
||||
@return a dictionary mapping "namespace" to "prefix-string or empty-string for the default namespace"
|
||||
*/
|
||||
-(NSMutableDictionary*) allPrefixesByNamespaceNormalized
|
||||
{
|
||||
NSMutableDictionary* prefixArraysByNamespace = [self allPrefixesByNamespace];
|
||||
NSMutableDictionary* normalizedPrefixesByNamespace = [NSMutableDictionary dictionary];
|
||||
|
||||
for( NSString* namespace in prefixArraysByNamespace )
|
||||
{
|
||||
NSArray* prefixes = [prefixArraysByNamespace objectForKey:namespace];
|
||||
|
||||
BOOL exportedAUniquePrefix = FALSE;
|
||||
for( NSString* nextPrefix in prefixes )
|
||||
{
|
||||
if( ! [normalizedPrefixesByNamespace.allValues containsObject:nextPrefix])
|
||||
{
|
||||
[normalizedPrefixesByNamespace setObject:nextPrefix forKey:namespace];
|
||||
exportedAUniquePrefix = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/** If that failed to find a unique prefix, we need to either generate one, or use the default prefix */
|
||||
if( ! exportedAUniquePrefix )
|
||||
{
|
||||
if( [namespace isEqualToString:@"http://w3.org/2000/svg"])
|
||||
{
|
||||
[normalizedPrefixesByNamespace setObject:@"" forKey:namespace];
|
||||
}
|
||||
else
|
||||
{
|
||||
/** Generate a new shortname that will OVERRIDE AND REPLACE whatever prefixes this attribute has */
|
||||
int suffix = 1;
|
||||
NSString* newPrefix = [namespace lastPathComponent];
|
||||
while( [normalizedPrefixesByNamespace.allValues containsObject:newPrefix])
|
||||
{
|
||||
suffix++;
|
||||
|
||||
newPrefix = [NSString stringWithFormat:@"%@-%i", [namespace lastPathComponent], suffix];
|
||||
}
|
||||
|
||||
[normalizedPrefixesByNamespace setObject:newPrefix forKey:namespace];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SVGKitLogVerbose(@"Normalized prefixes:\n%@", normalizedPrefixesByNamespace );
|
||||
return normalizedPrefixesByNamespace;
|
||||
}
|
||||
|
||||
@end
|
@ -1,13 +0,0 @@
|
||||
/**
|
||||
Makes the writable properties all package-private, effectively
|
||||
*/
|
||||
|
||||
#import "SVGDocument.h"
|
||||
|
||||
@interface SVGDocument ()
|
||||
@property (nonatomic, strong, readwrite) NSString* title;
|
||||
@property (nonatomic, strong, readwrite) NSString* referrer;
|
||||
@property (nonatomic, strong, readwrite) NSString* domain;
|
||||
@property (nonatomic, strong, readwrite) NSString* URL;
|
||||
@property (nonatomic, strong, readwrite) SVGSVGElement* rootElement;
|
||||
@end
|
@ -1,61 +0,0 @@
|
||||
/*
|
||||
http://www.w3.org/TR/SVG/struct.html#InterfaceSVGElementInstance
|
||||
|
||||
interface SVGElementInstance : EventTarget {
|
||||
readonly attribute SVGElement correspondingElement;
|
||||
readonly attribute SVGUseElement correspondingUseElement;
|
||||
readonly attribute SVGElementInstance parentNode;
|
||||
readonly attribute SVGElementInstanceList childNodes;
|
||||
readonly attribute SVGElementInstance firstChild;
|
||||
readonly attribute SVGElementInstance lastChild;
|
||||
readonly attribute SVGElementInstance previousSibling;
|
||||
readonly attribute SVGElementInstance nextSibling;
|
||||
*/
|
||||
|
||||
#import "SVGElement.h"
|
||||
#import "SVGElementInstanceList.h"
|
||||
|
||||
@class SVGUseElement;
|
||||
#import "SVGUseElement.h"
|
||||
|
||||
/**
|
||||
ADDITIONAL IMPLEMENTATION NOTES:
|
||||
|
||||
We make the two back-links into the SVG DOM Tree ("correspondingElement" and "correspondingUseElement") weak references to prevent
|
||||
a retain-cycle.
|
||||
|
||||
If you delete parts of the original tree, but don't do anything to update your USE tags / elements, then ... the back-links will
|
||||
become nil. This seems the most rational, "what you would expect", behaviour.
|
||||
*/
|
||||
|
||||
@interface SVGElementInstance : NSObject
|
||||
|
||||
|
||||
/*The corresponding element to which this object is an instance. For example, if a ‘use’ element references a ‘rect’ element, then an SVGElementInstance is created, with its correspondingElement being the SVGRectElement object for the ‘rect’ element. */
|
||||
@property(nonatomic, weak, readonly) SVGElement* correspondingElement;
|
||||
|
||||
|
||||
/* The corresponding ‘use’ element to which this SVGElementInstance object belongs. When ‘use’ elements are nested (e.g., a ‘use’ references another ‘use’ which references a graphics element such as a ‘rect’), then the correspondingUseElement is the outermost ‘use’ (i.e., the one which indirectly references the ‘rect’, not the one with the direct reference). */
|
||||
@property(nonatomic, weak, readonly) SVGUseElement* correspondingUseElement;
|
||||
|
||||
/* The parent of this SVGElementInstance within the instance tree. All SVGElementInstance objects have a parent except the SVGElementInstance which corresponds to the element which was directly referenced by the ‘use’ element, in which case parentNode is null. */
|
||||
@property(nonatomic,strong, readonly) SVGElementInstance* parentNode;
|
||||
|
||||
/* An SVGElementInstanceList that contains all children of this SVGElementInstance within the instance tree. If there are no children, this is an SVGElementInstanceList containing no entries (i.e., an empty list).
|
||||
firstChild (readonly SVGElementInstance) */
|
||||
@property(nonatomic,strong, readonly) SVGElementInstanceList* childNodes;
|
||||
|
||||
|
||||
/* The first child of this SVGElementInstance within the instance tree. If there is no such SVGElementInstance, this returns null. */
|
||||
@property(nonatomic,strong, readonly) SVGElementInstance* firstChild;
|
||||
|
||||
/* The last child of this SVGElementInstance within the instance tree. If there is no such SVGElementInstance, this returns null. */
|
||||
@property(nonatomic,strong, readonly) SVGElementInstance* lastChild;
|
||||
|
||||
/* The SVGElementInstance immediately preceding this SVGElementInstance. If there is no such SVGElementInstance, this returns null. */
|
||||
@property(nonatomic,strong, readonly) SVGElementInstance* previousSibling;
|
||||
|
||||
/* The SVGElementInstance immediately following this SVGElementInstance. If there is no such SVGElementInstance, this returns null. */
|
||||
@property(nonatomic,strong, readonly) SVGElementInstance* nextSibling;
|
||||
|
||||
@end
|
@ -1,86 +0,0 @@
|
||||
#import "SVGElementInstance.h"
|
||||
#import "SVGElementInstance_Mutable.h"
|
||||
|
||||
#import "SVGElementInstanceList_Internal.h"
|
||||
|
||||
@implementation SVGElementInstance
|
||||
|
||||
@synthesize parentNode;
|
||||
@synthesize childNodes;
|
||||
|
||||
- (void)dealloc {
|
||||
self.parentNode = nil;
|
||||
self.correspondingElement = nil;
|
||||
self.correspondingUseElement = nil;
|
||||
}
|
||||
|
||||
-(void)setParentNode:(SVGElementInstance *)newParentNode
|
||||
{
|
||||
if( newParentNode != self.parentNode )
|
||||
{
|
||||
if( newParentNode == nil )
|
||||
{
|
||||
/* additionally remove self from parent's childNodes */
|
||||
[self.parentNode.childNodes.internalArray removeObject:self];
|
||||
|
||||
parentNode = newParentNode;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* additionally ADD self to parent's childNodes */
|
||||
parentNode = newParentNode;
|
||||
|
||||
NSAssert( NSNotFound != [self.parentNode.childNodes.internalArray indexOfObject:self], @"Found that I was already a child of the node that I was being added to - should be impossible!" );
|
||||
|
||||
[self.parentNode.childNodes.internalArray addObject:self];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-(SVGElementInstance *)firstChild
|
||||
{
|
||||
if( [self.childNodes length] < 1 )
|
||||
return nil;
|
||||
else
|
||||
return [self.childNodes item:0];
|
||||
}
|
||||
|
||||
-(SVGElementInstance *)lastChild
|
||||
{
|
||||
if( [self.childNodes length] < 1 )
|
||||
return nil;
|
||||
else
|
||||
return [self.childNodes item: [self.childNodes length] - 1];
|
||||
}
|
||||
|
||||
-(SVGElementInstance *)previousSibling
|
||||
{
|
||||
if( self.parentNode == nil )
|
||||
return nil;
|
||||
else
|
||||
{
|
||||
NSUInteger indexInParent = [self.parentNode.childNodes.internalArray indexOfObject:self];
|
||||
|
||||
if( indexInParent < 1 )
|
||||
return nil;
|
||||
else
|
||||
return [self.parentNode.childNodes item:indexInParent-1];
|
||||
}
|
||||
}
|
||||
|
||||
-(SVGElementInstance *)nextSibling
|
||||
{
|
||||
if( self.parentNode == nil )
|
||||
return nil;
|
||||
else
|
||||
{
|
||||
NSUInteger indexInParent = [self.parentNode.childNodes.internalArray indexOfObject:self];
|
||||
|
||||
if( indexInParent >= [self.parentNode.childNodes length] )
|
||||
return nil;
|
||||
else
|
||||
return [self.parentNode.childNodes item:indexInParent + 1];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
@ -1,21 +0,0 @@
|
||||
/*
|
||||
http://www.w3.org/TR/SVG/struct.html#InterfaceSVGElementInstanceList
|
||||
|
||||
interface SVGElementInstanceList {
|
||||
|
||||
readonly attribute unsigned long length;
|
||||
|
||||
SVGElementInstance item(in unsigned long index);
|
||||
*/
|
||||
|
||||
#import "SVGElement.h"
|
||||
|
||||
@class SVGElementInstance;
|
||||
|
||||
@interface SVGElementInstanceList : SVGElement
|
||||
|
||||
@property(nonatomic, readonly) unsigned long length;
|
||||
|
||||
-(SVGElementInstance*) item:(unsigned long) index;
|
||||
|
||||
@end
|
@ -1,30 +0,0 @@
|
||||
#import "SVGElementInstanceList.h"
|
||||
#import "SVGElementInstanceList_Internal.h"
|
||||
|
||||
@implementation SVGElementInstanceList
|
||||
@synthesize internalArray;
|
||||
|
||||
|
||||
- (id)init
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
self.internalArray = [NSMutableArray array];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
-(unsigned long)length
|
||||
{
|
||||
return [self.internalArray count];
|
||||
}
|
||||
|
||||
-(SVGElementInstance*) item:(unsigned long) index
|
||||
{
|
||||
if( index >= [self.internalArray count] )
|
||||
return nil;
|
||||
|
||||
return [self.internalArray objectAtIndex:index];
|
||||
}
|
||||
|
||||
@end
|
@ -1,15 +0,0 @@
|
||||
//
|
||||
// SVGElementInstanceList_Internal.h
|
||||
// SVGKit-iOS
|
||||
//
|
||||
// Created by adam on 29/09/2012.
|
||||
// Copyright (c) 2012 na. All rights reserved.
|
||||
//
|
||||
|
||||
#import "SVGElementInstanceList.h"
|
||||
|
||||
@interface SVGElementInstanceList ()
|
||||
|
||||
@property(nonatomic,strong) NSMutableArray* internalArray;
|
||||
|
||||
@end
|
@ -1,8 +0,0 @@
|
||||
#import "SVGElementInstance.h"
|
||||
|
||||
@interface SVGElementInstance ()
|
||||
@property(nonatomic,weak, readwrite) SVGElement* correspondingElement;
|
||||
@property(nonatomic,weak, readwrite) SVGUseElement* correspondingUseElement;
|
||||
@property(nonatomic,strong, readwrite) SVGElementInstance* parentNode;
|
||||
@property(nonatomic,strong, readwrite) SVGElementInstanceList* childNodes;
|
||||
@end
|
@ -1,22 +0,0 @@
|
||||
/**
|
||||
* http://www.w3.org/TR/SVG/types.html#InterfaceSVGFitToViewBox
|
||||
|
||||
interface SVGFitToViewBox {
|
||||
readonly attribute SVGAnimatedRect viewBox;
|
||||
readonly attribute SVGAnimatedPreserveAspectRatio preserveAspectRatio;
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
|
||||
#import "SVGRect.h"
|
||||
#import "SVGAnimatedPreserveAspectRatio.h"
|
||||
|
||||
@protocol SVGFitToViewBox <NSObject>
|
||||
|
||||
@property (nonatomic) /* SVGAnimatedRect */ SVGRect viewBox;
|
||||
|
||||
@property(nonatomic,retain) SVGAnimatedPreserveAspectRatio* preserveAspectRatio;
|
||||
|
||||
@end
|
@ -1,21 +0,0 @@
|
||||
/**
|
||||
http://www.w3.org/TR/SVG/struct.html#InterfaceSVGGElement
|
||||
|
||||
interface SVGGElement : SVGElement,
|
||||
SVGTests,
|
||||
SVGLangSpace,
|
||||
SVGExternalResourcesRequired,
|
||||
SVGStylable,
|
||||
SVGTransformable {
|
||||
*/
|
||||
|
||||
#import "SVGElement.h"
|
||||
#import "SVGElement_ForParser.h"
|
||||
|
||||
#import "ConverterSVGToCALayer.h"
|
||||
#import "SVGTransformable.h"
|
||||
|
||||
|
||||
@interface SVGGElement : SVGElement <SVGTransformable, SVGStylable, ConverterSVGToCALayer >
|
||||
|
||||
@end
|
@ -1,71 +0,0 @@
|
||||
#import "SVGGElement.h"
|
||||
|
||||
#import "CALayerWithChildHitTest.h"
|
||||
|
||||
#import "SVGHelperUtilities.h"
|
||||
|
||||
@implementation SVGGElement
|
||||
|
||||
@synthesize transform; // each SVGElement subclass that conforms to protocol "SVGTransformable" has to re-synthesize this to work around bugs in Apple's Objective-C 2.0 design that don't allow @properties to be extended by categories / protocols
|
||||
|
||||
- (CALayer *) newLayer
|
||||
{
|
||||
|
||||
CALayer* _layer = [CALayerWithChildHitTest layer];
|
||||
|
||||
[SVGHelperUtilities configureCALayer:_layer usingElement:self];
|
||||
|
||||
return _layer;
|
||||
}
|
||||
|
||||
- (void)layoutLayer:(CALayer *)layer {
|
||||
|
||||
// null rect union any other rect will return the other rect
|
||||
CGRect mainRect = CGRectNull;
|
||||
|
||||
/** make mainrect the UNION of all sublayer's frames (i.e. their individual "bounds" inside THIS layer's space) */
|
||||
for ( CALayer *currentLayer in [layer sublayers] )
|
||||
{
|
||||
CGRect subLayerFrame = currentLayer.frame;
|
||||
mainRect = CGRectUnion(mainRect, subLayerFrame);
|
||||
}
|
||||
|
||||
NSAssert(!CGRectIsNull(mainRect), @"A G element has been generated with non-existent size and no contents. Apple cannot cope with this. As a workaround, we are resetting your layer to empty, but this may have unwanted side-effects (hard to test)" );
|
||||
if (CGRectIsNull(mainRect))
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
/** use mainrect (union of all sub-layer bounds) this layer's FRAME
|
||||
|
||||
i.e. top-left-corner of this layer will be "the top left corner of the convex-hull rect of all sublayers"
|
||||
AND: bottom-right-corner of this layer will be "the bottom-right corner of the convex-hull rect of all sublayers"
|
||||
*/
|
||||
layer.frame = mainRect;
|
||||
|
||||
/**
|
||||
If this group layer has a mask then since we've adjusted this layer's frame we need to offset the mask's frame by the opposite amount.
|
||||
*/
|
||||
if (layer.mask)
|
||||
layer.mask.frame = CGRectOffset(layer.mask.frame, -mainRect.origin.x, -mainRect.origin.y);
|
||||
|
||||
/** Changing THIS layer's frame now means all DIRECT sublayers are offset by too much (because when we change the offset
|
||||
of the parent frame (this.frame), Apple *does not* shift the sublayers around to keep them in same place.
|
||||
|
||||
NB: there are bugs in some Apple code in Interface Builder where it attempts to do exactly that (incorrectly, as the API
|
||||
is specifically designed NOT to do this), and ... Fails. But in code, thankfully, Apple *almost* never does this (there are a few method
|
||||
calls where it appears someone at Apple forgot how their API works, and tried to do the offsetting automatically. "Paved
|
||||
with good intentions...".
|
||||
*/
|
||||
|
||||
for (CALayer *currentLayer in [layer sublayers]) {
|
||||
CGRect frame = currentLayer.frame;
|
||||
frame.origin.x -= mainRect.origin.x;
|
||||
frame.origin.y -= mainRect.origin.y;
|
||||
currentLayer.frame = frame;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
@ -1,61 +0,0 @@
|
||||
/**
|
||||
To implement the official SVG Spec, some "extra" methods are needed that are SHARED between classes, but
|
||||
which in the SVG Spec the classes aren't subclass/superclass of each other - so that there's no way to
|
||||
implement it without copy/pasting the code.
|
||||
|
||||
To improve maintainability, we put those methods here, and then each place we need them has a 1-line method
|
||||
that delegates to a method body in this class.
|
||||
*/
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
#import "SVGElement.h"
|
||||
#import "SVGTransformable.h"
|
||||
#import "SVGFitToViewBox.h"
|
||||
|
||||
#define FORCE_RASTERIZE_LAYERS 0 // If True, all CALayers will be told to rasterize themselves. This MIGHT increase performance (or might not), but leads to blurriness whenever a layer is scaled / zoomed in
|
||||
#define IMPROVE_PERFORMANCE_BY_WORKING_AROUND_APPLE_FRAME_ALIGNMENT_BUG 1 // NB: Apple's code for rendering ANY CALayer is extremely slow if the layer has non-integer co-ordinates for its "frame" or "bounds" property. This flag technically makes your SVG's render incorrect at sub-pixel level, but often increases performance of Apple's rendering by a factor of 2 or more!
|
||||
@class SVGGradientLayer;
|
||||
@interface SVGHelperUtilities : NSObject
|
||||
|
||||
/**
|
||||
According to the SVG Spec, there are two types of element that affect the on-screen size/shape/position/rotation/skew of shapes/images:
|
||||
|
||||
1. Any ancestor that implements SVGTransformable
|
||||
2. Any "element that establishes a new viewport" - i.e. the <svg> tag and a few others
|
||||
|
||||
This method ONLY looks at current node to establish the above two things, to do a RELATIVE transform (relative to parent node)
|
||||
*/
|
||||
+(CGAffineTransform) transformRelativeIncludingViewportForTransformableOrViewportEstablishingElement:(SVGElement*) transformableOrSVGSVGElement;
|
||||
/**
|
||||
According to the SVG Spec, there are two types of element that affect the on-screen size/shape/position/rotation/skew of shapes/images:
|
||||
|
||||
1. Any ancestor that implements SVGTransformable
|
||||
2. Any "element that establishes a new viewport" - i.e. the <svg> tag and a few others
|
||||
|
||||
This method recurses upwards to combine the above two things for everything in the tree, to establish an ABSOLUTE transform
|
||||
*/
|
||||
+(CGAffineTransform) transformAbsoluteIncludingViewportForTransformableOrViewportEstablishingElement:(SVGElement*) transformableOrSVGSVGElement;
|
||||
|
||||
|
||||
/** Some things - e.g. setting layer's Opacity - have to be done for pretty much EVERY SVGElement; this method automatically looks
|
||||
at the incoming element, uses the protocols that element has (e.g. SVGStylable) to automatically adapt the layer.
|
||||
|
||||
This allows each SVGElement subclass to create a custom CALayer as needed (e.g. CATextLayer for text elements), but share the setup
|
||||
code.
|
||||
|
||||
If compiled with FORCE_RASTERIZE_LAYERS, also tells every layer to rasterize itself
|
||||
*/
|
||||
+(void) configureCALayer:(CALayer*) layer usingElement:(SVGElement*) nonStylableElement;
|
||||
|
||||
+(CALayer *) newCALayerForPathBasedSVGElement:(SVGElement*) svgElement withPath:(CGPathRef) path;
|
||||
+ (SVGGradientLayer*)getGradientLayerWithId:(NSString*)gradId
|
||||
forElement:(SVGElement*)svgElement
|
||||
withRect:(CGRect)r
|
||||
transform:(CGAffineTransform)transform;
|
||||
|
||||
+(CGColorRef) parseFillForElement:(SVGElement *)svgElement;
|
||||
+(CGColorRef) parseStrokeForElement:(SVGElement *)svgElement;
|
||||
+(void) parsePreserveAspectRatioFor:(Element<SVGFitToViewBox>*) element;
|
||||
|
||||
@end
|
@ -1,711 +0,0 @@
|
||||
#import "SVGHelperUtilities.h"
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "CAShapeLayerWithHitTest.h"
|
||||
#import "SVGUtils.h"
|
||||
#import "SVGGradientElement.h"
|
||||
#import "CGPathAdditions.h"
|
||||
|
||||
#import "SVGTransformable.h"
|
||||
#import "SVGSVGElement.h"
|
||||
#import "SVGGradientLayer.h"
|
||||
|
||||
@implementation SVGHelperUtilities
|
||||
|
||||
|
||||
+(CGAffineTransform) transformRelativeIncludingViewportForTransformableOrViewportEstablishingElement:(SVGElement*) transformableOrSVGSVGElement
|
||||
{
|
||||
NSAssert([transformableOrSVGSVGElement conformsToProtocol:@protocol(SVGTransformable)] || [transformableOrSVGSVGElement isKindOfClass:[SVGSVGElement class]], @"Illegal argument, sent a non-SVGTransformable, non-SVGSVGElement object to a method that requires an SVGTransformable (NB: Apple's Xcode is rubbish, it should have thrown a compiler error that you even tried to do this, but it often doesn't bother). Incoming instance = %@", transformableOrSVGSVGElement );
|
||||
|
||||
/**
|
||||
Each time you hit a viewPortElement in the DOM Tree, you
|
||||
have to insert an ADDITIONAL transform into the flow of:
|
||||
|
||||
parent-transform -> child-transform
|
||||
|
||||
has to become:
|
||||
|
||||
parent-transform -> VIEWPORT-TRANSFORM -> child-transform
|
||||
*/
|
||||
|
||||
CGAffineTransform currentRelativeTransform;
|
||||
CGAffineTransform optionalViewportTransform;
|
||||
|
||||
/**
|
||||
Current relative transform: for an incoming "SVGTransformable" it's .transform, for everything else its identity
|
||||
*/
|
||||
if( [transformableOrSVGSVGElement conformsToProtocol:@protocol(SVGTransformable)])
|
||||
{
|
||||
currentRelativeTransform = ((SVGElement<SVGTransformable>*)transformableOrSVGSVGElement).transform;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentRelativeTransform = CGAffineTransformIdentity;
|
||||
}
|
||||
|
||||
/**
|
||||
Optional relative transform: if incoming element establishes a viewport, do something clever; for everything else, use identity
|
||||
*/
|
||||
if( transformableOrSVGSVGElement.viewportElement == nil // if it's nil, it means THE OPPOSITE of what you'd expect - it means that it IS the viewport element - SVG Spec REQUIRES this
|
||||
|| transformableOrSVGSVGElement.viewportElement == transformableOrSVGSVGElement // ?? I don't understand: ?? if it's something other than itself, then: we simply don't need to worry about it ??
|
||||
)
|
||||
{
|
||||
SVGSVGElement<SVGFitToViewBox>* svgSVGElement = (SVGSVGElement<SVGFitToViewBox>*) transformableOrSVGSVGElement;
|
||||
|
||||
/**
|
||||
Calculate the "implicit" viewport->viewbox transform (caused by the <SVG> tag's possible "viewBox" attribute)
|
||||
Also calculate the "implicit" realViewport -> svgDefaultViewport transform (caused by the user changing the external
|
||||
size of the rendered SVG)
|
||||
*/
|
||||
SVGRect frameViewBox = svgSVGElement.viewBox; // the ACTUAL viewbox (may be Uninitalized if none specified in SVG file)
|
||||
SVGRect frameActualViewport = svgSVGElement.viewport; // the ACTUAL viewport (dictated by the graphics engine; may be Uninitialized if the renderer has too little info to decide on a viewport at all!)
|
||||
SVGRect frameRequestedViewport = svgSVGElement.requestedViewport; // the default viewport requested in the SVG source file (may be Uninitialized if no svg width or height params in original source file)
|
||||
|
||||
if( ! SVGRectIsInitialized(frameActualViewport))
|
||||
{
|
||||
/** We have NO VIEWPORT (renderer was presented too little info)
|
||||
|
||||
Net effect: we MUST render everything at 1:1, and apply NO FURTHER TRANSFORMS
|
||||
*/
|
||||
optionalViewportTransform = CGAffineTransformIdentity;
|
||||
}
|
||||
else
|
||||
{
|
||||
CGAffineTransform transformRealViewportToSVGViewport;
|
||||
CGAffineTransform transformSVGViewportToSVGViewBox;
|
||||
|
||||
/** Transform part 1: from REAL viewport to EXPECTED viewport */
|
||||
SVGRect viewportForViewBoxToRelateTo;
|
||||
if( SVGRectIsInitialized( frameRequestedViewport ))
|
||||
{
|
||||
viewportForViewBoxToRelateTo = frameRequestedViewport;
|
||||
transformRealViewportToSVGViewport = CGAffineTransformMakeScale( frameActualViewport.width / frameRequestedViewport.width, frameActualViewport.height / frameRequestedViewport.height);
|
||||
}
|
||||
else
|
||||
{
|
||||
viewportForViewBoxToRelateTo = frameActualViewport;
|
||||
transformRealViewportToSVGViewport = CGAffineTransformIdentity;
|
||||
}
|
||||
|
||||
/** Transform part 2: from EXPECTED viewport to internal viewBox */
|
||||
if( SVGRectIsInitialized( frameViewBox ) )
|
||||
{
|
||||
CGAffineTransform translateToViewBox = CGAffineTransformMakeTranslation( -frameViewBox.x, -frameViewBox.y );
|
||||
CGAffineTransform scaleToViewBox = CGAffineTransformMakeScale( viewportForViewBoxToRelateTo.width / frameViewBox.width, viewportForViewBoxToRelateTo.height / frameViewBox.height);
|
||||
|
||||
/** This is hard to find in the spec, but: if you have NO implementation of PreserveAspectRatio, you still need to
|
||||
read the spec on PreserveAspectRatio - because it defines a default behaviour for files that DO NOT specify it,
|
||||
which is different from the mathemetic default of co-ordinate systems.
|
||||
|
||||
In short, you MUST implement "<svg preserveAspectRatio=xMidYMid ... />", even if you're not supporting that attribute.
|
||||
*/
|
||||
if( svgSVGElement.preserveAspectRatio.baseVal.meetOrSlice == SVG_MEETORSLICE_MEET ) // ALWAYS TRUE in current implementation
|
||||
{
|
||||
if( ABS( svgSVGElement.aspectRatioFromWidthPerHeight - svgSVGElement.aspectRatioFromViewBox) > 0.00001 )
|
||||
{
|
||||
/** The aspect ratios for viewport and viewbox differ; Spec requires us to
|
||||
insert an extra transform that causes aspect ratio for internal data to be
|
||||
|
||||
... MEET: == KEPT CONSTANT
|
||||
|
||||
and to "aspect-scale to fit" (i.e. leaving letterboxes at topbottom / leftright as required)
|
||||
|
||||
c.f.: http://www.w3.org/TR/SVG/coords.html#PreserveAspectRatioAttribute (read carefully)
|
||||
*/
|
||||
|
||||
double ratioOfRatios = svgSVGElement.aspectRatioFromWidthPerHeight / svgSVGElement.aspectRatioFromViewBox;
|
||||
|
||||
SVGKitLogWarn(@"ratioOfRatios = %.2f", ratioOfRatios );
|
||||
SVGKitLogWarn(@"Experimental: auto-scaling viewbox transform to fulfil SVG spec's default MEET settings, because your SVG file has different aspect-ratios for viewBox and for svg.width,svg.height");
|
||||
|
||||
/**
|
||||
For MEET, we have to SHRINK the viewbox's contents if they aren't as wide:high as the viewport:
|
||||
*/
|
||||
CGAffineTransform catRestoreAspectRatio;
|
||||
if( ratioOfRatios > 1 ) {
|
||||
catRestoreAspectRatio = CGAffineTransformMakeScale( 1.0 / ratioOfRatios, 1.0 );
|
||||
} else if (ratioOfRatios != 0) {
|
||||
catRestoreAspectRatio = CGAffineTransformMakeScale( 1.0, 1.0 * ratioOfRatios );
|
||||
} else {
|
||||
catRestoreAspectRatio = CGAffineTransformIdentity;
|
||||
}
|
||||
|
||||
double xTranslationRequired;
|
||||
double yTranslationRequired;
|
||||
if( ratioOfRatios > 1.0 ) // if we're going to have space to either side
|
||||
{
|
||||
switch( svgSVGElement.preserveAspectRatio.baseVal.align )
|
||||
{
|
||||
case SVG_PRESERVEASPECTRATIO_XMINYMIN:
|
||||
case SVG_PRESERVEASPECTRATIO_XMINYMID:
|
||||
case SVG_PRESERVEASPECTRATIO_XMINYMAX:
|
||||
{
|
||||
xTranslationRequired = 0.0;
|
||||
}break;
|
||||
|
||||
case SVG_PRESERVEASPECTRATIO_XMIDYMIN:
|
||||
case SVG_PRESERVEASPECTRATIO_XMIDYMID:
|
||||
case SVG_PRESERVEASPECTRATIO_XMIDYMAX:
|
||||
{
|
||||
xTranslationRequired = ((ratioOfRatios-1.0)/2.0) * frameViewBox.width;
|
||||
}break;
|
||||
|
||||
case SVG_PRESERVEASPECTRATIO_XMAXYMIN:
|
||||
case SVG_PRESERVEASPECTRATIO_XMAXYMID:
|
||||
case SVG_PRESERVEASPECTRATIO_XMAXYMAX:
|
||||
{
|
||||
xTranslationRequired = ((ratioOfRatios-1.0) * frameViewBox.width);
|
||||
}break;
|
||||
|
||||
case SVG_PRESERVEASPECTRATIO_NONE:
|
||||
case SVG_PRESERVEASPECTRATIO_UNKNOWN:
|
||||
{
|
||||
xTranslationRequired = 0;
|
||||
}break;
|
||||
}
|
||||
}
|
||||
else
|
||||
xTranslationRequired = 0;
|
||||
|
||||
if( ratioOfRatios < 1.0 ) // if we're going to have space above and below
|
||||
{
|
||||
switch( svgSVGElement.preserveAspectRatio.baseVal.align )
|
||||
{
|
||||
case SVG_PRESERVEASPECTRATIO_XMINYMIN:
|
||||
case SVG_PRESERVEASPECTRATIO_XMIDYMIN:
|
||||
case SVG_PRESERVEASPECTRATIO_XMAXYMIN:
|
||||
{
|
||||
yTranslationRequired = 0.0;
|
||||
}break;
|
||||
|
||||
case SVG_PRESERVEASPECTRATIO_XMINYMID:
|
||||
case SVG_PRESERVEASPECTRATIO_XMIDYMID:
|
||||
case SVG_PRESERVEASPECTRATIO_XMAXYMID:
|
||||
{
|
||||
yTranslationRequired = ((1.0-ratioOfRatios)/2.0 * [svgSVGElement.height pixelsValue]);
|
||||
}break;
|
||||
|
||||
case SVG_PRESERVEASPECTRATIO_XMINYMAX:
|
||||
case SVG_PRESERVEASPECTRATIO_XMIDYMAX:
|
||||
case SVG_PRESERVEASPECTRATIO_XMAXYMAX:
|
||||
{
|
||||
yTranslationRequired = ((1.0-ratioOfRatios) * [svgSVGElement.height pixelsValue]);
|
||||
}break;
|
||||
|
||||
case SVG_PRESERVEASPECTRATIO_NONE:
|
||||
case SVG_PRESERVEASPECTRATIO_UNKNOWN:
|
||||
{
|
||||
yTranslationRequired = 0.0;
|
||||
}break;
|
||||
}
|
||||
}
|
||||
else
|
||||
yTranslationRequired = 0.0;
|
||||
/**
|
||||
For xMidYMid, we have to RE-CENTER the viewbox's contents if they aren't as wide:high as the viewport:
|
||||
*/
|
||||
CGAffineTransform catRecenterNewAspectRatio = CGAffineTransformMakeTranslation( xTranslationRequired, yTranslationRequired );
|
||||
|
||||
CGAffineTransform transformsThatHonourAspectRatioRequirements = CGAffineTransformConcat(catRecenterNewAspectRatio, catRestoreAspectRatio);
|
||||
|
||||
scaleToViewBox = CGAffineTransformConcat( transformsThatHonourAspectRatioRequirements, scaleToViewBox );
|
||||
}
|
||||
}
|
||||
else
|
||||
SVGKitLogWarn( @"Unsupported: preserveAspectRatio set to SLICE. Code to handle this doesn't exist yet.");
|
||||
|
||||
transformSVGViewportToSVGViewBox = CGAffineTransformConcat( translateToViewBox, scaleToViewBox );
|
||||
}
|
||||
else
|
||||
transformSVGViewportToSVGViewBox = CGAffineTransformIdentity;
|
||||
|
||||
optionalViewportTransform = CGAffineTransformConcat( transformRealViewportToSVGViewport, transformSVGViewportToSVGViewBox );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
optionalViewportTransform = CGAffineTransformIdentity;
|
||||
}
|
||||
|
||||
/**
|
||||
TOTAL relative based on the local "transform" property and the viewport (if present)
|
||||
*/
|
||||
CGAffineTransform result = CGAffineTransformConcat( currentRelativeTransform, optionalViewportTransform);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*!
|
||||
Re-calculates the absolute transform on-demand by querying parent's absolute transform and appending self's relative transform.
|
||||
|
||||
Can take ONLY TWO kinds of element:
|
||||
- something that implements SVGTransformable (non-transformables shouldn't be performing transforms!)
|
||||
- something that defines a new viewport co-ordinate system (i.e. the SVG tag itself; this is AN IMPLICIT TRANSFORMABLE!)
|
||||
*/
|
||||
+(CGAffineTransform) transformAbsoluteIncludingViewportForTransformableOrViewportEstablishingElement:(SVGElement*) transformableOrSVGSVGElement
|
||||
{
|
||||
NSAssert([transformableOrSVGSVGElement conformsToProtocol:@protocol(SVGTransformable)] || [transformableOrSVGSVGElement isKindOfClass:[SVGSVGElement class]], @"Illegal argument, sent a non-SVGTransformable, non-SVGSVGElement object to a method that requires an SVGTransformable (NB: Apple's Xcode is rubbish, it should have thrown a compiler error that you even tried to do this, but it often doesn't bother). Incoming instance = %@", transformableOrSVGSVGElement );
|
||||
|
||||
CGAffineTransform parentAbsoluteTransform = CGAffineTransformIdentity;
|
||||
|
||||
NSAssert( transformableOrSVGSVGElement.parentNode == nil || [transformableOrSVGSVGElement.parentNode isKindOfClass:[SVGElement class]], @"I don't know what to do when parent node is NOT an SVG element of some kind; presumably, this is when SVG root node gets embedded inside something else? The Spec IS UNCLEAR and doesn't clearly define ANYTHING here, and provides very few examples" );
|
||||
|
||||
/**
|
||||
Parent Absolute transform: one of the following
|
||||
|
||||
a. parent is an SVGTransformable (so recurse this method call to find it)
|
||||
b. parent is a viewport-generating element (so recurse this method call to find it)
|
||||
c. parent is nil (so treat it as Identity)
|
||||
d. parent is something else (so do a while loop until we hit an a, b, or c above)
|
||||
*/
|
||||
SVGElement* parentSVGElement = transformableOrSVGSVGElement;
|
||||
while( (parentSVGElement = (SVGElement*) parentSVGElement.parentNode) != nil )
|
||||
{
|
||||
if( [parentSVGElement conformsToProtocol:@protocol(SVGTransformable)] )
|
||||
{
|
||||
parentAbsoluteTransform = [self transformAbsoluteIncludingViewportForTransformableOrViewportEstablishingElement:parentSVGElement];
|
||||
break;
|
||||
}
|
||||
|
||||
if( [parentSVGElement isKindOfClass:[SVGSVGElement class]] )
|
||||
{
|
||||
parentAbsoluteTransform = [self transformAbsoluteIncludingViewportForTransformableOrViewportEstablishingElement:parentSVGElement];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
TOTAL absolute based on the parent transform with relative (and possible viewport) transforms
|
||||
*/
|
||||
CGAffineTransform result = CGAffineTransformConcat( [self transformRelativeIncludingViewportForTransformableOrViewportEstablishingElement:transformableOrSVGSVGElement], parentAbsoluteTransform );
|
||||
|
||||
//DEBUG: SVGKitLogWarn( @"[%@] self.transformAbsolute: returning: affine( (%2.2f %2.2f %2.2f %2.2f), (%2.2f %2.2f)", [self class], result.a, result.b, result.c, result.d, result.tx, result.ty);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
+(void) configureCALayer:(CALayer*) layer usingElement:(SVGElement*) nonStylableElement
|
||||
{
|
||||
layer.name = nonStylableElement.identifier;
|
||||
[layer setValue:nonStylableElement.identifier forKey:kSVGElementIdentifier];
|
||||
|
||||
#if FORCE_RASTERIZE_LAYERS
|
||||
if ([layer respondsToSelector:@selector(setShouldRasterize:)]) {
|
||||
[layer performSelector:@selector(setShouldRasterize:)
|
||||
withObject:[NSNumber numberWithBool:YES]];
|
||||
}
|
||||
|
||||
/** If you're going to rasterize, Apple's code is dumb, and needs to be "told" if its using a Retina display */
|
||||
layer.contentsScale = [[UIScreen mainScreen] scale];
|
||||
layer.rasterizationScale = _shapeLayer.contentsScale;
|
||||
#endif
|
||||
|
||||
if( [nonStylableElement conformsToProtocol:@protocol(SVGStylable)])
|
||||
{
|
||||
SVGElement<SVGStylable>* stylableElement = (SVGElement<SVGStylable>*) nonStylableElement;
|
||||
|
||||
NSString* actualOpacity = [stylableElement cascadedValueForStylableProperty:@"opacity" inherit:NO];
|
||||
layer.opacity = actualOpacity.length > 0 ? [actualOpacity floatValue] : 1.0f; // svg's "opacity" defaults to 1!
|
||||
|
||||
// Apply fill-rule on layer (only CAShapeLayer)
|
||||
NSString *fillRule = [stylableElement cascadedValueForStylableProperty:@"fill-rule"];
|
||||
if([fillRule isEqualToString:@"evenodd"] && [layer isKindOfClass:[CAShapeLayer class]]){
|
||||
CAShapeLayer *shapeLayer = (CAShapeLayer *)layer;
|
||||
shapeLayer.fillRule = @"even-odd";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+(CALayer *) newCALayerForPathBasedSVGElement:(SVGElement<SVGTransformable>*) svgElement withPath:(CGPathRef) pathRelative
|
||||
{
|
||||
CAShapeLayer* _shapeLayer = [CAShapeLayerWithHitTest layer];
|
||||
|
||||
[self configureCALayer:_shapeLayer usingElement:svgElement];
|
||||
|
||||
NSString* actualStroke = [svgElement cascadedValueForStylableProperty:@"stroke"];
|
||||
if (!actualStroke)
|
||||
actualStroke = @"none";
|
||||
NSString* actualStrokeWidth = [svgElement cascadedValueForStylableProperty:@"stroke-width"];
|
||||
|
||||
CGFloat strokeWidth = 1.0;
|
||||
|
||||
if (actualStrokeWidth)
|
||||
{
|
||||
SVGRect r = ((SVGSVGElement*) svgElement.viewportElement).viewport;
|
||||
|
||||
strokeWidth = [[SVGLength svgLengthFromNSString:actualStrokeWidth]
|
||||
pixelsValueWithDimension: hypot(r.width, r.height)];
|
||||
}
|
||||
|
||||
/** transform our LOCAL path into ABSOLUTE space */
|
||||
CGAffineTransform transformAbsolute = [self transformAbsoluteIncludingViewportForTransformableOrViewportEstablishingElement:svgElement];
|
||||
|
||||
// calculate the rendered dimensions of the path
|
||||
CGRect r = CGRectInset(CGPathGetBoundingBox(pathRelative), -strokeWidth/2., -strokeWidth/2.);
|
||||
CGRect transformedPathBB = CGRectApplyAffineTransform(r, transformAbsolute);
|
||||
|
||||
CGPathRef pathToPlaceInLayer = CGPathCreateCopyByTransformingPath(pathRelative, &transformAbsolute);
|
||||
|
||||
/** find out the ABSOLUTE BOUNDING BOX of our transformed path */
|
||||
//DEBUG ONLY: CGRect unTransformedPathBB = CGPathGetBoundingBox( _pathRelative );
|
||||
|
||||
#if IMPROVE_PERFORMANCE_BY_WORKING_AROUND_APPLE_FRAME_ALIGNMENT_BUG
|
||||
transformedPathBB = CGRectIntegral( transformedPathBB ); // ridiculous but improves performance of apple's code by up to 50% !
|
||||
#endif
|
||||
|
||||
/** NB: when we set the _shapeLayer.frame, it has a *side effect* of moving the path itself - so, in order to prevent that,
|
||||
because Apple didn't provide a BOOL to disable that "feature", we have to pre-shift the path forwards by the amount it
|
||||
will be shifted backwards */
|
||||
CGPathRef finalPath = CGPathCreateByOffsettingPath( pathToPlaceInLayer, transformedPathBB.origin.x, transformedPathBB.origin.y );
|
||||
|
||||
/** Can't use this - iOS 5 only! path = CGPathCreateCopyByTransformingPath(path, transformFromSVGUnitsToScreenUnits ); */
|
||||
|
||||
_shapeLayer.path = finalPath;
|
||||
CGPathRelease(finalPath);
|
||||
|
||||
/**
|
||||
NB: this line, by changing the FRAME of the layer, has the side effect of also changing the CGPATH's position in absolute
|
||||
space! This is why we needed the "CGPathRef finalPath =" line a few lines above...
|
||||
*/
|
||||
_shapeLayer.frame = transformedPathBB;
|
||||
|
||||
CGRect localRect = CGRectMake(0, 0, CGRectGetWidth(transformedPathBB), CGRectGetHeight(transformedPathBB));
|
||||
|
||||
//DEBUG ONLY: CGRect shapeLayerFrame = _shapeLayer.frame;
|
||||
CAShapeLayer* strokeLayer = _shapeLayer;
|
||||
CAShapeLayer* fillLayer = _shapeLayer;
|
||||
|
||||
if( strokeWidth > 0
|
||||
&& (! [@"none" isEqualToString:actualStroke]) )
|
||||
{
|
||||
/*
|
||||
We have to apply any scale-factor part of the affine transform to the stroke itself (this is bizarre and horrible, yes, but that's the spec for you!)
|
||||
*/
|
||||
CGSize fakeSize = CGSizeMake( strokeWidth, strokeWidth );
|
||||
fakeSize = CGSizeApplyAffineTransform( fakeSize, transformAbsolute );
|
||||
strokeLayer.lineWidth = hypot(fakeSize.width, fakeSize.height)/M_SQRT2;
|
||||
|
||||
NSString* actualStrokeOpacity = [svgElement cascadedValueForStylableProperty:@"stroke-opacity"];
|
||||
strokeLayer.strokeColor = [self parseStrokeForElement:svgElement fromStroke:actualStroke andOpacity:actualStrokeOpacity];
|
||||
|
||||
/**
|
||||
Stroke dash array
|
||||
*/
|
||||
NSString *dashArrayString = [svgElement cascadedValueForStylableProperty:@"stroke-dasharray"];
|
||||
if(dashArrayString != nil && ![dashArrayString isEqualToString:@""]) {
|
||||
NSArray *dashArrayStringComponents = [dashArrayString componentsSeparatedByString:@" "];
|
||||
if( [dashArrayStringComponents count] < 2 )
|
||||
{ // min 2 elements required, perhaps it's comma-separated:
|
||||
dashArrayStringComponents = [dashArrayString componentsSeparatedByString:@","];
|
||||
}
|
||||
if( [dashArrayStringComponents count] > 1 )
|
||||
{
|
||||
BOOL valid = NO;
|
||||
NSMutableArray *dashArray = [NSMutableArray array];
|
||||
for( NSString *n in dashArrayStringComponents ){
|
||||
[dashArray addObject:[NSNumber numberWithFloat:[n floatValue]]];
|
||||
if( !valid && [n floatValue] != 0 ){
|
||||
// avoid 'CGContextSetLineDash: invalid dash array: at least one element must be non-zero.'
|
||||
valid = YES;
|
||||
}
|
||||
}
|
||||
if( valid ){
|
||||
strokeLayer.lineDashPattern = dashArray;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Line joins + caps: butt / square / miter
|
||||
*/
|
||||
NSString* actualLineCap = [svgElement cascadedValueForStylableProperty:@"stroke-linecap"];
|
||||
NSString* actualLineJoin = [svgElement cascadedValueForStylableProperty:@"stroke-linejoin"];
|
||||
NSString* actualMiterLimit = [svgElement cascadedValueForStylableProperty:@"stroke-miterlimit"];
|
||||
if( actualLineCap.length > 0 )
|
||||
{
|
||||
if( [actualLineCap isEqualToString:@"butt"] )
|
||||
strokeLayer.lineCap = kCALineCapButt;
|
||||
else if( [actualLineCap isEqualToString:@"round"] )
|
||||
strokeLayer.lineCap = kCALineCapRound;
|
||||
else if( [actualLineCap isEqualToString:@"square"] )
|
||||
strokeLayer.lineCap = kCALineCapSquare;
|
||||
}
|
||||
if( actualLineJoin.length > 0 )
|
||||
{
|
||||
if( [actualLineJoin isEqualToString:@"miter"] )
|
||||
strokeLayer.lineJoin = kCALineJoinMiter;
|
||||
else if( [actualLineJoin isEqualToString:@"round"] )
|
||||
strokeLayer.lineJoin = kCALineJoinRound;
|
||||
else if( [actualLineJoin isEqualToString:@"bevel"] )
|
||||
strokeLayer.lineJoin = kCALineJoinBevel;
|
||||
}
|
||||
if( actualMiterLimit.length > 0 )
|
||||
{
|
||||
strokeLayer.miterLimit = [actualMiterLimit floatValue];
|
||||
}
|
||||
if ( [actualStroke hasPrefix:@"url"] )
|
||||
{
|
||||
// need a new fill layer because the stroke layer is becoming a mask
|
||||
fillLayer = [CAShapeLayerWithHitTest layer];
|
||||
fillLayer.frame = strokeLayer.frame;
|
||||
fillLayer.opacity = strokeLayer.opacity;
|
||||
fillLayer.path = strokeLayer.path;
|
||||
|
||||
NSArray *strokeArgs = [actualStroke componentsSeparatedByCharactersInSet:NSCharacterSet.whitespaceCharacterSet];
|
||||
NSString *strokeIdArg = strokeArgs.firstObject;
|
||||
NSRange idKeyRange = NSMakeRange(5, strokeIdArg.length - 6);
|
||||
NSString* strokeId = [strokeIdArg substringWithRange:idKeyRange];
|
||||
|
||||
// SVG spec: Vertical and horizontal lines don't have a boundingbox, since they are one-dimensional, even though the stroke-width makes it look like they should have a boundingbox with non-zero width and height.
|
||||
CGRect boundingBox = strokeLayer.frame;
|
||||
CGRect pathBoundingBox = CGPathGetPathBoundingBox(pathRelative);
|
||||
if (!CGRectIsEmpty(pathBoundingBox)) {
|
||||
// apply gradient
|
||||
SVGGradientLayer *gradientLayer = [self getGradientLayerWithId:strokeId forElement:svgElement withRect:boundingBox transform:transformAbsolute];
|
||||
|
||||
if (gradientLayer) {
|
||||
strokeLayer.frame = localRect;
|
||||
|
||||
strokeLayer.fillColor = nil;
|
||||
strokeLayer.strokeColor = [UIColor blackColor].CGColor;
|
||||
|
||||
gradientLayer.mask = strokeLayer;
|
||||
strokeLayer = (CAShapeLayer*) gradientLayer;
|
||||
} else {
|
||||
// no gradient, fallback
|
||||
}
|
||||
} else {
|
||||
// no boundingBox, fallback
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if( [@"none" isEqualToString:actualStroke] )
|
||||
{
|
||||
strokeLayer.strokeColor = nil; // This is how you tell Apple that the stroke is disabled; a strokewidth of 0 will NOT achieve this
|
||||
strokeLayer.lineWidth = 0.0f; // MUST set this explicitly, or Apple assumes 1.0
|
||||
}
|
||||
else
|
||||
{
|
||||
strokeLayer.lineWidth = 1.0f; // default value from SVG spec
|
||||
}
|
||||
}
|
||||
|
||||
NSString* actualFill = [svgElement cascadedValueForStylableProperty:@"fill"];
|
||||
NSString* actualFillOpacity = [svgElement cascadedValueForStylableProperty:@"fill-opacity"];
|
||||
|
||||
if ( [actualFill hasPrefix:@"url"] )
|
||||
{
|
||||
NSArray *fillArgs = [actualFill componentsSeparatedByCharactersInSet:NSCharacterSet.whitespaceCharacterSet];
|
||||
NSString *fillIdArg = fillArgs.firstObject;
|
||||
NSRange idKeyRange = NSMakeRange(5, fillIdArg.length - 6);
|
||||
NSString* fillId = [fillIdArg substringWithRange:idKeyRange];
|
||||
|
||||
/** Replace the return layer with a special layer using the URL fill */
|
||||
/** fetch the fill layer by URL using the DOM */
|
||||
SVGGradientLayer *gradientLayer = [self getGradientLayerWithId:fillId forElement:svgElement withRect:fillLayer.frame
|
||||
transform:transformAbsolute];
|
||||
if (gradientLayer) {
|
||||
CAShapeLayer* maskLayer = [CAShapeLayer layer];
|
||||
maskLayer.frame = localRect;
|
||||
maskLayer.path = fillLayer.path;
|
||||
maskLayer.fillColor = [UIColor blackColor].CGColor;
|
||||
maskLayer.strokeColor = nil;
|
||||
gradientLayer.mask = maskLayer;
|
||||
gradientLayer.frame = fillLayer.frame;
|
||||
fillLayer = (CAShapeLayer* )gradientLayer;
|
||||
} else {
|
||||
// no gradient, fallback
|
||||
}
|
||||
}
|
||||
else if( actualFill.length > 0 || actualFillOpacity.length > 0 )
|
||||
{
|
||||
fillLayer.fillColor = [self parseFillForElement:svgElement fromFill:actualFill andOpacity:actualFillOpacity];
|
||||
}
|
||||
CGPathRelease(pathToPlaceInLayer);
|
||||
|
||||
NSString* actualOpacity = [svgElement cascadedValueForStylableProperty:@"opacity" inherit:NO];
|
||||
fillLayer.opacity = actualOpacity.length > 0 ? [actualOpacity floatValue] : 1; // unusually, the "opacity" attribute defaults to 1, not 0
|
||||
|
||||
if (strokeLayer == fillLayer)
|
||||
{
|
||||
return strokeLayer;
|
||||
}
|
||||
CALayer* combined = [CALayer layer];
|
||||
|
||||
combined.frame = strokeLayer.frame;
|
||||
strokeLayer.frame = localRect;
|
||||
if ([strokeLayer isKindOfClass:[CAShapeLayer class]])
|
||||
strokeLayer.fillColor = nil;
|
||||
fillLayer.frame = localRect;
|
||||
[combined addSublayer:fillLayer];
|
||||
[combined addSublayer:strokeLayer];
|
||||
return combined;
|
||||
}
|
||||
|
||||
+ (SVGGradientLayer*)getGradientLayerWithId:(NSString*)gradId
|
||||
forElement:(SVGElement*)svgElement
|
||||
withRect:(CGRect)r
|
||||
transform:(CGAffineTransform)transform
|
||||
{
|
||||
/** Replace the return layer with a special layer using the URL fill */
|
||||
/** fetch the fill layer by URL using the DOM */
|
||||
NSAssert( svgElement.rootOfCurrentDocumentFragment != nil, @"This SVG shape has a URL fill type; it needs to search for that URL (%@) inside its nearest-ancestor <SVG> node, but the rootOfCurrentDocumentFragment reference was nil (suggests the parser failed, or the SVG file is corrupt)", gradId );
|
||||
|
||||
SVGGradientElement* svgGradient = (SVGGradientElement*) [svgElement.rootOfCurrentDocumentFragment getElementById:gradId];
|
||||
if (svgGradient == nil) {
|
||||
// SVG spec allows referenced gradient not exist and will use fallback color
|
||||
SVGKitLogWarn(@"This SVG shape has a URL fill (%@), but could not find an XML Node with that ID inside the DOM tree (suggests the parser failed, or the SVG file is corrupt)", gradId );
|
||||
}
|
||||
|
||||
[svgGradient synthesizeProperties];
|
||||
|
||||
SVGGradientLayer *gradientLayer = [svgGradient newGradientLayerForObjectRect:r
|
||||
viewportRect:svgElement.rootOfCurrentDocumentFragment.viewBox
|
||||
transform:transform];
|
||||
|
||||
return gradientLayer;
|
||||
}
|
||||
|
||||
+(CGColorRef) parseFillForElement:(SVGElement *)svgElement
|
||||
{
|
||||
NSString* actualFill = [svgElement cascadedValueForStylableProperty:@"fill"];
|
||||
NSString* actualFillOpacity = [svgElement cascadedValueForStylableProperty:@"fill-opacity"];
|
||||
return [self parseFillForElement:svgElement fromFill:actualFill andOpacity:actualFillOpacity];
|
||||
}
|
||||
|
||||
+(CGColorRef) parseFillForElement:(SVGElement *)svgElement fromFill:(NSString *)actualFill andOpacity:(NSString *)actualFillOpacity
|
||||
{
|
||||
return [self parsePaintColorForElement:svgElement paintColor:actualFill paintOpacity:actualFillOpacity defaultColor:@"white"];
|
||||
}
|
||||
|
||||
+(CGColorRef) parseStrokeForElement:(SVGElement *)svgElement
|
||||
{
|
||||
NSString* actualStroke = [svgElement cascadedValueForStylableProperty:@"stroke"];
|
||||
NSString* actualStrokeOpacity = [svgElement cascadedValueForStylableProperty:@"stroke-opacity"];
|
||||
return [self parseStrokeForElement:svgElement fromStroke:actualStroke andOpacity:actualStrokeOpacity];
|
||||
}
|
||||
|
||||
+(CGColorRef) parseStrokeForElement:(SVGElement *)svgElement fromStroke:(NSString *)actualStroke andOpacity:(NSString *)actualStrokeOpacity
|
||||
{
|
||||
return [self parsePaintColorForElement:svgElement paintColor:actualStroke paintOpacity:actualStrokeOpacity defaultColor:@"white"];
|
||||
}
|
||||
|
||||
/**
|
||||
Spec: https://www.w3.org/TR/SVG11/painting.html#SpecifyingPaint
|
||||
`fill` or `stroke` allows paint color. This should actually be a <paint> interface.
|
||||
`fill` default color is `black`, while `stroke` default color is `none`
|
||||
*/
|
||||
+(CGColorRef)parsePaintColorForElement:(SVGElement *)svgElement paintColor:(NSString *)paintColor paintOpacity:(NSString *)paintOpacity defaultColor:(NSString *)defaultColor {
|
||||
CGColorRef colorRef = NULL;
|
||||
if (!paintColor) {
|
||||
paintColor = @"none";
|
||||
}
|
||||
if ([paintColor isEqualToString:@"none"])
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
// there may be a url before the actual color like `url(#grad) #0f0`, parse it
|
||||
NSString *actualPaintColor;
|
||||
NSString *actualPaintOpacity = paintOpacity;
|
||||
NSArray *paintArgs = [paintColor componentsSeparatedByCharactersInSet:NSCharacterSet.whitespaceCharacterSet];
|
||||
if ([paintColor hasPrefix:@"url"]) {
|
||||
if (paintArgs.count > 1) {
|
||||
actualPaintColor = paintArgs[1];
|
||||
}
|
||||
} else {
|
||||
actualPaintColor = paintColor;
|
||||
}
|
||||
if( actualPaintColor.length > 0 || actualPaintOpacity.length > 0 ) {
|
||||
SVGColor paintColorSVGColor;
|
||||
if (actualPaintColor.length > 0) {
|
||||
if (![actualPaintColor isEqualToString:@"none"]) {
|
||||
paintColorSVGColor = SVGColorFromString([actualPaintColor UTF8String]); // have to use the intermediate of an SVGColor so that we can over-ride the ALPHA component in next line
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
if (![defaultColor isEqualToString:@"none"]) {
|
||||
paintColorSVGColor = SVGColorFromString([actualPaintColor UTF8String]);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if( actualPaintOpacity.length > 0 )
|
||||
paintColorSVGColor.a = (uint8_t) ([actualPaintOpacity floatValue] * 0xFF);
|
||||
|
||||
colorRef = CGColorWithSVGColor(paintColorSVGColor);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (![defaultColor isEqualToString:@"none"]) {
|
||||
colorRef = CGColorWithSVGColor(SVGColorFromString([defaultColor UTF8String]));
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
UIColor *color = [UIColor colorWithCGColor:colorRef];
|
||||
if ([color isEqual:[UIColor colorWithRed:0 green:0 blue:0 alpha:1.0]]) {
|
||||
return [UIColor whiteColor].CGColor;
|
||||
} else if ([color isEqual:[UIColor colorWithRed:1 green:1 blue:1 alpha:1.0]]) {
|
||||
return [UIColor blackColor].CGColor;
|
||||
} else {
|
||||
return colorRef;
|
||||
}
|
||||
|
||||
return colorRef;
|
||||
}
|
||||
|
||||
+(void) parsePreserveAspectRatioFor:(Element<SVGFitToViewBox>*) element
|
||||
{
|
||||
element.preserveAspectRatio = [SVGAnimatedPreserveAspectRatio new]; // automatically sets defaults
|
||||
|
||||
NSString* stringPreserveAspectRatio = [element getAttribute:@"preserveAspectRatio"];
|
||||
|
||||
if( stringPreserveAspectRatio.length > 0 )
|
||||
{
|
||||
NSArray* aspectRatioCommands = [stringPreserveAspectRatio componentsSeparatedByString:@" "];
|
||||
|
||||
for( NSString* aspectRatioCommand in aspectRatioCommands )
|
||||
{
|
||||
if( [aspectRatioCommand isEqualToString:@"meet"]) /** NB this is default anyway. Dont technically need to set it */
|
||||
element.preserveAspectRatio.baseVal.meetOrSlice = SVG_MEETORSLICE_MEET;
|
||||
else if( [aspectRatioCommand isEqualToString:@"slice"])
|
||||
element.preserveAspectRatio.baseVal.meetOrSlice = SVG_MEETORSLICE_SLICE;
|
||||
|
||||
else if( [aspectRatioCommand isEqualToString:@"xMinYMin"])
|
||||
element.preserveAspectRatio.baseVal.align = SVG_PRESERVEASPECTRATIO_XMINYMIN;
|
||||
else if( [aspectRatioCommand isEqualToString:@"xMinYMid"])
|
||||
element.preserveAspectRatio.baseVal.align = SVG_PRESERVEASPECTRATIO_XMINYMID;
|
||||
else if( [aspectRatioCommand isEqualToString:@"xMinYMax"])
|
||||
element.preserveAspectRatio.baseVal.align = SVG_PRESERVEASPECTRATIO_XMINYMAX;
|
||||
|
||||
else if( [aspectRatioCommand isEqualToString:@"xMidYMin"])
|
||||
element.preserveAspectRatio.baseVal.align = SVG_PRESERVEASPECTRATIO_XMIDYMIN;
|
||||
else if( [aspectRatioCommand isEqualToString:@"xMidYMid"])
|
||||
element.preserveAspectRatio.baseVal.align = SVG_PRESERVEASPECTRATIO_XMIDYMID;
|
||||
else if( [aspectRatioCommand isEqualToString:@"xMidYMax"])
|
||||
element.preserveAspectRatio.baseVal.align = SVG_PRESERVEASPECTRATIO_XMIDYMAX;
|
||||
|
||||
else if( [aspectRatioCommand isEqualToString:@"xMaxYMin"])
|
||||
element.preserveAspectRatio.baseVal.align = SVG_PRESERVEASPECTRATIO_XMAXYMIN;
|
||||
else if( [aspectRatioCommand isEqualToString:@"xMaxYMid"])
|
||||
element.preserveAspectRatio.baseVal.align = SVG_PRESERVEASPECTRATIO_XMAXYMID;
|
||||
else if( [aspectRatioCommand isEqualToString:@"xMaxYMax"])
|
||||
element.preserveAspectRatio.baseVal.align = SVG_PRESERVEASPECTRATIO_XMAXYMAX;
|
||||
|
||||
else
|
||||
{
|
||||
SVGKitLogWarn(@"Found unexpected preserve-aspect-ratio command inside element's 'preserveAspectRatio' attribute. Command = '%@'", aspectRatioCommand );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
@ -1,79 +0,0 @@
|
||||
/*!
|
||||
SVGLength.h
|
||||
|
||||
http://www.w3.org/TR/SVG/types.html#InterfaceSVGLength
|
||||
|
||||
// Length Unit Types
|
||||
const unsigned short SVG_LENGTHTYPE_UNKNOWN = 0;
|
||||
const unsigned short SVG_LENGTHTYPE_NUMBER = 1;
|
||||
const unsigned short SVG_LENGTHTYPE_PERCENTAGE = 2;
|
||||
const unsigned short SVG_LENGTHTYPE_EMS = 3;
|
||||
const unsigned short SVG_LENGTHTYPE_EXS = 4;
|
||||
const unsigned short SVG_LENGTHTYPE_PX = 5;
|
||||
const unsigned short SVG_LENGTHTYPE_CM = 6;
|
||||
const unsigned short SVG_LENGTHTYPE_MM = 7;
|
||||
const unsigned short SVG_LENGTHTYPE_IN = 8;
|
||||
const unsigned short SVG_LENGTHTYPE_PT = 9;
|
||||
const unsigned short SVG_LENGTHTYPE_PC = 10;
|
||||
|
||||
readonly attribute unsigned short unitType;
|
||||
attribute float value setraises(DOMException);
|
||||
attribute float valueInSpecifiedUnits setraises(DOMException);
|
||||
attribute DOMString valueAsString setraises(DOMException);
|
||||
|
||||
void newValueSpecifiedUnits(in unsigned short unitType, in float valueInSpecifiedUnits) raises(DOMException);
|
||||
void convertToSpecifiedUnits(in unsigned short unitType) raises(DOMException);
|
||||
};
|
||||
*/
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
typedef enum SVG_LENGTH_TYPE
|
||||
{
|
||||
SVG_LENGTHTYPE_UNKNOWN = 0,
|
||||
SVG_LENGTHTYPE_NUMBER = 1,
|
||||
SVG_LENGTHTYPE_PERCENTAGE = 2,
|
||||
SVG_LENGTHTYPE_EMS = 3,
|
||||
SVG_LENGTHTYPE_EXS = 4,
|
||||
SVG_LENGTHTYPE_PX = 5,
|
||||
SVG_LENGTHTYPE_CM = 6,
|
||||
SVG_LENGTHTYPE_MM = 7,
|
||||
SVG_LENGTHTYPE_IN = 8,
|
||||
SVG_LENGTHTYPE_PT = 9,
|
||||
SVG_LENGTHTYPE_PC = 10
|
||||
} SVG_LENGTH_TYPE;
|
||||
|
||||
|
||||
@interface SVGLength : NSObject
|
||||
|
||||
@property(nonatomic,readonly) SVG_LENGTH_TYPE unitType;
|
||||
@property(nonatomic) float value;
|
||||
@property(nonatomic) float valueInSpecifiedUnits;
|
||||
@property(nonatomic,strong) NSString* valueAsString;
|
||||
|
||||
-(void) newValueSpecifiedUnits:(SVG_LENGTH_TYPE) unitType valueInSpecifiedUnits:(float) valueInSpecifiedUnits;
|
||||
-(void) convertToSpecifiedUnits:(SVG_LENGTH_TYPE) unitType;
|
||||
|
||||
#pragma mark - things outside the spec but needed to make it usable in Objective C
|
||||
|
||||
+(SVGLength*) svgLengthZero;
|
||||
+(SVGLength*) svgLengthFromNSString:(NSString*) s;
|
||||
|
||||
/** returns this SVGLength as if it had been converted to pixels, using [self convertToSpecifiedUnits:SVG_LENGTHTYPE_PX]
|
||||
*/
|
||||
-(float) pixelsValue;
|
||||
|
||||
/** to calculate relative values pass in the appropriate viewport dimension (width, height, or diagonal measure)
|
||||
*/
|
||||
-(float) pixelsValueWithDimension:(float)dimension;
|
||||
|
||||
/** to calculate relative gradient values pass in the appropriate viewport dimension (width, height)
|
||||
* the different between this and `pixelsValueWithDimension` is that this one will treat number value which (0 <= value <= 1.0) as percent value and calculate the result. (used by gradient)
|
||||
*/
|
||||
-(float) pixelsValueWithGradientDimension:(float)dimension;
|
||||
|
||||
/** returns this SVGLength as if it had been converted to a raw number (USE pixelsValue instead, UNLESS you are dealing with something that you expect to be a percentage or
|
||||
similar non-pixel value), using [self convertToSpecifiedUnits:SVG_LENGTHTYPE_NUMBER]
|
||||
*/
|
||||
-(float) numberValue;
|
||||
|
||||
@end
|
@ -1,241 +0,0 @@
|
||||
#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
|
@ -1,51 +0,0 @@
|
||||
/*!
|
||||
|
||||
http://www.w3.org/TR/SVG/coords.html#InterfaceSVGMatrix
|
||||
|
||||
interface SVGMatrix {
|
||||
|
||||
attribute float a setraises(DOMException);
|
||||
attribute float b setraises(DOMException);
|
||||
attribute float c setraises(DOMException);
|
||||
attribute float d setraises(DOMException);
|
||||
attribute float e setraises(DOMException);
|
||||
attribute float f setraises(DOMException);
|
||||
|
||||
SVGMatrix multiply(in SVGMatrix secondMatrix);
|
||||
SVGMatrix inverse() raises(SVGException);
|
||||
SVGMatrix translate(in float x, in float y);
|
||||
SVGMatrix scale(in float scaleFactor);
|
||||
SVGMatrix scaleNonUniform(in float scaleFactorX, in float scaleFactorY);
|
||||
SVGMatrix rotate(in float angle);
|
||||
SVGMatrix rotateFromVector(in float x, in float y) raises(SVGException);
|
||||
SVGMatrix flipX();
|
||||
SVGMatrix flipY();
|
||||
SVGMatrix skewX(in float angle);
|
||||
SVGMatrix skewY(in float angle);
|
||||
};
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface SVGMatrix : NSObject
|
||||
|
||||
@property(nonatomic) float a;
|
||||
@property(nonatomic) float b;
|
||||
@property(nonatomic) float c;
|
||||
@property(nonatomic) float d;
|
||||
@property(nonatomic) float e;
|
||||
@property(nonatomic) float f;
|
||||
|
||||
-(SVGMatrix*) multiply:(SVGMatrix*) secondMatrix;
|
||||
-(SVGMatrix*) inverse;
|
||||
-(SVGMatrix*) translate:(float) x y:(float) y;
|
||||
-(SVGMatrix*) scale:(float) scaleFactor;
|
||||
-(SVGMatrix*) scaleNonUniform:(float) scaleFactorX scaleFactorY:(float) scaleFactorY;
|
||||
-(SVGMatrix*) rotate:(float) angle;
|
||||
-(SVGMatrix*) rotateFromVector:(float) x y:(float) y;
|
||||
-(SVGMatrix*) flipX;
|
||||
-(SVGMatrix*) flipY;
|
||||
-(SVGMatrix*) skewX:(float) angle;
|
||||
-(SVGMatrix*) skewY:(float) angle;
|
||||
|
||||
@end
|
@ -1,20 +0,0 @@
|
||||
|
||||
#import "SVGMatrix.h"
|
||||
|
||||
@implementation SVGMatrix
|
||||
|
||||
@synthesize a,b,c,d,e,f;
|
||||
|
||||
-(SVGMatrix*) multiply:(SVGMatrix*) secondMatrix { NSAssert( FALSE, @"Not implemented yet" ); return nil; }
|
||||
-(SVGMatrix*) inverse { NSAssert( FALSE, @"Not implemented yet" ); return nil; }
|
||||
-(SVGMatrix*) translate:(float) x y:(float) y { NSAssert( FALSE, @"Not implemented yet" ); return nil; }
|
||||
-(SVGMatrix*) scale:(float) scaleFactor { NSAssert( FALSE, @"Not implemented yet" ); return nil; }
|
||||
-(SVGMatrix*) scaleNonUniform:(float) scaleFactorX scaleFactorY:(float) scaleFactorY { NSAssert( FALSE, @"Not implemented yet" ); return nil; }
|
||||
-(SVGMatrix*) rotate:(float) angle { NSAssert( FALSE, @"Not implemented yet" ); return nil; }
|
||||
-(SVGMatrix*) rotateFromVector:(float) x y:(float) y { NSAssert( FALSE, @"Not implemented yet" ); return nil; }
|
||||
-(SVGMatrix*) flipX { NSAssert( FALSE, @"Not implemented yet" ); return nil; }
|
||||
-(SVGMatrix*) flipY { NSAssert( FALSE, @"Not implemented yet" ); return nil; }
|
||||
-(SVGMatrix*) skewX:(float) angle { NSAssert( FALSE, @"Not implemented yet" ); return nil; }
|
||||
-(SVGMatrix*) skewY:(float) angle { NSAssert( FALSE, @"Not implemented yet" ); return nil; }
|
||||
|
||||
@end
|
@ -1,12 +0,0 @@
|
||||
/*!
|
||||
|
||||
http://www.w3.org/TR/SVG/types.html#InterfaceSVGNumber
|
||||
|
||||
interface SVGNumber {
|
||||
attribute float value setraises(DOMException);
|
||||
};
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
float value;
|
||||
} SVGNumber;
|
@ -1,22 +0,0 @@
|
||||
/*!
|
||||
http://www.w3.org/TR/SVG/coords.html#InterfaceSVGPoint
|
||||
|
||||
interface SVGPoint {
|
||||
|
||||
attribute float x setraises(DOMException);
|
||||
attribute float y setraises(DOMException);
|
||||
|
||||
SVGPoint matrixTransform(in SVGMatrix matrix);
|
||||
};
|
||||
*/
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "SVGMatrix.h"
|
||||
|
||||
@interface SVGPoint : NSObject
|
||||
|
||||
@property(nonatomic,readonly) float x, y;
|
||||
|
||||
-(SVGPoint*) matrixTransform:(SVGMatrix*) matrix;
|
||||
|
||||
@end
|
@ -1,15 +0,0 @@
|
||||
|
||||
#import "SVGPoint.h"
|
||||
|
||||
@implementation SVGPoint
|
||||
|
||||
@synthesize x, y;
|
||||
|
||||
-(SVGPoint*) matrixTransform:(SVGMatrix*) matrix
|
||||
{
|
||||
NSAssert( FALSE, @"Not implemented yet" );
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
@ -1,59 +0,0 @@
|
||||
/**
|
||||
http://www.w3.org/TR/SVG/coords.html#InterfaceSVGPreserveAspectRatio
|
||||
|
||||
interface SVGPreserveAspectRatio {
|
||||
|
||||
// Alignment Types
|
||||
SVG_PRESERVEASPECTRATIO_UNKNOWN = 0;
|
||||
SVG_PRESERVEASPECTRATIO_NONE = 1;
|
||||
SVG_PRESERVEASPECTRATIO_XMINYMIN = 2;
|
||||
SVG_PRESERVEASPECTRATIO_XMIDYMIN = 3;
|
||||
SVG_PRESERVEASPECTRATIO_XMAXYMIN = 4;
|
||||
SVG_PRESERVEASPECTRATIO_XMINYMID = 5;
|
||||
SVG_PRESERVEASPECTRATIO_XMIDYMID = 6;
|
||||
SVG_PRESERVEASPECTRATIO_XMAXYMID = 7;
|
||||
SVG_PRESERVEASPECTRATIO_XMINYMAX = 8;
|
||||
SVG_PRESERVEASPECTRATIO_XMIDYMAX = 9;
|
||||
SVG_PRESERVEASPECTRATIO_XMAXYMAX = 10;
|
||||
|
||||
// Meet-or-slice Types
|
||||
SVG_MEETORSLICE_UNKNOWN = 0;
|
||||
SVG_MEETORSLICE_MEET = 1;
|
||||
SVG_MEETORSLICE_SLICE = 2;
|
||||
|
||||
attribute unsigned short align setraises(DOMException);
|
||||
attribute unsigned short meetOrSlice setraises(DOMException);
|
||||
};
|
||||
*/
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface SVGPreserveAspectRatio : NSObject
|
||||
|
||||
typedef enum SVG_PRESERVEASPECTRATIO
|
||||
{
|
||||
// Alignment Types
|
||||
SVG_PRESERVEASPECTRATIO_UNKNOWN = 0,
|
||||
SVG_PRESERVEASPECTRATIO_NONE = 1,
|
||||
SVG_PRESERVEASPECTRATIO_XMINYMIN = 2,
|
||||
SVG_PRESERVEASPECTRATIO_XMIDYMIN = 3,
|
||||
SVG_PRESERVEASPECTRATIO_XMAXYMIN = 4,
|
||||
SVG_PRESERVEASPECTRATIO_XMINYMID = 5,
|
||||
SVG_PRESERVEASPECTRATIO_XMIDYMID = 6,
|
||||
SVG_PRESERVEASPECTRATIO_XMAXYMID = 7,
|
||||
SVG_PRESERVEASPECTRATIO_XMINYMAX = 8,
|
||||
SVG_PRESERVEASPECTRATIO_XMIDYMAX = 9,
|
||||
SVG_PRESERVEASPECTRATIO_XMAXYMAX = 10
|
||||
} SVG_PRESERVEASPECTRATIO;
|
||||
|
||||
typedef enum SVG_MEETORSLICE
|
||||
{
|
||||
// Meet-or-slice Types
|
||||
SVG_MEETORSLICE_UNKNOWN = 0,
|
||||
SVG_MEETORSLICE_MEET = 1,
|
||||
SVG_MEETORSLICE_SLICE = 2
|
||||
} SVG_MEETORSLICE;
|
||||
|
||||
@property(nonatomic) SVG_PRESERVEASPECTRATIO align;
|
||||
@property(nonatomic) SVG_MEETORSLICE meetOrSlice;
|
||||
|
||||
@end
|
@ -1,15 +0,0 @@
|
||||
#import "SVGPreserveAspectRatio.h"
|
||||
|
||||
@implementation SVGPreserveAspectRatio
|
||||
|
||||
/** Sets default values mandated by SVG Spec */
|
||||
- (id)init
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
self.align = SVG_PRESERVEASPECTRATIO_XMIDYMID;
|
||||
self.meetOrSlice = SVG_MEETORSLICE_MEET;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@end
|
@ -1,43 +0,0 @@
|
||||
/*
|
||||
http://www.w3.org/TR/SVG/types.html#InterfaceSVGRect
|
||||
|
||||
interface SVGRect {
|
||||
attribute float x setraises(DOMException);
|
||||
attribute float y setraises(DOMException);
|
||||
attribute float width setraises(DOMException);
|
||||
attribute float height setraises(DOMException);
|
||||
};
|
||||
*/
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import <CoreGraphics/CoreGraphics.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
float width;
|
||||
float height;
|
||||
} SVGRect;
|
||||
|
||||
#pragma mark - utility methods that are NOT in the SVG Spec, bu which we need to implement it in ObjectiveC
|
||||
|
||||
/** C has no way of detecting if an SVGRect is deliberately 0 width (has special meaning in SVG), or accidentally (because it was
|
||||
never initialized).
|
||||
|
||||
Unfortunately, the SVG Spec authors defined "uninitialized" and "values of zero" to mean differnet things, so we MUST preserve
|
||||
that difference! */
|
||||
SVGRect SVGRectUninitialized(void);
|
||||
|
||||
/** c.f. note about SVGRectUninitialized() -- this method checks if a Rect is identical to the output of that method */
|
||||
BOOL SVGRectIsInitialized( SVGRect rect );
|
||||
|
||||
SVGRect SVGRectMake( float x, float y, float width, float height );
|
||||
|
||||
/** Convenience method to convert to ObjectiveC's kind of rect */
|
||||
CGRect CGRectFromSVGRect( SVGRect rect );
|
||||
|
||||
/** Convenience method to convert to ObjectiveC's kind of size - ONLY the width and height of this rect */
|
||||
CGSize CGSizeFromSVGRect( SVGRect rect );
|
||||
|
||||
NSString * _Nonnull NSStringFromSVGRect( SVGRect rect );
|
@ -1,43 +0,0 @@
|
||||
#import "SVGRect.h"
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
BOOL SVGRectIsInitialized( SVGRect rect )
|
||||
{
|
||||
return rect.x != -1 || rect.y != -1 || rect.width != -1 || rect.height != -1;
|
||||
}
|
||||
|
||||
SVGRect SVGRectUninitialized( void )
|
||||
{
|
||||
return SVGRectMake( -1, -1, -1, -1 );
|
||||
}
|
||||
|
||||
SVGRect SVGRectMake( float x, float y, float width, float height )
|
||||
{
|
||||
SVGRect result = { x, y, width, height };
|
||||
return result;
|
||||
}
|
||||
|
||||
CGRect CGRectFromSVGRect( SVGRect rect )
|
||||
{
|
||||
CGRect result = CGRectMake(rect.x, rect.y, rect.width, rect.height);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
CGSize CGSizeFromSVGRect( SVGRect rect )
|
||||
{
|
||||
CGSize result = CGSizeMake( rect.width, rect.height );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
NSString * NSStringFromSVGRect( SVGRect rect ) {
|
||||
CGRect cgRect = CGRectFromSVGRect(rect);
|
||||
#if SVGKIT_MAC
|
||||
return NSStringFromRect(cgRect);
|
||||
#else
|
||||
return NSStringFromCGRect(cgRect);
|
||||
#endif
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
#import "SVGSVGElement.h"
|
||||
|
||||
@interface SVGSVGElement ()
|
||||
|
||||
@property (nonatomic, strong, readwrite) /*FIXME: should be SVGAnimatedLength instead*/ SVGLength* x;
|
||||
@property (nonatomic, strong, readwrite) /*FIXME: should be SVGAnimatedLength instead*/ SVGLength* y;
|
||||
@property (nonatomic, strong, readwrite) /*FIXME: should be SVGAnimatedLength instead*/ SVGLength* width;
|
||||
@property (nonatomic, strong, readwrite) /*FIXME: should be SVGAnimatedLength instead*/ SVGLength* height;
|
||||
@property (nonatomic, strong, readwrite) NSString* contentScriptType;
|
||||
@property (nonatomic, strong, readwrite) NSString* contentStyleType;
|
||||
@property (nonatomic, readwrite) SVGRect viewport;
|
||||
@property (nonatomic, readwrite) float pixelUnitToMillimeterX;
|
||||
@property (nonatomic, readwrite) float pixelUnitToMillimeterY;
|
||||
@property (nonatomic, readwrite) float screenPixelToMillimeterX;
|
||||
@property (nonatomic, readwrite) float screenPixelToMillimeterY;
|
||||
@property (nonatomic, readwrite) BOOL useCurrentView;
|
||||
@property (nonatomic, strong, readwrite) SVGViewSpec* currentView;
|
||||
@property (nonatomic, readwrite) float currentScale;
|
||||
@property (nonatomic, strong, readwrite) SVGPoint* currentTranslate;
|
||||
|
||||
@end
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user