3902628e35
There is some logic in here for 2.0 as well, just as a "as long as I was looking at the specs", but only 1.0 is really supported. This seems to resolve the bug where some GPUs weren't advertising correctly that they had vertex array object support, by checking for both extension names (with and without "GL_" prefix) Of note, this saves about 18 Kb (5.5 Kb gzipped) of code size by compiling out the unneeded GLES checks/functionality. Bug: skia:8378 Change-Id: I773bf4dbf231b991051d2a9f640b8047a9010e7d Reviewed-on: https://skia-review.googlesource.com/c/skia/+/203461 Commit-Queue: Kevin Lubick <kjlubick@google.com> Reviewed-by: Brian Salomon <bsalomon@google.com>
812 lines
27 KiB
JavaScript
812 lines
27 KiB
JavaScript
// Adds JS functions to augment the CanvasKit interface.
|
|
// For example, if there is a wrapper around the C++ call or logic to allow
|
|
// chaining, it should go here.
|
|
|
|
// CanvasKit.onRuntimeInitialized is called after the WASM library has loaded.
|
|
// Anything that modifies an exposed class (e.g. SkPath) should be set
|
|
// after onRuntimeInitialized, otherwise, it can happen outside of that scope.
|
|
CanvasKit.onRuntimeInitialized = function() {
|
|
// All calls to 'this' need to go in externs.js so closure doesn't minify them away.
|
|
|
|
// Add some helpers for matrices. This is ported from SkMatrix.cpp
|
|
// to save complexity and overhead of going back and forth between
|
|
// C++ and JS layers.
|
|
// I would have liked to use something like DOMMatrix, except it
|
|
// isn't widely supported (would need polyfills) and it doesn't
|
|
// have a mapPoints() function (which could maybe be tacked on here).
|
|
// If DOMMatrix catches on, it would be worth re-considering this usage.
|
|
CanvasKit.SkMatrix = {};
|
|
function sdot(a, b, c, d, e, f) {
|
|
e = e || 0;
|
|
f = f || 0;
|
|
return a * b + c * d + e * f;
|
|
}
|
|
|
|
CanvasKit.SkMatrix.identity = function() {
|
|
return [
|
|
1, 0, 0,
|
|
0, 1, 0,
|
|
0, 0, 1,
|
|
];
|
|
};
|
|
|
|
// Return the inverse (if it exists) of this matrix.
|
|
// Otherwise, return the identity.
|
|
CanvasKit.SkMatrix.invert = function(m) {
|
|
var det = m[0]*m[4]*m[8] + m[1]*m[5]*m[6] + m[2]*m[3]*m[7]
|
|
- m[2]*m[4]*m[6] - m[1]*m[3]*m[8] - m[0]*m[5]*m[7];
|
|
if (!det) {
|
|
SkDebug('Warning, uninvertible matrix');
|
|
return CanvasKit.SkMatrix.identity();
|
|
}
|
|
return [
|
|
(m[4]*m[8] - m[5]*m[7])/det, (m[2]*m[7] - m[1]*m[8])/det, (m[1]*m[5] - m[2]*m[4])/det,
|
|
(m[5]*m[6] - m[3]*m[8])/det, (m[0]*m[8] - m[2]*m[6])/det, (m[2]*m[3] - m[0]*m[5])/det,
|
|
(m[3]*m[7] - m[4]*m[6])/det, (m[1]*m[6] - m[0]*m[7])/det, (m[0]*m[4] - m[1]*m[3])/det,
|
|
];
|
|
};
|
|
|
|
// Maps the given points according to the passed in matrix.
|
|
// Results are done in place.
|
|
// See SkMatrix.h::mapPoints for the docs on the math.
|
|
CanvasKit.SkMatrix.mapPoints = function(matrix, ptArr) {
|
|
if (ptArr.length % 2) {
|
|
throw 'mapPoints requires an even length arr';
|
|
}
|
|
for (var i = 0; i < ptArr.length; i+=2) {
|
|
var x = ptArr[i], y = ptArr[i+1];
|
|
// Gx+Hy+I
|
|
var denom = matrix[6]*x + matrix[7]*y + matrix[8];
|
|
// Ax+By+C
|
|
var xTrans = matrix[0]*x + matrix[1]*y + matrix[2];
|
|
// Dx+Ey+F
|
|
var yTrans = matrix[3]*x + matrix[4]*y + matrix[5];
|
|
ptArr[i] = xTrans/denom;
|
|
ptArr[i+1] = yTrans/denom;
|
|
}
|
|
return ptArr;
|
|
};
|
|
|
|
CanvasKit.SkMatrix.multiply = function(m1, m2) {
|
|
var result = [0,0,0, 0,0,0, 0,0,0];
|
|
for (var r = 0; r < 3; r++) {
|
|
for (var c = 0; c < 3; c++) {
|
|
// m1 and m2 are 1D arrays pretending to be 2D arrays
|
|
result[3*r + c] = sdot(m1[3*r + 0], m2[3*0 + c],
|
|
m1[3*r + 1], m2[3*1 + c],
|
|
m1[3*r + 2], m2[3*2 + c]);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// Return a matrix representing a rotation by n radians.
|
|
// px, py optionally say which point the rotation should be around
|
|
// with the default being (0, 0);
|
|
CanvasKit.SkMatrix.rotated = function(radians, px, py) {
|
|
px = px || 0;
|
|
py = py || 0;
|
|
var sinV = Math.sin(radians);
|
|
var cosV = Math.cos(radians);
|
|
return [
|
|
cosV, -sinV, sdot( sinV, py, 1 - cosV, px),
|
|
sinV, cosV, sdot(-sinV, px, 1 - cosV, py),
|
|
0, 0, 1,
|
|
];
|
|
};
|
|
|
|
CanvasKit.SkMatrix.scaled = function(sx, sy, px, py) {
|
|
px = px || 0;
|
|
py = py || 0;
|
|
return [
|
|
sx, 0, px - sx * px,
|
|
0, sy, py - sy * py,
|
|
0, 0, 1,
|
|
];
|
|
};
|
|
|
|
CanvasKit.SkMatrix.skewed = function(kx, ky, px, py) {
|
|
px = px || 0;
|
|
py = py || 0;
|
|
return [
|
|
1, kx, -kx * px,
|
|
ky, 1, -ky * py,
|
|
0, 0, 1,
|
|
];
|
|
};
|
|
|
|
CanvasKit.SkMatrix.translated = function(dx, dy) {
|
|
return [
|
|
1, 0, dx,
|
|
0, 1, dy,
|
|
0, 0, 1,
|
|
];
|
|
};
|
|
|
|
CanvasKit.SkPath.prototype.addArc = function(oval, startAngle, sweepAngle) {
|
|
// see arc() for the HTMLCanvas version
|
|
// note input angles are degrees.
|
|
this._addArc(oval, startAngle, sweepAngle);
|
|
return this;
|
|
};
|
|
|
|
CanvasKit.SkPath.prototype.addPath = function() {
|
|
// Takes 1, 2, 7, or 10 required args, where the first arg is always the path.
|
|
// The last arg is optional 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.
|
|
var args = Array.prototype.slice.call(arguments);
|
|
var path = args[0];
|
|
var extend = false;
|
|
if (typeof args[args.length-1] === "boolean") {
|
|
extend = args.pop();
|
|
}
|
|
if (args.length === 1) {
|
|
// Add path, unchanged. Use identity matrix
|
|
this._addPath(path, 1, 0, 0,
|
|
0, 1, 0,
|
|
0, 0, 1,
|
|
extend);
|
|
} else if (args.length === 2) {
|
|
// User provided the 9 params of a full matrix as an array.
|
|
var a = args[1];
|
|
this._addPath(path, a[0], a[1], a[2],
|
|
a[3], a[4], a[5],
|
|
a[6] || 0, a[7] || 0, a[8] || 1,
|
|
extend);
|
|
} else if (args.length === 7 || args.length === 10) {
|
|
// User provided the 9 params of a (full) matrix directly.
|
|
// (or just the 6 non perspective ones)
|
|
// These are in the same order as what Skia expects.
|
|
var a = args;
|
|
this._addPath(path, a[1], a[2], a[3],
|
|
a[4], a[5], a[6],
|
|
a[7] || 0, a[8] || 0, a[9] || 1,
|
|
extend);
|
|
} else {
|
|
SkDebug('addPath expected to take 1, 2, 7, or 10 required args. Got ' + args.length);
|
|
return null;
|
|
}
|
|
return this;
|
|
};
|
|
|
|
CanvasKit.SkPath.prototype.addRect = function() {
|
|
// Takes 1, 2, 4 or 5 args
|
|
// - SkRect
|
|
// - SkRect, isCCW
|
|
// - left, top, right, bottom
|
|
// - left, top, right, bottom, isCCW
|
|
if (arguments.length === 1 || arguments.length === 2) {
|
|
var r = arguments[0];
|
|
var ccw = arguments[1] || false;
|
|
this._addRect(r.fLeft, r.fTop, r.fRight, r.fBottom, ccw);
|
|
} else if (arguments.length === 4 || arguments.length === 5) {
|
|
var a = arguments;
|
|
this._addRect(a[0], a[1], a[2], a[3], a[4] || false);
|
|
} else {
|
|
SkDebug('addRect expected to take 1, 2, 4, or 5 args. Got ' + arguments.length);
|
|
return null;
|
|
}
|
|
return this;
|
|
};
|
|
|
|
CanvasKit.SkPath.prototype.addRoundRect = function() {
|
|
// Takes 3, 4, 6 or 7 args
|
|
// - SkRect, radii, ccw
|
|
// - SkRect, rx, ry, ccw
|
|
// - left, top, right, bottom, radii, ccw
|
|
// - left, top, right, bottom, rx, ry, ccw
|
|
var args = arguments;
|
|
if (args.length === 3 || args.length === 6) {
|
|
var radii = args[args.length-2];
|
|
} else if (args.length === 6 || args.length === 7){
|
|
// duplicate the given (rx, ry) pairs for each corner.
|
|
var rx = args[args.length-3];
|
|
var ry = args[args.length-2];
|
|
var radii = [rx, ry, rx, ry, rx, ry, rx, ry];
|
|
} else {
|
|
SkDebug('addRoundRect expected to take 3, 4, 6, or 7 args. Got ' + args.length);
|
|
return null;
|
|
}
|
|
if (radii.length !== 8) {
|
|
SkDebug('addRoundRect needs 8 radii provided. Got ' + radii.length);
|
|
return null;
|
|
}
|
|
var rptr = copy1dArray(radii, CanvasKit.HEAPF32);
|
|
if (args.length === 3 || args.length === 4) {
|
|
var r = args[0];
|
|
var ccw = args[args.length - 1];
|
|
this._addRoundRect(r.fLeft, r.fTop, r.fRight, r.fBottom, rptr, ccw);
|
|
} else if (args.length === 6 || args.length === 7) {
|
|
var a = args;
|
|
this._addRoundRect(a[0], a[1], a[2], a[3], rptr, ccw);
|
|
}
|
|
CanvasKit._free(rptr);
|
|
return this;
|
|
};
|
|
|
|
CanvasKit.SkPath.prototype.arc = function(x, y, radius, startAngle, endAngle, ccw) {
|
|
// emulates the HTMLCanvas behavior. See addArc() for the SkPath version.
|
|
// Note input angles are radians.
|
|
var bounds = CanvasKit.LTRBRect(x-radius, y-radius, x+radius, y+radius);
|
|
var sweep = radiansToDegrees(endAngle - startAngle) - (360 * !!ccw);
|
|
var temp = new CanvasKit.SkPath();
|
|
temp.addArc(bounds, radiansToDegrees(startAngle), sweep);
|
|
this.addPath(temp, true);
|
|
temp.delete();
|
|
return this;
|
|
};
|
|
|
|
CanvasKit.SkPath.prototype.arcTo = function() {
|
|
// takes 4, 5 or 7 args
|
|
// - 5 x1, y1, x2, y2, radius
|
|
// - 4 oval (as Rect), startAngle, sweepAngle, forceMoveTo
|
|
// - 7 x1, y1, x2, y2, startAngle, sweepAngle, forceMoveTo
|
|
var args = arguments;
|
|
if (args.length === 5) {
|
|
this._arcTo(args[0], args[1], args[2], args[3], args[4]);
|
|
} else if (args.length === 4) {
|
|
this._arcTo(args[0], args[1], args[2], args[3]);
|
|
} else if (args.length === 7) {
|
|
this._arcTo(CanvasKit.LTRBRect(args[0], args[1], args[2], args[3]),
|
|
args[4], args[5], args[6]);
|
|
} else {
|
|
throw 'Invalid args for arcTo. Expected 4, 5, or 7, got '+ args.length;
|
|
}
|
|
|
|
return this;
|
|
};
|
|
|
|
CanvasKit.SkPath.prototype.close = function() {
|
|
this._close();
|
|
return this;
|
|
};
|
|
|
|
CanvasKit.SkPath.prototype.conicTo = function(x1, y1, x2, y2, w) {
|
|
this._conicTo(x1, y1, x2, y2, w);
|
|
return this;
|
|
};
|
|
|
|
CanvasKit.SkPath.prototype.cubicTo = function(cp1x, cp1y, cp2x, cp2y, x, y) {
|
|
this._cubicTo(cp1x, cp1y, cp2x, cp2y, x, y);
|
|
return this;
|
|
};
|
|
|
|
CanvasKit.SkPath.prototype.dash = function(on, off, phase) {
|
|
if (this._dash(on, off, phase)) {
|
|
return this;
|
|
}
|
|
return null;
|
|
};
|
|
|
|
CanvasKit.SkPath.prototype.lineTo = function(x, y) {
|
|
this._lineTo(x, y);
|
|
return this;
|
|
};
|
|
|
|
CanvasKit.SkPath.prototype.moveTo = function(x, y) {
|
|
this._moveTo(x, y);
|
|
return this;
|
|
};
|
|
|
|
CanvasKit.SkPath.prototype.op = function(otherPath, op) {
|
|
if (this._op(otherPath, op)) {
|
|
return this;
|
|
}
|
|
return null;
|
|
};
|
|
|
|
CanvasKit.SkPath.prototype.quadTo = function(cpx, cpy, x, y) {
|
|
this._quadTo(cpx, cpy, x, y);
|
|
return this;
|
|
};
|
|
|
|
CanvasKit.SkPath.prototype.simplify = function() {
|
|
if (this._simplify()) {
|
|
return this;
|
|
}
|
|
return null;
|
|
};
|
|
|
|
CanvasKit.SkPath.prototype.stroke = function(opts) {
|
|
// Fill out any missing values with the default values.
|
|
/**
|
|
* See externs.js for this definition
|
|
* @type {StrokeOpts}
|
|
*/
|
|
opts = opts || {};
|
|
opts.width = opts.width || 1;
|
|
opts.miter_limit = opts.miter_limit || 4;
|
|
opts.cap = opts.cap || CanvasKit.StrokeCap.Butt;
|
|
opts.join = opts.join || CanvasKit.StrokeJoin.Miter;
|
|
opts.precision = opts.precision || 1;
|
|
if (this._stroke(opts)) {
|
|
return this;
|
|
}
|
|
return null;
|
|
};
|
|
|
|
CanvasKit.SkPath.prototype.transform = function() {
|
|
// Takes 1 or 9 args
|
|
if (arguments.length === 1) {
|
|
// argument 1 should be a 6 or 9 element array.
|
|
var a = arguments[0];
|
|
this._transform(a[0], a[1], a[2],
|
|
a[3], a[4], a[5],
|
|
a[6] || 0, a[7] || 0, a[8] || 1);
|
|
} else if (arguments.length === 6 || arguments.length === 9) {
|
|
// these arguments are the 6 or 9 members of the matrix
|
|
var a = arguments;
|
|
this._transform(a[0], a[1], a[2],
|
|
a[3], a[4], a[5],
|
|
a[6] || 0, a[7] || 0, a[8] || 1);
|
|
} else {
|
|
throw 'transform expected to take 1 or 9 arguments. Got ' + arguments.length;
|
|
}
|
|
return this;
|
|
};
|
|
// isComplement is optional, defaults to false
|
|
CanvasKit.SkPath.prototype.trim = function(startT, stopT, isComplement) {
|
|
if (this._trim(startT, stopT, !!isComplement)) {
|
|
return this;
|
|
}
|
|
return null;
|
|
};
|
|
|
|
// bones should be a 3d array.
|
|
// Each bone is a 3x2 transformation matrix in column major order:
|
|
// | scaleX skewX transX |
|
|
// | skewY scaleY transY |
|
|
// and bones is an array of those matrices.
|
|
// Returns a copy of this (SkVertices) with the bones applied.
|
|
CanvasKit.SkVertices.prototype.applyBones = function(bones) {
|
|
var bPtr = copy3dArray(bones, CanvasKit.HEAPF32);
|
|
var vert = this._applyBones(bPtr, bones.length);
|
|
CanvasKit._free(bPtr);
|
|
return vert;
|
|
}
|
|
|
|
CanvasKit.SkImage.prototype.encodeToData = function() {
|
|
if (!arguments.length) {
|
|
return this._encodeToData();
|
|
}
|
|
|
|
if (arguments.length === 2) {
|
|
var a = arguments;
|
|
return this._encodeToDataWithFormat(a[0], a[1]);
|
|
}
|
|
|
|
throw 'encodeToData expected to take 0 or 2 arguments. Got ' + arguments.length;
|
|
}
|
|
|
|
// str can be either a text string or a ShapedText object
|
|
CanvasKit.SkCanvas.prototype.drawText = function(str, x, y, paint, font) {
|
|
if (typeof str === 'string') {
|
|
// lengthBytesUTF8 and stringToUTF8Array are defined in the emscripten
|
|
// JS. See https://kripken.github.io/emscripten-site/docs/api_reference/preamble.js.html#stringToUTF8
|
|
// Add 1 for null terminator
|
|
var strLen = lengthBytesUTF8(str) + 1;
|
|
var strPtr = CanvasKit._malloc(strLen);
|
|
|
|
stringToUTF8(str, strPtr, strLen);
|
|
this._drawSimpleText(strPtr, strLen, x, y, font, paint);
|
|
} else {
|
|
this._drawShapedText(str, x, y, paint);
|
|
}
|
|
}
|
|
|
|
// returns Uint8Array
|
|
CanvasKit.SkCanvas.prototype.readPixels = function(x, y, w, h, alphaType,
|
|
colorType, dstRowBytes) {
|
|
// supply defaults (which are compatible with HTMLCanvas's getImageData)
|
|
alphaType = alphaType || CanvasKit.AlphaType.Unpremul;
|
|
colorType = colorType || CanvasKit.ColorType.RGBA_8888;
|
|
dstRowBytes = dstRowBytes || (4 * w);
|
|
|
|
var len = h * dstRowBytes
|
|
var pptr = CanvasKit._malloc(len);
|
|
var ok = this._readPixels({
|
|
'width': w,
|
|
'height': h,
|
|
'colorType': colorType,
|
|
'alphaType': alphaType,
|
|
}, pptr, dstRowBytes, x, y);
|
|
if (!ok) {
|
|
CanvasKit._free(pptr);
|
|
return null;
|
|
}
|
|
|
|
// The first typed array is just a view into memory. Because we will
|
|
// be free-ing that, we call slice to make a persistent copy.
|
|
var pixels = new Uint8Array(CanvasKit.HEAPU8.buffer, pptr, len).slice();
|
|
CanvasKit._free(pptr);
|
|
return pixels;
|
|
}
|
|
|
|
// pixels is a TypedArray. No matter the input size, it will be treated as
|
|
// a Uint8Array (essentially, a byte array).
|
|
CanvasKit.SkCanvas.prototype.writePixels = function(pixels, srcWidth, srcHeight,
|
|
destX, destY, alphaType, colorType) {
|
|
if (pixels.byteLength % (srcWidth * srcHeight)) {
|
|
throw 'pixels length must be a multiple of the srcWidth * srcHeight';
|
|
}
|
|
var bytesPerPixel = pixels.byteLength / (srcWidth * srcHeight);
|
|
// supply defaults (which are compatible with HTMLCanvas's putImageData)
|
|
alphaType = alphaType || CanvasKit.AlphaType.Unpremul;
|
|
colorType = colorType || CanvasKit.ColorType.RGBA_8888;
|
|
var srcRowBytes = bytesPerPixel * srcWidth;
|
|
|
|
var pptr = CanvasKit._malloc(pixels.byteLength);
|
|
CanvasKit.HEAPU8.set(pixels, pptr);
|
|
|
|
var ok = this._writePixels({
|
|
'width': srcWidth,
|
|
'height': srcHeight,
|
|
'colorType': colorType,
|
|
'alphaType': alphaType,
|
|
}, pptr, srcRowBytes, destX, destY);
|
|
|
|
CanvasKit._free(pptr);
|
|
return ok;
|
|
}
|
|
|
|
// Returns an array of the widths of the glyphs in this string.
|
|
CanvasKit.SkFont.prototype.getWidths = function(str) {
|
|
// add 1 for null terminator
|
|
var codePoints = str.length + 1;
|
|
// lengthBytesUTF8 and stringToUTF8Array are defined in the emscripten
|
|
// JS. See https://kripken.github.io/emscripten-site/docs/api_reference/preamble.js.html#stringToUTF8
|
|
// Add 1 for null terminator
|
|
var strBytes = lengthBytesUTF8(str) + 1;
|
|
var strPtr = CanvasKit._malloc(strBytes);
|
|
stringToUTF8(str, strPtr, strBytes);
|
|
|
|
var bytesPerFloat = 4;
|
|
// allocate widths == numCodePoints
|
|
var widthPtr = CanvasKit._malloc(codePoints * bytesPerFloat);
|
|
if (!this._getWidths(strPtr, strBytes, codePoints, widthPtr)) {
|
|
SkDebug('Could not compute widths');
|
|
CanvasKit._free(strPtr);
|
|
CanvasKit._free(widthPtr);
|
|
return null;
|
|
}
|
|
// reminder, this shouldn't copy the data, just is a nice way to
|
|
// wrap 4 bytes together into a float.
|
|
var widths = new Float32Array(CanvasKit.buffer, widthPtr, codePoints);
|
|
// This copies the data so we can free the CanvasKit memory
|
|
var retVal = Array.from(widths);
|
|
CanvasKit._free(strPtr);
|
|
CanvasKit._free(widthPtr);
|
|
return retVal;
|
|
}
|
|
|
|
// fontData should be an arrayBuffer
|
|
CanvasKit.SkFontMgr.prototype.MakeTypefaceFromData = function(fontData) {
|
|
var data = new Uint8Array(fontData);
|
|
|
|
var fptr = CanvasKit._malloc(data.byteLength);
|
|
CanvasKit.HEAPU8.set(data, fptr);
|
|
var font = this._makeTypefaceFromData(fptr, data.byteLength);
|
|
if (!font) {
|
|
SkDebug('Could not decode font data');
|
|
// We do not need to free the data since the C++ will do that for us
|
|
// when the font is deleted (or fails to decode);
|
|
return null;
|
|
}
|
|
return font;
|
|
}
|
|
|
|
CanvasKit.SkSurface.prototype.requestAnimationFrame = function(callback, dirtyRect) {
|
|
if (!this._cached_canvas) {
|
|
this._cached_canvas = this.getCanvas();
|
|
}
|
|
window.requestAnimationFrame(function() {
|
|
if (this._context !== undefined) {
|
|
CanvasKit.setCurrentContext(this._context);
|
|
}
|
|
|
|
callback(this._cached_canvas);
|
|
|
|
this.flush();
|
|
}.bind(this));
|
|
}
|
|
|
|
CanvasKit.SkTextBlob.MakeOnPath = function(str, path, font, initialOffset) {
|
|
if (!str || !str.length) {
|
|
SkDebug('ignoring 0 length string');
|
|
return;
|
|
}
|
|
if (!path || !path.countPoints()) {
|
|
SkDebug('ignoring empty path');
|
|
return;
|
|
}
|
|
if (path.countPoints() === 1) {
|
|
SkDebug('path has 1 point, returning normal textblob');
|
|
return this.MakeFromText(str, font);
|
|
}
|
|
|
|
if (!initialOffset) {
|
|
initialOffset = 0;
|
|
}
|
|
|
|
var widths = font.getWidths(str);
|
|
|
|
var rsx = new CanvasKit.RSXFormBuilder();
|
|
var meas = new CanvasKit.SkPathMeasure(path, false, 1);
|
|
var dist = initialOffset;
|
|
for (var i = 0; i < str.length; i++) {
|
|
var width = widths[i];
|
|
dist += width/2;
|
|
if (dist > meas.getLength()) {
|
|
// jump to next contour
|
|
if (!meas.nextContour()) {
|
|
// We have come to the end of the path - terminate the string
|
|
// right here.
|
|
str = str.substring(0, i);
|
|
break;
|
|
}
|
|
dist = width/2;
|
|
}
|
|
|
|
// Gives us the (x, y) coordinates as well as the cos/sin of the tangent
|
|
// line at that position.
|
|
var xycs = meas.getPosTan(dist);
|
|
var cx = xycs[0];
|
|
var cy = xycs[1];
|
|
var cosT = xycs[2];
|
|
var sinT = xycs[3];
|
|
|
|
var adjustedX = cx - (width/2 * cosT);
|
|
var adjustedY = cy - (width/2 * sinT);
|
|
|
|
rsx.push(cosT, sinT, adjustedX, adjustedY);
|
|
dist += width/2;
|
|
}
|
|
var retVal = this.MakeFromRSXform(str, rsx, font);
|
|
rsx.delete();
|
|
meas.delete();
|
|
return retVal;
|
|
}
|
|
|
|
CanvasKit.SkTextBlob.MakeFromRSXform = function(str, rsxBuilder, font) {
|
|
// lengthBytesUTF8 and stringToUTF8Array are defined in the emscripten
|
|
// JS. See https://kripken.github.io/emscripten-site/docs/api_reference/preamble.js.html#stringToUTF8
|
|
// Add 1 for null terminator
|
|
var strLen = lengthBytesUTF8(str) + 1;
|
|
var strPtr = CanvasKit._malloc(strLen);
|
|
// Add 1 for the null terminator.
|
|
stringToUTF8(str, strPtr, strLen);
|
|
var rptr = rsxBuilder.build();
|
|
|
|
var blob = CanvasKit.SkTextBlob._MakeFromRSXform(strPtr, strLen - 1,
|
|
rptr, font, CanvasKit.TextEncoding.UTF8);
|
|
if (!blob) {
|
|
SkDebug('Could not make textblob from string "' + str + '"');
|
|
return null;
|
|
}
|
|
|
|
var origDelete = blob.delete.bind(blob);
|
|
blob.delete = function() {
|
|
CanvasKit._free(strPtr);
|
|
origDelete();
|
|
}
|
|
return blob;
|
|
}
|
|
|
|
CanvasKit.SkTextBlob.MakeFromText = function(str, font) {
|
|
// lengthBytesUTF8 and stringToUTF8Array are defined in the emscripten
|
|
// JS. See https://kripken.github.io/emscripten-site/docs/api_reference/preamble.js.html#stringToUTF8
|
|
// Add 1 for null terminator
|
|
var strLen = lengthBytesUTF8(str) + 1;
|
|
var strPtr = CanvasKit._malloc(strLen);
|
|
// Add 1 for the null terminator.
|
|
stringToUTF8(str, strPtr, strLen);
|
|
|
|
var blob = CanvasKit.SkTextBlob._MakeFromText(strPtr, strLen - 1, font, CanvasKit.TextEncoding.UTF8);
|
|
if (!blob) {
|
|
SkDebug('Could not make textblob from string "' + str + '"');
|
|
return null;
|
|
}
|
|
|
|
var origDelete = blob.delete.bind(blob);
|
|
blob.delete = function() {
|
|
CanvasKit._free(strPtr);
|
|
origDelete();
|
|
}
|
|
return blob;
|
|
}
|
|
|
|
// Run through the JS files that are added at compile time.
|
|
if (CanvasKit._extraInitializations) {
|
|
CanvasKit._extraInitializations.forEach(function(init) {
|
|
init();
|
|
});
|
|
}
|
|
}; // end CanvasKit.onRuntimeInitialized, that is, anything changing prototypes or dynamic.
|
|
|
|
CanvasKit.LTRBRect = function(l, t, r, b) {
|
|
return {
|
|
fLeft: l,
|
|
fTop: t,
|
|
fRight: r,
|
|
fBottom: b,
|
|
};
|
|
}
|
|
|
|
CanvasKit.XYWHRect = function(x, y, w, h) {
|
|
return {
|
|
fLeft: x,
|
|
fTop: y,
|
|
fRight: x+w,
|
|
fBottom: y+h,
|
|
};
|
|
}
|
|
|
|
CanvasKit.MakePathFromCmds = function(cmds) {
|
|
var ptrLen = loadCmdsTypedArray(cmds);
|
|
var path = CanvasKit._MakePathFromCmds(ptrLen[0], ptrLen[1]);
|
|
CanvasKit._free(ptrLen[0]);
|
|
return path;
|
|
}
|
|
|
|
CanvasKit.MakeSkDashPathEffect = function(intervals, phase) {
|
|
if (!phase) {
|
|
phase = 0;
|
|
}
|
|
if (!intervals.length || intervals.length % 2 === 1) {
|
|
throw 'Intervals array must have even length';
|
|
}
|
|
var ptr = copy1dArray(intervals, CanvasKit.HEAPF32);
|
|
var dpe = CanvasKit._MakeSkDashPathEffect(ptr, intervals.length, phase);
|
|
CanvasKit._free(ptr);
|
|
return dpe;
|
|
}
|
|
|
|
// data is a TypedArray or ArrayBuffer e.g. from fetch().then(resp.arrayBuffer())
|
|
CanvasKit.MakeImageFromEncoded = function(data) {
|
|
data = new Uint8Array(data);
|
|
|
|
var iptr = CanvasKit._malloc(data.byteLength);
|
|
CanvasKit.HEAPU8.set(data, iptr);
|
|
var img = CanvasKit._decodeImage(iptr, data.byteLength);
|
|
if (!img) {
|
|
SkDebug('Could not decode image');
|
|
return null;
|
|
}
|
|
return img;
|
|
}
|
|
|
|
// imgData is an SkImage, e.g. from MakeImageFromEncoded or SkSurface.makeImageSnapshot
|
|
CanvasKit.MakeImageShader = function(img, xTileMode, yTileMode, clampUnpremul, localMatrix) {
|
|
if (!img) {
|
|
return null;
|
|
}
|
|
clampUnpremul = clampUnpremul || false;
|
|
if (localMatrix) {
|
|
// Add perspective args if not provided.
|
|
if (localMatrix.length === 6) {
|
|
localMatrix.push(0, 0, 1);
|
|
}
|
|
return CanvasKit._MakeImageShader(img, xTileMode, yTileMode, clampUnpremul, localMatrix);
|
|
} else {
|
|
return CanvasKit._MakeImageShader(img, xTileMode, yTileMode, clampUnpremul);
|
|
}
|
|
}
|
|
|
|
// pixels is a Uint8Array
|
|
CanvasKit.MakeImage = function(pixels, width, height, alphaType, colorType) {
|
|
var bytesPerPixel = pixels.byteLength / (width * height);
|
|
var info = {
|
|
'width': width,
|
|
'height': height,
|
|
'alphaType': alphaType,
|
|
'colorType': colorType,
|
|
};
|
|
var pptr = CanvasKit._malloc(pixels.byteLength);
|
|
CanvasKit.HEAPU8.set(pixels, pptr);
|
|
// No need to _free iptr, Image takes it with SkData::MakeFromMalloc
|
|
|
|
return CanvasKit._MakeImage(info, pptr, pixels.byteLength, width * bytesPerPixel);
|
|
}
|
|
|
|
CanvasKit.MakeLinearGradientShader = function(start, end, colors, pos, mode, localMatrix, flags) {
|
|
var colorPtr = copy1dArray(colors, CanvasKit.HEAP32);
|
|
var posPtr = copy1dArray(pos, CanvasKit.HEAPF32);
|
|
flags = flags || 0;
|
|
|
|
if (localMatrix) {
|
|
// Add perspective args if not provided.
|
|
if (localMatrix.length === 6) {
|
|
localMatrix.push(0, 0, 1);
|
|
}
|
|
var lgs = CanvasKit._MakeLinearGradientShader(start, end, colorPtr, posPtr,
|
|
colors.length, mode, flags, localMatrix);
|
|
} else {
|
|
var lgs = CanvasKit._MakeLinearGradientShader(start, end, colorPtr, posPtr,
|
|
colors.length, mode, flags);
|
|
}
|
|
|
|
CanvasKit._free(colorPtr);
|
|
CanvasKit._free(posPtr);
|
|
return lgs;
|
|
}
|
|
|
|
CanvasKit.MakeRadialGradientShader = function(center, radius, colors, pos, mode, localMatrix, flags) {
|
|
var colorPtr = copy1dArray(colors, CanvasKit.HEAP32);
|
|
var posPtr = copy1dArray(pos, CanvasKit.HEAPF32);
|
|
flags = flags || 0;
|
|
|
|
if (localMatrix) {
|
|
// Add perspective args if not provided.
|
|
if (localMatrix.length === 6) {
|
|
localMatrix.push(0, 0, 1);
|
|
}
|
|
var rgs = CanvasKit._MakeRadialGradientShader(center, radius, colorPtr, posPtr,
|
|
colors.length, mode, flags, localMatrix);
|
|
} else {
|
|
var rgs = CanvasKit._MakeRadialGradientShader(center, radius, colorPtr, posPtr,
|
|
colors.length, mode, flags);
|
|
}
|
|
|
|
CanvasKit._free(colorPtr);
|
|
CanvasKit._free(posPtr);
|
|
return rgs;
|
|
}
|
|
|
|
CanvasKit.MakeTwoPointConicalGradientShader = function(start, startRadius, end, endRadius,
|
|
colors, pos, mode, localMatrix, flags) {
|
|
var colorPtr = copy1dArray(colors, CanvasKit.HEAP32);
|
|
var posPtr = copy1dArray(pos, CanvasKit.HEAPF32);
|
|
flags = flags || 0;
|
|
|
|
if (localMatrix) {
|
|
// Add perspective args if not provided.
|
|
if (localMatrix.length === 6) {
|
|
localMatrix.push(0, 0, 1);
|
|
}
|
|
var rgs = CanvasKit._MakeTwoPointConicalGradientShader(
|
|
start, startRadius, end, endRadius,
|
|
colorPtr, posPtr, colors.length, mode, flags, localMatrix);
|
|
} else {
|
|
var rgs = CanvasKit._MakeTwoPointConicalGradientShader(
|
|
start, startRadius, end, endRadius,
|
|
colorPtr, posPtr, colors.length, mode, flags);
|
|
}
|
|
|
|
CanvasKit._free(colorPtr);
|
|
CanvasKit._free(posPtr);
|
|
return rgs;
|
|
}
|
|
|
|
CanvasKit.MakeSkVertices = function(mode, positions, textureCoordinates, colors,
|
|
boneIndices, boneWeights, indices, isVolatile) {
|
|
var positionPtr = copy2dArray(positions, CanvasKit.HEAPF32);
|
|
var texPtr = copy2dArray(textureCoordinates, CanvasKit.HEAPF32);
|
|
// Since we write the colors to memory as signed integers (JSColor), we can
|
|
// read them out on the other side as unsigned ints (SkColor) just fine
|
|
// - it's effectively casting.
|
|
var colorPtr = copy1dArray(colors, CanvasKit.HEAP32);
|
|
|
|
var boneIdxPtr = copy2dArray(boneIndices, CanvasKit.HEAP32);
|
|
var boneWtPtr = copy2dArray(boneWeights, CanvasKit.HEAPF32);
|
|
var idxPtr = copy1dArray(indices, CanvasKit.HEAPU16);
|
|
|
|
// Default isVolitile to true if not set
|
|
isVolatile = isVolatile === undefined ? true : isVolatile;
|
|
|
|
var idxCount = (indices && indices.length) || 0;
|
|
// _MakeVertices will copy all the values in, so we are free to release
|
|
// the memory after.
|
|
var vertices = CanvasKit._MakeSkVertices(mode, positions.length, positionPtr,
|
|
texPtr, colorPtr, boneIdxPtr, boneWtPtr,
|
|
idxCount, idxPtr, isVolatile);
|
|
positionPtr && CanvasKit._free(positionPtr);
|
|
texPtr && CanvasKit._free(texPtr);
|
|
colorPtr && CanvasKit._free(colorPtr);
|
|
idxPtr && CanvasKit._free(idxPtr);
|
|
boneIdxPtr && CanvasKit._free(boneIdxPtr);
|
|
boneWtPtr && CanvasKit._free(boneWtPtr);
|
|
return vertices;
|
|
}; |