|
| 1 | +diff --git a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/internal/span/CustomLineHeightSpan.kt b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/internal/span/CustomLineHeightSpan.kt |
| 2 | +index c73d42f..11b70e1 100644 |
| 3 | +--- a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/internal/span/CustomLineHeightSpan.kt |
| 4 | ++++ b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/internal/span/CustomLineHeightSpan.kt |
| 5 | +@@ -11,6 +11,7 @@ import android.graphics.Paint.FontMetricsInt |
| 6 | + import android.text.style.LineHeightSpan |
| 7 | + import kotlin.math.ceil |
| 8 | + import kotlin.math.floor |
| 9 | ++import kotlin.math.min |
| 10 | + |
| 11 | + /** |
| 12 | + * Implements a [LineHeightSpan] which follows web-like behavior for line height, unlike |
| 13 | +@@ -28,29 +29,42 @@ public class CustomLineHeightSpan(height: Float) : LineHeightSpan, ReactSpan { |
| 14 | + v: Int, |
| 15 | + fm: FontMetricsInt, |
| 16 | + ) { |
| 17 | +- // https://www.w3.org/TR/css-inline-3/#inline-height |
| 18 | +- // When its computed line-height is not normal, its layout bounds are derived solely from |
| 19 | +- // metrics of its first available font (ignoring glyphs from other fonts), and leading is used |
| 20 | +- // to adjust the effective A and D to add up to the used line-height. Calculate the leading L as |
| 21 | +- // L = line-height - (A + D). Half the leading (its half-leading) is added above A of the first |
| 22 | +- // available font, and the other half below D of the first available font, giving an effective |
| 23 | +- // ascent above the baseline of A′ = A + L/2, and an effective descent of D′ = D + L/2. However, |
| 24 | +- // if line-fit-edge is not leading and this is not the root inline box, if the half-leading is |
| 25 | +- // positive, treat it as zero. The layout bounds exactly encloses this effective A′ and D′. |
| 26 | ++ // This is more complicated that I wanted it to be. You can find a good explanation of what the |
| 27 | ++ // FontMetrics mean here: http://stackoverflow.com/questions/27631736. |
| 28 | ++ // The general solution is that if there's not enough height to show the full line height, we |
| 29 | ++ // will prioritize in this order: descent, ascent, bottom, top |
| 30 | + |
| 31 | +- val leading = lineHeight - ((-fm.ascent) + fm.descent) |
| 32 | +- fm.ascent -= ceil(leading / 2.0f).toInt() |
| 33 | +- fm.descent += floor(leading / 2.0f).toInt() |
| 34 | ++ if (fm.descent > lineHeight) { |
| 35 | ++ // Show as much descent as possible |
| 36 | ++ fm.descent = min(lineHeight.toDouble(), fm.descent.toDouble()).toInt() |
| 37 | ++ fm.bottom = fm.descent |
| 38 | ++ fm.ascent = 0 |
| 39 | ++ fm.top = fm.ascent |
| 40 | ++ } else if (-fm.ascent + fm.descent > lineHeight) { |
| 41 | ++ // Show all descent, and as much ascent as possible |
| 42 | ++ fm.bottom = fm.descent |
| 43 | ++ fm.ascent = -lineHeight + fm.descent |
| 44 | ++ fm.top = fm.ascent |
| 45 | ++ } else if (-fm.ascent + fm.bottom > lineHeight) { |
| 46 | ++ // Show all ascent, descent, as much bottom as possible |
| 47 | ++ fm.top = fm.ascent |
| 48 | ++ fm.bottom = fm.ascent + lineHeight |
| 49 | ++ } else if (-fm.top + fm.bottom > lineHeight) { |
| 50 | ++ // Show all ascent, descent, bottom, as much top as possible |
| 51 | ++ fm.top = fm.bottom - lineHeight |
| 52 | ++ } else { |
| 53 | ++ // Show proportionally additional ascent / top & descent / bottom |
| 54 | ++ val additional = lineHeight - (-fm.top + fm.bottom) |
| 55 | + |
| 56 | +- // The top of the first line, and the bottom of the last line, may influence bounds of the |
| 57 | +- // paragraph, so we match them to the text ascent/descent. It is otherwise desirable to allow |
| 58 | +- // line boxes to overlap (to allow too large glyphs to be drawn outside them), so we do not |
| 59 | +- // adjust the top/bottom of interior line-boxes. |
| 60 | +- if (start == 0) { |
| 61 | +- fm.top = fm.ascent |
| 62 | +- } |
| 63 | +- if (end == text.length) { |
| 64 | +- fm.bottom = fm.descent |
| 65 | +- } |
| 66 | ++ // Round up for the negative values and down for the positive values (arbitrary choice) |
| 67 | ++ // So that bottom - top equals additional even if it's an odd number. |
| 68 | ++ val top = (fm.top - ceil(additional / 2.0f)).toInt() |
| 69 | ++ val bottom = (fm.bottom + floor(additional / 2.0f)).toInt() |
| 70 | ++ |
| 71 | ++ fm.top = top |
| 72 | ++ fm.ascent = top |
| 73 | ++ fm.descent = bottom |
| 74 | ++ fm.bottom = bottom |
| 75 | ++ } |
| 76 | + } |
| 77 | + } |
0 commit comments