mirror of
https://github.com/status-im/react-native.git
synced 2025-01-30 03:05:44 +00:00
Implement DrawImage using Drawee
Summary: Alternative implementation of DrawImage using DraweeHierarchy instead of ImagePipeline directly. Yields same results, but potentially more stable. We'll run tests to measure performance of both. Reviewed By: ahmedre Differential Revision: D2746197
This commit is contained in:
parent
2daf696064
commit
7075744b94
@ -0,0 +1,146 @@
|
||||
/**
|
||||
* 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.Canvas;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.PorterDuffColorFilter;
|
||||
|
||||
import com.facebook.drawee.drawable.ScalingUtils.ScaleType;
|
||||
import com.facebook.drawee.generic.GenericDraweeHierarchy;
|
||||
import com.facebook.drawee.generic.RoundingParams;
|
||||
import com.facebook.imagepipeline.request.ImageRequest;
|
||||
import com.facebook.infer.annotation.Assertions;
|
||||
import com.facebook.react.views.image.ImageResizeMode;
|
||||
|
||||
/**
|
||||
* DrawImageWithDrawee is DrawCommand that can draw a local or remote image.
|
||||
* It uses DraweeRequestHelper internally to fetch and cache the images.
|
||||
*/
|
||||
/* package */ final class DrawImageWithDrawee extends AbstractDrawCommand implements DrawImage {
|
||||
|
||||
private @Nullable DraweeRequestHelper mRequestHelper;
|
||||
private @Nullable PorterDuffColorFilter mColorFilter;
|
||||
private ScaleType mScaleType = ImageResizeMode.defaultValue();
|
||||
private float mBorderWidth;
|
||||
private float mBorderRadius;
|
||||
private int mBorderColor;
|
||||
|
||||
@Override
|
||||
public boolean hasImageRequest() {
|
||||
return mRequestHelper != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setImageRequest(@Nullable ImageRequest imageRequest) {
|
||||
if (imageRequest == null) {
|
||||
mRequestHelper = null;
|
||||
} else {
|
||||
mRequestHelper = new DraweeRequestHelper(imageRequest);
|
||||
}
|
||||
}
|
||||
|
||||
@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 setBorderWidth(float borderWidth) {
|
||||
mBorderWidth = borderWidth;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getBorderWidth() {
|
||||
return mBorderWidth;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBorderRadius(float borderRadius) {
|
||||
mBorderRadius = borderRadius;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getBorderRadius() {
|
||||
return mBorderRadius;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBorderColor(int borderColor) {
|
||||
mBorderColor = borderColor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBorderColor() {
|
||||
return mBorderColor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDraw(Canvas canvas) {
|
||||
Assertions.assumeNotNull(mRequestHelper).getDrawable().draw(canvas);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttached(FlatViewGroup.InvalidateCallback callback) {
|
||||
GenericDraweeHierarchy hierarchy = Assertions.assumeNotNull(mRequestHelper).getHierarchy();
|
||||
|
||||
RoundingParams roundingParams = hierarchy.getRoundingParams();
|
||||
if (shouldDisplayBorder()) {
|
||||
if (roundingParams == null) {
|
||||
roundingParams = new RoundingParams();
|
||||
}
|
||||
|
||||
roundingParams.setBorder(mBorderColor, mBorderWidth);
|
||||
roundingParams.setCornersRadius(mBorderRadius);
|
||||
|
||||
// changes won't take effect until we re-apply rounding params, so do it now.
|
||||
hierarchy.setRoundingParams(roundingParams);
|
||||
} else if (roundingParams != null) {
|
||||
// clear rounding params
|
||||
hierarchy.setRoundingParams(null);
|
||||
}
|
||||
|
||||
hierarchy.setActualImageScaleType(mScaleType);
|
||||
hierarchy.setActualImageColorFilter(mColorFilter);
|
||||
|
||||
hierarchy.getTopLevelDrawable().setBounds(
|
||||
Math.round(getLeft()),
|
||||
Math.round(getTop()),
|
||||
Math.round(getRight()),
|
||||
Math.round(getBottom()));
|
||||
|
||||
mRequestHelper.attach(callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetached() {
|
||||
Assertions.assumeNotNull(mRequestHelper).detach();
|
||||
}
|
||||
|
||||
private boolean shouldDisplayBorder() {
|
||||
return mBorderColor != 0 || mBorderRadius >= 0.5f;
|
||||
}
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
/**
|
||||
* 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 android.content.res.Resources;
|
||||
import android.graphics.drawable.Drawable;
|
||||
|
||||
import com.facebook.drawee.controller.AbstractDraweeControllerBuilder;
|
||||
import com.facebook.drawee.generic.GenericDraweeHierarchy;
|
||||
import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder;
|
||||
import com.facebook.drawee.interfaces.DraweeController;
|
||||
import com.facebook.drawee.interfaces.DraweeController;
|
||||
import com.facebook.imagepipeline.request.ImageRequest;
|
||||
import com.facebook.infer.annotation.Assertions;
|
||||
|
||||
/* package */ final class DraweeRequestHelper {
|
||||
|
||||
private static GenericDraweeHierarchyBuilder sHierarchyBuilder;
|
||||
private static AbstractDraweeControllerBuilder sControllerBuilder;
|
||||
|
||||
/* package */ static void setResources(Resources resources) {
|
||||
sHierarchyBuilder = new GenericDraweeHierarchyBuilder(resources);
|
||||
}
|
||||
|
||||
/* package */ static void setDraweeControllerBuilder(AbstractDraweeControllerBuilder builder) {
|
||||
sControllerBuilder = builder;
|
||||
}
|
||||
|
||||
private final DraweeController mDraweeController;
|
||||
private int mAttachCounter;
|
||||
|
||||
/* package */ DraweeRequestHelper(ImageRequest imageRequest) {
|
||||
DraweeController controller = sControllerBuilder
|
||||
.setImageRequest(imageRequest)
|
||||
.setCallerContext(RCTImageView.getCallerContext())
|
||||
.build();
|
||||
|
||||
controller.setHierarchy(sHierarchyBuilder.build());
|
||||
|
||||
mDraweeController = controller;
|
||||
}
|
||||
|
||||
/* package */ void attach(FlatViewGroup.InvalidateCallback callback) {
|
||||
++mAttachCounter;
|
||||
if (mAttachCounter == 1) {
|
||||
getDrawable().setCallback(callback.get());
|
||||
mDraweeController.onAttach();
|
||||
}
|
||||
}
|
||||
|
||||
/* package */ void detach() {
|
||||
--mAttachCounter;
|
||||
if (mAttachCounter == 0) {
|
||||
mDraweeController.onDetach();
|
||||
}
|
||||
}
|
||||
|
||||
/* package */ GenericDraweeHierarchy getHierarchy() {
|
||||
return (GenericDraweeHierarchy) Assertions.assumeNotNull(mDraweeController.getHierarchy());
|
||||
}
|
||||
|
||||
/* package */ Drawable getDrawable() {
|
||||
return getHierarchy().getTopLevelDrawable();
|
||||
}
|
||||
}
|
@ -43,13 +43,6 @@ public class FlatUIImplementation extends UIImplementation {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Temporary storage for elements that need to be moved within a parent.
|
||||
* Only used inside #manageChildren() and always empty outside of it.
|
||||
*/
|
||||
private final ArrayList<FlatShadowNode> mNodesToMove = new ArrayList<>();
|
||||
private final StateBuilder mStateBuilder;
|
||||
|
||||
public static FlatUIImplementation createInstance(
|
||||
ReactApplicationContext reactContext,
|
||||
List<ViewManager> viewManagers) {
|
||||
@ -61,6 +54,7 @@ public class FlatUIImplementation extends UIImplementation {
|
||||
RCTImageView.setCallerContext(callerContext);
|
||||
}
|
||||
}
|
||||
DraweeRequestHelper.setResources(reactContext.getResources());
|
||||
|
||||
TypefaceCache.setAssetManager(reactContext.getAssets());
|
||||
|
||||
@ -78,18 +72,38 @@ public class FlatUIImplementation extends UIImplementation {
|
||||
FlatUIViewOperationQueue operationsQueue = new FlatUIViewOperationQueue(
|
||||
reactContext,
|
||||
nativeViewHierarchyManager);
|
||||
return new FlatUIImplementation(viewManagerRegistry, operationsQueue);
|
||||
return new FlatUIImplementation(reactImageManager, viewManagerRegistry, operationsQueue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Temporary storage for elements that need to be moved within a parent.
|
||||
* Only used inside #manageChildren() and always empty outside of it.
|
||||
*/
|
||||
private final ArrayList<FlatShadowNode> mNodesToMove = new ArrayList<>();
|
||||
private final StateBuilder mStateBuilder;
|
||||
private @Nullable ReactImageManager mReactImageManager;
|
||||
|
||||
private FlatUIImplementation(
|
||||
@Nullable ReactImageManager reactImageManager,
|
||||
ViewManagerRegistry viewManagers,
|
||||
FlatUIViewOperationQueue operationsQueue) {
|
||||
super(viewManagers, operationsQueue);
|
||||
mStateBuilder = new StateBuilder(operationsQueue);
|
||||
mReactImageManager = reactImageManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ReactShadowNode createRootShadowNode() {
|
||||
if (mReactImageManager != null) {
|
||||
// This is not the best place to initialize DraweeRequestHelper, but order of module
|
||||
// initialization is undefined, and this is pretty much the earliest when we are guarantied
|
||||
// that Fresco is initalized and DraweeControllerBuilder can be queried. This also happens
|
||||
// relatively rarely to have any performance considerations.
|
||||
DraweeRequestHelper.setDraweeControllerBuilder(
|
||||
mReactImageManager.getDraweeControllerBuilder());
|
||||
mReactImageManager = null;
|
||||
}
|
||||
|
||||
return new FlatRootShadowNode();
|
||||
}
|
||||
|
||||
|
@ -154,7 +154,7 @@ import com.facebook.react.uimanager.ReactPointerEventsView;
|
||||
|
||||
@Override
|
||||
protected boolean verifyDrawable(Drawable who) {
|
||||
return who == mHotspot || super.verifyDrawable(who);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -11,6 +11,8 @@ package com.facebook.react.flat;
|
||||
|
||||
/* package */ final class RCTImageViewManager extends FlatViewManager {
|
||||
|
||||
private static final boolean USE_IMAGEPIPELINE_DIRECTLY = false;
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "RCTImageView";
|
||||
@ -18,7 +20,11 @@ package com.facebook.react.flat;
|
||||
|
||||
@Override
|
||||
public RCTImageView createShadowNodeInstance() {
|
||||
return new RCTImageView(new DrawImageWithPipeline());
|
||||
if (USE_IMAGEPIPELINE_DIRECTLY) {
|
||||
return new RCTImageView(new DrawImageWithPipeline());
|
||||
} else {
|
||||
return new RCTImageView(new DrawImageWithDrawee());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
Loading…
x
Reference in New Issue
Block a user