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