All Downloads are FREE. Search and download functionalities are using the official Maven repository.

androidAndroidTest.androidx.compose.ui.text.platform.AndroidTextPaintTest.kt Maven / Gradle / Ivy

/*
 * 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.platform

import android.graphics.Paint
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.PathEffect
import androidx.compose.ui.graphics.Shader
import androidx.compose.ui.graphics.ShaderBrush
import androidx.compose.ui.graphics.Shadow
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.graphics.StrokeCap
import androidx.compose.ui.graphics.StrokeJoin
import androidx.compose.ui.graphics.asAndroidPathEffect
import androidx.compose.ui.graphics.drawscope.Fill
import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.text.style.TextDecoration
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SdkSuppress
import androidx.test.filters.SmallTest
import com.google.common.truth.Truth.assertThat
import kotlin.math.roundToInt
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
@SmallTest
class AndroidTextPaintTest {
    @Test
    fun constructor() {
        val density = 15.0f
        val textPaint = AndroidTextPaint(Paint.ANTI_ALIAS_FLAG, density)

        assertThat(textPaint.density).isEqualTo(15.0f)
        assertThat(textPaint.flags and Paint.ANTI_ALIAS_FLAG).isNotEqualTo(0)
    }

    @Test
    fun textDecoration_defaultValues() {
        val textPaint = defaultTextPaint
        assertThat(textPaint.isUnderlineText).isFalse()
        assertThat(textPaint.isStrikeThruText).isFalse()
    }

    @Test
    fun setTextDecoration_withNone() {
        val textPaint = defaultTextPaint
        textPaint.setTextDecoration(TextDecoration.None)
        assertThat(textPaint.isUnderlineText).isFalse()
        assertThat(textPaint.isStrikeThruText).isFalse()
    }

    @Test
    fun setTextDecoration_withNull() {
        val textPaint = defaultTextPaint
        textPaint.setTextDecoration(null)
        assertThat(textPaint.isUnderlineText).isFalse()
        assertThat(textPaint.isStrikeThruText).isFalse()
    }

    @Test
    fun setTextDecoration_withUnderline() {
        val textPaint = defaultTextPaint
        textPaint.setTextDecoration(TextDecoration.Underline)
        assertThat(textPaint.isUnderlineText).isTrue()
        assertThat(textPaint.isStrikeThruText).isFalse()
    }

    @Test
    fun setTextDecoration_withLineThrough() {
        val textPaint = defaultTextPaint
        textPaint.setTextDecoration(TextDecoration.LineThrough)
        assertThat(textPaint.isUnderlineText).isFalse()
        assertThat(textPaint.isStrikeThruText).isTrue()
    }

    @Test
    fun setTextDecoration_withLineThroughAndUnderline() {
        val textPaint = defaultTextPaint
        textPaint.setTextDecoration(
            TextDecoration.combine(
                listOf(TextDecoration.LineThrough, TextDecoration.Underline)
            )
        )
        assertThat(textPaint.isUnderlineText).isTrue()
        assertThat(textPaint.isStrikeThruText).isTrue()
    }

    @Test
    fun setTextDecoration_changeDecorationToNone() {
        val textPaint = defaultTextPaint
        textPaint.setTextDecoration(
            TextDecoration.combine(
                listOf(TextDecoration.LineThrough, TextDecoration.Underline)
            )
        )
        assertThat(textPaint.isUnderlineText).isTrue()
        assertThat(textPaint.isStrikeThruText).isTrue()

        textPaint.setTextDecoration(TextDecoration.None)
        assertThat(textPaint.isUnderlineText).isFalse()
        assertThat(textPaint.isStrikeThruText).isFalse()
    }

    @Test
    fun setTextDecoration_changeDecorationToNull() {
        val textPaint = defaultTextPaint
        textPaint.setTextDecoration(
            TextDecoration.combine(
                listOf(TextDecoration.LineThrough, TextDecoration.Underline)
            )
        )
        assertThat(textPaint.isUnderlineText).isTrue()
        assertThat(textPaint.isStrikeThruText).isTrue()

        textPaint.setTextDecoration(null)
        assertThat(textPaint.isUnderlineText).isTrue()
        assertThat(textPaint.isStrikeThruText).isTrue()
    }

    @Test
    fun setColor_to_valid_value() {
        val color = Color.Red
        val textPaint = defaultTextPaint
        textPaint.setColor(color)

        assertThat(textPaint.color).isEqualTo(color.toArgb())
    }

    @Test
    fun setColor_to_unspecified() {
        val textPaint = defaultTextPaint
        textPaint.setColor(Color.Unspecified)
        assertThat(textPaint.color).isNotEqualTo(Color.Unspecified.toArgb())

        textPaint.setColor(Color.Red)
        assertThat(textPaint.color).isEqualTo(Color.Red.toArgb())

        textPaint.setColor(Color.Unspecified)
        assertThat(textPaint.color).isEqualTo(Color.Red.toArgb())
    }

    @Test
    fun setColor_to_transparent() {
        val textPaint = defaultTextPaint
        textPaint.setColor(Color.Transparent)
        assertThat(textPaint.color).isEqualTo(Color.Transparent.toArgb())

        textPaint.setColor(Color.Red)
        assertThat(textPaint.color).isEqualTo(Color.Red.toArgb())

        textPaint.setColor(Color.Transparent)
        assertThat(textPaint.color).isEqualTo(Color.Transparent.toArgb())
    }

    @Test
    fun setShaderBrush_with_specified_size() {
        var calls = 0
        val brush = object : ShaderBrush() {
            val brush = linearGradient(listOf(Color.Red, Color.Blue))
            override fun createShader(size: Size): Shader {
                calls++
                return (brush as ShaderBrush).createShader(size)
            }
        }

        val size = Size(10f, 10f)
        val textPaint = defaultTextPaint
        textPaint.setBrush(brush, size)

        assertThat(textPaint.shader).isNotNull()
        assertThat(calls).isEqualTo(1)
    }

    @Test
    fun setShaderBrush_with_unspecified_size() {
        val brush = Brush.linearGradient(listOf(Color.Red, Color.Blue))
        val size = Size.Unspecified
        val textPaint = defaultTextPaint
        textPaint.setBrush(brush, size)

        assertThat(textPaint.shader).isNull()
    }

    @Test
    fun setColorBrush_with_specified_size() {
        val brush = SolidColor(Color.Red)
        val size = Size(10f, 10f)
        val textPaint = defaultTextPaint
        textPaint.setBrush(brush, size)

        assertThat(textPaint.shader).isNull()
        assertThat(textPaint.color).isEqualTo(Color.Red.toArgb())
    }

    @Test
    fun setColorBrush_with_unspecified_size() {
        val brush = SolidColor(Color.Red)
        val size = Size.Unspecified
        val textPaint = defaultTextPaint
        textPaint.setBrush(brush, size)

        assertThat(textPaint.shader).isNull()
        assertThat(textPaint.color).isEqualTo(Color.Red.toArgb())
    }

    @Test
    fun setColorBrush_with_alpha() {
        val brush = SolidColor(Color.Red)
        val size = Size.Unspecified
        val alpha = 0.6f
        val textPaint = defaultTextPaint
        textPaint.setBrush(brush, size, alpha)

        assertThat(textPaint.shader).isNull()
        assertThat(textPaint.color).isEqualTo(Color.Red.copy(0.6f).toArgb())
    }

    @Test
    fun setTransparentColorBrush_with_alpha_modulates() {
        val brush = SolidColor(Color.Red.copy(0.8f))
        val size = Size.Unspecified
        val alpha = 0.6f
        val textPaint = defaultTextPaint
        textPaint.setBrush(brush, size, alpha)

        assertThat(textPaint.shader).isNull()
        assertThat(textPaint.color).isEqualTo(Color.Red.copy(0.48f).toArgb())
    }

    @Test
    fun setBrush_with_tooHigh_alpha() {
        val brush = Brush.linearGradient(listOf(Color.Red, Color.Blue))
        val size = Size(10f, 10f)
        val alpha = 10e5f
        val textPaint = defaultTextPaint
        textPaint.setBrush(brush, size, alpha)

        assertThat(textPaint.shader).isNotNull()
        assertThat(textPaint.alpha).isEqualTo(255)
    }

    @Test
    fun setBrush_with_tooLow_alpha() {
        val brush = Brush.linearGradient(listOf(Color.Red, Color.Blue))
        val size = Size(10f, 10f)
        val alpha = -10e5f
        val textPaint = defaultTextPaint
        textPaint.setBrush(brush, size, alpha)

        assertThat(textPaint.shader).isNotNull()
        assertThat(textPaint.alpha).isEqualTo(0)
    }

    @Test
    fun setUnspecifiedBrush_with_specified_size() {
        val brush = SolidColor(Color.Unspecified)
        val size = Size(10f, 10f)
        val textPaint = defaultTextPaint
        textPaint.setBrush(brush, size)

        assertThat(textPaint.shader).isNull()
        assertThat(textPaint.color).isNotEqualTo(Color.Unspecified.toArgb())

        textPaint.setBrush(SolidColor(Color.Red), size)

        assertThat(textPaint.shader).isNull()
        assertThat(textPaint.color).isEqualTo(Color.Red.toArgb())
    }

    @Test
    fun setNullBrush_with_specified_size() {
        val brush = Brush.linearGradient(listOf(Color.Red, Color.Blue))
        val size = Size(10f, 10f)
        val textPaint = defaultTextPaint
        textPaint.setBrush(brush, size)

        assertThat(textPaint.shader).isNotNull()

        textPaint.setBrush(null, size)

        assertThat(textPaint.shader).isNull()
    }

    @Test
    fun setBrush_with_alpha() {
        val brush = Brush.linearGradient(listOf(Color.Red, Color.Blue))
        val size = Size(10f, 10f)
        val alpha = 0.6f
        val textPaint = defaultTextPaint
        textPaint.setBrush(brush, size, alpha)

        assertThat(textPaint.shader).isNotNull()
        assertThat(textPaint.alpha).isEqualTo((255 * 0.6f).roundToInt())

        textPaint.setBrush(null, size)

        assertThat(textPaint.shader).isNull()
        assertThat(textPaint.alpha).isEqualTo((255 * 0.6f).roundToInt())
    }

    @Test
    fun setBrush_with_alpha_only_alpha_changes() {
        val brush = Brush.linearGradient(listOf(Color.Red, Color.Blue))
        val size = Size(10f, 10f)
        val textPaint = defaultTextPaint
        textPaint.setBrush(brush, size, 0.6f)

        assertThat(textPaint.shader).isNotNull()
        assertThat(textPaint.alpha).isEqualTo((255 * 0.6f).roundToInt())

        textPaint.setBrush(brush, size, 0.8f)

        assertThat(textPaint.shader).isNotNull()
        assertThat(textPaint.alpha).isEqualTo((255 * 0.8f).roundToInt())
    }

    @Test
    fun setShaderBrush_after_setColor() {
        val brush = Brush.linearGradient(listOf(Color.Red, Color.Blue))
        val size = Size(10f, 10f)
        val alpha = 0.6f
        val textPaint = defaultTextPaint
        textPaint.setColor(Color.Red)
        textPaint.setBrush(brush, size, alpha)

        assertThat(textPaint.shader).isNotNull()
        assertThat(textPaint.alpha).isEqualTo((255 * 0.6f).roundToInt())
    }

    @Test
    fun setColor_after_setShaderBrush() {
        val brush = Brush.linearGradient(listOf(Color.Red, Color.Blue))
        val size = Size(10f, 10f)
        val alpha = 0.6f
        val textPaint = defaultTextPaint
        textPaint.setBrush(brush, size, alpha)
        textPaint.setColor(Color.Red)

        assertThat(textPaint.shader).isNull()
        assertThat(textPaint.color).isEqualTo(Color.Red.toArgb())
    }

    @SdkSuppress(minSdkVersion = 29)
    @Test
    fun shadow_default_values() {
        val textPaint = defaultTextPaint

        // default color is 0 since we do not update it
        assertThat(textPaint.shadowLayerDx).isEqualTo(0f)
        assertThat(textPaint.shadowLayerDy).isEqualTo(0f)
        assertThat(textPaint.shadowLayerRadius).isEqualTo(0f)
        assertThat(textPaint.shadowLayerColor).isEqualTo(0)
    }

    @SdkSuppress(minSdkVersion = 29)
    @Test
    fun setShadow() {
        val dx = 1f
        val dy = 2f
        val radius = 3f
        val color = Color.Red
        val textPaint = defaultTextPaint

        textPaint.setShadow(Shadow(color, Offset(dx, dy), radius))

        assertThat(textPaint.shadowLayerDx).isEqualTo(dx)
        assertThat(textPaint.shadowLayerDy).isEqualTo(dy)
        assertThat(textPaint.shadowLayerRadius).isEqualTo(radius)
        assertThat(textPaint.shadowLayerColor).isEqualTo(color.toArgb())
    }

    @SdkSuppress(minSdkVersion = 29)
    @Test
    fun resetShadow_to_None() {
        val dx = 1f
        val dy = 2f
        val radius = 3f
        val color = Color.Red
        val textPaint = defaultTextPaint

        textPaint.setShadow(Shadow(color, Offset(dx, dy), radius))
        textPaint.setShadow(Shadow.None)

        assertThat(textPaint.shadowLayerDx).isEqualTo(0f)
        assertThat(textPaint.shadowLayerDy).isEqualTo(0f)
        assertThat(textPaint.shadowLayerRadius).isEqualTo(0f)
        assertThat(textPaint.shadowLayerColor).isEqualTo(0)
    }

    @SdkSuppress(minSdkVersion = 29)
    @Test
    fun resetShadow_to_null_has_no_effect() {
        val dx = 1f
        val dy = 2f
        val radius = 3f
        val color = Color.Red
        val textPaint = defaultTextPaint

        textPaint.setShadow(Shadow(color, Offset(dx, dy), radius))
        textPaint.setShadow(null)

        assertThat(textPaint.shadowLayerDx).isEqualTo(dx)
        assertThat(textPaint.shadowLayerDy).isEqualTo(dy)
        assertThat(textPaint.shadowLayerRadius).isEqualTo(radius)
        assertThat(textPaint.shadowLayerColor).isEqualTo(color.toArgb())
    }

    @Test
    fun drawStyle_defaultValue() {
        val textPaint = defaultTextPaint
        assertThat(textPaint.style).isEqualTo(Paint.Style.FILL)
    }

    @Test
    fun setDrawStyle_withNull() {
        val textPaint = defaultTextPaint
        textPaint.setDrawStyle(null)
        assertThat(textPaint.style).isEqualTo(Paint.Style.FILL)
    }

    @Test
    fun setDrawStyle_withFill() {
        val textPaint = defaultTextPaint
        textPaint.setDrawStyle(Fill)
        assertThat(textPaint.style).isEqualTo(Paint.Style.FILL)
    }

    @Test
    fun setDrawStyle_withStroke() {
        val textPaint = defaultTextPaint
        val pathEffect = PathEffect.cornerPathEffect(4f)
        textPaint.setDrawStyle(
            Stroke(
                width = 4f,
                miter = 2f,
                join = StrokeJoin.Bevel,
                cap = StrokeCap.Square,
                pathEffect = pathEffect
            )
        )
        assertThat(textPaint.style).isEqualTo(Paint.Style.STROKE)
        assertThat(textPaint.strokeWidth).isEqualTo(4f)
        assertThat(textPaint.strokeMiter).isEqualTo(2f)
        assertThat(textPaint.strokeJoin).isEqualTo(Paint.Join.BEVEL)
        assertThat(textPaint.strokeCap).isEqualTo(Paint.Cap.SQUARE)
        assertThat(textPaint.pathEffect).isEqualTo(pathEffect.asAndroidPathEffect())
    }

    @Test
    fun setDrawStyle_withStrokeThenFill() {
        val textPaint = defaultTextPaint
        textPaint.setDrawStyle(
            Stroke(
                width = 4f,
                miter = 2f,
                join = StrokeJoin.Bevel,
                cap = StrokeCap.Square
            )
        )
        textPaint.setDrawStyle(Fill)
        assertThat(textPaint.style).isEqualTo(Paint.Style.FILL)
    }

    @Test
    fun setDrawStyle_changeDrawStyleToNull() {
        val textPaint = defaultTextPaint
        textPaint.setDrawStyle(
            Stroke(
                width = 4f,
                miter = 2f,
                join = StrokeJoin.Bevel,
                cap = StrokeCap.Square
            )
        )
        assertThat(textPaint.style).isEqualTo(Paint.Style.STROKE)

        textPaint.setDrawStyle(null)
        assertThat(textPaint.style).isEqualTo(Paint.Style.STROKE)
    }

    private val defaultTextPaint get() = AndroidTextPaint(flags = 0, density = 1.0f)
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy