Skip to content
Closed
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 numberDiff line numberDiff line change
Expand Up@@ -190,12 +190,17 @@ protected static Spannable fromTextCSSNode(ReactTextShadowNode textCSSNode) {
}

textCSSNode.mContainsImages = false;
textCSSNode.mHeightOfTallestInlineImage = Float.NaN;

// While setting the Spans on the final text, we also check whether any of them are images
for (int i = ops.size() - 1; i >= 0; i--) {
SetSpanOperation op = ops.get(i);
if (op.what instanceof TextInlineImageSpan) {
int height = ((TextInlineImageSpan)op.what).getHeight();
textCSSNode.mContainsImages = true;
if (Float.isNaN(textCSSNode.mHeightOfTallestInlineImage) || height > textCSSNode.mHeightOfTallestInlineImage) {
textCSSNode.mHeightOfTallestInlineImage = height;
}
}
op.execute(sb);
}
Expand DownExpand Up@@ -226,6 +231,14 @@ public void measure(
// technically, width should never be negative, but there is currently a bug in
boolean unconstrainedWidth = widthMode == CSSMeasureMode.UNDEFINED || width < 0;

float effectiveLineHeight = reactCSSNode.getEffectiveLineHeight();
float lineSpacingExtra = 0;
float lineSpacingMultiplier = 1;
if (!Float.isNaN(effectiveLineHeight)) {
lineSpacingExtra = effectiveLineHeight;
lineSpacingMultiplier = 0;
}

if (boring == null &&
(unconstrainedWidth ||
(!CSSConstants.isUndefined(desiredWidth) && desiredWidth <= width))) {
Expand All@@ -236,8 +249,8 @@ public void measure(
textPaint,
(int) Math.ceil(desiredWidth),
Layout.Alignment.ALIGN_NORMAL,
1,
0,
lineSpacingMultiplier,
lineSpacingExtra,
true);
} else if (boring != null && (unconstrainedWidth || boring.width <= width)) {
// Is used for single-line, boring text when the width is either unknown or bigger
Expand All@@ -247,8 +260,8 @@ public void measure(
textPaint,
boring.width,
Layout.Alignment.ALIGN_NORMAL,
1,
0,
lineSpacingMultiplier,
lineSpacingExtra,
boring,
true);
} else {
Expand All@@ -258,8 +271,8 @@ public void measure(
textPaint,
(int) width,
Layout.Alignment.ALIGN_NORMAL,
1,
0,
lineSpacingMultiplier,
lineSpacingExtra,
true);
}

Expand All@@ -269,13 +282,6 @@ public void measure(
reactCSSNode.mNumberOfLines < layout.getLineCount()) {
measureOutput.height = layout.getLineBottom(reactCSSNode.mNumberOfLines - 1);
}
if (reactCSSNode.mLineHeight != UNSET) {
int lines = reactCSSNode.mNumberOfLines != UNSET
? Math.min(reactCSSNode.mNumberOfLines, layout.getLineCount())
: layout.getLineCount();
float lineHeight = PixelUtil.toPixelFromSP(reactCSSNode.mLineHeight);
measureOutput.height = lineHeight * lines;
}
}
};

Expand All@@ -293,7 +299,7 @@ private static int parseNumericFontWeight(String fontWeightString) {
100 * (fontWeightString.charAt(0) - '0') : -1;
}

