1*c8dee2aaSAndroid Build Coastguard Worker<!DOCTYPE html> 2*c8dee2aaSAndroid Build Coastguard Worker<title>CanvasKit Extra features (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 { 9*c8dee2aaSAndroid Build Coastguard Worker border: 1px dashed #AAA; 10*c8dee2aaSAndroid Build Coastguard Worker } 11*c8dee2aaSAndroid Build Coastguard Worker #sk_legos,#sk_drinks,#sk_party,#sk_onboarding, #sk_animated_gif { 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> Skottie </h2> 19*c8dee2aaSAndroid Build Coastguard Worker<canvas id=sk_legos width=300 height=300></canvas> 20*c8dee2aaSAndroid Build Coastguard Worker<canvas id=sk_drinks width=500 height=500></canvas> 21*c8dee2aaSAndroid Build Coastguard Worker<canvas id=sk_party width=500 height=500></canvas> 22*c8dee2aaSAndroid Build Coastguard Worker<canvas id=sk_onboarding width=500 height=500></canvas> 23*c8dee2aaSAndroid Build Coastguard Worker<canvas id=sk_animated_gif width=500 height=500 24*c8dee2aaSAndroid Build Coastguard Worker title='This is an animated gif being animated in Skottie'></canvas> 25*c8dee2aaSAndroid Build Coastguard Worker 26*c8dee2aaSAndroid Build Coastguard Worker<h2> RT Shader </h2> 27*c8dee2aaSAndroid Build Coastguard Worker<canvas id=rtshader width=300 height=300></canvas> 28*c8dee2aaSAndroid Build Coastguard Worker<canvas id=rtshader2 width=300 height=300></canvas> 29*c8dee2aaSAndroid Build Coastguard Worker 30*c8dee2aaSAndroid Build Coastguard Worker<h2> Paragraph </h2> 31*c8dee2aaSAndroid Build Coastguard Worker<canvas id=para1 width=600 height=600></canvas> 32*c8dee2aaSAndroid Build Coastguard Worker<canvas id=para2 width=600 height=600 tabindex='-1'></canvas> 33*c8dee2aaSAndroid Build Coastguard Worker<canvas id=para3 width=600 height=600 tabindex='-1'></canvas> 34*c8dee2aaSAndroid Build Coastguard Worker`` 35*c8dee2aaSAndroid Build Coastguard Worker<h2> CanvasKit can serialize/deserialize .skp files</h2> 36*c8dee2aaSAndroid Build Coastguard Worker<canvas id=skp width=500 height=500></canvas> 37*c8dee2aaSAndroid Build Coastguard Worker 38*c8dee2aaSAndroid Build Coastguard Worker<h2> 3D perspective transformations </h2> 39*c8dee2aaSAndroid Build Coastguard Worker<canvas id=glyphgame width=500 height=500></canvas> 40*c8dee2aaSAndroid Build Coastguard Worker 41*c8dee2aaSAndroid Build Coastguard Worker<h2> Support for extended color spaces </h2> 42*c8dee2aaSAndroid Build Coastguard Worker<a href="chrome://flags/#force-color-profile">Force P3 profile</a> 43*c8dee2aaSAndroid Build Coastguard Worker<canvas id=colorsupport width=300 height=300></canvas> 44*c8dee2aaSAndroid Build Coastguard Worker 45*c8dee2aaSAndroid Build Coastguard Worker<script type="text/javascript" src="/build/canvaskit.js"></script> 46*c8dee2aaSAndroid Build Coastguard Worker 47*c8dee2aaSAndroid Build Coastguard Worker<script type="text/javascript" src="textapi_utils.js"></script> 48*c8dee2aaSAndroid Build Coastguard Worker 49*c8dee2aaSAndroid Build Coastguard Worker<script type="text/javascript" charset="utf-8"> 50*c8dee2aaSAndroid Build Coastguard Worker 51*c8dee2aaSAndroid Build Coastguard Worker var CanvasKit = null; 52*c8dee2aaSAndroid Build Coastguard Worker var cdn = 'https://storage.googleapis.com/skia-cdn/misc/'; 53*c8dee2aaSAndroid Build Coastguard Worker 54*c8dee2aaSAndroid Build Coastguard Worker const ckLoaded = CanvasKitInit({locateFile: (file) => '/build/'+file}); 55*c8dee2aaSAndroid Build Coastguard Worker 56*c8dee2aaSAndroid Build Coastguard Worker const loadLegoJSON = fetch(cdn + 'lego_loader.json').then((response) => response.text()); 57*c8dee2aaSAndroid Build Coastguard Worker const loadDrinksJSON = fetch(cdn + 'drinks.json').then((response) => response.text()); 58*c8dee2aaSAndroid Build Coastguard Worker const loadConfettiJSON = fetch(cdn + 'confetti.json').then((response) => response.text()); 59*c8dee2aaSAndroid Build Coastguard Worker const loadOnboardingJSON = fetch(cdn + 'onboarding.json').then((response) => response.text()); 60*c8dee2aaSAndroid Build Coastguard Worker const loadMultiframeJSON = fetch(cdn + 'skottie_sample_multiframe.json').then((response) => response.text()); 61*c8dee2aaSAndroid Build Coastguard Worker 62*c8dee2aaSAndroid Build Coastguard Worker const loadFlightGif = fetch(cdn + 'flightAnim.gif').then((response) => response.arrayBuffer()); 63*c8dee2aaSAndroid Build Coastguard Worker const loadFont = fetch(cdn + 'Roboto-Regular.ttf').then((response) => response.arrayBuffer()); 64*c8dee2aaSAndroid Build Coastguard Worker const loadDog = fetch(cdn + 'dog.jpg').then((response) => response.arrayBuffer()); 65*c8dee2aaSAndroid Build Coastguard Worker const loadMandrill = fetch(cdn + 'mandrill_256.png').then((response) => response.arrayBuffer()); 66*c8dee2aaSAndroid Build Coastguard Worker const loadBrickTex = fetch(cdn + 'brickwork-texture.jpg').then((response) => response.arrayBuffer()); 67*c8dee2aaSAndroid Build Coastguard Worker const loadBrickBump = fetch(cdn + 'brickwork_normal-map.jpg').then((response) => response.arrayBuffer()); 68*c8dee2aaSAndroid Build Coastguard Worker 69*c8dee2aaSAndroid Build Coastguard Worker // Examples which only require canvaskit 70*c8dee2aaSAndroid Build Coastguard Worker ckLoaded.then((CK) => { 71*c8dee2aaSAndroid Build Coastguard Worker CanvasKit = CK; 72*c8dee2aaSAndroid Build Coastguard Worker RTShaderAPI1(CanvasKit); 73*c8dee2aaSAndroid Build Coastguard Worker ColorSupport(CanvasKit); 74*c8dee2aaSAndroid Build Coastguard Worker SkpExample(CanvasKit); 75*c8dee2aaSAndroid Build Coastguard Worker }); 76*c8dee2aaSAndroid Build Coastguard Worker 77*c8dee2aaSAndroid Build Coastguard Worker // Examples requiring external resources. 78*c8dee2aaSAndroid Build Coastguard Worker // Set bounds to fix the 4:3 resolution of the legos 79*c8dee2aaSAndroid Build Coastguard Worker Promise.all([ckLoaded, loadLegoJSON]).then(([ck, jsonstr]) => { 80*c8dee2aaSAndroid Build Coastguard Worker SkottieExample(ck, 'sk_legos', jsonstr, [-50, 0, 350, 300]); 81*c8dee2aaSAndroid Build Coastguard Worker }); 82*c8dee2aaSAndroid Build Coastguard Worker // Re-size to fit 83*c8dee2aaSAndroid Build Coastguard Worker let fullBounds = [0, 0, 500, 500]; 84*c8dee2aaSAndroid Build Coastguard Worker Promise.all([ckLoaded, loadDrinksJSON]).then(([ck, jsonstr]) => { 85*c8dee2aaSAndroid Build Coastguard Worker SkottieExample(ck, 'sk_drinks', jsonstr, fullBounds); 86*c8dee2aaSAndroid Build Coastguard Worker }); 87*c8dee2aaSAndroid Build Coastguard Worker Promise.all([ckLoaded, loadConfettiJSON]).then(([ck, jsonstr]) => { 88*c8dee2aaSAndroid Build Coastguard Worker SkottieExample(ck, 'sk_party', jsonstr, fullBounds); 89*c8dee2aaSAndroid Build Coastguard Worker }); 90*c8dee2aaSAndroid Build Coastguard Worker Promise.all([ckLoaded, loadOnboardingJSON]).then(([ck, jsonstr]) => { 91*c8dee2aaSAndroid Build Coastguard Worker SkottieExample(ck, 'sk_onboarding', jsonstr, fullBounds); 92*c8dee2aaSAndroid Build Coastguard Worker }); 93*c8dee2aaSAndroid Build Coastguard Worker Promise.all([ckLoaded, loadMultiframeJSON, loadFlightGif]).then(([ck, jsonstr, gif]) => { 94*c8dee2aaSAndroid Build Coastguard Worker SkottieExample(ck, 'sk_animated_gif', jsonstr, fullBounds, {'image_0.png': gif}); 95*c8dee2aaSAndroid Build Coastguard Worker }); 96*c8dee2aaSAndroid Build Coastguard Worker 97*c8dee2aaSAndroid Build Coastguard Worker Promise.all([ckLoaded, loadFont]).then((results) => { 98*c8dee2aaSAndroid Build Coastguard Worker ParagraphAPI1(...results); 99*c8dee2aaSAndroid Build Coastguard Worker ParagraphAPI2(...results); 100*c8dee2aaSAndroid Build Coastguard Worker ParagraphAPI3(...results); 101*c8dee2aaSAndroid Build Coastguard Worker GlyphGame(...results) 102*c8dee2aaSAndroid Build Coastguard Worker }); 103*c8dee2aaSAndroid Build Coastguard Worker 104*c8dee2aaSAndroid Build Coastguard Worker const rectLeft = 0; 105*c8dee2aaSAndroid Build Coastguard Worker const rectTop = 1; 106*c8dee2aaSAndroid Build Coastguard Worker const rectRight = 2; 107*c8dee2aaSAndroid Build Coastguard Worker const rectBottom = 3; 108*c8dee2aaSAndroid Build Coastguard Worker 109*c8dee2aaSAndroid Build Coastguard Worker function SkottieExample(CanvasKit, id, jsonStr, bounds, assets) { 110*c8dee2aaSAndroid Build Coastguard Worker if (!CanvasKit || !jsonStr) { 111*c8dee2aaSAndroid Build Coastguard Worker return; 112*c8dee2aaSAndroid Build Coastguard Worker } 113*c8dee2aaSAndroid Build Coastguard Worker const animation = CanvasKit.MakeManagedAnimation(jsonStr, assets); 114*c8dee2aaSAndroid Build Coastguard Worker const duration = animation.duration() * 1000; 115*c8dee2aaSAndroid Build Coastguard Worker const size = animation.size(); 116*c8dee2aaSAndroid Build Coastguard Worker let c = document.getElementById(id); 117*c8dee2aaSAndroid Build Coastguard Worker bounds = bounds || CanvasKit.LTRBRect(0, 0, size.w, size.h); 118*c8dee2aaSAndroid Build Coastguard Worker 119*c8dee2aaSAndroid Build Coastguard Worker // Basic managed animation test. 120*c8dee2aaSAndroid Build Coastguard Worker if (id === 'sk_drinks') { 121*c8dee2aaSAndroid Build Coastguard Worker animation.setColor('BACKGROUND_FILL', CanvasKit.Color(0, 163, 199, 1.0)); 122*c8dee2aaSAndroid Build Coastguard Worker } 123*c8dee2aaSAndroid Build Coastguard Worker 124*c8dee2aaSAndroid Build Coastguard Worker const surface = CanvasKit.MakeCanvasSurface(id); 125*c8dee2aaSAndroid Build Coastguard Worker if (!surface) { 126*c8dee2aaSAndroid Build Coastguard Worker console.error('Could not make surface'); 127*c8dee2aaSAndroid Build Coastguard Worker return; 128*c8dee2aaSAndroid Build Coastguard Worker } 129*c8dee2aaSAndroid Build Coastguard Worker 130*c8dee2aaSAndroid Build Coastguard Worker let firstFrame = Date.now(); 131*c8dee2aaSAndroid Build Coastguard Worker 132*c8dee2aaSAndroid Build Coastguard Worker function drawFrame(canvas) { 133*c8dee2aaSAndroid Build Coastguard Worker let seek = ((Date.now() - firstFrame) / duration) % 1.0; 134*c8dee2aaSAndroid Build Coastguard Worker let damage = animation.seek(seek); 135*c8dee2aaSAndroid Build Coastguard Worker 136*c8dee2aaSAndroid Build Coastguard Worker if (damage[rectRight] > damage[rectLeft] && damage[rectBottom] > damage[rectTop]) { 137*c8dee2aaSAndroid Build Coastguard Worker canvas.clear(CanvasKit.WHITE); 138*c8dee2aaSAndroid Build Coastguard Worker animation.render(canvas, bounds); 139*c8dee2aaSAndroid Build Coastguard Worker } 140*c8dee2aaSAndroid Build Coastguard Worker surface.requestAnimationFrame(drawFrame); 141*c8dee2aaSAndroid Build Coastguard Worker } 142*c8dee2aaSAndroid Build Coastguard Worker surface.requestAnimationFrame(drawFrame); 143*c8dee2aaSAndroid Build Coastguard Worker 144*c8dee2aaSAndroid Build Coastguard Worker return surface; 145*c8dee2aaSAndroid Build Coastguard Worker } 146*c8dee2aaSAndroid Build Coastguard Worker 147*c8dee2aaSAndroid Build Coastguard Worker function ParagraphAPI1(CanvasKit, fontData) { 148*c8dee2aaSAndroid Build Coastguard Worker if (!CanvasKit || !fontData) { 149*c8dee2aaSAndroid Build Coastguard Worker return; 150*c8dee2aaSAndroid Build Coastguard Worker } 151*c8dee2aaSAndroid Build Coastguard Worker 152*c8dee2aaSAndroid Build Coastguard Worker const surface = CanvasKit.MakeCanvasSurface('para1'); 153*c8dee2aaSAndroid Build Coastguard Worker if (!surface) { 154*c8dee2aaSAndroid Build Coastguard Worker console.error('Could not make surface'); 155*c8dee2aaSAndroid Build Coastguard Worker return; 156*c8dee2aaSAndroid Build Coastguard Worker } 157*c8dee2aaSAndroid Build Coastguard Worker 158*c8dee2aaSAndroid Build Coastguard Worker const canvas = surface.getCanvas(); 159*c8dee2aaSAndroid Build Coastguard Worker const fontMgr = CanvasKit.FontMgr.FromData([fontData]); 160*c8dee2aaSAndroid Build Coastguard Worker 161*c8dee2aaSAndroid Build Coastguard Worker const paraStyle = new CanvasKit.ParagraphStyle({ 162*c8dee2aaSAndroid Build Coastguard Worker textStyle: { 163*c8dee2aaSAndroid Build Coastguard Worker color: CanvasKit.BLACK, 164*c8dee2aaSAndroid Build Coastguard Worker fontFamilies: ['Roboto'], 165*c8dee2aaSAndroid Build Coastguard Worker fontSize: 50, 166*c8dee2aaSAndroid Build Coastguard Worker }, 167*c8dee2aaSAndroid Build Coastguard Worker textAlign: CanvasKit.TextAlign.Left, 168*c8dee2aaSAndroid Build Coastguard Worker maxLines: 5, 169*c8dee2aaSAndroid Build Coastguard Worker }); 170*c8dee2aaSAndroid Build Coastguard Worker 171*c8dee2aaSAndroid Build Coastguard Worker const builder = CanvasKit.ParagraphBuilder.Make(paraStyle, fontMgr); 172*c8dee2aaSAndroid Build Coastguard Worker builder.addText('The quick brown fox ate a hamburgerfons and got sick.'); 173*c8dee2aaSAndroid Build Coastguard Worker const paragraph = builder.build(); 174*c8dee2aaSAndroid Build Coastguard Worker 175*c8dee2aaSAndroid Build Coastguard Worker let wrapTo = 0; 176*c8dee2aaSAndroid Build Coastguard Worker 177*c8dee2aaSAndroid Build Coastguard Worker let X = 100; 178*c8dee2aaSAndroid Build Coastguard Worker let Y = 100; 179*c8dee2aaSAndroid Build Coastguard Worker 180*c8dee2aaSAndroid Build Coastguard Worker const fontPaint = new CanvasKit.Paint(); 181*c8dee2aaSAndroid Build Coastguard Worker fontPaint.setStyle(CanvasKit.PaintStyle.Fill); 182*c8dee2aaSAndroid Build Coastguard Worker fontPaint.setAntiAlias(true); 183*c8dee2aaSAndroid Build Coastguard Worker 184*c8dee2aaSAndroid Build Coastguard Worker function drawFrame(canvas) { 185*c8dee2aaSAndroid Build Coastguard Worker canvas.clear(CanvasKit.WHITE); 186*c8dee2aaSAndroid Build Coastguard Worker wrapTo = 350 + 150 * Math.sin(Date.now() / 2000); 187*c8dee2aaSAndroid Build Coastguard Worker paragraph.layout(wrapTo); 188*c8dee2aaSAndroid Build Coastguard Worker canvas.drawParagraph(paragraph, 0, 0); 189*c8dee2aaSAndroid Build Coastguard Worker 190*c8dee2aaSAndroid Build Coastguard Worker canvas.drawLine(wrapTo, 0, wrapTo, 400, fontPaint); 191*c8dee2aaSAndroid Build Coastguard Worker 192*c8dee2aaSAndroid Build Coastguard Worker surface.requestAnimationFrame(drawFrame); 193*c8dee2aaSAndroid Build Coastguard Worker } 194*c8dee2aaSAndroid Build Coastguard Worker surface.requestAnimationFrame(drawFrame); 195*c8dee2aaSAndroid Build Coastguard Worker 196*c8dee2aaSAndroid Build Coastguard Worker let interact = (e) => { 197*c8dee2aaSAndroid Build Coastguard Worker X = e.offsetX*2; // multiply by 2 because the canvas is 300 css pixels wide, 198*c8dee2aaSAndroid Build Coastguard Worker Y = e.offsetY*2; // but the canvas itself is 600px wide 199*c8dee2aaSAndroid Build Coastguard Worker }; 200*c8dee2aaSAndroid Build Coastguard Worker 201*c8dee2aaSAndroid Build Coastguard Worker document.getElementById('para1').addEventListener('pointermove', interact); 202*c8dee2aaSAndroid Build Coastguard Worker return surface; 203*c8dee2aaSAndroid Build Coastguard Worker } 204*c8dee2aaSAndroid Build Coastguard Worker 205*c8dee2aaSAndroid Build Coastguard Worker function ParagraphAPI2(CanvasKit, fontData) { 206*c8dee2aaSAndroid Build Coastguard Worker if (!CanvasKit || !fontData) { 207*c8dee2aaSAndroid Build Coastguard Worker return; 208*c8dee2aaSAndroid Build Coastguard Worker } 209*c8dee2aaSAndroid Build Coastguard Worker 210*c8dee2aaSAndroid Build Coastguard Worker const surface = CanvasKit.MakeCanvasSurface('para2'); 211*c8dee2aaSAndroid Build Coastguard Worker if (!surface) { 212*c8dee2aaSAndroid Build Coastguard Worker console.error('Could not make surface'); 213*c8dee2aaSAndroid Build Coastguard Worker return; 214*c8dee2aaSAndroid Build Coastguard Worker } 215*c8dee2aaSAndroid Build Coastguard Worker 216*c8dee2aaSAndroid Build Coastguard Worker const mouse = MakeMouse(); 217*c8dee2aaSAndroid Build Coastguard Worker const cursor = MakeCursor(CanvasKit); 218*c8dee2aaSAndroid Build Coastguard Worker const canvas = surface.getCanvas(); 219*c8dee2aaSAndroid Build Coastguard Worker 220*c8dee2aaSAndroid Build Coastguard Worker const text0 = "In a hole in the ground there lived a hobbit. Not a nasty, dirty, " + 221*c8dee2aaSAndroid Build Coastguard Worker "wet hole full of worms and oozy smells. This was a hobbit-hole and " + 222*c8dee2aaSAndroid Build Coastguard Worker "that means good food, a warm hearth, and all the comforts of home."; 223*c8dee2aaSAndroid Build Coastguard Worker const LOC_X = 20, 224*c8dee2aaSAndroid Build Coastguard Worker LOC_Y = 20; 225*c8dee2aaSAndroid Build Coastguard Worker 226*c8dee2aaSAndroid Build Coastguard Worker const bgPaint = new CanvasKit.Paint(); 227*c8dee2aaSAndroid Build Coastguard Worker bgPaint.setColor([0.965, 0.965, 0.965, 1]); 228*c8dee2aaSAndroid Build Coastguard Worker 229*c8dee2aaSAndroid Build Coastguard Worker const editor = MakeEditor(text0, {typeface:null, size:24}, cursor, 400); 230*c8dee2aaSAndroid Build Coastguard Worker 231*c8dee2aaSAndroid Build Coastguard Worker editor.applyStyleToRange({size:100}, 0, 1); 232*c8dee2aaSAndroid Build Coastguard Worker editor.applyStyleToRange({italic:true}, 38, 38+6); 233*c8dee2aaSAndroid Build Coastguard Worker editor.applyStyleToRange({color:[1,0,0,1]}, 5, 5+4); 234*c8dee2aaSAndroid Build Coastguard Worker 235*c8dee2aaSAndroid Build Coastguard Worker editor.setXY(LOC_X, LOC_Y); 236*c8dee2aaSAndroid Build Coastguard Worker 237*c8dee2aaSAndroid Build Coastguard Worker function drawFrame(canvas) { 238*c8dee2aaSAndroid Build Coastguard Worker const lines = editor.getLines(); 239*c8dee2aaSAndroid Build Coastguard Worker 240*c8dee2aaSAndroid Build Coastguard Worker canvas.clear(CanvasKit.WHITE); 241*c8dee2aaSAndroid Build Coastguard Worker 242*c8dee2aaSAndroid Build Coastguard Worker if (mouse.isActive()) { 243*c8dee2aaSAndroid Build Coastguard Worker const pos = mouse.getPos(-LOC_X, -LOC_Y); 244*c8dee2aaSAndroid Build Coastguard Worker const a = lines_pos_to_index(lines, pos[0], pos[1]); 245*c8dee2aaSAndroid Build Coastguard Worker const b = lines_pos_to_index(lines, pos[2], pos[3]); 246*c8dee2aaSAndroid Build Coastguard Worker if (a == b) { 247*c8dee2aaSAndroid Build Coastguard Worker editor.setIndex(a); 248*c8dee2aaSAndroid Build Coastguard Worker } else { 249*c8dee2aaSAndroid Build Coastguard Worker editor.setIndices(a, b); 250*c8dee2aaSAndroid Build Coastguard Worker } 251*c8dee2aaSAndroid Build Coastguard Worker } 252*c8dee2aaSAndroid Build Coastguard Worker 253*c8dee2aaSAndroid Build Coastguard Worker canvas.drawRect(editor.bounds(), bgPaint); 254*c8dee2aaSAndroid Build Coastguard Worker editor.draw(canvas); 255*c8dee2aaSAndroid Build Coastguard Worker 256*c8dee2aaSAndroid Build Coastguard Worker surface.requestAnimationFrame(drawFrame); 257*c8dee2aaSAndroid Build Coastguard Worker } 258*c8dee2aaSAndroid Build Coastguard Worker surface.requestAnimationFrame(drawFrame); 259*c8dee2aaSAndroid Build Coastguard Worker 260*c8dee2aaSAndroid Build Coastguard Worker function interact(e) { 261*c8dee2aaSAndroid Build Coastguard Worker const type = e.type; 262*c8dee2aaSAndroid Build Coastguard Worker if (type === 'pointerup') { 263*c8dee2aaSAndroid Build Coastguard Worker mouse.setUp(e.offsetX, e.offsetY); 264*c8dee2aaSAndroid Build Coastguard Worker } else if (type === 'pointermove') { 265*c8dee2aaSAndroid Build Coastguard Worker mouse.setMove(e.offsetX, e.offsetY); 266*c8dee2aaSAndroid Build Coastguard Worker } else if (type === 'pointerdown') { 267*c8dee2aaSAndroid Build Coastguard Worker mouse.setDown(e.offsetX, e.offsetY); 268*c8dee2aaSAndroid Build Coastguard Worker } 269*c8dee2aaSAndroid Build Coastguard Worker }; 270*c8dee2aaSAndroid Build Coastguard Worker 271*c8dee2aaSAndroid Build Coastguard Worker function keyhandler(e) { 272*c8dee2aaSAndroid Build Coastguard Worker switch (e.key) { 273*c8dee2aaSAndroid Build Coastguard Worker case 'ArrowLeft': editor.moveDX(-1); return; 274*c8dee2aaSAndroid Build Coastguard Worker case 'ArrowRight': editor.moveDX(1); return; 275*c8dee2aaSAndroid Build Coastguard Worker case 'ArrowUp': 276*c8dee2aaSAndroid Build Coastguard Worker e.preventDefault(); 277*c8dee2aaSAndroid Build Coastguard Worker editor.moveDY(-1); 278*c8dee2aaSAndroid Build Coastguard Worker return; 279*c8dee2aaSAndroid Build Coastguard Worker case 'ArrowDown': 280*c8dee2aaSAndroid Build Coastguard Worker e.preventDefault(); 281*c8dee2aaSAndroid Build Coastguard Worker editor.moveDY(1); 282*c8dee2aaSAndroid Build Coastguard Worker return; 283*c8dee2aaSAndroid Build Coastguard Worker case 'Backspace': 284*c8dee2aaSAndroid Build Coastguard Worker editor.deleteSelection(); 285*c8dee2aaSAndroid Build Coastguard Worker return; 286*c8dee2aaSAndroid Build Coastguard Worker case 'Shift': 287*c8dee2aaSAndroid Build Coastguard Worker return; 288*c8dee2aaSAndroid Build Coastguard Worker } 289*c8dee2aaSAndroid Build Coastguard Worker if (e.ctrlKey) { 290*c8dee2aaSAndroid Build Coastguard Worker switch (e.key) { 291*c8dee2aaSAndroid Build Coastguard Worker case 'r': editor.applyStyleToSelection({color:[1,0,0,1]}); return; 292*c8dee2aaSAndroid Build Coastguard Worker case 'g': editor.applyStyleToSelection({color:[0,0.6,0,1]}); return; 293*c8dee2aaSAndroid Build Coastguard Worker case 'u': editor.applyStyleToSelection({color:[0,0,1,1]}); return; 294*c8dee2aaSAndroid Build Coastguard Worker case 'k': editor.applyStyleToSelection({color:[0,0,0,1]}); return; 295*c8dee2aaSAndroid Build Coastguard Worker 296*c8dee2aaSAndroid Build Coastguard Worker case 'i': editor.applyStyleToSelection({italic:'toggle'}); return; 297*c8dee2aaSAndroid Build Coastguard Worker case 'b': editor.applyStyleToSelection({bold:'toggle'}); return; 298*c8dee2aaSAndroid Build Coastguard Worker case 'l': editor.applyStyleToSelection({underline:'toggle'}); return; 299*c8dee2aaSAndroid Build Coastguard Worker 300*c8dee2aaSAndroid Build Coastguard Worker case ']': editor.applyStyleToSelection({size_add:1}); return; 301*c8dee2aaSAndroid Build Coastguard Worker case '[': editor.applyStyleToSelection({size_add:-1}); return; 302*c8dee2aaSAndroid Build Coastguard Worker } 303*c8dee2aaSAndroid Build Coastguard Worker } 304*c8dee2aaSAndroid Build Coastguard Worker if (!e.ctrlKey && !e.metaKey) { 305*c8dee2aaSAndroid Build Coastguard Worker e.preventDefault(); // at least needed for 'space' 306*c8dee2aaSAndroid Build Coastguard Worker editor.insert(e.key); 307*c8dee2aaSAndroid Build Coastguard Worker } 308*c8dee2aaSAndroid Build Coastguard Worker } 309*c8dee2aaSAndroid Build Coastguard Worker 310*c8dee2aaSAndroid Build Coastguard Worker document.getElementById('para2').addEventListener('pointermove', interact); 311*c8dee2aaSAndroid Build Coastguard Worker document.getElementById('para2').addEventListener('pointerdown', interact); 312*c8dee2aaSAndroid Build Coastguard Worker document.getElementById('para2').addEventListener('pointerup', interact); 313*c8dee2aaSAndroid Build Coastguard Worker document.getElementById('para2').addEventListener('keydown', keyhandler); 314*c8dee2aaSAndroid Build Coastguard Worker return surface; 315*c8dee2aaSAndroid Build Coastguard Worker } 316*c8dee2aaSAndroid Build Coastguard Worker 317*c8dee2aaSAndroid Build Coastguard Worker function ParagraphAPI3(CanvasKit, fontData) { 318*c8dee2aaSAndroid Build Coastguard Worker if (!CanvasKit || !fontData) { 319*c8dee2aaSAndroid Build Coastguard Worker return; 320*c8dee2aaSAndroid Build Coastguard Worker } 321*c8dee2aaSAndroid Build Coastguard Worker 322*c8dee2aaSAndroid Build Coastguard Worker const surface = CanvasKit.MakeCanvasSurface('para3'); 323*c8dee2aaSAndroid Build Coastguard Worker if (!surface) { 324*c8dee2aaSAndroid Build Coastguard Worker console.error('Could not make surface'); 325*c8dee2aaSAndroid Build Coastguard Worker return; 326*c8dee2aaSAndroid Build Coastguard Worker } 327*c8dee2aaSAndroid Build Coastguard Worker 328*c8dee2aaSAndroid Build Coastguard Worker const fontMgr = CanvasKit.FontMgr.FromData([fontData]); 329*c8dee2aaSAndroid Build Coastguard Worker 330*c8dee2aaSAndroid Build Coastguard Worker const paraStyle = new CanvasKit.ParagraphStyle({ 331*c8dee2aaSAndroid Build Coastguard Worker textStyle: { 332*c8dee2aaSAndroid Build Coastguard Worker color: CanvasKit.BLACK, 333*c8dee2aaSAndroid Build Coastguard Worker fontFamilies: ['Roboto'], 334*c8dee2aaSAndroid Build Coastguard Worker fontSize: 50, 335*c8dee2aaSAndroid Build Coastguard Worker }, 336*c8dee2aaSAndroid Build Coastguard Worker textAlign: CanvasKit.TextAlign.Left, 337*c8dee2aaSAndroid Build Coastguard Worker maxLines: 5, 338*c8dee2aaSAndroid Build Coastguard Worker }); 339*c8dee2aaSAndroid Build Coastguard Worker 340*c8dee2aaSAndroid Build Coastguard Worker const builder = CanvasKit.ParagraphBuilder.Make(paraStyle, fontMgr); 341*c8dee2aaSAndroid Build Coastguard Worker builder.addText('The quick brown fox ate a hamburgerfons and got sick.'); 342*c8dee2aaSAndroid Build Coastguard Worker 343*c8dee2aaSAndroid Build Coastguard Worker // The code below works for English-only text assuming 344*c8dee2aaSAndroid Build Coastguard Worker // that each character is a glyph (cluster), spaces are breaks between words, 345*c8dee2aaSAndroid Build Coastguard Worker // new lines are breaks between lines and the entire text is LTR. 346*c8dee2aaSAndroid Build Coastguard Worker 347*c8dee2aaSAndroid Build Coastguard Worker // In case the paragraph text was constructed in a set of calls we need the text 348*c8dee2aaSAndroid Build Coastguard Worker const text = builder.getText(); 349*c8dee2aaSAndroid Build Coastguard Worker 350*c8dee2aaSAndroid Build Coastguard Worker // Pass the entire text as one word. It's only used for the method 351*c8dee2aaSAndroid Build Coastguard Worker // getWords 352*c8dee2aaSAndroid Build Coastguard Worker const mallocedWords = CanvasKit.Malloc(Uint32Array, 2); 353*c8dee2aaSAndroid Build Coastguard Worker mallocedWords.toTypedArray().set([0, text.length]); 354*c8dee2aaSAndroid Build Coastguard Worker 355*c8dee2aaSAndroid Build Coastguard Worker // Pass each character as a separate grapheme 356*c8dee2aaSAndroid Build Coastguard Worker const mallocedGraphemes = CanvasKit.Malloc(Uint32Array, text.length + 1); 357*c8dee2aaSAndroid Build Coastguard Worker const graphemesArr = mallocedGraphemes.toTypedArray(); 358*c8dee2aaSAndroid Build Coastguard Worker for (let i = 0; i <= text.length; i++) { 359*c8dee2aaSAndroid Build Coastguard Worker graphemesArr[i] = i; 360*c8dee2aaSAndroid Build Coastguard Worker } 361*c8dee2aaSAndroid Build Coastguard Worker 362*c8dee2aaSAndroid Build Coastguard Worker // Pass each space as a "soft" break and each new line as a "hard" break. 363*c8dee2aaSAndroid Build Coastguard Worker const SOFT = 0; 364*c8dee2aaSAndroid Build Coastguard Worker const HARD = 1; 365*c8dee2aaSAndroid Build Coastguard Worker const lineBreaks = [0, SOFT]; 366*c8dee2aaSAndroid Build Coastguard Worker for (let i = 0; i < text.length; ++i) { 367*c8dee2aaSAndroid Build Coastguard Worker if (text[i] === ' ') { 368*c8dee2aaSAndroid Build Coastguard Worker lineBreaks.push(i + 1, SOFT); 369*c8dee2aaSAndroid Build Coastguard Worker } 370*c8dee2aaSAndroid Build Coastguard Worker if (text[i] === '\n') { 371*c8dee2aaSAndroid Build Coastguard Worker lineBreaks.push(i + 1, HARD); 372*c8dee2aaSAndroid Build Coastguard Worker } 373*c8dee2aaSAndroid Build Coastguard Worker } 374*c8dee2aaSAndroid Build Coastguard Worker lineBreaks.push(text.length, SOFT); 375*c8dee2aaSAndroid Build Coastguard Worker const mallocedLineBreaks = CanvasKit.Malloc(Uint32Array, lineBreaks.length); 376*c8dee2aaSAndroid Build Coastguard Worker mallocedLineBreaks.toTypedArray().set(lineBreaks); 377*c8dee2aaSAndroid Build Coastguard Worker 378*c8dee2aaSAndroid Build Coastguard Worker builder.setWordsUtf16(mallocedWords); 379*c8dee2aaSAndroid Build Coastguard Worker builder.setGraphemeBreaksUtf16(mallocedGraphemes); 380*c8dee2aaSAndroid Build Coastguard Worker builder.setLineBreaksUtf16(mallocedLineBreaks); 381*c8dee2aaSAndroid Build Coastguard Worker const paragraph = builder.build(); 382*c8dee2aaSAndroid Build Coastguard Worker 383*c8dee2aaSAndroid Build Coastguard Worker paragraph.layout(600); 384*c8dee2aaSAndroid Build Coastguard Worker 385*c8dee2aaSAndroid Build Coastguard Worker let wrapTo = 0; 386*c8dee2aaSAndroid Build Coastguard Worker 387*c8dee2aaSAndroid Build Coastguard Worker let X = 100; 388*c8dee2aaSAndroid Build Coastguard Worker let Y = 100; 389*c8dee2aaSAndroid Build Coastguard Worker 390*c8dee2aaSAndroid Build Coastguard Worker const fontPaint = new CanvasKit.Paint(); 391*c8dee2aaSAndroid Build Coastguard Worker fontPaint.setStyle(CanvasKit.PaintStyle.Fill); 392*c8dee2aaSAndroid Build Coastguard Worker fontPaint.setAntiAlias(true); 393*c8dee2aaSAndroid Build Coastguard Worker 394*c8dee2aaSAndroid Build Coastguard Worker function drawFrame(canvas) { 395*c8dee2aaSAndroid Build Coastguard Worker canvas.clear(CanvasKit.WHITE); 396*c8dee2aaSAndroid Build Coastguard Worker wrapTo = 350 + 150 * Math.sin(Date.now() / 2000); 397*c8dee2aaSAndroid Build Coastguard Worker paragraph.layout(wrapTo); 398*c8dee2aaSAndroid Build Coastguard Worker canvas.drawParagraph(paragraph, 0, 0); 399*c8dee2aaSAndroid Build Coastguard Worker 400*c8dee2aaSAndroid Build Coastguard Worker canvas.drawLine(wrapTo, 0, wrapTo, 400, fontPaint); 401*c8dee2aaSAndroid Build Coastguard Worker 402*c8dee2aaSAndroid Build Coastguard Worker surface.requestAnimationFrame(drawFrame); 403*c8dee2aaSAndroid Build Coastguard Worker } 404*c8dee2aaSAndroid Build Coastguard Worker surface.requestAnimationFrame(drawFrame); 405*c8dee2aaSAndroid Build Coastguard Worker 406*c8dee2aaSAndroid Build Coastguard Worker let interact = (e) => { 407*c8dee2aaSAndroid Build Coastguard Worker X = e.offsetX*2; // multiply by 2 because the canvas is 300 css pixels wide, 408*c8dee2aaSAndroid Build Coastguard Worker Y = e.offsetY*2; // but the canvas itself is 600px wide 409*c8dee2aaSAndroid Build Coastguard Worker }; 410*c8dee2aaSAndroid Build Coastguard Worker 411*c8dee2aaSAndroid Build Coastguard Worker document.getElementById('para1').addEventListener('pointermove', interact); 412*c8dee2aaSAndroid Build Coastguard Worker 413*c8dee2aaSAndroid Build Coastguard Worker return surface; 414*c8dee2aaSAndroid Build Coastguard Worker } 415*c8dee2aaSAndroid Build Coastguard Worker 416*c8dee2aaSAndroid Build Coastguard Worker function RTShaderAPI1(CanvasKit) { 417*c8dee2aaSAndroid Build Coastguard Worker if (!CanvasKit) { 418*c8dee2aaSAndroid Build Coastguard Worker return; 419*c8dee2aaSAndroid Build Coastguard Worker } 420*c8dee2aaSAndroid Build Coastguard Worker 421*c8dee2aaSAndroid Build Coastguard Worker const surface = CanvasKit.MakeCanvasSurface('rtshader'); 422*c8dee2aaSAndroid Build Coastguard Worker if (!surface) { 423*c8dee2aaSAndroid Build Coastguard Worker console.error('Could not make surface'); 424*c8dee2aaSAndroid Build Coastguard Worker return; 425*c8dee2aaSAndroid Build Coastguard Worker } 426*c8dee2aaSAndroid Build Coastguard Worker 427*c8dee2aaSAndroid Build Coastguard Worker const canvas = surface.getCanvas(); 428*c8dee2aaSAndroid Build Coastguard Worker 429*c8dee2aaSAndroid Build Coastguard Worker const effect = CanvasKit.RuntimeEffect.Make(spiralSkSL); 430*c8dee2aaSAndroid Build Coastguard Worker const shader = effect.makeShader([ 431*c8dee2aaSAndroid Build Coastguard Worker 0.5, 432*c8dee2aaSAndroid Build Coastguard Worker 150, 150, 433*c8dee2aaSAndroid Build Coastguard Worker 0, 1, 0, 1, 434*c8dee2aaSAndroid Build Coastguard Worker 1, 0, 0, 1]); 435*c8dee2aaSAndroid Build Coastguard Worker const paint = new CanvasKit.Paint(); 436*c8dee2aaSAndroid Build Coastguard Worker paint.setShader(shader); 437*c8dee2aaSAndroid Build Coastguard Worker canvas.drawRect(CanvasKit.LTRBRect(0, 0, 300, 300), paint); 438*c8dee2aaSAndroid Build Coastguard Worker 439*c8dee2aaSAndroid Build Coastguard Worker surface.flush(); 440*c8dee2aaSAndroid Build Coastguard Worker shader.delete(); 441*c8dee2aaSAndroid Build Coastguard Worker paint.delete(); 442*c8dee2aaSAndroid Build Coastguard Worker effect.delete(); 443*c8dee2aaSAndroid Build Coastguard Worker } 444*c8dee2aaSAndroid Build Coastguard Worker 445*c8dee2aaSAndroid Build Coastguard Worker // RTShader2 demo 446*c8dee2aaSAndroid Build Coastguard Worker Promise.all([ckLoaded, loadDog, loadMandrill]).then((values) => { 447*c8dee2aaSAndroid Build Coastguard Worker const [CanvasKit, dogData, mandrillData] = values; 448*c8dee2aaSAndroid Build Coastguard Worker const dogImg = CanvasKit.MakeImageFromEncoded(dogData); 449*c8dee2aaSAndroid Build Coastguard Worker if (!dogImg) { 450*c8dee2aaSAndroid Build Coastguard Worker console.error('could not decode dog'); 451*c8dee2aaSAndroid Build Coastguard Worker return; 452*c8dee2aaSAndroid Build Coastguard Worker } 453*c8dee2aaSAndroid Build Coastguard Worker const mandrillImg = CanvasKit.MakeImageFromEncoded(mandrillData); 454*c8dee2aaSAndroid Build Coastguard Worker if (!mandrillImg) { 455*c8dee2aaSAndroid Build Coastguard Worker console.error('could not decode mandrill'); 456*c8dee2aaSAndroid Build Coastguard Worker return; 457*c8dee2aaSAndroid Build Coastguard Worker } 458*c8dee2aaSAndroid Build Coastguard Worker const quadrantSize = 150; 459*c8dee2aaSAndroid Build Coastguard Worker 460*c8dee2aaSAndroid Build Coastguard Worker const dogShader = dogImg.makeShaderCubic( 461*c8dee2aaSAndroid Build Coastguard Worker CanvasKit.TileMode.Clamp, CanvasKit.TileMode.Clamp, 462*c8dee2aaSAndroid Build Coastguard Worker 1/3, 1/3, 463*c8dee2aaSAndroid Build Coastguard Worker CanvasKit.Matrix.scaled(quadrantSize/dogImg.width(), 464*c8dee2aaSAndroid Build Coastguard Worker quadrantSize/dogImg.height())); 465*c8dee2aaSAndroid Build Coastguard Worker const mandrillShader = mandrillImg.makeShaderCubic( 466*c8dee2aaSAndroid Build Coastguard Worker CanvasKit.TileMode.Clamp, CanvasKit.TileMode.Clamp, 467*c8dee2aaSAndroid Build Coastguard Worker 1/3, 1/3, 468*c8dee2aaSAndroid Build Coastguard Worker CanvasKit.Matrix.scaled( 469*c8dee2aaSAndroid Build Coastguard Worker quadrantSize/mandrillImg.width(), 470*c8dee2aaSAndroid Build Coastguard Worker quadrantSize/mandrillImg.height())); 471*c8dee2aaSAndroid Build Coastguard Worker 472*c8dee2aaSAndroid Build Coastguard Worker const surface = CanvasKit.MakeCanvasSurface('rtshader2'); 473*c8dee2aaSAndroid Build Coastguard Worker if (!surface) { 474*c8dee2aaSAndroid Build Coastguard Worker console.error('Could not make surface'); 475*c8dee2aaSAndroid Build Coastguard Worker return; 476*c8dee2aaSAndroid Build Coastguard Worker } 477*c8dee2aaSAndroid Build Coastguard Worker 478*c8dee2aaSAndroid Build Coastguard Worker const prog = ` 479*c8dee2aaSAndroid Build Coastguard Worker uniform shader before_map; 480*c8dee2aaSAndroid Build Coastguard Worker uniform shader after_map; 481*c8dee2aaSAndroid Build Coastguard Worker uniform shader threshold_map; 482*c8dee2aaSAndroid Build Coastguard Worker 483*c8dee2aaSAndroid Build Coastguard Worker uniform float cutoff; 484*c8dee2aaSAndroid Build Coastguard Worker uniform float slope; 485*c8dee2aaSAndroid Build Coastguard Worker 486*c8dee2aaSAndroid Build Coastguard Worker float smooth_cutoff(float x) { 487*c8dee2aaSAndroid Build Coastguard Worker x = x * slope + (0.5 - slope * cutoff); 488*c8dee2aaSAndroid Build Coastguard Worker return clamp(x, 0, 1); 489*c8dee2aaSAndroid Build Coastguard Worker } 490*c8dee2aaSAndroid Build Coastguard Worker 491*c8dee2aaSAndroid Build Coastguard Worker half4 main(float2 xy) { 492*c8dee2aaSAndroid Build Coastguard Worker half4 before = before_map.eval(xy); 493*c8dee2aaSAndroid Build Coastguard Worker half4 after = after_map.eval(xy); 494*c8dee2aaSAndroid Build Coastguard Worker 495*c8dee2aaSAndroid Build Coastguard Worker float m = smooth_cutoff(threshold_map.eval(xy).r); 496*c8dee2aaSAndroid Build Coastguard Worker return mix(before, after, half(m)); 497*c8dee2aaSAndroid Build Coastguard Worker }`; 498*c8dee2aaSAndroid Build Coastguard Worker 499*c8dee2aaSAndroid Build Coastguard Worker const canvas = surface.getCanvas(); 500*c8dee2aaSAndroid Build Coastguard Worker 501*c8dee2aaSAndroid Build Coastguard Worker const thresholdEffect = CanvasKit.RuntimeEffect.Make(prog); 502*c8dee2aaSAndroid Build Coastguard Worker const spiralEffect = CanvasKit.RuntimeEffect.Make(spiralSkSL); 503*c8dee2aaSAndroid Build Coastguard Worker 504*c8dee2aaSAndroid Build Coastguard Worker const draw = (x, y, shader) => { 505*c8dee2aaSAndroid Build Coastguard Worker const paint = new CanvasKit.Paint(); 506*c8dee2aaSAndroid Build Coastguard Worker paint.setShader(shader); 507*c8dee2aaSAndroid Build Coastguard Worker canvas.save(); 508*c8dee2aaSAndroid Build Coastguard Worker canvas.translate(x, y); 509*c8dee2aaSAndroid Build Coastguard Worker canvas.drawRect(CanvasKit.LTRBRect(0, 0, quadrantSize, quadrantSize), paint); 510*c8dee2aaSAndroid Build Coastguard Worker canvas.restore(); 511*c8dee2aaSAndroid Build Coastguard Worker paint.delete(); 512*c8dee2aaSAndroid Build Coastguard Worker }; 513*c8dee2aaSAndroid Build Coastguard Worker 514*c8dee2aaSAndroid Build Coastguard Worker const offscreenSurface = CanvasKit.MakeSurface(quadrantSize, quadrantSize); 515*c8dee2aaSAndroid Build Coastguard Worker const getBlurrySpiralShader = (rad_scale) => { 516*c8dee2aaSAndroid Build Coastguard Worker const oCanvas = offscreenSurface.getCanvas(); 517*c8dee2aaSAndroid Build Coastguard Worker 518*c8dee2aaSAndroid Build Coastguard Worker const spiralShader = spiralEffect.makeShader([ 519*c8dee2aaSAndroid Build Coastguard Worker rad_scale, 520*c8dee2aaSAndroid Build Coastguard Worker quadrantSize/2, quadrantSize/2, 521*c8dee2aaSAndroid Build Coastguard Worker 1, 1, 1, 1, 522*c8dee2aaSAndroid Build Coastguard Worker 0, 0, 0, 1]); 523*c8dee2aaSAndroid Build Coastguard Worker 524*c8dee2aaSAndroid Build Coastguard Worker const blur = CanvasKit.ImageFilter.MakeBlur(0.1, 0.1, CanvasKit.TileMode.Clamp, null); 525*c8dee2aaSAndroid Build Coastguard Worker 526*c8dee2aaSAndroid Build Coastguard Worker const paint = new CanvasKit.Paint(); 527*c8dee2aaSAndroid Build Coastguard Worker paint.setShader(spiralShader); 528*c8dee2aaSAndroid Build Coastguard Worker paint.setImageFilter(blur); 529*c8dee2aaSAndroid Build Coastguard Worker oCanvas.drawRect(CanvasKit.LTRBRect(0, 0, quadrantSize, quadrantSize), paint); 530*c8dee2aaSAndroid Build Coastguard Worker 531*c8dee2aaSAndroid Build Coastguard Worker paint.delete(); 532*c8dee2aaSAndroid Build Coastguard Worker blur.delete(); 533*c8dee2aaSAndroid Build Coastguard Worker spiralShader.delete(); 534*c8dee2aaSAndroid Build Coastguard Worker return offscreenSurface.makeImageSnapshot() 535*c8dee2aaSAndroid Build Coastguard Worker .makeShaderCubic(CanvasKit.TileMode.Clamp, CanvasKit.TileMode.Clamp, 536*c8dee2aaSAndroid Build Coastguard Worker 1/3, 1/3); 537*c8dee2aaSAndroid Build Coastguard Worker 538*c8dee2aaSAndroid Build Coastguard Worker }; 539*c8dee2aaSAndroid Build Coastguard Worker 540*c8dee2aaSAndroid Build Coastguard Worker const drawFrame = () => { 541*c8dee2aaSAndroid Build Coastguard Worker surface.requestAnimationFrame(drawFrame); 542*c8dee2aaSAndroid Build Coastguard Worker const thresholdShader = getBlurrySpiralShader(Math.sin(Date.now() / 5000) / 2); 543*c8dee2aaSAndroid Build Coastguard Worker 544*c8dee2aaSAndroid Build Coastguard Worker const blendShader = thresholdEffect.makeShaderWithChildren( 545*c8dee2aaSAndroid Build Coastguard Worker [0.5, 10], 546*c8dee2aaSAndroid Build Coastguard Worker [dogShader, mandrillShader, thresholdShader]); 547*c8dee2aaSAndroid Build Coastguard Worker draw(0, 0, blendShader); 548*c8dee2aaSAndroid Build Coastguard Worker draw(quadrantSize, 0, thresholdShader); 549*c8dee2aaSAndroid Build Coastguard Worker draw(0, quadrantSize, dogShader); 550*c8dee2aaSAndroid Build Coastguard Worker draw(quadrantSize, quadrantSize, mandrillShader); 551*c8dee2aaSAndroid Build Coastguard Worker 552*c8dee2aaSAndroid Build Coastguard Worker blendShader.delete(); 553*c8dee2aaSAndroid Build Coastguard Worker }; 554*c8dee2aaSAndroid Build Coastguard Worker 555*c8dee2aaSAndroid Build Coastguard Worker surface.requestAnimationFrame(drawFrame); 556*c8dee2aaSAndroid Build Coastguard Worker }); 557*c8dee2aaSAndroid Build Coastguard Worker 558*c8dee2aaSAndroid Build Coastguard Worker function SkpExample(CanvasKit) { 559*c8dee2aaSAndroid Build Coastguard Worker if (!CanvasKit) { 560*c8dee2aaSAndroid Build Coastguard Worker return; 561*c8dee2aaSAndroid Build Coastguard Worker } 562*c8dee2aaSAndroid Build Coastguard Worker 563*c8dee2aaSAndroid Build Coastguard Worker const surface = CanvasKit.MakeSWCanvasSurface('skp'); 564*c8dee2aaSAndroid Build Coastguard Worker if (!surface) { 565*c8dee2aaSAndroid Build Coastguard Worker console.error('Could not make surface'); 566*c8dee2aaSAndroid Build Coastguard Worker return; 567*c8dee2aaSAndroid Build Coastguard Worker } 568*c8dee2aaSAndroid Build Coastguard Worker 569*c8dee2aaSAndroid Build Coastguard Worker const paint = new CanvasKit.Paint(); 570*c8dee2aaSAndroid Build Coastguard Worker paint.setColor(CanvasKit.RED); 571*c8dee2aaSAndroid Build Coastguard Worker 572*c8dee2aaSAndroid Build Coastguard Worker const textPaint = new CanvasKit.Paint(); 573*c8dee2aaSAndroid Build Coastguard Worker const textFont = new CanvasKit.Font(CanvasKit.Typeface.GetDefault(), 20); 574*c8dee2aaSAndroid Build Coastguard Worker const pr = new CanvasKit.PictureRecorder(); 575*c8dee2aaSAndroid Build Coastguard Worker const skpCanvas = pr.beginRecording(CanvasKit.LTRBRect(0, 0, 200, 200)); 576*c8dee2aaSAndroid Build Coastguard Worker skpCanvas.drawRect(CanvasKit.LTRBRect(10, 10, 50, 50), paint); 577*c8dee2aaSAndroid Build Coastguard Worker skpCanvas.drawText('If you see this, CanvasKit loaded!!', 5, 100, textPaint, textFont); 578*c8dee2aaSAndroid Build Coastguard Worker 579*c8dee2aaSAndroid Build Coastguard Worker const pic = pr.finishRecordingAsPicture(); 580*c8dee2aaSAndroid Build Coastguard Worker const skpData = pic.serialize(); 581*c8dee2aaSAndroid Build Coastguard Worker 582*c8dee2aaSAndroid Build Coastguard Worker paint.delete(); 583*c8dee2aaSAndroid Build Coastguard Worker pr.delete(); 584*c8dee2aaSAndroid Build Coastguard Worker 585*c8dee2aaSAndroid Build Coastguard Worker const deserialized = CanvasKit.MakePicture(skpData); 586*c8dee2aaSAndroid Build Coastguard Worker 587*c8dee2aaSAndroid Build Coastguard Worker function drawFrame(canvas) { 588*c8dee2aaSAndroid Build Coastguard Worker if (deserialized) { 589*c8dee2aaSAndroid Build Coastguard Worker canvas.drawPicture(deserialized); 590*c8dee2aaSAndroid Build Coastguard Worker } else { 591*c8dee2aaSAndroid Build Coastguard Worker canvas.drawText('SKP did not deserialize', 5, 100, textPaint, textFont); 592*c8dee2aaSAndroid Build Coastguard Worker } 593*c8dee2aaSAndroid Build Coastguard Worker } 594*c8dee2aaSAndroid Build Coastguard Worker surface.drawOnce(drawFrame); 595*c8dee2aaSAndroid Build Coastguard Worker textPaint.delete(); 596*c8dee2aaSAndroid Build Coastguard Worker textFont.delete(); 597*c8dee2aaSAndroid Build Coastguard Worker } 598*c8dee2aaSAndroid Build Coastguard Worker 599*c8dee2aaSAndroid Build Coastguard Worker // Shows a hidden message by rotating all the characters in a kind of way that makes you 600*c8dee2aaSAndroid Build Coastguard Worker // search with your mouse. 601*c8dee2aaSAndroid Build Coastguard Worker function GlyphGame(canvas, robotoData) { 602*c8dee2aaSAndroid Build Coastguard Worker const surface = CanvasKit.MakeCanvasSurface('glyphgame'); 603*c8dee2aaSAndroid Build Coastguard Worker if (!surface) { 604*c8dee2aaSAndroid Build Coastguard Worker console.error('Could not make surface'); 605*c8dee2aaSAndroid Build Coastguard Worker return; 606*c8dee2aaSAndroid Build Coastguard Worker } 607*c8dee2aaSAndroid Build Coastguard Worker const sizeX = document.getElementById('glyphgame').width; 608*c8dee2aaSAndroid Build Coastguard Worker const sizeY = document.getElementById('glyphgame').height; 609*c8dee2aaSAndroid Build Coastguard Worker const halfDim = Math.min(sizeX, sizeY) / 2; 610*c8dee2aaSAndroid Build Coastguard Worker const margin = 50; 611*c8dee2aaSAndroid Build Coastguard Worker const marginTop = 25; 612*c8dee2aaSAndroid Build Coastguard Worker let rotX = 0; // expected to be updated in interact() 613*c8dee2aaSAndroid Build Coastguard Worker let rotY = 0; 614*c8dee2aaSAndroid Build Coastguard Worker let pointer = [500, 450]; 615*c8dee2aaSAndroid Build Coastguard Worker const radPerPixel = 0.005; // radians of subject rotation per pixel distance moved by mouse. 616*c8dee2aaSAndroid Build Coastguard Worker 617*c8dee2aaSAndroid Build Coastguard Worker const camAngle = Math.PI / 12; 618*c8dee2aaSAndroid Build Coastguard Worker const cam = { 619*c8dee2aaSAndroid Build Coastguard Worker 'eye' : [0, 0, 1 / Math.tan(camAngle/2) - 1], 620*c8dee2aaSAndroid Build Coastguard Worker 'coa' : [0, 0, 0], 621*c8dee2aaSAndroid Build Coastguard Worker 'up' : [0, 1, 0], 622*c8dee2aaSAndroid Build Coastguard Worker 'near' : 0.02, 623*c8dee2aaSAndroid Build Coastguard Worker 'far' : 4, 624*c8dee2aaSAndroid Build Coastguard Worker 'angle': camAngle, 625*c8dee2aaSAndroid Build Coastguard Worker }; 626*c8dee2aaSAndroid Build Coastguard Worker 627*c8dee2aaSAndroid Build Coastguard Worker let lastImage = null; 628*c8dee2aaSAndroid Build Coastguard Worker 629*c8dee2aaSAndroid Build Coastguard Worker const fontMgr = CanvasKit.FontMgr.FromData([robotoData]); 630*c8dee2aaSAndroid Build Coastguard Worker 631*c8dee2aaSAndroid Build Coastguard Worker const paraStyle = new CanvasKit.ParagraphStyle({ 632*c8dee2aaSAndroid Build Coastguard Worker textStyle: { 633*c8dee2aaSAndroid Build Coastguard Worker color: CanvasKit.Color(105, 56, 16), // brown 634*c8dee2aaSAndroid Build Coastguard Worker fontFamilies: ['Roboto'], 635*c8dee2aaSAndroid Build Coastguard Worker fontSize: 28, 636*c8dee2aaSAndroid Build Coastguard Worker }, 637*c8dee2aaSAndroid Build Coastguard Worker textAlign: CanvasKit.TextAlign.Left, 638*c8dee2aaSAndroid Build Coastguard Worker }); 639*c8dee2aaSAndroid Build Coastguard Worker const hStyle = CanvasKit.RectHeightStyle.Max; 640*c8dee2aaSAndroid Build Coastguard Worker const wStyle = CanvasKit.RectWidthStyle.Tight; 641*c8dee2aaSAndroid Build Coastguard Worker 642*c8dee2aaSAndroid Build Coastguard Worker const quotes = [ 643*c8dee2aaSAndroid Build Coastguard Worker 'Some activities superficially familiar to you are merely stupid and should be avoided for your safety, although they are not illegal as such. These include: giving your bank account details to the son of the Nigerian Minister of Finance; buying title to bridges, skyscrapers, spacecraft, planets, or other real assets; murder; selling your identity; and entering into financial contracts with entities running Economics 2.0 or higher.', 644*c8dee2aaSAndroid Build Coastguard Worker // Charles Stross - Accelerando 645*c8dee2aaSAndroid Build Coastguard Worker 'If only there were evil people somewhere insidiously committing evil deeds, and it were necessary only to separate them from the rest of us and destroy them. But the line dividing good and evil cuts through the heart of every human being. And who is willing to destroy a piece of his own heart?', 646*c8dee2aaSAndroid Build Coastguard Worker // Aleksandr Solzhenitsyn - The Gulag Archipelago 647*c8dee2aaSAndroid Build Coastguard Worker 'There is one metaphor of which the moderns are very fond; they are always saying, “You can’t put the clock back.” The simple and obvious answer is “You can.” A clock, being a piece of human construction, can be restored by the human finger to any figure or hour. In the same way society, being a piece of human construction, can be reconstructed upon any plan that has ever existed.', 648*c8dee2aaSAndroid Build Coastguard Worker // G. K. Chesterton - What's Wrong With The World? 649*c8dee2aaSAndroid Build Coastguard Worker ]; 650*c8dee2aaSAndroid Build Coastguard Worker 651*c8dee2aaSAndroid Build Coastguard Worker // pick one at random 652*c8dee2aaSAndroid Build Coastguard Worker const text = quotes[Math.floor(Math.random()*3)]; 653*c8dee2aaSAndroid Build Coastguard Worker const builder = CanvasKit.ParagraphBuilder.Make(paraStyle, fontMgr); 654*c8dee2aaSAndroid Build Coastguard Worker builder.addText(text); 655*c8dee2aaSAndroid Build Coastguard Worker const paragraph = builder.build(); 656*c8dee2aaSAndroid Build Coastguard Worker const font = new CanvasKit.Font(CanvasKit.Typeface.GetDefault(), 18); 657*c8dee2aaSAndroid Build Coastguard Worker // wrap the text to a given width. 658*c8dee2aaSAndroid Build Coastguard Worker paragraph.layout(sizeX - margin*2); 659*c8dee2aaSAndroid Build Coastguard Worker 660*c8dee2aaSAndroid Build Coastguard Worker // to rotate every glyph individually, calculate the bounding rect of each one, 661*c8dee2aaSAndroid Build Coastguard Worker // construct an array of rects and paragraphs that would draw each glyph individually. 662*c8dee2aaSAndroid Build Coastguard Worker const letters = Array(text.length); 663*c8dee2aaSAndroid Build Coastguard Worker for (let i = 0; i < text.length; i++) { 664*c8dee2aaSAndroid Build Coastguard Worker const r = paragraph.getRectsForRange(i, i+1, hStyle, wStyle)[0]; 665*c8dee2aaSAndroid Build Coastguard Worker // The character is drawn with drawParagraph so we can pass the paraStyle, 666*c8dee2aaSAndroid Build Coastguard Worker // and have our character be the exact size and shape the paragraph expected 667*c8dee2aaSAndroid Build Coastguard Worker // when it wrapped the text. canvas.drawText wouldn't cut it. 668*c8dee2aaSAndroid Build Coastguard Worker const tmpbuilder = CanvasKit.ParagraphBuilder.Make(paraStyle, fontMgr); 669*c8dee2aaSAndroid Build Coastguard Worker tmpbuilder.addText(text[i]); 670*c8dee2aaSAndroid Build Coastguard Worker const para = tmpbuilder.build(); 671*c8dee2aaSAndroid Build Coastguard Worker para.layout(100); 672*c8dee2aaSAndroid Build Coastguard Worker letters[i] = { 673*c8dee2aaSAndroid Build Coastguard Worker 'r': r, 674*c8dee2aaSAndroid Build Coastguard Worker 'para': para, 675*c8dee2aaSAndroid Build Coastguard Worker }; 676*c8dee2aaSAndroid Build Coastguard Worker } 677*c8dee2aaSAndroid Build Coastguard Worker 678*c8dee2aaSAndroid Build Coastguard Worker function drawFrame(canvas) { 679*c8dee2aaSAndroid Build Coastguard Worker // persistence of vision effect is done by drawing the past frame as an image, 680*c8dee2aaSAndroid Build Coastguard Worker // then covering with semitransparent background color. 681*c8dee2aaSAndroid Build Coastguard Worker if (lastImage) { 682*c8dee2aaSAndroid Build Coastguard Worker canvas.drawImage(lastImage, 0, 0, null); 683*c8dee2aaSAndroid Build Coastguard Worker canvas.drawColor(CanvasKit.Color(171, 244, 255, 0.1)); // sky blue, almost transparent 684*c8dee2aaSAndroid Build Coastguard Worker } else { 685*c8dee2aaSAndroid Build Coastguard Worker canvas.clear(CanvasKit.Color(171, 244, 255)); // sky blue, opaque 686*c8dee2aaSAndroid Build Coastguard Worker } 687*c8dee2aaSAndroid Build Coastguard Worker canvas.save(); 688*c8dee2aaSAndroid Build Coastguard Worker // Set up 3D view enviroment 689*c8dee2aaSAndroid Build Coastguard Worker canvas.concat(CanvasKit.M44.setupCamera( 690*c8dee2aaSAndroid Build Coastguard Worker CanvasKit.LTRBRect(0, 0, sizeX, sizeY), halfDim, cam)); 691*c8dee2aaSAndroid Build Coastguard Worker 692*c8dee2aaSAndroid Build Coastguard Worker // Rotate the whole paragraph as a unit. 693*c8dee2aaSAndroid Build Coastguard Worker const paraRotPoint = [halfDim, halfDim, 1]; 694*c8dee2aaSAndroid Build Coastguard Worker canvas.concat(CanvasKit.M44.multiply( 695*c8dee2aaSAndroid Build Coastguard Worker CanvasKit.M44.translated(paraRotPoint), 696*c8dee2aaSAndroid Build Coastguard Worker CanvasKit.M44.rotated([0,1,0], rotX), 697*c8dee2aaSAndroid Build Coastguard Worker CanvasKit.M44.rotated([1,0,0], rotY * 0.2), 698*c8dee2aaSAndroid Build Coastguard Worker CanvasKit.M44.translated(CanvasKit.Vector.mulScalar(paraRotPoint, -1)), 699*c8dee2aaSAndroid Build Coastguard Worker )); 700*c8dee2aaSAndroid Build Coastguard Worker 701*c8dee2aaSAndroid Build Coastguard Worker // Rotate every glyph in the paragraph individually. 702*c8dee2aaSAndroid Build Coastguard Worker let i = 0; 703*c8dee2aaSAndroid Build Coastguard Worker for (const letter of letters) { 704*c8dee2aaSAndroid Build Coastguard Worker canvas.save(); 705*c8dee2aaSAndroid Build Coastguard Worker let r = letter['r']; 706*c8dee2aaSAndroid Build Coastguard Worker // rotate about the center of the glyph's rect. 707*c8dee2aaSAndroid Build Coastguard Worker rotationPoint = [ 708*c8dee2aaSAndroid Build Coastguard Worker margin + r[rectLeft] + (r[rectRight] - r[rectLeft]) / 2, 709*c8dee2aaSAndroid Build Coastguard Worker marginTop + r[rectTop] + (r[rectBottom] - r[rectTop]) / 2, 710*c8dee2aaSAndroid Build Coastguard Worker 0 711*c8dee2aaSAndroid Build Coastguard Worker ]; 712*c8dee2aaSAndroid Build Coastguard Worker distanceFromPointer = CanvasKit.Vector.dist(pointer, rotationPoint.slice(0, 2)); 713*c8dee2aaSAndroid Build Coastguard Worker // Rotate more around the Y-axis depending on the glyph's distance from the pointer. 714*c8dee2aaSAndroid Build Coastguard Worker canvas.concat(CanvasKit.M44.multiply( 715*c8dee2aaSAndroid Build Coastguard Worker CanvasKit.M44.translated(rotationPoint), 716*c8dee2aaSAndroid Build Coastguard Worker // note that I'm rotating around the x axis first, undoing some of the rotation done to the whole 717*c8dee2aaSAndroid Build Coastguard Worker // paragraph above, where x came second. If I rotated y first, a lot of letters would end up 718*c8dee2aaSAndroid Build Coastguard Worker // upside down, which is a bit too hard to unscramble. 719*c8dee2aaSAndroid Build Coastguard Worker CanvasKit.M44.rotated([1,0,0], rotY * -0.6), 720*c8dee2aaSAndroid Build Coastguard Worker CanvasKit.M44.rotated([0,1,0], distanceFromPointer * -0.035), 721*c8dee2aaSAndroid Build Coastguard Worker CanvasKit.M44.translated(CanvasKit.Vector.mulScalar(rotationPoint, -1)), 722*c8dee2aaSAndroid Build Coastguard Worker )); 723*c8dee2aaSAndroid Build Coastguard Worker canvas.drawParagraph(letter['para'], margin + r[rectLeft], marginTop + r[rectTop]); 724*c8dee2aaSAndroid Build Coastguard Worker i++; 725*c8dee2aaSAndroid Build Coastguard Worker canvas.restore(); 726*c8dee2aaSAndroid Build Coastguard Worker } 727*c8dee2aaSAndroid Build Coastguard Worker canvas.restore(); 728*c8dee2aaSAndroid Build Coastguard Worker lastImage = surface.makeImageSnapshot(); 729*c8dee2aaSAndroid Build Coastguard Worker } 730*c8dee2aaSAndroid Build Coastguard Worker 731*c8dee2aaSAndroid Build Coastguard Worker function interact(e) { 732*c8dee2aaSAndroid Build Coastguard Worker pointer = [e.offsetX, e.offsetY] 733*c8dee2aaSAndroid Build Coastguard Worker rotX = (pointer[0] - halfDim) * radPerPixel; 734*c8dee2aaSAndroid Build Coastguard Worker rotY = (pointer[1] - halfDim) * radPerPixel * -1; 735*c8dee2aaSAndroid Build Coastguard Worker surface.requestAnimationFrame(drawFrame); 736*c8dee2aaSAndroid Build Coastguard Worker }; 737*c8dee2aaSAndroid Build Coastguard Worker 738*c8dee2aaSAndroid Build Coastguard Worker document.getElementById('glyphgame').addEventListener('pointermove', interact); 739*c8dee2aaSAndroid Build Coastguard Worker surface.requestAnimationFrame(drawFrame); 740*c8dee2aaSAndroid Build Coastguard Worker } 741*c8dee2aaSAndroid Build Coastguard Worker 742*c8dee2aaSAndroid Build Coastguard Worker function ColorSupport(CanvasKit) { 743*c8dee2aaSAndroid Build Coastguard Worker const surface = CanvasKit.MakeCanvasSurface('colorsupport', CanvasKit.ColorSpace.ADOBE_RGB); 744*c8dee2aaSAndroid Build Coastguard Worker if (!surface) { 745*c8dee2aaSAndroid Build Coastguard Worker console.error('Could not make surface'); 746*c8dee2aaSAndroid Build Coastguard Worker return; 747*c8dee2aaSAndroid Build Coastguard Worker } 748*c8dee2aaSAndroid Build Coastguard Worker const canvas = surface.getCanvas(); 749*c8dee2aaSAndroid Build Coastguard Worker 750*c8dee2aaSAndroid Build Coastguard Worker // If the surface is correctly initialized with a higher bit depth color type, 751*c8dee2aaSAndroid Build Coastguard Worker // And chrome is compositing it into a buffer with the P3 color space, 752*c8dee2aaSAndroid Build Coastguard Worker // then the inner round rect should be distinct and less saturated than the full red background. 753*c8dee2aaSAndroid Build Coastguard Worker // Even if the monitor it is viewed on cannot accurately represent that color space. 754*c8dee2aaSAndroid Build Coastguard Worker 755*c8dee2aaSAndroid Build Coastguard Worker let red = CanvasKit.Color4f(1, 0, 0, 1); 756*c8dee2aaSAndroid Build Coastguard Worker let paint = new CanvasKit.Paint(); 757*c8dee2aaSAndroid Build Coastguard Worker paint.setColor(red, CanvasKit.ColorSpace.ADOBE_RGB); 758*c8dee2aaSAndroid Build Coastguard Worker canvas.drawPaint(paint); 759*c8dee2aaSAndroid Build Coastguard Worker paint.setColor(red, CanvasKit.ColorSpace.DISPLAY_P3); 760*c8dee2aaSAndroid Build Coastguard Worker canvas.drawRRect(CanvasKit.RRectXY([50, 50, 250, 250], 30, 30), paint); 761*c8dee2aaSAndroid Build Coastguard Worker paint.setColor(red, CanvasKit.ColorSpace.SRGB); 762*c8dee2aaSAndroid Build Coastguard Worker canvas.drawRRect(CanvasKit.RRectXY([100, 100, 200, 200], 30, 30), paint); 763*c8dee2aaSAndroid Build Coastguard Worker 764*c8dee2aaSAndroid Build Coastguard Worker surface.flush(); 765*c8dee2aaSAndroid Build Coastguard Worker surface.delete(); 766*c8dee2aaSAndroid Build Coastguard Worker } 767*c8dee2aaSAndroid Build Coastguard Worker</script> 768