From ba7bef6ce83f6b4e18d923f1c561cbf07f393383 Mon Sep 17 00:00:00 2001 From: Maksym Komarychev Date: Fri, 13 Apr 2018 22:32:49 +0300 Subject: [PATCH] [android] fire onLayout --- .../java/com/horcrux/svg/GroupShadowNode.java | 7 +++++ .../com/horcrux/svg/RenderableShadowNode.java | 11 +++++++ .../com/horcrux/svg/SvgViewShadowNode.java | 15 ++++++++++ .../java/com/horcrux/svg/UseShadowNode.java | 2 ++ .../java/com/horcrux/svg/VirtualNode.java | 29 +++++++++++++++++++ 5 files changed, 64 insertions(+) diff --git a/android/src/main/java/com/horcrux/svg/GroupShadowNode.java b/android/src/main/java/com/horcrux/svg/GroupShadowNode.java index b8956b74..351c1eb6 100644 --- a/android/src/main/java/com/horcrux/svg/GroupShadowNode.java +++ b/android/src/main/java/com/horcrux/svg/GroupShadowNode.java @@ -69,6 +69,7 @@ class GroupShadowNode extends RenderableShadowNode { pushGlyphContext(); final SvgViewShadowNode svg = getSvgShadowNode(); final GroupShadowNode self = this; + final RectF groupRect = new RectF(); traverseChildren(new NodeRunnable() { public void run(ReactShadowNode lNode) { if (lNode instanceof VirtualNode) { @@ -79,6 +80,11 @@ class GroupShadowNode extends RenderableShadowNode { int count = node.saveAndSetupCanvas(canvas); node.draw(canvas, paint, opacity * mOpacity); + RectF r = node.getClientRect(); + if (r != null) { + groupRect.union(r); + } + node.restoreCanvas(canvas, count); if (node instanceof RenderableShadowNode) { @@ -98,6 +104,7 @@ class GroupShadowNode extends RenderableShadowNode { } } }); + this.setClientRect(groupRect); popGlyphContext(); } diff --git a/android/src/main/java/com/horcrux/svg/RenderableShadowNode.java b/android/src/main/java/com/horcrux/svg/RenderableShadowNode.java index 18d9fa1b..9704eba5 100644 --- a/android/src/main/java/com/horcrux/svg/RenderableShadowNode.java +++ b/android/src/main/java/com/horcrux/svg/RenderableShadowNode.java @@ -11,6 +11,7 @@ package com.horcrux.svg; import android.graphics.Canvas; import android.graphics.DashPathEffect; +import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Path; import android.graphics.RectF; @@ -20,7 +21,10 @@ import com.facebook.react.bridge.Arguments; import com.facebook.react.bridge.JSApplicationIllegalArgumentException; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.bridge.WritableArray; +import com.facebook.react.uimanager.OnLayoutEvent; +import com.facebook.react.uimanager.UIManagerModule; import com.facebook.react.uimanager.annotations.ReactProp; +import com.facebook.react.uimanager.events.EventDispatcher; import java.lang.reflect.Field; import java.util.ArrayList; @@ -204,6 +208,13 @@ abstract public class RenderableShadowNode extends VirtualNode { mPath.setFillType(mFillRule); } + RectF clientRect = new RectF(); + mPath.computeBounds(clientRect, true); + Matrix svgToViewMatrix = new Matrix(canvas.getMatrix()); + svgToViewMatrix.preConcat(this.getSvgShadowNode().getInvInitialCTM()); + svgToViewMatrix.mapRect(clientRect); + this.setClientRect(clientRect); + clip(canvas, paint); if (setupFillPaint(paint, opacity * mFillOpacity)) { diff --git a/android/src/main/java/com/horcrux/svg/SvgViewShadowNode.java b/android/src/main/java/com/horcrux/svg/SvgViewShadowNode.java index 4abce499..6843d7b3 100644 --- a/android/src/main/java/com/horcrux/svg/SvgViewShadowNode.java +++ b/android/src/main/java/com/horcrux/svg/SvgViewShadowNode.java @@ -28,6 +28,7 @@ import com.facebook.react.uimanager.annotations.ReactProp; import java.io.ByteArrayOutputStream; import java.util.HashMap; import java.util.Map; +import java.util.Stack; /** * Shadow node for RNSVG virtual tree root - RNSVGSvgView @@ -51,6 +52,9 @@ public class SvgViewShadowNode extends LayoutShadowNode { private int mMeetOrSlice; private Matrix mInvViewBoxMatrix = new Matrix(); private boolean mInvertible = true; + private Matrix initialCTM; + private Matrix invInitialCTM; + public SvgViewShadowNode() { mScale = DisplayMetricsHolder.getScreenDisplayMetrics().density; @@ -147,6 +151,9 @@ public class SvgViewShadowNode extends LayoutShadowNode { void drawChildren(final Canvas canvas) { mCanvas = canvas; + this.initialCTM = canvas.getMatrix(); + this.invInitialCTM = new Matrix(); + this.initialCTM.invert(this.invInitialCTM); if (mAlign != null) { RectF vbRect = getViewBox(); float width = getLayoutWidth(); @@ -277,4 +284,12 @@ public class SvgViewShadowNode extends LayoutShadowNode { runner.run(child); } } + + public Matrix getInitialCTM() { + return this.initialCTM; + } + + public Matrix getInvInitialCTM() { + return this.invInitialCTM; + } } diff --git a/android/src/main/java/com/horcrux/svg/UseShadowNode.java b/android/src/main/java/com/horcrux/svg/UseShadowNode.java index 1c5592ec..8363f511 100644 --- a/android/src/main/java/com/horcrux/svg/UseShadowNode.java +++ b/android/src/main/java/com/horcrux/svg/UseShadowNode.java @@ -63,6 +63,8 @@ class UseShadowNode extends RenderableShadowNode { template.draw(canvas, paint, opacity * mOpacity); } + this.setClientRect(template.getClientRect()); + template.restoreCanvas(canvas, count); if (template instanceof RenderableShadowNode) { ((RenderableShadowNode)template).resetProperties(); diff --git a/android/src/main/java/com/horcrux/svg/VirtualNode.java b/android/src/main/java/com/horcrux/svg/VirtualNode.java index 2a19674e..0f1244e2 100644 --- a/android/src/main/java/com/horcrux/svg/VirtualNode.java +++ b/android/src/main/java/com/horcrux/svg/VirtualNode.java @@ -21,8 +21,11 @@ import com.facebook.react.bridge.ReadableArray; import com.facebook.react.common.ReactConstants; import com.facebook.react.uimanager.DisplayMetricsHolder; import com.facebook.react.uimanager.LayoutShadowNode; +import com.facebook.react.uimanager.OnLayoutEvent; import com.facebook.react.uimanager.ReactShadowNode; +import com.facebook.react.uimanager.UIManagerModule; import com.facebook.react.uimanager.annotations.ReactProp; +import com.facebook.react.uimanager.events.EventDispatcher; import javax.annotation.Nullable; @@ -47,6 +50,7 @@ abstract class VirtualNode extends LayoutShadowNode { Matrix mMatrix = new Matrix(); Matrix mInvMatrix = new Matrix(); boolean mInvertible = true; + RectF mClientRect; private int mClipRule; private @Nullable String mClipPath; @@ -345,4 +349,29 @@ abstract class VirtualNode extends LayoutShadowNode { runner.run(child); } } + + void setClientRect(RectF rect) { + if (mClientRect != null && mClientRect.equals(rect)) { + return; + } + mClientRect = rect; + if (mClientRect == null) { + return; + } + EventDispatcher eventDispatcher = this.getThemedContext() + .getNativeModule(UIManagerModule.class) + .getEventDispatcher(); + eventDispatcher.dispatchEvent(OnLayoutEvent.obtain( + this.getReactTag(), + (int) mClientRect.left, + (int) mClientRect.top, + (int) mClientRect.width(), + (int) mClientRect.height() + )); + } + + public RectF getClientRect() { + return mClientRect; + } + }