Merge "Fix a few edge cases in MultiParagraph get functions" into androidx-main
diff --git a/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/MultiParagraphIntegrationTest.kt b/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/MultiParagraphIntegrationTest.kt
index 10b709b..ca467177 100644
--- a/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/MultiParagraphIntegrationTest.kt
+++ b/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/MultiParagraphIntegrationTest.kt
@@ -245,6 +245,141 @@
}
@Test
+ fun getOffsetForPosition_emptyLine() = with(defaultDensity) {
+ val lineLength = 2
+ val text = createAnnotatedString(mutableListOf("a".repeat(lineLength), ""))
+
+ val fontSize = 50.sp
+ val fontSizeInPx = fontSize.roundToPx()
+ // each line contains max 2 character
+ val width = lineLength * fontSizeInPx
+
+ val paragraph = simpleMultiParagraph(
+ text = text,
+ fontSize = fontSize,
+ width = width.toFloat()
+ )
+
+ // The text should be rendered as:
+ // aa
+ // <blank line>
+
+ val position = Offset(
+ x = (lineLength * fontSizeInPx) / 2f, // center of lines horizontally
+ y = fontSizeInPx * 1.5f // center of second line vertically
+ )
+
+ assertThat(paragraph.getOffsetForPosition(position)).isEqualTo(2)
+ }
+
+ @Test
+ fun getOffsetForPosition_emptyLines() = with(defaultDensity) {
+ val lineLength = 2
+ val text = createAnnotatedString(mutableListOf("a".repeat(lineLength), "", ""))
+
+ val fontSize = 50.sp
+ val fontSizeInPx = fontSize.roundToPx()
+ val width = lineLength * fontSizeInPx
+
+ val paragraph = simpleMultiParagraph(
+ text = text,
+ fontSize = fontSize,
+ width = width.toFloat()
+ )
+
+ // The text should be rendered as:
+ // aa
+ // <blank line>
+ // <blank line>
+
+ val position = Offset(
+ x = (lineLength * fontSizeInPx) / 2f, // center of lines horizontally
+ y = fontSizeInPx * 1.5f // center of second line vertically
+ )
+
+ assertThat(paragraph.getOffsetForPosition(position)).isEqualTo(2)
+ }
+
+ @Test
+ fun getLineForVerticalPosition() = with(defaultDensity) {
+ val lineLength = 4
+ val text = createAnnotatedString(List(2) { "a".repeat(lineLength) })
+
+ val fontSize = 50.sp
+ val fontSizeInPx = fontSize.roundToPx()
+ val width = lineLength * fontSizeInPx
+
+ val paragraph = simpleMultiParagraph(
+ text = text,
+ fontSize = fontSize,
+ width = width.toFloat()
+ )
+
+ // The text should be rendered as:
+ // aaaa
+ // aaaa
+
+ val lineHeight = fontSizeInPx.toFloat()
+ generateSequence(-0.5f) { it + 0.5f }
+ .takeWhile { it <= 3f }
+ .forEach {
+ val expected = it.toInt().coerceIn(0..1)
+ val actual = paragraph.getLineForVerticalPosition(lineHeight * it)
+ assertWithMessage("paragraph.getLineForVerticalPosition(lineHeight * $it) failed")
+ .that(actual).isEqualTo(expected)
+ }
+ }
+
+ @Test
+ fun getLineForVerticalPosition_emptyLine() = with(defaultDensity) {
+ val lineLength = 4
+ val text = createAnnotatedString(mutableListOf("a".repeat(lineLength), ""))
+
+ val fontSize = 50.sp
+ val fontSizeInPx = fontSize.roundToPx()
+ val width = lineLength * fontSizeInPx
+
+ val paragraph = simpleMultiParagraph(
+ text = text,
+ fontSize = fontSize,
+ width = width.toFloat()
+ )
+
+ // The text should be rendered as:
+ // aaaa
+ // <blank line>
+
+ val y = fontSizeInPx * 1.5f // center of second line vertically
+ val actual = paragraph.getLineForVerticalPosition(y)
+ assertThat(actual).isEqualTo(1)
+ }
+
+ @Test
+ fun getLineForVerticalPosition_emptyLines() = with(defaultDensity) {
+ val lineLength = 4
+ val text = createAnnotatedString(mutableListOf("a".repeat(lineLength), "", ""))
+
+ val fontSize = 50.sp
+ val fontSizeInPx = fontSize.roundToPx()
+ val width = lineLength * fontSizeInPx
+
+ val paragraph = simpleMultiParagraph(
+ text = text,
+ fontSize = fontSize,
+ width = width.toFloat()
+ )
+
+ // The text should be rendered as:
+ // aaaa
+ // <blank line>
+ // <blank line>
+
+ val y = fontSizeInPx * 1.5f // center of second line vertically
+ val actual = paragraph.getLineForVerticalPosition(y)
+ assertThat(actual).isEqualTo(1)
+ }
+
+ @Test
fun getBoundingBox() {
with(defaultDensity) {
val lineLength = 2
diff --git a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/MultiParagraph.kt b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/MultiParagraph.kt
index 7043425..d6a9bbd 100644
--- a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/MultiParagraph.kt
+++ b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/MultiParagraph.kt
@@ -470,7 +470,7 @@
}
return with(paragraphInfoList[paragraphIndex]) {
if (length == 0) {
- max(0, startIndex - 1)
+ startLineIndex
} else {
paragraph.getLineForVerticalPosition(
vertical.toLocalYPosition()
@@ -488,7 +488,7 @@
}
return with(paragraphInfoList[paragraphIndex]) {
if (length == 0) {
- max(0, startIndex - 1)
+ startIndex
} else {
paragraph.getOffsetForPosition(position.toLocal()).toGlobalIndex()
}