Skip to content

Commit 6a0c47a

Browse files
committed
refactor clipPath native code
refactor clipPath native code add strokeMiterlimit prop support
1 parent bb9380b commit 6a0c47a

30 files changed

+305
-152
lines changed

Example/examples/Gradients.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ class LinearGradientHorizontal extends Component{
2222
width="300"
2323
>
2424
<Defs>
25-
<LinearGradient id="grad" x1="0" y1="0" x2="170" y2="0">
25+
<LinearGradient id="grad" x1="65" y1="0" x2="235" y2="0">
2626
<Stop offset="0" stopColor="rgb(255,255,0)" stopOpacity="0" />
27-
<Stop offset="1" stopColor="red" stopOpacity="1" />
27+
<Stop offset="1" stopColor="red" />
2828
</LinearGradient>
2929
</Defs>
3030
<Ellipse cx="150" cy="75" rx="85" ry="55" fill="url(#grad)" />

README.md

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -568,12 +568,8 @@ npm install
568568
1. add native method for elements
569569
2. more Text features support
570570
3. Pattern element
571-
4. Image element (Android)
572-
5. calculate bounding box only if necessary.
573-
6. miterLimit
574-
7. move percentage convert and context bounding box to renderable
575-
8. implement touchable elements ()
576-
9. implement Animated elements
571+
4. implement touchable elements
572+
5. implement Animated elements
577573

578574
#### Thanks:
579575

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/**
2+
* Copyright (c) 2015-present, Horcrux.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the MIT-style license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
10+
package com.horcrux.svg;
11+
12+
import android.graphics.Canvas;
13+
import android.graphics.Paint;
14+
import android.graphics.Path;
15+
import android.graphics.Point;
16+
import android.view.View;
17+
import android.view.ViewGroup;
18+
19+
import com.facebook.react.uimanager.annotations.ReactProp;
20+
21+
/**
22+
* Shadow node for virtual RNSVGClipPath view
23+
*/
24+
public class RNSVGClipPathShadowNode extends RNSVGGroupShadowNode {
25+
26+
private String mName = null;
27+
28+
@ReactProp(name = "name")
29+
public void setName(String name) {
30+
mName = name;
31+
markUpdated();
32+
}
33+
34+
@Override
35+
public void draw(Canvas canvas, Paint paint, float opacity) {
36+
getSvgShadowNode().defineClipPath(getPath(canvas, paint), mName);
37+
}
38+
39+
@Override
40+
public int hitTest(Point point, View view) {
41+
return -1;
42+
}
43+
}

android/src/main/java/com/horcrux/svg/RNSVGGroupShadowNode.java

Lines changed: 10 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -17,46 +17,30 @@
1717
import android.view.View;
1818
import android.view.ViewGroup;
1919

20-
import com.facebook.react.uimanager.ReactShadowNode;
21-
import com.facebook.react.uimanager.annotations.ReactProp;
22-
2320
/**
2421
* Shadow node for virtual RNSVGGroup view
2522
*/
2623
public class RNSVGGroupShadowNode extends RNSVGVirtualNode {
2724

28-
private String mAsClipPath = null;
29-
30-
@ReactProp(name = "asClipPath")
31-
public void setAsClipPath(String asClipPath) {
32-
mAsClipPath = asClipPath;
33-
markUpdated();
34-
}
35-
3625
public void draw(Canvas canvas, Paint paint, float opacity) {
3726
opacity *= mOpacity;
3827
RNSVGSvgViewShadowNode svg = getSvgShadowNode();
3928

40-
if (mAsClipPath == null) {
41-
if (opacity > MIN_OPACITY_FOR_DRAW) {
42-
int count = saveAndSetupCanvas(canvas);
43-
clip(canvas, paint);
29+
if (opacity > MIN_OPACITY_FOR_DRAW) {
30+
int count = saveAndSetupCanvas(canvas);
31+
clip(canvas, paint);
4432

45-
for (int i = 0; i < getChildCount(); i++) {
46-
RNSVGVirtualNode child = (RNSVGVirtualNode) getChildAt(i);
47-
child.setupDimensions(canvas);
48-
child.draw(canvas, paint, opacity);
33+
for (int i = 0; i < getChildCount(); i++) {
34+
RNSVGVirtualNode child = (RNSVGVirtualNode) getChildAt(i);
35+
child.setupDimensions(canvas);
36+
child.draw(canvas, paint, opacity);
4937

50-
if (child.isTouchable()) {
51-
svg.enableTouchEvents();
52-
}
38+
if (child.isTouchable()) {
39+
svg.enableTouchEvents();
5340
}
54-
55-
restoreCanvas(canvas, count);
5641
}
5742

58-
} else {
59-
svg.defineClipPath(getPath(canvas, paint), mAsClipPath);
43+
restoreCanvas(canvas, count);
6044
}
6145
}
6246

@@ -74,11 +58,6 @@ protected Path getPath(Canvas canvas, Paint paint) {
7458

7559
@Override
7660
public int hitTest(Point point, View view) {
77-
78-
if (mAsClipPath != null) {
79-
return -1;
80-
}
81-
8261
int viewTag = -1;
8362
for (int i = getChildCount() - 1; i >= 0; i--) {
8463
viewTag = ((RNSVGVirtualNode) getChildAt(i)).hitTest(point, ((ViewGroup) view).getChildAt(i));

android/src/main/java/com/horcrux/svg/RNSVGPathShadowNode.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,12 @@ public class RNSVGPathShadowNode extends RNSVGVirtualNode {
5151

5252
private static final int FILL_RULE_EVENODD = 0;
5353
private static final int FILL_RULE_NONZERO = 1;
54+
5455
private @Nullable ReadableArray mStrokeColor;
5556
private @Nullable ReadableArray mFillColor;
5657
private @Nullable float[] mStrokeDasharray;
5758
private float mStrokeWidth = 1;
59+
private float mStrokeMiterlimit = 4;
5860
private float mStrokeDashoffset = 0;
5961
private Paint.Cap mStrokeLinecap = Paint.Cap.ROUND;
6062
private Paint.Join mStrokeLinejoin = Paint.Join.ROUND;
@@ -126,6 +128,12 @@ public void setStrokeWidth(float strokeWidth) {
126128
markUpdated();
127129
}
128130

131+
@ReactProp(name = "strokeMiterlimit", defaultFloat = 4f)
132+
public void setStrokeMiterlimit(float strokeMiterlimit) {
133+
mStrokeMiterlimit = strokeMiterlimit;
134+
markUpdated();
135+
}
136+
129137
@ReactProp(name = "strokeLinecap", defaultInt = CAP_ROUND)
130138
public void setStrokeLinecap(int strokeLinecap) {
131139
switch (strokeLinecap) {
@@ -185,8 +193,8 @@ public void draw(Canvas canvas, Paint paint, float opacity) {
185193
}
186194

187195
restoreCanvas(canvas, count);
196+
markUpdateSeen();
188197
}
189-
markUpdateSeen();
190198
}
191199

192200
private void setupPath() {
@@ -243,6 +251,7 @@ protected boolean setupStrokePaint(Paint paint, float opacity, @Nullable RectF
243251
paint.setStyle(Paint.Style.STROKE);
244252
paint.setStrokeCap(mStrokeLinecap);
245253
paint.setStrokeJoin(mStrokeLinejoin);
254+
paint.setStrokeMiter(mStrokeMiterlimit * mScale);
246255
paint.setStrokeWidth(mStrokeWidth * mScale);
247256
setupPaint(paint, opacity, mStrokeColor, box);
248257

android/src/main/java/com/horcrux/svg/RNSVGRenderableViewManager.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ public class RNSVGRenderableViewManager extends ViewGroupManager<ViewGroup> {
4141
/* package */ static final String CLASS_ELLIPSE = "RNSVGEllipse";
4242
/* package */ static final String CLASS_LINE = "RNSVGLine";
4343
/* package */ static final String CLASS_RECT = "RNSVGRect";
44+
/* package */ static final String CLASS_CLIP_PATH = "RNSVGClipPath";
4445

4546
private final String mClassName;
4647

@@ -78,6 +79,10 @@ public static RNSVGRenderableViewManager createRNSVGRectViewManager() {
7879
return new RNSVGRenderableViewManager(CLASS_RECT);
7980
}
8081

82+
public static RNSVGRenderableViewManager createRNSVGClipPathViewManager() {
83+
return new RNSVGRenderableViewManager(CLASS_CLIP_PATH);
84+
}
85+
8186
private RNSVGRenderableViewManager(String className) {
8287
mClassName = className;
8388
}
@@ -114,6 +119,9 @@ public RNSVGVirtualNode createShadowNodeInstance() {
114119
case CLASS_IMAGE:
115120
mVirtualNode = new RNSVGImageShadowNode();
116121
break;
122+
case CLASS_CLIP_PATH:
123+
mVirtualNode = new RNSVGClipPathShadowNode();
124+
break;
117125
default:
118126
throw new IllegalStateException("Unexpected type " + mClassName);
119127
}
@@ -141,6 +149,8 @@ public Class<? extends RNSVGVirtualNode> getShadowNodeClass() {
141149
return RNSVGTextShadowNode.class;
142150
case CLASS_IMAGE:
143151
return RNSVGImageShadowNode.class;
152+
case CLASS_CLIP_PATH:
153+
return RNSVGClipPathShadowNode.class;
144154
default:
145155
throw new IllegalStateException("Unexpected type " + mClassName);
146156
}

android/src/main/java/com/horcrux/svg/RNSVGTextShadowNode.java

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -73,29 +73,27 @@ public void setPath(@Nullable ReadableArray textPath) {
7373
public void draw(Canvas canvas, Paint paint, float opacity) {
7474

7575
opacity *= mOpacity;
76-
if (opacity <= MIN_OPACITY_FOR_DRAW) {
77-
return;
78-
}
76+
if (opacity > MIN_OPACITY_FOR_DRAW) {
77+
String text = formatText();
78+
if (text == null) {
79+
return;
80+
}
7981

80-
String text = formatText();
81-
if (text == null) {
82-
return;
83-
}
82+
// only set up the canvas if we have something to draw
83+
int count = saveAndSetupCanvas(canvas);
84+
clip(canvas, paint);
85+
RectF box = getBox(paint, text);
8486

85-
// only set up the canvas if we have something to draw
86-
int count = saveAndSetupCanvas(canvas);
87-
clip(canvas, paint);
88-
RectF box = getBox(paint, text);
87+
if (setupStrokePaint(paint, opacity, box)) {
88+
drawText(canvas, paint, text);
89+
}
90+
if (setupFillPaint(paint, opacity, box)) {
91+
drawText(canvas, paint, text);
92+
}
8993

90-
if (setupStrokePaint(paint, opacity, box)) {
91-
drawText(canvas, paint, text);
94+
restoreCanvas(canvas, count);
95+
markUpdateSeen();
9296
}
93-
if (setupFillPaint(paint, opacity, box)) {
94-
drawText(canvas, paint, text);
95-
}
96-
97-
restoreCanvas(canvas, count);
98-
markUpdateSeen();
9997
}
10098

10199
private void drawText(Canvas canvas, Paint paint, String text) {

android/src/main/java/com/horcrux/svg/RNSvgPackage.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ public List<ViewManager> createViewManagers(ReactApplicationContext reactContext
3333
RNSVGRenderableViewManager.createRNSVGRectViewManager(),
3434
RNSVGRenderableViewManager.createRNSVGTextViewManager(),
3535
RNSVGRenderableViewManager.createRNSVGImageViewManager(),
36+
RNSVGRenderableViewManager.createRNSVGClipPathViewManager(),
3637
new RNSVGSvgViewManager());
3738
}
3839

elements/ClipPath.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import React, {Component, PropTypes} from 'react';
22
import {NativeGroup} from './G';
33
import {set, remove} from '../lib/extract/extractClipping';
4+
import createNativeComponent from '../lib/createNativeComponent';
45

56
class ClipPath extends Component{
67
static displayName = 'ClipPath';
@@ -26,12 +27,13 @@ class ClipPath extends Component{
2627

2728
render() {
2829
set(this.id, this.id);
29-
30-
return <NativeGroup
31-
asClipPath={this.id}
32-
>{this.props.children}</NativeGroup>;
30+
return <RNSVGClipPath
31+
name={this.id}
32+
>{this.props.children}</RNSVGClipPath>;
3333
}
3434
}
3535

36+
const RNSVGClipPath = createNativeComponent('RNSVGClipPath');
37+
3638
export default ClipPath;
3739

elements/Defs.js

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ class DefsItem extends Component{
1212
static propType = {
1313
visible: PropTypes.bool
1414
};
15+
1516
static defaultProps = {
1617
visible: false
1718
};
@@ -75,16 +76,11 @@ class Defs extends Component{
7576
static Item = DefsItem;
7677
static Use = DefsUse;
7778

78-
shouldRender = false;
7979
getChildren = () => {
8080
return Children.map(this.props.children, child => {
8181
let {type} = child;
8282

8383
if (type === LinearGradient || type === RadialGradient || type === ClipPath) {
84-
if (type === ClipPath) {
85-
this.shouldRender = true;
86-
}
87-
8884
return cloneElement(child, {
8985
svgId: this.props.svgId
9086
});
@@ -99,10 +95,7 @@ class Defs extends Component{
9995
};
10096

10197
render() {
102-
let children = this.getChildren();
103-
return <NativeGroup opacity={this.shouldRender ? 1 : 0}>
104-
{children}
105-
</NativeGroup>;
98+
return <NativeGroup>{this.getChildren()}</NativeGroup>;
10699
}
107100
}
108101

0 commit comments

Comments
 (0)