Update rive-cpp to 2.0 version
[platform/core/uifw/rive-tizen.git] / submodule / skia / modules / canvaskit / npm_build / example.html
1 <!DOCTYPE html>
2 <title>CanvasKit (Skia via Web Assembly)</title>
3 <meta charset="utf-8" />
4 <meta http-equiv="X-UA-Compatible" content="IE=edge">
5 <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
7 <style>
8   canvas, img {
9     border: 1px dashed #AAA;
10   }
11   #api5_c, #api6_c {
12       width: 300px;
13       height: 300px;
14   }
15
16 </style>
17
18 <h2>Drop in replacement for HTML Canvas (e.g. node.js)</h2>
19 <img id=api1 width=300 height=300>
20 <canvas id=api1_c width=300 height=300></canvas>
21 <img id=api2 width=300 height=300>
22 <canvas id=api2_c width=300 height=300></canvas>
23 <img id=api3 width=300 height=300>
24 <canvas id=api3_c width=300 height=300></canvas>
25 <img id=api4 width=300 height=300>
26 <canvas id=api4_c width=300 height=300></canvas>
27 <img id=api5 width=300 height=300>
28 <canvas id=api5_c width=300 height=300></canvas>
29 <img id=api6 width=300 height=300>
30 <canvas id=api6_c width=300 height=300></canvas>
31 <img id=api7 width=300 height=300>
32 <canvas id=api7_c width=300 height=300></canvas>
33 <img id=api8 width=300 height=300>
34 <canvas id=api8_c width=300 height=300></canvas>
35
36 <h2> CanvasKit expands the functionality of a stock HTML canvas</h2>
37 <canvas id=vertex1 width=300 height=300></canvas>
38 <canvas id=gradient1 width=300 height=300></canvas>
39 <canvas id=patheffect width=300 height=300></canvas>
40 <canvas id=paths width=200 height=200></canvas>
41 <canvas id=pathperson width=300 height=300></canvas>
42 <canvas id=ink width=300 height=300></canvas>
43 <canvas id=surfaces width=300 height=300></canvas>
44 <canvas id=atlas width=300 height=300></canvas>
45 <canvas id=decode width=300 height=300></canvas>
46
47 <h2> CanvasKit can allow for text measurement/placement (e.g. breaking, kerning)</h2>
48 <canvas id=textonpath width=300 height=300></canvas>
49 <canvas id=drawGlyphs width=300 height=300></canvas>
50
51 <h2> Interactive drawPatch</h2>
52 <canvas id=interdrawpatch width=512 height=512></canvas>
53
54 <script type="text/javascript" src="/build/canvaskit.js"></script>
55
56 <script type="text/javascript" charset="utf-8">
57
58   var CanvasKit = null;
59   var cdn = 'https://storage.googleapis.com/skia-cdn/misc/';
60
61   const ckLoaded = CanvasKitInit({locateFile: (file) => '/build/'+file});
62
63   const loadRoboto = fetch(cdn + 'Roboto-Regular.ttf').then((response) => response.arrayBuffer());
64   const loadNotoSerif = fetch(cdn + 'NotoSerif-Regular.ttf').then((response) => response.arrayBuffer());
65   const loadTestImage = fetch(cdn + 'test.png').then((response) => response.arrayBuffer());
66
67   // Examples which only require canvaskit
68   ckLoaded.then((CK) => {
69     CanvasKit = CK;
70     PathExample(CanvasKit);
71     InkExample(CanvasKit);
72     PathPersonExample(CanvasKit);
73     VertexAPI1(CanvasKit);
74     GradiantAPI1(CanvasKit);
75     TextOnPathAPI1(CanvasKit);
76     DrawGlyphsAPI1(CanvasKit);
77     SurfaceAPI1(CanvasKit);
78     if (CanvasKit.MakeCanvas){
79       CanvasAPI1(CanvasKit);
80       CanvasAPI2(CanvasKit);
81       CanvasAPI3(CanvasKit);
82       CanvasAPI4(CanvasKit);
83       CanvasAPI5(CanvasKit);
84       CanvasAPI6(CanvasKit);
85       CanvasAPI7(CanvasKit);
86       CanvasAPI8(CanvasKit);
87     } else {
88       console.log("Skipping CanvasAPI1 because it's not compiled in");
89     }
90     InteractivePatch(CanvasKit);
91   });
92
93   // Examples requiring external resources
94   Promise.all([ckLoaded, loadRoboto]).then((results) => {DrawingExample(...results)});
95   Promise.all([ckLoaded, loadTestImage]).then((results) => {AtlasAPI1(...results)});
96   Promise.all([ckLoaded, loadTestImage]).then((results) => {DecodeAPI(...results)});
97
98   function DrawingExample(CanvasKit, robotoData) {
99     if (!robotoData || !CanvasKit) {
100       return;
101     }
102     const surface = CanvasKit.MakeCanvasSurface('patheffect');
103     if (!surface) {
104       console.error('Could not make surface');
105       return;
106     }
107
108     const paint = new CanvasKit.Paint();
109     const roboto = CanvasKit.Typeface.MakeFreeTypeFaceFromData(robotoData);
110
111     const textPaint = new CanvasKit.Paint();
112     textPaint.setColor(CanvasKit.RED);
113     textPaint.setAntiAlias(true);
114
115     const textFont = new CanvasKit.Font(roboto, 30);
116
117     let i = 0;
118
119     let X = 128;
120     let Y = 128;
121
122     function drawFrame(canvas) {
123       const path = starPath(CanvasKit, X, Y);
124       // Some animations see performance improvements by marking their
125       // paths as volatile.
126       path.setIsVolatile(true);
127       const dpe = CanvasKit.PathEffect.MakeDash([15, 5, 5, 10], i/5);
128       i++;
129
130       paint.setPathEffect(dpe);
131       paint.setStyle(CanvasKit.PaintStyle.Stroke);
132       paint.setStrokeWidth(5.0 + -3 * Math.cos(i/30));
133       paint.setAntiAlias(true);
134       paint.setColor(CanvasKit.Color(66, 129, 164, 1.0));
135
136       canvas.clear(CanvasKit.TRANSPARENT);
137
138       canvas.drawPath(path, paint);
139       canvas.drawText('Try Clicking!', 10, 280, textPaint, textFont);
140
141       dpe.delete();
142       path.delete();
143       surface.requestAnimationFrame(drawFrame);
144     }
145     surface.requestAnimationFrame(drawFrame);
146
147     // Make animation interactive
148     let interact = (e) => {
149       if (!e.pressure) {
150         return;
151       }
152       X = e.offsetX;
153       Y = e.offsetY;
154     };
155     document.getElementById('patheffect').addEventListener('pointermove', interact);
156     document.getElementById('patheffect').addEventListener('pointerdown', interact);
157     preventScrolling(document.getElementById('patheffect'));
158     // A client would need to delete this if it didn't go on for ever.
159     // paint.delete();
160     // textPaint.delete();
161     // textFont.delete();
162   }
163
164    function InteractivePatch(CanvasKit) {
165      const ELEM = 'interdrawpatch';
166      const surface = CanvasKit.MakeCanvasSurface(ELEM);
167      if (!surface) {
168        console.error('Could not make surface');
169        return;
170      }
171
172      let live_corner, live_index;
173
174      const paint = new CanvasKit.Paint();
175      const pts_paint = new CanvasKit.Paint();
176      pts_paint.setStyle(CanvasKit.PaintStyle.Stroke);
177      pts_paint.setStrokeWidth(9);
178      pts_paint.setStrokeCap(CanvasKit.StrokeCap.Round);
179
180      const line_paint = new CanvasKit.Paint();
181      line_paint.setStyle(CanvasKit.PaintStyle.Stroke);
182      line_paint.setStrokeWidth(2);
183
184      const colors = [CanvasKit.RED, CanvasKit.BLUE, CanvasKit.YELLOW, CanvasKit.CYAN];
185
186      const patch = [
187           [ 10,170,   10, 10,  170, 10],  // prev_vector, point, next_vector
188           [340, 10,  500, 10,  500,170],
189           [500,340,  500,500,  340,500],
190           [170,500,   10,500,   10,340],
191       ];
192
193       function get_corner(corner, index) {
194           return [corner[index*2+0], corner[index*2+1]];
195       }
196
197       function push_xy(array, xy) {
198           array.push(xy[0], xy[1]);
199       }
200
201       function patch_to_cubics(patch) {
202           const array = [];
203           push_xy(array, get_corner(patch[0],1));
204           push_xy(array, get_corner(patch[0],2));
205           for (let i = 1; i < 4; ++i) {
206               push_xy(array, get_corner(patch[i],0));
207               push_xy(array, get_corner(patch[i],1));
208               push_xy(array, get_corner(patch[i],2));
209           }
210           push_xy(array, get_corner(patch[0],0));
211
212           return array;
213       }
214
215      function drawFrame(canvas) {
216          const cubics = patch_to_cubics(patch);
217
218          canvas.drawColor(CanvasKit.WHITE);
219          canvas.drawPatch(cubics, colors, null, CanvasKit.BlendMode.Dst, paint);
220          if (live_corner) {
221              canvas.drawPoints(CanvasKit.PointMode.Polygon, live_corner, line_paint);
222          }
223          canvas.drawPoints(CanvasKit.PointMode.Points, cubics, pts_paint);
224
225          surface.requestAnimationFrame(drawFrame);
226      }
227
228      surface.requestAnimationFrame(drawFrame);
229
230      function length2(x, y) {
231          return x*x + y*y;
232      }
233      function hit_test(x,y, x1,y1) {
234          return length2(x-x1, y-y1) <= 10*10;
235      }
236      function pointer_up(e) {
237          live_corner = null;
238          live_index = null;
239       }
240
241      function pointer_down(e) {
242          live_corner = null;
243          live_index = null;
244          for (p of patch) {
245              for (let i = 0; i < 6; i += 2) {
246                  if (hit_test(p[i], p[i+1], e.offsetX, e.offsetY)) {
247                      live_corner = p;
248                      live_index = i;
249                  }
250              }
251          }
252       }
253
254      function pointer_move(e) {
255        if (e.pressure && live_corner) {
256            if (live_index == 2) {
257                // corner
258                const dx = e.offsetX - live_corner[2];
259                const dy = e.offsetY - live_corner[3];
260                for  (let i = 0; i < 3; ++i) {
261                    live_corner[i*2+0] += dx;
262                    live_corner[i*2+1] += dy;
263                }
264            } else {
265                // control-point
266                live_corner[live_index+0] = e.offsetX;
267                live_corner[live_index+1] = e.offsetY;
268             }
269         }
270      }
271      document.getElementById(ELEM).addEventListener('pointermove', pointer_move);
272      document.getElementById(ELEM).addEventListener('pointerdown', pointer_down);
273      document.getElementById(ELEM).addEventListener('pointerup', pointer_up);
274      preventScrolling(document.getElementById(ELEM));
275    }
276
277   function PathPersonExample(CanvasKit) {
278     const surface = CanvasKit.MakeSWCanvasSurface('pathperson');
279     if (!surface) {
280       console.error('Could not make surface');
281       return;
282     }
283
284     function drawFrame(canvas) {
285       const paint = new CanvasKit.Paint();
286       paint.setStrokeWidth(1.0);
287       paint.setAntiAlias(true);
288       paint.setColor(CanvasKit.Color(0, 0, 0, 1.0));
289       paint.setStyle(CanvasKit.PaintStyle.Stroke);
290
291       const path = new CanvasKit.Path();
292       path.moveTo(10, 10);
293       path.lineTo(100, 10);
294       path.moveTo(10, 10);
295       path.lineTo(10, 200);
296       path.moveTo(10, 100);
297       path.lineTo(100,100);
298       path.moveTo(10, 200);
299       path.lineTo(100, 200);
300
301       canvas.drawPath(path, paint);
302       path.delete();
303       paint.delete();
304     }
305     // Intentionally just draw frame once
306     surface.drawOnce(drawFrame);
307   }
308
309   function PathExample(CanvasKit) {
310     const surface = CanvasKit.MakeSWCanvasSurface('paths');
311     if (!surface) {
312       console.error('Could not make surface');
313       return;
314     }
315
316     function drawFrame(canvas) {
317       const paint = new CanvasKit.Paint();
318       paint.setStrokeWidth(1.0);
319       paint.setAntiAlias(true);
320       paint.setColor(CanvasKit.Color(0, 0, 0, 1.0));
321       paint.setStyle(CanvasKit.PaintStyle.Stroke);
322
323       const path = new CanvasKit.Path();
324       path.moveTo(20, 5);
325       path.lineTo(30, 20);
326       path.lineTo(40, 10);
327       path.lineTo(50, 20);
328       path.lineTo(60, 0);
329       path.lineTo(20, 5);
330
331       path.moveTo(20, 80);
332       path.cubicTo(90, 10, 160, 150, 190, 10);
333
334       path.moveTo(36, 148);
335       path.quadTo(66, 188, 120, 136);
336       path.lineTo(36, 148);
337
338       path.moveTo(150, 180);
339       path.arcToTangent(150, 100, 50, 200, 20);
340       path.lineTo(160, 160);
341
342       path.moveTo(20, 120);
343       path.lineTo(20, 120);
344
345       canvas.drawPath(path, paint);
346
347       const rrect = CanvasKit.RRectXY([100, 10, 140, 62], 10, 4);
348
349       const rrectPath = new CanvasKit.Path().addRRect(rrect, true);
350
351       canvas.drawPath(rrectPath, paint);
352
353       rrectPath.delete();
354       path.delete();
355       paint.delete();
356     }
357     // Intentionally just draw frame once
358     surface.drawOnce(drawFrame);
359   }
360
361   function preventScrolling(canvas) {
362     canvas.addEventListener('touchmove', (e) => {
363       // Prevents touch events in the canvas from scrolling the canvas.
364       e.preventDefault();
365       e.stopPropagation();
366     });
367   }
368
369   function InkExample(CanvasKit) {
370     const surface = CanvasKit.MakeCanvasSurface('ink');
371     if (!surface) {
372       console.error('Could not make surface');
373       return;
374     }
375
376     let paint = new CanvasKit.Paint();
377     paint.setAntiAlias(true);
378     paint.setColor(CanvasKit.Color(0, 0, 0, 1.0));
379     paint.setStyle(CanvasKit.PaintStyle.Stroke);
380     paint.setStrokeWidth(4.0);
381     paint.setPathEffect(CanvasKit.PathEffect.MakeCorner(50));
382
383     // Draw I N K
384     let path = new CanvasKit.Path();
385     path.moveTo(80, 30);
386     path.lineTo(80, 80);
387
388     path.moveTo(100, 80);
389     path.lineTo(100, 15);
390     path.lineTo(130, 95);
391     path.lineTo(130, 30);
392
393     path.moveTo(150, 30);
394     path.lineTo(150, 80);
395     path.moveTo(170, 30);
396     path.lineTo(150, 55);
397     path.lineTo(170, 80);
398
399     let paths = [path];
400     let paints = [paint];
401
402     function drawFrame(canvas) {
403       canvas.clear(CanvasKit.Color(255, 255, 255, 1.0));
404
405       for (let i = 0; i < paints.length && i < paths.length; i++) {
406         canvas.drawPath(paths[i], paints[i]);
407       }
408
409       surface.requestAnimationFrame(drawFrame);
410     }
411
412     let hold = false;
413     let interact = (e) => {
414       let type = e.type;
415       if (type === 'lostpointercapture' || type === 'pointerup' || !e.pressure ) {
416         hold = false;
417         return;
418       }
419       if (hold) {
420         path.lineTo(e.offsetX, e.offsetY);
421       } else {
422         paint = paint.copy();
423         paint.setColor(CanvasKit.Color(Math.random() * 255, Math.random() * 255, Math.random() * 255, Math.random() + .2));
424         paints.push(paint);
425         path = new CanvasKit.Path();
426         paths.push(path);
427         path.moveTo(e.offsetX, e.offsetY);
428       }
429       hold = true;
430     };
431     document.getElementById('ink').addEventListener('pointermove', interact);
432     document.getElementById('ink').addEventListener('pointerdown', interact);
433     document.getElementById('ink').addEventListener('lostpointercapture', interact);
434     document.getElementById('ink').addEventListener('pointerup', interact);
435     preventScrolling(document.getElementById('ink'));
436     surface.requestAnimationFrame(drawFrame);
437   }
438
439   function starPath(CanvasKit, X=128, Y=128, R=116) {
440     let p = new CanvasKit.Path();
441     p.moveTo(X + R, Y);
442     for (let i = 1; i < 8; i++) {
443       let a = 2.6927937 * i;
444       p.lineTo(X + R * Math.cos(a), Y + R * Math.sin(a));
445     }
446     return p;
447   }
448
449   function CanvasAPI1(CanvasKit) {
450     let skcanvas = CanvasKit.MakeCanvas(300, 300);
451     let realCanvas = document.getElementById('api1_c');
452
453     let skPromise   = fetch(cdn + 'test.png')
454                         // if clients want to use a Blob, they are responsible
455                         // for reading it themselves.
456                         .then((response) => response.arrayBuffer())
457                         .then((buffer) => {
458                           skcanvas._img = skcanvas.decodeImage(buffer);
459                         });
460     let realPromise = fetch(cdn + 'test.png')
461                         .then((response) => response.blob())
462                         .then((blob) => createImageBitmap(blob))
463                         .then((bitmap) => {
464                           realCanvas._img = bitmap;
465                         });
466
467     let realFontLoaded = new FontFace('Bungee', 'url(/tests/assets/Bungee-Regular.ttf)', {
468       'family': 'Bungee',
469       'style': 'normal',
470       'weight': '400',
471     }).load().then((font) => {
472       document.fonts.add(font);
473     });
474
475     let skFontLoaded = fetch('/tests/assets/Bungee-Regular.ttf').then(
476                              (response) => response.arrayBuffer()).then(
477                              (buffer) => {
478                                 // loadFont is synchronous
479                                 skcanvas.loadFont(buffer, {
480                                   'family': 'Bungee',
481                                   'style': 'normal',
482                                   'weight': '400',
483                                 });
484                               });
485
486     Promise.all([realPromise, skPromise, realFontLoaded, skFontLoaded]).then(() => {
487       for (let canvas of [skcanvas, realCanvas]) {
488         let ctx = canvas.getContext('2d');
489         ctx.fillStyle = '#EEE';
490         ctx.fillRect(0, 0, 300, 300);
491         ctx.fillStyle = 'black';
492         ctx.font = '26px Bungee';
493         ctx.rotate(.1);
494         let text = ctx.measureText('Awesome');
495         ctx.fillText('Awesome ', 25, 100);
496         ctx.strokeText('Groovy!', 35 + text.width, 100);
497
498         // Draw line under Awesome
499         ctx.strokeStyle = 'rgba(125,0,0,0.5)';
500         ctx.beginPath();
501         ctx.lineWidth = 6;
502         ctx.moveTo(25, 105);
503         ctx.lineTo(200, 105);
504         ctx.stroke();
505
506         // squished vertically
507         ctx.globalAlpha = 0.7;
508         ctx.imageSmoothingQuality = 'medium';
509         ctx.drawImage(canvas._img, 150, 150, 150, 100);
510         ctx.rotate(-.2);
511         ctx.imageSmoothingEnabled = false;
512         ctx.drawImage(canvas._img, 100, 150, 400, 350, 10, 200, 150, 100);
513
514         let idata = ctx.getImageData(80, 220, 40, 45);
515         ctx.putImageData(idata, 250, 10);
516         ctx.putImageData(idata, 200, 10, 20, 10, 20, 30);
517         ctx.resetTransform();
518         ctx.strokeStyle = 'black';
519         ctx.lineWidth = 1;
520         ctx.strokeRect(200, 10, 40, 45);
521
522         idata = ctx.createImageData(10, 20);
523         ctx.putImageData(idata, 10, 10);
524       }
525
526       document.getElementById('api1').src = skcanvas.toDataURL();
527       skcanvas.dispose();
528     });
529
530   }
531
532   function CanvasAPI2(CanvasKit) {
533     let skcanvas = CanvasKit.MakeCanvas(300, 300);
534     let realCanvas = document.getElementById('api2_c');
535     realCanvas.width = 300;
536     realCanvas.height = 300;
537
538     // svg data for a clock
539     skcanvas._path = skcanvas.makePath2D('M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8zm.5-13H11v6l5.25 3.15.75-1.23-4.5-2.67z');
540     realCanvas._path = new Path2D('M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8zm.5-13H11v6l5.25 3.15.75-1.23-4.5-2.67z');
541
542     for (let canvas of [skcanvas, realCanvas]) {
543       let ctx = canvas.getContext('2d');
544       ctx.scale(1.5, 1.5);
545       ctx.moveTo(20, 5);
546       ctx.lineTo(30, 20);
547       ctx.lineTo(40, 10);
548       ctx.lineTo(50, 20);
549       ctx.lineTo(60, 0);
550       ctx.lineTo(20, 5);
551
552       ctx.moveTo(20, 80);
553       ctx.bezierCurveTo(90, 10, 160, 150, 190, 10);
554
555       ctx.moveTo(36, 148);
556       ctx.quadraticCurveTo(66, 188, 120, 136);
557       ctx.lineTo(36, 148);
558
559       ctx.rect(5, 170, 20, 25);
560
561       ctx.moveTo(150, 180);
562       ctx.arcTo(150, 100, 50, 200, 20);
563       ctx.lineTo(160, 160);
564
565       ctx.moveTo(20, 120);
566       ctx.arc(20, 120, 18, 0, 1.75 * Math.PI);
567       ctx.lineTo(20, 120);
568
569       ctx.moveTo(150, 5);
570       ctx.ellipse(130, 25, 30, 10, -1*Math.PI/8, Math.PI/6, 1.5*Math.PI);
571
572       ctx.lineWidth = 4/3;
573       ctx.stroke();
574
575       // make a clock
576       ctx.stroke(canvas._path);
577
578       // Test edgecases and draw direction
579       ctx.beginPath();
580       ctx.arc(50, 100, 10, Math.PI, -Math.PI/2);
581       ctx.stroke();
582       ctx.beginPath();
583       ctx.arc(75, 100, 10, Math.PI, -Math.PI/2, true);
584       ctx.stroke();
585       ctx.beginPath();
586       ctx.arc(100, 100, 10, Math.PI, 100.1 * Math.PI, true);
587       ctx.stroke();
588       ctx.beginPath();
589       ctx.arc(125, 100, 10, Math.PI, 100.1 * Math.PI, false);
590       ctx.stroke();
591       ctx.beginPath();
592       ctx.ellipse(155, 100, 10, 15, Math.PI/8, 100.1 * Math.PI, Math.PI, true);
593       ctx.stroke();
594       ctx.beginPath();
595       ctx.ellipse(180, 100, 10, 15, Math.PI/8, Math.PI, 100.1 * Math.PI, true);
596       ctx.stroke();
597     }
598     document.getElementById('api2').src = skcanvas.toDataURL();
599     skcanvas.dispose();
600   }
601
602   function CanvasAPI3(CanvasKit) {
603     let skcanvas = CanvasKit.MakeCanvas(300, 300);
604     let realCanvas = document.getElementById('api3_c');
605     realCanvas.width = 300;
606     realCanvas.height = 300;
607
608     for (let canvas of [skcanvas, realCanvas]) {
609       let ctx = canvas.getContext('2d');
610       ctx.rect(10, 10, 20, 20);
611
612       ctx.scale(2.0, 4.0);
613       ctx.rect(30, 10, 20, 20);
614       ctx.resetTransform();
615
616       ctx.rotate(Math.PI / 3);
617       ctx.rect(50, 10, 20, 20);
618       ctx.resetTransform();
619
620       ctx.translate(30, -2);
621       ctx.rect(70, 10, 20, 20);
622       ctx.resetTransform();
623
624       ctx.translate(60, 0);
625       ctx.rotate(Math.PI / 6);
626       ctx.transform(1.5, 0, 0, 0.5, 0, 0); // effectively scale
627       ctx.rect(90, 10, 20, 20);
628       ctx.resetTransform();
629
630       ctx.save();
631       ctx.setTransform(2, 0, -.5, 2.5, -40, 120);
632       ctx.rect(110, 10, 20, 20);
633       ctx.lineTo(110, 0);
634       ctx.restore();
635       ctx.lineTo(220, 120);
636
637       ctx.scale(3.0, 3.0);
638       ctx.font = '6pt Noto Mono';
639       ctx.fillText('This text should be huge', 10, 80);
640       ctx.resetTransform();
641
642       ctx.strokeStyle = 'black';
643       ctx.lineWidth = 2;
644       ctx.stroke();
645
646       ctx.beginPath();
647       ctx.moveTo(250, 30);
648       ctx.lineTo(250, 80);
649       ctx.scale(3.0, 3.0);
650       ctx.lineTo(280/3, 90/3);
651       ctx.closePath();
652       ctx.strokeStyle = 'black';
653       ctx.lineWidth = 5;
654       ctx.stroke();
655
656     }
657     document.getElementById('api3').src = skcanvas.toDataURL();
658     skcanvas.dispose();
659   }
660
661   function CanvasAPI4(CanvasKit) {
662     let skcanvas = CanvasKit.MakeCanvas(300, 300);
663     let realCanvas = document.getElementById('api4_c');
664     realCanvas.width = 300;
665     realCanvas.height = 300;
666
667     for (let canvas of [skcanvas, realCanvas]) {
668       let ctx = canvas.getContext('2d');
669
670       ctx.strokeStyle = '#000';
671       ctx.fillStyle = '#CCC';
672       ctx.shadowColor = 'rebeccapurple';
673       ctx.shadowBlur = 1;
674       ctx.shadowOffsetX = 3;
675       ctx.shadowOffsetY = -8;
676       ctx.rect(10, 10, 30, 30);
677
678       ctx.save();
679       ctx.strokeStyle = '#C00';
680       ctx.fillStyle = '#00C';
681       ctx.shadowBlur = 0;
682       ctx.shadowColor = 'transparent';
683
684       ctx.stroke();
685
686       ctx.restore();
687       ctx.fill();
688
689       ctx.beginPath();
690       ctx.moveTo(36, 148);
691       ctx.quadraticCurveTo(66, 188, 120, 136);
692       ctx.closePath();
693       ctx.stroke();
694
695       ctx.beginPath();
696       ctx.shadowColor = '#993366AA';
697       ctx.shadowOffsetX = 8;
698       ctx.shadowBlur = 5;
699       ctx.setTransform(2, 0, -.5, 2.5, -40, 120);
700       ctx.rect(110, 10, 20, 20);
701       ctx.lineTo(110, 0);
702       ctx.resetTransform();
703       ctx.lineTo(220, 120);
704       ctx.stroke();
705
706       ctx.fillStyle = 'green';
707       ctx.font = '16pt Noto Mono';
708       ctx.fillText('This should be shadowed', 20, 80);
709
710       ctx.beginPath();
711       ctx.lineWidth = 6;
712       ctx.ellipse(10, 290, 30, 30, 0, 0, Math.PI * 2);
713       ctx.scale(2, 1);
714       ctx.moveTo(10, 290);
715       ctx.ellipse(10, 290, 30, 60, 0, 0, Math.PI * 2);
716       ctx.resetTransform();
717       ctx.scale(3, 1);
718       ctx.moveTo(10, 290);
719       ctx.ellipse(10, 290, 30, 90, 0, 0, Math.PI * 2);
720       ctx.stroke();
721     }
722     document.getElementById('api4').src = skcanvas.toDataURL();
723     skcanvas.dispose();
724   }
725
726   function CanvasAPI5(CanvasKit) {
727     let skcanvas = CanvasKit.MakeCanvas(600, 600);
728     let realCanvas = document.getElementById('api5_c');
729     realCanvas.width = 600;
730     realCanvas.height = 600;
731
732     for (let canvas of [skcanvas, realCanvas]) {
733       let ctx = canvas.getContext('2d');
734       ctx.scale(1.1, 1.1);
735       ctx.translate(10, 10);
736       // Shouldn't impact the fillRect calls
737       ctx.setLineDash([5, 3]);
738
739       ctx.fillStyle = 'rgba(200, 0, 100, 0.81)';
740       ctx.fillRect(20, 30, 100, 100);
741
742       ctx.globalAlpha = 0.81;
743       ctx.fillStyle = 'rgba(200, 0, 100, 1.0)';
744       ctx.fillRect(120, 30, 100, 100);
745       // This shouldn't do anything
746       ctx.globalAlpha = 0.1;
747
748       ctx.fillStyle = 'rgba(200, 0, 100, 0.9)';
749       ctx.globalAlpha = 0.9;
750       // Intentional no-op to check ordering
751       ctx.clearRect(220, 30, 100, 100);
752       ctx.fillRect(220, 30, 100, 100);
753
754       ctx.fillRect(320, 30, 100, 100);
755       ctx.clearRect(330, 40, 80, 80);
756
757       ctx.strokeStyle = 'blue';
758       ctx.lineWidth = 3;
759       ctx.setLineDash([5, 3]);
760       ctx.strokeRect(20, 150, 100, 100);
761       ctx.setLineDash([50, 30]);
762       ctx.strokeRect(125, 150, 100, 100);
763       ctx.lineDashOffset = 25;
764       ctx.strokeRect(230, 150, 100, 100);
765       ctx.setLineDash([2, 5, 9]);
766       ctx.strokeRect(335, 150, 100, 100);
767
768       ctx.setLineDash([5, 2]);
769       ctx.moveTo(336, 400);
770       ctx.quadraticCurveTo(366, 488, 120, 450);
771       ctx.lineTo(300, 400);
772       ctx.stroke();
773
774       ctx.font = '36pt Noto Mono';
775       ctx.strokeText('Dashed', 20, 350);
776       ctx.fillText('Not Dashed', 20, 400);
777
778     }
779     document.getElementById('api5').src = skcanvas.toDataURL();
780     skcanvas.dispose();
781   }
782
783   function CanvasAPI6(CanvasKit) {
784     let skcanvas = CanvasKit.MakeCanvas(600, 600);
785     let realCanvas = document.getElementById('api6_c');
786     realCanvas.width = 600;
787     realCanvas.height = 600;
788
789     for (let canvas of [skcanvas, realCanvas]) {
790       let ctx = canvas.getContext('2d');
791
792       let rgradient = ctx.createRadialGradient(200, 300, 10, 100, 100, 300);
793
794       // Add three color stops
795       rgradient.addColorStop(0, 'red');
796       rgradient.addColorStop(0.7, 'white');
797       rgradient.addColorStop(1, 'blue');
798
799       ctx.fillStyle = rgradient;
800       ctx.globalAlpha = 0.7;
801       ctx.fillRect(0, 0, 600, 600);
802       ctx.globalAlpha = 0.95;
803
804       ctx.beginPath();
805       ctx.arc(300, 100, 90, 0, Math.PI*1.66);
806       ctx.closePath();
807       ctx.strokeStyle = 'yellow';
808       ctx.lineWidth = 5;
809       ctx.stroke();
810       ctx.save();
811       ctx.clip();
812
813       let lgradient = ctx.createLinearGradient(200, 20, 420, 40);
814
815       // Add three color stops
816       lgradient.addColorStop(0, 'green');
817       lgradient.addColorStop(0.5, 'cyan');
818       lgradient.addColorStop(1, 'orange');
819
820       ctx.fillStyle = lgradient;
821
822       ctx.fillRect(200, 30, 200, 300);
823
824       ctx.restore();
825       ctx.fillRect(550, 550, 40, 40);
826
827     }
828     document.getElementById('api6').src = skcanvas.toDataURL();
829     skcanvas.dispose();
830   }
831
832   function CanvasAPI7(CanvasKit) {
833     let skcanvas = CanvasKit.MakeCanvas(300, 300);
834     let realCanvas = document.getElementById('api7_c');
835
836     let skPromise   = fetch(cdn + 'test.png')
837                         // if clients want to use a Blob, they are responsible
838                         // for reading it themselves.
839                         .then((response) => response.arrayBuffer())
840                         .then((buffer) => {
841                           skcanvas._img = skcanvas.decodeImage(buffer);
842                         });
843     let realPromise = fetch(cdn + 'test.png')
844                         .then((response) => response.blob())
845                         .then((blob) => createImageBitmap(blob))
846                         .then((bitmap) => {
847                           realCanvas._img = bitmap;
848                         });
849
850
851     Promise.all([realPromise, skPromise]).then(() => {
852       for (let canvas of [skcanvas, realCanvas]) {
853         let ctx = canvas.getContext('2d');
854         ctx.fillStyle = '#EEE';
855         ctx.fillRect(0, 0, 300, 300);
856         ctx.lineWidth = 20;
857         ctx.scale(0.1, 0.2);
858
859         let pattern = ctx.createPattern(canvas._img, 'repeat');
860         ctx.fillStyle = pattern;
861         ctx.fillRect(0, 0, 1500, 750);
862
863         pattern = ctx.createPattern(canvas._img, 'repeat-x');
864         ctx.fillStyle = pattern;
865         ctx.fillRect(1500, 0, 3000, 750);
866
867         ctx.globalAlpha = 0.7;
868         pattern = ctx.createPattern(canvas._img, 'repeat-y');
869         ctx.fillStyle = pattern;
870         ctx.fillRect(0, 750, 1500, 1500);
871         ctx.strokeRect(0, 750, 1500, 1500);
872
873         pattern = ctx.createPattern(canvas._img, 'no-repeat');
874         ctx.fillStyle = pattern;
875         pattern.setTransform({a: 1, b: -.1, c:.1, d: 0.5, e: 1800, f:800});
876         ctx.fillRect(0, 0, 3000, 1500);
877       }
878
879       document.getElementById('api7').src = skcanvas.toDataURL();
880       skcanvas.dispose();
881     });
882   }
883
884   function CanvasAPI8(CanvasKit) {
885     let skcanvas = CanvasKit.MakeCanvas(300, 300);
886     let realCanvas = document.getElementById('api8_c');
887
888     function drawPoint(ctx, x, y, color) {
889       ctx.fillStyle = color;
890       ctx.fillRect(x, y, 1, 1);
891     }
892     const IN = 'purple';
893     const OUT = 'orange';
894     const SCALE = 4;
895
896     const pts = [[3, 3], [4, 4], [5, 5], [10, 10], [8, 10], [6, 10],
897                  [6.5, 9], [15, 10], [17, 10], [17, 11], [24, 24],
898                  [25, 25], [26, 26], [27, 27]];
899
900     const tests = [
901       {
902         xOffset: 0,
903         yOffset: 0,
904         fillType: 'nonzero',
905         strokeWidth: 0,
906         testFn: (ctx, x, y) => ctx.isPointInPath(x * SCALE, y * SCALE, 'nonzero'),
907       },
908       {
909         xOffset: 30,
910         yOffset: 0,
911         fillType: 'evenodd',
912         strokeWidth: 0,
913         testFn: (ctx, x, y) => ctx.isPointInPath(x * SCALE, y * SCALE, 'evenodd'),
914       },
915       {
916         xOffset: 0,
917         yOffset: 30,
918         fillType: null,
919         strokeWidth: 1,
920         testFn: (ctx, x, y) => ctx.isPointInStroke(x * SCALE, y * SCALE),
921       },
922       {
923         xOffset: 30,
924         yOffset: 30,
925         fillType: null,
926         strokeWidth: 2,
927         testFn: (ctx, x, y) => ctx.isPointInStroke(x * SCALE, y * SCALE),
928       },
929     ];
930
931     for (let canvas of [skcanvas, realCanvas]) {
932       let ctx = canvas.getContext('2d');
933       ctx.font = '11px Noto Mono';
934       // Draw some visual aids
935       ctx.fillText('path-nonzero', 30, 15);
936       ctx.fillText('path-evenodd', 150, 15);
937       ctx.fillText('stroke-1px-wide', 30, 130);
938       ctx.fillText('stroke-2px-wide', 150, 130);
939       ctx.fillText('purple is IN, orange is OUT', 10, 280);
940
941       // Scale up to make single pixels easier to see
942       ctx.scale(SCALE, SCALE);
943       for (let test of tests) {
944         ctx.beginPath();
945         let xOffset = test.xOffset;
946         let yOffset = test.yOffset;
947
948         ctx.fillStyle = '#AAA';
949         ctx.lineWidth = test.strokeWidth;
950         ctx.rect(5+xOffset, 5+yOffset, 20, 20);
951         ctx.arc(15+xOffset, 15+yOffset, 8, 0, Math.PI*2, false);
952         if (test.fillType) {
953           ctx.fill(test.fillType);
954         } else {
955           ctx.stroke();
956         }
957
958         for (let pt of pts) {
959           let [x, y] = pt;
960           x += xOffset;
961           y += yOffset;
962           // naively apply transform when querying because the points queried
963           // ignore the CTM.
964           if (test.testFn(ctx, x, y)) {
965             drawPoint(ctx, x, y, IN);
966           } else {
967             drawPoint(ctx, x, y, OUT);
968           }
969         }
970       }
971     }
972
973     document.getElementById('api8').src = skcanvas.toDataURL();
974     skcanvas.dispose();
975   }
976
977   function VertexAPI1(CanvasKit) {
978     const surface = CanvasKit.MakeCanvasSurface('vertex1');
979     if (!surface) {
980       console.error('Could not make surface');
981       return;
982     }
983     const canvas = surface.getCanvas();
984     let paint = new CanvasKit.Paint();
985
986     // See https://fiddle.skia.org/c/f48b22eaad1bb7adcc3faaa321754af6
987     // for original c++ version.
988     let points = [0, 0,  250, 0,  100, 100,  0, 250];
989     let colors = [CanvasKit.RED, CanvasKit.BLUE,
990                   CanvasKit.YELLOW, CanvasKit.CYAN];
991     let vertices = CanvasKit.MakeVertices(CanvasKit.VertexMode.TriangleFan,
992                                             points, null, colors,
993                                             false /*isVolatile*/);
994
995     canvas.drawVertices(vertices, CanvasKit.BlendMode.Dst, paint);
996
997     vertices.delete();
998
999     // See https://fiddle.skia.org/c/e8bdae9bea3227758989028424fcac3d
1000     // for original c++ version.
1001     points   = [300, 300,  50, 300,  200, 200,  300, 50 ];
1002     let texs = [  0,   0,   0, 250,  250, 250,  250,  0 ];
1003     vertices = CanvasKit.MakeVertices(CanvasKit.VertexMode.TriangleFan,
1004                                             points, texs, colors);
1005
1006     let shader = CanvasKit.Shader.MakeLinearGradient([0, 0], [250, 0],
1007             colors, null, CanvasKit.TileMode.Clamp);
1008     paint.setShader(shader);
1009
1010     canvas.drawVertices(vertices, CanvasKit.BlendMode.Darken, paint);
1011     surface.flush();
1012
1013     shader.delete();
1014     paint.delete();
1015     surface.delete();
1016   }
1017
1018   function GradiantAPI1(CanvasKit) {
1019     const surface = CanvasKit.MakeSWCanvasSurface('gradient1');
1020     if (!surface) {
1021       console.error('Could not make surface');
1022       return;
1023     }
1024     const canvas = surface.getCanvas();
1025     let paint = new CanvasKit.Paint();
1026
1027     // See https://fiddle.skia.org/c/f48b22eaad1bb7adcc3faaa321754af6
1028     // for original c++ version.
1029     let colors = [CanvasKit.BLUE, CanvasKit.YELLOW, CanvasKit.RED];
1030     let pos =    [0, .7, 1.0];
1031     let transform = [2, 0, 0,
1032                      0, 2, 0,
1033                      0, 0, 1];
1034     let shader = CanvasKit.Shader.MakeRadialGradient([150, 150], 130, colors,
1035                               pos, CanvasKit.TileMode.Mirror, transform);
1036
1037     paint.setShader(shader);
1038     const textFont = new CanvasKit.Font(null, 75);
1039     const textBlob = CanvasKit.TextBlob.MakeFromText('Radial', textFont);
1040
1041     canvas.drawTextBlob(textBlob, 10, 200, paint);
1042     paint.delete();
1043     textFont.delete();
1044     textBlob.delete();
1045     surface.flush();
1046   }
1047
1048   function TextOnPathAPI1(CanvasKit) {
1049     const surface = CanvasKit.MakeSWCanvasSurface('textonpath');
1050     if (!surface) {
1051       console.error('Could not make surface');
1052       return;
1053     }
1054     const canvas = surface.getCanvas();
1055     const paint = new CanvasKit.Paint();
1056     paint.setStyle(CanvasKit.PaintStyle.Stroke);
1057     paint.setAntiAlias(true);
1058
1059     const font = new CanvasKit.Font(null, 24);
1060     const fontPaint = new CanvasKit.Paint();
1061     fontPaint.setStyle(CanvasKit.PaintStyle.Fill);
1062     fontPaint.setAntiAlias(true);
1063
1064     const arc = new CanvasKit.Path();
1065     arc.arcToOval(CanvasKit.LTRBRect(20, 40, 280, 300), -160, 140, true);
1066     arc.lineTo(210, 140);
1067     arc.arcToOval(CanvasKit.LTRBRect(20, 0, 280, 260), 160, -140, true);
1068
1069     const str = 'This téxt should follow the curve across contours...';
1070     const textBlob = CanvasKit.TextBlob.MakeOnPath(str, arc, font);
1071
1072     canvas.drawPath(arc, paint);
1073     canvas.drawTextBlob(textBlob, 0, 0, fontPaint);
1074
1075     surface.flush();
1076
1077     textBlob.delete();
1078     arc.delete();
1079     paint.delete();
1080     font.delete();
1081     fontPaint.delete();
1082   }
1083
1084     function DrawGlyphsAPI1(CanvasKit) {
1085         const surface = CanvasKit.MakeSWCanvasSurface('drawGlyphs');
1086         if (!surface) {
1087             console.error('Could not make surface');
1088             return;
1089         }
1090         const canvas = surface.getCanvas();
1091         const paint = new CanvasKit.Paint();
1092         const font = new CanvasKit.Font(null, 16);
1093         paint.setAntiAlias(true);
1094
1095         let glyphs = [];
1096         let positions = [];
1097         for (let i = 0; i < 256; ++i) {
1098             glyphs.push(i);
1099             positions.push((i % 16) * 16);
1100             positions.push(Math.round(i/16) * 16);
1101         }
1102         canvas.drawGlyphs(glyphs, positions, 16, 20, font, paint);
1103
1104         surface.flush();
1105
1106         paint.delete();
1107         font.delete();
1108     }
1109
1110   function SurfaceAPI1(CanvasKit) {
1111     const surface = CanvasKit.MakeCanvasSurface('surfaces');
1112     if (!surface) {
1113       console.error('Could not make surface');
1114       return;
1115     }
1116
1117     // create a subsurface as a temporary workspace.
1118     const subSurface = surface.makeSurface({
1119       width: 50,
1120       height: 50,
1121       alphaType: CanvasKit.AlphaType.Premul,
1122       colorType: CanvasKit.ColorType.RGBA_8888,
1123       colorSpace: CanvasKit.ColorSpace.SRGB,
1124     });
1125
1126     if (!subSurface) {
1127       console.error('Could not make subsurface');
1128       return;
1129     }
1130
1131     // draw a small "scene"
1132     const paint = new CanvasKit.Paint();
1133     paint.setColor(CanvasKit.Color(139, 228, 135, 0.95)); // greenish
1134     paint.setStyle(CanvasKit.PaintStyle.Fill);
1135     paint.setAntiAlias(true);
1136
1137     const subCanvas = subSurface.getCanvas();
1138     subCanvas.clear(CanvasKit.BLACK);
1139     subCanvas.drawRect(CanvasKit.LTRBRect(5, 15, 45, 40), paint);
1140
1141     paint.setColor(CanvasKit.Color(214, 93, 244)); // purplish
1142     for (let i = 0; i < 10; i++) {
1143       const x = Math.random() * 50;
1144       const y = Math.random() * 50;
1145
1146       subCanvas.drawOval(CanvasKit.XYWHRect(x, y, 6, 6), paint);
1147     }
1148
1149     // Snap it off as an Image - this image will be in the form the
1150     // parent surface prefers (e.g. Texture for GPU / Raster for CPU).
1151     const img = subSurface.makeImageSnapshot();
1152
1153     // clean up the temporary surface (which also cleans up subCanvas)
1154     subSurface.delete();
1155     paint.delete();
1156
1157     // Make it repeat a bunch with a shader
1158     const pattern = img.makeShaderCubic(CanvasKit.TileMode.Repeat, CanvasKit.TileMode.Mirror,
1159                                         1/3, 1/3);
1160     const patternPaint = new CanvasKit.Paint();
1161     patternPaint.setShader(pattern);
1162
1163     let i = 0;
1164
1165     function drawFrame(canvas) {
1166       i++;
1167       canvas.clear(CanvasKit.WHITE);
1168
1169       canvas.drawOval(CanvasKit.LTRBRect(i % 60, i % 60, 300 - (i% 60), 300 - (i % 60)), patternPaint);
1170       surface.requestAnimationFrame(drawFrame);
1171     }
1172     surface.requestAnimationFrame(drawFrame);
1173   }
1174
1175   function AtlasAPI1(CanvasKit, imgData) {
1176     if (!CanvasKit || !imgData) {
1177       return;
1178     }
1179     const surface = CanvasKit.MakeCanvasSurface('atlas');
1180     if (!surface) {
1181       console.error('Could not make surface');
1182       return;
1183     }
1184     const img = CanvasKit.MakeImageFromEncoded(imgData);
1185
1186     const paint = new CanvasKit.Paint();
1187     paint.setColor(CanvasKit.Color(0, 0, 0, 0.8));
1188
1189     // Allocate space for 2 rectangles.
1190     const srcs = CanvasKit.Malloc(Float32Array, 8);
1191     srcs.toTypedArray().set([
1192       0, 0, 250, 250, // LTRB
1193       250, 0, 500, 250
1194     ]);
1195
1196     // Allocate space for 2 RSXForms
1197     const dsts = CanvasKit.Malloc(Float32Array, 8);
1198     dsts.toTypedArray().set([
1199       .5, 0, 0, 0,  // scos, ssin, tx, ty
1200       0, .8, 200, 100
1201     ]);
1202
1203    // Allocate space for 4 colors.
1204     const colors = new CanvasKit.Malloc(Uint32Array, 2);
1205     colors.toTypedArray().set([
1206       CanvasKit.ColorAsInt( 85, 170,  10, 128), // light green
1207       CanvasKit.ColorAsInt( 51,  51, 191, 128), // light blue
1208     ]);
1209
1210     let i = 0;
1211
1212     function drawFrame(canvas) {
1213       canvas.clear(CanvasKit.WHITE);
1214       i++;
1215       let scale = 0.5 + Math.sin(i/40)/4;
1216
1217       // update the coordinates of existing sprites - note that this
1218       // does not require a full re-copy of the full array; they are
1219       // updated in-place.
1220       dsts.toTypedArray().set([0.5, 0, (2*i)%200, (5*Math.round(i/200)) % 200], 0);
1221       dsts.toTypedArray().set([scale*Math.sin(i/20), scale*Math.cos(i/20), 200, 100], 4);
1222
1223       canvas.drawAtlas(img, srcs, dsts, paint, CanvasKit.BlendMode.Plus, colors,
1224                        {filter: CanvasKit.FilterMode.Nearest});
1225       surface.requestAnimationFrame(drawFrame);
1226     }
1227     surface.requestAnimationFrame(drawFrame);
1228
1229   }
1230
1231   async function DecodeAPI(CanvasKit, imgData) {
1232     if (!CanvasKit || !imgData) {
1233       return;
1234     }
1235     const surface = CanvasKit.MakeCanvasSurface('decode');
1236     if (!surface) {
1237       console.error('Could not make surface');
1238       return;
1239     }
1240     const blob = new Blob([ imgData ]);
1241     // ImageBitmap is not supported in Safari
1242     const imageBitmap = await createImageBitmap(blob);
1243     const img = await CanvasKit.MakeImageFromCanvasImageSource(imageBitmap);
1244
1245     surface.drawOnce((canvas) => {
1246       canvas.drawImage(img, 0, 0, null);
1247     });
1248   }
1249 </script>