Finish Symbol refactor on Android

This commit is contained in:
Horcrux
2017-01-22 17:57:07 +08:00
parent 1b04e11ca4
commit 8cd78e830e
11 changed files with 165 additions and 120 deletions
@@ -178,7 +178,7 @@ public class ImageShadowNode extends RenderableShadowNode {
RectF vbRect = new RectF(0, 0, renderRect.width() / mScale, renderRect.height() / mScale);
RectF eRect = new RectF(getCanvasLeft(), getCanvasTop(), rectWidth / mScale + getCanvasLeft(), rectHeight / mScale + getCanvasTop());
Matrix transform = ViewBoxShadowNode.getTransform(vbRect, eRect, mAlign, mMeetOrSlice, false);
Matrix transform = ViewBox.getTransform(vbRect, eRect, mAlign, mMeetOrSlice, false);
transform.mapRect(renderRect);
Matrix translation = new Matrix();
@@ -176,8 +176,8 @@ class PropHelper {
float cx = PropHelper.fromPercentageToFloat(mPoints.getString(4), width, offsetX, scale);
float cy = PropHelper.fromPercentageToFloat(mPoints.getString(5), height, offsetY, scale) / (ry / rx);
// TODO: support focus point.
//float fx = PropHelper.fromPercentageToFloat(mPoints.getString(0), width, offsetX) * scale;
//float fy = PropHelper.fromPercentageToFloat(mPoints.getString(1), height, offsetY) * scale / (ry / rx);
//float fx = PropHelper.fromPercentageToFloat(mPoints.getString(0), width, offsetX, scale);
//float fy = PropHelper.fromPercentageToFloat(mPoints.getString(1), height, offsetY, scale) / (ry / rx);
Shader radialGradient = new RadialGradient(
cx,
cy,
@@ -35,7 +35,7 @@ public class RenderableViewManager extends ViewManager<View, LayoutShadowNode> {
/* package */ static final String CLASS_CLIP_PATH = "RNSVGClipPath";
/* package */ static final String CLASS_DEFS = "RNSVGDefs";
/* package */ static final String CLASS_USE = "RNSVGUse";
/* package */ static final String CLASS_VIEW_BOX = "RNSVGViewBox";
/* package */ static final String CLASS_SYMBOL = "RNSVGSymbol";
/* package */ static final String CLASS_LINEAR_GRADIENT = "RNSVGLinearGradient";
/* package */ static final String CLASS_RADIAL_GRADIENT = "RNSVGRadialGradient";
@@ -94,8 +94,8 @@ public class RenderableViewManager extends ViewManager<View, LayoutShadowNode> {
return new RenderableViewManager(CLASS_USE);
}
public static RenderableViewManager createViewBoxViewManager() {
return new RenderableViewManager(CLASS_VIEW_BOX);
public static RenderableViewManager createSymbolManager() {
return new RenderableViewManager(CLASS_SYMBOL);
}
public static RenderableViewManager createLinearGradientManager() {
@@ -144,8 +144,8 @@ public class RenderableViewManager extends ViewManager<View, LayoutShadowNode> {
return new DefsShadowNode();
case CLASS_USE:
return new UseShadowNode();
case CLASS_VIEW_BOX:
return new ViewBoxShadowNode();
case CLASS_SYMBOL:
return new SymbolShadowNode();
case CLASS_LINEAR_GRADIENT:
return new LinearGradientShadowNode();
case CLASS_RADIAL_GRADIENT:
@@ -184,8 +184,8 @@ public class RenderableViewManager extends ViewManager<View, LayoutShadowNode> {
return DefsShadowNode.class;
case CLASS_USE:
return UseShadowNode.class;
case CLASS_VIEW_BOX:
return ViewBoxShadowNode.class;
case CLASS_SYMBOL:
return SymbolShadowNode.class;
case CLASS_LINEAR_GRADIENT:
return LinearGradientShadowNode.class;
case CLASS_RADIAL_GRADIENT:
@@ -38,7 +38,7 @@ public class SvgPackage implements ReactPackage {
RenderableViewManager.createClipPathViewManager(),
RenderableViewManager.createDefsViewManager(),
RenderableViewManager.createUseViewManager(),
RenderableViewManager.createViewBoxViewManager(),
RenderableViewManager.createSymbolManager(),
RenderableViewManager.createLinearGradientManager(),
RenderableViewManager.createRadialGradientManager(),
new SvgViewManager());
@@ -23,6 +23,7 @@ import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.uimanager.UIManagerModule;
import com.facebook.react.uimanager.annotations.ReactProp;
import com.facebook.react.uimanager.events.RCTEventEmitter;
import com.facebook.react.uimanager.events.TouchEvent;
import com.facebook.react.uimanager.events.TouchEventCoalescingKeyHelper;
@@ -11,15 +11,20 @@ package com.horcrux.svg;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.Base64;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.util.Log;
import com.facebook.react.uimanager.DisplayMetricsHolder;
import com.facebook.react.uimanager.LayoutShadowNode;
import com.facebook.react.uimanager.UIViewOperationQueue;
import com.facebook.react.uimanager.annotations.ReactProp;
import java.io.ByteArrayOutputStream;
import java.util.HashMap;
@@ -35,6 +40,54 @@ public class SvgViewShadowNode extends LayoutShadowNode {
private final Map<String, VirtualNode> mDefinedTemplates = new HashMap<>();
private final Map<String, PropHelper.RNSVGBrush> mDefinedBrushes = new HashMap<>();
private Canvas mCanvas;
protected final float mScale;
private float mMinX;
private float mMinY;
private float mVbWidth;
private float mVbHeight;
private String mAlign;
private int mMeetOrSlice;
public SvgViewShadowNode() {
mScale = DisplayMetricsHolder.getScreenDisplayMetrics().density;
}
@ReactProp(name = "minX")
public void setMinX(float minX) {
mMinX = minX;
markUpdated();
}
@ReactProp(name = "minY")
public void setMinY(float minY) {
mMinY = minY;
markUpdated();
}
@ReactProp(name = "vbWidth")
public void setVbWidth(float vbWidth) {
mVbWidth = vbWidth;
markUpdated();
}
@ReactProp(name = "vbHeight")
public void setVbHeight(float vbHeight) {
mVbHeight = vbHeight;
markUpdated();
}
@ReactProp(name = "align")
public void setAlign(String align) {
mAlign = align;
markUpdated();
}
@ReactProp(name = "meetOrSlice")
public void setMeetOrSlice(int meetOrSlice) {
mMeetOrSlice = meetOrSlice;
markUpdated();
}
@Override
public boolean isVirtual() {
@@ -66,7 +119,6 @@ public class SvgViewShadowNode extends LayoutShadowNode {
mCanvas = new Canvas(bitmap);
drawChildren(mCanvas);
mCanvas = null;
return bitmap;
}
@@ -75,6 +127,14 @@ public class SvgViewShadowNode extends LayoutShadowNode {
}
private void drawChildren(Canvas canvas) {
if (mAlign != null) {
RectF vbRect = new RectF(mMinX * mScale, mMinY * mScale, (mMinX + mVbWidth) * mScale, (mMinY + mVbHeight) * mScale);
RectF eRect = new RectF(0, 0, getLayoutWidth(), getLayoutHeight());
Matrix viewBoxMatrix = ViewBox.getTransform(vbRect, eRect, mAlign, mMeetOrSlice, false);
canvas.concat(viewBoxMatrix);
}
Paint paint = new Paint();
for (int i = 0; i < getChildCount(); i++) {
@@ -0,0 +1,78 @@
/**
* 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.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.RectF;
import com.facebook.react.uimanager.annotations.ReactProp;
public class SymbolShadowNode extends GroupShadowNode {
private float mMinX;
private float mMinY;
private float mVbWidth;
private float mVbHeight;
private String mAlign;
private int mMeetOrSlice;
@ReactProp(name = "minX")
public void setMinX(float minX) {
mMinX = minX;
markUpdated();
}
@ReactProp(name = "minY")
public void setMinY(float minY) {
mMinY = minY;
markUpdated();
}
@ReactProp(name = "vbWidth")
public void setVbWidth(float vbWidth) {
mVbWidth = vbWidth;
markUpdated();
}
@ReactProp(name = "vbHeight")
public void setVbHeight(float vbHeight) {
mVbHeight = vbHeight;
markUpdated();
}
@ReactProp(name = "align")
public void setAlign(String align) {
mAlign = align;
markUpdated();
}
@ReactProp(name = "meetOrSlice")
public void setMeetOrSlice(int meetOrSlice) {
mMeetOrSlice = meetOrSlice;
markUpdated();
}
@Override
public void draw(Canvas canvas, Paint paint, float opacity) {
saveDefinition();
}
public void drawSymbol(Canvas canvas, Paint paint, float opacity, float width, float height) {
if (mAlign != null) {
RectF vbRect = new RectF(mMinX * mScale, mMinY * mScale, (mMinX + mVbWidth) * mScale, (mMinY + mVbHeight) * mScale);
RectF eRect = new RectF(0, 0, width, height);
Matrix viewBoxMatrix = ViewBox.getTransform(vbRect, eRect, mAlign, mMeetOrSlice, false);
canvas.concat(viewBoxMatrix);
super.draw(canvas, paint, opacity);
}
}
}
@@ -60,7 +60,14 @@ public class UseShadowNode extends RenderableShadowNode {
template.mergeProperties(this, mAttributeList, true);
int count = template.saveAndSetupCanvas(canvas);
clip(canvas, paint);
template.draw(canvas, paint, opacity * mOpacity);
if (template instanceof SymbolShadowNode) {
SymbolShadowNode symbol = (SymbolShadowNode)template;
symbol.drawSymbol(canvas, paint, opacity, relativeOnWidth(mWidth), relativeOnHeight(mHeight));
} else {
template.draw(canvas, paint, opacity * mOpacity);
}
template.restoreCanvas(canvas, count);
template.resetProperties();
} else {
@@ -9,103 +9,18 @@
package com.horcrux.svg;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.RectF;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.uimanager.annotations.ReactProp;
/**
* Shadow node for virtual ViewBox
*/
public class ViewBoxShadowNode extends GroupShadowNode {
public class ViewBox extends GroupShadowNode {
private static final int MOS_MEET = 0;
private static final int MOS_SLICE = 1;
private static final int MOS_NONE = 2;
private String mMinX;
private String mMinY;
private String mVbWidth;
private String mVbHeight;
private String mBoxWidth;
private String mBoxHeight;
private String mAlign;
private int mMeetOrSlice;
private boolean mFromSymbol = false;
@ReactProp(name = "minX")
public void setMinX(String minX) {
mMinX = minX;
markUpdated();
}
@ReactProp(name = "minY")
public void setMinY(String minY) {
mMinY = minY;
markUpdated();
}
@ReactProp(name = "vbWidth")
public void setVbWidth(String vbWidth) {
mVbWidth = vbWidth;
markUpdated();
}
@ReactProp(name = "vbHeight")
public void setVbHeight(String vbHeight) {
mVbHeight = vbHeight;
markUpdated();
}
@ReactProp(name = "width")
public void setWidth(String width) {
mBoxWidth = width;
markUpdated();
}
@ReactProp(name = "height")
public void setHeight(String height) {
mBoxHeight = height;
markUpdated();
}
@ReactProp(name = "align")
public void setAlign(String align) {
mAlign = align;
markUpdated();
}
@ReactProp(name = "meetOrSlice")
public void setMeetOrSlice(int meetOrSlice) {
mMeetOrSlice = meetOrSlice;
markUpdated();
}
@Override
protected int saveAndSetupCanvas(Canvas canvas) {
mMatrix = getTransformFromProps();
return super.saveAndSetupCanvas(canvas);
}
private Matrix getTransformFromProps() {
float vbX = relativeOnWidth(mMinX);
float vbY = relativeOnHeight(mMinY);
float vbWidth = relativeOnWidth(mVbWidth);
float vbHeight = relativeOnHeight(mVbHeight);
float eX = getCanvasLeft();
float eY = getCanvasTop();
float eWidth = mBoxWidth != null ? relativeOnWidth(mBoxWidth) : getCanvasWidth();
float eHeight = mBoxHeight != null ? relativeOnHeight(mBoxHeight) : getCanvasHeight();
return getTransform(new RectF(vbX, vbY, vbWidth + vbX, vbHeight + vbY), new RectF(eX, eY, eWidth + eX, eHeight + eY), mAlign, mMeetOrSlice, mFromSymbol);
}
static public Matrix getTransform(RectF vbRect, RectF eRect, String align, int meetOrSlice, boolean fromSymbol) {
// based on https://svgwg.org/svg2-draft/coords.html#ComputingAViewportsTransform
@@ -188,19 +103,4 @@ public class ViewBoxShadowNode extends GroupShadowNode {
transform.postScale(scaleX, scaleY);
return transform;
}
@Override
public void mergeProperties(VirtualNode target, ReadableArray mergeList, boolean inherited) {
if (target instanceof UseShadowNode) {
mFromSymbol = true;
mBoxWidth = ((UseShadowNode)target).getWidth();
mBoxHeight = ((UseShadowNode)target).getHeight();
}
}
@Override
public void resetProperties() {
mBoxWidth = mBoxHeight = null;
mFromSymbol = false;
}
}
@@ -206,12 +206,12 @@ public abstract class VirtualNode extends LayoutShadowNode {
return mSvgShadowNode;
}
protected float relativeOnWidth(String position) {
return PropHelper.fromPercentageToFloat(position, getCanvasWidth(), 0, mScale);
protected float relativeOnWidth(String length) {
return PropHelper.fromPercentageToFloat(length, getCanvasWidth(), 0, mScale);
}
protected float relativeOnHeight(String position) {
return PropHelper.fromPercentageToFloat(position, getCanvasHeight(), 0, mScale);
protected float relativeOnHeight(String length) {
return PropHelper.fromPercentageToFloat(length, getCanvasHeight(), 0, mScale);
}
protected float getCanvasWidth() {
+1 -2
View File
@@ -28,13 +28,12 @@
if (template) {
[self beginTransparencyLayer:context];
[self clip:context];
[template mergeProperties:self];
if ([template class] == [RNSVGSymbol class]) {
[template mergeProperties:self];
RNSVGSymbol *symbol = template;
[symbol renderSymbolTo:context width:[self relativeOnWidth:self.width] height:[self relativeOnWidth:self.height]];
} else {
[template mergeProperties:self];
[template renderTo:context];
}