skikoMain.org.jetbrains.compose.resources.SvgPainter.kt Maven / Gradle / Ivy
package org.jetbrains.compose.resources
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.geometry.isSpecified
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.graphics.ImageBitmapConfig
import androidx.compose.ui.graphics.drawscope.DrawScope
import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
import androidx.compose.ui.graphics.nativeCanvas
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.IntSize
import org.jetbrains.skia.Rect
import org.jetbrains.skia.svg.SVGDOM
import org.jetbrains.skia.svg.SVGLength
import org.jetbrains.skia.svg.SVGLengthUnit
import org.jetbrains.skia.svg.SVGPreserveAspectRatio
import org.jetbrains.skia.svg.SVGPreserveAspectRatioAlign
import kotlin.math.ceil
internal class SvgPainter(
private val dom: SVGDOM,
private val density: Density
) : Painter() {
private val root = dom.root
private val defaultSizePx: Size = run {
val width = root?.width?.withUnit(SVGLengthUnit.PX)?.value ?: 0f
val height = root?.height?.withUnit(SVGLengthUnit.PX)?.value ?: 0f
if (width == 0f && height == 0f) {
Size.Unspecified
} else {
Size(width, height)
}
}
init {
if (root?.viewBox == null && defaultSizePx.isSpecified) {
root?.viewBox = Rect.makeXYWH(0f, 0f, defaultSizePx.width, defaultSizePx.height)
}
}
override val intrinsicSize: Size get() {
return if (defaultSizePx.isSpecified) {
defaultSizePx * density.density
} else {
Size.Unspecified
}
}
private var previousDrawSize: Size = Size.Unspecified
private var alpha: Float = 1.0f
private var colorFilter: ColorFilter? = null
// with caching into bitmap FPS is 3x-4x higher (tested with idea-logo.svg with 30x30 icons)
private val drawCache = DrawCache()
override fun applyAlpha(alpha: Float): Boolean {
this.alpha = alpha
return true
}
override fun applyColorFilter(colorFilter: ColorFilter?): Boolean {
this.colorFilter = colorFilter
return true
}
override fun DrawScope.onDraw() {
if (previousDrawSize != size) {
drawCache.drawCachedImage(
ImageBitmapConfig.Argb8888,
IntSize(ceil(size.width).toInt(), ceil(size.height).toInt()),
density = this,
layoutDirection,
) {
drawSvg(size)
}
}
drawCache.drawInto(this, alpha, colorFilter)
}
private fun DrawScope.drawSvg(size: Size) {
drawIntoCanvas { canvas ->
root?.width = SVGLength(size.width, SVGLengthUnit.PX)
root?.height = SVGLength(size.height, SVGLengthUnit.PX)
root?.preserveAspectRatio = SVGPreserveAspectRatio(SVGPreserveAspectRatioAlign.NONE)
dom.render(canvas.nativeCanvas)
}
}
}