Using TextureView instead of Bitmap

This commit is contained in:
Horcrux
2016-11-08 21:45:40 +08:00
parent 8bfa80bf10
commit 7c6407e622
12 changed files with 185 additions and 237 deletions
@@ -9,9 +9,6 @@
package com.horcrux.svg;
import android.graphics.Point;
import android.view.View;
/**
* Shadow node for virtual RNSVGClipPath view
*/
@@ -21,9 +18,4 @@ public class RNSVGClipPathShadowNode extends RNSVGGroupShadowNode {
protected void saveDefinition() {
getSvgShadowNode().defineClipPath(this, mName);
}
@Override
public int hitTest(Point point, View view) {
return -1;
}
}
@@ -36,12 +36,7 @@ public class RNSVGDefinitionShadowNode extends RNSVGVirtualNode {
}
@Override
public int hitTest(Point point, View view, Matrix matrix) {
return -1;
}
@Override
public int hitTest(Point point, View view) {
public int hitTest(Point point, Matrix matrix) {
return -1;
}
@@ -71,7 +71,7 @@ public class RNSVGGroupShadowNode extends RNSVGPathShadowNode {
}
@Override
public int hitTest(Point point, View view, @Nullable Matrix matrix) {
public int hitTest(Point point, @Nullable Matrix matrix) {
int viewTag = -1;
Matrix combinedMatrix = new Matrix();
@@ -89,21 +89,15 @@ public class RNSVGGroupShadowNode extends RNSVGPathShadowNode {
RNSVGVirtualNode node = (RNSVGVirtualNode) child;
View childView = ((ViewGroup) view).getChildAt(i);
viewTag = node.hitTest(point, childView, combinedMatrix);
viewTag = node.hitTest(point, combinedMatrix);
if (viewTag != -1) {
return (node.isResponsible() || viewTag != childView.getId()) ? viewTag : view.getId();
return (node.isResponsible() || viewTag != child.getReactTag()) ? viewTag : getReactTag();
}
}
return viewTag;
}
@Override
public int hitTest(Point point, View view) {
return this.hitTest(point, view, null);
}
protected void saveDefinition() {
if (mName != null) {
getSvgShadowNode().defineTemplate(this, mName);
@@ -11,15 +11,14 @@ package com.horcrux.svg;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
import android.net.Uri;
import android.util.Log;
import com.facebook.common.executors.UiThreadImmediateExecutorService;
import com.facebook.common.logging.FLog;
@@ -123,22 +122,15 @@ public class RNSVGImageShadowNode extends RNSVGPathShadowNode {
}
}
private void loadBitmap(@Nonnull final ImageRequest request, @Nonnull final Canvas canvas, @Nonnull final Paint paint) {
private void loadBitmap(ImageRequest request, final Canvas canvas, final Paint paint) {
final DataSource<CloseableReference<CloseableImage>> dataSource
= Fresco.getImagePipeline().fetchDecodedImage(request, getThemedContext());
dataSource.subscribe(new BaseBitmapDataSubscriber() {
@Override
public void onNewResultImpl(@Nullable Bitmap bitmap) {
if (bitmap != null) {
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
paint.reset();
mLoading.set(false);
RNSVGSvgViewShadowNode svgShadowNode = getSvgShadowNode();
svgShadowNode.drawChildren(canvas, paint);
svgShadowNode.invalidateView();
}
public void onNewResultImpl(Bitmap bitmap) {
mLoading.set(false);
getSvgShadowNode().drawOutput();
}
@Override
@@ -163,7 +155,7 @@ public class RNSVGImageShadowNode extends RNSVGPathShadowNode {
return new Rect((int) x, (int) y, (int) (x + w), (int) (y + h));
}
private void doRender(@Nonnull final Canvas canvas, @Nonnull final Paint paint, @Nonnull final Bitmap bitmap, final float opacity) {
private void doRender(Canvas canvas, Paint paint, Bitmap bitmap, float opacity) {
final int count = saveAndSetupCanvas(canvas);
canvas.concat(mMatrix);
@@ -192,8 +184,8 @@ public class RNSVGImageShadowNode extends RNSVGPathShadowNode {
viewBox.setMinY("0");
viewBox.setVbWidth(renderRect.width() / mScale + "");
viewBox.setVbHeight(renderRect.height() / mScale + "");
viewBox.setWidth(rectWidth / mScale);
viewBox.setHeight(rectHeight / mScale);
viewBox.setWidth(rectWidth / mScale + "");
viewBox.setHeight(rectHeight / mScale + "");
viewBox.setAlign(mAlign);
viewBox.setMeetOrSlice(mMeetOrSlice);
viewBox.setupDimensions(new Rect(0, 0, (int) rectWidth, (int) rectHeight));
@@ -233,7 +225,7 @@ public class RNSVGImageShadowNode extends RNSVGPathShadowNode {
markUpdateSeen();
}
private void tryRender(@Nonnull final ImageRequest request, @Nonnull final Canvas canvas, @Nonnull final Paint paint, final float opacity) {
private void tryRender(ImageRequest request, Canvas canvas, Paint paint, float opacity) {
final DataSource<CloseableReference<CloseableImage>> dataSource
= Fresco.getImagePipeline().fetchImageFromBitmapCache(request, getThemedContext());
@@ -248,10 +240,14 @@ public class RNSVGImageShadowNode extends RNSVGPathShadowNode {
doRender(canvas, paint, bitmap, opacity);
}
}
} catch (Exception e) {
throw new IllegalStateException(e);
} finally {
CloseableReference.closeSafely(imageReference);
}
}
} catch (Exception e) {
throw new IllegalStateException(e);
} finally {
dataSource.close();
}
@@ -330,7 +330,7 @@ public class RNSVGPathShadowNode extends RNSVGVirtualNode {
}
@Override
public int hitTest(Point point, View view, @Nullable Matrix matrix) {
public int hitTest(Point point, @Nullable Matrix matrix) {
Bitmap bitmap = Bitmap.createBitmap(
mCanvasWidth,
mCanvasHeight,
@@ -356,9 +356,10 @@ public class RNSVGPathShadowNode extends RNSVGVirtualNode {
canvas.setBitmap(bitmap);
try {
if (bitmap.getPixel(point.x, point.y) != 0) {
return view.getId();
return getReactTag();
}
} catch (Exception e) {
return -1;
} finally {
bitmap.recycle();
@@ -366,11 +367,6 @@ public class RNSVGPathShadowNode extends RNSVGVirtualNode {
return -1;
}
@Override
public int hitTest(Point point, View view) {
return this.hitTest(point, view, null);
}
protected void setHitTestFill(Paint paint) {
paint.reset();
paint.setARGB(255, 0, 0, 0);
@@ -1,29 +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.
*/
package com.horcrux.svg;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
/**
* Custom {@link View} implementation that draws an RNSVGSvg React view and its \children.
*/
public class RNSVGRenderableView extends ViewGroup {
public RNSVGRenderableView(Context context) {
super(context);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
}
}
@@ -9,17 +9,22 @@
package com.horcrux.svg;
import android.view.View;
import android.view.ViewGroup;
import com.facebook.react.uimanager.BaseViewManager;
import com.facebook.react.uimanager.LayoutShadowNode;
import com.facebook.react.uimanager.ReactShadowNode;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.ViewGroupManager;
import com.facebook.react.uimanager.ViewManager;
/**
* ViewManager for all shadowed RNSVG views: Group, Path and Text. Since these never get rendered
* into native views and don't need any logic (all the logic is in {@link RNSVGSvgView}), this
* "stubbed" ViewManager is used for all of them.
*/
public class RNSVGRenderableViewManager extends ViewGroupManager<ViewGroup> {
public class RNSVGRenderableViewManager extends ViewManager<View, LayoutShadowNode> {
/* package */ static final String CLASS_GROUP = "RNSVGGroup";
/* package */ static final String CLASS_PATH = "RNSVGPath";
@@ -38,7 +43,6 @@ public class RNSVGRenderableViewManager extends ViewGroupManager<ViewGroup> {
private final String mClassName;
protected RNSVGVirtualNode mVirtualNode;
public static RNSVGRenderableViewManager createRNSVGGroupViewManager() {
return new RNSVGRenderableViewManager(CLASS_GROUP);
@@ -106,60 +110,43 @@ public class RNSVGRenderableViewManager extends ViewGroupManager<ViewGroup> {
}
@Override
public RNSVGVirtualNode createShadowNodeInstance() {
public LayoutShadowNode createShadowNodeInstance() {
switch (mClassName) {
case CLASS_GROUP:
mVirtualNode = new RNSVGGroupShadowNode();
break;
return new RNSVGGroupShadowNode();
case CLASS_PATH:
mVirtualNode = new RNSVGPathShadowNode();
break;
return new RNSVGPathShadowNode();
case CLASS_CIRCLE:
mVirtualNode = new RNSVGCircleShadowNode();
break;
return new RNSVGCircleShadowNode();
case CLASS_ELLIPSE:
mVirtualNode = new RNSVGEllipseShadowNode();
break;
return new RNSVGEllipseShadowNode();
case CLASS_LINE:
mVirtualNode = new RNSVGLineShadowNode();
break;
return new RNSVGLineShadowNode();
case CLASS_RECT:
mVirtualNode = new RNSVGRectShadowNode();
break;
return new RNSVGRectShadowNode();
case CLASS_TEXT:
mVirtualNode = new RNSVGTextShadowNode();
break;
return new RNSVGTextShadowNode();
case CLASS_IMAGE:
mVirtualNode = new RNSVGImageShadowNode();
break;
return new RNSVGImageShadowNode();
case CLASS_CLIP_PATH:
mVirtualNode = new RNSVGClipPathShadowNode();
break;
return new RNSVGClipPathShadowNode();
case CLASS_DEFS:
mVirtualNode = new RNSVGDefsShadowNode();
break;
return new RNSVGDefsShadowNode();
case CLASS_USE:
mVirtualNode = new RNSVGUseShadowNode();
break;
return new RNSVGUseShadowNode();
case CLASS_VIEW_BOX:
mVirtualNode = new RNSVGViewBoxShadowNode();
break;
return new RNSVGViewBoxShadowNode();
case CLASS_LINEAR_GRADIENT:
mVirtualNode = new RNSVGLinearGradientShadowNode();
break;
return new RNSVGLinearGradientShadowNode();
case CLASS_RADIAL_GRADIENT:
mVirtualNode = new RNSVGRadialGradientShadowNode();
break;
return new RNSVGRadialGradientShadowNode();
default:
throw new IllegalStateException("Unexpected type " + mClassName);
}
return mVirtualNode;
}
@Override
public Class<? extends RNSVGVirtualNode> getShadowNodeClass() {
public Class<? extends LayoutShadowNode> getShadowNodeClass() {
switch (mClassName) {
case CLASS_GROUP:
return RNSVGGroupShadowNode.class;
@@ -195,7 +182,12 @@ public class RNSVGRenderableViewManager extends ViewGroupManager<ViewGroup> {
}
@Override
protected ViewGroup createViewInstance(ThemedReactContext reactContext) {
return new RNSVGRenderableView(reactContext);
protected View createViewInstance(ThemedReactContext reactContext) {
throw new IllegalStateException("SVG elements does not map into a native view");
}
@Override
public void updateExtraData(View root, Object extraData) {
throw new IllegalStateException("SVG elements does not map into a native view");
}
}
@@ -19,13 +19,17 @@ import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.TextureView;
import com.facebook.react.ReactRootView;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.common.SystemClock;
import com.facebook.react.touch.OnInterceptTouchEventListener;
import com.facebook.react.touch.ReactInterceptingViewGroup;
import com.facebook.react.uimanager.TouchTargetHelper;
import com.facebook.react.uimanager.UIManagerModule;
import com.facebook.react.uimanager.events.NativeGestureUtil;
import com.facebook.react.uimanager.events.RCTEventEmitter;
import com.facebook.react.uimanager.events.TouchEvent;
import com.facebook.react.uimanager.events.TouchEventCoalescingKeyHelper;
@@ -35,8 +39,7 @@ import com.facebook.react.uimanager.events.EventDispatcher;
/**
* Custom {@link View} implementation that draws an RNSVGSvg React view and its \children.
*/
public class RNSVGSvgView extends ViewGroup {
public class RNSVGSvgView extends TextureView {
public enum Events {
EVENT_DATA_URL("onDataURL");
@@ -52,62 +55,36 @@ public class RNSVGSvgView extends ViewGroup {
}
}
private @Nullable Bitmap mBitmap;
private RCTEventEmitter mEventEmitter;
private EventDispatcher mEventDispatcher;
private RNSVGSvgViewShadowNode mSvgViewShadowNode;
private int mTargetTag;
private final TouchEventCoalescingKeyHelper mTouchEventCoalescingKeyHelper =
new TouchEventCoalescingKeyHelper();
public RNSVGSvgView(Context context) {
super(context);
}
public RNSVGSvgView(ReactContext reactContext) {
super(reactContext);
setOpaque(false);
mEventEmitter = reactContext.getJSModule(RCTEventEmitter.class);
mEventDispatcher = reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher();
}
public void setBitmap(Bitmap bitmap) {
if (mBitmap != null) {
mBitmap.recycle();
}
mBitmap = bitmap;
invalidate();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (mBitmap != null) {
canvas.drawBitmap(mBitmap, 0, 0, null);
}
private RNSVGSvgViewShadowNode getShadowNode() {
return RNSVGSvgViewShadowNode.getShadowNodeByTag(getId());
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
mTargetTag = mSvgViewShadowNode.hitTest(new Point((int) ev.getX(), (int) ev.getY()), this);
mTargetTag = getShadowNode().hitTest(new Point((int) ev.getX(), (int) ev.getY()));
if (mTargetTag != -1) {
handleTouchEvent(ev);
return true;
}
return super.dispatchTouchEvent(ev);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
}
public void setShadowNode(RNSVGSvgViewShadowNode shadowNode) {
mSvgViewShadowNode = shadowNode;
shadowNode.setSvgView(this);
}
private int getAbsoluteLeft(View view) {
int left = view.getLeft() - view.getScrollX();
@@ -159,6 +136,7 @@ public class RNSVGSvgView extends ViewGroup {
dispatch(ev, TouchEventType.END);
mTargetTag = -1;
} else if (action == MotionEvent.ACTION_MOVE) {
Log.e("asdasd", "asdasd");
// Update pointer position for current gesture
dispatch(ev, TouchEventType.MOVE);
} else if (action == MotionEvent.ACTION_POINTER_DOWN) {
@@ -195,7 +173,7 @@ public class RNSVGSvgView extends ViewGroup {
public void onDataURL() {
WritableMap event = Arguments.createMap();
event.putString("base64", mSvgViewShadowNode.getBase64());
event.putString("base64", getShadowNode().getBase64());
mEventEmitter.receiveEvent(getId(), Events.EVENT_DATA_URL.toString(), event);
}
}
@@ -10,10 +10,15 @@
package com.horcrux.svg;
import android.graphics.Bitmap;
import android.util.Log;
import android.util.SparseArray;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.common.MapBuilder;
import com.facebook.react.uimanager.BaseViewManager;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.ViewGroupManager;
import com.facebook.react.uimanager.ViewManager;
import java.util.ArrayList;
import java.util.HashMap;
@@ -25,14 +30,10 @@ import javax.annotation.Nullable;
* ViewManager for RNSVGSvgView React views. Renders as a {@link RNSVGSvgView} and handles
* invalidating the native view on shadow view updates happening in the underlying tree.
*/
public class RNSVGSvgViewManager extends ViewGroupManager<RNSVGSvgView> {
public class RNSVGSvgViewManager extends BaseViewManager<RNSVGSvgView, RNSVGSvgViewShadowNode> {
private static final String REACT_CLASS = "RNSVGSvgView";
// TODO: use an ArrayList to connect RNSVGSvgViewShadowNode with RNSVGSvgView, not sure if there will be a race condition.
// TODO: find a better way to replace this
private ArrayList<RNSVGSvgViewShadowNode> mSvgShadowNodes = new ArrayList<>();
public static final int COMMAND_TO_DATA_URL = 100;
private static final int COMMAND_TO_DATA_URL = 100;
@Override
public String getName() {
@@ -71,28 +72,23 @@ public class RNSVGSvgViewManager extends ViewGroupManager<RNSVGSvgView> {
}
}
@Override
public RNSVGSvgViewShadowNode createShadowNodeInstance() {
RNSVGSvgViewShadowNode node = new RNSVGSvgViewShadowNode();
mSvgShadowNodes.add(node);
return node;
}
@Override
public Class<RNSVGSvgViewShadowNode> getShadowNodeClass() {
return RNSVGSvgViewShadowNode.class;
}
@Override
public RNSVGSvgViewShadowNode createShadowNodeInstance() {
return new RNSVGSvgViewShadowNode();
}
@Override
protected RNSVGSvgView createViewInstance(ThemedReactContext reactContext) {
RNSVGSvgView svgView = new RNSVGSvgView(reactContext);
svgView.setShadowNode(mSvgShadowNodes.remove(0));
return svgView;
return new RNSVGSvgView(reactContext);
}
@Override
public void updateExtraData(RNSVGSvgView root, Object extraData) {
root.setBitmap((Bitmap) extraData);
root.setSurfaceTextureListener((RNSVGSvgViewShadowNode) extraData);
}
}
@@ -14,12 +14,22 @@ import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Point;
import android.util.Base64;
import android.util.SparseArray;
import android.view.TextureView;
import android.view.ViewGroup;
import android.graphics.Color;
import android.view.Surface;
import android.graphics.PorterDuff;
import android.graphics.SurfaceTexture;
import com.facebook.common.logging.FLog;
import com.facebook.imagepipeline.request.ImageRequest;
import com.facebook.react.common.ReactConstants;
import com.facebook.react.uimanager.LayoutShadowNode;
import com.facebook.react.uimanager.ReactShadowNode;
import com.facebook.react.uimanager.UIViewOperationQueue;
import javax.annotation.Nullable;
import java.io.ByteArrayOutputStream;
import java.util.HashMap;
import java.util.Map;
@@ -27,52 +37,60 @@ import java.util.Map;
/**
* Shadow node for RNSVG virtual tree root - RNSVGSvgView
*/
public class RNSVGSvgViewShadowNode extends LayoutShadowNode {
public class RNSVGSvgViewShadowNode extends LayoutShadowNode implements TextureView.SurfaceTextureListener {
private static final SparseArray<RNSVGSvgViewShadowNode> mTagToShadowNode = new SparseArray<>();
public static RNSVGSvgViewShadowNode getShadowNodeByTag(int tag) {
return mTagToShadowNode.get(tag);
}
private @Nullable Surface mSurface;
private boolean mResponsible = false;
private RNSVGSvgView mSvgView;
private static final Map<String, RNSVGVirtualNode> mDefinedClipPaths = new HashMap<>();
private static final Map<String, RNSVGVirtualNode> mDefinedTemplates = new HashMap<>();
private static final Map<String, PropHelper.RNSVGBrush> mDefinedBrushes = new HashMap<>();
@Override
public boolean isVirtual() {
return false;
}
@Override
public boolean isVirtualAnchor() {
return true;
}
@Override
public void onCollectExtraUpdates(UIViewOperationQueue uiUpdater) {
super.onCollectExtraUpdates(uiUpdater);
uiUpdater.enqueueUpdateExtraData(getReactTag(), drawOutput());
drawOutput();
uiUpdater.enqueueUpdateExtraData(getReactTag(), this);
}
private Object drawOutput() {
Bitmap bitmap = Bitmap.createBitmap(
(int) getLayoutWidth(),
(int) getLayoutHeight(),
Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
public void drawOutput() {
if (mSurface == null || !mSurface.isValid()) {
markChildrenUpdatesSeen(this);
return;
}
try {
Canvas canvas = mSurface.lockCanvas(null);
drawChildren(canvas);
if (mSurface != null) {
mSurface.unlockCanvasAndPost(canvas);
}
} catch (IllegalArgumentException | IllegalStateException e) {
FLog.e(ReactConstants.TAG, e.getClass().getSimpleName() + " in Svg.unlockCanvasAndPost");
}
}
private void drawChildren(Canvas canvas) {
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
Paint paint = new Paint();
drawChildren(canvas, paint);
return bitmap;
}
public String getBase64() {
Bitmap bitmap = (Bitmap)drawOutput();
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
bitmap.recycle();
byte[] bitmapBytes = stream.toByteArray();
return Base64.encodeToString(bitmapBytes, Base64.DEFAULT);
}
/**
* Draw all of the child nodes of this root node
*
* This method is synchronized since
* {@link com.horcrux.svg.RNSVGImageShadowNode#loadBitmap(ImageRequest, Canvas, Paint)} calls it
* asynchronously after images have loaded and are ready to be drawn.
*
* @param canvas
* @param paint
*/
public synchronized void drawChildren(Canvas canvas, Paint paint) {
for (int i = 0; i < getChildCount(); i++) {
if (!(getChildAt(i) instanceof RNSVGVirtualNode)) {
continue;
@@ -89,13 +107,56 @@ public class RNSVGSvgViewShadowNode extends LayoutShadowNode {
}
}
private void markChildrenUpdatesSeen(ReactShadowNode shadowNode) {
for (int i = 0; i < shadowNode.getChildCount(); i++) {
ReactShadowNode child = shadowNode.getChildAt(i);
child.markUpdateSeen();
markChildrenUpdatesSeen(child);
}
}
public String getBase64() {
Bitmap bitmap = Bitmap.createBitmap(
(int) getLayoutWidth(),
(int) getLayoutHeight(),
Bitmap.Config.ARGB_8888);
drawChildren(new Canvas(bitmap));
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
bitmap.recycle();
byte[] bitmapBytes = stream.toByteArray();
return Base64.encodeToString(bitmapBytes, Base64.DEFAULT);
}
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
mSurface = new Surface(surface);
mTagToShadowNode.put(getReactTag(), this);
drawOutput();
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
mTagToShadowNode.remove(getReactTag());
surface.release();
mSurface = null;
return true;
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {}
public void enableTouchEvents() {
if (!mResponsible) {
mResponsible = true;
}
}
public int hitTest(Point point, ViewGroup view) {
public int hitTest(Point point) {
if (!mResponsible) {
return -1;
}
@@ -107,7 +168,7 @@ public class RNSVGSvgViewShadowNode extends LayoutShadowNode {
continue;
}
viewTag = ((RNSVGVirtualNode) getChildAt(i)).hitTest(point, view.getChildAt(i));
viewTag = ((RNSVGVirtualNode) getChildAt(i)).hitTest(point);
if (viewTag != -1) {
break;
}
@@ -139,12 +200,4 @@ public class RNSVGSvgViewShadowNode extends LayoutShadowNode {
public PropHelper.RNSVGBrush getDefinedBrush(String brushRef) {
return mDefinedBrushes.get(brushRef);
}
public void setSvgView(RNSVGSvgView svgView) {
mSvgView = svgView;
}
protected void invalidateView() {
mSvgView.invalidate();
}
}
@@ -194,7 +194,7 @@ public class RNSVGTextShadowNode extends RNSVGPathShadowNode {
}
@Override
public int hitTest(Point point, View view, @Nullable Matrix matrix) {
public int hitTest(Point point, @Nullable Matrix matrix) {
Bitmap bitmap = Bitmap.createBitmap(
mCanvasWidth,
mCanvasHeight,
@@ -225,7 +225,7 @@ public class RNSVGTextShadowNode extends RNSVGPathShadowNode {
canvas.setBitmap(bitmap);
try {
if (bitmap.getPixel(point.x, point.y) != 0) {
return view.getId();
return getReactTag();
}
} catch (Exception e) {
return -1;
@@ -234,10 +234,4 @@ public class RNSVGTextShadowNode extends RNSVGPathShadowNode {
}
return -1;
}
@Override
public int hitTest(Point point, View view) {
return this.hitTest(point, view, null);
}
}
@@ -27,10 +27,6 @@ import com.facebook.react.uimanager.annotations.ReactProp;
import javax.annotation.Nullable;
/**
* Base class for RNSVGView virtual nodes: {@link RNSVGGroupShadowNode}, {@link RNSVGPathShadowNode} and
* indirectly for {@link RNSVGTextShadowNode}.
*/
public abstract class RNSVGVirtualNode extends LayoutShadowNode {
protected static final float MIN_OPACITY_FOR_DRAW = 0.01f;
@@ -42,6 +38,7 @@ public abstract class RNSVGVirtualNode extends LayoutShadowNode {
protected @Nullable Path mClipPath;
protected @Nullable String mClipPathRef;
private static final int PATH_TYPE_CLOSE = 1;
private static final int PATH_TYPE_CURVETO = 3;
private static final int PATH_TYPE_LINETO = 2;
@@ -49,6 +46,7 @@ public abstract class RNSVGVirtualNode extends LayoutShadowNode {
private static final int CLIP_RULE_EVENODD = 0;
private static final int CLIP_RULE_NONZERO = 1;
protected final float mScale;
private float[] mClipData;
private int mClipRule;
@@ -67,6 +65,11 @@ public abstract class RNSVGVirtualNode extends LayoutShadowNode {
mScale = DisplayMetricsHolder.getScreenDisplayMetrics().density;
}
@Override
public boolean isVirtual() {
return true;
}
public abstract void draw(Canvas canvas, Paint paint, float opacity);
/**
@@ -181,20 +184,6 @@ public abstract class RNSVGVirtualNode extends LayoutShadowNode {
mMatrix.setValues(sRawMatrix);
}
/**
* Returns the floor modulus of the float arguments. Java modulus will return a negative remainder
* when the divisor is negative. Modulus should always be positive. This mimics the behavior of
* Math.floorMod, introduced in Java 8.
*/
private float modulus(float x, float y) {
float remainder = x % y;
float ret = remainder;
if (remainder < 0) {
ret += y;
}
return ret;
}
/**
* Creates a {@link Path} from an array of instructions constructed by JS
* (see RNSVGSerializablePath.js). Each instruction starts with a type (see PATH_TYPE_*) followed
@@ -254,9 +243,11 @@ public abstract class RNSVGVirtualNode extends LayoutShadowNode {
}
}
abstract public int hitTest(Point point, View view, @Nullable Matrix matrix);
abstract public int hitTest(Point point, @Nullable Matrix matrix);
abstract public int hitTest(Point point, View view);
public int hitTest(Point point) {
return this.hitTest(point, null);
}
public boolean isResponsible() {
return mResponsible;