Files
IJSVG/source/IJSVGQuartzRenderer.m
T
Curtis Hard 6d4eb76803 Squashed commit of the following:
commit ffb55b0f31
Author: Curtis Hard <curtishard@me.com>
Date:   Fri Mar 2 13:28:40 2018 +0000

    Fixes viewBox origin translate

commit a4c032afa2
Author: Curtis Hard <curtishard@me.com>
Date:   Wed Feb 28 21:29:11 2018 +0000

    Added clip to viewport

commit abe8f4cba5
Author: Curtis Hard <curtishard@me.com>
Date:   Wed Feb 28 21:00:20 2018 +0000

    Fixes drawInRect not obeying origin

commit a16842271b
Author: Curtis Hard <curtishard@me.com>
Date:   Mon Feb 26 13:46:41 2018 +0000

    Resolves namespaces correctly + added common HTML list to be parsed as groups

commit 58126e06e4
Author: Curtis Hard <curtishard@me.com>
Date:   Sun Feb 25 21:58:49 2018 +0000

    Fixes!

commit 5af5e054ab
Author: Curtis Hard <curtishard@me.com>
Date:   Fri Feb 23 22:37:53 2018 +0000

    Fixed defNode being removed

commit edd3aa1f33
Author: Curtis Hard <curtishard@me.com>
Date:   Fri Feb 23 16:29:54 2018 +0000

    excluded various elements from diff

commit 3366bc4fa5
Author: Curtis Hard <curtishard@me.com>
Date:   Fri Feb 23 14:05:03 2018 +0000

    Better optimaztion

commit 104002183b
Author: Curtis Hard <curtishard@me.com>
Date:   Thu Feb 22 22:17:50 2018 +0000

    Added rudimenatry inline styles -> stylesheet

commit 7010b7ea50
Author: Curtis Hard <curtishard@me.com>
Date:   Thu Feb 22 13:33:32 2018 +0000

    Correct order of cleanup

commit 5266a8c07a
Author: Curtis Hard <curtishard@me.com>
Date:   Thu Feb 22 08:22:17 2018 +0000

    corrent length of string

commit caf55e8bdf
Author: Curtis Hard <curtishard@me.com>
Date:   Wed Feb 21 20:45:17 2018 +0000

    removes useless def if required

commit 8160d05eba
Author: Curtis Hard <curtishard@me.com>
Date:   Tue Feb 20 14:12:02 2018 +0000

    Refactor of a few methods

commit a6d6a06521
Author: Curtis Hard <curtishard@me.com>
Date:   Tue Feb 20 09:40:21 2018 +0000

    Added collpasing of gradients

commit 103a4d71f6
Author: Curtis Hard <curtishard@me.com>
Date:   Mon Feb 19 19:07:30 2018 +0000

    Reduced floats even more

commit 98874b1d2c
Author: Curtis Hard <curtishard@me.com>
Date:   Mon Feb 19 18:53:02 2018 +0000

    More compression goodness

commit e742db31e0
Author: Curtis Hard <curtishard@me.com>
Date:   Mon Feb 19 14:02:15 2018 +0000

    Added intermediateParent

commit 198fd09f07
Author: Curtis Hard <curtishard@me.com>
Date:   Mon Feb 19 11:51:37 2018 +0000

    Fixes! and performance increases

commit 3493194b1b
Author: Curtis Hard <curtishard@me.com>
Date:   Mon Feb 19 08:20:02 2018 +0000

    Scale computation

commit 0016775eaf
Author: Curtis Hard <curtishard@me.com>
Date:   Sun Feb 18 22:33:26 2018 +0000

    More goodness

commit 304a04cc22
Author: Curtis Hard <curtishard@me.com>
Date:   Sun Feb 18 22:32:04 2018 +0000

    Vastly improved the exporter

commit e4fd0af582
Author: Curtis Hard <curtishard@me.com>
Date:   Sun Feb 18 15:20:28 2018 +0000

    This is insanely important!

commit 69a2a0c97e
Author: Curtis Hard <curtishard@me.com>
Date:   Sun Feb 4 22:02:19 2018 +0000

    Refactor

commit 5299bb0479
Author: Curtis Hard <curtishard@me.com>
Date:   Sun Feb 4 21:58:21 2018 +0000

    will continue to use CoreAnimation for the time being

