560 lines
23 KiB
Kotlin
560 lines
23 KiB
Kotlin
package com.opensource.svgaplayer.drawer
|
|
|
|
import android.graphics.*
|
|
import android.os.Build
|
|
import android.text.StaticLayout
|
|
import android.text.TextUtils
|
|
import android.widget.ImageView
|
|
import com.opensource.svgaplayer.SVGADynamicEntity
|
|
import com.opensource.svgaplayer.SVGASoundManager
|
|
import com.opensource.svgaplayer.SVGAVideoEntity
|
|
import com.opensource.svgaplayer.entities.SVGAVideoShapeEntity
|
|
|
|
/**
|
|
* Created by cuiminghui on 2017/3/29.
|
|
*/
|
|
|
|
internal class SVGACanvasDrawer(videoItem: SVGAVideoEntity, val dynamicItem: SVGADynamicEntity) : SGVADrawer(videoItem) {
|
|
|
|
private val sharedValues = ShareValues()
|
|
private val drawTextCache: HashMap<String, Bitmap> = hashMapOf()
|
|
private val pathCache = PathCache()
|
|
|
|
private var beginIndexList: Array<Boolean>? = null
|
|
private var endIndexList: Array<Boolean>? = null
|
|
|
|
override fun drawFrame(canvas: Canvas, frameIndex: Int, scaleType: ImageView.ScaleType) {
|
|
super.drawFrame(canvas, frameIndex, scaleType)
|
|
playAudio(frameIndex)
|
|
this.pathCache.onSizeChanged(canvas)
|
|
val sprites = requestFrameSprites(frameIndex)
|
|
// Filter null sprites
|
|
if (sprites.count() <= 0) return
|
|
val matteSprites = mutableMapOf<String, SVGADrawerSprite>()
|
|
var saveID = -1
|
|
beginIndexList = null
|
|
endIndexList = null
|
|
|
|
// Filter no matte layer
|
|
var hasMatteLayer = false
|
|
sprites.get(0).imageKey?.let {
|
|
if (it.endsWith(".matte")) {
|
|
hasMatteLayer = true
|
|
}
|
|
}
|
|
sprites.forEachIndexed { index, svgaDrawerSprite ->
|
|
|
|
// Save matte sprite
|
|
svgaDrawerSprite.imageKey?.let {
|
|
/// No matte layer included or VERSION Unsopport matte
|
|
if (!hasMatteLayer || Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
|
// Normal sprite
|
|
drawSprite(svgaDrawerSprite, canvas, frameIndex)
|
|
// Continue
|
|
return@forEachIndexed
|
|
}
|
|
/// Cache matte sprite
|
|
if (it.endsWith(".matte")) {
|
|
matteSprites.put(it, svgaDrawerSprite)
|
|
// Continue
|
|
return@forEachIndexed
|
|
}
|
|
}
|
|
/// Is matte begin
|
|
if (isMatteBegin(index, sprites)) {
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
|
saveID = canvas.saveLayer(0f, 0f, canvas.width.toFloat(), canvas.height.toFloat(), null)
|
|
} else {
|
|
canvas.save()
|
|
}
|
|
}
|
|
/// Normal matte
|
|
drawSprite(svgaDrawerSprite, canvas, frameIndex)
|
|
|
|
/// Is matte end
|
|
if (isMatteEnd(index, sprites)) {
|
|
matteSprites.get(svgaDrawerSprite.matteKey)?.let {
|
|
drawSprite(it, this.sharedValues.shareMatteCanvas(canvas.width, canvas.height), frameIndex)
|
|
canvas.drawBitmap(this.sharedValues.sharedMatteBitmap(), 0f, 0f, this.sharedValues.shareMattePaint())
|
|
if (saveID != -1) {
|
|
canvas.restoreToCount(saveID)
|
|
} else {
|
|
canvas.restore()
|
|
}
|
|
// Continue
|
|
return@forEachIndexed
|
|
}
|
|
}
|
|
}
|
|
releaseFrameSprites(sprites)
|
|
}
|
|
|
|
private fun isMatteBegin(spriteIndex: Int, sprites: List<SVGADrawerSprite>): Boolean {
|
|
if (beginIndexList == null) {
|
|
val boolArray = Array(sprites.count()) { false }
|
|
sprites.forEachIndexed { index, svgaDrawerSprite ->
|
|
svgaDrawerSprite.imageKey?.let {
|
|
/// Filter matte sprite
|
|
if (it.endsWith(".matte")) {
|
|
// Continue
|
|
return@forEachIndexed
|
|
}
|
|
}
|
|
svgaDrawerSprite.matteKey?.let {
|
|
if (it.length > 0) {
|
|
sprites.get(index - 1)?.let { lastSprite ->
|
|
if (lastSprite.matteKey.isNullOrEmpty()) {
|
|
boolArray[index] = true
|
|
} else {
|
|
if (lastSprite.matteKey != svgaDrawerSprite.matteKey) {
|
|
boolArray[index] = true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
beginIndexList = boolArray
|
|
}
|
|
return beginIndexList?.get(spriteIndex) ?: false
|
|
}
|
|
|
|
private fun isMatteEnd(spriteIndex: Int, sprites: List<SVGADrawerSprite>): Boolean {
|
|
if (endIndexList == null) {
|
|
val boolArray = Array(sprites.count()) { false }
|
|
sprites.forEachIndexed { index, svgaDrawerSprite ->
|
|
svgaDrawerSprite.imageKey?.let {
|
|
/// Filter matte sprite
|
|
if (it.endsWith(".matte")) {
|
|
// Continue
|
|
return@forEachIndexed
|
|
}
|
|
}
|
|
svgaDrawerSprite.matteKey?.let {
|
|
if (it.length > 0) {
|
|
// Last one
|
|
if (index == sprites.count() - 1) {
|
|
boolArray[index] = true
|
|
} else {
|
|
sprites.get(index + 1)?.let { nextSprite ->
|
|
if (nextSprite.matteKey.isNullOrEmpty()) {
|
|
boolArray[index] = true
|
|
} else {
|
|
if (nextSprite.matteKey != svgaDrawerSprite.matteKey) {
|
|
boolArray[index] = true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
endIndexList = boolArray
|
|
}
|
|
return endIndexList?.get(spriteIndex) ?: false
|
|
}
|
|
|
|
private fun playAudio(frameIndex: Int) {
|
|
this.videoItem.audioList.forEach { audio ->
|
|
if (audio.startFrame == frameIndex) {
|
|
if (SVGASoundManager.isInit()) {
|
|
audio.soundID?.let { soundID ->
|
|
audio.playID = SVGASoundManager.play(soundID)
|
|
}
|
|
} else {
|
|
this.videoItem.soundPool?.let { soundPool ->
|
|
audio.soundID?.let { soundID ->
|
|
audio.playID = soundPool.play(soundID, 1.0f, 1.0f, 1, 0, 1.0f)
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
if (audio.endFrame <= frameIndex) {
|
|
audio.playID?.let {
|
|
if (SVGASoundManager.isInit()) {
|
|
SVGASoundManager.stop(it)
|
|
} else {
|
|
this.videoItem.soundPool?.stop(it)
|
|
}
|
|
}
|
|
audio.playID = null
|
|
}
|
|
}
|
|
}
|
|
|
|
private fun shareFrameMatrix(transform: Matrix): Matrix {
|
|
val matrix = this.sharedValues.sharedMatrix()
|
|
matrix.postScale(scaleInfo.scaleFx, scaleInfo.scaleFy)
|
|
matrix.postTranslate(scaleInfo.tranFx, scaleInfo.tranFy)
|
|
matrix.preConcat(transform)
|
|
return matrix
|
|
}
|
|
|
|
private fun drawSprite(sprite: SVGADrawerSprite, canvas: Canvas, frameIndex: Int) {
|
|
drawImage(sprite, canvas)
|
|
drawShape(sprite, canvas)
|
|
drawDynamic(sprite, canvas, frameIndex)
|
|
}
|
|
|
|
private fun drawImage(sprite: SVGADrawerSprite, canvas: Canvas) {
|
|
val imageKey = sprite.imageKey ?: return
|
|
val isHidden = dynamicItem.dynamicHidden[imageKey] == true
|
|
if (isHidden) {
|
|
return
|
|
}
|
|
val bitmapKey = if (imageKey.endsWith(".matte")) imageKey.substring(0, imageKey.length - 6) else imageKey
|
|
val drawingBitmap = (dynamicItem.dynamicImage[bitmapKey] ?: videoItem.imageMap[bitmapKey])
|
|
?: return
|
|
val frameMatrix = shareFrameMatrix(sprite.frameEntity.transform)
|
|
val paint = this.sharedValues.sharedPaint()
|
|
paint.isAntiAlias = videoItem.antiAlias
|
|
paint.isFilterBitmap = videoItem.antiAlias
|
|
paint.alpha = (sprite.frameEntity.alpha * 255).toInt()
|
|
if (sprite.frameEntity.maskPath != null) {
|
|
val maskPath = sprite.frameEntity.maskPath ?: return
|
|
canvas.save()
|
|
val path = this.sharedValues.sharedPath()
|
|
maskPath.buildPath(path)
|
|
path.transform(frameMatrix)
|
|
canvas.clipPath(path)
|
|
frameMatrix.preScale((sprite.frameEntity.layout.width / drawingBitmap.width).toFloat(), (sprite.frameEntity.layout.height / drawingBitmap.height).toFloat())
|
|
if (!drawingBitmap.isRecycled) {
|
|
canvas.drawBitmap(drawingBitmap, frameMatrix, paint)
|
|
}
|
|
canvas.restore()
|
|
} else {
|
|
frameMatrix.preScale((sprite.frameEntity.layout.width / drawingBitmap.width).toFloat(), (sprite.frameEntity.layout.height / drawingBitmap.height).toFloat())
|
|
if (!drawingBitmap.isRecycled) {
|
|
canvas.drawBitmap(drawingBitmap, frameMatrix, paint)
|
|
}
|
|
}
|
|
dynamicItem.dynamicIClickArea.let {
|
|
it.get(imageKey)?.let { listener ->
|
|
val matrixArray = floatArrayOf(0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f)
|
|
frameMatrix.getValues(matrixArray)
|
|
listener.onResponseArea(imageKey, matrixArray[2].toInt()
|
|
, matrixArray[5].toInt()
|
|
, (drawingBitmap.width * matrixArray[0] + matrixArray[2]).toInt()
|
|
, (drawingBitmap.height * matrixArray[4] + matrixArray[5]).toInt())
|
|
}
|
|
}
|
|
drawTextOnBitmap(canvas, drawingBitmap, sprite, frameMatrix)
|
|
}
|
|
|
|
private fun drawTextOnBitmap(canvas: Canvas, drawingBitmap: Bitmap, sprite: SVGADrawerSprite, frameMatrix: Matrix) {
|
|
if (dynamicItem.isTextDirty) {
|
|
this.drawTextCache.clear()
|
|
dynamicItem.isTextDirty = false
|
|
}
|
|
val imageKey = sprite.imageKey ?: return
|
|
var textBitmap: Bitmap? = null
|
|
dynamicItem.dynamicText[imageKey]?.let { drawingText ->
|
|
dynamicItem.dynamicTextPaint[imageKey]?.let { drawingTextPaint ->
|
|
drawTextCache[imageKey]?.let {
|
|
textBitmap = it
|
|
} ?: kotlin.run {
|
|
textBitmap = Bitmap.createBitmap(drawingBitmap.width, drawingBitmap.height, Bitmap.Config.ARGB_8888)
|
|
val drawRect = Rect(0, 0, drawingBitmap.width, drawingBitmap.height)
|
|
val textCanvas = Canvas(textBitmap)
|
|
drawingTextPaint.isAntiAlias = true
|
|
val fontMetrics = drawingTextPaint.getFontMetrics();
|
|
val top = fontMetrics.top
|
|
val bottom = fontMetrics.bottom
|
|
val baseLineY = drawRect.centerY() - top / 2 - bottom / 2
|
|
textCanvas.drawText(drawingText, drawRect.centerX().toFloat(), baseLineY, drawingTextPaint);
|
|
drawTextCache.put(imageKey, textBitmap as Bitmap)
|
|
}
|
|
}
|
|
}
|
|
|
|
dynamicItem.dynamicBoringLayoutText[imageKey]?.let {
|
|
drawTextCache[imageKey]?.let {
|
|
textBitmap = it
|
|
} ?: kotlin.run {
|
|
it.paint.isAntiAlias = true
|
|
|
|
textBitmap = Bitmap.createBitmap(drawingBitmap.width, drawingBitmap.height, Bitmap.Config.ARGB_8888)
|
|
val textCanvas = Canvas(textBitmap)
|
|
textCanvas.translate(0f, ((drawingBitmap.height - it.height) / 2).toFloat())
|
|
it.draw(textCanvas)
|
|
drawTextCache.put(imageKey, textBitmap as Bitmap)
|
|
}
|
|
}
|
|
|
|
dynamicItem.dynamicStaticLayoutText[imageKey]?.let {
|
|
drawTextCache[imageKey]?.let {
|
|
textBitmap = it
|
|
} ?: kotlin.run {
|
|
it.paint.isAntiAlias = true
|
|
var layout = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
|
var lineMax = try {
|
|
val field = StaticLayout::class.java.getDeclaredField("mMaximumVisibleLineCount")
|
|
field.isAccessible = true
|
|
field.getInt(it)
|
|
} catch (e: Exception) {
|
|
Int.MAX_VALUE
|
|
}
|
|
StaticLayout.Builder
|
|
.obtain(it.text, 0, it.text.length, it.paint, drawingBitmap.width)
|
|
.setAlignment(it.alignment)
|
|
.setMaxLines(lineMax)
|
|
.setEllipsize(TextUtils.TruncateAt.END)
|
|
.build()
|
|
} else {
|
|
StaticLayout(it.text, 0, it.text.length, it.paint, drawingBitmap.width, it.alignment, it.spacingMultiplier, it.spacingAdd, false)
|
|
}
|
|
textBitmap = Bitmap.createBitmap(drawingBitmap.width, drawingBitmap.height, Bitmap.Config.ARGB_8888)
|
|
val textCanvas = Canvas(textBitmap)
|
|
textCanvas.translate(0f, ((drawingBitmap.height - layout.height) / 2).toFloat())
|
|
layout.draw(textCanvas)
|
|
drawTextCache.put(imageKey, textBitmap as Bitmap)
|
|
}
|
|
}
|
|
textBitmap?.let { textBitmap ->
|
|
val paint = this.sharedValues.sharedPaint()
|
|
paint.isAntiAlias = videoItem.antiAlias
|
|
paint.alpha = (sprite.frameEntity.alpha * 255).toInt()
|
|
if (sprite.frameEntity.maskPath != null) {
|
|
val maskPath = sprite.frameEntity.maskPath ?: return@let
|
|
canvas.save()
|
|
canvas.concat(frameMatrix)
|
|
canvas.clipRect(0, 0, drawingBitmap.width, drawingBitmap.height)
|
|
val bitmapShader = BitmapShader(textBitmap, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT)
|
|
paint.shader = bitmapShader
|
|
val path = this.sharedValues.sharedPath()
|
|
maskPath.buildPath(path)
|
|
canvas.drawPath(path, paint)
|
|
canvas.restore()
|
|
} else {
|
|
paint.isFilterBitmap = videoItem.antiAlias
|
|
canvas.drawBitmap(textBitmap, frameMatrix, paint)
|
|
}
|
|
}
|
|
}
|
|
|
|
private fun drawShape(sprite: SVGADrawerSprite, canvas: Canvas) {
|
|
val frameMatrix = shareFrameMatrix(sprite.frameEntity.transform)
|
|
sprite.frameEntity.shapes.forEach { shape ->
|
|
shape.buildPath()
|
|
shape.shapePath?.let {
|
|
val paint = this.sharedValues.sharedPaint()
|
|
paint.reset()
|
|
paint.isAntiAlias = videoItem.antiAlias
|
|
paint.alpha = (sprite.frameEntity.alpha * 255).toInt()
|
|
val path = this.sharedValues.sharedPath()
|
|
path.reset()
|
|
path.addPath(this.pathCache.buildPath(shape))
|
|
val shapeMatrix = this.sharedValues.sharedMatrix2()
|
|
shapeMatrix.reset()
|
|
shape.transform?.let {
|
|
shapeMatrix.postConcat(it)
|
|
}
|
|
shapeMatrix.postConcat(frameMatrix)
|
|
path.transform(shapeMatrix)
|
|
shape.styles?.fill?.let {
|
|
if (it != 0x00000000) {
|
|
paint.style = Paint.Style.FILL
|
|
paint.color = it
|
|
val alpha = Math.min(255, Math.max(0, (sprite.frameEntity.alpha * 255).toInt()))
|
|
if (alpha != 255) {
|
|
paint.alpha = alpha
|
|
}
|
|
if (sprite.frameEntity.maskPath !== null) canvas.save()
|
|
sprite.frameEntity.maskPath?.let { maskPath ->
|
|
val path2 = this.sharedValues.sharedPath2()
|
|
maskPath.buildPath(path2)
|
|
path2.transform(frameMatrix)
|
|
canvas.clipPath(path2)
|
|
}
|
|
canvas.drawPath(path, paint)
|
|
if (sprite.frameEntity.maskPath !== null) canvas.restore()
|
|
}
|
|
}
|
|
shape.styles?.strokeWidth?.let {
|
|
if (it > 0) {
|
|
paint.alpha = (sprite.frameEntity.alpha * 255).toInt()
|
|
paint.style = Paint.Style.STROKE
|
|
shape.styles?.stroke?.let {
|
|
paint.color = it
|
|
val alpha = Math.min(255, Math.max(0, (sprite.frameEntity.alpha * 255).toInt()))
|
|
if (alpha != 255) {
|
|
paint.alpha = alpha
|
|
}
|
|
}
|
|
val scale = matrixScale(frameMatrix)
|
|
shape.styles?.strokeWidth?.let {
|
|
paint.strokeWidth = it * scale
|
|
}
|
|
shape.styles?.lineCap?.let {
|
|
when {
|
|
it.equals("butt", true) -> paint.strokeCap = Paint.Cap.BUTT
|
|
it.equals("round", true) -> paint.strokeCap = Paint.Cap.ROUND
|
|
it.equals("square", true) -> paint.strokeCap = Paint.Cap.SQUARE
|
|
}
|
|
}
|
|
shape.styles?.lineJoin?.let {
|
|
when {
|
|
it.equals("miter", true) -> paint.strokeJoin = Paint.Join.MITER
|
|
it.equals("round", true) -> paint.strokeJoin = Paint.Join.ROUND
|
|
it.equals("bevel", true) -> paint.strokeJoin = Paint.Join.BEVEL
|
|
}
|
|
}
|
|
shape.styles?.miterLimit?.let {
|
|
paint.strokeMiter = it.toFloat() * scale
|
|
}
|
|
shape.styles?.lineDash?.let {
|
|
if (it.size == 3 && (it[0] > 0 || it[1] > 0)) {
|
|
paint.pathEffect = DashPathEffect(floatArrayOf(
|
|
(if (it[0] < 1.0f) 1.0f else it[0]) * scale,
|
|
(if (it[1] < 0.1f) 0.1f else it[1]) * scale
|
|
), it[2] * scale)
|
|
}
|
|
}
|
|
if (sprite.frameEntity.maskPath !== null) canvas.save()
|
|
sprite.frameEntity.maskPath?.let { maskPath ->
|
|
val path2 = this.sharedValues.sharedPath2()
|
|
maskPath.buildPath(path2)
|
|
path2.transform(frameMatrix)
|
|
canvas.clipPath(path2)
|
|
}
|
|
canvas.drawPath(path, paint)
|
|
if (sprite.frameEntity.maskPath !== null) canvas.restore()
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
private val matrixScaleTempValues = FloatArray(16)
|
|
|
|
private fun matrixScale(matrix: Matrix): Float {
|
|
matrix.getValues(matrixScaleTempValues)
|
|
if (matrixScaleTempValues[0] == 0f) {
|
|
return 0f
|
|
}
|
|
var A = matrixScaleTempValues[0].toDouble()
|
|
var B = matrixScaleTempValues[3].toDouble()
|
|
var C = matrixScaleTempValues[1].toDouble()
|
|
var D = matrixScaleTempValues[4].toDouble()
|
|
if (A * D == B * C) return 0f
|
|
var scaleX = Math.sqrt(A * A + B * B)
|
|
A /= scaleX
|
|
B /= scaleX
|
|
var skew = A * C + B * D
|
|
C -= A * skew
|
|
D -= B * skew
|
|
var scaleY = Math.sqrt(C * C + D * D)
|
|
C /= scaleY
|
|
D /= scaleY
|
|
skew /= scaleY
|
|
if (A * D < B * C) {
|
|
scaleX = -scaleX
|
|
}
|
|
return if (scaleInfo.ratioX) Math.abs(scaleX.toFloat()) else Math.abs(scaleY.toFloat())
|
|
}
|
|
|
|
private fun drawDynamic(sprite: SVGADrawerSprite, canvas: Canvas, frameIndex: Int) {
|
|
val imageKey = sprite.imageKey ?: return
|
|
dynamicItem.dynamicDrawer[imageKey]?.let {
|
|
val frameMatrix = shareFrameMatrix(sprite.frameEntity.transform)
|
|
canvas.save()
|
|
canvas.concat(frameMatrix)
|
|
it.invoke(canvas, frameIndex)
|
|
canvas.restore()
|
|
}
|
|
dynamicItem.dynamicDrawerSized[imageKey]?.let {
|
|
val frameMatrix = shareFrameMatrix(sprite.frameEntity.transform)
|
|
canvas.save()
|
|
canvas.concat(frameMatrix)
|
|
it.invoke(canvas, frameIndex, sprite.frameEntity.layout.width.toInt(), sprite.frameEntity.layout.height.toInt())
|
|
canvas.restore()
|
|
}
|
|
}
|
|
|
|
class ShareValues {
|
|
|
|
private val sharedPaint = Paint()
|
|
private val sharedPath = Path()
|
|
private val sharedPath2 = Path()
|
|
private val sharedMatrix = Matrix()
|
|
private val sharedMatrix2 = Matrix()
|
|
|
|
private val shareMattePaint = Paint()
|
|
private var shareMatteCanvas: Canvas? = null
|
|
private var sharedMatteBitmap: Bitmap? = null
|
|
|
|
fun sharedPaint(): Paint {
|
|
sharedPaint.reset()
|
|
return sharedPaint
|
|
}
|
|
|
|
fun sharedPath(): Path {
|
|
sharedPath.reset()
|
|
return sharedPath
|
|
}
|
|
|
|
fun sharedPath2(): Path {
|
|
sharedPath2.reset()
|
|
return sharedPath2
|
|
}
|
|
|
|
fun sharedMatrix(): Matrix {
|
|
sharedMatrix.reset()
|
|
return sharedMatrix
|
|
}
|
|
|
|
fun sharedMatrix2(): Matrix {
|
|
sharedMatrix2.reset()
|
|
return sharedMatrix2
|
|
}
|
|
|
|
fun shareMattePaint(): Paint {
|
|
shareMattePaint.setXfermode(PorterDuffXfermode(PorterDuff.Mode.DST_IN))
|
|
return shareMattePaint
|
|
}
|
|
|
|
fun sharedMatteBitmap(): Bitmap {
|
|
return sharedMatteBitmap as Bitmap
|
|
}
|
|
|
|
fun shareMatteCanvas(width: Int, height: Int): Canvas {
|
|
if (shareMatteCanvas == null) {
|
|
sharedMatteBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ALPHA_8)
|
|
// shareMatteCanvas = Canvas(sharedMatteBitmap)
|
|
}
|
|
// val matteCanvas = shareMatteCanvas as Canvas
|
|
// matteCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR)
|
|
// return matteCanvas
|
|
return Canvas(sharedMatteBitmap)
|
|
}
|
|
}
|
|
|
|
class PathCache {
|
|
|
|
private var canvasWidth: Int = 0
|
|
private var canvasHeight: Int = 0
|
|
private val cache = HashMap<SVGAVideoShapeEntity, Path>()
|
|
|
|
fun onSizeChanged(canvas: Canvas) {
|
|
if (this.canvasWidth != canvas.width || this.canvasHeight != canvas.height) {
|
|
this.cache.clear()
|
|
}
|
|
this.canvasWidth = canvas.width
|
|
this.canvasHeight = canvas.height
|
|
}
|
|
|
|
fun buildPath(shape: SVGAVideoShapeEntity): Path {
|
|
if (!this.cache.containsKey(shape)) {
|
|
val path = Path()
|
|
path.set(shape.shapePath)
|
|
this.cache[shape] = path
|
|
}
|
|
return this.cache[shape]!!
|
|
}
|
|
|
|
}
|
|
|
|
}
|