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

org.fernice.flare.style.value.computed.Length.kt Maven / Gradle / Ivy

/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */
package org.fernice.flare.style.value.computed

import org.fernice.flare.cssparser.ToCss
import org.fernice.flare.style.value.ComputedValue
import org.fernice.flare.style.value.specified.AbsoluteLength
import org.fernice.flare.style.value.specified.FontRelativeLength
import org.fernice.flare.style.value.specified.Length
import org.fernice.flare.style.value.specified.NoCalcLength
import org.fernice.flare.style.value.specified.ViewportPercentageLength
import java.io.Writer

/**
 * Computed representation of [AbsoluteLength], [FontRelativeLength], [ViewportPercentageLength], [NoCalcLength]
 * and [Length].
 */
@JvmInline
value class PixelLength(val value: Float) : ComputedValue {

    fun px(): Float {
        return value
    }

    operator fun unaryMinus(): PixelLength {
        return PixelLength(-value)
    }

    operator fun plus(length: PixelLength): PixelLength {
        return PixelLength(value + length.value)
    }

    operator fun minus(length: PixelLength): PixelLength {
        return PixelLength(value - length.value)
    }

    operator fun times(length: PixelLength): PixelLength {
        return PixelLength(value * length.value)
    }

    operator fun div(length: PixelLength): PixelLength {
        return PixelLength(value / length.value)
    }

    companion object {

        private val zero: PixelLength by lazy { PixelLength(0f) }

        fun zero(): PixelLength {
            return zero
        }
    }
}

typealias Length = PixelLength

fun PixelLength.toAu(): Au {
    return Au.fromPx(this.value)
}

fun Au.toAu(): PixelLength {
    return PixelLength(this.toPx())
}

/**
 * Computed representation of [org.fernice.flare.style.value.specified.NonNegativeLength],
 * [org.fernice.flare.style.value.specified.NonNegativeLengthOrPercentage],
 * [org.fernice.flare.style.value.specified.NonNegativeLengthOrPercentageOrAuto] and
 * [org.fernice.flare.style.value.specified.NonNegativeLengthOrPercentageOrNone].
 */
data class NonNegativeLength(val length: PixelLength) : ComputedValue {

    fun scaleBy(factor: Float): NonNegativeLength {
        return new(length.px() * factor.coerceAtLeast(0f))
    }

    operator fun plus(other: NonNegativeLength): NonNegativeLength {
        return new(length.px() + other.length.px())
    }

    companion object {

        fun new(px: Float): NonNegativeLength {
            return NonNegativeLength(PixelLength(px.coerceAtLeast(0f)))
        }

        private val zero: NonNegativeLength by lazy { NonNegativeLength(PixelLength.zero()) }

        fun zero(): NonNegativeLength {
            return zero
        }
    }
}

fun NonNegativeLength.toAu(): Au {
    return this.length.toAu()
}

fun Au.toNonNegative(): NonNegativeLength {
    return NonNegativeLength(this.toAu())
}

fun PixelLength.toNonNegative(): NonNegativeLength {
    return NonNegativeLength(this)
}

private const val AU_PER_PX = 60

/**
 * Int-based unit primarily used for layouting. An AU is 1/60 of a pixel, removing the inaccuracy of floating-point
 * conversions.
 */
@JvmInline
value class Au(val value: Int) {

    fun toPx(): Float {
        return value / AU_PER_PX.toFloat()
    }

    fun scaleBy(float: Float): Au {
        return Au((value * float).toInt())
    }

    fun toFloat(): Float {
        return value / AU_PER_PX.toFloat()
    }

    operator fun plus(au: Au): Au {
        return Au(value + au.value)
    }

    operator fun minus(au: Au): Au {
        return Au(value - au.value)
    }

    operator fun times(au: Au): Au {
        return Au(value * au.value)
    }

    operator fun div(au: Au): Au {
        return Au(value / au.value)
    }

    operator fun plus(scalar: Int): Au {
        return Au(value + scalar)
    }

    operator fun minus(scalar: Int): Au {
        return Au(value - scalar)
    }

    operator fun times(scalar: Int): Au {
        return Au(value * scalar)
    }

    operator fun div(scalar: Int): Au {
        return Au(value / scalar)
    }

    fun max(au: Au): Au {
        return if (value >= au.value) {
            this
        } else {
            au
        }
    }

    fun min(au: Au): Au {
        return if (value <= au.value) {
            this
        } else {
            au
        }
    }

    companion object {

        fun fromAu64(double: Double): Au {
            return Au(double.toInt())
        }

        fun fromPx(px: Float): Au {
            return Au((px * AU_PER_PX).toInt())
        }

        fun fromPx(px: Int): Au {
            return Au((px * AU_PER_PX))
        }

        fun from(px: PixelLength): Au {
            return fromPx(px.value)
        }
    }
}

/**
 * Computed representation of [org.fernice.flare.style.value.specified.Percentage].
 */
data class Percentage(val value: Float) : ComputedValue, ToCss {

    override fun toCss(writer: Writer) {
        writer.append("$value%")
    }