private int mLineHeight = UNSET;
private float mLineHeight = Float.NaN;
private boolean mIsColorSet = false;
private int mColor;
private boolean mIsBackgroundColorSet = false;
Expand DownExpand Up@@ -340,6 +346,7 @@ private static int parseNumericFontWeight(String fontWeightString) {
private final boolean mIsVirtual;

protected boolean mContainsImages = false;
private float mHeightOfTallestInlineImage = Float.NaN;

public ReactTextShadowNode(boolean isVirtual) {
mIsVirtual = isVirtual;
Expand All@@ -348,6 +355,15 @@ public ReactTextShadowNode(boolean isVirtual) {
}
}

// Returns a line height which takes into account the requested line height
// and the height of the inline images.
public float getEffectiveLineHeight() {
boolean useInlineViewHeight = !Float.isNaN(mLineHeight) &&
!Float.isNaN(mHeightOfTallestInlineImage) &&
mHeightOfTallestInlineImage > mLineHeight;
return useInlineViewHeight ? mHeightOfTallestInlineImage : mLineHeight;
}

@Override
public void onBeforeLayout() {
if (mIsVirtual) {
Expand DownExpand Up@@ -380,7 +396,7 @@ public void setNumberOfLines(int numberOfLines) {

@ReactProp(name = ViewProps.LINE_HEIGHT, defaultInt = UNSET)
public void setLineHeight(int lineHeight) {
mLineHeight = lineHeight;
mLineHeight = lineHeight == UNSET ? Float.NaN : PixelUtil.toPixelFromSP(lineHeight);
markUpdated();
}

Expand DownExpand Up@@ -530,7 +546,7 @@ public void onCollectExtraUpdates(UIViewOperationQueue uiViewOperationQueue) {
super.onCollectExtraUpdates(uiViewOperationQueue);
if (mPreparedSpannableText != null) {
ReactTextUpdate reactTextUpdate =
new ReactTextUpdate(mPreparedSpannableText, UNSET, mContainsImages, getPadding());
new ReactTextUpdate(mPreparedSpannableText, UNSET, mContainsImages, getPadding(), getEffectiveLineHeight());
uiViewOperationQueue.enqueueUpdateExtraData(getReactTag(), reactTextUpdate);
}
}
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -27,19 +27,22 @@ public class ReactTextUpdate {
private final float mPaddingTop;
private final float mPaddingRight;
private final float mPaddingBottom;
private final float mLineHeight;

public ReactTextUpdate(
Spannable text,
int jsEventCounter,
boolean containsImages,
Spacing padding) {
Spacing padding,
float lineHeight) {
mText = text;
mJsEventCounter = jsEventCounter;
mContainsImages = containsImages;
mPaddingLeft = padding.get(Spacing.LEFT);
mPaddingTop = padding.get(Spacing.TOP);
mPaddingRight = padding.get(Spacing.RIGHT);
mPaddingBottom = padding.get(Spacing.BOTTOM);
mLineHeight = lineHeight;
}

public Spannable getText() {
Expand DownExpand Up@@ -69,4 +72,8 @@ public float getPaddingRight() {
public float getPaddingBottom() {
return mPaddingBottom;
}

public float getLineHeight() {
return mLineHeight;
}
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -17,6 +17,7 @@
import android.view.ViewGroup;
import android.widget.TextView;

import com.facebook.csslayout.FloatUtil;
import com.facebook.react.uimanager.ReactCompoundView;

public class ReactTextView extends TextView implements ReactCompoundView {
Expand All@@ -28,6 +29,7 @@ public class ReactTextView extends TextView implements ReactCompoundView {
private int mDefaultGravityHorizontal;
private int mDefaultGravityVertical;
private boolean mTextIsSelectable;
private float mLineHeight = Float.NaN;

public ReactTextView(Context context) {
super(context);
Expand All@@ -50,6 +52,16 @@ public void setText(ReactTextUpdate update) {
(int) Math.ceil(update.getPaddingTop()),
(int) Math.ceil(update.getPaddingRight()),
(int) Math.ceil(update.getPaddingBottom()));

float nextLineHeight = update.getLineHeight();
if (!FloatUtil.floatsEqual(mLineHeight, nextLineHeight)) {
mLineHeight = nextLineHeight;
if (Float.isNaN(mLineHeight)) { // NaN will be used if property gets reset
setLineSpacing(0, 1);
} else {
setLineSpacing(mLineHeight, 0);
}
}
}

@Override
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -103,15 +103,6 @@ public void setTextAlignVertical(ReactTextView view, @Nullable String textAlignV
}
}

@ReactProp(name = ViewProps.LINE_HEIGHT, defaultFloat = Float.NaN)
public void setLineHeight(ReactTextView view, float lineHeight) {
if (Float.isNaN(lineHeight)) { // NaN will be used if property gets reset
view.setLineSpacing(0, 1);
} else {
view.setLineSpacing(PixelUtil.toPixelFromSP(lineHeight), 0);
}
}

@ReactProp(name = "selectable")
public void setSelectable(ReactTextView view, boolean isSelectable) {
view.setTextIsSelectable(isSelectable);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -67,4 +67,14 @@ public static void possiblyUpdateInlineImageSpans(Spannable spannable, TextView
* 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();
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -146,13 +146,21 @@ public void draw(

canvas.save();

int transY = bottom - mDrawable.getBounds().bottom;

// Align to baseline by default
transY -= paint.getFontMetricsInt().descent;
int transY = y - mDrawable.getBounds().bottom;

canvas.translate(x, transY);
mDrawable.draw(canvas);
canvas.restore();
}

@Override
public int getWidth() {
return mWidth;
}

@Override
public int getHeight() {
return mHeight;
}
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -119,7 +119,7 @@ public void onCollectExtraUpdates(UIViewOperationQueue uiViewOperationQueue) {
if (mJsEventCount != UNSET) {
Spannable preparedSpannableText = fromTextCSSNode(this);
ReactTextUpdate reactTextUpdate =
new ReactTextUpdate(preparedSpannableText, mJsEventCount, mContainsImages, getPadding());
new ReactTextUpdate(preparedSpannableText, mJsEventCount, mContainsImages, getPadding(), getEffectiveLineHeight());
uiViewOperationQueue.enqueueUpdateExtraData(getReactTag(), reactTextUpdate);
}
}
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Android: Fix handling of line height with inline images by rigdern · Pull Request #8907 · react/react-native · GitHub
Skip to content
Closed
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 numberDiff line numberDiff line change
Expand Up@@ -190,12 +190,17 @@ protected static Spannable fromTextCSSNode(ReactTextShadowNode textCSSNode) {
}

textCSSNode.mContainsImages = false;
textCSSNode.mHeightOfTallestInlineImage = Float.NaN;

// While setting the Spans on the final text, we also check whether any of them are images
for (int i = ops.size() - 1; i >= 0; i--) {
SetSpanOperation op = ops.get(i);
if (op.what instanceof TextInlineImageSpan) {
int height = ((TextInlineImageSpan)op.what).getHeight();
textCSSNode.mContainsImages = true;
if (Float.isNaN(textCSSNode.mHeightOfTallestInlineImage) || height > textCSSNode.mHeightOfTallestInlineImage) {
textCSSNode.mHeightOfTallestInlineImage = height;
}
}
op.execute(sb);
}
Expand DownExpand Up@@ -226,6 +231,14 @@ public void measure(
// technically, width should never be negative, but there is currently a bug in
boolean unconstrainedWidth = widthMode == CSSMeasureMode.UNDEFINED || width < 0;

float effectiveLineHeight = reactCSSNode.getEffectiveLineHeight();
float lineSpacingExtra = 0;
float lineSpacingMultiplier = 1;
if (!Float.isNaN(effectiveLineHeight)) {
lineSpacingExtra = effectiveLineHeight;
lineSpacingMultiplier = 0;
}

if (boring == null &&
(unconstrainedWidth ||
(!CSSConstants.isUndefined(desiredWidth) && desiredWidth <= width))) {
Expand All@@ -236,8 +249,8 @@ public void measure(
textPaint,
(int) Math.ceil(desiredWidth),
Layout.Alignment.ALIGN_NORMAL,
1,
0,
lineSpacingMultiplier,
lineSpacingExtra,
true);
} else if (boring != null && (unconstrainedWidth || boring.width <= width)) {
// Is used for single-line, boring text when the width is either unknown or bigger
Expand All@@ -247,8 +260,8 @@ public void measure(
textPaint,
boring.width,
Layout.Alignment.ALIGN_NORMAL,
1,
0,
lineSpacingMultiplier,
lineSpacingExtra,
boring,
true);
} else {
Expand All@@ -258,8 +271,8 @@ public void measure(
textPaint,
(int) width,
Layout.Alignment.ALIGN_NORMAL,
1,
0,
lineSpacingMultiplier,
lineSpacingExtra,
true);
}

Expand All@@ -269,13 +282,6 @@ public void measure(
reactCSSNode.mNumberOfLines < layout.getLineCount()) {
measureOutput.height = layout.getLineBottom(reactCSSNode.mNumberOfLines - 1);
}
if (reactCSSNode.mLineHeight != UNSET) {
int lines = reactCSSNode.mNumberOfLines != UNSET
? Math.min(reactCSSNode.mNumberOfLines, layout.getLineCount())
: layout.getLineCount();
float lineHeight = PixelUtil.toPixelFromSP(reactCSSNode.mLineHeight);
measureOutput.height = lineHeight * lines;
}
}
};

Expand All@@ -293,7 +299,7 @@ private static int parseNumericFontWeight(String fontWeightString) {
100 * (fontWeightString.charAt(0) - '0') : -1;
}

private int mLineHeight = UNSET;
private float mLineHeight = Float.NaN;
private boolean mIsColorSet = false;
private int mColor;
private boolean mIsBackgroundColorSet = false;
Expand DownExpand Up@@ -340,6 +346,7 @@ private static int parseNumericFontWeight(String fontWeightString) {
private final boolean mIsVirtual;

protected boolean mContainsImages = false;
private float mHeightOfTallestInlineImage = Float.NaN;

public ReactTextShadowNode(boolean isVirtual) {
mIsVirtual = isVirtual;
Expand All@@ -348,6 +355,15 @@ public ReactTextShadowNode(boolean isVirtual) {
}
}

// Returns a line height which takes into account the requested line height
// and the height of the inline images.
public float getEffectiveLineHeight() {
boolean useInlineViewHeight = !Float.isNaN(mLineHeight) &&
!Float.isNaN(mHeightOfTallestInlineImage) &&
mHeightOfTallestInlineImage > mLineHeight;
return useInlineViewHeight ? mHeightOfTallestInlineImage : mLineHeight;
}

@Override
public void onBeforeLayout() {
if (mIsVirtual) {
Expand DownExpand Up@@ -380,7 +396,7 @@ public void setNumberOfLines(int numberOfLines) {

@ReactProp(name = ViewProps.LINE_HEIGHT, defaultInt = UNSET)
public void setLineHeight(int lineHeight) {
mLineHeight = lineHeight;
mLineHeight = lineHeight == UNSET ? Float.NaN : PixelUtil.toPixelFromSP(lineHeight);
markUpdated();
}

Expand DownExpand Up@@ -530,7 +546,7 @@ public void onCollectExtraUpdates(UIViewOperationQueue uiViewOperationQueue) {
super.onCollectExtraUpdates(uiViewOperationQueue);
if (mPreparedSpannableText != null) {
ReactTextUpdate reactTextUpdate =
new ReactTextUpdate(mPreparedSpannableText, UNSET, mContainsImages, getPadding());
new ReactTextUpdate(mPreparedSpannableText, UNSET, mContainsImages, getPadding(), getEffectiveLineHeight());
uiViewOperationQueue.enqueueUpdateExtraData(getReactTag(), reactTextUpdate);
}
}
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -27,19 +27,22 @@ public class ReactTextUpdate {
private final float mPaddingTop;
private final float mPaddingRight;
private final float mPaddingBottom;
private final float mLineHeight;

public ReactTextUpdate(
Spannable text,
int jsEventCounter,
boolean containsImages,
Spacing padding) {
Spacing padding,
float lineHeight) {
mText = text;
mJsEventCounter = jsEventCounter;
mContainsImages = containsImages;
mPaddingLeft = padding.get(Spacing.LEFT);
mPaddingTop = padding.get(Spacing.TOP);
mPaddingRight = padding.get(Spacing.RIGHT);
mPaddingBottom = padding.get(Spacing.BOTTOM);
mLineHeight = lineHeight;
}

public Spannable getText() {
Expand DownExpand Up@@ -69,4 +72,8 @@ public float getPaddingRight() {
public float getPaddingBottom() {
return mPaddingBottom;
}

public float getLineHeight() {
return mLineHeight;
}
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -17,6 +17,7 @@
import android.view.ViewGroup;
import android.widget.TextView;

import com.facebook.csslayout.FloatUtil;
import com.facebook.react.uimanager.ReactCompoundView;

public class ReactTextView extends TextView implements ReactCompoundView {
Expand All@@ -28,6 +29,7 @@ public class ReactTextView extends TextView implements ReactCompoundView {
private int mDefaultGravityHorizontal;
private int mDefaultGravityVertical;
private boolean mTextIsSelectable;
private float mLineHeight = Float.NaN;

public ReactTextView(Context context) {
super(context);
Expand All@@ -50,6 +52,16 @@ public void setText(ReactTextUpdate update) {
(int) Math.ceil(update.getPaddingTop()),
(int) Math.ceil(update.getPaddingRight()),
(int) Math.ceil(update.getPaddingBottom()));

float nextLineHeight = update.getLineHeight();
if (!FloatUtil.floatsEqual(mLineHeight, nextLineHeight)) {
mLineHeight = nextLineHeight;
if (Float.isNaN(mLineHeight)) { // NaN will be used if property gets reset
setLineSpacing(0, 1);
} else {
setLineSpacing(mLineHeight, 0);
}
}
}

@Override
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -103,15 +103,6 @@ public void setTextAlignVertical(ReactTextView view, @Nullable String textAlignV
}
}

@ReactProp(name = ViewProps.LINE_HEIGHT, defaultFloat = Float.NaN)
public void setLineHeight(ReactTextView view, float lineHeight) {
if (Float.isNaN(lineHeight)) { // NaN will be used if property gets reset
view.setLineSpacing(0, 1);
} else {
view.setLineSpacing(PixelUtil.toPixelFromSP(lineHeight), 0);
}
}

@ReactProp(name = "selectable")
public void setSelectable(ReactTextView view, boolean isSelectable) {
view.setTextIsSelectable(isSelectable);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -67,4 +67,14 @@ public static void possiblyUpdateInlineImageSpans(Spannable spannable, TextView
* 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();
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -146,13 +146,21 @@ public void draw(

canvas.save();

int transY = bottom - mDrawable.getBounds().bottom;

// Align to baseline by default
transY -= paint.getFontMetricsInt().descent;
int transY = y - mDrawable.getBounds().bottom;

canvas.translate(x, transY);
mDrawable.draw(canvas);
canvas.restore();
}

@Override
public int getWidth() {
return mWidth;
}

@Override
public int getHeight() {
return mHeight;
}
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -119,7 +119,7 @@ public void onCollectExtraUpdates(UIViewOperationQueue uiViewOperationQueue) {
if (mJsEventCount != UNSET) {
Spannable preparedSpannableText = fromTextCSSNode(this);
ReactTextUpdate reactTextUpdate =
new ReactTextUpdate(preparedSpannableText, mJsEventCount, mContainsImages, getPadding());
new ReactTextUpdate(preparedSpannableText, mJsEventCount, mContainsImages, getPadding(), getEffectiveLineHeight());
uiViewOperationQueue.enqueueUpdateExtraData(getReactTag(), reactTextUpdate);
}
}
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Android: Fix handling of line height with inline images by rigdern · Pull Request #8907 · react/react-native · GitHub
Skip to content
Closed
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 numberDiff line numberDiff line change
Expand Up@@ -190,12 +190,17 @@ protected static Spannable fromTextCSSNode(ReactTextShadowNode textCSSNode) {
}

textCSSNode.mContainsImages = false;
textCSSNode.mHeightOfTallestInlineImage = Float.NaN;

// While setting the Spans on the final text, we also check whether any of them are images
for (int i = ops.size() - 1; i >= 0; i--) {
SetSpanOperation op = ops.get(i);
if (op.what instanceof TextInlineImageSpan) {
int height = ((TextInlineImageSpan)op.what).getHeight();
textCSSNode.mContainsImages = true;
if (Float.isNaN(textCSSNode.mHeightOfTallestInlineImage) || height > textCSSNode.mHeightOfTallestInlineImage) {
textCSSNode.mHeightOfTallestInlineImage = height;
}
}
op.execute(sb);
}
Expand DownExpand Up@@ -226,6 +231,14 @@ public void measure(
// technically, width should never be negative, but there is currently a bug in
boolean unconstrainedWidth = widthMode == CSSMeasureMode.UNDEFINED || width < 0;

float effectiveLineHeight = reactCSSNode.getEffectiveLineHeight();
float lineSpacingExtra = 0;
float lineSpacingMultiplier = 1;
if (!Float.isNaN(effectiveLineHeight)) {
lineSpacingExtra = effectiveLineHeight;
lineSpacingMultiplier = 0;
}

if (boring == null &&
(unconstrainedWidth ||
(!CSSConstants.isUndefined(desiredWidth) && desiredWidth <= width))) {
Expand All@@ -236,8 +249,8 @@ public void measure(
textPaint,
(int) Math.ceil(desiredWidth),
Layout.Alignment.ALIGN_NORMAL,
1,
0,
lineSpacingMultiplier,
lineSpacingExtra,
true);
} else if (boring != null && (unconstrainedWidth || boring.width <= width)) {
// Is used for single-line, boring text when the width is either unknown or bigger
Expand All@@ -247,8 +260,8 @@ public void measure(
textPaint,
boring.width,
Layout.Alignment.ALIGN_NORMAL,
1,
0,
lineSpacingMultiplier,
lineSpacingExtra,
boring,
true);
} else {
Expand All@@ -258,8 +271,8 @@ public void measure(
textPaint,
(int) width,
Layout.Alignment.ALIGN_NORMAL,
1,
0,
lineSpacingMultiplier,
lineSpacingExtra,
true);
}

Expand All@@ -269,13 +282,6 @@ public void measure(
reactCSSNode.mNumberOfLines < layout.getLineCount()) {
measureOutput.height = layout.getLineBottom(reactCSSNode.mNumberOfLines - 1);
}
if (reactCSSNode.mLineHeight != UNSET) {
int lines = reactCSSNode.mNumberOfLines != UNSET
? Math.min(reactCSSNode.mNumberOfLines, layout.getLineCount())
: layout.getLineCount();
float lineHeight = PixelUtil.toPixelFromSP(reactCSSNode.mLineHeight);
measureOutput.height = lineHeight * lines;
}
}
};

Expand All@@ -293,7 +299,7 @@ private static int parseNumericFontWeight(String fontWeightString) {
100 * (fontWeightString.charAt(0) - '0') : -1;
}

private int mLineHeight = UNSET;
private float mLineHeight = Float.NaN;
private boolean mIsColorSet = false;
private int mColor;
private boolean mIsBackgroundColorSet = false;
Expand DownExpand Up@@ -340,6 +346,7 @@ private static int parseNumericFontWeight(String fontWeightString) {
private final boolean mIsVirtual;

protected boolean mContainsImages = false;
private float mHeightOfTallestInlineImage = Float.NaN;

public ReactTextShadowNode(boolean isVirtual) {
mIsVirtual = isVirtual;
Expand All@@ -348,6 +355,15 @@ public ReactTextShadowNode(boolean isVirtual) {
}
}

// Returns a line height which takes into account the requested line height
// and the height of the inline images.
public float getEffectiveLineHeight() {
boolean useInlineViewHeight = !Float.isNaN(mLineHeight) &&
!Float.isNaN(mHeightOfTallestInlineImage) &&
mHeightOfTallestInlineImage > mLineHeight;
return useInlineViewHeight ? mHeightOfTallestInlineImage : mLineHeight;
}

@Override
public void onBeforeLayout() {
if (mIsVirtual) {
Expand DownExpand Up@@ -380,7 +396,7 @@ public void setNumberOfLines(int numberOfLines) {

@ReactProp(name = ViewProps.LINE_HEIGHT, defaultInt = UNSET)
public void setLineHeight(int lineHeight) {
mLineHeight = lineHeight;
mLineHeight = lineHeight == UNSET ? Float.NaN : PixelUtil.toPixelFromSP(lineHeight);
markUpdated();
}

Expand DownExpand Up@@ -530,7 +546,7 @@ public void onCollectExtraUpdates(UIViewOperationQueue uiViewOperationQueue) {
super.onCollectExtraUpdates(uiViewOperationQueue);
if (mPreparedSpannableText != null) {
ReactTextUpdate reactTextUpdate =
new ReactTextUpdate(mPreparedSpannableText, UNSET, mContainsImages, getPadding());
new ReactTextUpdate(mPreparedSpannableText, UNSET, mContainsImages, getPadding(), getEffectiveLineHeight());
uiViewOperationQueue.enqueueUpdateExtraData(getReactTag(), reactTextUpdate);
}
}
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -27,19 +27,22 @@ public class ReactTextUpdate {
private final float mPaddingTop;
private final float mPaddingRight;
private final float mPaddingBottom;
private final float mLineHeight;

public ReactTextUpdate(
Spannable text,
int jsEventCounter,
boolean containsImages,
Spacing padding) {
Spacing padding,
float lineHeight) {
mText = text;
mJsEventCounter = jsEventCounter;
mContainsImages = containsImages;
mPaddingLeft = padding.get(Spacing.LEFT);
mPaddingTop = padding.get(Spacing.TOP);
mPaddingRight = padding.get(Spacing.RIGHT);
mPaddingBottom = padding.get(Spacing.BOTTOM);
mLineHeight = lineHeight;
}

public Spannable getText() {
Expand DownExpand Up@@ -69,4 +72,8 @@ public float getPaddingRight() {
public float getPaddingBottom() {
return mPaddingBottom;
}

public float getLineHeight() {
return mLineHeight;
}
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -17,6 +17,7 @@
import android.view.ViewGroup;
import android.widget.TextView;

import com.facebook.csslayout.FloatUtil;
import com.facebook.react.uimanager.ReactCompoundView;

public class ReactTextView extends TextView implements ReactCompoundView {
Expand All@@ -28,6 +29,7 @@ public class ReactTextView extends TextView implements ReactCompoundView {
private int mDefaultGravityHorizontal;
private int mDefaultGravityVertical;
private boolean mTextIsSelectable;
private float mLineHeight = Float.NaN;

public ReactTextView(Context context) {
super(context);
Expand All@@ -50,6 +52,16 @@ public void setText(ReactTextUpdate update) {
(int) Math.ceil(update.getPaddingTop()),
(int) Math.ceil(update.getPaddingRight()),
(int) Math.ceil(update.getPaddingBottom()));

float nextLineHeight = update.getLineHeight();
if (!FloatUtil.floatsEqual(mLineHeight, nextLineHeight)) {
mLineHeight = nextLineHeight;
if (Float.isNaN(mLineHeight)) { // NaN will be used if property gets reset
setLineSpacing(0, 1);
} else {
setLineSpacing(mLineHeight, 0);
}
}
}

@Override
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -103,15 +103,6 @@ public void setTextAlignVertical(ReactTextView view, @Nullable String textAlignV
}
}

@ReactProp(name = ViewProps.LINE_HEIGHT, defaultFloat = Float.NaN)
public void setLineHeight(ReactTextView view, float lineHeight) {
if (Float.isNaN(lineHeight)) { // NaN will be used if property gets reset
view.setLineSpacing(0, 1);
} else {
view.setLineSpacing(PixelUtil.toPixelFromSP(lineHeight), 0);
}
}

@ReactProp(name = "selectable")
public void setSelectable(ReactTextView view, boolean isSelectable) {
view.setTextIsSelectable(isSelectable);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -67,4 +67,14 @@ public static void possiblyUpdateInlineImageSpans(Spannable spannable, TextView
* 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();
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -146,13 +146,21 @@ public void draw(

canvas.save();

int transY = bottom - mDrawable.getBounds().bottom;

// Align to baseline by default
transY -= paint.getFontMetricsInt().descent;
int transY = y - mDrawable.getBounds().bottom;

canvas.translate(x, transY);
mDrawable.draw(canvas);
canvas.restore();
}

@Override
public int getWidth() {
return mWidth;
}

@Override
public int getHeight() {
return mHeight;
}
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -119,7 +119,7 @@ public void onCollectExtraUpdates(UIViewOperationQueue uiViewOperationQueue) {
if (mJsEventCount != UNSET) {
Spannable preparedSpannableText = fromTextCSSNode(this);
ReactTextUpdate reactTextUpdate =
new ReactTextUpdate(preparedSpannableText, mJsEventCount, mContainsImages, getPadding());
new ReactTextUpdate(preparedSpannableText, mJsEventCount, mContainsImages, getPadding(), getEffectiveLineHeight());
uiViewOperationQueue.enqueueUpdateExtraData(getReactTag(), reactTextUpdate);
}
}
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Android: Fix handling of line height with inline images by rigdern · Pull Request #8907 · react/react-native · GitHub
Skip to content
Closed
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 numberDiff line numberDiff line change
Expand Up@@ -190,12 +190,17 @@ protected static Spannable fromTextCSSNode(ReactTextShadowNode textCSSNode) {
}

textCSSNode.mContainsImages = false;
textCSSNode.mHeightOfTallestInlineImage = Float.NaN;

// While setting the Spans on the final text, we also check whether any of them are images
for (int i = ops.size() - 1; i >= 0; i--) {
SetSpanOperation op = ops.get(i);
if (op.what instanceof TextInlineImageSpan) {
int height = ((TextInlineImageSpan)op.what).getHeight();
textCSSNode.mContainsImages = true;
if (Float.isNaN(textCSSNode.mHeightOfTallestInlineImage) || height > textCSSNode.mHeightOfTallestInlineImage) {
textCSSNode.mHeightOfTallestInlineImage = height;
}
}
op.execute(sb);
}
Expand DownExpand Up@@ -226,6 +231,14 @@ public void measure(
// technically, width should never be negative, but there is currently a bug in
boolean unconstrainedWidth = widthMode == CSSMeasureMode.UNDEFINED || width < 0;

float effectiveLineHeight = reactCSSNode.getEffectiveLineHeight();
float lineSpacingExtra = 0;
float lineSpacingMultiplier = 1;
if (!Float.isNaN(effectiveLineHeight)) {
lineSpacingExtra = effectiveLineHeight;
lineSpacingMultiplier = 0;
}

if (boring == null &&
(unconstrainedWidth ||
(!CSSConstants.isUndefined(desiredWidth) && desiredWidth <= width))) {
Expand All@@ -236,8 +249,8 @@ public void measure(
textPaint,
(int) Math.ceil(desiredWidth),
Layout.Alignment.ALIGN_NORMAL,
1,
0,
lineSpacingMultiplier,
lineSpacingExtra,
true);
} else if (boring != null && (unconstrainedWidth || boring.width <= width)) {
// Is used for single-line, boring text when the width is either unknown or bigger
Expand All@@ -247,8 +260,8 @@ public void measure(
textPaint,
boring.width,
Layout.Alignment.ALIGN_NORMAL,
1,
0,
lineSpacingMultiplier,
lineSpacingExtra,
boring,
true);
} else {
Expand All@@ -258,8 +271,8 @@ public void measure(
textPaint,
(int) width,
Layout.Alignment.ALIGN_NORMAL,
1,
0,
lineSpacingMultiplier,
lineSpacingExtra,
true);
}

Expand All@@ -269,13 +282,6 @@ public void measure(
reactCSSNode.mNumberOfLines < layout.getLineCount()) {
measureOutput.height = layout.getLineBottom(reactCSSNode.mNumberOfLines - 1);
}
if (reactCSSNode.mLineHeight != UNSET) {
int lines = reactCSSNode.mNumberOfLines != UNSET
? Math.min(reactCSSNode.mNumberOfLines, layout.getLineCount())
: layout.getLineCount();
float lineHeight = PixelUtil.toPixelFromSP(reactCSSNode.mLineHeight);
measureOutput.height = lineHeight * lines;
}
}
};

Expand All@@ -293,7 +299,7 @@ private static int parseNumericFontWeight(String fontWeightString) {
100 * (fontWeightString.charAt(0) - '0') : -1;
}

private int mLineHeight = UNSET;
private float mLineHeight = Float.NaN;
private boolean mIsColorSet = false;
private int mColor;
private boolean mIsBackgroundColorSet = false;
Expand DownExpand Up@@ -340,6 +346,7 @@ private static int parseNumericFontWeight(String fontWeightString) {
private final boolean mIsVirtual;

protected boolean mContainsImages = false;
private float mHeightOfTallestInlineImage = Float.NaN;

public ReactTextShadowNode(boolean isVirtual) {
mIsVirtual = isVirtual;
Expand All@@ -348,6 +355,15 @@ public ReactTextShadowNode(boolean isVirtual) {
}
}

// Returns a line height which takes into account the requested line height
// and the height of the inline images.
public float getEffectiveLineHeight() {
boolean useInlineViewHeight = !Float.isNaN(mLineHeight) &&
!Float.isNaN(mHeightOfTallestInlineImage) &&
mHeightOfTallestInlineImage > mLineHeight;
return useInlineViewHeight ? mHeightOfTallestInlineImage : mLineHeight;
}

@Override
public void onBeforeLayout() {
if (mIsVirtual) {
Expand DownExpand Up@@ -380,7 +396,7 @@ public void setNumberOfLines(int numberOfLines) {

@ReactProp(name = ViewProps.LINE_HEIGHT, defaultInt = UNSET)
public void setLineHeight(int lineHeight) {
mLineHeight = lineHeight;
mLineHeight = lineHeight == UNSET ? Float.NaN : PixelUtil.toPixelFromSP(lineHeight);
markUpdated();
}

Expand DownExpand Up@@ -530,7 +546,7 @@ public void onCollectExtraUpdates(UIViewOperationQueue uiViewOperationQueue) {
super.onCollectExtraUpdates(uiViewOperationQueue);
if (mPreparedSpannableText != null) {
ReactTextUpdate reactTextUpdate =
new ReactTextUpdate(mPreparedSpannableText, UNSET, mContainsImages, getPadding());
new ReactTextUpdate(mPreparedSpannableText, UNSET, mContainsImages, getPadding(), getEffectiveLineHeight());
uiViewOperationQueue.enqueueUpdateExtraData(getReactTag(), reactTextUpdate);
}
}
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -27,19 +27,22 @@ public class ReactTextUpdate {
private final float mPaddingTop;
private final float mPaddingRight;
private final float mPaddingBottom;
private final float mLineHeight;

public ReactTextUpdate(
Spannable text,
int jsEventCounter,
boolean containsImages,
Spacing padding) {
Spacing padding,
float lineHeight) {
mText = text;
mJsEventCounter = jsEventCounter;
mContainsImages = containsImages;
mPaddingLeft = padding.get(Spacing.LEFT);
mPaddingTop = padding.get(Spacing.TOP);
mPaddingRight = padding.get(Spacing.RIGHT);
mPaddingBottom = padding.get(Spacing.BOTTOM);
mLineHeight = lineHeight;
}

public Spannable getText() {
Expand DownExpand Up@@ -69,4 +72,8 @@ public float getPaddingRight() {
public float getPaddingBottom() {
return mPaddingBottom;
}

public float getLineHeight() {
return mLineHeight;
}
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -17,6 +17,7 @@
import android.view.ViewGroup;
import android.widget.TextView;

import com.facebook.csslayout.FloatUtil;
import com.facebook.react.uimanager.ReactCompoundView;

public class ReactTextView extends TextView implements ReactCompoundView {
Expand All@@ -28,6 +29,7 @@ public class ReactTextView extends TextView implements ReactCompoundView {
private int mDefaultGravityHorizontal;
private int mDefaultGravityVertical;
private boolean mTextIsSelectable;
private float mLineHeight = Float.NaN;

public ReactTextView(Context context) {
super(context);
Expand All@@ -50,6 +52,16 @@ public void setText(ReactTextUpdate update) {
(int) Math.ceil(update.getPaddingTop()),
(int) Math.ceil(update.getPaddingRight()),
(int) Math.ceil(update.getPaddingBottom()));

float nextLineHeight = update.getLineHeight();
if (!FloatUtil.floatsEqual(mLineHeight, nextLineHeight)) {
mLineHeight = nextLineHeight;
if (Float.isNaN(mLineHeight)) { // NaN will be used if property gets reset
setLineSpacing(0, 1);
} else {
setLineSpacing(mLineHeight, 0);
}
}
}

@Override
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -103,15 +103,6 @@ public void setTextAlignVertical(ReactTextView view, @Nullable String textAlignV
}
}

@ReactProp(name = ViewProps.LINE_HEIGHT, defaultFloat = Float.NaN)
public void setLineHeight(ReactTextView view, float lineHeight) {
if (Float.isNaN(lineHeight)) { // NaN will be used if property gets reset
view.setLineSpacing(0, 1);
} else {
view.setLineSpacing(PixelUtil.toPixelFromSP(lineHeight), 0);
}
}

@ReactProp(name = "selectable")
public void setSelectable(ReactTextView view, boolean isSelectable) {
view.setTextIsSelectable(isSelectable);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -67,4 +67,14 @@ public static void possiblyUpdateInlineImageSpans(Spannable spannable, TextView
* 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();
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -146,13 +146,21 @@ public void draw(

canvas.save();

int transY = bottom - mDrawable.getBounds().bottom;

// Align to baseline by default
transY -= paint.getFontMetricsInt().descent;
int transY = y - mDrawable.getBounds().bottom;

canvas.translate(x, transY);
mDrawable.draw(canvas);
canvas.restore();
}

@Override
public int getWidth() {
return mWidth;
}

@Override
public int getHeight() {
return mHeight;
}
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -119,7 +119,7 @@ public void onCollectExtraUpdates(UIViewOperationQueue uiViewOperationQueue) {
if (mJsEventCount != UNSET) {
Spannable preparedSpannableText = fromTextCSSNode(this);
ReactTextUpdate reactTextUpdate =
new ReactTextUpdate(preparedSpannableText, mJsEventCount, mContainsImages, getPadding());
new ReactTextUpdate(preparedSpannableText, mJsEventCount, mContainsImages, getPadding(), getEffectiveLineHeight());
uiViewOperationQueue.enqueueUpdateExtraData(getReactTag(), reactTextUpdate);
}
}
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' Android: Fix handling of line height with inline images by rigdern · Pull Request #8907 · react/react-native · GitHub
Skip to content
Closed
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 numberDiff line numberDiff line change
Expand Up@@ -190,12 +190,17 @@ protected static Spannable fromTextCSSNode(ReactTextShadowNode textCSSNode) {
}

textCSSNode.mContainsImages = false;
textCSSNode.mHeightOfTallestInlineImage = Float.NaN;

// While setting the Spans on the final text, we also check whether any of them are images
for (int i = ops.size() - 1; i >= 0; i--) {
SetSpanOperation op = ops.get(i);
if (op.what instanceof TextInlineImageSpan) {
int height = ((TextInlineImageSpan)op.what).getHeight();
textCSSNode.mContainsImages = true;
if (Float.isNaN(textCSSNode.mHeightOfTallestInlineImage) || height > textCSSNode.mHeightOfTallestInlineImage) {
textCSSNode.mHeightOfTallestInlineImage = height;
}
}
op.execute(sb);
}
Expand DownExpand Up@@ -226,6 +231,14 @@ public void measure(
// technically, width should never be negative, but there is currently a bug in
boolean unconstrainedWidth = widthMode == CSSMeasureMode.UNDEFINED || width < 0;

float effectiveLineHeight = reactCSSNode.getEffectiveLineHeight();
float lineSpacingExtra = 0;
float lineSpacingMultiplier = 1;
if (!Float.isNaN(effectiveLineHeight)) {
lineSpacingExtra = effectiveLineHeight;
lineSpacingMultiplier = 0;
}

if (boring == null &&
(unconstrainedWidth ||
(!CSSConstants.isUndefined(desiredWidth) && desiredWidth <= width))) {
Expand All@@ -236,8 +249,8 @@ public void measure(
textPaint,
(int) Math.ceil(desiredWidth),
Layout.Alignment.ALIGN_NORMAL,
1,
0,
lineSpacingMultiplier,
lineSpacingExtra,
true);
} else if (boring != null && (unconstrainedWidth || boring.width <= width)) {
// Is used for single-line, boring text when the width is either unknown or bigger
Expand All@@ -247,8 +260,8 @@ public void measure(
textPaint,
boring.width,
Layout.Alignment.ALIGN_NORMAL,
1,
0,
lineSpacingMultiplier,
lineSpacingExtra,
boring,
true);
} else {
Expand All@@ -258,8 +271,8 @@ public void measure(
textPaint,
(int) width,
Layout.Alignment.ALIGN_NORMAL,
1,
0,
lineSpacingMultiplier,
lineSpacingExtra,
true);
}

Expand All@@ -269,13 +282,6 @@ public void measure(
reactCSSNode.mNumberOfLines < layout.getLineCount()) {
measureOutput.height = layout.getLineBottom(reactCSSNode.mNumberOfLines - 1);
}
if (reactCSSNode.mLineHeight != UNSET) {
int lines = reactCSSNode.mNumberOfLines != UNSET
? Math.min(reactCSSNode.mNumberOfLines, layout.getLineCount())
: layout.getLineCount();
float lineHeight = PixelUtil.toPixelFromSP(reactCSSNode.mLineHeight);
measureOutput.height = lineHeight * lines;
}
}
};

Expand All@@ -293,7 +299,7 @@ private static int parseNumericFontWeight(String fontWeightString) {
100 * (fontWeightString.charAt(0) - '0') : -1;
}

private int mLineHeight = UNSET;
private float mLineHeight = Float.NaN;
private boolean mIsColorSet = false;
private int mColor;
private boolean mIsBackgroundColorSet = false;
Expand DownExpand Up@@ -340,6 +346,7 @@ private static int parseNumericFontWeight(String fontWeightString) {
private final boolean mIsVirtual;

protected boolean mContainsImages = false;
private float mHeightOfTallestInlineImage = Float.NaN;

public ReactTextShadowNode(boolean isVirtual) {
mIsVirtual = isVirtual;
Expand All@@ -348,6 +355,15 @@ public ReactTextShadowNode(boolean isVirtual) {
}
}

// Returns a line height which takes into account the requested line height
// and the height of the inline images.
public float getEffectiveLineHeight() {
boolean useInlineViewHeight = !Float.isNaN(mLineHeight) &&
!Float.isNaN(mHeightOfTallestInlineImage) &&
mHeightOfTallestInlineImage > mLineHeight;
return useInlineViewHeight ? mHeightOfTallestInlineImage : mLineHeight;
}

@Override
public void onBeforeLayout() {
if (mIsVirtual) {
Expand DownExpand Up@@ -380,7 +396,7 @@ public void setNumberOfLines(int numberOfLines) {

@ReactProp(name = ViewProps.LINE_HEIGHT, defaultInt = UNSET)
public void setLineHeight(int lineHeight) {
mLineHeight = lineHeight;
mLineHeight = lineHeight == UNSET ? Float.NaN : PixelUtil.toPixelFromSP(lineHeight);
markUpdated();
}

Expand DownExpand Up@@ -530,7 +546,7 @@ public void onCollectExtraUpdates(UIViewOperationQueue uiViewOperationQueue) {
super.onCollectExtraUpdates(uiViewOperationQueue);
if (mPreparedSpannableText != null) {
ReactTextUpdate reactTextUpdate =
new ReactTextUpdate(mPreparedSpannableText, UNSET, mContainsImages, getPadding());
new ReactTextUpdate(mPreparedSpannableText, UNSET, mContainsImages, getPadding(), getEffectiveLineHeight());
uiViewOperationQueue.enqueueUpdateExtraData(getReactTag(), reactTextUpdate);
}
}
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -27,19 +27,22 @@ public class ReactTextUpdate {
private final float mPaddingTop;
private final float mPaddingRight;
private final float mPaddingBottom;
private final float mLineHeight;

public ReactTextUpdate(
Spannable text,
int jsEventCounter,
boolean containsImages,
Spacing padding) {
Spacing padding,
float lineHeight) {
mText = text;
mJsEventCounter = jsEventCounter;
mContainsImages = containsImages;
mPaddingLeft = padding.get(Spacing.LEFT);
mPaddingTop = padding.get(Spacing.TOP);
mPaddingRight = padding.get(Spacing.RIGHT);
mPaddingBottom = padding.get(Spacing.BOTTOM);
mLineHeight = lineHeight;
}

public Spannable getText() {
Expand DownExpand Up@@ -69,4 +72,8 @@ public float getPaddingRight() {
public float getPaddingBottom() {
return mPaddingBottom;
}

public float getLineHeight() {
return mLineHeight;
}
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -17,6 +17,7 @@
import android.view.ViewGroup;
import android.widget.TextView;

import com.facebook.csslayout.FloatUtil;
import com.facebook.react.uimanager.ReactCompoundView;

public class ReactTextView extends TextView implements ReactCompoundView {
Expand All@@ -28,6 +29,7 @@ public class ReactTextView extends TextView implements ReactCompoundView {
private int mDefaultGravityHorizontal;
private int mDefaultGravityVertical;
private boolean mTextIsSelectable;
private float mLineHeight = Float.NaN;

public ReactTextView(Context context) {
super(context);
Expand All@@ -50,6 +52,16 @@ public void setText(ReactTextUpdate update) {
(int) Math.ceil(update.getPaddingTop()),
(int) Math.ceil(update.getPaddingRight()),
(int) Math.ceil(update.getPaddingBottom()));

float nextLineHeight = update.getLineHeight();
if (!FloatUtil.floatsEqual(mLineHeight, nextLineHeight)) {
mLineHeight = nextLineHeight;
if (Float.isNaN(mLineHeight)) { // NaN will be used if property gets reset
setLineSpacing(0, 1);
} else {
setLineSpacing(mLineHeight, 0);
}
}
}

@Override
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -103,15 +103,6 @@ public void setTextAlignVertical(ReactTextView view, @Nullable String textAlignV
}
}

@ReactProp(name = ViewProps.LINE_HEIGHT, defaultFloat = Float.NaN)
public void setLineHeight(ReactTextView view, float lineHeight) {
if (Float.isNaN(lineHeight)) { // NaN will be used if property gets reset
view.setLineSpacing(0, 1);
} else {
view.setLineSpacing(PixelUtil.toPixelFromSP(lineHeight), 0);
}
}

@ReactProp(name = "selectable")
public void setSelectable(ReactTextView view, boolean isSelectable) {
view.setTextIsSelectable(isSelectable);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -67,4 +67,14 @@ public static void possiblyUpdateInlineImageSpans(Spannable spannable, TextView
* 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();
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -146,13 +146,21 @@ public void draw(

canvas.save();

int transY = bottom - mDrawable.getBounds().bottom;

// Align to baseline by default
transY -= paint.getFontMetricsInt().descent;
int transY = y - mDrawable.getBounds().bottom;

canvas.translate(x, transY);
mDrawable.draw(canvas);
canvas.restore();
}

@Override
public int getWidth() {
return mWidth;
}

@Override
public int getHeight() {
return mHeight;
}
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -119,7 +119,7 @@ public void onCollectExtraUpdates(UIViewOperationQueue uiViewOperationQueue) {
if (mJsEventCount != UNSET) {
Spannable preparedSpannableText = fromTextCSSNode(this);
ReactTextUpdate reactTextUpdate =
new ReactTextUpdate(preparedSpannableText, mJsEventCount, mContainsImages, getPadding());
new ReactTextUpdate(preparedSpannableText, mJsEventCount, mContainsImages, getPadding(), getEffectiveLineHeight());
uiViewOperationQueue.enqueueUpdateExtraData(getReactTag(), reactTextUpdate);
}
}
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Android: Fix handling of line height with inline images by rigdern · Pull Request #8907 · react/react-native · GitHub
Skip to content
Closed
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 numberDiff line numberDiff line change
Expand Up@@ -190,12 +190,17 @@ protected static Spannable fromTextCSSNode(ReactTextShadowNode textCSSNode) {
}

textCSSNode.mContainsImages = false;
textCSSNode.mHeightOfTallestInlineImage = Float.NaN;

// While setting the Spans on the final text, we also check whether any of them are images
for (int i = ops.size() - 1; i >= 0; i--) {
SetSpanOperation op = ops.get(i);
if (op.what instanceof TextInlineImageSpan) {
int height = ((TextInlineImageSpan)op.what).getHeight();
textCSSNode.mContainsImages = true;
if (Float.isNaN(textCSSNode.mHeightOfTallestInlineImage) || height > textCSSNode.mHeightOfTallestInlineImage) {
textCSSNode.mHeightOfTallestInlineImage = height;
}
}
op.execute(sb);
}
Expand DownExpand Up@@ -226,6 +231,14 @@ public void measure(
// technically, width should never be negative, but there is currently a bug in
boolean unconstrainedWidth = widthMode == CSSMeasureMode.UNDEFINED || width < 0;

float effectiveLineHeight = reactCSSNode.getEffectiveLineHeight();
float lineSpacingExtra = 0;
float lineSpacingMultiplier = 1;
if (!Float.isNaN(effectiveLineHeight)) {
lineSpacingExtra = effectiveLineHeight;
lineSpacingMultiplier = 0;
}

if (boring == null &&
(unconstrainedWidth ||
(!CSSConstants.isUndefined(desiredWidth) && desiredWidth <= width))) {
Expand All@@ -236,8 +249,8 @@ public void measure(
textPaint,
(int) Math.ceil(desiredWidth),
Layout.Alignment.ALIGN_NORMAL,
1,
0,
lineSpacingMultiplier,
lineSpacingExtra,
true);
} else if (boring != null && (unconstrainedWidth || boring.width <= width)) {
// Is used for single-line, boring text when the width is either unknown or bigger
Expand All@@ -247,8 +260,8 @@ public void measure(
textPaint,
boring.width,
Layout.Alignment.ALIGN_NORMAL,
1,
0,
lineSpacingMultiplier,
lineSpacingExtra,
boring,
true);
} else {
Expand All@@ -258,8 +271,8 @@ public void measure(
textPaint,
(int) width,
Layout.Alignment.ALIGN_NORMAL,
1,
0,
lineSpacingMultiplier,
lineSpacingExtra,
true);
}

Expand All@@ -269,13 +282,6 @@ public void measure(
reactCSSNode.mNumberOfLines < layout.getLineCount()) {
measureOutput.height = layout.getLineBottom(reactCSSNode.mNumberOfLines - 1);
}
if (reactCSSNode.mLineHeight != UNSET) {
int lines = reactCSSNode.mNumberOfLines != UNSET
? Math.min(reactCSSNode.mNumberOfLines, layout.getLineCount())
: layout.getLineCount();
float lineHeight = PixelUtil.toPixelFromSP(reactCSSNode.mLineHeight);
measureOutput.height = lineHeight * lines;
}
}
};

Expand All@@ -293,7 +299,7 @@ private static int parseNumericFontWeight(String fontWeightString) {
100 * (fontWeightString.charAt(0) - '0') : -1;
}

private int mLineHeight = UNSET;
private float mLineHeight = Float.NaN;
private boolean mIsColorSet = false;
private int mColor;
private boolean mIsBackgroundColorSet = false;
Expand DownExpand Up@@ -340,6 +346,7 @@ private static int parseNumericFontWeight(String fontWeightString) {
private final boolean mIsVirtual;

protected boolean mContainsImages = false;
private float mHeightOfTallestInlineImage = Float.NaN;

public ReactTextShadowNode(boolean isVirtual) {
mIsVirtual = isVirtual;
Expand All@@ -348,6 +355,15 @@ public ReactTextShadowNode(boolean isVirtual) {
}
}

// Returns a line height which takes into account the requested line height
// and the height of the inline images.
public float getEffectiveLineHeight() {
boolean useInlineViewHeight = !Float.isNaN(mLineHeight) &&
!Float.isNaN(mHeightOfTallestInlineImage) &&
mHeightOfTallestInlineImage > mLineHeight;
return useInlineViewHeight ? mHeightOfTallestInlineImage : mLineHeight;
}

@Override
public void onBeforeLayout() {
if (mIsVirtual) {
Expand DownExpand Up@@ -380,7 +396,7 @@ public void setNumberOfLines(int numberOfLines) {

@ReactProp(name = ViewProps.LINE_HEIGHT, defaultInt = UNSET)
public void setLineHeight(int lineHeight) {
mLineHeight = lineHeight;
mLineHeight = lineHeight == UNSET ? Float.NaN : PixelUtil.toPixelFromSP(lineHeight);
markUpdated();
}

Expand DownExpand Up@@ -530,7 +546,7 @@ public void onCollectExtraUpdates(UIViewOperationQueue uiViewOperationQueue) {
super.onCollectExtraUpdates(uiViewOperationQueue);
if (mPreparedSpannableText != null) {
ReactTextUpdate reactTextUpdate =
new ReactTextUpdate(mPreparedSpannableText, UNSET, mContainsImages, getPadding());
new ReactTextUpdate(mPreparedSpannableText, UNSET, mContainsImages, getPadding(), getEffectiveLineHeight());
uiViewOperationQueue.enqueueUpdateExtraData(getReactTag(), reactTextUpdate);
}
}
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -27,19 +27,22 @@ public class ReactTextUpdate {
private final float mPaddingTop;
private final float mPaddingRight;
private final float mPaddingBottom;
private final float mLineHeight;

public ReactTextUpdate(
Spannable text,
int jsEventCounter,
boolean containsImages,
Spacing padding) {
Spacing padding,
float lineHeight) {
mText = text;
mJsEventCounter = jsEventCounter;
mContainsImages = containsImages;
mPaddingLeft = padding.get(Spacing.LEFT);
mPaddingTop = padding.get(Spacing.TOP);
mPaddingRight = padding.get(Spacing.RIGHT);
mPaddingBottom = padding.get(Spacing.BOTTOM);
mLineHeight = lineHeight;
}

public Spannable getText() {
Expand DownExpand Up@@ -69,4 +72,8 @@ public float getPaddingRight() {
public float getPaddingBottom() {
return mPaddingBottom;
}

public float getLineHeight() {
return mLineHeight;
}
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -17,6 +17,7 @@
import android.view.ViewGroup;
import android.widget.TextView;

import com.facebook.csslayout.FloatUtil;
import com.facebook.react.uimanager.ReactCompoundView;

public class ReactTextView extends TextView implements ReactCompoundView {
Expand All@@ -28,6 +29,7 @@ public class ReactTextView extends TextView implements ReactCompoundView {
private int mDefaultGravityHorizontal;
private int mDefaultGravityVertical;
private boolean mTextIsSelectable;
private float mLineHeight = Float.NaN;

public ReactTextView(Context context) {
super(context);
Expand All@@ -50,6 +52,16 @@ public void setText(ReactTextUpdate update) {
(int) Math.ceil(update.getPaddingTop()),
(int) Math.ceil(update.getPaddingRight()),
(int) Math.ceil(update.getPaddingBottom()));

float nextLineHeight = update.getLineHeight();
if (!FloatUtil.floatsEqual(mLineHeight, nextLineHeight)) {
mLineHeight = nextLineHeight;
if (Float.isNaN(mLineHeight)) { // NaN will be used if property gets reset
setLineSpacing(0, 1);
} else {
setLineSpacing(mLineHeight, 0);
}
}
}

@Override
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -103,15 +103,6 @@ public void setTextAlignVertical(ReactTextView view, @Nullable String textAlignV
}
}

@ReactProp(name = ViewProps.LINE_HEIGHT, defaultFloat = Float.NaN)
public void setLineHeight(ReactTextView view, float lineHeight) {
if (Float.isNaN(lineHeight)) { // NaN will be used if property gets reset
view.setLineSpacing(0, 1);
} else {
view.setLineSpacing(PixelUtil.toPixelFromSP(lineHeight), 0);
}
}

@ReactProp(name = "selectable")
public void setSelectable(ReactTextView view, boolean isSelectable) {
view.setTextIsSelectable(isSelectable);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -67,4 +67,14 @@ public static void possiblyUpdateInlineImageSpans(Spannable spannable, TextView
* 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();
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -146,13 +146,21 @@ public void draw(

canvas.save();

int transY = bottom - mDrawable.getBounds().bottom;

// Align to baseline by default
transY -= paint.getFontMetricsInt().descent;
int transY = y - mDrawable.getBounds().bottom;

canvas.translate(x, transY);
mDrawable.draw(canvas);
canvas.restore();
}

@Override
public int getWidth() {
return mWidth;
}

@Override
public int getHeight() {
return mHeight;
}
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -119,7 +119,7 @@ public void onCollectExtraUpdates(UIViewOperationQueue uiViewOperationQueue) {
if (mJsEventCount != UNSET) {
Spannable preparedSpannableText = fromTextCSSNode(this);
ReactTextUpdate reactTextUpdate =
new ReactTextUpdate(preparedSpannableText, mJsEventCount, mContainsImages, getPadding());
new ReactTextUpdate(preparedSpannableText, mJsEventCount, mContainsImages, getPadding(), getEffectiveLineHeight());
uiViewOperationQueue.enqueueUpdateExtraData(getReactTag(), reactTextUpdate);
}
}
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); })(); Android: Fix handling of line height with inline images by rigdern · Pull Request #8907 · react/react-native · GitHub
Skip to content
Closed
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 numberDiff line numberDiff line change
Expand Up@@ -190,12 +190,17 @@ protected static Spannable fromTextCSSNode(ReactTextShadowNode textCSSNode) {
}

textCSSNode.mContainsImages = false;
textCSSNode.mHeightOfTallestInlineImage = Float.NaN;

// While setting the Spans on the final text, we also check whether any of them are images
for (int i = ops.size() - 1; i >= 0; i--) {
SetSpanOperation op = ops.get(i);
if (op.what instanceof TextInlineImageSpan) {
int height = ((TextInlineImageSpan)op.what).getHeight();
textCSSNode.mContainsImages = true;
if (Float.isNaN(textCSSNode.mHeightOfTallestInlineImage) || height > textCSSNode.mHeightOfTallestInlineImage) {
textCSSNode.mHeightOfTallestInlineImage = height;
}
}
op.execute(sb);
}
Expand DownExpand Up@@ -226,6 +231,14 @@ public void measure(
// technically, width should never be negative, but there is currently a bug in
boolean unconstrainedWidth = widthMode == CSSMeasureMode.UNDEFINED || width < 0;

float effectiveLineHeight = reactCSSNode.getEffectiveLineHeight();
float lineSpacingExtra = 0;
float lineSpacingMultiplier = 1;
if (!Float.isNaN(effectiveLineHeight)) {
lineSpacingExtra = effectiveLineHeight;
lineSpacingMultiplier = 0;
}

if (boring == null &&
(unconstrainedWidth ||
(!CSSConstants.isUndefined(desiredWidth) && desiredWidth <= width))) {
Expand All@@ -236,8 +249,8 @@ public void measure(
textPaint,
(int) Math.ceil(desiredWidth),
Layout.Alignment.ALIGN_NORMAL,
1,
0,
lineSpacingMultiplier,
lineSpacingExtra,
true);
} else if (boring != null && (unconstrainedWidth || boring.width <= width)) {
// Is used for single-line, boring text when the width is either unknown or bigger
Expand All@@ -247,8 +260,8 @@ public void measure(
textPaint,
boring.width,
Layout.Alignment.ALIGN_NORMAL,
1,
0,
lineSpacingMultiplier,
lineSpacingExtra,
boring,
true);
} else {
Expand All@@ -258,8 +271,8 @@ public void measure(
textPaint,
(int) width,
Layout.Alignment.ALIGN_NORMAL,
1,
0,
lineSpacingMultiplier,
lineSpacingExtra,
true);
}

Expand All@@ -269,13 +282,6 @@ public void measure(
reactCSSNode.mNumberOfLines < layout.getLineCount()) {
measureOutput.height = layout.getLineBottom(reactCSSNode.mNumberOfLines - 1);
}
if (reactCSSNode.mLineHeight != UNSET) {
int lines = reactCSSNode.mNumberOfLines != UNSET
? Math.min(reactCSSNode.mNumberOfLines, layout.getLineCount())
: layout.getLineCount();
float lineHeight = PixelUtil.toPixelFromSP(reactCSSNode.mLineHeight);
measureOutput.height = lineHeight * lines;
}
}
};

Expand All@@ -293,7 +299,7 @@ private static int parseNumericFontWeight(String fontWeightString) {
100 * (fontWeightString.charAt(0) - '0') : -1;
}

private int mLineHeight = UNSET;
private float mLineHeight = Float.NaN;
private boolean mIsColorSet = false;
private int mColor;
private boolean mIsBackgroundColorSet = false;
Expand DownExpand Up@@ -340,6 +346,7 @@ private static int parseNumericFontWeight(String fontWeightString) {
private final boolean mIsVirtual;

protected boolean mContainsImages = false;
private float mHeightOfTallestInlineImage = Float.NaN;

public ReactTextShadowNode(boolean isVirtual) {
mIsVirtual = isVirtual;
Expand All@@ -348,6 +355,15 @@ public ReactTextShadowNode(boolean isVirtual) {
}
}

// Returns a line height which takes into account the requested line height
// and the height of the inline images.
public float getEffectiveLineHeight() {
boolean useInlineViewHeight = !Float.isNaN(mLineHeight) &&
!Float.isNaN(mHeightOfTallestInlineImage) &&
mHeightOfTallestInlineImage > mLineHeight;
return useInlineViewHeight ? mHeightOfTallestInlineImage : mLineHeight;
}

@Override
public void onBeforeLayout() {
if (mIsVirtual) {
Expand DownExpand Up@@ -380,7 +396,7 @@ public void setNumberOfLines(int numberOfLines) {

@ReactProp(name = ViewProps.LINE_HEIGHT, defaultInt = UNSET)
public void setLineHeight(int lineHeight) {
mLineHeight = lineHeight;
mLineHeight = lineHeight == UNSET ? Float.NaN : PixelUtil.toPixelFromSP(lineHeight);
markUpdated();
}

Expand DownExpand Up@@ -530,7 +546,7 @@ public void onCollectExtraUpdates(UIViewOperationQueue uiViewOperationQueue) {
super.onCollectExtraUpdates(uiViewOperationQueue);
if (mPreparedSpannableText != null) {
ReactTextUpdate reactTextUpdate =
new ReactTextUpdate(mPreparedSpannableText, UNSET, mContainsImages, getPadding());
new ReactTextUpdate(mPreparedSpannableText, UNSET, mContainsImages, getPadding(), getEffectiveLineHeight());
uiViewOperationQueue.enqueueUpdateExtraData(getReactTag(), reactTextUpdate);
}
}
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -27,19 +27,22 @@ public class ReactTextUpdate {
private final float mPaddingTop;
private final float mPaddingRight;
private final float mPaddingBottom;
private final float mLineHeight;

public ReactTextUpdate(
Spannable text,
int jsEventCounter,
boolean containsImages,
Spacing padding) {
Spacing padding,
float lineHeight) {
mText = text;
mJsEventCounter = jsEventCounter;
mContainsImages = containsImages;
mPaddingLeft = padding.get(Spacing.LEFT);
mPaddingTop = padding.get(Spacing.TOP);
mPaddingRight = padding.get(Spacing.RIGHT);
mPaddingBottom = padding.get(Spacing.BOTTOM);
mLineHeight = lineHeight;
}

public Spannable getText() {
Expand DownExpand Up@@ -69,4 +72,8 @@ public float getPaddingRight() {
public float getPaddingBottom() {
return mPaddingBottom;
}

public float getLineHeight() {
return mLineHeight;
}
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -17,6 +17,7 @@
import android.view.ViewGroup;
import android.widget.TextView;

import com.facebook.csslayout.FloatUtil;
import com.facebook.react.uimanager.ReactCompoundView;

public class ReactTextView extends TextView implements ReactCompoundView {
Expand All@@ -28,6 +29,7 @@ public class ReactTextView extends TextView implements ReactCompoundView {
private int mDefaultGravityHorizontal;
private int mDefaultGravityVertical;
private boolean mTextIsSelectable;
private float mLineHeight = Float.NaN;

public ReactTextView(Context context) {
super(context);
Expand All@@ -50,6 +52,16 @@ public void setText(ReactTextUpdate update) {
(int) Math.ceil(update.getPaddingTop()),
(int) Math.ceil(update.getPaddingRight()),
(int) Math.ceil(update.getPaddingBottom()));

float nextLineHeight = update.getLineHeight();
if (!FloatUtil.floatsEqual(mLineHeight, nextLineHeight)) {
mLineHeight = nextLineHeight;
if (Float.isNaN(mLineHeight)) { // NaN will be used if property gets reset
setLineSpacing(0, 1);
} else {
setLineSpacing(mLineHeight, 0);
}
}
}

@Override
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -103,15 +103,6 @@ public void setTextAlignVertical(ReactTextView view, @Nullable String textAlignV
}
}

@ReactProp(name = ViewProps.LINE_HEIGHT, defaultFloat = Float.NaN)
public void setLineHeight(ReactTextView view, float lineHeight) {
if (Float.isNaN(lineHeight)) { // NaN will be used if property gets reset
view.setLineSpacing(0, 1);
} else {
view.setLineSpacing(PixelUtil.toPixelFromSP(lineHeight), 0);
}
}

@ReactProp(name = "selectable")
public void setSelectable(ReactTextView view, boolean isSelectable) {
view.setTextIsSelectable(isSelectable);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -67,4 +67,14 @@ public static void possiblyUpdateInlineImageSpans(Spannable spannable, TextView
* 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();
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -146,13 +146,21 @@ public void draw(

canvas.save();

int transY = bottom - mDrawable.getBounds().bottom;

// Align to baseline by default
transY -= paint.getFontMetricsInt().descent;
int transY = y - mDrawable.getBounds().bottom;

canvas.translate(x, transY);
mDrawable.draw(canvas);
canvas.restore();
}

@Override
public int getWidth() {
return mWidth;
}

@Override
public int getHeight() {
return mHeight;
}
}
Original file line numberDiff line numberDiff line change
Expand Up@@ -119,7 +119,7 @@ public void onCollectExtraUpdates(UIViewOperationQueue uiViewOperationQueue) {
if (mJsEventCount != UNSET) {
Spannable preparedSpannableText = fromTextCSSNode(this);
ReactTextUpdate reactTextUpdate =
new ReactTextUpdate(preparedSpannableText, mJsEventCount, mContainsImages, getPadding());
new ReactTextUpdate(preparedSpannableText, mJsEventCount, mContainsImages, getPadding(), getEffectiveLineHeight());
uiViewOperationQueue.enqueueUpdateExtraData(getReactTag(), reactTextUpdate);
}
}
Expand Down