[go: nahoru, domu]

blob: ace72249f313988076852034a4bcd11d6501b4b9 [file] [log] [blame]
/*
* Copyright 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.compose.ui.text
import androidx.test.platform.app.InstrumentationRegistry
import androidx.compose.ui.text.font.asFontFamily
import androidx.ui.unit.Density
import androidx.ui.unit.TextUnit
import androidx.ui.unit.em
import androidx.ui.unit.sp
import com.google.common.truth.Truth.assertThat
import org.junit.Test
class ParagraphPlaceholderIntegrationTest {
private val fontFamilyMeasureFont = FontTestData.BASIC_MEASURE_FONT.asFontFamily()
private val defaultDensity = Density(density = 1f, fontScale = 1f)
private val context = InstrumentationRegistry.getInstrumentation().context
@Test
fun placeHolder_alignAboveBaseLine_lessThanOriginalHeight() {
val text = "AAA"
val fontSize = 20
val height = 0.5.em
val width = 1.em
val placeholder = Placeholder(width, height, PlaceholderVerticalAlign.AboveBaseline)
val paragraph = simpleParagraph(
text = text,
fontSize = fontSize.sp,
placeholders = listOf(AnnotatedString.Range(placeholder, 1, 2)),
width = Float.MAX_VALUE
)
val placeholderRects = paragraph.placeholderRects
assertThat(placeholderRects.size).isEqualTo(1)
// Height won't be increased. Notice: in fontFamilyMeasureFont lineHeight = 1.2 * fontSize
assertThat(paragraph.getLineHeight(0)).isEqualTo(fontSize * 1.2f)
val bound = placeholderRects[0]!!
assertThat(bound.bottom).isEqualTo(paragraph.firstBaseline)
assertThat(bound.top).isEqualTo(paragraph.firstBaseline - height.value * fontSize)
// There is one character to the left of this placeholder.
assertThat(bound.left).isEqualTo(fontSize.toFloat())
assertThat(bound.right).isEqualTo(fontSize + fontSize * width.value)
}
@Test
fun placeHolder_alignAboveBaseLine_greaterThanOriginalHeight() {
val text = "AAA"
val fontSize = 20
val height = 2.em
val width = 1.em
val placeholder = Placeholder(width, height, PlaceholderVerticalAlign.AboveBaseline)
val paragraph = simpleParagraph(
text = text,
fontSize = fontSize.sp,
placeholders = listOf(AnnotatedString.Range(placeholder, 1, 2)),
width = Float.MAX_VALUE
)
val placeholderRects = paragraph.placeholderRects
assertThat(placeholderRects.size).isEqualTo(1)
// In the measure font, descent = 0.2 * fontSize, ascent = 1 * fontSize.
// In this case, ascent is pushed by placeholder to 2 * fontSize, so that
// lineHeight = 0.2 * fontSize + 2 * fontSize.
assertThat(paragraph.getLineHeight(0))
.isEqualTo(0.2f * fontSize + fontSize * height.value)
val bound = placeholderRects[0]!!
assertThat(bound.bottom).isEqualTo(paragraph.firstBaseline)
assertThat(bound.top).isEqualTo(paragraph.firstBaseline - height.value * fontSize)
// There is one character to the left of this placeholder.
assertThat(bound.left).isEqualTo(fontSize.toFloat())
assertThat(bound.right).isEqualTo(fontSize + fontSize * width.value)
}
@Test
fun placeHolder_alignBottom_lessThanOriginalHeight() {
val text = "AAA"
val fontSize = 20
val height = 0.5.em
val width = 1.em
val placeholder = Placeholder(width, height, PlaceholderVerticalAlign.Bottom)
val paragraph = simpleParagraph(
text = text,
fontSize = fontSize.sp,
placeholders = listOf(AnnotatedString.Range(placeholder, 1, 2)),
width = Float.MAX_VALUE
)
val placeholderRects = paragraph.placeholderRects
assertThat(placeholderRects.size).isEqualTo(1)
assertThat(paragraph.getLineHeight(0)).isEqualTo(1.2f * fontSize)
val bound = placeholderRects[0]!!
assertThat(bound.bottom).isEqualTo(paragraph.getLineBottom(0))
assertThat(bound.top)
.isEqualTo(paragraph.getLineBottom(0) - height.value * fontSize)
// There is one character to the left of this placeholder.
assertThat(bound.left).isEqualTo(fontSize.toFloat())
assertThat(bound.right).isEqualTo(fontSize + fontSize * width.value)
}
@Test
fun placeHolder_alignBottom_greaterThanOriginalHeight() {
val text = "AAA"
val fontSize = 20
val height = 2.em
val width = 1.em
val placeholder = Placeholder(width, height, PlaceholderVerticalAlign.Bottom)
val paragraph = simpleParagraph(
text = text,
fontSize = fontSize.sp,
placeholders = listOf(AnnotatedString.Range(placeholder, 1, 2)),
width = Float.MAX_VALUE
)
val placeholderRects = paragraph.placeholderRects
assertThat(placeholderRects.size).isEqualTo(1)
assertThat(paragraph.getLineHeight(0)).isEqualTo(height.value * fontSize)
val bound = placeholderRects[0]!!
assertThat(bound.bottom).isEqualTo(paragraph.getLineBottom(0))
assertThat(bound.top)
.isEqualTo(paragraph.getLineBottom(0) - height.value * fontSize)
// There is one character to the left of this placeholder.
assertThat(bound.left).isEqualTo(fontSize.toFloat())
assertThat(bound.right).isEqualTo(fontSize + fontSize * width.value)
}
@Test
fun placeHolder_alignTop_lessThanOriginalHeight() {
val text = "AAA"
val fontSize = 20
val height = 0.5.em
val width = 1.em
val placeholder = Placeholder(width, height, PlaceholderVerticalAlign.Top)
val paragraph = simpleParagraph(
text = text,
fontSize = fontSize.sp,
placeholders = listOf(AnnotatedString.Range(placeholder, 1, 2)),
width = Float.MAX_VALUE
)
val placeholderRects = paragraph.placeholderRects
assertThat(placeholderRects.size).isEqualTo(1)
assertThat(paragraph.getLineHeight(0)).isEqualTo(1.2f * fontSize)
val bound = placeholderRects[0]!!
// TODO(haoyuchang): use getLineTop instead
assertThat(bound.top).isEqualTo(paragraph.getLineBottom(-1))
assertThat(bound.bottom)
.isEqualTo(paragraph.getLineBottom(-1) + height.value * fontSize)
// There is one character to the left of this placeholder.
assertThat(bound.left).isEqualTo(fontSize.toFloat())
assertThat(bound.right).isEqualTo(fontSize + fontSize * width.value)
}
@Test
fun placeHolder_alignTop_greaterThanOriginalHeight() {
val text = "AAA"
val fontSize = 20
val height = 2.em
val width = 1.em
val placeholder = Placeholder(width, height, PlaceholderVerticalAlign.Top)
val paragraph = simpleParagraph(
text = text,
fontSize = fontSize.sp,
placeholders = listOf(AnnotatedString.Range(placeholder, 1, 2)),
width = Float.MAX_VALUE
)
val placeholderRects = paragraph.placeholderRects
assertThat(placeholderRects.size).isEqualTo(1)
assertThat(paragraph.getLineHeight(0)).isEqualTo(height.value * fontSize)
val bound = placeholderRects[0]!!
// TODO(haoyuchang): use getLineTop instead
assertThat(bound.top).isEqualTo(paragraph.getLineBottom(-1))
assertThat(bound.bottom)
.isEqualTo(paragraph.getLineBottom(-1) + height.value * fontSize)
// There is one character to the left of this placeholder.
assertThat(bound.left).isEqualTo(fontSize.toFloat())
assertThat(bound.right).isEqualTo(fontSize + fontSize * width.value)
}
@Test
fun placeHolder_alignCenter_lessThanOriginalHeight() {
val text = "AAA"
val fontSize = 20
val height = 0.5.em
val width = 1.em
val placeholder = Placeholder(width, height, PlaceholderVerticalAlign.Center)
val paragraph = simpleParagraph(
text = text,
fontSize = fontSize.sp,
placeholders = listOf(AnnotatedString.Range(placeholder, 1, 2)),
width = Float.MAX_VALUE
)
val placeholderRects = paragraph.placeholderRects
assertThat(placeholderRects.size).isEqualTo(1)
assertThat(paragraph.getLineHeight(0)).isEqualTo(fontSize * 1.2f)
val bound = placeholderRects[0]!!
// TODO(haoyuchang): We need getLineTop(0).
val lineCenter = (paragraph.getLineBottom(-1) + paragraph.getLineBottom(0)) / 2
assertThat(bound.top).isEqualTo(lineCenter - height.value * fontSize / 2)
assertThat(bound.bottom).isEqualTo(lineCenter + height.value * fontSize / 2)
// There is one character to the left of this placeholder.
assertThat(bound.left).isEqualTo(fontSize.toFloat())
assertThat(bound.right).isEqualTo(fontSize + fontSize * width.value)
}
@Test
fun placeHolder_alignCenter_greaterThanOriginalHeight() {
val text = "AAA"
val fontSize = 20
val height = 2.em
val width = 1.em
val placeholder = Placeholder(width, height, PlaceholderVerticalAlign.Center)
val paragraph = simpleParagraph(
text = text,
fontSize = fontSize.sp,
placeholders = listOf(AnnotatedString.Range(placeholder, 1, 2)),
width = Float.MAX_VALUE
)
val placeholderRects = paragraph.placeholderRects
assertThat(placeholderRects.size).isEqualTo(1)
assertThat(paragraph.getLineHeight(0)).isEqualTo(fontSize * height.value)
val bound = placeholderRects[0]!!
// TODO(haoyuchang): We need getLineTop(0).
val lineCenter = (paragraph.getLineBottom(-1) + paragraph.getLineBottom(0)) / 2
assertThat(bound.top).isEqualTo(lineCenter - height.value * fontSize / 2)
assertThat(bound.bottom).isEqualTo(lineCenter + height.value * fontSize / 2)
// There is one character to the left of this placeholder.
assertThat(bound.left).isEqualTo(fontSize.toFloat())
assertThat(bound.right).isEqualTo(fontSize + fontSize * width.value)
}
@Test
fun placeHolder_alignTextTop() {
val text = "AAB"
val fontSize = 20
val fontSizeSpan = 30
val height = 0.5.em
val width = 1.em
val placeholder = Placeholder(width, height, PlaceholderVerticalAlign.TextTop)
val paragraph = simpleParagraph(
text = text,
spanStyles = listOf(
AnnotatedString.Range(SpanStyle(fontSize = fontSizeSpan.sp), 2, 3)
),
placeholders = listOf(AnnotatedString.Range(placeholder, 1, 2)),
fontSize = fontSize.sp,
width = Float.MAX_VALUE
)
val placeholderRects = paragraph.placeholderRects
assertThat(placeholderRects.size).isEqualTo(1)
val bound = placeholderRects[0]!!
// TextTop aligns the inline element to top of the proceeding text.
// In the measurement font, the top equals to fontSize pixels above baseline.
val expectedTop = paragraph.firstBaseline - fontSize
assertThat(bound.top).isEqualTo(expectedTop)
assertThat(bound.bottom).isEqualTo(expectedTop + height.value * fontSize)
// There is one character to the left of this placeholder.
assertThat(bound.left).isEqualTo(fontSize.toFloat())
assertThat(bound.right).isEqualTo(fontSize + fontSize * width.value)
}
@Test
fun placeHolder_alignTextBottom() {
val text = "AAB"
val fontSize = 20
val fontSizeSpan = 30
val height = 0.5.em
val width = 1.em
val placeholder = Placeholder(width, height, PlaceholderVerticalAlign.TextBottom)
val paragraph = simpleParagraph(
text = text,
spanStyles = listOf(
AnnotatedString.Range(SpanStyle(fontSize = fontSizeSpan.sp), 2, 3)
),
placeholders = listOf(AnnotatedString.Range(placeholder, 1, 2)),
fontSize = fontSize.sp,
width = Float.MAX_VALUE
)
val placeholderRects = paragraph.placeholderRects
assertThat(placeholderRects.size).isEqualTo(1)
val bound = placeholderRects[0]!!
// TextBottom aligns the inline element to bottom of the proceeding text.
// In the measurement font, the bottom equals to fontSize * 0.2 pixels below baseline.
val expectedBottom = paragraph.firstBaseline + fontSize * 0.2f
assertThat(bound.bottom).isEqualTo(expectedBottom)
assertThat(bound.top).isEqualTo(expectedBottom - height.value * fontSize)
// There is one character to the left of this placeholder.
assertThat(bound.left).isEqualTo(fontSize.toFloat())
assertThat(bound.right).isEqualTo(fontSize + fontSize * width.value)
}
@Test
fun placeHolder_alignTextCenter() {
val text = "AAB"
val fontSize = 20
val fontSizeSpan = 30
val height = 0.5.em
val width = 1.em
val placeholder = Placeholder(width, height, PlaceholderVerticalAlign.TextCenter)
val paragraph = simpleParagraph(
text = text,
spanStyles = listOf(
AnnotatedString.Range(SpanStyle(fontSize = fontSizeSpan.sp), 2, 3)
),
placeholders = listOf(AnnotatedString.Range(placeholder, 1, 2)),
fontSize = fontSize.sp,
width = Float.MAX_VALUE
)
val placeholderRects = paragraph.placeholderRects
assertThat(placeholderRects.size).isEqualTo(1)
val bound = placeholderRects[0]!!
// TextCenter aligns the inline element to center of the proceeding text.
// In the measurement font, the center equals to fontSize * 0.3 pixels above baseline.
val expectedCenter = paragraph.firstBaseline - fontSize * 0.4f
assertThat(bound.top).isEqualTo(expectedCenter - height.value * fontSize / 2)
assertThat(bound.bottom).isEqualTo(expectedCenter + height.value * fontSize / 2)
// There is one character to the left of this placeholder.
assertThat(bound.left).isEqualTo(fontSize.toFloat())
assertThat(bound.right).isEqualTo(fontSize + fontSize * width.value)
}
@Test
fun placeHolder_withRtlText() {
val text = "\u05D0\u05D0\u05D0\u05D0"
val fontSize = 20f
val paragraphWidth = fontSize * (text.length + 3)
val height = 1.em
val width = 1.em
val placeholder = Placeholder(width, height, PlaceholderVerticalAlign.AboveBaseline)
val paragraph = simpleParagraph(
text = text,
placeholders = listOf(AnnotatedString.Range(placeholder, 1, 2)),
fontSize = fontSize.sp,
width = paragraphWidth
)
val placeholderRects = paragraph.placeholderRects
assertThat(placeholderRects.size).isEqualTo(1)
assertThat(paragraph.lineCount).isEqualTo(1)
val bound = placeholderRects[0]!!
val expectedBottom = paragraph.firstBaseline
assertThat(bound.top).isEqualTo(expectedBottom - height.value * fontSize)
assertThat(bound.bottom).isEqualTo(expectedBottom)
// Text is alight right: | RR_R|
assertThat(bound.left).isEqualTo(paragraphWidth - 2 * fontSize)
assertThat(bound.right).isEqualTo(paragraphWidth - 1 * fontSize)
}
@Test
fun placeHolder_withBiDiText_coversRtlChar() {
val text = "\u05D0\u05D0AA"
val fontSize = 20f
val paragraphWidth = fontSize * (text.length + 3)
val height = 1.em
val width = 1.em
val placeholder = Placeholder(width, height, PlaceholderVerticalAlign.AboveBaseline)
val paragraph = simpleParagraph(
text = text,
placeholders = listOf(AnnotatedString.Range(placeholder, 1, 2)),
fontSize = fontSize.sp,
width = paragraphWidth
)
val placeholderRects = paragraph.placeholderRects
assertThat(placeholderRects.size).isEqualTo(1)
assertThat(paragraph.lineCount).isEqualTo(1)
val bound = placeholderRects[0]!!
val expectedBottom = paragraph.firstBaseline
assertThat(bound.top).isEqualTo(expectedBottom - height.value * fontSize)
assertThat(bound.bottom).isEqualTo(expectedBottom)
// Text is align right: | LL_R|
assertThat(bound.left).isEqualTo(paragraphWidth - 2 * fontSize)
assertThat(bound.right).isEqualTo(paragraphWidth - 1 * fontSize)
}
@Test
fun placeHolder_withBiDiText_coversLtrChar() {
val text = "\u05D0\u05D0AA"
val fontSize = 20f
val paragraphWidth = fontSize * (text.length + 3)
val height = 1.em
val width = 1.em
val placeholder = Placeholder(width, height, PlaceholderVerticalAlign.AboveBaseline)
val paragraph = simpleParagraph(
text = text,
placeholders = listOf(AnnotatedString.Range(placeholder, 2, 3)),
fontSize = fontSize.sp,
width = paragraphWidth
)
val placeholderRects = paragraph.placeholderRects
assertThat(placeholderRects.size).isEqualTo(1)
assertThat(paragraph.lineCount).isEqualTo(1)
val bound = placeholderRects[0]!!
val expectedBottom = paragraph.firstBaseline
assertThat(bound.top).isEqualTo(expectedBottom - height.value * fontSize)
assertThat(bound.bottom).isEqualTo(expectedBottom)
// Text is align right: | L_RR|
assertThat(bound.left).isEqualTo(paragraphWidth - 3 * fontSize)
assertThat(bound.right).isEqualTo(paragraphWidth - 2 * fontSize)
}
@Test
fun placeHolder_withBiDiText_coversBiDiStr() {
val text = "\u05D0\u05D0AA"
val fontSize = 20f
val paragraphWidth = fontSize * (text.length + 3)
val height = 1.em
val width = 1.em
val placeholder = Placeholder(width, height, PlaceholderVerticalAlign.AboveBaseline)
val paragraph = simpleParagraph(
text = text,
placeholders = listOf(AnnotatedString.Range(placeholder, 1, 3)),
fontSize = fontSize.sp,
width = paragraphWidth
)
val placeholderRects = paragraph.placeholderRects
assertThat(placeholderRects.size).isEqualTo(1)
assertThat(paragraph.lineCount).isEqualTo(1)
val bound = placeholderRects[0]!!
val expectedBottom = paragraph.firstBaseline
assertThat(bound.top).isEqualTo(expectedBottom - height.value * fontSize)
assertThat(bound.bottom).isEqualTo(expectedBottom)
// Text is align right, 2 chars are covered: | L_R|
assertThat(bound.left).isEqualTo(paragraphWidth - 2 * fontSize)
assertThat(bound.right).isEqualTo(paragraphWidth - 1 * fontSize)
}
@Test
fun placeHolderRects_ellipsized() {
val text = "ABC"
val fontSize = 20f
val placeholder = Placeholder(1.em, 1.em, PlaceholderVerticalAlign.TextCenter)
val placeholders = listOf(
AnnotatedString.Range(placeholder, 0, 1),
AnnotatedString.Range(placeholder, 2, 3)
)
val paragraph = simpleParagraph(
text = text,
placeholders = placeholders,
fontSize = fontSize.sp,
width = 2 * fontSize,
maxLines = 1,
ellipsis = true
)
val placeholderRects = paragraph.placeholderRects
assertThat(placeholderRects.size).isEqualTo(placeholders.size)
assertThat(placeholderRects[0]).isNotNull()
// The second placeholder should be ellipsized.
assertThat(placeholderRects[1]).isNull()
}
private fun simpleParagraph(
text: String = "",
fontSize: TextUnit = TextUnit.Inherit,
spanStyles: List<AnnotatedString.Range<SpanStyle>> = listOf(),
placeholders: List<AnnotatedString.Range<Placeholder>> = listOf(),
width: Float = Float.MAX_VALUE,
maxLines: Int = Int.MAX_VALUE,
ellipsis: Boolean = false
): Paragraph {
return Paragraph(
text = text,
style = TextStyle(
fontSize = fontSize,
fontFamily = fontFamilyMeasureFont
),
spanStyles = spanStyles,
placeholders = placeholders,
maxLines = maxLines,
ellipsis = ellipsis,
constraints = ParagraphConstraints(width = width),
density = defaultDensity,
resourceLoader = TestFontResourceLoader(context)
)
}
}