• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1describe('Core canvas behavior', function() {
2    let container = document.createElement('div');
3    document.body.appendChild(container);
4    const CANVAS_WIDTH = 600;
5    const CANVAS_HEIGHT = 600;
6
7    beforeEach(function() {
8        container.innerHTML = `
9            <canvas width=600 height=600 id=test></canvas>
10            <canvas width=600 height=600 id=report></canvas>`;
11    });
12
13    afterEach(function() {
14        container.innerHTML = '';
15    });
16
17    it('can draw an SkPicture', function(done) {
18        LoadCanvasKit.then(catchException(done, () => {
19            // This is taken from example.html
20            const surface = CanvasKit.MakeCanvasSurface('test');
21            expect(surface).toBeTruthy('Could not make surface');
22            if (!surface) {
23                done();
24                return;
25            }
26            const spr = new CanvasKit.SkPictureRecorder();
27            const rcanvas = spr.beginRecording(
28                            CanvasKit.LTRBRect(0, 0, surface.width(), surface.height()));
29            const paint = new CanvasKit.SkPaint();
30            paint.setStrokeWidth(2.0);
31            paint.setAntiAlias(true);
32            paint.setColor(CanvasKit.Color(0, 0, 0, 1.0));
33            paint.setStyle(CanvasKit.PaintStyle.Stroke);
34
35            rcanvas.drawRoundRect(CanvasKit.LTRBRect(5, 35, 45, 80), 15, 10, paint);
36
37            const font = new CanvasKit.SkFont(null, 20);
38            rcanvas.drawText('this picture has a round rect', 5, 100, paint, font);
39            const pic = spr.finishRecordingAsPicture();
40            spr.delete();
41
42
43            const canvas = surface.getCanvas();
44            canvas.drawPicture(pic);
45
46            reportSurface(surface, 'picture_test', done);
47        }));
48    });
49
50    it('can compute tonal colors', function(done) {
51        LoadCanvasKit.then(catchException(done, () => {
52            const input = {
53                ambient: CanvasKit.BLUE,
54                spot: CanvasKit.RED,
55            };
56            const out = CanvasKit.computeTonalColors(input);
57
58            expect(out.ambient).toEqual(CanvasKit.Color(0,0,0,1));
59
60            const [r,g,b,a] = CanvasKit.getColorComponents(out.spot);
61            expect(r).toEqual(44);
62            expect(g).toEqual(0);
63            expect(b).toEqual(0);
64            expect(a).toBeCloseTo(0.969, 2);
65            done();
66        }));
67    });
68
69    // This helper is used for all the MakeImageFromEncoded tests.
70    function decodeAndDrawSingleFrameImage(imgName, goldName, done) {
71        const imgPromise = fetch(imgName)
72            .then((response) => response.arrayBuffer());
73        Promise.all([imgPromise, LoadCanvasKit]).then((values) => {
74            const imgData = values[0];
75            expect(imgData).toBeTruthy();
76            catchException(done, () => {
77                let img = CanvasKit.MakeImageFromEncoded(imgData);
78                expect(img).toBeTruthy();
79                const surface = CanvasKit.MakeCanvasSurface('test');
80                expect(surface).toBeTruthy('Could not make surface');
81                if (!surface) {
82                    done();
83                    return;
84                }
85                const canvas = surface.getCanvas();
86                let paint = new CanvasKit.SkPaint();
87                canvas.drawImage(img, 0, 0, paint);
88
89                paint.delete();
90                img.delete();
91
92                reportSurface(surface, goldName, done);
93            })();
94        });
95    }
96
97    it('can decode and draw a png', function(done) {
98        decodeAndDrawSingleFrameImage('/assets/mandrill_512.png', 'drawImage_png', done);
99    });
100
101    it('can decode and draw a jpg', function(done) {
102        decodeAndDrawSingleFrameImage('/assets/mandrill_h1v1.jpg', 'drawImage_jpg', done);
103    });
104
105    it('can decode and draw a (still) gif', function(done) {
106        decodeAndDrawSingleFrameImage('/assets/flightAnim.gif', 'drawImage_gif', done);
107    });
108
109    it('can decode and draw a still webp', function(done) {
110        decodeAndDrawSingleFrameImage('/assets/color_wheel.webp', 'drawImage_webp', done);
111    });
112
113   it('can readPixels from an SkImage', function(done) {
114        const imgPromise = fetch('/assets/mandrill_512.png')
115            .then((response) => response.arrayBuffer());
116        Promise.all([imgPromise, LoadCanvasKit]).then((values) => {
117            const imgData = values[0];
118            expect(imgData).toBeTruthy();
119            catchException(done, () => {
120                let img = CanvasKit.MakeImageFromEncoded(imgData);
121                expect(img).toBeTruthy();
122                const imageInfo = {
123                    alphaType: CanvasKit.AlphaType.Unpremul,
124                    colorType: CanvasKit.ColorType.RGBA_8888,
125                    width: img.width(),
126                    height: img.height(),
127                };
128
129                const pixels = img.readPixels(imageInfo, 0, 0);
130                // We know the image is 512 by 512 pixels in size, each pixel
131                // requires 4 bytes (R, G, B, A).
132                expect(pixels.length).toEqual(512 * 512 * 4);
133
134                img.delete();
135                done();
136            })();
137        });
138    });
139
140    it('can decode and draw an animated gif', function(done) {
141        const imgPromise = fetch('/assets/flightAnim.gif')
142            .then((response) => response.arrayBuffer());
143        Promise.all([imgPromise, LoadCanvasKit]).then((values) => {
144            const gifData = values[0];
145            expect(gifData).toBeTruthy();
146            catchException(done, () => {
147                let aImg = CanvasKit.MakeAnimatedImageFromEncoded(gifData);
148                expect(aImg).toBeTruthy();
149                expect(aImg.getRepetitionCount()).toEqual(-1); // infinite loop
150                expect(aImg.width()).toEqual(320);
151                expect(aImg.height()).toEqual(240);
152                expect(aImg.getFrameCount()).toEqual(60);
153
154                const surface = CanvasKit.MakeCanvasSurface('test');
155                expect(surface).toBeTruthy('Could not make surface');
156                if (!surface) {
157                    done();
158                    return;
159                }
160                const canvas = surface.getCanvas();
161                canvas.drawAnimatedImage(aImg, 0, 0);
162
163                let c = aImg.decodeNextFrame();
164                expect(c).not.toEqual(-1);
165                canvas.drawAnimatedImage(aImg, 300, 0);
166                for(let i = 0; i < 10; i++) {
167                    c = aImg.decodeNextFrame();
168                    expect(c).not.toEqual(-1);
169                }
170                canvas.drawAnimatedImage(aImg, 0, 300);
171                for(let i = 0; i < 10; i++) {
172                    c = aImg.decodeNextFrame();
173                    expect(c).not.toEqual(-1);
174                }
175                canvas.drawAnimatedImage(aImg, 300, 300);
176
177                aImg.delete();
178
179                reportSurface(surface, 'drawDrawable_animated_gif', done);
180            })();
181        });
182    });
183
184    it('can create an image "from scratch" by specifying pixels/colorInfo manually', function(done) {
185        LoadCanvasKit.then(catchException(done, () => {
186            const surface = CanvasKit.MakeCanvasSurface('test');
187            expect(surface).toBeTruthy('Could not make surface');
188            if (!surface) {
189                done();
190                return;
191            }
192            const canvas = surface.getCanvas();
193            canvas.clear(CanvasKit.WHITE);
194            const paint = new CanvasKit.SkPaint();
195
196            // This creates and draws an SkImage that is 1 pixel wide, 4 pixels tall with
197            // the colors listed below.
198            const pixels = Uint8Array.from([
199                255,   0,   0, 255, // opaque red
200                  0, 255,   0, 255, // opaque green
201                  0,   0, 255, 255, // opaque blue
202                255,   0, 255, 100, // transparent purple
203            ]);
204            const img = CanvasKit.MakeImage(pixels, 1, 4, CanvasKit.AlphaType.Unpremul, CanvasKit.ColorType.RGBA_8888);
205            canvas.drawImage(img, 1, 1, paint);
206
207            reportSurface(surface, '1x4_from_scratch', done);
208        }));
209    });
210
211    it('can blur using ImageFilter or MaskFilter', function(done) {
212        LoadCanvasKit.then(catchException(done, () => {
213            const surface = CanvasKit.MakeCanvasSurface('test');
214            expect(surface).toBeTruthy('Could not make surface');
215            if (!surface) {
216                done();
217                return;
218            }
219            const canvas = surface.getCanvas();
220            const pathUL = starPath(CanvasKit, 100, 100, 80);
221            const pathBR = starPath(CanvasKit, 400, 300, 80);
222            const paint = new CanvasKit.SkPaint();
223            const textFont = new CanvasKit.SkFont(null, 24);
224
225            canvas.drawText('Above: MaskFilter', 20, 220, paint, textFont);
226            canvas.drawText('Right: ImageFilter', 20, 260, paint, textFont);
227
228            paint.setColor(CanvasKit.BLUE);
229
230            const blurMask = CanvasKit.SkMaskFilter.MakeBlur(CanvasKit.BlurStyle.Normal, 5, true);
231            paint.setMaskFilter(blurMask);
232            canvas.drawPath(pathUL, paint);
233
234            const blurIF = CanvasKit.SkImageFilter.MakeBlur(8, 1, CanvasKit.TileMode.Decal, null);
235            paint.setImageFilter(blurIF);
236            canvas.drawPath(pathBR, paint);
237
238            surface.flush();
239
240            pathUL.delete();
241            pathBR.delete();
242            paint.delete();
243            blurMask.delete();
244            blurIF.delete();
245            textFont.delete();
246
247            reportSurface(surface, 'blur_filters', done);
248        }));
249    });
250
251    it('can use various image filters', function(done) {
252        const imgPromise = fetch('/assets/mandrill_512.png')
253            .then((response) => response.arrayBuffer());
254        Promise.all([imgPromise, LoadCanvasKit]).then((values) => {
255            const pngData = values[0];
256            expect(pngData).toBeTruthy();
257            catchException(done, () => {
258                let img = CanvasKit.MakeImageFromEncoded(pngData);
259                expect(img).toBeTruthy();
260                const surface = CanvasKit.MakeCanvasSurface('test');
261                expect(surface).toBeTruthy('Could not make surface');
262                if (!surface) {
263                    done();
264                    return;
265                }
266                const canvas = surface.getCanvas();
267                canvas.clear(CanvasKit.WHITE);
268                const paint = new CanvasKit.SkPaint();
269                paint.setAntiAlias(true);
270                paint.setColor(CanvasKit.Color(0, 255, 0, 1.0));
271                const redCF =  CanvasKit.SkColorFilter.MakeBlend(
272                        CanvasKit.Color(255, 0, 0, 0.1), CanvasKit.BlendMode.SrcOver);
273                const redIF = CanvasKit.SkImageFilter.MakeColorFilter(redCF, null);
274                const blurIF = CanvasKit.SkImageFilter.MakeBlur(8, 0.2, CanvasKit.TileMode.Decal, null);
275                const combined = CanvasKit.SkImageFilter.MakeCompose(redIF, blurIF);
276
277                // rotate 10 degrees centered on 200, 200
278                const m = CanvasKit.SkMatrix.rotated(Math.PI/18, 200, 200);
279                const rotated = CanvasKit.SkImageFilter.MakeMatrixTransform(m, CanvasKit.FilterQuality.Medium, combined);
280                paint.setImageFilter(rotated);
281
282                //canvas.rotate(10, 200, 200);
283                canvas.drawImage(img, 0, 0, paint);
284                canvas.drawRect(CanvasKit.LTRBRect(5, 35, 45, 80), paint);
285
286                surface.flush();
287
288                paint.delete();
289                redIF.delete();
290                redCF.delete();
291                blurIF.delete();
292                combined.delete();
293                rotated.delete();
294                img.delete();
295
296                reportSurface(surface, 'combined_filters', done);
297            })();
298        });
299    });
300
301    it('can use various image filters on animated images', function(done) {
302        const imgPromise = fetch('/assets/flightAnim.gif')
303            .then((response) => response.arrayBuffer());
304        Promise.all([imgPromise, LoadCanvasKit]).then((values) => {
305            const gifData = values[0];
306            expect(gifData).toBeTruthy();
307            catchException(done, () => {
308                let img = CanvasKit.MakeAnimatedImageFromEncoded(gifData);
309                expect(img).toBeTruthy();
310                const surface = CanvasKit.MakeCanvasSurface('test');
311                expect(surface).toBeTruthy('Could not make surface');
312                if (!surface) {
313                    done();
314                    return;
315                }
316                img.decodeNextFrame();
317                img.decodeNextFrame();
318                const canvas = surface.getCanvas();
319                canvas.clear(CanvasKit.WHITE);
320                const paint = new CanvasKit.SkPaint();
321                paint.setAntiAlias(true);
322                paint.setColor(CanvasKit.Color(0, 255, 0, 1.0));
323                const redCF =  CanvasKit.SkColorFilter.MakeBlend(
324                        CanvasKit.Color(255, 0, 0, 0.1), CanvasKit.BlendMode.SrcOver);
325                const redIF = CanvasKit.SkImageFilter.MakeColorFilter(redCF, null);
326                const blurIF = CanvasKit.SkImageFilter.MakeBlur(8, 0.2, CanvasKit.TileMode.Decal, null);
327                const combined = CanvasKit.SkImageFilter.MakeCompose(redIF, blurIF);
328                paint.setImageFilter(combined);
329
330                const frame = img.getCurrentFrame();
331                canvas.drawImage(frame, 100, 50, paint);
332
333                surface.flush();
334
335                paint.delete();
336                redIF.delete();
337                redCF.delete();
338                blurIF.delete();
339                combined.delete();
340                frame.delete();
341                img.delete();
342
343                reportSurface(surface, 'animated_filters', done);
344            })();
345        });
346    });
347
348    it('can decode and draw an skp', function(done) {
349        const skpPromise = fetch('/assets/red_line.skp')
350            .then((response) => response.arrayBuffer());
351        Promise.all([skpPromise, LoadCanvasKit]).then((values) => {
352            const skpData = values[0];
353            expect(skpData).toBeTruthy();
354            catchException(done, () => {
355                let pic = CanvasKit.MakeSkPicture(skpData);
356                expect(pic).toBeTruthy();
357                const surface = CanvasKit.MakeCanvasSurface('test');
358                expect(surface).toBeTruthy('Could not make surface');
359                if (!surface) {
360                    done();
361                    return;
362                }
363                const canvas = surface.getCanvas();
364                canvas.clear(CanvasKit.TRANSPARENT);
365                canvas.drawPicture(pic);
366
367                reportSurface(surface, 'drawImage_skp', done);
368            })();
369        });
370    });
371
372    it('can draw once using drawOnce utility method', function(done) {
373        LoadCanvasKit.then(catchException(done, () => {
374            const surface = CanvasKit.MakeCanvasSurface('test');
375            expect(surface).toBeTruthy('Could not make surface');
376            if (!surface) {
377                done();
378                return;
379            }
380
381            function drawFrame(canvas) {
382                const paint = new CanvasKit.SkPaint();
383                paint.setStrokeWidth(1.0);
384                paint.setAntiAlias(true);
385                paint.setColor(CanvasKit.Color(0, 0, 0, 1.0));
386                paint.setStyle(CanvasKit.PaintStyle.Stroke);
387                const path = new CanvasKit.SkPath();
388                path.moveTo(20, 5);
389                path.lineTo(30, 20);
390                path.lineTo(40, 10);
391                canvas.drawPath(path, paint);
392                path.delete();
393                paint.delete();
394                // surface hasn't been flushed yet (nor should we call flush
395                // ourselves), so reportSurface would likely be blank if we
396                // were to call it.
397                done();
398            }
399            surface.drawOnce(drawFrame);
400            // Reminder: drawOnce is async. In this test, we are just making
401            // sure the drawOnce function is there and doesn't crash, so we can
402            // just call done() when the frame is rendered.
403        }));
404    });
405
406    it('can use DecodeCache APIs', function(done) {
407        LoadCanvasKit.then(catchException(done, () => {
408            const initialLimit = CanvasKit.getDecodeCacheLimitBytes();
409            expect(initialLimit).toBeGreaterThan(1024 * 1024);
410
411            const newLimit = 42 * 1024 * 1024;
412            CanvasKit.setDecodeCacheLimitBytes(newLimit);
413            expect(CanvasKit.getDecodeCacheLimitBytes()).toEqual(newLimit);
414
415            // We cannot make any assumptions about this value,
416            // so we just make sure it doesn't crash.
417            CanvasKit.getDecodeCacheUsedBytes();
418
419            done();
420        }));
421    });
422
423    it('can combine shaders', function(done) {
424        LoadCanvasKit.then(catchException(done, () => {
425            const surface = CanvasKit.MakeCanvasSurface('test');
426            expect(surface).toBeTruthy('Could not make surface');
427            if (!surface) {
428                done();
429                return;
430            }
431            const canvas = surface.getCanvas();
432
433            const rShader = CanvasKit.SkShader.Color(CanvasKit.Color(255, 0, 0, 1.0));
434            const gShader = CanvasKit.SkShader.Color(CanvasKit.Color(0, 255, 0, 0.6));
435            const bShader = CanvasKit.SkShader.Color(CanvasKit.Color(0, 0, 255, 1.0));
436
437            const rgShader = CanvasKit.SkShader.Blend(CanvasKit.BlendMode.SrcOver, rShader, gShader);
438
439            const p = new CanvasKit.SkPaint();
440            p.setShader(rgShader);
441            canvas.drawPaint(p);
442
443            const gbShader = CanvasKit.SkShader.Lerp(0.5, gShader, bShader);
444
445            p.setShader(gbShader);
446            canvas.drawRect(CanvasKit.LTRBRect(5, 100, 300, 400), p);
447
448
449            reportSurface(surface, 'combined_shaders', done);
450        }));
451    });
452
453    it('exports consts correctly', function(done) {
454        LoadCanvasKit.then(catchException(done, () => {
455            expect(CanvasKit.TRANSPARENT).toEqual(0);
456            expect(CanvasKit.RED).toEqual(4294901760);
457
458            expect(CanvasKit.QUAD_VERB).toEqual(2);
459            expect(CanvasKit.CONIC_VERB).toEqual(3);
460
461            expect(CanvasKit.SaveLayerInitWithPrevious).toEqual(4);
462            expect(CanvasKit.SaveLayerF16ColorType).toEqual(16);
463
464            done();
465        }));
466    });
467
468});
469