commit 4f1943cad1
Author: Curtis Hard <curtishard@me.com>
Date:   Sun Feb 4 21:57:46 2018 +0000

    Fixes gradient strokes

commit f02d186293
Author: Curtis Hard <curtishard@me.com>
Date:   Sun Feb 4 11:15:04 2018 +0000

    trying to get masks to work

commit 3291718cfb
Author: Curtis Hard <curtishard@me.com>
Date:   Fri Feb 2 22:35:22 2018 +0000

    Beginning of quartz renderer

commit 6fbaaf5884
Author: Curtis Hard <curtishard@me.com>
Date:   Mon Jan 29 22:32:08 2018 +0000

    Removed useless log

commit abc65797ea
Author: Curtis Hard <curtishard@me.com>
Date:   Mon Jan 29 21:37:45 2018 +0000

    I think gradients work :D

commit af5a1c2718
Author: Curtis Hard <curtishard@me.com>
Date:   Sun Jan 28 22:18:02 2018 +0000

    Possible fx and fy things…

commit fb9a5282b9
Author: Curtis Hard <curtishard@me.com>
Date:   Sun Jan 28 19:22:40 2018 +0000

    Even more gradient fixes

commit d83933a103
Author: Curtis Hard <curtishard@me.com>
Date:   Sun Jan 28 14:21:50 2018 +0000

    Various improvements

commit bd7a0d5021
Author: Curtis Hard <curtishard@me.com>
Date:   Sat Jan 27 22:26:33 2018 +0000

    Start to linear

commit a9a038568c
Author: Curtis Hard <curtishard@me.com>
Date:   Sat Jan 27 21:14:25 2018 +0000

    This kind of actually works...

commit 77fbb38b6f
Author: Curtis Hard <curtishard@me.com>
Date:   Sat Jan 27 20:31:36 2018 +0000

    I guess this could be a good start?

    Posssible start of fixes?

commit 12c3191569
Author: Curtis Hard <curtishard@me.com>
Date:   Sat Jan 27 15:32:15 2018 +0000

    Added method for findind absolute position

commit e3e9626ef7
Author: Curtis Hard <curtishard@me.com>
Date:   Sat Jan 27 14:25:03 2018 +0000

    Fixes crash due to parentNode on temp groups being released

commit 1160d89f16
Author: Curtis Hard <curtishard@me.com>
Date:   Fri Jan 26 22:29:22 2018 +0000

    Fixes use statements with transforms

commit 1575cbfde8
Author: Curtis Hard <curtishard@me.com>
Date:   Fri Jan 26 18:16:03 2018 +0000

    Moved color tree over to modern syntax

commit 5c4c2eee91
Author: Curtis Hard <curtishard@me.com>
Date:   Thu Jan 25 18:23:53 2018 +0000

    Added HSL/HSLA support

commit 087b13e58f
Author: Curtis Hard <curtishard@me.com>
Date:   Wed Jan 24 22:24:43 2018 +0000

    Various image loading issues resolved from base64 images

commit 1183e167aa
Author: Curtis Hard <curtishard@me.com>
Date:   Wed Jan 24 21:21:41 2018 +0000

    Rect issue fix

commit 4dbfc59437
Author: Curtis Hard <curtishard@me.com>
Date:   Wed Jan 24 21:19:24 2018 +0000

    Moved transforms over from being concatinated to seperate calls

commit 409bd509fa
Author: Curtis Hard <curtishard@me.com>
Date:   Wed Jan 24 20:30:38 2018 +0000

    Fixes color issue

commit 8ae1d1b4e0
Author: Curtis Hard <curtishard@me.com>
Date:   Wed Jan 24 18:41:08 2018 +0000

    Removed check as its not needed here

commit 7243fbe5ff
Author: Curtis Hard <curtishard@me.com>
Date:   Wed Jan 24 18:35:43 2018 +0000

    Added excludeAttributes list to parseCommonAttributes

    added x and y to that list for rect

commit 51b9a5e85f
Author: Curtis Hard <curtishard@me.com>
Date:   Tue Jan 23 19:53:04 2018 +0000

    Added isSubcommand to IJSVGCommand

    - Fixes move command going awol when preceding move commands are not subcommands (woah)

commit 40098589de
Author: Curtis Hard <curtishard@me.com>
Date:   Mon Jan 22 22:04:48 2018 +0000

    removed reverseObjectEnumerator

    IJSVGTransform already deals with this at parse stage (was a test from earlier), spec states transforms are applied in reverse order (which parser already dealth with :-))

