/** * 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.Canvas; import android.graphics.Paint; import android.graphics.RectF; import android.text.style.ReplacementSpan; import com.facebook.imagepipeline.request.ImageRequest; import com.facebook.infer.annotation.Assertions; /* package */ final class InlineImageSpanWithPipeline extends ReplacementSpan implements AttachDetachListener, BitmapUpdateListener { private static final RectF TMP_RECT = new RectF(); private @Nullable PipelineRequestHelper mRequestHelper; private @Nullable FlatViewGroup.InvalidateCallback mCallback; private float mWidth; private float mHeight; private boolean mFrozen; /* package */ InlineImageSpanWithPipeline() { this(null, Float.NaN, Float.NaN); } private InlineImageSpanWithPipeline( @Nullable PipelineRequestHelper requestHelper, float width, float height) { mRequestHelper = requestHelper; mWidth = width; mHeight = height; } /* package */ InlineImageSpanWithPipeline mutableCopy() { return new InlineImageSpanWithPipeline(mRequestHelper, mWidth, mHeight); } /* package */ boolean hasImageRequest() { return mRequestHelper != null; } /** * Assigns a new image request to the DrawImage, or null to clear the image request. */ /* package */ void setImageRequest(@Nullable ImageRequest imageRequest) { if (imageRequest == null) { mRequestHelper = null; } else { mRequestHelper = new PipelineRequestHelper(imageRequest); } } /* package */ float getWidth() { return mWidth; } /* package */ void setWidth(float width) { mWidth = width; } /* package */ float getHeight() { return mHeight; } /* package */ void setHeight(float height) { mHeight = height; } /* package */ void freeze() { mFrozen = true; } /* package */ boolean isFrozen() { return mFrozen; } @Override public void onSecondaryAttach(Bitmap bitmap) { // We don't know if width or height changed, so invalidate just in case. Assertions.assumeNotNull(mCallback).invalidate(); } @Override public void onBitmapReady(Bitmap bitmap) { // Bitmap is now ready, draw it. Assertions.assumeNotNull(mCallback).invalidate(); } @Override public void onImageLoadEvent(int imageLoadEvent) { // ignore } @Override public void onAttached(FlatViewGroup.InvalidateCallback callback) { mCallback = callback; if (mRequestHelper != null) { mRequestHelper.attach(this); } } @Override public void onDetached() { if (mRequestHelper != null) { mRequestHelper.detach(); if (mRequestHelper.isDetached()) { // optional mCallback = null; } } } @Override public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) { if (fm != null) { fm.ascent = -Math.round(mHeight); fm.descent = 0; fm.top = fm.ascent; fm.bottom = 0; } return Math.round(mWidth); } @Override public void draw( Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint) { if (mRequestHelper == null) { return; } Bitmap bitmap = mRequestHelper.getBitmap(); if (bitmap == null) { return; } float bottomFloat = (float) bottom - paint.getFontMetricsInt().descent; TMP_RECT.set(x, bottomFloat - mHeight, x + mWidth, bottomFloat); canvas.drawBitmap(bitmap, null, TMP_RECT, paint); } }