From a136063f9081a327ca194789b2cdcb4fc150340a Mon Sep 17 00:00:00 2001 From: Horcrux Date: Wed, 20 Apr 2016 23:27:12 +0800 Subject: [PATCH] add filleRule for ios --- ios/RCTConvert+RNSVG.h | 2 ++ ios/RCTConvert+RNSVG.m | 6 ++++++ ios/RNSVG.xcodeproj/project.pbxproj | 2 ++ ios/RNSVGCGFillRule.h | 13 +++++++++++++ ios/RNSVGPath.m | 4 +++- ios/RNSVGRenderable.h | 2 ++ ios/RNSVGRenderable.m | 6 ++++++ ios/ViewManagers/RNSVGRenderableManager.m | 2 ++ lib/attributes.js | 5 +++-- lib/extractFill.js | 14 ++++++++++++-- lib/extractProps.js | 2 +- lib/extractTransform.js | 1 + 12 files changed, 53 insertions(+), 6 deletions(-) create mode 100644 ios/RNSVGCGFillRule.h diff --git a/ios/RCTConvert+RNSVG.h b/ios/RCTConvert+RNSVG.h index d26fe489..a1406b08 100644 --- a/ios/RCTConvert+RNSVG.h +++ b/ios/RCTConvert+RNSVG.h @@ -13,11 +13,13 @@ #import "RNSVGCGFloatArray.h" #import "RNSVGTextFrame.h" #import "RCTConvert.h" +#import "RNSVGCGFillRule.h" @interface RCTConvert (RNSVG) + (CGPathRef)CGPath:(id)json; + (CTTextAlignment)CTTextAlignment:(id)json; ++ (RNSVGCGFillRule)ARTCGFillRule:(id)json; + (RNSVGTextFrame)RNSVGTextFrame:(id)json; + (RNSVGCGFloatArray)RNSVGCGFloatArray:(id)json; + (RNSVGBrush *)RNSVGBrush:(id)json; diff --git a/ios/RCTConvert+RNSVG.m b/ios/RCTConvert+RNSVG.m index 5e74c9ed..f9ad8423 100644 --- a/ios/RCTConvert+RNSVG.m +++ b/ios/RCTConvert+RNSVG.m @@ -14,6 +14,7 @@ #import "RNSVGRadialGradient.h" #import "RNSVGSolidColor.h" #import "RCTLog.h" +#import "RNSVGCGFillRule.h" @implementation RCTConvert (RNSVG) @@ -72,6 +73,11 @@ RCT_ENUM_CONVERTER(CTTextAlignment, (@{ @"justify": @(kCTTextAlignmentJustified), }), kCTTextAlignmentNatural, integerValue) +RCT_ENUM_CONVERTER(RNSVGCGFillRule, (@{ + @"evenodd": @(kARTCGFillRuleEvenodd), + @"nonzero": @(kARTCGFillRuleNonzero), +}), kARTCGFillRuleEvenodd, intValue) + // This takes a tuple of text lines and a font to generate a CTLine for each text line. // This prepares everything for rendering a frame of text in RNSVGText. + (RNSVGTextFrame)RNSVGTextFrame:(id)json diff --git a/ios/RNSVG.xcodeproj/project.pbxproj b/ios/RNSVG.xcodeproj/project.pbxproj index 074f3025..93a7f975 100644 --- a/ios/RNSVG.xcodeproj/project.pbxproj +++ b/ios/RNSVG.xcodeproj/project.pbxproj @@ -80,6 +80,7 @@ 10A063011CC7320C0000CEEF /* RNSVGPath.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNSVGPath.m; sourceTree = ""; }; 10A063021CC7320C0000CEEF /* RNSVGSvgView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNSVGSvgView.h; sourceTree = ""; }; 10A063031CC7320C0000CEEF /* RNSVGSvgView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNSVGSvgView.m; sourceTree = ""; }; + 10FEAC6A1CC7D05200F1C23C /* RNSVGCGFillRule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNSVGCGFillRule.h; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -99,6 +100,7 @@ 0CF68AEA1AF0549300FF9E5C /* Brushes */, 0CF68AF81AF0549300FF9E5C /* ViewManagers */, 0CF68ADB1AF0549300FF9E5C /* RNSVGCGFloatArray.h */, + 10FEAC6A1CC7D05200F1C23C /* RNSVGCGFillRule.h */, 0CF68ADC1AF0549300FF9E5C /* RNSVGContainer.h */, 0CF68ADD1AF0549300FF9E5C /* RNSVGGroup.h */, 0CF68ADE1AF0549300FF9E5C /* RNSVGGroup.m */, diff --git a/ios/RNSVGCGFillRule.h b/ios/RNSVGCGFillRule.h new file mode 100644 index 00000000..d045d6c8 --- /dev/null +++ b/ios/RNSVGCGFillRule.h @@ -0,0 +1,13 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +typedef CF_ENUM(int32_t, RNSVGCGFillRule) { + kARTCGFillRuleEvenodd, + kARTCGFillRuleNonzero +}; \ No newline at end of file diff --git a/ios/RNSVGPath.m b/ios/RNSVGPath.m index c4dc6efb..e4a3969e 100644 --- a/ios/RNSVGPath.m +++ b/ios/RNSVGPath.m @@ -35,7 +35,7 @@ CGPathDrawingMode mode = kCGPathStroke; if (self.fill) { if ([self.fill applyFillColor:context]) { - mode = kCGPathFill; + mode = self.fillRule == kARTCGFillRuleEvenodd ? kCGPathEOFill : kCGPathFill; } else { CGContextSaveGState(context); CGContextAddPath(context, self.d); @@ -58,6 +58,8 @@ } if (mode == kCGPathFill) { mode = kCGPathFillStroke; + } else if (mode == kCGPathEOFill) { + mode = kCGPathEOFillStroke; } } diff --git a/ios/RNSVGRenderable.h b/ios/RNSVGRenderable.h index 104df36b..f6381df6 100644 --- a/ios/RNSVGRenderable.h +++ b/ios/RNSVGRenderable.h @@ -11,11 +11,13 @@ #import "RNSVGBrush.h" #import "RNSVGCGFloatArray.h" +#import "RNSVGCGFillRule.h" #import "RNSVGNode.h" @interface RNSVGRenderable : RNSVGNode @property (nonatomic, strong) RNSVGBrush *fill; +@property (nonatomic, assign) RNSVGCGFillRule fillRule; @property (nonatomic, assign) CGColorRef stroke; @property (nonatomic, assign) CGFloat strokeWidth; @property (nonatomic, assign) CGLineCap strokeLinecap; diff --git a/ios/RNSVGRenderable.m b/ios/RNSVGRenderable.m index 771ced13..6b28c362 100644 --- a/ios/RNSVGRenderable.m +++ b/ios/RNSVGRenderable.m @@ -17,6 +17,12 @@ _fill = fill; } +- (void)setFillRule:(RNSVGCGFillRule)fillRule +{ + [self invalidate]; + _fillRule = fillRule; +} + - (void)setStroke:(CGColorRef)stroke { if (stroke == _stroke) { diff --git a/ios/ViewManagers/RNSVGRenderableManager.m b/ios/ViewManagers/RNSVGRenderableManager.m index 2cfb3864..dd8d3b45 100644 --- a/ios/ViewManagers/RNSVGRenderableManager.m +++ b/ios/ViewManagers/RNSVGRenderableManager.m @@ -10,6 +10,7 @@ #import "RNSVGRenderableManager.h" #import "RCTConvert+RNSVG.h" +#import "RNSVGCGFillRule.h" @implementation RNSVGRenderableManager @@ -24,6 +25,7 @@ RCT_EXPORT_VIEW_PROPERTY(strokeWidth, CGFloat) RCT_EXPORT_VIEW_PROPERTY(strokeLinecap, CGLineCap) RCT_EXPORT_VIEW_PROPERTY(strokeLinejoin, CGLineJoin) RCT_EXPORT_VIEW_PROPERTY(fill, RNSVGBrush) +RCT_EXPORT_VIEW_PROPERTY(fillRule, RNSVGCGFillRule) RCT_EXPORT_VIEW_PROPERTY(stroke, CGColor) RCT_EXPORT_VIEW_PROPERTY(strokeDash, RNSVGCGFloatArray) diff --git a/lib/attributes.js b/lib/attributes.js index 5f390226..cf182e43 100644 --- a/lib/attributes.js +++ b/lib/attributes.js @@ -59,8 +59,9 @@ var RenderableAttributes = Object.assign({ diff: arrayDiffer }, strokeWidth: true, - strokeCap: true, - strokeJoin: true, + strokeLinecap: true, + strokeLinejoin: true, + fillRule: true, strokeDash: { diff: arrayDiffer } diff --git a/lib/extractFill.js b/lib/extractFill.js index 332ce401..605315e0 100644 --- a/lib/extractFill.js +++ b/lib/extractFill.js @@ -24,6 +24,11 @@ function remove(id) { delete fillPatterns[id]; } +const fillRules = { + evenodd: 0, + nonzero: 1 +}; + function fillFilter(props) { let {fill} = props; @@ -46,7 +51,7 @@ function fillFilter(props) { if (matched) { let patternName = `${matched[1]}:${props.svgId}`; let pattern = fillPatterns[patternName]; - + if (pattern) { if (pattern.length === 2) { let dimensions = this.getBoundingBox(); @@ -73,7 +78,12 @@ function fillFilter(props) { export default function(props) { let fill = fillFilter.call(this, props); - return extractBrush(fill, props); + let fillRule = fillRules[props.fillRule] === 0 ? 0 : 1; + + return { + fill: extractBrush(fill, props), + fillRule + }; } export { diff --git a/lib/extractProps.js b/lib/extractProps.js index b0c5da88..7d0948cb 100644 --- a/lib/extractProps.js +++ b/lib/extractProps.js @@ -17,7 +17,7 @@ export default function(props, options = {stroke: true, join: true, transform: t } if (options.fill) { - extractedProps.fill = extractFill.call(this, props); + Object.assign(extractedProps, extractFill.call(this, props)); } if (options.transform) { diff --git a/lib/extractTransform.js b/lib/extractTransform.js index e4c5f5a3..b1d938b6 100644 --- a/lib/extractTransform.js +++ b/lib/extractTransform.js @@ -24,6 +24,7 @@ function transformToMatrix(props) { ]; } + export default function (props) { let coords = props.origin ? props.origin.split(/\s*,\s*/) : [];