UNPKG

octopus-svga

Version:

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

1,649 lines (1,635 loc) 232 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 retry(_x) { return _retry.apply(this, arguments); } // 使用静态缓冲区,避免重复创建 function _retry() { _retry = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee4(fn) { var intervals, times, _args4 = arguments, _t5; return _regenerator().w(function (_context4) { while (1) switch (_context4.p = _context4.n) { case 0: intervals = _args4.length > 1 && _args4[1] !== undefined ? _args4[1] : []; times = 0; case 1: _context4.p = 2; _context4.n = 3; return fn(); case 3: return _context4.a(2, _context4.v); case 4: _context4.p = 4; _t5 = _context4.v; if (!(times >= intervals.length)) { _context4.n = 5; break; } throw _t5; case 5: _context4.n = 6; return new Promise(function (resolve) { return setTimeout(resolve, intervals[times]); }); case 6: times++; _context4.n = 1; break; case 7: return _context4.a(2); } }, _callee4, null, [[2, 4]]); })); return _retry.apply(this, arguments); } var BUFFER_SIZE = 4096; // 更大的缓冲区,减少字符串拼接次数 var STATIC_BUFFER = new Uint16Array(BUFFER_SIZE); // 预分配ASCII缓冲区 /** * 验证 UTF-8 解码的输入范围 * @param buffer - 输入的字节数组 * @param start - 起始位置 * @param end - 结束位置 * @throws RangeError 如果范围无效 */ function validateRange(buffer, start, end) { if (start < 0 || end > buffer.length) { throw new RangeError("Index out of range"); } } /** * 检测指定范围是否全为 ASCII 字符 * @param buffer - 输入的字节数组 * @param start - 起始位置 * @param end - 结束位置 * @returns true 如果所有字节 <= 0x7F */ function isAllAscii(buffer, start, end) { for (var i = start; i < end; i++) { if (buffer[i] > 0x7F) { return false; } } return true; } /** * 快速解码纯 ASCII 内容 * @param buffer - 输入的字节数组 * @param start - 起始位置 * @param end - 结束位置 * @returns 解码后的字符串 */ function decodeAsciiFastPath(buffer, start, end) { var resultParts = []; // 批量处理,每次处理 BUFFER_SIZE 个字节 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]; } // 将缓冲区转换为字符串 var str = ''; for (var k = 0; k < len; k++) { str += String.fromCharCode(STATIC_BUFFER[k]); } resultParts.push(str); } return resultParts.join(''); } /** * 解码单个 UTF-8 多字节序列 * @param buffer - 输入的字节数组 * @param pos - 当前位置(指向第一个字节) * @param end - 结束位置 * @returns { codePoint, nextPos } 解码结果和下一位置 */ function decodeUTF8Sequence(buffer, pos, end) { var byte = buffer[pos]; var codePoint; var nextPos = pos + 1; // 2 字节序列: 110xxxxx 10xxxxxx if ((byte & 0xE0) === 0xC0 && nextPos < end) { codePoint = (byte & 0x1F) << 6 | buffer[nextPos++] & 0x3F; } // 3 字节序列: 1110xxxx 10xxxxxx 10xxxxxx else if ((byte & 0xF0) === 0xE0 && nextPos + 1 < end) { codePoint = (byte & 0x0F) << 12 | (buffer[nextPos++] & 0x3F) << 6 | buffer[nextPos++] & 0x3F; } // 4 字节序列: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx else if ((byte & 0xF8) === 0xF0 && nextPos + 2 < end) { codePoint = (byte & 0x07) << 18 | (buffer[nextPos++] & 0x3F) << 12 | (buffer[nextPos++] & 0x3F) << 6 | buffer[nextPos++] & 0x3F; } // 无效的 UTF-8 序列 else { codePoint = 0xFFFD; // Unicode 替换字符 // 跳过可能的后续字节 while (nextPos < end && (buffer[nextPos] & 0xC0) === 0x80) { nextPos++; } } return { codePoint: codePoint, nextPos: nextPos }; } /** * 将码点追加到缓冲区,必要时提交 * @param staticBuffer - 静态缓冲区 * @param bufferPos - 当前缓冲区位置 * @param codePoint - 要追加的码点 * @param resultParts - 结果字符串数组 * @param forceCommit - 是否强制提交 * @returns 新的缓冲区位置 */ function appendToBuffer(staticBuffer, bufferPos, codePoint, resultParts, forceCommit) { staticBuffer[bufferPos++] = codePoint; // 检查是否需要提交缓冲区 if (bufferPos >= BUFFER_SIZE - 3) { var str = ''; for (var i = 0; i < bufferPos; i++) { str += String.fromCharCode(staticBuffer[i]); } resultParts.push(str); bufferPos = 0; } return bufferPos; } /** * 解码混合内容(ASCII + 多字节 UTF-8) * @param buffer - 输入的字节数组 * @param start - 起始位置 * @param end - 结束位置 * @returns 解码后的字符串 */ function decodeMixedContent(buffer, start, end) { var resultParts = []; var bufferPos = 0; var i = start; while (i < end) { var byte = buffer[i++]; // ASCII 字符处理 if (byte < 0x80) { STATIC_BUFFER[bufferPos++] = byte; // 如果缓冲区满了,提交并清空 if (bufferPos === BUFFER_SIZE) { var str = ''; for (var j = 0; j < bufferPos; j++) { str += String.fromCharCode(STATIC_BUFFER[j]); } resultParts.push(str); bufferPos = 0; } continue; } // 提交之前的 ASCII 字符 if (bufferPos > 0) { var _str = ''; for (var _j = 0; _j < bufferPos; _j++) { _str += String.fromCharCode(STATIC_BUFFER[_j]); } resultParts.push(_str); bufferPos = 0; } // 解码 UTF-8 多字节序列 var _decodeUTF8Sequence = decodeUTF8Sequence(buffer, i - 1, end), codePoint = _decodeUTF8Sequence.codePoint, nextPos = _decodeUTF8Sequence.nextPos; i = nextPos; // 处理 Unicode 代理对(超过 0xFFFF 的码点) if (codePoint > 0xFFFF) { var surrogateCodePoint = codePoint - 0x10000; STATIC_BUFFER[bufferPos++] = 0xD800 + (surrogateCodePoint >> 10); STATIC_BUFFER[bufferPos++] = 0xDC00 + (surrogateCodePoint & 0x3FF); // 检查缓冲区是否需要提交(预留空间给下一个可能的代理对) if (bufferPos >= BUFFER_SIZE - 2) { var _str2 = ''; for (var _j2 = 0; _j2 < bufferPos; _j2++) { _str2 += String.fromCharCode(STATIC_BUFFER[_j2]); } resultParts.push(_str2); bufferPos = 0; } } else { // 普通码点 bufferPos = appendToBuffer(STATIC_BUFFER, bufferPos, codePoint, resultParts); } } // 提交剩余字符 if (bufferPos > 0) { var _str3 = ''; for (var _j3 = 0; _j3 < bufferPos; _j3++) { _str3 += String.fromCharCode(STATIC_BUFFER[_j3]); } resultParts.push(_str3); } return resultParts.join(''); } /** * 优化的 UTF-8 解码函数 * 主要优化点: * 1. 使用静态缓冲区减少内存分配 * 2. 批量处理 ASCII 字符 * 3. 优化循环结构和条件判断 * 4. 使用 Uint16Array 代替普通数组提高性能 * * @param buffer - 输入的 UTF-8 编码字节数组 * @param start - 起始位置 * @param end - 结束位置 * @returns 解码后的字符串 */ function utf8(buffer, start, end) { // 1. 边界验证 validateRange(buffer, start, end); // 2. 处理空输入 if (end - start < 1) { return ""; } // 3. 快速路径:全 ASCII if (isAllAscii(buffer, start, end)) { return decodeAsciiFastPath(buffer, start, end); } // 4. 混合内容处理 return decodeMixedContent(buffer, start, end); } var OctopusPlatform = /*#__PURE__*/function () { function OctopusPlatform(plugins, version) { _classCallCheck(this, OctopusPlatform); /** * 插件列表 */ _defineProperty(this, "plugins", []); /** * 平台版本 */ _defineProperty(this, "platformVersion", "0.2.2"); /** * 应用版本 */ _defineProperty(this, "version", ""); /** * 全局变量 */ _defineProperty(this, "globals", { env: "unknown", br: null, dpr: 1, system: "" }); _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() { var envs = [{ name: 'h5', check: function check() { return typeof window !== 'undefined'; } }, { name: 'tt', check: function check() { return typeof tt !== 'undefined'; } }, { name: 'alipay', check: function check() { return typeof my !== 'undefined'; } }, { name: 'weapp', check: function check() { return typeof wx !== 'undefined'; } }, { name: 'harmony', check: function check() { return typeof has !== 'undefined'; } }]; for (var _i = 0, _envs = envs; _i < _envs.length; _i++) { var env = _envs[_i]; if (env.check()) return env.name; } throw new Error("Unsupported platform! Available: ".concat(envs.map(function (e) { return e.name; }).join(', '))); } }, { 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; case "harmony": system = has.getSystemInfoSync().platform; break; case "h5": if ("userAgentData" in navigator) { // @ts-ignore system = navigator.userAgentData.platform; } else { var UA = navigator.userAgent; if (/(Android|Adr)/i.test(UA)) { system = "android"; } else if (/\(i[^;]+;( U;)? CPU.+Mac OS X/i.test(UA)) { system = "ios"; } else if (/HarmonyOS/i.test(UA)) { system = "harmony"; } else { system = "unknown"; } } 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(self, plugin) { var value = plugin.install.call(self); Object.defineProperty(self, plugin.name, { get: function get() { return value; }, enumerable: true, configurable: true }); } /** * 创建平台实例的工厂函数 * * 通过工厂函数创建平台实例,无需继承。 * TypeScript 会根据插件列表自动推断实例的属性类型。 * * @param plugins - 插件列表 * @param version - 应用版本 * @returns 平台实例,自动推断插件属性类型 */ function createPlatform(plugins, version) { // 内部类:继承 OctopusPlatform 并实现 installPlugin var InternalPlatform = /*#__PURE__*/function (_OctopusPlatform2) { function InternalPlatform() { var _this; _classCallCheck(this, InternalPlatform); _this = _callSuper(this, InternalPlatform, [plugins, version]); _this.init(); // 在基类中调用 init return _this; } _inherits(InternalPlatform, _OctopusPlatform2); return _createClass(InternalPlatform, [{ key: "installPlugin", value: function installPlugin(plugin) { // 使用 installPlugin.ts 中的实现(包含类型断言) _installPlugin(this, plugin); } }]); }(OctopusPlatform); return new InternalPlatform(); } 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, dpr = _this$globals3.dpr; var intervals = [50, 100, 100]; function initCanvas(canvas, width, height, type) { if (!canvas) { throw new Error("canvas not found."); } // const MAX_SIZE = 1365; var context = canvas.getContext(type); // 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, options) { var type = (options === null || options === void 0 ? void 0 : options.type) || "2d"; 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, type); }, intervals); }; } return function (selector, options) { var type; var component; if (options) { // 如果是小程序组件对象 if (typeof options.setData === "function") { type = "2d"; component = options; } else { type = options.type || "2d"; component = options.component || null; } } else { type = "2d"; component = null; } 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, type)); } catch (e) { reject(e); } }); }); }, intervals); }; } }); /** * 用于处理数据解码 * @returns */ var pluginCodec = definePlugin({ name: "codec", 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 codec = { 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({}, codec), {}, { toDataURL: function toDataURL(data) { return b64Wrap(btoa(codec.bytesToString(data))); }, utf8: function utf8(data, start, end) { return textDecoder.decode(data.subarray(start, end)); } }); } return _objectSpread2(_objectSpread2({}, codec), {}, { toDataURL: function toDataURL(data) { return b64Wrap(br.arrayBufferToBase64(codec.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, { priority: "low" }).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-codec 解码能力 */ var pluginImage = definePlugin({ name: "image", dependencies: ["local", "codec"], install: function install() { var local = this.local, codec = this.codec; var env = this.globals.env; var printError = function printError(msg) { return console.error("image error: ".concat(msg)); }; var genImageSource = function genImageSource(data, _filepath) { return typeof data === "string" ? data : codec.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.crossOrigin = "anonymous"; 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 () { var _load = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee(createImage, data, filepath) { var _t; return _regenerator().w(function (_context) { while (1) switch (_context.p = _context.n) { case 0: if (!(data instanceof Uint8Array && "createImageBitmap" in globalThis)) { _context.n = 4; break; } _context.p = 1; _context.n = 2; return createImageBitmap(new Blob([codec.toBuffer(data)])); case 2: data = _context.v; _context.n = 4; break; case 3: _context.p = 3; _t = _context.v; printError(_t.message); case 4: if (!(data instanceof ImageBitmap)) { _context.n = 5; break; } return _context.a(2, data); case 5: return _context.a(2, loadImage(createImage(), genImageSource(data, filepath))); } }, _callee, null, [[1, 3]]); })); function load(_x3, _x4, _x5) { return _load.apply(this, arguments); } return load; }(), release: releaseImage }; } // FIXME: 支付宝小程序IDE保存临时文件会失败;抖音最大用户文件大小为10M if (env === "weapp") { genImageSource = /*#__PURE__*/function () { var _ref2 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee2(data, filepath) { return _regenerator().w(function (_context2) { while (1) switch (_context2.n) { case 0: if (!(typeof data === "string")) { _context2.n = 1; break; } return _context2.a(2, data); case 1: return _context2.a(2, local.write(codec.toBuffer(data), filepath).catch(function (ex) { printError(ex.errorMessage || ex.errMsg || ex.message); return codec.toDataURL(data); })); } }, _callee2); })); return function genImageSource(_x6, _x7) { return _ref2.apply(this, arguments); }; }(); } return { create: function create(canvas) { return canvas.createImage(); }, load: function () { var _load2 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee3(createImage, data, filepath) { var _t2, _t3, _t4; return _regenerator().w(function (_context3) { while (1) switch (_context3.n) { case 0: _t2 = loadImage; _t3 = createImage(); _context3.n = 1; return genImageSource(data, filepath); case 1: _t4 = _context3.v; return _context3.a(2, _t2(_t3, _t4)); } }, _callee3); })); function load(_x8, _x9, _x0) { return _load2.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 platform = createPlatform([pluginSelector, pluginCanvas, pluginOfsCanvas, pluginCodec, pluginDownload, pluginFsm, pluginImage, pluginNow, pluginPath, pluginRaf], "2.0.1");var ResourceManager = /*#__PURE__*/function () { function ResourceManager(painter) { _classCallCheck(this, ResourceManager); this.painter = painter; // 微信小程序创建调用太多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() { // 小程序 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(); // 支付宝小程序 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.path.is(img.src)) { 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 Arr