From 0a00f44ed8c8b309b0b4673d67a443e5d206aa4b Mon Sep 17 00:00:00 2001 From: adamgit Date: Sat, 16 Feb 2013 17:26:19 +0000 Subject: [PATCH] FIXED: SVG tags now render correctly with correct transforms, if the image data is embedded in the SVG (external images MIGHT OR MIGHT NOT work - we have no test data) --- SVGKit-iOS.xcodeproj/project.pbxproj | 2 ++ Source/DOM classes/SVG-DOM/SVGFitToViewBox.h | 17 +++++++++++ .../DOM classes/SVG-DOM/SVGHelperUtilities.m | 8 +++--- .../Unported or Partial DOM/SVGElement.m | 2 +- .../Unported or Partial DOM/SVGImageElement.h | 11 ++------ .../Unported or Partial DOM/SVGImageElement.m | 28 +++++++++++++------ .../Unported or Partial DOM/SVGSVGElement.h | 5 ++-- .../Unported or Partial DOM/SVGSVGElement.m | 15 ++++------ Source/SVGKImage.m | 1 + 9 files changed, 54 insertions(+), 35 deletions(-) create mode 100644 Source/DOM classes/SVG-DOM/SVGFitToViewBox.h diff --git a/SVGKit-iOS.xcodeproj/project.pbxproj b/SVGKit-iOS.xcodeproj/project.pbxproj index 6aa9a9224..7e32bddde 100644 --- a/SVGKit-iOS.xcodeproj/project.pbxproj +++ b/SVGKit-iOS.xcodeproj/project.pbxproj @@ -261,6 +261,7 @@ 66988DCE168A129500EC93C7 /* CSSValueList.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSSValueList.m; sourceTree = ""; }; 66988DD1168A13BC00EC93C7 /* CSSValue_ForSubclasses.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSSValue_ForSubclasses.h; sourceTree = ""; }; 66988DD9168A2F4200EC93C7 /* CSSPrimitiveValue_ConfigurablePixelsPerInch.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CSSPrimitiveValue_ConfigurablePixelsPerInch.h; sourceTree = ""; }; + 66A09CB016CFF494003CD5CD /* SVGFitToViewBox.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SVGFitToViewBox.h; sourceTree = ""; }; 66E8630E1688C2770059C9C4 /* AppleSucksDOMImplementation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppleSucksDOMImplementation.h; sourceTree = ""; }; 66E8630F1688C2770059C9C4 /* AppleSucksDOMImplementation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppleSucksDOMImplementation.m; sourceTree = ""; }; 66E863101688C2770059C9C4 /* Attr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Attr.h; sourceTree = ""; }; @@ -609,6 +610,7 @@ 663FD01216CAEF0B00CCBFB3 /* SVGHelperUtilities.h */, 663FD01316CAEF0C00CCBFB3 /* SVGHelperUtilities.m */, 663FD01716CAF05900CCBFB3 /* SVGTransformable.h */, + 66A09CB016CFF494003CD5CD /* SVGFitToViewBox.h */, 661ADBF016CC2FBE006F4BC3 /* SVGTextPositioningElement.h */, 661ADBF116CC2FBE006F4BC3 /* SVGTextPositioningElement.m */, 661ADBF516CC2FCA006F4BC3 /* SVGTextContentElement.h */, diff --git a/Source/DOM classes/SVG-DOM/SVGFitToViewBox.h b/Source/DOM classes/SVG-DOM/SVGFitToViewBox.h new file mode 100644 index 000000000..3f89d4366 --- /dev/null +++ b/Source/DOM classes/SVG-DOM/SVGFitToViewBox.h @@ -0,0 +1,17 @@ +/** + * http://www.w3.org/TR/SVG/types.html#InterfaceSVGFitToViewBox + + interface SVGFitToViewBox { + readonly attribute SVGAnimatedRect viewBox; + readonly attribute SVGAnimatedPreserveAspectRatio preserveAspectRatio; + */ + +#import + +#import + +@protocol SVGFitToViewBox + +@property (nonatomic) /* SVGAnimatedRect */ CGRect viewBox; + +@end diff --git a/Source/DOM classes/SVG-DOM/SVGHelperUtilities.m b/Source/DOM classes/SVG-DOM/SVGHelperUtilities.m index bc2f9e328..87f14377e 100644 --- a/Source/DOM classes/SVG-DOM/SVGHelperUtilities.m +++ b/Source/DOM classes/SVG-DOM/SVGHelperUtilities.m @@ -48,11 +48,11 @@ +(CGAffineTransform) transformRelativeIncludingViewportForTransformableOrViewpor || transformableOrSVGSVGElement.viewportElement == transformableOrSVGSVGElement // if it's some-other-object, then: we simply don't need to worry about it ) { - SVGSVGElement* svgSVGElement = (SVGSVGElement*) transformableOrSVGSVGElement; + SVGElement* svgSVGElement = (SVGElement*) transformableOrSVGSVGElement; /** Calculate the "implicit" viewport transform (caused by the tag's possible "viewBox" attribute) */ - CGRect frameViewBox = svgSVGElement.viewBoxFrame; - CGRect frameViewport = CGRectFromSVGRect( svgSVGElement.viewport ); + CGRect frameViewBox = svgSVGElement.viewBox; + CGRect frameViewport = CGRectFromSVGRect( ((SVGSVGElement*)svgSVGElement).viewport ); if( ! CGRectIsEmpty( frameViewBox ) ) { @@ -245,7 +245,7 @@ +(CALayer *) newCALayerForPathBasedSVGElement:(SVGElement*) sv //if( _shapeLayer != nil && svgGradient != nil ) //this nil check here is distrubing but blocking { - CAGradientLayer *gradientLayer = [((CAGradientLayer *)svgGradient) newGradientLayerForObjectRect:_shapeLayer.frame viewportRect:svgElement.rootOfCurrentDocumentFragment.viewBoxFrame]; + CAGradientLayer *gradientLayer = [((CAGradientLayer *)svgGradient) newGradientLayerForObjectRect:_shapeLayer.frame viewportRect:svgElement.rootOfCurrentDocumentFragment.viewBox]; NSLog(@"DOESNT WORK, APPLE's API APPEARS BROKEN???? - About to mask layer frame (%@) with a mask of frame (%@)", NSStringFromCGRect(gradientLayer.frame), NSStringFromCGRect(_shapeLayer.frame)); gradientLayer.mask =_shapeLayer; diff --git a/Source/DOM classes/Unported or Partial DOM/SVGElement.m b/Source/DOM classes/Unported or Partial DOM/SVGElement.m index f98dbba4e..2ddedb356 100644 --- a/Source/DOM classes/Unported or Partial DOM/SVGElement.m +++ b/Source/DOM classes/Unported or Partial DOM/SVGElement.m @@ -66,7 +66,7 @@ + (BOOL)shouldStoreContent { -(void) reCalculateAndSetViewportElementReferenceUsingFirstSVGAncestor:(SVGElement*) firstAncestor { // NB the root svg element IS a viewport, but SVG Spec defines it as NOT a viewport, and so we will overwrite this later - BOOL isTagAllowedToBeAViewport = [self.tagName isEqualToString:@"svg"] || [self.tagName isEqualToString:@"image"] || [self.tagName isEqualToString:@"foreignObject"]; + BOOL isTagAllowedToBeAViewport = [self.tagName isEqualToString:@"svg"] || [self.tagName isEqualToString:@"foreignObject"]; // NB: Spec lists "image" tag too but only as an IMPLICIT CREATOR - we don't actually handle it (it creates an tag ... that will be handled later) BOOL isTagDefiningAViewport = [self.attributes getNamedItem:@"width"] != nil || [self.attributes getNamedItem:@"height"] != nil; diff --git a/Source/DOM classes/Unported or Partial DOM/SVGImageElement.h b/Source/DOM classes/Unported or Partial DOM/SVGImageElement.h index 195e39ca2..9d3c7d801 100644 --- a/Source/DOM classes/Unported or Partial DOM/SVGImageElement.h +++ b/Source/DOM classes/Unported or Partial DOM/SVGImageElement.h @@ -1,19 +1,12 @@ -// -// SVGImageElement.h -// SvgLoader -// -// Created by Joshua May on 24/06/11. -// Copyright 2011 __MyCompanyName__. All rights reserved. -// - #import #import "SVGElement.h" #import "SVGTransformable.h" +#import "SVGFitToViewBox.h" #import "SVGElement_ForParser.h" // to resolve Xcode circular dependencies; in long term, parsing SHOULD NOT HAPPEN inside any class whose name starts "SVG" (because those are reserved classes for the SVG Spec) -@interface SVGImageElement : SVGElement +@interface SVGImageElement : SVGElement @property (nonatomic, readonly) CGFloat x; @property (nonatomic, readonly) CGFloat y; diff --git a/Source/DOM classes/Unported or Partial DOM/SVGImageElement.m b/Source/DOM classes/Unported or Partial DOM/SVGImageElement.m index 6812ec9bf..152841bbe 100644 --- a/Source/DOM classes/Unported or Partial DOM/SVGImageElement.m +++ b/Source/DOM classes/Unported or Partial DOM/SVGImageElement.m @@ -1,11 +1,3 @@ -// -// SVGKImageElement.m -// SvgLoader -// -// Created by Joshua May on 24/06/11. -// Copyright 2011 __MyCompanyName__. All rights reserved. -// - #import "SVGImageElement.h" #import "SVGHelperUtilities.h" @@ -42,6 +34,7 @@ @interface SVGImageElement() @implementation SVGImageElement @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 +@synthesize viewBox; // each SVGElement subclass that conforms to protocol "SVGFitToViewBox" 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 @synthesize x = _x; @synthesize y = _y; @@ -75,10 +68,24 @@ - (void)postProcessAttributesAddingErrorsTo:(SVGKParseResult *)parseResult { self.href = [self getAttribute:@"href"]; } + - (CALayer *) newLayer { - NSAssert( FALSE, @"NOT SUPPORTED: SVG Image Element . newLayer -- must be upgraded using the algorithm in SVGShapeElement.newLayer"); + CAShapeLayer* newLayer = [[CALayer alloc] init]; + newLayer.name = self.identifier; + [newLayer setValue:self.identifier forKey:kSVGElementIdentifier]; + + /** transform our LOCAL path into ABSOLUTE space */ + CGRect frame = CGRectMake(_x, _y, _width, _height); + frame = CGRectApplyAffineTransform(frame, [SVGHelperUtilities transformAbsoluteIncludingViewportForTransformableOrViewportEstablishingElement:self]); + newLayer.frame = frame; + + NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:_href]]; + SVGImageRef image = [SVGImage imageWithData:imageData]; + newLayer.contents = (id)SVGImageCGImage(image); + +#if OLD_CODE __block CALayer *layer = [[CALayer layer] retain]; layer.name = self.identifier; @@ -102,6 +109,9 @@ - (CALayer *) newLayer }); return layer; +#endif + + return newLayer; } - (void)layoutLayer:(CALayer *)layer { diff --git a/Source/DOM classes/Unported or Partial DOM/SVGSVGElement.h b/Source/DOM classes/Unported or Partial DOM/SVGSVGElement.h index c99fe9597..f4a63055a 100644 --- a/Source/DOM classes/Unported or Partial DOM/SVGSVGElement.h +++ b/Source/DOM classes/Unported or Partial DOM/SVGSVGElement.h @@ -47,6 +47,7 @@ */ #import "DocumentCSS.h" +#import "SVGFitToViewBox.h" #import "SVGElement.h" #import "SVGViewSpec.h" @@ -65,7 +66,7 @@ #import "SVGLayeredElement.h" -@interface SVGSVGElement : SVGElement < DocumentCSS, /* FIXME: refactor and delete this, it's in violation of the spec: */ SVGLayeredElement > +@interface SVGSVGElement : SVGElement < DocumentCSS, SVGFitToViewBox, /* FIXME: refactor and delete this, it's in violation of the spec: */ SVGLayeredElement > @@ -111,8 +112,6 @@ #pragma mark - below here VIOLATES THE STANDARD, but needs to be CAREFULLY merged with spec -@property (nonatomic, readonly) CGRect viewBoxFrame; // FIXME: this has NON TRIVIAL relationship to the viewport property above - - (SVGElement *)findFirstElementOfClass:(Class)class; /*< temporary convenience method until SVGDocument support is complete */ @end diff --git a/Source/DOM classes/Unported or Partial DOM/SVGSVGElement.m b/Source/DOM classes/Unported or Partial DOM/SVGSVGElement.m index f9b6e2ebf..5263e4976 100644 --- a/Source/DOM classes/Unported or Partial DOM/SVGSVGElement.m +++ b/Source/DOM classes/Unported or Partial DOM/SVGSVGElement.m @@ -10,10 +10,6 @@ #import #endif -@interface SVGSVGElement() -@property (nonatomic, readwrite) CGRect viewBoxFrame; -@end - @implementation SVGSVGElement @synthesize x; @@ -32,12 +28,13 @@ @implementation SVGSVGElement @synthesize currentScale; @synthesize currentTranslate; +@synthesize viewBox = _viewBox; + #pragma mark - NON SPEC, violating, properties -@synthesize viewBoxFrame = _viewBoxFrame; -(void)dealloc { - self.viewBoxFrame = CGRectNull; + self.viewBox = CGRectNull; [super dealloc]; } @@ -115,15 +112,15 @@ - (void)postProcessAttributesAddingErrorsTo:(SVGKParseResult *)parseResult { { NSArray* boxElements = [[self getAttribute:@"viewBox"] componentsSeparatedByString:@" "]; - _viewBoxFrame = CGRectMake([[boxElements objectAtIndex:0] floatValue], [[boxElements objectAtIndex:1] floatValue], [[boxElements objectAtIndex:2] floatValue], [[boxElements objectAtIndex:3] floatValue]); + _viewBox = CGRectMake([[boxElements objectAtIndex:0] floatValue], [[boxElements objectAtIndex:1] floatValue], [[boxElements objectAtIndex:2] floatValue], [[boxElements objectAtIndex:3] floatValue]); NSLog(@"[%@] WARNING: SVG spec says we should calculate the 'intrinsic aspect ratio'. Some badly-made SVG files work better if you do this and then post-multiply onto the specified viewBox attribute ... BUT they ALSO require that you 're-center' them inside the newly-created viewBox; and the SVG Spec DOES NOT SAY you should do that. All examples so far were authored in Inkscape, I think, so ... I think it's a serious bug in Inkscape that has tricked people into making incorrect SVG files. For example, c.f. http://en.wikipedia.org/wiki/File:BlankMap-World6-Equirectangular.svg", [self class]); //osx logging #if TARGET_OS_IPHONE - NSLog(@"[%@] DEBUG INFO: set document viewBox = %@", [self class], NSStringFromCGRect(self.viewBoxFrame)); + NSLog(@"[%@] DEBUG INFO: set document viewBox = %@", [self class], NSStringFromCGRect(self.viewBox)); #else //mac logging - NSLog(@"[%@] DEBUG INFO: set document viewBox = %@", [self class], NSStringFromRect(self.viewBoxFrame)); + NSLog(@"[%@] DEBUG INFO: set document viewBox = %@", [self class], NSStringFromRect(self.viewBox)); #endif } diff --git a/Source/SVGKImage.m b/Source/SVGKImage.m index 24d7e0edc..52083ba89 100644 --- a/Source/SVGKImage.m +++ b/Source/SVGKImage.m @@ -452,6 +452,7 @@ - (CALayer *)newLayerWithElement:(SVGElement *)element for (SVGElement *child in childNodes ) { if ([child conformsToProtocol:@protocol(SVGLayeredElement)]) { + CALayer *sublayer = [self newLayerWithElement:(SVGElement *)child]; if (!sublayer) {