diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/CustomLineHeightSpan.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/CustomLineHeightSpan.java index f12e1d1d083345..91b20a61221662 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/text/CustomLineHeightSpan.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/CustomLineHeightSpan.java @@ -47,8 +47,13 @@ public void chooseHeight( } else { // Show proportionally additional ascent and top final int additional = mHeight - (-fm.top + fm.bottom); - fm.top -= additional; - fm.ascent -= additional; + + // Round up for the negative values and down for the positive values (arbritary choice) + // So that bottom - top equals additional even if it's an odd number. + fm.top -= Math.ceil(additional / 2.0f); + fm.bottom += Math.floor(additional / 2.0f); + fm.ascent = fm.top; + fm.descent = fm.bottom; } } } diff --git a/ReactAndroid/src/test/java/com/facebook/react/views/text/CustomLineHeightSpanTest.java b/ReactAndroid/src/test/java/com/facebook/react/views/text/CustomLineHeightSpanTest.java new file mode 100644 index 00000000000000..eadb7d3544bcb5 --- /dev/null +++ b/ReactAndroid/src/test/java/com/facebook/react/views/text/CustomLineHeightSpanTest.java @@ -0,0 +1,106 @@ +package com.facebook.react.views.text; + +import android.graphics.Paint; + +import static org.fest.assertions.api.Assertions.assertThat; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.robolectric.RobolectricTestRunner; + +@RunWith(RobolectricTestRunner.class) +@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"}) +public class CustomLineHeightSpanTest { + + @Test + public void evenLineHeightShouldIncreaseAllMetricsProportionally() { + CustomLineHeightSpan customLineHeightSpan = new CustomLineHeightSpan(22); + Paint.FontMetricsInt fm = new Paint.FontMetricsInt(); + fm.top = -10; + fm.ascent = -5; + fm.descent = 5; + fm.bottom = 10; + customLineHeightSpan.chooseHeight("Hi", 0, 2, 0, 0, fm); + // Since line height is even it should be equally added to top and bottom. + assertThat(fm.top).isEqualTo(-11); + assertThat(fm.ascent).isEqualTo(-11); + assertThat(fm.descent).isEqualTo(11); + assertThat(fm.bottom).isEqualTo(11); + assertThat(fm.bottom - fm.top).isEqualTo(22); + } + + @Test + public void oddLineHeightShouldAlsoWork() { + CustomLineHeightSpan customLineHeightSpan = new CustomLineHeightSpan(23); + Paint.FontMetricsInt fm = new Paint.FontMetricsInt(); + fm.top = -10; + fm.ascent = -5; + fm.descent = 5; + fm.bottom = 10; + customLineHeightSpan.chooseHeight("Hi", 0, 2, 0, 0, fm); + // Only test that the sum is correct so the implementation + // is free to add the odd value either on top or bottom. + assertThat(fm.descent - fm.ascent).isEqualTo(23); + assertThat(fm.bottom - fm.top).isEqualTo(23); + } + + @Test + public void shouldReduceTopFirst() { + CustomLineHeightSpan customLineHeightSpan = new CustomLineHeightSpan(19); + Paint.FontMetricsInt fm = new Paint.FontMetricsInt(); + fm.top = -10; + fm.ascent = -5; + fm.descent = 5; + fm.bottom = 10; + customLineHeightSpan.chooseHeight("Hi", 0, 2, 0, 0, fm); + assertThat(fm.top).isEqualTo(-9); + assertThat(fm.ascent).isEqualTo(-5); + assertThat(fm.descent).isEqualTo(5); + assertThat(fm.bottom).isEqualTo(10); + } + + @Test + public void shouldReduceBottomSecond() { + CustomLineHeightSpan customLineHeightSpan = new CustomLineHeightSpan(14); + Paint.FontMetricsInt fm = new Paint.FontMetricsInt(); + fm.top = -10; + fm.ascent = -5; + fm.descent = 5; + fm.bottom = 10; + customLineHeightSpan.chooseHeight("Hi", 0, 2, 0, 0, fm); + assertThat(fm.top).isEqualTo(-5); + assertThat(fm.ascent).isEqualTo(-5); + assertThat(fm.descent).isEqualTo(5); + assertThat(fm.bottom).isEqualTo(9); + } + + @Test + public void shouldReduceAscentThird() { + CustomLineHeightSpan customLineHeightSpan = new CustomLineHeightSpan(9); + Paint.FontMetricsInt fm = new Paint.FontMetricsInt(); + fm.top = -10; + fm.ascent = -5; + fm.descent = 5; + fm.bottom = 10; + customLineHeightSpan.chooseHeight("Hi", 0, 2, 0, 0, fm); + assertThat(fm.top).isEqualTo(-4); + assertThat(fm.ascent).isEqualTo(-4); + assertThat(fm.descent).isEqualTo(5); + assertThat(fm.bottom).isEqualTo(5); + } + + @Test + public void shouldReduceDescentLast() { + CustomLineHeightSpan customLineHeightSpan = new CustomLineHeightSpan(4); + Paint.FontMetricsInt fm = new Paint.FontMetricsInt(); + fm.top = -10; + fm.ascent = -5; + fm.descent = 5; + fm.bottom = 10; + customLineHeightSpan.chooseHeight("Hi", 0, 2, 0, 0, fm); + assertThat(fm.top).isEqualTo(0); + assertThat(fm.ascent).isEqualTo(0); + assertThat(fm.descent).isEqualTo(4); + assertThat(fm.bottom).isEqualTo(4); + } +}