Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b3fcae36 authored by Hawkwood Glazier's avatar Hawkwood Glazier
Browse files

Format Font/Text Animation files

Undone on master with I7bde225a41ab41e8c419a9784eb0307691550f3f

Bug: 264262853
Test: None; ktfmt only
Change-Id: I7b53f5fb9dbe5ad9542d40f36181538c40c88538
parent fd0d46e0
Loading
Loading
Loading
Loading
+56 −50
Original line number Diff line number Diff line
@@ -33,9 +33,7 @@ private const val FONT_ITALIC_MIN = 0f
private const val FONT_ITALIC_ANIMATION_STEP = 0.1f
private const val FONT_ITALIC_DEFAULT_VALUE = 0f

/**
 * Provide interpolation of two fonts by adjusting font variation settings.
 */
/** Provide interpolation of two fonts by adjusting font variation settings. */
class FontInterpolator {

    /**
@@ -61,8 +59,11 @@ class FontInterpolator {
        var index: Int,
        val sortedAxes: MutableList<FontVariationAxis>
    ) {
        constructor(font: Font, axes: List<FontVariationAxis>) :
                this(font.sourceIdentifier,
        constructor(
            font: Font,
            axes: List<FontVariationAxis>
        ) : this(
            font.sourceIdentifier,
            font.ttcIndex,
            axes.toMutableList().apply { sortBy { it.tag } }
        )
@@ -86,9 +87,7 @@ class FontInterpolator {
    private val tmpInterpKey = InterpKey(null, null, 0f)
    private val tmpVarFontKey = VarFontKey(0, 0, mutableListOf())

    /**
     * Linear interpolate the font variation settings.
     */
    /** Linear interpolate the font variation settings. */
    fun lerp(start: Font, end: Font, progress: Float): Font {
        if (progress == 0f) {
            return start
@@ -115,19 +114,26 @@ class FontInterpolator {
        // this doesn't take much time since the variation axes is usually up to 5. If we need to
        // support more number of axes, we may want to preprocess the font and store the sorted axes
        // and also pre-fill the missing axes value with default value from 'fvar' table.
        val newAxes = lerp(startAxes, endAxes) { tag, startValue, endValue ->
        val newAxes =
            lerp(startAxes, endAxes) { tag, startValue, endValue ->
                when (tag) {
                    // TODO: Good to parse 'fvar' table for retrieving default value.
                TAG_WGHT -> adjustWeight(
                    TAG_WGHT ->
                        adjustWeight(
                            MathUtils.lerp(
                                startValue ?: FONT_WEIGHT_DEFAULT_VALUE,
                                endValue ?: FONT_WEIGHT_DEFAULT_VALUE,
                                progress))
                TAG_ITAL -> adjustItalic(
                                progress
                            )
                        )
                    TAG_ITAL ->
                        adjustItalic(
                            MathUtils.lerp(
                                startValue ?: FONT_ITALIC_DEFAULT_VALUE,
                                endValue ?: FONT_ITALIC_DEFAULT_VALUE,
                                progress))
                                progress
                            )
                        )
                    else -> {
                        require(startValue != null && endValue != null) {
                            "Unable to interpolate due to unknown default axes value : $tag"
@@ -149,9 +155,7 @@ class FontInterpolator {
        // This is the first time to make the font for the axes. Build and store it to the cache.
        // Font.Builder#build won't throw IOException since creating fonts from existing fonts will
        // not do any IO work.
        val newFont = Font.Builder(start)
                .setFontVariationSettings(newAxes.toTypedArray())
                .build()
        val newFont = Font.Builder(start).setFontVariationSettings(newAxes.toTypedArray()).build()
        interpCache[InterpKey(start, end, progress)] = newFont
        verFontCache[VarFontKey(start, newAxes)] = newFont
        return newFont
@@ -173,13 +177,15 @@ class FontInterpolator {
            val tagA = if (i < start.size) start[i].tag else null
            val tagB = if (j < end.size) end[j].tag else null

            val comp = when {
            val comp =
                when {
                    tagA == null -> 1
                    tagB == null -> -1
                    else -> tagA.compareTo(tagB)
                }

            val axis = when {
            val axis =
                when {
                    comp == 0 -> {
                        val v = filter(tagA!!, start[i++].styleValue, end[j++].styleValue)
                        FontVariationAxis(tagA, v)
+65 −82
Original line number Diff line number Diff line
@@ -36,8 +36,8 @@ typealias GlyphCallback = (TextAnimator.PositionedGlyph, Float) -> Unit
 * Currently this class can provide text style animation for text weight and text size. For example
 * the simple view that draws text with animating text size is like as follows:
 *
 * <pre>
 * <code>
 * <pre> <code>
 * ```
 *     class SimpleTextAnimation : View {
 *         @JvmOverloads constructor(...)
 *
@@ -53,83 +53,63 @@ typealias GlyphCallback = (TextAnimator.PositionedGlyph, Float) -> Unit
 *             animator.setTextStyle(-1 /* unchanged weight */, sizePx, animate)
 *         }
 *     }
 * </code>
 * </pre>
 * ```
 * </code> </pre>
 */
class TextAnimator(
    layout: Layout,
    private val invalidateCallback: () -> Unit
) {
class TextAnimator(layout: Layout, private val invalidateCallback: () -> Unit) {
    // Following two members are for mutable for testing purposes.
    public var textInterpolator: TextInterpolator = TextInterpolator(layout)
    public var animator: ValueAnimator = ValueAnimator.ofFloat(1f).apply {
    public var animator: ValueAnimator =
        ValueAnimator.ofFloat(1f).apply {
            duration = DEFAULT_ANIMATION_DURATION
            addUpdateListener {
                textInterpolator.progress = it.animatedValue as Float
                invalidateCallback()
            }
        addListener(object : AnimatorListenerAdapter() {
            addListener(
                object : AnimatorListenerAdapter() {
                    override fun onAnimationEnd(animation: Animator?) {
                        textInterpolator.rebase()
                    }
                    override fun onAnimationCancel(animation: Animator?) = textInterpolator.rebase()
        })
                }
            )
        }

    sealed class PositionedGlyph {

        /**
         * Mutable X coordinate of the glyph position relative from drawing offset.
         */
        /** Mutable X coordinate of the glyph position relative from drawing offset. */
        var x: Float = 0f

        /**
         * Mutable Y coordinate of the glyph position relative from the baseline.
         */
        /** Mutable Y coordinate of the glyph position relative from the baseline. */
        var y: Float = 0f

        /**
         * The current line of text being drawn, in a multi-line TextView.
         */
        /** The current line of text being drawn, in a multi-line TextView. */
        var lineNo: Int = 0

        /**
         * Mutable text size of the glyph in pixels.
         */
        /** Mutable text size of the glyph in pixels. */
        var textSize: Float = 0f

        /**
         * Mutable color of the glyph.
         */
        /** Mutable color of the glyph. */
        var color: Int = 0

        /**
         * Immutable character offset in the text that the current font run start.
         */
        /** Immutable character offset in the text that the current font run start. */
        abstract var runStart: Int
            protected set

        /**
         * Immutable run length of the font run.
         */
        /** Immutable run length of the font run. */
        abstract var runLength: Int
            protected set

        /**
         * Immutable glyph index of the font run.
         */
        /** Immutable glyph index of the font run. */
        abstract var glyphIndex: Int
            protected set

        /**
         * Immutable font instance for this font run.
         */
        /** Immutable font instance for this font run. */
        abstract var font: Font
            protected set

        /**
         * Immutable glyph ID for this glyph.
         */
        /** Immutable glyph ID for this glyph. */
        abstract var glyphId: Int
            protected set
    }
@@ -147,20 +127,18 @@ class TextAnimator(
    /**
     * GlyphFilter applied just before drawing to canvas for tweaking positions and text size.
     *
     * This callback is called for each glyphs just before drawing the glyphs. This function will
     * be called with the intrinsic position, size, color, glyph ID and font instance. You can
     * mutate the position, size and color for tweaking animations.
     * Do not keep the reference of passed glyph object. The interpolator reuses that object for
     * avoiding object allocations.
     * This callback is called for each glyphs just before drawing the glyphs. This function will be
     * called with the intrinsic position, size, color, glyph ID and font instance. You can mutate
     * the position, size and color for tweaking animations. Do not keep the reference of passed
     * glyph object. The interpolator reuses that object for avoiding object allocations.
     *
     * Details:
     * The text is drawn with font run units. The font run is a text segment that draws with the
     * same font. The {@code runStart} and {@code runLimit} is a range of the font run in the text
     * that current glyph is in. Once the font run is determined, the system will convert characters
     * into glyph IDs. The {@code glyphId} is the glyph identifier in the font and
     * {@code glyphIndex} is the offset of the converted glyph array. Please note that the
     * {@code glyphIndex} is not a character index, because the character will not be converted to
     * glyph one-by-one. If there are ligatures including emoji sequence, etc, the glyph ID may be
     * Details: The text is drawn with font run units. The font run is a text segment that draws
     * with the same font. The {@code runStart} and {@code runLimit} is a range of the font run in
     * the text that current glyph is in. Once the font run is determined, the system will convert
     * characters into glyph IDs. The {@code glyphId} is the glyph identifier in the font and {@code
     * glyphIndex} is the offset of the converted glyph array. Please note that the {@code
     * glyphIndex} is not a character index, because the character will not be converted to glyph
     * one-by-one. If there are ligatures including emoji sequence, etc, the glyph ID may be
     * composed from multiple characters.
     *
     * Here is an example of font runs: "fin. 終わり"
@@ -193,7 +171,9 @@ class TextAnimator(
     */
    var glyphFilter: GlyphCallback?
        get() = textInterpolator.glyphFilter
        set(value) { textInterpolator.glyphFilter = value }
        set(value) {
            textInterpolator.glyphFilter = value
        }

    fun draw(c: Canvas) = textInterpolator.draw(c)

@@ -237,7 +217,8 @@ class TextAnimator(
        if (weight >= 0) {
            // Paint#setFontVariationSettings creates Typeface instance from scratch. To reduce the
            // memory impact, cache the typeface result.
            textInterpolator.targetPaint.typeface = typefaceCache.getOrElse(weight) {
            textInterpolator.targetPaint.typeface =
                typefaceCache.getOrElse(weight) {
                    textInterpolator.targetPaint.fontVariationSettings = "'$TAG_WGHT' $weight"
                    textInterpolator.targetPaint.typeface
                }
@@ -249,14 +230,16 @@ class TextAnimator(

        if (animate) {
            animator.startDelay = delay
            animator.duration = if (duration == -1L) {
            animator.duration =
                if (duration == -1L) {
                    DEFAULT_ANIMATION_DURATION
                } else {
                    duration
                }
            interpolator?.let { animator.interpolator = it }
            if (onAnimationEnd != null) {
                val listener = object : AnimatorListenerAdapter() {
                val listener =
                    object : AnimatorListenerAdapter() {
                        override fun onAnimationEnd(animation: Animator?) {
                            onAnimationEnd.run()
                            animator.removeListener(this)
+113 −119
Original line number Diff line number Diff line
@@ -26,12 +26,8 @@ import android.util.MathUtils
import com.android.internal.graphics.ColorUtils
import java.lang.Math.max

/**
 * Provide text style linear interpolation for plain text.
 */
class TextInterpolator(
    layout: Layout
) {
/** Provide text style linear interpolation for plain text. */
class TextInterpolator(layout: Layout) {

    /**
     * Returns base paint used for interpolation.
@@ -64,12 +60,11 @@ class TextInterpolator(
        var baseFont: Font,
        var targetFont: Font
    ) {
        val length: Int get() = end - start
        val length: Int
            get() = end - start
    }

    /**
     * A class represents text layout of a single run.
     */
    /** A class represents text layout of a single run. */
    private class Run(
        val glyphIds: IntArray,
        val baseX: FloatArray, // same length as glyphIds
@@ -79,12 +74,8 @@ class TextInterpolator(
        val fontRuns: List<FontRun>
    )

    /**
     * A class represents text layout of a single line.
     */
    private class Line(
        val runs: List<Run>
    )
    /** A class represents text layout of a single line. */
    private class Line(val runs: List<Run>)

    private var lines = listOf<Line>()
    private val fontInterpolator = FontInterpolator()
@@ -106,8 +97,8 @@ class TextInterpolator(
    /**
     * The layout used for drawing text.
     *
     * Only non-styled text is supported. Even if the given layout is created from Spanned, the
     * span information is not used.
     * Only non-styled text is supported. Even if the given layout is created from Spanned, the span
     * information is not used.
     *
     * The paint objects used for interpolation are not changed by this method call.
     *
@@ -133,8 +124,8 @@ class TextInterpolator(
    /**
     * Recalculate internal text layout for interpolation.
     *
     * Whenever the target paint is modified, call this method to recalculate internal
     * text layout used for interpolation.
     * Whenever the target paint is modified, call this method to recalculate internal text layout
     * used for interpolation.
     */
    fun onTargetPaintModified() {
        updatePositionsAndFonts(shapeText(layout, targetPaint), updateBase = false)
@@ -143,8 +134,8 @@ class TextInterpolator(
    /**
     * Recalculate internal text layout for interpolation.
     *
     * Whenever the base paint is modified, call this method to recalculate internal
     * text layout used for interpolation.
     * Whenever the base paint is modified, call this method to recalculate internal text layout
     * used for interpolation.
     */
    fun onBasePaintModified() {
        updatePositionsAndFonts(shapeText(layout, basePaint), updateBase = true)
@@ -155,11 +146,11 @@ class TextInterpolator(
     *
     * The text interpolator does not calculate all the text position by text shaper due to
     * performance reasons. Instead, the text interpolator shape the start and end state and
     * calculate text position of the middle state by linear interpolation. Due to this trick,
     * the text positions of the middle state is likely different from the text shaper result.
     * So, if you want to start animation from the middle state, you will see the glyph jumps due to
     * this trick, i.e. the progress 0.5 of interpolation between weight 400 and 700 is different
     * from text shape result of weight 550.
     * calculate text position of the middle state by linear interpolation. Due to this trick, the
     * text positions of the middle state is likely different from the text shaper result. So, if
     * you want to start animation from the middle state, you will see the glyph jumps due to this
     * trick, i.e. the progress 0.5 of interpolation between weight 400 and 700 is different from
     * text shape result of weight 550.
     *
     * After calling this method, do not call onBasePaintModified() since it reshape the text and
     * update the base state. As in above notice, the text shaping result at current progress is
@@ -171,8 +162,8 @@ class TextInterpolator(
     * animate weight from 200 to 400, then if you want to move back to 200 at the half of the
     * animation, it will look like
     *
     * <pre>
     * <code>
     * <pre> <code>
     * ```
     *     val interp = TextInterpolator(layout)
     *
     *     // Interpolate between weight 200 to 400.
@@ -202,9 +193,8 @@ class TextInterpolator(
     *         // progress is 0.5
     *         animator.start()
     *     }
     * </code>
     * </pre>
     *
     * ```
     * </code> </pre>
     */
    fun rebase() {
        if (progress == 0f) {
@@ -266,17 +256,20 @@ class TextInterpolator(
        }

        var maxRunLength = 0
        lines = baseLayout.zip(targetLayout) { baseLine, targetLine ->
            val runs = baseLine.zip(targetLine) { base, target ->

        lines =
            baseLayout.zip(targetLayout) { baseLine, targetLine ->
                val runs =
                    baseLine.zip(targetLine) { base, target ->
                        require(base.glyphCount() == target.glyphCount()) {
                            "Inconsistent glyph count at line ${lines.size}"
                        }

                        val glyphCount = base.glyphCount()

                // Good to recycle the array if the existing array can hold the new layout result.
                val glyphIds = IntArray(glyphCount) {
                        // Good to recycle the array if the existing array can hold the new layout
                        // result.
                        val glyphIds =
                            IntArray(glyphCount) {
                                base.getGlyphId(it).also { baseGlyphId ->
                                    require(baseGlyphId == target.getGlyphId(it)) {
                                        "Inconsistent glyph ID at $it in line ${lines.size}"
@@ -305,7 +298,7 @@ class TextInterpolator(

                                if (baseFont !== nextBaseFont) {
                                    require(targetFont !== nextTargetFont) {
                                "Base font has changed at $i but target font has not changed."
                                        "Base font has changed at $i but target font is unchanged."
                                    }
                                    // Font transition point. push run and reset context.
                                    fontRun.add(FontRun(start, i, baseFont, targetFont))
@@ -314,11 +307,12 @@ class TextInterpolator(
                                    targetFont = nextTargetFont
                                    start = i
                                    require(FontInterpolator.canInterpolate(baseFont, targetFont)) {
                                "Cannot interpolate font at $start ($baseFont vs $targetFont)"
                                        "Cannot interpolate font at $start" +
                                            " ($baseFont vs $targetFont)"
                                    }
                                } else { // baseFont === nextBaseFont
                                    require(targetFont === nextTargetFont) {
                                "Base font has not changed at $i but target font has changed."
                                        "Base font is unchanged at $i but target font has changed."
                                    }
                                }
                            }
@@ -397,7 +391,8 @@ class TextInterpolator(
                    0,
                    i - prevStart,
                    font,
                        tmpPaintForGlyph)
                    tmpPaintForGlyph
                )
                prevStart = i
                arrayIndex = 0
            }
@@ -413,7 +408,8 @@ class TextInterpolator(
            0,
            run.end - prevStart,
            font,
                tmpPaintForGlyph)
            tmpPaintForGlyph
        )
    }

    private fun updatePositionsAndFonts(
@@ -421,9 +417,7 @@ class TextInterpolator(
        updateBase: Boolean
    ) {
        // Update target positions with newly calculated text layout.
        check(layoutResult.size == lines.size) {
            "The new layout result has different line count."
        }
        check(layoutResult.size == lines.size) { "The new layout result has different line count." }

        lines.zip(layoutResult) { line, runs ->
            line.runs.zip(runs) { lineRun, newGlyphs ->
@@ -483,10 +477,7 @@ class TextInterpolator(
    }

    // Shape the text and stores the result to out argument.
    private fun shapeText(
        layout: Layout,
        paint: TextPaint
    ): List<List<PositionedGlyphs>> {
    private fun shapeText(layout: Layout, paint: TextPaint): List<List<PositionedGlyphs>> {
        var text = StringBuilder()
        val out = mutableListOf<List<PositionedGlyphs>>()
        for (lineNo in 0 until layout.lineCount) { // Shape all lines.
@@ -500,10 +491,13 @@ class TextInterpolator(
            }

            val runs = mutableListOf<PositionedGlyphs>()
            TextShaper.shapeText(layout.text, lineStart, count, layout.textDirectionHeuristic,
                    paint) { _, _, glyphs, _ ->
                runs.add(glyphs)
            }
            TextShaper.shapeText(
                layout.text,
                lineStart,
                count,
                layout.textDirectionHeuristic,
                paint
            ) { _, _, glyphs, _ -> runs.add(glyphs) }
            out.add(runs)

            if (lineNo > 0) {
+0 −2
Original line number Diff line number Diff line
+packages/SystemUI
-packages/SystemUI/animation/src/com/android/systemui/animation/FontInterpolator.kt
-packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt
-packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt
-packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt
-packages/SystemUI/checks/src/com/android/internal/systemui/lint/BindServiceViaContextDetector.kt
-packages/SystemUI/checks/src/com/android/internal/systemui/lint/BroadcastSentViaContextDetector.kt