xref: /aosp_15_r20/external/skia/site/docs/user/modules/quickstart.md (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker
2*c8dee2aaSAndroid Build Coastguard Worker---
3*c8dee2aaSAndroid Build Coastguard Workertitle: "CanvasKit - Quickstart"
4*c8dee2aaSAndroid Build Coastguard WorkerlinkTitle: "CanvasKit - Quickstart"
5*c8dee2aaSAndroid Build Coastguard Worker
6*c8dee2aaSAndroid Build Coastguard Worker---
7*c8dee2aaSAndroid Build Coastguard Worker
8*c8dee2aaSAndroid Build Coastguard Worker
9*c8dee2aaSAndroid Build Coastguard WorkerCanvasKit is a wasm module that uses Skia to draw to canvas elements a more advance feature set than the canvas API.
10*c8dee2aaSAndroid Build Coastguard Worker
11*c8dee2aaSAndroid Build Coastguard WorkerMinimal application
12*c8dee2aaSAndroid Build Coastguard Worker-------------------
13*c8dee2aaSAndroid Build Coastguard Worker
14*c8dee2aaSAndroid Build Coastguard WorkerThis example is a minimal Canvaskit application that draws a rounded rect for one frame.
15*c8dee2aaSAndroid Build Coastguard WorkerIt pulls the wasm binary from unpkg.com but you can also build and host it yourself.
16*c8dee2aaSAndroid Build Coastguard Worker
17*c8dee2aaSAndroid Build Coastguard Worker<!--?prettify?-->
18*c8dee2aaSAndroid Build Coastguard Worker``` js
19*c8dee2aaSAndroid Build Coastguard Worker<canvas id=foo width=300 height=300></canvas>
20*c8dee2aaSAndroid Build Coastguard Worker
21*c8dee2aaSAndroid Build Coastguard Worker<script type="text/javascript"
22*c8dee2aaSAndroid Build Coastguard Worker  src="https://unpkg.com/[email protected]/bin/canvaskit.js"></script>
23*c8dee2aaSAndroid Build Coastguard Worker<script type="text/javascript">
24*c8dee2aaSAndroid Build Coastguard Worker  const ckLoaded = CanvasKitInit({
25*c8dee2aaSAndroid Build Coastguard Worker    locateFile: (file) => 'https://unpkg.com/[email protected]/bin/'+file});
26*c8dee2aaSAndroid Build Coastguard Worker  ckLoaded.then((CanvasKit) => {
27*c8dee2aaSAndroid Build Coastguard Worker    const surface = CanvasKit.MakeCanvasSurface('foo');
28*c8dee2aaSAndroid Build Coastguard Worker
29*c8dee2aaSAndroid Build Coastguard Worker    const paint = new CanvasKit.Paint();
30*c8dee2aaSAndroid Build Coastguard Worker    paint.setColor(CanvasKit.Color4f(0.9, 0, 0, 1.0));
31*c8dee2aaSAndroid Build Coastguard Worker    paint.setStyle(CanvasKit.PaintStyle.Stroke);
32*c8dee2aaSAndroid Build Coastguard Worker    paint.setAntiAlias(true);
33*c8dee2aaSAndroid Build Coastguard Worker    const rr = CanvasKit.RRectXY(CanvasKit.LTRBRect(10, 60, 210, 260), 25, 15);
34*c8dee2aaSAndroid Build Coastguard Worker
35*c8dee2aaSAndroid Build Coastguard Worker    function draw(canvas) {
36*c8dee2aaSAndroid Build Coastguard Worker      canvas.clear(CanvasKit.WHITE);
37*c8dee2aaSAndroid Build Coastguard Worker      canvas.drawRRect(rr, paint);
38*c8dee2aaSAndroid Build Coastguard Worker    }
39*c8dee2aaSAndroid Build Coastguard Worker    surface.drawOnce(draw);
40*c8dee2aaSAndroid Build Coastguard Worker  });
41*c8dee2aaSAndroid Build Coastguard Worker</script>
42*c8dee2aaSAndroid Build Coastguard Worker```
43*c8dee2aaSAndroid Build Coastguard Worker
44*c8dee2aaSAndroid Build Coastguard Worker<canvas id=foo width=300 height=300></canvas>
45*c8dee2aaSAndroid Build Coastguard Worker
46*c8dee2aaSAndroid Build Coastguard Worker<script type="text/javascript"
47*c8dee2aaSAndroid Build Coastguard Worker  src="https://unpkg.com/[email protected]/bin/canvaskit.js"></script>
48*c8dee2aaSAndroid Build Coastguard Worker<script type="text/javascript">
49*c8dee2aaSAndroid Build Coastguard Worker  const ckLoaded = CanvasKitInit({
50*c8dee2aaSAndroid Build Coastguard Worker    locateFile: (file) => 'https://unpkg.com/[email protected]/bin/'+file});
51*c8dee2aaSAndroid Build Coastguard Worker  ckLoaded.then((CanvasKit) => {
52*c8dee2aaSAndroid Build Coastguard Worker    const surface = CanvasKit.MakeCanvasSurface('foo');
53*c8dee2aaSAndroid Build Coastguard Worker
54*c8dee2aaSAndroid Build Coastguard Worker    const paint = new CanvasKit.Paint();
55*c8dee2aaSAndroid Build Coastguard Worker    paint.setColor(CanvasKit.Color4f(0.9, 0, 0, 1.0));
56*c8dee2aaSAndroid Build Coastguard Worker    paint.setStyle(CanvasKit.PaintStyle.Stroke);
57*c8dee2aaSAndroid Build Coastguard Worker    paint.setAntiAlias(true);
58*c8dee2aaSAndroid Build Coastguard Worker    const rr = CanvasKit.RRectXY(CanvasKit.LTRBRect(10, 60, 210, 260), 25, 15);
59*c8dee2aaSAndroid Build Coastguard Worker
60*c8dee2aaSAndroid Build Coastguard Worker    function draw(canvas) {
61*c8dee2aaSAndroid Build Coastguard Worker      canvas.clear(CanvasKit.WHITE);
62*c8dee2aaSAndroid Build Coastguard Worker      canvas.drawRRect(rr, paint);
63*c8dee2aaSAndroid Build Coastguard Worker    }
64*c8dee2aaSAndroid Build Coastguard Worker    surface.drawOnce(draw);
65*c8dee2aaSAndroid Build Coastguard Worker  });
66*c8dee2aaSAndroid Build Coastguard Worker</script>
67*c8dee2aaSAndroid Build Coastguard Worker
68*c8dee2aaSAndroid Build Coastguard WorkerLet's break it down into parts and explain what they are doing:
69*c8dee2aaSAndroid Build Coastguard Worker
70*c8dee2aaSAndroid Build Coastguard Worker`<canvas id=foo width=300 height=300></canvas>` Creates the canvas to which CanvasKit will draw.
71*c8dee2aaSAndroid Build Coastguard WorkerThis element is where we control the width and height of the drawing buffer, while it's css style
72*c8dee2aaSAndroid Build Coastguard Workerwould control any scaling applied after drawing to those pixels. Despite using a canvas element,
73*c8dee2aaSAndroid Build Coastguard WorkerCanvasKit isn't calling the HTML canvas's own draw methods. It is using this canvas element to
74*c8dee2aaSAndroid Build Coastguard Workerget a WebGL2 context and performing most of the drawing work in C++ code compiled to WebAssembly,
75*c8dee2aaSAndroid Build Coastguard Workerthen sending commands to the GPU at the end of each frame.
76*c8dee2aaSAndroid Build Coastguard Worker
77*c8dee2aaSAndroid Build Coastguard Worker<!--?prettify?-->
78*c8dee2aaSAndroid Build Coastguard Worker``` html
79*c8dee2aaSAndroid Build Coastguard Worker<script type="text/javascript"
80*c8dee2aaSAndroid Build Coastguard Worker  src="https://unpkg.com/[email protected]/bin/canvaskit.js"></script>
81*c8dee2aaSAndroid Build Coastguard Worker```
82*c8dee2aaSAndroid Build Coastguard Workerand
83*c8dee2aaSAndroid Build Coastguard Worker
84*c8dee2aaSAndroid Build Coastguard Worker<!--?prettify?-->
85*c8dee2aaSAndroid Build Coastguard Worker``` js
86*c8dee2aaSAndroid Build Coastguard Workerconst ckLoaded = CanvasKitInit({
87*c8dee2aaSAndroid Build Coastguard Worker  locateFile: (file) => 'https://unpkg.com/[email protected]/bin/'+file});
88*c8dee2aaSAndroid Build Coastguard WorkerckLoaded.then((CanvasKit) => {
89*c8dee2aaSAndroid Build Coastguard Worker```
90*c8dee2aaSAndroid Build Coastguard Workerare loading the canvaskit helper js and wasm binary respectively. CanvasKitInit accepts a function
91*c8dee2aaSAndroid Build Coastguard Workerfor allowing you to alter the path where it will try to find `canvaskit.wasm` and returns a promise
92*c8dee2aaSAndroid Build Coastguard Workerthat resolves with the loaded module, which we typically name `CanvasKit`.
93*c8dee2aaSAndroid Build Coastguard Worker
94*c8dee2aaSAndroid Build Coastguard Worker<!--?prettify?-->
95*c8dee2aaSAndroid Build Coastguard Worker``` js
96*c8dee2aaSAndroid Build Coastguard Workerconst surface = CanvasKit.MakeCanvasSurface('foo');
97*c8dee2aaSAndroid Build Coastguard Worker```
98*c8dee2aaSAndroid Build Coastguard WorkerCreates a Surface associated with the HTML canvas element above.
99*c8dee2aaSAndroid Build Coastguard WorkerHardware acceleration is the default behavior, but can be overridden by calling
100*c8dee2aaSAndroid Build Coastguard Worker`MakeSWCanvasSurface` instead. `MakeCanvasSurface` is also where alternative color spaces or gl
101*c8dee2aaSAndroid Build Coastguard Workerattrtributes can be specified.
102*c8dee2aaSAndroid Build Coastguard Worker
103*c8dee2aaSAndroid Build Coastguard Worker<!--?prettify?-->
104*c8dee2aaSAndroid Build Coastguard Worker``` js
105*c8dee2aaSAndroid Build Coastguard Workerconst paint = new CanvasKit.Paint();
106*c8dee2aaSAndroid Build Coastguard Workerpaint.setColor(CanvasKit.Color4f(0.9, 0, 0, 1.0));
107*c8dee2aaSAndroid Build Coastguard Workerpaint.setStyle(CanvasKit.PaintStyle.Stroke);
108*c8dee2aaSAndroid Build Coastguard Workerpaint.setAntiAlias(true);
109*c8dee2aaSAndroid Build Coastguard Workerconst rr = CanvasKit.RRectXY(CanvasKit.LTRBRect(10, 60, 210, 260), 25, 15);
110*c8dee2aaSAndroid Build Coastguard Worker```
111*c8dee2aaSAndroid Build Coastguard WorkerCreates a paint, a description of how to fill or stroke rects, paths, text and other geometry in
112*c8dee2aaSAndroid Build Coastguard Workercanvaskit. `rr` is a rounded rect, with corners having a radius of 25 in the x axis, and 15 pixels
113*c8dee2aaSAndroid Build Coastguard Workerin the y axis.
114*c8dee2aaSAndroid Build Coastguard Worker
115*c8dee2aaSAndroid Build Coastguard Worker<!--?prettify?-->
116*c8dee2aaSAndroid Build Coastguard Worker``` js
117*c8dee2aaSAndroid Build Coastguard Workerfunction draw(canvas) {
118*c8dee2aaSAndroid Build Coastguard Worker  canvas.clear(CanvasKit.WHITE);
119*c8dee2aaSAndroid Build Coastguard Worker  canvas.drawRRect(rr, paint);
120*c8dee2aaSAndroid Build Coastguard Worker}
121*c8dee2aaSAndroid Build Coastguard Worker```
122*c8dee2aaSAndroid Build Coastguard WorkerDefines a function that will draw our frame. The function is provided a Canvas object on which we
123*c8dee2aaSAndroid Build Coastguard Workermake draw calls. One to clear the entire canvas, and one to draw the rounded rect with the
124*c8dee2aaSAndroid Build Coastguard Workerpaint from above.
125*c8dee2aaSAndroid Build Coastguard Worker
126*c8dee2aaSAndroid Build Coastguard WorkerWe also delete the paint object. CanvasKit objects created with `new` or methods prefixed with
127*c8dee2aaSAndroid Build Coastguard Worker`make` must be deleted for the wasm memory to be released. Javascript's GC will not take care of
128*c8dee2aaSAndroid Build Coastguard Workerit automatically. `rr` is just an array, wasn't created with `new` and doesn't point to any WASM
129*c8dee2aaSAndroid Build Coastguard Workermemory, so we don't have to call delete on it.
130*c8dee2aaSAndroid Build Coastguard Worker
131*c8dee2aaSAndroid Build Coastguard Worker<!--?prettify?-->
132*c8dee2aaSAndroid Build Coastguard Worker``` js
133*c8dee2aaSAndroid Build Coastguard Workersurface.drawOnce(draw);
134*c8dee2aaSAndroid Build Coastguard Workerpaint.delete()
135*c8dee2aaSAndroid Build Coastguard Worker```
136*c8dee2aaSAndroid Build Coastguard WorkerHand the drawing function to `surface.drawOnce` which makes the calls and flushes the surface.
137*c8dee2aaSAndroid Build Coastguard WorkerUpon flushing, Skia will batch and send WebGL commands, making visible changes appear onscreen.
138*c8dee2aaSAndroid Build Coastguard WorkerThis example draws once and disposes of the surface. As promised, it is is a minimal
139*c8dee2aaSAndroid Build Coastguard Workerapplication.
140*c8dee2aaSAndroid Build Coastguard Worker
141*c8dee2aaSAndroid Build Coastguard WorkerBasic Draw Loop
142*c8dee2aaSAndroid Build Coastguard Worker---------------
143*c8dee2aaSAndroid Build Coastguard Worker
144*c8dee2aaSAndroid Build Coastguard WorkerWhat if we need to redraw to our canvas every frame? This example
145*c8dee2aaSAndroid Build Coastguard Workerbounces a rounded rect around like a 90s screensaver.
146*c8dee2aaSAndroid Build Coastguard Worker
147*c8dee2aaSAndroid Build Coastguard Worker<!--?prettify?-->
148*c8dee2aaSAndroid Build Coastguard Worker``` js
149*c8dee2aaSAndroid Build Coastguard WorkerckLoaded.then((CanvasKit) => {
150*c8dee2aaSAndroid Build Coastguard Worker  const surface = CanvasKit.MakeCanvasSurface('foo2');
151*c8dee2aaSAndroid Build Coastguard Worker
152*c8dee2aaSAndroid Build Coastguard Worker  const paint = new CanvasKit.Paint();
153*c8dee2aaSAndroid Build Coastguard Worker  paint.setColor(CanvasKit.Color4f(0.9, 0, 0, 1.0));
154*c8dee2aaSAndroid Build Coastguard Worker  paint.setStyle(CanvasKit.PaintStyle.Stroke);
155*c8dee2aaSAndroid Build Coastguard Worker  paint.setAntiAlias(true);
156*c8dee2aaSAndroid Build Coastguard Worker  // const rr = CanvasKit.RRectXY(CanvasKit.LTRBRect(10, 60, 210, 260), 25, 15);
157*c8dee2aaSAndroid Build Coastguard Worker  const w = 100; // size of rect
158*c8dee2aaSAndroid Build Coastguard Worker  const h = 60;
159*c8dee2aaSAndroid Build Coastguard Worker  let x = 10; // initial position of top left corner.
160*c8dee2aaSAndroid Build Coastguard Worker  let y = 60;
161*c8dee2aaSAndroid Build Coastguard Worker  let dirX = 1; // box is always moving at a constant speed in one of the four diagonal directions
162*c8dee2aaSAndroid Build Coastguard Worker  let dirY = 1;
163*c8dee2aaSAndroid Build Coastguard Worker
164*c8dee2aaSAndroid Build Coastguard Worker  function drawFrame(canvas) {
165*c8dee2aaSAndroid Build Coastguard Worker    // boundary check
166*c8dee2aaSAndroid Build Coastguard Worker    if (x < 0 || x+w > 300) {
167*c8dee2aaSAndroid Build Coastguard Worker      dirX *= -1; // reverse x direction when hitting side walls
168*c8dee2aaSAndroid Build Coastguard Worker    }
169*c8dee2aaSAndroid Build Coastguard Worker    if (y < 0 || y+h > 300) {
170*c8dee2aaSAndroid Build Coastguard Worker      dirY *= -1; // reverse y direction when hitting top and bottom walls
171*c8dee2aaSAndroid Build Coastguard Worker    }
172*c8dee2aaSAndroid Build Coastguard Worker    // move
173*c8dee2aaSAndroid Build Coastguard Worker    x += dirX;
174*c8dee2aaSAndroid Build Coastguard Worker    y += dirY;
175*c8dee2aaSAndroid Build Coastguard Worker
176*c8dee2aaSAndroid Build Coastguard Worker    canvas.clear(CanvasKit.WHITE);
177*c8dee2aaSAndroid Build Coastguard Worker    const rr = CanvasKit.RRectXY(CanvasKit.LTRBRect(x, y, x+w, y+h), 25, 15);
178*c8dee2aaSAndroid Build Coastguard Worker    canvas.drawRRect(rr, paint);
179*c8dee2aaSAndroid Build Coastguard Worker    surface.requestAnimationFrame(drawFrame);
180*c8dee2aaSAndroid Build Coastguard Worker  }
181*c8dee2aaSAndroid Build Coastguard Worker  surface.requestAnimationFrame(drawFrame);
182*c8dee2aaSAndroid Build Coastguard Worker});
183*c8dee2aaSAndroid Build Coastguard Worker```
184*c8dee2aaSAndroid Build Coastguard Worker
185*c8dee2aaSAndroid Build Coastguard Worker<canvas id=foo2 width=300 height=300></canvas>
186*c8dee2aaSAndroid Build Coastguard Worker
187*c8dee2aaSAndroid Build Coastguard Worker<script type="text/javascript">
188*c8dee2aaSAndroid Build Coastguard Worker  ckLoaded.then((CanvasKit) => {
189*c8dee2aaSAndroid Build Coastguard Worker    const surface = CanvasKit.MakeCanvasSurface('foo2');
190*c8dee2aaSAndroid Build Coastguard Worker
191*c8dee2aaSAndroid Build Coastguard Worker    const paint = new CanvasKit.Paint();
192*c8dee2aaSAndroid Build Coastguard Worker    paint.setColor(CanvasKit.Color4f(0.9, 0, 0, 1.0));
193*c8dee2aaSAndroid Build Coastguard Worker    paint.setStyle(CanvasKit.PaintStyle.Stroke);
194*c8dee2aaSAndroid Build Coastguard Worker    paint.setAntiAlias(true);
195*c8dee2aaSAndroid Build Coastguard Worker    // const rr = CanvasKit.RRectXY(CanvasKit.LTRBRect(10, 60, 210, 260), 25, 15);
196*c8dee2aaSAndroid Build Coastguard Worker    const w = 100; // size of rect
197*c8dee2aaSAndroid Build Coastguard Worker    const h = 60;
198*c8dee2aaSAndroid Build Coastguard Worker    let x = 10; // initial position of top left corner.
199*c8dee2aaSAndroid Build Coastguard Worker    let y = 60;
200*c8dee2aaSAndroid Build Coastguard Worker    // The box is always moving at a constant speed in one of the four diagonal directions
201*c8dee2aaSAndroid Build Coastguard Worker    let dirX = 1;
202*c8dee2aaSAndroid Build Coastguard Worker    let dirY = 1;
203*c8dee2aaSAndroid Build Coastguard Worker
204*c8dee2aaSAndroid Build Coastguard Worker    function drawFrame(canvas) {
205*c8dee2aaSAndroid Build Coastguard Worker      // boundary check
206*c8dee2aaSAndroid Build Coastguard Worker      if (x < 0 || x+w > 300) {
207*c8dee2aaSAndroid Build Coastguard Worker        dirX *= -1; // reverse x direction when hitting side walls
208*c8dee2aaSAndroid Build Coastguard Worker      }
209*c8dee2aaSAndroid Build Coastguard Worker      if (y < 0 || y+h > 300) {
210*c8dee2aaSAndroid Build Coastguard Worker        dirY *= -1; // reverse y direction when hitting top and bottom walls
211*c8dee2aaSAndroid Build Coastguard Worker      }
212*c8dee2aaSAndroid Build Coastguard Worker      // move
213*c8dee2aaSAndroid Build Coastguard Worker      x += dirX;
214*c8dee2aaSAndroid Build Coastguard Worker      y += dirY;
215*c8dee2aaSAndroid Build Coastguard Worker
216*c8dee2aaSAndroid Build Coastguard Worker      canvas.clear(CanvasKit.WHITE);
217*c8dee2aaSAndroid Build Coastguard Worker      const rr = CanvasKit.RRectXY(CanvasKit.LTRBRect(x, y, x+w, y+h), 25, 15);
218*c8dee2aaSAndroid Build Coastguard Worker      canvas.drawRRect(rr, paint);
219*c8dee2aaSAndroid Build Coastguard Worker      surface.requestAnimationFrame(drawFrame);
220*c8dee2aaSAndroid Build Coastguard Worker    }
221*c8dee2aaSAndroid Build Coastguard Worker    surface.requestAnimationFrame(drawFrame);
222*c8dee2aaSAndroid Build Coastguard Worker  });
223*c8dee2aaSAndroid Build Coastguard Worker</script>
224*c8dee2aaSAndroid Build Coastguard Worker
225*c8dee2aaSAndroid Build Coastguard WorkerThe main difference here is that we define a function to be called before each frame is drawn and
226*c8dee2aaSAndroid Build Coastguard Workerpass it to `surface.requestAnimationFrame(drawFrame);` That callback is handed a `canvas` and
227*c8dee2aaSAndroid Build Coastguard Workerflushing is taken care of.
228*c8dee2aaSAndroid Build Coastguard Worker
229*c8dee2aaSAndroid Build Coastguard Worker<!--?prettify?-->
230*c8dee2aaSAndroid Build Coastguard Worker``` js
231*c8dee2aaSAndroid Build Coastguard Workerfunction drawFrame(canvas) {
232*c8dee2aaSAndroid Build Coastguard Worker  canvas.clear(CanvasKit.WHITE);
233*c8dee2aaSAndroid Build Coastguard Worker  // code to update and draw the frame goes here
234*c8dee2aaSAndroid Build Coastguard Worker  surface.requestAnimationFrame(drawFrame);
235*c8dee2aaSAndroid Build Coastguard Worker}
236*c8dee2aaSAndroid Build Coastguard Workersurface.requestAnimationFrame(drawFrame);
237*c8dee2aaSAndroid Build Coastguard Worker```
238*c8dee2aaSAndroid Build Coastguard Worker
239*c8dee2aaSAndroid Build Coastguard WorkerCreates a function to serve as our main drawing loop. Each time a frame is about to be rendered
240*c8dee2aaSAndroid Build Coastguard Worker(the browser will typically target 60fps), our function is called, we clear the canvas with white,
241*c8dee2aaSAndroid Build Coastguard Workerredraw the round rect, and call `surface.requestAnimationFrame(drawFrame)` registering the
242*c8dee2aaSAndroid Build Coastguard Workerfunction to be called again before the next frame.
243*c8dee2aaSAndroid Build Coastguard Worker
244*c8dee2aaSAndroid Build Coastguard Worker`surface.requestAnimationFrame(drawFrame)` combines window.requestAnimationFrame with
245*c8dee2aaSAndroid Build Coastguard Worker`surface.flush()` and should be used in all the same ways. If your application would only make
246*c8dee2aaSAndroid Build Coastguard Workervisible changes as a result of mouse events,
247*c8dee2aaSAndroid Build Coastguard Workerdon't call `surface.requestAnimationFrame` at the end of your drawFrame function. Call it only
248*c8dee2aaSAndroid Build Coastguard Workerafter handling mouse input.
249*c8dee2aaSAndroid Build Coastguard Worker
250*c8dee2aaSAndroid Build Coastguard WorkerText Shaping
251*c8dee2aaSAndroid Build Coastguard Worker------------
252*c8dee2aaSAndroid Build Coastguard Worker
253*c8dee2aaSAndroid Build Coastguard WorkerOne of the biggest features that CanvasKit offers over the HTML Canvas API is paragraph shaping.
254*c8dee2aaSAndroid Build Coastguard WorkerTo use text your applicatoin, supply a font file and use Promise.all to run your code when both
255*c8dee2aaSAndroid Build Coastguard WorkerCanvasKit and the font file are ready.
256*c8dee2aaSAndroid Build Coastguard Worker
257*c8dee2aaSAndroid Build Coastguard Worker<!--?prettify?-->
258*c8dee2aaSAndroid Build Coastguard Worker``` js
259*c8dee2aaSAndroid Build Coastguard Workerconst loadFont = fetch('https://storage.googleapis.com/skia-cdn/misc/Roboto-Regular.ttf')
260*c8dee2aaSAndroid Build Coastguard Worker  .then((response) => response.arrayBuffer());
261*c8dee2aaSAndroid Build Coastguard Worker
262*c8dee2aaSAndroid Build Coastguard WorkerPromise.all([ckLoaded, loadFont]).then(([CanvasKit, robotoData]) => {
263*c8dee2aaSAndroid Build Coastguard Worker  const surface = CanvasKit.MakeCanvasSurface('foo3');
264*c8dee2aaSAndroid Build Coastguard Worker  const canvas = surface.getCanvas();
265*c8dee2aaSAndroid Build Coastguard Worker  canvas.clear(CanvasKit.Color4f(0.9, 0.9, 0.9, 1.0));
266*c8dee2aaSAndroid Build Coastguard Worker
267*c8dee2aaSAndroid Build Coastguard Worker  const fontMgr = CanvasKit.FontMgr.FromData([robotoData]);
268*c8dee2aaSAndroid Build Coastguard Worker  const paraStyle = new CanvasKit.ParagraphStyle({
269*c8dee2aaSAndroid Build Coastguard Worker    textStyle: {
270*c8dee2aaSAndroid Build Coastguard Worker      color: CanvasKit.BLACK,
271*c8dee2aaSAndroid Build Coastguard Worker      fontFamilies: ['Roboto'],
272*c8dee2aaSAndroid Build Coastguard Worker      fontSize: 28,
273*c8dee2aaSAndroid Build Coastguard Worker    },
274*c8dee2aaSAndroid Build Coastguard Worker    textAlign: CanvasKit.TextAlign.Left,
275*c8dee2aaSAndroid Build Coastguard Worker  });
276*c8dee2aaSAndroid Build Coastguard Worker  const text = 'Any sufficiently entrenched technology is indistinguishable from Javascript';
277*c8dee2aaSAndroid Build Coastguard Worker  const builder = CanvasKit.ParagraphBuilder.Make(paraStyle, fontMgr);
278*c8dee2aaSAndroid Build Coastguard Worker  builder.addText(text);
279*c8dee2aaSAndroid Build Coastguard Worker  const paragraph = builder.build();
280*c8dee2aaSAndroid Build Coastguard Worker  paragraph.layout(290); // width in pixels to use when wrapping text
281*c8dee2aaSAndroid Build Coastguard Worker  canvas.drawParagraph(paragraph, 10, 10);
282*c8dee2aaSAndroid Build Coastguard Worker  surface.flush();
283*c8dee2aaSAndroid Build Coastguard Worker});
284*c8dee2aaSAndroid Build Coastguard Worker```
285*c8dee2aaSAndroid Build Coastguard Worker
286*c8dee2aaSAndroid Build Coastguard Worker<canvas id=foo3 width=300 height=300></canvas>
287*c8dee2aaSAndroid Build Coastguard Worker
288*c8dee2aaSAndroid Build Coastguard Worker<script type="text/javascript">
289*c8dee2aaSAndroid Build Coastguard Workerconst loadFont = fetch('https://storage.googleapis.com/skia-cdn/misc/Roboto-Regular.ttf')
290*c8dee2aaSAndroid Build Coastguard Worker  .then((response) => response.arrayBuffer());
291*c8dee2aaSAndroid Build Coastguard Worker
292*c8dee2aaSAndroid Build Coastguard WorkerPromise.all([ckLoaded, loadFont]).then(([CanvasKit, robotoData]) => {
293*c8dee2aaSAndroid Build Coastguard Worker  const surface = CanvasKit.MakeCanvasSurface('foo3');
294*c8dee2aaSAndroid Build Coastguard Worker  const canvas = surface.getCanvas();
295*c8dee2aaSAndroid Build Coastguard Worker  canvas.clear(CanvasKit.Color4f(0.9, 0.9, 0.9, 1.0));
296*c8dee2aaSAndroid Build Coastguard Worker
297*c8dee2aaSAndroid Build Coastguard Worker  const fontMgr = CanvasKit.FontMgr.FromData([robotoData]);
298*c8dee2aaSAndroid Build Coastguard Worker  const paraStyle = new CanvasKit.ParagraphStyle({
299*c8dee2aaSAndroid Build Coastguard Worker    textStyle: {
300*c8dee2aaSAndroid Build Coastguard Worker      color: CanvasKit.BLACK,
301*c8dee2aaSAndroid Build Coastguard Worker      fontFamilies: ['Roboto'],
302*c8dee2aaSAndroid Build Coastguard Worker      fontSize: 28,
303*c8dee2aaSAndroid Build Coastguard Worker    },
304*c8dee2aaSAndroid Build Coastguard Worker    textAlign: CanvasKit.TextAlign.Left,
305*c8dee2aaSAndroid Build Coastguard Worker  });
306*c8dee2aaSAndroid Build Coastguard Worker  const text = 'Any sufficiently entrenched technology is indistinguishable from Javascript';
307*c8dee2aaSAndroid Build Coastguard Worker  const builder = CanvasKit.ParagraphBuilder.Make(paraStyle, fontMgr);
308*c8dee2aaSAndroid Build Coastguard Worker  builder.addText(text);
309*c8dee2aaSAndroid Build Coastguard Worker  const paragraph = builder.build();
310*c8dee2aaSAndroid Build Coastguard Worker  paragraph.layout(290); // width in pixels to use when wrapping text
311*c8dee2aaSAndroid Build Coastguard Worker  canvas.drawParagraph(paragraph, 10, 10);
312*c8dee2aaSAndroid Build Coastguard Worker  surface.flush();
313*c8dee2aaSAndroid Build Coastguard Worker});
314*c8dee2aaSAndroid Build Coastguard Worker</script>
315*c8dee2aaSAndroid Build Coastguard Worker
316*c8dee2aaSAndroid Build Coastguard Worker<!--?prettify?-->
317*c8dee2aaSAndroid Build Coastguard Worker``` js
318*c8dee2aaSAndroid Build Coastguard Workerconst fontMgr = CanvasKit.FontMgr.FromData([robotoData]);
319*c8dee2aaSAndroid Build Coastguard Worker```
320*c8dee2aaSAndroid Build Coastguard WorkerCreates an object that provides fonts by name to various text facilities in CanvasKit. You could
321*c8dee2aaSAndroid Build Coastguard Workerload more than one font in this statement if needed.
322*c8dee2aaSAndroid Build Coastguard Worker
323*c8dee2aaSAndroid Build Coastguard Worker<!--?prettify?-->
324*c8dee2aaSAndroid Build Coastguard Worker``` js
325*c8dee2aaSAndroid Build Coastguard Workerconst paraStyle = new CanvasKit.ParagraphStyle({
326*c8dee2aaSAndroid Build Coastguard Worker  textStyle: {
327*c8dee2aaSAndroid Build Coastguard Worker    color: CanvasKit.BLACK,
328*c8dee2aaSAndroid Build Coastguard Worker    fontFamilies: ['Roboto'],
329*c8dee2aaSAndroid Build Coastguard Worker    fontSize: 28,
330*c8dee2aaSAndroid Build Coastguard Worker  },
331*c8dee2aaSAndroid Build Coastguard Worker  textAlign: CanvasKit.TextAlign.Left,
332*c8dee2aaSAndroid Build Coastguard Worker});
333*c8dee2aaSAndroid Build Coastguard Worker```
334*c8dee2aaSAndroid Build Coastguard WorkerSpecifies the style of the text. The font's name, Roboto, will be used to fetch it from the font
335*c8dee2aaSAndroid Build Coastguard Workermanager. You can specify either (color) or (foregroundColor and backgroundColor) in order to have
336*c8dee2aaSAndroid Build Coastguard Workera highlight. For the full documentation of the API, check out the Typescript definitions in the
337*c8dee2aaSAndroid Build Coastguard Worker`types/` subfolder of the npm package or in the
338*c8dee2aaSAndroid Build Coastguard Worker[Skia repo](https://github.com/google/skia/tree/main/modules/canvaskit/npm_build/types).
339*c8dee2aaSAndroid Build Coastguard Worker
340*c8dee2aaSAndroid Build Coastguard Worker<!--?prettify?-->
341*c8dee2aaSAndroid Build Coastguard Worker``` js
342*c8dee2aaSAndroid Build Coastguard Workerconst builder = CanvasKit.ParagraphBuilder.Make(paraStyle, fontMgr);
343*c8dee2aaSAndroid Build Coastguard Workerbuilder.addText(text);
344*c8dee2aaSAndroid Build Coastguard Workerconst paragraph = builder.build();
345*c8dee2aaSAndroid Build Coastguard Worker```
346*c8dee2aaSAndroid Build Coastguard WorkerNext, we create a `ParagraphBuilder` with a style, add some text, and finalize it with `build()`.
347*c8dee2aaSAndroid Build Coastguard WorkerAlternatively, we could use multiple `TextStyle`s in one paragraph with
348*c8dee2aaSAndroid Build Coastguard Worker
349*c8dee2aaSAndroid Build Coastguard Worker<!--?prettify?-->
350*c8dee2aaSAndroid Build Coastguard Worker``` js
351*c8dee2aaSAndroid Build Coastguard Workerconst builder = CanvasKit.ParagraphBuilder.Make(paraStyle, fontMgr);
352*c8dee2aaSAndroid Build Coastguard Workerbuilder.addText(text1);
353*c8dee2aaSAndroid Build Coastguard Workerconst boldTextStyle = CanvasKit.TextStyle({
354*c8dee2aaSAndroid Build Coastguard Worker    color: CanvasKit.BLACK,
355*c8dee2aaSAndroid Build Coastguard Worker    fontFamilies: ['Roboto'],
356*c8dee2aaSAndroid Build Coastguard Worker    fontSize: 28,
357*c8dee2aaSAndroid Build Coastguard Worker    fontStyle: {'weight': CanvasKit.FontWeight.Bold},
358*c8dee2aaSAndroid Build Coastguard Worker})
359*c8dee2aaSAndroid Build Coastguard Workerbuilder.pushStyle(boldTextStyle);
360*c8dee2aaSAndroid Build Coastguard Workerbuilder.addText(text2);
361*c8dee2aaSAndroid Build Coastguard Workerbuilder.pop();
362*c8dee2aaSAndroid Build Coastguard Workerbuilder.addText(text3);
363*c8dee2aaSAndroid Build Coastguard Workerconst paragraph = builder.build();
364*c8dee2aaSAndroid Build Coastguard Worker```
365*c8dee2aaSAndroid Build Coastguard WorkerFinally, we *layout* the paragraph, meaning wrap the text to a particular width, and draw it to
366*c8dee2aaSAndroid Build Coastguard Workerthe canvas with
367*c8dee2aaSAndroid Build Coastguard Worker
368*c8dee2aaSAndroid Build Coastguard Worker<!--?prettify?-->
369*c8dee2aaSAndroid Build Coastguard Worker``` js
370*c8dee2aaSAndroid Build Coastguard Workerparagraph.layout(290); // width in pixels to use when wrapping text
371*c8dee2aaSAndroid Build Coastguard Workercanvas.drawParagraph(paragraph, 10, 10); // (x, y) position of left top corner of paragraph.
372*c8dee2aaSAndroid Build Coastguard Worker```
373*c8dee2aaSAndroid Build Coastguard Worker
374