From 00e81309ca4799e5819a6b112f1a9e5e09289226 Mon Sep 17 00:00:00 2001 From: Harvey Zhao Date: Sun, 13 Sep 2026 23:16:04 +0800 Subject: [PATCH] test(danmuku): [PKG-DANMUKU-07] verify native load and shared layer stability --- .../artplayer-plugin-danmuku/ARCHITECTURE.md | 8 + refactor/baselines/danmuku-mask-contract.md | 5 +- .../danmuku-stability-validation.json | 6157 +++++++++++++++++ .../2026-09-13-PKG-DANMUKU-07-stability.md | 66 + refactor/danmuku-stability.md | 70 + refactor/impact-policy.json | 2 +- refactor/plan.md | 5 +- refactor/progress.md | 14 + refactor/risk-table.md | 2 +- refactor/risks.json | 17 +- refactor/tasks.json | 8 +- test/browser/README.md | 11 + test/browser/danmuku-mask-boundary.spec.js | 176 + test/browser/danmuku-stability.spec.js | 194 + 14 files changed, 6724 insertions(+), 11 deletions(-) create mode 100644 refactor/baselines/danmuku-stability-validation.json create mode 100644 refactor/changes/2026-09-13-PKG-DANMUKU-07-stability.md create mode 100644 refactor/danmuku-stability.md create mode 100644 test/browser/danmuku-mask-boundary.spec.js create mode 100644 test/browser/danmuku-stability.spec.js diff --git a/packages/artplayer-plugin-danmuku/ARCHITECTURE.md b/packages/artplayer-plugin-danmuku/ARCHITECTURE.md index 616e16a44..74e9a09b4 100644 --- a/packages/artplayer-plugin-danmuku/ARCHITECTURE.md +++ b/packages/artplayer-plugin-danmuku/ARCHITECTURE.md @@ -136,6 +136,14 @@ legacy build targets remain es2020 and es2015; syntax lowering does not polyfill ## Scheduling ownership +The root `art.template.$danmuku` belongs to the core template, not this plugin. +The Mask plugin captures this layer and the core video, and listens to core +ready/destroy; it does not read Danmuku queues, owners or plugin events. Renderer +cleanup owns individual comment nodes. Reset/replacement must preserve the root +identity and external mask styles; hide/show owns only its visibility opacity. +CSS-mask boundary tests do not establish model inference, SDK cleanup or complete +Mask integration. Those remain responsibilities of the Mask migration tasks. + Keep at most one pending RAF and one asynchronous preparation batch. Native `play` and `playing` both invoke the existing start path and retain its events, but must not create competing loops. Ready items precede wait items; wait selection diff --git a/refactor/baselines/danmuku-mask-contract.md b/refactor/baselines/danmuku-mask-contract.md index 8634e8104..85436aeda 100644 --- a/refactor/baselines/danmuku-mask-contract.md +++ b/refactor/baselines/danmuku-mask-contract.md @@ -53,7 +53,10 @@ `setBackend` fulfilled false 视为已执行 fallback。 registrar 捕获 `art.template.$video/$danmuku`,订阅 ready→start、destroy→stop。 -必须在 Danmuku 插件建立 `$danmuku` 后注册;demo 正是先 Danmuku 再 Mask。 +需要核心模板已经提供 `$danmuku/$video`;demo 使用先 Danmuku 再 Mask 的顺序。 +2026-09-13(PKG-DANMUKU-07)纠正初始记录:`$danmuku` 由核心模板创建, +不是 Danmuku 插件创建,因此 demo 顺序本身不构成 Mask 对 Danmuku 注册的硬依赖。 +Mask 源码不读取 Danmuku 队列、owner 或插件事件;完整模型组合仍待 Mask 验收。 start 建立 2D canvas 并设置 `$danmuku.style`:maskMode=alpha、maskSize=contain、 maskRepeat=no-repeat、backgroundSize=contain、backgroundRepeat=no-repeat。 每轮以视频固有尺寸推理,白色前景/黑色背景生成 binary mask,drawMask 后将 RGB diff --git a/refactor/baselines/danmuku-stability-validation.json b/refactor/baselines/danmuku-stability-validation.json new file mode 100644 index 000000000..e25723164 --- /dev/null +++ b/refactor/baselines/danmuku-stability-validation.json @@ -0,0 +1,6157 @@ +{ + "schemaVersion": 1, + "task": "PKG-DANMUKU-07", + "status": "done", + "capturedAt": "2026-09-13T15:15:04.455Z", + "baselineCommit": "4f559cb31d6b69a37439c6db2d32ca28ae5c78f3", + "report": { + "file": "refactor/.cache/danmuku07-stability-final.json", + "sha256": "474aa2aa3b0fa8f5700307db9a05d2253e15ab3d90f7cd2a1434c1b5ff131bc8" + }, + "stats": { + "startTime": "2026-09-13T15:08:26.510Z", + "duration": 308645.533, + "expected": 66, + "skipped": 0, + "unexpected": 0, + "flaky": 0 + }, + "groups": { + "chromium/danmuku-mask-boundary.spec.js": 2, + "firefox/danmuku-mask-boundary.spec.js": 2, + "webkit/danmuku-mask-boundary.spec.js": 2, + "chromium/danmuku-resources.spec.js": 16, + "firefox/danmuku-resources.spec.js": 16, + "webkit/danmuku-resources.spec.js": 16, + "chromium/danmuku-stability.spec.js": 4, + "firefox/danmuku-stability.spec.js": 4, + "webkit/danmuku-stability.spec.js": 4 + }, + "versions": { + "chromium": { + "browser": "153.0.8010.12", + "platform": "win32" + }, + "firefox": { + "browser": "155.0", + "platform": "win32" + }, + "webkit": { + "browser": "26.6", + "platform": "win32" + } + }, + "loads": [ + { + "engine": "chromium", + "implementation": "published", + "rowsPerSecond": 2, + "sha256": "7c8749288711ef97e80b6f9f00981170aa73f62a8ae25d6d663749a4aef62a8f", + "cycles": [ + { + "cycle": 0, + "base": 0.374546, + "startWall": 627.8000000119209, + "endWall": 14764, + "time": 14.477616, + "decodedWidth": 640, + "visibleCount": 24, + "uniqueVisible": 24, + "missedSampling": [], + "sampledNotVisible": [], + "queue": 24, + "states": { + "wait": 24, + "ready": 0, + "emit": 0, + "stop": 0 + }, + "nodes": 4, + "pooled": 3, + "uniquePool": 3, + "referenced": 0, + "distinctReferences": 0, + "uniqueStateMembers": 24, + "validStateMembers": true, + "heap": { + "used": 10000000, + "total": 10000000 + }, + "scheduled": 24, + "framesWallMs": { + "count": 846, + "p50": 16.699999999999818, + "p95": 16.799999999999272, + "max": 16.80000000000109 + }, + "framesMediaSeconds": { + "count": 846, + "p50": 0.0166590000000002, + "p95": 0.018034000000000106, + "max": 0.01936200000000099 + } + }, + { + "cycle": 1, + "base": 14.477616, + "startWall": 14773.699999988079, + "endWall": 28914.5, + "time": 28.577985, + "decodedWidth": 640, + "visibleCount": 24, + "uniqueVisible": 24, + "missedSampling": [], + "sampledNotVisible": [], + "queue": 48, + "states": { + "wait": 48, + "ready": 0, + "emit": 0, + "stop": 0 + }, + "nodes": 5, + "pooled": 3, + "uniquePool": 3, + "referenced": 0, + "distinctReferences": 0, + "uniqueStateMembers": 48, + "validStateMembers": true, + "heap": { + "used": 10000000, + "total": 10000000 + }, + "scheduled": 24, + "framesWallMs": { + "count": 846, + "p50": 16.69999999999891, + "p95": 16.700000000000728, + "max": 16.80000000000291 + }, + "framesMediaSeconds": { + "count": 846, + "p50": 0.016647999999999996, + "p95": 0.018342000000000525, + "max": 0.023869999999998726 + } + }, + { + "cycle": 2, + "base": 28.577985, + "startWall": 28922, + "endWall": 43066.10000002384, + "time": 42.680636, + "decodedWidth": 640, + "visibleCount": 24, + "uniqueVisible": 24, + "missedSampling": [], + "sampledNotVisible": [], + "queue": 72, + "states": { + "wait": 72, + "ready": 0, + "emit": 0, + "stop": 0 + }, + "nodes": 6, + "pooled": 3, + "uniquePool": 3, + "referenced": 0, + "distinctReferences": 0, + "uniqueStateMembers": 72, + "validStateMembers": true, + "heap": { + "used": 10000000, + "total": 10000000 + }, + "scheduled": 24, + "framesWallMs": { + "count": 846, + "p50": 16.69999999999709, + "p95": 16.799999999995634, + "max": 16.80000000000291 + }, + "framesMediaSeconds": { + "count": 846, + "p50": 0.0166959999999996, + "p95": 0.01811000000000007, + "max": 0.020167000000000712 + } + } + ], + "sampleGapsIncludingLifecyclePauses": { + "framesWallMs": { + "count": 2538, + "p50": 16.69999999999709, + "p95": 16.700000000004366, + "max": 66.70000000000073 + }, + "framesMediaSeconds": { + "count": 2538, + "p50": 0.016670000000004848, + "p95": 0.018145000000000522, + "max": 0.05940100000000115 + }, + "samplingWallMs": { + "count": 2607, + "p50": 16.69999998807907, + "p95": 17.80000001192093, + "max": 83.90000003576279 + }, + "samplingMediaSeconds": { + "count": 2607, + "p50": 0.016633999999999816, + "p95": 0.018132999999999733, + "max": 0.0597139999999996 + } + }, + "totalVisible": 72, + "uniqueVisible": 72, + "recycled": 72, + "callbacks": 75, + "allocations": 6, + "reuses": 69, + "bypassedPool": 0, + "workers": [ + { + "posts": 75, + "replies": 75, + "terminated": 1, + "errors": [] + } + ], + "errors": [], + "destroyed": true, + "retainedPlayerRoots": 0 + }, + { + "engine": "chromium", + "implementation": "published", + "rowsPerSecond": 20, + "sha256": "7c8749288711ef97e80b6f9f00981170aa73f62a8ae25d6d663749a4aef62a8f", + "cycles": [ + { + "cycle": 0, + "base": 0.369621, + "startWall": 586.3999999761581, + "endWall": 14722.399999976158, + "time": 14.460377, + "decodedWidth": 640, + "visibleCount": 240, + "uniqueVisible": 240, + "missedSampling": [], + "sampledNotVisible": [], + "queue": 240, + "states": { + "wait": 240, + "ready": 0, + "emit": 0, + "stop": 0 + }, + "nodes": 22, + "pooled": 21, + "uniquePool": 21, + "referenced": 0, + "distinctReferences": 0, + "uniqueStateMembers": 240, + "validStateMembers": true, + "heap": { + "used": 10000000, + "total": 10000000 + }, + "scheduled": 240, + "framesWallMs": { + "count": 845, + "p50": 16.699999999999818, + "p95": 16.700000000000728, + "max": 16.80000000000109 + }, + "framesMediaSeconds": { + "count": 845, + "p50": 0.016639999999998878, + "p95": 0.018498000000001014, + "max": 0.019878999999999536 + } + }, + { + "cycle": 1, + "base": 14.460377, + "startWall": 14737.300000011921, + "endWall": 28888.399999976158, + "time": 28.579458, + "decodedWidth": 640, + "visibleCount": 240, + "uniqueVisible": 240, + "missedSampling": [], + "sampledNotVisible": [], + "queue": 480, + "states": { + "wait": 480, + "ready": 0, + "emit": 0, + "stop": 0 + }, + "nodes": 23, + "pooled": 21, + "uniquePool": 21, + "referenced": 0, + "distinctReferences": 0, + "uniqueStateMembers": 480, + "validStateMembers": true, + "heap": { + "used": 10000000, + "total": 10000000 + }, + "scheduled": 240, + "framesWallMs": { + "count": 846, + "p50": 16.69999999999891, + "p95": 16.799999999999272, + "max": 16.80000000000291 + }, + "framesMediaSeconds": { + "count": 846, + "p50": 0.01665800000000317, + "p95": 0.018109000000002595, + "max": 0.02022799999999947 + } + }, + { + "cycle": 2, + "base": 28.579458, + "startWall": 28905.399999976158, + "endWall": 43037.10000002384, + "time": 42.662662, + "decodedWidth": 640, + "visibleCount": 240, + "uniqueVisible": 240, + "missedSampling": [], + "sampledNotVisible": [], + "queue": 720, + "states": { + "wait": 720, + "ready": 0, + "emit": 0, + "stop": 0 + }, + "nodes": 24, + "pooled": 21, + "uniquePool": 21, + "referenced": 0, + "distinctReferences": 0, + "uniqueStateMembers": 720, + "validStateMembers": true, + "heap": { + "used": 10000000, + "total": 10000000 + }, + "scheduled": 240, + "framesWallMs": { + "count": 845, + "p50": 16.69999999999709, + "p95": 16.700000000004366, + "max": 16.80000000000291 + }, + "framesMediaSeconds": { + "count": 845, + "p50": 0.016683000000000447, + "p95": 0.018039000000001693, + "max": 0.01981900000000536 + } + } + ], + "sampleGapsIncludingLifecyclePauses": { + "framesWallMs": { + "count": 2536, + "p50": 16.69999999999709, + "p95": 16.700000000004366, + "max": 83.40000000000146 + }, + "framesMediaSeconds": { + "count": 2536, + "p50": 0.016664000000002233, + "p95": 0.018217999999997403, + "max": 0.07596999999999987 + }, + "samplingWallMs": { + "count": 2603, + "p50": 16.600000023841858, + "p95": 17.80000001192093, + "max": 99.30000001192093 + }, + "samplingMediaSeconds": { + "count": 2603, + "p50": 0.016636000000005424, + "p95": 0.018202999999999747, + "max": 0.07654499999999942 + } + }, + "totalVisible": 720, + "uniqueVisible": 720, + "recycled": 720, + "callbacks": 723, + "allocations": 24, + "reuses": 699, + "bypassedPool": 0, + "workers": [ + { + "posts": 723, + "replies": 723, + "terminated": 1, + "errors": [] + } + ], + "errors": [], + "destroyed": true, + "retainedPlayerRoots": 0 + }, + { + "engine": "chromium", + "implementation": "candidate", + "rowsPerSecond": 2, + "sha256": "e8193aa8fae3329b3a8e435fc450726d9305e258dddea043ff3114f058516a66", + "cycles": [ + { + "cycle": 0, + "base": 0.369808, + "startWall": 609.9000000357628, + "endWall": 14777.800000011921, + "time": 14.494251, + "decodedWidth": 640, + "visibleCount": 24, + "uniqueVisible": 24, + "missedSampling": [], + "sampledNotVisible": [], + "queue": 24, + "states": { + "wait": 24, + "ready": 0, + "emit": 0, + "stop": 0 + }, + "nodes": 3, + "pooled": 3, + "uniquePool": 3, + "referenced": 0, + "distinctReferences": 0, + "uniqueStateMembers": 24, + "validStateMembers": true, + "heap": { + "used": 10000000, + "total": 10000000 + }, + "scheduled": 24, + "framesWallMs": { + "count": 847, + "p50": 16.699999999999818, + "p95": 16.700000000000728, + "max": 16.80000000000109 + }, + "framesMediaSeconds": { + "count": 847, + "p50": 0.016671999999999798, + "p95": 0.017968999999999014, + "max": 0.019351999999999592 + } + }, + { + "cycle": 1, + "base": 14.494251, + "startWall": 14789.400000035763, + "endWall": 28912.200000047684, + "time": 28.58184, + "decodedWidth": 640, + "visibleCount": 24, + "uniqueVisible": 24, + "missedSampling": [], + "sampledNotVisible": [], + "queue": 48, + "states": { + "wait": 48, + "ready": 0, + "emit": 0, + "stop": 0 + }, + "nodes": 3, + "pooled": 3, + "uniquePool": 3, + "referenced": 0, + "distinctReferences": 0, + "uniqueStateMembers": 48, + "validStateMembers": true, + "heap": { + "used": 10000000, + "total": 10000000 + }, + "scheduled": 24, + "framesWallMs": { + "count": 845, + "p50": 16.69999999999891, + "p95": 16.799999999999272, + "max": 16.80000000000291 + }, + "framesMediaSeconds": { + "count": 845, + "p50": 0.016664999999999708, + "p95": 0.01806399999999897, + "max": 0.024385999999999797 + } + }, + { + "cycle": 2, + "base": 28.58184, + "startWall": 28921.80000001192, + "endWall": 43076.200000047684, + "time": 42.715746, + "decodedWidth": 640, + "visibleCount": 24, + "uniqueVisible": 24, + "missedSampling": [], + "sampledNotVisible": [], + "queue": 72, + "states": { + "wait": 72, + "ready": 0, + "emit": 0, + "stop": 0 + }, + "nodes": 3, + "pooled": 3, + "uniquePool": 3, + "referenced": 0, + "distinctReferences": 0, + "uniqueStateMembers": 72, + "validStateMembers": true, + "heap": { + "used": 10000000, + "total": 10000000 + }, + "scheduled": 24, + "framesWallMs": { + "count": 847, + "p50": 16.69999999999709, + "p95": 16.700000000004366, + "max": 16.80000000000291 + }, + "framesMediaSeconds": { + "count": 847, + "p50": 0.016697000000000628, + "p95": 0.01815099999999603, + "max": 0.019627999999997314 + } + } + ], + "sampleGapsIncludingLifecyclePauses": { + "framesWallMs": { + "count": 2539, + "p50": 16.69999999999709, + "p95": 16.700000000004366, + "max": 66.70000000000073 + }, + "framesMediaSeconds": { + "count": 2539, + "p50": 0.016674000000001854, + "p95": 0.018076000000000647, + "max": 0.061954999999999316 + }, + "samplingWallMs": { + "count": 2536, + "p50": 16.69999998807907, + "p95": 17.899999976158142, + "max": 83.09999996423721 + }, + "samplingMediaSeconds": { + "count": 2536, + "p50": 0.016676000000000357, + "p95": 0.018077999999995598, + "max": 0.0623389999999997 + } + }, + "totalVisible": 72, + "uniqueVisible": 72, + "recycled": 72, + "callbacks": 72, + "allocations": 3, + "reuses": 69, + "bypassedPool": 0, + "workers": [ + { + "posts": 72, + "replies": 72, + "terminated": 1, + "errors": [] + } + ], + "errors": [], + "destroyed": true, + "retainedPlayerRoots": 0 + }, + { + "engine": "chromium", + "implementation": "candidate", + "rowsPerSecond": 20, + "sha256": "e8193aa8fae3329b3a8e435fc450726d9305e258dddea043ff3114f058516a66", + "cycles": [ + { + "cycle": 0, + "base": 0.374623, + "startWall": 604.1999999880791, + "endWall": 14771.5, + "time": 14.496561, + "decodedWidth": 640, + "visibleCount": 240, + "uniqueVisible": 240, + "missedSampling": [], + "sampledNotVisible": [], + "queue": 240, + "states": { + "wait": 240, + "ready": 0, + "emit": 0, + "stop": 0 + }, + "nodes": 21, + "pooled": 21, + "uniquePool": 21, + "referenced": 0, + "distinctReferences": 0, + "uniqueStateMembers": 240, + "validStateMembers": true, + "heap": { + "used": 10000000, + "total": 10000000 + }, + "scheduled": 240, + "framesWallMs": { + "count": 847, + "p50": 16.699999999999818, + "p95": 16.700000000000728, + "max": 16.80000000000109 + }, + "framesMediaSeconds": { + "count": 847, + "p50": 0.01671499999999959, + "p95": 0.018153999999999115, + "max": 0.019287000000000276 + } + }, + { + "cycle": 1, + "base": 14.496561, + "startWall": 14789, + "endWall": 28950, + "time": 28.613425, + "decodedWidth": 640, + "visibleCount": 240, + "uniqueVisible": 240, + "missedSampling": [], + "sampledNotVisible": [], + "queue": 480, + "states": { + "wait": 480, + "ready": 0, + "emit": 0, + "stop": 0 + }, + "nodes": 21, + "pooled": 21, + "uniquePool": 21, + "referenced": 0, + "distinctReferences": 0, + "uniqueStateMembers": 480, + "validStateMembers": true, + "heap": { + "used": 10000000, + "total": 10000000 + }, + "scheduled": 240, + "framesWallMs": { + "count": 847, + "p50": 16.69999999999891, + "p95": 16.700000000000728, + "max": 16.80000000000291 + }, + "framesMediaSeconds": { + "count": 847, + "p50": 0.01666099999999915, + "p95": 0.018369999999997333, + "max": 0.020493999999999346 + } + }, + { + "cycle": 2, + "base": 28.613425, + "startWall": 28967.600000023842, + "endWall": 43120.69999998808, + "time": 42.719133, + "decodedWidth": 640, + "visibleCount": 240, + "uniqueVisible": 240, + "missedSampling": [], + "sampledNotVisible": [], + "queue": 720, + "states": { + "wait": 720, + "ready": 0, + "emit": 0, + "stop": 0 + }, + "nodes": 21, + "pooled": 21, + "uniquePool": 21, + "referenced": 0, + "distinctReferences": 0, + "uniqueStateMembers": 720, + "validStateMembers": true, + "heap": { + "used": 10000000, + "total": 10000000 + }, + "scheduled": 240, + "framesWallMs": { + "count": 846, + "p50": 16.69999999999709, + "p95": 16.799999999995634, + "max": 16.80000000000291 + }, + "framesMediaSeconds": { + "count": 846, + "p50": 0.016661999999996624, + "p95": 0.018042000000001224, + "max": 0.019764000000002113 + } + } + ], + "sampleGapsIncludingLifecyclePauses": { + "framesWallMs": { + "count": 2540, + "p50": 16.69999999999709, + "p95": 16.700000000004366, + "max": 83.40000000000146 + }, + "framesMediaSeconds": { + "count": 2540, + "p50": 0.01668199999999942, + "p95": 0.0182399999999987, + "max": 0.06178000000000239 + }, + "samplingWallMs": { + "count": 2537, + "p50": 16.69999998807907, + "p95": 17.80000001192093, + "max": 100.40000003576279 + }, + "samplingMediaSeconds": { + "count": 2537, + "p50": 0.016683999999997923, + "p95": 0.0182399999999987, + "max": 0.06213999999999942 + } + }, + "totalVisible": 720, + "uniqueVisible": 720, + "recycled": 720, + "callbacks": 720, + "allocations": 21, + "reuses": 699, + "bypassedPool": 0, + "workers": [ + { + "posts": 720, + "replies": 720, + "terminated": 1, + "errors": [] + } + ], + "errors": [], + "destroyed": true, + "retainedPlayerRoots": 0 + }, + { + "engine": "firefox", + "implementation": "published", + "rowsPerSecond": 2, + "sha256": "7c8749288711ef97e80b6f9f00981170aa73f62a8ae25d6d663749a4aef62a8f", + "cycles": [ + { + "cycle": 0, + "base": 0.425651, + "startWall": 728, + "endWall": 14945, + "time": 14.549274, + "decodedWidth": 640, + "visibleCount": 24, + "uniqueVisible": 24, + "missedSampling": [], + "sampledNotVisible": [], + "queue": 24, + "states": { + "wait": 24, + "ready": 0, + "emit": 0, + "stop": 0 + }, + "nodes": 4, + "pooled": 3, + "uniquePool": 3, + "referenced": 0, + "distinctReferences": 0, + "uniqueStateMembers": 24, + "validStateMembers": true, + "heap": null, + "scheduled": 24, + "framesWallMs": { + "count": 848, + "p50": 16.659999999999854, + "p95": 16.68000000000029, + "max": 21.579999999999927 + }, + "framesMediaSeconds": { + "count": 848, + "p50": 0, + "p95": 0.04182500000000111, + "max": 0.04531200000000002 + } + }, + { + "cycle": 1, + "base": 14.549274, + "startWall": 14965, + "endWall": 29244, + "time": 28.779661, + "decodedWidth": 640, + "visibleCount": 24, + "uniqueVisible": 24, + "missedSampling": [], + "sampledNotVisible": [], + "queue": 48, + "states": { + "wait": 48, + "ready": 0, + "emit": 0, + "stop": 0 + }, + "nodes": 5, + "pooled": 3, + "uniquePool": 3, + "referenced": 0, + "distinctReferences": 0, + "uniqueStateMembers": 48, + "validStateMembers": true, + "heap": null, + "scheduled": 24, + "framesWallMs": { + "count": 852, + "p50": 16.659999999999854, + "p95": 16.68000000000029, + "max": 20.720000000001164 + }, + "framesMediaSeconds": { + "count": 852, + "p50": 0, + "p95": 0.0414500000000011, + "max": 0.044920999999998656 + } + }, + { + "cycle": 2, + "base": 28.779661, + "startWall": 29256, + "endWall": 43519, + "time": 42.950316, + "decodedWidth": 640, + "visibleCount": 24, + "uniqueVisible": 24, + "missedSampling": [], + "sampledNotVisible": [], + "queue": 72, + "states": { + "wait": 72, + "ready": 0, + "emit": 0, + "stop": 0 + }, + "nodes": 6, + "pooled": 3, + "uniquePool": 3, + "referenced": 0, + "distinctReferences": 0, + "uniqueStateMembers": 72, + "validStateMembers": true, + "heap": null, + "scheduled": 24, + "framesWallMs": { + "count": 851, + "p50": 16.660000000003492, + "p95": 16.68000000000029, + "max": 19.81999999999971 + }, + "framesMediaSeconds": { + "count": 851, + "p50": 0, + "p95": 0.0416450000000026, + "max": 0.04536300000000182 + } + } + ], + "sampleGapsIncludingLifecyclePauses": { + "framesWallMs": { + "count": 2551, + "p50": 16.659999999999854, + "p95": 16.68000000000029, + "max": 100 + }, + "framesMediaSeconds": { + "count": 2551, + "p50": 0, + "p95": 0.041733000000000686, + "max": 0.04536300000000182 + }, + "samplingWallMs": { + "count": 2624, + "p50": 17, + "p95": 18, + "max": 101 + }, + "samplingMediaSeconds": { + "count": 2624, + "p50": 0, + "p95": 0.041701999999999906, + "max": 0.04536300000000182 + } + }, + "totalVisible": 72, + "uniqueVisible": 72, + "recycled": 72, + "callbacks": 75, + "allocations": 6, + "reuses": 69, + "bypassedPool": 0, + "workers": [ + { + "posts": 75, + "replies": 75, + "terminated": 1, + "errors": [] + } + ], + "errors": [], + "destroyed": true, + "retainedPlayerRoots": 0 + }, + { + "engine": "firefox", + "implementation": "published", + "rowsPerSecond": 20, + "sha256": "7c8749288711ef97e80b6f9f00981170aa73f62a8ae25d6d663749a4aef62a8f", + "cycles": [ + { + "cycle": 0, + "base": 0.424629, + "startWall": 718, + "endWall": 15066, + "time": 14.695414, + "decodedWidth": 640, + "visibleCount": 240, + "uniqueVisible": 240, + "missedSampling": [], + "sampledNotVisible": [], + "queue": 240, + "states": { + "wait": 240, + "ready": 0, + "emit": 0, + "stop": 0 + }, + "nodes": 23, + "pooled": 22, + "uniquePool": 22, + "referenced": 0, + "distinctReferences": 0, + "uniqueStateMembers": 240, + "validStateMembers": true, + "heap": null, + "scheduled": 240, + "framesWallMs": { + "count": 856, + "p50": 16.659999999999854, + "p95": 16.68000000000029, + "max": 20.699999999999818 + }, + "framesMediaSeconds": { + "count": 856, + "p50": 0, + "p95": 0.041786999999999797, + "max": 0.04524600000000012 + } + }, + { + "cycle": 1, + "base": 14.695414, + "startWall": 15087, + "endWall": 29354, + "time": 28.8765, + "decodedWidth": 640, + "visibleCount": 240, + "uniqueVisible": 240, + "missedSampling": [], + "sampledNotVisible": [], + "queue": 480, + "states": { + "wait": 480, + "ready": 0, + "emit": 0, + "stop": 0 + }, + "nodes": 24, + "pooled": 22, + "uniquePool": 22, + "referenced": 0, + "distinctReferences": 0, + "uniqueStateMembers": 480, + "validStateMembers": true, + "heap": null, + "scheduled": 240, + "framesWallMs": { + "count": 850, + "p50": 16.659999999999854, + "p95": 16.68000000000029, + "max": 20.979999999999563 + }, + "framesMediaSeconds": { + "count": 850, + "p50": 0, + "p95": 0.04186299999999932, + "max": 0.045232999999999635 + } + }, + { + "cycle": 2, + "base": 28.8765, + "startWall": 29376, + "endWall": 43637, + "time": 43.066147, + "decodedWidth": 640, + "visibleCount": 240, + "uniqueVisible": 240, + "missedSampling": [], + "sampledNotVisible": [], + "queue": 720, + "states": { + "wait": 720, + "ready": 0, + "emit": 0, + "stop": 0 + }, + "nodes": 24, + "pooled": 21, + "uniquePool": 21, + "referenced": 0, + "distinctReferences": 0, + "uniqueStateMembers": 720, + "validStateMembers": true, + "heap": null, + "scheduled": 240, + "framesWallMs": { + "count": 851, + "p50": 16.660000000003492, + "p95": 16.68000000000029, + "max": 18.860000000000582 + }, + "framesMediaSeconds": { + "count": 851, + "p50": 0, + "p95": 0.041758000000001516, + "max": 0.04478300000000246 + } + } + ], + "sampleGapsIncludingLifecyclePauses": { + "framesWallMs": { + "count": 2557, + "p50": 16.659999999999854, + "p95": 16.68000000000029, + "max": 116.67999999999665 + }, + "framesMediaSeconds": { + "count": 2557, + "p50": 0, + "p95": 0.04180399999999995, + "max": 0.04524600000000012 + }, + "samplingWallMs": { + "count": 2631, + "p50": 17, + "p95": 18, + "max": 116 + }, + "samplingMediaSeconds": { + "count": 2631, + "p50": 0, + "p95": 0.04177699999999618, + "max": 0.04524600000000012 + } + }, + "totalVisible": 720, + "uniqueVisible": 720, + "recycled": 720, + "callbacks": 723, + "allocations": 24, + "reuses": 699, + "bypassedPool": 0, + "workers": [ + { + "posts": 723, + "replies": 723, + "terminated": 1, + "errors": [] + } + ], + "errors": [], + "destroyed": true, + "retainedPlayerRoots": 0 + }, + { + "engine": "firefox", + "implementation": "candidate", + "rowsPerSecond": 2, + "sha256": "e8193aa8fae3329b3a8e435fc450726d9305e258dddea043ff3114f058516a66", + "cycles": [ + { + "cycle": 0, + "base": 0.427679, + "startWall": 714, + "endWall": 14964, + "time": 14.596651, + "decodedWidth": 640, + "visibleCount": 24, + "uniqueVisible": 24, + "missedSampling": [], + "sampledNotVisible": [], + "queue": 24, + "states": { + "wait": 24, + "ready": 0, + "emit": 0, + "stop": 0 + }, + "nodes": 3, + "pooled": 3, + "uniquePool": 3, + "referenced": 0, + "distinctReferences": 0, + "uniqueStateMembers": 24, + "validStateMembers": true, + "heap": null, + "scheduled": 24, + "framesWallMs": { + "count": 850, + "p50": 16.659999999999854, + "p95": 16.68000000000029, + "max": 21.699999999999818 + }, + "framesMediaSeconds": { + "count": 850, + "p50": 0, + "p95": 0.04170599999999958, + "max": 0.04553100000000043 + } + }, + { + "cycle": 1, + "base": 14.596651, + "startWall": 14976, + "endWall": 29230, + "time": 28.767115, + "decodedWidth": 640, + "visibleCount": 24, + "uniqueVisible": 24, + "missedSampling": [], + "sampledNotVisible": [], + "queue": 48, + "states": { + "wait": 48, + "ready": 0, + "emit": 0, + "stop": 0 + }, + "nodes": 3, + "pooled": 3, + "uniquePool": 3, + "referenced": 0, + "distinctReferences": 0, + "uniqueStateMembers": 48, + "validStateMembers": true, + "heap": null, + "scheduled": 24, + "framesWallMs": { + "count": 850, + "p50": 16.659999999999854, + "p95": 16.68000000000029, + "max": 21.260000000002037 + }, + "framesMediaSeconds": { + "count": 850, + "p50": 0, + "p95": 0.04095400000000282, + "max": 0.04606899999999925 + } + }, + { + "cycle": 2, + "base": 28.767115, + "startWall": 29240, + "endWall": 43452, + "time": 42.937943, + "decodedWidth": 640, + "visibleCount": 24, + "uniqueVisible": 24, + "missedSampling": [], + "sampledNotVisible": [], + "queue": 72, + "states": { + "wait": 72, + "ready": 0, + "emit": 0, + "stop": 0 + }, + "nodes": 3, + "pooled": 3, + "uniquePool": 3, + "referenced": 0, + "distinctReferences": 0, + "uniqueStateMembers": 72, + "validStateMembers": true, + "heap": null, + "scheduled": 24, + "framesWallMs": { + "count": 848, + "p50": 16.660000000003492, + "p95": 16.68000000000029, + "max": 18.720000000001164 + }, + "framesMediaSeconds": { + "count": 848, + "p50": 0, + "p95": 0.04165899999999567, + "max": 0.04530800000000568 + } + } + ], + "sampleGapsIncludingLifecyclePauses": { + "framesWallMs": { + "count": 2548, + "p50": 16.659999999999854, + "p95": 16.68000000000029, + "max": 100 + }, + "framesMediaSeconds": { + "count": 2548, + "p50": 0, + "p95": 0.041519000000000084, + "max": 0.04606899999999925 + }, + "samplingWallMs": { + "count": 2548, + "p50": 17, + "p95": 18, + "max": 99 + }, + "samplingMediaSeconds": { + "count": 2548, + "p50": 0, + "p95": 0.041519000000000084, + "max": 0.04606899999999925 + } + }, + "totalVisible": 72, + "uniqueVisible": 72, + "recycled": 72, + "callbacks": 72, + "allocations": 3, + "reuses": 69, + "bypassedPool": 0, + "workers": [ + { + "posts": 72, + "replies": 72, + "terminated": 1, + "errors": [] + } + ], + "errors": [], + "destroyed": true, + "retainedPlayerRoots": 0 + }, + { + "engine": "firefox", + "implementation": "candidate", + "rowsPerSecond": 20, + "sha256": "e8193aa8fae3329b3a8e435fc450726d9305e258dddea043ff3114f058516a66", + "cycles": [ + { + "cycle": 0, + "base": 0.181611, + "startWall": 437, + "endWall": 14704, + "time": 14.375495, + "decodedWidth": 640, + "visibleCount": 240, + "uniqueVisible": 240, + "missedSampling": [], + "sampledNotVisible": [], + "queue": 240, + "states": { + "wait": 240, + "ready": 0, + "emit": 0, + "stop": 0 + }, + "nodes": 21, + "pooled": 21, + "uniquePool": 21, + "referenced": 0, + "distinctReferences": 0, + "uniqueStateMembers": 240, + "validStateMembers": true, + "heap": null, + "scheduled": 240, + "framesWallMs": { + "count": 851, + "p50": 16.659999999999854, + "p95": 16.68000000000029, + "max": 21.0600000000004 + }, + "framesMediaSeconds": { + "count": 851, + "p50": 0, + "p95": 0.0420170000000013, + "max": 0.04489000000000054 + } + }, + { + "cycle": 1, + "base": 14.375495, + "startWall": 14730, + "endWall": 28990, + "time": 28.559151, + "decodedWidth": 640, + "visibleCount": 240, + "uniqueVisible": 240, + "missedSampling": [], + "sampledNotVisible": [], + "queue": 480, + "states": { + "wait": 480, + "ready": 0, + "emit": 0, + "stop": 0 + }, + "nodes": 22, + "pooled": 22, + "uniquePool": 22, + "referenced": 0, + "distinctReferences": 0, + "uniqueStateMembers": 480, + "validStateMembers": true, + "heap": null, + "scheduled": 240, + "framesWallMs": { + "count": 850, + "p50": 16.659999999999854, + "p95": 16.68000000000029, + "max": 20.92000000000189 + }, + "framesMediaSeconds": { + "count": 850, + "p50": 0, + "p95": 0.04180500000000009, + "max": 0.04524799999999907 + } + }, + { + "cycle": 2, + "base": 28.559151, + "startWall": 29012, + "endWall": 43243, + "time": 42.690484, + "decodedWidth": 640, + "visibleCount": 240, + "uniqueVisible": 240, + "missedSampling": [], + "sampledNotVisible": [], + "queue": 720, + "states": { + "wait": 720, + "ready": 0, + "emit": 0, + "stop": 0 + }, + "nodes": 22, + "pooled": 22, + "uniquePool": 22, + "referenced": 0, + "distinctReferences": 0, + "uniqueStateMembers": 720, + "validStateMembers": true, + "heap": null, + "scheduled": 240, + "framesWallMs": { + "count": 849, + "p50": 16.660000000003492, + "p95": 16.68000000000029, + "max": 19 + }, + "framesMediaSeconds": { + "count": 849, + "p50": 0, + "p95": 0.04203499999999849, + "max": 0.04544299999999879 + } + } + ], + "sampleGapsIncludingLifecyclePauses": { + "framesWallMs": { + "count": 2550, + "p50": 16.659999999999854, + "p95": 16.68000000000029, + "max": 116.66000000000167 + }, + "framesMediaSeconds": { + "count": 2550, + "p50": 0, + "p95": 0.04198500000000038, + "max": 0.04544299999999879 + }, + "samplingWallMs": { + "count": 2550, + "p50": 17, + "p95": 18, + "max": 117 + }, + "samplingMediaSeconds": { + "count": 2550, + "p50": 0, + "p95": 0.04198500000000038, + "max": 0.04544299999999879 + } + }, + "totalVisible": 720, + "uniqueVisible": 720, + "recycled": 720, + "callbacks": 720, + "allocations": 22, + "reuses": 698, + "bypassedPool": 0, + "workers": [ + { + "posts": 720, + "replies": 720, + "terminated": 1, + "errors": [] + } + ], + "errors": [], + "destroyed": true, + "retainedPlayerRoots": 0 + }, + { + "engine": "webkit", + "implementation": "published", + "rowsPerSecond": 2, + "sha256": "7c8749288711ef97e80b6f9f00981170aa73f62a8ae25d6d663749a4aef62a8f", + "cycles": [ + { + "cycle": 0, + "base": 0.2676458, + "startWall": 1302, + "endWall": 16269, + "time": 15.0319999, + "decodedWidth": 640, + "visibleCount": 24, + "uniqueVisible": 24, + "missedSampling": [], + "sampledNotVisible": [], + "queue": 24, + "states": { + "wait": 24, + "ready": 0, + "emit": 0, + "stop": 0 + }, + "nodes": 4, + "pooled": 3, + "uniquePool": 3, + "referenced": 0, + "distinctReferences": 0, + "uniqueStateMembers": 24, + "validStateMembers": true, + "heap": null, + "scheduled": 24, + "framesWallMs": { + "count": 358, + "p50": 45, + "p95": 61, + "max": 64 + }, + "framesMediaSeconds": { + "count": 358, + "p50": 0.045270799999999056, + "p95": 0.06116659999999996, + "max": 0.06383330000000065 + } + }, + { + "cycle": 1, + "base": 15.0319999, + "startWall": 16311, + "endWall": 31301, + "time": 29.7106039, + "decodedWidth": 640, + "visibleCount": 24, + "uniqueVisible": 24, + "missedSampling": [], + "sampledNotVisible": [], + "queue": 48, + "states": { + "wait": 48, + "ready": 0, + "emit": 0, + "stop": 0 + }, + "nodes": 5, + "pooled": 3, + "uniquePool": 3, + "referenced": 0, + "distinctReferences": 0, + "uniqueStateMembers": 48, + "validStateMembers": true, + "heap": null, + "scheduled": 24, + "framesWallMs": { + "count": 363, + "p50": 45, + "p95": 61, + "max": 76 + }, + "framesMediaSeconds": { + "count": 363, + "p50": 0.045270900000002, + "p95": 0.06120830000000055, + "max": 0.07685419999999965 + } + }, + { + "cycle": 2, + "base": 29.7106039, + "startWall": 31312, + "endWall": 46136, + "time": 44.2841962, + "decodedWidth": 640, + "visibleCount": 24, + "uniqueVisible": 24, + "missedSampling": [], + "sampledNotVisible": [], + "queue": 72, + "states": { + "wait": 72, + "ready": 0, + "emit": 0, + "stop": 0 + }, + "nodes": 6, + "pooled": 3, + "uniquePool": 3, + "referenced": 0, + "distinctReferences": 0, + "uniqueStateMembers": 72, + "validStateMembers": true, + "heap": null, + "scheduled": 24, + "framesWallMs": { + "count": 370, + "p50": 45, + "p95": 49, + "max": 78 + }, + "framesMediaSeconds": { + "count": 370, + "p50": 0.044770800000002, + "p95": 0.049208300000003646, + "max": 0.07760420000000323 + } + } + ], + "sampleGapsIncludingLifecyclePauses": { + "framesWallMs": { + "count": 1091, + "p50": 45, + "p95": 61, + "max": 365 + }, + "framesMediaSeconds": { + "count": 1091, + "p50": 0.045083300000001714, + "p95": 0.060958299999999355, + "max": 0.07760420000000323 + }, + "samplingWallMs": { + "count": 1120, + "p50": 45, + "p95": 61, + "max": 365 + }, + "samplingMediaSeconds": { + "count": 1120, + "p50": 0.04497920000000022, + "p95": 0.06087510000000007, + "max": 0.07762500000000472 + } + }, + "totalVisible": 72, + "uniqueVisible": 72, + "recycled": 72, + "callbacks": 75, + "allocations": 6, + "reuses": 69, + "bypassedPool": 0, + "workers": [ + { + "posts": 75, + "replies": 75, + "terminated": 1, + "errors": [] + } + ], + "errors": [], + "destroyed": true, + "retainedPlayerRoots": 0 + }, + { + "engine": "webkit", + "implementation": "published", + "rowsPerSecond": 20, + "sha256": "7c8749288711ef97e80b6f9f00981170aa73f62a8ae25d6d663749a4aef62a8f", + "cycles": [ + { + "cycle": 0, + "base": 0.2983958, + "startWall": 1309, + "endWall": 16297, + "time": 15.0258749, + "decodedWidth": 640, + "visibleCount": 240, + "uniqueVisible": 240, + "missedSampling": [], + "sampledNotVisible": [], + "queue": 240, + "states": { + "wait": 240, + "ready": 0, + "emit": 0, + "stop": 0 + }, + "nodes": 23, + "pooled": 22, + "uniquePool": 22, + "referenced": 0, + "distinctReferences": 0, + "uniqueStateMembers": 240, + "validStateMembers": true, + "heap": null, + "scheduled": 240, + "framesWallMs": { + "count": 220, + "p50": 77, + "p95": 79, + "max": 93 + }, + "framesMediaSeconds": { + "count": 220, + "p50": 0.07679159999999996, + "p95": 0.07877080000000003, + "max": 0.09327089999999982 + } + }, + { + "cycle": 1, + "base": 15.0258749, + "startWall": 16320, + "endWall": 31241, + "time": 29.6541872, + "decodedWidth": 640, + "visibleCount": 240, + "uniqueVisible": 240, + "missedSampling": [], + "sampledNotVisible": [], + "queue": 480, + "states": { + "wait": 480, + "ready": 0, + "emit": 0, + "stop": 0 + }, + "nodes": 24, + "pooled": 22, + "uniquePool": 22, + "referenced": 0, + "distinctReferences": 0, + "uniqueStateMembers": 480, + "validStateMembers": true, + "heap": null, + "scheduled": 240, + "framesWallMs": { + "count": 219, + "p50": 77, + "p95": 79, + "max": 93 + }, + "framesMediaSeconds": { + "count": 219, + "p50": 0.07679169999999758, + "p95": 0.07897920000000269, + "max": 0.09302089999999907 + } + }, + { + "cycle": 2, + "base": 29.6541872, + "startWall": 31285, + "endWall": 46222, + "time": 44.2532795, + "decodedWidth": 640, + "visibleCount": 240, + "uniqueVisible": 240, + "missedSampling": [], + "sampledNotVisible": [], + "queue": 720, + "states": { + "wait": 720, + "ready": 0, + "emit": 0, + "stop": 0 + }, + "nodes": 25, + "pooled": 22, + "uniquePool": 22, + "referenced": 0, + "distinctReferences": 0, + "uniqueStateMembers": 720, + "validStateMembers": true, + "heap": null, + "scheduled": 240, + "framesWallMs": { + "count": 220, + "p50": 77, + "p95": 79, + "max": 94 + }, + "framesMediaSeconds": { + "count": 220, + "p50": 0.07668759999999963, + "p95": 0.07902080000000211, + "max": 0.09408340000000237 + } + } + ], + "sampleGapsIncludingLifecyclePauses": { + "framesWallMs": { + "count": 659, + "p50": 77, + "p95": 79, + "max": 414 + }, + "framesMediaSeconds": { + "count": 659, + "p50": 0.07675000000000054, + "p95": 0.07889580000000151, + "max": 0.09408340000000237 + }, + "samplingWallMs": { + "count": 689, + "p50": 77, + "p95": 79, + "max": 414 + }, + "samplingMediaSeconds": { + "count": 689, + "p50": 0.07662499999999994, + "p95": 0.0788542000000021, + "max": 0.0940833000000012 + } + }, + "totalVisible": 720, + "uniqueVisible": 720, + "recycled": 720, + "callbacks": 723, + "allocations": 25, + "reuses": 698, + "bypassedPool": 0, + "workers": [ + { + "posts": 723, + "replies": 723, + "terminated": 1, + "errors": [] + } + ], + "errors": [], + "destroyed": true, + "retainedPlayerRoots": 0 + }, + { + "engine": "webkit", + "implementation": "candidate", + "rowsPerSecond": 2, + "sha256": "e8193aa8fae3329b3a8e435fc450726d9305e258dddea043ff3114f058516a66", + "cycles": [ + { + "cycle": 0, + "base": 0.37275, + "startWall": 1294, + "endWall": 16315, + "time": 15.1836874, + "decodedWidth": 640, + "visibleCount": 24, + "uniqueVisible": 24, + "missedSampling": [], + "sampledNotVisible": [], + "queue": 24, + "states": { + "wait": 24, + "ready": 0, + "emit": 0, + "stop": 0 + }, + "nodes": 3, + "pooled": 3, + "uniquePool": 3, + "referenced": 0, + "distinctReferences": 0, + "uniqueStateMembers": 24, + "validStateMembers": true, + "heap": null, + "scheduled": 24, + "framesWallMs": { + "count": 363, + "p50": 45, + "p95": 61, + "max": 64 + }, + "framesMediaSeconds": { + "count": 363, + "p50": 0.045187499999999936, + "p95": 0.06122919999999965, + "max": 0.06333330000000004 + } + }, + { + "cycle": 1, + "base": 15.1836874, + "startWall": 16375, + "endWall": 31283, + "time": 29.8325622, + "decodedWidth": 640, + "visibleCount": 24, + "uniqueVisible": 24, + "missedSampling": [], + "sampledNotVisible": [], + "queue": 48, + "states": { + "wait": 48, + "ready": 0, + "emit": 0, + "stop": 0 + }, + "nodes": 3, + "pooled": 3, + "uniquePool": 3, + "referenced": 0, + "distinctReferences": 0, + "uniqueStateMembers": 48, + "validStateMembers": true, + "heap": null, + "scheduled": 24, + "framesWallMs": { + "count": 361, + "p50": 45, + "p95": 61, + "max": 64 + }, + "framesMediaSeconds": { + "count": 361, + "p50": 0.04527080000000083, + "p95": 0.06106250000000024, + "max": 0.06364589999999737 + } + }, + { + "cycle": 2, + "base": 29.8325622, + "startWall": 31328, + "endWall": 46200, + "time": 44.4231129, + "decodedWidth": 640, + "visibleCount": 24, + "uniqueVisible": 24, + "missedSampling": [], + "sampledNotVisible": [], + "queue": 72, + "states": { + "wait": 72, + "ready": 0, + "emit": 0, + "stop": 0 + }, + "nodes": 3, + "pooled": 3, + "uniquePool": 3, + "referenced": 0, + "distinctReferences": 0, + "uniqueStateMembers": 72, + "validStateMembers": true, + "heap": null, + "scheduled": 24, + "framesWallMs": { + "count": 365, + "p50": 45, + "p95": 61, + "max": 63 + }, + "framesMediaSeconds": { + "count": 365, + "p50": 0.044958299999997564, + "p95": 0.060916699999999935, + "max": 0.06322919999999854 + } + } + ], + "sampleGapsIncludingLifecyclePauses": { + "framesWallMs": { + "count": 1089, + "p50": 45, + "p95": 61, + "max": 337 + }, + "framesMediaSeconds": { + "count": 1089, + "p50": 0.045125000000000526, + "p95": 0.06106250000000024, + "max": 0.06364589999999737 + }, + "samplingWallMs": { + "count": 1089, + "p50": 45, + "p95": 61, + "max": 338 + }, + "samplingMediaSeconds": { + "count": 1089, + "p50": 0.045125000000000526, + "p95": 0.061062499999998465, + "max": 0.06362500000000182 + } + }, + "totalVisible": 72, + "uniqueVisible": 72, + "recycled": 72, + "callbacks": 72, + "allocations": 3, + "reuses": 69, + "bypassedPool": 0, + "workers": [ + { + "posts": 72, + "replies": 72, + "terminated": 1, + "errors": [] + } + ], + "errors": [], + "destroyed": true, + "retainedPlayerRoots": 0 + }, + { + "engine": "webkit", + "implementation": "candidate", + "rowsPerSecond": 20, + "sha256": "e8193aa8fae3329b3a8e435fc450726d9305e258dddea043ff3114f058516a66", + "cycles": [ + { + "cycle": 0, + "base": 0.3515, + "startWall": 1224, + "endWall": 16051, + "time": 14.9101248, + "decodedWidth": 640, + "visibleCount": 240, + "uniqueVisible": 240, + "missedSampling": [], + "sampledNotVisible": [], + "queue": 240, + "states": { + "wait": 240, + "ready": 0, + "emit": 0, + "stop": 0 + }, + "nodes": 22, + "pooled": 22, + "uniquePool": 22, + "referenced": 0, + "distinctReferences": 0, + "uniqueStateMembers": 240, + "validStateMembers": true, + "heap": null, + "scheduled": 240, + "framesWallMs": { + "count": 217, + "p50": 77, + "p95": 80, + "max": 109 + }, + "framesMediaSeconds": { + "count": 217, + "p50": 0.07679170000000024, + "p95": 0.0804999999999998, + "max": 0.10902089999999998 + } + }, + { + "cycle": 1, + "base": 14.9101248, + "startWall": 16109, + "endWall": 31070, + "time": 29.5584789, + "decodedWidth": 640, + "visibleCount": 240, + "uniqueVisible": 240, + "missedSampling": [], + "sampledNotVisible": [], + "queue": 480, + "states": { + "wait": 480, + "ready": 0, + "emit": 0, + "stop": 0 + }, + "nodes": 22, + "pooled": 22, + "uniquePool": 22, + "referenced": 0, + "distinctReferences": 0, + "uniqueStateMembers": 480, + "validStateMembers": true, + "heap": null, + "scheduled": 240, + "framesWallMs": { + "count": 220, + "p50": 77, + "p95": 79, + "max": 93 + }, + "framesMediaSeconds": { + "count": 220, + "p50": 0.07683340000000172, + "p95": 0.07910419999999974, + "max": 0.0930624999999985 + } + }, + { + "cycle": 2, + "base": 29.5584789, + "startWall": 31135, + "endWall": 46123, + "time": 44.2043628, + "decodedWidth": 640, + "visibleCount": 240, + "uniqueVisible": 240, + "missedSampling": [], + "sampledNotVisible": [], + "queue": 720, + "states": { + "wait": 720, + "ready": 0, + "emit": 0, + "stop": 0 + }, + "nodes": 22, + "pooled": 22, + "uniquePool": 22, + "referenced": 0, + "distinctReferences": 0, + "uniqueStateMembers": 720, + "validStateMembers": true, + "heap": null, + "scheduled": 240, + "framesWallMs": { + "count": 219, + "p50": 77, + "p95": 79, + "max": 95 + }, + "framesMediaSeconds": { + "count": 219, + "p50": 0.0768333000000041, + "p95": 0.0792707999999962, + "max": 0.09527079999999444 + } + } + ], + "sampleGapsIncludingLifecyclePauses": { + "framesWallMs": { + "count": 656, + "p50": 77, + "p95": 80, + "max": 428 + }, + "framesMediaSeconds": { + "count": 656, + "p50": 0.07679170000000024, + "p95": 0.07935409999999621, + "max": 0.10902089999999998 + }, + "samplingWallMs": { + "count": 656, + "p50": 77, + "p95": 80, + "max": 429 + }, + "samplingMediaSeconds": { + "count": 656, + "p50": 0.07679170000000024, + "p95": 0.07958329999999947, + "max": 0.10904169999999969 + } + }, + "totalVisible": 720, + "uniqueVisible": 720, + "recycled": 720, + "callbacks": 720, + "allocations": 22, + "reuses": 698, + "bypassedPool": 0, + "workers": [ + { + "posts": 720, + "replies": 720, + "terminated": 1, + "errors": [] + } + ], + "errors": [], + "destroyed": true, + "retainedPlayerRoots": 0 + } + ], + "mask": [ + { + "engine": "chromium", + "title": "published: Danmuku retains the core layer and external CSS mask across commands and retained-HTML destroy", + "snapshots": [ + { + "label": "before-registration", + "sameLayer": true, + "connected": true, + "styles": [ + { + "name": "mask-image", + "value": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")", + "priority": "", + "computed": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")" + }, + { + "name": "mask-mode", + "value": "alpha", + "priority": "", + "computed": "alpha" + }, + { + "name": "mask-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "mask-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + }, + { + "name": "background-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "background-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + } + ], + "children": 0, + "opacity": "", + "time": 0 + }, + { + "label": "after-registration", + "sameLayer": true, + "connected": true, + "styles": [ + { + "name": "mask-image", + "value": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")", + "priority": "", + "computed": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")" + }, + { + "name": "mask-mode", + "value": "alpha", + "priority": "", + "computed": "alpha" + }, + { + "name": "mask-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "mask-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + }, + { + "name": "background-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "background-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + } + ], + "children": 0, + "opacity": "1", + "time": 0 + }, + { + "label": "after-native-emit", + "sameLayer": true, + "connected": true, + "styles": [ + { + "name": "mask-image", + "value": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")", + "priority": "", + "computed": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")" + }, + { + "name": "mask-mode", + "value": "alpha", + "priority": "", + "computed": "alpha" + }, + { + "name": "mask-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "mask-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + }, + { + "name": "background-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "background-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + } + ], + "children": 1, + "opacity": "1", + "time": 0.032529 + }, + { + "label": "after-reset", + "sameLayer": true, + "connected": true, + "styles": [ + { + "name": "mask-image", + "value": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")", + "priority": "", + "computed": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")" + }, + { + "name": "mask-mode", + "value": "alpha", + "priority": "", + "computed": "alpha" + }, + { + "name": "mask-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "mask-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + }, + { + "name": "background-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "background-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + } + ], + "children": 1, + "opacity": "1", + "time": 0.046696 + }, + { + "label": "after-no-argument-load", + "sameLayer": true, + "connected": true, + "styles": [ + { + "name": "mask-image", + "value": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")", + "priority": "", + "computed": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")" + }, + { + "name": "mask-mode", + "value": "alpha", + "priority": "", + "computed": "alpha" + }, + { + "name": "mask-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "mask-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + }, + { + "name": "background-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "background-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + } + ], + "children": 0, + "opacity": "1", + "time": 0.049324 + }, + { + "label": "after-replacement-native-emit", + "sameLayer": true, + "connected": true, + "styles": [ + { + "name": "mask-image", + "value": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")", + "priority": "", + "computed": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")" + }, + { + "name": "mask-mode", + "value": "alpha", + "priority": "", + "computed": "alpha" + }, + { + "name": "mask-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "mask-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + }, + { + "name": "background-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "background-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + } + ], + "children": 1, + "opacity": "1", + "time": 0.065865 + }, + { + "label": "after-hide", + "sameLayer": true, + "connected": true, + "styles": [ + { + "name": "mask-image", + "value": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")", + "priority": "", + "computed": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")" + }, + { + "name": "mask-mode", + "value": "alpha", + "priority": "", + "computed": "alpha" + }, + { + "name": "mask-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "mask-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + }, + { + "name": "background-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "background-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + } + ], + "children": 1, + "opacity": "0", + "time": 0.070047 + }, + { + "label": "after-show", + "sameLayer": true, + "connected": true, + "styles": [ + { + "name": "mask-image", + "value": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")", + "priority": "", + "computed": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")" + }, + { + "name": "mask-mode", + "value": "alpha", + "priority": "", + "computed": "alpha" + }, + { + "name": "mask-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "mask-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + }, + { + "name": "background-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "background-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + } + ], + "children": 1, + "opacity": "1", + "time": 0.07497 + }, + { + "label": "after-destroy-false", + "sameLayer": true, + "connected": true, + "styles": [ + { + "name": "mask-image", + "value": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")", + "priority": "", + "computed": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")" + }, + { + "name": "mask-mode", + "value": "alpha", + "priority": "", + "computed": "alpha" + }, + { + "name": "mask-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "mask-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + }, + { + "name": "background-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "background-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + } + ], + "children": 0, + "opacity": "1", + "time": 0 + }, + { + "label": "after-destroy-native-frames", + "sameLayer": true, + "connected": true, + "styles": [ + { + "name": "mask-image", + "value": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")", + "priority": "", + "computed": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")" + }, + { + "name": "mask-mode", + "value": "alpha", + "priority": "", + "computed": "alpha" + }, + { + "name": "mask-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "mask-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + }, + { + "name": "background-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "background-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + } + ], + "children": 0, + "opacity": "1", + "time": 0 + } + ], + "workers": [ + { + "requests": [ + { + "type": "getDanmuTop", + "id": 1 + }, + { + "type": "getDanmuTop", + "id": 2 + } + ], + "replies": [ + { + "id": 1, + "result": 10 + }, + { + "id": 2, + "result": 10 + } + ], + "terminated": 1 + } + ], + "visible": [ + "MASK-BOUNDARY-EMIT", + "MASK-BOUNDARY-AFTER-LOAD" + ], + "errors": [] + }, + { + "engine": "chromium", + "title": "candidate: Danmuku retains the core layer and external CSS mask across commands and retained-HTML destroy", + "snapshots": [ + { + "label": "before-registration", + "sameLayer": true, + "connected": true, + "styles": [ + { + "name": "mask-image", + "value": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")", + "priority": "", + "computed": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")" + }, + { + "name": "mask-mode", + "value": "alpha", + "priority": "", + "computed": "alpha" + }, + { + "name": "mask-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "mask-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + }, + { + "name": "background-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "background-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + } + ], + "children": 0, + "opacity": "", + "time": 0 + }, + { + "label": "after-registration", + "sameLayer": true, + "connected": true, + "styles": [ + { + "name": "mask-image", + "value": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")", + "priority": "", + "computed": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")" + }, + { + "name": "mask-mode", + "value": "alpha", + "priority": "", + "computed": "alpha" + }, + { + "name": "mask-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "mask-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + }, + { + "name": "background-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "background-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + } + ], + "children": 0, + "opacity": "1", + "time": 0 + }, + { + "label": "after-native-emit", + "sameLayer": true, + "connected": true, + "styles": [ + { + "name": "mask-image", + "value": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")", + "priority": "", + "computed": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")" + }, + { + "name": "mask-mode", + "value": "alpha", + "priority": "", + "computed": "alpha" + }, + { + "name": "mask-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "mask-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + }, + { + "name": "background-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "background-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + } + ], + "children": 1, + "opacity": "1", + "time": 0.035365 + }, + { + "label": "after-reset", + "sameLayer": true, + "connected": true, + "styles": [ + { + "name": "mask-image", + "value": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")", + "priority": "", + "computed": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")" + }, + { + "name": "mask-mode", + "value": "alpha", + "priority": "", + "computed": "alpha" + }, + { + "name": "mask-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "mask-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + }, + { + "name": "background-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "background-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + } + ], + "children": 1, + "opacity": "1", + "time": 0.051809 + }, + { + "label": "after-no-argument-load", + "sameLayer": true, + "connected": true, + "styles": [ + { + "name": "mask-image", + "value": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")", + "priority": "", + "computed": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")" + }, + { + "name": "mask-mode", + "value": "alpha", + "priority": "", + "computed": "alpha" + }, + { + "name": "mask-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "mask-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + }, + { + "name": "background-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "background-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + } + ], + "children": 0, + "opacity": "1", + "time": 0.054545 + }, + { + "label": "after-replacement-native-emit", + "sameLayer": true, + "connected": true, + "styles": [ + { + "name": "mask-image", + "value": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")", + "priority": "", + "computed": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")" + }, + { + "name": "mask-mode", + "value": "alpha", + "priority": "", + "computed": "alpha" + }, + { + "name": "mask-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "mask-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + }, + { + "name": "background-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "background-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + } + ], + "children": 1, + "opacity": "1", + "time": 0.070648 + }, + { + "label": "after-hide", + "sameLayer": true, + "connected": true, + "styles": [ + { + "name": "mask-image", + "value": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")", + "priority": "", + "computed": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")" + }, + { + "name": "mask-mode", + "value": "alpha", + "priority": "", + "computed": "alpha" + }, + { + "name": "mask-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "mask-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + }, + { + "name": "background-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "background-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + } + ], + "children": 1, + "opacity": "0", + "time": 0.076207 + }, + { + "label": "after-show", + "sameLayer": true, + "connected": true, + "styles": [ + { + "name": "mask-image", + "value": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")", + "priority": "", + "computed": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")" + }, + { + "name": "mask-mode", + "value": "alpha", + "priority": "", + "computed": "alpha" + }, + { + "name": "mask-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "mask-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + }, + { + "name": "background-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "background-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + } + ], + "children": 1, + "opacity": "1", + "time": 0.080349 + }, + { + "label": "after-destroy-false", + "sameLayer": true, + "connected": true, + "styles": [ + { + "name": "mask-image", + "value": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")", + "priority": "", + "computed": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")" + }, + { + "name": "mask-mode", + "value": "alpha", + "priority": "", + "computed": "alpha" + }, + { + "name": "mask-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "mask-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + }, + { + "name": "background-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "background-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + } + ], + "children": 0, + "opacity": "1", + "time": 0 + }, + { + "label": "after-destroy-native-frames", + "sameLayer": true, + "connected": true, + "styles": [ + { + "name": "mask-image", + "value": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")", + "priority": "", + "computed": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")" + }, + { + "name": "mask-mode", + "value": "alpha", + "priority": "", + "computed": "alpha" + }, + { + "name": "mask-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "mask-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + }, + { + "name": "background-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "background-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + } + ], + "children": 0, + "opacity": "1", + "time": 0 + } + ], + "workers": [ + { + "requests": [ + { + "type": "getDanmuTop", + "id": 1 + }, + { + "type": "getDanmuTop", + "id": 2 + }, + { + "type": "getDanmuTop", + "id": 3 + } + ], + "replies": [ + { + "id": 1, + "result": 10 + }, + { + "id": 2, + "result": 10 + }, + { + "id": 3, + "result": 10 + } + ], + "terminated": 1 + } + ], + "visible": [ + "MASK-BOUNDARY-EMIT", + "MASK-BOUNDARY-EMIT", + "MASK-BOUNDARY-AFTER-LOAD" + ], + "errors": [] + }, + { + "engine": "firefox", + "title": "published: Danmuku retains the core layer and external CSS mask across commands and retained-HTML destroy", + "snapshots": [ + { + "label": "before-registration", + "sameLayer": true, + "connected": true, + "styles": [ + { + "name": "mask-image", + "value": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")", + "priority": "", + "computed": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")" + }, + { + "name": "mask-mode", + "value": "alpha", + "priority": "", + "computed": "alpha" + }, + { + "name": "mask-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "mask-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + }, + { + "name": "background-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "background-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + } + ], + "children": 0, + "opacity": "", + "time": 0 + }, + { + "label": "after-registration", + "sameLayer": true, + "connected": true, + "styles": [ + { + "name": "mask-image", + "value": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")", + "priority": "", + "computed": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")" + }, + { + "name": "mask-mode", + "value": "alpha", + "priority": "", + "computed": "alpha" + }, + { + "name": "mask-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "mask-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + }, + { + "name": "background-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "background-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + } + ], + "children": 0, + "opacity": "1", + "time": 0 + }, + { + "label": "after-native-emit", + "sameLayer": true, + "connected": true, + "styles": [ + { + "name": "mask-image", + "value": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")", + "priority": "", + "computed": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")" + }, + { + "name": "mask-mode", + "value": "alpha", + "priority": "", + "computed": "alpha" + }, + { + "name": "mask-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "mask-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + }, + { + "name": "background-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "background-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + } + ], + "children": 1, + "opacity": "1", + "time": 0.001882 + }, + { + "label": "after-reset", + "sameLayer": true, + "connected": true, + "styles": [ + { + "name": "mask-image", + "value": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")", + "priority": "", + "computed": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")" + }, + { + "name": "mask-mode", + "value": "alpha", + "priority": "", + "computed": "alpha" + }, + { + "name": "mask-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "mask-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + }, + { + "name": "background-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "background-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + } + ], + "children": 1, + "opacity": "1", + "time": 0.041666 + }, + { + "label": "after-no-argument-load", + "sameLayer": true, + "connected": true, + "styles": [ + { + "name": "mask-image", + "value": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")", + "priority": "", + "computed": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")" + }, + { + "name": "mask-mode", + "value": "alpha", + "priority": "", + "computed": "alpha" + }, + { + "name": "mask-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "mask-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + }, + { + "name": "background-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "background-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + } + ], + "children": 0, + "opacity": "1", + "time": 0.041666 + }, + { + "label": "after-replacement-native-emit", + "sameLayer": true, + "connected": true, + "styles": [ + { + "name": "mask-image", + "value": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")", + "priority": "", + "computed": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")" + }, + { + "name": "mask-mode", + "value": "alpha", + "priority": "", + "computed": "alpha" + }, + { + "name": "mask-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "mask-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + }, + { + "name": "background-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "background-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + } + ], + "children": 1, + "opacity": "1", + "time": 0.041666 + }, + { + "label": "after-hide", + "sameLayer": true, + "connected": true, + "styles": [ + { + "name": "mask-image", + "value": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")", + "priority": "", + "computed": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")" + }, + { + "name": "mask-mode", + "value": "alpha", + "priority": "", + "computed": "alpha" + }, + { + "name": "mask-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "mask-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + }, + { + "name": "background-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "background-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + } + ], + "children": 1, + "opacity": "0", + "time": 0.083332 + }, + { + "label": "after-show", + "sameLayer": true, + "connected": true, + "styles": [ + { + "name": "mask-image", + "value": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")", + "priority": "", + "computed": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")" + }, + { + "name": "mask-mode", + "value": "alpha", + "priority": "", + "computed": "alpha" + }, + { + "name": "mask-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "mask-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + }, + { + "name": "background-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "background-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + } + ], + "children": 1, + "opacity": "1", + "time": 0.083332 + }, + { + "label": "after-destroy-false", + "sameLayer": true, + "connected": true, + "styles": [ + { + "name": "mask-image", + "value": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")", + "priority": "", + "computed": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")" + }, + { + "name": "mask-mode", + "value": "alpha", + "priority": "", + "computed": "alpha" + }, + { + "name": "mask-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "mask-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + }, + { + "name": "background-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "background-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + } + ], + "children": 0, + "opacity": "1", + "time": 0 + }, + { + "label": "after-destroy-native-frames", + "sameLayer": true, + "connected": true, + "styles": [ + { + "name": "mask-image", + "value": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")", + "priority": "", + "computed": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")" + }, + { + "name": "mask-mode", + "value": "alpha", + "priority": "", + "computed": "alpha" + }, + { + "name": "mask-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "mask-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + }, + { + "name": "background-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "background-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + } + ], + "children": 0, + "opacity": "1", + "time": 0 + } + ], + "workers": [ + { + "requests": [ + { + "type": "getDanmuTop", + "id": 1 + }, + { + "type": "getDanmuTop", + "id": 2 + }, + { + "type": "getDanmuTop", + "id": 3 + } + ], + "replies": [ + { + "id": 1, + "result": 10 + }, + { + "id": 2, + "result": 10 + }, + { + "id": 3, + "result": 10 + } + ], + "terminated": 1 + } + ], + "visible": [ + "MASK-BOUNDARY-EMIT", + "MASK-BOUNDARY-EMIT", + "MASK-BOUNDARY-AFTER-LOAD" + ], + "errors": [] + }, + { + "engine": "firefox", + "title": "candidate: Danmuku retains the core layer and external CSS mask across commands and retained-HTML destroy", + "snapshots": [ + { + "label": "before-registration", + "sameLayer": true, + "connected": true, + "styles": [ + { + "name": "mask-image", + "value": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")", + "priority": "", + "computed": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")" + }, + { + "name": "mask-mode", + "value": "alpha", + "priority": "", + "computed": "alpha" + }, + { + "name": "mask-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "mask-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + }, + { + "name": "background-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "background-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + } + ], + "children": 0, + "opacity": "", + "time": 0 + }, + { + "label": "after-registration", + "sameLayer": true, + "connected": true, + "styles": [ + { + "name": "mask-image", + "value": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")", + "priority": "", + "computed": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")" + }, + { + "name": "mask-mode", + "value": "alpha", + "priority": "", + "computed": "alpha" + }, + { + "name": "mask-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "mask-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + }, + { + "name": "background-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "background-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + } + ], + "children": 0, + "opacity": "1", + "time": 0 + }, + { + "label": "after-native-emit", + "sameLayer": true, + "connected": true, + "styles": [ + { + "name": "mask-image", + "value": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")", + "priority": "", + "computed": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")" + }, + { + "name": "mask-mode", + "value": "alpha", + "priority": "", + "computed": "alpha" + }, + { + "name": "mask-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "mask-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + }, + { + "name": "background-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "background-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + } + ], + "children": 1, + "opacity": "1", + "time": 0.041666 + }, + { + "label": "after-reset", + "sameLayer": true, + "connected": true, + "styles": [ + { + "name": "mask-image", + "value": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")", + "priority": "", + "computed": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")" + }, + { + "name": "mask-mode", + "value": "alpha", + "priority": "", + "computed": "alpha" + }, + { + "name": "mask-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "mask-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + }, + { + "name": "background-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "background-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + } + ], + "children": 1, + "opacity": "1", + "time": 0.041666 + }, + { + "label": "after-no-argument-load", + "sameLayer": true, + "connected": true, + "styles": [ + { + "name": "mask-image", + "value": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")", + "priority": "", + "computed": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")" + }, + { + "name": "mask-mode", + "value": "alpha", + "priority": "", + "computed": "alpha" + }, + { + "name": "mask-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "mask-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + }, + { + "name": "background-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "background-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + } + ], + "children": 0, + "opacity": "1", + "time": 0.041666 + }, + { + "label": "after-replacement-native-emit", + "sameLayer": true, + "connected": true, + "styles": [ + { + "name": "mask-image", + "value": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")", + "priority": "", + "computed": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")" + }, + { + "name": "mask-mode", + "value": "alpha", + "priority": "", + "computed": "alpha" + }, + { + "name": "mask-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "mask-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + }, + { + "name": "background-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "background-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + } + ], + "children": 1, + "opacity": "1", + "time": 0.083332 + }, + { + "label": "after-hide", + "sameLayer": true, + "connected": true, + "styles": [ + { + "name": "mask-image", + "value": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")", + "priority": "", + "computed": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")" + }, + { + "name": "mask-mode", + "value": "alpha", + "priority": "", + "computed": "alpha" + }, + { + "name": "mask-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "mask-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + }, + { + "name": "background-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "background-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + } + ], + "children": 1, + "opacity": "0", + "time": 0.083332 + }, + { + "label": "after-show", + "sameLayer": true, + "connected": true, + "styles": [ + { + "name": "mask-image", + "value": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")", + "priority": "", + "computed": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")" + }, + { + "name": "mask-mode", + "value": "alpha", + "priority": "", + "computed": "alpha" + }, + { + "name": "mask-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "mask-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + }, + { + "name": "background-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "background-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + } + ], + "children": 1, + "opacity": "1", + "time": 0.083332 + }, + { + "label": "after-destroy-false", + "sameLayer": true, + "connected": true, + "styles": [ + { + "name": "mask-image", + "value": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")", + "priority": "", + "computed": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")" + }, + { + "name": "mask-mode", + "value": "alpha", + "priority": "", + "computed": "alpha" + }, + { + "name": "mask-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "mask-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + }, + { + "name": "background-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "background-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + } + ], + "children": 0, + "opacity": "1", + "time": 0 + }, + { + "label": "after-destroy-native-frames", + "sameLayer": true, + "connected": true, + "styles": [ + { + "name": "mask-image", + "value": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")", + "priority": "", + "computed": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")" + }, + { + "name": "mask-mode", + "value": "alpha", + "priority": "", + "computed": "alpha" + }, + { + "name": "mask-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "mask-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + }, + { + "name": "background-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "background-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + } + ], + "children": 0, + "opacity": "1", + "time": 0 + } + ], + "workers": [ + { + "requests": [ + { + "type": "getDanmuTop", + "id": 1 + }, + { + "type": "getDanmuTop", + "id": 2 + }, + { + "type": "getDanmuTop", + "id": 3 + } + ], + "replies": [ + { + "id": 1, + "result": 10 + }, + { + "id": 2, + "result": 10 + }, + { + "id": 3, + "result": 10 + } + ], + "terminated": 1 + } + ], + "visible": [ + "MASK-BOUNDARY-EMIT", + "MASK-BOUNDARY-EMIT", + "MASK-BOUNDARY-AFTER-LOAD" + ], + "errors": [] + }, + { + "engine": "webkit", + "title": "published: Danmuku retains the core layer and external CSS mask across commands and retained-HTML destroy", + "snapshots": [ + { + "label": "before-registration", + "sameLayer": true, + "connected": true, + "styles": [ + { + "name": "mask-image", + "value": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")", + "priority": "", + "computed": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")" + }, + { + "name": "mask-mode", + "value": "alpha", + "priority": "", + "computed": "alpha" + }, + { + "name": "mask-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "mask-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + }, + { + "name": "background-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "background-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + } + ], + "children": 0, + "opacity": "", + "time": 0 + }, + { + "label": "after-registration", + "sameLayer": true, + "connected": true, + "styles": [ + { + "name": "mask-image", + "value": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")", + "priority": "", + "computed": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")" + }, + { + "name": "mask-mode", + "value": "alpha", + "priority": "", + "computed": "alpha" + }, + { + "name": "mask-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "mask-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + }, + { + "name": "background-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "background-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + } + ], + "children": 0, + "opacity": "1", + "time": 0 + }, + { + "label": "after-native-emit", + "sameLayer": true, + "connected": true, + "styles": [ + { + "name": "mask-image", + "value": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")", + "priority": "", + "computed": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")" + }, + { + "name": "mask-mode", + "value": "alpha", + "priority": "", + "computed": "alpha" + }, + { + "name": "mask-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "mask-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + }, + { + "name": "background-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "background-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + } + ], + "children": 1, + "opacity": "1", + "time": 0.0560853 + }, + { + "label": "after-reset", + "sameLayer": true, + "connected": true, + "styles": [ + { + "name": "mask-image", + "value": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")", + "priority": "", + "computed": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")" + }, + { + "name": "mask-mode", + "value": "alpha", + "priority": "", + "computed": "alpha" + }, + { + "name": "mask-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "mask-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + }, + { + "name": "background-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "background-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + } + ], + "children": 1, + "opacity": "1", + "time": 0.1145099 + }, + { + "label": "after-no-argument-load", + "sameLayer": true, + "connected": true, + "styles": [ + { + "name": "mask-image", + "value": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")", + "priority": "", + "computed": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")" + }, + { + "name": "mask-mode", + "value": "alpha", + "priority": "", + "computed": "alpha" + }, + { + "name": "mask-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "mask-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + }, + { + "name": "background-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "background-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + } + ], + "children": 0, + "opacity": "1", + "time": 0.1331493 + }, + { + "label": "after-replacement-native-emit", + "sameLayer": true, + "connected": true, + "styles": [ + { + "name": "mask-image", + "value": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")", + "priority": "", + "computed": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")" + }, + { + "name": "mask-mode", + "value": "alpha", + "priority": "", + "computed": "alpha" + }, + { + "name": "mask-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "mask-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + }, + { + "name": "background-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "background-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + } + ], + "children": 1, + "opacity": "1", + "time": 0.2290091 + }, + { + "label": "after-hide", + "sameLayer": true, + "connected": true, + "styles": [ + { + "name": "mask-image", + "value": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")", + "priority": "", + "computed": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")" + }, + { + "name": "mask-mode", + "value": "alpha", + "priority": "", + "computed": "alpha" + }, + { + "name": "mask-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "mask-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + }, + { + "name": "background-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "background-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + } + ], + "children": 1, + "opacity": "0", + "time": 0.2411342 + }, + { + "label": "after-show", + "sameLayer": true, + "connected": true, + "styles": [ + { + "name": "mask-image", + "value": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")", + "priority": "", + "computed": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")" + }, + { + "name": "mask-mode", + "value": "alpha", + "priority": "", + "computed": "alpha" + }, + { + "name": "mask-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "mask-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + }, + { + "name": "background-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "background-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + } + ], + "children": 1, + "opacity": "1", + "time": 0.2466298 + }, + { + "label": "after-destroy-false", + "sameLayer": true, + "connected": true, + "styles": [ + { + "name": "mask-image", + "value": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")", + "priority": "", + "computed": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")" + }, + { + "name": "mask-mode", + "value": "alpha", + "priority": "", + "computed": "alpha" + }, + { + "name": "mask-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "mask-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + }, + { + "name": "background-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "background-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + } + ], + "children": 0, + "opacity": "1", + "time": 0 + }, + { + "label": "after-destroy-native-frames", + "sameLayer": true, + "connected": true, + "styles": [ + { + "name": "mask-image", + "value": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")", + "priority": "", + "computed": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")" + }, + { + "name": "mask-mode", + "value": "alpha", + "priority": "", + "computed": "alpha" + }, + { + "name": "mask-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "mask-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + }, + { + "name": "background-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "background-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + } + ], + "children": 0, + "opacity": "1", + "time": 0 + } + ], + "workers": [ + { + "requests": [ + { + "type": "getDanmuTop", + "id": 1 + }, + { + "type": "getDanmuTop", + "id": 2 + } + ], + "replies": [ + { + "id": 1, + "result": 10 + }, + { + "id": 2, + "result": 10 + } + ], + "terminated": 1 + } + ], + "visible": [ + "MASK-BOUNDARY-EMIT", + "MASK-BOUNDARY-AFTER-LOAD" + ], + "errors": [] + }, + { + "engine": "webkit", + "title": "candidate: Danmuku retains the core layer and external CSS mask across commands and retained-HTML destroy", + "snapshots": [ + { + "label": "before-registration", + "sameLayer": true, + "connected": true, + "styles": [ + { + "name": "mask-image", + "value": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")", + "priority": "", + "computed": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")" + }, + { + "name": "mask-mode", + "value": "alpha", + "priority": "", + "computed": "alpha" + }, + { + "name": "mask-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "mask-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + }, + { + "name": "background-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "background-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + } + ], + "children": 0, + "opacity": "", + "time": 0 + }, + { + "label": "after-registration", + "sameLayer": true, + "connected": true, + "styles": [ + { + "name": "mask-image", + "value": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")", + "priority": "", + "computed": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")" + }, + { + "name": "mask-mode", + "value": "alpha", + "priority": "", + "computed": "alpha" + }, + { + "name": "mask-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "mask-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + }, + { + "name": "background-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "background-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + } + ], + "children": 0, + "opacity": "1", + "time": 0 + }, + { + "label": "after-native-emit", + "sameLayer": true, + "connected": true, + "styles": [ + { + "name": "mask-image", + "value": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")", + "priority": "", + "computed": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")" + }, + { + "name": "mask-mode", + "value": "alpha", + "priority": "", + "computed": "alpha" + }, + { + "name": "mask-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "mask-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + }, + { + "name": "background-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "background-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + } + ], + "children": 1, + "opacity": "1", + "time": 0.0547591 + }, + { + "label": "after-reset", + "sameLayer": true, + "connected": true, + "styles": [ + { + "name": "mask-image", + "value": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")", + "priority": "", + "computed": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")" + }, + { + "name": "mask-mode", + "value": "alpha", + "priority": "", + "computed": "alpha" + }, + { + "name": "mask-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "mask-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + }, + { + "name": "background-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "background-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + } + ], + "children": 1, + "opacity": "1", + "time": 0.1121272 + }, + { + "label": "after-no-argument-load", + "sameLayer": true, + "connected": true, + "styles": [ + { + "name": "mask-image", + "value": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")", + "priority": "", + "computed": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")" + }, + { + "name": "mask-mode", + "value": "alpha", + "priority": "", + "computed": "alpha" + }, + { + "name": "mask-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "mask-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + }, + { + "name": "background-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "background-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + } + ], + "children": 0, + "opacity": "1", + "time": 0.1244461 + }, + { + "label": "after-replacement-native-emit", + "sameLayer": true, + "connected": true, + "styles": [ + { + "name": "mask-image", + "value": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")", + "priority": "", + "computed": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")" + }, + { + "name": "mask-mode", + "value": "alpha", + "priority": "", + "computed": "alpha" + }, + { + "name": "mask-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "mask-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + }, + { + "name": "background-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "background-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + } + ], + "children": 1, + "opacity": "1", + "time": 0.2397548 + }, + { + "label": "after-hide", + "sameLayer": true, + "connected": true, + "styles": [ + { + "name": "mask-image", + "value": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")", + "priority": "", + "computed": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")" + }, + { + "name": "mask-mode", + "value": "alpha", + "priority": "", + "computed": "alpha" + }, + { + "name": "mask-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "mask-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + }, + { + "name": "background-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "background-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + } + ], + "children": 1, + "opacity": "0", + "time": 0.2532712 + }, + { + "label": "after-show", + "sameLayer": true, + "connected": true, + "styles": [ + { + "name": "mask-image", + "value": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")", + "priority": "", + "computed": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")" + }, + { + "name": "mask-mode", + "value": "alpha", + "priority": "", + "computed": "alpha" + }, + { + "name": "mask-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "mask-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + }, + { + "name": "background-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "background-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + } + ], + "children": 1, + "opacity": "1", + "time": 0.2585794 + }, + { + "label": "after-destroy-false", + "sameLayer": true, + "connected": true, + "styles": [ + { + "name": "mask-image", + "value": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")", + "priority": "", + "computed": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")" + }, + { + "name": "mask-mode", + "value": "alpha", + "priority": "", + "computed": "alpha" + }, + { + "name": "mask-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "mask-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + }, + { + "name": "background-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "background-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + } + ], + "children": 0, + "opacity": "1", + "time": 0 + }, + { + "label": "after-destroy-native-frames", + "sameLayer": true, + "connected": true, + "styles": [ + { + "name": "mask-image", + "value": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")", + "priority": "", + "computed": "url(\"data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22640%22%20height%3D%22360%22%3E%3Crect%20width%3D%22320%22%20height%3D%22360%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E\")" + }, + { + "name": "mask-mode", + "value": "alpha", + "priority": "", + "computed": "alpha" + }, + { + "name": "mask-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "mask-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + }, + { + "name": "background-size", + "value": "contain", + "priority": "", + "computed": "contain" + }, + { + "name": "background-repeat", + "value": "no-repeat", + "priority": "", + "computed": "no-repeat" + } + ], + "children": 0, + "opacity": "1", + "time": 0 + } + ], + "workers": [ + { + "requests": [ + { + "type": "getDanmuTop", + "id": 1 + }, + { + "type": "getDanmuTop", + "id": 2 + } + ], + "replies": [ + { + "id": 1, + "result": 10 + }, + { + "id": 2, + "result": 10 + } + ], + "terminated": 1 + } + ], + "visible": [ + "MASK-BOUNDARY-EMIT", + "MASK-BOUNDARY-AFTER-LOAD" + ], + "errors": [] + } + ], + "resources": [ + { + "engine": "chromium", + "title": "published: shared setting mount preserves the surviving instance and later user changes", + "workers": [ + { + "terminated": 1 + }, + { + "terminated": 1 + } + ], + "sends": [], + "messages": [], + "errors": [], + "retainedSettings": 0, + "timers": 0 + }, + { + "engine": "chromium", + "title": "published: invalid setting mount rolls back plugin resources while preserving the original error", + "workers": [ + { + "terminated": 1 + }, + { + "terminated": 1 + } + ], + "sends": [], + "messages": [], + "errors": [], + "retainedSettings": 0, + "timers": 0 + }, + { + "engine": "chromium", + "title": "published: destroy cancels pending setting send without clearing retained input or starting a lock", + "workers": [ + { + "terminated": 1 + } + ], + "sends": [ + { + "index": 0, + "text": "PENDING", + "receiver": true + } + ], + "messages": [], + "errors": [], + "retainedSettings": 0, + "timers": 0 + }, + { + "engine": "chromium", + "title": "published: destroy clears active send timer and leaves another mounted instance usable", + "workers": [ + { + "terminated": 1 + }, + { + "terminated": 1 + } + ], + "sends": [ + { + "index": 0, + "text": "LOCK", + "receiver": true + }, + { + "index": 1, + "text": "SECOND", + "receiver": true + } + ], + "messages": [], + "errors": [], + "retainedSettings": 0, + "timers": 0 + }, + { + "engine": "chromium", + "title": "published: rejected setting callback retains input and original console error without an unhandled rejection", + "workers": [ + { + "terminated": 1 + } + ], + "sends": [ + { + "index": 0, + "text": "REJECT", + "receiver": true + } + ], + "messages": [], + "errors": [ + [ + "Error emitting danmuku:", + "controlled setting rejection" + ] + ], + "retainedSettings": 0, + "timers": 0 + }, + { + "engine": "chromium", + "title": "published: destroy false releases actual renderer nodes while retaining the player shell", + "workers": [ + { + "terminated": 1 + } + ], + "sends": [], + "messages": [ + "VISIBLE" + ], + "errors": [], + "retainedSettings": 0, + "timers": 0 + }, + { + "engine": "chromium", + "title": "published: replacement load removes a moved renderer node and preserves unrelated body content", + "workers": [ + { + "terminated": 1 + } + ], + "sends": [], + "messages": [ + "MOVED" + ], + "errors": [], + "retainedSettings": 0, + "timers": 0 + }, + { + "engine": "chromium", + "title": "published: narrow heatmap invalid sampling stays responsive and two instances have independent gradients", + "workers": [ + { + "terminated": 1 + }, + { + "terminated": 1 + } + ], + "sends": [], + "messages": [], + "errors": [], + "retainedSettings": 0, + "timers": 0 + }, + { + "engine": "chromium", + "title": "candidate: shared setting mount preserves the surviving instance and later user changes", + "workers": [ + { + "terminated": 1 + }, + { + "terminated": 1 + } + ], + "sends": [], + "messages": [], + "errors": [], + "retainedSettings": 0, + "timers": 0 + }, + { + "engine": "chromium", + "title": "candidate: invalid setting mount rolls back plugin resources while preserving the original error", + "workers": [ + { + "terminated": 1 + }, + { + "terminated": 1 + } + ], + "sends": [], + "messages": [], + "errors": [], + "retainedSettings": 0, + "timers": 0 + }, + { + "engine": "chromium", + "title": "candidate: destroy cancels pending setting send without clearing retained input or starting a lock", + "workers": [ + { + "terminated": 1 + } + ], + "sends": [ + { + "index": 0, + "text": "PENDING", + "receiver": true + } + ], + "messages": [], + "errors": [], + "retainedSettings": 0, + "timers": 0 + }, + { + "engine": "chromium", + "title": "candidate: destroy clears active send timer and leaves another mounted instance usable", + "workers": [ + { + "terminated": 1 + }, + { + "terminated": 1 + } + ], + "sends": [ + { + "index": 0, + "text": "LOCK", + "receiver": true + }, + { + "index": 1, + "text": "SECOND", + "receiver": true + } + ], + "messages": [], + "errors": [], + "retainedSettings": 0, + "timers": 0 + }, + { + "engine": "chromium", + "title": "candidate: rejected setting callback retains input and original console error without an unhandled rejection", + "workers": [ + { + "terminated": 1 + } + ], + "sends": [ + { + "index": 0, + "text": "REJECT", + "receiver": true + } + ], + "messages": [], + "errors": [ + [ + "Error emitting danmuku:", + "controlled setting rejection" + ] + ], + "retainedSettings": 0, + "timers": 0 + }, + { + "engine": "chromium", + "title": "candidate: destroy false releases actual renderer nodes while retaining the player shell", + "workers": [ + { + "terminated": 1 + } + ], + "sends": [], + "messages": [ + "VISIBLE" + ], + "errors": [], + "retainedSettings": 0, + "timers": 0 + }, + { + "engine": "chromium", + "title": "candidate: replacement load removes a moved renderer node and preserves unrelated body content", + "workers": [ + { + "terminated": 1 + } + ], + "sends": [], + "messages": [ + "MOVED" + ], + "errors": [], + "retainedSettings": 0, + "timers": 0 + }, + { + "engine": "chromium", + "title": "candidate: narrow heatmap invalid sampling stays responsive and two instances have independent gradients", + "workers": [ + { + "terminated": 1 + }, + { + "terminated": 1 + } + ], + "sends": [], + "messages": [], + "errors": [], + "retainedSettings": 0, + "timers": 0 + }, + { + "engine": "firefox", + "title": "published: shared setting mount preserves the surviving instance and later user changes", + "workers": [ + { + "terminated": 1 + }, + { + "terminated": 1 + } + ], + "sends": [], + "messages": [], + "errors": [], + "retainedSettings": 0, + "timers": 0 + }, + { + "engine": "firefox", + "title": "published: invalid setting mount rolls back plugin resources while preserving the original error", + "workers": [ + { + "terminated": 1 + }, + { + "terminated": 1 + } + ], + "sends": [], + "messages": [], + "errors": [], + "retainedSettings": 0, + "timers": 0 + }, + { + "engine": "firefox", + "title": "published: destroy cancels pending setting send without clearing retained input or starting a lock", + "workers": [ + { + "terminated": 1 + } + ], + "sends": [ + { + "index": 0, + "text": "PENDING", + "receiver": true + } + ], + "messages": [], + "errors": [], + "retainedSettings": 0, + "timers": 0 + }, + { + "engine": "firefox", + "title": "published: destroy clears active send timer and leaves another mounted instance usable", + "workers": [ + { + "terminated": 1 + }, + { + "terminated": 1 + } + ], + "sends": [ + { + "index": 0, + "text": "LOCK", + "receiver": true + }, + { + "index": 1, + "text": "SECOND", + "receiver": true + } + ], + "messages": [], + "errors": [], + "retainedSettings": 0, + "timers": 0 + }, + { + "engine": "firefox", + "title": "published: rejected setting callback retains input and original console error without an unhandled rejection", + "workers": [ + { + "terminated": 1 + } + ], + "sends": [ + { + "index": 0, + "text": "REJECT", + "receiver": true + } + ], + "messages": [], + "errors": [ + [ + "Error emitting danmuku:", + "controlled setting rejection" + ] + ], + "retainedSettings": 0, + "timers": 0 + }, + { + "engine": "firefox", + "title": "published: destroy false releases actual renderer nodes while retaining the player shell", + "workers": [ + { + "terminated": 1 + } + ], + "sends": [], + "messages": [ + "VISIBLE" + ], + "errors": [], + "retainedSettings": 0, + "timers": 0 + }, + { + "engine": "firefox", + "title": "published: replacement load removes a moved renderer node and preserves unrelated body content", + "workers": [ + { + "terminated": 1 + } + ], + "sends": [], + "messages": [ + "MOVED" + ], + "errors": [], + "retainedSettings": 0, + "timers": 0 + }, + { + "engine": "firefox", + "title": "published: narrow heatmap invalid sampling stays responsive and two instances have independent gradients", + "workers": [ + { + "terminated": 1 + }, + { + "terminated": 1 + } + ], + "sends": [], + "messages": [], + "errors": [], + "retainedSettings": 0, + "timers": 0 + }, + { + "engine": "firefox", + "title": "candidate: shared setting mount preserves the surviving instance and later user changes", + "workers": [ + { + "terminated": 1 + }, + { + "terminated": 1 + } + ], + "sends": [], + "messages": [], + "errors": [], + "retainedSettings": 0, + "timers": 0 + }, + { + "engine": "firefox", + "title": "candidate: invalid setting mount rolls back plugin resources while preserving the original error", + "workers": [ + { + "terminated": 1 + }, + { + "terminated": 1 + } + ], + "sends": [], + "messages": [], + "errors": [], + "retainedSettings": 0, + "timers": 0 + }, + { + "engine": "firefox", + "title": "candidate: destroy cancels pending setting send without clearing retained input or starting a lock", + "workers": [ + { + "terminated": 1 + } + ], + "sends": [ + { + "index": 0, + "text": "PENDING", + "receiver": true + } + ], + "messages": [], + "errors": [], + "retainedSettings": 0, + "timers": 0 + }, + { + "engine": "firefox", + "title": "candidate: destroy clears active send timer and leaves another mounted instance usable", + "workers": [ + { + "terminated": 1 + }, + { + "terminated": 1 + } + ], + "sends": [ + { + "index": 0, + "text": "LOCK", + "receiver": true + }, + { + "index": 1, + "text": "SECOND", + "receiver": true + } + ], + "messages": [], + "errors": [], + "retainedSettings": 0, + "timers": 0 + }, + { + "engine": "firefox", + "title": "candidate: rejected setting callback retains input and original console error without an unhandled rejection", + "workers": [ + { + "terminated": 1 + } + ], + "sends": [ + { + "index": 0, + "text": "REJECT", + "receiver": true + } + ], + "messages": [], + "errors": [ + [ + "Error emitting danmuku:", + "controlled setting rejection" + ] + ], + "retainedSettings": 0, + "timers": 0 + }, + { + "engine": "firefox", + "title": "candidate: destroy false releases actual renderer nodes while retaining the player shell", + "workers": [ + { + "terminated": 1 + } + ], + "sends": [], + "messages": [ + "VISIBLE" + ], + "errors": [], + "retainedSettings": 0, + "timers": 0 + }, + { + "engine": "firefox", + "title": "candidate: replacement load removes a moved renderer node and preserves unrelated body content", + "workers": [ + { + "terminated": 1 + } + ], + "sends": [], + "messages": [ + "MOVED" + ], + "errors": [], + "retainedSettings": 0, + "timers": 0 + }, + { + "engine": "firefox", + "title": "candidate: narrow heatmap invalid sampling stays responsive and two instances have independent gradients", + "workers": [ + { + "terminated": 1 + }, + { + "terminated": 1 + } + ], + "sends": [], + "messages": [], + "errors": [], + "retainedSettings": 0, + "timers": 0 + }, + { + "engine": "webkit", + "title": "published: shared setting mount preserves the surviving instance and later user changes", + "workers": [ + { + "terminated": 1 + }, + { + "terminated": 1 + } + ], + "sends": [], + "messages": [], + "errors": [], + "retainedSettings": 0, + "timers": 0 + }, + { + "engine": "webkit", + "title": "published: invalid setting mount rolls back plugin resources while preserving the original error", + "workers": [ + { + "terminated": 1 + }, + { + "terminated": 1 + } + ], + "sends": [], + "messages": [], + "errors": [], + "retainedSettings": 0, + "timers": 0 + }, + { + "engine": "webkit", + "title": "published: destroy cancels pending setting send without clearing retained input or starting a lock", + "workers": [ + { + "terminated": 1 + } + ], + "sends": [ + { + "index": 0, + "text": "PENDING", + "receiver": true + } + ], + "messages": [], + "errors": [], + "retainedSettings": 0, + "timers": 0 + }, + { + "engine": "webkit", + "title": "published: destroy clears active send timer and leaves another mounted instance usable", + "workers": [ + { + "terminated": 1 + }, + { + "terminated": 1 + } + ], + "sends": [ + { + "index": 0, + "text": "LOCK", + "receiver": true + }, + { + "index": 1, + "text": "SECOND", + "receiver": true + } + ], + "messages": [], + "errors": [], + "retainedSettings": 0, + "timers": 0 + }, + { + "engine": "webkit", + "title": "published: rejected setting callback retains input and original console error without an unhandled rejection", + "workers": [ + { + "terminated": 1 + } + ], + "sends": [ + { + "index": 0, + "text": "REJECT", + "receiver": true + } + ], + "messages": [], + "errors": [ + [ + "Error emitting danmuku:", + "controlled setting rejection" + ] + ], + "retainedSettings": 0, + "timers": 0 + }, + { + "engine": "webkit", + "title": "published: destroy false releases actual renderer nodes while retaining the player shell", + "workers": [ + { + "terminated": 1 + } + ], + "sends": [], + "messages": [ + "VISIBLE" + ], + "errors": [], + "retainedSettings": 0, + "timers": 0 + }, + { + "engine": "webkit", + "title": "published: replacement load removes a moved renderer node and preserves unrelated body content", + "workers": [ + { + "terminated": 1 + } + ], + "sends": [], + "messages": [ + "MOVED" + ], + "errors": [], + "retainedSettings": 0, + "timers": 0 + }, + { + "engine": "webkit", + "title": "published: narrow heatmap invalid sampling stays responsive and two instances have independent gradients", + "workers": [ + { + "terminated": 1 + }, + { + "terminated": 1 + } + ], + "sends": [], + "messages": [], + "errors": [], + "retainedSettings": 0, + "timers": 0 + }, + { + "engine": "webkit", + "title": "candidate: shared setting mount preserves the surviving instance and later user changes", + "workers": [ + { + "terminated": 1 + }, + { + "terminated": 1 + } + ], + "sends": [], + "messages": [], + "errors": [], + "retainedSettings": 0, + "timers": 0 + }, + { + "engine": "webkit", + "title": "candidate: invalid setting mount rolls back plugin resources while preserving the original error", + "workers": [ + { + "terminated": 1 + }, + { + "terminated": 1 + } + ], + "sends": [], + "messages": [], + "errors": [], + "retainedSettings": 0, + "timers": 0 + }, + { + "engine": "webkit", + "title": "candidate: destroy cancels pending setting send without clearing retained input or starting a lock", + "workers": [ + { + "terminated": 1 + } + ], + "sends": [ + { + "index": 0, + "text": "PENDING", + "receiver": true + } + ], + "messages": [], + "errors": [], + "retainedSettings": 0, + "timers": 0 + }, + { + "engine": "webkit", + "title": "candidate: destroy clears active send timer and leaves another mounted instance usable", + "workers": [ + { + "terminated": 1 + }, + { + "terminated": 1 + } + ], + "sends": [ + { + "index": 0, + "text": "LOCK", + "receiver": true + }, + { + "index": 1, + "text": "SECOND", + "receiver": true + } + ], + "messages": [], + "errors": [], + "retainedSettings": 0, + "timers": 0 + }, + { + "engine": "webkit", + "title": "candidate: rejected setting callback retains input and original console error without an unhandled rejection", + "workers": [ + { + "terminated": 1 + } + ], + "sends": [ + { + "index": 0, + "text": "REJECT", + "receiver": true + } + ], + "messages": [], + "errors": [ + [ + "Error emitting danmuku:", + "controlled setting rejection" + ] + ], + "retainedSettings": 0, + "timers": 0 + }, + { + "engine": "webkit", + "title": "candidate: destroy false releases actual renderer nodes while retaining the player shell", + "workers": [ + { + "terminated": 1 + } + ], + "sends": [], + "messages": [ + "VISIBLE" + ], + "errors": [], + "retainedSettings": 0, + "timers": 0 + }, + { + "engine": "webkit", + "title": "candidate: replacement load removes a moved renderer node and preserves unrelated body content", + "workers": [ + { + "terminated": 1 + } + ], + "sends": [], + "messages": [ + "MOVED" + ], + "errors": [], + "retainedSettings": 0, + "timers": 0 + }, + { + "engine": "webkit", + "title": "candidate: narrow heatmap invalid sampling stays responsive and two instances have independent gradients", + "workers": [ + { + "terminated": 1 + }, + { + "terminated": 1 + } + ], + "sends": [], + "messages": [], + "errors": [], + "retainedSettings": 0, + "timers": 0 + } + ], + "checks": [ + { + "file": "refactor/.cache/danmuku07-lint.log", + "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + { + "file": "refactor/.cache/danmuku07-impact.log", + "sha256": "a273a996c268b4ad09d1a4fed9b75ede1417e499f26ccbed7f134d00209f5c3e" + } + ], + "scope": "Candidate core with fixed published/candidate plugins at 2 and 20 rows per second, three native 14-second append/play/pause cycles. Source candidate, synchronous true callbacks, antiOverlap false. Hard candidate delivery/once/recycle/state ownership/actual node reuse checks. Two-core CSS root-mask boundary plus existing resource suite. Not model inference, device equivalence, unbounded soak or heap leak proof.", + "timingDiagnosis": { + "evidence": "refactor/baselines/danmuku-frame-sampling-validation.json", + "resolvedDefects": [ + "PKG-DANMUKU-11", + "PKG-DANMUKU-12" + ], + "unchangedBoundary": "An 800ms blocked main thread cannot sample crossed timestamps under the historical +/-0.1-second rule. No invisible catchup or seeded readiness is used in the load suite." + }, + "failures": [ + { + "file": "refactor/.cache/danmuku07-stability-first.json", + "sha256": "89fbdf1c241eb8f855dcd7b69dc59cd3e6047aedaa3b6d73f8cd83764f4b1a38" + } + ], + "calibration": "First two Chromium cases failed only because the test wrongly expected load(rows) to replace. Source contract confirmed append; queue expectation changed to cumulative count while each-cycle visible count stayed exact. Initial corrected 12-case run passed, then independent review added actual node identity reuse, per-item state membership, once-only final visible/recycle and nonempty Worker assertions for this final run.", + "reusedEvidence": [ + "refactor/baselines/danmuku-frame-sampling-validation.json", + "refactor/baselines/danmuku-lifetime-validation.json", + "refactor/baselines/danmuku-heatmap-density-validation.json" + ], + "reuseReason": "No runtime or declaration change after PKG-DANMUKU-12. Its source/modern/legacy tests cover asynchronous serial dispatch, cancellation, geometry and visible lifetime; this task adds native load/resource/CSS evidence rather than claiming those paths were rerun by the load suite.", + "fingerprints": [ + { + "file": "test/browser/danmuku-stability.spec.js", + "sha256": "2778330a1a907c6d710ac8d47004c36e1527c94817644f1419f9ea71340e084e" + }, + { + "file": "test/browser/danmuku-mask-boundary.spec.js", + "sha256": "4220fa681f8d577ac666d02807f60337fb2a71bfc27cd1e1b0c47807215e1bdc" + }, + { + "file": "test/browser/danmuku-resources.spec.js", + "sha256": "f0d09e962cb422a66bd644c52268aff8f288606ae9c93676fa979539743f9c6b" + }, + { + "file": "packages/artplayer-plugin-danmuku/src/scheduler.ts", + "sha256": "8b5623a34e81253f08633c0240cf632e23f890b76ebfe96e21da23597cd35447" + }, + { + "file": "packages/artplayer-plugin-danmuku/src/scheduling-buffer.ts", + "sha256": "0a7eaf5229adcc74a8d9814fbc9a61cb3990045b3e99ac4ad9dc3f65fb9aab2e" + }, + { + "file": "packages/artplayer-plugin-danmuku/src/renderer.ts", + "sha256": "6ac4b1991c6cb683353a811f41b6ca025401029720cbcadaff120616ca936cdf" + }, + { + "file": "packages/artplayer-plugin-danmuku-mask/src/index.js", + "sha256": "2397900688f86bc74bc86a4e870f69478a651bd8df02bba543cdab832773fd6e" + } + ], + "remaining": [ + "PKG-DANMUKU-08 full combinations", + "PKG-DANMUKU-09 final distribution/docs", + "Mask lifecycle/TS/model migration and genuine model integration", + "Device and release review gates" + ] +} diff --git a/refactor/changes/2026-09-13-PKG-DANMUKU-07-stability.md b/refactor/changes/2026-09-13-PKG-DANMUKU-07-stability.md new file mode 100644 index 000000000..3a87f7cef --- /dev/null +++ b/refactor/changes/2026-09-13-PKG-DANMUKU-07-stability.md @@ -0,0 +1,66 @@ +# PKG-DANMUKU-07 弹幕稳定性与共享层边界 + +已完成本任务限定的验收,任务及提交状态以tasks.json和Git为准。此项对12后的生产 +实现增加原生负载和资源验收,没有改变运行时、声明、依赖、版本或构建内容。 + +## 验收范围 + +- 候选核心中比较固定npm5.3.0插件与候选源码,三引擎,每秒2和20条,各三轮 + 14秒真实媒体播放。每轮追加12秒的时间戳序列,三轮总计72/720条;其余时间 + 让弹幕自然显示和到期。保留真实RAF、视频时钟、Worker与原始readys getter。 +- 候选逐项检查采样/显示无丢失,三轮总显示和回收均恰好一次;队列追加语义、 + 每条对象只属于一个对应状态池、空闲池唯一性、根层节点和空闲池一致均受断言保护。 + 包装原始节点getter只记录身份,确认实际重复使用旧节点,并且有空闲节点时 + 不绕过池分配新节点;Worker必须存在且唯一,正常请求全部回复,销毁恰好一次。 +- 旧插件结果保留为对照观察,没有把其可能的历史缺陷豁免用于候选断言。 + 每轮帧间隔单独统计;包含暂停/加载转换的总采样间隔另列,不能当纯播放卡顿。 + 可选performance.memory是未强制GC的读数,不能证明泄漏或作跨引擎内存排名。 +- 两核心、三引擎运行已有资源用例:共享挂载、初始化回滚、发送取消/锁、原始 + 错误、destroy(false)、替换加载移除被移动的节点、热图实例隔离。 +- 新增两核心的CSS mask边界用例:注册前就取得核心根层,以固定内联SVG mask + 验证emit/reset/无参替换load/hide/show/destroy(false)中的层引用和样式保持, + 销毁后两帧没有晚请求和新子节点。此用例设置资源测试的ready前置状态、采用 + 原生0.25播放速率,不能当时间戳负载证据;负载用例没有这些设置。 + +## 问题处置与兼容性 + +早期原生时间窗口诊断区分了两个来源:800ms主线程完全阻塞,及600ms用户异步 +回调使旧调度停止采样。11独立修复隐藏Worker等待吞掉显示寿命;12独立修复异步 +放置期间的采样和到期维护。07继续检查这些修复后的实际负载及资源状态。 +没有把公开±0.1秒窗口改成无限追赶,因此完全阻塞时未被采样的时间点仍可错过。 + +本轮首个测试版本错误地把`load(rows)`当作替换,第二轮队列断言收到48/480而 +错误预期24/240。核实原实现后修正累计队列预期,当轮显示数仍精确24/240;没有 +修改生产语义。初步12项通过后,经独立审查补足Worker非空、节点身份复用、 +逐条状态归属和跨轮恰好一次的断言,最终需按补强后的文件重新验证。 + +Mask仅依赖核心提供的video/弹幕根层及ready/destroy,不读取弹幕队列、Owner +或插件事件。旧契约文档误称根层由Danmuku建立,已依据核心模板纠正并注明日期。 +固定发布归档和生产Mask源码未改。Mask自身晚推理复活RAF、模型dispose、并发 +start、模型和完整组合问题仍由Mask迁移任务处理,不能从本CSS测试判定通过。 + +## 维护与重跑 + +```sh +yarn test:browser test/browser/danmuku-stability.spec.js test/browser/danmuku-mask-boundary.spec.js test/browser/danmuku-resources.spec.js --workers=2 +``` + +负载测试的90秒单例deadline来自三轮42秒媒体预算及设置/销毁开销;没有扩大 +已有短用例超时。每次运行必须等待进程终态,归档report/results,再运行另一格式。 +正常来源是当前源码UMD;两个新用例均支持ARTPLAYER_DANMUKU_ARTIFACT。 + +包内ARCHITECTURE.md与refactor/danmuku-stability.md记录根层归属、诊断及限制。 +07未修改生产,因此复用12已记录的264项源码/136项产物单测、严格类型/构建,及 +其异步/几何/生命周期验证;不声称这些由本次持续负载套件重新完成。 +08完整组合、09最终分发、真实Mask模型/设备以及全项目发布复盘继续保留。 +回退本任务只撤销测试和文档,不应回退11/12已交付修复。 + +## 最终结果 + +补强后的66项浏览器检查全部通过(12项负载、6项CSS边界、48项资源),0重试、 +0跳过。每个负载用例完成三轮42秒原生媒体推进,候选两档各72/720条均完整且 +只显示/回收一次。精确节点复用、堆读数和帧间隔见 +[机器证据](../baselines/danmuku-stability-validation.json)。 +新测试lint通过;影响分析检查通过,保留Danmuku/Mask组合验证边,仅纠正其 +“Danmuku创建根层”的错误原因,不降低CI范围。测试由现有Playwright目录自动发现。 +未运行远端CI、未推送或发布。 diff --git a/refactor/danmuku-stability.md b/refactor/danmuku-stability.md new file mode 100644 index 000000000..6f48162c4 --- /dev/null +++ b/refactor/danmuku-stability.md @@ -0,0 +1,70 @@ +# PKG-DANMUKU-07 稳定性工作记录 + +本任务已在12后的运行时完成下述限定范围验收,任务与提交状态以tasks.json及Git为准。 +06类型检查、11/12修复与本任务证据分别维护;真实模型、完整组合和发布验收仍待后续任务。 + +## 已执行的时间窗口诊断 + +`test/browser/danmuku-timing-diagnostic.spec.js`在候选核心中比较实际npm5.3.0插件与 +06候选源码,使用本地90秒视频的短片段、原生RAF/媒体时钟和真实Worker。独立RAF +观察与实际readys getter采样分别记录;getter只包装读取,不修改返回数组或状态。 +每例3条弹幕,后置sentinel证明间隔后仍能正常发送。12项诊断通过意味着取证完成, +不代表漏掉弹幕的结果可以作为稳定性通过。 + +| 场景 | Chromium | Firefox | Windows WebKit | 新旧共同结果 | +| --- | --- | --- | --- | --- | +| 注入800ms主线程工作 | 最大媒体帧间隔约800ms | 约777–809ms | 约838–856ms | 前两条未进入任何readys采样,sentinel显示 | +| beforeVisible等待600ms | 原生帧间隔约19–21ms,采样间隔616–618ms | 帧44ms,采样583–609ms | 帧63–64ms,采样622–647ms | 第一条与sentinel显示,中间条未采样 | + +这解释了两种不同来源:前者浏览器主线程无法及时调度,后者浏览器仍在出帧,但 +插件等待当前异步准备完成而不再读取新的候选窗口。±0.1秒和串行回调都有明确 +历史语义;后续方案必须比较seek、hide/show、stop/start和false重试边界,不能 +直接改成无限追赶或并行回调。当前不据此声称全部真实负载问题已解决。 + +报告位于refactor/.cache/danmuku07-timing-diagnostic.json,日志及附件保留同名前缀。 +候选是11计时修复之前的06源码,具体构建SHA在每项danmuku-timing-observation中; +后续变更需说明哪些观察仍适用,不把旧报告冒充新提交的验证。 + +## 当前下一步 + +以下为本轮执行入口的历史清单,现已通过最终66项原生用例落实本任务范围。 +下一实施阶段为08组合或其他已就绪包任务;09分发和真实Mask模型/设备仍不能据此关闭。 + +1. 11计时修复和12采样修复已分别提交并核验;当前HEAD为 + `4f559cb31d6b69a37439c6db2d32ca28ae5c78f3`,恢复本任务。 + 12源码/main/legacy各102项浏览器通过,慢回调中间行已恢复;CPU完全阻塞 + 的未采样窗口仍保留。见[12证据](baselines/danmuku-frame-sampling-validation.json)。 +2. 对实际持续播放记录scheduled、readys、callback、placed、visible、recycled及 + 原生RAF/媒体间隔,区分false、拒绝、轨道满、取消和错过采样。 +3. 比较正常密度、密集队列和连续生命周期后的节点池、Worker、监听器与计时器。 + 已有受控三小时快进只证明离散状态,不是真实三小时播放或内存测量。 +4. 根据证据决定是否需要兼容内部修复,并为每个独立修复保留任务和commit。 +5. 明确Mask可依赖的当前队列/DOM/事件边界,再交付07验收与后续08组合矩阵。 + +不增加任意弹幕上限,不通过修改媒体时钟、预置ready或放宽断言伪造负载通过。 + +## 本轮新增的持续播放与边界取证 + +`test/browser/danmuku-stability.spec.js` 使用候选核心、实际npm5.3.0/候选插件、 +原生视频/RAF/Worker,每秒2或20条,各三轮14秒实际媒体推进。每轮追加12秒 +的时间戳序列,余下时间用于自然显示和回收;逐条记录采样/显示/回收,同时记录 +状态池、节点/空闲池、真实帧和可选未强制GC的堆内存读数。不是三小时耐久测试, +也不把不同浏览器的performance.memory当作可比的泄漏证明。 + +首轮Chromium两个用例因测试误把`load(rows)`当作替换,在第二轮队列断言失败: +收到48/480,错误预期24/240。核对运行实现后按既有追加契约修正为累计队列数, +当轮显示数量仍严格断言24/240;没有改变生产API。失败报告与trace保留在 +`refactor/.cache/danmuku07-stability-first.json`及同前缀results中。 + +Mask静态审查已确认其直接依赖只有核心video/root层/ready/destroy,未读取弹幕 +队列或Owner。已纠正旧契约对根层创建归属的错误描述;核心模板及节点绑定为依据。 +后续CSS mask边界测试明确不加载真实模型,不代替Mask03/05的候选生命周期与组合验收。 + +最终补强了非空Worker、实际节点复用、每条状态归属和跨轮显示/回收恰好一次检查。 +12负载、6共享mask层、48资源测试共66项在三引擎全部通过,0重试/跳过。 +见[变更记录](changes/2026-09-13-PKG-DANMUKU-07-stability.md)和 +[机器证据](baselines/danmuku-stability-validation.json)。 + +本次候选每秒2条用例三轮72条只分配3个节点、实际复用69次;每秒20条三轮720条 +分配21–22个节点、复用698–699次。旧版对应分配6及24–25个节点。两者该正常 +同步回调负载下都完整显示;差异是本次原生样本观察,不是通用吞吐或长期内存承诺。 diff --git a/refactor/impact-policy.json b/refactor/impact-policy.json index 6e06fb209..114f40621 100644 --- a/refactor/impact-policy.json +++ b/refactor/impact-policy.json @@ -121,7 +121,7 @@ { "dependency": "artplayer-plugin-danmuku", "consumer": "artplayer-plugin-danmuku-mask", - "reason": "Mask renders into the $danmuku element supplied by the danmuku plugin", + "reason": "Mask and Danmuku share the core-owned $danmuku layer; retain combination validation for root identity, styles and lifecycle", "evidence": [ "packages/artplayer-plugin-danmuku-mask/src/index.js", "docs/assets/example/danmuku.mask.js" diff --git a/refactor/plan.md b/refactor/plan.md index 5aced626f..e3eee6575 100644 --- a/refactor/plan.md +++ b/refactor/plan.md @@ -4,7 +4,7 @@ 基线:`40fcda6a37d0049d42e49c1e64e70d4fd9ba5f7f`。总任务 231 项,范围 22 个包及工作区/示例。 -状态:todo 68 / doing 15 / blocked 0 / done 148 / deferred 0。风险 L/M/H 表示兼容风险,不表示工期。 +状态:todo 68 / doing 14 / blocked 0 / done 149 / deferred 0。风险 L/M/H 表示兼容风险,不表示工期。 前置依赖是启动条件;验收是完成条件。任务可以继续拆分,但不能复用或悄悄删除旧 ID。 @@ -315,7 +315,7 @@ | PKG-DANMUKU-04 | artplayer-plugin-danmuku
整理时钟、队列与轨道调度 | PKG-DANMUKU-03, CORE-10 | danmuku 调度器和确定性时钟测试 | seek/暂停/倍率/长时间运行无顺序和碰撞回归 | H | done | | PKG-DANMUKU-05 | artplayer-plugin-danmuku
整理 DOM 渲染、设置、热力图与 worker | PKG-DANMUKU-04, CORE-14, CORE-18 | renderer/setting/heatmap/worker 职责及资源归属 | mount/icons/设置和 worker 协议保持,销毁无后台工作 | H | done | | PKG-DANMUKU-06 | artplayer-plugin-danmuku
迁移 TS 与公开声明 | PKG-DANMUKU-05, ENG-04, ENG-06 | 自有模块、worker 消息、option/item/result 类型 | 旧参数、扩展字段和事件消费通过,vendored 边界清楚 | H | done | -| PKG-DANMUKU-07 | artplayer-plugin-danmuku
弹幕能力稳定性验收 | PKG-DANMUKU-06, PKG-DANMUKU-10, PKG-DANMUKU-11, PKG-DANMUKU-12 | 负载/渲染/资源对比及 mask 可依赖的稳定边界 | 在试点核心中旧插件 API 与关键帧路径通过 | H | doing | +| PKG-DANMUKU-07 | artplayer-plugin-danmuku
弹幕能力稳定性验收 | PKG-DANMUKU-06, PKG-DANMUKU-10, PKG-DANMUKU-11, PKG-DANMUKU-12 | 负载/渲染/资源对比及 mask 可依赖的稳定边界 | 在试点核心中旧插件 API 与关键帧路径通过 | H | done | | PKG-DANMUKU-08 | artplayer-plugin-danmuku
完成新旧核心与组合验收 | PKG-DANMUKU-07, CORE-22 | 最终核心/旧核心、mask/fullscreen/PiP 组合报告 | 性能无未解释退化,反复装卸无累计资源 | H | todo | | PKG-DANMUKU-09 | artplayer-plugin-danmuku
完成分发、示例与文档 | PKG-DANMUKU-08, ENG-07 | danmuku.js、README、声明、worker 与产物 | tarball 和静态 icons 等旧调用通过,有独立回退版本 | H | todo | | PKG-DANMUKU-10 | artplayer-plugin-danmuku
修复 issue958 密集热力图过高与曲线裁平 | PKG-DANMUKU-05 | 自动密度缩放与曲线边界、历史自定义坐标兼容及真实浏览器红绿证据 | 16000条三种分布在两核心三引擎和source/main/legacy不遮挡;显式轴和自定义points保持旧解释,有单独commit | M | done | @@ -562,6 +562,7 @@ - PKG-DANMUKU-04: [记录](changes/2026-09-13-PKG-DANMUKU-04-scheduler.md) [记录](baselines/danmuku-scheduler-validation.json) - PKG-DANMUKU-05: [记录](changes/2026-09-13-PKG-DANMUKU-05-resources.md) [记录](baselines/danmuku-resources-validation.json) - PKG-DANMUKU-06: [记录](changes/2026-09-13-PKG-DANMUKU-06-types.md) [记录](baselines/danmuku-types-validation.json) +- PKG-DANMUKU-07: [记录](changes/2026-09-13-PKG-DANMUKU-07-stability.md) [记录](baselines/danmuku-stability-validation.json) [记录](danmuku-stability.md) - PKG-CANVAS-01: [记录](changes/2026-09-12-PKG-CANVAS-01-contract.md) [记录](baselines/canvas-contract.md) [记录](baselines/canvas-release.json) [记录](canvas-validation.md) [记录](baselines/canvas-contract-validation.json) - PKG-CANVAS-02: [记录](changes/2026-09-12-PKG-CANVAS-02-tests.md) [记录](baselines/canvas-behavior-validation.json) [记录](canvas-validation.md) - PKG-CANVAS-03: [记录](changes/2026-09-12-PKG-CANVAS-03-lifecycle.md) [记录](baselines/canvas-lifecycle-validation.json) [记录](canvas-validation.md) diff --git a/refactor/progress.md b/refactor/progress.md index f56c5902e..f7d7ed1cb 100644 --- a/refactor/progress.md +++ b/refactor/progress.md @@ -1,5 +1,19 @@ # 进度与证据 +## PKG-DANMUKU-07 弹幕稳定性阶段验收完成 + +12后的源码在三引擎完成新旧插件两档负载对照,每例三轮42秒原生播放;候选 +72/720条全部采样、显示并回收一次,真实节点复用、状态池唯一归属和Worker清理通过。 +两核心共享CSS mask根层与已有资源回归通过;最终12+6+48共66项,0重试/跳过。 +首轮错误测试把load(rows)当替换,修正为历史追加契约并保留失败报告;独立审查 +补足复用与跨轮重复断言。Mask不依赖队列,根层属于核心;纠正文档和影响映射原因, +保留组合CI范围。lint及影响检查通过,没有生产/声明/依赖变化,复用12的相关验证。 +见[变更](changes/2026-09-13-PKG-DANMUKU-07-stability.md)和 +[证据](baselines/danmuku-stability-validation.json)。DANMUKU-LOAD-01按已解释来源及 +11/12独立修复闭环;CPU阻塞下旧窗口不追赶的边界明确保留,不声称无条件无漏弹幕。 +231项:149 done、14 doing、68 todo。08完整组合、09分发、真实Mask模型和设备/ +发布复盘继续;独立本地提交,不推送、不发布。 + ## PKG-DANMUKU-12 持续采样与串行放置完成 异步beforeVisible/Worker等待期间继续原生RAF采样和可见寿命维护,以内部身份 diff --git a/refactor/risk-table.md b/refactor/risk-table.md index 8e3dfda2a..dc9d17727 100644 --- a/refactor/risk-table.md +++ b/refactor/risk-table.md @@ -237,7 +237,7 @@ | DANMUKU-SOURCE-01 | open / 已复现 | Danmuku registry Git associations differ from releases and static icon provenance remains incomplete | PKG-DANMUKU-09 | | DANMUKU-TRACK-01 | resolved / 已复现 | Native simultaneous fixed Danmuku comments can overlap with duplicate start loops and repeated Worker IDs | PKG-DANMUKU-04, PKG-DANMUKU-05, PKG-DANMUKU-07 | | DANMUKU-INPUT-02 | resolved / 已复现 | Intermediate explicit-zero correction regressed accepted NaN timestamp fallback | PKG-DANMUKU-04 | -| DANMUKU-LOAD-01 | open / 待取证 | Native lifecycle fixtures sometimes miss timestamp eligibility during concurrent workload; real frame/window behavior needs load evidence | PKG-DANMUKU-07 | +| DANMUKU-LOAD-01 | resolved / 已复现 | Native lifecycle fixtures sometimes miss timestamp eligibility during concurrent workload; real frame/window behavior needs load evidence | PKG-DANMUKU-07 | | DANMUKU-HEATMAP-02 | resolved / 已复现 | Issue958 dense automatic heatmaps exceed the fixed Y domain and flatten across video | PKG-DANMUKU-10 | | DANMUKU-TIMING-01 | resolved / 已复现 | Hidden Worker wait is deducted from visible lifetime and can recycle a comment immediately after visible | PKG-DANMUKU-11 | | DANMUKU-SAMPLING-01 | resolved / 已复现 | Serial asynchronous placement stops native frame eligibility sampling and delays existing visible expiry | PKG-DANMUKU-12 | diff --git a/refactor/risks.json b/refactor/risks.json index d53f8b11b..05a61fe3c 100644 --- a/refactor/risks.json +++ b/refactor/risks.json @@ -5290,18 +5290,27 @@ { "id": "DANMUKU-LOAD-01", "title": "Native lifecycle fixtures sometimes miss timestamp eligibility during concurrent workload; real frame/window behavior needs load evidence", - "confirmation": "unverified", - "status": "open", + "confirmation": "reproduced", + "status": "resolved", "owners": [ "PKG-DANMUKU-07" ], "evidence": [ "refactor/changes/2026-09-13-PKG-DANMUKU-05-resources.md", "refactor/baselines/danmuku-resources-validation.json", - "test/browser/danmuku-scheduler.spec.js" + "test/browser/danmuku-scheduler.spec.js", + "refactor/baselines/danmuku-stability-validation.json", + "refactor/baselines/danmuku-frame-sampling-validation.json" ], "compatibleResolution": "Capture native RAF/media-time gaps and scheduled/eligible/visible item counts under realistic load before deciding whether the old plus/minus 0.1 second eligibility rule needs a compatible correction.", - "closureCriteria": "Real load runs explain missing scheduled items with frame and media evidence, and any confirmed implementation defect has a regression and compatible fix; seeding ready in lifecycle fixtures is not closure evidence." + "closureCriteria": "Real load runs explain missing scheduled items with frame and media evidence, and any confirmed implementation defect has a regression and compatible fix; seeding ready in lifecycle fixtures is not closure evidence.", + "resolutionEvidence": [ + "refactor/baselines/danmuku-stability-validation.json", + "refactor/changes/2026-09-13-PKG-DANMUKU-07-stability.md", + "refactor/baselines/danmuku-frame-sampling-validation.json", + "refactor/baselines/danmuku-lifetime-validation.json" + ], + "resolutionRationale": "Native timing evidence distinguishes unobserved CPU-blocked windows from asynchronous scheduler starvation. Tasks 11/12 fix the reproduced implementation defects. Final three-engine real-load runs keep candidate scheduled rows observed/displayed/recycled exactly once, with actual node reuse and state/Worker ownership; unchanged historical CPU-gap semantics and full model/device/release scope remain explicit." }, { "id": "DANMUKU-HEATMAP-02", diff --git a/refactor/tasks.json b/refactor/tasks.json index 4cb4b9d21..73ff89664 100644 --- a/refactor/tasks.json +++ b/refactor/tasks.json @@ -3384,11 +3384,15 @@ "PKG-DANMUKU-11", "PKG-DANMUKU-12" ], - "status": "doing", + "status": "done", "risk": "H", "deliverable": "负载/渲染/资源对比及 mask 可依赖的稳定边界", "acceptance": "在试点核心中旧插件 API 与关键帧路径通过", - "evidence": [] + "evidence": [ + "changes/2026-09-13-PKG-DANMUKU-07-stability.md", + "baselines/danmuku-stability-validation.json", + "danmuku-stability.md" + ] }, { "id": "PKG-DANMUKU-08", diff --git a/test/browser/README.md b/test/browser/README.md index 792449247..b83aa0ad3 100644 --- a/test/browser/README.md +++ b/test/browser/README.md @@ -147,3 +147,14 @@ rows and serial callbacks; the fixed published baseline retains its missing midd row. CPU-block observations remain diagnostic, not no-loss acceptance. Both it and `danmuku-lifetime.spec.js` accept the same artifact override. The latter verifies the full visible lifetime after a controlled delay to an actual Worker request. + +`danmuku-stability.spec.js` runs three native 14-second media cycles at 2 or 20 +rows per second, appending through the public load(rows) contract. The candidate +must deliver and recycle every row once, preserve state membership and reuse +actual node identities. Its 90-second per-case deadline budgets the 42 seconds +of media plus setup/teardown; it is not a relaxation of other tests. Heap readings +remain observations. No media/RAF clock is replaced or ready state seeded here. +`danmuku-mask-boundary.spec.js` verifies the core-owned root and external CSS mask +across commands and destroy(false), with actual video and placement Worker. It +uses explicit ready rows for resource setup and a fixed SVG mask; it does not +load the Mask SDK/model or provide timestamp-delivery evidence. diff --git a/test/browser/danmuku-mask-boundary.spec.js b/test/browser/danmuku-mask-boundary.spec.js new file mode 100644 index 000000000..756802247 --- /dev/null +++ b/test/browser/danmuku-mask-boundary.spec.js @@ -0,0 +1,176 @@ +import fs from 'node:fs' +import process from 'node:process' +import { hash } from '../../refactor/scripts/releases.mjs' +import { compilePackage } from '../helpers/load.js' +import { expect, test } from './fixtures.js' + +let candidate +test.beforeAll(async () => { + candidate = process.env.ARTPLAYER_DANMUKU_ARTIFACT + ? fs.readFileSync(process.env.ARTPLAYER_DANMUKU_ARTIFACT, 'utf8') + : await compilePackage('artplayer-plugin-danmuku', 'umd') +}) + +async function setup(page, core, testInfo) { + const external = [] + const origin = new URL(testInfo.project.use.baseURL).origin + await page.route('**/*', (route) => { + if (new URL(route.request().url()).origin !== origin) { + external.push(route.request().url()) + return route.abort() + } + return route.continue() + }) + await page.goto(`/test/player.html?core=${core}`) + await page.addScriptTag({ content: candidate }) + await page.evaluate(() => { + window.maskBoundaryEvidence = { snapshots: [], workers: [], visible: [], errors: [] } + const NativeWorker = window.Worker + window.Worker = class extends NativeWorker { + constructor(url, options) { + super(url, options) + this.observation = { requests: [], replies: [], terminated: 0 } + window.maskBoundaryEvidence.workers.push(this.observation) + this.addEventListener('message', ({ data }) => this.observation.replies.push({ id: data.id, result: data.result ?? null })) + } + + postMessage(message, ...args) { + this.observation.requests.push({ type: message.type, id: message.id }) + return super.postMessage(message, ...args) + } + + terminate() { + this.observation.terminated++ + return super.terminate() + } + } + window.art = new window.Artplayer({ container: '.player', url: '/test/pattern.mp4', muted: true }) + window.maskBoundaryLayer = window.art.template.$danmuku + const layer = window.maskBoundaryLayer + // Fixed CSS input tests Danmuku's shared-layer contract. No Mask plugin, + // model, TensorFlow backend or segmentation output is loaded or simulated. + const svg = '' + layer.style.maskImage = `url("data:image/svg+xml,${encodeURIComponent(svg)}")` + Object.assign(layer.style, { maskMode: 'alpha', maskSize: 'contain', maskRepeat: 'no-repeat', backgroundSize: 'contain', backgroundRepeat: 'no-repeat' }) + window.maskBoundarySnapshot = (label) => { + const properties = ['mask-image', 'mask-mode', 'mask-size', 'mask-repeat', 'background-size', 'background-repeat'] + const computed = getComputedStyle(layer) + const snapshot = { + label, + sameLayer: window.art.template.$danmuku === layer, + connected: layer.isConnected, + styles: properties.map(name => ({ name, value: layer.style.getPropertyValue(name), priority: layer.style.getPropertyPriority(name), computed: computed.getPropertyValue(name) })), + children: layer.children.length, + opacity: layer.style.opacity, + time: window.art.currentTime, + } + window.maskBoundaryEvidence.snapshots.push(snapshot) + return snapshot + } + window.maskBoundaryBase = window.maskBoundarySnapshot('before-registration') + window.art.on('artplayerPluginDanmuku:visible', item => window.maskBoundaryEvidence.visible.push(item.id)) + window.art.on('artplayerPluginDanmuku:error', error => window.maskBoundaryEvidence.errors.push(String(error))) + window.art.plugins.add(window.artplayerPluginDanmuku({ danmuku: [], heatmap: false, speed: 8, margin: [10, 10], fontSize: 20 })) + window.maskBoundaryPlugin = window.art.plugins.artplayerPluginDanmuku + document.querySelector('#play').onclick = () => window.art.play() + }) + await expect.poll(() => page.evaluate(() => window.art.isReady && window.art.template.$video.videoWidth > 0)).toBe(true) + // Real slow playback leaves room for lifecycle checks on the finite fixture. + await page.evaluate(() => window.art.playbackRate = 0.25) + await testInfo.attach('danmuku-mask-boundary-inputs', { + contentType: 'application/json', + body: JSON.stringify({ core, artifact: process.env.ARTPLAYER_DANMUKU_ARTIFACT || 'source UMD', sha256: hash(candidate), media: '/test/pattern.mp4', scope: 'Shared root-layer identity and CSS preservation with fixed inline SVG mask; native video, DOM, RAF and placement Worker. No Mask SDK/model/end-to-end acceptance. Eligible rows are explicit resource-test preconditions, not timestamp-delivery evidence.' }), + }) + return external +} + +async function assertLayer(page, label) { + const { baseline, snapshot } = await page.evaluate(label => ({ baseline: window.maskBoundaryBase, snapshot: window.maskBoundarySnapshot(label) }), label) + expect(snapshot.sameLayer, label).toBe(true) + expect(snapshot.connected, label).toBe(true) + expect(snapshot.styles, label).toEqual(baseline.styles) + return snapshot +} + +async function renderRow(page, id) { + await page.evaluate(async (id) => { + const owner = await window.maskBoundaryPlugin.emit({ id, text: id, mode: 1, time: 0 }) + // Establish eligibility, then require actual placement Worker and visible DOM. + owner.setState(owner.queue[owner.queue.length - 1], 'ready') + window.maskBoundaryOwner = owner + }, id) + await page.click('#play') + await expect.poll(() => page.evaluate(id => window.maskBoundaryEvidence.visible.includes(id), id)).toBe(true) + await expect.poll(() => page.evaluate((id) => { + const node = [...window.maskBoundaryLayer.children].find(node => node.dataset.id === id) + if (!node) + return false + const rect = node.getBoundingClientRect() + return node.dataset.state === 'emit' && getComputedStyle(node).visibility === 'visible' && rect.width > 0 && rect.height > 0 + }, id)).toBe(true) +} + +test.afterEach(async ({ page }, testInfo) => { + if (page.isClosed()) + return + const evidence = await page.evaluate(() => { + if (window.maskBoundaryEvidence && window.art && !window.art.isDestroy) + window.art.destroy(false) + return window.maskBoundaryEvidence ?? null + }) + await testInfo.attach('danmuku-mask-boundary-evidence', { contentType: 'application/json', body: JSON.stringify(evidence) }) +}) + +for (const core of ['published', 'candidate']) { + test(`${core}: Danmuku retains the core layer and external CSS mask across commands and retained-HTML destroy`, async ({ page }, testInfo) => { + const external = await setup(page, core, testInfo) + const initial = await assertLayer(page, 'after-registration') + const image = initial.styles.find(item => item.name === 'mask-image') + expect(image.value).toContain('data:image/svg+xml,') + expect(image.computed).toContain('data:image/svg+xml,') + await renderRow(page, 'MASK-BOUNDARY-EMIT') + await expect.poll(() => page.evaluate(() => window.art.currentTime)).toBeGreaterThan(0) + await assertLayer(page, 'after-native-emit') + await testInfo.attach('danmuku-mask-boundary-playing', { contentType: 'image/png', body: await page.screenshot() }) + + const reset = await page.evaluate(() => { + const owner = window.maskBoundaryPlugin.reset() + return { sameOwner: owner === window.maskBoundaryOwner, states: owner.queue.map(item => item.$state) } + }) + expect(reset).toEqual({ sameOwner: true, states: ['wait'] }) + await assertLayer(page, 'after-reset') + + const replacement = await page.evaluate(async () => { + window.maskBoundaryPlugin.config({ danmuku: [{ id: 'CONFIGURED-REPLACEMENT', text: 'CONFIGURED-REPLACEMENT', time: 100 }] }) + const owner = await window.maskBoundaryPlugin.load() + return { sameOwner: owner === window.maskBoundaryOwner, ids: owner.queue.map(item => item.id) } + }) + expect(replacement).toEqual({ sameOwner: true, ids: ['CONFIGURED-REPLACEMENT'] }) + await assertLayer(page, 'after-no-argument-load') + await renderRow(page, 'MASK-BOUNDARY-AFTER-LOAD') + await assertLayer(page, 'after-replacement-native-emit') + + await page.evaluate(() => window.maskBoundaryPlugin.hide()) + expect((await assertLayer(page, 'after-hide')).opacity).toBe('0') + await page.evaluate(() => window.maskBoundaryPlugin.show()) + expect((await assertLayer(page, 'after-show')).opacity).toBe('1') + + const beforeDestroy = await page.evaluate(() => ({ workers: window.maskBoundaryEvidence.workers, errors: window.maskBoundaryEvidence.errors })) + expect(beforeDestroy.errors).toEqual([]) + expect(beforeDestroy.workers).toHaveLength(1) + expect(beforeDestroy.workers[0].requests.length).toBeGreaterThanOrEqual(2) + expect(beforeDestroy.workers[0].replies.length).toBeGreaterThanOrEqual(2) + await page.evaluate(() => window.art.destroy(false)) + const destroyed = await assertLayer(page, 'after-destroy-false') + expect(destroyed.children).toBe(0) + // Use the native frame clock to detect immediate late plugin writes after cleanup. + await page.evaluate(() => new Promise(resolve => requestAnimationFrame(() => requestAnimationFrame(resolve)))) + const settled = await assertLayer(page, 'after-destroy-native-frames') + expect(settled.children).toBe(0) + const terminal = await page.evaluate(() => ({ workers: window.maskBoundaryEvidence.workers, errors: window.maskBoundaryEvidence.errors })) + expect(terminal.errors).toEqual([]) + expect(terminal.workers[0].terminated).toBe(1) + expect(terminal.workers[0].requests).toEqual(beforeDestroy.workers[0].requests) + expect(external).toEqual([]) + }) +} diff --git a/test/browser/danmuku-stability.spec.js b/test/browser/danmuku-stability.spec.js new file mode 100644 index 000000000..dd45ecfcf --- /dev/null +++ b/test/browser/danmuku-stability.spec.js @@ -0,0 +1,194 @@ +import assert from 'node:assert/strict' +import fs from 'node:fs' +import process from 'node:process' +import { ensureArchive, hash, readMember } from '../../refactor/scripts/releases.mjs' +import { compilePackage } from '../helpers/load.js' +import { expect, test } from './fixtures.js' + +const implementations = new Map() +test.beforeAll(async () => { + const release = JSON.parse(fs.readFileSync(new URL('../../refactor/baselines/danmuku-release.json', import.meta.url), 'utf8')).release + const member = `package/${release.manifest.main.replace(/^\.\//u, '')}` + const published = readMember(await ensureArchive(release), member) + assert.equal(hash(published), release.files[member]) + implementations.set('published', published.toString()) + implementations.set('candidate', process.env.ARTPLAYER_DANMUKU_ARTIFACT + ? fs.readFileSync(process.env.ARTPLAYER_DANMUKU_ARTIFACT, 'utf8') + : await compilePackage('artplayer-plugin-danmuku', 'umd')) +}) + +for (const implementation of ['published', 'candidate']) { + for (const rate of [2, 20]) { + test(`${implementation}: ${rate} rows per second across three native playback cycles`, async ({ page }, testInfo) => { + // Three 14-second media cycles plus setup/teardown; this is a bounded soak, + // not the ordinary short browser test deadline or a synthetic clock jump. + test.setTimeout(90000) + await page.goto('/test/player.html?core=candidate') + const code = implementations.get(implementation) + await page.addScriptTag({ content: code }) + await page.evaluate(() => window.createPlayer('/assets/sample/video.mp4')) + await page.click('#play') + await expect.poll(() => page.evaluate(() => window.art.currentTime)).toBeGreaterThan(0.1) + await page.click('#pause') + await page.evaluate(() => { + const art = window.art + const evidence = window.stabilityEvidence = { workers: [], frames: [], samples: [], visible: [], recycled: [], callbacks: [], cycles: [], errors: [], allocations: 0, reuses: 0, bypassedPool: 0 } + const NativeWorker = window.Worker + window.Worker = class extends NativeWorker { + constructor(...args) { + super(...args) + this.record = { posts: 0, replies: 0, terminated: 0, errors: [] } + evidence.workers.push(this.record) + this.addEventListener('message', () => this.record.replies++) + this.addEventListener('error', event => this.record.errors.push(event.message)) + } + + postMessage(...args) { + this.record.posts++ + return super.postMessage(...args) + } + + terminate() { + this.record.terminated++ + return super.terminate() + } + } + art.on('artplayerPluginDanmuku:error', error => evidence.errors.push(String(error))) + art.on('artplayerPluginDanmuku:visible', row => evidence.visible.push({ id: row.id, time: art.currentTime, wall: performance.now() })) + art.plugins.add(window.artplayerPluginDanmuku({ + danmuku: [], + heatmap: false, + emitter: false, + speed: 1, + antiOverlap: false, + beforeVisible(row) { + evidence.callbacks.push({ id: row.id, time: art.currentTime }) + return true + }, + })) + const owner = window.stabilityOwner = art.plugins.artplayerPluginDanmuku.config({}) + const acquire = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(owner), '$ref').get + const acquired = new WeakSet() + Object.defineProperty(owner, '$ref', { configurable: true, get() { + const available = new Set(this.$refs) + const ref = acquire.call(this) + if (available.size && !available.has(ref)) + evidence.bypassedPool++ + if (acquired.has(ref)) + evidence.reuses++ + else evidence.allocations++ + acquired.add(ref) + return ref + } }) + const getter = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(owner), 'readys').get + Object.defineProperty(owner, 'readys', { configurable: true, get() { + const rows = getter.call(this) + evidence.samples.push({ time: art.currentTime, wall: performance.now(), ids: rows.map(row => row.id) }) + return rows + } }) + const makeWait = owner.makeWait.bind(owner) + owner.makeWait = (row) => { + if (row.$state === 'emit') + evidence.recycled.push({ id: row.id, time: art.currentTime }) + return makeWait(row) + } + const frame = (wall) => { + if (art.playing) + evidence.frames.push({ wall, time: art.currentTime }) + window.stabilityFrame = requestAnimationFrame(frame) + } + window.stabilityFrame = requestAnimationFrame(frame) + }) + try { + for (let cycle = 0; cycle < 3; cycle++) { + await page.evaluate(async ({ cycle, rate }) => { + const art = window.art + const base = art.currentTime + const rows = Array.from({ length: 12 * rate }, (_, index) => ({ id: `${cycle}-${index}`, text: `Row ${index}`, time: base + 0.5 + index / rate, mode: index % 3 })) + await art.plugins.artplayerPluginDanmuku.load(rows) + window.stabilityEnd = base + 14 + window.stabilityEvidence.cycles.push({ cycle, base, rows: rows.map(row => ({ id: row.id, time: row.time })), startWall: performance.now() }) + }, { cycle, rate }) + await page.click('#play') + await expect.poll(() => page.evaluate(() => window.art.currentTime >= window.stabilityEnd), { timeout: 22000 }).toBe(true) + await page.click('#pause') + const snapshot = await page.evaluate(() => { + const owner = window.stabilityOwner + const record = window.stabilityEvidence.cycles.at(-1) + const ids = new Set(record.rows.map(row => row.id)) + const visible = window.stabilityEvidence.visible.filter(row => ids.has(row.id)) + const sampled = new Set(window.stabilityEvidence.samples.flatMap(sample => sample.ids).filter(id => ids.has(id))) + const shown = new Set(visible.map(row => row.id)) + const refs = owner.queue.map(row => row.$ref).filter(Boolean) + const queue = new Set(owner.queue) + const members = Object.values(owner.states).flat() + const memory = performance.memory + Object.assign(record, { + endWall: performance.now(), + time: window.art.currentTime, + decodedWidth: window.art.video.videoWidth, + visibleCount: visible.length, + uniqueVisible: shown.size, + missedSampling: record.rows.filter(row => !sampled.has(row.id)).map(row => row.id), + sampledNotVisible: record.rows.filter(row => sampled.has(row.id) && !shown.has(row.id)).map(row => row.id), + queue: owner.queue.length, + states: Object.fromEntries(Object.entries(owner.states).map(([state, rows]) => [state, rows.length])), + nodes: owner.$danmuku.children.length, + pooled: owner.$refs.length, + uniquePool: new Set(owner.$refs).size, + referenced: refs.length, + distinctReferences: new Set(refs).size, + uniqueStateMembers: new Set(members).size, + validStateMembers: Object.entries(owner.states).every(([state, rows]) => rows.every(row => queue.has(row) && row.$state === state)), + heap: memory ? { used: memory.usedJSHeapSize, total: memory.totalJSHeapSize } : null, + }) + return record + }) + expect(snapshot.decodedWidth).toBeGreaterThan(0) + expect(snapshot.time - snapshot.base).toBeGreaterThanOrEqual(14) + // load(rows) appends by public contract; old rows stay in the queue. + expect(snapshot.queue).toBe((cycle + 1) * 12 * rate) + expect(Object.values(snapshot.states).reduce((sum, count) => sum + count, 0)).toBe(snapshot.queue) + if (implementation === 'candidate') { + expect(snapshot.missedSampling).toEqual([]) + expect(snapshot.sampledNotVisible).toEqual([]) + expect(snapshot.visibleCount).toBe(12 * rate) + expect(snapshot.uniqueVisible).toBe(12 * rate) + expect(snapshot.referenced).toBe(0) + expect(snapshot.uniquePool).toBe(snapshot.pooled) + expect(snapshot.nodes).toBe(snapshot.pooled) + expect(snapshot.uniqueStateMembers).toBe(snapshot.queue) + expect(snapshot.validStateMembers).toBe(true) + } + } + } + finally { + const evidence = await page.evaluate(() => { + cancelAnimationFrame(window.stabilityFrame) + window.art.destroy() + return { ...window.stabilityEvidence, destroyed: window.art.isDestroy, retainedPlayerRoots: document.querySelectorAll('.art-video-player').length } + }) + await testInfo.attach('danmuku-stability-observation', { contentType: 'application/json', body: JSON.stringify({ implementation, rate, sha256: hash(code), evidence, scope: 'Three bounded real media cycles; published defects are observed, candidate delivery and resource ownership are asserted. Optional unforced heap readings are not leak proof or comparable across engines.' }) }) + expect(evidence.destroyed).toBe(true) + expect(evidence.retainedPlayerRoots).toBe(0) + expect(evidence.errors).toEqual([]) + expect(evidence.workers).toHaveLength(1) + if (implementation === 'candidate' && evidence.cycles.length === 3) { + const expected = evidence.cycles.flatMap(cycle => cycle.rows.map(row => row.id)).sort() + expect(evidence.visible.map(row => row.id).sort()).toEqual(expected) + expect(evidence.recycled.map(row => row.id).sort()).toEqual(expected) + expect(evidence.bypassedPool).toBe(0) + expect(evidence.reuses).toBeGreaterThan(0) + expect(evidence.allocations + evidence.reuses).toBe(expected.length) + expect(evidence.cycles.at(-1).nodes).toBe(evidence.allocations) + } + for (const worker of evidence.workers) { + expect(worker.terminated).toBe(1) + expect(worker.errors).toEqual([]) + if (implementation === 'candidate') + expect(worker.posts).toBe(worker.replies) + } + } + }) + } +}