From c9498efc8e04a0eb7cb03af5a0202cf30b0b33d1 Mon Sep 17 00:00:00 2001 From: Kevin Lubick Date: Wed, 2 Sep 2020 15:20:00 -0400 Subject: [PATCH] [canvaskit] Replace RRect objects with TypedArrays. This is about 2.5x faster. Will try to do the same for Rects in a followup CL. Change-Id: Ia1ba1381435f4eee2fcf4f0cc2738e3306edd5f9 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/312304 Reviewed-by: Nathaniel Nifong --- modules/canvaskit/CHANGELOG.md | 8 ++ modules/canvaskit/canvaskit_bindings.cpp | 59 ++++-------- modules/canvaskit/externs.js | 38 ++++---- modules/canvaskit/helper.js | 12 +++ modules/canvaskit/interface.js | 111 +++++++++++++---------- modules/canvaskit/tests/canvas.spec.js | 47 +++++++--- 6 files changed, 159 insertions(+), 116 deletions(-) diff --git a/modules/canvaskit/CHANGELOG.md b/modules/canvaskit/CHANGELOG.md index 580d99562d..1522d4ef81 100644 --- a/modules/canvaskit/CHANGELOG.md +++ b/modules/canvaskit/CHANGELOG.md @@ -6,6 +6,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Breaking + - SkRRect (Rectangles with rounded corners) are no longer returned from `CanvasKit.RRectXY` + nor accepted as JS objects. Instead, the format is 12 floats in either an array, a + Float32Array or a piece of memory returned by CanvasKit.Malloc. The first 4 floats + are the left, top, right, bottom numbers of the rectangle and then 4 sets of points + starting in the upper left corner and going clockwise. This change allows for faster + transfer between JS and WASM code. + ### Changed - We now compile CanvasKit with emsdk 2.0.0 when testing and deploying to npm. - WebGL interface creation is a little leaner in terms of code size and speed. diff --git a/modules/canvaskit/canvaskit_bindings.cpp b/modules/canvaskit/canvaskit_bindings.cpp index bde7e50d92..c229ce9863 100644 --- a/modules/canvaskit/canvaskit_bindings.cpp +++ b/modules/canvaskit/canvaskit_bindings.cpp @@ -106,6 +106,19 @@ SkColor4f ptrToSkColor4f(uintptr_t /* float* */ cPtr) { return color; } +SkRRect ptrToSkRRect(uintptr_t /* float* */ fPtr) { + // In order, these floats should be 4 floats for the rectangle + // (left, top, right, bottom) and then 8 floats for the radii + // (upper left, upper right, lower right, lower left). + const SkScalar* twelveFloats = reinterpret_cast(fPtr); + const SkRect rect = reinterpret_cast(twelveFloats)[0]; + const SkVector* radiiValues = reinterpret_cast(twelveFloats + 4); + + SkRRect rr; + rr.setRectRadii(rect, radiiValues); + return rr; +} + // Surface creation structs and helpers struct SimpleImageInfo { int width; @@ -689,28 +702,6 @@ struct PosTan { SkScalar px, py, tx, ty; }; -// SimpleRRect is simpler than passing a (complex) SkRRect over the wire to JS. -struct SimpleRRect { - SkRect rect; - - SkScalar rx1; - SkScalar ry1; - SkScalar rx2; - SkScalar ry2; - SkScalar rx3; - SkScalar ry3; - SkScalar rx4; - SkScalar ry4; -}; - -SkRRect toRRect(const SimpleRRect& r) { - SkVector fRadii[4] = {{r.rx1, r.ry1}, {r.rx2, r.ry2}, - {r.rx3, r.ry3}, {r.rx4, r.ry4}}; - SkRRect rr; - rr.setRectRadii(r.rect, fRadii); - return rr; -} - // This function is private, we call it in interface.js void computeTonalColors(uintptr_t cPtrAmbi /* float * */, uintptr_t cPtrSpot /* float * */) { // private methods accepting colors take pointers to floats already copied into wasm memory. @@ -1003,8 +994,8 @@ EMSCRIPTEN_BINDINGS(Skia) { self.clear(ptrToSkColor4f(cPtr)); })) .function("clipPath", select_overload(&SkCanvas::clipPath)) - .function("clipRRect", optional_override([](SkCanvas& self, const SimpleRRect& r, SkClipOp op, bool doAntiAlias) { - self.clipRRect(toRRect(r), op, doAntiAlias); + .function("_clipRRect", optional_override([](SkCanvas& self, uintptr_t /* float* */ fPtr, SkClipOp op, bool doAntiAlias) { + self.clipRRect(ptrToSkRRect(fPtr), op, doAntiAlias); })) .function("clipRect", select_overload(&SkCanvas::clipRect)) .function("_concat", optional_override([](SkCanvas& self, uintptr_t /* SkScalar* */ mPtr) { @@ -1042,8 +1033,9 @@ EMSCRIPTEN_BINDINGS(Skia) { .function("drawColorInt", optional_override([](SkCanvas& self, SkColor color, SkBlendMode mode) { self.drawColor(color, mode); })) - .function("drawDRRect",optional_override([](SkCanvas& self, const SimpleRRect& o, const SimpleRRect& i, const SkPaint& paint) { - self.drawDRRect(toRRect(o), toRRect(i), paint); + .function("_drawDRRect",optional_override([](SkCanvas& self, uintptr_t /* float* */ outerPtr, + uintptr_t /* float* */ innerPtr, const SkPaint& paint) { + self.drawDRRect(ptrToSkRRect(outerPtr), ptrToSkRRect(innerPtr), paint); })) .function("drawAnimatedImage", optional_override([](SkCanvas& self, sk_sp& aImg, SkScalar x, SkScalar y)->void { @@ -1082,8 +1074,8 @@ EMSCRIPTEN_BINDINGS(Skia) { const SkPoint* pts = reinterpret_cast(pptr); self.drawPoints(mode, count, pts, paint); })) - .function("drawRRect",optional_override([](SkCanvas& self, const SimpleRRect& r, const SkPaint& paint) { - self.drawRRect(toRRect(r), paint); + .function("_drawRRect",optional_override([](SkCanvas& self, uintptr_t /* float* */ fPtr, const SkPaint& paint) { + self.drawRRect(ptrToSkRRect(fPtr), paint); })) .function("drawRect", &SkCanvas::drawRect) .function("drawRoundRect", &SkCanvas::drawRoundRect) @@ -1858,17 +1850,6 @@ EMSCRIPTEN_BINDINGS(Skia) { .field("fRight", &SkRect::fRight) .field("fBottom", &SkRect::fBottom); - value_object("SkRRect") - .field("rect", &SimpleRRect::rect) - .field("rx1", &SimpleRRect::rx1) - .field("ry1", &SimpleRRect::ry1) - .field("rx2", &SimpleRRect::rx2) - .field("ry2", &SimpleRRect::ry2) - .field("rx3", &SimpleRRect::rx3) - .field("ry3", &SimpleRRect::ry3) - .field("rx4", &SimpleRRect::rx4) - .field("ry4", &SimpleRRect::ry4); - value_object("SkIRect") .field("fLeft", &SkIRect::fLeft) .field("fTop", &SkIRect::fTop) diff --git a/modules/canvaskit/externs.js b/modules/canvaskit/externs.js index 4e2603eb81..e70d8c7224 100644 --- a/modules/canvaskit/externs.js +++ b/modules/canvaskit/externs.js @@ -185,13 +185,11 @@ var CanvasKit = { SkCanvas: { // public API (from C++ bindings) clipPath: function() {}, - clipRRect: function() {}, clipRect: function() {}, drawAnimatedImage: function() {}, drawArc: function() {}, drawCircle: function() {}, drawColorInt: function() {}, - drawDRRect: function() {}, drawImage: function() {}, drawImageNine: function() {}, drawImageRect: function() {}, @@ -201,7 +199,6 @@ var CanvasKit = { drawParagraph: function() {}, drawPath: function() {}, drawPicture: function() {}, - drawRRect: function() {}, drawRect: function() {}, drawRoundRect: function() {}, drawText: function() {}, @@ -223,24 +220,38 @@ var CanvasKit = { prototype: { clear: function() {}, + clipRRect: function() {}, + concat44: function() {}, // deprecated + concat: function() {}, + drawAtlas: function() {}, drawColor: function() {}, drawColorComponents: function() {}, + drawDRRect: function() {}, + drawPoints: function() {}, + drawRRect: function() {}, drawShadow: function() {}, + drawText: function() {}, + findMarkedCTM: function() {}, + getLocalToDevice: function() {}, + getTotalMatrix: function() {}, + readPixels: function() {}, + writePixels : function() {}, }, // private API _clear: function() {}, + _clipRRect: function() {}, _concat: function() {}, _drawAtlas: function() {}, _drawColor: function() {}, + _drawDRRect: function() {}, _drawPoints: function() {}, + _drawRRect: function() {}, _drawShadow: function() {}, _drawSimpleText: function() {}, - _getLocalToCamera: function() {}, - _getLocalToDevice: function() {}, - _getLocalToWorld: function() {}, - _getTotalMatrix: function() {}, _findMarkedCTM: function() {}, + _getLocalToDevice: function() {}, + _getTotalMatrix: function() {}, _readPixels: function() {}, _writePixels: function() {}, delete: function() {}, @@ -932,19 +943,6 @@ CanvasKit.SkSurface.prototype.captureFrameAsSkPicture = function() {}; CanvasKit.SkImage.prototype.encodeToData = function() {}; CanvasKit.SkImage.prototype.makeShader = function() {}; -CanvasKit.SkCanvas.prototype.concat = function() {}; -CanvasKit.SkCanvas.prototype.concat44 = function() {}; // deprecated -CanvasKit.SkCanvas.prototype.drawAtlas = function() {}; -CanvasKit.SkCanvas.prototype.drawPoints = function() {}; -CanvasKit.SkCanvas.prototype.drawText = function() {}; -CanvasKit.SkCanvas.prototype.getLocalToCamera = function() {}; -CanvasKit.SkCanvas.prototype.getLocalToDevice = function() {}; -CanvasKit.SkCanvas.prototype.getLocalToWorld = function() {}; -CanvasKit.SkCanvas.prototype.getTotalMatrix = function() {}; -/** @return {Uint8Array} */ -CanvasKit.SkCanvas.prototype.readPixels = function() {}; -CanvasKit.SkCanvas.prototype.writePixels = function() {}; - CanvasKit.SkFontMgr.prototype.MakeTypefaceFromData = function() {}; CanvasKit.SkFont.prototype.getWidths = function() {}; diff --git a/modules/canvaskit/helper.js b/modules/canvaskit/helper.js index 230b1a2306..54c777aad3 100644 --- a/modules/canvaskit/helper.js +++ b/modules/canvaskit/helper.js @@ -465,6 +465,18 @@ function copyColorFromWasm(colorPtr) { return rv; } +// These will be initialized after loading. +var _scratchRRect; +var _scratchRRectPtr = nullptr; + +var _scratchRRect2; +var _scratchRRect2Ptr = nullptr; + + +function copyRRectToWasm(twelveFloats, ptr) { + return copy1dArray(twelveFloats, "HEAPF32", ptr || _scratchRRectPtr); +} + // Caching the Float32Arrays can save having to reallocate them // over and over again. var Float32ArrayCache = {}; diff --git a/modules/canvaskit/interface.js b/modules/canvaskit/interface.js index 15fad7ddb7..3b44742ec8 100644 --- a/modules/canvaskit/interface.js +++ b/modules/canvaskit/interface.js @@ -16,6 +16,13 @@ CanvasKit.onRuntimeInitialized = function() { _scratch3x3Matrix = CanvasKit.Malloc(Float32Array, 9); // 9 matrix scalars. _scratch3x3MatrixPtr = _scratch3x3Matrix['byteOffset']; + + _scratchRRect = CanvasKit.Malloc(Float32Array, 12); // 4 scalars for rrect, 8 for radii. + _scratchRRectPtr = _scratchRRect['byteOffset']; + + _scratchRRect2 = CanvasKit.Malloc(Float32Array, 12); // 4 scalars for rrect, 8 for radii. + _scratchRRect2Ptr = _scratchRRect2['byteOffset']; + // Create single copies of all three supported color spaces // These are sk_sp CanvasKit.SkColorSpace.SRGB = CanvasKit.SkColorSpace._MakeSRGB(); @@ -312,7 +319,7 @@ CanvasKit.onRuntimeInitialized = function() { // angle is in radians. CanvasKit.SkM44.perspective = function(near, far, angle) { if (skIsDebug && (far <= near)) { - throw "far must be greater than near when constructing SkM44 using perspective."; + throw 'far must be greater than near when constructing SkM44 using perspective.'; } var dInv = 1 / (far - near); var halfAngle = angle / 2; @@ -438,7 +445,7 @@ CanvasKit.onRuntimeInitialized = function() { CanvasKit.SkM44.mustInvert = function(m) { var m2 = CanvasKit.SkM44.invert(m); if (m2 === null) { - throw "Matrix not invertible"; + throw 'Matrix not invertible'; } return m2; } @@ -568,9 +575,9 @@ CanvasKit.onRuntimeInitialized = function() { // The weights array is optional (only used for conics). CanvasKit.SkPath.MakeFromVerbsPointsWeights = function(verbs, pts, weights) { - var verbsPtr = copy1dArray(verbs, "HEAPU8"); - var pointsPtr = copy1dArray(pts, "HEAPF32"); - var weightsPtr = copy1dArray(weights, "HEAPF32"); + var verbsPtr = copy1dArray(verbs, 'HEAPU8'); + var pointsPtr = copy1dArray(pts, 'HEAPF32'); + var weightsPtr = copy1dArray(weights, 'HEAPF32'); var numWeights = (weights && weights.length) || 0; var path = CanvasKit.SkPath._MakeFromVerbsPointsWeights( verbsPtr, verbs.length, pointsPtr, pts.length, weightsPtr, numWeights); @@ -605,7 +612,7 @@ CanvasKit.onRuntimeInitialized = function() { var args = Array.prototype.slice.call(arguments); var path = args[0]; var extend = false; - if (typeof args[args.length-1] === "boolean") { + if (typeof args[args.length-1] === 'boolean') { extend = args.pop(); } if (args.length === 1) { @@ -649,7 +656,7 @@ CanvasKit.onRuntimeInitialized = function() { ptr = points.byteOffset; n = points.length/2; } else { - ptr = copy2dArray(points, "HEAPF32"); + ptr = copy2dArray(points, 'HEAPF32'); n = points.length; } this._addPoly(ptr, n, close); @@ -699,7 +706,7 @@ CanvasKit.onRuntimeInitialized = function() { SkDebug('addRoundRect needs 8 radii provided. Got ' + radii.length); return null; } - var rptr = copy1dArray(radii, "HEAPF32"); + var rptr = copy1dArray(radii, 'HEAPF32'); if (args.length === 3 || args.length === 4) { var r = args[0]; var ccw = args[args.length - 1]; @@ -714,9 +721,9 @@ CanvasKit.onRuntimeInitialized = function() { // The weights array is optional (only used for conics). CanvasKit.SkPath.prototype.addVerbsPointsWeights = function(verbs, points, weights) { - var verbsPtr = copy1dArray(verbs, "HEAPU8"); - var pointsPtr = copy1dArray(points, "HEAPF32"); - var weightsPtr = copy1dArray(weights, "HEAPF32"); + var verbsPtr = copy1dArray(verbs, 'HEAPU8'); + var pointsPtr = copy1dArray(points, 'HEAPF32'); + var weightsPtr = copy1dArray(weights, 'HEAPF32'); var numWeights = (weights && weights.length) || 0; this._addVerbsPointsWeights(verbsPtr, verbs.length, pointsPtr, points.length, weightsPtr, numWeights); @@ -940,9 +947,9 @@ CanvasKit.onRuntimeInitialized = function() { CanvasKit.SkImage.prototype.readPixels = function(imageInfo, srcX, srcY) { var rowBytes; - // Important to use ["string"] notation here, otherwise the closure compiler will + // Important to use ['string'] notation here, otherwise the closure compiler will // minify away the colorType. - switch (imageInfo["colorType"]) { + switch (imageInfo['colorType']) { case CanvasKit.ColorType.RGBA_8888: rowBytes = imageInfo.width * 4; // 1 byte per channel == 4 bytes per pixel in 8888 break; @@ -950,21 +957,21 @@ CanvasKit.onRuntimeInitialized = function() { rowBytes = imageInfo.width * 16; // 4 bytes per channel == 16 bytes per pixel in F32 break; default: - SkDebug("Colortype not yet supported"); + SkDebug('Colortype not yet supported'); return; } var pBytes = rowBytes * imageInfo.height; var pPtr = CanvasKit._malloc(pBytes); if (!this._readPixels(imageInfo, pPtr, rowBytes, srcX, srcY)) { - SkDebug("Could not read pixels with the given inputs"); + SkDebug('Could not read pixels with the given inputs'); return null; } // Put those pixels into a typed array of the right format and then // make a copy with slice() that we can return. var retVal = null; - switch (imageInfo["colorType"]) { + switch (imageInfo['colorType']) { case CanvasKit.ColorType.RGBA_8888: retVal = new Uint8Array(CanvasKit.HEAPU8.buffer, pPtr, pBytes).slice(); break; @@ -979,11 +986,16 @@ CanvasKit.onRuntimeInitialized = function() { } // Accepts an array of four numbers in the range of 0-1 representing a 4f color - CanvasKit.SkCanvas.prototype.clear = function (color4f) { + CanvasKit.SkCanvas.prototype.clear = function(color4f) { var cPtr = copyColorToWasm(color4f); this._clear(cPtr); } + CanvasKit.SkCanvas.prototype.clipRRect = function(rrect, op, antialias) { + var rPtr = copyRRectToWasm(rrect); + this._clipRRect(rPtr, op, antialias); + } + // concat takes a 3x2, a 3x3, or a 4x4 matrix and upscales it (if needed) to 4x4. This is because // under the hood, SkCanvas uses a 4x4 matrix. CanvasKit.SkCanvas.prototype.concat = function(matr) { @@ -1024,7 +1036,7 @@ CanvasKit.onRuntimeInitialized = function() { if (srcRects.build) { srcRectPtr = srcRects.build(); } else { - srcRectPtr = copy1dArray(srcRects, "HEAPF32"); + srcRectPtr = copy1dArray(srcRects, 'HEAPF32'); } var count = 1; @@ -1033,7 +1045,7 @@ CanvasKit.onRuntimeInitialized = function() { dstXformPtr = dstXforms.build(); count = dstXforms.length; } else { - dstXformPtr = copy1dArray(dstXforms, "HEAPF32"); + dstXformPtr = copy1dArray(dstXforms, 'HEAPF32'); count = dstXforms.length / 4; } @@ -1042,7 +1054,7 @@ CanvasKit.onRuntimeInitialized = function() { if (colors.build) { colorPtr = colors.build(); } else { - colorPtr = copy1dArray(assureIntColors(colors), "HEAPU32"); + colorPtr = copy1dArray(assureIntColors(colors), 'HEAPU32'); } } @@ -1077,6 +1089,12 @@ CanvasKit.onRuntimeInitialized = function() { } } + CanvasKit.SkCanvas.prototype.drawDRRect = function(outer, inner, paint) { + var oPtr = copyRRectToWasm(outer, _scratchRRectPtr); + var iPtr = copyRRectToWasm(inner, _scratchRRect2Ptr); + this._drawDRRect(oPtr, iPtr, paint); + } + // points is either an array of [x, y] where x and y are numbers or // a typed array from Malloc where the even indices will be treated // as x coordinates and the odd indices will be treated as y coordinates. @@ -1089,13 +1107,18 @@ CanvasKit.onRuntimeInitialized = function() { ptr = points.byteOffset; n = points.length/2; } else { - ptr = copy2dArray(points, "HEAPF32"); + ptr = copy2dArray(points, 'HEAPF32'); n = points.length; } this._drawPoints(mode, ptr, n, paint); freeArraysThatAreNotMallocedByUsers(ptr, points); } + CanvasKit.SkCanvas.prototype.drawRRect = function(rrect, paint) { + var rPtr = copyRRectToWasm(rrect); + this._drawRRect(rPtr, paint); + } + CanvasKit.SkCanvas.prototype.drawShadow = function(path, zPlaneParams, lightPos, lightRadius, ambientColor, spotColor, flags) { var ambiPtr = copyColorToWasmNoScratch(ambientColor); var spotPtr = copyColorToWasmNoScratch(spotColor); @@ -1182,7 +1205,7 @@ CanvasKit.onRuntimeInitialized = function() { colorSpace = colorSpace || CanvasKit.SkColorSpace.SRGB; var srcRowBytes = bytesPerPixel * srcWidth; - var pptr = copy1dArray(pixels, "HEAPU8"); + var pptr = copy1dArray(pixels, 'HEAPU8'); var ok = this._writePixels({ 'width': srcWidth, 'height': srcHeight, @@ -1206,7 +1229,7 @@ CanvasKit.onRuntimeInitialized = function() { if (!colorMatrix || colorMatrix.length !== 20) { throw 'invalid color matrix'; } - var fptr = copy1dArray(colorMatrix, "HEAPF32"); + var fptr = copy1dArray(colorMatrix, 'HEAPF32'); // We know skia memcopies the floats, so we can free our memory after the call returns. var m = CanvasKit.SkColorFilter._makeMatrix(fptr); freeArraysThatAreNotMallocedByUsers(fptr, colorMatrix); @@ -1295,7 +1318,7 @@ CanvasKit.onRuntimeInitialized = function() { if (!intervals.length || intervals.length % 2 === 1) { throw 'Intervals array must have even length'; } - var ptr = copy1dArray(intervals, "HEAPF32"); + var ptr = copy1dArray(intervals, 'HEAPF32'); var dpe = CanvasKit.SkPathEffect._MakeDash(ptr, intervals.length, phase); freeArraysThatAreNotMallocedByUsers(ptr, intervals); return dpe; @@ -1311,7 +1334,7 @@ CanvasKit.onRuntimeInitialized = function() { CanvasKit.SkShader.MakeLinearGradient = function(start, end, colors, pos, mode, localMatrix, flags, colorSpace) { colorSpace = colorSpace || null var cPtrInfo = copyFlexibleColorArray(colors); - var posPtr = copy1dArray(pos, "HEAPF32"); + var posPtr = copy1dArray(pos, 'HEAPF32'); flags = flags || 0; var localMatrixPtr = copy3x3MatrixToWasm(localMatrix); @@ -1326,7 +1349,7 @@ CanvasKit.onRuntimeInitialized = function() { CanvasKit.SkShader.MakeRadialGradient = function(center, radius, colors, pos, mode, localMatrix, flags, colorSpace) { colorSpace = colorSpace || null var cPtrInfo = copyFlexibleColorArray(colors); - var posPtr = copy1dArray(pos, "HEAPF32"); + var posPtr = copy1dArray(pos, 'HEAPF32'); flags = flags || 0; var localMatrixPtr = copy3x3MatrixToWasm(localMatrix); @@ -1341,7 +1364,7 @@ CanvasKit.onRuntimeInitialized = function() { CanvasKit.SkShader.MakeSweepGradient = function(cx, cy, colors, pos, mode, localMatrix, flags, startAngle, endAngle, colorSpace) { colorSpace = colorSpace || null var cPtrInfo = copyFlexibleColorArray(colors); - var posPtr = copy1dArray(pos, "HEAPF32"); + var posPtr = copy1dArray(pos, 'HEAPF32'); flags = flags || 0; startAngle = startAngle || 0; endAngle = endAngle || 360; @@ -1361,7 +1384,7 @@ CanvasKit.onRuntimeInitialized = function() { colors, pos, mode, localMatrix, flags, colorSpace) { colorSpace = colorSpace || null var cPtrInfo = copyFlexibleColorArray(colors); - var posPtr = copy1dArray(pos, "HEAPF32"); + var posPtr = copy1dArray(pos, 'HEAPF32'); flags = flags || 0; var localMatrixPtr = copy3x3MatrixToWasm(localMatrix); @@ -1431,20 +1454,16 @@ CanvasKit.XYWHRect = function(x, y, w, h) { }; }; -// RRectXY returns an RRect with the given rect and a radiusX and radiusY for -// all 4 corners. +// RRectXY returns a TypedArray representing an RRect with the given rect and a radiusX and +// radiusY for all 4 corners. CanvasKit.RRectXY = function(rect, rx, ry) { - return { - rect: rect, - rx1: rx, - ry1: ry, - rx2: rx, - ry2: ry, - rx3: rx, - ry3: ry, - rx4: rx, - ry4: ry, - }; + return Float32Array.of( + rect['fLeft'], rect['fTop'], rect['fRight'], rect['fBottom'], + rx, ry, + rx, ry, + rx, ry, + rx, ry, + ); }; // data is a TypedArray or ArrayBuffer e.g. from fetch().then(resp.arrayBuffer()) @@ -1519,7 +1538,7 @@ CanvasKit.MakeImage = function(pixels, width, height, alphaType, colorType, colo 'colorType': colorType, 'colorSpace': colorSpace, }; - var pptr = copy1dArray(pixels, "HEAPU8"); + var pptr = copy1dArray(pixels, 'HEAPU8'); // No need to _free pptr, Image takes it with SkData::MakeFromMalloc return CanvasKit._MakeImage(info, pptr, pixels.length, width * bytesPerPixel); @@ -1550,19 +1569,19 @@ CanvasKit.MakeSkVertices = function(mode, positions, textureCoordinates, colors, var builder = new CanvasKit._SkVerticesBuilder(mode, positions.length, idxCount, flags); - copy2dArray(positions, "HEAPF32", builder.positions()); + copy2dArray(positions, 'HEAPF32', builder.positions()); if (builder.texCoords()) { - copy2dArray(textureCoordinates, "HEAPF32", builder.texCoords()); + copy2dArray(textureCoordinates, 'HEAPF32', builder.texCoords()); } if (builder.colors()) { if (colors.build) { throw('Color builder not accepted by MakeSkVertices, use array of ints'); } else { - copy1dArray(assureIntColors(colors), "HEAPU32", builder.colors()); + copy1dArray(assureIntColors(colors), 'HEAPU32', builder.colors()); } } if (builder.indices()) { - copy1dArray(indices, "HEAPU16", builder.indices()); + copy1dArray(indices, 'HEAPU16', builder.indices()); } // Create the vertices, which owns the memory that the builder had allocated. diff --git a/modules/canvaskit/tests/canvas.spec.js b/modules/canvaskit/tests/canvas.spec.js index bb283ed8ca..bb89f03d50 100644 --- a/modules/canvaskit/tests/canvas.spec.js +++ b/modules/canvaskit/tests/canvas.spec.js @@ -177,22 +177,47 @@ describe('Canvas Behavior', () => { canvas.clear(CanvasKit.WHITE); - canvas.drawRRect({ - rect: CanvasKit.LTRBRect(10, 10, 210, 210), - rx1: 10, // top left corner, going clockwise - ry1: 30, - rx2: 30, - ry2: 10, - rx3: 50, - ry3: 75, - rx4: 120, - ry4: 120, - }, paint); + canvas.drawRRect([10, 10, 210, 210, + // top left corner, going clockwise + 10, 30, + 30, 10, + 50, 75, + 120, 120, + ], paint); path.delete(); paint.delete(); }); + // As above, except with the array passed in via malloc'd memory. + gm('rrect_8corners_malloc_canvas', (canvas) => { + const path = starPath(CanvasKit); + + const paint = new CanvasKit.SkPaint(); + + paint.setStyle(CanvasKit.PaintStyle.Stroke); + paint.setStrokeWidth(3.0); + paint.setAntiAlias(true); + paint.setColor(CanvasKit.BLACK); + + canvas.clear(CanvasKit.WHITE); + + const rrect = CanvasKit.Malloc(Float32Array, 12); + rrect.toTypedArray().set([10, 10, 210, 210, + // top left corner, going clockwise + 10, 30, + 30, 10, + 50, 75, + 120, 120, + ]); + + canvas.drawRRect(rrect, paint); + + CanvasKit.Free(rrect); + path.delete(); + paint.delete(); + }); + gm('drawDRRect_canvas', (canvas) => { const path = starPath(CanvasKit);