Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix null safety in views/text/frescosupport #48612

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@
import android.content.res.Resources;
import android.net.Uri;
import androidx.annotation.Nullable;
import androidx.core.util.Preconditions;
import com.facebook.common.logging.FLog;
import com.facebook.common.util.UriUtil;
import com.facebook.drawee.controller.AbstractDraweeControllerBuilder;
import com.facebook.infer.annotation.Nullsafe;
import com.facebook.react.bridge.Dynamic;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
Expand All @@ -27,10 +29,11 @@
import java.util.Locale;

/** Shadow node that represents an inline image. Loading is done using Fresco. */
@Nullsafe(Nullsafe.Mode.LOCAL)
class FrescoBasedReactTextInlineImageShadowNode extends ReactTextInlineImageShadowNode {

private @Nullable Uri mUri;
private ReadableMap mHeaders;
private @Nullable ReadableMap mHeaders;
private final AbstractDraweeControllerBuilder mDraweeControllerBuilder;
private final @Nullable Object mCallerContext;
private float mWidth = YogaConstants.UNDEFINED;
Expand All @@ -46,8 +49,10 @@ public FrescoBasedReactTextInlineImageShadowNode(

@ReactProp(name = "src")
public void setSource(@Nullable ReadableArray sources) {
final String source =
(sources == null || sources.size() == 0) ? null : sources.getMap(0).getString("uri");
final @Nullable String source =
(sources == null || sources.size() == 0 || sources.getType(0) != ReadableType.Map)
? null
: Preconditions.checkNotNull(sources.getMap(0)).getString("uri");
Uri uri = null;
if (source != null) {
try {
Expand All @@ -70,7 +75,7 @@ public void setSource(@Nullable ReadableArray sources) {
}

@ReactProp(name = "headers")
public void setHeaders(ReadableMap headers) {
public void setHeaders(@Nullable ReadableMap headers) {
mHeaders = headers;
}

Expand Down Expand Up @@ -109,7 +114,7 @@ public void setResizeMode(@Nullable String resizeMode) {
return mUri;
}

public ReadableMap getHeaders() {
public @Nullable ReadableMap getHeaders() {
return mHeaders;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,15 @@
import android.net.Uri;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.core.util.Preconditions;
import com.facebook.drawee.controller.AbstractDraweeControllerBuilder;
import com.facebook.drawee.drawable.ScalingUtils;
import com.facebook.drawee.generic.GenericDraweeHierarchy;
import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder;
import com.facebook.drawee.interfaces.DraweeController;
import com.facebook.drawee.view.DraweeHolder;
import com.facebook.imagepipeline.request.ImageRequest;
import com.facebook.imagepipeline.request.ImageRequestBuilder;
import com.facebook.infer.annotation.Nullsafe;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.modules.fresco.ReactNetworkImageRequest;
import com.facebook.react.uimanager.PixelUtil;
Expand All @@ -40,6 +41,7 @@
* <p>Note: It borrows code from DynamicDrawableSpan and if that code updates how it computes size
* or draws, we need to update this as well.
*/
@Nullsafe(Nullsafe.Mode.LOCAL)
class FrescoBasedReactTextInlineImageSpan extends TextInlineImageSpan {

private @Nullable Drawable mDrawable;
Expand All @@ -51,8 +53,8 @@ class FrescoBasedReactTextInlineImageSpan extends TextInlineImageSpan {
private int mTintColor;
private Uri mUri;
private int mWidth;
private ReadableMap mHeaders;
private String mResizeMode;
private @Nullable ReadableMap mHeaders;
private @Nullable String mResizeMode;

private @Nullable TextView mTextView;

Expand All @@ -62,10 +64,10 @@ public FrescoBasedReactTextInlineImageSpan(
int width,
int tintColor,
@Nullable Uri uri,
ReadableMap headers,
@Nullable ReadableMap headers,
AbstractDraweeControllerBuilder draweeControllerBuilder,
@Nullable Object callerContext,
String resizeMode) {
@Nullable String resizeMode) {
mDraweeHolder = new DraweeHolder(GenericDraweeHierarchyBuilder.newInstance(resources).build());
mDraweeControllerBuilder = draweeControllerBuilder;
mCallerContext = callerContext;
Expand Down Expand Up @@ -116,7 +118,7 @@ public int getSize(Paint paint, CharSequence text, int start, int end, Paint.Fon
return mWidth;
}

public void setTextView(TextView textView) {
public void setTextView(@Nullable TextView textView) {
mTextView = textView;
}

Expand All @@ -135,18 +137,20 @@ public void draw(
ImageRequestBuilder imageRequestBuilder = ImageRequestBuilder.newBuilderWithSource(mUri);
ImageRequest imageRequest =
ReactNetworkImageRequest.fromBuilderWithHeaders(imageRequestBuilder, mHeaders);
mDraweeHolder.getHierarchy().setActualImageScaleType(getResizeMode(mResizeMode));
DraweeController draweeController =
mDraweeControllerBuilder
.reset()
.setOldController(mDraweeHolder.getController())
.setCallerContext(mCallerContext)
.setImageRequest(imageRequest)
.build();
mDraweeHolder
.getHierarchy()
.setActualImageScaleType(ImageResizeMode.toScaleType(mResizeMode));
mDraweeControllerBuilder.reset();
mDraweeControllerBuilder.setOldController(mDraweeHolder.getController());
if (mCallerContext != null) {
mDraweeControllerBuilder.setCallerContext(mCallerContext);
}
mDraweeControllerBuilder.setImageRequest(imageRequest);
DraweeController draweeController = mDraweeControllerBuilder.build();
mDraweeHolder.setController(draweeController);
mDraweeControllerBuilder.reset();

mDrawable = mDraweeHolder.getTopLevelDrawable();
mDrawable = Preconditions.checkNotNull(mDraweeHolder.getTopLevelDrawable());
mDrawable.setBounds(0, 0, mWidth, mHeight);
if (mTintColor != 0) {
mDrawable.setColorFilter(mTintColor, PorterDuff.Mode.SRC_IN);
Expand All @@ -168,10 +172,6 @@ public void draw(
canvas.restore();
}

private ScalingUtils.ScaleType getResizeMode(String resizeMode) {
return ImageResizeMode.toScaleType(resizeMode);
}

@Override
public int getWidth() {
return mWidth;
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

package com.facebook.react.views.text.internal

import com.facebook.react.uimanager.LayoutShadowNode
import com.facebook.react.views.text.internal.span.TextInlineImageSpan
import com.facebook.yoga.YogaNode

/** Base class for [YogaNode]s that represent inline images. */
internal abstract class ReactTextInlineImageShadowNode : LayoutShadowNode() {
/**
* Build a [TextInlineImageSpan] from this node. This will be added to the TextView in place of
* this node.
*/
public abstract fun buildInlineImageSpan(): TextInlineImageSpan
}
Loading