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

skikoMain.androidx.compose.ui.text.platform.ParagraphLayouter.skiko.kt Maven / Gradle / Ivy

/*
 * Copyright 2021 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 androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shadow
import androidx.compose.ui.graphics.takeOrElse
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.Placeholder
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.style.ResolvedTextDirection
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.unit.Density
import org.jetbrains.skia.paragraph.Paragraph

/**
 * The purpose of this class is to store already built paragraph and pass it between
 * different internal entities (from SkiaParagraphIntrinsics to SkiaParagraph).
 *
 * An alternative to passing and reusing existed paragraph is to build it again, but it is 2.5x
 * slower.
 *
 * LayoutedParagraph should has only one owner to avoid concurrent usage.
 *
 * Tests:
 *
 * val text = (1..100000).joinToString(" ")
 * reusedParagraph.layout(300f): 116.848500ms
 * builder.build().layout(300f): 288.302300ms
 *
 * text = (1..10000).joinToString(" ")
 * reusedParagraph.layout(300f): 10.004400ms
 * builder.build().layout(300f): 23.421500ms
 */
class ParagraphLayouter(
    val text: String,
    textDirection: ResolvedTextDirection,
    style: TextStyle,
    spanStyles: List>,
    placeholders: List>,
    density: Density,
    fontFamilyResolver: FontFamily.Resolver
) {
    private val builder = ParagraphBuilder(
        fontFamilyResolver = fontFamilyResolver,
        text = text,
        textStyle = style,
        spanStyles = spanStyles,
        placeholders = placeholders,
        density = density,
        textDirection = textDirection
    )
    private var para = builder.build()

    private var width: Float = -1f

    val defaultHeight get() = builder.defaultHeight
    val defaultFont get() = builder.defaultFont
    val paragraphStyle get() = builder.paragraphStyle

    fun layoutParagraph(
        width: Float = this.width,
        maxLines: Int = builder.maxLines,
        ellipsis: String = builder.ellipsis,
        color: Color = builder.textStyle.color,
        shadow: Shadow? = builder.textStyle.shadow,
        textDecoration: TextDecoration? = builder.textStyle.textDecoration,
    ): Paragraph {
        val actualColor = color.takeOrElse { builder.textStyle.color }
        if (
            builder.maxLines != maxLines ||
            builder.ellipsis != ellipsis ||
            builder.textStyle.color != actualColor ||
            builder.textStyle.shadow != shadow ||
            builder.textStyle.textDecoration != textDecoration
        ) {
            this.width = width
            builder.maxLines = maxLines
            builder.ellipsis = ellipsis
            builder.textStyle = builder.textStyle.copy(
                color = actualColor,
                shadow = shadow,
                textDecoration = textDecoration
            )
            para = builder.build()
            para.layout(width)
        } else if (this.width != width) {
            this.width = width
            para.layout(width)
        }
        return para
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy