1fc0c1c0f8
This CL makes a copy of all the files in //modules/canvaskit/tests/ and puts them into //modules/canvaskit/tests/bazel. They are slightly modified to run in Bazel (renamed to be more clear what they are and using EverythingLoaded instead of CanvasKitLoaded). The original files will be deleted when we no longer test CanvasKit outside of Bazel. Suggested Review Order: - hello_world.js is now smoke_test.js. That test polls the gold_test_env server, but does not create an image. - test_reporter.js which is much simplified from the non-Bazel version (due to the removal of a bunch of PathKit stuff). These JS tests are not the C++ gms. This means that we need to capture the PNG ourselves, which we do using the <canvas> API toDataURL(). This is base64 encoded, which is conveniently the format accepted by the gold_test_env server. - karma.bazel.js and assets/BUILD.bazel which make all the test assets available under a shortened path /assets. - Feel free to skip over the remaining *_test.js, as they are basically the same as what is currently checked in, just with the modifications above. - Any remaining files. Change-Id: I45fc38da38faf11f21011e7381d390e6bb299df4 Bug: skia:12541 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/513916 Reviewed-by: Leandro Lovisolo <lovisolo@google.com> Reviewed-by: Ben Wagner <bungeman@google.com>
328 lines
11 KiB
JavaScript
328 lines
11 KiB
JavaScript
describe('Skottie behavior', () => {
|
|
let container;
|
|
|
|
beforeEach(async () => {
|
|
await EverythingLoaded;
|
|
container = document.createElement('div');
|
|
container.innerHTML = `
|
|
<canvas width=600 height=600 id=test></canvas>
|
|
<canvas width=600 height=600 id=report></canvas>`;
|
|
document.body.appendChild(container);
|
|
});
|
|
|
|
afterEach(() => {
|
|
document.body.removeChild(container);
|
|
});
|
|
|
|
const expectArrayCloseTo = (a, b, precision) => {
|
|
precision = precision || 14; // digits of precision in base 10
|
|
expect(a.length).toEqual(b.length);
|
|
for (let i=0; i<a.length; i++) {
|
|
expect(a[i]).toBeCloseTo(b[i], precision);
|
|
}
|
|
};
|
|
|
|
const imgPromise = fetch('/assets/flightAnim.gif')
|
|
.then((response) => response.arrayBuffer());
|
|
const jsonPromise = fetch('/assets/animated_gif.json')
|
|
.then((response) => response.text());
|
|
const washPromise = fetch('/assets/map-shield.json')
|
|
.then((response) => response.text());
|
|
|
|
gm('skottie_animgif', (canvas, promises) => {
|
|
if (!CanvasKit.skottie || !CanvasKit.managed_skottie) {
|
|
console.warn('Skipping test because not compiled with skottie');
|
|
return;
|
|
}
|
|
expect(promises[1]).not.toBe('NOT FOUND');
|
|
const animation = CanvasKit.MakeManagedAnimation(promises[1], {
|
|
'flightAnim.gif': promises[0],
|
|
});
|
|
expect(animation).toBeTruthy();
|
|
const bounds = CanvasKit.LTRBRect(0, 0, 500, 500);
|
|
|
|
const size = animation.size();
|
|
expectArrayCloseTo(size, Float32Array.of(800, 600), 4);
|
|
|
|
canvas.clear(CanvasKit.WHITE);
|
|
animation.render(canvas, bounds);
|
|
|
|
// We intentionally make the length of this array 5 and add a sentinel value
|
|
// of 999 so we can make sure the bounds are copied into this rect and a new
|
|
// one is not allocated.
|
|
const damageRect = Float32Array.of(0, 0, 0, 0, 999);
|
|
|
|
// There was a bug, fixed in https://skia-review.googlesource.com/c/skia/+/241757
|
|
// that seeking again and drawing again revealed.
|
|
animation.seek(0.5, damageRect);
|
|
expectArrayCloseTo(damageRect, Float32Array.of(0, 0, 800, 600, 999), 4);
|
|
|
|
canvas.clear(CanvasKit.WHITE);
|
|
animation.render(canvas, bounds);
|
|
animation.delete();
|
|
}, imgPromise, jsonPromise);
|
|
|
|
gm('skottie_setcolor', (canvas, promises) => {
|
|
if (!CanvasKit.skottie || !CanvasKit.managed_skottie) {
|
|
console.warn('Skipping test because not compiled with skottie');
|
|
return;
|
|
}
|
|
expect(promises[0]).not.toBe('NOT FOUND');
|
|
const bounds = CanvasKit.LTRBRect(0, 0, 500, 500);
|
|
canvas.clear(CanvasKit.WHITE);
|
|
|
|
const animation = CanvasKit.MakeManagedAnimation(promises[0]);
|
|
expect(animation).toBeTruthy();
|
|
animation.setColor('$Icon Fill', CanvasKit.RED);
|
|
animation.seek(0.5);
|
|
animation.render(canvas, bounds);
|
|
animation.delete();
|
|
}, washPromise);
|
|
|
|
it('can load audio assets', (done) => {
|
|
if (!CanvasKit.skottie || !CanvasKit.managed_skottie) {
|
|
console.warn('Skipping test because not compiled with skottie');
|
|
return;
|
|
}
|
|
const mockSoundMap = {
|
|
map : new Map(),
|
|
getPlayer : function(name) {return this.map.get(name)},
|
|
setPlayer : function(name, player) {this.map.set(name, player)},
|
|
};
|
|
function mockPlayer(name) {
|
|
this.name = name;
|
|
this.wasPlayed = false,
|
|
this.seek = function(t) {
|
|
this.wasPlayed = true;
|
|
}
|
|
}
|
|
for (let i = 0; i < 20; i++) {
|
|
var name = 'audio_' + i;
|
|
mockSoundMap.setPlayer(name, new mockPlayer(name));
|
|
}
|
|
fetch('/assets/audio_external.json')
|
|
.then((response) => response.text())
|
|
.then((lottie) => {
|
|
const animation = CanvasKit.MakeManagedAnimation(lottie, null, null, mockSoundMap);
|
|
expect(animation).toBeTruthy();
|
|
// 190 frames in sample lottie
|
|
for (let t = 0; t < 190; t++) {
|
|
animation.seekFrame(t);
|
|
}
|
|
animation.delete();
|
|
for(const player of mockSoundMap.map.values()) {
|
|
expect(player.wasPlayed).toBeTrue(player.name + " was not played");
|
|
}
|
|
done();
|
|
});
|
|
});
|
|
|
|
it('can get logs', (done) => {
|
|
if (!CanvasKit.skottie || !CanvasKit.managed_skottie) {
|
|
console.warn('Skipping test because not compiled with skottie');
|
|
return;
|
|
}
|
|
|
|
const logger = {
|
|
errors: [],
|
|
warnings: [],
|
|
|
|
reset: function() { this.errors = []; this.warnings = []; },
|
|
|
|
// Logger API
|
|
onError: function(err) { this.errors.push(err) },
|
|
onWarning: function(wrn) { this.warnings.push(wrn) }
|
|
};
|
|
|
|
{
|
|
const json = `{
|
|
"v": "5.2.1",
|
|
"w": 100,
|
|
"h": 100,
|
|
"fr": 10,
|
|
"ip": 0,
|
|
"op": 100,
|
|
"layers": [{
|
|
"ty": 3,
|
|
"nm": "null",
|
|
"ind": 0,
|
|
"ip": 0
|
|
}]
|
|
}`;
|
|
const animation = CanvasKit.MakeManagedAnimation(json, null, null, null, logger);
|
|
expect(animation).toBeTruthy();
|
|
expect(logger.errors.length).toEqual(0);
|
|
expect(logger.warnings.length).toEqual(0);
|
|
}
|
|
|
|
{
|
|
const json = `{
|
|
"v": "5.2.1",
|
|
"w": 100,
|
|
"h": 100,
|
|
"fr": 10,
|
|
"ip": 0,
|
|
"op": 100,
|
|
"layers": [{
|
|
"ty": 2,
|
|
"nm": "image",
|
|
"ind": 0,
|
|
"ip": 0
|
|
}]
|
|
}`;
|
|
const animation = CanvasKit.MakeManagedAnimation(json, null, null, null, logger);
|
|
expect(animation).toBeTruthy();
|
|
expect(logger.errors.length).toEqual(1);
|
|
expect(logger.warnings.length).toEqual(0);
|
|
|
|
// Image layer missing refID
|
|
expect(logger.errors[0].includes('missing ref'));
|
|
logger.reset();
|
|
}
|
|
|
|
{
|
|
const json = `{
|
|
"v": "5.2.1",
|
|
"w": 100,
|
|
"h": 100,
|
|
"fr": 10,
|
|
"ip": 0,
|
|
"op": 100,
|
|
"layers": [{
|
|
"ty": 1,
|
|
"nm": "solid",
|
|
"sw": 100,
|
|
"sh": 100,
|
|
"sc": "#aabbcc",
|
|
"ind": 0,
|
|
"ip": 0,
|
|
"ef": [{
|
|
"mn": "FOO"
|
|
}]
|
|
}]
|
|
}`;
|
|
const animation = CanvasKit.MakeManagedAnimation(json, null, null, null, logger);
|
|
expect(animation).toBeTruthy();
|
|
expect(logger.errors.length).toEqual(0);
|
|
expect(logger.warnings.length).toEqual(1);
|
|
|
|
// Unsupported effect FOO
|
|
expect(logger.warnings[0].includes('FOO'));
|
|
logger.reset();
|
|
}
|
|
|
|
done();
|
|
});
|
|
|
|
it('can access dynamic props', () => {
|
|
if (!CanvasKit.skottie || !CanvasKit.managed_skottie) {
|
|
console.warn('Skipping test because not compiled with skottie');
|
|
return;
|
|
}
|
|
|
|
const json = `{
|
|
"v": "5.2.1",
|
|
"w": 100,
|
|
"h": 100,
|
|
"fr": 10,
|
|
"ip": 0,
|
|
"op": 100,
|
|
"fonts": {
|
|
"list": [{
|
|
"fName": "test_font",
|
|
"fFamily": "test-family",
|
|
"fStyle": "TestFontStyle"
|
|
}]
|
|
},
|
|
"layers": [
|
|
{
|
|
"ty": 4,
|
|
"nm": "__shape_layer",
|
|
"ind": 0,
|
|
"ip": 0,
|
|
"shapes": [
|
|
{
|
|
"ty": "el",
|
|
"p": { "a": 0, "k": [ 50, 50 ] },
|
|
"s": { "a": 0, "k": [ 50, 50 ] }
|
|
},{
|
|
"ty": "fl",
|
|
"nm": "__shape_fill",
|
|
"c": { "a": 0, "k": [ 1, 0, 0] }
|
|
},{
|
|
"ty": "tr",
|
|
"nm": "__shape_opacity",
|
|
"o": { "a": 0, "k": 50 }
|
|
}
|
|
]
|
|
},{
|
|
"ty": 5,
|
|
"nm": "__text_layer",
|
|
"ip": 0,
|
|
"t": {
|
|
"d": {
|
|
"k": [{
|
|
"t": 0,
|
|
"s": {
|
|
"f": "test_font",
|
|
"s": 100,
|
|
"t": "Foo Bar Baz",
|
|
"lh": 120,
|
|
"ls": 12
|
|
}
|
|
}]
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}`;
|
|
|
|
const animation = CanvasKit.MakeManagedAnimation(json, null, '__');
|
|
expect(animation).toBeTruthy();
|
|
|
|
{
|
|
const colors = animation.getColorProps();
|
|
expect(colors.length).toEqual(1);
|
|
expect(colors[0].key).toEqual('__shape_fill');
|
|
expect(colors[0].value).toEqual(CanvasKit.ColorAsInt(255,0,0,255));
|
|
|
|
const opacities = animation.getOpacityProps();
|
|
expect(opacities.length).toEqual(1);
|
|
expect(opacities[0].key).toEqual('__shape_opacity');
|
|
expect(opacities[0].value).toEqual(50);
|
|
|
|
const texts = animation.getTextProps();
|
|
expect(texts.length).toEqual(1);
|
|
expect(texts[0].key).toEqual('__text_layer');
|
|
expect(texts[0].value.text).toEqual('Foo Bar Baz');
|
|
expect(texts[0].value.size).toEqual(100);
|
|
}
|
|
|
|
expect(animation.setColor('__shape_fill', [0,1,0,1])).toEqual(true);
|
|
expect(animation.setOpacity('__shape_opacity', 100)).toEqual(true);
|
|
expect(animation.setText('__text_layer', 'baz bar foo', 10)).toEqual(true);
|
|
|
|
{
|
|
const colors = animation.getColorProps();
|
|
expect(colors.length).toEqual(1);
|
|
expect(colors[0].key).toEqual('__shape_fill');
|
|
expect(colors[0].value).toEqual(CanvasKit.ColorAsInt(0,255,0,255));
|
|
|
|
const opacities = animation.getOpacityProps();
|
|
expect(opacities.length).toEqual(1);
|
|
expect(opacities[0].key).toEqual('__shape_opacity');
|
|
expect(opacities[0].value).toEqual(100);
|
|
|
|
const texts = animation.getTextProps();
|
|
expect(texts.length).toEqual(1);
|
|
expect(texts[0].key).toEqual('__text_layer');
|
|
expect(texts[0].value.text).toEqual('baz bar foo');
|
|
expect(texts[0].value.size).toEqual(10);
|
|
}
|
|
|
|
expect(animation.setColor('INVALID_KEY', [0,1,0,1])).toEqual(false);
|
|
expect(animation.setOpacity('INVALID_KEY', 100)).toEqual(false);
|
|
expect(animation.setText('INVALID KEY', '', 10)).toEqual(false);
|
|
});
|
|
});
|