Skip to content

🗑️ Calculate line height and font metrics - CLOSED 🗑️ #8

New issue

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

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

Already on GitHub? Sign in to your account

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 number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@
import android.text.TextPaint;
import android.text.style.MetricAffectingSpan;
import androidx.annotation.Nullable;
import com.facebook.common.logging.FLog;
import com.facebook.infer.annotation.Nullsafe;

@Nullsafe(Nullsafe.Mode.LOCAL)
public class CustomStyleSpan extends MetricAffectingSpan implements ReactSpan {

private static final String TAG = "CustomStyleSpan";
/**
* 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
Expand All @@ -38,6 +40,8 @@ public class CustomStyleSpan extends MetricAffectingSpan implements ReactSpan {
private final String mCurrentText;
private String mTextAlignVertical;
private int mHighestLineHeight;
private int mLineHeight;
private int mLineCount;

public CustomStyleSpan(
int fontStyle,
Expand Down Expand Up @@ -67,7 +71,8 @@ public void updateDrawState(TextPaint ds) {
mAssetManager,
mTextAlignVertical,
mCurrentText,
mHighestLineHeight);
mHighestLineHeight,
mLineHeight);
}

@Override
Expand All @@ -81,7 +86,8 @@ public void updateMeasureState(TextPaint paint) {
mAssetManager,
mTextAlignVertical,
mCurrentText,
mHighestLineHeight);
mHighestLineHeight,
mLineHeight);
}

public int getStyle() {
Expand All @@ -105,7 +111,8 @@ private static void apply(
AssetManager assetManager,
@Nullable String textAlignVertical,
String currentText,
int highestLineHeight) {
int highestLineHeight,
int lineHeight) {
Typeface typeface =
ReactTypefaceUtils.applyStyles(paint.getTypeface(), style, weight, family, assetManager);
paint.setFontFeatureSettings(fontFeatureSettings);
Expand All @@ -119,33 +126,54 @@ private static void apply(
if (highestLineHeight != 0) {
// the span with the highest lineHeight sets the height for all rows
paint.baselineShift -= highestLineHeight / 2 - paint.getTextSize() / 2;
} else if (lineHeight > 0) {
float fontHeight = paint.getFontMetrics().bottom - paint.getFontMetrics().top;
String methodName = new Object() {}.getClass().getEnclosingMethod().getName();
FLog.w(
"React::" + TAG,
methodName
+ " currentText: "
+ (currentText)
+ " fontHeight: "
+ (fontHeight)
+ " lineHeight: "
+ (lineHeight)
+ " paint.getFontMetrics().top: "
+ (paint.getFontMetrics().top)
+ " paint.getFontMetrics().bottom: "
+ (paint.getFontMetrics().bottom));
paint.baselineShift -= lineHeight - paint.getTextSize();
} else {
// works only with single line and without fontSize
// https://bit.ly/3W2eJKT
// if lineHeight is not set, align the text using the font metrics
// https://stackoverflow.com/a/27631737/7295772
// top ------------- -26
// ascent ------------- -30
// baseline __my Text____ 0
// descent _____________ 8
// bottom _____________ 1
paint.baselineShift -= bounds.bottom - paint.ascent() + bounds.top;
// top -------------
// ascent -------------
// baseline __my Text____
// descent _____________
// bottom _____________
// paint.baselineShift += paint.getFontMetrics().top - paint.getFontMetrics().ascent;
}
}
if (textAlignVertical == "bottom-child") {
if (highestLineHeight != 0) {
// the span with the highest lineHeight sets the height for all rows
paint.baselineShift += highestLineHeight / 2 - paint.getTextSize() / 2;
} else if (lineHeight > 0) {
paint.baselineShift += lineHeight - paint.getTextSize();
} else {
// works only with single line and without fontSize
// https://bit.ly/3W2eJKT
paint.baselineShift += paint.descent();
// paint.baselineShift += paint.getFontMetrics().bottom - paint.descent();
}
}
}
}

public void updateSpan(int highestLineHeight) {
public void updateSpan(int highestLineHeight, int lineCount, int lineHeight) {
mHighestLineHeight = highestLineHeight;
mLineCount = lineCount;
mLineHeight = lineHeight;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,33 @@

package com.facebook.react.views.text;

import android.text.TextPaint;
import android.text.style.AbsoluteSizeSpan;
import androidx.annotation.NonNull;
import com.facebook.common.logging.FLog;

/*
* Wraps {@link AbsoluteSizeSpan} as a {@link ReactSpan}.
*/
public class ReactAbsoluteSizeSpan extends AbsoluteSizeSpan implements ReactSpan {
private static final String TAG = "ReactAbsoluteSizeSpan";

public ReactAbsoluteSizeSpan(int size) {
super(size);
}

@Override
public void updateDrawState(@NonNull TextPaint ds) {
super.updateDrawState(ds);
String methodName = new Object() {}.getClass().getEnclosingMethod().getName();
FLog.w(
"React::" + TAG,
methodName
+ " ds.getFontMetrics().top: "
+ (ds.getFontMetrics().top)
+ " ds.getFontMetrics().bottom: "
+ (ds.getFontMetrics().bottom)
+ " getSize(): "
+ (getSize()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
package com.facebook.react.views.text;

import android.content.Context;
import android.text.Layout;
import android.text.Spannable;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
Expand Down Expand Up @@ -43,6 +44,7 @@ public class ReactTextViewManager
private static final short TX_STATE_KEY_MOST_RECENT_EVENT_COUNT = 3;

@VisibleForTesting public static final String REACT_CLASS = "RCTText";
private static final String TAG = "ReactTextViewManager";

protected @Nullable ReactTextViewManagerCallback mReactTextViewManagerCallback;

Expand Down Expand Up @@ -104,20 +106,23 @@ public void updateExtraData(ReactTextView view, Object extraData) {

CustomLineHeightSpan[] customLineHeightSpans =
spannable.getSpans(0, spannable.length(), CustomLineHeightSpan.class);
int highestLineHeight = 0;
if (customLineHeightSpans.length > 0) {
int highestLineHeight = 0;
for (CustomLineHeightSpan span : customLineHeightSpans) {
if (highestLineHeight == 0 || span.getLineHeight() > highestLineHeight) {
highestLineHeight = span.getLineHeight();
}
}
}

CustomStyleSpan[] customStyleSpans =
spannable.getSpans(0, spannable.length(), CustomStyleSpan.class);
if (customStyleSpans.length != 0) {
for (CustomStyleSpan span : customStyleSpans) {
span.updateSpan(highestLineHeight);
}
CustomStyleSpan[] customStyleSpans =
spannable.getSpans(0, spannable.length(), CustomStyleSpan.class);
if (customStyleSpans.length != 0) {
Layout layout = view.getLayout();
int lineCount = layout != null ? layout.getLineCount() : 1;
int lineHeight = layout != null ? layout.getHeight() : 0;
for (CustomStyleSpan span : customStyleSpans) {
span.updateSpan(highestLineHeight, lineCount, lineHeight);
}
}
}
Expand Down
26 changes: 16 additions & 10 deletions packages/rn-tester/js/examples/Text/TextExample.android.js
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,7 @@ class NestedTextVerticalAlign extends React.Component<{...}> {
<Text>
vertical align is set to{' '}
<Text style={{backgroundColor: 'red'}}>{textAlignVertical}</Text>
<Text style={{backgroundColor: 'green'}}>{fontSize}</Text>
</Text>
<Button
onPress={() => this.changeVerticalAlign()}
Expand All @@ -323,20 +324,25 @@ class NestedTextVerticalAlign extends React.Component<{...}> {
/>
<Button onPress={() => this.increaseFont()} title="increase font" />
<View>
<Text
style={{
fontSize,
backgroundColor: 'yellow',
}}>
<View style={{height: 300, backgroundColor: 'red'}}>
<Text
style={{
textAlignVertical,
backgroundColor: 'green',
color: 'white',
flex: 1,
fontSize,
textAlignVertical: 'center',
allowFontScaling: false,
backgroundColor: 'yellow',
}}>
Custom font
<Text
style={{
textAlignVertical,
backgroundColor: 'green',
color: 'white',
}}>
CusTom teXt PjYx;,\
</Text>
</Text>
</Text>
</View>
<Text>
Without lineHeight prop, the green text is correctly aligned, but
does not support ReactAbsoluteSizeSpan (nested Text with different
Expand Down