diff --git a/ReactAndroid/src/main/java/com/facebook/react/flat/DrawImageWithDrawee.java b/ReactAndroid/src/main/java/com/facebook/react/flat/DrawImageWithDrawee.java index cfb2f00c8b8..47a88b666df 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/flat/DrawImageWithDrawee.java +++ b/ReactAndroid/src/main/java/com/facebook/react/flat/DrawImageWithDrawee.java @@ -11,8 +11,8 @@ package com.facebook.react.flat; import javax.annotation.Nullable; -import java.util.HashMap; -import java.util.Map; +import java.util.LinkedList; +import java.util.List; import android.content.Context; import android.graphics.Canvas; @@ -31,6 +31,9 @@ import com.facebook.react.bridge.ReadableMap; import com.facebook.react.views.image.ImageLoadEvent; import com.facebook.react.views.image.ImageResizeMode; import com.facebook.react.views.image.ReactImageView; +import com.facebook.react.views.imagehelper.ImageSource; +import com.facebook.react.views.imagehelper.MultiSourceHelper; +import com.facebook.react.views.imagehelper.MultiSourceHelper.MultiSourceResult; /** * DrawImageWithDrawee is DrawCommand that can draw a local or remote image. @@ -39,7 +42,7 @@ import com.facebook.react.views.image.ReactImageView; /* package */ final class DrawImageWithDrawee extends AbstractDrawCommand implements DrawImage, ControllerListener { - private @Nullable Map mSources; + private final List mSources = new LinkedList<>(); private @Nullable Context mContext; private @Nullable DraweeRequestHelper mRequestHelper; private @Nullable PorterDuffColorFilter mColorFilter; @@ -53,25 +56,25 @@ import com.facebook.react.views.image.ReactImageView; @Override public boolean hasImageRequest() { - return mSources != null && !mSources.isEmpty(); + return !mSources.isEmpty(); } @Override public void setSource(Context context, @Nullable ReadableArray sources) { - if (mSources == null) { - mSources = new HashMap<>(); - } mSources.clear(); if (sources != null && sources.size() != 0) { // Optimize for the case where we have just one uri, case in which we don't need the sizes if (sources.size() == 1) { - mSources.put(sources.getMap(0).getString("uri"), 0.0d); + ReadableMap source = sources.getMap(0); + mSources.add(new ImageSource(context, source.getString("uri"))); } else { for (int idx = 0; idx < sources.size(); idx++) { ReadableMap source = sources.getMap(idx); - mSources.put( + mSources.add(new ImageSource( + context, source.getString("uri"), - source.getDouble("width") * source.getDouble("height")); + source.getDouble("width"), + source.getDouble("height"))); } } } @@ -227,39 +230,30 @@ import com.facebook.react.views.image.ReactImageView; } private void computeRequestHelper() { - String[] imageSources = getImageSources(); - if (imageSources == null) { + MultiSourceResult multiSource = MultiSourceHelper.getBestSourceForSize( + Math.round(getRight() - getLeft()), + Math.round(getBottom() - getTop()), + mSources); + ImageSource source = multiSource.getBestResult(); + ImageSource cachedSource = multiSource.getBestResultInCache(); + if (source == null) { mRequestHelper = null; return; } - ImageRequest imageRequest = - ImageRequestHelper.createImageRequest(Assertions.assertNotNull(mContext), imageSources[0]); + ImageRequest imageRequest = ImageRequestHelper.createImageRequest( + Assertions.assertNotNull(mContext), + source.getSource()); ImageRequest cachedImageRequest = null; - if (imageSources.length >= 2 && imageSources[1] != null) { + if (cachedSource != null) { cachedImageRequest = ImageRequestHelper.createImageRequest( Assertions.assumeNotNull(mContext), - imageSources[1]); + cachedSource.getSource()); } mRequestHelper = new DraweeRequestHelper(Assertions.assertNotNull(imageRequest), cachedImageRequest, this); } - private @Nullable String[] getImageSources() { - if (mSources == null || mSources.isEmpty()) { - return null; - } - if (hasMultipleSources()) { - final double targetImageSize = (getRight() - getLeft()) * (getBottom() - getTop()); - return MultiSourceImageHelper.getImageSourceFromMultipleSources(targetImageSize, mSources); - } - return new String[]{mSources.keySet().iterator().next()}; - } - - private boolean hasMultipleSources() { - return Assertions.assertNotNull(mSources).size() > 1; - } - private boolean shouldDisplayBorder() { return mBorderColor != 0 || mBorderRadius >= 0.5f; } diff --git a/ReactAndroid/src/main/java/com/facebook/react/flat/DrawImageWithPipeline.java b/ReactAndroid/src/main/java/com/facebook/react/flat/DrawImageWithPipeline.java index 275bb5a2cfd..aae8c6e30ea 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/flat/DrawImageWithPipeline.java +++ b/ReactAndroid/src/main/java/com/facebook/react/flat/DrawImageWithPipeline.java @@ -11,8 +11,8 @@ package com.facebook.react.flat; import javax.annotation.Nullable; -import java.util.HashMap; -import java.util.Map; +import java.util.LinkedList; +import java.util.List; import android.content.Context; import android.graphics.Bitmap; @@ -32,6 +32,9 @@ import com.facebook.react.bridge.ReadableArray; import com.facebook.react.bridge.ReadableMap; import com.facebook.react.views.image.ImageResizeMode; import com.facebook.react.views.image.ReactImageView; +import com.facebook.react.views.imagehelper.ImageSource; +import com.facebook.react.views.imagehelper.MultiSourceHelper; +import com.facebook.react.views.imagehelper.MultiSourceHelper.MultiSourceResult; /** * DrawImageWithPipeline is DrawCommand that can draw a local or remote image. @@ -43,7 +46,7 @@ import com.facebook.react.views.image.ReactImageView; 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 @Nullable Map mSources; + private final List mSources = new LinkedList<>(); private @Nullable Context mContext; private final Matrix mTransform = new Matrix(); private ScaleType mScaleType = ImageResizeMode.defaultValue(); @@ -62,25 +65,25 @@ import com.facebook.react.views.image.ReactImageView; @Override public boolean hasImageRequest() { - return mSources != null && !mSources.isEmpty(); + return !mSources.isEmpty(); } @Override public void setSource(Context context, @Nullable ReadableArray sources) { - if (mSources == null) { - mSources = new HashMap<>(); - } mSources.clear(); if (sources != null && sources.size() != 0) { // Optimize for the case where we have just one uri, case in which we don't need the sizes if (sources.size() == 1) { - mSources.put(sources.getMap(0).getString("uri"), 0.0d); + ReadableMap source = sources.getMap(0); + mSources.add(new ImageSource(context, source.getString("uri"))); } else { for (int idx = 0; idx < sources.size(); idx++) { ReadableMap source = sources.getMap(idx); - mSources.put( + mSources.add(new ImageSource( + context, source.getString("uri"), - source.getDouble("width") * source.getDouble("height")); + source.getDouble("width"), + source.getDouble("height"))); } } } @@ -225,32 +228,23 @@ import com.facebook.react.views.image.ReactImageView; } private void computeRequestHelper() { - String[] imageSources = getImageSources(); - if (imageSources == null) { + MultiSourceResult multiSource = MultiSourceHelper.getBestSourceForSize( + Math.round(getRight() - getLeft()), + Math.round(getBottom() - getTop()), + mSources); + ImageSource source = multiSource.getBestResult(); + if (source == null) { mRequestHelper = null; return; } - ImageRequest imageRequest = - ImageRequestHelper.createImageRequest(Assertions.assertNotNull(mContext), imageSources[0]); + ImageRequest imageRequest = ImageRequestHelper.createImageRequest( + Assertions.assertNotNull(mContext), + source.getSource()); + // DrawImageWithPipeline does now support displaying low res cache images before request mRequestHelper = new PipelineRequestHelper(Assertions.assertNotNull(imageRequest)); } - private @Nullable String[] getImageSources() { - if (mSources == null || mSources.isEmpty()) { - return null; - } - if (hasMultipleSources()) { - final double targetImageSize = (getRight() - getLeft()) * (getBottom() - getTop()); - return MultiSourceImageHelper.getImageSourceFromMultipleSources(targetImageSize, mSources); - } - return new String[]{mSources.keySet().iterator().next()}; - } - - private boolean hasMultipleSources() { - return Assertions.assertNotNull(mSources).size() > 1; - } - /* package */ void updateBounds(Bitmap bitmap) { Assertions.assumeNotNull(mCallback).invalidate(); diff --git a/ReactAndroid/src/main/java/com/facebook/react/flat/MultiSourceImageHelper.java b/ReactAndroid/src/main/java/com/facebook/react/flat/MultiSourceImageHelper.java deleted file mode 100644 index dca80864623..00000000000 --- a/ReactAndroid/src/main/java/com/facebook/react/flat/MultiSourceImageHelper.java +++ /dev/null @@ -1,61 +0,0 @@ -/** - * 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 java.util.Map; - -import android.net.Uri; - -import com.facebook.imagepipeline.core.ImagePipeline; -import com.facebook.imagepipeline.core.ImagePipelineFactory; - -/** - * Helper class for computing the source to be used for an Image. - */ -/* package */ class MultiSourceImageHelper { - - /** - * Chooses the image source with the size closest to the target image size. Must be called only - * after the layout pass when the sizes of the target image have been computed, and when there - * are at least two sources to choose from. - */ - public static @Nullable String[] getImageSourceFromMultipleSources( - double targetImageSize, - Map sources) { - ImagePipeline imagePipeline = ImagePipelineFactory.getInstance().getImagePipeline(); - double bestPrecision = Double.MAX_VALUE; - double bestCachePrecision = Double.MAX_VALUE; - String imageSource = null; - String cachedImageSource = null; - for (Map.Entry source : sources.entrySet()) { - final double precision = Math.abs(1.0 - (source.getValue()) / targetImageSize); - if (precision < bestPrecision) { - bestPrecision = precision; - imageSource = source.getKey(); - } - - Uri sourceUri = Uri.parse(source.getKey()); - if (precision < bestCachePrecision && - (imagePipeline.isInBitmapMemoryCache(sourceUri) || - imagePipeline.isInDiskCacheSync(sourceUri))) { - bestCachePrecision = precision; - cachedImageSource = source.getKey(); - } - } - - // don't use cached image source if it's the same as the image source - if (cachedImageSource != null && cachedImageSource.equals(imageSource)) { - cachedImageSource = null; - } - return new String[]{imageSource, cachedImageSource}; - } -}