Allow int32ARGBColor and use it to represent colors instead of rgbaArray

int32ARGBColor is 0xaarrggbb format to allow no processing

Optimize default fill handling
Improve gradient input validation
Simplify gradient extraction
Use a single array to represent gradient, with two numbers per stop
Reuse transform props in extractProps, short circuit identity transform.

[android] Refactor ImageView, fix mLoading
This commit is contained in:
Mikael Sand
2019-02-02 02:11:42 +02:00
parent 36cda8b706
commit 1c518c9896
12 changed files with 228 additions and 135 deletions
@@ -65,15 +65,13 @@ class Brush {
}
private static void parseGradientStops(ReadableArray value, int stopsCount, float[] stops, int[] stopsColors, float opacity) {
int startStops = value.size() - stopsCount;
for (int i = 0; i < stopsCount; i++) {
stops[i] = (float) value.getDouble(startStops + i);
stopsColors[i] = Color.argb(
(int) (value.getDouble(i * 4 + 3) * 255 * opacity),
(int) (value.getDouble(i * 4) * 255),
(int) (value.getDouble(i * 4 + 1) * 255),
(int) (value.getDouble(i * 4 + 2) * 255));
int stopIndex = i * 2;
stops[i] = (float) value.getDouble(stopIndex);
int color = value.getInt(stopIndex + 1);
int alpha = color >>> 24;
int combined = Math.round((float)alpha * opacity);
stopsColors[i] = combined << 24 | (color & 0x00ffffff);
}
}
@@ -157,7 +155,7 @@ class Brush {
return;
}
int stopsCount = mColors.size() / 5;
int stopsCount = mColors.size() / 2;
int[] stopsColors = new int[stopsCount];
float[] stops = new float[stopsCount];
parseGradientStops(mColors, stopsCount, stops, stopsColors, opacity);
@@ -23,11 +23,11 @@ import com.facebook.common.logging.FLog;
import com.facebook.common.references.CloseableReference;
import com.facebook.datasource.DataSource;
import com.facebook.drawee.backends.pipeline.Fresco;
import com.facebook.imagepipeline.core.ImagePipeline;
import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber;
import com.facebook.imagepipeline.image.CloseableBitmap;
import com.facebook.imagepipeline.image.CloseableImage;
import com.facebook.imagepipeline.request.ImageRequest;
import com.facebook.imagepipeline.request.ImageRequestBuilder;
import com.facebook.react.bridge.Dynamic;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReadableMap;
@@ -121,13 +121,15 @@ class ImageView extends RenderableView {
@Override
void draw(final Canvas canvas, final Paint paint, final float opacity) {
if (!mLoading.get()) {
final ImageSource imageSource = new ImageSource(mContext, uriString);
ImagePipeline imagePipeline = Fresco.getImagePipeline();
ImageSource imageSource = new ImageSource(mContext, uriString);
ImageRequest request = ImageRequest.fromUri(imageSource.getUri());
boolean inMemoryCache = imagePipeline.isInBitmapMemoryCache(request);
final ImageRequest request = ImageRequestBuilder.newBuilderWithSource(imageSource.getUri()).build();
if (Fresco.getImagePipeline().isInBitmapMemoryCache(request)) {
tryRender(request, canvas, paint, opacity * mOpacity);
if (inMemoryCache) {
tryRenderFromBitmapCache(imagePipeline, request, canvas, paint, opacity * mOpacity);
} else {
loadBitmap(request);
loadBitmap(imagePipeline, request);
}
}
}
@@ -139,29 +141,29 @@ class ImageView extends RenderableView {
return path;
}
private void loadBitmap(ImageRequest request) {
private void loadBitmap(final ImagePipeline imagePipeline, final ImageRequest request) {
mLoading.set(true);
final DataSource<CloseableReference<CloseableImage>> dataSource
= Fresco.getImagePipeline().fetchDecodedImage(request, mContext);
dataSource.subscribe(new BaseBitmapDataSubscriber() {
@Override
public void onNewResultImpl(Bitmap bitmap) {
mLoading.set(false);
SvgView view = getSvgView();
if (view != null) {
view.invalidate();
}
}
= imagePipeline.fetchDecodedImage(request, mContext);
BaseBitmapDataSubscriber subscriber = new BaseBitmapDataSubscriber() {
@Override
public void onNewResultImpl(Bitmap bitmap) {
mLoading.set(false);
SvgView view = getSvgView();
if (view != null) {
view.invalidate();
}
}
@Override
public void onFailureImpl(DataSource dataSource) {
// No cleanup required here.
// TODO: more details about this failure
mLoading.set(false);
FLog.w(ReactConstants.TAG, dataSource.getFailureCause(), "RNSVG: fetchDecodedImage failed!");
}
},
UiThreadImmediateExecutorService.getInstance()
);
@Override
public void onFailureImpl(DataSource dataSource) {
// No cleanup required here.
// TODO: more details about this failure
mLoading.set(false);
FLog.w(ReactConstants.TAG, dataSource.getFailureCause(), "RNSVG: fetchDecodedImage failed!");
}
};
dataSource.subscribe(subscriber, UiThreadImmediateExecutorService.getInstance());
}
@Nonnull
@@ -177,7 +179,7 @@ class ImageView extends RenderableView {
h = mImageHeight * mScale;
}
return new RectF((float)x, (float)y, (float)(x + w), (float)(y + h));
return new RectF((float) x, (float) y, (float) (x + w), (float) (y + h));
}
private void doRender(Canvas canvas, Paint paint, Bitmap bitmap, float opacity) {
@@ -212,27 +214,37 @@ class ImageView extends RenderableView {
this.setClientRect(vbRect);
}
private void tryRender(ImageRequest request, Canvas canvas, Paint paint, float opacity) {
private void tryRenderFromBitmapCache(ImagePipeline imagePipeline, ImageRequest request, Canvas canvas, Paint paint, float opacity) {
final DataSource<CloseableReference<CloseableImage>> dataSource
= Fresco.getImagePipeline().fetchImageFromBitmapCache(request, mContext);
= imagePipeline.fetchImageFromBitmapCache(request, mContext);
try {
final CloseableReference<CloseableImage> imageReference = dataSource.getResult();
if (imageReference != null) {
try {
if (imageReference.get() instanceof CloseableBitmap) {
final Bitmap bitmap = ((CloseableBitmap) imageReference.get()).getUnderlyingBitmap();
if (bitmap != null) {
doRender(canvas, paint, bitmap, opacity);
}
}
} catch (Exception e) {
throw new IllegalStateException(e);
} finally {
CloseableReference.closeSafely(imageReference);
}
if (imageReference == null) {
return;
}
try {
CloseableImage closeableImage = imageReference.get();
if (!(closeableImage instanceof CloseableBitmap)) {
return;
}
CloseableBitmap closeableBitmap = (CloseableBitmap) closeableImage;
final Bitmap bitmap = closeableBitmap.getUnderlyingBitmap();
if (bitmap == null) {
return;
}
doRender(canvas, paint, bitmap, opacity);
} catch (Exception e) {
throw new IllegalStateException(e);
} finally {
CloseableReference.closeSafely(imageReference);
}
} catch (Exception e) {
throw new IllegalStateException(e);
} finally {
@@ -403,12 +403,19 @@ abstract public class RenderableView extends VirtualView {
int colorType = colors.getInt(0);
switch (colorType) {
case 0:
// solid color
paint.setARGB(
(int) (colors.size() > 4 ? colors.getDouble(4) * opacity * 255 : opacity * 255),
(int) (colors.getDouble(1) * 255),
(int) (colors.getDouble(2) * 255),
(int) (colors.getDouble(3) * 255));
if (colors.size() == 2) {
int color = colors.getInt(1);
int alpha = color >>> 24;
int combined = Math.round((float)alpha * opacity);
paint.setColor(combined << 24 | (color & 0x00ffffff));
} else {
// solid color
paint.setARGB(
(int) (colors.size() > 4 ? colors.getDouble(4) * opacity * 255 : opacity * 255),
(int) (colors.getDouble(1) * 255),
(int) (colors.getDouble(2) * 255),
(int) (colors.getDouble(3) * 255));
}
break;
case 1: {
Brush brush = getSvgView().getDefinedBrush(colors.getString(1));