Files
react-native/ReactAndroid/src/main/java/com/facebook/react/flat/DrawImageWithPipeline.java
Denis Koroskin 7db444c9ae Pass FlatViewGroup to DrawCommand.draw()
Summary: @public To render `View`s inside `FlatViewGroup`, we need to pass the parent to `DrawCommand.draw()` method. Used in a followup diff.

Reviewed By: sriramramani

Differential Revision: D2564478
2016-12-19 13:40:16 -08:00

202 lines
5.6 KiB
Java

/**
* 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.flat;
import javax.annotation.Nullable;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.Shader;
import com.facebook.drawee.drawable.ScalingUtils.ScaleType;
import com.facebook.imagepipeline.request.ImageRequest;
import com.facebook.infer.annotation.Assertions;
import com.facebook.react.views.image.ImageResizeMode;
/**
* DrawImageWithPipeline is DrawCommand that can draw a local or remote image.
* It uses BitmapRequestHelper internally to fetch and cache the images.
*/
/* package */ final class DrawImageWithPipeline extends AbstractDrawBorder implements DrawImage {
private static final Paint PAINT = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
private static final int BORDER_BITMAP_PATH_DIRTY = 1 << 1;
private final Matrix mTransform = new Matrix();
private ScaleType mScaleType = ImageResizeMode.defaultValue();
private @Nullable BitmapRequestHelper mBitmapRequestHelper;
private @Nullable PorterDuffColorFilter mColorFilter;
private @Nullable FlatViewGroup.InvalidateCallback mCallback;
private @Nullable Path mPathForRoundedBitmap;
private @Nullable BitmapShader mBitmapShader;
private boolean mForceClip;
@Override
public boolean hasImageRequest() {
return mBitmapRequestHelper != null;
}
@Override
public void setImageRequest(@Nullable ImageRequest imageRequest) {
mBitmapShader = null;
if (imageRequest == null) {
mBitmapRequestHelper = null;
} else {
mBitmapRequestHelper = new BitmapRequestHelper(imageRequest, this);
}
}
@Override
public void setTintColor(int tintColor) {
if (tintColor == 0) {
mColorFilter = null;
} else {
mColorFilter = new PorterDuffColorFilter(tintColor, PorterDuff.Mode.SRC_ATOP);
}
}
@Override
public void setScaleType(ScaleType scaleType) {
mScaleType = scaleType;
}
@Override
public ScaleType getScaleType() {
return mScaleType;
}
@Override
public void draw(FlatViewGroup parent, Canvas canvas) {
Bitmap bitmap = Assertions.assumeNotNull(mBitmapRequestHelper).getBitmap();
if (bitmap == null) {
return;
}
PAINT.setColorFilter(mColorFilter);
if (mForceClip) {
canvas.save();
canvas.clipRect(getLeft(), getTop(), getRight(), getBottom());
}
if (getBorderRadius() < 0.5f) {
canvas.drawBitmap(bitmap, mTransform, PAINT);
} else {
if (mBitmapShader == null) {
mBitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
mBitmapShader.setLocalMatrix(mTransform);
}
PAINT.setShader(mBitmapShader);
canvas.drawPath(getPathForRoundedBitmap(), PAINT);
}
drawBorders(canvas);
if (mForceClip) {
canvas.restore();
}
}
@Override
public void setBorderRadius(float borderRadius) {
super.setBorderRadius(borderRadius);
setFlag(BORDER_BITMAP_PATH_DIRTY);
}
@Override
public void onAttached(FlatViewGroup.InvalidateCallback callback) {
mCallback = callback;
Assertions.assumeNotNull(mBitmapRequestHelper).attach();
}
@Override
public void onDetached() {
Assertions.assumeNotNull(mBitmapRequestHelper).detach();
if (mBitmapRequestHelper.isDetached()) {
// Make sure we don't hold on to the Bitmap.
mBitmapShader = null;
}
}
@Override
protected void onBoundsChanged() {
super.onBoundsChanged();
setFlag(BORDER_BITMAP_PATH_DIRTY);
}
/* package */ void updateBounds(Bitmap bitmap) {
Assertions.assumeNotNull(mCallback).invalidate();
float left = getLeft();
float top = getTop();
float containerWidth = getRight() - left;
float containerHeight = getBottom() - top;
float imageWidth = (float) bitmap.getWidth();
float imageHeight = (float) bitmap.getHeight();
mForceClip = false;
if (mScaleType == ScaleType.FIT_XY) {
mTransform.setScale(containerWidth / imageWidth, containerHeight / imageHeight);
mTransform.postTranslate(left, top);
return;
}
final float scale;
if (mScaleType == ScaleType.CENTER_INSIDE) {
final float ratio;
if (containerWidth >= imageWidth && containerHeight >= imageHeight) {
scale = 1.0f;
} else {
scale = Math.min(containerWidth / imageWidth, containerHeight / imageHeight);
}
} else {
scale = Math.max(containerWidth / imageWidth, containerHeight / imageHeight);
}
float paddingLeft = (containerWidth - imageWidth * scale) / 2;
float paddingTop = (containerHeight - imageHeight * scale) / 2;
mForceClip = paddingLeft < 0 || paddingTop < 0;
mTransform.setScale(scale, scale);
mTransform.postTranslate(left + paddingLeft, top + paddingTop);
if (mBitmapShader != null) {
mBitmapShader.setLocalMatrix(mTransform);
}
}
private Path getPathForRoundedBitmap() {
if (isFlagSet(BORDER_BITMAP_PATH_DIRTY)) {
if (mPathForRoundedBitmap == null) {
mPathForRoundedBitmap = new Path();
}
updatePath(mPathForRoundedBitmap, 1.0f);
resetFlag(BORDER_BITMAP_PATH_DIRTY);
}
return mPathForRoundedBitmap;
}
}