mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Convert the whole com.facebook.react.views.text.internal.span package to Kotlin (#43923)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/43923 Another round of Kotlin migration. This time I'm doing `com.facebook.react.views.text.internal.span` which has been recently been annotated as `Nullsafe` Changelog: [Internal] [Changed] - Convert the whole `com.facebook.react.views.text.internal.span` package to Kotlin Reviewed By: tdn120 Differential Revision: D55802155 fbshipit-source-id: 4bed023557f45a43d921df73dfc685e547788fd4
This commit is contained in:
committed by
Facebook GitHub Bot
parent
47a00f97d8
commit
98a38cc1a7
+1
-1
@@ -382,7 +382,7 @@ public abstract class ReactBaseTextShadowNode extends LayoutShadowNode
|
||||
// or images.
|
||||
for (int priorityIndex = 0; priorityIndex < ops.size(); priorityIndex++) {
|
||||
final SetSpanOperation op = ops.get(ops.size() - priorityIndex - 1);
|
||||
final ReactSpan what = op.getWhat();
|
||||
final ReactSpan what = op.what;
|
||||
|
||||
boolean isInlineImage = what instanceof TextInlineImageSpan;
|
||||
if (isInlineImage || what instanceof TextInlineViewPlaceholderSpan) {
|
||||
|
||||
-48
@@ -1,48 +0,0 @@
|
||||
/*
|
||||
* 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.span;
|
||||
|
||||
import android.text.TextPaint;
|
||||
import android.text.style.MetricAffectingSpan;
|
||||
import com.facebook.infer.annotation.Nullsafe;
|
||||
|
||||
/**
|
||||
* A {@link MetricAffectingSpan} that allows to set the letter spacing on the selected text span.
|
||||
*
|
||||
* <p>The letter spacing is specified in pixels, which are converted to ems at paint time; this span
|
||||
* must therefore be applied after any spans affecting font size.
|
||||
*/
|
||||
@Nullsafe(Nullsafe.Mode.LOCAL)
|
||||
public class CustomLetterSpacingSpan extends MetricAffectingSpan implements ReactSpan {
|
||||
|
||||
private final float mLetterSpacing;
|
||||
|
||||
public CustomLetterSpacingSpan(float letterSpacing) {
|
||||
mLetterSpacing = letterSpacing;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDrawState(TextPaint paint) {
|
||||
apply(paint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateMeasureState(TextPaint paint) {
|
||||
apply(paint);
|
||||
}
|
||||
|
||||
public float getSpacing() {
|
||||
return mLetterSpacing;
|
||||
}
|
||||
|
||||
private void apply(TextPaint paint) {
|
||||
if (!Float.isNaN(mLetterSpacing)) {
|
||||
paint.setLetterSpacing(mLetterSpacing);
|
||||
}
|
||||
}
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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.span
|
||||
|
||||
import android.text.TextPaint
|
||||
import android.text.style.MetricAffectingSpan
|
||||
|
||||
/**
|
||||
* A [MetricAffectingSpan] that allows to set the letter spacing on the selected text span.
|
||||
*
|
||||
* The letter spacing is specified in pixels, which are converted to ems at paint time; this span
|
||||
* must therefore be applied after any spans affecting font size.
|
||||
*/
|
||||
public class CustomLetterSpacingSpan(public val spacing: Float) : MetricAffectingSpan(), ReactSpan {
|
||||
public override fun updateDrawState(paint: TextPaint) {
|
||||
apply(paint)
|
||||
}
|
||||
|
||||
public override fun updateMeasureState(paint: TextPaint) {
|
||||
apply(paint)
|
||||
}
|
||||
|
||||
private fun apply(paint: TextPaint) {
|
||||
if (!spacing.isNaN()) {
|
||||
paint.letterSpacing = spacing
|
||||
}
|
||||
}
|
||||
}
|
||||
-68
@@ -1,68 +0,0 @@
|
||||
/*
|
||||
* 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.span;
|
||||
|
||||
import android.graphics.Paint;
|
||||
import android.text.style.LineHeightSpan;
|
||||
import com.facebook.infer.annotation.Nullsafe;
|
||||
|
||||
/**
|
||||
* We use a custom {@link LineHeightSpan}, because `lineSpacingExtra` is broken. Details here:
|
||||
* https://github.com/facebook/react-native/issues/7546
|
||||
*/
|
||||
@Nullsafe(Nullsafe.Mode.LOCAL)
|
||||
public class CustomLineHeightSpan implements LineHeightSpan, ReactSpan {
|
||||
private final int mHeight;
|
||||
|
||||
public CustomLineHeightSpan(float height) {
|
||||
mHeight = (int) Math.ceil(height);
|
||||
}
|
||||
|
||||
public int getLineHeight() {
|
||||
return mHeight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void chooseHeight(
|
||||
CharSequence text, int start, int end, int spanstartv, int v, Paint.FontMetricsInt fm) {
|
||||
// This is more complicated that I wanted it to be. You can find a good explanation of what the
|
||||
// FontMetrics mean here: http://stackoverflow.com/questions/27631736.
|
||||
// The general solution is that if there's not enough height to show the full line height, we
|
||||
// will prioritize in this order: descent, ascent, bottom, top
|
||||
|
||||
if (fm.descent > mHeight) {
|
||||
// Show as much descent as possible
|
||||
fm.bottom = fm.descent = Math.min(mHeight, fm.descent);
|
||||
fm.top = fm.ascent = 0;
|
||||
} else if (-fm.ascent + fm.descent > mHeight) {
|
||||
// Show all descent, and as much ascent as possible
|
||||
fm.bottom = fm.descent;
|
||||
fm.top = fm.ascent = -mHeight + fm.descent;
|
||||
} else if (-fm.ascent + fm.bottom > mHeight) {
|
||||
// Show all ascent, descent, as much bottom as possible
|
||||
fm.top = fm.ascent;
|
||||
fm.bottom = fm.ascent + mHeight;
|
||||
} else if (-fm.top + fm.bottom > mHeight) {
|
||||
// Show all ascent, descent, bottom, as much top as possible
|
||||
fm.top = fm.bottom - mHeight;
|
||||
} else {
|
||||
// Show proportionally additional ascent / top & descent / bottom
|
||||
final int additional = mHeight - (-fm.top + fm.bottom);
|
||||
|
||||
// Round up for the negative values and down for the positive values (arbitrary choice)
|
||||
// So that bottom - top equals additional even if it's an odd number.
|
||||
final int top = (int) (fm.top - Math.ceil(additional / 2.0f));
|
||||
final int bottom = (int) (fm.bottom + Math.floor(additional / 2.0f));
|
||||
|
||||
fm.top = top;
|
||||
fm.ascent = top;
|
||||
fm.descent = bottom;
|
||||
fm.bottom = bottom;
|
||||
}
|
||||
}
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* 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.span
|
||||
|
||||
import android.graphics.Paint.FontMetricsInt
|
||||
import android.text.style.LineHeightSpan
|
||||
import kotlin.math.ceil
|
||||
import kotlin.math.floor
|
||||
import kotlin.math.min
|
||||
|
||||
/**
|
||||
* We use a custom [LineHeightSpan], because `lineSpacingExtra` is broken. Details here:
|
||||
* https://github.com/facebook/react-native/issues/7546
|
||||
*/
|
||||
public class CustomLineHeightSpan(height: Float) : LineHeightSpan, ReactSpan {
|
||||
public val lineHeight: Int = ceil(height.toDouble()).toInt()
|
||||
|
||||
public override fun chooseHeight(
|
||||
text: CharSequence?,
|
||||
start: Int,
|
||||
end: Int,
|
||||
spanstartv: Int,
|
||||
v: Int,
|
||||
fm: FontMetricsInt
|
||||
) {
|
||||
// This is more complicated that I wanted it to be. You can find a good explanation of what the
|
||||
// FontMetrics mean here: http://stackoverflow.com/questions/27631736.
|
||||
// The general solution is that if there's not enough height to show the full line height, we
|
||||
// will prioritize in this order: descent, ascent, bottom, top
|
||||
|
||||
if (fm.descent > lineHeight) {
|
||||
// Show as much descent as possible
|
||||
fm.descent = min(lineHeight.toDouble(), fm.descent.toDouble()).toInt()
|
||||
fm.bottom = fm.descent
|
||||
fm.ascent = 0
|
||||
fm.top = fm.ascent
|
||||
} else if (-fm.ascent + fm.descent > lineHeight) {
|
||||
// Show all descent, and as much ascent as possible
|
||||
fm.bottom = fm.descent
|
||||
fm.ascent = -lineHeight + fm.descent
|
||||
fm.top = fm.ascent
|
||||
} else if (-fm.ascent + fm.bottom > lineHeight) {
|
||||
// Show all ascent, descent, as much bottom as possible
|
||||
fm.top = fm.ascent
|
||||
fm.bottom = fm.ascent + lineHeight
|
||||
} else if (-fm.top + fm.bottom > lineHeight) {
|
||||
// Show all ascent, descent, bottom, as much top as possible
|
||||
fm.top = fm.bottom - lineHeight
|
||||
} else {
|
||||
// Show proportionally additional ascent / top & descent / bottom
|
||||
val additional = lineHeight - (-fm.top + fm.bottom)
|
||||
|
||||
// Round up for the negative values and down for the positive values (arbitrary choice)
|
||||
// So that bottom - top equals additional even if it's an odd number.
|
||||
val top = (fm.top - ceil(additional / 2.0f)).toInt()
|
||||
val bottom = (fm.bottom + floor(additional / 2.0f)).toInt()
|
||||
|
||||
fm.top = top
|
||||
fm.ascent = top
|
||||
fm.descent = bottom
|
||||
fm.bottom = bottom
|
||||
}
|
||||
}
|
||||
}
|
||||
-93
@@ -1,93 +0,0 @@
|
||||
/*
|
||||
* 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.span;
|
||||
|
||||
import android.content.res.AssetManager;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Typeface;
|
||||
import android.text.TextPaint;
|
||||
import android.text.style.MetricAffectingSpan;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.facebook.infer.annotation.Nullsafe;
|
||||
import com.facebook.react.common.ReactConstants;
|
||||
import com.facebook.react.common.assets.ReactFontManager;
|
||||
import com.facebook.react.views.text.ReactTypefaceUtils;
|
||||
|
||||
/**
|
||||
* A {@link MetricAffectingSpan} that allows to change the style of the displayed font.
|
||||
* CustomStyleSpan will try to load the fontFamily with the right style and weight from the assets.
|
||||
* The custom fonts will have to be located in the res/assets folder of the application. The
|
||||
* supported custom fonts extensions are .ttf and .otf. For each font family the bold, italic and
|
||||
* bold_italic variants are supported. Given a "family" font family the files in the assets/fonts
|
||||
* folder need to be family.ttf(.otf) family_bold.ttf(.otf) family_italic.ttf(.otf) and
|
||||
* family_bold_italic.ttf(.otf). If the right font is not found in the assets folder CustomStyleSpan
|
||||
* will fallback on the most appropriate default typeface depending on the style. Fonts are
|
||||
* retrieved and cached using the {@link ReactFontManager}
|
||||
*/
|
||||
@Nullsafe(Nullsafe.Mode.LOCAL)
|
||||
public class CustomStyleSpan extends MetricAffectingSpan implements ReactSpan {
|
||||
private final AssetManager mAssetManager;
|
||||
|
||||
private final int mStyle;
|
||||
private final int mWeight;
|
||||
private final @Nullable String mFeatureSettings;
|
||||
private final @Nullable String mFontFamily;
|
||||
|
||||
public CustomStyleSpan(
|
||||
int fontStyle,
|
||||
int fontWeight,
|
||||
@Nullable String fontFeatureSettings,
|
||||
@Nullable String fontFamily,
|
||||
AssetManager assetManager) {
|
||||
mStyle = fontStyle;
|
||||
mWeight = fontWeight;
|
||||
mFeatureSettings = fontFeatureSettings;
|
||||
mFontFamily = fontFamily;
|
||||
mAssetManager = assetManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDrawState(TextPaint ds) {
|
||||
apply(ds, mStyle, mWeight, mFeatureSettings, mFontFamily, mAssetManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateMeasureState(TextPaint paint) {
|
||||
apply(paint, mStyle, mWeight, mFeatureSettings, mFontFamily, mAssetManager);
|
||||
}
|
||||
|
||||
public int getStyle() {
|
||||
return mStyle == ReactConstants.UNSET ? Typeface.NORMAL : mStyle;
|
||||
}
|
||||
|
||||
public int getWeight() {
|
||||
return mWeight == ReactConstants.UNSET ? ReactFontManager.TypefaceStyle.NORMAL : mWeight;
|
||||
}
|
||||
|
||||
public @Nullable String getFontFamily() {
|
||||
return mFontFamily;
|
||||
}
|
||||
|
||||
public @Nullable String getFontFeatureSettings() {
|
||||
return mFeatureSettings;
|
||||
}
|
||||
|
||||
private static void apply(
|
||||
Paint paint,
|
||||
int style,
|
||||
int weight,
|
||||
@Nullable String fontFeatureSettings,
|
||||
@Nullable String family,
|
||||
AssetManager assetManager) {
|
||||
Typeface typeface =
|
||||
ReactTypefaceUtils.applyStyles(paint.getTypeface(), style, weight, family, assetManager);
|
||||
paint.setFontFeatureSettings(fontFeatureSettings);
|
||||
paint.setTypeface(typeface);
|
||||
paint.setSubpixelText(true);
|
||||
}
|
||||
}
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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.span
|
||||
|
||||
import android.content.res.AssetManager
|
||||
import android.graphics.Paint
|
||||
import android.graphics.Typeface
|
||||
import android.text.TextPaint
|
||||
import android.text.style.MetricAffectingSpan
|
||||
import com.facebook.react.common.ReactConstants
|
||||
import com.facebook.react.common.assets.ReactFontManager
|
||||
import com.facebook.react.views.text.ReactTypefaceUtils
|
||||
|
||||
/**
|
||||
* A [MetricAffectingSpan] that allows to change the style of the displayed font. CustomStyleSpan
|
||||
* will try to load the fontFamily with the right style and weight from the assets. The custom fonts
|
||||
* will have to be located in the res/assets folder of the application. The supported custom fonts
|
||||
* extensions are .ttf and .otf. For each font family the bold, italic and bold_italic variants are
|
||||
* supported. Given a "family" font family the files in the assets/fonts folder need to be
|
||||
* family.ttf(.otf) family_bold.ttf(.otf) family_italic.ttf(.otf) and family_bold_italic.ttf(.otf).
|
||||
* If the right font is not found in the assets folder CustomStyleSpan will fallback on the most
|
||||
* appropriate default typeface depending on the style. Fonts are retrieved and cached using the
|
||||
* [ReactFontManager]
|
||||
*/
|
||||
public class CustomStyleSpan(
|
||||
private val privateStyle: Int,
|
||||
private val privateWeight: Int,
|
||||
public val fontFeatureSettings: String?,
|
||||
public val fontFamily: String?,
|
||||
private val assetManager: AssetManager
|
||||
) : MetricAffectingSpan(), ReactSpan {
|
||||
public override fun updateDrawState(ds: TextPaint) {
|
||||
apply(ds, privateStyle, privateWeight, fontFeatureSettings, fontFamily, assetManager)
|
||||
}
|
||||
|
||||
public override fun updateMeasureState(paint: TextPaint) {
|
||||
apply(paint, privateStyle, privateWeight, fontFeatureSettings, fontFamily, assetManager)
|
||||
}
|
||||
|
||||
public val style: Int
|
||||
get() =
|
||||
if (privateStyle == ReactConstants.UNSET) {
|
||||
Typeface.NORMAL
|
||||
} else {
|
||||
privateStyle
|
||||
}
|
||||
|
||||
public val weight: Int
|
||||
get() =
|
||||
if (privateWeight == ReactConstants.UNSET) {
|
||||
ReactFontManager.TypefaceStyle.NORMAL
|
||||
} else {
|
||||
privateWeight
|
||||
}
|
||||
|
||||
public companion object {
|
||||
private fun apply(
|
||||
paint: Paint,
|
||||
style: Int,
|
||||
weight: Int,
|
||||
fontFeatureSettingsParam: String?,
|
||||
family: String?,
|
||||
assetManager: AssetManager
|
||||
) {
|
||||
val typeface =
|
||||
ReactTypefaceUtils.applyStyles(paint.typeface, style, weight, family, assetManager)
|
||||
paint.apply {
|
||||
fontFeatureSettings = fontFeatureSettingsParam
|
||||
setTypeface(typeface)
|
||||
isSubpixelText = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-21
@@ -1,21 +0,0 @@
|
||||
/*
|
||||
* 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.span;
|
||||
|
||||
import android.text.style.AbsoluteSizeSpan;
|
||||
import com.facebook.infer.annotation.Nullsafe;
|
||||
|
||||
/*
|
||||
* Wraps {@link AbsoluteSizeSpan} as a {@link ReactSpan}.
|
||||
*/
|
||||
@Nullsafe(Nullsafe.Mode.LOCAL)
|
||||
public class ReactAbsoluteSizeSpan extends AbsoluteSizeSpan implements ReactSpan {
|
||||
public ReactAbsoluteSizeSpan(int size) {
|
||||
super(size);
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
* 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.span
|
||||
|
||||
import android.text.style.AbsoluteSizeSpan
|
||||
|
||||
/** Wraps [AbsoluteSizeSpan] as a [ReactSpan]. */
|
||||
public class ReactAbsoluteSizeSpan(size: Int) : AbsoluteSizeSpan(size), ReactSpan
|
||||
-21
@@ -1,21 +0,0 @@
|
||||
/*
|
||||
* 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.span;
|
||||
|
||||
import android.text.style.BackgroundColorSpan;
|
||||
import com.facebook.infer.annotation.Nullsafe;
|
||||
|
||||
/*
|
||||
* Wraps {@link BackgroundColorSpan} as a {@link ReactSpan}.
|
||||
*/
|
||||
@Nullsafe(Nullsafe.Mode.LOCAL)
|
||||
public class ReactBackgroundColorSpan extends BackgroundColorSpan implements ReactSpan {
|
||||
public ReactBackgroundColorSpan(int color) {
|
||||
super(color);
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
* 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.span
|
||||
|
||||
import android.text.style.BackgroundColorSpan
|
||||
|
||||
/** Wraps [BackgroundColorSpan] as a [ReactSpan]. */
|
||||
public class ReactBackgroundColorSpan(color: Int) : BackgroundColorSpan(color), ReactSpan
|
||||
-71
@@ -1,71 +0,0 @@
|
||||
/*
|
||||
* 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.span;
|
||||
|
||||
import android.text.TextPaint;
|
||||
import android.text.style.ClickableSpan;
|
||||
import android.view.View;
|
||||
import androidx.annotation.NonNull;
|
||||
import com.facebook.infer.annotation.Nullsafe;
|
||||
import com.facebook.react.bridge.ReactContext;
|
||||
import com.facebook.react.uimanager.UIManagerHelper;
|
||||
import com.facebook.react.uimanager.events.EventDispatcher;
|
||||
import com.facebook.react.views.text.ReactTextView;
|
||||
import com.facebook.react.views.text.TextLayoutManager;
|
||||
import com.facebook.react.views.view.ViewGroupClickEvent;
|
||||
|
||||
/**
|
||||
* This class is used in {@link TextLayoutManager} to linkify and style a span of text with
|
||||
* accessibilityRole="link". This is needed to make nested Text components accessible.
|
||||
*
|
||||
* <p>For example, if your React component looks like this:
|
||||
*
|
||||
* <pre>{@code
|
||||
* <Text>
|
||||
* Some text with
|
||||
* <Text onPress={onPress} accessible={true} accessibilityRole="link">a link</Text>
|
||||
* in the middle.
|
||||
* </Text>
|
||||
* }</pre>
|
||||
*
|
||||
* then only one {@link ReactTextView} will be created, for the parent. The child Text component
|
||||
* does not exist as a native view, and therefore has no accessibility properties. Instead, we have
|
||||
* to use spans on the parent's {@link ReactTextView} to properly style the child, and to make it
|
||||
* accessible (TalkBack announces that the text has links available, and the links are exposed in
|
||||
* the context menu).
|
||||
*/
|
||||
@Nullsafe(Nullsafe.Mode.LOCAL)
|
||||
public class ReactClickableSpan extends ClickableSpan implements ReactSpan {
|
||||
|
||||
private final int mReactTag;
|
||||
|
||||
public ReactClickableSpan(int reactTag) {
|
||||
mReactTag = reactTag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(@NonNull View view) {
|
||||
ReactContext context = (ReactContext) view.getContext();
|
||||
EventDispatcher eventDispatcher =
|
||||
UIManagerHelper.getEventDispatcherForReactTag(context, mReactTag);
|
||||
if (eventDispatcher != null) {
|
||||
eventDispatcher.dispatchEvent(
|
||||
new ViewGroupClickEvent(UIManagerHelper.getSurfaceId(context), mReactTag));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDrawState(@NonNull TextPaint ds) {
|
||||
// no-op to make sure we don't change the link color or add an underline by default, as the
|
||||
// superclass does.
|
||||
}
|
||||
|
||||
public int getReactTag() {
|
||||
return mReactTag;
|
||||
}
|
||||
}
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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.span
|
||||
|
||||
import android.text.TextPaint
|
||||
import android.text.style.ClickableSpan
|
||||
import android.view.View
|
||||
import com.facebook.react.bridge.ReactContext
|
||||
import com.facebook.react.uimanager.UIManagerHelper
|
||||
import com.facebook.react.views.text.ReactTextView
|
||||
import com.facebook.react.views.view.ViewGroupClickEvent
|
||||
|
||||
/**
|
||||
* This class is used in [TextLayoutManager] to linkify and style a span of text with
|
||||
* accessibilityRole="link". This is needed to make nested Text components accessible.
|
||||
*
|
||||
* For example, if your React component looks like this:
|
||||
* ```js
|
||||
* <Text>
|
||||
* Some text with
|
||||
* <Text onPress={onPress} accessible={true} accessibilityRole="link">a link</Text>
|
||||
* in the middle.
|
||||
* </Text>
|
||||
* ```
|
||||
*
|
||||
* then only one [ReactTextView] will be created, for the parent. The child Text component does not
|
||||
* exist as a native view, and therefore has no accessibility properties. Instead, we have to use
|
||||
* spans on the parent's [ReactTextView] to properly style the child, and to make it accessible
|
||||
* (TalkBack announces that the text has links available, and the links are exposed in the context
|
||||
* menu).
|
||||
*/
|
||||
public class ReactClickableSpan(public val reactTag: Int) : ClickableSpan(), ReactSpan {
|
||||
public override fun onClick(view: View) {
|
||||
val context = view.context as ReactContext
|
||||
val eventDispatcher = UIManagerHelper.getEventDispatcherForReactTag(context, reactTag)
|
||||
eventDispatcher?.dispatchEvent(
|
||||
ViewGroupClickEvent(UIManagerHelper.getSurfaceId(context), reactTag))
|
||||
}
|
||||
|
||||
public override fun updateDrawState(ds: TextPaint) {
|
||||
// no-op to make sure we don't change the link color or add an underline by default, as the
|
||||
// superclass does.
|
||||
}
|
||||
}
|
||||
-21
@@ -1,21 +0,0 @@
|
||||
/*
|
||||
* 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.span;
|
||||
|
||||
import android.text.style.ForegroundColorSpan;
|
||||
import com.facebook.infer.annotation.Nullsafe;
|
||||
|
||||
/*
|
||||
* Wraps {@link ForegroundColorSpan} as a {@link ReactSpan}.
|
||||
*/
|
||||
@Nullsafe(Nullsafe.Mode.LOCAL)
|
||||
public class ReactForegroundColorSpan extends ForegroundColorSpan implements ReactSpan {
|
||||
public ReactForegroundColorSpan(int color) {
|
||||
super(color);
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
* 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.span
|
||||
|
||||
import android.text.style.ForegroundColorSpan
|
||||
|
||||
/** Wraps [ForegroundColorSpan] as a [ReactSpan]. */
|
||||
public class ReactForegroundColorSpan(color: Int) : ForegroundColorSpan(color), ReactSpan
|
||||
-17
@@ -1,17 +0,0 @@
|
||||
/*
|
||||
* 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.span;
|
||||
|
||||
import com.facebook.infer.annotation.Nullsafe;
|
||||
|
||||
/*
|
||||
* Enables us to distinguish between spans that were added by React Native and spans that were
|
||||
* added by something else. All spans that React Native adds should implement this interface.
|
||||
*/
|
||||
@Nullsafe(Nullsafe.Mode.LOCAL)
|
||||
public interface ReactSpan {}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* 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.span
|
||||
|
||||
/**
|
||||
* Enables us to distinguish between spans that were added by React Native and spans that were added
|
||||
* by something else. All spans that React Native adds should implement this interface.
|
||||
*/
|
||||
public interface ReactSpan
|
||||
-17
@@ -1,17 +0,0 @@
|
||||
/*
|
||||
* 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.span;
|
||||
|
||||
import android.text.style.StrikethroughSpan;
|
||||
import com.facebook.infer.annotation.Nullsafe;
|
||||
|
||||
/*
|
||||
* Wraps {@link StrikethroughSpan} as a {@link ReactSpan}.
|
||||
*/
|
||||
@Nullsafe(Nullsafe.Mode.LOCAL)
|
||||
public class ReactStrikethroughSpan extends StrikethroughSpan implements ReactSpan {}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
* 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.span
|
||||
|
||||
import android.text.style.StrikethroughSpan
|
||||
|
||||
/** Wraps [StrikethroughSpan] as a [ReactSpan]. */
|
||||
public class ReactStrikethroughSpan : StrikethroughSpan(), ReactSpan
|
||||
-28
@@ -1,28 +0,0 @@
|
||||
/*
|
||||
* 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.span;
|
||||
|
||||
import com.facebook.infer.annotation.Nullsafe;
|
||||
|
||||
/**
|
||||
* Instances of this class are used to place reactTag information of nested text react nodes into
|
||||
* spannable text rendered by single {@link TextView}
|
||||
*/
|
||||
@Nullsafe(Nullsafe.Mode.LOCAL)
|
||||
public class ReactTagSpan implements ReactSpan {
|
||||
|
||||
private final int mReactTag;
|
||||
|
||||
public ReactTagSpan(int reactTag) {
|
||||
mReactTag = reactTag;
|
||||
}
|
||||
|
||||
public int getReactTag() {
|
||||
return mReactTag;
|
||||
}
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* 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.span
|
||||
|
||||
/**
|
||||
* Instances of this class are used to place reactTag information of nested text react nodes into
|
||||
* spannable text rendered by single [TextView]
|
||||
*/
|
||||
public class ReactTagSpan(public val reactTag: Int) : ReactSpan
|
||||
-17
@@ -1,17 +0,0 @@
|
||||
/*
|
||||
* 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.span;
|
||||
|
||||
import android.text.style.UnderlineSpan;
|
||||
import com.facebook.infer.annotation.Nullsafe;
|
||||
|
||||
/*
|
||||
* Wraps {@link UnderlineSpan} as a {@link ReactSpan}.
|
||||
*/
|
||||
@Nullsafe(Nullsafe.Mode.LOCAL)
|
||||
public class ReactUnderlineSpan extends UnderlineSpan implements ReactSpan {}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
* 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.span
|
||||
|
||||
import android.text.style.UnderlineSpan
|
||||
|
||||
/** Wraps [UnderlineSpan] as a [ReactSpan]. */
|
||||
public class ReactUnderlineSpan : UnderlineSpan(), ReactSpan
|
||||
-66
@@ -1,66 +0,0 @@
|
||||
/*
|
||||
* 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.span;
|
||||
|
||||
import android.text.Spannable;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.Spanned;
|
||||
import com.facebook.common.logging.FLog;
|
||||
import com.facebook.infer.annotation.Nullsafe;
|
||||
|
||||
@Nullsafe(Nullsafe.Mode.LOCAL)
|
||||
public class SetSpanOperation {
|
||||
private static final String TAG = "SetSpanOperation";
|
||||
static final int SPAN_MAX_PRIORITY = Spanned.SPAN_PRIORITY >> Spanned.SPAN_PRIORITY_SHIFT;
|
||||
|
||||
protected int start, end;
|
||||
|
||||
private final ReactSpan what;
|
||||
|
||||
public SetSpanOperation(int start, int end, ReactSpan what) {
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
this.what = what;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param sb builder
|
||||
* @param priorityIndex index of this operation in the topological sorting which puts operations
|
||||
* with higher priority before operations with lower priority.
|
||||
*/
|
||||
public void execute(SpannableStringBuilder sb, int priorityIndex) {
|
||||
assert priorityIndex >= 0;
|
||||
|
||||
// All spans will automatically extend to the right of the text, but not the left - except
|
||||
// for spans that start at the beginning of the text.
|
||||
int spanFlags = Spannable.SPAN_EXCLUSIVE_INCLUSIVE;
|
||||
if (start == 0) {
|
||||
spanFlags = Spannable.SPAN_INCLUSIVE_INCLUSIVE;
|
||||
}
|
||||
|
||||
// Calculate priority, assigning the highest values to operations with the highest priority
|
||||
final int priority = SPAN_MAX_PRIORITY - priorityIndex;
|
||||
|
||||
if (priority < 0) {
|
||||
FLog.w(TAG, "Text tree size exceeded the limit, styling may become unpredictable");
|
||||
}
|
||||
|
||||
// If the computed priority doesn't fit in the flags, clamp it. The effect might not be correct
|
||||
// in 100% of cases, but doing nothing (as we did in the past) leads to totally random results.
|
||||
final int effectivePriority = Math.max(priority, 0);
|
||||
|
||||
spanFlags &= ~Spannable.SPAN_PRIORITY;
|
||||
spanFlags |= (effectivePriority << Spannable.SPAN_PRIORITY_SHIFT) & Spannable.SPAN_PRIORITY;
|
||||
|
||||
sb.setSpan(what, start, end, spanFlags);
|
||||
}
|
||||
|
||||
public ReactSpan getWhat() {
|
||||
return what;
|
||||
}
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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.span
|
||||
|
||||
import android.text.Spannable
|
||||
import android.text.SpannableStringBuilder
|
||||
import android.text.Spanned
|
||||
import com.facebook.common.logging.FLog
|
||||
import kotlin.math.max
|
||||
|
||||
public class SetSpanOperation(
|
||||
private val start: Int,
|
||||
private val end: Int,
|
||||
@JvmField public val what: ReactSpan
|
||||
) {
|
||||
/**
|
||||
* @param builder Spannable string builder
|
||||
* @param priorityIndex index of this operation in the topological sorting which puts operations
|
||||
* with higher priority before operations with lower priority.
|
||||
*/
|
||||
public fun execute(builder: SpannableStringBuilder, priorityIndex: Int) {
|
||||
check(priorityIndex >= 0)
|
||||
// All spans will automatically extend to the right of the text, but not the left - except
|
||||
// for spans that start at the beginning of the text.
|
||||
var spanFlags = Spannable.SPAN_EXCLUSIVE_INCLUSIVE
|
||||
if (start == 0) {
|
||||
spanFlags = Spannable.SPAN_INCLUSIVE_INCLUSIVE
|
||||
}
|
||||
|
||||
// Calculate priority, assigning the highest values to operations with the highest priority
|
||||
val priority = SPAN_MAX_PRIORITY - priorityIndex
|
||||
|
||||
if (priority < 0) {
|
||||
FLog.w(TAG, "Text tree size exceeded the limit, styling may become unpredictable")
|
||||
}
|
||||
|
||||
// If the computed priority doesn't fit in the flags, clamp it. The effect might not be correct
|
||||
// in 100% of cases, but doing nothing (as we did in the past) leads to totally random results.
|
||||
val effectivePriority = max(priority, 0)
|
||||
|
||||
spanFlags = spanFlags and Spannable.SPAN_PRIORITY.inv()
|
||||
spanFlags =
|
||||
spanFlags or
|
||||
((effectivePriority shl Spannable.SPAN_PRIORITY_SHIFT) and Spannable.SPAN_PRIORITY)
|
||||
|
||||
builder.setSpan(what, start, end, spanFlags)
|
||||
}
|
||||
|
||||
public companion object {
|
||||
private const val TAG = "SetSpanOperation"
|
||||
public const val SPAN_MAX_PRIORITY: Int = Spanned.SPAN_PRIORITY shr Spanned.SPAN_PRIORITY_SHIFT
|
||||
}
|
||||
}
|
||||
-30
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* 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.span;
|
||||
|
||||
import android.text.TextPaint;
|
||||
import android.text.style.CharacterStyle;
|
||||
import com.facebook.infer.annotation.Nullsafe;
|
||||
|
||||
@Nullsafe(Nullsafe.Mode.LOCAL)
|
||||
public class ShadowStyleSpan extends CharacterStyle implements ReactSpan {
|
||||
private final float mDx, mDy, mRadius;
|
||||
private final int mColor;
|
||||
|
||||
public ShadowStyleSpan(float dx, float dy, float radius, int color) {
|
||||
mDx = dx;
|
||||
mDy = dy;
|
||||
mRadius = radius;
|
||||
mColor = color;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDrawState(TextPaint textPaint) {
|
||||
textPaint.setShadowLayer(mRadius, mDx, mDy, mColor);
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* 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.span
|
||||
|
||||
import android.text.TextPaint
|
||||
import android.text.style.CharacterStyle
|
||||
|
||||
public class ShadowStyleSpan(
|
||||
private val dx: Float,
|
||||
private val dy: Float,
|
||||
private val radius: Float,
|
||||
private val color: Int
|
||||
) : CharacterStyle(), ReactSpan {
|
||||
public override fun updateDrawState(textPaint: TextPaint) {
|
||||
textPaint.setShadowLayer(radius, dx, dy, color)
|
||||
}
|
||||
}
|
||||
-61
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
* 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.span;
|
||||
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.text.Spannable;
|
||||
import android.text.style.ReplacementSpan;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.facebook.infer.annotation.Nullsafe;
|
||||
|
||||
/** Base class for inline image spans. */
|
||||
@Nullsafe(Nullsafe.Mode.LOCAL)
|
||||
public abstract class TextInlineImageSpan extends ReplacementSpan implements ReactSpan {
|
||||
|
||||
/**
|
||||
* For TextInlineImageSpan we need to update the Span to know that the window is attached and the
|
||||
* TextView that we will set as the callback on the Drawable.
|
||||
*
|
||||
* @param spannable The spannable that may contain TextInlineImageSpans
|
||||
* @param view The view which will be set as the callback for the Drawable
|
||||
*/
|
||||
public static void possiblyUpdateInlineImageSpans(Spannable spannable, TextView view) {
|
||||
TextInlineImageSpan[] spans =
|
||||
spannable.getSpans(0, spannable.length(), TextInlineImageSpan.class);
|
||||
for (TextInlineImageSpan span : spans) {
|
||||
span.onAttachedToWindow();
|
||||
span.setTextView(view);
|
||||
}
|
||||
}
|
||||
|
||||
/** Get the drawable that is span represents. */
|
||||
public abstract @Nullable Drawable getDrawable();
|
||||
|
||||
/** Called by the text view from {@link View#onDetachedFromWindow()}, */
|
||||
public abstract void onDetachedFromWindow();
|
||||
|
||||
/** Called by the text view from {@link View#onStartTemporaryDetach()}. */
|
||||
public abstract void onStartTemporaryDetach();
|
||||
|
||||
/** Called by the text view from {@link View#onAttachedToWindow()}. */
|
||||
public abstract void onAttachedToWindow();
|
||||
|
||||
/** Called by the text view from {@link View#onFinishTemporaryDetach()}. */
|
||||
public abstract void onFinishTemporaryDetach();
|
||||
|
||||
/** Set the textview that will contain this span. */
|
||||
public abstract void setTextView(TextView textView);
|
||||
|
||||
/** Get the width of the span. */
|
||||
public abstract int getWidth();
|
||||
|
||||
/** Get the height of the span. */
|
||||
public abstract int getHeight();
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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.span
|
||||
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.text.Spannable
|
||||
import android.text.style.ReplacementSpan
|
||||
import android.view.View
|
||||
import android.widget.TextView
|
||||
|
||||
/** Base class for inline image spans. */
|
||||
public abstract class TextInlineImageSpan : ReplacementSpan(), ReactSpan {
|
||||
/** Get the drawable that is span represents. */
|
||||
public abstract val drawable: Drawable?
|
||||
|
||||
/** Called by the text view from [View.onDetachedFromWindow], */
|
||||
public abstract fun onDetachedFromWindow()
|
||||
|
||||
/** Called by the text view from [View.onStartTemporaryDetach]. */
|
||||
public abstract fun onStartTemporaryDetach()
|
||||
|
||||
/** Called by the text view from [View.onAttachedToWindow]. */
|
||||
public abstract fun onAttachedToWindow()
|
||||
|
||||
/** Called by the text view from [View.onFinishTemporaryDetach]. */
|
||||
public abstract fun onFinishTemporaryDetach()
|
||||
|
||||
/** Set the textview that will contain this span. */
|
||||
public abstract fun setTextView(textView: TextView?)
|
||||
|
||||
/** Get the width of the span. */
|
||||
public abstract val width: Int
|
||||
|
||||
/** Get the height of the span. */
|
||||
public abstract val height: Int
|
||||
|
||||
public companion object {
|
||||
/**
|
||||
* For TextInlineImageSpan we need to update the Span to know that the window is attached and
|
||||
* the TextView that we will set as the callback on the Drawable.
|
||||
*
|
||||
* @param spannable The spannable that may contain TextInlineImageSpans
|
||||
* @param view The view which will be set as the callback for the Drawable
|
||||
*/
|
||||
@JvmStatic
|
||||
public fun possiblyUpdateInlineImageSpans(spannable: Spannable, view: TextView?) {
|
||||
spannable.getSpans(0, spannable.length, TextInlineImageSpan::class.java).forEach { s ->
|
||||
s.onAttachedToWindow()
|
||||
s.setTextView(view)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-69
@@ -1,69 +0,0 @@
|
||||
/*
|
||||
* 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.span;
|
||||
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.text.style.ReplacementSpan;
|
||||
import com.facebook.infer.annotation.Nullsafe;
|
||||
|
||||
/**
|
||||
* TextInlineViewPlaceholderSpan is a span for inlined views that are inside <Text/>. It computes
|
||||
* its size based on the input size. It contains no draw logic, just positioning logic.
|
||||
*/
|
||||
@Nullsafe(Nullsafe.Mode.LOCAL)
|
||||
public class TextInlineViewPlaceholderSpan extends ReplacementSpan implements ReactSpan {
|
||||
private int mReactTag;
|
||||
private int mWidth;
|
||||
private int mHeight;
|
||||
|
||||
public TextInlineViewPlaceholderSpan(int reactTag, int width, int height) {
|
||||
mReactTag = reactTag;
|
||||
mWidth = width;
|
||||
mHeight = height;
|
||||
}
|
||||
|
||||
public int getReactTag() {
|
||||
return mReactTag;
|
||||
}
|
||||
|
||||
public int getWidth() {
|
||||
return mWidth;
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
return mHeight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) {
|
||||
// NOTE: This getSize code is copied from DynamicDrawableSpan and modified to not use a Drawable
|
||||
|
||||
if (fm != null) {
|
||||
fm.ascent = -mHeight;
|
||||
fm.descent = 0;
|
||||
|
||||
fm.top = fm.ascent;
|
||||
fm.bottom = 0;
|
||||
}
|
||||
|
||||
return mWidth;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(
|
||||
Canvas canvas,
|
||||
CharSequence text,
|
||||
int start,
|
||||
int end,
|
||||
float x,
|
||||
int top,
|
||||
int y,
|
||||
int bottom,
|
||||
Paint paint) {}
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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.span
|
||||
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Paint
|
||||
import android.graphics.Paint.FontMetricsInt
|
||||
import android.text.style.ReplacementSpan
|
||||
|
||||
/**
|
||||
* TextInlineViewPlaceholderSpan is a span for inlined views that are inside <Text></Text>. It
|
||||
* computes its size based on the input size. It contains no draw logic, just positioning logic.
|
||||
*/
|
||||
public class TextInlineViewPlaceholderSpan(
|
||||
public val reactTag: Int,
|
||||
public val width: Int,
|
||||
public val height: Int
|
||||
) : ReplacementSpan(), ReactSpan {
|
||||
public override fun getSize(
|
||||
paint: Paint,
|
||||
text: CharSequence?,
|
||||
start: Int,
|
||||
end: Int,
|
||||
fm: FontMetricsInt?
|
||||
): Int {
|
||||
// NOTE: This getSize code is copied from DynamicDrawableSpan and modified to not use a Drawable
|
||||
if (fm != null) {
|
||||
fm.ascent = -height
|
||||
fm.descent = 0
|
||||
fm.top = fm.ascent
|
||||
fm.bottom = 0
|
||||
}
|
||||
return width
|
||||
}
|
||||
|
||||
public override fun draw(
|
||||
canvas: Canvas,
|
||||
text: CharSequence?,
|
||||
start: Int,
|
||||
end: Int,
|
||||
x: Float,
|
||||
top: Int,
|
||||
y: Int,
|
||||
bottom: Int,
|
||||
paint: Paint
|
||||
): Unit = Unit
|
||||
}
|
||||
Reference in New Issue
Block a user