1*c8dee2aaSAndroid Build Coastguard Workerdescribe('Skottie behavior', () => { 2*c8dee2aaSAndroid Build Coastguard Worker let container; 3*c8dee2aaSAndroid Build Coastguard Worker 4*c8dee2aaSAndroid Build Coastguard Worker beforeEach(async () => { 5*c8dee2aaSAndroid Build Coastguard Worker await EverythingLoaded; 6*c8dee2aaSAndroid Build Coastguard Worker container = document.createElement('div'); 7*c8dee2aaSAndroid Build Coastguard Worker container.innerHTML = ` 8*c8dee2aaSAndroid Build Coastguard Worker <canvas width=600 height=600 id=test></canvas> 9*c8dee2aaSAndroid Build Coastguard Worker <canvas width=600 height=600 id=report></canvas>`; 10*c8dee2aaSAndroid Build Coastguard Worker document.body.appendChild(container); 11*c8dee2aaSAndroid Build Coastguard Worker }); 12*c8dee2aaSAndroid Build Coastguard Worker 13*c8dee2aaSAndroid Build Coastguard Worker afterEach(() => { 14*c8dee2aaSAndroid Build Coastguard Worker document.body.removeChild(container); 15*c8dee2aaSAndroid Build Coastguard Worker }); 16*c8dee2aaSAndroid Build Coastguard Worker 17*c8dee2aaSAndroid Build Coastguard Worker const expectArrayCloseTo = (a, b, precision) => { 18*c8dee2aaSAndroid Build Coastguard Worker precision = precision || 14; // digits of precision in base 10 19*c8dee2aaSAndroid Build Coastguard Worker expect(a.length).toEqual(b.length); 20*c8dee2aaSAndroid Build Coastguard Worker for (let i=0; i<a.length; i++) { 21*c8dee2aaSAndroid Build Coastguard Worker expect(a[i]).toBeCloseTo(b[i], precision); 22*c8dee2aaSAndroid Build Coastguard Worker } 23*c8dee2aaSAndroid Build Coastguard Worker }; 24*c8dee2aaSAndroid Build Coastguard Worker 25*c8dee2aaSAndroid Build Coastguard Worker const imgPromise = fetch('/assets/flightAnim.gif') 26*c8dee2aaSAndroid Build Coastguard Worker .then((response) => response.arrayBuffer()); 27*c8dee2aaSAndroid Build Coastguard Worker const jsonPromise = fetch('/assets/animated_gif.json') 28*c8dee2aaSAndroid Build Coastguard Worker .then((response) => response.text()); 29*c8dee2aaSAndroid Build Coastguard Worker const washPromise = fetch('/assets/map-shield.json') 30*c8dee2aaSAndroid Build Coastguard Worker .then((response) => response.text()); 31*c8dee2aaSAndroid Build Coastguard Worker const slotPromise = fetch('/assets/skottie_basic_slots.json') 32*c8dee2aaSAndroid Build Coastguard Worker .then((response) => response.text()); 33*c8dee2aaSAndroid Build Coastguard Worker const editPromise = fetch('/assets/text_edit.json') 34*c8dee2aaSAndroid Build Coastguard Worker .then((response) => response.text()); 35*c8dee2aaSAndroid Build Coastguard Worker const inlineFontPromise = fetch('/assets/skottie_inline_font.json') 36*c8dee2aaSAndroid Build Coastguard Worker .then((response) => response.text()); 37*c8dee2aaSAndroid Build Coastguard Worker const notoSerifPromise = fetch('/assets/NotoSerif-Regular.ttf').then( 38*c8dee2aaSAndroid Build Coastguard Worker (response) => response.arrayBuffer()); 39*c8dee2aaSAndroid Build Coastguard Worker 40*c8dee2aaSAndroid Build Coastguard Worker gm('skottie_animgif', (canvas, promises) => { 41*c8dee2aaSAndroid Build Coastguard Worker if (!CanvasKit.skottie || !CanvasKit.managed_skottie) { 42*c8dee2aaSAndroid Build Coastguard Worker console.warn('Skipping test because not compiled with skottie'); 43*c8dee2aaSAndroid Build Coastguard Worker return; 44*c8dee2aaSAndroid Build Coastguard Worker } 45*c8dee2aaSAndroid Build Coastguard Worker expect(promises[1]).not.toBe('NOT FOUND'); 46*c8dee2aaSAndroid Build Coastguard Worker const animation = CanvasKit.MakeManagedAnimation(promises[1], { 47*c8dee2aaSAndroid Build Coastguard Worker 'flightAnim.gif': promises[0], 48*c8dee2aaSAndroid Build Coastguard Worker }); 49*c8dee2aaSAndroid Build Coastguard Worker expect(animation).toBeTruthy(); 50*c8dee2aaSAndroid Build Coastguard Worker const bounds = CanvasKit.LTRBRect(0, 0, 500, 500); 51*c8dee2aaSAndroid Build Coastguard Worker 52*c8dee2aaSAndroid Build Coastguard Worker const size = animation.size(); 53*c8dee2aaSAndroid Build Coastguard Worker expectArrayCloseTo(size, Float32Array.of(800, 600), 4); 54*c8dee2aaSAndroid Build Coastguard Worker 55*c8dee2aaSAndroid Build Coastguard Worker animation.render(canvas, bounds); 56*c8dee2aaSAndroid Build Coastguard Worker 57*c8dee2aaSAndroid Build Coastguard Worker // We intentionally make the length of this array 5 and add a sentinel value 58*c8dee2aaSAndroid Build Coastguard Worker // of 999 so we can make sure the bounds are copied into this rect and a new 59*c8dee2aaSAndroid Build Coastguard Worker // one is not allocated. 60*c8dee2aaSAndroid Build Coastguard Worker const damageRect = Float32Array.of(0, 0, 0, 0, 999); 61*c8dee2aaSAndroid Build Coastguard Worker 62*c8dee2aaSAndroid Build Coastguard Worker // There was a bug, fixed in https://skia-review.googlesource.com/c/skia/+/241757 63*c8dee2aaSAndroid Build Coastguard Worker // that seeking again and drawing again revealed. 64*c8dee2aaSAndroid Build Coastguard Worker animation.seek(0.5, damageRect); 65*c8dee2aaSAndroid Build Coastguard Worker expectArrayCloseTo(damageRect, Float32Array.of(0, 0, 800, 600, 999), 4); 66*c8dee2aaSAndroid Build Coastguard Worker 67*c8dee2aaSAndroid Build Coastguard Worker canvas.clear(CanvasKit.WHITE); 68*c8dee2aaSAndroid Build Coastguard Worker animation.render(canvas, bounds); 69*c8dee2aaSAndroid Build Coastguard Worker animation.delete(); 70*c8dee2aaSAndroid Build Coastguard Worker }, imgPromise, jsonPromise); 71*c8dee2aaSAndroid Build Coastguard Worker 72*c8dee2aaSAndroid Build Coastguard Worker gm('skottie_setcolor', (canvas, promises) => { 73*c8dee2aaSAndroid Build Coastguard Worker if (!CanvasKit.skottie || !CanvasKit.managed_skottie) { 74*c8dee2aaSAndroid Build Coastguard Worker console.warn('Skipping test because not compiled with skottie'); 75*c8dee2aaSAndroid Build Coastguard Worker return; 76*c8dee2aaSAndroid Build Coastguard Worker } 77*c8dee2aaSAndroid Build Coastguard Worker expect(promises[0]).not.toBe('NOT FOUND'); 78*c8dee2aaSAndroid Build Coastguard Worker const bounds = CanvasKit.LTRBRect(0, 0, 500, 500); 79*c8dee2aaSAndroid Build Coastguard Worker 80*c8dee2aaSAndroid Build Coastguard Worker const animation = CanvasKit.MakeManagedAnimation(promises[0]); 81*c8dee2aaSAndroid Build Coastguard Worker expect(animation).toBeTruthy(); 82*c8dee2aaSAndroid Build Coastguard Worker animation.setColor('$Icon Fill', CanvasKit.RED); 83*c8dee2aaSAndroid Build Coastguard Worker animation.seek(0.5); 84*c8dee2aaSAndroid Build Coastguard Worker animation.render(canvas, bounds); 85*c8dee2aaSAndroid Build Coastguard Worker animation.delete(); 86*c8dee2aaSAndroid Build Coastguard Worker }, washPromise); 87*c8dee2aaSAndroid Build Coastguard Worker 88*c8dee2aaSAndroid Build Coastguard Worker gm('skottie_slots', (canvas, promises) => { 89*c8dee2aaSAndroid Build Coastguard Worker if (!CanvasKit.skottie || !CanvasKit.managed_skottie) { 90*c8dee2aaSAndroid Build Coastguard Worker console.warn('Skipping test because not compiled with skottie'); 91*c8dee2aaSAndroid Build Coastguard Worker return; 92*c8dee2aaSAndroid Build Coastguard Worker } 93*c8dee2aaSAndroid Build Coastguard Worker expect(promises[0]).not.toBe('NOT FOUND'); 94*c8dee2aaSAndroid Build Coastguard Worker const bounds = CanvasKit.LTRBRect(0, 0, 500, 500); 95*c8dee2aaSAndroid Build Coastguard Worker 96*c8dee2aaSAndroid Build Coastguard Worker const animation = CanvasKit.MakeManagedAnimation(promises[0], { 97*c8dee2aaSAndroid Build Coastguard Worker 'flightAnim.gif': promises[1], 98*c8dee2aaSAndroid Build Coastguard Worker 'NotoSerif': promises[2], 99*c8dee2aaSAndroid Build Coastguard Worker }); 100*c8dee2aaSAndroid Build Coastguard Worker expect(animation).toBeTruthy(); 101*c8dee2aaSAndroid Build Coastguard Worker 102*c8dee2aaSAndroid Build Coastguard Worker const slotInfo = animation.getSlotInfo(); 103*c8dee2aaSAndroid Build Coastguard Worker expect(slotInfo.colorSlotIDs).toEqual(['FillsGroup', 'StrokeGroup']); 104*c8dee2aaSAndroid Build Coastguard Worker expect(slotInfo.scalarSlotIDs).toEqual(['Opacity']); 105*c8dee2aaSAndroid Build Coastguard Worker expect(slotInfo.vec2SlotIDs).toEqual(['ScaleGroup']); 106*c8dee2aaSAndroid Build Coastguard Worker expect(slotInfo.imageSlotIDs).toEqual(['ImageSource']); 107*c8dee2aaSAndroid Build Coastguard Worker expect(slotInfo.textSlotIDs).toEqual(['TextSource']); 108*c8dee2aaSAndroid Build Coastguard Worker 109*c8dee2aaSAndroid Build Coastguard Worker expect(animation.getScalarSlot('Opacity')).toBe(100); 110*c8dee2aaSAndroid Build Coastguard Worker const textProp = animation.getTextSlot('TextSource'); 111*c8dee2aaSAndroid Build Coastguard Worker expect(textProp.text).toBe('text slots'); 112*c8dee2aaSAndroid Build Coastguard Worker 113*c8dee2aaSAndroid Build Coastguard Worker textProp.text = 'new text'; 114*c8dee2aaSAndroid Build Coastguard Worker textProp.fillColor = CanvasKit.CYAN; 115*c8dee2aaSAndroid Build Coastguard Worker textProp.strokeColor = CanvasKit.MAGENTA; 116*c8dee2aaSAndroid Build Coastguard Worker 117*c8dee2aaSAndroid Build Coastguard Worker expect(animation.setColorSlot('FillsGroup', CanvasKit.RED)).toBeTruthy(); 118*c8dee2aaSAndroid Build Coastguard Worker expect(animation.setScalarSlot('Opacity', 25)).toBeTruthy(); 119*c8dee2aaSAndroid Build Coastguard Worker expect(animation.setVec2Slot('ScaleGroup', [25, 50])).toBeTruthy(); 120*c8dee2aaSAndroid Build Coastguard Worker expect(animation.setImageSlot('ImageSource', 'flighAnim.gif')).toBeTruthy(); 121*c8dee2aaSAndroid Build Coastguard Worker expect(animation.setTextSlot('TextSource', textProp)).toBeTruthy(); 122*c8dee2aaSAndroid Build Coastguard Worker 123*c8dee2aaSAndroid Build Coastguard Worker expectArrayCloseTo(animation.getColorSlot('FillsGroup'), CanvasKit.RED, 4); 124*c8dee2aaSAndroid Build Coastguard Worker expect(animation.getScalarSlot('Opacity')).toBe(25); 125*c8dee2aaSAndroid Build Coastguard Worker expectArrayCloseTo(animation.getVec2Slot('ScaleGroup'), [25, 50], 4); 126*c8dee2aaSAndroid Build Coastguard Worker 127*c8dee2aaSAndroid Build Coastguard Worker const newTextSlot = animation.getTextSlot('TextSource'); 128*c8dee2aaSAndroid Build Coastguard Worker expect(newTextSlot.text).toBe('new text'); 129*c8dee2aaSAndroid Build Coastguard Worker expectArrayCloseTo(newTextSlot.fillColor, CanvasKit.CYAN, 4); 130*c8dee2aaSAndroid Build Coastguard Worker expectArrayCloseTo(newTextSlot.strokeColor, CanvasKit.MAGENTA, 4); 131*c8dee2aaSAndroid Build Coastguard Worker 132*c8dee2aaSAndroid Build Coastguard Worker expect(animation.getColorSlot('Bad ID')).toBeFalsy(); 133*c8dee2aaSAndroid Build Coastguard Worker expect(animation.getScalarSlot('Bad ID')).toBeFalsy(); 134*c8dee2aaSAndroid Build Coastguard Worker expect(animation.getVec2Slot('Bad ID')).toBeFalsy(); 135*c8dee2aaSAndroid Build Coastguard Worker expect(animation.getTextSlot('Bad ID')).toBeFalsy(); 136*c8dee2aaSAndroid Build Coastguard Worker 137*c8dee2aaSAndroid Build Coastguard Worker animation.seek(0.5); 138*c8dee2aaSAndroid Build Coastguard Worker animation.render(canvas, bounds); 139*c8dee2aaSAndroid Build Coastguard Worker animation.delete(); 140*c8dee2aaSAndroid Build Coastguard Worker }, slotPromise, imgPromise, notoSerifPromise); 141*c8dee2aaSAndroid Build Coastguard Worker 142*c8dee2aaSAndroid Build Coastguard Worker gm('skottie_textedit', (canvas, promises) => { 143*c8dee2aaSAndroid Build Coastguard Worker if (!CanvasKit.skottie || !CanvasKit.managed_skottie) { 144*c8dee2aaSAndroid Build Coastguard Worker console.warn('Skipping test because not compiled with skottie'); 145*c8dee2aaSAndroid Build Coastguard Worker return; 146*c8dee2aaSAndroid Build Coastguard Worker } 147*c8dee2aaSAndroid Build Coastguard Worker expect(promises[0]).not.toBe('NOT FOUND'); 148*c8dee2aaSAndroid Build Coastguard Worker const bounds = CanvasKit.LTRBRect(0, 0, 600, 600); 149*c8dee2aaSAndroid Build Coastguard Worker 150*c8dee2aaSAndroid Build Coastguard Worker const animation = CanvasKit.MakeManagedAnimation(promises[0], { 151*c8dee2aaSAndroid Build Coastguard Worker // The animation is looking for a font called ArialMT, but we just 152*c8dee2aaSAndroid Build Coastguard Worker // provide it the data for an arbitrary typeface. 153*c8dee2aaSAndroid Build Coastguard Worker "ArialMT": promises[1], 154*c8dee2aaSAndroid Build Coastguard Worker }); 155*c8dee2aaSAndroid Build Coastguard Worker expect(animation).toBeTruthy(); 156*c8dee2aaSAndroid Build Coastguard Worker 157*c8dee2aaSAndroid Build Coastguard Worker // The animation contains two text layers grouped under the "text_layer" ID, and one 158*c8dee2aaSAndroid Build Coastguard Worker // descriptive text layer. 159*c8dee2aaSAndroid Build Coastguard Worker { 160*c8dee2aaSAndroid Build Coastguard Worker const texts = animation.getTextProps(); 161*c8dee2aaSAndroid Build Coastguard Worker expect(texts.length).toEqual(2); 162*c8dee2aaSAndroid Build Coastguard Worker expect(texts[0].key).toEqual('text_layer'); 163*c8dee2aaSAndroid Build Coastguard Worker expect(texts[0].value.text).toEqual('foo'); 164*c8dee2aaSAndroid Build Coastguard Worker } 165*c8dee2aaSAndroid Build Coastguard Worker 166*c8dee2aaSAndroid Build Coastguard Worker expect(animation.attachEditor('txt_layer', 0)).toBeFalse(); // nonexistent layer 167*c8dee2aaSAndroid Build Coastguard Worker expect(animation.attachEditor('text_layer', 2)).toBeFalse(); // nonexistent index 168*c8dee2aaSAndroid Build Coastguard Worker expect(animation.attachEditor('text_layer', 0)).toBeTrue(); 169*c8dee2aaSAndroid Build Coastguard Worker expect(animation.attachEditor('text_layer', 1)).toBeTrue(); 170*c8dee2aaSAndroid Build Coastguard Worker 171*c8dee2aaSAndroid Build Coastguard Worker { 172*c8dee2aaSAndroid Build Coastguard Worker // no effect, editor inactive 173*c8dee2aaSAndroid Build Coastguard Worker expect(animation.dispatchEditorKey('Backspace')).toBeFalse(); 174*c8dee2aaSAndroid Build Coastguard Worker 175*c8dee2aaSAndroid Build Coastguard Worker const texts = animation.getTextProps(); 176*c8dee2aaSAndroid Build Coastguard Worker expect(texts.length).toEqual(2); 177*c8dee2aaSAndroid Build Coastguard Worker expect(texts[0].key).toEqual('text_layer'); 178*c8dee2aaSAndroid Build Coastguard Worker expect(texts[0].value.text).toEqual('foo'); 179*c8dee2aaSAndroid Build Coastguard Worker } 180*c8dee2aaSAndroid Build Coastguard Worker 181*c8dee2aaSAndroid Build Coastguard Worker animation.enableEditor(true); 182*c8dee2aaSAndroid Build Coastguard Worker animation.setEditorCursorWeight(1.5); 183*c8dee2aaSAndroid Build Coastguard Worker 184*c8dee2aaSAndroid Build Coastguard Worker // To be fully functional, the editor requires glyph data issued during rendering callbacks. 185*c8dee2aaSAndroid Build Coastguard Worker animation.seek(0); 186*c8dee2aaSAndroid Build Coastguard Worker animation.render(canvas, bounds); 187*c8dee2aaSAndroid Build Coastguard Worker 188*c8dee2aaSAndroid Build Coastguard Worker { 189*c8dee2aaSAndroid Build Coastguard Worker expect(animation.dispatchEditorKey('Backspace')).toBeTrue(); 190*c8dee2aaSAndroid Build Coastguard Worker expect(animation.dispatchEditorKey('Backspace')).toBeTrue(); 191*c8dee2aaSAndroid Build Coastguard Worker expect(animation.dispatchEditorKey('Backspace')).toBeTrue(); 192*c8dee2aaSAndroid Build Coastguard Worker expect(animation.dispatchEditorKey('b')).toBeTrue(); 193*c8dee2aaSAndroid Build Coastguard Worker expect(animation.dispatchEditorKey('a')).toBeTrue(); 194*c8dee2aaSAndroid Build Coastguard Worker expect(animation.dispatchEditorKey('r')).toBeTrue(); 195*c8dee2aaSAndroid Build Coastguard Worker 196*c8dee2aaSAndroid Build Coastguard Worker const texts = animation.getTextProps(); 197*c8dee2aaSAndroid Build Coastguard Worker expect(texts.length).toEqual(2); 198*c8dee2aaSAndroid Build Coastguard Worker expect(texts[0].key).toEqual('text_layer'); 199*c8dee2aaSAndroid Build Coastguard Worker expect(texts[0].value.text).toEqual('bar'); 200*c8dee2aaSAndroid Build Coastguard Worker } 201*c8dee2aaSAndroid Build Coastguard Worker 202*c8dee2aaSAndroid Build Coastguard Worker // Final render, after edits. 203*c8dee2aaSAndroid Build Coastguard Worker animation.seek(0); 204*c8dee2aaSAndroid Build Coastguard Worker animation.render(canvas, bounds); 205*c8dee2aaSAndroid Build Coastguard Worker animation.delete(); 206*c8dee2aaSAndroid Build Coastguard Worker }, editPromise, notoSerifPromise); 207*c8dee2aaSAndroid Build Coastguard Worker 208*c8dee2aaSAndroid Build Coastguard Worker gm('skottie_inlinefont', (canvas, promises) => { 209*c8dee2aaSAndroid Build Coastguard Worker if (!CanvasKit.skottie || !CanvasKit.managed_skottie) { 210*c8dee2aaSAndroid Build Coastguard Worker console.warn('Skipping test because not compiled with skottie'); 211*c8dee2aaSAndroid Build Coastguard Worker return; 212*c8dee2aaSAndroid Build Coastguard Worker } 213*c8dee2aaSAndroid Build Coastguard Worker expect(promises[0]).not.toBe('NOT FOUND'); 214*c8dee2aaSAndroid Build Coastguard Worker const bounds = CanvasKit.LTRBRect(0, 0, 600, 600); 215*c8dee2aaSAndroid Build Coastguard Worker 216*c8dee2aaSAndroid Build Coastguard Worker const animation = CanvasKit.MakeManagedAnimation(promises[0]); 217*c8dee2aaSAndroid Build Coastguard Worker expect(animation).toBeTruthy(); 218*c8dee2aaSAndroid Build Coastguard Worker 219*c8dee2aaSAndroid Build Coastguard Worker animation.seek(0); 220*c8dee2aaSAndroid Build Coastguard Worker animation.render(canvas, bounds); 221*c8dee2aaSAndroid Build Coastguard Worker animation.delete(); 222*c8dee2aaSAndroid Build Coastguard Worker }, inlineFontPromise); 223*c8dee2aaSAndroid Build Coastguard Worker 224*c8dee2aaSAndroid Build Coastguard Worker it('can load audio assets', (done) => { 225*c8dee2aaSAndroid Build Coastguard Worker if (!CanvasKit.skottie || !CanvasKit.managed_skottie) { 226*c8dee2aaSAndroid Build Coastguard Worker console.warn('Skipping test because not compiled with skottie'); 227*c8dee2aaSAndroid Build Coastguard Worker return; 228*c8dee2aaSAndroid Build Coastguard Worker } 229*c8dee2aaSAndroid Build Coastguard Worker const mockSoundMap = { 230*c8dee2aaSAndroid Build Coastguard Worker map : new Map(), 231*c8dee2aaSAndroid Build Coastguard Worker getPlayer : function(name) {return this.map.get(name)}, 232*c8dee2aaSAndroid Build Coastguard Worker setPlayer : function(name, player) {this.map.set(name, player)}, 233*c8dee2aaSAndroid Build Coastguard Worker }; 234*c8dee2aaSAndroid Build Coastguard Worker function mockPlayer(name) { 235*c8dee2aaSAndroid Build Coastguard Worker this.name = name; 236*c8dee2aaSAndroid Build Coastguard Worker this.wasPlayed = false, 237*c8dee2aaSAndroid Build Coastguard Worker this.seek = function(t) { 238*c8dee2aaSAndroid Build Coastguard Worker this.wasPlayed = true; 239*c8dee2aaSAndroid Build Coastguard Worker } 240*c8dee2aaSAndroid Build Coastguard Worker } 241*c8dee2aaSAndroid Build Coastguard Worker for (let i = 0; i < 20; i++) { 242*c8dee2aaSAndroid Build Coastguard Worker var name = 'audio_' + i; 243*c8dee2aaSAndroid Build Coastguard Worker mockSoundMap.setPlayer(name, new mockPlayer(name)); 244*c8dee2aaSAndroid Build Coastguard Worker } 245*c8dee2aaSAndroid Build Coastguard Worker fetch('/assets/audio_external.json') 246*c8dee2aaSAndroid Build Coastguard Worker .then((response) => response.text()) 247*c8dee2aaSAndroid Build Coastguard Worker .then((lottie) => { 248*c8dee2aaSAndroid Build Coastguard Worker const animation = CanvasKit.MakeManagedAnimation(lottie, null, null, mockSoundMap); 249*c8dee2aaSAndroid Build Coastguard Worker expect(animation).toBeTruthy(); 250*c8dee2aaSAndroid Build Coastguard Worker // 190 frames in sample lottie 251*c8dee2aaSAndroid Build Coastguard Worker for (let t = 0; t < 190; t++) { 252*c8dee2aaSAndroid Build Coastguard Worker animation.seekFrame(t); 253*c8dee2aaSAndroid Build Coastguard Worker } 254*c8dee2aaSAndroid Build Coastguard Worker animation.delete(); 255*c8dee2aaSAndroid Build Coastguard Worker for(const player of mockSoundMap.map.values()) { 256*c8dee2aaSAndroid Build Coastguard Worker expect(player.wasPlayed).toBeTrue(player.name + " was not played"); 257*c8dee2aaSAndroid Build Coastguard Worker } 258*c8dee2aaSAndroid Build Coastguard Worker done(); 259*c8dee2aaSAndroid Build Coastguard Worker }); 260*c8dee2aaSAndroid Build Coastguard Worker }); 261*c8dee2aaSAndroid Build Coastguard Worker 262*c8dee2aaSAndroid Build Coastguard Worker it('can get logs', (done) => { 263*c8dee2aaSAndroid Build Coastguard Worker if (!CanvasKit.skottie || !CanvasKit.managed_skottie) { 264*c8dee2aaSAndroid Build Coastguard Worker console.warn('Skipping test because not compiled with skottie'); 265*c8dee2aaSAndroid Build Coastguard Worker return; 266*c8dee2aaSAndroid Build Coastguard Worker } 267*c8dee2aaSAndroid Build Coastguard Worker 268*c8dee2aaSAndroid Build Coastguard Worker const logger = { 269*c8dee2aaSAndroid Build Coastguard Worker errors: [], 270*c8dee2aaSAndroid Build Coastguard Worker warnings: [], 271*c8dee2aaSAndroid Build Coastguard Worker 272*c8dee2aaSAndroid Build Coastguard Worker reset: function() { this.errors = []; this.warnings = []; }, 273*c8dee2aaSAndroid Build Coastguard Worker 274*c8dee2aaSAndroid Build Coastguard Worker // Logger API 275*c8dee2aaSAndroid Build Coastguard Worker onError: function(err) { this.errors.push(err) }, 276*c8dee2aaSAndroid Build Coastguard Worker onWarning: function(wrn) { this.warnings.push(wrn) } 277*c8dee2aaSAndroid Build Coastguard Worker }; 278*c8dee2aaSAndroid Build Coastguard Worker 279*c8dee2aaSAndroid Build Coastguard Worker { 280*c8dee2aaSAndroid Build Coastguard Worker const json = `{ 281*c8dee2aaSAndroid Build Coastguard Worker "v": "5.2.1", 282*c8dee2aaSAndroid Build Coastguard Worker "w": 100, 283*c8dee2aaSAndroid Build Coastguard Worker "h": 100, 284*c8dee2aaSAndroid Build Coastguard Worker "fr": 10, 285*c8dee2aaSAndroid Build Coastguard Worker "ip": 0, 286*c8dee2aaSAndroid Build Coastguard Worker "op": 100, 287*c8dee2aaSAndroid Build Coastguard Worker "layers": [{ 288*c8dee2aaSAndroid Build Coastguard Worker "ty": 3, 289*c8dee2aaSAndroid Build Coastguard Worker "nm": "null", 290*c8dee2aaSAndroid Build Coastguard Worker "ind": 0, 291*c8dee2aaSAndroid Build Coastguard Worker "ip": 0 292*c8dee2aaSAndroid Build Coastguard Worker }] 293*c8dee2aaSAndroid Build Coastguard Worker }`; 294*c8dee2aaSAndroid Build Coastguard Worker const animation = CanvasKit.MakeManagedAnimation(json, null, null, null, logger); 295*c8dee2aaSAndroid Build Coastguard Worker expect(animation).toBeTruthy(); 296*c8dee2aaSAndroid Build Coastguard Worker expect(logger.errors.length).toEqual(0); 297*c8dee2aaSAndroid Build Coastguard Worker expect(logger.warnings.length).toEqual(0); 298*c8dee2aaSAndroid Build Coastguard Worker } 299*c8dee2aaSAndroid Build Coastguard Worker 300*c8dee2aaSAndroid Build Coastguard Worker { 301*c8dee2aaSAndroid Build Coastguard Worker const json = `{ 302*c8dee2aaSAndroid Build Coastguard Worker "v": "5.2.1", 303*c8dee2aaSAndroid Build Coastguard Worker "w": 100, 304*c8dee2aaSAndroid Build Coastguard Worker "h": 100, 305*c8dee2aaSAndroid Build Coastguard Worker "fr": 10, 306*c8dee2aaSAndroid Build Coastguard Worker "ip": 0, 307*c8dee2aaSAndroid Build Coastguard Worker "op": 100, 308*c8dee2aaSAndroid Build Coastguard Worker "layers": [{ 309*c8dee2aaSAndroid Build Coastguard Worker "ty": 2, 310*c8dee2aaSAndroid Build Coastguard Worker "nm": "image", 311*c8dee2aaSAndroid Build Coastguard Worker "ind": 0, 312*c8dee2aaSAndroid Build Coastguard Worker "ip": 0 313*c8dee2aaSAndroid Build Coastguard Worker }] 314*c8dee2aaSAndroid Build Coastguard Worker }`; 315*c8dee2aaSAndroid Build Coastguard Worker const animation = CanvasKit.MakeManagedAnimation(json, null, null, null, logger); 316*c8dee2aaSAndroid Build Coastguard Worker expect(animation).toBeTruthy(); 317*c8dee2aaSAndroid Build Coastguard Worker expect(logger.errors.length).toEqual(1); 318*c8dee2aaSAndroid Build Coastguard Worker expect(logger.warnings.length).toEqual(0); 319*c8dee2aaSAndroid Build Coastguard Worker 320*c8dee2aaSAndroid Build Coastguard Worker // Image layer missing refID 321*c8dee2aaSAndroid Build Coastguard Worker expect(logger.errors[0].includes('missing ref')); 322*c8dee2aaSAndroid Build Coastguard Worker logger.reset(); 323*c8dee2aaSAndroid Build Coastguard Worker } 324*c8dee2aaSAndroid Build Coastguard Worker 325*c8dee2aaSAndroid Build Coastguard Worker { 326*c8dee2aaSAndroid Build Coastguard Worker const json = `{ 327*c8dee2aaSAndroid Build Coastguard Worker "v": "5.2.1", 328*c8dee2aaSAndroid Build Coastguard Worker "w": 100, 329*c8dee2aaSAndroid Build Coastguard Worker "h": 100, 330*c8dee2aaSAndroid Build Coastguard Worker "fr": 10, 331*c8dee2aaSAndroid Build Coastguard Worker "ip": 0, 332*c8dee2aaSAndroid Build Coastguard Worker "op": 100, 333*c8dee2aaSAndroid Build Coastguard Worker "layers": [{ 334*c8dee2aaSAndroid Build Coastguard Worker "ty": 1, 335*c8dee2aaSAndroid Build Coastguard Worker "nm": "solid", 336*c8dee2aaSAndroid Build Coastguard Worker "sw": 100, 337*c8dee2aaSAndroid Build Coastguard Worker "sh": 100, 338*c8dee2aaSAndroid Build Coastguard Worker "sc": "#aabbcc", 339*c8dee2aaSAndroid Build Coastguard Worker "ind": 0, 340*c8dee2aaSAndroid Build Coastguard Worker "ip": 0, 341*c8dee2aaSAndroid Build Coastguard Worker "ef": [{ 342*c8dee2aaSAndroid Build Coastguard Worker "mn": "FOO" 343*c8dee2aaSAndroid Build Coastguard Worker }] 344*c8dee2aaSAndroid Build Coastguard Worker }] 345*c8dee2aaSAndroid Build Coastguard Worker }`; 346*c8dee2aaSAndroid Build Coastguard Worker const animation = CanvasKit.MakeManagedAnimation(json, null, null, null, logger); 347*c8dee2aaSAndroid Build Coastguard Worker expect(animation).toBeTruthy(); 348*c8dee2aaSAndroid Build Coastguard Worker expect(logger.errors.length).toEqual(0); 349*c8dee2aaSAndroid Build Coastguard Worker expect(logger.warnings.length).toEqual(1); 350*c8dee2aaSAndroid Build Coastguard Worker 351*c8dee2aaSAndroid Build Coastguard Worker // Unsupported effect FOO 352*c8dee2aaSAndroid Build Coastguard Worker expect(logger.warnings[0].includes('FOO')); 353*c8dee2aaSAndroid Build Coastguard Worker logger.reset(); 354*c8dee2aaSAndroid Build Coastguard Worker } 355*c8dee2aaSAndroid Build Coastguard Worker 356*c8dee2aaSAndroid Build Coastguard Worker done(); 357*c8dee2aaSAndroid Build Coastguard Worker }); 358*c8dee2aaSAndroid Build Coastguard Worker 359*c8dee2aaSAndroid Build Coastguard Worker it('can access dynamic props', () => { 360*c8dee2aaSAndroid Build Coastguard Worker if (!CanvasKit.skottie || !CanvasKit.managed_skottie) { 361*c8dee2aaSAndroid Build Coastguard Worker console.warn('Skipping test because not compiled with skottie'); 362*c8dee2aaSAndroid Build Coastguard Worker return; 363*c8dee2aaSAndroid Build Coastguard Worker } 364*c8dee2aaSAndroid Build Coastguard Worker 365*c8dee2aaSAndroid Build Coastguard Worker const json = `{ 366*c8dee2aaSAndroid Build Coastguard Worker "v": "5.2.1", 367*c8dee2aaSAndroid Build Coastguard Worker "w": 100, 368*c8dee2aaSAndroid Build Coastguard Worker "h": 100, 369*c8dee2aaSAndroid Build Coastguard Worker "fr": 10, 370*c8dee2aaSAndroid Build Coastguard Worker "ip": 0, 371*c8dee2aaSAndroid Build Coastguard Worker "op": 100, 372*c8dee2aaSAndroid Build Coastguard Worker "fonts": { 373*c8dee2aaSAndroid Build Coastguard Worker "list": [{ 374*c8dee2aaSAndroid Build Coastguard Worker "fName": "test_font", 375*c8dee2aaSAndroid Build Coastguard Worker "fFamily": "test-family", 376*c8dee2aaSAndroid Build Coastguard Worker "fStyle": "TestFontStyle" 377*c8dee2aaSAndroid Build Coastguard Worker }] 378*c8dee2aaSAndroid Build Coastguard Worker }, 379*c8dee2aaSAndroid Build Coastguard Worker "layers": [ 380*c8dee2aaSAndroid Build Coastguard Worker { 381*c8dee2aaSAndroid Build Coastguard Worker "ty": 4, 382*c8dee2aaSAndroid Build Coastguard Worker "nm": "__shape_layer", 383*c8dee2aaSAndroid Build Coastguard Worker "ind": 0, 384*c8dee2aaSAndroid Build Coastguard Worker "ip": 0, 385*c8dee2aaSAndroid Build Coastguard Worker "shapes": [ 386*c8dee2aaSAndroid Build Coastguard Worker { 387*c8dee2aaSAndroid Build Coastguard Worker "ty": "el", 388*c8dee2aaSAndroid Build Coastguard Worker "p": { "a": 0, "k": [ 50, 50 ] }, 389*c8dee2aaSAndroid Build Coastguard Worker "s": { "a": 0, "k": [ 50, 50 ] } 390*c8dee2aaSAndroid Build Coastguard Worker },{ 391*c8dee2aaSAndroid Build Coastguard Worker "ty": "fl", 392*c8dee2aaSAndroid Build Coastguard Worker "nm": "__shape_fill", 393*c8dee2aaSAndroid Build Coastguard Worker "c": { "a": 0, "k": [ 1, 0, 0] } 394*c8dee2aaSAndroid Build Coastguard Worker },{ 395*c8dee2aaSAndroid Build Coastguard Worker "ty": "tr", 396*c8dee2aaSAndroid Build Coastguard Worker "nm": "__shape_opacity", 397*c8dee2aaSAndroid Build Coastguard Worker "o": { "a": 0, "k": 50 } 398*c8dee2aaSAndroid Build Coastguard Worker } 399*c8dee2aaSAndroid Build Coastguard Worker ] 400*c8dee2aaSAndroid Build Coastguard Worker },{ 401*c8dee2aaSAndroid Build Coastguard Worker "ty": 5, 402*c8dee2aaSAndroid Build Coastguard Worker "nm": "__text_layer", 403*c8dee2aaSAndroid Build Coastguard Worker "ip": 0, 404*c8dee2aaSAndroid Build Coastguard Worker "t": { 405*c8dee2aaSAndroid Build Coastguard Worker "d": { 406*c8dee2aaSAndroid Build Coastguard Worker "k": [{ 407*c8dee2aaSAndroid Build Coastguard Worker "t": 0, 408*c8dee2aaSAndroid Build Coastguard Worker "s": { 409*c8dee2aaSAndroid Build Coastguard Worker "f": "test_font", 410*c8dee2aaSAndroid Build Coastguard Worker "s": 100, 411*c8dee2aaSAndroid Build Coastguard Worker "t": "Foo Bar Baz", 412*c8dee2aaSAndroid Build Coastguard Worker "lh": 120, 413*c8dee2aaSAndroid Build Coastguard Worker "ls": 12 414*c8dee2aaSAndroid Build Coastguard Worker } 415*c8dee2aaSAndroid Build Coastguard Worker }] 416*c8dee2aaSAndroid Build Coastguard Worker } 417*c8dee2aaSAndroid Build Coastguard Worker } 418*c8dee2aaSAndroid Build Coastguard Worker } 419*c8dee2aaSAndroid Build Coastguard Worker ] 420*c8dee2aaSAndroid Build Coastguard Worker }`; 421*c8dee2aaSAndroid Build Coastguard Worker 422*c8dee2aaSAndroid Build Coastguard Worker const animation = CanvasKit.MakeManagedAnimation(json, null, '__'); 423*c8dee2aaSAndroid Build Coastguard Worker expect(animation).toBeTruthy(); 424*c8dee2aaSAndroid Build Coastguard Worker 425*c8dee2aaSAndroid Build Coastguard Worker { 426*c8dee2aaSAndroid Build Coastguard Worker const colors = animation.getColorProps(); 427*c8dee2aaSAndroid Build Coastguard Worker expect(colors.length).toEqual(1); 428*c8dee2aaSAndroid Build Coastguard Worker expect(colors[0].key).toEqual('__shape_fill'); 429*c8dee2aaSAndroid Build Coastguard Worker expect(colors[0].value).toEqual(CanvasKit.ColorAsInt(255,0,0,255)); 430*c8dee2aaSAndroid Build Coastguard Worker 431*c8dee2aaSAndroid Build Coastguard Worker const opacities = animation.getOpacityProps(); 432*c8dee2aaSAndroid Build Coastguard Worker expect(opacities.length).toEqual(1); 433*c8dee2aaSAndroid Build Coastguard Worker expect(opacities[0].key).toEqual('__shape_opacity'); 434*c8dee2aaSAndroid Build Coastguard Worker expect(opacities[0].value).toEqual(50); 435*c8dee2aaSAndroid Build Coastguard Worker 436*c8dee2aaSAndroid Build Coastguard Worker const texts = animation.getTextProps(); 437*c8dee2aaSAndroid Build Coastguard Worker expect(texts.length).toEqual(1); 438*c8dee2aaSAndroid Build Coastguard Worker expect(texts[0].key).toEqual('__text_layer'); 439*c8dee2aaSAndroid Build Coastguard Worker expect(texts[0].value.text).toEqual('Foo Bar Baz'); 440*c8dee2aaSAndroid Build Coastguard Worker expect(texts[0].value.size).toEqual(100); 441*c8dee2aaSAndroid Build Coastguard Worker } 442*c8dee2aaSAndroid Build Coastguard Worker 443*c8dee2aaSAndroid Build Coastguard Worker expect(animation.setColor('__shape_fill', [0,1,0,1])).toEqual(true); 444*c8dee2aaSAndroid Build Coastguard Worker expect(animation.setOpacity('__shape_opacity', 100)).toEqual(true); 445*c8dee2aaSAndroid Build Coastguard Worker expect(animation.setText('__text_layer', 'baz bar foo', 10)).toEqual(true); 446*c8dee2aaSAndroid Build Coastguard Worker 447*c8dee2aaSAndroid Build Coastguard Worker { 448*c8dee2aaSAndroid Build Coastguard Worker const colors = animation.getColorProps(); 449*c8dee2aaSAndroid Build Coastguard Worker expect(colors.length).toEqual(1); 450*c8dee2aaSAndroid Build Coastguard Worker expect(colors[0].key).toEqual('__shape_fill'); 451*c8dee2aaSAndroid Build Coastguard Worker expect(colors[0].value).toEqual(CanvasKit.ColorAsInt(0,255,0,255)); 452*c8dee2aaSAndroid Build Coastguard Worker 453*c8dee2aaSAndroid Build Coastguard Worker const opacities = animation.getOpacityProps(); 454*c8dee2aaSAndroid Build Coastguard Worker expect(opacities.length).toEqual(1); 455*c8dee2aaSAndroid Build Coastguard Worker expect(opacities[0].key).toEqual('__shape_opacity'); 456*c8dee2aaSAndroid Build Coastguard Worker expect(opacities[0].value).toEqual(100); 457*c8dee2aaSAndroid Build Coastguard Worker 458*c8dee2aaSAndroid Build Coastguard Worker const texts = animation.getTextProps(); 459*c8dee2aaSAndroid Build Coastguard Worker expect(texts.length).toEqual(1); 460*c8dee2aaSAndroid Build Coastguard Worker expect(texts[0].key).toEqual('__text_layer'); 461*c8dee2aaSAndroid Build Coastguard Worker expect(texts[0].value.text).toEqual('baz bar foo'); 462*c8dee2aaSAndroid Build Coastguard Worker expect(texts[0].value.size).toEqual(10); 463*c8dee2aaSAndroid Build Coastguard Worker } 464*c8dee2aaSAndroid Build Coastguard Worker 465*c8dee2aaSAndroid Build Coastguard Worker expect(animation.setColor('INVALID_KEY', [0,1,0,1])).toEqual(false); 466*c8dee2aaSAndroid Build Coastguard Worker expect(animation.setOpacity('INVALID_KEY', 100)).toEqual(false); 467*c8dee2aaSAndroid Build Coastguard Worker expect(animation.setText('INVALID KEY', '', 10)).toEqual(false); 468*c8dee2aaSAndroid Build Coastguard Worker }); 469*c8dee2aaSAndroid Build Coastguard Worker}); 470