refactor clipPath native code

refactor clipPath native code
add strokeMiterlimit prop support
This commit is contained in:
Horcrux
2016-05-21 19:58:49 +08:00
parent bb9380b049
commit 6a0c47a898
30 changed files with 305 additions and 152 deletions

View File

@@ -22,9 +22,9 @@ class LinearGradientHorizontal extends Component{
width="300"
>
<Defs>
<LinearGradient id="grad" x1="0" y1="0" x2="170" y2="0">
<LinearGradient id="grad" x1="65" y1="0" x2="235" y2="0">
<Stop offset="0" stopColor="rgb(255,255,0)" stopOpacity="0" />
<Stop offset="1" stopColor="red" stopOpacity="1" />
<Stop offset="1" stopColor="red" />
</LinearGradient>
</Defs>
<Ellipse cx="150" cy="75" rx="85" ry="55" fill="url(#grad)" />

View File

@@ -568,12 +568,8 @@ npm install
1. add native method for elements
2. more Text features support
3. Pattern element
4. Image element (Android)
5. calculate bounding box only if necessary.
6. miterLimit
7. move percentage convert and context bounding box to renderable
8. implement touchable elements ()
9. implement Animated elements
4. implement touchable elements
5. implement Animated elements
#### Thanks:

View File

@@ -0,0 +1,43 @@
/**
* 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.
*/
package com.horcrux.svg;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.view.View;
import android.view.ViewGroup;
import com.facebook.react.uimanager.annotations.ReactProp;
/**
* Shadow node for virtual RNSVGClipPath view
*/
public class RNSVGClipPathShadowNode extends RNSVGGroupShadowNode {
private String mName = null;
@ReactProp(name = "name")
public void setName(String name) {
mName = name;
markUpdated();
}
@Override
public void draw(Canvas canvas, Paint paint, float opacity) {
getSvgShadowNode().defineClipPath(getPath(canvas, paint), mName);
}
@Override
public int hitTest(Point point, View view) {
return -1;
}
}

View File

@@ -17,27 +17,15 @@ import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import com.facebook.react.uimanager.ReactShadowNode;
import com.facebook.react.uimanager.annotations.ReactProp;
/**
* Shadow node for virtual RNSVGGroup view
*/
public class RNSVGGroupShadowNode extends RNSVGVirtualNode {
private String mAsClipPath = null;
@ReactProp(name = "asClipPath")
public void setAsClipPath(String asClipPath) {
mAsClipPath = asClipPath;
markUpdated();
}
public void draw(Canvas canvas, Paint paint, float opacity) {
opacity *= mOpacity;
RNSVGSvgViewShadowNode svg = getSvgShadowNode();
if (mAsClipPath == null) {
if (opacity > MIN_OPACITY_FOR_DRAW) {
int count = saveAndSetupCanvas(canvas);
clip(canvas, paint);
@@ -54,10 +42,6 @@ public class RNSVGGroupShadowNode extends RNSVGVirtualNode {
restoreCanvas(canvas, count);
}
} else {
svg.defineClipPath(getPath(canvas, paint), mAsClipPath);
}
}
@Override
@@ -74,11 +58,6 @@ public class RNSVGGroupShadowNode extends RNSVGVirtualNode {
@Override
public int hitTest(Point point, View view) {
if (mAsClipPath != null) {
return -1;
}
int viewTag = -1;
for (int i = getChildCount() - 1; i >= 0; i--) {
viewTag = ((RNSVGVirtualNode) getChildAt(i)).hitTest(point, ((ViewGroup) view).getChildAt(i));

View File

@@ -51,10 +51,12 @@ public class RNSVGPathShadowNode extends RNSVGVirtualNode {
private static final int FILL_RULE_EVENODD = 0;
private static final int FILL_RULE_NONZERO = 1;
private @Nullable ReadableArray mStrokeColor;
private @Nullable ReadableArray mFillColor;
private @Nullable float[] mStrokeDasharray;
private float mStrokeWidth = 1;
private float mStrokeMiterlimit = 4;
private float mStrokeDashoffset = 0;
private Paint.Cap mStrokeLinecap = Paint.Cap.ROUND;
private Paint.Join mStrokeLinejoin = Paint.Join.ROUND;
@@ -126,6 +128,12 @@ public class RNSVGPathShadowNode extends RNSVGVirtualNode {
markUpdated();
}
@ReactProp(name = "strokeMiterlimit", defaultFloat = 4f)
public void setStrokeMiterlimit(float strokeMiterlimit) {
mStrokeMiterlimit = strokeMiterlimit;
markUpdated();
}
@ReactProp(name = "strokeLinecap", defaultInt = CAP_ROUND)
public void setStrokeLinecap(int strokeLinecap) {
switch (strokeLinecap) {
@@ -185,9 +193,9 @@ public class RNSVGPathShadowNode extends RNSVGVirtualNode {
}
restoreCanvas(canvas, count);
}
markUpdateSeen();
}
}
private void setupPath() {
// init path after both fillRule and path have been set
@@ -243,6 +251,7 @@ public class RNSVGPathShadowNode extends RNSVGVirtualNode {
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeCap(mStrokeLinecap);
paint.setStrokeJoin(mStrokeLinejoin);
paint.setStrokeMiter(mStrokeMiterlimit * mScale);
paint.setStrokeWidth(mStrokeWidth * mScale);
setupPaint(paint, opacity, mStrokeColor, box);

View File

@@ -41,6 +41,7 @@ public class RNSVGRenderableViewManager extends ViewGroupManager<ViewGroup> {
/* package */ static final String CLASS_ELLIPSE = "RNSVGEllipse";
/* package */ static final String CLASS_LINE = "RNSVGLine";
/* package */ static final String CLASS_RECT = "RNSVGRect";
/* package */ static final String CLASS_CLIP_PATH = "RNSVGClipPath";
private final String mClassName;
@@ -78,6 +79,10 @@ public class RNSVGRenderableViewManager extends ViewGroupManager<ViewGroup> {
return new RNSVGRenderableViewManager(CLASS_RECT);
}
public static RNSVGRenderableViewManager createRNSVGClipPathViewManager() {
return new RNSVGRenderableViewManager(CLASS_CLIP_PATH);
}
private RNSVGRenderableViewManager(String className) {
mClassName = className;
}
@@ -114,6 +119,9 @@ public class RNSVGRenderableViewManager extends ViewGroupManager<ViewGroup> {
case CLASS_IMAGE:
mVirtualNode = new RNSVGImageShadowNode();
break;
case CLASS_CLIP_PATH:
mVirtualNode = new RNSVGClipPathShadowNode();
break;
default:
throw new IllegalStateException("Unexpected type " + mClassName);
}
@@ -141,6 +149,8 @@ public class RNSVGRenderableViewManager extends ViewGroupManager<ViewGroup> {
return RNSVGTextShadowNode.class;
case CLASS_IMAGE:
return RNSVGImageShadowNode.class;
case CLASS_CLIP_PATH:
return RNSVGClipPathShadowNode.class;
default:
throw new IllegalStateException("Unexpected type " + mClassName);
}

View File

@@ -73,10 +73,7 @@ public class RNSVGTextShadowNode extends RNSVGPathShadowNode {
public void draw(Canvas canvas, Paint paint, float opacity) {
opacity *= mOpacity;
if (opacity <= MIN_OPACITY_FOR_DRAW) {
return;
}
if (opacity > MIN_OPACITY_FOR_DRAW) {
String text = formatText();
if (text == null) {
return;
@@ -97,6 +94,7 @@ public class RNSVGTextShadowNode extends RNSVGPathShadowNode {
restoreCanvas(canvas, count);
markUpdateSeen();
}
}
private void drawText(Canvas canvas, Paint paint, String text) {
applyTextPropertiesToPaint(paint);

View File

@@ -33,6 +33,7 @@ public class RNSvgPackage implements ReactPackage {
RNSVGRenderableViewManager.createRNSVGRectViewManager(),
RNSVGRenderableViewManager.createRNSVGTextViewManager(),
RNSVGRenderableViewManager.createRNSVGImageViewManager(),
RNSVGRenderableViewManager.createRNSVGClipPathViewManager(),
new RNSVGSvgViewManager());
}

View File

@@ -1,6 +1,7 @@
import React, {Component, PropTypes} from 'react';
import {NativeGroup} from './G';
import {set, remove} from '../lib/extract/extractClipping';
import createNativeComponent from '../lib/createNativeComponent';
class ClipPath extends Component{
static displayName = 'ClipPath';
@@ -26,12 +27,13 @@ class ClipPath extends Component{
render() {
set(this.id, this.id);
return <RNSVGClipPath
name={this.id}
>{this.props.children}</RNSVGClipPath>;
}
}
return <NativeGroup
asClipPath={this.id}
>{this.props.children}</NativeGroup>;
}
}
const RNSVGClipPath = createNativeComponent('RNSVGClipPath');
export default ClipPath;

View File

@@ -12,6 +12,7 @@ class DefsItem extends Component{
static propType = {
visible: PropTypes.bool
};
static defaultProps = {
visible: false
};
@@ -75,16 +76,11 @@ class Defs extends Component{
static Item = DefsItem;
static Use = DefsUse;
shouldRender = false;
getChildren = () => {
return Children.map(this.props.children, child => {
let {type} = child;
if (type === LinearGradient || type === RadialGradient || type === ClipPath) {
if (type === ClipPath) {
this.shouldRender = true;
}
return cloneElement(child, {
svgId: this.props.svgId
});
@@ -99,10 +95,7 @@ class Defs extends Component{
};
render() {
let children = this.getChildren();
return <NativeGroup opacity={this.shouldRender ? 1 : 0}>
{children}
</NativeGroup>;
return <NativeGroup>{this.getChildren()}</NativeGroup>;
}
}

View File

@@ -1,9 +1,15 @@
import {Component, PropTypes} from 'react';
import {numberProp} from '../lib/props';
class Stop extends Component{
static displayName = 'Stop';
static propTypes = {
stopColor: PropTypes.string,
stopOpacity: PropTypes.oneOfType([PropTypes.string, PropTypes.number])
stopOpacity: numberProp
};
static defaultProps = {
stopOpacity: 1
};
render() {

View File

@@ -0,0 +1,20 @@
/**
* 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 <Foundation/Foundation.h>
#import "RNSVGContainer.h"
#import "RNSVGGroup.h"
#import "RNSVGSvgView.h"
@interface RNSVGClipPath : RNSVGGroup
@property (nonatomic, strong) NSString *name;
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event;
@end

View File

@@ -0,0 +1,25 @@
/**
* 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 "RNSVGClipPath.h"
@implementation RNSVGClipPath
- (void)renderLayerTo:(CGContextRef)context
{
[[self getSvgView] defineClipPath:[self getPath:context] clipPathId:self.name];
}
// hitTest delagate
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
return nil;
}
@end

View File

@@ -7,16 +7,14 @@
*/
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import "RNSVGContainer.h"
#import "RNSVGNode.h"
#import "RNSVGCGFCRule.h"
#import "RNSVGSvgView.h"
#import "RNSVGNode.h"
@interface RNSVGGroup : RNSVGNode <RNSVGContainer>
@property (nonatomic, strong) NSString *asClipPath; // Current group is a <ClipPath /> element and asClipPath is its id.
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event;
- (RNSVGSvgView *)getSvgView;
@end

View File

@@ -12,7 +12,6 @@
- (void)renderLayerTo:(CGContextRef)context
{
if (self.asClipPath == NULL) {
RNSVGSvgView* svg = [self getSvgView];
[self clip:context];
@@ -23,9 +22,6 @@
self.touchable = YES;
}
}
} else {
[self defineClipPath:[self getPath:context] clipPathId:self.asClipPath];
}
}
- (CGPathRef)getPath:(CGContextRef)context
@@ -51,14 +47,5 @@
return nil;
}
- (RNSVGSvgView *)getSvgView
{
UIView *parent = self.superview;
while ([parent class] != [RNSVGSvgView class]) {
parent = parent.superview;
}
return (RNSVGSvgView *)parent;
}
@end

View File

@@ -81,6 +81,10 @@
// add hit area
CGPathAddPath(self.nodeArea, nil, CGPathCreateWithRect(CGRectMake(x, y, w, h), nil));
if (self.opacity == 0) {
return;
}
[self clip:context];
CGContextSaveGState(context);
CGContextTranslateCTM(context, 0, h);

View File

@@ -31,12 +31,22 @@
return;
}
CGPathDrawingMode mode = kCGPathStroke;
BOOL fillColor = YES;
// Add path to nodeArea
CGPathAddPath(self.nodeArea, nil, _d);
if (self.stroke) {
// Add stroke to nodeArea
CGPathRef strokePath = CGPathCreateCopyByStrokingPath(_d, nil, self.strokeWidth, self.strokeLinecap, self.strokeLinejoin, self.strokeMiterlimit);
CGPathAddPath(self.nodeArea, nil, strokePath);
}
if (self.opacity == 0) {
return;
}
CGPathDrawingMode mode = kCGPathStroke;
BOOL fillColor = YES;
if (self.fill) {
mode = self.fillRule == kRNSVGCGFCRuleEvenodd ? kCGPathEOFill : kCGPathFill;
fillColor = [self.fill applyFillColor:context];
@@ -55,10 +65,6 @@
}
}
if (self.stroke) {
// Add stroke to nodeArea
CGPathRef strokePath = CGPathCreateCopyByStrokingPath(_d, nil, self.strokeWidth, self.strokeLinecap, self.strokeLinejoin, 0);
CGPathAddPath(self.nodeArea, nil, strokePath);
CGContextSetLineWidth(context, self.strokeWidth);
CGContextSetLineCap(context, self.strokeLinecap);
CGContextSetLineJoin(context, self.strokeLinejoin);

View File

@@ -14,4 +14,13 @@
@property (nonatomic, assign) BOOL touchable;
/**
* define <ClipPath></ClipPath> content as clipPath template.
*/
- (void)defineClipPath:(CGPathRef)clipPath clipPathId:(NSString *)clipPathId;
- (void)removeClipPath:(NSString *)clipPathId;
- (CGPathRef)getDefinedClipPath:(NSString *)clipPathId;
@end

View File

@@ -12,6 +12,9 @@
#import "RCTLog.h"
@implementation RNSVGSvgView
{
NSMutableDictionary *clipPaths;
}
- (void)invalidate
{
@@ -41,4 +44,24 @@
return self.touchable ? [super hitTest:point withEvent:event] : nil;
}
- (void)defineClipPath:(CGPathRef)clipPath clipPathId:(NSString *)clipPathId
{
if (clipPaths == NULL) {
clipPaths = [[NSMutableDictionary alloc] init];
}
[clipPaths setValue:[NSValue valueWithPointer:clipPath] forKey:clipPathId];
}
- (void)removeClipPath:(NSString *)clipPathId
{
if (clipPaths != NULL) {
[clipPaths removeObjectForKey:clipPathId];
}
}
- (CGPathRef)getDefinedClipPath:(NSString *)clipPathId
{
return [[clipPaths valueForKey:clipPathId] pointerValue];
}
@end

View File

@@ -7,7 +7,6 @@
objects = {
/* Begin PBXBuildFile section */
0CF68B061AF0549300FF9E5C /* RNSVGNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AE01AF0549300FF9E5C /* RNSVGNode.m */; };
0CF68B071AF0549300FF9E5C /* RNSVGRenderable.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AE21AF0549300FF9E5C /* RNSVGRenderable.m */; };
0CF68B0B1AF0549300FF9E5C /* RNSVGBrush.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AEC1AF0549300FF9E5C /* RNSVGBrush.m */; };
0CF68B0C1AF0549300FF9E5C /* RNSVGLinearGradient.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF68AEE1AF0549300FF9E5C /* RNSVGLinearGradient.m */; };
@@ -38,6 +37,9 @@
10BA0D491CE74E3D00887C2B /* RNSVGEllipse.m in Sources */ = {isa = PBXBuildFile; fileRef = 10BA0D431CE74E3D00887C2B /* RNSVGEllipse.m */; };
10BA0D4A1CE74E3D00887C2B /* RNSVGLine.m in Sources */ = {isa = PBXBuildFile; fileRef = 10BA0D451CE74E3D00887C2B /* RNSVGLine.m */; };
10BA0D4B1CE74E3D00887C2B /* RNSVGRect.m in Sources */ = {isa = PBXBuildFile; fileRef = 10BA0D471CE74E3D00887C2B /* RNSVGRect.m */; };
10ED4A9B1CF065260078BC02 /* RNSVGClipPath.m in Sources */ = {isa = PBXBuildFile; fileRef = 10ED4A9A1CF065260078BC02 /* RNSVGClipPath.m */; };
10ED4A9E1CF0656A0078BC02 /* RNSVGClipPathManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 10ED4A9D1CF0656A0078BC02 /* RNSVGClipPathManager.m */; };
10ED4AA21CF078830078BC02 /* RNSVGNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 10ED4AA11CF078830078BC02 /* RNSVGNode.m */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
@@ -54,8 +56,6 @@
/* Begin PBXFileReference section */
0CF68AC11AF0540F00FF9E5C /* libRNSVG.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRNSVG.a; sourceTree = BUILT_PRODUCTS_DIR; };
0CF68ADF1AF0549300FF9E5C /* RNSVGNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNSVGNode.h; sourceTree = "<group>"; };
0CF68AE01AF0549300FF9E5C /* RNSVGNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNSVGNode.m; sourceTree = "<group>"; };
0CF68AE11AF0549300FF9E5C /* RNSVGRenderable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNSVGRenderable.h; sourceTree = "<group>"; };
0CF68AE21AF0549300FF9E5C /* RNSVGRenderable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNSVGRenderable.m; sourceTree = "<group>"; };
0CF68AEB1AF0549300FF9E5C /* RNSVGBrush.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNSVGBrush.h; sourceTree = "<group>"; };
@@ -120,6 +120,12 @@
10BA0D451CE74E3D00887C2B /* RNSVGLine.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNSVGLine.m; path = Shapes/RNSVGLine.m; sourceTree = "<group>"; };
10BA0D461CE74E3D00887C2B /* RNSVGRect.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSVGRect.h; path = Shapes/RNSVGRect.h; sourceTree = "<group>"; };
10BA0D471CE74E3D00887C2B /* RNSVGRect.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNSVGRect.m; path = Shapes/RNSVGRect.m; sourceTree = "<group>"; };
10ED4A991CF065260078BC02 /* RNSVGClipPath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSVGClipPath.h; path = Elements/RNSVGClipPath.h; sourceTree = "<group>"; };
10ED4A9A1CF065260078BC02 /* RNSVGClipPath.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNSVGClipPath.m; path = Elements/RNSVGClipPath.m; sourceTree = "<group>"; };
10ED4A9C1CF0656A0078BC02 /* RNSVGClipPathManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNSVGClipPathManager.h; sourceTree = "<group>"; };
10ED4A9D1CF0656A0078BC02 /* RNSVGClipPathManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNSVGClipPathManager.m; sourceTree = "<group>"; };
10ED4AA01CF078830078BC02 /* RNSVGNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNSVGNode.h; sourceTree = "<group>"; };
10ED4AA11CF078830078BC02 /* RNSVGNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNSVGNode.m; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -143,8 +149,8 @@
0CF68AEA1AF0549300FF9E5C /* Brushes */,
0CF68AF81AF0549300FF9E5C /* ViewManagers */,
1039D2A11CE721A7001E90A8 /* RNSVGContainer.h */,
0CF68ADF1AF0549300FF9E5C /* RNSVGNode.h */,
0CF68AE01AF0549300FF9E5C /* RNSVGNode.m */,
10ED4AA01CF078830078BC02 /* RNSVGNode.h */,
10ED4AA11CF078830078BC02 /* RNSVGNode.m */,
0CF68AE11AF0549300FF9E5C /* RNSVGRenderable.h */,
0CF68AE21AF0549300FF9E5C /* RNSVGRenderable.m */,
0CF68AC21AF0540F00FF9E5C /* Products */,
@@ -179,6 +185,8 @@
0CF68AF81AF0549300FF9E5C /* ViewManagers */ = {
isa = PBXGroup;
children = (
10ED4A9C1CF0656A0078BC02 /* RNSVGClipPathManager.h */,
10ED4A9D1CF0656A0078BC02 /* RNSVGClipPathManager.m */,
10BA0D1C1CE74E3100887C2B /* RNSVGCircleManager.h */,
10BA0D1D1CE74E3100887C2B /* RNSVGCircleManager.m */,
10BA0D1E1CE74E3100887C2B /* RNSVGEllipseManager.h */,
@@ -237,6 +245,8 @@
1039D2801CE71DCF001E90A8 /* Elements */ = {
isa = PBXGroup;
children = (
10ED4A991CF065260078BC02 /* RNSVGClipPath.h */,
10ED4A9A1CF065260078BC02 /* RNSVGClipPath.m */,
1039D2811CE71EB7001E90A8 /* RNSVGGroup.h */,
1039D2821CE71EB7001E90A8 /* RNSVGGroup.m */,
1039D2831CE71EB7001E90A8 /* RNSVGImage.h */,
@@ -331,7 +341,9 @@
10BA0D3B1CE74E3100887C2B /* RNSVGRectManager.m in Sources */,
0CF68B071AF0549300FF9E5C /* RNSVGRenderable.m in Sources */,
1039D2891CE71EB7001E90A8 /* RNSVGGroup.m in Sources */,
0CF68B061AF0549300FF9E5C /* RNSVGNode.m in Sources */,
10ED4A9E1CF0656A0078BC02 /* RNSVGClipPathManager.m in Sources */,
10ED4AA21CF078830078BC02 /* RNSVGNode.m in Sources */,
10ED4A9B1CF065260078BC02 /* RNSVGClipPath.m in Sources */,
10BA0D3E1CE74E3100887C2B /* RNSVGSvgViewManager.m in Sources */,
0CF68B0F1AF0549300FF9E5C /* RNSVGSolidColor.m in Sources */,
10BA0D3A1CE74E3100887C2B /* RNSVGPathManager.m in Sources */,

View File

@@ -9,6 +9,7 @@
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import "RNSVGCGFCRule.h"
#import "RNSVGSvgView.h"
/**
* RNSVG nodes are implemented as empty UIViews but this is just an implementation detail to fit
@@ -42,11 +43,6 @@
- (CGPathRef)getClipPath;
/**
* define <ClipPath></ClipPath> content as clipPath template.
*/
- (void)defineClipPath:(CGPathRef)clipPath clipPathId:(NSString *)clipPathId;
/**
* getPath will return the path inside node as a ClipPath.
*/
@@ -55,4 +51,6 @@
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event;
- (RNSVGSvgView *)getSvgView;
@end

View File

@@ -8,13 +8,9 @@
#import "RNSVGNode.h"
#import "RNSVGContainer.h"
static NSMutableDictionary *ClipPaths;
#import "RNSVGClipPath.h"
@implementation RNSVGNode
{
NSString *definedClipPathId;
}
- (void)insertSubview:(UIView *)subview atIndex:(NSInteger)index
{
@@ -30,6 +26,16 @@ static NSMutableDictionary *ClipPaths;
- (void)setOpacity:(CGFloat)opacity
{
if (opacity == _opacity) {
return;
}
if (opacity < 0) {
opacity = 0;
} else if (opacity > 1) {
opacity = 1;
}
[self invalidate];
_opacity = opacity;
}
@@ -50,15 +56,7 @@ static NSMutableDictionary *ClipPaths;
{
float opacity = self.opacity;
if (opacity <= 0) {
// Nothing to paint
return;
}
BOOL transparent = opacity < 1;
if (!transparent) {
opacity = 1;
}
// This needs to be painted on a layer before being composited.
CGContextSaveGState(context);
@@ -84,22 +82,6 @@ static NSMutableDictionary *ClipPaths;
_clipPath = CGPathRetain(clipPath);
}
-(void)defineClipPath:(CGPathRef)clipPath clipPathId:(NSString *)clipPathId
{
if (clipPath == _clipPath) {
return;
}
[self invalidate];
CGPathRelease(_clipPath);
_clipPath = CGPathRetain(clipPath);
if (ClipPaths == NULL) {
ClipPaths = [[NSMutableDictionary alloc] init];
}
definedClipPathId = clipPathId;
[ClipPaths setValue:[NSValue valueWithPointer:_clipPath] forKey:clipPathId];
}
- (CGPathRef)getPath: (CGContextRef) context
{
// abstract
@@ -113,7 +95,7 @@ static NSMutableDictionary *ClipPaths;
if (self.clipPath) {
clipPath = self.clipPath;
} else if (self.clipPathId) {
clipPath = [[ClipPaths valueForKey:self.clipPathId] pointerValue];
clipPath = [[self getSvgView] getDefinedClipPath:self.clipPathId];
}
return clipPath;
@@ -144,6 +126,16 @@ static NSMutableDictionary *ClipPaths;
// abstract
}
- (RNSVGSvgView *)getSvgView
{
UIView *parent = self.superview;
while ([parent class] != [RNSVGSvgView class]) {
parent = parent.superview;
}
return (RNSVGSvgView *)parent;
}
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event;
{
// abstract
@@ -153,9 +145,6 @@ static NSMutableDictionary *ClipPaths;
- (void)dealloc
{
CGPathRelease(_clipPath);
if (definedClipPathId) {
[ClipPaths removeObjectForKey:definedClipPathId];
}
}
@end

View File

@@ -21,6 +21,7 @@
@property (nonatomic, assign) CGFloat strokeWidth;
@property (nonatomic, assign) CGLineCap strokeLinecap;
@property (nonatomic, assign) CGLineJoin strokeLinejoin;
@property (nonatomic, assign) CGFloat strokeMiterlimit;
@property (nonatomic, assign) RNSVGCGFloatArray strokeDasharray;
@property (nonatomic, assign) CGFloat strokeDashoffset;
@property (nonatomic, assign) CGMutablePathRef nodeArea;

View File

@@ -67,6 +67,12 @@
_strokeDashoffset = strokeDashoffset;
}
- (void)setStrokeMiterlimit:(CGFloat)strokeMiterlimit
{
[self invalidate];
_strokeMiterlimit = strokeMiterlimit;
}
- (void)dealloc
{
CGPathRelease(_nodeArea);

View File

@@ -0,0 +1,13 @@
/**
* 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 "RNSVGNodeManager.h"
@interface RNSVGClipPathManager : RNSVGNodeManager
@end

View File

@@ -0,0 +1,23 @@
/**
* 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 "RNSVGClipPathManager.h"
#import "RNSVGClipPath.h"
@implementation RNSVGClipPathManager
RCT_EXPORT_MODULE()
- (RNSVGNode *)node
{
return [RNSVGClipPath new];
}
RCT_EXPORT_VIEW_PROPERTY(name, NSString)
@end

View File

@@ -22,6 +22,5 @@ RCT_EXPORT_MODULE()
RCT_EXPORT_VIEW_PROPERTY(clipPath, CGPath)
RCT_EXPORT_VIEW_PROPERTY(clipRule, RNSVGCGFCRule)
RCT_EXPORT_VIEW_PROPERTY(asClipPath, NSString)
@end

View File

@@ -30,5 +30,6 @@ 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)
@end

View File

@@ -44,7 +44,8 @@ function strokeFilter(props) {
strokeLinejoin: joins[props.strokeLinejoin] || 0,
strokeDasharray: strokeDasharray || null,
strokeWidth: strokeWidth || 1,
strokeDashoffset: strokeDasharray ? (+props.strokeDashoffset || 0) : null
strokeDashoffset: strokeDasharray ? (+props.strokeDashoffset || 0) : null,
strokeMiterlimit: props.strokeMiterlimit || 4
};
}

View File

@@ -45,7 +45,8 @@ const strokeProps = {
strokeDasharray: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.number), PropTypes.string]),
strokeDashoffset: numberProp,
strokeLinecap: PropTypes.oneOf(['butt', 'square', 'round']),
strokeLinejoin: PropTypes.oneOf(['miter', 'bevel', 'round'])
strokeLinejoin: PropTypes.oneOf(['miter', 'bevel', 'round']),
strokeMiterlimit: numberProp
};
const textProps = {