2019-02-28 15:06:18 +00:00
|
|
|
// Adds compile-time JS functions to augment the CanvasKit interface.
|
|
|
|
// Specifically, anything that should only be on the Skottie builds of canvaskit.
|
|
|
|
|
2019-11-27 15:34:18 +00:00
|
|
|
// assets is a dictionary of named blobs: { key: ArrayBuffer, ... }
|
|
|
|
// The keys should be well-behaved strings - they're turned into null-terminated
|
|
|
|
// strings for the native side.
|
2020-08-20 18:51:41 +00:00
|
|
|
|
|
|
|
// prop_filter_prefix is an optional string acting as a name filter for selecting
|
|
|
|
// "interesting" Lottie properties (surfaced in the embedded player controls)
|
2021-02-09 21:43:30 +00:00
|
|
|
|
2021-02-10 20:49:48 +00:00
|
|
|
// soundMap is an optional object that maps string names to AudioPlayers
|
|
|
|
// AudioPlayers manage a single audio layer with a seek function
|
2021-02-17 16:52:10 +00:00
|
|
|
|
|
|
|
// logger is an optional logging object, expected to provide two functions:
|
|
|
|
// - onError(err_str, json_node_str)
|
|
|
|
// - onWarning(wrn_str, json_node_str)
|
|
|
|
CanvasKit.MakeManagedAnimation = function(json, assets, prop_filter_prefix, soundMap, logger) {
|
2019-02-28 15:06:18 +00:00
|
|
|
if (!CanvasKit._MakeManagedAnimation) {
|
|
|
|
throw 'Not compiled with MakeManagedAnimation';
|
|
|
|
}
|
2020-08-20 18:51:41 +00:00
|
|
|
if (!prop_filter_prefix) {
|
|
|
|
prop_filter_prefix = '';
|
|
|
|
}
|
2019-02-28 22:48:31 +00:00
|
|
|
if (!assets) {
|
2021-02-17 16:52:10 +00:00
|
|
|
return CanvasKit._MakeManagedAnimation(json, 0, nullptr, nullptr, nullptr, prop_filter_prefix,
|
|
|
|
soundMap, logger);
|
2019-02-28 15:06:18 +00:00
|
|
|
}
|
2019-02-28 22:48:31 +00:00
|
|
|
var assetNamePtrs = [];
|
|
|
|
var assetDataPtrs = [];
|
|
|
|
var assetSizes = [];
|
|
|
|
|
|
|
|
var assetKeys = Object.keys(assets || {});
|
|
|
|
for (var i = 0; i < assetKeys.length; i++) {
|
|
|
|
var key = assetKeys[i];
|
|
|
|
var buffer = assets[key];
|
2019-02-28 15:06:18 +00:00
|
|
|
var data = new Uint8Array(buffer);
|
|
|
|
|
|
|
|
var iptr = CanvasKit._malloc(data.byteLength);
|
|
|
|
CanvasKit.HEAPU8.set(data, iptr);
|
2019-02-28 22:48:31 +00:00
|
|
|
assetDataPtrs.push(iptr);
|
|
|
|
assetSizes.push(data.byteLength);
|
2019-02-28 15:06:18 +00:00
|
|
|
|
|
|
|
// 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(key) + 1;
|
|
|
|
var strPtr = CanvasKit._malloc(strLen);
|
|
|
|
|
|
|
|
stringToUTF8(key, strPtr, strLen);
|
2019-02-28 22:48:31 +00:00
|
|
|
assetNamePtrs.push(strPtr);
|
2019-02-28 21:05:09 +00:00
|
|
|
}
|
|
|
|
|
2019-02-28 15:06:18 +00:00
|
|
|
// Not entirely sure if it matters, but the uintptr_t are 32 bits
|
|
|
|
// we want to copy our array of uintptr_t into the right size memory.
|
[canvaskit] Fix infrequent crash in SkFontMgr.FromData
The bug here is very subtle, as is the mitigation.
Quick background on WASM memory, there is an object
called wasmMemory (which might be hoisted into scope for
CanvasKit's pre-js functions), of type WebAssembly.Memory
which is a resizable ArrayBuffer. Emscripten provides the
JS code to initialize this and handle size increases.
Emscripten also provides TypedArray "views" into this buffer.
These are called CanvasKit.HEAPU8, CanvasKit.HEAPF32, etc.
When there is a call to CanvasKit._malloc, wasmMemory may
be resized. If that happens, the previous TypedArray views
become invalid. However, in the same call to _malloc,
emscripten will refresh the views [1]. So, dealing with
CanvasKit.HEAPU8 directly (quick aside, we never expect clients
to mess with these views, only us in our glue JS code
[e.g. interface.js]), should always be safe because if they
were to be invalidated in a call to _malloc, the views would
be refreshed before _malloc continues.
The problem that existed before was when we were passing
CanvasKit.HEAP* as a parameter to a function, in which the
function would call _malloc before using the typed array
parameter:
//... let us suppose wasmMemory is backed by ArrayBuffer D
copy1dArray(arr, HEAPU32);
// The HEAPU32 TypedArray (backed by ArrayBuffer D) is stored
// to a function parameter "dest"
function copy1dArray(arr, dest, ptr) {
// ...
if (!ptr) {
ptr = CanvasKit._malloc(arr.length * dest.BYTES_PER_ELEMENT);
// Suppose _malloc needs to resize wasmMemory and is
// now backed by ArrayBuffer E.
// Note: The field CanvasKit.HEAPU32 is correctly backed
// by ArrayBuffer E, but variable dest still points to a
// TypedArray backed by ArrayBuffer D.
}
// dest.set will fail with a "neutered ArrayBuffer" error
// because ArrayBuffer D is effectively gone (replaced by E).
dest.set(arr, ptr / dest.BYTES_PER_ELEMENT);
The fix here is to pass in the field name indicating the TypedArray
view we want to write our data into instead of using the
view itself as the parameter.
[1] https://github.com/emscripten-core/emscripten/blob/e4271595539cf1ca81128280cdc72f7245e700a0/src/preamble.js#L344
Change-Id: I46cfb98f8bdf928b61690a5ced034a5961356398
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/294516
Reviewed-by: Nathaniel Nifong <nifong@google.com>
2020-06-05 11:13:48 +00:00
|
|
|
var namesPtr = copy1dArray(assetNamePtrs, "HEAPU32");
|
|
|
|
var assetsPtr = copy1dArray(assetDataPtrs, "HEAPU32");
|
|
|
|
var assetSizesPtr = copy1dArray(assetSizes, "HEAPU32");
|
2019-02-28 21:05:09 +00:00
|
|
|
|
2019-02-28 22:48:31 +00:00
|
|
|
var anim = CanvasKit._MakeManagedAnimation(json, assetKeys.length, namesPtr,
|
2021-02-17 16:52:10 +00:00
|
|
|
assetsPtr, assetSizesPtr, prop_filter_prefix,
|
|
|
|
soundMap, logger);
|
2019-02-28 15:06:18 +00:00
|
|
|
|
2019-11-27 15:34:18 +00:00
|
|
|
// The C++ code has made copies of the asset and string data, so free our copies.
|
2019-02-28 22:48:31 +00:00
|
|
|
CanvasKit._free(namesPtr);
|
|
|
|
CanvasKit._free(assetsPtr);
|
|
|
|
CanvasKit._free(assetSizesPtr);
|
2019-02-28 15:06:18 +00:00
|
|
|
|
|
|
|
return anim;
|
|
|
|
};
|
2020-05-04 20:46:17 +00:00
|
|
|
|
|
|
|
(function(CanvasKit){
|
|
|
|
CanvasKit._extraInitializations = CanvasKit._extraInitializations || [];
|
|
|
|
CanvasKit._extraInitializations.push(function() {
|
|
|
|
|
2020-09-03 14:02:10 +00:00
|
|
|
CanvasKit.Animation.prototype.render = function(canvas, dstRect) {
|
2021-02-02 13:18:11 +00:00
|
|
|
copyRectToWasm(dstRect, _scratchFourFloatsAPtr);
|
|
|
|
this._render(canvas, _scratchFourFloatsAPtr);
|
|
|
|
};
|
|
|
|
|
|
|
|
CanvasKit.Animation.prototype.size = function(optSize) {
|
|
|
|
// This will copy 2 floats into a space for 4 floats
|
|
|
|
this._size(_scratchFourFloatsAPtr);
|
|
|
|
var ta = _scratchFourFloatsA['toTypedArray']();
|
|
|
|
if (optSize) {
|
|
|
|
// We cannot call optSize.set() because it is an error to call .set() with
|
|
|
|
// a source bigger than the destination.
|
|
|
|
optSize[0] = ta[0];
|
|
|
|
optSize[1] = ta[1];
|
|
|
|
return optSize;
|
|
|
|
}
|
|
|
|
// Be sure to return a copy of just the first 2 values.
|
|
|
|
return ta.slice(0, 2);
|
|
|
|
};
|
2020-05-04 20:46:17 +00:00
|
|
|
|
2020-09-03 14:02:10 +00:00
|
|
|
if (CanvasKit.ManagedAnimation) {
|
|
|
|
CanvasKit.ManagedAnimation.prototype.render = function(canvas, dstRect) {
|
2021-02-02 13:18:11 +00:00
|
|
|
copyRectToWasm(dstRect, _scratchFourFloatsAPtr);
|
|
|
|
this._render(canvas, _scratchFourFloatsAPtr);
|
|
|
|
};
|
2020-09-03 14:02:10 +00:00
|
|
|
|
|
|
|
CanvasKit.ManagedAnimation.prototype.seek = function(t, optDamageRect) {
|
2021-02-02 13:18:11 +00:00
|
|
|
this._seek(t, _scratchFourFloatsAPtr);
|
|
|
|
var ta = _scratchFourFloatsA['toTypedArray']();
|
2020-09-03 14:02:10 +00:00
|
|
|
if (optDamageRect) {
|
|
|
|
optDamageRect.set(ta);
|
|
|
|
return optDamageRect;
|
|
|
|
}
|
|
|
|
return ta.slice();
|
2021-02-02 13:18:11 +00:00
|
|
|
};
|
2020-09-03 14:02:10 +00:00
|
|
|
|
|
|
|
CanvasKit.ManagedAnimation.prototype.seekFrame = function(frame, optDamageRect) {
|
2021-02-02 13:18:11 +00:00
|
|
|
this._seekFrame(frame, _scratchFourFloatsAPtr);
|
|
|
|
var ta = _scratchFourFloatsA['toTypedArray']();
|
2020-09-03 14:02:10 +00:00
|
|
|
if (optDamageRect) {
|
|
|
|
optDamageRect.set(ta);
|
|
|
|
return optDamageRect;
|
|
|
|
}
|
|
|
|
return ta.slice();
|
2021-02-02 13:18:11 +00:00
|
|
|
};
|
2020-09-03 14:02:10 +00:00
|
|
|
|
|
|
|
CanvasKit.ManagedAnimation.prototype.setColor = function(key, color) {
|
|
|
|
var cPtr = copyColorToWasm(color);
|
2021-03-10 15:33:18 +00:00
|
|
|
return this._setColor(key, cPtr);
|
2021-02-02 13:18:11 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
CanvasKit.ManagedAnimation.prototype.size = function(optSize) {
|
|
|
|
// This will copy 2 floats into a space for 4 floats
|
|
|
|
this._size(_scratchFourFloatsAPtr);
|
|
|
|
var ta = _scratchFourFloatsA['toTypedArray']();
|
|
|
|
if (optSize) {
|
|
|
|
// We cannot call optSize.set() because it is an error to call .set() with
|
|
|
|
// a source bigger than the destination.
|
|
|
|
optSize[0] = ta[0];
|
|
|
|
optSize[1] = ta[1];
|
|
|
|
return optSize;
|
|
|
|
}
|
|
|
|
// Be sure to return a copy of just the first 2 values.
|
|
|
|
return ta.slice(0, 2);
|
|
|
|
};
|
2020-09-03 14:02:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-05-04 20:46:17 +00:00
|
|
|
});
|
2020-06-01 15:25:47 +00:00
|
|
|
}(Module)); // When this file is loaded in, the high level object is "Module";
|