1
+ import Browser from './Browser' ;
2
+ import { isSVG , isImageBitMap , isString , hasOwn } from './util' ;
3
+
4
+ type ResourceUrl = string | string [ ] ;
5
+
6
+ type ResourceCacheItem = {
7
+ image : ImageBitmap ;
8
+ width : number ;
9
+ height : number ;
10
+ refCnt : number ;
11
+ }
12
+
13
+ /**
14
+ * resouce key support ImageBitMap by Map
15
+ * this.resources.set(imagebitmap,cache);
16
+ * https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Map
17
+ */
18
+
19
+
20
+ class ResourceCacheMap {
21
+ resources : Map < string | ImageBitmap , ResourceCacheItem > ;
22
+
23
+ //@internal
24
+ _errors : Map < string | ImageBitmap , number > ;
25
+
26
+ constructor ( ) {
27
+ this . resources = new Map ( ) ;
28
+ this . _errors = new Map ( ) ;
29
+ }
30
+
31
+
32
+ addResource ( url : [ string , number | string , number | string ] , img ) {
33
+ const imgUrl = this . _getImgUrl ( url as any ) ;
34
+ this . resources . set ( imgUrl , {
35
+ image : img ,
36
+ width : + url [ 1 ] ,
37
+ height : + url [ 2 ] ,
38
+ refCnt : 0
39
+ } )
40
+ //is Image
41
+ if ( img && img . width && img . height && ! img . close && Browser . imageBitMap && ! Browser . safari && ! Browser . iosWeixin ) {
42
+ if ( img . src && isSVG ( img . src ) ) {
43
+ return ;
44
+ }
45
+ createImageBitmap ( img ) . then ( imageBitmap => {
46
+ if ( ! this . resources . has ( imgUrl ) ) {
47
+ //removed
48
+ return ;
49
+ }
50
+ this . resources . get ( imgUrl ) . image = imageBitmap ;
51
+ } ) ;
52
+ }
53
+ }
54
+
55
+ isResourceLoaded ( url : ResourceUrl , checkSVG ?: boolean ) {
56
+ if ( ! url ) {
57
+ return false ;
58
+ }
59
+ const imgUrl = this . _getImgUrl ( url ) ;
60
+ if ( this . _errors . has ( imgUrl ) ) {
61
+ return true ;
62
+ }
63
+ const img = this . resources . get ( imgUrl ) ;
64
+ if ( ! img ) {
65
+ return false ;
66
+ }
67
+ if ( checkSVG && isSVG ( url [ 0 ] ) && ( + url [ 1 ] > img . width || + url [ 2 ] > img . height ) ) {
68
+ return false ;
69
+ }
70
+ return true ;
71
+ }
72
+
73
+ login ( url : string ) {
74
+ const res = this . resources . get ( url ) ;
75
+ if ( res ) {
76
+ res . refCnt ++ ;
77
+ }
78
+ }
79
+
80
+ logout ( url : string ) {
81
+ const res = this . resources . get ( url ) ;
82
+ if ( res && res . refCnt -- <= 0 ) {
83
+ if ( res . image && res . image . close ) {
84
+ res . image . close ( ) ;
85
+ }
86
+ this . resources . delete ( url ) ;
87
+ }
88
+ }
89
+
90
+ getImage ( url : ResourceUrl ) {
91
+ const imgUrl = this . _getImgUrl ( url ) ;
92
+ if ( ! this . isResourceLoaded ( url ) || this . _errors . has ( imgUrl ) ) {
93
+ return null ;
94
+ }
95
+ return this . resources . get ( imgUrl ) . image ;
96
+ }
97
+
98
+ markErrorResource ( url : ResourceUrl ) {
99
+ const imgUrl = this . _getImgUrl ( url ) ;
100
+ this . _errors . set ( imgUrl , 1 ) ;
101
+ }
102
+
103
+ merge ( res : ResourceCacheMap ) {
104
+ if ( ! res ) {
105
+ return this ;
106
+ }
107
+ const otherResource = res . resources ;
108
+ if ( otherResource ) {
109
+ otherResource . forEach ( ( value , key ) => {
110
+ const img = value ;
111
+ this . addResource ( [ key as string , img . width , img . height ] , img . image ) ;
112
+ } )
113
+ }
114
+ return this ;
115
+ }
116
+
117
+ forEach ( fn : ( key : string | ImageBitmap , value : any ) => void ) {
118
+ if ( ! this . resources ) {
119
+ return this ;
120
+ }
121
+ this . resources . forEach ( ( value , key ) => {
122
+ fn ( key , value ) ;
123
+ } )
124
+ return this ;
125
+ }
126
+
127
+ //@internal
128
+ _getImgUrl ( url : ResourceUrl ) {
129
+ if ( isImageBitMap ( url ) ) {
130
+ return url ;
131
+ }
132
+ let imgUrl ;
133
+ if ( Array . isArray ( url ) ) {
134
+ imgUrl = url [ 0 ] ;
135
+ } else if ( isString ( url ) ) {
136
+ imgUrl = url ;
137
+ }
138
+ if ( ! imgUrl ) {
139
+ console . error ( `get url key error,the url is:` , url ) ;
140
+ }
141
+ return imgUrl ;
142
+ }
143
+
144
+ remove ( ) {
145
+ if ( ! this . resources ) {
146
+ return this ;
147
+ }
148
+ this . resources . forEach ( ( value ) => {
149
+ if ( value && value . image && value . image . close ) {
150
+ value . image . close ( ) ;
151
+ }
152
+ } )
153
+ this . resources . clear ( ) ;
154
+ return this ;
155
+ }
156
+ }
157
+
158
+
159
+ export class ResourceCache {
160
+ resources : any ;
161
+
162
+ //@internal
163
+ _errors : any ;
164
+
165
+ constructor ( ) {
166
+ this . resources = { } ;
167
+ this . _errors = { } ;
168
+ }
169
+
170
+ addResource ( url : [ string , number | string , number | string ] , img ) {
171
+ this . resources [ url [ 0 ] ] = {
172
+ image : img ,
173
+ width : + url [ 1 ] ,
174
+ height : + url [ 2 ] ,
175
+ refCnt : 0
176
+ } ;
177
+ if ( img && img . width && img . height && ! img . close && Browser . imageBitMap && ! Browser . safari && ! Browser . iosWeixin ) {
178
+ if ( img . src && isSVG ( img . src ) ) {
179
+ return ;
180
+ }
181
+ createImageBitmap ( img ) . then ( imageBitmap => {
182
+ if ( ! this . resources [ url [ 0 ] ] ) {
183
+ //removed
184
+ return ;
185
+ }
186
+ this . resources [ url [ 0 ] ] . image = imageBitmap ;
187
+ } ) ;
188
+ }
189
+ }
190
+
191
+ isResourceLoaded ( url : ResourceUrl , checkSVG ?: boolean ) {
192
+ if ( ! url ) {
193
+ return false ;
194
+ }
195
+ const imgUrl = this . _getImgUrl ( url ) ;
196
+ if ( this . _errors [ imgUrl ] ) {
197
+ return true ;
198
+ }
199
+ const img = this . resources [ imgUrl ] ;
200
+ if ( ! img ) {
201
+ return false ;
202
+ }
203
+ if ( checkSVG && isSVG ( url [ 0 ] ) && ( + url [ 1 ] > img . width || + url [ 2 ] > img . height ) ) {
204
+ return false ;
205
+ }
206
+ return true ;
207
+ }
208
+
209
+ login ( url : string ) {
210
+ const res = this . resources [ url ] ;
211
+ if ( res ) {
212
+ res . refCnt ++ ;
213
+ }
214
+ }
215
+
216
+ logout ( url : string ) {
217
+ const res = this . resources [ url ] ;
218
+ if ( res && res . refCnt -- <= 0 ) {
219
+ if ( res . image && res . image . close ) {
220
+ res . image . close ( ) ;
221
+ }
222
+ delete this . resources [ url ] ;
223
+ }
224
+ }
225
+
226
+ getImage ( url : ResourceUrl ) {
227
+ const imgUrl = this . _getImgUrl ( url ) ;
228
+ if ( ! this . isResourceLoaded ( url ) || this . _errors [ imgUrl ] ) {
229
+ return null ;
230
+ }
231
+ return this . resources [ imgUrl ] . image ;
232
+ }
233
+
234
+ markErrorResource ( url : ResourceUrl ) {
235
+ this . _errors [ this . _getImgUrl ( url ) ] = 1 ;
236
+ }
237
+
238
+ merge ( res : any ) {
239
+ if ( ! res ) {
240
+ return this ;
241
+ }
242
+ for ( const p in res . resources ) {
243
+ const img = res . resources [ p ] ;
244
+ this . addResource ( [ p , img . width , img . height ] , img . image ) ;
245
+ }
246
+ return this ;
247
+ }
248
+
249
+ forEach ( fn : ( key : string , value : any ) => void ) {
250
+ if ( ! this . resources ) {
251
+ return this ;
252
+ }
253
+ for ( const p in this . resources ) {
254
+ if ( hasOwn ( this . resources , p ) ) {
255
+ fn ( p , this . resources [ p ] ) ;
256
+ }
257
+ }
258
+ return this ;
259
+ }
260
+
261
+ //@internal
262
+ _getImgUrl ( url : ResourceUrl ) {
263
+ if ( ! Array . isArray ( url ) ) {
264
+ return url ;
265
+ }
266
+ return url [ 0 ] ;
267
+ }
268
+
269
+ remove ( ) {
270
+ for ( const p in this . resources ) {
271
+ const res = this . resources [ p ] ;
272
+ if ( res && res . image && res . image . close ) {
273
+ // close bitmap
274
+ res . image . close ( ) ;
275
+ }
276
+ }
277
+ this . resources = { } ;
278
+ }
279
+ }
280
+
281
+ // Dynamically obtain resource cache instances
282
+ export function getResouceCacheInstance ( ) : ResourceCache {
283
+ if ( Browser . decodeImageInWorker ) {
284
+ return new ResourceCacheMap ( ) as ResourceCache ;
285
+ }
286
+ return new ResourceCache ( ) ;
287
+ }
0 commit comments