From 85ab1c67c5b757c6738af0f81075a963e1a5ca89 Mon Sep 17 00:00:00 2001 From: Horcrux Date: Thu, 19 May 2016 00:13:59 +0800 Subject: [PATCH] add Image support for Android --- .../com/horcrux/svg/RNSVGGroupShadowNode.java | 13 +---- .../com/horcrux/svg/RNSVGImageShadowNode.java | 47 ++++++++++++------- .../horcrux/svg/RNSVGSvgViewShadowNode.java | 16 +++++-- .../com/horcrux/svg/RNSVGVirtualNode.java | 15 ++++-- 4 files changed, 55 insertions(+), 36 deletions(-) diff --git a/android/src/main/java/com/horcrux/svg/RNSVGGroupShadowNode.java b/android/src/main/java/com/horcrux/svg/RNSVGGroupShadowNode.java index b0a0802b..189652e3 100644 --- a/android/src/main/java/com/horcrux/svg/RNSVGGroupShadowNode.java +++ b/android/src/main/java/com/horcrux/svg/RNSVGGroupShadowNode.java @@ -38,14 +38,14 @@ public class RNSVGGroupShadowNode extends RNSVGVirtualNode { if (opacity > MIN_OPACITY_FOR_DRAW) { saveAndSetupCanvas(canvas); clip(canvas, paint); - RNSVGSvgViewShadowNode svg = getSvgView(); + RNSVGSvgViewShadowNode svg = getSvgShadowNode(); if (mAsClipPath == null) { for (int i = 0; i < getChildCount(); i++) { RNSVGVirtualNode child = (RNSVGVirtualNode) getChildAt(i); child.setDimensions(mWidth, mHeight); child.draw(canvas, paint, opacity); - child.markUpdateSeen(); + //child.markUpdateSeen(); if (child.isTouchable() && !svg.touchable) { svg.touchable = true; @@ -87,13 +87,4 @@ public class RNSVGGroupShadowNode extends RNSVGVirtualNode { return viewTag; } - - private RNSVGSvgViewShadowNode getSvgView() { - ReactShadowNode parent = getParent(); - - while (!(parent instanceof RNSVGSvgViewShadowNode)) { - parent = parent.getParent(); - } - return (RNSVGSvgViewShadowNode)parent; - } } diff --git a/android/src/main/java/com/horcrux/svg/RNSVGImageShadowNode.java b/android/src/main/java/com/horcrux/svg/RNSVGImageShadowNode.java index e1005f1e..40b4d938 100644 --- a/android/src/main/java/com/horcrux/svg/RNSVGImageShadowNode.java +++ b/android/src/main/java/com/horcrux/svg/RNSVGImageShadowNode.java @@ -14,7 +14,9 @@ import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; +import android.graphics.Color; import android.graphics.Paint; +import android.graphics.PorterDuff; import android.graphics.Rect; import android.graphics.RectF; import android.net.Uri; @@ -40,16 +42,18 @@ public class RNSVGImageShadowNode extends RNSVGPathShadowNode { private String mH; private ReadableMap mSrc; private Uri mUri; + private Bitmap mBitmap; private boolean mLocalImage; private class BitmapWorkerTask extends AsyncTask { private final Canvas mCanvas; private final Paint mPaint; - private int data = 0; - - public BitmapWorkerTask(Canvas canvas, Paint paint) { + private RNSVGSvgViewShadowNode mSvgShadowNode; + public BitmapWorkerTask(Canvas canvas, Paint paint, RNSVGSvgViewShadowNode node) { // Use a WeakReference to ensure the ImageView can be garbage collected mCanvas = canvas; mPaint = paint; + mSvgShadowNode = node; + mSvgShadowNode.mBitmapCount++; } // Decode image in background. @@ -75,15 +79,11 @@ public class RNSVGImageShadowNode extends RNSVGPathShadowNode { @Override protected void onPostExecute(@Nullable Bitmap bitmap) { if (bitmap != null) { - 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); - - clip(mCanvas, mPaint); - mCanvas.restoreToCount(1); - mCanvas.drawBitmap(bitmap, null, new Rect((int)x, (int)y, (int)(x + w), (int)(y + h)), null); - mCanvas.restoreToCount(2); + mBitmap = bitmap; + mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); + mPaint.reset(); + mSvgShadowNode.mBitmapCount--; + mSvgShadowNode.drawChildren(mCanvas, mPaint, mWidth, mHeight); } } } @@ -141,12 +141,27 @@ public class RNSVGImageShadowNode extends RNSVGPathShadowNode { @Override public void draw(Canvas canvas, Paint paint, float opacity) { - canvas.saveLayer(0f, 0f, 0f, 0f, paint, Canvas.ALL_SAVE_FLAG); - loadBitmap(getResourceDrawableId(getThemedContext(), null), canvas, paint); + RNSVGSvgViewShadowNode node = getSvgShadowNode(); + if (mBitmap != null) { + // TODO: fixme + // 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) { + mBitmap.recycle(); + } + } else { + loadBitmap(getResourceDrawableId(getThemedContext(), null), canvas, paint, node); + } } - public void loadBitmap(int resId, Canvas canvas, Paint paint) { - BitmapWorkerTask task = new BitmapWorkerTask(canvas, paint); + public void loadBitmap(int resId, Canvas canvas, Paint paint, RNSVGSvgViewShadowNode node) { + + BitmapWorkerTask task = new BitmapWorkerTask(canvas, paint, node); task.execute(resId); } diff --git a/android/src/main/java/com/horcrux/svg/RNSVGSvgViewShadowNode.java b/android/src/main/java/com/horcrux/svg/RNSVGSvgViewShadowNode.java index c8588a07..23cf2ed3 100644 --- a/android/src/main/java/com/horcrux/svg/RNSVGSvgViewShadowNode.java +++ b/android/src/main/java/com/horcrux/svg/RNSVGSvgViewShadowNode.java @@ -11,8 +11,10 @@ package com.horcrux.svg; import android.graphics.Bitmap; 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,6 +27,8 @@ import com.facebook.react.uimanager.UIViewOperationQueue; public class RNSVGSvgViewShadowNode extends LayoutShadowNode { public boolean touchable = false; + public int mBitmapCount = 0; + @Override public void onCollectExtraUpdates(UIViewOperationQueue uiUpdater) { super.onCollectExtraUpdates(uiUpdater); @@ -32,8 +36,6 @@ public class RNSVGSvgViewShadowNode extends LayoutShadowNode { } private Object drawOutput() { - // TODO(7255985): Use TextureView and pass Svg from the view to draw on it asynchronously - // instead of passing the bitmap (which is inefficient especially in terms of memory usage) float width = (int) getLayoutWidth(); float height = (int) getLayoutHeight(); Bitmap bitmap = Bitmap.createBitmap( @@ -43,18 +45,22 @@ public class RNSVGSvgViewShadowNode extends LayoutShadowNode { Canvas canvas = new Canvas(bitmap); Paint paint = new Paint(); + drawChildren(canvas, paint, width, height); + + return bitmap; + } + + public void drawChildren(Canvas canvas, Paint paint, float width, float height) { for (int i = 0; i < getChildCount(); i++) { RNSVGVirtualNode child = (RNSVGVirtualNode) getChildAt(i); child.setDimensions(width, height); child.draw(canvas, paint, 1f); - child.markUpdateSeen(); + //child.markUpdateSeen(); if (child.isTouchable() && !touchable) { touchable = true; } } - - return bitmap; } public int hitTest(Point point, ViewGroup view) { diff --git a/android/src/main/java/com/horcrux/svg/RNSVGVirtualNode.java b/android/src/main/java/com/horcrux/svg/RNSVGVirtualNode.java index 325dee61..14b5ac09 100644 --- a/android/src/main/java/com/horcrux/svg/RNSVGVirtualNode.java +++ b/android/src/main/java/com/horcrux/svg/RNSVGVirtualNode.java @@ -263,10 +263,8 @@ public abstract class RNSVGVirtualNode extends LayoutShadowNode { } protected void clip(Canvas canvas, Paint paint) { - Path clip = null; - if (mClipPath != null) { - clip = mClipPath; - } else if (mClipPathId != null) { + Path clip = mClipPath; + if (clip == null && mClipPathId != null) { clip = CLIP_PATHS.get(mClipPathId); } @@ -294,6 +292,15 @@ public abstract class RNSVGVirtualNode extends LayoutShadowNode { abstract protected Path getPath(Canvas canvas, Paint paint); + protected RNSVGSvgViewShadowNode getSvgShadowNode() { + ReactShadowNode parent = getParent(); + + while (!(parent instanceof RNSVGSvgViewShadowNode)) { + parent = parent.getParent(); + } + return (RNSVGSvgViewShadowNode)parent; + } + protected void finalize() { if (mDefinedClipPathId != null) { CLIP_PATHS.remove(mDefinedClipPathId);