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