    companion object {

        val hundred: Percentage by lazy { Percentage(1f) }

        fun hundred(): Percentage {
            return hundred
        }

        val fifty: Percentage by lazy { Percentage(0.5f) }
    }
}

sealed class LengthOrPercentage : ComputedValue {

    data class Length(val length: PixelLength) : LengthOrPercentage()
    data class Percentage(val percentage: org.fernice.flare.style.value.computed.Percentage) : LengthOrPercentage()
    data class Calc(val calc: CalcLengthOrPercentage) : LengthOrPercentage()

    fun toPixelLength(containingLength: Au): PixelLength {
        return when (this) {
            is LengthOrPercentage.Length -> {
                length
            }
            is LengthOrPercentage.Percentage -> {
                containingLength.scaleBy(percentage.value).toAu()
            }
            is LengthOrPercentage.Calc -> {
                calc.toPixelLength(containingLength) ?: error("calculation should have resulted in length")
            }
        }
    }

    companion object {

        val zero: LengthOrPercentage by lazy { LengthOrPercentage.Length(PixelLength(0f)) }
        val fifty: LengthOrPercentage by lazy { LengthOrPercentage.Percentage(org.fernice.flare.style.value.computed.Percentage.fifty) }
        val Hundred: LengthOrPercentage by lazy { LengthOrPercentage.Percentage(org.fernice.flare.style.value.computed.Percentage.hundred) }

        fun zero(): LengthOrPercentage {
            return zero
        }
    }
}

data class NonNegativeLengthOrPercentage(val value: LengthOrPercentage) : ComputedValue {

    fun toPixelLength(containingLength: Au): PixelLength {
        return value.toPixelLength(containingLength)
    }

    companion object {

        private val zero: NonNegativeLengthOrPercentage by lazy { NonNegativeLengthOrPercentage(LengthOrPercentage.zero()) }

        fun zero(): NonNegativeLengthOrPercentage {
            return zero
        }
    }
}

sealed class LengthOrPercentageOrAuto : ComputedValue {

    data class Length(val length: PixelLength) : LengthOrPercentageOrAuto()
    data class Percentage(val percentage: org.fernice.flare.style.value.computed.Percentage) : LengthOrPercentageOrAuto()
    data class Calc(val calc: CalcLengthOrPercentage) : LengthOrPercentageOrAuto()
    object Auto : LengthOrPercentageOrAuto()

    fun toPixelLength(containingLength: Au): PixelLength {
        return when (this) {
            is LengthOrPercentageOrAuto.Length -> {
                length
            }
            is LengthOrPercentageOrAuto.Percentage -> {
                containingLength.scaleBy(percentage.value).toAu()
            }
            is LengthOrPercentageOrAuto.Calc -> {
                calc.toPixelLength(containingLength) ?: error("calculation should have resulted in length")
            }
            is LengthOrPercentageOrAuto.Auto -> {
                PixelLength.zero()
            }
        }
    }

    fun toPixelLength(containingLength: Au, referenceLength: Au): PixelLength {
        return when (this) {
            is LengthOrPercentageOrAuto.Length -> {
                length
            }
            is LengthOrPercentageOrAuto.Percentage -> {
                containingLength.scaleBy(percentage.value).toAu()
            }
            is LengthOrPercentageOrAuto.Calc -> {
                calc.toPixelLength(containingLength) ?: error("calculation should have resulted in length")
            }
            is LengthOrPercentageOrAuto.Auto -> {
                referenceLength.toAu()
            }
        }
    }

    companion object {

        private val zero: LengthOrPercentageOrAuto by lazy { LengthOrPercentageOrAuto.Length(PixelLength.zero()) }

        fun zero(): LengthOrPercentageOrAuto {
            return zero
        }
    }
}

data class NonNegativeLengthOrPercentageOrAuto(val value: LengthOrPercentageOrAuto) : ComputedValue {

    fun toPixelLength(containingLength: Au): PixelLength {
        return value.toPixelLength(containingLength)
    }

    fun toPixelLength(containingLength: Au, referenceLength: Au): PixelLength {
        return value.toPixelLength(containingLength, referenceLength)
    }

    companion object {
        private val auto: NonNegativeLengthOrPercentageOrAuto by lazy { NonNegativeLengthOrPercentageOrAuto(LengthOrPercentageOrAuto.Auto) }

        fun auto(): NonNegativeLengthOrPercentageOrAuto {
            return auto
        }
    }
}

sealed class LengthOrPercentageOrNone : ComputedValue {

    data class Length(val length: PixelLength) : LengthOrPercentageOrNone()
    data class Percentage(val percentage: org.fernice.flare.style.value.computed.Percentage) : LengthOrPercentageOrNone()
    data class Calc(val calc: CalcLengthOrPercentage) : LengthOrPercentageOrNone()
    object None : LengthOrPercentageOrNone()
}

data class NonNegativeLengthOrPercentageOrNone(val value: LengthOrPercentageOrNone) : ComputedValue




© 2015 - 2025 Weber Informatics LLC | Privacy Policy