mirror of
https://github.com/zoriya/react-native-svg.git
synced 2026-06-06 16:32:24 +00:00
Using TextureView instead of Bitmap
This commit is contained in:
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user