Implement TextStyle.fontSize with AbsoluteSizeSpan in framework
Bug: 121157451
Test: ./gradlew ui-port:test
Test: ./gradlew ui-port:connectedAndroidTest
Change-Id: I5b360de03d547e87ba570b73d618f411be3eca7f
diff --git a/ui/port/src/androidTest/java/androidx/ui/port/engine/text/ParagraphTest.kt b/ui/port/src/androidTest/java/androidx/ui/port/engine/text/ParagraphTest.kt
index e6af9d8..23569c4 100644
--- a/ui/port/src/androidTest/java/androidx/ui/port/engine/text/ParagraphTest.kt
+++ b/ui/port/src/androidTest/java/androidx/ui/port/engine/text/ParagraphTest.kt
@@ -23,12 +23,14 @@
import androidx.ui.engine.geometry.Offset
import androidx.ui.engine.text.FontFallback
import androidx.ui.engine.text.Paragraph
+import androidx.ui.engine.text.ParagraphBuilder
import androidx.ui.engine.text.ParagraphConstraints
import androidx.ui.engine.text.ParagraphStyle
import androidx.ui.engine.text.TextAffinity
import androidx.ui.engine.text.TextAlign
import androidx.ui.engine.text.TextDirection
import androidx.ui.engine.text.TextPosition
+import androidx.ui.engine.text.TextStyle
import androidx.ui.engine.window.Locale
import androidx.ui.port.bitmap
import androidx.ui.port.matchers.equalToBitmap
@@ -769,6 +771,76 @@
)
}
+ @Test
+ fun textStyle_setFontSizeOnWholeText() {
+ val text = "abcde"
+ val fontSize = 20.0
+ val textStyle = TextStyle(fontSize = fontSize)
+ val paragraphWidth = fontSize * text.length
+
+ val paragraph = simpleParagraph(
+ text = text,
+ textStyles = listOf(ParagraphBuilder.TextStyleIndex(textStyle, 0, text.length))
+ )
+ paragraph.layout(ParagraphConstraints(width = paragraphWidth))
+ val paragraphImpl = paragraph.paragraphImpl
+
+ // Make sure there is only one line, so that we can use getLineRight to test fontSize.
+ assertThat(paragraphImpl.lineCount, equalTo(1))
+ // Notice that in this test font, the width of character equals to fontSize.
+ assertThat(paragraphImpl.getLineWidth(0), equalTo(fontSize * text.length))
+ }
+
+ @Test
+ fun textStyle_setFontSizeOnPartOfText() {
+ val text = "abcde"
+ val fontSize = 20.0
+ val textStyleFontSize = 30.0
+ val textStyle = TextStyle(fontSize = textStyleFontSize)
+ val paragraphWidth = textStyleFontSize * text.length
+
+ val paragraph = simpleParagraph(
+ text = text,
+ textStyles = listOf(ParagraphBuilder.TextStyleIndex(textStyle, 0, "abc".length)),
+ fontSize = fontSize
+ )
+ paragraph.layout(ParagraphConstraints(width = paragraphWidth))
+ val paragraphImpl = paragraph.paragraphImpl
+
+ // Make sure there is only one line, so that we can use getLineRight to test fontSize.
+ assertThat(paragraphImpl.lineCount, equalTo(1))
+ // Notice that in this test font, the width of character equals to fontSize.
+ val expectedLineRight = "abc".length * textStyleFontSize + "de".length * fontSize
+ assertThat(paragraphImpl.getLineWidth(0), equalTo(expectedLineRight))
+ }
+
+ @Test
+ fun textStyle_seFontSizeTwice_lastOneOverwrite() {
+ val text = "abcde"
+ val fontSize = 20.0
+ val textStyle = TextStyle(fontSize = fontSize)
+
+ val fontSizeOverwrite = 30.0
+ val textStyleOverwrite = TextStyle(fontSize = fontSizeOverwrite)
+ val paragraphWidth = fontSizeOverwrite * text.length
+
+ val paragraph = simpleParagraph(
+ text = text,
+ textStyles = listOf(
+ ParagraphBuilder.TextStyleIndex(textStyle, 0, text.length),
+ ParagraphBuilder.TextStyleIndex(textStyleOverwrite, 0, "abc".length)
+ )
+ )
+ paragraph.layout(ParagraphConstraints(width = paragraphWidth))
+ val paragraphImpl = paragraph.paragraphImpl
+
+ // Make sure there is only one line, so that we can use getLineRight to test fontSize.
+ assertThat(paragraphImpl.lineCount, equalTo(1))
+ // Notice that in this test font, the width of character equals to fontSize.
+ val expectedWidth = "abc".length * fontSizeOverwrite + "de".length * fontSize
+ assertThat(paragraphImpl.getLineWidth(0), equalTo(expectedWidth))
+ }
+
// TODO(migration/siyamed) add test
@Test
fun getWordBoundary() {
@@ -780,11 +852,12 @@
textDirection: TextDirection? = null,
fontSize: Double? = null,
maxLines: Int? = null,
- lineHeight: Double? = null
+ lineHeight: Double? = null,
+ textStyles: List<ParagraphBuilder.TextStyleIndex> = listOf()
): Paragraph {
return Paragraph(
text = StringBuilder(text),
- textStyles = listOf(),
+ textStyles = textStyles,
paragraphStyle = ParagraphStyle(
textAlign = textAlign,
textDirection = textDirection,
diff --git a/ui/port/src/androidTest/java/androidx/ui/port/engine/text/platform/ParagraphAndroidTest.kt b/ui/port/src/androidTest/java/androidx/ui/port/engine/text/platform/ParagraphAndroidTest.kt
index 4885677..27875c02 100644
--- a/ui/port/src/androidTest/java/androidx/ui/port/engine/text/platform/ParagraphAndroidTest.kt
+++ b/ui/port/src/androidTest/java/androidx/ui/port/engine/text/platform/ParagraphAndroidTest.kt
@@ -4,6 +4,7 @@
import android.graphics.Paint
import android.graphics.Typeface
import android.text.TextPaint
+import android.text.style.AbsoluteSizeSpan
import android.text.style.ForegroundColorSpan
import androidx.test.filters.SmallTest
import androidx.test.platform.app.InstrumentationRegistry
@@ -74,7 +75,7 @@
fun textStyle_setColorOnWholeText() {
val text = "abcde"
val fontSize = 20.0
- val layoutWidth = text.length * fontSize
+ val paragraphWidth = text.length * fontSize
val textStyle = TextStyle(color = Color(0xFF0000FF.toInt()))
val paragraph = simpleParagraph(
@@ -82,7 +83,7 @@
textStyles = listOf(ParagraphBuilder.TextStyleIndex(textStyle, 0, text.length)),
fontSize = fontSize
)
- paragraph.layout(layoutWidth)
+ paragraph.layout(paragraphWidth)
assertThat(paragraph.underlyingText, hasSpan(ForegroundColorSpan::class, 0, text.length))
}
@@ -91,7 +92,7 @@
fun textStyle_setColorOnPartOfText() {
val text = "abcde"
val fontSize = 20.0
- val layoutWidth = text.length * fontSize
+ val paragraphWidth = text.length * fontSize
val textStyle = TextStyle(color = Color(0xFF0000FF.toInt()))
val paragraph = simpleParagraph(
@@ -99,7 +100,7 @@
textStyles = listOf(ParagraphBuilder.TextStyleIndex(textStyle, 0, "abc".length)),
fontSize = fontSize
)
- paragraph.layout(layoutWidth)
+ paragraph.layout(paragraphWidth)
assertThat(paragraph.underlyingText, hasSpan(ForegroundColorSpan::class, 0, "abc".length))
}
@@ -108,7 +109,7 @@
fun textStyle_setColorTwice_lastOneOverwrite() {
val text = "abcde"
val fontSize = 20.0
- val layoutWidth = text.length * fontSize
+ val paragraphWidth = text.length * fontSize
val textStyle = TextStyle(color = Color(0xFF0000FF.toInt()))
val textStyleOverwrite = TextStyle(color = Color(0xFF00FF00.toInt()))
@@ -120,7 +121,7 @@
),
fontSize = fontSize
)
- paragraph.layout(layoutWidth)
+ paragraph.layout(paragraphWidth)
assertThat(paragraph.underlyingText, hasSpan(ForegroundColorSpan::class, 0, text.length))
assertThat(paragraph.underlyingText, hasSpan(ForegroundColorSpan::class, 0, "abc".length))
@@ -130,6 +131,64 @@
)
}
+ @Test
+ fun textStyle_setFontSizeOnWholeText() {
+ val text = "abcde"
+ val fontSize = 20.0
+ val paragraphWidth = text.length * fontSize
+ val textStyle = TextStyle(fontSize = fontSize)
+
+ val paragraph = simpleParagraph(
+ text = text,
+ textStyles = listOf(ParagraphBuilder.TextStyleIndex(textStyle, 0, text.length))
+ )
+ paragraph.layout(paragraphWidth)
+
+ assertThat(paragraph.underlyingText, hasSpan(AbsoluteSizeSpan::class, 0, text.length))
+ }
+
+ @Test
+ fun textStyle_setFontSizeOnPartText() {
+ val text = "abcde"
+ val fontSize = 20.0
+ val paragraphWidth = text.length * fontSize
+ val textStyle = TextStyle(fontSize = fontSize)
+
+ val paragraph = simpleParagraph(
+ text = text,
+ textStyles = listOf(ParagraphBuilder.TextStyleIndex(textStyle, 0, "abc".length))
+ )
+ paragraph.layout(paragraphWidth)
+
+ assertThat(paragraph.underlyingText, hasSpan(AbsoluteSizeSpan::class, 0, "abc".length))
+ }
+
+ @Test
+ fun textStyle_setFontSizeTwice_lastOneOverwrite() {
+ val text = "abcde"
+ val fontSize = 20.0
+ val fontSizeOverwrite = 30.0
+ val paragraphWidth = text.length * fontSizeOverwrite
+ val textStyle = TextStyle(fontSize = fontSize)
+ val textStyleOverwrite = TextStyle(fontSize = fontSizeOverwrite)
+
+ val paragraph = simpleParagraph(
+ text = text,
+ textStyles = listOf(
+ ParagraphBuilder.TextStyleIndex(textStyle, 0, text.length),
+ ParagraphBuilder.TextStyleIndex(textStyleOverwrite, 0, "abc".length)
+ )
+ )
+ paragraph.layout(paragraphWidth)
+
+ assertThat(paragraph.underlyingText, hasSpan(AbsoluteSizeSpan::class, 0, text.length))
+ assertThat(paragraph.underlyingText, hasSpan(AbsoluteSizeSpan::class, 0, "abc".length))
+ assertThat(
+ paragraph.underlyingText,
+ hasSpanOnTop(AbsoluteSizeSpan::class, 0, "abc".length)
+ )
+ }
+
private fun simpleParagraph(
text: CharSequence = "",
textStyles: List<ParagraphBuilder.TextStyleIndex> = listOf(),
diff --git a/ui/port/src/main/java/androidx/ui/engine/text/platform/ParagraphAndroid.kt b/ui/port/src/main/java/androidx/ui/engine/text/platform/ParagraphAndroid.kt
index 89028c8..ee86092 100644
--- a/ui/port/src/main/java/androidx/ui/engine/text/platform/ParagraphAndroid.kt
+++ b/ui/port/src/main/java/androidx/ui/engine/text/platform/ParagraphAndroid.kt
@@ -18,6 +18,7 @@
import android.text.SpannableString
import android.text.Spanned
import android.text.TextPaint
+import android.text.style.AbsoluteSizeSpan
import android.text.style.ForegroundColorSpan
import androidx.text.LayoutCompat.ALIGN_CENTER
import androidx.text.LayoutCompat.ALIGN_LEFT
@@ -43,6 +44,7 @@
import androidx.ui.painting.Canvas
import java.util.Locale
import kotlin.math.floor
+import kotlin.math.roundToInt
internal class ParagraphAndroid constructor(
val text: StringBuilder,
@@ -169,6 +171,8 @@
fun getLineHeight(index: Int): Double = ensureLayout.getLineHeight(index)
+ fun getLineWidth(index: Int): Double = ensureLayout.getLineWidth(index)
+
fun paint(canvas: Canvas, x: Double, y: Double) {
val tmpLayout = layout ?: throw IllegalStateException("paint cannot be " +
"called before layout() is called")
@@ -197,7 +201,15 @@
)
}
// TODO(Migration/haoyuchang): implement decoration, decorationStyle, decorationColor
- // TODO(Migration/haoyuchang): implement fontWeight, fontStyle, fontFamily, fontSize
+ style.fontSize?.let {
+ spannableString.setSpan(
+ AbsoluteSizeSpan(it.roundToInt()),
+ start,
+ end,
+ Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
+ )
+ }
+ // TODO(Migration/haoyuchang): implement fontWeight, fontStyle, fontFamily
// TODO(Migration/haoyuchang): implement textBaseLine
// TODO(Migration/haoyuchang): implement letterSpacing, wordSpacing
// TODO(Migration/haoyuchang): implement height