q-component q-test-accumulator { q-property manifest: q-map { } q-property results: q-map { } q-property manualStatus: q-map { } q-signal refreshRequested() q-signal resultReported(testNo, value) q-signal expectedReported(testNo, expectedList) q-signal passingReported(testNo, isPassing) q-signal outcomeReported(testNo, isPassing, value) function normalize(v) { return String(v == null ? "" : v).replace(/\s+/g, " ").trim(); } function mapKeys(store) { if (store && typeof store.keys === "function") { return store.keys(); } return []; } function mapGet(store, key) { if (store && typeof store.value === "function") { return store.value(key); } return undefined; } function ensureModelStore(targetProp) { var store = this.component[targetProp]; if (store && typeof store.set === "function" && typeof store.value === "function" && typeof store.keys === "function") { return store; } var seed = {}; if (store && typeof store === "object") { var keys = Object.keys(store); for (var i = 0; i < keys.length; i += 1) { seed[keys[i]] = store[keys[i]]; } } this.component[targetProp] = QModel(seed); return this.component[targetProp]; } function mapSet(targetProp, key, value) { var store = this.component.ensureModelStore(targetProp); store.set(key, value); } function doneMarkerState(testNo) { var key = String(testNo || ""); var host = document.querySelector("#host-t" + key); if (!host) { return "none"; } var doneNode = host.querySelector("#t" + key + "-done"); if (!doneNode) { return "none"; } var token = String(doneNode.textContent == null ? "" : doneNode.textContent).trim().toLowerCase(); if (token === "1" || token === "true" || token === "done" || token === "ok" || token === "pass") { return "done"; } return "pending"; } function bootstrapManifest() { var cards = document.querySelectorAll(".test-card"); var data = {}; for (var i = 0; i < cards.length; i += 1) { var card = cards[i]; var cardId = String(card.getAttribute("id") || ""); if (cardId.indexOf("card-") !== 0) { continue; } var key = cardId.slice(5); if (!key) { continue; } var titleNode = card.querySelector(".test-head h2"); var rawTitle = titleNode ? String(titleNode.textContent || "") : ("Test " + key); var title = rawTitle.replace(/^\s*\d+\.\s*/, ""); var expectedNode = card.querySelector(".test-expected"); var expectedText = expectedNode ? String(expectedNode.textContent || "") : ""; expectedText = expectedText.replace(/^Expected:\s*/i, "").trim(); var expected = []; if (expectedText) { expected = expectedText.split("|").map(function(part) { return String(part || "").trim(); }).filter(function(part) { return part.length > 0; }); } var deprecated = expected.length === 1 && expected[0].toLowerCase() === "test has been deprecated"; data[key] = { title: title, expected: expected, deprecated: deprecated }; } this.component.manifest = QModel(data); } function ensureManifest() { var manifest = this.component.ensureModelStore("manifest"); var currentKeys = this.component.mapKeys(manifest); var cardCount = document.querySelectorAll(".test-card[id^='card-']").length; if (currentKeys.length === 0 || cardCount > currentKeys.length) { this.component.bootstrapManifest(); } } function setExpected(testNo, expectedList) { var key = String(testNo); var entry = this.component.mapGet(this.component.manifest, key) || {}; if (!entry || typeof entry !== "object") { entry = {}; } entry.expected = Array.isArray(expectedList) ? expectedList.slice() : [String(expectedList || "")]; this.component.mapSet("manifest", key, entry); } function setResult(testNo, value) { this.component.mapSet("results", String(testNo), String(value == null ? "" : value)); } function setPassing(testNo, isPassing) { var key = String(testNo); var value = isPassing ? "pass" : "fail"; this.component.mapSet("manualStatus", key, value); } function report(testNo, isPassing, value) { this.component.setPassing(testNo, isPassing); if (value !== undefined) { this.component.setResult(testNo, value); } this.component.showResults(); } function evaluateOne(testNo) { var key = String(testNo); var entry = this.component.mapGet(this.component.manifest, key) || {}; var expected = Array.isArray(entry.expected) ? entry.expected : []; var deprecated = entry.deprecated === true; var title = String(entry.title || ""); var actual = String(this.component.mapGet(this.component.results, key) || ""); var manual = this.component.ensureModelStore("manualStatus"); var status = ""; var hasResult = false; hasResult = this.component.mapKeys(this.component.ensureModelStore("results")).indexOf(key) >= 0; status = this.component.mapGet(manual, key); if (status !== "pass" && status !== "fail" && status !== "deprecated" && deprecated) { status = "deprecated"; } if (status !== "pass" && status !== "fail" && status !== "deprecated") { status = hasResult ? "pass" : "pending"; } var doneState = this.component.doneMarkerState(key); if (status !== "pass" && status !== "fail" && status !== "deprecated" && doneState === "pending") { status = "pending"; } if (status === "pass" && doneState === "pending") { status = "pending"; } if (status === "pass" && !deprecated) { var normalizedActual = this.component.normalize(actual); for (var i = 0; i < expected.length; i += 1) { var token = this.component.normalize(expected[i]); if (token && normalizedActual.indexOf(token) < 0) { status = "fail"; break; } } } var badge = document.querySelector("#badge-" + key); if (badge) { badge.className = "badge " + status; badge.textContent = status; } return { key: key, title: title, status: status, actual: actual, expected: expected }; } function evaluateAll() { var hosts = document.querySelectorAll("q-html[data-test-no]"); for (var i = 0; i < hosts.length; i += 1) { var host = hosts[i]; var no = String(host.getAttribute("data-test-no") || ""); if (!no) { continue; } this.component.setResult(no, host.innerHTML); } this.component.showResults(); } function refresh() { this.component.evaluateAll(); } function showResults() { this.component.ensureManifest(); var keys = this.component.mapKeys(this.component.manifest); var passed = 0; var failed = 0; var pending = 0; var lines = []; for (var i = 0; i < keys.length; i += 1) { var rec = this.component.evaluateOne(keys[i]); if (rec.status === "pass") { passed += 1; } if (rec.status === "fail") { failed += 1; lines.push(rec.key + ". " + rec.title + "\n expected: " + rec.expected.join(" | ") + "\n actual: " + this.component.normalize(rec.actual)); } if (rec.status !== "pass" && rec.status !== "fail") { pending += 1; } } document.querySelector("#sum-pass").textContent = "Passes: " + String(passed); document.querySelector("#sum-fail").textContent = "Failures: " + String(failed); document.querySelector("#sum-pending").textContent = "Pending: " + String(pending); document.querySelector("#failed-list").textContent = lines.length > 0 ? lines.join("\n\n") : "none"; } onrefreshRequested { this.component.refresh(); } onresultReported { var p = event && event.detail && event.detail.params ? event.detail.params : {}; this.component.setResult(p.testNo, p.value); this.component.showResults(); } onexpectedReported { var p = event && event.detail && event.detail.params ? event.detail.params : {}; this.component.setExpected(p.testNo, p.expectedList); this.component.showResults(); } onpassingReported { var p = event && event.detail && event.detail.params ? event.detail.params : {}; this.component.setPassing(p.testNo, p.isPassing); this.component.showResults(); } onoutcomeReported { var p = event && event.detail && event.detail.params ? event.detail.params : {}; this.component.report(p.testNo, p.isPassing, p.value); } onReady { try { if (!this.component) { return; } if (typeof this.component.bootstrapManifest === "function") { this.component.bootstrapManifest(); } if (typeof this.refreshRequested === "function") { this.refreshRequested(); } else if (typeof this.component.refresh === "function") { this.component.refresh(); } setTimeout(function() { try { if (this.component && typeof this.component.refresh === "function") { this.component.refresh(); } } catch (err1) { console.warn("accumulator delayed refresh(250) failed", err1); } }.bind(this), 250); setTimeout(function() { try { if (this.component && typeof this.component.refresh === "function") { this.component.refresh(); } } catch (err2) { console.warn("accumulator delayed refresh(1000) failed", err2); } }.bind(this), 1000); } catch (err) { console.warn("accumulator onReady failed", err); } } div.panel { div.summary { span#sum-fail.fail { text { Failures: 0 } } span#sum-pending.pending { text { Pending: 0 } } span#sum-pass.pass { text { Passes: 0 } } } div.actions { button#btn-refresh { type: "button" onclick { var acc = document.querySelector("#acc-main"); if (!acc) { return; } if (typeof acc.refreshRequested === "function") { acc.refreshRequested(); } } text { Refresh } } button#btn-copy { type: "button" onclick { var txt = document.querySelector("#failed-list").textContent; if (navigator.clipboard && typeof navigator.clipboard.writeText === "function") { navigator.clipboard.writeText(txt); } } text { Copy Failures } } button#btn-loop { type: "button" onclick { QHtml.printEventLoopSnapshot({ limit: 80, includePayload: false }); } text { Print Event Loop } } } pre#failed-list { text { none } } } } q-test-accumulator#acc-main { } q-timer accRefreshTimer { interval: 5000 repeat: true running: false ontimeout { var acc = document.querySelector("#acc-main"); if (!acc) { return; } if (typeof acc.refreshRequested === "function") { acc.refreshRequested(); } } }

Canvas and Web Workers

section
Includes: tests 84, 85, 86, 87, 99, 101, 102, 116
q-canvas, q-worker, worker signals, Promise-returning worker methods, and canvas compatibility tests. Back to test index.

84. q-canvas screensaver bounce (start/stop button)

pending
Expected: t84-ok | frames=
button#t84-toggle { type: "button" text { start } onclick { var running = String(t84Timer.running) === "true" || t84Timer.running === true || Number(t84Timer.running) === 1; if (running) { t84Timer.stop(); this.textContent = "start"; return; } window.__t84 = null; $("#t84-out").textContent = "waiting"; $("#t84-done").textContent = "0"; t84Timer.start(); this.textContent = "stop"; } } q-canvas myCanvas84 { width: 180 height: 96 } div#t84-out { text { waiting } } div#t84-meta { text { frames=0|bounces=0 } } div#t84-done { text { 0 } } q-timer t84Timer { interval: 30 repeat: true running: false ontimeout { var c = myCanvas84; if (!c || !c.context) { return; } if (!window.__t84) { window.__t84 = { x: 60, y: 34, vx: 1, vy: -1, r: 14, rv: 1, rr: 40, gg: 120, bb: 210, dr: 1, dg: 1, db: 1, f: 0, b: 0 }; } var s = window.__t84; var w = Number(c.width || 180); var h = Number(c.height || 96); s.x = s.x + s.vx; s.y = s.y + s.vy; if (s.x - s.r <= 0 || s.x + s.r >= w) { s.vx = -s.vx; s.b = s.b + 1; } if (s.y - s.r <= 0 || s.y + s.r >= h) { s.vy = -s.vy; s.b = s.b + 1; } if (s.x - s.r < 0) { s.x = s.r; } if (s.x + s.r > w) { s.x = w - s.r; } if (s.y - s.r < 0) { s.y = s.r; } if (s.y + s.r > h) { s.y = h - s.r; } var edgeLimit = Math.floor(Math.min(s.x, w - s.x, s.y, h - s.y) - 1); if (!Number.isFinite(edgeLimit)) { edgeLimit = 6; } if (edgeLimit < 6) { edgeLimit = 6; } if (edgeLimit > 22) { edgeLimit = 22; } if (s.r > edgeLimit) { s.r = edgeLimit; s.rv = -Math.abs(s.rv); } s.r = s.r + s.rv; if (s.r >= edgeLimit) { s.r = edgeLimit; s.rv = -Math.abs(s.rv); } if (s.r <= 6) { s.r = 6; s.rv = Math.abs(s.rv); } s.rr = s.rr + s.dr; if (s.rr >= 255 || s.rr <= 0) { s.dr = -s.dr; } s.gg = s.gg + s.dg; if (s.gg >= 255 || s.gg <= 0) { s.dg = -s.dg; } s.bb = s.bb + s.db; if (s.bb >= 255 || s.bb <= 0) { s.db = -s.db; } var ctx = c.context; ctx.clearRect(0, 0, w, h); ctx.fillStyle = "rgba(" + s.rr + "," + s.gg + "," + s.bb + ",0.85)"; ctx.beginPath(); ctx.arc(s.x, s.y, s.r, 0, Math.PI * 2); ctx.fill(); s.f = s.f + 1; $("#t84-meta").textContent = "frames=" + s.f + "|bounces=" + s.b; if (s.f > 44 && s.b > 0) { $("#t84-out").textContent = "t84-ok"; $("#t84-done").textContent = "1"; } } } onReady { var acc = document.querySelector("#acc-main"); if (acc) { acc.resultReported(84, this.innerHTML); } }

85. q-canvas diagonal pixel-runner (start/stop button)

pending
Expected: t85-ok
button#t85-toggle { type: "button" text { start } onclick { var running = String(t85Timer.running) === "true" || t85Timer.running === true || Number(t85Timer.running) === 1; if (running) { t85Timer.stop(); this.textContent = "start"; return; } window.__t85 = null; $("#t85-out").textContent = "waiting"; $("#t85-done").textContent = "0"; t85Timer.start(); this.textContent = "stop"; } } q-canvas myCanvas85 { width: 164 height: 92 } div#t85-out { text { waiting } } div#t85-done { text { 0 } } q-timer t85Timer { interval: 30 repeat: true running: false ontimeout { var c = myCanvas85; if (!c || !c.context) { return; } if (!window.__t85) { window.__t85 = { x: 2, y: 2, vx: 1, vy: 1, rr: 120, gg: 40, bb: 180, dr: 1, dg: -1, db: 1, f: 0, b: 0 }; } var s = window.__t85; var w = Number(c.width || 164); var h = Number(c.height || 92); s.x = s.x + s.vx; s.y = s.y + s.vy; if (s.x <= 0 || s.x >= w - 2) { s.vx = -s.vx; s.b = s.b + 1; } if (s.y <= 0 || s.y >= h - 2) { s.vy = -s.vy; s.b = s.b + 1; } s.rr = s.rr + s.dr; if (s.rr <= 0 || s.rr >= 255) { s.dr = -s.dr; } s.gg = s.gg + s.dg; if (s.gg <= 0 || s.gg >= 255) { s.dg = -s.dg; } s.bb = s.bb + s.db; if (s.bb <= 0 || s.bb >= 255) { s.db = -s.db; } c.context.clearRect(0, 0, w, h); c.context.fillStyle = "rgba(" + s.rr + "," + s.gg + "," + s.bb + ",0.9)"; c.context.fillRect(s.x, s.y, 2, 2); s.f = s.f + 1; if (s.f > 42 && s.b > 0) { $("#t85-out").textContent = "t85-ok"; $("#t85-done").textContent = "1"; } } } onReady { var acc = document.querySelector("#acc-main"); if (acc) { acc.resultReported(85, this.innerHTML); } }

86. q-canvas transparent overlay (start/stop button)

pending
Expected: base-86 | t86-ok
button#t86-toggle { type: "button" text { start } onclick { var running = String(t86Timer.running) === "true" || t86Timer.running === true || Number(t86Timer.running) === 1; if (running) { t86Timer.stop(); this.textContent = "start"; return; } window.__t86 = null; $("#t86-out").textContent = "waiting"; $("#t86-done").textContent = "0"; t86Timer.start(); this.textContent = "stop"; } } div#t86-wrap { style { position: relative; width: 180px; height: 96px; border: 1px solid #94a3b8; background-color: #e2e8f0; } div#t86-base { text { base-86 } } } q-canvas myCanvas86 { width: 180 height: 96 } div#t86-out { text { waiting } } div#t86-done { text { 0 } } q-timer t86Timer { interval: 30 repeat: true running: false ontimeout { var c = myCanvas86; var wrap = $("#t86-wrap"); if (!c || !c.context || !wrap) { return; } if (c.parentNode !== wrap) { c.style.position = "absolute"; c.style.left = "0px"; c.style.top = "0px"; c.style.pointerEvents = "none"; c.style.backgroundColor = "transparent"; wrap.appendChild(c); } if (!window.__t86) { window.__t86 = { x: 9, y: 9, vx: 1, vy: 1, f: 0 }; } var s = window.__t86; var w = Number(c.width || 180); var h = Number(c.height || 96); s.x = s.x + s.vx; s.y = s.y + s.vy; if (s.x <= 7 || s.x >= w - 7) { s.vx = -s.vx; } if (s.y <= 7 || s.y >= h - 7) { s.vy = -s.vy; } c.context.clearRect(0, 0, w, h); c.context.fillStyle = "rgba(30,64,175,0.92)"; c.context.beginPath(); c.context.arc(s.x, s.y, 7, 0, Math.PI * 2); c.context.fill(); s.f = s.f + 1; if (s.f > 34) { $("#t86-out").textContent = "t86-ok"; $("#t86-done").textContent = "1"; } } } onReady { var acc = document.querySelector("#acc-main"); if (acc) { acc.resultReported(86, this.innerHTML); } }

87. q-canvas independent animated surfaces (start/stop button)

pending
Expected: t87-ok
button#t87-toggle { type: "button" text { start } onclick { var running = String(t87Timer.running) === "true" || t87Timer.running === true || Number(t87Timer.running) === 1; if (running) { t87Timer.stop(); this.textContent = "start"; return; } window.__t87 = null; $("#t87-out").textContent = "waiting"; $("#t87-done").textContent = "0"; t87Timer.start(); this.textContent = "stop"; } } q-canvas myCanvas87a { width: 96 height: 48 } q-canvas myCanvas87b { width: 96 height: 48 } div#t87-out { text { waiting } } div#t87-done { text { 0 } } q-timer t87Timer { interval: 30 repeat: true running: false ontimeout { var a = myCanvas87a; var b = myCanvas87b; if (!a || !b || !a.context || !b.context) { return; } if (!window.__t87) { window.__t87 = { xa: 2, xb: 2, f: 0 }; } var s = window.__t87; s.xa = (s.xa + 1) % 90; s.xb = (s.xb + 1) % 90; a.context.clearRect(0, 0, 96, 48); b.context.clearRect(0, 0, 96, 48); a.context.fillStyle = "rgba(16,185,129,0.9)"; b.context.fillStyle = "rgba(244,63,94,0.9)"; a.context.fillRect(s.xa, 12, 6, 6); b.context.fillRect(s.xb, 26, 6, 6); s.f = s.f + 1; if (s.f > 28) { $("#t87-out").textContent = "t87-ok"; $("#t87-done").textContent = "1"; } } } onReady { var acc = document.querySelector("#acc-main"); if (acc) { acc.resultReported(87, this.innerHTML); } }

99. q-worker method returns Promise + auto property resolve assignment

pending
Expected: A,B,C
q-worker myworker99 { q-property myprops: q-array { "A", "B", "C" } function dowork() { var rv = []; for (var i = 0; i < 3; i += 1) { rv.push(this.component.myprops[i]); } return rv.join(","); } } q-component mycomp99 { q-property someprop: "waiting" myworker99 worker { } function report99() { var acc = document.querySelector("#acc-main"); var host = this.closest("q-html"); if (!acc || !host) { return; } acc.resultReported(99, host.innerHTML); } onReady { this.component.someprop = worker.dowork(); } onsomepropchanged { this.component.report99(); } div#t99-out { text { ${this.component.someprop} } } } mycomp99 { } onReady { }

101. q-worker property mutation + q-signal emission from worker call

pending
Expected: 5 | id="t101-signal"
q-worker calcworker101 { q-property base: 2 q-signal done(result) function compute(step) { this.component.base = Number(this.component.base || 0) + Number(step || 0); this.component.done(this.component.base); return this.component.base; } } q-component host101 { q-property out: "waiting" q-property signalOut: "waiting" calcworker101 worker { } function report101() { var acc = document.querySelector("#acc-main"); var host = this.closest("q-html"); if (!acc || !host) { return; } acc.resultReported(101, host.innerHTML); } onReady { worker.done.connect(function(evt) { var args = evt && Array.isArray(evt.args) ? evt.args : [evt]; this.component.signalOut = String(args.length > 0 && typeof args[0] !== "undefined" ? args[0] : "none"); }); this.component.out = worker.compute(3); } onoutchanged { this.component.report101(); } onsignaloutchanged { this.component.report101(); } div#t101-out { text { ${this.component.out} } } div#t101-signal { text { ${this.component.signalOut} } } } host101 { } onReady { }

102. q-worker + q-canvas minimal start/stop

pending
Expected: Start | Stop | worker102inst | t102-canvas
q-worker worker102 { q-signal updateShapeData(payload) function draw(stateJson, width, height, epochMs) { var st = null; try { st = JSON.parse(String(stateJson || "")); } catch (e) { st = null; } if (!st) { st = { x: 24, y: 24, vx: 1.7, vy: 1.3, r: 14, c1: 120, c2: 80, c3: 200 }; } var w = Math.max(80, Number(width || 320)); var h = Math.max(60, Number(height || 180)); st.x = Number(st.x || 0) + Number(st.vx || 0); st.y = Number(st.y || 0) + Number(st.vy || 0); st.r = Math.max(8, Math.min(30, Number(st.r || 14) + Math.sin(Number(epochMs || Date.now()) * 0.002) * 0.22)); if (st.x <= st.r || st.x >= (w - st.r)) { st.vx = -Number(st.vx || 0); } if (st.y <= st.r || st.y >= (h - st.r)) { st.vy = -Number(st.vy || 0); } st.c1 = (Number(st.c1 || 0) + 1) % 256; st.c2 = (Number(st.c2 || 0) + 2) % 256; st.c3 = (Number(st.c3 || 0) + 3) % 256; var payload = JSON.stringify(st); this.component.updateShapeData(payload); return payload; } } worker102 worker102inst { } q-component host102 { q-property running: 0 q-property state: "" function drawSomeShapes(payloadJson) { var cv = myCanvas102; if (!cv || !cv.context) { return; } var st = null; try { st = JSON.parse(String(payloadJson || "")); } catch (e) { st = null; } if (!st) { return; } var w = Number(cv.width || 320); var h = Number(cv.height || 180); cv.context.clearRect(0, 0, w, h); cv.context.fillStyle = "rgba(15,23,42,0.25)"; cv.context.fillRect(0, 0, w, h); cv.context.fillStyle = "rgb(" + String(Number(st.c1 || 0)) + "," + String(Number(st.c2 || 0)) + "," + String(Number(st.c3 || 0)) + ")"; cv.context.beginPath(); cv.context.arc(Number(st.x || 0), Number(st.y || 0), Number(st.r || 10), 0, Math.PI * 2); cv.context.fill(); } function draw() { if (Number(this.component.running || 0) !== 1) { return; } var cv = myCanvas102; var w = Number(cv && cv.width ? cv.width : 320); var h = Number(cv && cv.height ? cv.height : 180); var next = worker102inst.draw(this.component.state, w, h, Date.now()); if (next && typeof next.then === "function") { var self = this; next.then(function(payload) { self.component.state = String(payload || ""); }); } else { this.component.state = String(next || ""); } } onReady { worker102inst.updateShapeData.connect(function(payload) { this.component.state = String(payload || ""); this.component.drawSomeShapes(this.component.state); }); var wrap = this.querySelector("#t102-wrap"); if (wrap && myCanvas102 && myCanvas102.parentNode !== wrap) { wrap.appendChild(myCanvas102); } } div#t102-controls { button#t102-start { type: "button" onclick { host102inst.running = 1; t102Timer.start(); $("#t102-status").textContent = "running"; $("#t102-done").textContent = "0"; } text { Start } } button#t102-stop { type: "button" onclick { host102inst.running = 0; t102Timer.stop(); $("#t102-status").textContent = "stopped"; $("#t102-done").textContent = "1"; } text { Stop } } div#t102-status { text { idle } } div#t102-done { text { 0 } } } div#t102-worker-ref { text { worker102inst } } div#t102-wrap { style { width: 320px; height: 180px; border: 1px solid #94a3b8; background-color: rgba(15,23,42,0.08); } } } host102 host102inst { } q-canvas myCanvas102 { id: "t102-canvas" width: 320 height: 180 } q-timer t102Timer { interval: 10 repeat: true running: false ontimeout { host102inst.draw(); } } onReady { var acc = document.querySelector("#acc-main"); if (acc) { acc.resultReported(102, this.innerHTML); } }

116. q-painter remains compatible with q-canvas rendering

pending
Expected: t116-ok
q-painter painter116 { q-property tone: "rgba(220,240,255,0.8)" onpaint { this.fillStyle = this.tone; this.fillRect(0, 0, this.width, this.height); } } q-style style116 { width: 90px height: 26px border: 1px solid #1e293b q-style-painter { background { painter116 } } } q-theme theme116 { .t116-panel { style116 } } theme116 { div#t116-painter.t116-panel { text { } } } q-canvas myCanvas116 { width: 48 height: 24 } div#t116-out { text { waiting } } onReady { var host = this; setTimeout(function() { var acc = document.querySelector("#acc-main"); var out = host.querySelector("#t116-out"); var panel = host.querySelector("#t116-painter"); var c = myCanvas116; var support = !!(CSS && CSS.paintWorklet && typeof CSS.paintWorklet.addModule === "function"); var okCanvas = false; if (c && c.context) { c.context.clearRect(0, 0, Number(c.width || 48), Number(c.height || 24)); c.context.fillStyle = "#22c55e"; c.context.fillRect(2, 2, 18, 10); var px = c.context.getImageData(3, 3, 1, 1).data; okCanvas = !!(px && px.length >= 4 && Number(px[3]) > 0); } var bg = panel ? String(panel.style.backgroundImage || "").trim() : ""; var okPainter = support ? (bg.indexOf("paint(") >= 0) : true; var ok = okCanvas && okPainter; var value = (ok ? "t116-ok" : "t116-fail") + "|canvas=" + String(okCanvas ? 1 : 0) + "|painter=" + String(okPainter ? 1 : 0); if (out) { out.textContent = value; } if (acc && typeof acc.outcomeReported === "function") { acc.outcomeReported(116, ok, value); } else if (acc && typeof acc.resultReported === "function") { acc.resultReported(116, value); } }, 520); }