UNPKG

fugafacere

Version:

A pure-JS implementation of the W3C's Canvas-2D Context API that can run on top of either Expo Graphics or a browser WebGL context.

303 lines (237 loc) 8.4 kB
spec: | <html> <head> <title>%name% // WebGL2DContext conformance</title> <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1"> <style> div { padding: 5px; } canvas { border: 1px black solid; } .progress { font: 100% monospace; } .failure { background-color: red; color: white; font: 100% sans-serif; } .success { background-color: #88FF88; font: 100% sans-serif; } .failure a:link { color: white } .failure a:visited { color: white } </style> <script type="text/javascript" src="bundle.js"></script> <script type="text/javascript" src="assets.js"></script> <script type="text/javascript" src="asserts.js"></script> <script type="text/javascript"> window.ImageData = ImageData; async function getAsset(name) { return new Promise((resolve, reject) => { let img = document.createElement("IMG") img.onload = () => resolve(img) img.onerror = reject img.src = rawImageAssets[name] }) } function bootCanvas(container, id, width, height, needsHighBitDepth) { var canvas = document.createElement("CANVAS") canvas.setAttribute("id", id) canvas.setAttribute("width", width) canvas.setAttribute("height", height) container.appendChild(canvas) var gl = canvas.getContext("webgl2", { stencil: 8, preserveDrawingBuffer: true }); gl.viewportWidth = canvas.width; gl.viewportHeight = canvas.height; if (!gl) { console.log("Could not initialise WebGL, sorry :-(") return null; } gl.clearColor(1.0, 0.0, 0.0, 1.0); gl.clear(gl.COLOR_BUFFER_BIT); /* TODO: figure out how to pass some gradient tests that need * more grad stops: */ let ctx = new Expo2DContext.default(gl, {maxGradStops: 50, renderWithOffscreenBuffer: needsHighBitDepth}) ctx.getContext = () => {return ctx;} return [canvas, gl, ctx] } function spinner_graphic(i) { let anim = ["/","&ndash;","\\","|","/","&ndash;","\\", "|"] return anim[i%anim.length] } var testContexts = {}; function focusTest (num) { window.ctx = testContexts[num][0] window.allContexts = testContexts[num] } window.onhashchange = () => { var url = new URL(window.location) var hashVal = url.hash.substr(1) if (hashVal in testContexts) { focusTest(hashVal) } } async function runTests() { // TODO: assets?? if (!window.testComplete) { window.testComplete = (testResults, completedTests, totalTests) => { /* PUPPETEER STUB */ }; } testContexts = {}; var tests = document.getElementsByClassName("test") var url = new URL(window.location) if (url.searchParams.get("runTests") != null) { selected_test_ids = url.searchParams.get("runTests").split(",").map((x) => parseInt(x)) selected_test_ids = selected_test_ids.filter((elm, idx) => {return isFinite(elm)}) tests = selected_test_ids.map((x) => document.getElementById("test_"+x+"_content")) } var cleanUp = url.searchParams.get("noCleanup") == null let suite_status = document.getElementById("suite_status") var failures = new Set(); var failureSummaryHTML = "Failed:<ul>" let i = 0; var testIteration = async (i) => { if (i >= tests.length) { finishTests(); return; } let test_area = tests[i] let test = test_area.dataset let allCanvases = [] let allWebGLContexts = [] let allContexts = [] let failureMessages = [] let test_fn = eval("test_"+test.id+"_body"); let needsHighBitDepth = test_fn.toString().includes("getImageData"); for (let j=0; j<parseInt(test.contexts); j++) { let [canvas, gl, ctx] = bootCanvas( test_area, "canvas_"+test.id+"_"+j, parseInt(test.width), parseInt(test.height), needsHighBitDepth ) // Install fake getContext wrapper to allow context objects to be // used in place of canvas objects for our tests: ctx.getContext = (unused) => {return ctx}; allCanvases.push(canvas) allWebGLContexts.push(gl) allContexts.push(ctx) } let onFail = TriggerObject((message) => { let status_box = document.getElementById("test_"+test.id+"_status") status_box.setAttribute("class","failure") status_box.innerHTML += message + "<br />"; failureMessages.push(message) if (!failures.has(test.id)) { failureSummaryHTML += "<li><a href='#"+test.id+"'>"+test.id+": "+test.description+"</a></li>" failures.add(test.id); } }) try { await test_fn(onFail, allCanvases, allContexts); } catch (err) { onFail.trigger(false, err.toString()); } if (cleanUp) { // Copy the resulting drawings out of the original canvas and // safely trash the old gl context, to free up resources: for (let j=0; j<parseInt(test.contexts); j++) { let canvas_clone = allCanvases[j].cloneNode(true); let clone_ctx = canvas_clone.getContext('2d'); clone_ctx.drawImage(allCanvases[j], 0, 0); allCanvases[j].replaceWith(canvas_clone); allWebGLContexts[j].getExtension('WEBGL_lose_context').loseContext(); allWebGLContexts[j] = null; } } else { testContexts[test.id] = allContexts } suite_status.innerHTML = "["+ spinner_graphic(i) + "] Tests run: " + (i+1) + " / " + tests.length; window.testComplete( Object.assign({ "failureMessages": failureMessages }, test), i+1, tests.length); setTimeout(() => { testIteration(i+1) }, 1); } var finishTests = () => { if (failures.size > 0) { failureSummaryHTML = (tests.length-failures.size) + "/" + tests.length + " tests passed<br />"+failureSummaryHTML failureSummaryHTML += "</ul><br />" suite_status.setAttribute("class","failure") suite_status.innerHTML = failureSummaryHTML } else { suite_status.setAttribute("class","success") suite_status.innerHTML = "[:)] All tests pass !" } if (!cleanUp && tests.length==1){ focusTest(tests[0].dataset.id) } else { window.onhashchange() } }; testIteration(0); } </script> </head> <body onload="runTests();"> <h1> %name% </h1> <div id="suite_status" class="progress">&nbsp;</div> <hr /> %tests% <br /><br /> &lt;3 </body> </html> test: | <p><a id="%id%" href="#%id%"\>%id%</a>: %description%</p> <script> async function test_%id%_body(t, allCanvases, allContexts) { %init% let ctx = allContexts[0]; let canvas = allCanvases[0]; %body% } </script> <div class="test" id="test_%id%_content" data-contexts="%totalContexts%" data-id="%id%" data-name="%name%" data-width="%width%" data-height="%height%" data-description="%description%">&nbsp;</div><br /> <div id="test_%id%_status">&nbsp;</div> [<a href="?runTests=%id%&noCleanup#%id%" onclick="window.location.reload()">solo run</a>] <hr /> asset_definition: | "%asset_filename%": "assets/%asset_filename%" assets: | var rawImageAssets = { %assetlist% } index_item: | <li><a data-name="2d.%name%" data-count="%count%" href="%filename%">2d.%name%</a> (%count% tests)</li> index: | <html><body> <ul> %indexlist% </ul> </body></html> filenames: | %name%.html disabled: | <!-- DISABLED: %reason% %body% -->