Skip to content

Commit ddc3844

Browse files
authored
Merge pull request svga#40 from andyliumstar/master
cache path in drawer & handle canvas size change
2 parents ef2ad7b + a9b85c4 commit ddc3844

File tree

5 files changed

+75
-60
lines changed

5 files changed

+75
-60
lines changed

library/src/main/java/com/opensource/svgaplayer/SGVADrawer.kt

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.opensource.svgaplayer
22

3+
import android.graphics.Canvas
34
import android.widget.ImageView
45

56
/**
@@ -8,6 +9,8 @@ import android.widget.ImageView
89

910
open class SGVADrawer(val videoItem: SVGAVideoEntity) {
1011

12+
val scaleEntity = ScaleEntity()
13+
1114
inner class SVGADrawerSprite(val imageKey: String?, val frameEntity: SVGAVideoSpriteFrameEntity)
1215

1316
internal fun requestFrameSprites(frameIndex: Int): List<SVGADrawerSprite> {
@@ -22,8 +25,12 @@ open class SGVADrawer(val videoItem: SVGAVideoEntity) {
2225
}
2326
}
2427

25-
open fun drawFrame(frameIndex: Int, scaleType: ImageView.ScaleType) {
28+
open fun drawFrame(canvas : Canvas, frameIndex: Int, scaleType: ImageView.ScaleType) {
29+
performScaleType(canvas,scaleType)
30+
}
2631

32+
open fun performScaleType(canvas : Canvas,scaleType: ImageView.ScaleType) {
33+
scaleEntity.performScaleType(canvas.width.toFloat(),canvas.height.toFloat(),videoItem.videoSize.width.toFloat(),videoItem.videoSize.height.toFloat(),scaleType)
2734
}
2835

2936
}

library/src/main/java/com/opensource/svgaplayer/SVGACanvasDrawer.kt

+62-48
Original file line numberDiff line numberDiff line change
@@ -10,69 +10,74 @@ import android.widget.ImageView
1010

1111
class SVGACanvasDrawer(videoItem: SVGAVideoEntity, val dynamicItem: SVGADynamicEntity) : SGVADrawer(videoItem) {
1212

13-
var canvas: Canvas? = null
14-
var scaleEntity:ScaleEntity = ScaleEntity()
15-
13+
private var canvasW = 0
14+
private var canvasH = 0
1615
private val sharedPaint = Paint()
1716
private val sharedPath = Path()
1817
private val sharedPath2 = Path()
19-
private val sharedContentTransform = Matrix()
18+
private val sharedShapeMatrix= Matrix()
19+
private val sharedFrameMatrix= Matrix()
20+
private val sharedPathMap = HashMap<SVGAVideoShapeEntity,Path>()
21+
22+
override fun drawFrame(canvas :Canvas, frameIndex: Int, scaleType: ImageView.ScaleType) {
23+
super.drawFrame(canvas,frameIndex, scaleType)
24+
resetCachePath(canvas)
2025

21-
override fun drawFrame(frameIndex: Int, scaleType: ImageView.ScaleType) {
22-
super.drawFrame(frameIndex, scaleType)
2326
val sprites = requestFrameSprites(frameIndex)
24-
performScaleType(scaleType)
2527
sprites.forEach {
26-
drawSprite(it)
28+
drawSprite(it,canvas)
2729
}
2830
}
2931

30-
private fun enableScaleEntity(){
31-
sharedContentTransform.reset()
32-
sharedContentTransform.postScale(scaleEntity.scaleFx, scaleEntity.scaleFy)
33-
sharedContentTransform.postTranslate(scaleEntity.tranFx, scaleEntity.tranFy)
32+
private fun resetCachePath(canvas :Canvas){
33+
if(canvasW != canvas.width || canvasH != canvas.height){
34+
sharedPathMap.clear()
35+
}
36+
canvasW = canvas.width
37+
canvasH = canvas.height
3438
}
3539

36-
private fun performScaleType(scaleType: ImageView.ScaleType) {
37-
val canvas = this.canvas ?: return
38-
scaleEntity.performScaleType(canvas.width.toFloat(),canvas.height.toFloat(),videoItem.videoSize.width.toFloat(),videoItem.videoSize.height.toFloat(),scaleType)
40+
private fun resetShareMatrix(transform :Matrix){
41+
sharedFrameMatrix.reset()
42+
sharedFrameMatrix.postScale(scaleEntity.scaleFx, scaleEntity.scaleFy)
43+
sharedFrameMatrix.postTranslate(scaleEntity.tranFx, scaleEntity.tranFy)
44+
sharedFrameMatrix.preConcat(transform)
3945
}
4046

41-
private fun drawSprite(sprite: SVGADrawerSprite) {
42-
drawImage(sprite)
43-
drawShape(sprite)
47+
private fun drawSprite(sprite: SVGADrawerSprite,canvas :Canvas) {
48+
drawImage(sprite, canvas)
49+
drawShape(sprite, canvas)
4450
}
4551

46-
private fun drawImage(sprite: SVGADrawerSprite) {
47-
val canvas = this.canvas ?: return
52+
private fun drawImage(sprite: SVGADrawerSprite, canvas :Canvas) {
4853
(dynamicItem.dynamicImage[sprite.imageKey] ?: videoItem.images[sprite.imageKey])?.let {
54+
resetShareMatrix(sprite.frameEntity.transform)
55+
4956
sharedPaint.reset()
5057
sharedPaint.isAntiAlias = videoItem.antiAlias
5158
sharedPaint.isFilterBitmap = videoItem.antiAlias
5259
sharedPaint.alpha = (sprite.frameEntity.alpha * 255).toInt()
53-
enableScaleEntity()
54-
sharedContentTransform.preConcat(sprite.frameEntity.transform)
60+
5561
if (sprite.frameEntity.maskPath != null) {
5662
val maskPath = sprite.frameEntity.maskPath ?: return@let
5763
canvas.save()
5864
sharedPath.reset()
5965
maskPath.buildPath(sharedPath)
60-
sharedPath.transform(sharedContentTransform)
66+
sharedPath.transform(sharedFrameMatrix)
6167
canvas.clipPath(sharedPath)
62-
sharedContentTransform.preScale((sprite.frameEntity.layout.width / it.width).toFloat(), (sprite.frameEntity.layout.width / it.width).toFloat())
63-
canvas.drawBitmap(it, sharedContentTransform, sharedPaint)
68+
sharedFrameMatrix.preScale((sprite.frameEntity.layout.width / it.width).toFloat(), (sprite.frameEntity.layout.width / it.width).toFloat())
69+
canvas.drawBitmap(it, sharedFrameMatrix, sharedPaint)
6470
canvas.restore()
6571
}
6672
else {
67-
sharedContentTransform.preScale((sprite.frameEntity.layout.width / it.width).toFloat(), (sprite.frameEntity.layout.width / it.width).toFloat())
68-
canvas.drawBitmap(it, sharedContentTransform, sharedPaint)
73+
sharedFrameMatrix.preScale((sprite.frameEntity.layout.width / it.width).toFloat(), (sprite.frameEntity.layout.width / it.width).toFloat())
74+
canvas.drawBitmap(it, sharedFrameMatrix, sharedPaint)
6975
}
70-
drawText(it, sprite)
76+
drawText(canvas,it, sprite)
7177
}
7278
}
7379

74-
private fun drawText(drawingBitmap: Bitmap, sprite: SVGADrawerSprite) {
75-
val canvas = this.canvas ?: return
80+
private fun drawText(canvas :Canvas, drawingBitmap: Bitmap, sprite: SVGADrawerSprite) {
7681
dynamicItem.dynamicText[sprite.imageKey]?.let { drawingText ->
7782
dynamicItem.dynamicTextPaint[sprite.imageKey]?.let { drawingTextPaint ->
7883
val textBitmap = Bitmap.createBitmap(drawingBitmap.width, drawingBitmap.height, Bitmap.Config.ARGB_8888)
@@ -91,7 +96,7 @@ class SVGACanvasDrawer(videoItem: SVGAVideoEntity, val dynamicItem: SVGADynamicE
9196
if (sprite.frameEntity.maskPath != null) {
9297
val maskPath = sprite.frameEntity.maskPath ?: return@let
9398
canvas.save()
94-
canvas.concat(sharedContentTransform)
99+
canvas.concat(sharedFrameMatrix)
95100
canvas.clipRect(0, 0, drawingBitmap.width, drawingBitmap.height)
96101
val bitmapShader = BitmapShader(textBitmap, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT)
97102
sharedPaint.shader = bitmapShader
@@ -102,63 +107,72 @@ class SVGACanvasDrawer(videoItem: SVGAVideoEntity, val dynamicItem: SVGADynamicE
102107
}
103108
else {
104109
sharedPaint.isFilterBitmap = videoItem.antiAlias
105-
canvas.drawBitmap(textBitmap, sharedContentTransform, sharedPaint)
110+
canvas.drawBitmap(textBitmap, sharedFrameMatrix, sharedPaint)
106111
}
107112
}
108113
}
109114
}
110115

111-
private fun drawShape(sprite: SVGADrawerSprite) {
112-
val canvas = this.canvas ?: return
113-
enableScaleEntity()
114-
sharedContentTransform.preConcat(sprite.frameEntity.transform)
116+
private fun drawShape(sprite: SVGADrawerSprite, canvas :Canvas) {
117+
resetShareMatrix(sprite.frameEntity.transform)
115118
sprite.frameEntity.shapes.forEach { shape ->
116-
sharedPath.reset()
117119
shape.buildPath()
118120
shape.shapePath?.let {
119-
sharedPath.addPath(it)
120-
}
121-
if (!sharedPath.isEmpty) {
122-
sharedPath.transform(sharedContentTransform)
123121
sharedPaint.reset()
124122
sharedPaint.isAntiAlias = videoItem.antiAlias
125123
sharedPaint.alpha = (sprite.frameEntity.alpha * 255).toInt()
124+
125+
if(!sharedPathMap.containsKey(shape)){
126+
sharedShapeMatrix.reset()
127+
shape.transform?.let {
128+
sharedShapeMatrix.postConcat(it)
129+
}
130+
sharedShapeMatrix.postConcat(sharedFrameMatrix)
131+
132+
val path = Path()
133+
path.set(shape.shapePath)
134+
path.transform(sharedShapeMatrix)
135+
sharedPathMap.put(shape,path)
136+
}
137+
126138
shape.styles?.fill?.let {
127139
if (it != 0x00000000) {
128140
sharedPaint.color = it
129141
if (sprite.frameEntity.maskPath !== null) canvas.save()
130142
sprite.frameEntity.maskPath?.let { maskPath ->
131143
sharedPath2.reset()
132144
maskPath.buildPath(sharedPath2)
133-
sharedPath2.transform(this.sharedContentTransform)
145+
sharedPath2.transform(this.sharedFrameMatrix)
134146
canvas.clipPath(sharedPath2)
135147
}
136-
canvas.drawPath(sharedPath, sharedPaint)
148+
canvas.drawPath(sharedPathMap.get(shape), sharedPaint)
137149
if (sprite.frameEntity.maskPath !== null) canvas.restore()
138150
}
139151
}
152+
140153
shape.styles?.strokeWidth?.let {
141154
if (it > 0) {
142155
resetShapeStrokePaint(shape)
143156
if (sprite.frameEntity.maskPath !== null) canvas.save()
144157
sprite.frameEntity.maskPath?.let { maskPath ->
145158
sharedPath2.reset()
146159
maskPath.buildPath(sharedPath2)
147-
sharedPath2.transform(this.sharedContentTransform)
160+
sharedPath2.transform(this.sharedFrameMatrix)
148161
canvas.clipPath(sharedPath2)
149162
}
150-
canvas.drawPath(sharedPath, sharedPaint)
163+
canvas.drawPath(sharedPathMap.get(shape), sharedPaint)
151164
if (sprite.frameEntity.maskPath !== null) canvas.restore()
152165
}
153166
}
154167
}
168+
155169
}
156170
}
157171

158172
private val tValues = FloatArray(16)
159173

160174
private fun requestScale(): Float {
161-
this.sharedContentTransform.getValues(tValues)
175+
this.sharedFrameMatrix.getValues(tValues)
162176
if (tValues[0] == 0f) {
163177
return 0f
164178
}
@@ -190,7 +204,7 @@ class SVGACanvasDrawer(videoItem: SVGAVideoEntity, val dynamicItem: SVGADynamicE
190204
shape.styles?.stroke?.let {
191205
sharedPaint.color = it
192206
}
193-
207+
194208
val scale = requestScale()
195209
shape.styles?.strokeWidth?.let {
196210
sharedPaint.strokeWidth = it * scale
@@ -213,7 +227,7 @@ class SVGACanvasDrawer(videoItem: SVGAVideoEntity, val dynamicItem: SVGADynamicE
213227
sharedPaint.strokeMiter = it.toFloat() * scale
214228
}
215229
shape.styles?.lineDash?.let {
216-
if (it.size == 3 && it[0] > 0 && it[1] > 0) {
230+
if (it.size == 3 && (it[0] > 0 || it[1] > 0)) {
217231
sharedPaint.pathEffect = DashPathEffect(floatArrayOf(
218232
(if (it[0] < 1.0f) 1.0f else it[0]) * scale,
219233
(if (it[1] < 0.1f) 0.1f else it[1]) * scale

library/src/main/java/com/opensource/svgaplayer/SVGAImageView.kt

+2-3
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,7 @@ class SVGADrawable(val videoItem: SVGAVideoEntity, val dynamicItem: SVGADynamicE
4949
return
5050
}
5151
canvas?.let {
52-
drawer.canvas = it
53-
drawer.drawFrame(currentFrame, scaleType)
52+
drawer.drawFrame(it,currentFrame, scaleType)
5453
}
5554
}
5655

@@ -272,4 +271,4 @@ open class SVGAImageView : ImageView {
272271
stepToFrame(frame, andPlay)
273272
}
274273

275-
}
274+
}

library/src/main/java/com/opensource/svgaplayer/SVGAPath.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ class SVGAPath(originValue: String) {
1313

1414
fun buildPath(toPath: Path) {
1515
cachedPath?.let {
16-
toPath.addPath(it)
16+
toPath.set(it)
1717
return
1818
}
1919
val cachedPath = Path()
@@ -31,7 +31,7 @@ class SVGAPath(originValue: String) {
3131
}
3232
}
3333
this.cachedPath = cachedPath
34-
toPath.addPath(cachedPath)
34+
toPath.set(cachedPath)
3535
}
3636

3737
private fun operate(finalPath: Path, method: String, args: StringTokenizer) {

library/src/main/java/com/opensource/svgaplayer/SVGAVideoShapeEntity.kt

+1-6
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,8 @@ import android.graphics.Color
44
import android.graphics.Matrix
55
import android.graphics.Path
66
import android.graphics.RectF
7-
import android.os.Build
87
import com.opensource.svgaplayer.proto.ShapeEntity
9-
10-
import org.json.JSONArray
11-
import org.json.JSONException
128
import org.json.JSONObject
13-
149
import java.util.HashMap
1510

1611
/**
@@ -283,7 +278,7 @@ class SVGAVideoShapeEntity {
283278
sharedPath.addRoundRect(RectF(x, y, x + width, y + height), cornerRadius, cornerRadius, Path.Direction.CW)
284279
}
285280
this.shapePath = Path()
286-
this.shapePath?.addPath(sharedPath)
281+
this.shapePath?.set(sharedPath)
287282
}
288283

289284
}

0 commit comments

Comments
 (0)