aboutsummaryrefslogtreecommitdiff
path: root/experimental
diff options
context:
space:
mode:
authorKevin Lubick <kjlubick@google.com>2018-10-16 10:15:01 -0400
committerKevin Lubick <kjlubick@google.com>2018-10-16 14:32:28 +0000
commit3d99b1e347bef67f77c2d373f5d7824f23b0515c (patch)
tree84b926c0540830b9ffa3aa59cbfb51be128b9619 /experimental
parent1bfcbb57e6cbffed2bab932a77d5637dcbde7fa2 (diff)
downloadskqp-3d99b1e347bef67f77c2d373f5d7824f23b0515c.tar.gz
Add Correctness tests for CanvasKit
Also make a CPU only and GPU only build (although the latter still has a lot of CPU logic). Bug: skia: Change-Id: I857c2300021c2adb5344865c28e4ad3e8d332954 Reviewed-on: https://skia-review.googlesource.com/c/162022 Reviewed-by: Kevin Lubick <kjlubick@google.com>
Diffstat (limited to 'experimental')
-rw-r--r--experimental/canvaskit/Makefile25
-rw-r--r--experimental/canvaskit/canvas-kit/.gitignore1
-rw-r--r--experimental/canvaskit/canvaskit/.gitignore3
-rw-r--r--experimental/canvaskit/canvaskit/cpu_example.html (renamed from experimental/canvaskit/canvas-kit/cpu_example.html)0
-rw-r--r--experimental/canvaskit/canvaskit/example.html (renamed from experimental/canvaskit/canvas-kit/example.html)0
-rw-r--r--experimental/canvaskit/canvaskit/package.json (renamed from experimental/canvaskit/canvas-kit/package.json)0
-rw-r--r--experimental/canvaskit/canvaskit_bindings.cpp11
-rwxr-xr-xexperimental/canvaskit/compile.sh15
-rw-r--r--experimental/canvaskit/externs.js4
-rw-r--r--experimental/canvaskit/interface.js88
-rw-r--r--experimental/canvaskit/karma.conf.js72
-rw-r--r--experimental/canvaskit/package.json15
-rw-r--r--experimental/canvaskit/tests/path.spec.js166
13 files changed, 332 insertions, 68 deletions
diff --git a/experimental/canvaskit/Makefile b/experimental/canvaskit/Makefile
index 65764fb8ef..f63395dd47 100644
--- a/experimental/canvaskit/Makefile
+++ b/experimental/canvaskit/Makefile
@@ -1,25 +1,30 @@
clean:
rm -rf ../../out/canvaskit_wasm
- rm -rf ./canvas-kit/bin
+ rm -rf ./canvaskit/bin
$(MAKE) release
release:
# Does an incremental build where possible.
./compile.sh
- mkdir -p ./canvas-kit/bin
- cp ../../out/canvaskit_wasm/canvaskit.js ./canvas-kit/bin
- cp ../../out/canvaskit_wasm/canvaskit.wasm ./canvas-kit/bin
+ mkdir -p ./canvaskit/bin
+ cp ../../out/canvaskit_wasm/canvaskit.js ./canvaskit/bin
+ cp ../../out/canvaskit_wasm/canvaskit.wasm ./canvaskit/bin
debug:
# Does an incremental build where possible.
./compile.sh debug
- mkdir -p ./canvas-kit/bin
- cp ../../out/canvaskit_wasm/canvaskit.js ./canvas-kit/bin
- cp ../../out/canvaskit_wasm/canvaskit.wasm ./canvas-kit/bin
+ mkdir -p ./canvaskit/bin
+ cp ../../out/canvaskit_wasm_debug/canvaskit.js ./canvaskit/bin
+ cp ../../out/canvaskit_wasm_debug/canvaskit.wasm ./canvaskit/bin
local-example:
- rm -rf node_modules/canvas-kit
+ rm -rf node_modules/canvaskit
mkdir -p node_modules
- ln -s -T ../canvas-kit node_modules/canvas-kit
- echo "Go check out http://localhost:8000/canvas-kit/example.html"
+ ln -s -T ../canvaskit node_modules/canvaskit
+ echo "Go check out http://localhost:8000/canvaskit/example.html"
python serve.py
+
+test-continuous:
+ echo "Assuming npm install has been run by user"
+ echo "Also assuming make debug or release has also been run by a user (if needed)"
+ npx karma start ./karma.conf.js --no-single-run --watch-poll \ No newline at end of file
diff --git a/experimental/canvaskit/canvas-kit/.gitignore b/experimental/canvaskit/canvas-kit/.gitignore
deleted file mode 100644
index 6dd29b7f8d..0000000000
--- a/experimental/canvaskit/canvas-kit/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-bin/ \ No newline at end of file
diff --git a/experimental/canvaskit/canvaskit/.gitignore b/experimental/canvaskit/canvaskit/.gitignore
new file mode 100644
index 0000000000..d3c34990ba
--- /dev/null
+++ b/experimental/canvaskit/canvaskit/.gitignore
@@ -0,0 +1,3 @@
+bin/
+package-lock.json
+node_modules/ \ No newline at end of file
diff --git a/experimental/canvaskit/canvas-kit/cpu_example.html b/experimental/canvaskit/canvaskit/cpu_example.html
index f4bf85bee3..f4bf85bee3 100644
--- a/experimental/canvaskit/canvas-kit/cpu_example.html
+++ b/experimental/canvaskit/canvaskit/cpu_example.html
diff --git a/experimental/canvaskit/canvas-kit/example.html b/experimental/canvaskit/canvaskit/example.html
index 8b2fb51fad..8b2fb51fad 100644
--- a/experimental/canvaskit/canvas-kit/example.html
+++ b/experimental/canvaskit/canvaskit/example.html
diff --git a/experimental/canvaskit/canvas-kit/package.json b/experimental/canvaskit/canvaskit/package.json
index 76dd8e9922..76dd8e9922 100644
--- a/experimental/canvaskit/canvas-kit/package.json
+++ b/experimental/canvaskit/canvaskit/package.json
diff --git a/experimental/canvaskit/canvaskit_bindings.cpp b/experimental/canvaskit/canvaskit_bindings.cpp
index 82e65c7bd6..fcf0042faa 100644
--- a/experimental/canvaskit/canvaskit_bindings.cpp
+++ b/experimental/canvaskit/canvaskit_bindings.cpp
@@ -13,7 +13,6 @@
#endif
#include "SkCanvas.h"
-#include "SkCanvas.h"
#include "SkDashPathEffect.h"
#include "SkCornerPathEffect.h"
#include "SkDiscretePathEffect.h"
@@ -211,10 +210,12 @@ EMSCRIPTEN_BINDINGS(Skia) {
function("_getWebGLSurface", &getWebGLSurface, allow_raw_pointers());
function("currentContext", &emscripten_webgl_get_current_context);
function("setCurrentContext", &emscripten_webgl_make_context_current);
-#endif
+ constant("gpu", true);
+#else
function("_getRasterN32PremulSurface", optional_override([](int width, int height)->sk_sp<SkSurface> {
return SkSurface::MakeRasterN32Premul(width, height, nullptr);
}), allow_raw_pointers());
+#endif
function("MakeSkCornerPathEffect", &SkCornerPathEffect::Make, allow_raw_pointers());
function("MakeSkDiscretePathEffect", &SkDiscretePathEffect::Make, allow_raw_pointers());
// Won't be called directly, there's a JS helper to deal with typed arrays.
@@ -236,6 +237,9 @@ EMSCRIPTEN_BINDINGS(Skia) {
.function("drawPath", &SkCanvas::drawPath)
.function("drawRect", &SkCanvas::drawRect)
.function("drawText", optional_override([](SkCanvas& self, std::string text, SkScalar x, SkScalar y, const SkPaint& p) {
+ // TODO(kjlubick): This does not work well for non-ascii
+ // Need to maybe add a helper in interface.js that supports UTF-8
+ // Otherwise, go with std::wstring and set UTF-32 encoding.
self.drawText(text.c_str(), text.length(), x, y, p);
}))
.function("flush", &SkCanvas::flush)
@@ -271,7 +275,6 @@ EMSCRIPTEN_BINDINGS(Skia) {
class_<SkPathEffect>("SkPathEffect")
.smart_ptr<sk_sp<SkPathEffect>>("sk_sp<SkPathEffect>");
- //TODO make these chainable like PathKit
class_<SkPath>("SkPath")
.constructor<>()
.constructor<const SkPath&>()
@@ -297,6 +300,7 @@ EMSCRIPTEN_BINDINGS(Skia) {
.smart_ptr<sk_sp<SkSurface>>("sk_sp<SkSurface>")
.function("width", &SkSurface::width)
.function("height", &SkSurface::height)
+ .function("_flush", &SkSurface::flush)
.function("makeImageSnapshot", &SkSurface::makeImageSnapshot)
.function("_readPixels", optional_override([](SkSurface& self, int width, int height, uintptr_t /* uint8_t* */ cptr)->bool {
auto* dst = reinterpret_cast<uint8_t*>(cptr);
@@ -358,5 +362,6 @@ EMSCRIPTEN_BINDINGS(Skia) {
}), allow_raw_pointers());
function("MakeAnimation", &MakeAnimation);
+ constant("skottie", true);
#endif
}
diff --git a/experimental/canvaskit/compile.sh b/experimental/canvaskit/compile.sh
index 67be659dca..7cfdd042b4 100755
--- a/experimental/canvaskit/compile.sh
+++ b/experimental/canvaskit/compile.sh
@@ -13,8 +13,6 @@ if [[ ! -d $EMSDK ]]; then
exit 1
fi
-BUILD_DIR=${BUILD_DIR:="out/canvaskit_wasm"}
-mkdir -p $BUILD_DIR
# Navigate to SKIA_HOME from where this file is located.
pushd $BASE_DIR/../..
@@ -24,17 +22,24 @@ EMCXX=`which em++`
RELEASE_CONF="-Oz --closure 1 --llvm-lto 3 -DSK_RELEASE"
EXTRA_CFLAGS="\"-DSK_RELEASE\""
+
if [[ $@ == *debug* ]]; then
echo "Building a Debug build"
EXTRA_CFLAGS="\"-DSK_DEBUG\""
- RELEASE_CONF="-O0 --js-opts 0 -s SAFE_HEAP=1 -s ASSERTIONS=1 -s GL_ASSERTIONS=1 -g3 -DPATHKIT_TESTING -DSK_DEBUG"
+ RELEASE_CONF="-O0 --js-opts 0 -s DEMANGLE_SUPPORT=1 -s SAFE_HEAP=1 -s ASSERTIONS=1 -s GL_ASSERTIONS=1 -g3 -DPATHKIT_TESTING -DSK_DEBUG"
+ BUILD_DIR=${BUILD_DIR:="out/canvaskit_wasm_debug"}
+else
+ BUILD_DIR=${BUILD_DIR:="out/canvaskit_wasm"}
fi
+mkdir -p $BUILD_DIR
+
GN_GPU="skia_enable_gpu=true"
WASM_GPU="-lEGL -lGLESv2 -DSK_SUPPORT_GPU=1"
-if [[ $@ == *no_gpu* ]]; then
- echo "Omitting the GPU backend"
+if [[ $@ == *cpu* ]]; then
+ echo "Using the CPU backend instead of the GPU backend"
GN_GPU="skia_enable_gpu=false"
+ GN_GPU_FLAGS=""
WASM_GPU="-DSK_SUPPORT_GPU=0"
fi
diff --git a/experimental/canvaskit/externs.js b/experimental/canvaskit/externs.js
index c0f6c66444..801bad620e 100644
--- a/experimental/canvaskit/externs.js
+++ b/experimental/canvaskit/externs.js
@@ -31,6 +31,8 @@ var CanvasKit = {
MakeSkDashPathEffect: function(intervals, phase) {},
setCurrentContext: function() {},
LTRBRect: function(l, t, r, b) {},
+ gpu: {},
+ skottie: {},
// private API (i.e. things declared in the bindings that we use
// in the pre-js file)
@@ -78,9 +80,11 @@ var CanvasKit = {
SkSurface: {
// public API should go below because closure still will
// remove things declared here and not on the prototype.
+ flush: function() {},
// private API
_readPixels: function(w, h, ptr) {},
+ _flush: function() {},
}
}
diff --git a/experimental/canvaskit/interface.js b/experimental/canvaskit/interface.js
index 98be5ef1af..938ef3eda9 100644
--- a/experimental/canvaskit/interface.js
+++ b/experimental/canvaskit/interface.js
@@ -107,49 +107,55 @@
return this;
};
- CanvasKit.SkSurface.prototype.flush = function() {
- var success = this._readPixels(this._width, this._height, this._pixelPtr);
- if (!success) {
- console.err('could not read pixels');
- return;
+ if (CanvasKit.gpu) {
+ CanvasKit.getWebGLSurface = function(htmlID) {
+ var canvas = document.getElementById(htmlID);
+ if (!canvas) {
+ throw 'Canvas with id ' + htmlID + ' was not found';
+ }
+ // Maybe better to use clientWidth/height. See:
+ // https://webglfundamentals.org/webgl/lessons/webgl-anti-patterns.html
+ return this._getWebGLSurface(htmlID, canvas.width, canvas.height);
+ };
+
+ CanvasKit.SkSurface.prototype.flush = function() {
+ this._flush();
}
-
- var pixels = new Uint8ClampedArray(CanvasKit.buffer, this._pixelPtr, this._pixelLen);
- var imageData = new ImageData(pixels, this._width, this._height);
-
- this.canvas.getContext('2d').putImageData(imageData, 0, 0);
-
- };
- }
-
- CanvasKit.getWebGLSurface = function(htmlID) {
- var canvas = document.getElementById(htmlID);
- if (!canvas) {
- throw 'Canvas with id ' + htmlID + ' was not found';
+ } else {
+ CanvasKit.getRasterN32PremulSurface = function(htmlID) {
+ var canvas = document.getElementById(htmlID);
+ if (!canvas) {
+ throw 'Canvas with id ' + htmlID + ' was not found';
+ }
+ // Maybe better to use clientWidth/height. See:
+ // https://webglfundamentals.org/webgl/lessons/webgl-anti-patterns.html
+ var surface = this._getRasterN32PremulSurface(canvas.width, canvas.height);
+ if (surface) {
+ surface.canvas = canvas;
+ surface._width = canvas.width;
+ surface._height = canvas.height;
+ surface._pixelLen = surface._width * surface._height * 4; // it's 8888
+ // Allocate the buffer of pixels to be used to draw back and forth.
+ surface._pixelPtr = CanvasKit._malloc(surface._pixelLen);
+ }
+ return surface;
+ };
+
+ CanvasKit.SkSurface.prototype.flush = function() {
+ this._flush();
+ var success = this._readPixels(this._width, this._height, this._pixelPtr);
+ if (!success) {
+ console.err('could not read pixels');
+ return;
+ }
+
+ var pixels = new Uint8ClampedArray(CanvasKit.buffer, this._pixelPtr, this._pixelLen);
+ var imageData = new ImageData(pixels, this._width, this._height);
+
+ this.canvas.getContext('2d').putImageData(imageData, 0, 0);
+ };
}
- // Maybe better to use clientWidth/height. See:
- // https://webglfundamentals.org/webgl/lessons/webgl-anti-patterns.html
- return this._getWebGLSurface(htmlID, canvas.width, canvas.height);
- }
-
- CanvasKit.getRasterN32PremulSurface = function(htmlID) {
- var canvas = document.getElementById(htmlID);
- if (!canvas) {
- throw 'Canvas with id ' + htmlID + ' was not found';
- }
- // Maybe better to use clientWidth/height. See:
- // https://webglfundamentals.org/webgl/lessons/webgl-anti-patterns.html
- var surface = this._getRasterN32PremulSurface(canvas.width, canvas.height);
- if (surface) {
- surface.canvas = canvas;
- surface._width = canvas.width;
- surface._height = canvas.height;
- surface._pixelLen = surface._width * surface._height * 4; // it's 8888
- // Allocate the buffer of pixels to be used to draw back and forth.
- surface._pixelPtr = CanvasKit._malloc(surface._pixelLen);
- }
- return surface;
- }
+ } // end CanvasKit.onRuntimeInitialized, that is, anything changing prototypes or dynamic.
// Likely only used for tests.
CanvasKit.LTRBRect = function(l, t, r, b) {
diff --git a/experimental/canvaskit/karma.conf.js b/experimental/canvaskit/karma.conf.js
new file mode 100644
index 0000000000..31f5b463b7
--- /dev/null
+++ b/experimental/canvaskit/karma.conf.js
@@ -0,0 +1,72 @@
+const isDocker = require('is-docker')();
+
+module.exports = function(config) {
+ // Set the default values to be what are needed when testing the
+ // WebAssembly build locally.
+ let cfg = {
+ // frameworks to use
+ // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
+ frameworks: ['jasmine'],
+
+ // list of files / patterns to load in the browser
+ files: [
+ { pattern: 'canvaskit/bin/canvaskit.wasm', included:false, served:true},
+ '../../modules/pathkit/tests/testReporter.js',
+ 'canvaskit/bin/canvaskit.js',
+ 'tests/*.spec.js'
+ ],
+
+ proxies: {
+ '/canvaskit/': '/base/canvaskit/bin/'
+ },
+
+ // test results reporter to use
+ // possible values: 'dots', 'progress'
+ // available reporters: https://npmjs.org/browse/keyword/karma-reporter
+ reporters: ['progress'],
+
+ // web server port
+ port: 4444,
+
+ // enable / disable colors in the output (reporters and logs)
+ colors: true,
+
+ // level of logging
+ // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
+ logLevel: config.LOG_INFO,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ autoWatch: true,
+
+ browserDisconnectTimeout: 15000,
+ browserNoActivityTimeout: 15000,
+
+ // start these browsers
+ browsers: ['Chrome'],
+
+ // Continuous Integration mode
+ // if true, Karma captures browsers, runs the tests and exits
+ singleRun: false,
+
+ // Concurrency level
+ // how many browser should be started simultaneous
+ concurrency: Infinity,
+ };
+
+ if (isDocker) {
+ // See https://hackernoon.com/running-karma-tests-with-headless-chrome-inside-docker-ae4aceb06ed3
+ cfg.browsers = ['ChromeHeadlessNoSandbox'],
+ cfg.customLaunchers = {
+ ChromeHeadlessNoSandbox: {
+ base: 'ChromeHeadless',
+ flags: [
+ // Without this flag, we see an error:
+ // Failed to move to new namespace: PID namespaces supported, Network namespace supported, but failed: errno = Operation not permitted
+ '--no-sandbox'
+ ],
+ },
+ };
+ }
+
+ config.set(cfg);
+}
diff --git a/experimental/canvaskit/package.json b/experimental/canvaskit/package.json
index 9986143406..3a0a8620f0 100644
--- a/experimental/canvaskit/package.json
+++ b/experimental/canvaskit/package.json
@@ -4,15 +4,14 @@
"description": "private",
"private": true,
"main": "index.js",
- "dependencies": {
- },
+ "dependencies": {},
"devDependencies": {
- "is-docker": "^1.1.0",
- "jasmine-core": "^3.1.0",
- "karma": "^2.0.5",
- "karma-chrome-launcher": "^2.2.0",
- "karma-jasmine": "^1.1.2",
- "requirejs": "^2.3.5"
+ "is-docker": "~1.1.0",
+ "jasmine-core": "~3.1.0",
+ "karma": "~3.0.0",
+ "karma-chrome-launcher": "~2.2.0",
+ "karma-jasmine": "~1.1.2",
+ "requirejs": "~2.3.5"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
diff --git a/experimental/canvaskit/tests/path.spec.js b/experimental/canvaskit/tests/path.spec.js
new file mode 100644
index 0000000000..0be3032d15
--- /dev/null
+++ b/experimental/canvaskit/tests/path.spec.js
@@ -0,0 +1,166 @@
+
+describe('CanvasKit\'s Path Behavior', function() {
+ // Note, don't try to print the CanvasKit object - it can cause Karma/Jasmine to lock up.
+ var CanvasKit = null;
+ const LoadCanvasKit = new Promise(function(resolve, reject) {
+ if (CanvasKit) {
+ resolve();
+ } else {
+ CanvasKitInit({
+ locateFile: (file) => '/canvaskit/'+file,
+ }).then((_CanvasKit) => {
+ CanvasKit = _CanvasKit;
+ CanvasKit.initFonts();
+ resolve();
+ });
+ }
+ });
+
+ let container = document.createElement('div');
+ document.body.appendChild(container);
+ const CANVAS_WIDTH = 600;
+ const CANVAS_HEIGHT = 600;
+
+ beforeEach(function() {
+ container.innerHTML = `
+ <canvas width=600 height=600 id=test></canvas>
+ <canvas width=600 height=600 id=report></canvas>`;
+ });
+
+ afterEach(function() {
+ container.innerHTML = '';
+ });
+
+ function getSurface() {
+ if (CanvasKit.gpu) {
+ return CanvasKit.getWebGLSurface('test');
+ }
+ return CanvasKit.getRasterN32PremulSurface('test');
+ }
+
+
+ function reportSurface(surface, testname, done) {
+ // In docker, the webgl canvas is blank, but the surface has the pixel
+ // data. So, we copy it out and draw it to a normal canvas to take a picture.
+ // To be consistent across CPU and GPU, we just do it for all configurations
+ // (even though the CPU canvas shows up after flush just fine).
+ let pixelLen = CANVAS_WIDTH * CANVAS_HEIGHT * 4; // 4 bytes for r,g,b,a
+ let pixelPtr = CanvasKit._malloc(pixelLen);
+ let success = surface._readPixels(CANVAS_WIDTH, CANVAS_HEIGHT, pixelPtr);
+ if (!success) {
+ done();
+ expect(success).toBeFalsy('could not read pixels');
+ return;
+ }
+ let pixels = new Uint8ClampedArray(CanvasKit.buffer, pixelPtr, pixelLen);
+ var imageData = new ImageData(pixels, CANVAS_WIDTH, CANVAS_HEIGHT);
+
+ let reportingCanvas = document.getElementById('report');
+ reportingCanvas.getContext('2d').putImageData(imageData, 0, 0);
+ CanvasKit._free(pixelPtr);
+ reportCanvas(reportingCanvas, testname).then(() => {
+ done();
+ }).catch(reportError(done));
+ }
+
+ it('can draw a path', function(done) {
+ LoadCanvasKit.then(() => {
+ // This is taken from example.html
+ const surface = getSurface();
+ expect(surface).toBeTruthy('Could not make surface')
+ if (!surface) {
+ done();
+ return;
+ }
+ const canvas = surface.getCanvas();
+ const paint = new CanvasKit.SkPaint();
+ 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.SkPath();
+ 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.arcTo(150, 100, 50, 200, 20);
+ path.lineTo(160, 160);
+
+ path.moveTo(20, 120);
+ path.lineTo(20, 120);
+
+ path.transform([2, 0, 0,
+ 0, 2, 0,
+ 0, 0, 1 ])
+
+ canvas.drawPath(path, paint);
+ surface.flush();
+
+ path.delete();
+ paint.delete();
+
+ reportSurface(surface, 'path_api_example', done);
+ });
+ // See CanvasKit for more tests, since they share implementation
+ });
+
+ function starPath(CanvasKit, X=128, Y=128, R=116) {
+ let p = new CanvasKit.SkPath();
+ 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;
+ }
+
+ it('can apply an effect and draw text', function(done) {
+ LoadCanvasKit.then(() => {
+ const surface = getSurface();
+ expect(surface).toBeTruthy('Could not make surface')
+ if (!surface) {
+ done();
+ return;
+ }
+ const canvas = surface.getCanvas();
+ const path = starPath(CanvasKit);
+
+ const paint = new CanvasKit.SkPaint();
+
+ const textPaint = new CanvasKit.SkPaint();
+ textPaint.setColor(CanvasKit.Color(40, 0, 0, 1.0));
+ textPaint.setTextSize(30);
+ textPaint.setAntiAlias(true);
+
+ const dpe = CanvasKit.MakeSkDashPathEffect([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(path, paint);
+ canvas.drawText('This is text', 10, 280, textPaint);
+ surface.flush();
+ dpe.delete();
+ path.delete();
+
+ reportSurface(surface, 'effect_and_text_example', done);
+ });
+ });
+});