[go: nahoru, domu]

blob: edd5922412de84b88ce941c42500fd5d218355ba [file] [log] [blame]
Louis Pullen-Freilich26940682019-05-01 16:44:01 +01001package androidx.ui.engine.text.platform
Haoyu Zhang10fc6502018-11-09 15:50:11 -08002
Haoyu Zhang10fc6502018-11-09 15:50:11 -08003import android.graphics.Paint
Haoyu Zhang10fc6502018-11-09 15:50:11 -08004import android.text.TextPaint
Haoyu Zhangbb51ccf2018-12-17 15:07:43 -08005import android.text.style.AbsoluteSizeSpan
Haoyu Zhang0c4fd022019-01-02 13:53:10 -08006import android.text.style.BackgroundColorSpan
Haoyu Zhang47f57a22018-12-12 13:16:40 -08007import android.text.style.ForegroundColorSpan
Haoyu Zhang7fc59172019-03-01 17:03:31 -08008import android.text.style.LeadingMarginSpan
Haoyu Zhang4b201d22018-12-18 14:27:38 -08009import android.text.style.LocaleSpan
Haoyu Zhang24eb32f2019-05-21 16:16:37 -070010import android.text.style.RelativeSizeSpan
Haoyu Zhang15750922019-02-19 13:44:17 -080011import android.text.style.ScaleXSpan
Haoyu Zhangb5677202018-12-19 14:22:18 -080012import android.text.style.StrikethroughSpan
13import android.text.style.UnderlineSpan
Haoyu Zhang97d5e722019-01-04 17:32:34 -080014import androidx.test.filters.SdkSuppress
Haoyu Zhang10fc6502018-11-09 15:50:11 -080015import androidx.test.filters.SmallTest
16import androidx.test.platform.app.InstrumentationRegistry
Haoyu Zhang2eb38cd2018-11-21 15:05:28 -080017import androidx.text.StaticLayoutCompat
Haoyu Zhang40ce6bf2019-01-28 15:58:20 -080018import androidx.text.style.BaselineShiftSpan
Haoyu Zhang588aaef2019-02-20 14:47:39 -080019import androidx.text.style.FontFeatureSpan
Haoyu Zhang1588ba0f2018-12-19 16:47:10 -080020import androidx.text.style.LetterSpacingSpan
Haoyu Zhang2a036c832019-03-08 11:57:13 -080021import androidx.text.style.ShadowSpan
Haoyu Zhang15750922019-02-19 13:44:17 -080022import androidx.text.style.SkewXSpan
Siyamed Sinir70f336a2018-12-27 10:37:09 -080023import androidx.text.style.TypefaceSpan
Haoyu Zhang97d5e722019-01-04 17:32:34 -080024import androidx.text.style.WordSpacingSpan
Haoyu Zhang7fc59172019-03-01 17:03:31 -080025import androidx.ui.core.px
Haoyu Zhang2a036c832019-03-08 11:57:13 -080026import androidx.ui.engine.geometry.Offset
Haoyu Zhang40ce6bf2019-01-28 15:58:20 -080027import androidx.ui.engine.text.BaselineShift
Siyamed Sinirf18dcca2018-12-20 18:25:10 -080028import androidx.ui.engine.text.FontStyle
Siyamed Sinir21796012018-12-26 13:51:17 -080029import androidx.ui.engine.text.FontSynthesis
Louis Pullen-Freilich26940682019-05-01 16:44:01 +010030import androidx.ui.engine.text.FontTestData.Companion.BASIC_MEASURE_FONT
Siyamed Sinirf18dcca2018-12-20 18:25:10 -080031import androidx.ui.engine.text.FontWeight
Haoyu Zhang10fc6502018-11-09 15:50:11 -080032import androidx.ui.engine.text.ParagraphStyle
33import androidx.ui.engine.text.TextAlign
Haoyu Zhangb5677202018-12-19 14:22:18 -080034import androidx.ui.engine.text.TextDecoration
Louis Pullen-Freilich26940682019-05-01 16:44:01 +010035import androidx.ui.engine.text.TextGeometricTransform
36import androidx.ui.engine.text.TextIndent
Siyamed Sinirf18dcca2018-12-20 18:25:10 -080037import androidx.ui.engine.text.font.FontFamily
38import androidx.ui.engine.text.font.asFontFamily
Haoyu Zhang4b201d22018-12-18 14:27:38 -080039import androidx.ui.engine.window.Locale
Siyamed Sinir00aa7172019-02-01 13:15:56 -080040import androidx.ui.matchers.equalToBitmap
41import androidx.ui.matchers.hasSpan
42import androidx.ui.matchers.hasSpanOnTop
George Mounta3145782019-05-02 10:08:03 -070043import androidx.ui.graphics.Color
Haoyu Zhang2a036c832019-03-08 11:57:13 -080044import androidx.ui.painting.Shadow
Haoyu Zhang27429892019-06-11 13:19:57 -070045import androidx.ui.painting.AnnotatedString
46import androidx.ui.painting.TextStyle
Siyamed Sinirf18dcca2018-12-20 18:25:10 -080047import com.nhaarman.mockitokotlin2.any
48import com.nhaarman.mockitokotlin2.eq
49import com.nhaarman.mockitokotlin2.mock
50import com.nhaarman.mockitokotlin2.never
51import com.nhaarman.mockitokotlin2.spy
52import com.nhaarman.mockitokotlin2.times
53import com.nhaarman.mockitokotlin2.verify
Haoyu Zhangb5677202018-12-19 14:22:18 -080054import org.hamcrest.Matchers.equalTo
Siyamed Sinirf18dcca2018-12-20 18:25:10 -080055import org.hamcrest.Matchers.not
56import org.hamcrest.Matchers.nullValue
Haoyu Zhangc11ef5a2019-01-14 16:35:05 -080057import org.junit.Assert.assertFalse
Haoyu Zhang47f57a22018-12-12 13:16:40 -080058import org.junit.Assert.assertThat
Haoyu Zhangc11ef5a2019-01-14 16:35:05 -080059import org.junit.Assert.assertTrue
Haoyu Zhang10fc6502018-11-09 15:50:11 -080060import org.junit.Before
61import org.junit.Test
62import org.junit.runner.RunWith
63import org.junit.runners.JUnit4
Haoyu Zhang10fc6502018-11-09 15:50:11 -080064import kotlin.math.ceil
65
66@RunWith(JUnit4::class)
67@SmallTest
68class ParagraphAndroidTest {
Siyamed Sinirf18dcca2018-12-20 18:25:10 -080069 private lateinit var fontFamily: FontFamily
Haoyu Zhang10fc6502018-11-09 15:50:11 -080070
71 @Before
72 fun setup() {
Haoyu Zhang47f57a22018-12-12 13:16:40 -080073 // This sample font provides the following features:
74 // 1. The width of most of visible characters equals to font size.
75 // 2. The LTR/RTL characters are rendered as â–¶/â—€.
76 // 3. The fontMetrics passed to TextPaint has descend - ascend equal to 1.2 * fontSize.
Siyamed Sinirf18dcca2018-12-20 18:25:10 -080077 fontFamily = BASIC_MEASURE_FONT.asFontFamily()
78 fontFamily.context = InstrumentationRegistry.getInstrumentation().context
Haoyu Zhang10fc6502018-11-09 15:50:11 -080079 }
80
81 @Test
82 fun draw_with_newline_and_line_break_default_values() {
George Mountb1cdd862018-12-21 10:54:42 -080083 val fontSize = 50.0f
Haoyu Zhang10fc6502018-11-09 15:50:11 -080084 for (text in arrayOf("abc\ndef", "\u05D0\u05D1\u05D2\n\u05D3\u05D4\u05D5")) {
85 val paragraphAndroid = simpleParagraph(
Haoyu Zhang27429892019-06-11 13:19:57 -070086 text = text,
Siyamed Sinirf18dcca2018-12-20 18:25:10 -080087 fontSize = fontSize,
88 fontFamily = fontFamily
Haoyu Zhang10fc6502018-11-09 15:50:11 -080089 )
90
91 // 2 chars width
92 paragraphAndroid.layout(width = 2 * fontSize)
93
94 val textPaint = TextPaint(Paint.ANTI_ALIAS_FLAG)
George Mountb1cdd862018-12-21 10:54:42 -080095 textPaint.textSize = fontSize
Siyamed Sinirf18dcca2018-12-20 18:25:10 -080096 textPaint.typeface = TypefaceAdapter().create(fontFamily)
Haoyu Zhang10fc6502018-11-09 15:50:11 -080097
Haoyu Zhang2eb38cd2018-11-21 15:05:28 -080098 val staticLayout = StaticLayoutCompat.Builder(
99 text,
100 textPaint,
101 ceil(paragraphAndroid.width).toInt()
Haoyu Zhang10fc6502018-11-09 15:50:11 -0800102 )
Haoyu Zhang2eb38cd2018-11-21 15:05:28 -0800103 .setEllipsizedWidth(ceil(paragraphAndroid.width).toInt())
104 .build()
Haoyu Zhang47f57a22018-12-12 13:16:40 -0800105 assertThat(paragraphAndroid.bitmap(), equalToBitmap(staticLayout.bitmap()))
Haoyu Zhang10fc6502018-11-09 15:50:11 -0800106 }
107 }
108
Haoyu Zhang47f57a22018-12-12 13:16:40 -0800109 @Test
haoyua8e48a52019-06-25 12:23:27 -0700110 fun testAnnotatedString_setColorOnWholeText() {
Haoyu Zhang47f57a22018-12-12 13:16:40 -0800111 val text = "abcde"
Haoyu Zhang47f57a22018-12-12 13:16:40 -0800112 val textStyle = TextStyle(color = Color(0xFF0000FF.toInt()))
113
114 val paragraph = simpleParagraph(
115 text = text,
Haoyu Zhang27429892019-06-11 13:19:57 -0700116 textStyles = listOf(AnnotatedString.Item(textStyle, 0, text.length))
Haoyu Zhang47f57a22018-12-12 13:16:40 -0800117 )
George Mountb1cdd862018-12-21 10:54:42 -0800118 paragraph.layout(100.0f)
Haoyu Zhang47f57a22018-12-12 13:16:40 -0800119
120 assertThat(paragraph.underlyingText, hasSpan(ForegroundColorSpan::class, 0, text.length))
121 }
122
123 @Test
haoyua8e48a52019-06-25 12:23:27 -0700124 fun testAnnotatedString_setColorOnPartOfText() {
Haoyu Zhang47f57a22018-12-12 13:16:40 -0800125 val text = "abcde"
Haoyu Zhang47f57a22018-12-12 13:16:40 -0800126 val textStyle = TextStyle(color = Color(0xFF0000FF.toInt()))
127
128 val paragraph = simpleParagraph(
129 text = text,
Haoyu Zhang27429892019-06-11 13:19:57 -0700130 textStyles = listOf(AnnotatedString.Item(textStyle, 0, "abc".length))
Haoyu Zhang47f57a22018-12-12 13:16:40 -0800131 )
George Mountb1cdd862018-12-21 10:54:42 -0800132 paragraph.layout(100.0f)
Haoyu Zhang47f57a22018-12-12 13:16:40 -0800133
134 assertThat(paragraph.underlyingText, hasSpan(ForegroundColorSpan::class, 0, "abc".length))
135 }
136
137 @Test
haoyua8e48a52019-06-25 12:23:27 -0700138 fun testAnnotatedString_setColorTwice_lastOneOverwrite() {
Haoyu Zhang47f57a22018-12-12 13:16:40 -0800139 val text = "abcde"
Haoyu Zhang47f57a22018-12-12 13:16:40 -0800140 val textStyle = TextStyle(color = Color(0xFF0000FF.toInt()))
141 val textStyleOverwrite = TextStyle(color = Color(0xFF00FF00.toInt()))
142
143 val paragraph = simpleParagraph(
144 text = text,
145 textStyles = listOf(
Haoyu Zhang27429892019-06-11 13:19:57 -0700146 AnnotatedString.Item(textStyle, 0, text.length),
147 AnnotatedString.Item(textStyleOverwrite, 0, "abc".length)
Haoyu Zhang4b201d22018-12-18 14:27:38 -0800148 )
Haoyu Zhang47f57a22018-12-12 13:16:40 -0800149 )
George Mountb1cdd862018-12-21 10:54:42 -0800150 paragraph.layout(100.0f)
Haoyu Zhang47f57a22018-12-12 13:16:40 -0800151
152 assertThat(paragraph.underlyingText, hasSpan(ForegroundColorSpan::class, 0, text.length))
153 assertThat(paragraph.underlyingText, hasSpan(ForegroundColorSpan::class, 0, "abc".length))
154 assertThat(
155 paragraph.underlyingText,
156 hasSpanOnTop(ForegroundColorSpan::class, 0, "abc".length)
157 )
158 }
159
Haoyu Zhangbb51ccf2018-12-17 15:07:43 -0800160 @Test
Haoyu Zhangb5677202018-12-19 14:22:18 -0800161 fun testStyle_setTextDecorationOnWholeText_withLineThrough() {
162 val text = "abcde"
Siyamed Sinir9fd89f42019-05-20 18:04:29 -0700163 val textStyle = TextStyle(decoration = TextDecoration.LineThrough)
Haoyu Zhangb5677202018-12-19 14:22:18 -0800164
165 val paragraph = simpleParagraph(
166 text = text,
Haoyu Zhang27429892019-06-11 13:19:57 -0700167 textStyles = listOf(AnnotatedString.Item(textStyle, 0, text.length))
Haoyu Zhangb5677202018-12-19 14:22:18 -0800168 )
George Mountb1cdd862018-12-21 10:54:42 -0800169 paragraph.layout(100.0f)
Haoyu Zhangb5677202018-12-19 14:22:18 -0800170
171 assertThat(paragraph.underlyingText.toString(), equalTo(text))
172 assertThat(paragraph.underlyingText, hasSpan(StrikethroughSpan::class, 0, text.length))
173 }
174
175 @Test
176 fun testStyle_setTextDecorationOnWholeText_withUnderline() {
177 val text = "abcde"
Siyamed Sinir9fd89f42019-05-20 18:04:29 -0700178 val textStyle = TextStyle(decoration = TextDecoration.Underline)
Haoyu Zhangb5677202018-12-19 14:22:18 -0800179
180 val paragraph = simpleParagraph(
181 text = text,
Haoyu Zhang27429892019-06-11 13:19:57 -0700182 textStyles = listOf(AnnotatedString.Item(textStyle, 0, text.length))
Haoyu Zhangb5677202018-12-19 14:22:18 -0800183 )
George Mountb1cdd862018-12-21 10:54:42 -0800184 paragraph.layout(100.0f)
Haoyu Zhangb5677202018-12-19 14:22:18 -0800185
186 assertThat(paragraph.underlyingText.toString(), equalTo(text))
187 assertThat(paragraph.underlyingText, hasSpan(UnderlineSpan::class, 0, text.length))
188 }
189
190 @Test
191 fun testStyle_setTextDecorationOnPartText_withLineThrough() {
192 val text = "abcde"
Siyamed Sinir9fd89f42019-05-20 18:04:29 -0700193 val textStyle = TextStyle(decoration = TextDecoration.LineThrough)
Haoyu Zhangb5677202018-12-19 14:22:18 -0800194
195 val paragraph = simpleParagraph(
196 text = text,
Haoyu Zhang27429892019-06-11 13:19:57 -0700197 textStyles = listOf(AnnotatedString.Item(textStyle, 0, "abc".length))
Haoyu Zhangb5677202018-12-19 14:22:18 -0800198 )
George Mountb1cdd862018-12-21 10:54:42 -0800199 paragraph.layout(100.0f)
Haoyu Zhangb5677202018-12-19 14:22:18 -0800200
201 assertThat(paragraph.underlyingText.toString(), equalTo(text))
202 assertThat(paragraph.underlyingText, hasSpan(StrikethroughSpan::class, 0, "abc".length))
203 }
204
205 @Test
206 fun testStyle_setTextDecorationOnPartText_withUnderline() {
207 val text = "abcde"
Siyamed Sinir9fd89f42019-05-20 18:04:29 -0700208 val textStyle = TextStyle(decoration = TextDecoration.Underline)
Haoyu Zhangb5677202018-12-19 14:22:18 -0800209
210 val paragraph = simpleParagraph(
211 text = text,
Haoyu Zhang27429892019-06-11 13:19:57 -0700212 textStyles = listOf(AnnotatedString.Item(textStyle, 0, "abc".length))
Haoyu Zhangb5677202018-12-19 14:22:18 -0800213 )
George Mountb1cdd862018-12-21 10:54:42 -0800214 paragraph.layout(100.0f)
Haoyu Zhangb5677202018-12-19 14:22:18 -0800215
216 assertThat(paragraph.underlyingText.toString(), equalTo(text))
217 assertThat(paragraph.underlyingText, hasSpan(UnderlineSpan::class, 0, "abc".length))
218 }
219
220 @Test
221 fun testStyle_setTextDecoration_withLineThroughAndUnderline() {
222 val text = "abcde"
223 val textStyle = TextStyle(
224 decoration = TextDecoration.combine(
Siyamed Sinir9fd89f42019-05-20 18:04:29 -0700225 listOf(TextDecoration.LineThrough, TextDecoration.Underline)
Haoyu Zhangb5677202018-12-19 14:22:18 -0800226 )
227 )
228
229 val paragraph = simpleParagraph(
230 text = text,
Haoyu Zhang27429892019-06-11 13:19:57 -0700231 textStyles = listOf(AnnotatedString.Item(textStyle, 0, "abc".length))
Haoyu Zhangb5677202018-12-19 14:22:18 -0800232 )
George Mountb1cdd862018-12-21 10:54:42 -0800233 paragraph.layout(100.0f)
Haoyu Zhangb5677202018-12-19 14:22:18 -0800234
235 assertThat(paragraph.underlyingText.toString(), equalTo(text))
236 assertThat(paragraph.underlyingText, hasSpan(UnderlineSpan::class, 0, "abc".length))
237 assertThat(paragraph.underlyingText, hasSpan(StrikethroughSpan::class, 0, "abc".length))
238 }
239
240 @Test
haoyua8e48a52019-06-25 12:23:27 -0700241 fun testAnnotatedString_setFontSizeOnWholeText() {
Haoyu Zhangbb51ccf2018-12-17 15:07:43 -0800242 val text = "abcde"
George Mountb1cdd862018-12-21 10:54:42 -0800243 val fontSize = 20.0f
Haoyu Zhangbb51ccf2018-12-17 15:07:43 -0800244 val paragraphWidth = text.length * fontSize
245 val textStyle = TextStyle(fontSize = fontSize)
246
247 val paragraph = simpleParagraph(
248 text = text,
Haoyu Zhang27429892019-06-11 13:19:57 -0700249 textStyles = listOf(AnnotatedString.Item(textStyle, 0, text.length))
Haoyu Zhangbb51ccf2018-12-17 15:07:43 -0800250 )
251 paragraph.layout(paragraphWidth)
252
253 assertThat(paragraph.underlyingText, hasSpan(AbsoluteSizeSpan::class, 0, text.length))
254 }
255
256 @Test
haoyua8e48a52019-06-25 12:23:27 -0700257 fun testAnnotatedString_setFontSizeOnPartText() {
Haoyu Zhangbb51ccf2018-12-17 15:07:43 -0800258 val text = "abcde"
George Mountb1cdd862018-12-21 10:54:42 -0800259 val fontSize = 20.0f
Haoyu Zhangbb51ccf2018-12-17 15:07:43 -0800260 val paragraphWidth = text.length * fontSize
261 val textStyle = TextStyle(fontSize = fontSize)
262
263 val paragraph = simpleParagraph(
264 text = text,
Haoyu Zhang27429892019-06-11 13:19:57 -0700265 textStyles = listOf(AnnotatedString.Item(textStyle, 0, "abc".length))
Haoyu Zhangbb51ccf2018-12-17 15:07:43 -0800266 )
267 paragraph.layout(paragraphWidth)
268
269 assertThat(paragraph.underlyingText, hasSpan(AbsoluteSizeSpan::class, 0, "abc".length))
270 }
271
272 @Test
haoyua8e48a52019-06-25 12:23:27 -0700273 fun testAnnotatedString_setFontSizeTwice_lastOneOverwrite() {
Haoyu Zhangbb51ccf2018-12-17 15:07:43 -0800274 val text = "abcde"
George Mountb1cdd862018-12-21 10:54:42 -0800275 val fontSize = 20.0f
276 val fontSizeOverwrite = 30.0f
Haoyu Zhangbb51ccf2018-12-17 15:07:43 -0800277 val paragraphWidth = text.length * fontSizeOverwrite
278 val textStyle = TextStyle(fontSize = fontSize)
279 val textStyleOverwrite = TextStyle(fontSize = fontSizeOverwrite)
280
281 val paragraph = simpleParagraph(
282 text = text,
283 textStyles = listOf(
Haoyu Zhang27429892019-06-11 13:19:57 -0700284 AnnotatedString.Item(textStyle, 0, text.length),
285 AnnotatedString.Item(textStyleOverwrite, 0, "abc".length)
Haoyu Zhangbb51ccf2018-12-17 15:07:43 -0800286 )
287 )
288 paragraph.layout(paragraphWidth)
289
290 assertThat(paragraph.underlyingText, hasSpan(AbsoluteSizeSpan::class, 0, text.length))
291 assertThat(paragraph.underlyingText, hasSpan(AbsoluteSizeSpan::class, 0, "abc".length))
292 assertThat(
293 paragraph.underlyingText,
294 hasSpanOnTop(AbsoluteSizeSpan::class, 0, "abc".length)
295 )
296 }
297
Haoyu Zhang1588ba0f2018-12-19 16:47:10 -0800298 @Test
haoyua8e48a52019-06-25 12:23:27 -0700299 fun testAnnotatedString_setFontSizeScaleOnWholeText() {
Haoyu Zhang24eb32f2019-05-21 16:16:37 -0700300 val text = "abcde"
301 val fontSizeScale = 2.0f
302 val textStyle = TextStyle(fontSizeScale = fontSizeScale)
303
304 val paragraph = simpleParagraph(
305 text = text,
Haoyu Zhang27429892019-06-11 13:19:57 -0700306 textStyles = listOf(AnnotatedString.Item(textStyle, 0, text.length))
Haoyu Zhang24eb32f2019-05-21 16:16:37 -0700307 )
308 paragraph.layout(100f)
309
310 assertThat(
311 paragraph.underlyingText,
312 hasSpan(RelativeSizeSpan::class, 0, text.length) {
313 it.sizeChange == fontSizeScale
314 }
315 )
316 }
317
318 @Test
haoyua8e48a52019-06-25 12:23:27 -0700319 fun testAnnotatedString_setFontSizeScaleOnPartText() {
Haoyu Zhang24eb32f2019-05-21 16:16:37 -0700320 val text = "abcde"
321 val fontSizeScale = 2.0f
322 val textStyle = TextStyle(fontSizeScale = fontSizeScale)
323
324 val paragraph = simpleParagraph(
325 text = text,
Haoyu Zhang27429892019-06-11 13:19:57 -0700326 textStyles = listOf(AnnotatedString.Item(textStyle, 0, "abc".length))
Haoyu Zhang24eb32f2019-05-21 16:16:37 -0700327 )
328 paragraph.layout(100f)
329
330 assertThat(
331 paragraph.underlyingText,
332 hasSpan(RelativeSizeSpan::class, 0, "abc".length) {
333 it.sizeChange == fontSizeScale
334 }
335 )
336 }
337
338 @Test
haoyua8e48a52019-06-25 12:23:27 -0700339 fun testAnnotatedString_setLetterSpacingOnWholeText() {
Haoyu Zhang1588ba0f2018-12-19 16:47:10 -0800340 val text = "abcde"
George Mountb1cdd862018-12-21 10:54:42 -0800341 val letterSpacing = 2.0f
Haoyu Zhang1588ba0f2018-12-19 16:47:10 -0800342 val textStyle = TextStyle(letterSpacing = letterSpacing)
343
344 val paragraph = simpleParagraph(
345 text = text,
Haoyu Zhang27429892019-06-11 13:19:57 -0700346 textStyles = listOf(AnnotatedString.Item(textStyle, 0, text.length))
Haoyu Zhang1588ba0f2018-12-19 16:47:10 -0800347 )
George Mountb1cdd862018-12-21 10:54:42 -0800348 paragraph.layout(100.0f)
Haoyu Zhang1588ba0f2018-12-19 16:47:10 -0800349 assertThat(paragraph.underlyingText.toString(), equalTo(text))
350 assertThat(paragraph.underlyingText, hasSpan(LetterSpacingSpan::class, 0, text.length))
351 }
352
353 @Test
haoyua8e48a52019-06-25 12:23:27 -0700354 fun testAnnotatedString_setLetterSpacingOnPartText() {
Haoyu Zhang1588ba0f2018-12-19 16:47:10 -0800355 val text = "abcde"
George Mountb1cdd862018-12-21 10:54:42 -0800356 val textStyle = TextStyle(letterSpacing = 2.0f)
Haoyu Zhang1588ba0f2018-12-19 16:47:10 -0800357
358 val paragraph = simpleParagraph(
359 text = text,
Haoyu Zhang27429892019-06-11 13:19:57 -0700360 textStyles = listOf(AnnotatedString.Item(textStyle, 0, "abc".length))
Haoyu Zhang1588ba0f2018-12-19 16:47:10 -0800361 )
George Mountb1cdd862018-12-21 10:54:42 -0800362 paragraph.layout(100.0f)
Haoyu Zhang1588ba0f2018-12-19 16:47:10 -0800363 assertThat(paragraph.underlyingText.toString(), equalTo(text))
364 assertThat(paragraph.underlyingText, hasSpan(LetterSpacingSpan::class, 0, "abc".length))
365 }
366
367 @Test
haoyua8e48a52019-06-25 12:23:27 -0700368 fun testAnnotatedString_setLetterSpacingTwice_lastOneOverwrite() {
Haoyu Zhang1588ba0f2018-12-19 16:47:10 -0800369 val text = "abcde"
George Mountb1cdd862018-12-21 10:54:42 -0800370 val textStyle = TextStyle(letterSpacing = 2.0f)
371 val textStyleOverwrite = TextStyle(letterSpacing = 3.0f)
Haoyu Zhang1588ba0f2018-12-19 16:47:10 -0800372
373 val paragraph = simpleParagraph(
374 text = text,
375 textStyles = listOf(
Haoyu Zhang27429892019-06-11 13:19:57 -0700376 AnnotatedString.Item(textStyle, 0, text.length),
377 AnnotatedString.Item(textStyleOverwrite, 0, "abc".length)
Haoyu Zhang1588ba0f2018-12-19 16:47:10 -0800378 )
379 )
George Mountb1cdd862018-12-21 10:54:42 -0800380 paragraph.layout(100.0f)
Haoyu Zhang1588ba0f2018-12-19 16:47:10 -0800381 assertThat(paragraph.underlyingText.toString(), equalTo(text))
382 assertThat(paragraph.underlyingText, hasSpan(LetterSpacingSpan::class, 0, text.length))
383 assertThat(paragraph.underlyingText, hasSpan(LetterSpacingSpan::class, 0, "abc".length))
384 assertThat(
385 paragraph.underlyingText,
386 hasSpanOnTop(LetterSpacingSpan::class, 0, "abc".length)
387 )
388 }
389
Siyamed Sinir70f336a2018-12-27 10:37:09 -0800390 @Test
haoyuf6e7c0c2019-06-18 16:04:02 -0700391 @SdkSuppress(minSdkVersion = 29)
haoyua8e48a52019-06-25 12:23:27 -0700392 fun testAnnotatedString_setWordSpacingOnWholeText() {
Haoyu Zhang97d5e722019-01-04 17:32:34 -0800393 val text = "ab cd"
394 val wordSpacing = 2.0f
395 val textStyle = TextStyle(wordSpacing = wordSpacing)
396
397 val paragraph = simpleParagraph(
398 text = text,
Haoyu Zhang27429892019-06-11 13:19:57 -0700399 textStyles = listOf(AnnotatedString.Item(textStyle, 0, text.length))
Haoyu Zhang97d5e722019-01-04 17:32:34 -0800400 )
401 // Notice that the width doesn't matter for this test.
402 paragraph.layout(100.0f)
403
404 assertThat(paragraph.underlyingText.toString(), equalTo(text))
405 assertThat(
406 paragraph.underlyingText,
407 hasSpan(WordSpacingSpan::class, 0, text.length) { span ->
408 span.wordSpacing == wordSpacing.toFloat()
409 }
410 )
411 }
412
413 @Test
haoyuf6e7c0c2019-06-18 16:04:02 -0700414 @SdkSuppress(minSdkVersion = 29)
haoyua8e48a52019-06-25 12:23:27 -0700415 fun testAnnotatedString_setWordSpacingOnPartText() {
Haoyu Zhang97d5e722019-01-04 17:32:34 -0800416 val text = "abc d"
417 val wordSpacing = 2.0f
418 val textStyle = TextStyle(wordSpacing = wordSpacing)
419
420 val paragraph = simpleParagraph(
421 text = text,
Haoyu Zhang27429892019-06-11 13:19:57 -0700422 textStyles = listOf(AnnotatedString.Item(textStyle, 0, "abc".length))
Haoyu Zhang97d5e722019-01-04 17:32:34 -0800423 )
424 // Notice that the width doesn't matter for this test.
425 paragraph.layout(100.0f)
426
427 assertThat(paragraph.underlyingText.toString(), equalTo(text))
428 assertThat(
429 paragraph.underlyingText,
430 hasSpan(WordSpacingSpan::class, 0, "abc".length) { span ->
431 span.wordSpacing == wordSpacing.toFloat()
432 }
433 )
434 }
435
436 @Test
haoyuf6e7c0c2019-06-18 16:04:02 -0700437 @SdkSuppress(minSdkVersion = 29)
haoyua8e48a52019-06-25 12:23:27 -0700438 fun testAnnotatedString_setWordSpacingTwice_lastOneOverwrite() {
Haoyu Zhang97d5e722019-01-04 17:32:34 -0800439 val text = "abc d"
440 val wordSpacing = 2.0f
441 val textStyle = TextStyle(wordSpacing = wordSpacing)
442 val wordSpacingOverwrite = 3.0f
443 val textStyleOverwrite = TextStyle(wordSpacing = wordSpacingOverwrite)
444
445 val paragraph = simpleParagraph(
446 text = text,
447 textStyles = listOf(
Haoyu Zhang27429892019-06-11 13:19:57 -0700448 AnnotatedString.Item(textStyle, 0, text.length),
449 AnnotatedString.Item(textStyleOverwrite, 0, "abc".length)
Haoyu Zhang97d5e722019-01-04 17:32:34 -0800450 )
451 )
452 // Notice that the width doesn't matter for this test.
453 paragraph.layout(100.0f)
454
455 assertThat(paragraph.underlyingText.toString(), equalTo(text))
456 assertThat(
457 paragraph.underlyingText,
458 hasSpan(WordSpacingSpan::class, 0, text.length) { span ->
459 span.wordSpacing == wordSpacing.toFloat()
460 }
461 )
462 assertThat(
463 paragraph.underlyingText,
464 hasSpan(WordSpacingSpan::class, 0, "abc".length) { span ->
465 span.wordSpacing == wordSpacingOverwrite.toFloat()
466 }
467 )
468 assertThat(
469 paragraph.underlyingText,
470 hasSpanOnTop(WordSpacingSpan::class, 0, "abc".length) { span ->
471 span.wordSpacing == wordSpacingOverwrite.toFloat()
472 }
473 )
474 }
475
476 @Test
haoyua8e48a52019-06-25 12:23:27 -0700477 fun testAnnotatedString_setBackgroundOnWholeText() {
Haoyu Zhang0c4fd022019-01-02 13:53:10 -0800478 val text = "abcde"
479 val color = Color(0xFF0000FF.toInt())
Haoyu Zhang437d9452019-01-04 17:34:04 -0800480 val textStyle = TextStyle(background = color)
Haoyu Zhang0c4fd022019-01-02 13:53:10 -0800481
482 val paragraph = simpleParagraph(
483 text = text,
Haoyu Zhang27429892019-06-11 13:19:57 -0700484 textStyles = listOf(AnnotatedString.Item(textStyle, 0, text.length))
Haoyu Zhang0c4fd022019-01-02 13:53:10 -0800485 )
George Mountb1cdd862018-12-21 10:54:42 -0800486 paragraph.layout(100.0f)
Haoyu Zhang0c4fd022019-01-02 13:53:10 -0800487
488 assertThat(paragraph.underlyingText.toString(), equalTo(text))
489 assertThat(paragraph.underlyingText,
490 hasSpan(BackgroundColorSpan::class, 0, text.length) { span ->
George Mounta3145782019-05-02 10:08:03 -0700491 span.backgroundColor == color.toArgb()
Haoyu Zhang0c4fd022019-01-02 13:53:10 -0800492 }
493 )
494 }
495
496 @Test
haoyua8e48a52019-06-25 12:23:27 -0700497 fun testAnnotatedString_setBackgroundOnPartText() {
Haoyu Zhang0c4fd022019-01-02 13:53:10 -0800498 val text = "abcde"
499 val color = Color(0xFF0000FF.toInt())
Haoyu Zhang437d9452019-01-04 17:34:04 -0800500 val textStyle = TextStyle(background = color)
Haoyu Zhang0c4fd022019-01-02 13:53:10 -0800501
502 val paragraph = simpleParagraph(
503 text = text,
Haoyu Zhang27429892019-06-11 13:19:57 -0700504 textStyles = listOf(AnnotatedString.Item(textStyle, 0, "abc".length))
Haoyu Zhang0c4fd022019-01-02 13:53:10 -0800505 )
George Mountb1cdd862018-12-21 10:54:42 -0800506 paragraph.layout(100.0f)
Haoyu Zhang0c4fd022019-01-02 13:53:10 -0800507
508 assertThat(paragraph.underlyingText.toString(), equalTo(text))
509 assertThat(paragraph.underlyingText,
510 hasSpan(BackgroundColorSpan::class, 0, "abc".length) { span ->
George Mounta3145782019-05-02 10:08:03 -0700511 span.backgroundColor == color.toArgb()
Haoyu Zhang0c4fd022019-01-02 13:53:10 -0800512 }
513 )
514 }
515
516 @Test
haoyua8e48a52019-06-25 12:23:27 -0700517 fun testAnnotatedString_setBackgroundTwice_lastOneOverwrite() {
Haoyu Zhang0c4fd022019-01-02 13:53:10 -0800518 val text = "abcde"
519 val color = Color(0xFF0000FF.toInt())
Haoyu Zhang437d9452019-01-04 17:34:04 -0800520 val textStyle = TextStyle(background = color)
Haoyu Zhang0c4fd022019-01-02 13:53:10 -0800521 val colorOverwrite = Color(0xFF00FF00.toInt())
Haoyu Zhang437d9452019-01-04 17:34:04 -0800522 val textStyleOverwrite = TextStyle(background = colorOverwrite)
Haoyu Zhang0c4fd022019-01-02 13:53:10 -0800523
524 val paragraph = simpleParagraph(
525 text = text,
526 textStyles = listOf(
Haoyu Zhang27429892019-06-11 13:19:57 -0700527 AnnotatedString.Item(textStyle, 0, text.length),
528 AnnotatedString.Item(textStyleOverwrite, 0, "abc".length)
Haoyu Zhang0c4fd022019-01-02 13:53:10 -0800529 )
530 )
George Mountb1cdd862018-12-21 10:54:42 -0800531 paragraph.layout(100.0f)
Haoyu Zhang0c4fd022019-01-02 13:53:10 -0800532
533 assertThat(paragraph.underlyingText.toString(), equalTo(text))
534 assertThat(paragraph.underlyingText,
535 hasSpan(BackgroundColorSpan::class, 0, text.length) { span ->
George Mounta3145782019-05-02 10:08:03 -0700536 span.backgroundColor == color.toArgb()
Haoyu Zhang0c4fd022019-01-02 13:53:10 -0800537 }
538 )
539 assertThat(paragraph.underlyingText,
540 hasSpan(BackgroundColorSpan::class, 0, "abc".length) { span ->
George Mounta3145782019-05-02 10:08:03 -0700541 span.backgroundColor == colorOverwrite.toArgb()
Haoyu Zhang0c4fd022019-01-02 13:53:10 -0800542 }
543 )
544 assertThat(
545 paragraph.underlyingText,
546 hasSpanOnTop(BackgroundColorSpan::class, 0, "abc".length) { span ->
George Mounta3145782019-05-02 10:08:03 -0700547 span.backgroundColor == colorOverwrite.toArgb()
Haoyu Zhang0c4fd022019-01-02 13:53:10 -0800548 }
549 )
550 }
551
552 @Test
haoyua8e48a52019-06-25 12:23:27 -0700553 fun testAnnotatedString_setLocaleOnWholeText() {
Haoyu Zhang4b201d22018-12-18 14:27:38 -0800554 val text = "abcde"
555 val locale = Locale("en", "US")
556 val textStyle = TextStyle(locale = locale)
557
558 val paragraph = simpleParagraph(
559 text = text,
Haoyu Zhang27429892019-06-11 13:19:57 -0700560 textStyles = listOf(AnnotatedString.Item(textStyle, 0, text.length))
Haoyu Zhang4b201d22018-12-18 14:27:38 -0800561 )
George Mountb1cdd862018-12-21 10:54:42 -0800562 paragraph.layout(100.0f)
Haoyu Zhang4b201d22018-12-18 14:27:38 -0800563
564 assertThat(paragraph.underlyingText, hasSpan(LocaleSpan::class, 0, text.length))
565 }
566
567 @Test
haoyua8e48a52019-06-25 12:23:27 -0700568 fun testAnnotatedString_setLocaleOnPartText() {
Haoyu Zhang4b201d22018-12-18 14:27:38 -0800569 val text = "abcde"
570 val locale = Locale("en", "US")
571 val textStyle = TextStyle(locale = locale)
572
573 val paragraph = simpleParagraph(
574 text = text,
Haoyu Zhang27429892019-06-11 13:19:57 -0700575 textStyles = listOf(AnnotatedString.Item(textStyle, 0, "abc".length))
Haoyu Zhang4b201d22018-12-18 14:27:38 -0800576 )
George Mountb1cdd862018-12-21 10:54:42 -0800577 paragraph.layout(100.0f)
Haoyu Zhang4b201d22018-12-18 14:27:38 -0800578
579 assertThat(paragraph.underlyingText, hasSpan(LocaleSpan::class, 0, "abc".length))
580 }
581
582 @Test
haoyua8e48a52019-06-25 12:23:27 -0700583 fun testAnnotatedString_setLocaleTwice_lastOneOverwrite() {
Haoyu Zhang4b201d22018-12-18 14:27:38 -0800584 val text = "abcde"
585 val textStyle = TextStyle(locale = Locale("en", "US"))
586 val textStyleOverwrite = TextStyle(locale = Locale("ja", "JP"))
587
588 val paragraph = simpleParagraph(
589 text = text,
590 textStyles = listOf(
Haoyu Zhang27429892019-06-11 13:19:57 -0700591 AnnotatedString.Item(textStyle, 0, text.length),
592 AnnotatedString.Item(textStyleOverwrite, 0, "abc".length)
Haoyu Zhang4b201d22018-12-18 14:27:38 -0800593 )
594 )
George Mountb1cdd862018-12-21 10:54:42 -0800595 paragraph.layout(100.0f)
Haoyu Zhang4b201d22018-12-18 14:27:38 -0800596
597 assertThat(paragraph.underlyingText, hasSpan(LocaleSpan::class, 0, text.length))
598 assertThat(paragraph.underlyingText, hasSpan(LocaleSpan::class, 0, "abc".length))
599 assertThat(
600 paragraph.underlyingText,
601 hasSpanOnTop(LocaleSpan::class, 0, "abc".length)
602 )
603 }
604
605 @Test
haoyua8e48a52019-06-25 12:23:27 -0700606 fun testAnnotatedString_setBaselineShiftOnWholeText() {
Haoyu Zhang40ce6bf2019-01-28 15:58:20 -0800607 val text = "abcde"
Siyamed Sinirf544c152019-05-21 12:12:21 -0700608 val textStyle = TextStyle(baselineShift = BaselineShift.Subscript)
Haoyu Zhang40ce6bf2019-01-28 15:58:20 -0800609
610 val paragraph = simpleParagraph(
611 text = text,
Haoyu Zhang27429892019-06-11 13:19:57 -0700612 textStyles = listOf(AnnotatedString.Item(textStyle, 0, text.length))
Haoyu Zhang40ce6bf2019-01-28 15:58:20 -0800613 )
614 // width is not important
615 paragraph.layout(100.0f)
616
617 assertThat(paragraph.underlyingText, hasSpan(BaselineShiftSpan::class, 0, text.length))
618 }
619
620 @Test
haoyua8e48a52019-06-25 12:23:27 -0700621 fun testAnnotatedString_setBaselineShiftOnPartText() {
Haoyu Zhang40ce6bf2019-01-28 15:58:20 -0800622 val text = "abcde"
Siyamed Sinirf544c152019-05-21 12:12:21 -0700623 val textStyle = TextStyle(baselineShift = BaselineShift.Superscript)
Haoyu Zhang40ce6bf2019-01-28 15:58:20 -0800624
625 val paragraph = simpleParagraph(
626 text = text,
Haoyu Zhang27429892019-06-11 13:19:57 -0700627 textStyles = listOf(AnnotatedString.Item(textStyle, 0, "abc".length))
Haoyu Zhang40ce6bf2019-01-28 15:58:20 -0800628 )
629 // width is not important
630 paragraph.layout(100.0f)
631
632 assertThat(paragraph.underlyingText, hasSpan(BaselineShiftSpan::class, 0, "abc".length))
633 }
634
635 @Test
haoyua8e48a52019-06-25 12:23:27 -0700636 fun testAnnotatedString_setBaselineShiftTwice_LastOneOnTop() {
Haoyu Zhang40ce6bf2019-01-28 15:58:20 -0800637 val text = "abcde"
Siyamed Sinirf544c152019-05-21 12:12:21 -0700638 val textStyle = TextStyle(baselineShift = BaselineShift.Subscript)
639 val textStyleOverwrite = TextStyle(baselineShift = BaselineShift.Superscript)
Haoyu Zhang40ce6bf2019-01-28 15:58:20 -0800640
641 val paragraph = simpleParagraph(
642 text = text,
643 textStyles = listOf(
Haoyu Zhang27429892019-06-11 13:19:57 -0700644 AnnotatedString.Item(textStyle, 0, text.length),
645 AnnotatedString.Item(textStyleOverwrite, 0, "abc".length)
Haoyu Zhang40ce6bf2019-01-28 15:58:20 -0800646 )
647 )
648 // width is not important
649 paragraph.layout(100.0f)
650
651 assertThat(paragraph.underlyingText, hasSpan(BaselineShiftSpan::class, 0, text.length))
652 assertThat(paragraph.underlyingText, hasSpan(BaselineShiftSpan::class, 0, "abc".length))
653 assertThat(
654 paragraph.underlyingText,
655 hasSpanOnTop(BaselineShiftSpan::class, 0, "abc".length)
656 )
657 }
658
659 @Test
haoyua8e48a52019-06-25 12:23:27 -0700660 fun testAnnotatedString_setTextGeometricTransformWithNull_noSpanSet() {
Haoyu Zhang15750922019-02-19 13:44:17 -0800661 val text = "abcde"
662 val textStyle = TextStyle(textGeometricTransform = TextGeometricTransform(null, null))
663
664 val paragraph = simpleParagraph(
665 text = text,
Haoyu Zhang27429892019-06-11 13:19:57 -0700666 textStyles = listOf(AnnotatedString.Item(textStyle, 0, text.length))
Haoyu Zhang15750922019-02-19 13:44:17 -0800667 )
668 // width is not important
669 paragraph.layout(100.0f)
670
671 assertThat(paragraph.underlyingText, not(hasSpan(ScaleXSpan::class, 0, text.length)))
672 assertThat(paragraph.underlyingText, not(hasSpan(SkewXSpan::class, 0, text.length)))
673 }
674
675 @Test
haoyua8e48a52019-06-25 12:23:27 -0700676 fun testAnnotatedString_setTextGeometricTransformWithScaleX() {
Haoyu Zhang15750922019-02-19 13:44:17 -0800677 val text = "abcde"
678 val scaleX = 0.5f
679 val textStyle = TextStyle(textGeometricTransform = TextGeometricTransform(scaleX, null))
680
681 val paragraph = simpleParagraph(
682 text = text,
Haoyu Zhang27429892019-06-11 13:19:57 -0700683 textStyles = listOf(AnnotatedString.Item(textStyle, 0, text.length))
Haoyu Zhang15750922019-02-19 13:44:17 -0800684 )
685 // width is not important
686 paragraph.layout(100.0f)
687
688 assertThat(
689 paragraph.underlyingText,
690 hasSpan(ScaleXSpan::class, 0, text.length) { it.scaleX == scaleX }
691 )
692 assertThat(paragraph.underlyingText, not(hasSpan(SkewXSpan::class, 0, text.length)))
693 }
694
695 @Test
haoyua8e48a52019-06-25 12:23:27 -0700696 fun testAnnotatedString_setTextGeometricTransformWithSkewX() {
Haoyu Zhang15750922019-02-19 13:44:17 -0800697 val text = "aa"
698 val skewX = 1f
699 val textStyle = TextStyle(textGeometricTransform = TextGeometricTransform(null, skewX))
700
701 val paragraph = simpleParagraph(
702 text = text,
Haoyu Zhang27429892019-06-11 13:19:57 -0700703 textStyles = listOf(AnnotatedString.Item(textStyle, 0, text.length))
Haoyu Zhang15750922019-02-19 13:44:17 -0800704 )
705 // width is not important
706 paragraph.layout(100.0f)
707
708 assertThat(
709 paragraph.underlyingText,
710 hasSpan(SkewXSpan::class, 0, text.length) { it.skewX == skewX }
711 )
712 assertThat(paragraph.underlyingText, not(hasSpan(ScaleXSpan::class, 0, text.length)))
713 }
714
715 @Test
Siyamed Sinir2690d532019-06-21 13:16:00 -0700716 fun textIndent_onWholeParagraph() {
Haoyu Zhang7fc59172019-03-01 17:03:31 -0800717 val text = "abc\ndef"
718 val firstLine = 40
719 val restLine = 20
Haoyu Zhang7fc59172019-03-01 17:03:31 -0800720
721 val paragraph = simpleParagraph(
722 text = text,
Siyamed Sinir2690d532019-06-21 13:16:00 -0700723 textIndent = TextIndent(firstLine.px, restLine.px)
Haoyu Zhang7fc59172019-03-01 17:03:31 -0800724 )
725 // width is not important
726 paragraph.layout(100.0f)
727
728 assertThat(
729 paragraph.underlyingText,
Siyamed Sinir2690d532019-06-21 13:16:00 -0700730 hasSpan(LeadingMarginSpan.Standard::class, 0, text.length) {
Haoyu Zhang7fc59172019-03-01 17:03:31 -0800731 it.getLeadingMargin(true) == firstLine && it.getLeadingMargin(false) == restLine
732 }
733 )
734 }
735
736 @Test
haoyua8e48a52019-06-25 12:23:27 -0700737 fun testAnnotatedString_setShadow() {
Haoyu Zhang2a036c832019-03-08 11:57:13 -0800738 val text = "abcde"
739 val color = Color(0xFF00FF00.toInt())
740 val offset = Offset(1f, 2f)
741 val radius = 3.px
742 val textStyle = TextStyle(shadow = Shadow(color, offset, radius))
743
744 val paragraph = simpleParagraph(
745 text = text,
746 textStyles = listOf(
Haoyu Zhang27429892019-06-11 13:19:57 -0700747 AnnotatedString.Item(textStyle, start = 0, end = text.length)
Haoyu Zhang2a036c832019-03-08 11:57:13 -0800748 )
749 )
750 // width is not important
751 paragraph.layout(100.0f)
752
753 assertThat(
754 paragraph.underlyingText,
755 hasSpan(ShadowSpan::class, start = 0, end = text.length) {
George Mounta3145782019-05-02 10:08:03 -0700756 return@hasSpan it.color == color.toArgb() &&
Haoyu Zhang2a036c832019-03-08 11:57:13 -0800757 it.offsetX == offset.dx &&
758 it.offsetY == offset.dy &&
759 it.radius == radius.value
760 }
761 )
762 }
763
764 @Test
haoyua8e48a52019-06-25 12:23:27 -0700765 fun testAnnotatedString_setShadowTwice_lastOnTop() {
Haoyu Zhang2a036c832019-03-08 11:57:13 -0800766 val text = "abcde"
767 val color = Color(0xFF00FF00.toInt())
768 val offset = Offset(1f, 2f)
769 val radius = 3.px
770 val textStyle = TextStyle(shadow = Shadow(color, offset, radius))
771
772 val colorOverwrite = Color(0xFF0000FF.toInt())
773 val offsetOverwrite = Offset(3f, 2f)
774 val radiusOverwrite = 1.px
775 val textStyleOverwrite = TextStyle(
776 shadow = Shadow(colorOverwrite, offsetOverwrite, radiusOverwrite)
777 )
778
779 val paragraph = simpleParagraph(
780 text = text,
781 textStyles = listOf(
Haoyu Zhang27429892019-06-11 13:19:57 -0700782 AnnotatedString.Item(textStyle, start = 0, end = text.length),
783 AnnotatedString.Item(textStyleOverwrite, start = 0, end = "abc".length)
Haoyu Zhang2a036c832019-03-08 11:57:13 -0800784 )
785 )
786 // width is not important
787 paragraph.layout(100.0f)
788
789 assertThat(
790 paragraph.underlyingText,
791 hasSpan(ShadowSpan::class, start = 0, end = text.length) {
George Mounta3145782019-05-02 10:08:03 -0700792 return@hasSpan it.color == color.toArgb() &&
Haoyu Zhang2a036c832019-03-08 11:57:13 -0800793 it.offsetX == offset.dx &&
794 it.offsetY == offset.dy &&
795 it.radius == radius.value
796 }
797 )
798 assertThat(
799 paragraph.underlyingText,
800 hasSpanOnTop(ShadowSpan::class, start = 0, end = "abc".length) {
George Mounta3145782019-05-02 10:08:03 -0700801 return@hasSpanOnTop it.color == colorOverwrite.toArgb() &&
Haoyu Zhang2a036c832019-03-08 11:57:13 -0800802 it.offsetX == offsetOverwrite.dx &&
803 it.offsetY == offsetOverwrite.dy &&
804 it.radius == radiusOverwrite.value
805 }
806 )
807 }
808
809 @Test
haoyua8e48a52019-06-25 12:23:27 -0700810 fun testAnnotatedString_fontFamily_addsTypefaceSpanWithCorrectTypeface() {
Siyamed Sinir70f336a2018-12-27 10:37:09 -0800811 val text = "abcde"
812 val textStyle = TextStyle(
813 fontFamily = fontFamily,
Siyamed Siniradf982d2019-05-20 17:35:13 -0700814 fontStyle = FontStyle.Italic,
Siyamed Sinir70f336a2018-12-27 10:37:09 -0800815 fontWeight = FontWeight.bold
816 )
817 val expectedTypeface = TypefaceAdapter().create(
818 fontFamily = fontFamily,
Siyamed Siniradf982d2019-05-20 17:35:13 -0700819 fontStyle = FontStyle.Italic,
Siyamed Sinir70f336a2018-12-27 10:37:09 -0800820 fontWeight = FontWeight.bold
821 )
Siyamed Sinir37298412018-12-27 19:47:15 -0800822 val expectedStart = 0
823 val expectedEnd = "abc".length
Siyamed Sinir70f336a2018-12-27 10:37:09 -0800824
825 val paragraph = simpleParagraph(
826 text = text,
Siyamed Sinir37298412018-12-27 19:47:15 -0800827 textStyles = listOf(
Haoyu Zhang27429892019-06-11 13:19:57 -0700828 AnnotatedString.Item(
Siyamed Sinir37298412018-12-27 19:47:15 -0800829 textStyle,
830 expectedStart,
831 expectedEnd
832 )
833 )
Siyamed Sinir70f336a2018-12-27 10:37:09 -0800834 )
George Mountb1cdd862018-12-21 10:54:42 -0800835 paragraph.layout(100.0f)
Siyamed Sinir70f336a2018-12-27 10:37:09 -0800836
837 assertThat(paragraph.underlyingText.toString(), equalTo(text))
838 assertThat(
839 paragraph.underlyingText,
Siyamed Sinir37298412018-12-27 19:47:15 -0800840 hasSpan(TypefaceSpan::class, expectedStart, expectedEnd) { span ->
Siyamed Sinir70f336a2018-12-27 10:37:09 -0800841 span.typeface == expectedTypeface
Siyamed Sinir37298412018-12-27 19:47:15 -0800842 })
843 }
844
845 @Test
haoyua8e48a52019-06-25 12:23:27 -0700846 fun testAnnotatedString_fontFamily_whenFontSynthesizeTurnedOff() {
Siyamed Sinir37298412018-12-27 19:47:15 -0800847 val text = "abcde"
848 val textStyle = TextStyle(
849 fontFamily = fontFamily,
Siyamed Siniradf982d2019-05-20 17:35:13 -0700850 fontStyle = FontStyle.Italic,
Siyamed Sinir37298412018-12-27 19:47:15 -0800851 fontWeight = FontWeight.bold,
Siyamed Sinir934a3442019-06-18 12:57:13 -0700852 fontSynthesis = FontSynthesis.None
Siyamed Sinir70f336a2018-12-27 10:37:09 -0800853 )
Siyamed Sinir37298412018-12-27 19:47:15 -0800854 val expectedTypeface = TypefaceAdapter().create(
855 fontFamily = fontFamily,
Siyamed Siniradf982d2019-05-20 17:35:13 -0700856 fontStyle = FontStyle.Italic,
Siyamed Sinir37298412018-12-27 19:47:15 -0800857 fontWeight = FontWeight.bold,
Siyamed Sinir934a3442019-06-18 12:57:13 -0700858 fontSynthesis = FontSynthesis.None
Siyamed Sinir37298412018-12-27 19:47:15 -0800859 )
860 val expectedStart = 0
861 val expectedEnd = "abc".length
862
863 val paragraph = simpleParagraph(
864 text = text,
865 textStyles = listOf(
Haoyu Zhang27429892019-06-11 13:19:57 -0700866 AnnotatedString.Item(
Siyamed Sinir37298412018-12-27 19:47:15 -0800867 textStyle,
868 expectedStart,
869 expectedEnd
870 )
871 )
872 )
George Mountb1cdd862018-12-21 10:54:42 -0800873 paragraph.layout(100.0f)
Siyamed Sinir37298412018-12-27 19:47:15 -0800874
875 assertThat(paragraph.underlyingText.toString(), equalTo(text))
876 assertThat(
877 paragraph.underlyingText,
878 hasSpan(TypefaceSpan::class, expectedStart, expectedEnd) { span ->
879 span.typeface == expectedTypeface
880 })
Siyamed Sinir70f336a2018-12-27 10:37:09 -0800881 }
882
883 @Test
haoyua8e48a52019-06-25 12:23:27 -0700884 fun testAnnotatedString_fontFeatureSetting_setSpanOnText() {
Haoyu Zhang588aaef2019-02-20 14:47:39 -0800885 val text = "abc"
886 val fontFeatureSettings = "\"kern\" 0"
887 val textStyle = TextStyle(fontFeatureSettings = fontFeatureSettings)
888
889 val paragraph = simpleParagraph(
890 text = text,
Haoyu Zhang27429892019-06-11 13:19:57 -0700891 textStyles = listOf(AnnotatedString.Item(textStyle, 0, "abc".length))
Haoyu Zhang588aaef2019-02-20 14:47:39 -0800892 )
893 // width is not important
894 paragraph.layout(100.0f)
895
896 assertThat(
897 paragraph.underlyingText,
898 hasSpan(FontFeatureSpan::class, 0, "abc".length) {
899 it.fontFeatureSettings == fontFeatureSettings
900 })
901 }
902
903 @Test
Siyamed Sinirf18dcca2018-12-20 18:25:10 -0800904 fun testEmptyFontFamily() {
905 val typefaceAdapter = mock<TypefaceAdapter>()
906 val paragraph = simpleParagraph(
907 text = "abc",
908 typefaceAdapter = typefaceAdapter
909 )
George Mountb1cdd862018-12-21 10:54:42 -0800910 paragraph.layout(Float.MAX_VALUE)
Siyamed Sinirf18dcca2018-12-20 18:25:10 -0800911
912 verify(typefaceAdapter, never()).create(
913 fontFamily = any(),
914 fontWeight = any(),
Siyamed Sinir21796012018-12-26 13:51:17 -0800915 fontStyle = any(),
916 fontSynthesis = any()
Siyamed Sinirf18dcca2018-12-20 18:25:10 -0800917 )
918 assertThat(paragraph.textPaint.typeface, nullValue())
919 }
920
921 @Test
922 fun testEmptyFontFamily_withBoldFontWeightSelection() {
923 val typefaceAdapter = spy(TypefaceAdapter())
924
925 val paragraph = simpleParagraph(
926 text = "abc",
927 fontFamily = null,
928 fontWeight = FontWeight.bold,
929 typefaceAdapter = typefaceAdapter
930 )
George Mountb1cdd862018-12-21 10:54:42 -0800931 paragraph.layout(Float.MAX_VALUE)
Siyamed Sinirf18dcca2018-12-20 18:25:10 -0800932
933 verify(typefaceAdapter, times(1)).create(
934 fontFamily = eq(null),
935 fontWeight = eq(FontWeight.bold),
Siyamed Siniradf982d2019-05-20 17:35:13 -0700936 fontStyle = eq(FontStyle.Normal),
Siyamed Sinir934a3442019-06-18 12:57:13 -0700937 fontSynthesis = eq(FontSynthesis.All)
Siyamed Sinirf18dcca2018-12-20 18:25:10 -0800938 )
939
940 val typeface = paragraph.textPaint.typeface
941 assertThat(typeface, not(nullValue()))
942 assertThat(typeface.isBold, equalTo(true))
943 assertThat(typeface.isItalic, equalTo(false))
944 }
945
946 @Test
947 fun testEmptyFontFamily_withFontStyleSelection() {
948 val typefaceAdapter = spy(TypefaceAdapter())
949 val paragraph = simpleParagraph(
950 text = "abc",
951 fontFamily = null,
Siyamed Siniradf982d2019-05-20 17:35:13 -0700952 fontStyle = FontStyle.Italic,
Siyamed Sinirf18dcca2018-12-20 18:25:10 -0800953 typefaceAdapter = typefaceAdapter
954 )
George Mountb1cdd862018-12-21 10:54:42 -0800955 paragraph.layout(Float.MAX_VALUE)
Siyamed Sinirf18dcca2018-12-20 18:25:10 -0800956
957 verify(typefaceAdapter, times(1)).create(
958 fontFamily = eq(null),
959 fontWeight = eq(FontWeight.normal),
Siyamed Siniradf982d2019-05-20 17:35:13 -0700960 fontStyle = eq(FontStyle.Italic),
Siyamed Sinir934a3442019-06-18 12:57:13 -0700961 fontSynthesis = eq(FontSynthesis.All)
Siyamed Sinirf18dcca2018-12-20 18:25:10 -0800962 )
963
964 val typeface = paragraph.textPaint.typeface
965 assertThat(typeface, not(nullValue()))
966 assertThat(typeface.isBold, equalTo(false))
967 assertThat(typeface.isItalic, equalTo(true))
968 }
969
970 @Test
971 fun testFontFamily_withGenericFamilyName() {
972 val typefaceAdapter = spy(TypefaceAdapter())
973 val fontFamily = FontFamily("sans-serif")
974
975 val paragraph = simpleParagraph(
976 text = "abc",
977 fontFamily = fontFamily,
978 typefaceAdapter = typefaceAdapter
979 )
George Mountb1cdd862018-12-21 10:54:42 -0800980 paragraph.layout(Float.MAX_VALUE)
Siyamed Sinirf18dcca2018-12-20 18:25:10 -0800981
982 verify(typefaceAdapter, times(1)).create(
983 fontFamily = eq(fontFamily),
984 fontWeight = eq(FontWeight.normal),
Siyamed Siniradf982d2019-05-20 17:35:13 -0700985 fontStyle = eq(FontStyle.Normal),
Siyamed Sinir934a3442019-06-18 12:57:13 -0700986 fontSynthesis = eq(FontSynthesis.All)
Siyamed Sinirf18dcca2018-12-20 18:25:10 -0800987 )
988
989 val typeface = paragraph.textPaint.typeface
990 assertThat(typeface, not(nullValue()))
991 assertThat(typeface.isBold, equalTo(false))
992 assertThat(typeface.isItalic, equalTo(false))
993 }
994
995 @Test
996 fun testFontFamily_withCustomFont() {
997 val typefaceAdapter = spy(TypefaceAdapter())
998 val paragraph = simpleParagraph(
999 text = "abc",
1000 fontFamily = fontFamily,
1001 typefaceAdapter = typefaceAdapter
1002 )
George Mountb1cdd862018-12-21 10:54:42 -08001003 paragraph.layout(Float.MAX_VALUE)
Siyamed Sinirf18dcca2018-12-20 18:25:10 -08001004
1005 verify(typefaceAdapter, times(1)).create(
1006 fontFamily = eq(fontFamily),
1007 fontWeight = eq(FontWeight.normal),
Siyamed Siniradf982d2019-05-20 17:35:13 -07001008 fontStyle = eq(FontStyle.Normal),
Siyamed Sinir934a3442019-06-18 12:57:13 -07001009 fontSynthesis = eq(FontSynthesis.All)
Siyamed Sinirf18dcca2018-12-20 18:25:10 -08001010 )
1011 val typeface = paragraph.textPaint.typeface
1012 assertThat(typeface.isBold, equalTo(false))
1013 assertThat(typeface.isItalic, equalTo(false))
1014 }
1015
Haoyu Zhangc11ef5a2019-01-14 16:35:05 -08001016 @Test
1017 fun testEllipsis_withMaxLineEqualsNull_doesNotEllipsis() {
1018 val text = "abc"
1019 val fontSize = 20f
1020 val paragraphWidth = (text.length - 1) * fontSize
1021 val paragraph = simpleParagraph(
1022 text = text,
1023 fontFamily = fontFamily,
1024 fontSize = fontSize,
1025 ellipsis = true
1026 )
1027 paragraph.layout(paragraphWidth)
1028 for (i in 0 until paragraph.lineCount) {
1029 assertFalse(paragraph.isEllipsisApplied(i))
1030 }
1031 }
1032
1033 @Test
1034 fun testEllipsis_withMaxLinesLessThanTextLines_doesEllipsis() {
1035 val text = "abcde"
1036 val fontSize = 100f
1037 // Note that on API 21, if the next line only contains 1 character, ellipsis won't work
1038 val paragraphWidth = (text.length - 1.5f) * fontSize
1039 val paragraph = simpleParagraph(
1040 text = text,
1041 fontFamily = fontFamily,
1042 fontSize = fontSize,
1043 ellipsis = true,
1044 maxLines = 1
1045 )
1046 paragraph.layout(paragraphWidth)
1047
1048 assertTrue(paragraph.isEllipsisApplied(0))
1049 }
1050
1051 @Test
1052 fun testEllipsis_withMaxLinesMoreThanTextLines_doesNotEllipsis() {
1053 val text = "abc"
1054 val fontSize = 100f
1055 val paragraphWidth = (text.length - 1) * fontSize
1056 val maxLines = ceil(text.length * fontSize / paragraphWidth).toInt()
1057 val paragraph = simpleParagraph(
1058 text = text,
1059 fontFamily = fontFamily,
1060 fontSize = fontSize,
1061 ellipsis = true,
1062 maxLines = maxLines
1063 )
1064 paragraph.layout(paragraphWidth)
1065
1066 for (i in 0 until paragraph.lineCount) {
1067 assertFalse(paragraph.isEllipsisApplied(i))
1068 }
1069 }
1070
Haoyu Zhang10fc6502018-11-09 15:50:11 -08001071 private fun simpleParagraph(
Haoyu Zhang27429892019-06-11 13:19:57 -07001072 text: String = "",
1073 textStyles: List<AnnotatedString.Item<TextStyle>> = listOf(),
Siyamed Sinir2690d532019-06-21 13:16:00 -07001074 textIndent: TextIndent? = null,
Haoyu Zhang10fc6502018-11-09 15:50:11 -08001075 textAlign: TextAlign? = null,
George Mountb1cdd862018-12-21 10:54:42 -08001076 fontSize: Float? = null,
Haoyu Zhangc11ef5a2019-01-14 16:35:05 -08001077 ellipsis: Boolean? = null,
Siyamed Sinirf18dcca2018-12-20 18:25:10 -08001078 maxLines: Int? = null,
1079 fontFamily: FontFamily? = null,
1080 fontWeight: FontWeight? = null,
1081 fontStyle: FontStyle? = null,
1082 typefaceAdapter: TypefaceAdapter = TypefaceAdapter()
Haoyu Zhang10fc6502018-11-09 15:50:11 -08001083 ): ParagraphAndroid {
1084 return ParagraphAndroid(
Haoyu Zhang27429892019-06-11 13:19:57 -07001085 text = text,
Haoyu Zhang47f57a22018-12-12 13:16:40 -08001086 textStyles = textStyles,
Siyamed Sinirf18dcca2018-12-20 18:25:10 -08001087 typefaceAdapter = typefaceAdapter,
Siyamed Sinir883e0232019-06-25 12:38:12 -07001088 style = TextStyle(
Siyamed Sinirf18dcca2018-12-20 18:25:10 -08001089 fontFamily = fontFamily,
1090 fontSize = fontSize,
1091 fontWeight = fontWeight,
1092 fontStyle = fontStyle
haoyua8e48a52019-06-25 12:23:27 -07001093 ),
Siyamed Sinir883e0232019-06-25 12:38:12 -07001094 paragraphStyle = ParagraphStyle(
1095 textAlign = textAlign,
1096 textIndent = textIndent,
1097 ellipsis = ellipsis,
1098 maxLines = maxLines
1099 )
Haoyu Zhang10fc6502018-11-09 15:50:11 -08001100 )
1101 }
Siyamed Sinir2690d532019-06-21 13:16:00 -07001102}