diff --git a/Example/examples/Circle.js b/Example/examples/Circle.js index 2a18b6a8..f29951cd 100644 --- a/Example/examples/Circle.js +++ b/Example/examples/Circle.js @@ -37,7 +37,7 @@ class StrokeCircle extends Component{ r="45" stroke="purple" strokeWidth="2.5" - fill={null} + fill="none" /> ; } diff --git a/Example/examples/Definations.js b/Example/examples/Definations.js index fc4640e6..b188b787 100644 --- a/Example/examples/Definations.js +++ b/Example/examples/Definations.js @@ -25,10 +25,10 @@ class DefsExample extends Component{ > - + - + @@ -41,9 +41,9 @@ class DefsExample extends Component{ - + - + ; } diff --git a/Example/examples/Path.js b/Example/examples/Path.js index b85f79ab..7377b876 100644 --- a/Example/examples/Path.js +++ b/Example/examples/Path.js @@ -11,6 +11,7 @@ import Svg, { class PathExample extends Component{ static title = 'Path'; + render() { return this.root = ele} - asClipPath={this.props.asClipPath} + mergeList={reusableProps(extractedProps, props)} > {this.props.children} ; diff --git a/elements/Use.js b/elements/Use.js index 12e1a2c2..84c40397 100644 --- a/elements/Use.js +++ b/elements/Use.js @@ -1,10 +1,11 @@ import {PropTypes} from 'react'; import {pathProps} from '../lib/props'; -import {UseAttributes, RenderableOnlyAttributes} from '../lib/attributes'; +import {UseAttributes} from '../lib/attributes'; import Shape from './Shape'; import React from 'react'; import patternReg from '../lib/extract/patternReg'; import createReactNativeComponentClass from 'react/lib/createReactNativeComponentClass'; +import reusableProps from '../lib/reusableProps'; import _ from 'lodash'; class Defs extends Shape { @@ -33,8 +34,6 @@ class Defs extends Shape { console.warn('Invalid `href` prop for `Use` element, expected a href like `"url(#id)"`, but got: "' + props.href + '"'); } - let mergeList = []; - let extractedProps = this.extractProps(props, { stroke: true, fill: true, @@ -42,26 +41,10 @@ class Defs extends Shape { transform: true }); - Object.keys(RenderableOnlyAttributes).forEach(name => { - - if (!_.isNil(props[name])) { - // clipPath prop may provide `clipPathRef` as native prop - if (name === 'clipPath') { - if (extractedProps[name]) { - mergeList.push(name); - } else if (extractedProps.clipPathRef) { - mergeList.push('clipPathRef'); - } - } else { - mergeList.push(name); - } - } - }); - return this.root = ele} {...extractedProps} - mergeList={mergeList} + mergeList={reusableProps(extractedProps, props)} href={href} >{props.children}; } diff --git a/ios/Elements/RNSVGGroup.h b/ios/Elements/RNSVGGroup.h index ad4bd435..9091519f 100644 --- a/ios/Elements/RNSVGGroup.h +++ b/ios/Elements/RNSVGGroup.h @@ -15,6 +15,8 @@ @interface RNSVGGroup : RNSVGNode +@property (nonatomic, copy) NSArray *mergeList; + - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event; @end diff --git a/ios/Elements/RNSVGGroup.m b/ios/Elements/RNSVGGroup.m index dc6c7e7b..ba1b8e91 100644 --- a/ios/Elements/RNSVGGroup.m +++ b/ios/Elements/RNSVGGroup.m @@ -17,6 +17,7 @@ [self clip:context]; for (RNSVGNode *node in self.subviews) { + //[node mergeProperties:self mergeList:self.mergeList]; [node renderTo:context]; if (node.responsible && !svg.responsible) { @@ -32,7 +33,7 @@ CGAffineTransform transform = node.transform; CGPathAddPath(path, &transform, [node getPath:context]); } - return path; + return (CGPathRef)CFAutorelease(path); } // hitTest delagate diff --git a/ios/Elements/RNSVGImage.m b/ios/Elements/RNSVGImage.m index a732a874..560c6055 100644 --- a/ios/Elements/RNSVGImage.m +++ b/ios/Elements/RNSVGImage.m @@ -14,6 +14,7 @@ { CGImageRef image; } + - (void)setSrc:(id)src { if (src == _src) { @@ -79,7 +80,10 @@ CGFloat h = [convert stringToFloat:self.height relative:height offset:0]; // add hit area - CGPathAddPath(self.nodeArea, nil, CGPathCreateWithRect(CGRectMake(x, y, w, h), nil)); + self.hitArea = CGPathCreateMutable(); + CGPathRef rect = CGPathCreateWithRect(CGRectMake(x, y, w, h), nil); + CGPathAddPath(self.hitArea, nil, rect); + CGPathRelease(rect); if (self.opacity == 0) { return; diff --git a/ios/Elements/RNSVGPath.m b/ios/Elements/RNSVGPath.m index 846fca88..13393297 100644 --- a/ios/Elements/RNSVGPath.m +++ b/ios/Elements/RNSVGPath.m @@ -31,13 +31,14 @@ return; } - // Add path to nodeArea - CGPathAddPath(self.nodeArea, nil, _d); + // Add path to hitArea + self.hitArea = CGPathCreateMutableCopy(_d); if (self.stroke) { - // Add stroke to nodeArea + // Add stroke to hitArea CGPathRef strokePath = CGPathCreateCopyByStrokingPath(_d, nil, self.strokeWidth, self.strokeLinecap, self.strokeLinejoin, self.strokeMiterlimit); - CGPathAddPath(self.nodeArea, nil, strokePath); + CGPathAddPath(self.hitArea, nil, strokePath); + CGPathRelease(strokePath); } if (self.opacity == 0) { diff --git a/ios/Elements/RNSVGUse.h b/ios/Elements/RNSVGUse.h index 746d916b..91413cf8 100644 --- a/ios/Elements/RNSVGUse.h +++ b/ios/Elements/RNSVGUse.h @@ -17,5 +17,4 @@ @property (nonatomic, strong) NSString *href; @property (nonatomic, copy) NSArray *mergeList; - @end diff --git a/ios/Elements/RNSVGUse.m b/ios/Elements/RNSVGUse.m index efe98bcc..13a67d87 100644 --- a/ios/Elements/RNSVGUse.m +++ b/ios/Elements/RNSVGUse.m @@ -23,9 +23,21 @@ { RNSVGNode* template = [[self getSvgView] getDefinedTemplate:self.href]; if (template) { + CGFloat opacity = self.opacity; + BOOL transparent = opacity < 1; + + if (transparent) { + CGContextBeginTransparencyLayer(context, NULL); + } + + [self clip:context]; [template mergeProperties:self mergeList:self.mergeList]; [template renderTo:context]; [template resetProperties]; + + if (transparent) { + CGContextEndTransparencyLayer(context); + } } else if (self.href) { // TODO: calling yellow box here RCTLogWarn(@"`Use` element expected a pre-defined svg template as `href` prop, template named: %@ is not defined.", self.href); diff --git a/ios/RNSVG.xcodeproj/project.pbxproj b/ios/RNSVG.xcodeproj/project.pbxproj index 2d8aa615..fa74592f 100644 --- a/ios/RNSVG.xcodeproj/project.pbxproj +++ b/ios/RNSVG.xcodeproj/project.pbxproj @@ -19,7 +19,6 @@ 1039D28A1CE71EB7001E90A8 /* RNSVGImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 1039D2841CE71EB7001E90A8 /* RNSVGImage.m */; }; 1039D28B1CE71EB7001E90A8 /* RNSVGPath.m in Sources */ = {isa = PBXBuildFile; fileRef = 1039D2861CE71EB7001E90A8 /* RNSVGPath.m */; }; 1039D28C1CE71EB7001E90A8 /* RNSVGSvgView.m in Sources */ = {isa = PBXBuildFile; fileRef = 1039D2881CE71EB7001E90A8 /* RNSVGSvgView.m */; }; - 1039D2941CE71EC2001E90A8 /* RnSVGGlyphCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 1039D28E1CE71EC2001E90A8 /* RnSVGGlyphCache.m */; }; 1039D2951CE71EC2001E90A8 /* RNSVGText.m in Sources */ = {isa = PBXBuildFile; fileRef = 1039D2901CE71EC2001E90A8 /* RNSVGText.m */; }; 1039D2961CE71EC2001E90A8 /* UIBezierPath-Points.m in Sources */ = {isa = PBXBuildFile; fileRef = 1039D2931CE71EC2001E90A8 /* UIBezierPath-Points.m */; }; 1039D2A01CE72177001E90A8 /* RCTConvert+RNSVG.m in Sources */ = {isa = PBXBuildFile; fileRef = 1039D29C1CE72177001E90A8 /* RCTConvert+RNSVG.m */; }; @@ -88,8 +87,6 @@ 1039D2861CE71EB7001E90A8 /* RNSVGPath.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNSVGPath.m; path = Elements/RNSVGPath.m; sourceTree = ""; }; 1039D2871CE71EB7001E90A8 /* RNSVGSvgView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSVGSvgView.h; path = Elements/RNSVGSvgView.h; sourceTree = ""; }; 1039D2881CE71EB7001E90A8 /* RNSVGSvgView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNSVGSvgView.m; path = Elements/RNSVGSvgView.m; sourceTree = ""; }; - 1039D28D1CE71EC2001E90A8 /* RNSVGGlyphCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSVGGlyphCache.h; path = Text/RNSVGGlyphCache.h; sourceTree = ""; }; - 1039D28E1CE71EC2001E90A8 /* RnSVGGlyphCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RnSVGGlyphCache.m; path = Text/RnSVGGlyphCache.m; sourceTree = ""; }; 1039D28F1CE71EC2001E90A8 /* RNSVGText.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSVGText.h; path = Text/RNSVGText.h; sourceTree = ""; }; 1039D2901CE71EC2001E90A8 /* RNSVGText.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNSVGText.m; path = Text/RNSVGText.m; sourceTree = ""; }; 1039D2911CE71EC2001E90A8 /* RNSVGTextFrame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSVGTextFrame.h; path = Text/RNSVGTextFrame.h; sourceTree = ""; }; @@ -265,8 +262,6 @@ 1039D27F1CE71D9B001E90A8 /* Text */ = { isa = PBXGroup; children = ( - 1039D28D1CE71EC2001E90A8 /* RNSVGGlyphCache.h */, - 1039D28E1CE71EC2001E90A8 /* RnSVGGlyphCache.m */, 1039D28F1CE71EC2001E90A8 /* RNSVGText.h */, 1039D2901CE71EC2001E90A8 /* RNSVGText.m */, 1039D2911CE71EC2001E90A8 /* RNSVGTextFrame.h */, @@ -373,7 +368,6 @@ 1039D28A1CE71EB7001E90A8 /* RNSVGImage.m in Sources */, 10BA0D4B1CE74E3D00887C2B /* RNSVGRect.m in Sources */, 10BA0D341CE74E3100887C2B /* RNSVGCircleManager.m in Sources */, - 1039D2941CE71EC2001E90A8 /* RnSVGGlyphCache.m in Sources */, 10BEC1BC1D3F66F500FDCB19 /* RNSVGLinearGradient.m in Sources */, 1039D2B01CE72F27001E90A8 /* RNSVGPercentageConverter.m in Sources */, 10BA0D491CE74E3D00887C2B /* RNSVGEllipse.m in Sources */, diff --git a/ios/RNSVGNode.m b/ios/RNSVGNode.m index b57d09c1..88f06eca 100644 --- a/ios/RNSVGNode.m +++ b/ios/RNSVGNode.m @@ -11,9 +11,6 @@ #import "RNSVGClipPath.h" @implementation RNSVGNode -{ - CGFloat originOpacity; -} - (void)insertReactSubview:(UIView *)subview atIndex:(NSInteger)atIndex { @@ -76,11 +73,14 @@ CGContextSaveGState(context); CGContextConcatCTM(context, self.transform); CGContextSetAlpha(context, opacity); + if (transparent) { CGContextBeginTransparencyLayer(context, NULL); } + [self renderClip:context]; [self renderLayerTo:context]; + if (transparent) { CGContextEndTransparencyLayer(context); } @@ -118,7 +118,7 @@ - (CGPathRef)getPath: (CGContextRef) context { // abstract - return CGPathCreateMutable(); + return (CGPathRef)CFAutorelease(CGPathCreateMutable()); } - (void)clip:(CGContextRef)context @@ -193,13 +193,12 @@ - (void)mergeProperties:(__kindof RNSVGNode *)target mergeList:(NSArray *)mergeList { - originOpacity = self.opacity; - self.opacity = target.opacity * self.opacity; + // abstract } - (void)resetProperties { - self.opacity = originOpacity; + // abstract } - (void)dealloc diff --git a/ios/RNSVGRenderable.h b/ios/RNSVGRenderable.h index a174936c..1049b042 100644 --- a/ios/RNSVGRenderable.h +++ b/ios/RNSVGRenderable.h @@ -26,7 +26,7 @@ @property (nonatomic, assign) CGFloat strokeMiterlimit; @property (nonatomic, assign) RNSVGCGFloatArray strokeDasharray; @property (nonatomic, assign) CGFloat strokeDashoffset; -@property (nonatomic, assign) CGMutablePathRef nodeArea; +@property (nonatomic, assign) CGMutablePathRef hitArea; - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event; diff --git a/ios/RNSVGRenderable.m b/ios/RNSVGRenderable.m index e8314a2c..66f8105e 100644 --- a/ios/RNSVGRenderable.m +++ b/ios/RNSVGRenderable.m @@ -16,13 +16,24 @@ - (id)init { - self = [super init]; - if (self) { - _nodeArea = CGPathCreateMutable(); + if (self = [super init]) { + _fillOpacity = 1; + _strokeOpacity = 1; + _strokeWidth = 1; } return self; } +- (void)setHitArea:(CGMutablePathRef)hitArea +{ + if (hitArea == _hitArea) { + return; + } + [self invalidate]; + CGPathRelease(_hitArea); + _hitArea = hitArea; +} + - (void)setFill:(RNSVGBrush *)fill { [self invalidate]; @@ -79,7 +90,7 @@ - (void)dealloc { - CGPathRelease(_nodeArea); + CGPathRelease(_hitArea); if (_strokeDasharray.array) { free(_strokeDasharray.array); } @@ -106,7 +117,7 @@ - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { CGPathRef clipPath = self.clipPath; - if (self.nodeArea && CGPathContainsPoint(self.nodeArea, nil, point, NO)) { + if (self.hitArea && CGPathContainsPoint(self.hitArea, nil, point, NO)) { if (!clipPath) { return self; } else { @@ -131,8 +142,6 @@ [originProperties setValue:[self valueForKey:key] forKey:key]; [self setValue:[target valueForKey:key] forKey:key]; } - - [super mergeProperties:target mergeList:mergeList]; } - (void)resetProperties diff --git a/ios/Shapes/RNSVGCircle.m b/ios/Shapes/RNSVGCircle.m index 513971e8..6bc13c91 100644 --- a/ios/Shapes/RNSVGCircle.m +++ b/ios/Shapes/RNSVGCircle.m @@ -67,7 +67,7 @@ } CGPathAddArc(path, nil, cx, cy, r, 0, 2*M_PI, YES); - return path; + return (CGPathRef)CFAutorelease(path); } @end diff --git a/ios/Shapes/RNSVGEllipse.m b/ios/Shapes/RNSVGEllipse.m index 53c4b64a..07f51292 100644 --- a/ios/Shapes/RNSVGEllipse.m +++ b/ios/Shapes/RNSVGEllipse.m @@ -67,7 +67,7 @@ CGFloat rx = [convert stringToFloat:self.rx relative:width offset:0]; CGFloat ry = [convert stringToFloat:self.ry relative:height offset:0]; CGPathAddEllipseInRect(path, nil, CGRectMake(cx - rx, cy - ry, rx * 2, ry * 2)); - return path; + return (CGPathRef)CFAutorelease(path); } @end diff --git a/ios/Shapes/RNSVGLine.m b/ios/Shapes/RNSVGLine.m index 33275a3c..f01f2146 100644 --- a/ios/Shapes/RNSVGLine.m +++ b/ios/Shapes/RNSVGLine.m @@ -69,7 +69,7 @@ CGPathMoveToPoint(path, nil, x1, y1); CGPathAddLineToPoint(path, nil, x2, y2); - return path; + return (CGPathRef)CFAutorelease(path); } @end diff --git a/ios/Shapes/RNSVGRect.m b/ios/Shapes/RNSVGRect.m index 9c2ac9fa..cb9b1785 100644 --- a/ios/Shapes/RNSVGRect.m +++ b/ios/Shapes/RNSVGRect.m @@ -109,7 +109,7 @@ CGPathAddRect(path, nil, CGRectMake(x, y, w, h)); } - return path; + return (CGPathRef)CFAutorelease(path); } @end diff --git a/ios/Text/RNSVGGlyphCache.h b/ios/Text/RNSVGGlyphCache.h deleted file mode 100644 index 114b1bb4..00000000 --- a/ios/Text/RNSVGGlyphCache.h +++ /dev/null @@ -1,27 +0,0 @@ -/** - * Copyright (c) 2015-present, Horcrux. - * All rights reserved. - * - * This source code is licensed under the MIT-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -// This implements a very simple glyph cache. -// It maps from CTFontRef to CGGlyph to CGPathRef in order to reuse glyphs. -// It does NOT try to retain the keys that are used (CTFontRef or CGGlyph) -// but that is not an issue with respect to how it is used by this sample. - -#import -#import -#import "RNSVGRenderable.h" - -@interface RNSVGGlyphCache : NSObject -{ - CFMutableDictionaryRef cache; -} - -- (id)init; -- (CGPathRef)pathForGlyph:(CGGlyph)glyph fromFont:(CTFontRef)font; - - -@end \ No newline at end of file diff --git a/ios/Text/RNSVGText.h b/ios/Text/RNSVGText.h index d283062a..05e249e1 100644 --- a/ios/Text/RNSVGText.h +++ b/ios/Text/RNSVGText.h @@ -10,7 +10,6 @@ #import "UIBezierPath-Points.h" #import "RNSVGPath.h" #import "RNSVGTextFrame.h" -#import "RNSVGGlyphCache.h" @interface RNSVGText : RNSVGPath diff --git a/ios/Text/RNSVGText.m b/ios/Text/RNSVGText.m index ff39d98c..d7984667 100644 --- a/ios/Text/RNSVGText.m +++ b/ios/Text/RNSVGText.m @@ -32,7 +32,7 @@ static void RNSVGFreeTextFrame(RNSVGTextFrame frame) - (void)setTextFrame:(RNSVGTextFrame)frame { - if (frame.lines != _textFrame.lines) { + if (frame.lines == _textFrame.lines) { RNSVGFreeTextFrame(_textFrame); } [self invalidate]; @@ -82,25 +82,25 @@ static void RNSVGFreeTextFrame(RNSVGTextFrame frame) // We should consider snapping this shift to device pixels to improve rendering quality // when a line has subpixel width. CGAffineTransform offset = CGAffineTransformMakeTranslation(-shift, frame.baseLine + frame.lineHeight * i + (self.path ? -frame.lineHeight : 0)); - CGPathAddPath(path, &offset, [self setLinePath:frame.lines[i]]); + + CGMutablePathRef line = [self setLinePath:frame.lines[i]]; + CGPathAddPath(path, &offset, line); + CGPathRelease(line); } - return path; + return (CGPathRef)CFAutorelease(path); } -- (CGPathRef)setLinePath:(CTLineRef)line +- (CGMutablePathRef)setLinePath:(CTLineRef)line { - CGAffineTransform upsideDown = CGAffineTransformMakeScale(1.0, -1.0); CGMutablePathRef path = CGPathCreateMutable(); - RNSVGGlyphCache *cache = [[RNSVGGlyphCache alloc] init]; CTLineGetGlyphRuns(line); CFArrayRef glyphRuns = CTLineGetGlyphRuns(line); CFIndex runCount = CFArrayGetCount(glyphRuns); CFIndex glyphIndex = 0; - for(CFIndex i = 0; i < runCount; ++i) - { - + + for(CFIndex i = 0; i < runCount; ++i) { // For each run, we need to get the glyphs, their font (to get the path) and their locations. CTRunRef run = CFArrayGetValueAtIndex(glyphRuns, i); CFIndex runGlyphCount = CTRunGetGlyphCount(run); @@ -112,9 +112,11 @@ static void RNSVGFreeTextFrame(RNSVGTextFrame frame) CTRunGetGlyphs(run, CFRangeMake(0, 0), glyphs); CFDictionaryRef attributes = CTRunGetAttributes(run); CTFontRef runFont = CFDictionaryGetValue(attributes, kCTFontAttributeName); + for(CFIndex j = 0; j < runGlyphCount; ++j, ++glyphIndex) { - CGPathRef letter = [cache pathForGlyph:glyphs[j] fromFont:runFont]; + CGPathRef letter = CTFontCreatePathForGlyph(runFont, glyphs[j], nil); CGPoint point = positions[j]; + if (letter) { CGAffineTransform transform; @@ -122,23 +124,29 @@ static void RNSVGFreeTextFrame(RNSVGTextFrame frame) if (self.path) { CGPoint slope; CGRect bounding = CGPathGetBoundingBox(letter); - UIBezierPath* path = [UIBezierPath bezierPathWithCGPath:self.path]; - CGFloat percentConsumed = (point.x + bounding.size.width) / path.length; + UIBezierPath* pathAlong = [UIBezierPath bezierPathWithCGPath:self.path]; + CGFloat percentConsumed = (point.x + bounding.size.width) / pathAlong.length; if (percentConsumed >= 1.0f) { + CGPathRelease(letter); continue; } - CGPoint targetPoint = [path pointAtPercent:percentConsumed withSlope: &slope]; + CGPoint targetPoint = [pathAlong pointAtPercent:percentConsumed withSlope: &slope]; float angle = atan(slope.y / slope.x); // + M_PI; - if (slope.x < 0) angle += M_PI; // going left, update the angle + if (slope.x < 0) { + angle += M_PI; // going left, update the angle + } transform = CGAffineTransformMakeTranslation(targetPoint.x - bounding.size.width, targetPoint.y); transform = CGAffineTransformRotate(transform, angle); transform = CGAffineTransformScale(transform, 1.0, -1.0); } else { transform = CGAffineTransformTranslate(upsideDown, point.x, point.y); } + CGPathAddPath(path, &transform, letter); } + + CGPathRelease(letter); } } diff --git a/ios/Text/RnSVGGlyphCache.m b/ios/Text/RnSVGGlyphCache.m deleted file mode 100644 index 9b80ba72..00000000 --- a/ios/Text/RnSVGGlyphCache.m +++ /dev/null @@ -1,63 +0,0 @@ -/** - * Copyright (c) 2015-present, Horcrux. - * All rights reserved. - * - * This source code is licensed under the MIT-style license found in the - * LICENSE file in the root directory of this source tree. - */ - -#import "RNSVGGlyphCache.h" - -@implementation RNSVGGlyphCache - --(id)init -{ - self = [super init]; - if(self) - { - cache = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, NULL, &kCFTypeDictionaryValueCallBacks); - } - return self; -} - --(void)dealloc -{ - CFRelease(cache); -} - --(CGPathRef)pathForGlyph:(CGGlyph)glyph fromFont:(CTFontRef)font -{ - // First we lookup the font to get to its glyph dictionary - CFMutableDictionaryRef glyphDict = (CFMutableDictionaryRef)CFDictionaryGetValue(cache, font); - if(!glyphDict) - { - // And if this font hasn't been seen before, we'll create and set the dictionary for it - glyphDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, NULL, &kCFTypeDictionaryValueCallBacks); - CFDictionarySetValue(cache, font, glyphDict); - CFRelease(glyphDict); - } - // Next we try to get a path for the given glyph from the glyph dictionary - CGPathRef path = (CGPathRef)CFDictionaryGetValue(glyphDict, (const void *)(uintptr_t)glyph); - if(!path) - { - // If the path hasn't been seen before, then we'll create the path from the font & glyph and cache it. - path = CTFontCreatePathForGlyph(font, glyph, NULL); - if(!path) - { - // If a glyph does not have a path, then we need a placeholder to set in the dictionary - path = (CGPathRef)kCFNull; - } - CFDictionarySetValue(glyphDict, (const void *)(uintptr_t)glyph, path); - CFRelease(path); - } - if(path == (CGPathRef)kCFNull) - { - // If we got the placeholder, then set the path to NULL - // (this will happen either after discovering the glyph path is NULL, - // or after looking that up in the dictionary). - path = NULL; - } - return path; -} - -@end \ No newline at end of file diff --git a/ios/Text/UIBezierPath-Points.m b/ios/Text/UIBezierPath-Points.m index e29df010..17a3c996 100644 --- a/ios/Text/UIBezierPath-Points.m +++ b/ios/Text/UIBezierPath-Points.m @@ -76,7 +76,7 @@ void getPointsFromBezier(void *info, const CGPathElement *element) { // Use total length to calculate the percent of path consumed at each control point NSArray *points = self.points; - int pointCount = points.count; + NSUInteger pointCount = points.count; float totalPointLength = self.length; float distanceTravelled = 0.0f; diff --git a/ios/ViewManagers/RNSVGGroupManager.h b/ios/ViewManagers/RNSVGGroupManager.h index 6c052c35..84f7c82c 100644 --- a/ios/ViewManagers/RNSVGGroupManager.h +++ b/ios/ViewManagers/RNSVGGroupManager.h @@ -6,8 +6,8 @@ * LICENSE file in the root directory of this source tree. */ -#import "RNSVGNodeManager.h" +#import "RNSVGRenderableManager.h" -@interface RNSVGGroupManager : RNSVGNodeManager +@interface RNSVGGroupManager : RNSVGRenderableManager @end diff --git a/ios/ViewManagers/RNSVGGroupManager.m b/ios/ViewManagers/RNSVGGroupManager.m index fa2daa31..02635f74 100644 --- a/ios/ViewManagers/RNSVGGroupManager.m +++ b/ios/ViewManagers/RNSVGGroupManager.m @@ -19,8 +19,6 @@ RCT_EXPORT_MODULE() return [RNSVGGroup new]; } - -RCT_EXPORT_VIEW_PROPERTY(clipPath, CGPath) -RCT_EXPORT_VIEW_PROPERTY(clipRule, RNSVGCGFCRule) +RCT_EXPORT_VIEW_PROPERTY(mergeList, NSArray) @end diff --git a/ios/ViewManagers/RNSVGNodeManager.m b/ios/ViewManagers/RNSVGNodeManager.m index e465f224..18a98e0c 100644 --- a/ios/ViewManagers/RNSVGNodeManager.m +++ b/ios/ViewManagers/RNSVGNodeManager.m @@ -33,6 +33,8 @@ RCT_EXPORT_VIEW_PROPERTY(name, NSString) RCT_EXPORT_VIEW_PROPERTY(opacity, CGFloat) RCT_EXPORT_VIEW_PROPERTY(transform, CGAffineTransform) RCT_EXPORT_VIEW_PROPERTY(clipPathRef, NSString) +RCT_EXPORT_VIEW_PROPERTY(clipPath, CGPath) +RCT_EXPORT_VIEW_PROPERTY(clipRule, RNSVGCGFCRule) RCT_EXPORT_VIEW_PROPERTY(responsible, BOOL) @end diff --git a/ios/ViewManagers/RNSVGRenderableManager.m b/ios/ViewManagers/RNSVGRenderableManager.m index ce3fc13c..ae3c594d 100644 --- a/ios/ViewManagers/RNSVGRenderableManager.m +++ b/ios/ViewManagers/RNSVGRenderableManager.m @@ -28,8 +28,6 @@ RCT_EXPORT_VIEW_PROPERTY(strokeOpacity, CGFloat) RCT_EXPORT_VIEW_PROPERTY(strokeWidth, CGFloat) RCT_EXPORT_VIEW_PROPERTY(strokeLinecap, CGLineCap) RCT_EXPORT_VIEW_PROPERTY(strokeLinejoin, CGLineJoin) -RCT_EXPORT_VIEW_PROPERTY(clipPath, CGPath) -RCT_EXPORT_VIEW_PROPERTY(clipRule, RNSVGCGFCRule) RCT_EXPORT_VIEW_PROPERTY(strokeDasharray, RNSVGCGFloatArray) RCT_EXPORT_VIEW_PROPERTY(strokeDashoffset, CGFloat) RCT_EXPORT_VIEW_PROPERTY(strokeMiterlimit, CGFloat) diff --git a/lib/attributes.js b/lib/attributes.js index c5b7fbf2..d183b75b 100644 --- a/lib/attributes.js +++ b/lib/attributes.js @@ -47,7 +47,11 @@ const NodeAttributes = { diff: arrayDiffer }, opacity: true, + clipRule: true, clipPathRef: true, + clipPath: { + diff: arrayDiffer + }, responsible: true }; @@ -64,10 +68,6 @@ const RenderableOnlyAttributes = { strokeWidth: true, strokeLinecap: true, strokeLinejoin: true, - clipPath: { - diff: arrayDiffer - }, - clipRule: true, strokeDasharray: { diff: arrayDiffer }, @@ -78,10 +78,9 @@ const RenderableOnlyAttributes = { const RenderableAttributes = merge({}, NodeAttributes, RenderableOnlyAttributes); const GroupAttributes = merge({ - clipPath: { + mergeList: { diff: arrayDiffer - }, - clipRule: true + } }, NodeAttributes); const UseAttributes = merge({ diff --git a/lib/extract/extractProps.js b/lib/extract/extractProps.js index 2353804c..ecdd15be 100644 --- a/lib/extract/extractProps.js +++ b/lib/extract/extractProps.js @@ -3,11 +3,12 @@ import extractStroke from './extractStroke'; import extractTransform from './extractTransform'; import extractClipping from './extractClipping'; import extractResponder from './extractResponder'; +import extractOpacity from './extractOpacity'; import _ from 'lodash'; export default function(props, options = {stroke: true, transform: true, fill: true, responder: true}) { let extractedProps = { - opacity: +props.opacity || 1 + opacity: extractOpacity(props.opacity) }; if (props.id) { diff --git a/lib/extract/extractStroke.js b/lib/extract/extractStroke.js index 674d2273..671cd649 100644 --- a/lib/extract/extractStroke.js +++ b/lib/extract/extractStroke.js @@ -1,5 +1,6 @@ import extractBrush from './extractBrush'; import extractOpacity from './extractOpacity'; +import _ from 'lodash'; let separator = /\s*,\s*/; const caps = { @@ -15,12 +16,19 @@ const joins = { }; export default function(props) { - let strokeWidth = +props.strokeWidth; let {stroke} = props; - if (!strokeWidth && !stroke) { + if (!stroke) { return null; } + let strokeWidth = +props.strokeWidth; + + if (_.isNil(props.strokeWidth)) { + strokeWidth = 1; + } else if (!strokeWidth) { + return; + } + let strokeDasharray = props.strokeDasharray; if (typeof strokeDasharray === 'string') { @@ -42,7 +50,7 @@ export default function(props) { strokeLinecap: caps[props.strokeLinecap] || 0, strokeLinejoin: joins[props.strokeLinejoin] || 0, strokeDasharray: strokeDasharray || null, - strokeWidth: strokeWidth || 1, + strokeWidth: strokeWidth, strokeDashoffset: strokeDasharray ? (+props.strokeDashoffset || 0) : null, strokeMiterlimit: props.strokeMiterlimit || 4 }; diff --git a/lib/reusableProps.js b/lib/reusableProps.js new file mode 100644 index 00000000..07be0dc2 --- /dev/null +++ b/lib/reusableProps.js @@ -0,0 +1,22 @@ +import {RenderableOnlyAttributes} from '../lib/attributes'; +import _ from 'lodash'; + +export default function (extractedProps, originProps) { + let reusableProps = []; + Object.keys(RenderableOnlyAttributes).forEach(name => { + if (!_.isNil(originProps[name])) { + // clipPath prop may provide `clipPathRef` as native prop + if (name === 'clipPath') { + if (extractedProps[name]) { + reusableProps.push(name); + } else if (extractedProps.clipPathRef) { + reusableProps.push('clipPathRef'); + } + } else { + reusableProps.push(name); + } + } + }); + + return reusableProps; +}