/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
package com.facebook.react.views.art;
import javax.annotation.Nullable;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.uimanager.DisplayMetricsHolder;
import com.facebook.react.uimanager.annotations.ReactProp;
import com.facebook.react.uimanager.ReactShadowNode;
/**
* Base class for ARTView virtual nodes: {@link ARTGroupShadowNode}, {@link ARTShapeShadowNode} and
* indirectly for {@link ARTTextShadowNode}.
*/
public abstract class ARTVirtualNode extends ReactShadowNode {
protected static final float MIN_OPACITY_FOR_DRAW = 0.01f;
private static final float[] sMatrixData = new float[9];
private static final float[] sRawMatrix = new float[9];
protected float mOpacity = 1f;
private @Nullable Matrix mMatrix = new Matrix();
protected final float mScale;
public ARTVirtualNode() {
mScale = DisplayMetricsHolder.getWindowDisplayMetrics().density;
}
@Override
public boolean isVirtual() {
return true;
}
public abstract void draw(Canvas canvas, Paint paint, float opacity);
/**
* Sets up the transform matrix on the canvas before an element is drawn.
*
* NB: for perf reasons this does not apply opacity, as that would mean creating a new canvas
* layer (which allocates an offscreen bitmap) and having it composited afterwards. Instead, the
* drawing code should apply opacity recursively.
*
* @param canvas the canvas to set up
*/
protected final void saveAndSetupCanvas(Canvas canvas) {
canvas.save();
if (mMatrix != null) {
canvas.concat(mMatrix);
}
}
/**
* Restore the canvas after an element was drawn. This is always called in mirror with
* {@link #saveAndSetupCanvas}.
*
* @param canvas the canvas to restore
*/
protected void restoreCanvas(Canvas canvas) {
canvas.restore();
}
@ReactProp(name = "opacity", defaultFloat = 1f)
public void setOpacity(float opacity) {
mOpacity = opacity;
markUpdated();
}
@ReactProp(name = "transform")
public void setTransform(@Nullable ReadableArray transformArray) {
if (transformArray != null) {
int matrixSize = PropHelper.toFloatArray(transformArray, sMatrixData);
if (matrixSize == 6) {
setupMatrix();
} else if (matrixSize != -1) {
throw new JSApplicationIllegalArgumentException("Transform matrices must be of size 6");
}
} else {
mMatrix = null;
}
markUpdated();
}
protected void setupMatrix() {
sRawMatrix[0] = sMatrixData[0];
sRawMatrix[1] = sMatrixData[2];
sRawMatrix[2] = sMatrixData[4] * mScale;
sRawMatrix[3] = sMatrixData[1];
sRawMatrix[4] = sMatrixData[3];
sRawMatrix[5] = sMatrixData[5] * mScale;
sRawMatrix[6] = 0;
sRawMatrix[7] = 0;
sRawMatrix[8] = 1;
if (mMatrix == null) {
mMatrix = new Matrix();
}
mMatrix.setValues(sRawMatrix);
}
}