UNPKG

octopus-svga

Version:

高性能SVGA动效播放器,支持Web/微信小程序/支付宝小程序/抖音小程序,设计目标是 解析速度更快、体积更小、性能更高、兼容性更高、功能更丰富。

1,662 lines (1,648 loc) 228 kB
(function(g,f){typeof exports==='object'&&typeof module!=='undefined'?f(exports):typeof define==='function'&&define.amd?define(['exports'],f):(g=typeof globalThis!=='undefined'?globalThis:g||self,f(g.OctopusSvga={}));})(this,(function(exports){'use strict';function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; } function _arrayWithHoles(r) { if (Array.isArray(r)) return r; } function _assertThisInitialized(e) { if (void 0 === e) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); return e; } function asyncGeneratorStep(n, t, e, r, o, a, c) { try { var i = n[a](c), u = i.value; } catch (n) { return void e(n); } i.done ? t(u) : Promise.resolve(u).then(r, o); } function _asyncToGenerator(n) { return function () { var t = this, e = arguments; return new Promise(function (r, o) { var a = n.apply(t, e); function _next(n) { asyncGeneratorStep(a, r, o, _next, _throw, "next", n); } function _throw(n) { asyncGeneratorStep(a, r, o, _next, _throw, "throw", n); } _next(void 0); }); }; } function _callSuper(t, o, e) { return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e)); } function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); } function _defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || false, o.configurable = true, "value" in o && (o.writable = true), Object.defineProperty(e, _toPropertyKey(o.key), o); } } function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: false }), e; } function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e) { t && (r = t); var n = 0, F = function () {}; return { s: F, n: function () { return n >= r.length ? { done: true } : { done: false, value: r[n++] }; }, e: function (r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = true, u = false; return { s: function () { t = t.call(r); }, n: function () { var r = t.next(); return a = r.done, r; }, e: function (r) { u = true, o = r; }, f: function () { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; } function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: true, configurable: true, writable: true }) : e[r] = t, e; } function _getPrototypeOf(t) { return _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function (t) { return t.__proto__ || Object.getPrototypeOf(t); }, _getPrototypeOf(t); } function _inherits(t, e) { if ("function" != typeof e && null !== e) throw new TypeError("Super expression must either be null or a function"); t.prototype = Object.create(e && e.prototype, { constructor: { value: t, writable: true, configurable: true } }), Object.defineProperty(t, "prototype", { writable: false }), e && _setPrototypeOf(t, e); } function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function () { return !!t; })(); } function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = true, o = false; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = true, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread2(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), true).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } function _possibleConstructorReturn(t, e) { if (e && ("object" == typeof e || "function" == typeof e)) return e; if (void 0 !== e) throw new TypeError("Derived constructors may only return object or undefined"); return _assertThisInitialized(t); } function _regenerator() { /*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/babel/babel/blob/main/packages/babel-helpers/LICENSE */ var e, t, r = "function" == typeof Symbol ? Symbol : {}, n = r.iterator || "@@iterator", o = r.toStringTag || "@@toStringTag"; function i(r, n, o, i) { var c = n && n.prototype instanceof Generator ? n : Generator, u = Object.create(c.prototype); return _regeneratorDefine(u, "_invoke", function (r, n, o) { var i, c, u, f = 0, p = o || [], y = false, G = { p: 0, n: 0, v: e, a: d, f: d.bind(e, 4), d: function (t, r) { return i = t, c = 0, u = e, G.n = r, a; } }; function d(r, n) { for (c = r, u = n, t = 0; !y && f && !o && t < p.length; t++) { var o, i = p[t], d = G.p, l = i[2]; r > 3 ? (o = l === n) && (u = i[(c = i[4]) ? 5 : (c = 3, 3)], i[4] = i[5] = e) : i[0] <= d && ((o = r < 2 && d < i[1]) ? (c = 0, G.v = n, G.n = i[1]) : d < l && (o = r < 3 || i[0] > n || n > l) && (i[4] = r, i[5] = n, G.n = l, c = 0)); } if (o || r > 1) return a; throw y = true, n; } return function (o, p, l) { if (f > 1) throw TypeError("Generator is already running"); for (y && 1 === p && d(p, l), c = p, u = l; (t = c < 2 ? e : u) || !y;) { i || (c ? c < 3 ? (c > 1 && (G.n = -1), d(c, u)) : G.n = u : G.v = u); try { if (f = 2, i) { if (c || (o = "next"), t = i[o]) { if (!(t = t.call(i, u))) throw TypeError("iterator result is not an object"); if (!t.done) return t; u = t.value, c < 2 && (c = 0); } else 1 === c && (t = i.return) && t.call(i), c < 2 && (u = TypeError("The iterator does not provide a '" + o + "' method"), c = 1); i = e; } else if ((t = (y = G.n < 0) ? u : r.call(n, G)) !== a) break; } catch (t) { i = e, c = 1, u = t; } finally { f = 1; } } return { value: t, done: y }; }; }(r, o, i), true), u; } var a = {}; function Generator() {} function GeneratorFunction() {} function GeneratorFunctionPrototype() {} t = Object.getPrototypeOf; var c = [][n] ? t(t([][n]())) : (_regeneratorDefine(t = {}, n, function () { return this; }), t), u = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(c); function f(e) { return Object.setPrototypeOf ? Object.setPrototypeOf(e, GeneratorFunctionPrototype) : (e.__proto__ = GeneratorFunctionPrototype, _regeneratorDefine(e, o, "GeneratorFunction")), e.prototype = Object.create(u), e; } return GeneratorFunction.prototype = GeneratorFunctionPrototype, _regeneratorDefine(u, "constructor", GeneratorFunctionPrototype), _regeneratorDefine(GeneratorFunctionPrototype, "constructor", GeneratorFunction), GeneratorFunction.displayName = "GeneratorFunction", _regeneratorDefine(GeneratorFunctionPrototype, o, "GeneratorFunction"), _regeneratorDefine(u), _regeneratorDefine(u, o, "Generator"), _regeneratorDefine(u, n, function () { return this; }), _regeneratorDefine(u, "toString", function () { return "[object Generator]"; }), (_regenerator = function () { return { w: i, m: f }; })(); } function _regeneratorDefine(e, r, n, t) { var i = Object.defineProperty; try { i({}, "", {}); } catch (e) { i = 0; } _regeneratorDefine = function (e, r, n, t) { if (r) i ? i(e, r, { value: n, enumerable: !t, configurable: !t, writable: !t }) : e[r] = n;else { function o(r, n) { _regeneratorDefine(e, r, function (e) { return this._invoke(r, n, e); }); } o("next", 0), o("throw", 1), o("return", 2); } }, _regeneratorDefine(e, r, n, t); } function _setPrototypeOf(t, e) { return _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function (t, e) { return t.__proto__ = e, t; }, _setPrototypeOf(t, e); } function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); } function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return (String )(t); } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; } function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }/****************************************************************************** Copyright (c) Microsoft Corporation. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ***************************************************************************** */ /* global Reflect, Promise, SuppressedError, Symbol, Iterator */ function __awaiter(thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); } typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) { var e = new Error(message); return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e; };var noop$1 = function noop() {}; function delay(callback, interval) { return new Promise(function (resolve) { return setTimeout(function () { return resolve(callback()); }, interval); }); } function retry(_x) { return _retry.apply(this, arguments); } // 使用静态缓冲区,避免重复创建 function _retry() { _retry = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee3(fn) { var intervals, times, _args3 = arguments, _t4; return _regenerator().w(function (_context3) { while (1) switch (_context3.p = _context3.n) { case 0: intervals = _args3.length > 1 && _args3[1] !== undefined ? _args3[1] : []; times = _args3.length > 2 && _args3[2] !== undefined ? _args3[2] : 0; _context3.p = 1; return _context3.a(2, fn()); case 2: _context3.p = 2; _t4 = _context3.v; if (!(times >= intervals.length)) { _context3.n = 3; break; } throw _t4; case 3: return _context3.a(2, delay(function () { return retry(fn, intervals, ++times); }, intervals[times])); } }, _callee3, null, [[1, 2]]); })); return _retry.apply(this, arguments); } var BUFFER_SIZE = 4096; // 更大的缓冲区,减少字符串拼接次数 var STATIC_BUFFER = new Uint16Array(BUFFER_SIZE); // 预分配ASCII缓冲区 /** * 优化的 UTF-8 解码函数 * 主要优化点: * 1. 使用静态缓冲区减少内存分配 * 2. 批量处理 ASCII 字符 * 3. 优化循环结构和条件判断 * 4. 使用 Uint16Array 代替普通数组提高性能 */ function utf8(buffer, start, end) { // 边界检查 if (start < 0 || end > buffer.length) throw new RangeError("Index out of range"); if (end - start < 1) return ""; var resultParts = []; var bufferPos = 0; var appendBuffer = function appendBuffer(parts) { resultParts.push(String.fromCharCode.apply(null, Array.from(parts))); }; // 快速路径:检查是否全是 ASCII var allAscii = true; for (var i = start; i < end; i++) { if (buffer[i] > 0x7F) { allAscii = false; break; } } // 全 ASCII 优化路径 if (allAscii) { for (var _i = start; _i < end; _i += BUFFER_SIZE) { var chunkEnd = Math.min(_i + BUFFER_SIZE, end); var len = chunkEnd - _i; // 直接复制到 Uint16Array for (var j = 0; j < len; j++) { STATIC_BUFFER[j] = buffer[_i + j]; } appendBuffer(STATIC_BUFFER.subarray(0, len)); } return resultParts.join(''); } // 混合内容处理 for (var _i2 = start; _i2 < end;) { var byte = buffer[_i2++]; // ASCII 字符处理 if (byte < 0x80) { STATIC_BUFFER[bufferPos++] = byte; // 如果缓冲区满了,提交并清空 if (bufferPos === BUFFER_SIZE) { appendBuffer(STATIC_BUFFER); bufferPos = 0; } continue; } // 提交之前的 ASCII 字符 if (bufferPos > 0) { appendBuffer(STATIC_BUFFER.subarray(0, bufferPos)); bufferPos = 0; } // 变长编码处理 - 使用查表法代替多个条件判断 var codePoint = void 0; // 2 字节序列: 110xxxxx 10xxxxxx if ((byte & 0xE0) === 0xC0 && _i2 < end) { codePoint = (byte & 0x1F) << 6 | buffer[_i2++] & 0x3F; } // 3 字节序列: 1110xxxx 10xxxxxx 10xxxxxx else if ((byte & 0xF0) === 0xE0 && _i2 + 1 < end) { codePoint = (byte & 0x0F) << 12 | (buffer[_i2++] & 0x3F) << 6 | buffer[_i2++] & 0x3F; } // 4 字节序列: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx else if ((byte & 0xF8) === 0xF0 && _i2 + 2 < end) { codePoint = (byte & 0x07) << 18 | (buffer[_i2++] & 0x3F) << 12 | (buffer[_i2++] & 0x3F) << 6 | buffer[_i2++] & 0x3F; // 处理 Unicode 代理对 if (codePoint > 0xFFFF) { codePoint -= 0x10000; STATIC_BUFFER[bufferPos++] = 0xD800 + (codePoint >> 10); STATIC_BUFFER[bufferPos++] = 0xDC00 + (codePoint & 0x3FF); // 检查缓冲区是否需要提交 if (bufferPos >= BUFFER_SIZE - 2) { // 预留空间给下一个可能的代理对 appendBuffer(STATIC_BUFFER.subarray(0, bufferPos)); bufferPos = 0; } continue; } } // 无效的 UTF-8 序列 else { codePoint = 0xFFFD; // Unicode 替换字符 // 跳过可能的后续字节 while (_i2 < end && (buffer[_i2] & 0xC0) === 0x80) _i2++; } STATIC_BUFFER[bufferPos++] = codePoint; // 检查缓冲区是否需要提交 if (bufferPos >= BUFFER_SIZE - 3) { // 预留空间给下一个可能的多字节字符 appendBuffer(STATIC_BUFFER.subarray(0, bufferPos)); bufferPos = 0; } } // 提交剩余字符 if (bufferPos > 0) { appendBuffer(STATIC_BUFFER.subarray(0, bufferPos)); } return resultParts.join(''); } var OctopusPlatform = /*#__PURE__*/function () { function OctopusPlatform(plugins, version) { _classCallCheck(this, OctopusPlatform); /** * 插件列表 */ _defineProperty(this, "plugins", []); /** * 平台版本 */ _defineProperty(this, "platformVersion", "0.1.3"); /** * 应用版本 */ _defineProperty(this, "version", ""); /** * 全局变量 */ _defineProperty(this, "globals", { env: "unknown", br: null, dpr: 1, system: "unknown" }); _defineProperty(this, "noop", noop$1); _defineProperty(this, "retry", retry); this.version = version || ""; this.plugins = plugins; this.globals.env = this.autoEnv(); } return _createClass(OctopusPlatform, [{ key: "init", value: function init() { var globals = this.globals, plugins = this.plugins; var collection = new Map(); var names = []; var installedPlugins = new Set(); globals.br = this.useBridge(); globals.dpr = this.usePixelRatio(); globals.system = this.useSystem(); var _iterator = _createForOfIteratorHelper(plugins), _step; try { for (_iterator.s(); !(_step = _iterator.n()).done;) { var plugin = _step.value; names.push(plugin.name); collection.set(plugin.name, plugin); } } catch (err) { _iterator.e(err); } finally { _iterator.f(); } this.usePlugins(collection, names, installedPlugins); installedPlugins.clear(); } }, { key: "autoEnv", value: function autoEnv() { // FIXME:由于抖音场景支持wx对象,所以需要放在wx对象之前检查 if (typeof window !== "undefined") { return "h5"; } if (typeof tt !== "undefined") { return "tt"; } if (typeof my !== "undefined") { return "alipay"; } if (typeof wx !== "undefined") { return "weapp"; } throw new Error("Unsupported platform!"); } }, { key: "useBridge", value: function useBridge() { switch (this.globals.env) { case "alipay": return my; case "tt": return tt; case "weapp": return wx; } return globalThis; } }, { key: "usePixelRatio", value: function usePixelRatio() { var _this$globals = this.globals, env = _this$globals.env, br = _this$globals.br; if (env === "h5") { return devicePixelRatio; } if ("getWindowInfo" in br) { return br.getWindowInfo().pixelRatio; } if ("getSystemInfoSync" in br) { return br.getSystemInfoSync().pixelRatio; } return 1; } }, { key: "useSystem", value: function useSystem() { var env = this.globals.env; var system; switch (env) { case "weapp": system = wx.getDeviceInfo().platform; break; case "alipay": system = my.getDeviceBaseInfo().platform; break; case "tt": system = tt.getDeviceInfoSync().platform; break; default: system = "unknown"; } return system.toLowerCase(); } }, { key: "usePlugins", value: function usePlugins(plugins, pluginNames, installedPlugins) { var _iterator2 = _createForOfIteratorHelper(pluginNames), _step2; try { for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) { var pluginName = _step2.value; if (!plugins.has(pluginName)) { throw new Error("Plugin ".concat(pluginName, " not found")); } if (installedPlugins.has(pluginName)) { return; } var plugin = plugins.get(pluginName); // 递归调用依赖 if (Array.isArray(plugin.dependencies)) { var _iterator3 = _createForOfIteratorHelper(plugin.dependencies), _step3; try { for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) { var _plugins$get; var dependency = _step3.value; if (typeof ((_plugins$get = plugins.get(dependency)) === null || _plugins$get === void 0 ? void 0 : _plugins$get.install) !== "function") { throw new Error("Plugin ".concat(pluginName, " depends on plugin ").concat(dependency, ", but ").concat(dependency, " is not found")); } } // 递归加载依赖 } catch (err) { _iterator3.e(err); } finally { _iterator3.f(); } this.usePlugins(plugins, plugin.dependencies, installedPlugins); } this.installPlugin(plugin); installedPlugins.add(pluginName); } } catch (err) { _iterator2.e(err); } finally { _iterator2.f(); } } }, { key: "switch", value: function _switch(env) { this.globals.env = env; this.init(); } }]); }(); /** * 定义平台插件 */ var definePlugin = function definePlugin(plugin) { return plugin; }; function installPlugin(platform, plugin) { var value = plugin.install.call(platform); Object.defineProperty(platform, plugin.name, { get: function get() { return value; }, enumerable: true, configurable: true }); } var pluginSelector = definePlugin({ name: "getSelector", install: function install() { var _this$globals2 = this.globals, env = _this$globals2.env, br = _this$globals2.br; if (env === "h5") { return function (selector) { return document.querySelector(selector); }; } return function (selector, component) { return (component || br).createSelectorQuery().select(selector).fields({ node: true, size: true }); }; } }); /** * 通过选择器匹配获取canvas实例 * @returns */ var pluginCanvas = definePlugin({ name: "getCanvas", dependencies: ["getSelector"], install: function install() { var retry = this.retry, getSelector = this.getSelector; var _this$globals3 = this.globals, env = _this$globals3.env; _this$globals3.br; var dpr = _this$globals3.dpr; var intervals = [50, 100, 100]; function initCanvas(canvas, width, height) { if (!canvas) { throw new Error("canvas not found."); } // const MAX_SIZE = 1365; var context = canvas.getContext("2d"); // let virtualWidth = width * dpr; // let virtualHeight = height * dpr; // // 微信小程序限制canvas最大尺寸为 1365 * 1365 // if ( // env === "weapp" && // (virtualWidth > MAX_SIZE || virtualHeight > MAX_SIZE) // ) { // if (virtualWidth > virtualHeight) { // virtualHeight = (virtualHeight / virtualWidth) * MAX_SIZE; // virtualWidth = MAX_SIZE; // } else { // virtualWidth = (virtualWidth / virtualHeight) * MAX_SIZE; // virtualHeight = MAX_SIZE; // } // } // canvas!.width = virtualWidth; // canvas!.height = virtualHeight; canvas.width = width * dpr; canvas.height = height * dpr; return { canvas: canvas, context: context }; } if (env === "h5") { return function (selector) { return retry(function () { // FIXME: Taro 对 canvas 做了特殊处理,canvas 元素的 id 会被加上 canvas-id 的前缀 var canvas = getSelector("canvas[canvas-id=".concat(selector.slice(1), "]")) || getSelector(selector); return initCanvas(canvas, canvas === null || canvas === void 0 ? void 0 : canvas.clientWidth, canvas === null || canvas === void 0 ? void 0 : canvas.clientHeight); }, intervals); }; } return function (selector, component) { return retry(function () { return new Promise(function (resolve, reject) { var query = getSelector(selector, component); query.exec(function (res) { var _ref = res[0] || {}, node = _ref.node, width = _ref.width, height = _ref.height; try { resolve(initCanvas(node, width, height)); } catch (e) { reject(e); } }); }); }, intervals); }; } }); /** * 用于处理数据解码 * @returns */ var pluginDecode = definePlugin({ name: "decode", install: function install() { var _this$globals4 = this.globals, env = _this$globals4.env, br = _this$globals4.br; var b64Wrap = function b64Wrap(b64) { var type = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "image/png"; return "data:".concat(type, ";base64,").concat(b64); }; var decode = { toBuffer: function toBuffer(data) { var buffer = data.buffer, byteOffset = data.byteOffset, byteLength = data.byteLength; if (buffer instanceof ArrayBuffer) { return buffer.slice(byteOffset, byteOffset + byteLength); } var view = new Uint8Array(byteLength); view.set(data); return view.buffer; }, bytesToString: function bytesToString(data) { var chunkSize = 8192; // 安全的块大小 var result = ""; for (var i = 0; i < data.length; i += chunkSize) { var chunk = data.slice(i, i + chunkSize); // 在安全的块上使用 String.fromCharCode result += String.fromCharCode.apply(null, Array.from(chunk)); } return result; } }; if (env === "h5") { var textDecoder = new TextDecoder("utf-8", { fatal: true }); return _objectSpread2(_objectSpread2({}, decode), {}, { toDataURL: function toDataURL(data) { return b64Wrap(btoa(decode.bytesToString(data))); }, utf8: function utf8(data, start, end) { return textDecoder.decode(data.subarray(start, end)); } }); } return _objectSpread2(_objectSpread2({}, decode), {}, { toDataURL: function toDataURL(data) { return b64Wrap(br.arrayBufferToBase64(decode.toBuffer(data))); }, utf8: utf8 }); } }); /** * 用于处理远程文件读取 * @returns */ var pluginDownload = definePlugin({ name: "remote", install: function install() { var _this$globals5 = this.globals, env = _this$globals5.env, br = _this$globals5.br; var isRemote = function isRemote(url) { return /^(blob:)?http(s)?:\/\//.test(url); }; if (env === "h5") { return { is: isRemote, fetch: function (_fetch) { function fetch(_x2) { return _fetch.apply(this, arguments); } fetch.toString = function () { return _fetch.toString(); }; return fetch; }(function (url) { return fetch(url).then(function (response) { if (response.ok) { return response.arrayBuffer(); } throw new Error("HTTP error, status=".concat(response.status, ", statusText=").concat(response.statusText)); }); }) }; } function download(url, enableCache) { return new Promise(function (resolve, reject) { br.request({ url: url, // @ts-ignore 支付宝小程序必须有该字段 dataType: "arraybuffer", responseType: "arraybuffer", enableCache: enableCache, success: function success(res) { return resolve(res.data); }, fail: reject }); }).catch(function (err) { var errorMessage = err.errMsg || err.errorMessage || err.message; // FIXME: 可能存在写入网络缓存空间失败的情况,此时重新下载 if (errorMessage.includes("ERR_CACHE_WRITE_FAILURE") || errorMessage.includes("ERR_CACHE_WRITE_FAILED")) { return download(url, false); } throw err; }); } return { is: isRemote, fetch: function fetch(url) { return download(url, true); } }; } }); /** * 用于处理本地文件存储 * @returns */ var pluginFsm = definePlugin({ name: "local", install: function install() { var _this$globals6 = this.globals, env = _this$globals6.env, br = _this$globals6.br; if (env === "h5" || env === "tt") { return null; } var fsm = br.getFileSystemManager(); return { exists: function exists(filepath) { return new Promise(function (resolve) { fsm.access({ path: filepath, success: function success() { return resolve(true); }, fail: function fail() { return resolve(false); } }); }); }, write: function write(data, filePath) { return new Promise(function (resolve, reject) { fsm.writeFile({ filePath: filePath, data: data, success: function success() { return resolve(filePath); }, fail: reject }); }); }, read: function read(filePath) { return new Promise(function (resolve, reject) { fsm.readFile({ filePath: filePath, success: function success(res) { return resolve(res.data); }, fail: reject }); }); }, remove: function remove(filePath) { return new Promise(function (resolve, reject) { fsm.unlink({ filePath: filePath, success: function success() { return resolve(filePath); }, fail: reject }); }); } }; } }); /** * 图片加载插件 * @package plugin-fsm 本地文件存储能力 * @package plugin-path 路径处理能力 * @package plugin-decode 解码能力 */ var pluginImage = definePlugin({ name: "image", dependencies: ["local", "decode"], install: function install() { var local = this.local, decode = this.decode; var env = this.globals.env; var genImageSource = function genImageSource(data, _filepath) { return typeof data === "string" ? data : decode.toDataURL(data); }; /** * 加载图片 * @param img * @param url * @returns */ function loadImage(img, url) { return new Promise(function (resolve, reject) { img.onload = function () { return resolve(img); }; img.onerror = function () { return reject(new Error("SVGA LOADING FAILURE: ".concat(url))); }; img.src = url; }); } function releaseImage(img) { img.onload = null; img.onerror = null; img.src = ""; } if (env === "h5") { return { create: function create(_) { return new Image(); }, load: function load(createImage, data, filepath) { // 由于ImageBitmap在图片渲染上有优势,故优先使用 if (data instanceof Uint8Array && "createImageBitmap" in globalThis) { return createImageBitmap(new Blob([decode.toBuffer(data)])); } if (data instanceof ImageBitmap) { return Promise.resolve(data); } return loadImage(createImage(), genImageSource(data, filepath)); }, release: releaseImage }; } // FIXME: 支付宝小程序IDE保存临时文件会失败;抖音最大用户文件大小为10M if (env === "weapp") { genImageSource = /*#__PURE__*/function () { var _ref2 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee(data, filepath) { return _regenerator().w(function (_context) { while (1) switch (_context.n) { case 0: if (!(typeof data === "string")) { _context.n = 1; break; } return _context.a(2, data); case 1: return _context.a(2, local.write(decode.toBuffer(data), filepath).catch(function (ex) { console.warn("image write fail: ".concat(ex.errorMessage || ex.errMsg || ex.message)); return decode.toDataURL(data); })); } }, _callee); })); return function genImageSource(_x3, _x4) { return _ref2.apply(this, arguments); }; }(); } return { create: function create(canvas) { return canvas.createImage(); }, load: function () { var _load = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee2(createImage, data, filepath) { var _t, _t2, _t3; return _regenerator().w(function (_context2) { while (1) switch (_context2.n) { case 0: _t = loadImage; _t2 = createImage(); _context2.n = 1; return genImageSource(data, filepath); case 1: _t3 = _context2.v; return _context2.a(2, _t(_t2, _t3)); } }, _callee2); })); function load(_x5, _x6, _x7) { return _load.apply(this, arguments); } return load; }(), release: releaseImage }; } }); var pluginNow = definePlugin({ name: "now", install: function install() { var _this$globals7 = this.globals, env = _this$globals7.env, br = _this$globals7.br; // performance可以提供更高精度的时间测量,且不受系统时间的调整(如更改系统时间或同步时间)的影响 var perf = env === "h5" || env === "tt" ? performance : br.getPerformance(); if (typeof (perf === null || perf === void 0 ? void 0 : perf.now) === "function") { // 支付宝小程序的performance.now()获取的是当前时间戳,单位是微秒。 if (perf.now() - Date.now() > 1) { return function () { return perf.now() / 1000; }; } // H5环境下,performance.now()获取的不是当前时间戳,而是从页面加载开始的时间戳,单位是毫秒。 return function () { return perf.now(); }; } return function () { return Date.now(); }; } }); /** * 用于创建离屏canvas * @returns */ var pluginOfsCanvas = definePlugin({ name: "getOfsCanvas", install: function install() { var env = this.globals.env; var createOffscreenCanvas; if (env === "h5") { createOffscreenCanvas = function createOffscreenCanvas(options) { return new OffscreenCanvas(options.width, options.height); }; } else if (env === "alipay") { createOffscreenCanvas = function createOffscreenCanvas(options) { return my.createOffscreenCanvas(options); }; } else if (env === "tt") { createOffscreenCanvas = function createOffscreenCanvas(options) { var canvas = tt.createOffscreenCanvas(); canvas.width = options.width; canvas.height = options.height; return canvas; }; } else { createOffscreenCanvas = function createOffscreenCanvas(options) { return wx.createOffscreenCanvas(options); }; } return function (options) { var type = options.type || "2d"; var canvas = createOffscreenCanvas(_objectSpread2(_objectSpread2({}, options), {}, { type: type })); var context = canvas.getContext(type); return { canvas: canvas, context: context }; }; } }); /** * 用于处理文件路径 * @returns */ var pluginPath = definePlugin({ name: "path", install: function install() { var _this$globals8 = this.globals, env = _this$globals8.env, br = _this$globals8.br; var filename = function filename(path) { var filepath = path.split(/\?#/g)[0]; return filepath.substring(filepath.lastIndexOf("/") + 1); }; if (env === "h5" || env === "tt") { return { USER_DATA_PATH: "", is: function is(_) { return false; }, filename: filename, resolve: function resolve(filename, prefix) { return ""; } }; } var USER_DATA_PATH = br.env.USER_DATA_PATH; return { USER_DATA_PATH: USER_DATA_PATH, is: function is(filepath) { return filepath === null || filepath === void 0 ? void 0 : filepath.startsWith(USER_DATA_PATH); }, filename: filename, resolve: function resolve(filename, prefix) { return "".concat(USER_DATA_PATH, "/").concat(prefix ? "".concat(prefix, "__") : "").concat(filename); } }; } }); /** * 用于处理requestAnimationFrame * @returns */ var pluginRaf = definePlugin({ name: "rAF", install: function install() { var env = this.globals.env; function requestAnimationFrameImpl() { return function (callback) { return setTimeout(callback, Math.max(0, 16 - Date.now() % 16)); }; } if (env === "h5") { var rAF = "requestAnimationFrame" in globalThis ? requestAnimationFrame : requestAnimationFrameImpl(); return function (_, callback) { return rAF(callback); }; } return function (canvas, callback) { // 检查canvas是否存在 try { return canvas.requestAnimationFrame(callback); } catch (error) { console.warn(error.message); return requestAnimationFrameImpl()(callback); } }; } });var EnhancedPlatform = /*#__PURE__*/function (_OctopusPlatform) { function EnhancedPlatform() { var _this; _classCallCheck(this, EnhancedPlatform); _this = _callSuper(this, EnhancedPlatform, [[pluginSelector, pluginCanvas, pluginOfsCanvas, pluginDecode, pluginDownload, pluginFsm, pluginImage, pluginNow, pluginPath, pluginRaf], "1.2.2"]); _this.init(); return _this; } _inherits(EnhancedPlatform, _OctopusPlatform); return _createClass(EnhancedPlatform, [{ key: "installPlugin", value: function installPlugin$1(plugin) { installPlugin(this, plugin); } }]); }(OctopusPlatform); var platform = new EnhancedPlatform();var ResourceManager = /*#__PURE__*/function () { function ResourceManager(painter) { _classCallCheck(this, ResourceManager); this.painter = painter; // FIXME: 微信小程序创建调用太多createImage会导致微信/微信小程序崩溃 this.caches = []; /** * 动态素材 */ this.dynamicMaterials = new Map(); /** * 素材 */ this.materials = new Map(); /** * 已清理Image对象的坐标 */ this.point = 0; } /** * 创建图片标签 * @returns */ return _createClass(ResourceManager, [{ key: "createImage", value: function createImage() { var img = null; if (this.point > 0) { this.point--; img = this.caches.shift(); } if (!img) { img = platform.image.create(this.painter.F); } this.caches.push(img); return img; } /** * 将 ImageBitmap 插入到 caches * @param img */ }, { key: "inertBitmapIntoCaches", value: function inertBitmapIntoCaches(img) { if (ResourceManager.isBitmap(img)) { this.caches.push(img); } } /** * 加载额外的图片资源 * @param source 资源内容/地址 * @param filename 文件名称 * @returns */ }, { key: "loadExtImage", value: function loadExtImage(source, filename) { var _this = this; return platform.image.load(function () { return _this.createImage(); }, source, platform.path.resolve(filename, "ext")).then(function (img) { _this.inertBitmapIntoCaches(img); return img; }); } /** * 加载图片集 * @param images 图片数据 * @param filename 文件名称 * @returns */ }, { key: "loadImagesWithRecord", value: function loadImagesWithRecord(images_1, filename_1) { return __awaiter(this, arguments, void 0, function (images, filename) { var _this2 = this; var type = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : "normal"; return /*#__PURE__*/_regenerator().m(function _callee() { var imageAwaits, imageFilename; return _regenerator().w(function (_context) { while (1) switch (_context.n) { case 0: imageAwaits = []; imageFilename = "".concat(filename.replace(/\.svga$/g, ""), ".png"); Object.entries(images).forEach(function (_ref) { var _ref2 = _slicedToArray(_ref, 2), name = _ref2[0], image = _ref2[1]; // 过滤 1px 透明图 if (image instanceof Uint8Array && image.byteLength < 70) { return; } var p = platform.image.load(function () { return _this2.createImage(); }, image, platform.path.resolve(imageFilename, type === "dynamic" ? "dyn_".concat(name) : name)).then(function (img) { _this2.inertBitmapIntoCaches(img); if (type === "dynamic") { _this2.dynamicMaterials.set(name, img); } else { _this2.materials.set(name, img); } }); imageAwaits.push(p); }); _context.n = 1; return Promise.all(imageAwaits); case 1: return _context.a(2); } }, _callee); })(); }); } /** * 释放图片资源 */ }, { key: "release", value: function release() { // FIXME: 小程序 image 对象需要手动释放内存,否则可能导致小程序崩溃 var _iterator = _createForOfIteratorHelper(this.caches), _step; try { for (_iterator.s(); !(_step = _iterator.n()).done;) { var img = _step.value; ResourceManager.releaseOne(img); } } catch (err) { _iterator.e(err); } finally { _iterator.f(); } this.materials.clear(); this.dynamicMaterials.clear(); // FIXME: 支付宝小程序 image 修改 src 无法触发 onload 事件 platform.globals.env === "alipay" ? this.cleanup() : this.tidyUp(); } /** * 整理图片资源,将重复的图片资源移除 */ }, { key: "tidyUp", value: function tidyUp() { // 通过 Set 的去重特性,保持 caches 元素的唯一性 this.caches = Array.from(new Set(this.caches)); this.point = this.caches.length; } /** * 清理图片资源 */ }, { key: "cleanup", value: function cleanup() { this.caches.length = 0; this.point = 0; } }], [{ key: "isBitmap", value: /** * 判断是否是 ImageBitmap * @param img * @returns */ function isBitmap(img) { return platform.globals.env === "h5" && img instanceof ImageBitmap; } /** * 释放内存资源(图片) * @param img */ }, { key: "releaseOne", value: function releaseOne(img) { if (ResourceManager.isBitmap(img)) { img.close(); } else if (img.src !== "") { // 【微信】将存在本地的文件删除,防止用户空间被占满 if (platform.globals.env === "weapp" && img.src.includes(platform.path.USER_DATA_PATH)) { platform.local.remove(img.src); } platform.image.release(img); } } }]); }();function readFloatLEImpl() { // 使用静态DataView池 var DATA_VIEW_POOL_SIZE = 4; var dataViewPool = Array(DATA_VIEW_POOL_SIZE).fill(0).map(function () { return new DataView(new ArrayBuffer(8)); }); // 使用8字节支持double var currentViewIndex = 0; return function readFloatLE(buf, pos) { if (pos < 0 || pos + 4 > buf.length) throw new RangeError("Index out of range"); // 轮换使用DataView池中的实例 var view = dataViewPool[currentViewIndex]; currentViewIndex = (currentViewIndex + 1) % DATA_VIEW_POOL_SIZE; // 直接设置字节,避免创建subarray var u8 = new Uint8Array(view.buffer); u8[0] = buf[pos]; u8[1] = buf[pos + 1]; u8[2] = buf[pos + 2]; u8[3] = buf[pos + 3]; return view.getFloat32(0, true); }; } var readFloatLE = readFloatLEImpl();/** * 简易的hash算法 * @param buff * @param start * @param end * @param step * @returns */ function calculateHash(buff, start, end, step) { // 使用简单的哈希算法 var hash = 0; for (var i = start; i < end; i += step) { // 简单的哈希算法,类似于字符串哈希 hash = (hash << 5) - hash + buff[i]; hash = hash & hash; // 转换为32位整数 } // 添加数据长度作为哈希的一部分,增加唯一性 hash = (hash << 5) - hash + end - start; hash = hash & hash; // 转换为字符串 return hash.toString(36); }var Preflight = /*#__PURE__*/function () { function Preflight() { _classCallCheck(this, Preflight); this.caches = new Map(); this.count = 0; } return _createClass(Preflight, [{ key: "size", get: function get() { return this.caches.size; } }, { key: "hitCount", get: function get() { return this.count; } // get cache() { // return Object.fromEntries(this.caches); // } /** * 计算二进制数据的哈希值 * @param reader Reader对象 * @param end 结束位置 * @returns 哈希值 */ }, { key: "calculate", value: function calculate(reader, end) { // 保存原始位置 var startPos = reader.pos, buf = reader.buf; var endPos = Math.min(end, reader.len); // 采样数据以加快计算速度,同时保持足够的唯一性 // 对于大数据,每隔几个字节采样一次 var step = Math.max(1, Math.floor((endPos - startPos) / 100)); return calculateHash(buf, startPos, endPos, step); } /** * 检查是否存在缓存数据 * @param key 键 * @returns 是否存在 */ }, { key: "has", value: function has(key) { var hit = this.caches.has(key); if (hit) { this.count++; } return hit; // return this.caches.has(key); } /** * 获取缓存数据 * @param key 键 * @returns 缓存数据 */ }, { key: "get", value: function get(key) { return this.caches.get(key); } /** * 设置缓存数据 * @param key 键 * @param value 缓存数据 */ }, { key: "set", value: function set(key, value) { this.caches.set(key, value); } /** * 清空所有缓存数据 */ }, { key: "clear", value: function clear() { this.count = 0; this.caches.clear(); } }]); }();var Reader = /*#__PURE__*/function () { /** * Constructs a new reader instance using the specified buffer. * @classdesc Wire format reader using `Uint8Array` if available, otherwise `Array`. * @constructor * @param {Uint8Array} buffer Buffer to read from */ function Reader(buffer) { _classCallCheck(this, Reader); this.preflight = new Preflight(); this.buf = buffer; this.pos = 0; this.len = buffer.length; } return _createClass(Reader, [{ key: "indexOutOfRange", value: function indexOutOfRange(reader, writeLength) { return new RangeError("index out of range: " + reader.pos + " + " + (writeLength || 1) + " > " + reader.len); } /** * 将复杂逻辑分离到单独方法 * @returns */ }, { key: "readVarint32Slow", value: function readVarint32Slow() { var byte = this.buf[this.pos++]; var value = byte & 0x7f; var shift = 7; // 使用do-while循环减少条件判断 do { if (this.pos >= this.len) { throw this.indexOutOfRange(this); } byte = this.buf[this.pos++]; value |= (byte & 0x7f) << shift; shift += 7; } while (byte >= 128 && shift < 32); return value >>> 0; // 确保无符号 } /** * Reads a sequence of bytes preceded by its length as a varint. * @param length * @returns */ }, { key: "end", value: function end(length) { return length === undefined ? this.len : this.pos + length; } /** * Reads a varint as an unsigned 32 bit value. * @function * @returns {number} Value read */ }, { key: "uint32", value: function uint32() { // 快速路径:大多数情况下是单字节 var byte = this.buf[this.pos]; if (byte < 128) { this.pos++; return byte; } // 慢速路径:多字节处理 return this.readVarint32Slow(); } /** * Reads a varint as a signed 32 bit value. * @returns {number} Value read */ }, { key: "int32", value: function int32() { return this.uint32() | 0; } /** * Reads a float (32 bit) as a number. * @function * @returns {number} Value read */ }, { key: "float", value: function float() { var pos = this.pos + 4; if (pos > this.len) { throw this.indexOutOfRange(this, 4); } var value = readFloatLE(this.buf, this.pos); this.pos = pos; return value; } /** * read bytes range * @returns */ }, { key: "getBytesRange", value: function getBytesRange() { var length = this.uint32(); var start = this.pos; var end = start + length; if (end > this.len) { throw this.indexOutOfRange(this, length); }