fix clip bug

This commit is contained in:
Horcrux
2016-05-21 16:21:54 +08:00
parent 85ab1c67c5
commit 404bdf3782
11 changed files with 114 additions and 78 deletions

View File

@@ -49,6 +49,14 @@ class ClipPathAttr extends Component{
height="100"
fill="url(#grad)"
clipPath="M50,5L20,99L95,39L5,39L80,99z"
onStartShouldSetResponder={() => alert("1111111")}
/>
<Rect
x="40%"
y="0"
width="20%"
height="20%"
fill="pink"
/>
</Svg>;
}

View File

@@ -1,8 +1,10 @@
/**
* Sample React Native App
* https://github.com/facebook/react-native
* Sample React Native App for react-native-svg library
* https://github.com/magicismight/react-native-svg/tree/master/Example
*/
'use strict';
import React, {Component} from 'react';
import {
AppRegistry,
StyleSheet,
@@ -15,8 +17,6 @@ import {
Easing
} from 'react-native';
import React, {Component} from 'react';
import {
Svg,
Circle,
@@ -108,7 +108,7 @@ const styles = StyleSheet.create({
const names = ['Svg', 'Stroking', 'Path', 'Line', 'Rect', 'Polygon', 'Polyline', 'Circle', 'Ellipse', 'G', 'Text', 'Use', 'Symbol', 'Gradients', 'Clipping', 'Image'];
class ArtSvgExample extends Component {
class SvgExample extends Component {
constructor() {
super(...arguments);
this.state = {
@@ -239,7 +239,7 @@ class ArtSvgExample extends Component {
</View>
</Animated.Modal>
<Text style={styles.welcome}>
SVG by ART!
SVG library for React Native
</Text>
<ScrollView
style={styles.content}
@@ -251,4 +251,4 @@ class ArtSvgExample extends Component {
}
}
AppRegistry.registerComponent('ArtSvgExample', () => ArtSvgExample);
AppRegistry.registerComponent('ArtSvgExample', () => SvgExample);

View File

@@ -63,8 +63,6 @@ public class RNSVGEllipseShadowNode extends RNSVGPathShadowNode {
@Override
protected Path getPath(Canvas canvas, Paint paint) {
Path path = new Path();
// draw ellipse
float cx = PropHelper.fromPercentageToFloat(mCx, mWidth, 0, mScale);
float cy = PropHelper.fromPercentageToFloat(mCy, mHeight, 0, mScale);
float rx = PropHelper.fromPercentageToFloat(mRx, mWidth, 0, mScale);

View File

@@ -36,25 +36,26 @@ public class RNSVGGroupShadowNode extends RNSVGVirtualNode {
public void draw(Canvas canvas, Paint paint, float opacity) {
opacity *= mOpacity;
if (opacity > MIN_OPACITY_FOR_DRAW) {
saveAndSetupCanvas(canvas);
int count = saveAndSetupCanvas(canvas);
clip(canvas, paint);
RNSVGSvgViewShadowNode svg = getSvgShadowNode();
if (mAsClipPath == null) {
for (int i = 0; i < getChildCount(); i++) {
RNSVGVirtualNode child = (RNSVGVirtualNode) getChildAt(i);
child.setDimensions(mWidth, mHeight);
child.setupDimensions(canvas);
child.draw(canvas, paint, opacity);
//child.markUpdateSeen();
if (child.isTouchable() && !svg.touchable) {
svg.touchable = true;
if (child.isTouchable()) {
svg.enableTouchEvents();
}
}
} else {
defineClipPath(getPath(canvas, paint), mAsClipPath);
}
restoreCanvas(canvas);
restoreCanvas(canvas, count);
}
}
@@ -64,6 +65,7 @@ public class RNSVGGroupShadowNode extends RNSVGVirtualNode {
for (int i = 0; i < getChildCount(); i++) {
RNSVGVirtualNode child = (RNSVGVirtualNode) getChildAt(i);
child.setupDimensions(canvas);
path.addPath(child.getPath(canvas, paint));
}
return path;
@@ -71,8 +73,7 @@ public class RNSVGGroupShadowNode extends RNSVGVirtualNode {
@Override
public int hitTest(Point point, View view) {
// TODO: run hit test only if necessary
// TODO: ClipPath never run hitTest
if (mAsClipPath != null) {
return -1;
}

View File

@@ -16,6 +16,7 @@ import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.RectF;
@@ -24,8 +25,10 @@ import android.os.AsyncTask;
import android.provider.MediaStore;
import android.util.Log;
import com.facebook.common.logging.FLog;
import com.facebook.common.util.UriUtil;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.common.ReactConstants;
import com.facebook.react.uimanager.annotations.ReactProp;
import java.net.URL;
@@ -40,10 +43,11 @@ public class RNSVGImageShadowNode extends RNSVGPathShadowNode {
private String mY;
private String mW;
private String mH;
private ReadableMap mSrc;
private Uri mUri;
private Bitmap mBitmap;
private boolean mLocalImage;
private boolean mLoading;
private class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {
private final Canvas mCanvas;
private final Paint mPaint;
@@ -53,7 +57,7 @@ public class RNSVGImageShadowNode extends RNSVGPathShadowNode {
mCanvas = canvas;
mPaint = paint;
mSvgShadowNode = node;
mSvgShadowNode.mBitmapCount++;
mSvgShadowNode.increaseCounter();
}
// Decode image in background.
@@ -70,6 +74,7 @@ public class RNSVGImageShadowNode extends RNSVGPathShadowNode {
bitmap = BitmapFactory.decodeStream(url.openConnection().getInputStream());
}
} catch (Exception e) {
FLog.w(ReactConstants.TAG, "RNSVG: load Image load failed!:" + e.getMessage());
}
return bitmap;
@@ -80,10 +85,10 @@ public class RNSVGImageShadowNode extends RNSVGPathShadowNode {
protected void onPostExecute(@Nullable Bitmap bitmap) {
if (bitmap != null) {
mBitmap = bitmap;
mSvgShadowNode.decreaseCounter();
mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
mPaint.reset();
mSvgShadowNode.mBitmapCount--;
mSvgShadowNode.drawChildren(mCanvas, mPaint, mWidth, mHeight);
mSvgShadowNode.drawChildren(mCanvas, mPaint);
}
}
}
@@ -114,8 +119,6 @@ public class RNSVGImageShadowNode extends RNSVGPathShadowNode {
@ReactProp(name = "src")
public void setSrc(@Nullable ReadableMap src) {
mSrc = src;
if (src != null) {
String uri = src.getString("uri");
if (uri != null) {
@@ -143,24 +146,28 @@ public class RNSVGImageShadowNode extends RNSVGPathShadowNode {
public void draw(Canvas canvas, Paint paint, float opacity) {
RNSVGSvgViewShadowNode node = getSvgShadowNode();
if (mBitmap != null) {
// TODO: fixme
// clip(canvas, paint);
int count = saveAndSetupCanvas(canvas);
clip(canvas, paint);
float x = PropHelper.fromPercentageToFloat(mX, mWidth, 0, mScale);
float y = PropHelper.fromPercentageToFloat(mY, mHeight, 0, mScale);
float w = PropHelper.fromPercentageToFloat(mW, mWidth, 0, mScale);
float h = PropHelper.fromPercentageToFloat(mH, mHeight, 0, mScale);
canvas.drawBitmap(mBitmap, null, new Rect((int) x, (int) y, (int) (x + w), (int)(y + h)), null);
if (node.mBitmapCount == 0) {
restoreCanvas(canvas, count);
markUpdateSeen();
if (node.isCounterEmpty()) {
mBitmap.recycle();
}
} else {
} else if (!mLoading) {
mLoading = true;
loadBitmap(getResourceDrawableId(getThemedContext(), null), canvas, paint, node);
}
}
public void loadBitmap(int resId, Canvas canvas, Paint paint, RNSVGSvgViewShadowNode node) {
BitmapWorkerTask task = new BitmapWorkerTask(canvas, paint, node);
task.execute(resId);
}

View File

@@ -68,7 +68,6 @@ public class RNSVGLineShadowNode extends RNSVGPathShadowNode {
@Override
protected Path getPath(Canvas canvas, Paint paint) {
Path path = new Path();
float x1 = PropHelper.fromPercentageToFloat(mX1, mWidth, 0, mScale);
float y1 = PropHelper.fromPercentageToFloat(mY1, mHeight, 0, mScale);
float x2 = PropHelper.fromPercentageToFloat(mX2, mWidth, 0, mScale);

View File

@@ -61,14 +61,12 @@ public class RNSVGPathShadowNode extends RNSVGVirtualNode {
private Path.FillType mFillRule = Path.FillType.WINDING;
private boolean mFillRuleSet;
protected Path mPath;
private boolean mPathSet;
private float[] mD;
@ReactProp(name = "d")
public void setPath(@Nullable ReadableArray shapePath) {
mD = PropHelper.toFloatArray(shapePath);
mPathSet = true;
setupPath();
markUpdated();
}
@@ -169,8 +167,9 @@ public class RNSVGPathShadowNode extends RNSVGVirtualNode {
@Override
public void draw(Canvas canvas, Paint paint, float opacity) {
opacity *= mOpacity;
if (opacity > MIN_OPACITY_FOR_DRAW) {
saveAndSetupCanvas(canvas);
int count = saveAndSetupCanvas(canvas);
if (mPath == null) {
throw new JSApplicationIllegalArgumentException(
"Paths should have a valid path (d) prop");
@@ -185,17 +184,17 @@ public class RNSVGPathShadowNode extends RNSVGVirtualNode {
canvas.drawPath(mPath, paint);
}
restoreCanvas(canvas);
restoreCanvas(canvas, count);
}
markUpdateSeen();
}
private void setupPath() {
// init path after both fillRule and path have been set
if (mFillRuleSet && mPathSet) {
mPath = getPath(null, null);
RectF box = new RectF();
mPath.computeBounds(box, true);
if (mFillRuleSet && mD != null) {
mPath = new Path();
mPath.setFillType(mFillRule);
super.createPath(mD, mPath);
}
}
@@ -327,28 +326,30 @@ public class RNSVGPathShadowNode extends RNSVGVirtualNode {
}
protected Path getPath(@Nullable Canvas canvas, @Nullable Paint paint) {
Path path = new Path();
path.setFillType(mFillRule);
super.createPath(mD, path);
return path;
@Override
protected Path getPath(Canvas canvas, Paint paint) {
return mPath;
}
@Override
public int hitTest(Point point, View view) {
Bitmap bitmap = Bitmap.createBitmap(
(int) mWidth,
(int) mHeight,
mWidth,
mHeight,
Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
canvas.concat(mMatrix);
if (mMatrix != null) {
canvas.concat(mMatrix);
}
Paint paint = new Paint();
clip(canvas, paint);
setHitTestFill(paint);
canvas.drawPath(mPath, paint);
if (setHitTestStroke(paint)) {
canvas.drawPath(mPath, paint);
}

View File

@@ -87,7 +87,6 @@ public class RNSVGRectShadowNode extends RNSVGPathShadowNode {
@Override
protected Path getPath(Canvas canvas, Paint paint) {
Path path = new Path();
float x = PropHelper.fromPercentageToFloat(mX, mWidth, 0, mScale);
float y = PropHelper.fromPercentageToFloat(mY, mHeight, 0, mScale);
float w = PropHelper.fromPercentageToFloat(mW, mWidth, 0, mScale);

View File

@@ -14,7 +14,6 @@ import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.PorterDuff;
import android.util.Log;
import android.view.ViewGroup;
@@ -25,9 +24,10 @@ import com.facebook.react.uimanager.UIViewOperationQueue;
* Shadow node for RNSVG virtual tree root - RNSVGSvgView
*/
public class RNSVGSvgViewShadowNode extends LayoutShadowNode {
public boolean touchable = false;
public int mBitmapCount = 0;
private int mCounter = 0;
private boolean mTouchable = false;
@Override
public void onCollectExtraUpdates(UIViewOperationQueue uiUpdater) {
@@ -36,35 +36,39 @@ public class RNSVGSvgViewShadowNode extends LayoutShadowNode {
}
private Object drawOutput() {
float width = (int) getLayoutWidth();
float height = (int) getLayoutHeight();
Bitmap bitmap = Bitmap.createBitmap(
(int) width,
(int) height,
(int) getLayoutWidth(),
(int) getLayoutHeight(),
Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint();
drawChildren(canvas, paint, width, height);
drawChildren(canvas, paint);
return bitmap;
}
public void drawChildren(Canvas canvas, Paint paint, float width, float height) {
public void drawChildren(Canvas canvas, Paint paint) {
for (int i = 0; i < getChildCount(); i++) {
RNSVGVirtualNode child = (RNSVGVirtualNode) getChildAt(i);
child.setDimensions(width, height);
child.setupDimensions(canvas);
child.draw(canvas, paint, 1f);
//child.markUpdateSeen();
if (child.isTouchable() && !touchable) {
touchable = true;
if (child.isTouchable() && !mTouchable) {
mTouchable = true;
}
}
}
public void enableTouchEvents() {
if (!mTouchable) {
mTouchable = true;
}
}
public int hitTest(Point point, ViewGroup view) {
if (!touchable) {
if (!mTouchable) {
return -1;
}
@@ -79,4 +83,16 @@ public class RNSVGSvgViewShadowNode extends LayoutShadowNode {
return viewTag;
}
public void increaseCounter() {
mCounter++;
}
public void decreaseCounter() {
mCounter--;
}
public boolean isCounterEmpty() {
return mCounter == 0;
}
}

View File

@@ -83,7 +83,7 @@ public class RNSVGTextShadowNode extends RNSVGPathShadowNode {
}
// only set up the canvas if we have something to draw
saveAndSetupCanvas(canvas);
int count = saveAndSetupCanvas(canvas);
clip(canvas, paint);
RectF box = getBox(paint, text);
@@ -94,7 +94,7 @@ public class RNSVGTextShadowNode extends RNSVGPathShadowNode {
drawText(canvas, paint, text);
}
restoreCanvas(canvas);
restoreCanvas(canvas, count);
markUpdateSeen();
}
@@ -197,14 +197,14 @@ public class RNSVGTextShadowNode extends RNSVGPathShadowNode {
@Override
public int hitTest(Point point, View view) {
Bitmap bitmap = Bitmap.createBitmap(
(int) mWidth,
(int) mHeight,
mWidth,
mHeight,
Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
canvas.concat(mMatrix);
// todo clip detect
if (mMatrix != null) {
canvas.concat(mMatrix);
}
String text = formatText();
if (text == null) {

View File

@@ -39,7 +39,7 @@ import java.util.Map;
* indirectly for {@link RNSVGTextShadowNode}.
*/
public abstract class RNSVGVirtualNode extends LayoutShadowNode {
protected static Map<String, Path> CLIP_PATHS = new HashMap<>();
private static final Map<String, Path> CLIP_PATHS = new HashMap<>();
protected static final float MIN_OPACITY_FOR_DRAW = 0.01f;
@@ -64,10 +64,9 @@ public abstract class RNSVGVirtualNode extends LayoutShadowNode {
private int mClipRule;
private boolean mClipRuleSet;
private boolean mClipDataSet;
protected float mWidth = 0;
protected float mHeight = 0;
protected boolean mTouchable;
protected int mWidth;
protected int mHeight;
public RNSVGVirtualNode() {
mScale = DisplayMetricsHolder.getWindowDisplayMetrics().density;
@@ -84,11 +83,14 @@ public abstract class RNSVGVirtualNode extends LayoutShadowNode {
*
* @param canvas the canvas to set up
*/
protected final void saveAndSetupCanvas(Canvas canvas) {
protected final int saveAndSetupCanvas(Canvas canvas) {
int count = canvas.getSaveCount();
canvas.save();
if (mMatrix != null) {
canvas.concat(mMatrix);
}
return count;
}
/**
@@ -97,8 +99,8 @@ public abstract class RNSVGVirtualNode extends LayoutShadowNode {
*
* @param canvas the canvas to restore
*/
protected void restoreCanvas(Canvas canvas) {
canvas.restore();
protected void restoreCanvas(Canvas canvas, int count) {
canvas.restoreToCount(count);
}
@ReactProp(name = "clipPath")
@@ -274,11 +276,6 @@ public abstract class RNSVGVirtualNode extends LayoutShadowNode {
}
}
public void setDimensions(float width, float height) {
mWidth = width;
mHeight = height;
}
abstract public int hitTest(Point point, View view);
protected void defineClipPath(Path clipPath, String clipPathId) {
@@ -296,11 +293,21 @@ public abstract class RNSVGVirtualNode extends LayoutShadowNode {
ReactShadowNode parent = getParent();
while (!(parent instanceof RNSVGSvgViewShadowNode)) {
parent = parent.getParent();
if (parent == null) {
return null;
} else {
parent = parent.getParent();
}
}
return (RNSVGSvgViewShadowNode)parent;
}
protected void setupDimensions(Canvas canvas) {
mWidth = canvas.getWidth();
mHeight = canvas.getHeight();
}
protected void finalize() {
if (mDefinedClipPathId != null) {
CLIP_PATHS.remove(mDefinedClipPathId);