commit 7cb96b21f2
Author: Curtis Hard <curtishard@me.com>
Date:   Mon Jan 22 22:01:56 2018 +0000

    Removed use of origin here as its computed in apply defaults

commit 1bff7c6970
Author: Curtis Hard <curtishard@me.com>
Date:   Mon Jan 22 21:48:07 2018 +0000

    Various fixes… still going…
2018-03-02 13:51:49 +00:00

248 lines
8.3 KiB
Objective-C

//
// IJSVGRenderer.m
// IJSVGExample
//
// Created by Curtis Hard on 31/01/2018.
// Copyright © 2018 Curtis Hard. All rights reserved.
//
#import "IJSVGQuartzRenderer.h"
#import "IJSVG.h"
#import "IJSVGLayerTree.h"
#import "IJSVGGradientLayer.h"
#import "IJSVGStrokeLayer.h"
@implementation IJSVGQuartzRenderer
@synthesize scale, viewPort, backingScale;
- (void)renderLayer:(IJSVGLayer *)layer
inContext:(CGContextRef)ctx
{
// if layer is hidden, no need to continue
// trying to render it, its useless!
if(layer.hidden == YES) {
return;
}
// check which layers can actually be rendered
if(layer.class == IJSVGStrokeLayer.class ||
layer.class == IJSVGGradientLayer.class) {
return;
}
CGContextSaveGState(ctx);
// apply any transfroms so children also transform too
CGContextConcatCTM(ctx, layer.affineTransform);
CGContextSetAlpha(ctx, layer.opacity);
// is there a mask?!
if(layer.mask != nil) {
IJSVGLayer * maskLayer = (IJSVGLayer *)layer.mask;
CGRect rect;
CGImageRef maskImage = [self newMaskedImageForLayer:maskLayer
proposedRect:&rect];
CGRect maskRect = CGRectMake(0, 0, rect.size.width, rect.size.height);
CGContextClipToMask(ctx, maskRect, maskImage);
CGContextTranslateCTM(ctx, rect.origin.x, rect.origin.y);
CGImageRelease(maskImage);
}
// render itself
[self _renderLayer:layer
inContext:ctx];
// render the children recursively
for(IJSVGLayer * sublayer in layer.sublayers) {
[self renderLayer:sublayer
inContext:ctx];
}
CGContextRestoreGState(ctx);
}
- (void)_renderLayer:(IJSVGLayer *)layer
inContext:(CGContextRef)ctx
{
// is a shape layer
if(layer.class == IJSVGShapeLayer.class) {
// move the path
CGContextTranslateCTM(ctx, layer.frame.origin.x,
layer.frame.origin.y);
// find the shape
IJSVGShapeLayer * shape = (IJSVGShapeLayer *)layer;
CGPathRef path = shape.path;
// has just a plain fill color
CGContextSaveGState(ctx); {
CGContextAddPath(ctx, path);
if([shape.fillRule isEqualToString:kCAFillRuleEvenOdd]) {
CGContextEOClip(ctx);
} else {
CGContextClip(ctx);
}
CGContextAddPath(ctx, path);
if(shape.gradientFillLayer == nil) {
if(shape.fillColor != nil) {
CGContextSetFillColorWithColor(ctx, shape.fillColor);
CGContextFillPath(ctx);
}
// has a gradient fill
} else if(shape.gradientFillLayer != nil) {
CGContextSaveGState(ctx); {
CGContextSetAlpha(ctx, shape.gradientFillLayer.opacity);
[shape.gradientFillLayer drawInContext:ctx];
} CGContextRestoreGState(ctx);
}
} CGContextRestoreGState(ctx);
// stroke must be done outside of the fill due to
// clipping path will cause it to render incorrectly
CGContextSaveGState(ctx); {
// any stroke?
if(shape.strokeLayer != nil) {
IJSVGStrokeLayer * strokeLayer = (IJSVGStrokeLayer *)shape.strokeLayer;
if(strokeLayer.strokeColor != nil) {
CGContextSaveGState(ctx); {
// set opacity
CGContextSetAlpha(ctx, strokeLayer.opacity);
CGContextSetLineCap(ctx, [self.class lineCapFromLayer:strokeLayer]);
CGContextSetLineJoin(ctx, [self.class lineJoinFromLayer:strokeLayer]);
// are there any line dashes?
NSArray * dash = strokeLayer.lineDashPattern;
CGFloat * lengths = (CGFloat *)malloc(sizeof(CGFloat)*dash.count);
NSInteger i = 0;
for(NSNumber * number in dash) {
lengths[i++] = number.floatValue;
}
CGContextSetLineDash(ctx, strokeLayer.lineDashPhase,
lengths, dash.count);
free(lengths);
// get bounding box of the current path
CGContextAddPath(ctx, strokeLayer.path);
CGContextSetLineWidth(ctx, strokeLayer.lineWidth);
CGContextSetStrokeColorWithColor(ctx, strokeLayer.strokeColor);
CGContextStrokePath(ctx);
} CGContextRestoreGState(ctx);
}
} else {
CGContextSetLineWidth(ctx, 0.f);
CGContextStrokePath(ctx);
}
} CGContextRestoreGState(ctx);
}
}
+ (CGLineJoin)lineJoinFromLayer:(IJSVGShapeLayer *)layer
{
if([layer.lineJoin isEqualToString:kCALineJoinBevel]) {
return kCGLineJoinBevel;
} else if([layer.lineJoin isEqualToString:kCALineJoinMiter]) {
return kCGLineJoinMiter;
}
return kCGLineJoinRound;
}
+ (CGLineCap)lineCapFromLayer:(IJSVGShapeLayer *)layer
{
if([layer.lineCap isEqualToString:kCALineCapButt]) {
return kCGLineCapButt;
} else if([layer.lineCap isEqualToString:kCALineCapRound]) {
return kCGLineCapRound;
}
return kCGLineCapSquare;
}
+ (CGRect)findFrameForLayer:(IJSVGLayer *)layer
{
CGRect rect = layer.frame;
return [self _recursivelyFindFrameForLayer:layer
rect:rect];
}
+ (CGRect)_recursivelyFindFrameForLayer:(IJSVGLayer *)layer
rect:(CGRect)rect
{
CGRect frame = layer.frame;
if(CGRectGetMinX(frame) < CGRectGetMinX(rect)) {
rect.origin.x = CGRectGetMinX(frame);
}
if(CGRectGetMinY(frame) < CGRectGetMinY(rect)) {
rect.origin.y = CGRectGetMinY(frame);
}
if(CGRectGetMaxX(frame) > CGRectGetMaxX(rect)) {
rect.size.width = CGRectGetMaxX(frame);
}
if(CGRectGetMaxY(frame) > CGRectGetMaxY(rect)) {
rect.size.height = CGRectGetMaxY(frame);
}
for(IJSVGLayer * sublayer in layer.sublayers) {
rect = [self _recursivelyFindFrameForLayer:sublayer
rect:rect];
}
return rect;
}
- (CGRect)convertLayerFrame:(CGRect)rect
{
rect.size.width = fabs(rect.origin.x - rect.size.width);
rect.size.height = fabs(rect.origin.y - rect.size.height);
rect.origin.x = rect.origin.y = 0.f;
return rect;
}
- (CGImageRef)newImageForLayer:(IJSVGLayer *)layer
colorSpace:(CGColorSpaceRef)colorSpace
proposedRect:(CGRect *)proposedRect
{
// create color space and new context
NSRect cRect = [self.class findFrameForLayer:layer];
NSRect convertedSize = [self convertLayerFrame:cRect];
CGSize size = cRect.size;
*proposedRect = cRect;
CGFloat actualScale = self.scale * self.backingScale;
CGContextRef ctx = CGBitmapContextCreate(NULL, size.width * actualScale,
size.height * actualScale,
8, 0, colorSpace,
kCGImageAlphaPremultipliedLast);
CGContextScaleCTM(ctx, actualScale, actualScale);
// render the layer tree into this context
[self renderLayer:layer
inContext:ctx];
// grab image from it
CGImageRef image = CGBitmapContextCreateImage(ctx);
// clean memory
CGContextRelease(ctx);
return image;
}
- (CGImageRef)newMaskedImageForLayer:(IJSVGLayer *)layer
proposedRect:(CGRect *)proposedRect
{
// create color space and new context
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();
CGImageRef image = [self newImageForLayer:layer
colorSpace:colorSpace
proposedRect:proposedRect];
CGColorSpaceRelease(colorSpace);
return image;
}
@end