Import Cobalt 25.master.0.1033734
diff --git a/third_party/skia/modules/canvaskit/npm_build/.gitignore b/third_party/skia/modules/canvaskit/npm_build/.gitignore
new file mode 100644
index 0000000..10e23fa
--- /dev/null
+++ b/third_party/skia/modules/canvaskit/npm_build/.gitignore
@@ -0,0 +1,4 @@
+bin/
+debug/
+package-lock.json
+node_modules/
diff --git a/third_party/skia/modules/canvaskit/npm_build/CODE_OF_CONDUCT.md b/third_party/skia/modules/canvaskit/npm_build/CODE_OF_CONDUCT.md
new file mode 100644
index 0000000..e5358bc
--- /dev/null
+++ b/third_party/skia/modules/canvaskit/npm_build/CODE_OF_CONDUCT.md
@@ -0,0 +1,93 @@
+# Code of Conduct
+
+## Our Pledge
+
+In the interest of fostering an open and welcoming environment, we as
+contributors and maintainers pledge to making participation in our project and
+our community a harassment-free experience for everyone, regardless of age, body
+size, disability, ethnicity, gender identity and expression, level of
+experience, education, socio-economic status, nationality, personal appearance,
+race, religion, or sexual identity and orientation.
+
+## Our Standards
+
+Examples of behavior that contributes to creating a positive environment
+include:
+
+* Using welcoming and inclusive language
+* Being respectful of differing viewpoints and experiences
+* Gracefully accepting constructive criticism
+* Focusing on what is best for the community
+* Showing empathy towards other community members
+
+Examples of unacceptable behavior by participants include:
+
+* The use of sexualized language or imagery and unwelcome sexual attention or
+ advances
+* Trolling, insulting/derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or electronic
+ address, without explicit permission
+* Other conduct which could reasonably be considered inappropriate in a
+ professional setting
+
+## Our Responsibilities
+
+Project maintainers are responsible for clarifying the standards of acceptable
+behavior and are expected to take appropriate and fair corrective action in
+response to any instances of unacceptable behavior.
+
+Project maintainers have the right and responsibility to remove, edit, or reject
+comments, commits, code, wiki edits, issues, and other contributions that are
+not aligned to this Code of Conduct, or to ban temporarily or permanently any
+contributor for other behaviors that they deem inappropriate, threatening,
+offensive, or harmful.
+
+## Scope
+
+This Code of Conduct applies both within project spaces and in public spaces
+when an individual is representing the project or its community. Examples of
+representing a project or community include using an official project e-mail
+address, posting via an official social media account, or acting as an appointed
+representative at an online or offline event. Representation of a project may be
+further defined and clarified by project maintainers.
+
+This Code of Conduct also applies outside the project spaces when the Project
+Steward has a reasonable belief that an individual's behavior may have a
+negative impact on the project or its community.
+
+## Conflict Resolution
+
+We do not believe that all conflict is bad; healthy debate and disagreement
+often yield positive results. However, it is never okay to be disrespectful or
+to engage in behavior that violates the project’s code of conduct.
+
+If you see someone violating the code of conduct, you are encouraged to address
+the behavior directly with those involved. Many issues can be resolved quickly
+and easily, and this gives people more control over the outcome of their
+dispute. If you are unable to resolve the matter for any reason, or if the
+behavior is threatening or harassing, report it. We are dedicated to providing
+an environment where participants feel welcome and safe.
+
+Reports should be directed to [Heather Miller](mailto:hcm@google.com), the
+Project Steward(s) for *canvaskit*. It is the Project Steward’s duty to
+receive and address reported violations of the code of conduct. They will then
+work with a committee consisting of representatives from the Open Source
+Programs Office and the Google Open Source Strategy team. If for any reason you
+are uncomfortable reaching out the Project Steward, please email
+opensource@google.com.
+
+We will investigate every complaint, but you may not receive a direct response.
+We will use our discretion in determining when and how to follow up on reported
+incidents, which may range from not taking action to permanent expulsion from
+the project and project-sponsored spaces. We will notify the accused of the
+report and provide them an opportunity to discuss it before any action is taken.
+The identity of the reporter will be omitted from the details of the report
+supplied to the accused. In potentially harmful situations, such as ongoing
+harassment or threats to anyone's safety, we may take action without notice.
+
+## Attribution
+
+This Code of Conduct is adapted from the Contributor Covenant, version 1.4,
+available at
+https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
diff --git a/third_party/skia/modules/canvaskit/npm_build/CONTRIBUTING.md b/third_party/skia/modules/canvaskit/npm_build/CONTRIBUTING.md
new file mode 100644
index 0000000..5fa3c4a
--- /dev/null
+++ b/third_party/skia/modules/canvaskit/npm_build/CONTRIBUTING.md
@@ -0,0 +1,21 @@
+# How to Contribute
+
+We'd love to accept your patches and contributions to this project. There are
+just a few small guidelines you need to follow.
+
+## Contributor License Agreement
+
+Contributions to this project must be accompanied by a Contributor License
+Agreement. You (or your employer) retain the copyright to your contribution;
+this simply gives us permission to use and redistribute your contributions as
+part of the project. Head over to <https://cla.developers.google.com/> to see
+your current agreements on file or to sign a new one.
+
+You generally only need to submit a CLA once, so if you've already submitted one
+(even if it was for a different project), you probably don't need to do it
+again.
+
+## Code reviews
+
+All submissions, including submissions by project members, require review.
+Please see the guidelines for contributing code at https://skia.org/dev/contrib/
\ No newline at end of file
diff --git a/third_party/skia/modules/canvaskit/npm_build/LICENSE b/third_party/skia/modules/canvaskit/npm_build/LICENSE
new file mode 100644
index 0000000..fc53e3e
--- /dev/null
+++ b/third_party/skia/modules/canvaskit/npm_build/LICENSE
@@ -0,0 +1,29 @@
+// Copyright (c) 2011 Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+--------------------------------------------------------------------------------
diff --git a/third_party/skia/modules/canvaskit/npm_build/README.md b/third_party/skia/modules/canvaskit/npm_build/README.md
new file mode 100644
index 0000000..a2c2f63
--- /dev/null
+++ b/third_party/skia/modules/canvaskit/npm_build/README.md
@@ -0,0 +1,119 @@
+A WASM version of Skia's Canvas API.
+
+See https://skia.org/user/modules/canvaskit for more background information.
+
+# Getting Started
+
+## Browser
+To use the library, run `npm install canvaskit-wasm` and then simply include it:
+
+ <script src="/node_modules/canvaskit-wasm/bin/canvaskit.js"></script>
+ CanvasKitInit({
+ locateFile: (file) => '/node_modules/canvaskit-wasm/bin/'+file,
+ }).then((CanvasKit) => {
+ // Code goes here using CanvasKit
+ });
+
+As with all npm packages, there's a freely available CDN via unpkg.com:
+
+ <script src="https://unpkg.com/canvaskit-wasm@0.18.1/bin/canvaskit.js"></script>
+ CanvasKitInit({
+ locateFile: (file) => 'https://unpkg.com/canvaskit-wasm@0.18.1/bin/'+file,
+ }).then(...)
+
+## Node
+To use CanvasKit in Node, it's similar to the browser:
+
+ const CanvasKitInit = require('/node_modules/canvaskit-wasm/bin/canvaskit.js');
+ CanvasKitInit({
+ locateFile: (file) => __dirname + '/bin/'+file,
+ }).then((CanvasKit) => {
+ // Code goes here using CanvasKit
+ });
+
+With node, you also need to supply the `--expose-wasm` flag.
+
+## WebPack
+
+WebPack's support for WASM is still somewhat experimental, but CanvasKit can be
+used with a few configuration changes.
+
+In the JS code, use require():
+
+ const CanvasKitInit = require('canvaskit-wasm/bin/canvaskit.js')
+ CanvasKitInit().then((CanvasKit) => {
+ // Code goes here using CanvasKit
+ });
+
+Since WebPack does not expose the entire `/node_modules/` directory, but instead
+packages only the needed pieces, we have to copy canvaskit.wasm into the build directory.
+One such solution is to use [CopyWebpackPlugin](https://github.com/webpack-contrib/copy-webpack-plugin).
+For example, add the following plugin:
+
+ config.plugins.push(
+ new CopyWebpackPlugin([
+ { from: 'node_modules/canvaskit-wasm/bin/canvaskit.wasm' }
+ ])
+ );
+
+If webpack gives an error similar to:
+
+ ERROR in ./node_modules/canvaskit-wasm/bin/canvaskit.js
+ Module not found: Error: Can't resolve 'fs' in '...'
+
+Then, add the following configuration change to the node section of the config:
+
+ config.node = {
+ fs: 'empty'
+ };
+
+
+# Using the CanvasKit API
+
+See `example.html` and `node.example.js` for demos of how to use the core API.
+
+See `extra.html` for some optional add-ins like an animation player (Skottie)
+and a particles system.
+
+See `types/index.d.ts` for a typescript definition file that contains all the
+APIs and some documentation about them.
+
+## Drop-in Canvas2D replacement
+For environments where an HTML canvas is not available (e.g. Node, headless servers),
+CanvasKit has an optional API (included by default) that mostly mirrors the HTML canvas.
+
+ let skcanvas = CanvasKit.MakeCanvas(600, 600);
+
+ let ctx = skcanvas.getContext('2d');
+ let rgradient = ctx.createRadialGradient(200, 300, 10, 100, 100, 300);
+
+ // Add three color stops
+ rgradient.addColorStop(0, 'red');
+ rgradient.addColorStop(0.7, 'white');
+ rgradient.addColorStop(1, 'blue');
+
+ ctx.fillStyle = rgradient;
+ ctx.globalAlpha = 0.7;
+ ctx.fillRect(0, 0, 600, 600);
+
+ let imgData = skcanvas.toDataURL();
+ // imgData is now a base64 encoded image.
+
+See more examples in `example.html` and `node.example.js`.
+
+### Known issues with Canvas2D Emulation layer
+ - measureText returns width only and does no shaping. It is only sort of valid with ASCII letters.
+ - textAlign is not supported.
+ - textBaseAlign is not supported.
+ - fillText does not support the width parameter.
+
+# Filing bugs
+
+Please file bugs at [skbug.com](skbug.com).
+It may be convenient to use [our online fiddle](jsfiddle.skia.org/canvaskit) to demonstrate any issues encountered.
+
+See CONTRIBUTING.md for more information on sending pull requests.
+
+# Types and Documentation
+
+There are Typescript types and associated API docs in types/.
diff --git a/third_party/skia/modules/canvaskit/npm_build/example.html b/third_party/skia/modules/canvaskit/npm_build/example.html
new file mode 100644
index 0000000..a194580
--- /dev/null
+++ b/third_party/skia/modules/canvaskit/npm_build/example.html
@@ -0,0 +1,1249 @@
+<!DOCTYPE html>
+<title>CanvasKit (Skia via Web Assembly)</title>
+<meta charset="utf-8" />
+<meta http-equiv="X-UA-Compatible" content="IE=edge">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+
+<style>
+ canvas, img {
+ border: 1px dashed #AAA;
+ }
+ #api5_c, #api6_c {
+ width: 300px;
+ height: 300px;
+ }
+
+</style>
+
+<h2>Drop in replacement for HTML Canvas (e.g. node.js)</h2>
+<img id=api1 width=300 height=300>
+<canvas id=api1_c width=300 height=300></canvas>
+<img id=api2 width=300 height=300>
+<canvas id=api2_c width=300 height=300></canvas>
+<img id=api3 width=300 height=300>
+<canvas id=api3_c width=300 height=300></canvas>
+<img id=api4 width=300 height=300>
+<canvas id=api4_c width=300 height=300></canvas>
+<img id=api5 width=300 height=300>
+<canvas id=api5_c width=300 height=300></canvas>
+<img id=api6 width=300 height=300>
+<canvas id=api6_c width=300 height=300></canvas>
+<img id=api7 width=300 height=300>
+<canvas id=api7_c width=300 height=300></canvas>
+<img id=api8 width=300 height=300>
+<canvas id=api8_c width=300 height=300></canvas>
+
+<h2> CanvasKit expands the functionality of a stock HTML canvas</h2>
+<canvas id=vertex1 width=300 height=300></canvas>
+<canvas id=gradient1 width=300 height=300></canvas>
+<canvas id=patheffect width=300 height=300></canvas>
+<canvas id=paths width=200 height=200></canvas>
+<canvas id=pathperson width=300 height=300></canvas>
+<canvas id=ink width=300 height=300></canvas>
+<canvas id=surfaces width=300 height=300></canvas>
+<canvas id=atlas width=300 height=300></canvas>
+<canvas id=decode width=300 height=300></canvas>
+
+<h2> CanvasKit can allow for text measurement/placement (e.g. breaking, kerning)</h2>
+<canvas id=textonpath width=300 height=300></canvas>
+<canvas id=drawGlyphs width=300 height=300></canvas>
+
+<h2> Interactive drawPatch</h2>
+<canvas id=interdrawpatch width=512 height=512></canvas>
+
+<script type="text/javascript" src="/build/canvaskit.js"></script>
+
+<script type="text/javascript" charset="utf-8">
+
+ var CanvasKit = null;
+ var cdn = 'https://storage.googleapis.com/skia-cdn/misc/';
+
+ const ckLoaded = CanvasKitInit({locateFile: (file) => '/build/'+file});
+
+ const loadRoboto = fetch(cdn + 'Roboto-Regular.ttf').then((response) => response.arrayBuffer());
+ const loadNotoSerif = fetch(cdn + 'NotoSerif-Regular.ttf').then((response) => response.arrayBuffer());
+ const loadTestImage = fetch(cdn + 'test.png').then((response) => response.arrayBuffer());
+
+ // Examples which only require canvaskit
+ ckLoaded.then((CK) => {
+ CanvasKit = CK;
+ PathExample(CanvasKit);
+ InkExample(CanvasKit);
+ PathPersonExample(CanvasKit);
+ VertexAPI1(CanvasKit);
+ GradiantAPI1(CanvasKit);
+ TextOnPathAPI1(CanvasKit);
+ DrawGlyphsAPI1(CanvasKit);
+ SurfaceAPI1(CanvasKit);
+ if (CanvasKit.MakeCanvas){
+ CanvasAPI1(CanvasKit);
+ CanvasAPI2(CanvasKit);
+ CanvasAPI3(CanvasKit);
+ CanvasAPI4(CanvasKit);
+ CanvasAPI5(CanvasKit);
+ CanvasAPI6(CanvasKit);
+ CanvasAPI7(CanvasKit);
+ CanvasAPI8(CanvasKit);
+ } else {
+ console.log("Skipping CanvasAPI1 because it's not compiled in");
+ }
+ InteractivePatch(CanvasKit);
+ });
+
+ // Examples requiring external resources
+ Promise.all([ckLoaded, loadRoboto]).then((results) => {DrawingExample(...results)});
+ Promise.all([ckLoaded, loadTestImage]).then((results) => {AtlasAPI1(...results)});
+ Promise.all([ckLoaded, loadTestImage]).then((results) => {DecodeAPI(...results)});
+
+ function DrawingExample(CanvasKit, robotoData) {
+ if (!robotoData || !CanvasKit) {
+ return;
+ }
+ const surface = CanvasKit.MakeCanvasSurface('patheffect');
+ if (!surface) {
+ console.error('Could not make surface');
+ return;
+ }
+
+ const paint = new CanvasKit.Paint();
+ const roboto = CanvasKit.Typeface.MakeFreeTypeFaceFromData(robotoData);
+
+ const textPaint = new CanvasKit.Paint();
+ textPaint.setColor(CanvasKit.RED);
+ textPaint.setAntiAlias(true);
+
+ const textFont = new CanvasKit.Font(roboto, 30);
+
+ let i = 0;
+
+ let X = 128;
+ let Y = 128;
+
+ function drawFrame(canvas) {
+ const path = starPath(CanvasKit, X, Y);
+ // Some animations see performance improvements by marking their
+ // paths as volatile.
+ path.setIsVolatile(true);
+ const dpe = CanvasKit.PathEffect.MakeDash([15, 5, 5, 10], i/5);
+ i++;
+
+ paint.setPathEffect(dpe);
+ paint.setStyle(CanvasKit.PaintStyle.Stroke);
+ paint.setStrokeWidth(5.0 + -3 * Math.cos(i/30));
+ paint.setAntiAlias(true);
+ paint.setColor(CanvasKit.Color(66, 129, 164, 1.0));
+
+ canvas.clear(CanvasKit.TRANSPARENT);
+
+ canvas.drawPath(path, paint);
+ canvas.drawText('Try Clicking!', 10, 280, textPaint, textFont);
+
+ dpe.delete();
+ path.delete();
+ surface.requestAnimationFrame(drawFrame);
+ }
+ surface.requestAnimationFrame(drawFrame);
+
+ // Make animation interactive
+ let interact = (e) => {
+ if (!e.pressure) {
+ return;
+ }
+ X = e.offsetX;
+ Y = e.offsetY;
+ };
+ document.getElementById('patheffect').addEventListener('pointermove', interact);
+ document.getElementById('patheffect').addEventListener('pointerdown', interact);
+ preventScrolling(document.getElementById('patheffect'));
+ // A client would need to delete this if it didn't go on for ever.
+ // paint.delete();
+ // textPaint.delete();
+ // textFont.delete();
+ }
+
+ function InteractivePatch(CanvasKit) {
+ const ELEM = 'interdrawpatch';
+ const surface = CanvasKit.MakeCanvasSurface(ELEM);
+ if (!surface) {
+ console.error('Could not make surface');
+ return;
+ }
+
+ let live_corner, live_index;
+
+ const paint = new CanvasKit.Paint();
+ const pts_paint = new CanvasKit.Paint();
+ pts_paint.setStyle(CanvasKit.PaintStyle.Stroke);
+ pts_paint.setStrokeWidth(9);
+ pts_paint.setStrokeCap(CanvasKit.StrokeCap.Round);
+
+ const line_paint = new CanvasKit.Paint();
+ line_paint.setStyle(CanvasKit.PaintStyle.Stroke);
+ line_paint.setStrokeWidth(2);
+
+ const colors = [CanvasKit.RED, CanvasKit.BLUE, CanvasKit.YELLOW, CanvasKit.CYAN];
+
+ const patch = [
+ [ 10,170, 10, 10, 170, 10], // prev_vector, point, next_vector
+ [340, 10, 500, 10, 500,170],
+ [500,340, 500,500, 340,500],
+ [170,500, 10,500, 10,340],
+ ];
+
+ function get_corner(corner, index) {
+ return [corner[index*2+0], corner[index*2+1]];
+ }
+
+ function push_xy(array, xy) {
+ array.push(xy[0], xy[1]);
+ }
+
+ function patch_to_cubics(patch) {
+ const array = [];
+ push_xy(array, get_corner(patch[0],1));
+ push_xy(array, get_corner(patch[0],2));
+ for (let i = 1; i < 4; ++i) {
+ push_xy(array, get_corner(patch[i],0));
+ push_xy(array, get_corner(patch[i],1));
+ push_xy(array, get_corner(patch[i],2));
+ }
+ push_xy(array, get_corner(patch[0],0));
+
+ return array;
+ }
+
+ function drawFrame(canvas) {
+ const cubics = patch_to_cubics(patch);
+
+ canvas.drawColor(CanvasKit.WHITE);
+ canvas.drawPatch(cubics, colors, null, CanvasKit.BlendMode.Dst, paint);
+ if (live_corner) {
+ canvas.drawPoints(CanvasKit.PointMode.Polygon, live_corner, line_paint);
+ }
+ canvas.drawPoints(CanvasKit.PointMode.Points, cubics, pts_paint);
+
+ surface.requestAnimationFrame(drawFrame);
+ }
+
+ surface.requestAnimationFrame(drawFrame);
+
+ function length2(x, y) {
+ return x*x + y*y;
+ }
+ function hit_test(x,y, x1,y1) {
+ return length2(x-x1, y-y1) <= 10*10;
+ }
+ function pointer_up(e) {
+ live_corner = null;
+ live_index = null;
+ }
+
+ function pointer_down(e) {
+ live_corner = null;
+ live_index = null;
+ for (p of patch) {
+ for (let i = 0; i < 6; i += 2) {
+ if (hit_test(p[i], p[i+1], e.offsetX, e.offsetY)) {
+ live_corner = p;
+ live_index = i;
+ }
+ }
+ }
+ }
+
+ function pointer_move(e) {
+ if (e.pressure && live_corner) {
+ if (live_index == 2) {
+ // corner
+ const dx = e.offsetX - live_corner[2];
+ const dy = e.offsetY - live_corner[3];
+ for (let i = 0; i < 3; ++i) {
+ live_corner[i*2+0] += dx;
+ live_corner[i*2+1] += dy;
+ }
+ } else {
+ // control-point
+ live_corner[live_index+0] = e.offsetX;
+ live_corner[live_index+1] = e.offsetY;
+ }
+ }
+ }
+ document.getElementById(ELEM).addEventListener('pointermove', pointer_move);
+ document.getElementById(ELEM).addEventListener('pointerdown', pointer_down);
+ document.getElementById(ELEM).addEventListener('pointerup', pointer_up);
+ preventScrolling(document.getElementById(ELEM));
+ }
+
+ function PathPersonExample(CanvasKit) {
+ const surface = CanvasKit.MakeSWCanvasSurface('pathperson');
+ if (!surface) {
+ console.error('Could not make surface');
+ return;
+ }
+
+ function drawFrame(canvas) {
+ const paint = new CanvasKit.Paint();
+ paint.setStrokeWidth(1.0);
+ paint.setAntiAlias(true);
+ paint.setColor(CanvasKit.Color(0, 0, 0, 1.0));
+ paint.setStyle(CanvasKit.PaintStyle.Stroke);
+
+ const path = new CanvasKit.Path();
+ path.moveTo(10, 10);
+ path.lineTo(100, 10);
+ path.moveTo(10, 10);
+ path.lineTo(10, 200);
+ path.moveTo(10, 100);
+ path.lineTo(100,100);
+ path.moveTo(10, 200);
+ path.lineTo(100, 200);
+
+ canvas.drawPath(path, paint);
+ path.delete();
+ paint.delete();
+ }
+ // Intentionally just draw frame once
+ surface.drawOnce(drawFrame);
+ }
+
+ function PathExample(CanvasKit) {
+ const surface = CanvasKit.MakeSWCanvasSurface('paths');
+ if (!surface) {
+ console.error('Could not make surface');
+ return;
+ }
+
+ function drawFrame(canvas) {
+ const paint = new CanvasKit.Paint();
+ paint.setStrokeWidth(1.0);
+ paint.setAntiAlias(true);
+ paint.setColor(CanvasKit.Color(0, 0, 0, 1.0));
+ paint.setStyle(CanvasKit.PaintStyle.Stroke);
+
+ const path = new CanvasKit.Path();
+ path.moveTo(20, 5);
+ path.lineTo(30, 20);
+ path.lineTo(40, 10);
+ path.lineTo(50, 20);
+ path.lineTo(60, 0);
+ path.lineTo(20, 5);
+
+ path.moveTo(20, 80);
+ path.cubicTo(90, 10, 160, 150, 190, 10);
+
+ path.moveTo(36, 148);
+ path.quadTo(66, 188, 120, 136);
+ path.lineTo(36, 148);
+
+ path.moveTo(150, 180);
+ path.arcToTangent(150, 100, 50, 200, 20);
+ path.lineTo(160, 160);
+
+ path.moveTo(20, 120);
+ path.lineTo(20, 120);
+
+ canvas.drawPath(path, paint);
+
+ const rrect = CanvasKit.RRectXY([100, 10, 140, 62], 10, 4);
+
+ const rrectPath = new CanvasKit.Path().addRRect(rrect, true);
+
+ canvas.drawPath(rrectPath, paint);
+
+ rrectPath.delete();
+ path.delete();
+ paint.delete();
+ }
+ // Intentionally just draw frame once
+ surface.drawOnce(drawFrame);
+ }
+
+ function preventScrolling(canvas) {
+ canvas.addEventListener('touchmove', (e) => {
+ // Prevents touch events in the canvas from scrolling the canvas.
+ e.preventDefault();
+ e.stopPropagation();
+ });
+ }
+
+ function InkExample(CanvasKit) {
+ const surface = CanvasKit.MakeCanvasSurface('ink');
+ if (!surface) {
+ console.error('Could not make surface');
+ return;
+ }
+
+ let paint = new CanvasKit.Paint();
+ paint.setAntiAlias(true);
+ paint.setColor(CanvasKit.Color(0, 0, 0, 1.0));
+ paint.setStyle(CanvasKit.PaintStyle.Stroke);
+ paint.setStrokeWidth(4.0);
+ paint.setPathEffect(CanvasKit.PathEffect.MakeCorner(50));
+
+ // Draw I N K
+ let path = new CanvasKit.Path();
+ path.moveTo(80, 30);
+ path.lineTo(80, 80);
+
+ path.moveTo(100, 80);
+ path.lineTo(100, 15);
+ path.lineTo(130, 95);
+ path.lineTo(130, 30);
+
+ path.moveTo(150, 30);
+ path.lineTo(150, 80);
+ path.moveTo(170, 30);
+ path.lineTo(150, 55);
+ path.lineTo(170, 80);
+
+ let paths = [path];
+ let paints = [paint];
+
+ function drawFrame(canvas) {
+ canvas.clear(CanvasKit.Color(255, 255, 255, 1.0));
+
+ for (let i = 0; i < paints.length && i < paths.length; i++) {
+ canvas.drawPath(paths[i], paints[i]);
+ }
+
+ surface.requestAnimationFrame(drawFrame);
+ }
+
+ let hold = false;
+ let interact = (e) => {
+ let type = e.type;
+ if (type === 'lostpointercapture' || type === 'pointerup' || !e.pressure ) {
+ hold = false;
+ return;
+ }
+ if (hold) {
+ path.lineTo(e.offsetX, e.offsetY);
+ } else {
+ paint = paint.copy();
+ paint.setColor(CanvasKit.Color(Math.random() * 255, Math.random() * 255, Math.random() * 255, Math.random() + .2));
+ paints.push(paint);
+ path = new CanvasKit.Path();
+ paths.push(path);
+ path.moveTo(e.offsetX, e.offsetY);
+ }
+ hold = true;
+ };
+ document.getElementById('ink').addEventListener('pointermove', interact);
+ document.getElementById('ink').addEventListener('pointerdown', interact);
+ document.getElementById('ink').addEventListener('lostpointercapture', interact);
+ document.getElementById('ink').addEventListener('pointerup', interact);
+ preventScrolling(document.getElementById('ink'));
+ surface.requestAnimationFrame(drawFrame);
+ }
+
+ function starPath(CanvasKit, X=128, Y=128, R=116) {
+ let p = new CanvasKit.Path();
+ p.moveTo(X + R, Y);
+ for (let i = 1; i < 8; i++) {
+ let a = 2.6927937 * i;
+ p.lineTo(X + R * Math.cos(a), Y + R * Math.sin(a));
+ }
+ return p;
+ }
+
+ function CanvasAPI1(CanvasKit) {
+ let skcanvas = CanvasKit.MakeCanvas(300, 300);
+ let realCanvas = document.getElementById('api1_c');
+
+ let skPromise = fetch(cdn + 'test.png')
+ // if clients want to use a Blob, they are responsible
+ // for reading it themselves.
+ .then((response) => response.arrayBuffer())
+ .then((buffer) => {
+ skcanvas._img = skcanvas.decodeImage(buffer);
+ });
+ let realPromise = fetch(cdn + 'test.png')
+ .then((response) => response.blob())
+ .then((blob) => createImageBitmap(blob))
+ .then((bitmap) => {
+ realCanvas._img = bitmap;
+ });
+
+ let realFontLoaded = new FontFace('Bungee', 'url(/tests/assets/Bungee-Regular.ttf)', {
+ 'family': 'Bungee',
+ 'style': 'normal',
+ 'weight': '400',
+ }).load().then((font) => {
+ document.fonts.add(font);
+ });
+
+ let skFontLoaded = fetch('/tests/assets/Bungee-Regular.ttf').then(
+ (response) => response.arrayBuffer()).then(
+ (buffer) => {
+ // loadFont is synchronous
+ skcanvas.loadFont(buffer, {
+ 'family': 'Bungee',
+ 'style': 'normal',
+ 'weight': '400',
+ });
+ });
+
+ Promise.all([realPromise, skPromise, realFontLoaded, skFontLoaded]).then(() => {
+ for (let canvas of [skcanvas, realCanvas]) {
+ let ctx = canvas.getContext('2d');
+ ctx.fillStyle = '#EEE';
+ ctx.fillRect(0, 0, 300, 300);
+ ctx.fillStyle = 'black';
+ ctx.font = '26px Bungee';
+ ctx.rotate(.1);
+ let text = ctx.measureText('Awesome');
+ ctx.fillText('Awesome ', 25, 100);
+ ctx.strokeText('Groovy!', 35 + text.width, 100);
+
+ // Draw line under Awesome
+ ctx.strokeStyle = 'rgba(125,0,0,0.5)';
+ ctx.beginPath();
+ ctx.lineWidth = 6;
+ ctx.moveTo(25, 105);
+ ctx.lineTo(200, 105);
+ ctx.stroke();
+
+ // squished vertically
+ ctx.globalAlpha = 0.7;
+ ctx.imageSmoothingQuality = 'medium';
+ ctx.drawImage(canvas._img, 150, 150, 150, 100);
+ ctx.rotate(-.2);
+ ctx.imageSmoothingEnabled = false;
+ ctx.drawImage(canvas._img, 100, 150, 400, 350, 10, 200, 150, 100);
+
+ let idata = ctx.getImageData(80, 220, 40, 45);
+ ctx.putImageData(idata, 250, 10);
+ ctx.putImageData(idata, 200, 10, 20, 10, 20, 30);
+ ctx.resetTransform();
+ ctx.strokeStyle = 'black';
+ ctx.lineWidth = 1;
+ ctx.strokeRect(200, 10, 40, 45);
+
+ idata = ctx.createImageData(10, 20);
+ ctx.putImageData(idata, 10, 10);
+ }
+
+ document.getElementById('api1').src = skcanvas.toDataURL();
+ skcanvas.dispose();
+ });
+
+ }
+
+ function CanvasAPI2(CanvasKit) {
+ let skcanvas = CanvasKit.MakeCanvas(300, 300);
+ let realCanvas = document.getElementById('api2_c');
+ realCanvas.width = 300;
+ realCanvas.height = 300;
+
+ // svg data for a clock
+ 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');
+ 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');
+
+ for (let canvas of [skcanvas, realCanvas]) {
+ let ctx = canvas.getContext('2d');
+ ctx.scale(1.5, 1.5);
+ ctx.moveTo(20, 5);
+ ctx.lineTo(30, 20);
+ ctx.lineTo(40, 10);
+ ctx.lineTo(50, 20);
+ ctx.lineTo(60, 0);
+ ctx.lineTo(20, 5);
+
+ ctx.moveTo(20, 80);
+ ctx.bezierCurveTo(90, 10, 160, 150, 190, 10);
+
+ ctx.moveTo(36, 148);
+ ctx.quadraticCurveTo(66, 188, 120, 136);
+ ctx.lineTo(36, 148);
+
+ ctx.rect(5, 170, 20, 25);
+
+ ctx.moveTo(150, 180);
+ ctx.arcTo(150, 100, 50, 200, 20);
+ ctx.lineTo(160, 160);
+
+ ctx.moveTo(20, 120);
+ ctx.arc(20, 120, 18, 0, 1.75 * Math.PI);
+ ctx.lineTo(20, 120);
+
+ ctx.moveTo(150, 5);
+ ctx.ellipse(130, 25, 30, 10, -1*Math.PI/8, Math.PI/6, 1.5*Math.PI);
+
+ ctx.lineWidth = 4/3;
+ ctx.stroke();
+
+ // make a clock
+ ctx.stroke(canvas._path);
+
+ // Test edgecases and draw direction
+ ctx.beginPath();
+ ctx.arc(50, 100, 10, Math.PI, -Math.PI/2);
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.arc(75, 100, 10, Math.PI, -Math.PI/2, true);
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.arc(100, 100, 10, Math.PI, 100.1 * Math.PI, true);
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.arc(125, 100, 10, Math.PI, 100.1 * Math.PI, false);
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.ellipse(155, 100, 10, 15, Math.PI/8, 100.1 * Math.PI, Math.PI, true);
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.ellipse(180, 100, 10, 15, Math.PI/8, Math.PI, 100.1 * Math.PI, true);
+ ctx.stroke();
+ }
+ document.getElementById('api2').src = skcanvas.toDataURL();
+ skcanvas.dispose();
+ }
+
+ function CanvasAPI3(CanvasKit) {
+ let skcanvas = CanvasKit.MakeCanvas(300, 300);
+ let realCanvas = document.getElementById('api3_c');
+ realCanvas.width = 300;
+ realCanvas.height = 300;
+
+ for (let canvas of [skcanvas, realCanvas]) {
+ let ctx = canvas.getContext('2d');
+ ctx.rect(10, 10, 20, 20);
+
+ ctx.scale(2.0, 4.0);
+ ctx.rect(30, 10, 20, 20);
+ ctx.resetTransform();
+
+ ctx.rotate(Math.PI / 3);
+ ctx.rect(50, 10, 20, 20);
+ ctx.resetTransform();
+
+ ctx.translate(30, -2);
+ ctx.rect(70, 10, 20, 20);
+ ctx.resetTransform();
+
+ ctx.translate(60, 0);
+ ctx.rotate(Math.PI / 6);
+ ctx.transform(1.5, 0, 0, 0.5, 0, 0); // effectively scale
+ ctx.rect(90, 10, 20, 20);
+ ctx.resetTransform();
+
+ ctx.save();
+ ctx.setTransform(2, 0, -.5, 2.5, -40, 120);
+ ctx.rect(110, 10, 20, 20);
+ ctx.lineTo(110, 0);
+ ctx.restore();
+ ctx.lineTo(220, 120);
+
+ ctx.scale(3.0, 3.0);
+ ctx.font = '6pt Noto Mono';
+ ctx.fillText('This text should be huge', 10, 80);
+ ctx.resetTransform();
+
+ ctx.strokeStyle = 'black';
+ ctx.lineWidth = 2;
+ ctx.stroke();
+
+ ctx.beginPath();
+ ctx.moveTo(250, 30);
+ ctx.lineTo(250, 80);
+ ctx.scale(3.0, 3.0);
+ ctx.lineTo(280/3, 90/3);
+ ctx.closePath();
+ ctx.strokeStyle = 'black';
+ ctx.lineWidth = 5;
+ ctx.stroke();
+
+ }
+ document.getElementById('api3').src = skcanvas.toDataURL();
+ skcanvas.dispose();
+ }
+
+ function CanvasAPI4(CanvasKit) {
+ let skcanvas = CanvasKit.MakeCanvas(300, 300);
+ let realCanvas = document.getElementById('api4_c');
+ realCanvas.width = 300;
+ realCanvas.height = 300;
+
+ for (let canvas of [skcanvas, realCanvas]) {
+ let ctx = canvas.getContext('2d');
+
+ ctx.strokeStyle = '#000';
+ ctx.fillStyle = '#CCC';
+ ctx.shadowColor = 'rebeccapurple';
+ ctx.shadowBlur = 1;
+ ctx.shadowOffsetX = 3;
+ ctx.shadowOffsetY = -8;
+ ctx.rect(10, 10, 30, 30);
+
+ ctx.save();
+ ctx.strokeStyle = '#C00';
+ ctx.fillStyle = '#00C';
+ ctx.shadowBlur = 0;
+ ctx.shadowColor = 'transparent';
+
+ ctx.stroke();
+
+ ctx.restore();
+ ctx.fill();
+
+ ctx.beginPath();
+ ctx.moveTo(36, 148);
+ ctx.quadraticCurveTo(66, 188, 120, 136);
+ ctx.closePath();
+ ctx.stroke();
+
+ ctx.beginPath();
+ ctx.shadowColor = '#993366AA';
+ ctx.shadowOffsetX = 8;
+ ctx.shadowBlur = 5;
+ ctx.setTransform(2, 0, -.5, 2.5, -40, 120);
+ ctx.rect(110, 10, 20, 20);
+ ctx.lineTo(110, 0);
+ ctx.resetTransform();
+ ctx.lineTo(220, 120);
+ ctx.stroke();
+
+ ctx.fillStyle = 'green';
+ ctx.font = '16pt Noto Mono';
+ ctx.fillText('This should be shadowed', 20, 80);
+
+ ctx.beginPath();
+ ctx.lineWidth = 6;
+ ctx.ellipse(10, 290, 30, 30, 0, 0, Math.PI * 2);
+ ctx.scale(2, 1);
+ ctx.moveTo(10, 290);
+ ctx.ellipse(10, 290, 30, 60, 0, 0, Math.PI * 2);
+ ctx.resetTransform();
+ ctx.scale(3, 1);
+ ctx.moveTo(10, 290);
+ ctx.ellipse(10, 290, 30, 90, 0, 0, Math.PI * 2);
+ ctx.stroke();
+ }
+ document.getElementById('api4').src = skcanvas.toDataURL();
+ skcanvas.dispose();
+ }
+
+ function CanvasAPI5(CanvasKit) {
+ let skcanvas = CanvasKit.MakeCanvas(600, 600);
+ let realCanvas = document.getElementById('api5_c');
+ realCanvas.width = 600;
+ realCanvas.height = 600;
+
+ for (let canvas of [skcanvas, realCanvas]) {
+ let ctx = canvas.getContext('2d');
+ ctx.scale(1.1, 1.1);
+ ctx.translate(10, 10);
+ // Shouldn't impact the fillRect calls
+ ctx.setLineDash([5, 3]);
+
+ ctx.fillStyle = 'rgba(200, 0, 100, 0.81)';
+ ctx.fillRect(20, 30, 100, 100);
+
+ ctx.globalAlpha = 0.81;
+ ctx.fillStyle = 'rgba(200, 0, 100, 1.0)';
+ ctx.fillRect(120, 30, 100, 100);
+ // This shouldn't do anything
+ ctx.globalAlpha = 0.1;
+
+ ctx.fillStyle = 'rgba(200, 0, 100, 0.9)';
+ ctx.globalAlpha = 0.9;
+ // Intentional no-op to check ordering
+ ctx.clearRect(220, 30, 100, 100);
+ ctx.fillRect(220, 30, 100, 100);
+
+ ctx.fillRect(320, 30, 100, 100);
+ ctx.clearRect(330, 40, 80, 80);
+
+ ctx.strokeStyle = 'blue';
+ ctx.lineWidth = 3;
+ ctx.setLineDash([5, 3]);
+ ctx.strokeRect(20, 150, 100, 100);
+ ctx.setLineDash([50, 30]);
+ ctx.strokeRect(125, 150, 100, 100);
+ ctx.lineDashOffset = 25;
+ ctx.strokeRect(230, 150, 100, 100);
+ ctx.setLineDash([2, 5, 9]);
+ ctx.strokeRect(335, 150, 100, 100);
+
+ ctx.setLineDash([5, 2]);
+ ctx.moveTo(336, 400);
+ ctx.quadraticCurveTo(366, 488, 120, 450);
+ ctx.lineTo(300, 400);
+ ctx.stroke();
+
+ ctx.font = '36pt Noto Mono';
+ ctx.strokeText('Dashed', 20, 350);
+ ctx.fillText('Not Dashed', 20, 400);
+
+ }
+ document.getElementById('api5').src = skcanvas.toDataURL();
+ skcanvas.dispose();
+ }
+
+ function CanvasAPI6(CanvasKit) {
+ let skcanvas = CanvasKit.MakeCanvas(600, 600);
+ let realCanvas = document.getElementById('api6_c');
+ realCanvas.width = 600;
+ realCanvas.height = 600;
+
+ for (let canvas of [skcanvas, realCanvas]) {
+ let ctx = canvas.getContext('2d');
+
+ let rgradient = ctx.createRadialGradient(200, 300, 10, 100, 100, 300);
+
+ // Add three color stops
+ rgradient.addColorStop(0, 'red');
+ rgradient.addColorStop(0.7, 'white');
+ rgradient.addColorStop(1, 'blue');
+
+ ctx.fillStyle = rgradient;
+ ctx.globalAlpha = 0.7;
+ ctx.fillRect(0, 0, 600, 600);
+ ctx.globalAlpha = 0.95;
+
+ ctx.beginPath();
+ ctx.arc(300, 100, 90, 0, Math.PI*1.66);
+ ctx.closePath();
+ ctx.strokeStyle = 'yellow';
+ ctx.lineWidth = 5;
+ ctx.stroke();
+ ctx.save();
+ ctx.clip();
+
+ let lgradient = ctx.createLinearGradient(200, 20, 420, 40);
+
+ // Add three color stops
+ lgradient.addColorStop(0, 'green');
+ lgradient.addColorStop(0.5, 'cyan');
+ lgradient.addColorStop(1, 'orange');
+
+ ctx.fillStyle = lgradient;
+
+ ctx.fillRect(200, 30, 200, 300);
+
+ ctx.restore();
+ ctx.fillRect(550, 550, 40, 40);
+
+ }
+ document.getElementById('api6').src = skcanvas.toDataURL();
+ skcanvas.dispose();
+ }
+
+ function CanvasAPI7(CanvasKit) {
+ let skcanvas = CanvasKit.MakeCanvas(300, 300);
+ let realCanvas = document.getElementById('api7_c');
+
+ let skPromise = fetch(cdn + 'test.png')
+ // if clients want to use a Blob, they are responsible
+ // for reading it themselves.
+ .then((response) => response.arrayBuffer())
+ .then((buffer) => {
+ skcanvas._img = skcanvas.decodeImage(buffer);
+ });
+ let realPromise = fetch(cdn + 'test.png')
+ .then((response) => response.blob())
+ .then((blob) => createImageBitmap(blob))
+ .then((bitmap) => {
+ realCanvas._img = bitmap;
+ });
+
+
+ Promise.all([realPromise, skPromise]).then(() => {
+ for (let canvas of [skcanvas, realCanvas]) {
+ let ctx = canvas.getContext('2d');
+ ctx.fillStyle = '#EEE';
+ ctx.fillRect(0, 0, 300, 300);
+ ctx.lineWidth = 20;
+ ctx.scale(0.1, 0.2);
+
+ let pattern = ctx.createPattern(canvas._img, 'repeat');
+ ctx.fillStyle = pattern;
+ ctx.fillRect(0, 0, 1500, 750);
+
+ pattern = ctx.createPattern(canvas._img, 'repeat-x');
+ ctx.fillStyle = pattern;
+ ctx.fillRect(1500, 0, 3000, 750);
+
+ ctx.globalAlpha = 0.7;
+ pattern = ctx.createPattern(canvas._img, 'repeat-y');
+ ctx.fillStyle = pattern;
+ ctx.fillRect(0, 750, 1500, 1500);
+ ctx.strokeRect(0, 750, 1500, 1500);
+
+ pattern = ctx.createPattern(canvas._img, 'no-repeat');
+ ctx.fillStyle = pattern;
+ pattern.setTransform({a: 1, b: -.1, c:.1, d: 0.5, e: 1800, f:800});
+ ctx.fillRect(0, 0, 3000, 1500);
+ }
+
+ document.getElementById('api7').src = skcanvas.toDataURL();
+ skcanvas.dispose();
+ });
+ }
+
+ function CanvasAPI8(CanvasKit) {
+ let skcanvas = CanvasKit.MakeCanvas(300, 300);
+ let realCanvas = document.getElementById('api8_c');
+
+ function drawPoint(ctx, x, y, color) {
+ ctx.fillStyle = color;
+ ctx.fillRect(x, y, 1, 1);
+ }
+ const IN = 'purple';
+ const OUT = 'orange';
+ const SCALE = 4;
+
+ const pts = [[3, 3], [4, 4], [5, 5], [10, 10], [8, 10], [6, 10],
+ [6.5, 9], [15, 10], [17, 10], [17, 11], [24, 24],
+ [25, 25], [26, 26], [27, 27]];
+
+ const tests = [
+ {
+ xOffset: 0,
+ yOffset: 0,
+ fillType: 'nonzero',
+ strokeWidth: 0,
+ testFn: (ctx, x, y) => ctx.isPointInPath(x * SCALE, y * SCALE, 'nonzero'),
+ },
+ {
+ xOffset: 30,
+ yOffset: 0,
+ fillType: 'evenodd',
+ strokeWidth: 0,
+ testFn: (ctx, x, y) => ctx.isPointInPath(x * SCALE, y * SCALE, 'evenodd'),
+ },
+ {
+ xOffset: 0,
+ yOffset: 30,
+ fillType: null,
+ strokeWidth: 1,
+ testFn: (ctx, x, y) => ctx.isPointInStroke(x * SCALE, y * SCALE),
+ },
+ {
+ xOffset: 30,
+ yOffset: 30,
+ fillType: null,
+ strokeWidth: 2,
+ testFn: (ctx, x, y) => ctx.isPointInStroke(x * SCALE, y * SCALE),
+ },
+ ];
+
+ for (let canvas of [skcanvas, realCanvas]) {
+ let ctx = canvas.getContext('2d');
+ ctx.font = '11px Noto Mono';
+ // Draw some visual aids
+ ctx.fillText('path-nonzero', 30, 15);
+ ctx.fillText('path-evenodd', 150, 15);
+ ctx.fillText('stroke-1px-wide', 30, 130);
+ ctx.fillText('stroke-2px-wide', 150, 130);
+ ctx.fillText('purple is IN, orange is OUT', 10, 280);
+
+ // Scale up to make single pixels easier to see
+ ctx.scale(SCALE, SCALE);
+ for (let test of tests) {
+ ctx.beginPath();
+ let xOffset = test.xOffset;
+ let yOffset = test.yOffset;
+
+ ctx.fillStyle = '#AAA';
+ ctx.lineWidth = test.strokeWidth;
+ ctx.rect(5+xOffset, 5+yOffset, 20, 20);
+ ctx.arc(15+xOffset, 15+yOffset, 8, 0, Math.PI*2, false);
+ if (test.fillType) {
+ ctx.fill(test.fillType);
+ } else {
+ ctx.stroke();
+ }
+
+ for (let pt of pts) {
+ let [x, y] = pt;
+ x += xOffset;
+ y += yOffset;
+ // naively apply transform when querying because the points queried
+ // ignore the CTM.
+ if (test.testFn(ctx, x, y)) {
+ drawPoint(ctx, x, y, IN);
+ } else {
+ drawPoint(ctx, x, y, OUT);
+ }
+ }
+ }
+ }
+
+ document.getElementById('api8').src = skcanvas.toDataURL();
+ skcanvas.dispose();
+ }
+
+ function VertexAPI1(CanvasKit) {
+ const surface = CanvasKit.MakeCanvasSurface('vertex1');
+ if (!surface) {
+ console.error('Could not make surface');
+ return;
+ }
+ const canvas = surface.getCanvas();
+ let paint = new CanvasKit.Paint();
+
+ // See https://fiddle.skia.org/c/f48b22eaad1bb7adcc3faaa321754af6
+ // for original c++ version.
+ let points = [0, 0, 250, 0, 100, 100, 0, 250];
+ let colors = [CanvasKit.RED, CanvasKit.BLUE,
+ CanvasKit.YELLOW, CanvasKit.CYAN];
+ let vertices = CanvasKit.MakeVertices(CanvasKit.VertexMode.TriangleFan,
+ points, null, colors,
+ false /*isVolatile*/);
+
+ canvas.drawVertices(vertices, CanvasKit.BlendMode.Dst, paint);
+
+ vertices.delete();
+
+ // See https://fiddle.skia.org/c/e8bdae9bea3227758989028424fcac3d
+ // for original c++ version.
+ points = [300, 300, 50, 300, 200, 200, 300, 50 ];
+ let texs = [ 0, 0, 0, 250, 250, 250, 250, 0 ];
+ vertices = CanvasKit.MakeVertices(CanvasKit.VertexMode.TriangleFan,
+ points, texs, colors);
+
+ let shader = CanvasKit.Shader.MakeLinearGradient([0, 0], [250, 0],
+ colors, null, CanvasKit.TileMode.Clamp);
+ paint.setShader(shader);
+
+ canvas.drawVertices(vertices, CanvasKit.BlendMode.Darken, paint);
+ surface.flush();
+
+ shader.delete();
+ paint.delete();
+ surface.delete();
+ }
+
+ function GradiantAPI1(CanvasKit) {
+ const surface = CanvasKit.MakeSWCanvasSurface('gradient1');
+ if (!surface) {
+ console.error('Could not make surface');
+ return;
+ }
+ const canvas = surface.getCanvas();
+ let paint = new CanvasKit.Paint();
+
+ // See https://fiddle.skia.org/c/f48b22eaad1bb7adcc3faaa321754af6
+ // for original c++ version.
+ let colors = [CanvasKit.BLUE, CanvasKit.YELLOW, CanvasKit.RED];
+ let pos = [0, .7, 1.0];
+ let transform = [2, 0, 0,
+ 0, 2, 0,
+ 0, 0, 1];
+ let shader = CanvasKit.Shader.MakeRadialGradient([150, 150], 130, colors,
+ pos, CanvasKit.TileMode.Mirror, transform);
+
+ paint.setShader(shader);
+ const textFont = new CanvasKit.Font(null, 75);
+ const textBlob = CanvasKit.TextBlob.MakeFromText('Radial', textFont);
+
+ canvas.drawTextBlob(textBlob, 10, 200, paint);
+ paint.delete();
+ textFont.delete();
+ textBlob.delete();
+ surface.flush();
+ }
+
+ function TextOnPathAPI1(CanvasKit) {
+ const surface = CanvasKit.MakeSWCanvasSurface('textonpath');
+ if (!surface) {
+ console.error('Could not make surface');
+ return;
+ }
+ const canvas = surface.getCanvas();
+ const paint = new CanvasKit.Paint();
+ paint.setStyle(CanvasKit.PaintStyle.Stroke);
+ paint.setAntiAlias(true);
+
+ const font = new CanvasKit.Font(null, 24);
+ const fontPaint = new CanvasKit.Paint();
+ fontPaint.setStyle(CanvasKit.PaintStyle.Fill);
+ fontPaint.setAntiAlias(true);
+
+ const arc = new CanvasKit.Path();
+ arc.arcToOval(CanvasKit.LTRBRect(20, 40, 280, 300), -160, 140, true);
+ arc.lineTo(210, 140);
+ arc.arcToOval(CanvasKit.LTRBRect(20, 0, 280, 260), 160, -140, true);
+
+ const str = 'This téxt should follow the curve across contours...';
+ const textBlob = CanvasKit.TextBlob.MakeOnPath(str, arc, font);
+
+ canvas.drawPath(arc, paint);
+ canvas.drawTextBlob(textBlob, 0, 0, fontPaint);
+
+ surface.flush();
+
+ textBlob.delete();
+ arc.delete();
+ paint.delete();
+ font.delete();
+ fontPaint.delete();
+ }
+
+ function DrawGlyphsAPI1(CanvasKit) {
+ const surface = CanvasKit.MakeSWCanvasSurface('drawGlyphs');
+ if (!surface) {
+ console.error('Could not make surface');
+ return;
+ }
+ const canvas = surface.getCanvas();
+ const paint = new CanvasKit.Paint();
+ const font = new CanvasKit.Font(null, 16);
+ paint.setAntiAlias(true);
+
+ let glyphs = [];
+ let positions = [];
+ for (let i = 0; i < 256; ++i) {
+ glyphs.push(i);
+ positions.push((i % 16) * 16);
+ positions.push(Math.round(i/16) * 16);
+ }
+ canvas.drawGlyphs(glyphs, positions, 16, 20, font, paint);
+
+ surface.flush();
+
+ paint.delete();
+ font.delete();
+ }
+
+ function SurfaceAPI1(CanvasKit) {
+ const surface = CanvasKit.MakeCanvasSurface('surfaces');
+ if (!surface) {
+ console.error('Could not make surface');
+ return;
+ }
+
+ // create a subsurface as a temporary workspace.
+ const subSurface = surface.makeSurface({
+ width: 50,
+ height: 50,
+ alphaType: CanvasKit.AlphaType.Premul,
+ colorType: CanvasKit.ColorType.RGBA_8888,
+ colorSpace: CanvasKit.ColorSpace.SRGB,
+ });
+
+ if (!subSurface) {
+ console.error('Could not make subsurface');
+ return;
+ }
+
+ // draw a small "scene"
+ const paint = new CanvasKit.Paint();
+ paint.setColor(CanvasKit.Color(139, 228, 135, 0.95)); // greenish
+ paint.setStyle(CanvasKit.PaintStyle.Fill);
+ paint.setAntiAlias(true);
+
+ const subCanvas = subSurface.getCanvas();
+ subCanvas.clear(CanvasKit.BLACK);
+ subCanvas.drawRect(CanvasKit.LTRBRect(5, 15, 45, 40), paint);
+
+ paint.setColor(CanvasKit.Color(214, 93, 244)); // purplish
+ for (let i = 0; i < 10; i++) {
+ const x = Math.random() * 50;
+ const y = Math.random() * 50;
+
+ subCanvas.drawOval(CanvasKit.XYWHRect(x, y, 6, 6), paint);
+ }
+
+ // Snap it off as an Image - this image will be in the form the
+ // parent surface prefers (e.g. Texture for GPU / Raster for CPU).
+ const img = subSurface.makeImageSnapshot();
+
+ // clean up the temporary surface (which also cleans up subCanvas)
+ subSurface.delete();
+ paint.delete();
+
+ // Make it repeat a bunch with a shader
+ const pattern = img.makeShaderCubic(CanvasKit.TileMode.Repeat, CanvasKit.TileMode.Mirror,
+ 1/3, 1/3);
+ const patternPaint = new CanvasKit.Paint();
+ patternPaint.setShader(pattern);
+
+ let i = 0;
+
+ function drawFrame(canvas) {
+ i++;
+ canvas.clear(CanvasKit.WHITE);
+
+ canvas.drawOval(CanvasKit.LTRBRect(i % 60, i % 60, 300 - (i% 60), 300 - (i % 60)), patternPaint);
+ surface.requestAnimationFrame(drawFrame);
+ }
+ surface.requestAnimationFrame(drawFrame);
+ }
+
+ function AtlasAPI1(CanvasKit, imgData) {
+ if (!CanvasKit || !imgData) {
+ return;
+ }
+ const surface = CanvasKit.MakeCanvasSurface('atlas');
+ if (!surface) {
+ console.error('Could not make surface');
+ return;
+ }
+ const img = CanvasKit.MakeImageFromEncoded(imgData);
+
+ const paint = new CanvasKit.Paint();
+ paint.setColor(CanvasKit.Color(0, 0, 0, 0.8));
+
+ // Allocate space for 2 rectangles.
+ const srcs = CanvasKit.Malloc(Float32Array, 8);
+ srcs.toTypedArray().set([
+ 0, 0, 250, 250, // LTRB
+ 250, 0, 500, 250
+ ]);
+
+ // Allocate space for 2 RSXForms
+ const dsts = CanvasKit.Malloc(Float32Array, 8);
+ dsts.toTypedArray().set([
+ .5, 0, 0, 0, // scos, ssin, tx, ty
+ 0, .8, 200, 100
+ ]);
+
+ // Allocate space for 4 colors.
+ const colors = new CanvasKit.Malloc(Uint32Array, 2);
+ colors.toTypedArray().set([
+ CanvasKit.ColorAsInt( 85, 170, 10, 128), // light green
+ CanvasKit.ColorAsInt( 51, 51, 191, 128), // light blue
+ ]);
+
+ let i = 0;
+
+ function drawFrame(canvas) {
+ canvas.clear(CanvasKit.WHITE);
+ i++;
+ let scale = 0.5 + Math.sin(i/40)/4;
+
+ // update the coordinates of existing sprites - note that this
+ // does not require a full re-copy of the full array; they are
+ // updated in-place.
+ dsts.toTypedArray().set([0.5, 0, (2*i)%200, (5*Math.round(i/200)) % 200], 0);
+ dsts.toTypedArray().set([scale*Math.sin(i/20), scale*Math.cos(i/20), 200, 100], 4);
+
+ canvas.drawAtlas(img, srcs, dsts, paint, CanvasKit.BlendMode.Plus, colors,
+ {filter: CanvasKit.FilterMode.Nearest});
+ surface.requestAnimationFrame(drawFrame);
+ }
+ surface.requestAnimationFrame(drawFrame);
+
+ }
+
+ async function DecodeAPI(CanvasKit, imgData) {
+ if (!CanvasKit || !imgData) {
+ return;
+ }
+ const surface = CanvasKit.MakeCanvasSurface('decode');
+ if (!surface) {
+ console.error('Could not make surface');
+ return;
+ }
+ const blob = new Blob([ imgData ]);
+ // ImageBitmap is not supported in Safari
+ const imageBitmap = await createImageBitmap(blob);
+ const img = await CanvasKit.MakeImageFromCanvasImageSource(imageBitmap);
+
+ surface.drawOnce((canvas) => {
+ canvas.drawImage(img, 0, 0, null);
+ });
+ }
+</script>
diff --git a/third_party/skia/modules/canvaskit/npm_build/extra.html b/third_party/skia/modules/canvaskit/npm_build/extra.html
new file mode 100644
index 0000000..862ef0a
--- /dev/null
+++ b/third_party/skia/modules/canvaskit/npm_build/extra.html
@@ -0,0 +1,737 @@
+<!DOCTYPE html>
+<title>CanvasKit Extra features (Skia via Web Assembly)</title>
+<meta charset="utf-8" />
+<meta http-equiv="X-UA-Compatible" content="IE=edge">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+
+<style>
+ canvas {
+ border: 1px dashed #AAA;
+ }
+ #sk_legos,#sk_drinks,#sk_party,#sk_onboarding, #sk_animated_gif {
+ width: 300px;
+ height: 300px;
+ }
+
+</style>
+
+<h2> Skottie </h2>
+<canvas id=sk_legos width=300 height=300></canvas>
+<canvas id=sk_drinks width=500 height=500></canvas>
+<canvas id=sk_party width=500 height=500></canvas>
+<canvas id=sk_onboarding width=500 height=500></canvas>
+<canvas id=sk_animated_gif width=500 height=500
+ title='This is an animated gif being animated in Skottie'></canvas>
+
+<h2> RT Shader </h2>
+<canvas id=rtshader width=300 height=300></canvas>
+<canvas id=rtshader2 width=300 height=300></canvas>
+
+<h2> Particles </h2>
+<canvas id=particles width=500 height=500></canvas>
+
+<h2> Paragraph </h2>
+<canvas id=para1 width=600 height=600></canvas>
+<canvas id=para2 width=600 height=600 tabindex='-1'></canvas>
+
+<h2> CanvasKit can serialize/deserialize .skp files</h2>
+<canvas id=skp width=500 height=500></canvas>
+
+<h2> 3D perspective transformations </h2>
+<canvas id=glyphgame width=500 height=500></canvas>
+
+<h2> Support for extended color spaces </h2>
+<a href="chrome://flags/#force-color-profile">Force P3 profile</a>
+<canvas id=colorsupport width=300 height=300></canvas>
+
+<script type="text/javascript" src="/build/canvaskit.js"></script>
+
+<script type="text/javascript" src="textapi_utils.js"></script>
+
+<script type="text/javascript" charset="utf-8">
+
+ var CanvasKit = null;
+ var cdn = 'https://storage.googleapis.com/skia-cdn/misc/';
+
+ const ckLoaded = CanvasKitInit({locateFile: (file) => '/build/'+file});
+
+ const loadLegoJSON = fetch(cdn + 'lego_loader.json').then((response) => response.text());
+ const loadDrinksJSON = fetch(cdn + 'drinks.json').then((response) => response.text());
+ const loadConfettiJSON = fetch(cdn + 'confetti.json').then((response) => response.text());
+ const loadOnboardingJSON = fetch(cdn + 'onboarding.json').then((response) => response.text());
+ const loadMultiframeJSON = fetch(cdn + 'skottie_sample_multiframe.json').then((response) => response.text());
+
+ const loadFlightGif = fetch(cdn + 'flightAnim.gif').then((response) => response.arrayBuffer());
+ const loadFont = fetch(cdn + 'Roboto-Regular.ttf').then((response) => response.arrayBuffer());
+ const loadDog = fetch(cdn + 'dog.jpg').then((response) => response.arrayBuffer());
+ const loadMandrill = fetch(cdn + 'mandrill_256.png').then((response) => response.arrayBuffer());
+ const loadBrickTex = fetch(cdn + 'brickwork-texture.jpg').then((response) => response.arrayBuffer());
+ const loadBrickBump = fetch(cdn + 'brickwork_normal-map.jpg').then((response) => response.arrayBuffer());
+
+ const curves = {
+ "MaxCount": 1000,
+ "Drawable": {
+ "Type": "SkCircleDrawable",
+ "Radius": 2
+ },
+ "Code": [`
+ void effectSpawn(inout Effect effect) {
+ effect.rate = 200;
+ effect.color = float4(1, 0, 0, 1);
+ }
+ void spawn(inout Particle p) {
+ p.lifetime = 3 + rand(p.seed);
+ p.vel.y = -50;
+ }
+
+ void update(inout Particle p) {
+ float w = mix(15, 3, p.age);
+ p.pos.x = sin(radians(p.age * 320)) * mix(25, 10, p.age) + mix(-w, w, rand(p.seed));
+ if (rand(p.seed) < 0.5) { p.pos.x = -p.pos.x; }
+
+ p.color.g = (mix(75, 220, p.age) + mix(-30, 30, rand(p.seed))) / 255;
+ }
+ `
+ ],
+ "Bindings": []
+ };
+
+ const spiralSkSL = `
+ uniform float rad_scale;
+ uniform float2 in_center;
+ uniform float4 in_colors0;
+ uniform float4 in_colors1;
+
+ half4 main(float2 p) {
+ float2 pp = p - in_center;
+ float radius = sqrt(dot(pp, pp));
+ radius = sqrt(radius);
+ float angle = atan(pp.y / pp.x);
+ float t = (angle + 3.1415926/2) / (3.1415926);
+ t += radius * rad_scale;
+ t = fract(t);
+ return half4(mix(in_colors0, in_colors1, t));
+ }`;
+
+ // Examples which only require canvaskit
+ ckLoaded.then((CK) => {
+ CanvasKit = CK;
+ ParticlesAPI1(CanvasKit);
+ RTShaderAPI1(CanvasKit);
+ ColorSupport(CanvasKit);
+ SkpExample(CanvasKit);
+ });
+
+ // Examples requiring external resources.
+ // Set bounds to fix the 4:3 resolution of the legos
+ Promise.all([ckLoaded, loadLegoJSON]).then(([ck, jsonstr]) => {
+ SkottieExample(ck, 'sk_legos', jsonstr, [-50, 0, 350, 300]);
+ });
+ // Re-size to fit
+ let fullBounds = [0, 0, 500, 500];
+ Promise.all([ckLoaded, loadDrinksJSON]).then(([ck, jsonstr]) => {
+ SkottieExample(ck, 'sk_drinks', jsonstr, fullBounds);
+ });
+ Promise.all([ckLoaded, loadConfettiJSON]).then(([ck, jsonstr]) => {
+ SkottieExample(ck, 'sk_party', jsonstr, fullBounds);
+ });
+ Promise.all([ckLoaded, loadOnboardingJSON]).then(([ck, jsonstr]) => {
+ SkottieExample(ck, 'sk_onboarding', jsonstr, fullBounds);
+ });
+ Promise.all([ckLoaded, loadMultiframeJSON, loadFlightGif]).then(([ck, jsonstr, gif]) => {
+ SkottieExample(ck, 'sk_animated_gif', jsonstr, fullBounds, {'image_0.png': gif});
+ });
+
+ Promise.all([ckLoaded, loadFont]).then((results) => {
+ ParagraphAPI1(...results);
+ ParagraphAPI2(...results);
+ GlyphGame(...results)
+ });
+
+ const rectLeft = 0;
+ const rectTop = 1;
+ const rectRight = 2;
+ const rectBottom = 3;
+
+ function SkottieExample(CanvasKit, id, jsonStr, bounds, assets) {
+ if (!CanvasKit || !jsonStr) {
+ return;
+ }
+ const animation = CanvasKit.MakeManagedAnimation(jsonStr, assets);
+ const duration = animation.duration() * 1000;
+ const size = animation.size();
+ let c = document.getElementById(id);
+ bounds = bounds || CanvasKit.LTRBRect(0, 0, size.w, size.h);
+
+ // Basic managed animation test.
+ if (id === 'sk_drinks') {
+ animation.setColor('BACKGROUND_FILL', CanvasKit.Color(0, 163, 199, 1.0));
+ }
+
+ const surface = CanvasKit.MakeCanvasSurface(id);
+ if (!surface) {
+ console.error('Could not make surface');
+ return;
+ }
+
+ let firstFrame = Date.now();
+
+ function drawFrame(canvas) {
+ let seek = ((Date.now() - firstFrame) / duration) % 1.0;
+ let damage = animation.seek(seek);
+
+ if (damage[rectRight] > damage[rectLeft] && damage[rectBottom] > damage[rectTop]) {
+ canvas.clear(CanvasKit.WHITE);
+ animation.render(canvas, bounds);
+ }
+ surface.requestAnimationFrame(drawFrame);
+ }
+ surface.requestAnimationFrame(drawFrame);
+
+ return surface;
+ }
+
+ function ParticlesAPI1(CanvasKit) {
+ const surface = CanvasKit.MakeCanvasSurface('particles');
+ if (!surface) {
+ console.error('Could not make surface');
+ return;
+ }
+ const canvas = surface.getCanvas();
+ canvas.translate(250, 450);
+
+ const particles = CanvasKit.MakeParticles(JSON.stringify(curves));
+ particles.start(Date.now() / 1000.0, true);
+
+ function drawFrame(canvas) {
+ canvas.clear(CanvasKit.BLACK);
+
+ particles.update(Date.now() / 1000.0);
+ particles.draw(canvas);
+ surface.requestAnimationFrame(drawFrame);
+ }
+ surface.requestAnimationFrame(drawFrame);
+ }
+
+ function ParagraphAPI1(CanvasKit, fontData) {
+ if (!CanvasKit || !fontData) {
+ return;
+ }
+
+ const surface = CanvasKit.MakeCanvasSurface('para1');
+ if (!surface) {
+ console.error('Could not make surface');
+ return;
+ }
+
+ const canvas = surface.getCanvas();
+ const fontMgr = CanvasKit.FontMgr.FromData([fontData]);
+
+ const paraStyle = new CanvasKit.ParagraphStyle({
+ textStyle: {
+ color: CanvasKit.BLACK,
+ fontFamilies: ['Roboto'],
+ fontSize: 50,
+ },
+ textAlign: CanvasKit.TextAlign.Left,
+ maxLines: 5,
+ });
+
+ const builder = CanvasKit.ParagraphBuilder.Make(paraStyle, fontMgr);
+ builder.addText('The quick brown fox ate a hamburgerfons and got sick.');
+ const paragraph = builder.build();
+
+ let wrapTo = 0;
+
+ let X = 100;
+ let Y = 100;
+
+ const fontPaint = new CanvasKit.Paint();
+ fontPaint.setStyle(CanvasKit.PaintStyle.Fill);
+ fontPaint.setAntiAlias(true);
+
+ function drawFrame(canvas) {
+ canvas.clear(CanvasKit.WHITE);
+ wrapTo = 350 + 150 * Math.sin(Date.now() / 2000);
+ paragraph.layout(wrapTo);
+ canvas.drawParagraph(paragraph, 0, 0);
+
+ canvas.drawLine(wrapTo, 0, wrapTo, 400, fontPaint);
+
+ surface.requestAnimationFrame(drawFrame);
+ }
+ surface.requestAnimationFrame(drawFrame);
+
+ let interact = (e) => {
+ X = e.offsetX*2; // multiply by 2 because the canvas is 300 css pixels wide,
+ Y = e.offsetY*2; // but the canvas itself is 600px wide
+ };
+
+ document.getElementById('para1').addEventListener('pointermove', interact);
+ return surface;
+ }
+
+ function ParagraphAPI2(CanvasKit, fontData) {
+ if (!CanvasKit || !fontData) {
+ return;
+ }
+
+ const surface = CanvasKit.MakeCanvasSurface('para2');
+ if (!surface) {
+ console.error('Could not make surface');
+ return;
+ }
+
+ const mouse = MakeMouse();
+ const cursor = MakeCursor(CanvasKit);
+ const canvas = surface.getCanvas();
+
+ const text0 = "In a hole in the ground there lived a hobbit. Not a nasty, dirty, " +
+ "wet hole full of worms and oozy smells. This was a hobbit-hole and " +
+ "that means good food, a warm hearth, and all the comforts of home.";
+ const LOC_X = 20,
+ LOC_Y = 20;
+
+ const bgPaint = new CanvasKit.Paint();
+ bgPaint.setColor([0.965, 0.965, 0.965, 1]);
+
+ const editor = MakeEditor(text0, {typeface:null, size:24}, cursor, 400);
+
+ editor.applyStyleToRange({size:100}, 0, 1);
+ editor.applyStyleToRange({italic:true}, 38, 38+6);
+ editor.applyStyleToRange({color:[1,0,0,1]}, 5, 5+4);
+
+ editor.setXY(LOC_X, LOC_Y);
+
+ function drawFrame(canvas) {
+ const lines = editor.getLines();
+
+ canvas.clear(CanvasKit.WHITE);
+
+ if (mouse.isActive()) {
+ const pos = mouse.getPos(-LOC_X, -LOC_Y);
+ const a = lines_pos_to_index(lines, pos[0], pos[1]);
+ const b = lines_pos_to_index(lines, pos[2], pos[3]);
+ if (a == b) {
+ editor.setIndex(a);
+ } else {
+ editor.setIndices(a, b);
+ }
+ }
+
+ canvas.drawRect(editor.bounds(), bgPaint);
+ editor.draw(canvas);
+
+ surface.requestAnimationFrame(drawFrame);
+ }
+ surface.requestAnimationFrame(drawFrame);
+
+ function interact(e) {
+ const type = e.type;
+ if (type === 'pointerup') {
+ mouse.setUp(e.offsetX, e.offsetY);
+ } else if (type === 'pointermove') {
+ mouse.setMove(e.offsetX, e.offsetY);
+ } else if (type === 'pointerdown') {
+ mouse.setDown(e.offsetX, e.offsetY);
+ }
+ };
+
+ function keyhandler(e) {
+ switch (e.key) {
+ case 'ArrowLeft': editor.moveDX(-1); return;
+ case 'ArrowRight': editor.moveDX(1); return;
+ case 'ArrowUp':
+ e.preventDefault();
+ editor.moveDY(-1);
+ return;
+ case 'ArrowDown':
+ e.preventDefault();
+ editor.moveDY(1);
+ return;
+ case 'Backspace':
+ editor.deleteSelection();
+ return;
+ case 'Shift':
+ return;
+ }
+ if (e.ctrlKey) {
+ switch (e.key) {
+ case 'r': editor.applyStyleToSelection({color:[1,0,0,1]}); return;
+ case 'g': editor.applyStyleToSelection({color:[0,0.6,0,1]}); return;
+ case 'u': editor.applyStyleToSelection({color:[0,0,1,1]}); return;
+ case 'k': editor.applyStyleToSelection({color:[0,0,0,1]}); return;
+
+ case 'i': editor.applyStyleToSelection({italic:'toggle'}); return;
+ case 'b': editor.applyStyleToSelection({bold:'toggle'}); return;
+ case 'l': editor.applyStyleToSelection({underline:'toggle'}); return;
+
+ case ']': editor.applyStyleToSelection({size_add:1}); return;
+ case '[': editor.applyStyleToSelection({size_add:-1}); return;
+ }
+ }
+ if (!e.ctrlKey && !e.metaKey) {
+ e.preventDefault(); // at least needed for 'space'
+ editor.insert(e.key);
+ }
+ }
+
+ document.getElementById('para2').addEventListener('pointermove', interact);
+ document.getElementById('para2').addEventListener('pointerdown', interact);
+ document.getElementById('para2').addEventListener('pointerup', interact);
+ document.getElementById('para2').addEventListener('keydown', keyhandler);
+ return surface;
+ }
+
+ function RTShaderAPI1(CanvasKit) {
+ if (!CanvasKit) {
+ return;
+ }
+
+ const surface = CanvasKit.MakeCanvasSurface('rtshader');
+ if (!surface) {
+ console.error('Could not make surface');
+ return;
+ }
+
+ const canvas = surface.getCanvas();
+
+ const effect = CanvasKit.RuntimeEffect.Make(spiralSkSL);
+ const shader = effect.makeShader([
+ 0.5,
+ 150, 150,
+ 0, 1, 0, 1,
+ 1, 0, 0, 1]);
+ const paint = new CanvasKit.Paint();
+ paint.setShader(shader);
+ canvas.drawRect(CanvasKit.LTRBRect(0, 0, 300, 300), paint);
+
+ surface.flush();
+ shader.delete();
+ paint.delete();
+ effect.delete();
+ }
+
+ // RTShader2 demo
+ Promise.all([ckLoaded, loadDog, loadMandrill]).then((values) => {
+ const [CanvasKit, dogData, mandrillData] = values;
+ const dogImg = CanvasKit.MakeImageFromEncoded(dogData);
+ if (!dogImg) {
+ console.error('could not decode dog');
+ return;
+ }
+ const mandrillImg = CanvasKit.MakeImageFromEncoded(mandrillData);
+ if (!mandrillImg) {
+ console.error('could not decode mandrill');
+ return;
+ }
+ const quadrantSize = 150;
+
+ const dogShader = dogImg.makeShaderCubic(
+ CanvasKit.TileMode.Clamp, CanvasKit.TileMode.Clamp,
+ 1/3, 1/3,
+ CanvasKit.Matrix.scaled(quadrantSize/dogImg.width(),
+ quadrantSize/dogImg.height()));
+ const mandrillShader = mandrillImg.makeShaderCubic(
+ CanvasKit.TileMode.Clamp, CanvasKit.TileMode.Clamp,
+ 1/3, 1/3,
+ CanvasKit.Matrix.scaled(
+ quadrantSize/mandrillImg.width(),
+ quadrantSize/mandrillImg.height()));
+
+ const surface = CanvasKit.MakeCanvasSurface('rtshader2');
+ if (!surface) {
+ console.error('Could not make surface');
+ return;
+ }
+
+ const prog = `
+ uniform shader before_map;
+ uniform shader after_map;
+ uniform shader threshold_map;
+
+ uniform float cutoff;
+ uniform float slope;
+
+ float smooth_cutoff(float x) {
+ x = x * slope + (0.5 - slope * cutoff);
+ return clamp(x, 0, 1);
+ }
+
+ half4 main(float2 xy) {
+ half4 before = before_map.eval(xy);
+ half4 after = after_map.eval(xy);
+
+ float m = smooth_cutoff(threshold_map.eval(xy).r);
+ return mix(before, after, half(m));
+ }`;
+
+ const canvas = surface.getCanvas();
+
+ const thresholdEffect = CanvasKit.RuntimeEffect.Make(prog);
+ const spiralEffect = CanvasKit.RuntimeEffect.Make(spiralSkSL);
+
+ const draw = (x, y, shader) => {
+ const paint = new CanvasKit.Paint();
+ paint.setShader(shader);
+ canvas.save();
+ canvas.translate(x, y);
+ canvas.drawRect(CanvasKit.LTRBRect(0, 0, quadrantSize, quadrantSize), paint);
+ canvas.restore();
+ paint.delete();
+ };
+
+ const offscreenSurface = CanvasKit.MakeSurface(quadrantSize, quadrantSize);
+ const getBlurrySpiralShader = (rad_scale) => {
+ const oCanvas = offscreenSurface.getCanvas();
+
+ const spiralShader = spiralEffect.makeShader([
+ rad_scale,
+ quadrantSize/2, quadrantSize/2,
+ 1, 1, 1, 1,
+ 0, 0, 0, 1]);
+
+ const blur = CanvasKit.ImageFilter.MakeBlur(0.1, 0.1, CanvasKit.TileMode.Clamp, null);
+
+ const paint = new CanvasKit.Paint();
+ paint.setShader(spiralShader);
+ paint.setImageFilter(blur);
+ oCanvas.drawRect(CanvasKit.LTRBRect(0, 0, quadrantSize, quadrantSize), paint);
+
+ paint.delete();
+ blur.delete();
+ spiralShader.delete();
+ return offscreenSurface.makeImageSnapshot()
+ .makeShaderCubic(CanvasKit.TileMode.Clamp, CanvasKit.TileMode.Clamp,
+ 1/3, 1/3);
+
+ };
+
+ const drawFrame = () => {
+ surface.requestAnimationFrame(drawFrame);
+ const thresholdShader = getBlurrySpiralShader(Math.sin(Date.now() / 5000) / 2);
+
+ const blendShader = thresholdEffect.makeShaderWithChildren(
+ [0.5, 10],
+ [dogShader, mandrillShader, thresholdShader]);
+ draw(0, 0, blendShader);
+ draw(quadrantSize, 0, thresholdShader);
+ draw(0, quadrantSize, dogShader);
+ draw(quadrantSize, quadrantSize, mandrillShader);
+
+ blendShader.delete();
+ };
+
+ surface.requestAnimationFrame(drawFrame);
+ });
+
+ function SkpExample(CanvasKit) {
+ if (!CanvasKit) {
+ return;
+ }
+
+ const surface = CanvasKit.MakeSWCanvasSurface('skp');
+ if (!surface) {
+ console.error('Could not make surface');
+ return;
+ }
+
+ const paint = new CanvasKit.Paint();
+ paint.setColor(CanvasKit.RED);
+
+ const textPaint = new CanvasKit.Paint();
+ const textFont = new CanvasKit.Font(null, 20);
+ const pr = new CanvasKit.PictureRecorder();
+ const skpCanvas = pr.beginRecording(CanvasKit.LTRBRect(0, 0, 200, 200));
+ skpCanvas.drawRect(CanvasKit.LTRBRect(10, 10, 50, 50), paint);
+ skpCanvas.drawText('If you see this, CanvasKit loaded!!', 5, 100, textPaint, textFont);
+
+ const pic = pr.finishRecordingAsPicture();
+ const skpData = pic.serialize();
+
+ paint.delete();
+ pr.delete();
+
+ const deserialized = CanvasKit.MakePicture(skpData);
+
+ function drawFrame(canvas) {
+ if (deserialized) {
+ canvas.drawPicture(deserialized);
+ } else {
+ canvas.drawText('SKP did not deserialize', 5, 100, textPaint, textFont);
+ }
+ }
+ surface.drawOnce(drawFrame);
+ textPaint.delete();
+ textFont.delete();
+ }
+
+ // Shows a hidden message by rotating all the characters in a kind of way that makes you
+ // search with your mouse.
+ function GlyphGame(canvas, robotoData) {
+ const surface = CanvasKit.MakeCanvasSurface('glyphgame');
+ if (!surface) {
+ console.error('Could not make surface');
+ return;
+ }
+ const sizeX = document.getElementById('glyphgame').width;
+ const sizeY = document.getElementById('glyphgame').height;
+ const halfDim = Math.min(sizeX, sizeY) / 2;
+ const margin = 50;
+ const marginTop = 25;
+ let rotX = 0; // expected to be updated in interact()
+ let rotY = 0;
+ let pointer = [500, 450];
+ const radPerPixel = 0.005; // radians of subject rotation per pixel distance moved by mouse.
+
+ const camAngle = Math.PI / 12;
+ const cam = {
+ 'eye' : [0, 0, 1 / Math.tan(camAngle/2) - 1],
+ 'coa' : [0, 0, 0],
+ 'up' : [0, 1, 0],
+ 'near' : 0.02,
+ 'far' : 4,
+ 'angle': camAngle,
+ };
+
+ let lastImage = null;
+
+ const fontMgr = CanvasKit.FontMgr.FromData([robotoData]);
+
+ const paraStyle = new CanvasKit.ParagraphStyle({
+ textStyle: {
+ color: CanvasKit.Color(105, 56, 16), // brown
+ fontFamilies: ['Roboto'],
+ fontSize: 28,
+ },
+ textAlign: CanvasKit.TextAlign.Left,
+ });
+ const hStyle = CanvasKit.RectHeightStyle.Max;
+ const wStyle = CanvasKit.RectWidthStyle.Tight;
+
+ const quotes = [
+ '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.',
+ // Charles Stross - Accelerando
+ '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?',
+ // Aleksandr Solzhenitsyn - The Gulag Archipelago
+ '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.',
+ // G. K. Chesterton - What's Wrong With The World?
+ ];
+
+ // pick one at random
+ const text = quotes[Math.floor(Math.random()*3)];
+ const builder = CanvasKit.ParagraphBuilder.Make(paraStyle, fontMgr);
+ builder.addText(text);
+ const paragraph = builder.build();
+ const font = new CanvasKit.Font(null, 18);
+ // wrap the text to a given width.
+ paragraph.layout(sizeX - margin*2);
+
+ // to rotate every glyph individually, calculate the bounding rect of each one,
+ // construct an array of rects and paragraphs that would draw each glyph individually.
+ const letters = Array(text.length);
+ for (let i = 0; i < text.length; i++) {
+ const r = paragraph.getRectsForRange(i, i+1, hStyle, wStyle)[0];
+ // The character is drawn with drawParagraph so we can pass the paraStyle,
+ // and have our character be the exact size and shape the paragraph expected
+ // when it wrapped the text. canvas.drawText wouldn't cut it.
+ const tmpbuilder = CanvasKit.ParagraphBuilder.Make(paraStyle, fontMgr);
+ tmpbuilder.addText(text[i]);
+ const para = tmpbuilder.build();
+ para.layout(100);
+ letters[i] = {
+ 'r': r,
+ 'para': para,
+ };
+ }
+
+ function drawFrame(canvas) {
+ // persistence of vision effect is done by drawing the past frame as an image,
+ // then covering with semitransparent background color.
+ if (lastImage) {
+ canvas.drawImage(lastImage, 0, 0, null);
+ canvas.drawColor(CanvasKit.Color(171, 244, 255, 0.1)); // sky blue, almost transparent
+ } else {
+ canvas.clear(CanvasKit.Color(171, 244, 255)); // sky blue, opaque
+ }
+ canvas.save();
+ // Set up 3D view enviroment
+ canvas.concat(CanvasKit.M44.setupCamera(
+ CanvasKit.LTRBRect(0, 0, sizeX, sizeY), halfDim, cam));
+
+ // Rotate the whole paragraph as a unit.
+ const paraRotPoint = [halfDim, halfDim, 1];
+ canvas.concat(CanvasKit.M44.multiply(
+ CanvasKit.M44.translated(paraRotPoint),
+ CanvasKit.M44.rotated([0,1,0], rotX),
+ CanvasKit.M44.rotated([1,0,0], rotY * 0.2),
+ CanvasKit.M44.translated(CanvasKit.Vector.mulScalar(paraRotPoint, -1)),
+ ));
+
+ // Rotate every glyph in the paragraph individually.
+ let i = 0;
+ for (const letter of letters) {
+ canvas.save();
+ let r = letter['r'];
+ // rotate about the center of the glyph's rect.
+ rotationPoint = [
+ margin + r[rectLeft] + (r[rectRight] - r[rectLeft]) / 2,
+ marginTop + r[rectTop] + (r[rectBottom] - r[rectTop]) / 2,
+ 0
+ ];
+ distanceFromPointer = CanvasKit.Vector.dist(pointer, rotationPoint.slice(0, 2));
+ // Rotate more around the Y-axis depending on the glyph's distance from the pointer.
+ canvas.concat(CanvasKit.M44.multiply(
+ CanvasKit.M44.translated(rotationPoint),
+ // note that I'm rotating around the x axis first, undoing some of the rotation done to the whole
+ // paragraph above, where x came second. If I rotated y first, a lot of letters would end up
+ // upside down, which is a bit too hard to unscramble.
+ CanvasKit.M44.rotated([1,0,0], rotY * -0.6),
+ CanvasKit.M44.rotated([0,1,0], distanceFromPointer * -0.035),
+ CanvasKit.M44.translated(CanvasKit.Vector.mulScalar(rotationPoint, -1)),
+ ));
+ canvas.drawParagraph(letter['para'], margin + r[rectLeft], marginTop + r[rectTop]);
+ i++;
+ canvas.restore();
+ }
+ canvas.restore();
+ lastImage = surface.makeImageSnapshot();
+ }
+
+ function interact(e) {
+ pointer = [e.offsetX, e.offsetY]
+ rotX = (pointer[0] - halfDim) * radPerPixel;
+ rotY = (pointer[1] - halfDim) * radPerPixel * -1;
+ surface.requestAnimationFrame(drawFrame);
+ };
+
+ document.getElementById('glyphgame').addEventListener('pointermove', interact);
+ surface.requestAnimationFrame(drawFrame);
+ }
+
+ function ColorSupport(CanvasKit) {
+ const surface = CanvasKit.MakeCanvasSurface('colorsupport', CanvasKit.ColorSpace.ADOBE_RGB);
+ if (!surface) {
+ console.error('Could not make surface');
+ return;
+ }
+ const canvas = surface.getCanvas();
+
+ // If the surface is correctly initialized with a higher bit depth color type,
+ // And chrome is compositing it into a buffer with the P3 color space,
+ // then the inner round rect should be distinct and less saturated than the full red background.
+ // Even if the monitor it is viewed on cannot accurately represent that color space.
+
+ let red = CanvasKit.Color4f(1, 0, 0, 1);
+ let paint = new CanvasKit.Paint();
+ paint.setColor(red, CanvasKit.ColorSpace.ADOBE_RGB);
+ canvas.drawPaint(paint);
+ paint.setColor(red, CanvasKit.ColorSpace.DISPLAY_P3);
+ canvas.drawRRect(CanvasKit.RRectXY([50, 50, 250, 250], 30, 30), paint);
+ paint.setColor(red, CanvasKit.ColorSpace.SRGB);
+ canvas.drawRRect(CanvasKit.RRectXY([100, 100, 200, 200], 30, 30), paint);
+
+ surface.flush();
+ surface.delete();
+ }
+</script>
diff --git a/third_party/skia/modules/canvaskit/npm_build/multicanvas.html b/third_party/skia/modules/canvaskit/npm_build/multicanvas.html
new file mode 100644
index 0000000..3460b7b
--- /dev/null
+++ b/third_party/skia/modules/canvaskit/npm_build/multicanvas.html
@@ -0,0 +1,130 @@
+<!DOCTYPE html>
+<title>CanvasKit (Skia via Web Assembly)</title>
+<meta charset="utf-8" />
+<meta http-equiv="X-UA-Compatible" content="IE=edge">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+
+<style>
+ canvas, img {
+ border: 1px dashed #AAA;
+ }
+
+</style>
+
+<canvas id=api1 width=300 height=300></canvas>
+<canvas id=api2 width=300 height=300></canvas>
+<canvas id=api3 width=300 height=300></canvas>
+
+<br>
+
+<img id="src" src="https://storage.googleapis.com/skia-cdn/misc/test.png"
+ width=40 height=40 crossorigin="anonymous">
+
+<canvas id=api4 width=300 height=300></canvas>
+<canvas id=api5 width=300 height=300></canvas>
+<canvas id=api6 width=300 height=300></canvas>
+
+<script type="text/javascript" src="/build/canvaskit.js"></script>
+<script type="text/javascript" charset="utf-8">
+ const cdn = 'https://storage.googleapis.com/skia-cdn/misc/';
+
+ const ckLoaded = CanvasKitInit({locateFile: (file) => '/build/'+file});
+ const loadTestImage = fetch(cdn + 'test.png').then((response) => response.arrayBuffer());
+ const imageEle = document.getElementById("src");
+
+ Promise.all([ckLoaded, loadTestImage, imageEle.decode()]).then((results) => {
+ ContextSharingExample(results[0]);
+ MultiCanvasExample(...results);
+ });
+
+ // This example shows how CanvasKit can automatically switch between multiple canvases
+ // with different WebGL contexts.
+ function MultiCanvasExample(CanvasKit, imgBytes) {
+ const paint = new CanvasKit.Paint();
+
+ const surfOne = CanvasKit.MakeWebGLCanvasSurface("api1");
+ const canvasOne = surfOne.getCanvas();
+ const surfTwo = CanvasKit.MakeWebGLCanvasSurface("api2");
+ const canvasTwo = surfTwo.getCanvas();
+ const surfThree = CanvasKit.MakeWebGLCanvasSurface("api3");
+ const canvasThree = surfThree.getCanvas();
+
+ function firstFrame() {
+ paint.setColor(CanvasKit.Color4f(1, 0, 0, 1)); // red
+ canvasOne.drawRect(CanvasKit.LTRBRect(0, 0, 300, 300), paint);
+ surfOne.flush();
+
+ paint.setColor(CanvasKit.Color4f(0, 1, 0, 1)); // green
+ canvasTwo.drawRect(CanvasKit.LTRBRect(0, 0, 300, 300), paint);
+ surfTwo.flush();
+
+ paint.setColor(CanvasKit.Color4f(0, 0, 1, 1)); // blue
+ canvasThree.drawRect(CanvasKit.LTRBRect(0, 0, 300, 300), paint);
+ surfThree.flush();
+
+ window.requestAnimationFrame(secondFrame);
+ }
+
+ let img;
+ function secondFrame() {
+ img = CanvasKit.MakeImageFromEncoded(imgBytes);
+
+ canvasOne.drawImageCubic(img, 10, 10, 0.3, 0.3, null);
+ surfOne.flush();
+
+ canvasTwo.drawImageCubic(img, 10, 10, 0.3, 0.3, null);
+ surfTwo.flush();
+
+ canvasThree.drawImageCubic(img, 10, 10, 0.3, 0.3, null);
+ surfThree.flush();
+
+ window.requestAnimationFrame(thirdFrame);
+ }
+
+ function thirdFrame() {
+ canvasOne.drawImageCubic(img, 100, 100, 0.3, 0.3, null);
+ surfOne.flush();
+
+ canvasTwo.drawImageCubic(img, 100, 100, 0.3, 0.3, null);
+ surfTwo.flush();
+
+ canvasThree.drawImageCubic(img, 100, 100, 0.3, 0.3, null);
+ surfThree.flush();
+ img.delete();
+ }
+
+ window.requestAnimationFrame(firstFrame);
+ }
+
+ function ContextSharingExample(CanvasKit) {
+ const img = CanvasKit.MakeLazyImageFromTextureSource(imageEle);
+
+ const surfOne = CanvasKit.MakeWebGLCanvasSurface("api4");
+ const surfTwo = CanvasKit.MakeWebGLCanvasSurface("api5");
+ const surfThree = CanvasKit.MakeWebGLCanvasSurface("api6");
+
+ let i = 0;
+ function drawFrame(canvas) {
+ canvas.drawImageCubic(img, 5+i, 5+i, 0.3, 0.3, null);
+ i += 1
+ if (i >= 3) {
+ if (i > 60) {
+ img.delete();
+ return;
+ }
+ if (i % 2) {
+ surfOne.requestAnimationFrame(drawFrame);
+ } else {
+ surfTwo.requestAnimationFrame(drawFrame);
+ }
+
+ }
+ }
+
+ surfOne.requestAnimationFrame(drawFrame);
+ surfTwo.requestAnimationFrame(drawFrame);
+ surfThree.requestAnimationFrame(drawFrame);
+ }
+
+
+</script>
\ No newline at end of file
diff --git a/third_party/skia/modules/canvaskit/npm_build/node.example.js b/third_party/skia/modules/canvaskit/npm_build/node.example.js
new file mode 100644
index 0000000..8c31882
--- /dev/null
+++ b/third_party/skia/modules/canvaskit/npm_build/node.example.js
@@ -0,0 +1,116 @@
+const CanvasKitInit = require('./bin/canvaskit.js');
+const fs = require('fs');
+const path = require('path');
+
+const assetPath = path.join(__dirname, '..', 'tests', 'assets');
+
+CanvasKitInit({
+ locateFile: (file) => __dirname + '/bin/'+file,
+}).then((CanvasKit) => {
+ let canvas = CanvasKit.MakeCanvas(300, 300);
+
+
+ let img = fs.readFileSync(path.join(assetPath, 'mandrill_512.png'));
+ img = canvas.decodeImage(img);
+
+ let fontData = fs.readFileSync(path.join(assetPath, 'Roboto-Regular.woff'));
+ canvas.loadFont(fontData, {
+ 'family': 'Roboto',
+ 'style': 'normal',
+ 'weight': '400',
+ });
+
+ let ctx = canvas.getContext('2d');
+ ctx.font = '30px Roboto';
+ ctx.rotate(.1);
+ ctx.fillText('Awesome ', 50, 100);
+ ctx.strokeText('Groovy!', 250, 100);
+
+ // Draw line under Awesome
+ ctx.strokeStyle = 'rgba(125,0,0,0.5)';
+ ctx.beginPath();
+ ctx.lineWidth = 6;
+ ctx.lineTo(50, 102);
+ ctx.lineTo(250, 102);
+ ctx.stroke();
+
+ // squished vertically
+ ctx.globalAlpha = 0.7
+ ctx.imageSmoothingQuality = 'medium';
+ ctx.drawImage(img, 150, 150, 150, 100);
+ ctx.rotate(-.2);
+ ctx.imageSmoothingEnabled = false;
+ ctx.drawImage(img, 100, 150, 400, 350, 10, 200, 150, 100);
+
+ console.log('drop in Canvas2D replacement');
+ console.log('<img src="' + canvas.toDataURL() + '" />');
+
+ fancyAPI(CanvasKit);
+});
+
+function fancyAPI(CanvasKit) {
+ let surface = CanvasKit.MakeSurface(300, 300);
+ const canvas = surface.getCanvas();
+
+ const paint = new CanvasKit.Paint();
+
+ let robotoData = fs.readFileSync(path.join(assetPath, 'Roboto-Regular.woff'));
+ const roboto = CanvasKit.Typeface.MakeFreeTypeFaceFromData(robotoData);
+
+ const textPaint = new CanvasKit.Paint();
+ textPaint.setColor(CanvasKit.Color(40, 0, 0));
+ textPaint.setAntiAlias(true);
+
+ const textFont = new CanvasKit.Font(roboto, 30);
+
+ const skpath = starPath(CanvasKit);
+ const dpe = CanvasKit.PathEffect.MakeDash([15, 5, 5, 10], 1);
+
+ paint.setPathEffect(dpe);
+ paint.setStyle(CanvasKit.PaintStyle.Stroke);
+ paint.setStrokeWidth(5.0);
+ paint.setAntiAlias(true);
+ paint.setColor(CanvasKit.Color(66, 129, 164, 1.0));
+
+ canvas.clear(CanvasKit.Color(255, 255, 255, 1.0));
+
+ canvas.drawPath(skpath, paint);
+ canvas.drawText('Try Clicking!', 10, 280, textPaint, textFont);
+
+ surface.flush();
+
+ const img = surface.makeImageSnapshot();
+ if (!img) {
+ console.error('no snapshot');
+ return;
+ }
+ const pngBytes = img.encodeToBytes();
+ if (!pngBytes) {
+ console.error('encoding failure');
+ return;
+ }
+ // See https://stackoverflow.com/a/12713326
+ let b64encoded = Buffer.from(pngBytes).toString('base64');
+ console.log('Other APIs too!');
+ console.log(`<img src="data:image/png;base64,${b64encoded}" />`);
+
+ // These delete calls free up memeory in the C++ WASM memory block.
+ dpe.delete();
+ skpath.delete();
+ textPaint.delete();
+ paint.delete();
+ roboto.delete();
+ textFont.delete();
+
+ surface.dispose();
+}
+
+function starPath(CanvasKit, X=128, Y=128, R=116) {
+ let p = new CanvasKit.Path();
+ p.moveTo(X + R, Y);
+ for (let i = 1; i < 8; i++) {
+ let a = 2.6927937 * i;
+ p.lineTo(X + R * Math.cos(a), Y + R * Math.sin(a));
+ }
+ return p;
+}
diff --git a/third_party/skia/modules/canvaskit/npm_build/package.json b/third_party/skia/modules/canvaskit/npm_build/package.json
new file mode 100644
index 0000000..2402600
--- /dev/null
+++ b/third_party/skia/modules/canvaskit/npm_build/package.json
@@ -0,0 +1,23 @@
+{
+ "name": "canvaskit-wasm",
+ "version": "0.33.0",
+ "description": "A WASM version of Skia's Canvas API",
+ "main": "bin/canvaskit.js",
+ "homepage": "https://github.com/google/skia/tree/main/modules/canvaskit",
+ "bugs": {
+ "url": "https://bugs.chromium.org/p/skia/issues/entry"
+ },
+ "permsRepo": "skia-dev/.github",
+ "publishConfig": {
+ "registry": "https://wombat-dressing-room.appspot.com"
+ },
+ "scripts": {
+ "dtslint": "dtslint types"
+ },
+ "types": "./types/index.d.ts",
+ "license": "BSD-3-Clause",
+ "devDependencies": {
+ "dtslint": "^4.0.4",
+ "typescript": "^4.0.3"
+ }
+}
diff --git a/third_party/skia/modules/canvaskit/npm_build/shaping.html b/third_party/skia/modules/canvaskit/npm_build/shaping.html
new file mode 100644
index 0000000..2ffb9ae
--- /dev/null
+++ b/third_party/skia/modules/canvaskit/npm_build/shaping.html
@@ -0,0 +1,179 @@
+<!DOCTYPE html>
+<title>WIP Shaping in JS Demo</title>
+<meta charset="utf-8" />
+<meta http-equiv="X-UA-Compatible" content="IE=edge">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+
+<style>
+ canvas {
+ border: 1px dashed #AAA;
+ }
+
+ #input {
+ height: 300px;
+ }
+
+</style>
+
+<h2> (Really Bad) Shaping in JS </h2>
+<textarea id=input></textarea>
+<canvas id=shaped_text width=300 height=300></canvas>
+
+<script type="text/javascript" src="/build/canvaskit.js"></script>
+
+<script type="text/javascript" charset="utf-8">
+
+ let CanvasKit = null;
+ const cdn = 'https://storage.googleapis.com/skia-cdn/misc/';
+
+ const ckLoaded = CanvasKitInit({locateFile: (file) => '/build/'+file});
+ const loadFont = fetch(cdn + 'Roboto-Regular.ttf').then((response) => response.arrayBuffer());
+ // This font works with interobang.
+ //const loadFont = fetch('https://storage.googleapis.com/skia-cdn/google-web-fonts/SourceSansPro-Regular.ttf').then((response) => response.arrayBuffer());
+
+ document.getElementById('input').value = 'An aegis protected the fox!?';
+
+ // Examples requiring external resources.
+ Promise.all([ckLoaded, loadFont]).then((results) => {
+ ShapingJS(...results);
+ });
+
+ function ShapingJS(CanvasKit, fontData) {
+ if (!CanvasKit || !fontData) {
+ return;
+ }
+
+ const surface = CanvasKit.MakeCanvasSurface('shaped_text');
+ if (!surface) {
+ console.error('Could not make surface');
+ return;
+ }
+
+ const typeface = CanvasKit.Typeface.MakeFreeTypeFaceFromData(fontData);
+
+ const paint = new CanvasKit.Paint();
+
+ paint.setColor(CanvasKit.BLUE);
+ paint.setStyle(CanvasKit.PaintStyle.Stroke);
+
+ const textPaint = new CanvasKit.Paint();
+ const textFont = new CanvasKit.Font(typeface, 20);
+ textFont.setLinearMetrics(true);
+ textFont.setSubpixel(true);
+ textFont.setHinting(CanvasKit.FontHinting.Slight);
+
+
+ // Only care about these characters for now. If we get any unknown characters, we'll replace
+ // them with the first glyph here (the replacement glyph).
+ // We put the family code point second to make sure we handle >16 bit codes correctly.
+ const alphabet = "�👪abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 _.,?!æâ€½";
+ const ids = textFont.getGlyphIDs(alphabet);
+ const unknownCharacterGlyphID = ids[0];
+ // char here means "string version of unicode code point". This makes the code below a bit more
+ // readable than just integers. We just have to take care when reading these in that we don't
+ // grab the second half of a 32 bit code unit.
+ const charsToGlyphIDs = {};
+ // Indexes in JS correspond to a 16 bit or 32 bit code unit. If a code point is wider than
+ // 16 bits, it overflows into the next index. codePointAt will return a >16 bit value if the
+ // given index overflows. We need to check for this and skip the next index lest we get a
+ // garbage value (the second half of the Unicode code point.
+ let glyphIdx = 0;
+ for (let i = 0; i < alphabet.length; i++) {
+ charsToGlyphIDs[alphabet[i]] = ids[glyphIdx];
+ if (alphabet.codePointAt(i) > 65535) {
+ i++; // skip the next index because that will be the second half of the code point.
+ }
+ glyphIdx++;
+ }
+
+ // TODO(kjlubick): linear metrics so we get "correct" data (e.g. floats).
+ const bounds = textFont.getGlyphBounds(ids, textPaint);
+ const widths = textFont.getGlyphWidths(ids, textPaint);
+ // See https://www.freetype.org/freetype2/docs/glyphs/glyphs-3.html
+ // Note that in Skia, y-down is positive, so it is common to see yMax below be negative.
+ const glyphMetricsByGlyphID = {};
+ for (let i = 0; i < ids.length; i++) {
+ glyphMetricsByGlyphID[ids[i]] = {
+ xMin: bounds[i*4],
+ yMax: bounds[i*4 + 1],
+ xMax: bounds[i*4 + 2],
+ yMin: bounds[i*4 + 3],
+ xAdvance: widths[i],
+ };
+ }
+
+ const shapeAndDrawText = (str, canvas, x, y, maxWidth, font, paint) => {
+ const LINE_SPACING = 20;
+
+ // This is a conservative estimate - it can be shorter if we have ligatures code points
+ // that span multiple 16bit words.
+ const glyphs = CanvasKit.MallocGlyphIDs(str.length);
+ let glyphArr = glyphs.toTypedArray();
+
+ // Turn the code points into glyphs, accounting for up to 2 ligatures.
+ let shapedGlyphIdx = -1;
+ for (let i = 0; i < str.length; i++) {
+ const char = str[i];
+ shapedGlyphIdx++;
+ // POC Ligature support.
+ if (charsToGlyphIDs['æ'] && char === 'a' && str[i+1] === 'e') {
+ glyphArr[shapedGlyphIdx] = charsToGlyphIDs['æ'];
+ i++; // skip next code point
+ continue;
+ }
+ if (charsToGlyphIDs['‽'] && (
+ (char === '?' && str[i+1] === '!') || (char === '!' && str[i+1] === '?' ))) {
+ glyphArr[shapedGlyphIdx] = charsToGlyphIDs['‽'];
+ i++; // skip next code point
+ continue;
+ }
+ glyphArr[shapedGlyphIdx] = charsToGlyphIDs[char] || unknownCharacterGlyphID;
+ if (str.codePointAt(i) > 65535) {
+ i++; // skip the next index because that will be the second half of the code point.
+ }
+ }
+ // Trim down our array of glyphs to only the amount we have after ligatures and code points
+ // that are > 16 bits.
+ glyphArr = glyphs.subarray(0, shapedGlyphIdx+1);
+
+ // Break our glyphs into runs based on the maxWidth and the xAdvance.
+ const glyphRuns = [];
+ let currentRunStartIdx = 0;
+ let currentWidth = 0;
+ for (let i = 0; i < glyphArr.length; i++) {
+ const nextGlyphWidth = glyphMetricsByGlyphID[glyphArr[i]].xAdvance;
+ if (currentWidth + nextGlyphWidth > maxWidth) {
+ glyphRuns.push(glyphs.subarray(currentRunStartIdx, i));
+ currentRunStartIdx = i;
+ currentWidth = 0;
+ }
+ currentWidth += nextGlyphWidth;
+ }
+ glyphRuns.push(glyphs.subarray(currentRunStartIdx, glyphArr.length));
+
+ // Draw all those runs.
+ for (let i = 0; i < glyphRuns.length; i++) {
+ const blob = CanvasKit.TextBlob.MakeFromGlyphs(glyphRuns[i], font);
+ if (blob) {
+ canvas.drawTextBlob(blob, x, y + LINE_SPACING*i, paint);
+ }
+ blob.delete();
+ }
+ CanvasKit.Free(glyphs);
+ }
+
+ const drawFrame = (canvas) => {
+ canvas.clear(CanvasKit.WHITE);
+ canvas.drawText('a + e = ae (no ligature)',
+ 5, 30, textPaint, textFont);
+ canvas.drawText('a + e = æ (hard-coded ligature)',
+ 5, 50, textPaint, textFont);
+
+ canvas.drawRect(CanvasKit.LTRBRect(10, 80, 280, 290), paint);
+ shapeAndDrawText(document.getElementById('input').value, canvas, 15, 100, 265, textFont, textPaint);
+
+ surface.requestAnimationFrame(drawFrame)
+ };
+ surface.requestAnimationFrame(drawFrame);
+ }
+</script>
diff --git a/third_party/skia/modules/canvaskit/npm_build/textapi_utils.js b/third_party/skia/modules/canvaskit/npm_build/textapi_utils.js
new file mode 100644
index 0000000..9f46889
--- /dev/null
+++ b/third_party/skia/modules/canvaskit/npm_build/textapi_utils.js
@@ -0,0 +1,659 @@
+
+function ASSERT(pred) {
+ console.assert(pred, 'assert failed');
+}
+
+function LOG(...args) {
+ // comment out for non-debugging
+// console.log(args);
+}
+
+function MakeCursor(CanvasKit) {
+ const linePaint = new CanvasKit.Paint();
+ linePaint.setColor([0,0,1,1]);
+ linePaint.setStyle(CanvasKit.PaintStyle.Stroke);
+ linePaint.setStrokeWidth(2);
+ linePaint.setAntiAlias(true);
+
+ const pathPaint = new CanvasKit.Paint();
+ pathPaint.setColor([0,0,1,0.25]);
+ linePaint.setAntiAlias(true);
+
+ return {
+ _line_paint: linePaint, // wrap in weak-ref so we can delete it?
+ _path_paint: pathPaint,
+ _x: 0,
+ _top: 0,
+ _bottom: 0,
+ _path: null, // only use x,top,bottom if path is null
+ _draws_per_sec: 2,
+
+ // pass 0 for no-draw, pass inf. for always on
+ setBlinkRate: function(blinks_per_sec) {
+ this._draws_per_sec = blinks_per_sec;
+ },
+ place: function(x, top, bottom) {
+ this._x = x;
+ this._top = top;
+ this._bottom = bottom;
+
+ this._path = null;
+ },
+ setPath: function(path) {
+ this._path = path;
+ },
+ draw_before: function(canvas) {
+ if (this._path) {
+ canvas.drawPath(this._path, this._path_paint);
+ }
+ },
+ draw_after: function(canvas) {
+ if (this._path) {
+ return;
+ }
+ if (Math.floor(Date.now() * this._draws_per_sec / 1000) & 1) {
+ canvas.drawLine(this._x, this._top, this._x, this._bottom, this._line_paint);
+ }
+ },
+ };
+}
+
+function MakeMouse() {
+ return {
+ _start_x: 0, _start_y: 0,
+ _curr_x: 0, _curr_y: 0,
+ _active: false,
+
+ isActive: function() {
+ return this._active;
+ },
+ setDown: function(x, y) {
+ this._start_x = this._curr_x = x;
+ this._start_y = this._curr_y = y;
+ this._active = true;
+ },
+ setMove: function(x, y) {
+ this._curr_x = x;
+ this._curr_y = y;
+ },
+ setUp: function(x, y) {
+ this._curr_x = x;
+ this._curr_y = y;
+ this._active = false;
+ },
+ getPos: function(dx, dy) {
+ return [ this._start_x + dx, this._start_y + dy, this._curr_x + dx, this._curr_y + dy ];
+ },
+ };
+}
+
+function runs_x_to_index(runs, x) {
+ for (const r of runs) {
+ for (let i = 1; i < r.offsets.length; i += 1) {
+ if (x < r.positions[i*2]) {
+ const mid = (r.positions[i*2-2] + r.positions[i*2]) * 0.5;
+ if (x <= mid) {
+ return r.offsets[i-1];
+ } else {
+ return r.offsets[i];
+ }
+ }
+ }
+ }
+ const r = runs[runs.length-1];
+ return r.offsets[r.offsets.length-1];
+}
+
+function lines_pos_to_index(lines, x, y) {
+ if (y < lines[0].top) {
+ return 0;
+ }
+ for (const l of lines) {
+ if (y <= l.bottom) {
+ return runs_x_to_index(l.runs, x);
+ }
+ }
+ return lines[lines.length - 1].textRange.last;
+}
+
+function runs_index_to_run(runs, index) {
+ for (const r of runs) {
+ if (index <= r.offsets[r.offsets.length-1]) {
+ return r;
+ }
+ }
+ return runs[runs.length-1]; // last run
+}
+
+function runs_index_to_x(runs, index) {
+ const r = runs_index_to_run(runs, index);
+ for (const i in r.offsets) {
+ if (index == r.offsets[i]) {
+ return r.positions[i*2];
+ }
+ }
+ return r.positions[r.positions.length-2]; // last x
+}
+
+function lines_index_to_line_index(lines, index) {
+ let i = 0;
+ for (const l of lines) {
+ if (index <= l.textRange.last) {
+ return i;
+ }
+ i += 1;
+ }
+ return lines.length-1;
+}
+
+function lines_index_to_line(lines, index) {
+ return lines[lines_index_to_line_index(lines, index)];
+}
+
+function lines_index_to_x(lines, index) {
+ for (const l of lines) {
+ if (index <= l.textRange.last) {
+ return runs_index_to_x(l.runs, index);
+ }
+ }
+}
+
+function lines_indices_to_path(lines, a, b, width) {
+ if (a == b) {
+ return null;
+ }
+ if (a > b) { [a, b] = [b, a]; }
+
+ const path = new CanvasKit.Path();
+ const la = lines_index_to_line(lines, a);
+ const lb = lines_index_to_line(lines, b);
+ const ax = runs_index_to_x(la.runs, a);
+ const bx = runs_index_to_x(lb.runs, b);
+ if (la == lb) {
+ path.addRect([ax, la.top, bx, la.bottom]);
+ } else {
+ path.addRect([ax, la.top, width, la.bottom]);
+ path.addRect([0, lb.top, bx, lb.bottom]);
+ if (la.bottom < lb.top) {
+ path.addRect([0, la.bottom, width, lb.top]); // extra lines inbetween
+ }
+ }
+ return path;
+}
+
+function string_del(str, start, end) {
+ return str.slice(0, start) + str.slice(end, str.length);
+}
+
+function make_default_paint() {
+ const p = new CanvasKit.Paint();
+ p.setAntiAlias(true);
+ return p;
+}
+
+function make_default_font(tf) {
+ const font = new CanvasKit.Font(tf);
+ font.setSubpixel(true);
+ return font;
+}
+
+function MakeStyle(length) {
+ return {
+ _length: length,
+ typeface: null,
+ size: null,
+ color: null,
+ bold: null,
+ italic: null,
+ underline: null,
+
+ _check_toggle: function(src, dst) {
+ if (src == 'toggle') {
+ return !dst;
+ } else {
+ return src;
+ }
+ },
+
+ // returns true if we changed something affecting layout
+ mergeFrom: function(src) {
+ let layoutChanged = false;
+
+ if (src.typeface && this.typeface !== src.typeface) {
+ this.typeface = src.typeface;
+ layoutChanged = true;
+ }
+ if (src.size && this.size !== src.size) {
+ this.size = src.size;
+ layoutChanged = true;
+ }
+ if (src.color) { this.color = src.color; }
+
+ if (src.bold) {
+ this.bold = this._check_toggle(src.bold, this.bold);
+ }
+ if (src.italic) {
+ this.italic = this._check_toggle(src.italic, this.italic);
+ }
+ if (src.underline) {
+ this.underline = this._check_toggle(src.underline, this.underline);
+ }
+
+ if (src.size_add) {
+ this.size += src.size_add;
+ layoutChanged = true;
+ }
+
+ return layoutChanged;
+ }
+ };
+}
+
+function MakeEditor(text, style, cursor, width) {
+ const ed = {
+ _text: text,
+ _lines: null,
+ _cursor: cursor,
+ _width: width,
+ _index: { start: 0, end: 0 },
+ _styles: null,
+ // drawing
+ _X: 0,
+ _Y: 0,
+ _paint: make_default_paint(),
+ _font: make_default_font(style.typeface),
+
+ getLines: function() { return this._lines; },
+
+ width: function() {
+ return this._width;
+ },
+ height: function() {
+ return this._lines[this._lines.length-1].bottom;
+ },
+ bounds: function() {
+ return [this._X, this._Y, this._X + this.width(), this._Y + this.height()];
+ },
+ setXY: function(x, y) {
+ this._X = x;
+ this._Y = y;
+ },
+
+ _rebuild_selection: function() {
+ const a = this._index.start;
+ const b = this._index.end;
+ ASSERT(a >= 0 && a <= b && b <= this._text.length);
+ if (a === b) {
+ const l = lines_index_to_line(this._lines, a);
+ const x = runs_index_to_x(l.runs, a);
+ this._cursor.place(x, l.top, l.bottom);
+ } else {
+ this._cursor.setPath(lines_indices_to_path(this._lines, a, b, this._width));
+ }
+ },
+ setIndex: function(i) {
+ this._index.start = this._index.end = i;
+ this._rebuild_selection();
+ },
+ setIndices: function(a, b) {
+ if (a > b) { [a, b] = [b, a]; }
+ this._index.start = a;
+ this._index.end = b;
+ this._rebuild_selection();
+ },
+ moveDX: function(dx) {
+ let index;
+ if (this._index.start == this._index.end) {
+ // just adjust and pin
+ index = Math.max(Math.min(this._index.start + dx, this._text.length), 0);
+ } else {
+ // 'deselect' the region, and turn it into just a single index
+ index = dx < 0 ? this._index.start : this._index.end;
+ }
+ this.setIndex(index);
+ },
+ moveDY: function(dy) {
+ let index = (dy < 0) ? this._index.start : this._index.end;
+ const i = lines_index_to_line_index(this._lines, index);
+ if (dy < 0 && i == 0) {
+ index = 0;
+ } else if (dy > 0 && i == this._lines.length - 1) {
+ index = this._text.length;
+ } else {
+ const x = runs_index_to_x(this._lines[i].runs, index);
+ // todo: statefully track "original" x when an up/down sequence started,
+ // so we can avoid drift.
+ index = runs_x_to_index(this._lines[i+dy].runs, x);
+ }
+ this.setIndex(index);
+ },
+
+ _validateStyles: function() {
+ let len = 0;
+ for (const s of this._styles) {
+ len += s._length;
+ }
+ ASSERT(len === this._text.length);
+ },
+ _validateBlocks: function(blocks) {
+ let len = 0;
+ for (const b of blocks) {
+ len += b.length;
+ }
+ ASSERT(len === this._text.length);
+ },
+
+ _buildLines: function() {
+ this._validateStyles();
+
+ const build_sparse = true;
+ const blocks = [];
+ let block = null;
+ for (const s of this._styles) {
+ if (build_sparse) {
+ if (!block || (block.typeface === s.typeface && block.size === s.size)) {
+ if (!block) {
+ block = { length: 0, typeface: s.typeface, size: s.size };
+ }
+ block.length += s._length;
+ } else {
+ blocks.push(block);
+ block = { length: s._length, typeface: s.typeface, size: s.size };
+ }
+ } else {
+ // force a block on every style boundary for now
+ blocks.push({ length: s._length, typeface: s.typeface, size: s.size });
+ }
+ }
+ if (build_sparse) {
+ blocks.push(block);
+ }
+ this._validateBlocks(blocks);
+
+ this._lines = CanvasKit.ParagraphBuilder.ShapeText(this._text, blocks, this._width);
+ this._rebuild_selection();
+
+ // add textRange to each run, to aid in drawing
+ this._runs = [];
+ for (const l of this._lines) {
+ for (const r of l.runs) {
+ r.textRange = { start: r.offsets[0], end: r.offsets[r.offsets.length-1] };
+ this._runs.push(r);
+ }
+ }
+ },
+
+ // note: this does not rebuild lines/runs, or update the cursor,
+ // but it does edit the text and styles
+ // returns true if it deleted anything
+ _deleteRange: function(start, end) {
+ ASSERT(start >= 0 && end <= this._text.length);
+ ASSERT(start <= end);
+ if (start === end) {
+ return false;
+ }
+
+ this._delete_style_range(start, end);
+ // Do this after shrink styles (we use text.length in an assert)
+ this._text = string_del(this._text, start, end);
+ },
+ deleteSelection: function() {
+ let start = this._index.start;
+ if (start == this._index.end) {
+ if (start == 0) {
+ return; // nothing to do
+ }
+ this._deleteRange(start - 1, start);
+ start -= 1;
+ } else {
+ this._deleteRange(start, this._index.end);
+ }
+ this._index.start = this._index.end = start;
+ this._buildLines();
+ },
+ insert: function(charcode) {
+ if (this._index.start != this._index.end) {
+ this.deleteSelection();
+ }
+ const index = this._index.start;
+
+ // do this before edit the text (we use text.length in an assert)
+ const [i, prev_len] = this.find_style_index_and_prev_length(index);
+ this._styles[i]._length += 1;
+
+ // now grow the text
+ this._text = this._text.slice(0, index) + charcode + this._text.slice(index);
+
+ this._index.start = this._index.end = index + 1;
+ this._buildLines();
+ },
+
+ draw: function(canvas) {
+ canvas.save();
+ canvas.translate(this._X, this._Y);
+
+ this._cursor.draw_before(canvas);
+
+ const runs = this._runs;
+ const styles = this._styles;
+ const f = this._font;
+ const p = this._paint;
+
+ let s = styles[0];
+ let sindex = 0;
+ let s_start = 0;
+ let s_end = s._length;
+
+ let r = runs[0];
+ let rindex = 0;
+
+ let start = 0;
+ let end = 0;
+ while (start < this._text.length) {
+ while (r.textRange.end <= start) {
+ r = runs[++rindex];
+ if (!r) {
+ // ran out of runs, so the remaining text must just be WS
+ break;
+ }
+ }
+ if (!r) break;
+ while (s_end <= start) {
+ s = styles[++sindex];
+ s_start = s_end;
+ s_end += s._length;
+ }
+ end = Math.min(r.textRange.end, s_end);
+
+ LOG('New range: ', start, end,
+ 'from run', r.textRange.start, r.textRange.end,
+ 'style', s_start, s_end);
+
+ // check that we have anything to draw
+ if (r.textRange.start >= end) {
+ start = end;
+ continue; // could be a span of WS with no glyphs
+ }
+
+// f.setTypeface(r.typeface); // r.typeface is always null (for now)
+ f.setSize(r.size);
+ f.setEmbolden(s.bold);
+ f.setSkewX(s.italic ? -0.2 : 0);
+ p.setColor(s.color ? s.color : [0,0,0,1]);
+
+ let gly = r.glyphs;
+ let pos = r.positions;
+ if (start > r.textRange.start || end < r.textRange.end) {
+ // search for the subset of glyphs to draw
+ let glyph_start, glyph_end;
+ for (let i = 0; i < r.offsets.length; ++i) {
+ if (r.offsets[i] >= start) {
+ glyph_start = i;
+ break;
+ }
+ }
+ for (let i = glyph_start+1; i < r.offsets.length; ++i) {
+ if (r.offsets[i] >= end) {
+ glyph_end = i;
+ break;
+ }
+ }
+ LOG(' glyph subrange', glyph_start, glyph_end);
+ gly = gly.slice(glyph_start, glyph_end);
+ // +2 at the end so we can see the trailing position (esp. for underlines)
+ pos = pos.slice(glyph_start*2, glyph_end*2 + 2);
+ } else {
+ LOG(' use entire glyph run');
+ }
+ canvas.drawGlyphs(gly, pos, 0, 0, f, p);
+
+ if (s.underline) {
+ const gap = 2;
+ const Y = pos[1]; // first Y
+ const lastX = pos[gly.length*2];
+ const sects = f.getGlyphIntercepts(gly, pos, Y+2, Y+4);
+
+ let x = pos[0];
+ for (let i = 0; i < sects.length; i += 2) {
+ const end = sects[i] - gap;
+ if (x < end) {
+ canvas.drawRect([x, Y+2, end, Y+4], p);
+ }
+ x = sects[i+1] + gap;
+ }
+ if (x < lastX) {
+ canvas.drawRect([x, Y+2, lastX, Y+4], p);
+ }
+ }
+
+ start = end;
+ }
+
+ this._cursor.draw_after(canvas);
+ canvas.restore();
+ },
+
+ // Styling
+
+ // returns [index, prev total length before this style]
+ find_style_index_and_prev_length: function(index) {
+ let len = 0;
+ for (let i = 0; i < this._styles.length; ++i) {
+ const l = this._styles[i]._length;
+ len += l;
+ // < favors the latter style if index is between two styles
+ if (index < len) {
+ return [i, len - l];
+ }
+ }
+ ASSERT(len === this._text.length);
+ return [this._styles.length-1, len];
+ },
+ _delete_style_range: function(start, end) {
+ // shrink/remove styles
+ //
+ // [.....][....][....][.....] styles
+ // [..................] start...end
+ //
+ // - trim the first style
+ // - remove the middle styles
+ // - trim the last style
+
+ let N = end - start;
+ let [i, prev_len] = this.find_style_index_and_prev_length(start);
+ let s = this._styles[i];
+ if (start > prev_len) {
+ // we overlap the first style (but not entirely
+ const skip = start - prev_len;
+ ASSERT(skip < s._length);
+ const shrink = Math.min(N, s._length - skip);
+ ASSERT(shrink > 0);
+ s._length -= shrink;
+ N -= shrink;
+ if (N === 0) {
+ return;
+ }
+ i += 1;
+ ASSERT(i < this._styles.length);
+ }
+ while (N > 0) {
+ s = this._styles[i];
+ if (N >= s._length) {
+ N -= s._length;
+ this._styles.splice(i, 1);
+ } else {
+ s._length -= N;
+ break;
+ }
+ }
+ },
+
+ applyStyleToRange: function(style, start, end) {
+ if (start > end) { [start, end] = [end, start]; }
+ ASSERT(start >= 0 && end <= this._text.length);
+ if (start === end) {
+ return;
+ }
+
+ LOG('trying to apply', style, start, end);
+ let i;
+ for (i = 0; i < this._styles.length; ++i) {
+ if (start <= this._styles[i]._length) {
+ break;
+ }
+ start -= this._styles[i]._length;
+ end -= this._styles[i]._length;
+ }
+
+ let s = this._styles[i];
+ // do we need to fission off a clean subset for the head of s?
+ if (start > 0) {
+ const ns = Object.assign({}, s);
+ s._length = start;
+ ns._length -= start;
+ LOG('initial splice', i, start, s._length, ns._length);
+ i += 1;
+ this._styles.splice(i, 0, ns);
+ end -= start;
+ // we don't use start any more
+ }
+ // merge into any/all whole styles we overlap
+ let layoutChanged = false;
+ while (end >= this._styles[i]._length) {
+ LOG('whole run merging for style index', i)
+ layoutChanged |= this._styles[i].mergeFrom(style);
+ end -= this._styles[i]._length;
+ i += 1;
+ if (end == 0) {
+ break;
+ }
+ }
+ // do we partially cover the last run
+ if (end > 0) {
+ s = this._styles[i];
+ const ns = Object.assign({}, s); // the new first half
+ ns._length = end;
+ s._length -= end; // trim the (unchanged) tail
+ LOG('merging tail', i, ns._length, s._length);
+ layoutChanged |= ns.mergeFrom(style);
+ this._styles.splice(i, 0, ns);
+ }
+
+ this._validateStyles();
+ LOG('after applying styles', this._styles);
+
+ if (layoutChanged) {
+ this._buildLines();
+ }
+ },
+ applyStyleToSelection: function(style) {
+ this.applyStyleToRange(style, this._index.start, this._index.end);
+ },
+ };
+
+ const s = MakeStyle(ed._text.length);
+ s.mergeFrom(style);
+ ed._styles = [ s ];
+ ed._buildLines();
+ return ed;
+}
diff --git a/third_party/skia/modules/canvaskit/npm_build/types/README.md b/third_party/skia/modules/canvaskit/npm_build/types/README.md
new file mode 100644
index 0000000..ae3b85d
--- /dev/null
+++ b/third_party/skia/modules/canvaskit/npm_build/types/README.md
@@ -0,0 +1,4 @@
+This folder contains Typescript function definitions and documentation.
+
+The goal will be to keep these up to date and contribute them to the
+DefinitelyTyped project.
diff --git a/third_party/skia/modules/canvaskit/npm_build/types/canvaskit-wasm-tests.ts b/third_party/skia/modules/canvaskit/npm_build/types/canvaskit-wasm-tests.ts
new file mode 100644
index 0000000..47eb2fc
--- /dev/null
+++ b/third_party/skia/modules/canvaskit/npm_build/types/canvaskit-wasm-tests.ts
@@ -0,0 +1,980 @@
+// This file is type-checked by the Typescript definitions. It is not actually executed.
+// Test it by running `npm run dtslint` in the parent directory.
+import {
+ CanvasKitInit,
+ AnimatedImage,
+ Canvas,
+ CanvasKit,
+ ColorFilter,
+ Font,
+ FontMgr,
+ Image,
+ ImageFilter,
+ ImageInfo,
+ MaskFilter,
+ Paint,
+ Paragraph,
+ Path,
+ PathEffect,
+ Shader,
+ SkPicture,
+ TextBlob,
+ Typeface,
+ Vertices,
+} from "canvaskit-wasm";
+
+CanvasKitInit({locateFile: (file: string) => '/node_modules/canvaskit/bin/' + file}).then((CK: CanvasKit) => {
+ animatedImageTests(CK);
+ canvasTests(CK);
+ canvas2DTests(CK);
+ colorFilterTests(CK);
+ colorTests(CK);
+ contourMeasureTests(CK);
+ imageFilterTests(CK);
+ imageTests(CK);
+ fontTests(CK);
+ fontMgrTests(CK);
+ globalTests(CK);
+ mallocTests(CK);
+ maskFilterTests(CK);
+ matrixTests(CK);
+ paintTests(CK);
+ paragraphTests(CK);
+ paragraphBuilderTests(CK);
+ particlesTests(CK);
+ pathEffectTests(CK);
+ pathTests(CK);
+ pictureTests(CK);
+ rectangleTests(CK);
+ runtimeEffectTests(CK);
+ skottieTests(CK);
+ shaderTests(CK);
+ surfaceTests(CK);
+ textBlobTests(CK);
+ typefaceTests(CK);
+ vectorTests(CK);
+ verticesTests(CK);
+});
+
+function animatedImageTests(CK: CanvasKit) {
+ const buff = new ArrayBuffer(10);
+ const img = CK.MakeAnimatedImageFromEncoded(buff); // $ExpectType AnimatedImage | null
+ if (!img) return;
+ const n = img.decodeNextFrame(); // $ExpectType number
+ const f = img.getFrameCount(); // $ExpectType number
+ const r = img.getRepetitionCount(); // $ExpectType number
+ const h = img.height(); // $ExpectType number
+ const still = img.makeImageAtCurrentFrame(); // $ExpectType Image | null
+ const ms = img.currentFrameDuration(); // $ExpectType number
+ img.reset();
+ const w = img.width(); // $ExpectType number
+}
+
+// In an effort to keep these type-checking tests easy to read and understand, we can "inject"
+// types instead of actually having to create them from scratch. To inject them, we define them
+// as an optional parameter and then have a null check to make sure that optional-ness does not
+// cause errors.
+function canvasTests(CK: CanvasKit, canvas?: Canvas, paint?: Paint, path?: Path,
+ img?: Image, aImg?: AnimatedImage, para?: Paragraph,
+ skp?: SkPicture, font?: Font, textBlob?: TextBlob, verts?: Vertices,
+ imageInfo?: ImageInfo, imgFilter?: ImageFilter) {
+ if (!canvas || !paint || !path || !img || !aImg || !para || !skp || !font ||
+ !textBlob || !verts || !imageInfo || !imgFilter) {
+ return;
+ }
+ const someColor = [0.9, 0.8, 0.7, 0.6]; // Making sure arrays are accepted as colors.
+ const someRect = [4, 3, 2, 1]; // Making sure arrays are accepted as rects.
+ // Making sure arrays are accepted as rrects.
+ const someRRect = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
+ const someMatrix = CK.Malloc(Float32Array, 16); // Make sure matrixes can be malloc'd.
+
+ canvas.clear(CK.RED);
+ canvas.clipPath(path, CK.ClipOp.Intersect, false);
+ canvas.clipRect(someRect, CK.ClipOp.Intersect, true);
+ canvas.clipRRect(CK.RRectXY(someRect, 10, 20), CK.ClipOp.Difference, true);
+ canvas.concat([1, 0, 0, 0, 1, 0, 0, 0, 1]);
+ canvas.concat(someMatrix);
+ canvas.drawArc(someRect, 0, 90, true, paint);
+ canvas.drawAtlas(img, [1, 2, 3, 4, 5, 6, 7, 8], [8, 7, 6, 5, 4, 3, 2, 1], paint);
+ canvas.drawAtlas(img, [1, 2, 3, 4, 5, 6, 7, 8], [8, 7, 6, 5, 4, 3, 2, 1], paint,
+ CK.BlendMode.Darken,
+ [CK.ColorAsInt(100, 110, 120), CK.ColorAsInt(130, 140, 150)]);
+ canvas.drawAtlas(img, [1, 2, 3, 4, 5, 6, 7, 8], [8, 7, 6, 5, 4, 3, 2, 1], paint,
+ null, null, {B: 0, C: 0.5});
+ canvas.drawAtlas(img, [1, 2, 3, 4, 5, 6, 7, 8], [8, 7, 6, 5, 4, 3, 2, 1], paint,
+ null, null, {filter: CK.FilterMode.Linear, mipmap: CK.MipmapMode.Nearest});
+ canvas.drawCircle(20, 20, 20, paint);
+ canvas.drawColor(someColor);
+ canvas.drawColor(someColor, CK.BlendMode.ColorDodge);
+ canvas.drawColorComponents(0.2, 1.0, -0.02, 0.5);
+ canvas.drawColorComponents(0.2, 1.0, -0.02, 0.5, CK.BlendMode.ColorDodge);
+ canvas.drawColorInt(CK.ColorAsInt(100, 110, 120));
+ canvas.drawColorInt(CK.ColorAsInt(100, 110, 120), CK.BlendMode.ColorDodge);
+ canvas.drawDRRect(someRRect, CK.RRectXY(someRect, 10, 20), paint);
+ canvas.drawImage(img, 0, -43);
+ canvas.drawImage(img, 0, -43, paint);
+ canvas.drawImageCubic(img, 0, -43, 1 / 3, 1 / 4, null);
+ canvas.drawImageOptions(img, 0, -43, CK.FilterMode.Nearest, CK.MipmapMode.Nearest, paint);
+ canvas.drawImageNine(img, someRect, someRect, CK.FilterMode.Nearest);
+ canvas.drawImageNine(img, CK.XYWHiRect(10, 20, 40, 40), someRect, CK.FilterMode.Linear, paint);
+ canvas.drawImageRect(img, someRect, someRect, paint);
+ canvas.drawImageRect(img, CK.XYWHRect(90, 90, 40, 40), someRect, paint);
+ canvas.drawImageRect(img, someRect, someRect, paint, true);
+ canvas.drawImageRectCubic(img, someRect, someRect, 1 / 5, 1 / 6);
+ canvas.drawImageRectCubic(img, someRect, someRect, 1 / 5, 1 / 6, paint);
+ canvas.drawImageRectOptions(img, someRect, someRect, CK.FilterMode.Linear, CK.MipmapMode.None);
+ canvas.drawImageRectOptions(img, someRect, someRect, CK.FilterMode.Linear, CK.MipmapMode.None, paint);
+ canvas.drawLine(1, 2, 3, 4, paint);
+ canvas.drawOval(someRect, paint);
+ canvas.drawPaint(paint);
+ canvas.drawParagraph(para, 10, 7);
+ const cubics = [1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
+ 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12];
+ const colors = [CK.RED, CK.BLUE, CK.GREEN, CK.WHITE];
+ const texs = [1, 1, 2, 2, 3, 3, 4, 4];
+ canvas.drawPatch(cubics, null, null, null, paint);
+ canvas.drawPatch(cubics, colors, null, CK.BlendMode.Clear, paint);
+ canvas.drawPatch(cubics, null, texs, null, paint);
+ canvas.drawPatch(cubics, colors, texs, CK.BlendMode.SrcOver, paint);
+ canvas.drawPath(path, paint);
+ canvas.drawPicture(skp);
+ canvas.drawPoints(CK.PointMode.Lines, [1, 2, 3, 4, 5, 6], paint);
+ canvas.drawRect(someRect, paint);
+ canvas.drawRect4f(5, 6, 7, 8, paint);
+ canvas.drawRRect(someRRect, paint);
+ canvas.drawShadow(path, [1, 2, 3], [4, 5, 6], 7, someColor, CK.BLUE, 0);
+ const mallocedVector3 = CK.Malloc(Float32Array, 3);
+ canvas.drawShadow(path, mallocedVector3, mallocedVector3, 7, someColor, CK.BLUE, 0);
+ canvas.drawText('foo', 1, 2, paint, font);
+ canvas.drawTextBlob(textBlob, 10, 20, paint);
+ canvas.drawVertices(verts, CK.BlendMode.DstOut, paint);
+ const matrTwo = canvas.getLocalToDevice(); // $ExpectType Float32Array
+ const sc = canvas.getSaveCount(); // $ExpectType number
+ const matrThree = canvas.getTotalMatrix(); // $ExpectType number[]
+ const surface = canvas.makeSurface(imageInfo); // $ExpectType Surface | null
+ const pixels = canvas.readPixels(85, 1000, {// $Uint8Array | Float32Array | null
+ width: 79,
+ height: 205,
+ colorType: CK.ColorType.RGBA_8888,
+ alphaType: CK.AlphaType.Unpremul,
+ colorSpace: CK.ColorSpace.SRGB,
+ });
+ const m = CK.Malloc(Uint8Array, 10);
+ img.readPixels(85, 1000, {
+ width: 79,
+ height: 205,
+ colorType: CK.ColorType.RGBA_8888,
+ alphaType: CK.AlphaType.Unpremul,
+ colorSpace: CK.ColorSpace.SRGB,
+ }, m, 4 * 85);
+ canvas.restore();
+ canvas.restoreToCount(2);
+ canvas.rotate(1, 2, 3);
+ const height = canvas.save(); // $ExpectType number
+ const h2 = canvas.saveLayer(); // $ExpectType number
+ const h3 = canvas.saveLayer(paint); // $ExpectType number
+ const h4 = canvas.saveLayer(paint, someRect);
+ const h5 = canvas.saveLayer(paint, someRect, imgFilter, CK.SaveLayerF16ColorType);
+ const h6 = canvas.saveLayer(paint, someRect, null, CK.SaveLayerInitWithPrevious);
+ canvas.scale(5, 10);
+ canvas.skew(10, 5);
+ canvas.translate(20, 30);
+ const ok = canvas.writePixels([1, 2, 3, 4], 1, 1, 10, 20); // $ExpectType boolean
+ const ok2 = canvas.writePixels([1, 2, 3, 4], 1, 1, 10, 20, CK.AlphaType.Premul,
+ CK.ColorType.Alpha_8, CK.ColorSpace.DISPLAY_P3);
+}
+
+function canvas2DTests(CK: CanvasKit) {
+ const bytes = new ArrayBuffer(10);
+
+ const canvas = CK.MakeCanvas(100, 200);
+ const img = canvas.decodeImage(bytes);
+ const ctx = canvas.getContext('2d');
+ ctx!.lineTo(2, 4);
+ canvas.loadFont(bytes, {
+ family: 'BungeeNonSystem',
+ style: 'normal',
+ weight: '400',
+ });
+ const p2d = canvas.makePath2D();
+ p2d.quadraticCurveTo(1, 2, 3, 4);
+ const iData = new CK.ImageData(40, 50);
+ const imgStr = canvas.toDataURL();
+}
+
+function colorTests(CK: CanvasKit) {
+ const colorOne = CK.Color(200, 200, 200, 0.8); // $ExpectType Float32Array
+ const colorTwo = CK.Color4f(0.8, 0.8, 0.8, 0.7); // $ExpectType Float32Array
+ const colorThree = CK.ColorAsInt(240, 230, 220); // $ExpectType number
+ const colorFour = CK.parseColorString('#887766'); // $ExpectType Float32Array
+ const colors = CK.computeTonalColors({ // $ExpectType TonalColorsOutput
+ ambient: colorOne,
+ spot: [0.2, 0.4, 0.6, 0.8],
+ });
+
+ // Deprecated Color functions
+ const [r, g, b, a] = CK.getColorComponents(colorTwo);
+ const alphaChanged = CK.multiplyByAlpha(colorOne, 0.1);
+}
+
+function colorFilterTests(CK: CanvasKit) {
+ const cf = CK.ColorFilter; // less typing
+ const filterOne = cf.MakeBlend(CK.CYAN, CK.BlendMode.ColorBurn); // $ExpectType ColorFilter
+ const filterTwo = cf.MakeLinearToSRGBGamma(); // $ExpectType ColorFilter
+ const filterThree = cf.MakeSRGBToLinearGamma(); // $ExpectType ColorFilter
+ const filterFour = cf.MakeCompose(filterOne, filterTwo); // $ExpectType ColorFilter
+ const filterFive = cf.MakeLerp(0.7, filterThree, filterFour); // $ExpectType ColorFilter
+
+ const r = CK.ColorMatrix.rotated(0, .707, -.707); // $ExpectType Float32Array
+ const b = CK.ColorMatrix.rotated(2, .5, .866);
+ const s = CK.ColorMatrix.scaled(0.9, 1.5, 0.8, 0.8);
+ let cm = CK.ColorMatrix.concat(r, s);
+ cm = CK.ColorMatrix.concat(cm, b);
+ CK.ColorMatrix.postTranslate(cm, 20, 0, -10, 0);
+
+ const filterSix = CK.ColorFilter.MakeMatrix(cm); // $ExpectType ColorFilter
+}
+
+function contourMeasureTests(CK: CanvasKit, path?: Path) {
+ if (!path) return;
+ const iter = new CK.ContourMeasureIter(path, true, 2); // $ExpectType ContourMeasureIter
+ const contour = iter.next(); // $ExpectType ContourMeasure | null
+ if (!contour) return;
+ const pt = contour.getPosTan(2); // $ExpectType Float32Array
+ contour.getPosTan(2, pt);
+ const segment = contour.getSegment(0, 20, true); // $ExpectType Path
+ const closed = contour.isClosed(); // $ExpectType boolean
+ const length = contour.length(); // $ExpectType number
+}
+
+function imageTests(CK: CanvasKit, imgElement?: HTMLImageElement) {
+ if (!imgElement) return;
+ const buff = new ArrayBuffer(10);
+ const img = CK.MakeImageFromEncoded(buff); // $ExpectType Image | null
+ const img2 = CK.MakeImageFromCanvasImageSource(imgElement); // $ExpectType Image
+ const img3 = CK.MakeImage({ // $ExpectType Image | null
+ width: 1,
+ height: 1,
+ alphaType: CK.AlphaType.Premul,
+ colorType: CK.ColorType.RGBA_8888,
+ colorSpace: CK.ColorSpace.SRGB
+ }, Uint8Array.of(255, 0, 0, 250), 4);
+ const img4 = CK.MakeLazyImageFromTextureSource(imgElement); // $ExpectType Image
+ const img5 = CK.MakeLazyImageFromTextureSource(imgElement, {
+ width: 1,
+ height: 1,
+ alphaType: CK.AlphaType.Premul,
+ colorType: CK.ColorType.RGBA_8888,
+ });
+ if (!img) return;
+ const dOne = img.encodeToBytes(); // $ExpectType Uint8Array | null
+ const dTwo = img.encodeToBytes(CK.ImageFormat.JPEG, 97);
+ const h = img.height();
+ const w = img.width();
+ const s1 = img.makeShaderCubic(CK.TileMode.Decal, CK.TileMode.Repeat, 1 / 3, 1 / 3); // $ExpectType Shader
+ const mm = img.makeCopyWithDefaultMipmaps(); // $ExpectType Image
+ const s2 = mm.makeShaderOptions(CK.TileMode.Decal, CK.TileMode.Repeat, // $ExpectType Shader
+ CK.FilterMode.Nearest, CK.MipmapMode.Linear,
+ CK.Matrix.identity());
+ const pixels = img.readPixels(85, 1000, { // $ExpectType Float32Array | Uint8Array | null
+ width: 79,
+ height: 205,
+ colorType: CK.ColorType.RGBA_8888,
+ alphaType: CK.AlphaType.Unpremul,
+ colorSpace: CK.ColorSpace.SRGB,
+ });
+ const m = CK.Malloc(Uint8Array, 10);
+ img.readPixels(85, 1000, {
+ width: 79,
+ height: 205,
+ colorType: CK.ColorType.RGBA_8888,
+ alphaType: CK.AlphaType.Unpremul,
+ colorSpace: CK.ColorSpace.SRGB,
+ }, m, 4 * 85);
+ const ii = img.getImageInfo(); // $ExpectType PartialImageInfo
+ const cs = img.getColorSpace(); // $ExpectType ColorSpace
+ cs.delete();
+ img.delete();
+}
+
+function imageFilterTests(CK: CanvasKit, colorFilter?: ColorFilter) {
+ if (!colorFilter) return;
+ const imgf = CK.ImageFilter; // less typing
+ const filter = imgf.MakeBlur(2, 4, CK.TileMode.Mirror, null); // $ExpectType ImageFilter
+ const filter1 = imgf.MakeBlur(2, 4, CK.TileMode.Decal, filter); // $ExpectType ImageFilter
+ const filter2 = imgf.MakeColorFilter(colorFilter, null); // $ExpectType ImageFilter
+ const filter3 = imgf.MakeColorFilter(colorFilter, filter); // $ExpectType ImageFilter
+ const filter4 = imgf.MakeCompose(null, filter2); // $ExpectType ImageFilter
+ const filter5 = imgf.MakeCompose(filter3, null); // $ExpectType ImageFilter
+ const filter6 = imgf.MakeCompose(filter4, filter2); // $ExpectType ImageFilter
+ const filter7 = imgf.MakeMatrixTransform(CK.Matrix.scaled(2, 3, 10, 10),
+ { B: 0, C: 0.5 }, null);
+ const filter8 = imgf.MakeMatrixTransform(CK.M44.identity(),
+ { filter: CK.FilterMode.Linear, mipmap: CK.MipmapMode.Nearest },
+ filter6);
+ const filter9 = imgf.MakeMatrixTransform(CK.M44.identity(),
+ { filter: CK.FilterMode.Nearest },
+ filter6);
+}
+
+function fontTests(CK: CanvasKit, face?: Typeface, paint?: Paint) {
+ if (!face || !paint) return;
+ const font = new CK.Font(); // $ExpectType Font
+ const f2 = new CK.Font(face); // $ExpectType Font
+ const f3 = new CK.Font(null); // $ExpectType Font
+ const f4 = new CK.Font(face, 20); // $ExpectType Font
+ const f5 = new CK.Font(null, 20); // $ExpectType Font
+ const f6 = new CK.Font(null, 20, 2, 3); // $ExpectType Font
+ const f7 = new CK.Font(face, 20, 4, 5); // $ExpectType Font
+
+ const glyphMalloc = CK.MallocGlyphIDs(20);
+ const someGlyphs = [1, 2, 3, 4, 5];
+
+ const glyphBounds = font.getGlyphBounds(glyphMalloc, paint); // $ExpectType Float32Array
+ font.getGlyphBounds(someGlyphs, null, glyphBounds);
+
+ const ids = font.getGlyphIDs('abcd');
+ font.getGlyphIDs('efgh', 4, ids);
+
+ const widths = font.getGlyphWidths(glyphMalloc, paint);
+ font.getGlyphWidths(someGlyphs, null, widths);
+
+ const sects = font.getGlyphIntercepts(ids, [10, 20], -60, -40);
+
+ font.getScaleX();
+ font.getSize();
+ font.getSkewX();
+ font.getTypeface();
+ font.setEdging(CK.FontEdging.Alias);
+ font.setEmbeddedBitmaps(true);
+ font.setHinting(CK.FontHinting.Slight);
+ font.setLinearMetrics(true);
+ font.setScaleX(5);
+ font.setSize(15);
+ font.setSkewX(2);
+ font.setSubpixel(true);
+ font.setTypeface(null);
+ font.setTypeface(face);
+}
+
+function fontMgrTests(CK: CanvasKit) {
+ const buff1 = new ArrayBuffer(10);
+ const buff2 = new ArrayBuffer(20);
+
+ const fm = CK.FontMgr.FromData(buff1, buff2)!;
+ fm.countFamilies();
+ fm.getFamilyName(0);
+}
+
+function globalTests(CK: CanvasKit, path?: Path) {
+ if (!path) {
+ return;
+ }
+ const n = CK.getDecodeCacheLimitBytes();
+ const u = CK.getDecodeCacheUsedBytes();
+ CK.setDecodeCacheLimitBytes(1000);
+ const matr = CK.Matrix.rotated(Math.PI / 6);
+ const p = CK.getShadowLocalBounds(matr, path, [0, 0, 1], [500, 500, 20], 20,
+ CK.ShadowDirectionalLight | CK.ShadowGeometricOnly | CK.ShadowDirectionalLight);
+ const mallocedVector3 = CK.Malloc(Float32Array, 3);
+ const q = CK.getShadowLocalBounds(matr, path, mallocedVector3, mallocedVector3, 20,
+ CK.ShadowDirectionalLight | CK.ShadowGeometricOnly | CK.ShadowDirectionalLight);
+}
+
+function paintTests(CK: CanvasKit, colorFilter?: ColorFilter, imageFilter?: ImageFilter,
+ maskFilter?: MaskFilter, pathEffect?: PathEffect, shader?: Shader) {
+ if (!colorFilter || !colorFilter || !imageFilter || !maskFilter || !pathEffect || !shader) {
+ return;
+ }
+ const paint = new CK.Paint(); // $ExpectType Paint
+ const newPaint = paint.copy(); // $ExpectType Paint
+ const color = paint.getColor(); // $ExpectType Float32Array
+ const sc = paint.getStrokeCap();
+ const sj = paint.getStrokeJoin();
+ const limit = paint.getStrokeMiter(); // $ExpectType number
+ const width = paint.getStrokeWidth(); // $ExpectType number
+ paint.setAlphaf(0.8);
+ paint.setAntiAlias(true);
+ paint.setBlendMode(CK.BlendMode.DstOut);
+ paint.setColor(CK.RED);
+ paint.setColor([0, 0, 1.2, 0.5], CK.ColorSpace.DISPLAY_P3);
+ paint.setColorComponents(0, 0, 0.9, 1.0);
+ paint.setColorComponents(0, 0, 1.2, 0.5, CK.ColorSpace.DISPLAY_P3);
+ paint.setColorFilter(colorFilter);
+ paint.setColorInt(CK.ColorAsInt(20, 30, 40));
+ paint.setColorInt(CK.ColorAsInt(20, 30, 40), CK.ColorSpace.SRGB);
+ paint.setImageFilter(imageFilter);
+ paint.setMaskFilter(maskFilter);
+ paint.setPathEffect(pathEffect);
+ paint.setShader(shader);
+ paint.setStrokeCap(CK.StrokeCap.Round);
+ paint.setStrokeJoin(CK.StrokeJoin.Miter);
+ paint.setStrokeMiter(10);
+ paint.setStrokeWidth(20);
+ paint.setStyle(CK.PaintStyle.Fill);
+ paint.delete();
+}
+
+function pathTests(CK: CanvasKit) {
+ const path = new CK.Path(); // $ExpectType Path
+ const p2 = CK.Path.MakeFromCmds([ // $ExpectType Path | null
+ CK.MOVE_VERB, 0, 10,
+ CK.LINE_VERB, 30, 40,
+ CK.QUAD_VERB, 20, 50, 45, 60,
+ ]);
+ const verbs = CK.Malloc(Uint8Array, 10);
+ const points = CK.Malloc(Float32Array, 10);
+ const p3 = CK.Path.MakeFromVerbsPointsWeights(verbs, [1, 2, 3, 4]); // $ExpectType Path
+ const p4 = CK.Path.MakeFromVerbsPointsWeights([CK.CONIC_VERB], points, [2.3]);
+ const p5 = CK.Path.MakeFromOp(p4, p2!, CK.PathOp.ReverseDifference); // $ExpectType Path | null
+ const p6 = CK.Path.MakeFromSVGString('M 205,5 L 795,5 z'); // $ExpectType Path | null
+ const p7 = p3.makeAsWinding(); // $ExpectType Path | null
+
+ const someRect = CK.LTRBRect(10, 20, 30, 40);
+ // Making sure arrays are accepted as rrects.
+ const someRRect = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
+
+ path.addArc(someRect, 0, 270);
+ path.addOval(someRect);
+ path.addOval(someRect, true, 3);
+ path.addPath(p2);
+ path.addPoly([20, 20, 40, 40, 20, 40], true);
+ path.addRect(someRect);
+ path.addRect(someRect, true);
+ path.addRRect(someRRect);
+ path.addRRect(someRRect, true);
+ path.addVerbsPointsWeights(verbs, [1, 2, 3, 4]);
+ path.addVerbsPointsWeights([CK.CONIC_VERB], points, [2.3]);
+ path.arc(0, 0, 10, 0, Math.PI / 2);
+ path.arc(0, 0, 10, 0, Math.PI / 2, true);
+ path.arcToOval(someRect, 15, 60, true);
+ path.arcToRotated(2, 4, 90, false, true, 0, 20);
+ path.arcToTangent(20, 20, 40, 50, 2);
+ path.close();
+ let bounds = path.computeTightBounds(); // $ExpectType Float32Array
+ path.computeTightBounds(bounds);
+ path.conicTo(1, 2, 3, 4, 5);
+ let ok = path.contains(10, 20); // $ExpectType boolean
+ const pCopy = path.copy(); // $ExpectType Path
+ const count = path.countPoints(); // $ExpectType number
+ path.cubicTo(10, 10, 10, 10, 10, 10);
+ ok = path.dash(8, 4, 1);
+ ok = path.equals(pCopy);
+ bounds = path.getBounds(); // $ExpectType Float32Array
+ path.getBounds(bounds);
+ const ft = path.getFillType();
+ const pt = path.getPoint(7); // $ExpectType Float32Array
+ path.getPoint(8, pt);
+ ok = path.isEmpty();
+ ok = path.isVolatile();
+ path.lineTo(10, -20);
+ path.moveTo(-20, -30);
+ path.offset(100, 100);
+ ok = path.op(p2!, CK.PathOp.Difference);
+ path.quadTo(10, 20, 30, 40);
+ path.rArcTo(10, 10, 90, false, true, 2, 4);
+ path.rConicTo(-1, 2, 4, 9, 3);
+ path.rCubicTo(20, 30, 40, 50, 2, 1);
+ path.reset();
+ path.rewind();
+ path.rLineTo(20, 30);
+ path.rMoveTo(40, 80);
+ path.rQuadTo(1, 2, 3, 4);
+ path.setFillType(CK.FillType.EvenOdd);
+ path.setIsVolatile(true);
+ ok = path.simplify();
+ path.stroke();
+ path.stroke({});
+ path.stroke({
+ width: 20,
+ miter_limit: 9,
+ precision: 0.5,
+ cap: CK.StrokeCap.Butt,
+ join: CK.StrokeJoin.Miter,
+ });
+ const cmds = path.toCmds(); // $ExpectType Float32Array
+ const str = path.toSVGString(); // $ExpectType string
+ path.transform(CK.Matrix.identity());
+ path.transform(1, 0, 0, 0, 1, 0, 0, 0, 1);
+ path.trim(0.1, 0.7, false);
+}
+
+function paragraphTests(CK: CanvasKit, p?: Paragraph) {
+ if (!p) return;
+ const a = p.didExceedMaxLines(); // $ExpectType boolean
+ const b = p.getAlphabeticBaseline(); // $ExpectType number
+ const c = p.getGlyphPositionAtCoordinate(10, 3); // $ExpectType PositionWithAffinity
+ const d = p.getHeight(); // $ExpectType number
+ const e = p.getIdeographicBaseline(); // $ExpectType number
+ const f = p.getLongestLine(); // $ExpectType number
+ const g = p.getMaxIntrinsicWidth(); // $ExpectType number
+ const h = p.getMaxWidth(); // $ExpectType number
+ const i = p.getMinIntrinsicWidth(); // $ExpectType number
+ const j = p.getRectsForPlaceholders(); // $ExpectType Float32Array
+ const k = p.getRectsForRange(2, 10, CK.RectHeightStyle.Max, // $ExpectType Float32Array
+ CK.RectWidthStyle.Tight);
+ const l = p.getWordBoundary(10); // $ExpectType URange
+ p.layout(300);
+ const m = p.getLineMetrics(); // $ExpectType LineMetrics[]
+ const n = CK.GlyphRunFlags.IsWhiteSpace === 1;
+}
+
+function paragraphBuilderTests(CK: CanvasKit, fontMgr?: FontMgr, paint?: Paint) {
+ if (!fontMgr || !paint) return;
+ const paraStyle = new CK.ParagraphStyle({ // $ExpectType ParagraphStyle
+ textStyle: {
+ color: CK.BLACK,
+ fontFamilies: ['Noto Serif'],
+ fontSize: 20,
+ },
+ textAlign: CK.TextAlign.Center,
+ maxLines: 8,
+ ellipsis: '.._.',
+ strutStyle: {
+ strutEnabled: true,
+ fontFamilies: ['Roboto'],
+ fontSize: 28,
+ heightMultiplier: 1.5,
+ forceStrutHeight: true,
+ },
+ disableHinting: true,
+ heightMultiplier: 2.5,
+ textDirection: CK.TextDirection.LTR,
+ textHeightBehavior: CK.TextHeightBehavior.DisableFirstAscent
+ });
+ const blueText = new CK.TextStyle({ // $ExpectType TextStyle
+ backgroundColor: CK.Color(234, 208, 232), // light pink
+ color: CK.Color(48, 37, 199),
+ fontFamilies: ['Noto Serif'],
+ decoration: CK.LineThroughDecoration,
+ decorationStyle: CK.DecorationStyle.Dashed,
+ decorationThickness: 1.5, // multiplier based on font size
+ fontSize: 24,
+ fontFeatures: [{name: 'smcp', value: 1}],
+ shadows: [{color: CK.BLACK, blurRadius: 15},
+ {color: CK.RED, blurRadius: 5, offset: [10, 10]}],
+ });
+
+ const builder = CK.ParagraphBuilder.Make(paraStyle, fontMgr); // $ExpectType ParagraphBuilder
+
+ builder.pushStyle(blueText);
+ builder.addText('VAVAVAVAVAVAVA\nVAVA\n');
+ builder.pop();
+ const paragraph = builder.build(); // $ExpectType Paragraph
+
+ const buf = new ArrayBuffer(10);
+ const fontSrc = CK.TypefaceFontProvider.Make(); // $ExpectType TypefaceFontProvider
+ fontSrc.registerFont(buf, 'sans-serif');
+ const builder2 = CK.ParagraphBuilder.MakeFromFontProvider(// $ExpectType ParagraphBuilder
+ paraStyle, fontSrc);
+ builder2.pushPaintStyle(blueText, paint, paint);
+ builder2.addPlaceholder();
+ builder2.addPlaceholder(10, 20, CK.PlaceholderAlignment.Top, CK.TextBaseline.Ideographic, 3);
+ builder2.reset();
+}
+
+function particlesTests(CK: CanvasKit, canvas?: Canvas) {
+ if (!canvas) return;
+
+ const par = CK.MakeParticles('some json'); // $ExpectType Particles
+ par.draw(canvas);
+ par.uniforms()[0] = 1.2;
+ const a = par.getUniform(1); // $ExpectType SkSLUniform
+ const b = par.getUniformCount(); // $ExpectType number
+ const c = par.getUniformFloatCount(); // $ExpectType number
+ const d = par.getUniformName(3); // $ExpectType string
+ par.uniforms()[2] = 4.5;
+ par.setPosition([3, 5]);
+ par.setRate(3);
+ par.start(0, true);
+ par.update(2);
+
+ const buff = new ArrayBuffer(10);
+ const par2 = CK.MakeParticles('other json', { // $ExpectType Particles
+ 'flightAnim.gif': buff,
+ });
+}
+
+function pathEffectTests(CK: CanvasKit, path?: Path) {
+ if (!path) {
+ return;
+ }
+ const pe1 = CK.PathEffect.MakeCorner(2); // $ExpectType PathEffect | null
+ const pe2 = CK.PathEffect.MakeDash([2, 4]); // $ExpectType PathEffect
+ const pe3 = CK.PathEffect.MakeDash([2, 4, 6, 8], 10); // $ExpectType PathEffect
+ const pe4 = CK.PathEffect.MakeDiscrete(10, 2, 0); // $ExpectType PathEffect
+ const pe5 = CK.PathEffect.MakePath1D(path, 3, 4, CK.Path1DEffect.Morph); // $ExpectType PathEffect | null
+ const matr = CK.Matrix.scaled(3, 2);
+ const pe6 = CK.PathEffect.MakePath2D(matr, path); // $ExpectType PathEffect | null
+ const pe7 = CK.PathEffect.MakeLine2D(3.2, matr); // $ExpectType PathEffect | null
+}
+
+function mallocTests(CK: CanvasKit) {
+ const mFoo = CK.Malloc(Float32Array, 5);
+ const mArray = mFoo.toTypedArray(); // $ExpectType TypedArray
+ mArray[3] = 1.7;
+ const mSubArray = mFoo.subarray(0, 2); // $ExpectType TypedArray
+ mSubArray[0] = 2;
+ CK.Free(mFoo);
+}
+
+function maskFilterTests(CK: CanvasKit) {
+ const mf = CK.MaskFilter.MakeBlur(CK.BlurStyle.Solid, 8, false); // $ExpectType MaskFilter
+}
+
+function matrixTests(CK: CanvasKit) {
+ const m33 = CK.Matrix; // less typing
+ const matrA = m33.identity(); // $ExpectType number[]
+ const matrB = m33.rotated(0.1); // $ExpectType number[]
+ const matrC = m33.rotated(0.1, 15, 20); // $ExpectType number[]
+ const matrD = m33.multiply(matrA, matrB); // $ExpectType number[]
+ const matrE = m33.multiply(matrA, matrB, matrC, matrB, matrA); // $ExpectType number[]
+ const matrF = m33.scaled(1, 2); // $ExpectType number[]
+ const matrG = m33.scaled(1, 2, 3, 4); // $ExpectType number[]
+ const matrH = m33.skewed(1, 2); // $ExpectType number[]
+ const matrI = m33.skewed(1, 2, 3, 4); // $ExpectType number[]
+ const matrJ = m33.translated(1, 2); // $ExpectType number[]
+ const matrK = m33.invert(matrJ);
+
+ const m44 = CK.M44;
+ const matr1 = m44.identity(); // $ExpectType number[]
+ const matr2 = m44.invert(matr1);
+ const matr3 = m44.lookat([1, 2, 3], [4, 5, 6], [7, 8, 9]); // $ExpectType number[]
+ const matr4 = m44.multiply(matr1, matr3); // $ExpectType number[]
+ const matr5 = m44.mustInvert(matr1); // $ExpectType number[]
+ const matr6 = m44.perspective(1, 8, 0.4); // $ExpectType number[]
+ const matr7 = m44.rc(matr6, 0, 3); // $ExpectType number
+ const matr8 = m44.rotated([2, 3, 4], -0.4); // $ExpectType number[]
+ const matr9 = m44.rotatedUnitSinCos([4, 3, 2], 0.9, 0.1); // $ExpectType number[]
+ const matr10 = m44.scaled([5, 5, 5]); // $ExpectType number[]
+ const matr11 = m44.setupCamera(CK.LTRBRect(1, 2, 3, 4), 0.4, {
+ eye: [0, 0, 1],
+ coa: [0, 0, 0],
+ up: [0, 1, 0],
+ near: 0.2,
+ far: 4,
+ angle: Math.PI / 12,
+ });
+ const matr12 = m44.translated([3, 2, 1]); // $ExpectType number[]
+ const matr13 = m44.transpose([4, 5, 8]); // $ExpectType number[]
+}
+
+function pictureTests(CK: CanvasKit) {
+ const recorder = new CK.PictureRecorder(); // $ExpectType PictureRecorder
+ const canvas = recorder.beginRecording(CK.LTRBRect(0, 0, 100, 100)); // $ExpectType Canvas
+ const pic = recorder.finishRecordingAsPicture(); // $ExpectType SkPicture
+ const bytes = pic.serialize(); // $ExpectType Uint8Array | null
+ const pic2 = CK.MakePicture(bytes!);
+ const shader1 = pic2!.makeShader(CK.TileMode.Clamp, CK.TileMode.Decal, CK.FilterMode.Nearest);
+ const shader2 = pic2!.makeShader(CK.TileMode.Clamp, CK.TileMode.Decal, CK.FilterMode.Nearest,
+ CK.Matrix.rotated(3));
+ const shader3 = pic2!.makeShader(CK.TileMode.Clamp, CK.TileMode.Decal, CK.FilterMode.Nearest,
+ CK.Matrix.skewed(2, 1), CK.LTRBRect(3, 4, 5, 6));
+}
+
+function rectangleTests(CK: CanvasKit) {
+ const rectOne = CK.LTRBRect(5, 10, 20, 30); // $ExpectType Float32Array
+ const rectTwo = CK.XYWHRect(5, 10, 15, 20); // $ExpectType Float32Array
+ const iRectOne = CK.LTRBiRect(105, 110, 120, 130); // $ExpectType Int32Array
+ const iRectTwo = CK.XYWHiRect(105, 110, 15, 20); // $ExpectType Int32Array
+ const rrectOne = CK.RRectXY(rectOne, 3, 7); // $ExpectType Float32Array
+}
+
+function runtimeEffectTests(CK: CanvasKit) {
+ const rt = CK.RuntimeEffect.Make('not real sksl code'); // $ExpectType RuntimeEffect | null
+ if (!rt) return;
+ const rt2 = CK.RuntimeEffect.Make('not real sksl code', (err) => {
+ console.log(err);
+ });
+ const someMatr = CK.Matrix.translated(2, 60);
+ const s1 = rt.makeShader([0, 1]); // $ExpectType Shader
+ const s2 = rt.makeShader([0, 1], someMatr); // $ExpectType Shader
+ const s3 = rt.makeShaderWithChildren([4, 5], [s1, s2]); // $ExpectType Shader
+ const s4 = rt.makeShaderWithChildren([4, 5], [s1, s2], someMatr); // $ExpectType Shader
+ const a = rt.getUniform(1); // $ExpectType SkSLUniform
+ const b = rt.getUniformCount(); // $ExpectType number
+ const c = rt.getUniformFloatCount(); // $ExpectType number
+ const d = rt.getUniformName(3); // $ExpectType string
+}
+
+function skottieTests(CK: CanvasKit, canvas?: Canvas) {
+ if (!canvas) return;
+
+ const anim = CK.MakeAnimation('some json'); // $ExpectType SkottieAnimation
+ const a = anim.duration(); // $ExpectType number
+ const b = anim.fps(); // $ExpectType number
+ const c = anim.version(); // $ExpectType string
+ const d = anim.size(); // $ExpectType Float32Array
+ anim.size(d);
+ const rect = anim.seek(0.5);
+ anim.seek(0.6, rect);
+ const rect2 = anim.seekFrame(12.3);
+ anim.seekFrame(12.3, rect2);
+ anim.render(canvas);
+ anim.render(canvas, rect);
+
+ const buff = new ArrayBuffer(10);
+ const mAnim = CK.MakeManagedAnimation('other json', { // $ExpectType ManagedSkottieAnimation
+ 'flightAnim.gif': buff,
+ });
+ mAnim.setColor('slider', CK.WHITE);
+ mAnim.setOpacity('slider', 0.8);
+ const e = mAnim.getMarkers(); // $ExpectType AnimationMarker[]
+ const f = mAnim.getColorProps(); // $ExpectType ColorProperty[]
+ const g = mAnim.getOpacityProps(); // $ExpectType OpacityProperty[]
+ const h = mAnim.getTextProps(); // $ExpectType TextProperty[]
+
+ const i = mAnim.setColor('foo', CK.RED); // $ExpectType boolean
+ const j = mAnim.setOpacity('foo', 0.5); // $ExpectType boolean
+ const k = mAnim.setText('foo', 'bar', 12); // $ExpectType boolean
+}
+
+function shaderTests(CK: CanvasKit) {
+ const s1 = CK.Shader.MakeColor([0.8, 0.2, 0.5, 0.9], // $ExpectType Shader
+ CK.ColorSpace.SRGB);
+ const s2 = CK.Shader.MakeBlend(CK.BlendMode.Src, s1, s1); // $ExpectType Shader
+ const s4 = CK.Shader.MakeLinearGradient(// $ExpectType Shader
+ [0, 0], [50, 100],
+ Float32Array.of(
+ 0, 1, 0, 0.8,
+ 1, 0, 0, 1,
+ 0, 0, 1, 0.5,
+ ),
+ [0, 0.65, 1.0],
+ CK.TileMode.Mirror
+ );
+ const s5 = CK.Shader.MakeLinearGradient(// $ExpectType Shader
+ [0, 0], [50, 100],
+ Float32Array.of(
+ 0, 1, 0, 0.8,
+ 1, 0, 0, 1,
+ 0, 0, 1, 0.5,
+ ),
+ null,
+ CK.TileMode.Clamp,
+ CK.Matrix.rotated(Math.PI / 4, 0, 100),
+ 1,
+ CK.ColorSpace.SRGB,
+ );
+ const s6 = CK.Shader.MakeRadialGradient(// $ExpectType Shader
+ [0, 0], 50,
+ Float32Array.of(
+ 0, 1, 0, 0.8,
+ 1, 0, 0, 1,
+ 0, 0, 1, 0.5,
+ ),
+ [0, 0.65, 1.0],
+ CK.TileMode.Decal,
+ );
+ const s7 = CK.Shader.MakeRadialGradient(// $ExpectType Shader
+ [0, 0], 50,
+ Float32Array.of(
+ 0, 1, 0, 0.8,
+ 1, 0, 0, 1,
+ 0, 0, 1, 0.5,
+ ),
+ null,
+ CK.TileMode.Clamp,
+ CK.Matrix.skewed(3, -3),
+ 1,
+ CK.ColorSpace.SRGB,
+ );
+ const s8 = CK.Shader.MakeTwoPointConicalGradient(// $ExpectType Shader
+ [0, 0], 20,
+ [50, 100], 60,
+ Float32Array.of(
+ 0, 1, 0, 0.8,
+ 1, 0, 0, 1,
+ 0, 0, 1, 0.5,
+ ),
+ [0, 0.65, 1.0],
+ CK.TileMode.Mirror
+ );
+ const s9 = CK.Shader.MakeTwoPointConicalGradient(// $ExpectType Shader
+ [0, 0], 20,
+ [50, 100], 60,
+ Float32Array.of(
+ 0, 1, 0, 0.8,
+ 1, 0, 0, 1,
+ 0, 0, 1, 0.5,
+ ),
+ [0, 0.65, 1.0],
+ CK.TileMode.Mirror,
+ CK.Matrix.rotated(Math.PI / 4, 0, 100),
+ 1,
+ CK.ColorSpace.SRGB,
+ );
+ const s10 = CK.Shader.MakeSweepGradient(// $ExpectType Shader
+ 0, 20,
+ Float32Array.of(
+ 0, 1, 0, 0.8,
+ 1, 0, 0, 1,
+ 0, 0, 1, 0.5,
+ ),
+ [0, 0.65, 1.0],
+ CK.TileMode.Mirror
+ );
+ const s11 = CK.Shader.MakeSweepGradient(// $ExpectType Shader
+ 0, 20,
+ Float32Array.of(
+ 0, 1, 0, 0.8,
+ 1, 0, 0, 1,
+ 0, 0, 1, 0.5,
+ ),
+ null,
+ CK.TileMode.Mirror,
+ CK.Matrix.rotated(Math.PI / 4, 0, 100),
+ 1,
+ 15, 275, // start, end angle in degrees.
+ CK.ColorSpace.SRGB,
+ );
+ const s12 = CK.Shader.MakeFractalNoise(0.1, 0.05, 2, 0, 80, 80); // $ExpectType Shader
+ const s13 = CK.Shader.MakeTurbulence(0.1, 0.05, 2, 0, 80, 80); // $ExpectType Shader
+}
+
+function surfaceTests(CK: CanvasKit, gl?: WebGLRenderingContext) {
+ if (!gl) {
+ return;
+ }
+ const canvasEl = document.querySelector('canvas') as HTMLCanvasElement;
+ const surfaceOne = CK.MakeCanvasSurface(canvasEl)!; // $ExpectType Surface
+ const surfaceTwo = CK.MakeCanvasSurface('my_canvas')!;
+ const surfaceThree = CK.MakeSWCanvasSurface(canvasEl)!; // $ExpectType Surface
+ const surfaceFour = CK.MakeSWCanvasSurface('my_canvas')!;
+ const surfaceFive = CK.MakeWebGLCanvasSurface(canvasEl, // $ExpectType Surface
+ CK.ColorSpace.SRGB, {
+ majorVersion: 2,
+ preferLowPowerToHighPerformance: 1,
+ })!;
+ const surfaceSix = CK.MakeWebGLCanvasSurface('my_canvas', CK.ColorSpace.DISPLAY_P3, {
+ enableExtensionsByDefault: 2,
+ })!;
+ const surfaceSeven = CK.MakeSurface(200, 200)!; // $ExpectType Surface
+ const m = CK.Malloc(Uint8Array, 5 * 5 * 4);
+ const surfaceEight = CK.MakeRasterDirectSurface({
+ width: 5,
+ height: 5,
+ colorType: CK.ColorType.RGBA_8888,
+ alphaType: CK.AlphaType.Premul,
+ colorSpace: CK.ColorSpace.SRGB,
+ }, m, 20);
+
+ surfaceOne.flush();
+ const canvas = surfaceTwo.getCanvas(); // $ExpectType Canvas
+ const ii = surfaceThree.imageInfo(); // $ExpectType ImageInfo
+ const h = surfaceFour.height(); // $ExpectType number
+ const w = surfaceFive.width(); // $ExpectType number
+ const subsurface = surfaceOne.makeSurface(ii); // $ExpectType Surface
+ const isGPU = subsurface.reportBackendTypeIsGPU(); // $ExpectType boolean
+ const count = surfaceThree.sampleCnt(); // $ExpectType number
+ const img = surfaceFour.makeImageSnapshot([0, 3, 2, 5]); // $ExpectType Image
+ const img2 = surfaceSix.makeImageSnapshot(); // $ExpectType Image
+ const img3 = surfaceFour.makeImageFromTexture(gl.createTexture()!, {
+ height: 40,
+ width: 80,
+ colorType: CK.ColorType.RGBA_8888,
+ alphaType: CK.AlphaType.Unpremul,
+ colorSpace: CK.ColorSpace.SRGB,
+ });
+ const img4 = surfaceFour.makeImageFromTextureSource(new Image()); // $ExpectType Image | null
+ const videoEle = document.createElement('video');
+ const img5 = surfaceFour.makeImageFromTextureSource(videoEle, {
+ height: 40,
+ width: 80,
+ colorType: CK.ColorType.RGBA_8888,
+ alphaType: CK.AlphaType.Unpremul,
+ });
+ const img6 = surfaceFour.makeImageFromTextureSource(new ImageData(40, 80)); // $ExpectType Image | null
+
+ surfaceSeven.delete();
+
+ const ctx = CK.GetWebGLContext(canvasEl); // $ExpectType number
+ CK.deleteContext(ctx);
+ const grCtx = CK.MakeGrContext(ctx);
+ const surfaceNine = CK.MakeOnScreenGLSurface(grCtx!, 100, 400, // $ExpectType Surface
+ CK.ColorSpace.ADOBE_RGB)!;
+
+ const rt = CK.MakeRenderTarget(grCtx!, 100, 200); // $ExpectType Surface | null
+ const rt2 = CK.MakeRenderTarget(grCtx!, { // $ExpectType Surface | null
+ width: 79,
+ height: 205,
+ colorType: CK.ColorType.RGBA_8888,
+ alphaType: CK.AlphaType.Premul,
+ colorSpace: CK.ColorSpace.SRGB,
+ });
+
+ const drawFrame = (canvas: Canvas) => {
+ canvas.clear([0, 0, 0, 0]);
+ };
+ surfaceFour.requestAnimationFrame(drawFrame);
+ surfaceFour.drawOnce(drawFrame);
+
+ surfaceFour.updateTextureFromSource(img5!, videoEle);
+}
+
+function textBlobTests(CK: CanvasKit, font?: Font, path?: Path) {
+ if (!font || !path) return;
+ const tb = CK.TextBlob; // less typing
+ const ids = font.getGlyphIDs('abc');
+ const mXforms = CK.Malloc(Float32Array, ids.length * 4);
+
+ const blob = tb.MakeFromGlyphs([5, 6, 7, 8], font); // $ExpectType TextBlob
+ const blob1 = tb.MakeFromGlyphs(ids, font); // $ExpectType TextBlob
+ const blob2 = tb.MakeFromRSXform('cdf', mXforms, font); // $ExpectType TextBlob
+ const blob3 = tb.MakeFromRSXform('c', [-1, 0, 2, 3], font); // $ExpectType TextBlob
+ const blob4 = tb.MakeFromRSXformGlyphs([3, 6], mXforms, font); // $ExpectType TextBlob
+ const blob5 = tb.MakeFromRSXformGlyphs(ids, [-1, 0, 2, 3], font); // $ExpectType TextBlob
+ const blob6 = tb.MakeFromText('xyz', font); // $ExpectType TextBlob
+ const blob7 = tb.MakeOnPath('tuv', path, font); // $ExpectType TextBlob
+ const blob8 = tb.MakeOnPath('tuv', path, font, 10); // $ExpectType TextBlob
+}
+
+function typefaceTests(CK: CanvasKit) {
+ const face = CK.Typeface.MakeFreeTypeFaceFromData(new ArrayBuffer(10));
+
+ const ids = face!.getGlyphIDs('abcd');
+ face!.getGlyphIDs('efgh', 4, ids);
+}
+
+function vectorTests(CK: CanvasKit) {
+ const a = [1, 2, 3];
+ const b = [4, 5, 6];
+
+ const vec = CK.Vector; // less typing
+ const v1 = vec.add(a, b); // $ExpectType VectorN
+ const v2 = vec.cross(a, b); // $ExpectType Vector3
+ const n1 = vec.dist(a, b); // $ExpectType number
+ const n2 = vec.dot(a, b); // $ExpectType number
+ const n3 = vec.length(a); // $ExpectType number
+ const n4 = vec.lengthSquared(a); // $ExpectType number
+ const v3 = vec.mulScalar(a, 10); // $ExpectType VectorN
+ const v4 = vec.normalize(a); // $ExpectType VectorN
+ const v5 = vec.sub(a, b); // $ExpectType VectorN
+}
+
+function verticesTests(CK: CanvasKit) {
+ const points = [
+ 70, 170, 40, 90, 130, 150, 100, 50,
+ 225, 150, 225, 60, 310, 180, 330, 100,
+ ];
+ const textureCoordinates = [
+ 0, 240, 0, 0, 80, 240, 80, 0,
+ 160, 240, 160, 0, 240, 240, 240, 0,
+ ];
+ const vertices = CK.MakeVertices(CK.VertexMode.TrianglesStrip, // $ExpectType Vertices
+ points, textureCoordinates);
+
+ const points2 = new Float32Array(points);
+ // 1d float color array
+ const colors = Float32Array.of(
+ 1, 0, 0, 1, // red
+ 0, 1, 0, 1, // green
+ 0, 0, 1, 1, // blue
+ 1, 0, 1, 1); // purple
+ const vertices2 = CK.MakeVertices(CK.VertexMode.TriangleFan,
+ points2, null, colors, null, true);
+
+ const rect = vertices.bounds(); // $ExpectType Float32Array
+ vertices.bounds(rect);
+ const id = vertices.uniqueID(); // $ExpectType number
+}
diff --git a/third_party/skia/modules/canvaskit/npm_build/types/index.d.ts b/third_party/skia/modules/canvaskit/npm_build/types/index.d.ts
new file mode 100644
index 0000000..3abbcc3
--- /dev/null
+++ b/third_party/skia/modules/canvaskit/npm_build/types/index.d.ts
@@ -0,0 +1,4173 @@
+// Minimum TypeScript Version: 3.7
+export function CanvasKitInit(opts: CanvasKitInitOptions): Promise<CanvasKit>;
+
+export interface CanvasKitInitOptions {
+ /**
+ * This callback will be invoked when the CanvasKit loader needs to fetch a file (e.g.
+ * the blob of WASM code). The correct url prefix should be applied.
+ * @param file - the name of the file that is about to be loaded.
+ */
+ locateFile(file: string): string;
+}
+
+export interface CanvasKit {
+ // Helpers
+ /**
+ * Constructs a Color with the same API as CSS's rgba(), that is
+ * Internally, Colors are four unpremultiplied 32-bit floats: r, g, b, a.
+ * In order to construct one with more precision or in a wider gamut,
+ * use CanvasKit.Color4f().
+ *
+ * @param r - red value, clamped to [0, 255].
+ * @param g - green value, clamped to [0, 255].
+ * @param b - blue value, clamped to [0, 255].
+ * @param a - alpha value, from 0 to 1.0. By default is 1.0 (opaque).
+ */
+ Color(r: number, g: number, b: number, a?: number): Color;
+
+ /**
+ * Construct a 4-float color. Float values are typically between 0.0 and 1.0.
+ * @param r - red value.
+ * @param g - green value.
+ * @param b - blue value.
+ * @param a - alpha value. By default is 1.0 (opaque).
+ */
+ Color4f(r: number, g: number, b: number, a?: number): Color;
+
+ /**
+ * Constructs a Color as a 32 bit unsigned integer, with 8 bits assigned to each channel.
+ * Channels are expected to be between 0 and 255 and will be clamped as such.
+ * If a is omitted, it will be 255 (opaque).
+ *
+ * This is not the preferred way to use colors in Skia APIs, use Color or Color4f.
+ * @param r - red value, clamped to [0, 255].
+ * @param g - green value, clamped to [0, 255].
+ * @param b - blue value, clamped to [0, 255].
+ * @param a - alpha value, from 0 to 1.0. By default is 1.0 (opaque).
+ */
+ ColorAsInt(r: number, g: number, b: number, a?: number): ColorInt;
+
+ /**
+ * Returns a css style [r, g, b, a] where r, g, b are returned as
+ * ints in the range [0, 255] and where a is scaled between 0 and 1.0.
+ * [Deprecated] - this is trivial now that Color is 4 floats.
+ */
+ getColorComponents(c: Color): number[];
+
+ /**
+ * Takes in a CSS color value and returns a CanvasKit.Color
+ * (which is an array of 4 floats in RGBA order). An optional colorMap
+ * may be provided which maps custom strings to values.
+ * In the CanvasKit canvas2d shim layer, we provide this map for processing
+ * canvas2d calls, but not here for code size reasons.
+ */
+ parseColorString(color: string, colorMap?: Record<string, Color>): Color;
+
+ /**
+ * Returns a copy of the passed in color with a new alpha value applied.
+ * [Deprecated] - this is trivial now that Color is 4 floats.
+ */
+ multiplyByAlpha(c: Color, alpha: number): Color;
+
+ /**
+ * Computes color values for one-pass tonal alpha.
+ * Note, if malloced colors are passed in, the memory pointed at by the MallocObj
+ * will be overwritten with the computed tonal colors (and thus the return val can be
+ * ignored).
+ * @param colors
+ */
+ computeTonalColors(colors: TonalColorsInput): TonalColorsOutput;
+
+ /**
+ * Returns a rectangle with the given paramaters. See Rect.h for more.
+ * @param left - The x coordinate of the upper-left corner.
+ * @param top - The y coordinate of the upper-left corner.
+ * @param right - The x coordinate of the lower-right corner.
+ * @param bottom - The y coordinate of the lower-right corner.
+ */
+ LTRBRect(left: number, top: number, right: number, bottom: number): Rect;
+
+ /**
+ * Returns a rectangle with the given paramaters. See Rect.h for more.
+ * @param x - The x coordinate of the upper-left corner.
+ * @param y - The y coordinate of the upper-left corner.
+ * @param width - The width of the rectangle.
+ * @param height - The height of the rectangle.
+ */
+ XYWHRect(x: number, y: number, width: number, height: number): Rect;
+
+ /**
+ * Returns a rectangle with the given integer paramaters. See Rect.h for more.
+ * @param left - The x coordinate of the upper-left corner.
+ * @param top - The y coordinate of the upper-left corner.
+ * @param right - The x coordinate of the lower-right corner.
+ * @param bottom - The y coordinate of the lower-right corner.
+ */
+ LTRBiRect(left: number, top: number, right: number, bottom: number): IRect;
+
+ /**
+ * Returns a rectangle with the given paramaters. See Rect.h for more.
+ * @param x - The x coordinate of the upper-left corner.
+ * @param y - The y coordinate of the upper-left corner.
+ * @param width - The width of the rectangle.
+ * @param height - The height of the rectangle.
+ */
+ XYWHiRect(x: number, y: number, width: number, height: number): IRect;
+
+ /**
+ * Returns a rectangle with rounded corners consisting of the given rectangle and
+ * the same radiusX and radiusY for all four corners.
+ * @param rect - The base rectangle.
+ * @param rx - The radius of the corners in the x direction.
+ * @param ry - The radius of the corners in the y direction.
+ */
+ RRectXY(rect: InputRect, rx: number, ry: number): RRect;
+
+ /**
+ * Generate bounding box for shadows relative to path. Includes both the ambient and spot
+ * shadow bounds. This pairs with Canvas.drawShadow().
+ * See SkShadowUtils.h for more details.
+ * @param ctm - Current transformation matrix to device space.
+ * @param path - The occluder used to generate the shadows.
+ * @param zPlaneParams - Values for the plane function which returns the Z offset of the
+ * occluder from the canvas based on local x and y values (the current
+ * matrix is not applied).
+ * @param lightPos - The 3D position of the light relative to the canvas plane. This is
+ * independent of the canvas's current matrix.
+ * @param lightRadius - The radius of the disc light.
+ * @param flags - See SkShadowFlags.h; 0 means use default options.
+ * @param dstRect - if provided, the bounds will be copied into this rect instead of allocating
+ * a new one.
+ * @returns The bounding rectangle or null if it could not be computed.
+ */
+ getShadowLocalBounds(ctm: InputMatrix, path: Path, zPlaneParams: InputVector3,
+ lightPos: InputVector3, lightRadius: number, flags: number,
+ dstRect?: Rect): Rect | null;
+
+ /**
+ * Malloc returns a TypedArray backed by the C++ memory of the
+ * given length. It should only be used by advanced users who
+ * can manage memory and initialize values properly. When used
+ * correctly, it can save copying of data between JS and C++.
+ * When used incorrectly, it can lead to memory leaks.
+ * Any memory allocated by CanvasKit.Malloc needs to be released with CanvasKit.Free.
+ *
+ * const mObj = CanvasKit.Malloc(Float32Array, 20);
+ * Get a TypedArray view around the malloc'd memory (this does not copy anything).
+ * const ta = mObj.toTypedArray();
+ * // store data into ta
+ * const cf = CanvasKit.ColorFilter.MakeMatrix(ta); // mObj could also be used.
+ *
+ * // eventually...
+ * CanvasKit.Free(mObj);
+ *
+ * @param typedArray - constructor for the typedArray.
+ * @param len - number of *elements* to store.
+ */
+ Malloc(typedArray: TypedArrayConstructor, len: number): MallocObj;
+
+ /**
+ * As Malloc but for GlyphIDs. This helper exists to make sure the JS side and the C++ side
+ * stay in agreement with how wide GlyphIDs are.
+ * @param len - number of GlyphIDs to make space for.
+ */
+ MallocGlyphIDs(len: number): MallocObj;
+
+ /**
+ * Free frees the memory returned by Malloc.
+ * Any memory allocated by CanvasKit.Malloc needs to be released with CanvasKit.Free.
+ */
+ Free(m: MallocObj): void;
+
+ // Surface related functions
+ /**
+ * Creates a Surface on a given canvas. If both GPU and CPU modes have been compiled in, this
+ * will first try to create a GPU surface and then fallback to a CPU one if that fails. If just
+ * the CPU mode has been compiled in, a CPU surface will be created.
+ * @param canvas - either the canvas element itself or a string with the DOM id of it.
+ */
+ MakeCanvasSurface(canvas: HTMLCanvasElement | string): Surface | null;
+
+ /**
+ * Creates a Raster (CPU) Surface that will draw into the provided Malloc'd buffer. This allows
+ * clients to efficiently be able to read the current pixels w/o having to copy.
+ * The length of pixels must be at least height * bytesPerRow bytes big.
+ * @param ii
+ * @param pixels
+ * @param bytesPerRow - How many bytes are per row. This is at least width * bytesPerColorType. For example,
+ * an 8888 ColorType has 4 bytes per pixel, so a 5 pixel wide 8888 surface needs at least
+ * 5 * 4 = 20 bytesPerRow. Some clients may have more than the usual to make the data line
+ * up with a particular multiple.
+ */
+ MakeRasterDirectSurface(ii: ImageInfo, pixels: MallocObj, bytesPerRow: number): Surface | null;
+
+ /**
+ * Creates a CPU backed (aka raster) surface.
+ * @param canvas - either the canvas element itself or a string with the DOM id of it.
+ */
+ MakeSWCanvasSurface(canvas: HTMLCanvasElement | string): Surface | null;
+
+ /**
+ * A helper for creating a WebGL backed (aka GPU) surface and falling back to a CPU surface if
+ * the GPU one cannot be created. This works for both WebGL 1 and WebGL 2.
+ * @param canvas - Either the canvas element itself or a string with the DOM id of it.
+ * @param colorSpace - One of the supported color spaces. Default is SRGB.
+ * @param opts - Options that will get passed to the creation of the WebGL context.
+ */
+ MakeWebGLCanvasSurface(canvas: HTMLCanvasElement | string, colorSpace?: ColorSpace,
+ opts?: WebGLOptions): Surface | null;
+
+ /**
+ * Returns a CPU backed surface with the given dimensions, an SRGB colorspace, Unpremul
+ * alphaType and 8888 color type. The pixels belonging to this surface will be in memory and
+ * not visible.
+ * @param width - number of pixels of the width of the drawable area.
+ * @param height - number of pixels of the height of the drawable area.
+ */
+ MakeSurface(width: number, height: number): Surface | null;
+
+ /**
+ * Creates a WebGL Context from the given canvas with the given options. If options are omitted,
+ * sensible defaults will be used.
+ * @param canvas
+ * @param opts
+ */
+ GetWebGLContext(canvas: HTMLCanvasElement, opts?: WebGLOptions): WebGLContextHandle;
+
+ /**
+ * Creates a GrDirectContext from the given WebGL Context.
+ * @param ctx
+ */
+ MakeGrContext(ctx: WebGLContextHandle): GrDirectContext | null;
+
+ /**
+ * Creates a Surface that will be drawn to the given GrDirectContext (and show up on screen).
+ * @param ctx
+ * @param width - number of pixels of the width of the visible area.
+ * @param height - number of pixels of the height of the visible area.
+ * @param colorSpace
+ */
+ MakeOnScreenGLSurface(ctx: GrDirectContext, width: number, height: number,
+ colorSpace: ColorSpace): Surface | null;
+
+ /**
+ * Returns a (non-visible) Surface on the GPU. It has the given dimensions and uses 8888
+ * color depth and premultiplied alpha. See Surface.h for more details.
+ * @param ctx
+ * @param width
+ * @param height
+ */
+ MakeRenderTarget(ctx: GrDirectContext, width: number, height: number): Surface | null;
+
+ /**
+ * Returns a (non-visible) Surface on the GPU. It has the settings provided by image info.
+ * See Surface.h for more details.
+ * @param ctx
+ * @param info
+ */
+ MakeRenderTarget(ctx: GrDirectContext, info: ImageInfo): Surface | null;
+
+ /**
+ * Returns a texture-backed image based on the content in src. It assumes the image is
+ * RGBA_8888, unpremul and SRGB. This image can be re-used across multiple surfaces.
+ *
+ * Not available for software-backed surfaces.
+ * @param src - CanvasKit will take ownership of the TextureSource and clean it up when
+ * the image is destroyed.
+ * @param info - If provided, will be used to determine the width/height/format of the
+ * source image. If not, sensible defaults will be used.
+ */
+ MakeLazyImageFromTextureSource(src: TextureSource, info?: ImageInfo | PartialImageInfo): Image;
+
+ /**
+ * Deletes the associated WebGLContext. Function not available on the CPU version.
+ * @param ctx
+ */
+ deleteContext(ctx: WebGLContextHandle): void;
+
+ /**
+ * Returns the max size of the global cache for bitmaps used by CanvasKit.
+ */
+ getDecodeCacheLimitBytes(): number;
+ /**
+ * Returns the current size of the global cache for bitmaps used by CanvasKit.
+ */
+ getDecodeCacheUsedBytes(): number;
+
+ /**
+ * Sets the max size of the global cache for bitmaps used by CanvasKit.
+ * @param size - number of bytes that can be used to cache bitmaps.
+ */
+ setDecodeCacheLimitBytes(size: number): void;
+
+ /**
+ * Decodes the given bytes into an animated image. Returns null if the bytes were invalid.
+ * The passed in bytes will be copied into the WASM heap, so the caller can dispose of them.
+ *
+ * The returned AnimatedImage will be "pointing to" the first frame, i.e. currentFrameDuration
+ * and makeImageAtCurrentFrame will be referring to the first frame.
+ * @param bytes
+ */
+ MakeAnimatedImageFromEncoded(bytes: Uint8Array | ArrayBuffer): AnimatedImage | null;
+
+ /**
+ * Returns an emulated Canvas2D of the given size.
+ * @param width
+ * @param height
+ */
+ MakeCanvas(width: number, height: number): EmulatedCanvas2D;
+
+ /**
+ * Returns an image with the given pixel data and format.
+ * Note that we will always make a copy of the pixel data, because of inconsistencies in
+ * behavior between GPU and CPU (i.e. the pixel data will be turned into a GPU texture and
+ * not modifiable after creation).
+ *
+ * @param info
+ * @param bytes - bytes representing the pixel data.
+ * @param bytesPerRow
+ */
+ MakeImage(info: ImageInfo, bytes: number[] | Uint8Array | Uint8ClampedArray,
+ bytesPerRow: number): Image | null;
+
+ /**
+ * Return an Image backed by the encoded data, but attempt to defer decoding until the image
+ * is actually used/drawn. This deferral allows the system to cache the result, either on the
+ * CPU or on the GPU, depending on where the image is drawn.
+ * This decoding uses the codecs that have been compiled into CanvasKit. If the bytes are
+ * invalid (or an unrecognized codec), null will be returned. See Image.h for more details.
+ * @param bytes
+ */
+ MakeImageFromEncoded(bytes: Uint8Array | ArrayBuffer): Image | null;
+
+ /**
+ * Returns an Image with the data from the provided CanvasImageSource (e.g. <img>). This will
+ * use the browser's built in codecs, in that src will be drawn to a canvas and then readback
+ * and placed into an Image.
+ * @param src
+ */
+ MakeImageFromCanvasImageSource(src: CanvasImageSource): Image;
+
+ /**
+ * Returns an SkPicture which has been serialized previously to the given bytes.
+ * @param bytes
+ */
+ MakePicture(bytes: Uint8Array | ArrayBuffer): SkPicture | null;
+
+ /**
+ * Returns an Vertices based on the given positions and optional parameters.
+ * See SkVertices.h (especially the Builder) for more details.
+ * @param mode
+ * @param positions
+ * @param textureCoordinates
+ * @param colors - either a list of int colors or a flattened color array.
+ * @param indices
+ * @param isVolatile
+ */
+ MakeVertices(mode: VertexMode, positions: InputFlattenedPointArray,
+ textureCoordinates?: InputFlattenedPointArray | null,
+ colors?: Float32Array | ColorIntArray | null, indices?: number[] | null,
+ isVolatile?: boolean): Vertices;
+
+ /**
+ * Returns a Skottie animation built from the provided json string.
+ * Requires that Skottie be compiled into CanvasKit.
+ * @param json
+ */
+ MakeAnimation(json: string): SkottieAnimation;
+
+ /**
+ * Returns a managed Skottie animation built from the provided json string and assets.
+ * Requires that Skottie be compiled into CanvasKit.
+ * @param json
+ * @param assets - a dictionary of named blobs: { key: ArrayBuffer, ... }
+ * @param filterPrefix - an optional string acting as a name filter for selecting "interesting"
+ * Lottie properties (surfaced in the embedded player controls)
+ * @param soundMap - an optional mapping of sound identifiers (strings) to AudioPlayers.
+ * Only needed if the animation supports sound.
+ */
+ MakeManagedAnimation(json: string, assets?: Record<string, ArrayBuffer>,
+ filterPrefix?: string, soundMap?: SoundMap): ManagedSkottieAnimation;
+
+ /**
+ * Returns a Particles effect built from the provided json string and assets.
+ * Requires that Particles be compiled into CanvasKit
+ * @param json
+ * @param assets
+ */
+ MakeParticles(json: string, assets?: Record<string, ArrayBuffer>): Particles;
+
+ // Constructors, i.e. things made with `new CanvasKit.Foo()`;
+ readonly ImageData: ImageDataConstructor;
+ readonly ParagraphStyle: ParagraphStyleConstructor;
+ readonly ContourMeasureIter: ContourMeasureIterConstructor;
+ readonly Font: FontConstructor;
+ readonly Paint: DefaultConstructor<Paint>;
+ readonly Path: PathConstructorAndFactory;
+ readonly PictureRecorder: DefaultConstructor<PictureRecorder>;
+ readonly TextStyle: TextStyleConstructor;
+
+ // Factories, i.e. things made with CanvasKit.Foo.MakeTurboEncabulator()
+ readonly ParagraphBuilder: ParagraphBuilderFactory;
+ readonly ColorFilter: ColorFilterFactory;
+ readonly FontMgr: FontMgrFactory;
+ readonly ImageFilter: ImageFilterFactory;
+ readonly MaskFilter: MaskFilterFactory;
+ readonly PathEffect: PathEffectFactory;
+ readonly RuntimeEffect: RuntimeEffectFactory;
+ readonly Shader: ShaderFactory;
+ readonly TextBlob: TextBlobFactory;
+ readonly Typeface: TypefaceFactory;
+ readonly TypefaceFontProvider: TypefaceFontProviderFactory;
+
+ // Misc
+ readonly ColorMatrix: ColorMatrixHelpers;
+ readonly Matrix: Matrix3x3Helpers;
+ readonly M44: Matrix4x4Helpers;
+ readonly Vector: VectorHelpers;
+
+ // Core Enums
+ readonly AlphaType: AlphaTypeEnumValues;
+ readonly BlendMode: BlendModeEnumValues;
+ readonly BlurStyle: BlurStyleEnumValues;
+ readonly ClipOp: ClipOpEnumValues;
+ readonly ColorType: ColorTypeEnumValues;
+ readonly FillType: FillTypeEnumValues;
+ readonly FilterMode: FilterModeEnumValues;
+ readonly FontEdging: FontEdgingEnumValues;
+ readonly FontHinting: FontHintingEnumValues;
+ readonly GlyphRunFlags: GlyphRunFlagValues;
+ readonly ImageFormat: ImageFormatEnumValues;
+ readonly MipmapMode: MipmapModeEnumValues;
+ readonly PaintStyle: PaintStyleEnumValues;
+ readonly Path1DEffect: Path1DEffectStyleEnumValues;
+ readonly PathOp: PathOpEnumValues;
+ readonly PointMode: PointModeEnumValues;
+ readonly ColorSpace: ColorSpaceEnumValues;
+ readonly StrokeCap: StrokeCapEnumValues;
+ readonly StrokeJoin: StrokeJoinEnumValues;
+ readonly TileMode: TileModeEnumValues;
+ readonly VertexMode: VertexModeEnumValues;
+
+ // Core Constants
+ readonly TRANSPARENT: Color;
+ readonly BLACK: Color;
+ readonly WHITE: Color;
+ readonly RED: Color;
+ readonly GREEN: Color;
+ readonly BLUE: Color;
+ readonly YELLOW: Color;
+ readonly CYAN: Color;
+ readonly MAGENTA: Color;
+
+ readonly MOVE_VERB: number;
+ readonly LINE_VERB: number;
+ readonly QUAD_VERB: number;
+ readonly CONIC_VERB: number;
+ readonly CUBIC_VERB: number;
+ readonly CLOSE_VERB: number;
+
+ readonly SaveLayerInitWithPrevious: SaveLayerFlag;
+ readonly SaveLayerF16ColorType: SaveLayerFlag;
+
+ /**
+ * Use this shadow flag to indicate the occluding object is not opaque. Knowing that the
+ * occluder is opaque allows us to cull shadow geometry behind it and improve performance.
+ */
+ readonly ShadowTransparentOccluder: number;
+ /**
+ * Use this shadow flag to not use analytic shadows.
+ */
+ readonly ShadowGeometricOnly: number;
+ /**
+ * Use this shadow flag to indicate the light position represents a direction and light radius
+ * is blur radius at elevation 1.
+ */
+ readonly ShadowDirectionalLight: number;
+
+ readonly gpu?: boolean; // true if GPU code was compiled in
+ readonly managed_skottie?: boolean; // true if advanced (managed) Skottie code was compiled in
+ readonly particles?: boolean; // true if Particles code was compiled in
+ readonly rt_effect?: boolean; // true if RuntimeEffect was compiled in
+ readonly skottie?: boolean; // true if base Skottie code was compiled in
+
+ // Paragraph Enums
+ readonly Affinity: AffinityEnumValues;
+ readonly DecorationStyle: DecorationStyleEnumValues;
+ readonly FontSlant: FontSlantEnumValues;
+ readonly FontWeight: FontWeightEnumValues;
+ readonly FontWidth: FontWidthEnumValues;
+ readonly PlaceholderAlignment: PlaceholderAlignmentEnumValues;
+ readonly RectHeightStyle: RectHeightStyleEnumValues;
+ readonly RectWidthStyle: RectWidthStyleEnumValues;
+ readonly TextAlign: TextAlignEnumValues;
+ readonly TextBaseline: TextBaselineEnumValues;
+ readonly TextDirection: TextDirectionEnumValues;
+ readonly TextHeightBehavior: TextHeightBehaviorEnumValues;
+
+ // Paragraph Constants
+ readonly NoDecoration: number;
+ readonly UnderlineDecoration: number;
+ readonly OverlineDecoration: number;
+ readonly LineThroughDecoration: number;
+}
+
+export interface Camera {
+ /** a 3d point locating the camera. */
+ eye: Vector3;
+ /** center of attention - the 3d point the camera is looking at. */
+ coa: Vector3;
+ /**
+ * A unit vector pointing the cameras up direction. Note that using only eye and coa
+ * would leave the roll of the camera unspecified.
+ */
+ up: Vector3;
+ /** near clipping plane distance */
+ near: number;
+ /** far clipping plane distance */
+ far: number;
+ /** field of view in radians */
+ angle: AngleInRadians;
+}
+
+/**
+ * CanvasKit is built with Emscripten and Embind. Embind adds the following methods to all objects
+ * that are exposed with it.
+ */
+export interface EmbindObject<T extends EmbindObject<T>> {
+ clone(): T;
+ delete(): void;
+ deleteLater(): void;
+ isAliasOf(other: any): boolean;
+ isDeleted(): boolean;
+}
+
+/**
+ * Represents the set of enum values.
+ */
+export interface EmbindEnum {
+ readonly values: number[];
+}
+
+/**
+ * Represents a single member of an enum.
+ */
+export interface EmbindEnumEntity {
+ readonly value: number;
+}
+
+export interface EmulatedCanvas2D {
+ /**
+ * Cleans up all resources associated with this emulated canvas.
+ */
+ dispose(): void;
+ /**
+ * Decodes an image with the given bytes.
+ * @param bytes
+ */
+ decodeImage(bytes: ArrayBuffer | Uint8Array): Image;
+
+ /**
+ * Returns an emulated canvas2d context if type == '2d', null otherwise.
+ * @param type
+ */
+ getContext(type: string): EmulatedCanvas2DContext | null;
+
+ /**
+ * Loads the given font with the given descriptors. Emulates new FontFace().
+ * @param bytes
+ * @param descriptors
+ */
+ loadFont(bytes: ArrayBuffer | Uint8Array, descriptors: Record<string, string>): void;
+
+ /**
+ * Returns an new emulated Path2D object.
+ * @param str - an SVG string representing a path.
+ */
+ makePath2D(str?: string): EmulatedPath2D;
+
+ /**
+ * Returns the current canvas as a base64 encoded image string.
+ * @param codec - image/png by default; image/jpeg also supported.
+ * @param quality
+ */
+ toDataURL(codec?: string, quality?: number): string;
+}
+
+/** Part of the Canvas2D emulation code */
+export type EmulatedCanvas2DContext = CanvasRenderingContext2D;
+export type EmulatedImageData = ImageData;
+export type EmulatedPath2D = Path2D;
+
+export interface FontStyle {
+ weight?: FontWeight;
+ width?: FontWidth;
+ slant?: FontSlant;
+}
+
+/**
+ * See GrDirectContext.h for more on this class.
+ */
+export interface GrDirectContext extends EmbindObject<GrDirectContext> {
+ getResourceCacheLimitBytes(): number;
+ getResourceCacheUsageBytes(): number;
+ releaseResourcesAndAbandonContext(): void;
+ setResourceCacheLimitBytes(bytes: number): void;
+}
+
+/**
+ * See Metrics.h for more on this struct.
+ */
+export interface LineMetrics {
+ /** The index in the text buffer the line begins. */
+ startIndex: number;
+ /** The index in the text buffer the line ends. */
+ endIndex: number;
+ endExcludingWhitespaces: number;
+ endIncludingNewline: number;
+ /** True if the line ends in a hard break (e.g. newline) */
+ isHardBreak: boolean;
+ /**
+ * The final computed ascent for the line. This can be impacted by
+ * the strut, height, scaling, as well as outlying runs that are very tall.
+ */
+ ascent: number;
+ /**
+ * The final computed descent for the line. This can be impacted by
+ * the strut, height, scaling, as well as outlying runs that are very tall.
+ */
+ descent: number;
+ /** round(ascent + descent) */
+ height: number;
+ /** width of the line */
+ width: number;
+ /** The left edge of the line. The right edge can be obtained with `left + width` */
+ left: number;
+ /** The y position of the baseline for this line from the top of the paragraph. */
+ baseline: number;
+ /** Zero indexed line number. */
+ lineNumber: number;
+}
+
+export interface Range {
+ first: number;
+ last: number;
+}
+
+/**
+ * Information for a run of shaped text. See Paragraph.getShapedLines()
+ *
+ * Notes:
+ * positions is documented as Float32, but it holds twice as many as you expect, and they
+ * are treated logically as pairs of floats: {x0, y0}, {x1, y1}, ... for each glyph.
+ *
+ * positions and offsets arrays have 1 extra slot (actually 2 for positions)
+ * to describe the location "after" the last glyph in the glyphs array.
+ */
+export interface GlyphRun {
+ typeface: Typeface; // currently set to null (temporary)
+ size: number;
+ fakeBold: boolean;
+ fakeItalic: boolean;
+
+ glyphs: Uint16Array;
+ positions: Float32Array; // alternating x0, y0, x1, y1, ...
+ offsets: Uint32Array;
+ flags: number; // see GlyphRunFlags
+}
+
+/**
+ * Information for a paragraph of text. See Paragraph.getShapedLines()
+ */
+ export interface ShapedLine {
+ textRange: Range; // first and last character offsets for the line (derived from runs[])
+ top: number; // top y-coordinate for the line
+ bottom: number; // bottom y-coordinate for the line
+ baseline: number; // baseline y-coordinate for the line
+ runs: GlyphRun[]; // array of GlyphRun objects for the line
+}
+
+/**
+ * Input to ShapeText(..., FontBlock[], ...);
+ */
+export interface FontBlock {
+ length: number; // number of text codepoints this block is applied to
+
+ typeface: Typeface;
+ size: number;
+ fakeBold: boolean;
+ fakeItalic: boolean;
+}
+
+/**
+ * This object is a wrapper around a pointer to some memory on the WASM heap. The type of the
+ * pointer was determined at creation time.
+ */
+export interface MallocObj {
+ /**
+ * The number of objects this pointer refers to.
+ */
+ readonly length: number;
+ /**
+ * The "pointer" into the WASM memory. Should be fixed over the lifetime of the object.
+ */
+ readonly byteOffset: number;
+ /**
+ * Return a read/write view into a subset of the memory. Do not cache the TypedArray this
+ * returns, it may be invalidated if the WASM heap is resized. This is the same as calling
+ * .toTypedArray().subarray() except the returned TypedArray can also be passed into an API
+ * and not cause an additional copy.
+ */
+ subarray(start: number, end: number): TypedArray;
+ /**
+ * Return a read/write view of the memory. Do not cache the TypedArray this returns, it may be
+ * invalidated if the WASM heap is resized. If this TypedArray is passed into a CanvasKit API,
+ * it will not be copied again, only the pointer will be re-used.
+ */
+ toTypedArray(): TypedArray;
+}
+
+/**
+ * This represents a subset of an animation's duration.
+ */
+export interface AnimationMarker {
+ name: string;
+ t0: number; // 0.0 to 1.0
+ t1: number; // 0.0 to 1.0
+}
+
+/**
+ * This object maintains a single audio layer during skottie playback
+ */
+export interface AudioPlayer {
+ /**
+ * Playback control callback, emitted for each corresponding Animation::seek().
+ *
+ * Will seek to time t (seconds) relative to the layer's timeline origin.
+ * Negative t values are used to signal off state (stop playback outside layer span).
+ */
+ seek(t: number): void;
+}
+
+/**
+ * Mapping of sound names (strings) to AudioPlayers
+ */
+export interface SoundMap {
+ /**
+ * Returns AudioPlayer for a certain audio layer
+ * @param key string identifier, name of audio file the desired AudioPlayer manages
+ */
+ getPlayer(key: string): AudioPlayer;
+}
+
+/**
+ * Named color property.
+ */
+export interface ColorProperty {
+ /**
+ * Property identifier, usually the node name.
+ */
+ key: string;
+ /**
+ * Property value (RGBA, 255-based).
+ */
+ value: ColorInt;
+}
+
+/**
+ * Named opacity property.
+ */
+export interface OpacityProperty {
+ /**
+ * Property identifier, usually the node name.
+ */
+ key: string;
+ /**
+ * Property value (0..100).
+ */
+ value: number;
+}
+
+/**
+ * Text property value.
+ */
+export interface TextValue {
+ /**
+ * The text string payload.
+ */
+ text: string;
+ /**
+ * Font size.
+ */
+ size: number;
+}
+
+/**
+ * Named text property.
+ */
+export interface TextProperty {
+ /**
+ * Property identifier, usually the node name.
+ */
+ key: string;
+ /**
+ * Property value.
+ */
+ value: TextValue;
+}
+
+export interface ManagedSkottieAnimation extends SkottieAnimation {
+ setColor(key: string, color: InputColor): boolean;
+ setOpacity(key: string, opacity: number): boolean;
+ setText(key: string, text: string, size: number): boolean;
+ getMarkers(): AnimationMarker[];
+ getColorProps(): ColorProperty[];
+ getOpacityProps(): OpacityProperty[];
+ getTextProps(): TextProperty[];
+}
+
+/**
+ * See Paragraph.h for more information on this class. This is only available if Paragraph has
+ * been compiled in.
+ */
+export interface Paragraph extends EmbindObject<Paragraph> {
+ didExceedMaxLines(): boolean;
+ getAlphabeticBaseline(): number;
+
+ /**
+ * Returns the index of the glyph that corresponds to the provided coordinate,
+ * with the top left corner as the origin, and +y direction as down.
+ */
+ getGlyphPositionAtCoordinate(dx: number, dy: number): PositionWithAffinity;
+
+ getHeight(): number;
+ getIdeographicBaseline(): number;
+ getLineMetrics(): LineMetrics[];
+ getLongestLine(): number;
+ getMaxIntrinsicWidth(): number;
+ getMaxWidth(): number;
+ getMinIntrinsicWidth(): number;
+ getRectsForPlaceholders(): FlattenedRectangleArray;
+
+ /**
+ * Returns bounding boxes that enclose all text in the range of glpyh indexes [start, end).
+ * @param start
+ * @param end
+ * @param hStyle
+ * @param wStyle
+ */
+ getRectsForRange(start: number, end: number, hStyle: RectHeightStyle,
+ wStyle: RectWidthStyle): FlattenedRectangleArray;
+
+ /**
+ * Finds the first and last glyphs that define a word containing the glyph at index offset.
+ * @param offset
+ */
+ getWordBoundary(offset: number): URange;
+
+ /**
+ * Returns an array of ShapedLine objects, describing the paragraph.
+ */
+ getShapedLines(): ShapedLine[];
+
+ /**
+ * Lays out the text in the paragraph so it is wrapped to the given width.
+ * @param width
+ */
+ layout(width: number): void;
+}
+
+export interface ParagraphBuilder extends EmbindObject<ParagraphBuilder> {
+ /**
+ * Pushes the information required to leave an open space.
+ * @param width
+ * @param height
+ * @param alignment
+ * @param baseline
+ * @param offset
+ */
+ addPlaceholder(width?: number, height?: number, alignment?: PlaceholderAlignment,
+ baseline?: TextBaseline, offset?: number): void;
+
+ /**
+ * Adds text to the builder. Forms the proper runs to use the upper-most style
+ * on the style_stack.
+ * @param str
+ */
+ addText(str: string): void;
+
+ /**
+ * Returns a Paragraph object that can be used to be layout and paint the text to an
+ * Canvas.
+ */
+ build(): Paragraph;
+
+ /**
+ * Remove a style from the stack. Useful to apply different styles to chunks
+ * of text such as bolding.
+ */
+ pop(): void;
+
+ /**
+ * Push a style to the stack. The corresponding text added with addText will
+ * use the top-most style.
+ * @param text
+ */
+ pushStyle(text: TextStyle): void;
+
+ /**
+ * Pushes a TextStyle using paints instead of colors for foreground and background.
+ * @param textStyle
+ * @param fg
+ * @param bg
+ */
+ pushPaintStyle(textStyle: TextStyle, fg: Paint, bg: Paint): void;
+
+ /**
+ * Resets this builder to its initial state, discarding any text, styles, placeholders that have
+ * been added, but keeping the initial ParagraphStyle.
+ */
+ reset(): void;
+}
+
+export interface ParagraphStyle {
+ disableHinting?: boolean;
+ ellipsis?: string;
+ heightMultiplier?: number;
+ maxLines?: number;
+ strutStyle?: StrutStyle;
+ textAlign?: TextAlign;
+ textDirection?: TextDirection;
+ textHeightBehavior?: TextHeightBehavior;
+ textStyle?: TextStyle;
+}
+
+export interface PositionWithAffinity {
+ pos: number;
+ affinity: Affinity;
+}
+
+/**
+ * See SkParticleEffect.h for more details.
+ */
+export interface Particles extends EmbindObject<Particles> {
+ /**
+ * Draws the current state of the particles on the given canvas.
+ * @param canvas
+ */
+ draw(canvas: Canvas): void;
+
+ /**
+ * Returns a Float32Array bound to the WASM memory of these uniforms. Changing these
+ * floats will change the corresponding uniforms instantly.
+ */
+ uniforms(): Float32Array;
+
+ /**
+ * Returns the nth uniform from the effect.
+ * @param index
+ */
+ getUniform(index: number): SkSLUniform;
+
+ /**
+ * Returns the number of uniforms on the effect.
+ */
+ getUniformCount(): number;
+
+ /**
+ * Returns the total number of floats across all uniforms on the effect. This is the length
+ * of the array returned by `uniforms()`. For example, an effect with a single float3 uniform,
+ * would return 1 from `getUniformCount()`, but 3 from `getUniformFloatCount()`.
+ */
+ getUniformFloatCount(): number;
+
+ /**
+ * Returns the name of the nth effect uniform.
+ * @param index
+ */
+ getUniformName(index: number): string;
+
+ /**
+ * Sets the base position of the effect.
+ * @param point
+ */
+ setPosition(point: InputPoint): void;
+
+ /**
+ * Sets the base rate of the effect.
+ * @param rate
+ */
+ setRate(rate: number): void;
+
+ /**
+ * Starts playing the effect.
+ * @param now
+ * @param looping
+ */
+ start(now: number, looping: boolean): void;
+
+ /**
+ * Updates the effect using the new time.
+ * @param now
+ */
+ update(now: number): void;
+}
+
+export interface SkSLUniform {
+ columns: number;
+ rows: number;
+ /** The index into the uniforms array that this uniform begins. */
+ slot: number;
+}
+
+/**
+ * See SkAnimatedImage.h for more information on this class.
+ */
+export interface AnimatedImage extends EmbindObject<AnimatedImage> {
+ /**
+ * Returns the length of the current frame in ms.
+ */
+ currentFrameDuration(): number;
+ /**
+ * Decodes the next frame. Returns the length of that new frame in ms.
+ * Returns -1 when the animation is on the last frame.
+ */
+ decodeNextFrame(): number;
+
+ /**
+ * Return the total number of frames in the animation.
+ */
+ getFrameCount(): number;
+
+ /**
+ * Return the repetition count for this animation.
+ */
+ getRepetitionCount(): number;
+
+ /**
+ * Returns the possibly scaled height of the image.
+ */
+ height(): number;
+
+ /**
+ * Returns a still image of the current frame or null if there is no current frame.
+ */
+ makeImageAtCurrentFrame(): Image | null;
+
+ /**
+ * Reset the animation to the beginning.
+ */
+ reset(): void;
+
+ /**
+ * Returns the possibly scaled width of the image.
+ */
+ width(): number;
+}
+
+/**
+ * See SkCanvas.h for more information on this class.
+ */
+export interface Canvas extends EmbindObject<Canvas> {
+ /**
+ * Fills the current clip with the given color using Src BlendMode.
+ * This has the effect of replacing all pixels contained by clip with color.
+ * @param color
+ */
+ clear(color: InputColor): void;
+
+ /**
+ * Replaces clip with the intersection or difference of the current clip and path,
+ * with an aliased or anti-aliased clip edge.
+ * @param path
+ * @param op
+ * @param doAntiAlias
+ */
+ clipPath(path: Path, op: ClipOp, doAntiAlias: boolean): void;
+
+ /**
+ * Replaces clip with the intersection or difference of the current clip and rect,
+ * with an aliased or anti-aliased clip edge.
+ * @param rect
+ * @param op
+ * @param doAntiAlias
+ */
+ clipRect(rect: InputRect, op: ClipOp, doAntiAlias: boolean): void;
+
+ /**
+ * Replaces clip with the intersection or difference of the current clip and rrect,
+ * with an aliased or anti-aliased clip edge.
+ * @param rrect
+ * @param op
+ * @param doAntiAlias
+ */
+ clipRRect(rrect: InputRRect, op: ClipOp, doAntiAlias: boolean): void;
+
+ /**
+ * Replaces current matrix with m premultiplied with the existing matrix.
+ * @param m
+ */
+ concat(m: InputMatrix): void;
+
+ /**
+ * Draws arc using clip, Matrix, and Paint paint.
+ *
+ * Arc is part of oval bounded by oval, sweeping from startAngle to startAngle plus
+ * sweepAngle. startAngle and sweepAngle are in degrees.
+ * @param oval - bounds of oval containing arc to draw
+ * @param startAngle - angle in degrees where arc begins
+ * @param sweepAngle - sweep angle in degrees; positive is clockwise
+ * @param useCenter - if true, include the center of the oval
+ * @param paint
+ */
+ drawArc(oval: InputRect, startAngle: AngleInDegrees, sweepAngle: AngleInDegrees,
+ useCenter: boolean, paint: Paint): void;
+
+ /**
+ * Draws a set of sprites from atlas, using clip, Matrix, and optional Paint paint.
+ * @param atlas - Image containing sprites
+ * @param srcRects - Rect locations of sprites in atlas
+ * @param dstXforms - RSXform mappings for sprites in atlas
+ * @param paint
+ * @param blendMode - BlendMode combining colors and sprites
+ * @param colors - If provided, will be blended with sprite using blendMode.
+ * @param sampling - Specifies sampling options. If null, bilinear is used.
+ */
+ drawAtlas(atlas: Image, srcRects: InputFlattenedRectangleArray,
+ dstXforms: InputFlattenedRSXFormArray, paint: Paint,
+ blendMode?: BlendMode | null, colors?: ColorIntArray | null,
+ sampling?: CubicResampler | FilterOptions): void;
+
+ /**
+ * Draws a circle at (cx, cy) with the given radius.
+ * @param cx
+ * @param cy
+ * @param radius
+ * @param paint
+ */
+ drawCircle(cx: number, cy: number, radius: number, paint: Paint): void;
+
+ /**
+ * Fills clip with the given color.
+ * @param color
+ * @param blendMode - defaults to SrcOver.
+ */
+ drawColor(color: InputColor, blendMode?: BlendMode): void;
+
+ /**
+ * Fills clip with the given color.
+ * @param r - red value (typically from 0 to 1.0).
+ * @param g - green value (typically from 0 to 1.0).
+ * @param b - blue value (typically from 0 to 1.0).
+ * @param a - alpha value, range 0 to 1.0 (1.0 is opaque).
+ * @param blendMode - defaults to SrcOver.
+ */
+ drawColorComponents(r: number, g: number, b: number, a: number, blendMode?: BlendMode): void;
+
+ /**
+ * Fills clip with the given color.
+ * @param color
+ * @param blendMode - defaults to SrcOver.
+ */
+ drawColorInt(color: ColorInt, blendMode?: BlendMode): void;
+
+ /**
+ * Draws RRect outer and inner using clip, Matrix, and Paint paint.
+ * outer must contain inner or the drawing is undefined.
+ * @param outer
+ * @param inner
+ * @param paint
+ */
+ drawDRRect(outer: InputRRect, inner: InputRRect, paint: Paint): void;
+
+ /**
+ * Draws a run of glyphs, at corresponding positions, in a given font.
+ * @param glyphs the array of glyph IDs (Uint16TypedArray)
+ * @param positions the array of x,y floats to position each glyph
+ * @param x x-coordinate of the origin of the entire run
+ * @param y y-coordinate of the origin of the entire run
+ * @param font the font that contains the glyphs
+ * @param paint
+ */
+ drawGlyphs(glyphs: InputGlyphIDArray,
+ positions: InputFlattenedPointArray,
+ x: number, y: number,
+ font: Font, paint: Paint): void;
+
+ /**
+ * Draws the given image with its top-left corner at (left, top) using the current clip,
+ * the current matrix, and optionally-provided paint.
+ * @param img
+ * @param left
+ * @param top
+ * @param paint
+ */
+ drawImage(img: Image, left: number, top: number, paint?: Paint | null): void;
+
+ /**
+ * Draws the given image with its top-left corner at (left, top) using the current clip,
+ * the current matrix. It will use the cubic sampling options B and C if necessary.
+ * @param img
+ * @param left
+ * @param top
+ * @param B - See CubicResampler in SkSamplingOptions.h for more information
+ * @param C - See CubicResampler in SkSamplingOptions.h for more information
+ * @param paint
+ */
+ drawImageCubic(img: Image, left: number, top: number, B: number, C: number,
+ paint?: Paint | null): void;
+
+ /**
+ * Draws the given image with its top-left corner at (left, top) using the current clip,
+ * the current matrix. It will use the provided sampling options if necessary.
+ * @param img
+ * @param left
+ * @param top
+ * @param fm - The filter mode.
+ * @param mm - The mipmap mode. Note: for settings other than None, the image must have mipmaps
+ * calculated with makeCopyWithDefaultMipmaps;
+ * @param paint
+ */
+ drawImageOptions(img: Image, left: number, top: number, fm: FilterMode,
+ mm: MipmapMode, paint?: Paint | null): void;
+
+ /**
+ * Draws the provided image stretched proportionally to fit into dst rectangle.
+ * The center rectangle divides the image into nine sections: four sides, four corners, and
+ * the center.
+ * @param img
+ * @param center
+ * @param dest
+ * @param filter - what technique to use when sampling the image
+ * @param paint
+ */
+ drawImageNine(img: Image, center: InputIRect, dest: InputRect, filter: FilterMode,
+ paint?: Paint | null): void;
+
+ /**
+ * Draws sub-rectangle src from provided image, scaled and translated to fill dst rectangle.
+ * @param img
+ * @param src
+ * @param dest
+ * @param paint
+ * @param fastSample - if false, will filter strictly within src.
+ */
+ drawImageRect(img: Image, src: InputRect, dest: InputRect, paint: Paint,
+ fastSample?: boolean): void;
+
+ /**
+ * Draws sub-rectangle src from provided image, scaled and translated to fill dst rectangle.
+ * It will use the cubic sampling options B and C if necessary.
+ * @param img
+ * @param src
+ * @param dest
+ * @param B - See CubicResampler in SkSamplingOptions.h for more information
+ * @param C - See CubicResampler in SkSamplingOptions.h for more information
+ * @param paint
+ */
+ drawImageRectCubic(img: Image, src: InputRect, dest: InputRect,
+ B: number, C: number, paint?: Paint | null): void;
+
+ /**
+ * Draws sub-rectangle src from provided image, scaled and translated to fill dst rectangle.
+ * It will use the provided sampling options if necessary.
+ * @param img
+ * @param src
+ * @param dest
+ * @param fm - The filter mode.
+ * @param mm - The mipmap mode. Note: for settings other than None, the image must have mipmaps
+ * calculated with makeCopyWithDefaultMipmaps;
+ * @param paint
+ */
+ drawImageRectOptions(img: Image, src: InputRect, dest: InputRect, fm: FilterMode,
+ mm: MipmapMode, paint?: Paint | null): void;
+
+ /**
+ * Draws line segment from (x0, y0) to (x1, y1) using the current clip, current matrix,
+ * and the provided paint.
+ * @param x0
+ * @param y0
+ * @param x1
+ * @param y1
+ * @param paint
+ */
+ drawLine(x0: number, y0: number, x1: number, y1: number, paint: Paint): void;
+
+ /**
+ * Draws an oval bounded by the given rectangle using the current clip, current matrix,
+ * and the provided paint.
+ * @param oval
+ * @param paint
+ */
+ drawOval(oval: InputRect, paint: Paint): void;
+
+ /**
+ * Fills clip with the given paint.
+ * @param paint
+ */
+ drawPaint(paint: Paint): void;
+
+ /**
+ * Draws the given Paragraph at the provided coordinates.
+ * Requires the Paragraph code to be compiled in.
+ * @param p
+ * @param x
+ * @param y
+ */
+ drawParagraph(p: Paragraph, x: number, y: number): void;
+
+ /**
+ * Draws the given path using the current clip, current matrix, and the provided paint.
+ * @param path
+ * @param paint
+ */
+ drawPath(path: Path, paint: Paint): void;
+
+ /**
+ * Draws a cubic patch defined by 12 control points [top, right, bottom, left] with optional
+ * colors and shader-coordinates [4] specifed for each corner [top-left, top-right, bottom-right, bottom-left]
+ * @param cubics 12 points : 4 connected cubics specifying the boundary of the patch
+ * @param colors optional colors interpolated across the patch
+ * @param texs optional shader coordinates interpolated across the patch
+ * @param mode Specifies how shader and colors blend (if both are specified)
+ * @param paint
+ */
+ drawPatch(cubics: InputFlattenedPointArray,
+ colors?: ColorIntArray | Color[] | null,
+ texs?: InputFlattenedPointArray | null,
+ mode?: BlendMode | null,
+ paint?: Paint): void;
+
+ /**
+ * Draws the given picture using the current clip, current matrix, and the provided paint.
+ * @param skp
+ */
+ drawPicture(skp: SkPicture): void;
+
+ /**
+ * Draws the given points using the current clip, current matrix, and the provided paint.
+ *
+ * See Canvas.h for more on the mode and its interaction with paint.
+ * @param mode
+ * @param points
+ * @param paint
+ */
+ drawPoints(mode: PointMode, points: InputFlattenedPointArray, paint: Paint): void;
+
+ /**
+ * Draws the given rectangle using the current clip, current matrix, and the provided paint.
+ * @param rect
+ * @param paint
+ */
+ drawRect(rect: InputRect, paint: Paint): void;
+
+ /**
+ * Draws the given rectangle using the current clip, current matrix, and the provided paint.
+ * @param left
+ * @param top
+ * @param right
+ * @param bottom
+ * @param paint
+ */
+ drawRect4f(left: number, top: number, right: number, bottom: number, paint: Paint): void;
+
+ /**
+ * Draws the given rectangle with rounded corners using the current clip, current matrix,
+ * and the provided paint.
+ * @param rrect
+ * @param paint
+ */
+ drawRRect(rrect: InputRRect, paint: Paint): void;
+
+ /**
+ * Draw an offset spot shadow and outlining ambient shadow for the given path using a disc
+ * light. See SkShadowUtils.h for more details
+ * @param path - The occluder used to generate the shadows.
+ * @param zPlaneParams - Values for the plane function which returns the Z offset of the
+ * occluder from the canvas based on local x and y values (the current
+ * matrix is not applied).
+ * @param lightPos - The 3D position of the light relative to the canvas plane. This is
+ * independent of the canvas's current matrix.
+ * @param lightRadius - The radius of the disc light.
+ * @param ambientColor - The color of the ambient shadow.
+ * @param spotColor - The color of the spot shadow.
+ * @param flags - See SkShadowFlags.h; 0 means use default options.
+ */
+ drawShadow(path: Path, zPlaneParams: InputVector3, lightPos: InputVector3, lightRadius: number,
+ ambientColor: InputColor, spotColor: InputColor, flags: number): void;
+
+ /**
+ * Draw the given text at the location (x, y) using the provided paint and font. The text will
+ * be drawn as is; no shaping, left-to-right, etc.
+ * @param str
+ * @param x
+ * @param y
+ * @param paint
+ * @param font
+ */
+ drawText(str: string, x: number, y: number, paint: Paint, font: Font): void;
+
+ /**
+ * Draws the given TextBlob at (x, y) using the current clip, current matrix, and the
+ * provided paint. Reminder that the fonts used to draw TextBlob are part of the blob.
+ * @param blob
+ * @param x
+ * @param y
+ * @param paint
+ */
+ drawTextBlob(blob: TextBlob, x: number, y: number, paint: Paint): void;
+
+ /**
+ * Draws the given vertices (a triangle mesh) using the current clip, current matrix, and the
+ * provided paint.
+ * If paint contains an Shader and vertices does not contain texCoords, the shader
+ * is mapped using the vertices' positions.
+ * If vertices colors are defined in vertices, and Paint paint contains Shader,
+ * BlendMode mode combines vertices colors with Shader.
+ * @param verts
+ * @param mode
+ * @param paint
+ */
+ drawVertices(verts: Vertices, mode: BlendMode, paint: Paint): void;
+
+ /**
+ * Returns the current transform from local coordinates to the 'device', which for most
+ * purposes means pixels.
+ */
+ getLocalToDevice(): Matrix4x4;
+
+ /**
+ * Returns the number of saved states, each containing: Matrix and clip.
+ * Equals the number of save() calls less the number of restore() calls plus one.
+ * The save count of a new canvas is one.
+ */
+ getSaveCount(): number;
+
+ /**
+ * Legacy version of getLocalToDevice(), which strips away any Z information, and
+ * just returns a 3x3 version.
+ */
+ getTotalMatrix(): number[];
+
+ /**
+ * Creates Surface matching info and props, and associates it with Canvas.
+ * Returns null if no match found.
+ * @param info
+ */
+ makeSurface(info: ImageInfo): Surface | null;
+
+ /**
+ * Returns a TypedArray containing the pixels reading starting at (srcX, srcY) and does not
+ * exceed the size indicated by imageInfo. See SkCanvas.h for more on the caveats.
+ *
+ * If dest is not provided, we allocate memory equal to the provided height * the provided
+ * bytesPerRow to fill the data with.
+ *
+ * This is generally a very expensive call for the GPU backend.
+ *
+ * @param srcX
+ * @param srcY
+ * @param imageInfo - describes the destination format of the pixels.
+ * @param dest - If provided, the pixels will be copied into the allocated buffer allowing
+ * access to the pixels without allocating a new TypedArray.
+ * @param bytesPerRow - number of bytes per row. Must be provided if dest is set. This
+ * depends on destination ColorType. For example, it must be at least 4 * width for
+ * the 8888 color type.
+ * @returns a TypedArray appropriate for the specified ColorType. Note that 16 bit floats are
+ * not supported in JS, so that colorType corresponds to raw bytes Uint8Array.
+ */
+ readPixels(srcX: number, srcY: number, imageInfo: ImageInfo, dest?: MallocObj,
+ bytesPerRow?: number): Uint8Array | Float32Array | null;
+
+ /**
+ * Removes changes to the current matrix and clip since Canvas state was
+ * last saved. The state is removed from the stack.
+ * Does nothing if the stack is empty.
+ */
+ restore(): void;
+
+ /**
+ * Restores state to a previous stack value.
+ * @param saveCount
+ */
+ restoreToCount(saveCount: number): void;
+
+ /**
+ * Rotates the current matrix by the number of degrees.
+ * @param rot - angle of rotation in degrees.
+ * @param rx
+ * @param ry
+ */
+ rotate(rot: AngleInDegrees, rx: number, ry: number): void;
+
+ /**
+ * Saves the current matrix and clip and returns current height of the stack.
+ */
+ save(): number;
+
+ /**
+ * Saves Matrix and clip, and allocates a SkBitmap for subsequent drawing.
+ * Calling restore() discards changes to Matrix and clip, and draws the SkBitmap.
+ * It returns the height of the stack.
+ * See Canvas.h for more.
+ * @param paint
+ * @param bounds
+ * @param backdrop
+ * @param flags
+ */
+ saveLayer(paint?: Paint, bounds?: InputRect | null, backdrop?: ImageFilter | null,
+ flags?: SaveLayerFlag): number;
+
+ /**
+ * Scales the current matrix by sx on the x-axis and sy on the y-axis.
+ * @param sx
+ * @param sy
+ */
+ scale(sx: number, sy: number): void;
+
+ /**
+ * Skews Matrix by sx on the x-axis and sy on the y-axis. A positive value of sx
+ * skews the drawing right as y-axis values increase; a positive value of sy skews
+ * the drawing down as x-axis values increase.
+ * @param sx
+ * @param sy
+ */
+ skew(sx: number, sy: number): void;
+
+ /**
+ * Translates Matrix by dx along the x-axis and dy along the y-axis.
+ * @param dx
+ * @param dy
+ */
+ translate(dx: number, dy: number): void;
+
+ /**
+ * Writes the given rectangle of pixels to the provided coordinates. The source pixels
+ * will be converted to the canvas's alphaType and colorType if they do not match.
+ * @param pixels
+ * @param srcWidth
+ * @param srcHeight
+ * @param destX
+ * @param destY
+ * @param alphaType - defaults to Unpremul
+ * @param colorType - defaults to RGBA_8888
+ * @param colorSpace - defaults to SRGB
+ */
+ writePixels(pixels: Uint8Array | number[], srcWidth: number, srcHeight: number,
+ destX: number, destY: number, alphaType?: AlphaType, colorType?: ColorType,
+ colorSpace?: ColorSpace): boolean;
+}
+
+/**
+ * See SkColorFilter.h for more on this class. The objects are opaque.
+ */
+export type ColorFilter = EmbindObject<ColorFilter>;
+
+export interface ContourMeasureIter extends EmbindObject<ContourMeasureIter> {
+ /**
+ * Iterates through contours in path, returning a contour-measure object for each contour
+ * in the path. Returns null when it is done.
+ *
+ * See SkContourMeasure.h for more details.
+ */
+ next(): ContourMeasure | null;
+}
+
+export interface ContourMeasure extends EmbindObject<ContourMeasure> {
+ /**
+ * Returns the given position and tangent line for the distance on the given contour.
+ * The return value is 4 floats in this order: posX, posY, vecX, vecY.
+ * @param distance - will be pinned between 0 and length().
+ * @param output - if provided, the four floats of the PosTan will be copied into this array
+ * instead of allocating a new one.
+ */
+ getPosTan(distance: number, output?: PosTan): PosTan;
+
+ /**
+ * Returns an Path representing the segement of this contour.
+ * @param startD - will be pinned between 0 and length()
+ * @param stopD - will be pinned between 0 and length()
+ * @param startWithMoveTo
+ */
+ getSegment(startD: number, stopD: number, startWithMoveTo: boolean): Path;
+
+ /**
+ * Returns true if the contour is closed.
+ */
+ isClosed(): boolean;
+
+ /**
+ * Returns the length of this contour.
+ */
+ length(): number;
+}
+
+export interface FontMetrics {
+ ascent: number; // suggested space above the baseline. < 0
+ descent: number; // suggested space below the baseline. > 0
+ leading: number; // suggested spacing between descent of previous line and ascent of next line.
+ bounds?: Rect; // smallest rect containing all glyphs (relative to 0,0)
+}
+
+/**
+ * See SkFont.h for more on this class.
+ */
+export interface Font extends EmbindObject<Font> {
+ /**
+ * Returns the FontMetrics for this font.
+ */
+ getMetrics(): FontMetrics;
+
+ /**
+ * Retrieves the bounds for each glyph in glyphs.
+ * If paint is not null, its stroking, PathEffect, and MaskFilter fields are respected.
+ * These are returned as flattened rectangles. For each glyph, there will be 4 floats for
+ * left, top, right, bottom (relative to 0, 0) for that glyph.
+ * @param glyphs
+ * @param paint
+ * @param output - if provided, the results will be copied into this array.
+ */
+ getGlyphBounds(glyphs: InputGlyphIDArray, paint?: Paint | null,
+ output?: Float32Array): Float32Array;
+
+ /**
+ * Retrieves the glyph ids for each code point in the provided string. This call is passed to
+ * the typeface of this font. Note that glyph IDs are typeface-dependent; different faces
+ * may have different ids for the same code point.
+ * @param str
+ * @param numCodePoints - the number of code points in the string. Defaults to str.length.
+ * @param output - if provided, the results will be copied into this array.
+ */
+ getGlyphIDs(str: string, numCodePoints?: number,
+ output?: GlyphIDArray): GlyphIDArray;
+
+ /**
+ * Retrieves the advanceX measurements for each glyph.
+ * If paint is not null, its stroking, PathEffect, and MaskFilter fields are respected.
+ * One width per glyph is returned in the returned array.
+ * @param glyphs
+ * @param paint
+ * @param output - if provided, the results will be copied into this array.
+ */
+ getGlyphWidths(glyphs: InputGlyphIDArray, paint?: Paint | null,
+ output?: Float32Array): Float32Array;
+
+ /**
+ * Computes any intersections of a thick "line" and a run of positionsed glyphs.
+ * The thick line is represented as a top and bottom coordinate (positive for
+ * below the baseline, negative for above). If there are no intersections
+ * (e.g. if this is intended as an underline, and there are no "collisions")
+ * then the returned array will be empty. If there are intersections, the array
+ * will contain pairs of X coordinates [start, end] for each segment that
+ * intersected with a glyph.
+ *
+ * @param glyphs the glyphs to intersect with
+ * @param positions x,y coordinates (2 per glyph) for each glyph
+ * @param top top of the thick "line" to use for intersection testing
+ * @param bottom bottom of the thick "line" to use for intersection testing
+ * @return array of [start, end] x-coordinate pairs. Maybe be empty.
+ */
+ getGlyphIntercepts(glyphs: InputGlyphIDArray, positions: Float32Array | number[],
+ top: number, bottom: number): Float32Array;
+
+ /**
+ * Returns text scale on x-axis. Default value is 1.
+ */
+ getScaleX(): number;
+
+ /**
+ * Returns text size in points.
+ */
+ getSize(): number;
+
+ /**
+ * Returns text skew on x-axis. Default value is zero.
+ */
+ getSkewX(): number;
+
+ /**
+ * Returns embolden effect for this font. Default value is false.
+ */
+ isEmbolden(): boolean;
+
+ /**
+ * Returns the Typeface set for this font.
+ */
+ getTypeface(): Typeface | null;
+
+ /**
+ * Requests, but does not require, that edge pixels draw opaque or with partial transparency.
+ * @param edging
+ */
+ setEdging(edging: FontEdging): void;
+
+ /**
+ * Requests, but does not require, to use bitmaps in fonts instead of outlines.
+ * @param embeddedBitmaps
+ */
+ setEmbeddedBitmaps(embeddedBitmaps: boolean): void;
+
+ /**
+ * Sets level of glyph outline adjustment.
+ * @param hinting
+ */
+ setHinting(hinting: FontHinting): void;
+
+ /**
+ * Requests, but does not require, linearly scalable font and glyph metrics.
+ *
+ * For outline fonts 'true' means font and glyph metrics should ignore hinting and rounding.
+ * Note that some bitmap formats may not be able to scale linearly and will ignore this flag.
+ * @param linearMetrics
+ */
+ setLinearMetrics(linearMetrics: boolean): void;
+
+ /**
+ * Sets the text scale on the x-axis.
+ * @param sx
+ */
+ setScaleX(sx: number): void;
+
+ /**
+ * Sets the text size in points on this font.
+ * @param points
+ */
+ setSize(points: number): void;
+
+ /**
+ * Sets the text-skew on the x axis for this font.
+ * @param sx
+ */
+ setSkewX(sx: number): void;
+
+ /**
+ * Set embolden effect for this font.
+ * @param embolden
+ */
+ setEmbolden(embolden: boolean): void;
+
+ /**
+ * Requests, but does not require, that glyphs respect sub-pixel positioning.
+ * @param subpixel
+ */
+ setSubpixel(subpixel: boolean): void;
+
+ /**
+ * Sets the typeface to use with this font. null means to clear the typeface and use the
+ * default one.
+ * @param face
+ */
+ setTypeface(face: Typeface | null): void;
+}
+
+/**
+ * See SkFontMgr.h for more details
+ */
+export interface FontMgr extends EmbindObject<FontMgr> {
+ /**
+ * Return the number of font families loaded in this manager. Useful for debugging.
+ */
+ countFamilies(): number;
+
+ /**
+ * Return the nth family name. Useful for debugging.
+ * @param index
+ */
+ getFamilyName(index: number): string;
+}
+
+/**
+ * See SkImage.h for more information on this class.
+ */
+export interface Image extends EmbindObject<Image> {
+ /**
+ * Encodes this image's pixels to the specified format and returns them. Must be built with
+ * the specified codec. If the options are unspecified, sensible defaults will be
+ * chosen.
+ * @param fmt - PNG is the default value.
+ * @param quality - a value from 0 to 100; 100 is the least lossy. May be ignored.
+ */
+ encodeToBytes(fmt?: EncodedImageFormat, quality?: number): Uint8Array | null;
+
+ /**
+ * Returns the color space associated with this object.
+ * It is the user's responsibility to call delete() on this after it has been used.
+ */
+ getColorSpace(): ColorSpace;
+
+ /**
+ * Returns the width, height, colorType and alphaType associated with this image.
+ * Colorspace is separate so as to not accidentally leak that memory.
+ */
+ getImageInfo(): PartialImageInfo;
+
+ /**
+ * Return the height in pixels of the image.
+ */
+ height(): number;
+
+ /**
+ * Returns an Image with the same "base" pixels as the this image, but with mipmap levels
+ * automatically generated and attached.
+ */
+ makeCopyWithDefaultMipmaps(): Image;
+
+ /**
+ * Returns this image as a shader with the specified tiling. It will use cubic sampling.
+ * @param tx - tile mode in the x direction.
+ * @param ty - tile mode in the y direction.
+ * @param B - See CubicResampler in SkSamplingOptions.h for more information
+ * @param C - See CubicResampler in SkSamplingOptions.h for more information
+ * @param localMatrix
+ */
+ makeShaderCubic(tx: TileMode, ty: TileMode, B: number, C: number,
+ localMatrix?: InputMatrix): Shader;
+
+ /**
+ * Returns this image as a shader with the specified tiling. It will use cubic sampling.
+ * @param tx - tile mode in the x direction.
+ * @param ty - tile mode in the y direction.
+ * @param fm - The filter mode.
+ * @param mm - The mipmap mode. Note: for settings other than None, the image must have mipmaps
+ * calculated with makeCopyWithDefaultMipmaps;
+ * @param localMatrix
+ */
+ makeShaderOptions(tx: TileMode, ty: TileMode, fm: FilterMode, mm: MipmapMode,
+ localMatrix?: InputMatrix): Shader;
+
+ /**
+ * Returns a TypedArray containing the pixels reading starting at (srcX, srcY) and does not
+ * exceed the size indicated by imageInfo. See SkImage.h for more on the caveats.
+ *
+ * If dest is not provided, we allocate memory equal to the provided height * the provided
+ * bytesPerRow to fill the data with.
+ *
+ * @param srcX
+ * @param srcY
+ * @param imageInfo - describes the destination format of the pixels.
+ * @param dest - If provided, the pixels will be copied into the allocated buffer allowing
+ * access to the pixels without allocating a new TypedArray.
+ * @param bytesPerRow - number of bytes per row. Must be provided if dest is set. This
+ * depends on destination ColorType. For example, it must be at least 4 * width for
+ * the 8888 color type.
+ * @returns a TypedArray appropriate for the specified ColorType. Note that 16 bit floats are
+ * not supported in JS, so that colorType corresponds to raw bytes Uint8Array.
+ */
+ readPixels(srcX: number, srcY: number, imageInfo: ImageInfo, dest?: MallocObj,
+ bytesPerRow?: number): Uint8Array | Float32Array | null;
+
+ /**
+ * Return the width in pixels of the image.
+ */
+ width(): number;
+}
+
+/**
+ * See ImageFilter.h for more on this class. The objects are opaque.
+ */
+export type ImageFilter = EmbindObject<ImageFilter>;
+
+export interface ImageInfo {
+ alphaType: AlphaType;
+ colorSpace: ColorSpace;
+ colorType: ColorType;
+ height: number;
+ width: number;
+}
+
+export interface PartialImageInfo {
+ alphaType: AlphaType;
+ colorType: ColorType;
+ height: number;
+ width: number;
+}
+
+/*
+ * Specifies sampling with bicubic coefficients
+ */
+export interface CubicResampler {
+ B: number; // 0..1
+ C: number; // 0..1
+}
+
+/**
+ * Specifies sampling using filter and mipmap options
+ */
+export interface FilterOptions {
+ filter: FilterMode;
+ mipmap?: MipmapMode; // defaults to None if not specified
+}
+
+/**
+ * See SkMaskFilter.h for more on this class. The objects are opaque.
+ */
+export type MaskFilter = EmbindObject<MaskFilter>;
+
+/**
+ * See SkPaint.h for more information on this class.
+ */
+export interface Paint extends EmbindObject<Paint> {
+ /**
+ * Returns a copy of this paint.
+ */
+ copy(): Paint;
+
+ /**
+ * Retrieves the alpha and RGB unpremultiplied. RGB are extended sRGB values
+ * (sRGB gamut, and encoded with the sRGB transfer function).
+ */
+ getColor(): Color;
+
+ /**
+ * Returns the geometry drawn at the beginning and end of strokes.
+ */
+ getStrokeCap(): StrokeCap;
+
+ /**
+ * Returns the geometry drawn at the corners of strokes.
+ */
+ getStrokeJoin(): StrokeJoin;
+
+ /**
+ * Returns the limit at which a sharp corner is drawn beveled.
+ */
+ getStrokeMiter(): number;
+
+ /**
+ * Returns the thickness of the pen used to outline the shape.
+ */
+ getStrokeWidth(): number;
+
+ /**
+ * Replaces alpha, leaving RGBA unchanged. 0 means fully transparent, 1.0 means opaque.
+ * @param alpha
+ */
+ setAlphaf(alpha: number): void;
+
+ /**
+ * Requests, but does not require, that edge pixels draw opaque or with
+ * partial transparency.
+ * @param aa
+ */
+ setAntiAlias(aa: boolean): void;
+
+ /**
+ * Sets the blend mode that is, the mode used to combine source color
+ * with destination color.
+ * @param mode
+ */
+ setBlendMode(mode: BlendMode): void;
+
+ /**
+ * Sets alpha and RGB used when stroking and filling. The color is four floating
+ * point values, unpremultiplied. The color values are interpreted as being in
+ * the provided colorSpace.
+ * @param color
+ * @param colorSpace - defaults to sRGB
+ */
+ setColor(color: InputColor, colorSpace?: ColorSpace): void;
+
+ /**
+ * Sets alpha and RGB used when stroking and filling. The color is four floating
+ * point values, unpremultiplied. The color values are interpreted as being in
+ * the provided colorSpace.
+ * @param r
+ * @param g
+ * @param b
+ * @param a
+ * @param colorSpace - defaults to sRGB
+ */
+ setColorComponents(r: number, g: number, b: number, a: number, colorSpace?: ColorSpace): void;
+
+ /**
+ * Sets the current color filter, replacing the existing one if there was one.
+ * @param filter
+ */
+ setColorFilter(filter: ColorFilter): void;
+
+ /**
+ * Sets the color used when stroking and filling. The color values are interpreted as being in
+ * the provided colorSpace.
+ * @param color
+ * @param colorSpace - defaults to sRGB.
+ */
+ setColorInt(color: ColorInt, colorSpace?: ColorSpace): void;
+
+ /**
+ * Sets the current image filter, replacing the existing one if there was one.
+ * @param filter
+ */
+ setImageFilter(filter: ImageFilter): void;
+
+ /**
+ * Sets the current mask filter, replacing the existing one if there was one.
+ * @param filter
+ */
+ setMaskFilter(filter: MaskFilter): void;
+
+ /**
+ * Sets the current path effect, replacing the existing one if there was one.
+ * @param effect
+ */
+ setPathEffect(effect: PathEffect): void;
+
+ /**
+ * Sets the current shader, replacing the existing one if there was one.
+ * @param shader
+ */
+ setShader(shader: Shader): void;
+
+ /**
+ * Sets the geometry drawn at the beginning and end of strokes.
+ * @param cap
+ */
+ setStrokeCap(cap: StrokeCap): void;
+
+ /**
+ * Sets the geometry drawn at the corners of strokes.
+ * @param join
+ */
+ setStrokeJoin(join: StrokeJoin): void;
+
+ /**
+ * Sets the limit at which a sharp corner is drawn beveled.
+ * @param limit
+ */
+ setStrokeMiter(limit: number): void;
+
+ /**
+ * Sets the thickness of the pen used to outline the shape.
+ * @param width
+ */
+ setStrokeWidth(width: number): void;
+
+ /**
+ * Sets whether the geometry is filled or stroked.
+ * @param style
+ */
+ setStyle(style: PaintStyle): void;
+}
+
+/**
+ * See SkPath.h for more information on this class.
+ */
+export interface Path extends EmbindObject<Path> {
+ /**
+ * Appends arc to Path, as the start of new contour. Arc added is part of ellipse
+ * bounded by oval, from startAngle through sweepAngle. Both startAngle and
+ * sweepAngle are measured in degrees, where zero degrees is aligned with the
+ * positive x-axis, and positive sweeps extends arc clockwise.
+ * Returns the modified path for easier chaining.
+ * @param oval
+ * @param startAngle
+ * @param sweepAngle
+ */
+ addArc(oval: InputRect, startAngle: AngleInDegrees, sweepAngle: AngleInDegrees): Path;
+
+ /**
+ * Adds oval to Path, appending kMove_Verb, four kConic_Verb, and kClose_Verb.
+ * Oval is upright ellipse bounded by Rect oval with radii equal to half oval width
+ * and half oval height. Oval begins at start and continues clockwise by default.
+ * Returns the modified path for easier chaining.
+ * @param oval
+ * @param isCCW - if the path should be drawn counter-clockwise or not
+ * @param startIndex - index of initial point of ellipse
+ */
+ addOval(oval: InputRect, isCCW?: boolean, startIndex?: number): Path;
+
+ /**
+ * Takes 1, 2, 7, or 10 required args, where the first arg is always the path.
+ * The last arg is an optional boolean and chooses between add or extend mode.
+ * The options for the remaining args are:
+ * - an array of 6 or 9 parameters (perspective is optional)
+ * - the 9 parameters of a full matrix or
+ * the 6 non-perspective params of a matrix.
+ * Returns the modified path for easier chaining (or null if params were incorrect).
+ * @param args
+ */
+ addPath(...args: any[]): Path | null;
+
+ /**
+ * Adds contour created from array of n points, adding (count - 1) line segments.
+ * Contour added starts at pts[0], then adds a line for every additional point
+ * in pts array. If close is true, appends kClose_Verb to Path, connecting
+ * pts[count - 1] and pts[0].
+ * Returns the modified path for easier chaining.
+ * @param points
+ * @param close - if true, will add a line connecting last point to the first point.
+ */
+ addPoly(points: InputFlattenedPointArray, close: boolean): Path;
+
+ /**
+ * Adds Rect to Path, appending kMove_Verb, three kLine_Verb, and kClose_Verb,
+ * starting with top-left corner of Rect; followed by top-right, bottom-right,
+ * and bottom-left if isCCW is false; or followed by bottom-left,
+ * bottom-right, and top-right if isCCW is true.
+ * Returns the modified path for easier chaining.
+ * @param rect
+ * @param isCCW
+ */
+ addRect(rect: InputRect, isCCW?: boolean): Path;
+
+ /**
+ * Adds rrect to Path, creating a new closed contour.
+ * Returns the modified path for easier chaining.
+ * @param rrect
+ * @param isCCW
+ */
+ addRRect(rrect: InputRRect, isCCW?: boolean): Path;
+
+ /**
+ * Adds the given verbs and associated points/weights to the path. The process
+ * reads the first verb from verbs and then the appropriate number of points from the
+ * FlattenedPointArray (e.g. 2 points for moveTo, 4 points for quadTo, etc). If the verb is
+ * a conic, a weight will be read from the WeightList.
+ * Returns the modified path for easier chaining
+ * @param verbs - the verbs that create this path, in the order of being drawn.
+ * @param points - represents n points with 2n floats.
+ * @param weights - used if any of the verbs are conics, can be omitted otherwise.
+ */
+ addVerbsPointsWeights(verbs: VerbList, points: InputFlattenedPointArray,
+ weights?: WeightList): Path;
+
+ /**
+ * Adds an arc to this path, emulating the Canvas2D behavior.
+ * Returns the modified path for easier chaining.
+ * @param x
+ * @param y
+ * @param radius
+ * @param startAngle
+ * @param endAngle
+ * @param isCCW
+ */
+ arc(x: number, y: number, radius: number, startAngle: AngleInRadians, endAngle: AngleInRadians,
+ isCCW?: boolean): Path;
+
+ /**
+ * Appends arc to Path. Arc added is part of ellipse
+ * bounded by oval, from startAngle through sweepAngle. Both startAngle and
+ * sweepAngle are measured in degrees, where zero degrees is aligned with the
+ * positive x-axis, and positive sweeps extends arc clockwise.
+ * Returns the modified path for easier chaining.
+ * @param oval
+ * @param startAngle
+ * @param endAngle
+ * @param forceMoveTo
+ */
+ arcToOval(oval: InputRect, startAngle: AngleInDegrees, endAngle: AngleInDegrees,
+ forceMoveTo: boolean): Path;
+
+ /**
+ * Appends arc to Path. Arc is implemented by one or more conics weighted to
+ * describe part of oval with radii (rx, ry) rotated by xAxisRotate degrees. Arc
+ * curves from last Path Point to (x, y), choosing one of four possible routes:
+ * clockwise or counterclockwise, and smaller or larger. See SkPath.h for more details.
+ * Returns the modified path for easier chaining.
+ * @param rx
+ * @param ry
+ * @param xAxisRotate
+ * @param useSmallArc
+ * @param isCCW
+ * @param x
+ * @param y
+ */
+ arcToRotated(rx: number, ry: number, xAxisRotate: AngleInDegrees, useSmallArc: boolean,
+ isCCW: boolean, x: number, y: number): Path;
+
+ /**
+ * Appends arc to Path, after appending line if needed. Arc is implemented by conic
+ * weighted to describe part of circle. Arc is contained by tangent from
+ * last Path point to (x1, y1), and tangent from (x1, y1) to (x2, y2). Arc
+ * is part of circle sized to radius, positioned so it touches both tangent lines.
+ * Returns the modified path for easier chaining.
+ * @param x1
+ * @param y1
+ * @param x2
+ * @param y2
+ * @param radius
+ */
+ arcToTangent(x1: number, y1: number, x2: number, y2: number, radius: number): Path;
+
+ /**
+ * Appends CLOSE_VERB to Path. A closed contour connects the first and last point
+ * with a line, forming a continuous loop.
+ * Returns the modified path for easier chaining.
+ */
+ close(): Path;
+
+ /**
+ * Returns minimum and maximum axes values of the lines and curves in Path.
+ * Returns (0, 0, 0, 0) if Path contains no points.
+ * Returned bounds width and height may be larger or smaller than area affected
+ * when Path is drawn.
+ *
+ * Behaves identically to getBounds() when Path contains
+ * only lines. If Path contains curves, computed bounds includes
+ * the maximum extent of the quad, conic, or cubic; is slower than getBounds();
+ * and unlike getBounds(), does not cache the result.
+ * @param outputArray - if provided, the bounding box will be copied into this array instead of
+ * allocating a new one.
+ */
+ computeTightBounds(outputArray?: Rect): Rect;
+
+ /**
+ * Adds conic from last point towards (x1, y1), to (x2, y2), weighted by w.
+ * If Path is empty, or path is closed, the last point is set to (0, 0)
+ * before adding conic.
+ * Returns the modified path for easier chaining.
+ * @param x1
+ * @param y1
+ * @param x2
+ * @param y2
+ * @param w
+ */
+ conicTo(x1: number, y1: number, x2: number, y2: number, w: number): Path;
+
+ /**
+ * Returns true if the point (x, y) is contained by Path, taking into
+ * account FillType.
+ * @param x
+ * @param y
+ */
+ contains(x: number, y: number): boolean;
+
+ /**
+ * Returns a copy of this Path.
+ */
+ copy(): Path;
+
+ /**
+ * Returns the number of points in this path. Initially zero.
+ */
+ countPoints(): number;
+
+ /**
+ * Adds cubic from last point towards (x1, y1), then towards (x2, y2), ending at
+ * (x3, y3). If Path is empty, or path is closed, the last point is set to
+ * (0, 0) before adding cubic.
+ * @param cpx1
+ * @param cpy1
+ * @param cpx2
+ * @param cpy2
+ * @param x
+ * @param y
+ */
+ cubicTo(cpx1: number, cpy1: number, cpx2: number, cpy2: number, x: number, y: number): Path;
+
+ /**
+ * Changes this path to be the dashed version of itself. This is the same effect as creating
+ * a DashPathEffect and calling filterPath on this path.
+ * @param on
+ * @param off
+ * @param phase
+ */
+ dash(on: number, off: number, phase: number): boolean;
+
+ /**
+ * Returns true if other path is equal to this path.
+ * @param other
+ */
+ equals(other: Path): boolean;
+
+ /**
+ * Returns minimum and maximum axes values of Point array.
+ * Returns (0, 0, 0, 0) if Path contains no points. Returned bounds width and height may
+ * be larger or smaller than area affected when Path is drawn.
+ * @param outputArray - if provided, the bounding box will be copied into this array instead of
+ * allocating a new one.
+ */
+ getBounds(outputArray?: Rect): Rect;
+
+ /**
+ * Return the FillType for this path.
+ */
+ getFillType(): FillType;
+
+ /**
+ * Returns the Point at index in Point array. Valid range for index is
+ * 0 to countPoints() - 1.
+ * @param index
+ * @param outputArray - if provided, the point will be copied into this array instead of
+ * allocating a new one.
+ */
+ getPoint(index: number, outputArray?: Point): Point;
+
+ /**
+ * Returns true if there are no verbs in the path.
+ */
+ isEmpty(): boolean;
+
+ /**
+ * Returns true if the path is volatile; it will not be altered or discarded
+ * by the caller after it is drawn. Path by default have volatile set false, allowing
+ * Surface to attach a cache of data which speeds repeated drawing. If true, Surface
+ * may not speed repeated drawing.
+ */
+ isVolatile(): boolean;
+
+ /**
+ * Adds line from last point to (x, y). If Path is empty, or last path is closed,
+ * last point is set to (0, 0) before adding line.
+ * Returns the modified path for easier chaining.
+ * @param x
+ * @param y
+ */
+ lineTo(x: number, y: number): Path;
+
+ /**
+ * Returns a new path that covers the same area as the original path, but with the
+ * Winding FillType. This may re-draw some contours in the path as counter-clockwise
+ * instead of clockwise to achieve that effect. If such a transformation cannot
+ * be done, null is returned.
+ */
+ makeAsWinding(): Path | null;
+
+ /**
+ * Adds beginning of contour at the given point.
+ * Returns the modified path for easier chaining.
+ * @param x
+ * @param y
+ */
+ moveTo(x: number, y: number): Path;
+
+ /**
+ * Translates all the points in the path by dx, dy.
+ * Returns the modified path for easier chaining.
+ * @param dx
+ * @param dy
+ */
+ offset(dx: number, dy: number): Path;
+
+ /**
+ * Combines this path with the other path using the given PathOp. Returns false if the operation
+ * fails.
+ * @param other
+ * @param op
+ */
+ op(other: Path, op: PathOp): boolean;
+
+ /**
+ * Adds quad from last point towards (x1, y1), to (x2, y2).
+ * If Path is empty, or path is closed, last point is set to (0, 0) before adding quad.
+ * Returns the modified path for easier chaining.
+ * @param x1
+ * @param y1
+ * @param x2
+ * @param y2
+ */
+ quadTo(x1: number, y1: number, x2: number, y2: number): Path;
+
+ /**
+ * Relative version of arcToRotated.
+ * @param rx
+ * @param ry
+ * @param xAxisRotate
+ * @param useSmallArc
+ * @param isCCW
+ * @param dx
+ * @param dy
+ */
+ rArcTo(rx: number, ry: number, xAxisRotate: AngleInDegrees, useSmallArc: boolean,
+ isCCW: boolean, dx: number, dy: number): Path;
+
+ /**
+ * Relative version of conicTo.
+ * @param dx1
+ * @param dy1
+ * @param dx2
+ * @param dy2
+ * @param w
+ */
+ rConicTo(dx1: number, dy1: number, dx2: number, dy2: number, w: number): Path;
+
+ /**
+ * Relative version of cubicTo.
+ * @param cpx1
+ * @param cpy1
+ * @param cpx2
+ * @param cpy2
+ * @param x
+ * @param y
+ */
+ rCubicTo(cpx1: number, cpy1: number, cpx2: number, cpy2: number, x: number, y: number): Path;
+
+ /**
+ * Sets Path to its initial state.
+ * Removes verb array, point array, and weights, and sets FillType to Winding.
+ * Internal storage associated with Path is released
+ */
+ reset(): void;
+
+ /**
+ * Sets Path to its initial state.
+ * Removes verb array, point array, and weights, and sets FillType to Winding.
+ * Internal storage associated with Path is *not* released.
+ * Use rewind() instead of reset() if Path storage will be reused and performance
+ * is critical.
+ */
+ rewind(): void;
+
+ /**
+ * Relative version of lineTo.
+ * @param x
+ * @param y
+ */
+ rLineTo(x: number, y: number): Path;
+
+ /**
+ * Relative version of moveTo.
+ * @param x
+ * @param y
+ */
+ rMoveTo(x: number, y: number): Path;
+
+ /**
+ * Relative version of quadTo.
+ * @param x1
+ * @param y1
+ * @param x2
+ * @param y2
+ */
+ rQuadTo(x1: number, y1: number, x2: number, y2: number): Path;
+
+ /**
+ * Sets FillType, the rule used to fill Path.
+ * @param fill
+ */
+ setFillType(fill: FillType): void;
+
+ /**
+ * Specifies whether Path is volatile; whether it will be altered or discarded
+ * by the caller after it is drawn. Path by default have volatile set false.
+ *
+ * Mark animating or temporary paths as volatile to improve performance.
+ * Mark unchanging Path non-volatile to improve repeated rendering.
+ * @param volatile
+ */
+ setIsVolatile(volatile: boolean): void;
+
+ /**
+ * Set this path to a set of non-overlapping contours that describe the
+ * same area as the original path.
+ * The curve order is reduced where possible so that cubics may
+ * be turned into quadratics, and quadratics maybe turned into lines.
+ *
+ * Returns true if operation was able to produce a result.
+ */
+ simplify(): boolean;
+
+ /**
+ * Turns this path into the filled equivalent of the stroked path. Returns null if the operation
+ * fails (e.g. the path is a hairline).
+ * @param opts - describe how stroked path should look.
+ */
+ stroke(opts?: StrokeOpts): Path | null;
+
+ /**
+ * Serializes the contents of this path as a series of commands.
+ * The first item will be a verb, followed by any number of arguments needed. Then it will
+ * be followed by another verb, more arguments and so on.
+ */
+ toCmds(): Float32Array;
+
+ /**
+ * Returns this path as an SVG string.
+ */
+ toSVGString(): string;
+
+ /**
+ * Takes a 3x3 matrix as either an array or as 9 individual params.
+ * @param args
+ */
+ transform(...args: any[]): Path;
+
+ /**
+ * Take start and stop "t" values (values between 0...1), and modify this path such that
+ * it is a subset of the original path.
+ * The trim values apply to the entire path, so if it contains several contours, all of them
+ * are including in the calculation.
+ * Null is returned if either input value is NaN.
+ * @param startT - a value in the range [0.0, 1.0]. 0.0 is the beginning of the path.
+ * @param stopT - a value in the range [0.0, 1.0]. 1.0 is the end of the path.
+ * @param isComplement
+ */
+ trim(startT: number, stopT: number, isComplement: boolean): Path | null;
+}
+
+/**
+ * See SkPathEffect.h for more on this class. The objects are opaque.
+ */
+export type PathEffect = EmbindObject<PathEffect>;
+
+/**
+ * See SkPicture.h for more information on this class.
+ *
+ * Of note, SkPicture is *not* what is colloquially thought of as a "picture" (what we
+ * call a bitmap). An SkPicture is a series of draw commands.
+ */
+export interface SkPicture extends EmbindObject<SkPicture> {
+ /**
+ * Returns a new shader that will draw with this picture.
+ *
+ * @param tmx The tiling mode to use when sampling in the x-direction.
+ * @param tmy The tiling mode to use when sampling in the y-direction.
+ * @param mode How to filter the tiles
+ * @param localMatrix Optional matrix used when sampling
+ * @param tileRect The tile rectangle in picture coordinates: this represents the subset
+ * (or superset) of the picture used when building a tile. It is not
+ * affected by localMatrix and does not imply scaling (only translation
+ * and cropping). If null, the tile rect is considered equal to the picture
+ * bounds.
+ */
+ makeShader(tmx: TileMode, tmy: TileMode, mode: FilterMode,
+ localMatrix?: InputMatrix, tileRect?: InputRect): Shader;
+
+ /**
+ * Returns the serialized format of this SkPicture. The format may change at anytime and
+ * no promises are made for backwards or forward compatibility.
+ */
+ serialize(): Uint8Array | null;
+}
+
+export interface PictureRecorder extends EmbindObject<PictureRecorder> {
+ /**
+ * Returns a canvas on which to draw. When done drawing, call finishRecordingAsPicture()
+ *
+ * @param bounds - a rect to cull the results.
+ */
+ beginRecording(bounds: InputRect): Canvas;
+
+ /**
+ * Returns the captured draw commands as a picture and invalidates the canvas returned earlier.
+ */
+ finishRecordingAsPicture(): SkPicture;
+}
+
+/**
+ * See SkRuntimeEffect.h for more details.
+ */
+export interface RuntimeEffect extends EmbindObject<RuntimeEffect> {
+ /**
+ * Returns a shader executed using the given uniform data.
+ * @param uniforms
+ * @param localMatrix
+ */
+ makeShader(uniforms: Float32Array | number[],
+ localMatrix?: InputMatrix): Shader;
+
+ /**
+ * Returns a shader executed using the given uniform data and the children as inputs.
+ * @param uniforms
+ * @param children
+ * @param localMatrix
+ */
+ makeShaderWithChildren(uniforms: Float32Array | number[],
+ children?: Shader[], localMatrix?: InputMatrix): Shader;
+
+ /**
+ * Returns the nth uniform from the effect.
+ * @param index
+ */
+ getUniform(index: number): SkSLUniform;
+
+ /**
+ * Returns the number of uniforms on the effect.
+ */
+ getUniformCount(): number;
+
+ /**
+ * Returns the total number of floats across all uniforms on the effect. This is the length
+ * of the uniforms array expected by makeShader. For example, an effect with a single float3
+ * uniform, would return 1 from `getUniformCount()`, but 3 from `getUniformFloatCount()`.
+ */
+ getUniformFloatCount(): number;
+
+ /**
+ * Returns the name of the nth effect uniform.
+ * @param index
+ */
+ getUniformName(index: number): string;
+}
+
+/**
+ * See SkShader.h for more on this class. The objects are opaque.
+ */
+export type Shader = EmbindObject<Shader>;
+
+export interface Surface extends EmbindObject<Surface> {
+ /**
+ * A convenient way to draw exactly once on the canvas associated with this surface.
+ * This requires an environment where a global function called requestAnimationFrame is
+ * available (e.g. on the web, not on Node). Users do not need to flush the surface,
+ * or delete/dispose of it as that is taken care of automatically with this wrapper.
+ *
+ * Node users should call getCanvas() and work with that canvas directly.
+ */
+ drawOnce(drawFrame: (_: Canvas) => void): void;
+
+ /**
+ * Clean up the surface and any extra memory.
+ * [Deprecated]: In the future, calls to delete() will be sufficient to clean up the memory.
+ */
+ dispose(): void;
+
+ /**
+ * Make sure any queued draws are sent to the screen or the GPU.
+ */
+ flush(): void;
+
+ /**
+ * Return a canvas that is backed by this surface. Any draws to the canvas will (eventually)
+ * show up on the surface. The returned canvas is owned by the surface and does NOT need to
+ * be cleaned up by the client.
+ */
+ getCanvas(): Canvas;
+
+ /**
+ * Returns the height of this surface in pixels.
+ */
+ height(): number;
+
+ /**
+ * Returns the ImageInfo associated with this surface.
+ */
+ imageInfo(): ImageInfo;
+
+ /**
+ * Creates an Image from the provided texture and info. The Image will own the texture;
+ * when the image is deleted, the texture will be cleaned up.
+ * @param tex
+ * @param info - describes the content of the texture.
+ */
+ makeImageFromTexture(tex: WebGLTexture, info: ImageInfo): Image | null;
+
+ /**
+ * Returns a texture-backed image based on the content in src. It uses RGBA_8888, unpremul
+ * and SRGB - for more control, use makeImageFromTexture.
+ *
+ * The underlying texture for this image will be created immediately from src, so
+ * it can be disposed of after this call. This image will *only* be usable for this
+ * surface (because WebGL textures are not transferable to other WebGL contexts).
+ * For an image that can be used across multiple surfaces, at the cost of being lazily
+ * loaded, see MakeLazyImageFromTextureSource.
+ *
+ * Not available for software-backed surfaces.
+ * @param src
+ * @param info - If provided, will be used to determine the width/height/format of the
+ * source image. If not, sensible defaults will be used.
+ */
+ makeImageFromTextureSource(src: TextureSource, info?: ImageInfo | PartialImageInfo): Image | null;
+
+ /**
+ * Returns current contents of the surface as an Image. This image will be optimized to be
+ * drawn to another surface of the same type. For example, if this surface is backed by the
+ * GPU, the returned Image will be backed by a GPU texture.
+ */
+ makeImageSnapshot(bounds?: InputIRect): Image;
+
+ /**
+ * Returns a compatible Surface, haring the same raster or GPU properties of the original.
+ * The pixels are not shared.
+ * @param info - width, height, etc of the Surface.
+ */
+ makeSurface(info: ImageInfo): Surface;
+
+ /**
+ * Returns if this Surface is a GPU-backed surface or not.
+ */
+ reportBackendTypeIsGPU(): boolean;
+
+ /**
+ * A convenient way to draw multiple frames on the canvas associated with this surface.
+ * This requires an environment where a global function called requestAnimationFrame is
+ * available (e.g. on the web, not on Node). Users do not need to flush the surface,
+ * as that is taken care of automatically with this wrapper.
+ *
+ * Users should probably call surface.requestAnimationFrame in the callback function to
+ * draw multiple frames, e.g. of an animation.
+ *
+ * Node users should call getCanvas() and work with that canvas directly.
+ */
+ requestAnimationFrame(drawFrame: (_: Canvas) => void): void;
+
+ /**
+ * If this surface is GPU-backed, return the sample count of the surface.
+ */
+ sampleCnt(): number;
+
+ /**
+ * Updates the underlying GPU texture of the image to be the contents of the provided
+ * TextureSource. Has no effect on CPU backend or if img was not created with either
+ * makeImageFromTextureSource or makeImageFromTexture.
+ * If the provided TextureSource is of different dimensions than the Image, the contents
+ * will be deformed (e.g. squished). The ColorType, AlphaType, and ColorSpace of src should
+ * match the original settings used to create the Image or it may draw strange.
+ *
+ * @param img - A texture-backed Image.
+ * @param src - A valid texture source of any dimensions.
+ */
+ updateTextureFromSource(img: Image, src: TextureSource): void;
+
+ /**
+ * Returns the width of this surface in pixels.
+ */
+ width(): number;
+}
+
+/**
+ * See SkTextBlob.h for more on this class. The objects are opaque.
+ */
+export type TextBlob = EmbindObject<TextBlob>;
+
+/**
+ * See SkTypeface.h for more on this class. The objects are opaque.
+ */
+export interface Typeface extends EmbindObject<Typeface> {
+ /**
+ * Retrieves the glyph ids for each code point in the provided string. Note that glyph IDs
+ * are typeface-dependent; different faces may have different ids for the same code point.
+ * @param str
+ * @param numCodePoints - the number of code points in the string. Defaults to str.length.
+ * @param output - if provided, the results will be copied into this array.
+ */
+ getGlyphIDs(str: string, numCodePoints?: number,
+ output?: GlyphIDArray): GlyphIDArray;
+}
+
+/**
+ * See SkVertices.h for more on this class.
+ */
+export interface Vertices extends EmbindObject<Vertices> {
+ /**
+ * Return the bounding area for the vertices.
+ * @param outputArray - if provided, the bounding box will be copied into this array instead of
+ * allocating a new one.
+ */
+ bounds(outputArray?: Rect): Rect;
+
+ /**
+ * Return a unique ID for this vertices object.
+ */
+ uniqueID(): number;
+}
+
+export interface SkottieAnimation extends EmbindObject<SkottieAnimation> {
+ /**
+ * Returns the animation duration in seconds.
+ */
+ duration(): number;
+ /**
+ * Returns the animation frame rate (frames / second).
+ */
+ fps(): number;
+
+ /**
+ * Draws current animation frame. Must call seek or seekFrame first.
+ * @param canvas
+ * @param dstRect
+ */
+ render(canvas: Canvas, dstRect?: InputRect): void;
+
+ /**
+ * [deprecated] - use seekFrame
+ * @param t - value from [0.0, 1.0]; 0 is first frame, 1 is final frame.
+ * @param damageRect - will copy damage frame into this if provided.
+ */
+ seek(t: number, damageRect?: Rect): Rect;
+
+ /**
+ * Update the animation state to match |t|, specified as a frame index
+ * i.e. relative to duration() * fps().
+ *
+ * Returns the rectangle that was affected by this animation.
+ *
+ * @param frame - Fractional values are allowed and meaningful - e.g.
+ * 0.0 -> first frame
+ * 1.0 -> second frame
+ * 0.5 -> halfway between first and second frame
+ * @param damageRect - will copy damage frame into this if provided.
+ */
+ seekFrame(frame: number, damageRect?: Rect): Rect;
+
+ /**
+ * Return the size of this animation.
+ * @param outputSize - If provided, the size will be copied into here as width, height.
+ */
+ size(outputSize?: Point): Point;
+ version(): string;
+}
+
+/**
+ * Options used for Path.stroke(). If an option is omitted, a sensible default will be used.
+ */
+export interface StrokeOpts {
+ /** The width of the stroked lines. */
+ width?: number;
+ miter_limit?: number;
+ /**
+ * if > 1, increase precision, else if (0 < resScale < 1) reduce precision to
+ * favor speed and size
+ */
+ precision?: number;
+ join?: StrokeJoin;
+ cap?: StrokeCap;
+}
+
+export interface StrutStyle {
+ strutEnabled?: boolean;
+ fontFamilies?: string[];
+ fontStyle?: FontStyle;
+ fontSize?: number;
+ heightMultiplier?: number;
+ halfLeading?: boolean;
+ leading?: number;
+ forceStrutHeight?: boolean;
+}
+
+export interface TextFontFeatures {
+ name: string;
+ value: number;
+}
+
+export interface TextShadow {
+ color?: InputColor;
+ /**
+ * 2d array for x and y offset. Defaults to [0, 0]
+ */
+ offset?: number[];
+ blurRadius?: number;
+}
+
+export interface TextStyle {
+ backgroundColor?: InputColor;
+ color?: InputColor;
+ decoration?: number;
+ decorationColor?: InputColor;
+ decorationThickness?: number;
+ decorationStyle?: DecorationStyle;
+ fontFamilies?: string[];
+ fontFeatures?: TextFontFeatures[];
+ fontSize?: number;
+ fontStyle?: FontStyle;
+ foregroundColor?: InputColor;
+ heightMultiplier?: number;
+ halfLeading?: boolean;
+ letterSpacing?: number;
+ locale?: string;
+ shadows?: TextShadow[];
+ textBaseline?: TextBaseline;
+ wordSpacing?: number;
+}
+
+export interface TonalColorsInput {
+ ambient: InputColor;
+ spot: InputColor;
+}
+
+export interface TonalColorsOutput {
+ ambient: Color;
+ spot: Color;
+}
+
+export interface TypefaceFontProvider extends EmbindObject<TypefaceFontProvider> {
+ /**
+ * Registers a given typeface with the given family name (ignoring whatever name the
+ * typface has for itself).
+ * @param bytes - the raw bytes for a typeface.
+ * @param family
+ */
+ registerFont(bytes: ArrayBuffer | Uint8Array, family: string): void;
+}
+
+export interface URange {
+ start: number;
+ end: number;
+}
+
+/**
+ * Options for configuring a WebGL context. If an option is omitted, a sensible default will
+ * be used. These are defined by the WebGL standards.
+ */
+export interface WebGLOptions {
+ alpha?: number;
+ antialias?: number;
+ depth?: number;
+ enableExtensionsByDefault?: number;
+ explicitSwapControl?: number;
+ failIfMajorPerformanceCaveat?: number;
+ majorVersion?: number;
+ minorVersion?: number;
+ preferLowPowerToHighPerformance?: number;
+ premultipliedAlpha?: number;
+ preserveDrawingBuffer?: number;
+ renderViaOffscreenBackBuffer?: number;
+ stencil?: number;
+}
+
+export interface DefaultConstructor<T> {
+ new (): T;
+}
+
+export interface ColorMatrixHelpers {
+ /**
+ * Returns a new ColorMatrix that is the result of multiplying outer*inner
+ * @param outer
+ * @param inner
+ */
+ concat(outer: ColorMatrix, inner: ColorMatrix): ColorMatrix;
+
+ /**
+ * Returns an identity ColorMatrix.
+ */
+ identity(): ColorMatrix;
+
+ /**
+ * Sets the 4 "special" params that will translate the colors after they are multiplied
+ * by the 4x4 matrix.
+ * @param m
+ * @param dr - delta red
+ * @param dg - delta green
+ * @param db - delta blue
+ * @param da - delta alpha
+ */
+ postTranslate(m: ColorMatrix, dr: number, dg: number, db: number, da: number): ColorMatrix;
+
+ /**
+ * Returns a new ColorMatrix that is rotated around a given axis.
+ * @param axis - 0 for red, 1 for green, 2 for blue
+ * @param sine - sin(angle)
+ * @param cosine - cos(angle)
+ */
+ rotated(axis: number, sine: number, cosine: number): ColorMatrix;
+
+ /**
+ * Returns a new ColorMatrix that scales the colors as specified.
+ * @param redScale
+ * @param greenScale
+ * @param blueScale
+ * @param alphaScale
+ */
+ scaled(redScale: number, greenScale: number, blueScale: number,
+ alphaScale: number): ColorMatrix;
+}
+
+/**
+ * A constructor for making an ImageData that is compatible with the Canvas2D emulation code.
+ */
+export interface ImageDataConstructor {
+ new (width: number, height: number): EmulatedImageData;
+ new (pixels: Uint8ClampedArray, width: number, height: number): EmulatedImageData;
+}
+
+/**
+ * TODO(kjlubick) Make this API return Float32Arrays
+ */
+export interface Matrix3x3Helpers {
+ /**
+ * Returns a new identity 3x3 matrix.
+ */
+ identity(): number[];
+
+ /**
+ * Returns the inverse of the given 3x3 matrix or null if it is not invertible.
+ * @param m
+ */
+ invert(m: Matrix3x3 | number[]): number[] | null;
+
+ /**
+ * Maps the given 2d points according to the given 3x3 matrix.
+ * @param m
+ * @param points - the flattened points to map; the results are computed in place on this array.
+ */
+ mapPoints(m: Matrix3x3 | number[], points: number[]): number[];
+
+ /**
+ * Multiplies the provided 3x3 matrices together from left to right.
+ * @param matrices
+ */
+ multiply(...matrices: Array<(Matrix3x3 | number[])>): number[];
+
+ /**
+ * Returns a new 3x3 matrix representing a rotation by n radians.
+ * @param radians
+ * @param px - the X value to rotate around, defaults to 0.
+ * @param py - the Y value to rotate around, defaults to 0.
+ */
+ rotated(radians: AngleInRadians, px?: number, py?: number): number[];
+
+ /**
+ * Returns a new 3x3 matrix representing a scale in the x and y directions.
+ * @param sx - the scale in the X direction.
+ * @param sy - the scale in the Y direction.
+ * @param px - the X value to scale from, defaults to 0.
+ * @param py - the Y value to scale from, defaults to 0.
+ */
+ scaled(sx: number, sy: number, px?: number, py?: number): number[];
+
+ /**
+ * Returns a new 3x3 matrix representing a scale in the x and y directions.
+ * @param kx - the kurtosis in the X direction.
+ * @param ky - the kurtosis in the Y direction.
+ * @param px - the X value to skew from, defaults to 0.
+ * @param py - the Y value to skew from, defaults to 0.
+ */
+ skewed(kx: number, ky: number, px?: number, py?: number): number[];
+
+ /**
+ * Returns a new 3x3 matrix representing a translation in the x and y directions.
+ * @param dx
+ * @param dy
+ */
+ translated(dx: number, dy: number): number[];
+}
+
+/**
+ * See SkM44.h for more details.
+ */
+export interface Matrix4x4Helpers {
+ /**
+ * Returns a new identity 4x4 matrix.
+ */
+ identity(): number[];
+
+ /**
+ * Returns the inverse of the given 4x4 matrix or null if it is not invertible.
+ * @param matrix
+ */
+ invert(matrix: Matrix4x4 | number[]): number[] | null;
+
+ /**
+ * Return a new 4x4 matrix representing a camera at eyeVec, pointed at centerVec.
+ * @param eyeVec
+ * @param centerVec
+ * @param upVec
+ */
+ lookat(eyeVec: Vector3, centerVec: Vector3, upVec: Vector3): number[];
+
+ /**
+ * Multiplies the provided 4x4 matrices together from left to right.
+ * @param matrices
+ */
+ multiply(...matrices: Array<(Matrix4x4 | number[])>): number[];
+
+ /**
+ * Returns the inverse of the given 4x4 matrix or throws if it is not invertible.
+ * @param matrix
+ */
+ mustInvert(matrix: Matrix4x4 | number[]): number[];
+
+ /**
+ * Returns a new 4x4 matrix representing a perspective.
+ * @param near
+ * @param far
+ * @param radians
+ */
+ perspective(near: number, far: number, radians: AngleInRadians): number[];
+
+ /**
+ * Returns the value at the specified row and column of the given 4x4 matrix.
+ * @param matrix
+ * @param row
+ * @param col
+ */
+ rc(matrix: Matrix4x4 | number[], row: number, col: number): number;
+
+ /**
+ * Returns a new 4x4 matrix representing a rotation around the provided vector.
+ * @param axis
+ * @param radians
+ */
+ rotated(axis: Vector3, radians: AngleInRadians): number[];
+
+ /**
+ * Returns a new 4x4 matrix representing a rotation around the provided vector.
+ * Rotation is provided redundantly as both sin and cos values.
+ * This rotate can be used when you already have the cosAngle and sinAngle values
+ * so you don't have to atan(cos/sin) to call roatated() which expects an angle in radians.
+ * This does no checking! Behavior for invalid sin or cos values or non-normalized axis vectors
+ * is incorrect. Prefer rotated().
+ * @param axis
+ * @param sinAngle
+ * @param cosAngle
+ */
+ rotatedUnitSinCos(axis: Vector3, sinAngle: number, cosAngle: number): number[];
+
+ /**
+ * Returns a new 4x4 matrix representing a scale by the provided vector.
+ * @param vec
+ */
+ scaled(vec: Vector3): number[];
+
+ /**
+ * Returns a new 4x4 matrix that sets up a 3D perspective view from a given camera.
+ * @param area - describes the viewport. (0, 0, canvas_width, canvas_height) suggested.
+ * @param zScale - describes the scale of the z axis. min(width, height)/2 suggested
+ * @param cam
+ */
+ setupCamera(area: InputRect, zScale: number, cam: Camera): number[];
+
+ /**
+ * Returns a new 4x4 matrix representing a translation by the provided vector.
+ * @param vec
+ */
+ translated(vec: Vector3): number[];
+
+ /**
+ * Returns a new 4x4 matrix that is the transpose of this 4x4 matrix.
+ * @param matrix
+ */
+ transpose(matrix: Matrix4x4 | number[]): number[];
+}
+
+export interface ParagraphBuilderFactory {
+ /**
+ * Creates a ParagraphBuilder using the fonts available from the given font manager.
+ * @param style
+ * @param fontManager
+ */
+ Make(style: ParagraphStyle, fontManager: FontMgr): ParagraphBuilder;
+
+ /**
+ * Creates a ParagraphBuilder using the fonts available from the given font provider.
+ * @param style
+ * @param fontSrc
+ */
+ MakeFromFontProvider(style: ParagraphStyle, fontSrc: TypefaceFontProvider): ParagraphBuilder;
+
+ /**
+ * Return a shaped array of lines
+ */
+ ShapeText(text: string, runs: FontBlock[], width?: number): ShapedLine[];
+}
+
+export interface ParagraphStyleConstructor {
+ /**
+ * Fills out all optional fields with defaults. The emscripten bindings complain if there
+ * is a field undefined and it was expecting a float (for example).
+ * @param ps
+ */
+ new(ps: ParagraphStyle): ParagraphStyle;
+}
+
+/**
+ * See SkColorFilter.h for more.
+ */
+export interface ColorFilterFactory {
+ /**
+ * Makes a color filter with the given color and blend mode.
+ * @param color
+ * @param mode
+ */
+ MakeBlend(color: InputColor, mode: BlendMode): ColorFilter;
+
+ /**
+ * Makes a color filter composing two color filters.
+ * @param outer
+ * @param inner
+ */
+ MakeCompose(outer: ColorFilter, inner: ColorFilter): ColorFilter;
+
+ /**
+ * Makes a color filter that is linearly interpolated between two other color filters.
+ * @param t - a float in the range of 0.0 to 1.0.
+ * @param dst
+ * @param src
+ */
+ MakeLerp(t: number, dst: ColorFilter, src: ColorFilter): ColorFilter;
+
+ /**
+ * Makes a color filter that converts between linear colors and sRGB colors.
+ */
+ MakeLinearToSRGBGamma(): ColorFilter;
+
+ /**
+ * Creates a color filter using the provided color matrix.
+ * @param cMatrix
+ */
+ MakeMatrix(cMatrix: InputColorMatrix): ColorFilter;
+
+ /**
+ * Makes a color filter that converts between sRGB colors and linear colors.
+ */
+ MakeSRGBToLinearGamma(): ColorFilter;
+}
+
+export interface ContourMeasureIterConstructor {
+ /**
+ * Creates an ContourMeasureIter with the given path.
+ * @param path
+ * @param forceClosed - if path should be forced close before measuring it.
+ * @param resScale - controls the precision of the measure. values > 1 increase the
+ * precision (and possibly slow down the computation).
+ */
+ new (path: Path, forceClosed: boolean, resScale: number): ContourMeasureIter;
+}
+
+/**
+ * See SkFont.h for more.
+ */
+export interface FontConstructor extends DefaultConstructor<Font> {
+ /**
+ * Constructs Font with default values with Typeface.
+ * @param face
+ * @param size - font size in points. If not specified, uses a default value.
+ */
+ new (face: Typeface | null, size?: number): Font;
+
+ /**
+ * Constructs Font with default values with Typeface and size in points,
+ * horizontal scale, and horizontal skew. Horizontal scale emulates condensed
+ * and expanded fonts. Horizontal skew emulates oblique fonts.
+ * @param face
+ * @param size
+ * @param scaleX
+ * @param skewX
+ */
+ new (face: Typeface | null, size: number, scaleX: number, skewX: number): Font;
+}
+
+export interface FontMgrFactory {
+ /**
+ * Create an FontMgr with the created font data. Returns null if buffers was empty.
+ * @param buffers
+ */
+ FromData(...buffers: ArrayBuffer[]): FontMgr | null;
+}
+
+/**
+ * See effects/ImageFilters.h for more.
+ */
+export interface ImageFilterFactory {
+ /**
+ * Create a filter that blurs its input by the separate X and Y sigmas. The provided tile mode
+ * is used when the blur kernel goes outside the input image.
+ *
+ * @param sigmaX - The Gaussian sigma value for blurring along the X axis.
+ * @param sigmaY - The Gaussian sigma value for blurring along the Y axis.
+ * @param mode
+ * @param input - if null, it will use the dynamic source image (e.g. a saved layer)
+ */
+ MakeBlur(sigmaX: number, sigmaY: number, mode: TileMode,
+ input: ImageFilter | null): ImageFilter;
+
+ /**
+ * Create a filter that applies the color filter to the input filter results.
+ * @param cf
+ * @param input - if null, it will use the dynamic source image (e.g. a saved layer)
+ */
+ MakeColorFilter(cf: ColorFilter, input: ImageFilter | null): ImageFilter;
+
+ /**
+ * Create a filter that composes 'inner' with 'outer', such that the results of 'inner' are
+ * treated as the source bitmap passed to 'outer'.
+ * If either param is null, the other param will be returned.
+ * @param outer
+ * @param inner - if null, it will use the dynamic source image (e.g. a saved layer)
+ */
+ MakeCompose(outer: ImageFilter | null, inner: ImageFilter | null): ImageFilter;
+
+ /**
+ * Create a filter that transforms the input image by 'matrix'. This matrix transforms the
+ * local space, which means it effectively happens prior to any transformation coming from the
+ * Canvas initiating the filtering.
+ * @param matr
+ * @param sampling
+ * @param input - if null, it will use the dynamic source image (e.g. a saved layer)
+ */
+ MakeMatrixTransform(matr: InputMatrix, sampling: FilterOptions | CubicResampler,
+ input: ImageFilter | null): ImageFilter;
+}
+
+/**
+ * See SkMaskFilter.h for more details.
+ */
+export interface MaskFilterFactory {
+ /**
+ * Create a blur maskfilter
+ * @param style
+ * @param sigma - Standard deviation of the Gaussian blur to apply. Must be > 0.
+ * @param respectCTM - if true the blur's sigma is modified by the CTM.
+ */
+ MakeBlur(style: BlurStyle, sigma: number, respectCTM: boolean): MaskFilter;
+}
+
+/**
+ * Contains the ways to create an Path.
+ */
+export interface PathConstructorAndFactory extends DefaultConstructor<Path> {
+ /**
+ * Creates a new path from the given list of path commands. If this fails, null will be
+ * returned instead.
+ * @param cmds
+ */
+ MakeFromCmds(cmds: InputCommands): Path | null;
+
+ /**
+ * Creates a new path by combining the given paths according to op. If this fails, null will
+ * be returned instead.
+ * @param one
+ * @param two
+ * @param op
+ */
+ MakeFromOp(one: Path, two: Path, op: PathOp): Path | null;
+
+ /**
+ * Creates a new path from the provided SVG string. If this fails, null will be
+ * returned instead.
+ * @param str
+ */
+ MakeFromSVGString(str: string): Path | null;
+
+ /**
+ * Creates a new path using the provided verbs and associated points and weights. The process
+ * reads the first verb from verbs and then the appropriate number of points from the
+ * FlattenedPointArray (e.g. 2 points for moveTo, 4 points for quadTo, etc). If the verb is
+ * a conic, a weight will be read from the WeightList.
+ * If the data is malformed (e.g. not enough points), the resulting path will be incomplete.
+ * @param verbs - the verbs that create this path, in the order of being drawn.
+ * @param points - represents n points with 2n floats.
+ * @param weights - used if any of the verbs are conics, can be omitted otherwise.
+ */
+ MakeFromVerbsPointsWeights(verbs: VerbList, points: InputFlattenedPointArray,
+ weights?: WeightList): Path;
+}
+
+/**
+ * See SkPathEffect.h for more details.
+ */
+export interface PathEffectFactory {
+ /**
+ * Returns a PathEffect that can turn sharp corners into rounded corners.
+ * @param radius - if <=0, returns null
+ */
+ MakeCorner(radius: number): PathEffect | null;
+
+ /**
+ * Returns a PathEffect that add dashes to the path.
+ *
+ * See SkDashPathEffect.h for more details.
+ *
+ * @param intervals - even number of entries with even indicies specifying the length of
+ * the "on" intervals, and the odd indices specifying the length of "off".
+ * @param phase - offset length into the intervals array. Defaults to 0.
+ */
+ MakeDash(intervals: number[], phase?: number): PathEffect;
+
+ /**
+ * Returns a PathEffect that breaks path into segments of segLength length, and randomly move
+ * the endpoints away from the original path by a maximum of deviation.
+ * @param segLength - length of the subsegments.
+ * @param dev - limit of the movement of the endpoints.
+ * @param seedAssist - modifies the randomness. See SkDiscretePathEffect.h for more.
+ */
+ MakeDiscrete(segLength: number, dev: number, seedAssist: number): PathEffect;
+
+ /**
+ * Returns a PathEffect that will fill the drawing path with a pattern made by applying
+ * the given matrix to a repeating set of infinitely long lines of the given width.
+ * For example, the scale of the provided matrix will determine how far apart the lines
+ * should be drawn its rotation affects the lines' orientation.
+ * @param width - must be >= 0
+ * @param matrix
+ */
+ MakeLine2D(width: number, matrix: InputMatrix): PathEffect | null;
+
+ /**
+ * Returns a PathEffect which implements dashing by replicating the specified path.
+ * @param path The path to replicate (dash)
+ * @param advance The space between instances of path
+ * @param phase distance (mod advance) along path for its initial position
+ * @param style how to transform path at each point (based on the current
+ * position and tangent)
+ */
+ MakePath1D(path: Path, advance: number, phase: number, style: Path1DEffectStyle):
+ PathEffect | null;
+
+ /**
+ * Returns a PathEffect that will fill the drawing path with a pattern by repeating the
+ * given path according to the provided matrix. For example, the scale of the matrix
+ * determines how far apart the path instances should be drawn.
+ * @param matrix
+ * @param path
+ */
+ MakePath2D(matrix: InputMatrix, path: Path): PathEffect | null;
+}
+
+/**
+ * See RuntimeEffect.h for more details.
+ */
+export interface DebugTrace extends EmbindObject<DebugTrace> {
+ writeTrace(): string;
+}
+
+export interface TracedShader {
+ shader: Shader;
+ debugTrace: DebugTrace;
+}
+
+export interface RuntimeEffectFactory {
+ /**
+ * Compiles a RuntimeEffect from the given shader code.
+ * @param sksl - Source code for a shader written in SkSL
+ * @param callback - will be called with any compilation error. If not provided, errors will
+ * be printed to console.log().
+ */
+ Make(sksl: string, callback?: (err: string) => void): RuntimeEffect | null;
+
+ /**
+ * Adds debug tracing to an existing RuntimeEffect.
+ * @param shader - An already-assembled shader, created with RuntimeEffect.makeShader.
+ * @param traceCoordX - the X coordinate of the device-space pixel to trace
+ * @param traceCoordY - the Y coordinate of the device-space pixel to trace
+ */
+ MakeTraced(shader: Shader, traceCoordX: number, traceCoordY: number): TracedShader;
+}
+
+/**
+ * For more information, see SkShaders.h.
+ */
+export interface ShaderFactory {
+ /**
+ * Returns a shader that combines the given shaders with a BlendMode.
+ * @param mode
+ * @param one
+ * @param two
+ */
+ MakeBlend(mode: BlendMode, one: Shader, two: Shader): Shader;
+
+ /**
+ * Returns a shader with a given color and colorspace.
+ * @param color
+ * @param space
+ */
+ MakeColor(color: InputColor, space: ColorSpace): Shader;
+
+ /**
+ * Returns a shader with Perlin Fractal Noise.
+ * See SkPerlinNoiseShader.h for more details
+ * @param baseFreqX - base frequency in the X direction; range [0.0, 1.0]
+ * @param baseFreqY - base frequency in the Y direction; range [0.0, 1.0]
+ * @param octaves
+ * @param seed
+ * @param tileW - if this and tileH are non-zero, the frequencies will be modified so that the
+ * noise will be tileable for the given size.
+ * @param tileH - if this and tileW are non-zero, the frequencies will be modified so that the
+ * noise will be tileable for the given size.
+ */
+ MakeFractalNoise(baseFreqX: number, baseFreqY: number, octaves: number, seed: number,
+ tileW: number, tileH: number): Shader;
+
+ /**
+ * Returns a shader that generates a linear gradient between the two specified points.
+ * See SkGradientShader.h for more.
+ * @param start
+ * @param end
+ * @param colors - colors to be distributed between start and end.
+ * @param pos - May be null. The relative positions of colors. If supplied must be same length
+ * as colors.
+ * @param mode
+ * @param localMatrix
+ * @param flags - By default gradients will interpolate their colors in unpremul space
+ * and then premultiply each of the results. By setting this to 1, the
+ * gradients will premultiply their colors first, and then interpolate
+ * between them.
+ * @param colorSpace
+ */
+ MakeLinearGradient(start: InputPoint, end: InputPoint, colors: InputFlexibleColorArray,
+ pos: number[] | null, mode: TileMode, localMatrix?: InputMatrix,
+ flags?: number, colorSpace?: ColorSpace): Shader;
+
+ /**
+ * Returns a shader that generates a radial gradient given the center and radius.
+ * See SkGradientShader.h for more.
+ * @param center
+ * @param radius
+ * @param colors - colors to be distributed between the center and edge.
+ * @param pos - May be null. The relative positions of colors. If supplied must be same length
+ * as colors. Range [0.0, 1.0]
+ * @param mode
+ * @param localMatrix
+ * @param flags - 0 to interpolate colors in unpremul, 1 to interpolate colors in premul.
+ * @param colorSpace
+ */
+ MakeRadialGradient(center: InputPoint, radius: number, colors: InputFlexibleColorArray,
+ pos: number[] | null, mode: TileMode, localMatrix?: InputMatrix,
+ flags?: number, colorSpace?: ColorSpace): Shader;
+
+ /**
+ * Returns a shader that generates a sweep gradient given a center.
+ * See SkGradientShader.h for more.
+ * @param cx
+ * @param cy
+ * @param colors - colors to be distributed around the center, within the provided angles.
+ * @param pos - May be null. The relative positions of colors. If supplied must be same length
+ * as colors. Range [0.0, 1.0]
+ * @param mode
+ * @param localMatrix
+ * @param flags - 0 to interpolate colors in unpremul, 1 to interpolate colors in premul.
+ * @param startAngle - angle corresponding to 0.0. Defaults to 0 degrees.
+ * @param endAngle - angle corresponding to 1.0. Defaults to 360 degrees.
+ * @param colorSpace
+ */
+ MakeSweepGradient(cx: number, cy: number, colors: InputFlexibleColorArray,
+ pos: number[] | null, mode: TileMode, localMatrix?: InputMatrix | null,
+ flags?: number, startAngle?: AngleInDegrees, endAngle?: AngleInDegrees,
+ colorSpace?: ColorSpace): Shader;
+
+ /**
+ * Returns a shader with Perlin Turbulence.
+ * See SkPerlinNoiseShader.h for more details
+ * @param baseFreqX - base frequency in the X direction; range [0.0, 1.0]
+ * @param baseFreqY - base frequency in the Y direction; range [0.0, 1.0]
+ * @param octaves
+ * @param seed
+ * @param tileW - if this and tileH are non-zero, the frequencies will be modified so that the
+ * noise will be tileable for the given size.
+ * @param tileH - if this and tileW are non-zero, the frequencies will be modified so that the
+ * noise will be tileable for the given size.
+ */
+ MakeTurbulence(baseFreqX: number, baseFreqY: number, octaves: number, seed: number,
+ tileW: number, tileH: number): Shader;
+
+ /**
+ * Returns a shader that generates a conical gradient given two circles.
+ * See SkGradientShader.h for more.
+ * @param start
+ * @param startRadius
+ * @param end
+ * @param endRadius
+ * @param colors
+ * @param pos
+ * @param mode
+ * @param localMatrix
+ * @param flags
+ * @param colorSpace
+ */
+ MakeTwoPointConicalGradient(start: InputPoint, startRadius: number, end: InputPoint,
+ endRadius: number, colors: InputFlexibleColorArray,
+ pos: number[] | null, mode: TileMode, localMatrix?: InputMatrix,
+ flags?: number, colorSpace?: ColorSpace): Shader;
+}
+
+/**
+ * See SkTextBlob.h for more details.
+ */
+export interface TextBlobFactory {
+ /**
+ * Return a TextBlob with a single run of text.
+ *
+ * It does not perform typeface fallback for characters not found in the Typeface.
+ * It does not perform kerning or other complex shaping; glyphs are positioned based on their
+ * default advances.
+ * @param glyphs - if using Malloc'd array, be sure to use CanvasKit.MallocGlyphIDs().
+ * @param font
+ */
+ MakeFromGlyphs(glyphs: InputGlyphIDArray, font: Font): TextBlob;
+
+ /**
+ * Returns a TextBlob built from a single run of text with rotation, scale, and translations.
+ *
+ * It uses the default character-to-glyph mapping from the typeface in the font.
+ * @param str
+ * @param rsxforms
+ * @param font
+ */
+ MakeFromRSXform(str: string, rsxforms: InputFlattenedRSXFormArray, font: Font): TextBlob;
+
+ /**
+ * Returns a TextBlob built from a single run of text with rotation, scale, and translations.
+ *
+ * @param glyphs - if using Malloc'd array, be sure to use CanvasKit.MallocGlyphIDs().
+ * @param rsxforms
+ * @param font
+ */
+ MakeFromRSXformGlyphs(glyphs: InputGlyphIDArray, rsxforms: InputFlattenedRSXFormArray,
+ font: Font): TextBlob;
+
+ /**
+ * Return a TextBlob with a single run of text.
+ *
+ * It uses the default character-to-glyph mapping from the typeface in the font.
+ * It does not perform typeface fallback for characters not found in the Typeface.
+ * It does not perform kerning or other complex shaping; glyphs are positioned based on their
+ * default advances.
+ * @param str
+ * @param font
+ */
+ MakeFromText(str: string, font: Font): TextBlob;
+
+ /**
+ * Returns a TextBlob that has the glyphs following the contours of the given path.
+ *
+ * It is a convenience wrapper around MakeFromRSXform and ContourMeasureIter.
+ * @param str
+ * @param path
+ * @param font
+ * @param initialOffset - the length in pixels to start along the path.
+ */
+ MakeOnPath(str: string, path: Path, font: Font, initialOffset?: number): TextBlob;
+}
+
+export interface TextStyleConstructor {
+ /**
+ * Fills out all optional fields with defaults. The emscripten bindings complain if there
+ * is a field undefined and it was expecting a float (for example).
+ * @param ts
+ */
+ new(ts: TextStyle): TextStyle;
+}
+
+export interface TypefaceFactory {
+ /**
+ * Create a typeface using Freetype from the specified bytes and return it. CanvasKit supports
+ * .ttf, .woff and .woff2 fonts. It returns null if the bytes cannot be decoded.
+ * @param fontData
+ */
+ MakeFreeTypeFaceFromData(fontData: ArrayBuffer): Typeface | null;
+}
+
+export interface TypefaceFontProviderFactory {
+ /**
+ * Return an empty TypefaceFontProvider
+ */
+ Make(): TypefaceFontProvider;
+}
+
+/**
+ * Functions for manipulating vectors. It is Loosely based off of SkV3 in SkM44.h but Skia
+ * also has SkVec2 and Skv4. This combines them and works on vectors of any length.
+ */
+export interface VectorHelpers {
+ /**
+ * Adds 2 vectors together, term by term, returning a new Vector.
+ * @param a
+ * @param b
+ */
+ add(a: VectorN, b: VectorN): VectorN;
+
+ /**
+ * Returns the cross product of the two vectors. Only works for length 3.
+ * @param a
+ * @param b
+ */
+ cross(a: Vector3, b: Vector3): Vector3;
+
+ /**
+ * Returns the length(sub(a, b))
+ * @param a
+ * @param b
+ */
+ dist(a: VectorN, b: VectorN): number;
+
+ /**
+ * Returns the dot product of the two vectors.
+ * @param a
+ * @param b
+ */
+ dot(a: VectorN, b: VectorN): number;
+
+ /**
+ * Returns the length of this vector, which is always positive.
+ * @param v
+ */
+ length(v: VectorN): number;
+
+ /**
+ * Returns the length squared of this vector.
+ * @param v
+ */
+ lengthSquared(v: VectorN): number;
+
+ /**
+ * Returns a new vector which is v multiplied by the scalar s.
+ * @param v
+ * @param s
+ */
+ mulScalar(v: VectorN, s: number): VectorN;
+
+ /**
+ * Returns a normalized vector.
+ * @param v
+ */
+ normalize(v: VectorN): VectorN;
+
+ /**
+ * Subtracts vector b from vector a (termwise).
+ * @param a
+ * @param b
+ */
+ sub(a: VectorN, b: VectorN): VectorN;
+}
+
+/**
+ * A PosTan is a Float32Array of length 4, representing a position and a tangent vector. In order,
+ * the values are [px, py, tx, ty].
+ */
+export type PosTan = Float32Array;
+/**
+ * An Color is represented by 4 floats, typically with values between 0 and 1.0. In order,
+ * the floats correspond to red, green, blue, alpha.
+ */
+export type Color = Float32Array;
+export type ColorInt = number; // deprecated, prefer Color
+/**
+ * An ColorMatrix is a 4x4 color matrix that transforms the 4 color channels
+ * with a 1x4 matrix that post-translates those 4 channels.
+ * For example, the following is the layout with the scale (S) and post-transform
+ * (PT) items indicated.
+ * RS, 0, 0, 0 | RPT
+ * 0, GS, 0, 0 | GPT
+ * 0, 0, BS, 0 | BPT
+ * 0, 0, 0, AS | APT
+ */
+export type ColorMatrix = Float32Array;
+/**
+ * An IRect is represented by 4 ints. In order, the ints correspond to left, top,
+ * right, bottom. See Rect.h for more
+ */
+export type IRect = Int32Array;
+/**
+ * An Point is represented by 2 floats: (x, y).
+ */
+export type Point = Float32Array;
+/**
+ * An Rect is represented by 4 floats. In order, the floats correspond to left, top,
+ * right, bottom. See Rect.h for more
+ */
+export type Rect = Float32Array;
+/**
+ * An RRect (rectangle with rounded corners) is represented by 12 floats. In order, the floats
+ * correspond to left, top, right, bottom and then in pairs, the radiusX, radiusY for upper-left,
+ * upper-right, lower-right, lower-left. See RRect.h for more.
+ */
+export type RRect = Float32Array;
+
+export type WebGLContextHandle = number;
+export type AngleInDegrees = number;
+export type AngleInRadians = number;
+export type SaveLayerFlag = number;
+
+export type TypedArrayConstructor = Float32ArrayConstructor | Int32ArrayConstructor |
+ Int16ArrayConstructor | Int8ArrayConstructor | Uint32ArrayConstructor |
+ Uint16ArrayConstructor | Uint8ArrayConstructor;
+export type TypedArray = Float32Array | Int32Array | Int16Array | Int8Array | Uint32Array |
+ Uint16Array | Uint8Array;
+
+export type ColorIntArray = MallocObj | Uint32Array | number[];
+/**
+ * FlattenedPointArray represents n points by 2*n float values. In order, the values should
+ * be the x, y for each point.
+ */
+export type FlattenedPointArray = Float32Array;
+/**
+ * FlattenedRectangleArray represents n rectangles by 4*n float values. In order, the values should
+ * be the top, left, right, bottom point for each rectangle.
+ */
+export type FlattenedRectangleArray = Float32Array;
+
+export type GlyphIDArray = Uint16Array;
+/**
+ * A command is a verb and then any arguments needed to fulfill that path verb.
+ * InputCommands is a flattened structure of one or more of these.
+ * Examples:
+ * [CanvasKit.MOVE_VERB, 0, 10,
+ * CanvasKit.QUAD_VERB, 20, 50, 45, 60,
+ * CanvasKit.LINE_VERB, 30, 40]
+ */
+export type InputCommands = MallocObj | Float32Array | number[];
+/**
+ * VerbList holds verb constants like CanvasKit.MOVE_VERB, CanvasKit.CUBIC_VERB.
+ */
+export type VerbList = MallocObj | Uint8Array | number[];
+/**
+ * WeightList holds weights for conics when making paths.
+ */
+export type WeightList = MallocObj | Float32Array | number[];
+
+export type Matrix4x4 = Float32Array;
+export type Matrix3x3 = Float32Array;
+export type Matrix3x2 = Float32Array;
+/**
+ * Vector3 represents an x, y, z coordinate or vector. It has length 3.
+ */
+export type Vector3 = number[];
+
+/**
+ * VectorN represents a vector of length n.
+ */
+export type VectorN = number[];
+
+/**
+ * CanvasKit APIs accept normal arrays, typed arrays, or Malloc'd memory as colors.
+ * Length 4.
+ */
+export type InputColor = MallocObj | Color | number[];
+/**
+ * CanvasKit APIs accept normal arrays, typed arrays, or Malloc'd memory as color matrices.
+ * Length 20.
+ */
+export type InputColorMatrix = MallocObj | ColorMatrix | number[];
+/**
+ * CanvasKit APIs accept normal arrays, typed arrays, or Malloc'd memory as glyph IDs.
+ * Length n for n glyph IDs.
+ */
+export type InputGlyphIDArray = MallocObj | GlyphIDArray | number[];
+/**
+ * CanvasKit APIs accept normal arrays, typed arrays, or Malloc'd memory as flattened points.
+ * Length 2 * n for n points.
+ */
+export type InputFlattenedPointArray = MallocObj | FlattenedPointArray | number[];
+/**
+ * CanvasKit APIs accept normal arrays, typed arrays, or Malloc'd memory as flattened rectangles.
+ * Length 4 * n for n rectangles.
+ */
+export type InputFlattenedRectangleArray = MallocObj | FlattenedRectangleArray | number[];
+/**
+ * Some APIs accept a flattened array of colors in one of two ways - groups of 4 float values for
+ * r, g, b, a or just integers that have 8 bits for each these. CanvasKit will detect which one
+ * it is and act accordingly. Additionally, this can be an array of Float32Arrays of length 4
+ * (e.g. Color). This is convenient for things like gradients when matching up colors to stops.
+ */
+export type InputFlexibleColorArray = Float32Array | Uint32Array | Float32Array[];
+/**
+ * CanvasKit APIs accept a Float32Array or a normal array (of length 2) as a Point.
+ */
+export type InputPoint = Point | number[];
+/**
+ * CanvasKit APIs accept all of these matrix types. Under the hood, we generally use 4x4 matrices.
+ */
+export type InputMatrix = MallocObj | Matrix4x4 | Matrix3x3 | Matrix3x2 | DOMMatrix | number[];
+/**
+ * CanvasKit APIs accept normal arrays, typed arrays, or Malloc'd memory as rectangles.
+ * Length 4.
+ */
+export type InputRect = MallocObj | Rect | number[];
+/**
+ * CanvasKit APIs accept normal arrays, typed arrays, or Malloc'd memory as (int) rectangles.
+ * Length 4.
+ */
+export type InputIRect = MallocObj | IRect | number[];
+/**
+ * CanvasKit APIs accept normal arrays, typed arrays, or Malloc'd memory as rectangles with
+ * rounded corners. Length 12.
+ */
+export type InputRRect = MallocObj | RRect | number[];
+/**
+ * This represents n RSXforms by 4*n float values. In order, the values should
+ * be scos, ssin, tx, ty for each RSXForm. See RSXForm.h for more details.
+ */
+export type InputFlattenedRSXFormArray = MallocObj | Float32Array | number[];
+/**
+ * CanvasKit APIs accept normal arrays, typed arrays, or Malloc'd memory as a vector of 3 floats.
+ * For example, this is the x, y, z coordinates.
+ */
+export type InputVector3 = MallocObj | Vector3 | Float32Array;
+/**
+ * These are the types that webGL's texImage2D supports as a way to get data from as a texture.
+ * Not listed, but also supported are https://developer.mozilla.org/en-US/docs/Web/API/VideoFrame
+ */
+export type TextureSource = TypedArray | HTMLImageElement | HTMLVideoElement | ImageData | ImageBitmap;
+
+export type AlphaType = EmbindEnumEntity;
+export type BlendMode = EmbindEnumEntity;
+export type BlurStyle = EmbindEnumEntity;
+export type ClipOp = EmbindEnumEntity;
+export type ColorSpace = EmbindObject<ColorSpace>;
+export type ColorType = EmbindEnumEntity;
+export type EncodedImageFormat = EmbindEnumEntity;
+export type FillType = EmbindEnumEntity;
+export type FilterMode = EmbindEnumEntity;
+export type FontEdging = EmbindEnumEntity;
+export type FontHinting = EmbindEnumEntity;
+export type MipmapMode = EmbindEnumEntity;
+export type PaintStyle = EmbindEnumEntity;
+export type Path1DEffectStyle = EmbindEnumEntity;
+export type PathOp = EmbindEnumEntity;
+export type PointMode = EmbindEnumEntity;
+export type StrokeCap = EmbindEnumEntity;
+export type StrokeJoin = EmbindEnumEntity;
+export type TileMode = EmbindEnumEntity;
+export type VertexMode = EmbindEnumEntity;
+
+export type Affinity = EmbindEnumEntity;
+export type DecorationStyle = EmbindEnumEntity;
+export type FontSlant = EmbindEnumEntity;
+export type FontWeight = EmbindEnumEntity;
+export type FontWidth = EmbindEnumEntity;
+export type PlaceholderAlignment = EmbindEnumEntity;
+export type RectHeightStyle = EmbindEnumEntity;
+export type RectWidthStyle = EmbindEnumEntity;
+export type TextAlign = EmbindEnumEntity;
+export type TextBaseline = EmbindEnumEntity;
+export type TextDirection = EmbindEnumEntity;
+export type TextHeightBehavior = EmbindEnumEntity;
+
+export interface AffinityEnumValues extends EmbindEnum {
+ Upstream: Affinity;
+ Downstream: Affinity;
+}
+
+export interface AlphaTypeEnumValues extends EmbindEnum {
+ Opaque: AlphaType;
+ Premul: AlphaType;
+ Unpremul: AlphaType;
+}
+
+export interface BlendModeEnumValues extends EmbindEnum {
+ Clear: BlendMode;
+ Src: BlendMode;
+ Dst: BlendMode;
+ SrcOver: BlendMode;
+ DstOver: BlendMode;
+ SrcIn: BlendMode;
+ DstIn: BlendMode;
+ SrcOut: BlendMode;
+ DstOut: BlendMode;
+ SrcATop: BlendMode;
+ DstATop: BlendMode;
+ Xor: BlendMode;
+ Plus: BlendMode;
+ Modulate: BlendMode;
+ Screen: BlendMode;
+ Overlay: BlendMode;
+ Darken: BlendMode;
+ Lighten: BlendMode;
+ ColorDodge: BlendMode;
+ ColorBurn: BlendMode;
+ HardLight: BlendMode;
+ SoftLight: BlendMode;
+ Difference: BlendMode;
+ Exclusion: BlendMode;
+ Multiply: BlendMode;
+ Hue: BlendMode;
+ Saturation: BlendMode;
+ Color: BlendMode;
+ Luminosity: BlendMode;
+}
+
+export interface BlurStyleEnumValues extends EmbindEnum {
+ Normal: BlurStyle;
+ Solid: BlurStyle;
+ Outer: BlurStyle;
+ Inner: BlurStyle;
+}
+
+export interface ClipOpEnumValues extends EmbindEnum {
+ Difference: ClipOp;
+ Intersect: ClipOp;
+}
+
+/**
+ * The currently supported color spaces. These are all singleton values.
+ */
+export interface ColorSpaceEnumValues { // not a typical enum, but effectively like one.
+ // These are all singleton values - don't call delete on them.
+ readonly SRGB: ColorSpace;
+ readonly DISPLAY_P3: ColorSpace;
+ readonly ADOBE_RGB: ColorSpace;
+
+ /**
+ * Returns true if the two color spaces are equal.
+ * @param a
+ * @param b
+ */
+ Equals(a: ColorSpace, b: ColorSpace): boolean;
+}
+
+export interface ColorTypeEnumValues extends EmbindEnum {
+ Alpha_8: ColorType;
+ RGB_565: ColorType;
+ RGBA_8888: ColorType;
+ BGRA_8888: ColorType;
+ RGBA_1010102: ColorType;
+ RGB_101010x: ColorType;
+ Gray_8: ColorType;
+ RGBA_F16: ColorType;
+ RGBA_F32: ColorType;
+}
+
+export interface DecorationStyleEnumValues extends EmbindEnum {
+ Solid: DecorationStyle;
+ Double: DecorationStyle;
+ Dotted: DecorationStyle;
+ Dashed: DecorationStyle;
+ Wavy: DecorationStyle;
+}
+
+export interface FillTypeEnumValues extends EmbindEnum {
+ Winding: FillType;
+ EvenOdd: FillType;
+}
+
+export interface FilterModeEnumValues extends EmbindEnum {
+ Linear: FilterMode;
+ Nearest: FilterMode;
+}
+
+export interface FontEdgingEnumValues extends EmbindEnum {
+ Alias: FontEdging;
+ AntiAlias: FontEdging;
+ SubpixelAntiAlias: FontEdging;
+}
+
+export interface FontHintingEnumValues extends EmbindEnum {
+ None: FontHinting;
+ Slight: FontHinting;
+ Normal: FontHinting;
+ Full: FontHinting;
+}
+
+export interface FontSlantEnumValues extends EmbindEnum {
+ Upright: FontSlant;
+ Italic: FontSlant;
+ Oblique: FontSlant;
+}
+
+export interface FontWeightEnumValues extends EmbindEnum {
+ Invisible: FontWeight;
+ Thin: FontWeight;
+ ExtraLight: FontWeight;
+ Light: FontWeight;
+ Normal: FontWeight;
+ Medium: FontWeight;
+ SemiBold: FontWeight;
+ Bold: FontWeight;
+ ExtraBold: FontWeight;
+ Black: FontWeight;
+ ExtraBlack: FontWeight;
+}
+
+export interface FontWidthEnumValues extends EmbindEnum {
+ UltraCondensed: FontWidth;
+ ExtraCondensed: FontWidth;
+ Condensed: FontWidth;
+ SemiCondensed: FontWidth;
+ Normal: FontWidth;
+ SemiExpanded: FontWidth;
+ Expanded: FontWidth;
+ ExtraExpanded: FontWidth;
+ UltraExpanded: FontWidth;
+}
+
+/*
+ * These values can be OR'd together
+ */
+export interface GlyphRunFlagValues {
+ IsWhiteSpace: number;
+}
+
+export interface ImageFormatEnumValues extends EmbindEnum {
+ // TODO(kjlubick) When these are compiled in depending on the availability of the codecs,
+ // be sure to make these nullable.
+ PNG: EncodedImageFormat;
+ JPEG: EncodedImageFormat;
+ WEBP: EncodedImageFormat;
+}
+
+export interface MipmapModeEnumValues extends EmbindEnum {
+ None: MipmapMode;
+ Nearest: MipmapMode;
+ Linear: MipmapMode;
+}
+
+export interface PaintStyleEnumValues extends EmbindEnum {
+ Fill: PaintStyle;
+ Stroke: PaintStyle;
+}
+
+export interface Path1DEffectStyleEnumValues extends EmbindEnum {
+ // Translate the shape to each position
+ Translate: Path1DEffectStyle;
+ // Rotate the shape about its center
+ Rotate: Path1DEffectStyle;
+ // Transform each point and turn lines into curves
+ Morph: Path1DEffectStyle;
+}
+
+export interface PathOpEnumValues extends EmbindEnum {
+ Difference: PathOp;
+ Intersect: PathOp;
+ Union: PathOp;
+ XOR: PathOp;
+ ReverseDifference: PathOp;
+}
+
+export interface PlaceholderAlignmentEnumValues extends EmbindEnum {
+ Baseline: PlaceholderAlignment;
+ AboveBaseline: PlaceholderAlignment;
+ BelowBaseline: PlaceholderAlignment;
+ Top: PlaceholderAlignment;
+ Bottom: PlaceholderAlignment;
+ Middle: PlaceholderAlignment;
+}
+
+export interface PointModeEnumValues extends EmbindEnum {
+ Points: PointMode;
+ Lines: PointMode;
+ Polygon: PointMode;
+}
+
+export interface RectHeightStyleEnumValues extends EmbindEnum {
+ Tight: RectHeightStyle;
+ Max: RectHeightStyle;
+ IncludeLineSpacingMiddle: RectHeightStyle;
+ IncludeLineSpacingTop: RectHeightStyle;
+ IncludeLineSpacingBottom: RectHeightStyle;
+ Strut: RectHeightStyle;
+}
+
+export interface RectWidthStyleEnumValues extends EmbindEnum {
+ Tight: RectWidthStyle;
+ Max: RectWidthStyle;
+}
+
+export interface StrokeCapEnumValues extends EmbindEnum {
+ Butt: StrokeCap;
+ Round: StrokeCap;
+ Square: StrokeCap;
+}
+
+export interface StrokeJoinEnumValues extends EmbindEnum {
+ Bevel: StrokeJoin;
+ Miter: StrokeJoin;
+ Round: StrokeJoin;
+}
+
+export interface TextAlignEnumValues extends EmbindEnum {
+ Left: TextAlign;
+ Right: TextAlign;
+ Center: TextAlign;
+ Justify: TextAlign;
+ Start: TextAlign;
+ End: TextAlign;
+}
+
+export interface TextBaselineEnumValues extends EmbindEnum {
+ Alphabetic: TextBaseline;
+ Ideographic: TextBaseline;
+}
+
+export interface TextDirectionEnumValues extends EmbindEnum {
+ LTR: TextDirection;
+ RTL: TextDirection;
+}
+
+export interface TextHeightBehaviorEnumValues extends EmbindEnum {
+ All: TextHeightBehavior;
+ DisableFirstAscent: TextHeightBehavior;
+ DisableLastDescent: TextHeightBehavior;
+ DisableAll: TextHeightBehavior;
+}
+
+export interface TileModeEnumValues extends EmbindEnum {
+ Clamp: TileMode;
+ Decal: TileMode;
+ Mirror: TileMode;
+ Repeat: TileMode;
+}
+
+export interface VertexModeEnumValues extends EmbindEnum {
+ Triangles: VertexMode;
+ TrianglesStrip: VertexMode;
+ TriangleFan: VertexMode;
+}
diff --git a/third_party/skia/modules/canvaskit/npm_build/types/tsconfig.json b/third_party/skia/modules/canvaskit/npm_build/types/tsconfig.json
new file mode 100644
index 0000000..98dd08e
--- /dev/null
+++ b/third_party/skia/modules/canvaskit/npm_build/types/tsconfig.json
@@ -0,0 +1,14 @@
+{
+ "compilerOptions": {
+ "module": "commonjs",
+ "lib": ["es6", "dom"],
+ "noImplicitAny": true,
+ "noImplicitThis": true,
+ "strictNullChecks": true,
+ "strictFunctionTypes": true,
+ "noEmit": true,
+
+ "baseUrl": ".",
+ "paths": { "canvaskit-wasm": ["."] }
+ }
+}
diff --git a/third_party/skia/modules/canvaskit/npm_build/types/tslint.json b/third_party/skia/modules/canvaskit/npm_build/types/tslint.json
new file mode 100644
index 0000000..cb90cb0
--- /dev/null
+++ b/third_party/skia/modules/canvaskit/npm_build/types/tslint.json
@@ -0,0 +1,14 @@
+{
+ "extends": "dtslint/dtslint.json",
+ "rules": {
+ "no-bad-reference": true,
+ "no-declare-current-package": true,
+ "no-self-import": true,
+ "no-outside-dependencies": true,
+
+ "no-redundant-jsdoc": false,
+ "no-redundant-jsdoc-2": true,
+
+ "npm-naming": [true, { "mode": "code" }]
+ }
+}