| <!DOCTYPE html><!-- webkit-test-runner [ CSSPaintingAPIEnabled=true ] --> |
| <meta name="author" title="Justin Michaud" href="mailto:justin_michaud@webkit.org"> |
| <meta name="assert" content="registerPaint accesses arguments in the correct order"> |
| <link rel="help" content="https://drafts.css-houdini.org/css-paint-api-1/"> |
| <script src="resources/testharness.js"></script> |
| |
| <style> |
| #paint { |
| background-image: paint(my-paint); |
| width: 150px; |
| height: 150px; |
| } |
| </style> |
| |
| <div id="paint"></div> |
| |
| <script id="code" type="text/worklet"> |
| class MyPaint { |
| paint() { } |
| } |
| |
| test(function() { |
| registerPaint('basic1', class { |
| static get inputProperties() { return ["--test"]; } |
| paint() { } |
| }); |
| }, 'test that registerPaint runs'); |
| |
| test(function() { |
| globalThis.registerPaint('basic1-globalThis', class { |
| static get inputProperties() { return ["--test"]; } |
| paint() { } |
| }); |
| }, 'test that registerPaint runs (called on globalThis)'); |
| |
| test(function() { |
| registerPaint('basic2', class { |
| paint() { } |
| }); |
| }, 'test that registerPaint runs without inputProperties'); |
| |
| test(function() { |
| registerPaint('basic3', class { |
| static get inputArguments() { return ["<length>"]; } |
| paint() { } |
| }); |
| }, 'test that registerPaint runs with inputArguments'); |
| |
| test(function() { |
| registerPaint('basic4', class { |
| static get contextOptions() { return { alpha: true }; } |
| paint() { } |
| }); |
| }, 'test that registerPaint runs with contextOptions'); |
| |
| test(function() { |
| registerPaint('basic5', MyPaint); |
| assert_throws({'name': 'InvalidModificationError'}, () => registerPaint('basic5', MyPaint)); |
| registerPaint('basic6', class extends MyPaint { }); |
| }, 'test that registerPaint runs with predefined class'); |
| |
| test(function() { |
| assert_throws({'name': 'TypeError'}, () => registerPaint('basic6', 'test')); |
| assert_throws(new TypeError(), () => registerPaint('basic8')); |
| assert_throws(new TypeError(), () => registerPaint('basic9', [])); |
| assert_throws(new TypeError(), () => registerPaint('basic10', {})); |
| assert_throws(new TypeError(), () => registerPaint('basic11', 5)); |
| assert_throws(new TypeError(), () => registerPaint('', 5)); |
| }, 'test that registerPaint accepts only a string and a class constructor'); |
| |
| test(function () { |
| const calls = []; |
| const proxy = new Proxy(class extends MyPaint { }, { |
| get: function (target, name) { |
| calls.push(name); |
| return target[name]; |
| } |
| }); |
| registerPaint('test-proto', proxy); |
| assert_array_equals(calls, ["inputProperties", "inputArguments", "contextOptions", "prototype"]); |
| }, 'must get "prototype" property of the constructor'); |
| |
| test(function () { |
| const calls = []; |
| const proxy = new Proxy(class extends MyPaint { }, { |
| get: function (target, name) { |
| calls.push(name); |
| if (name == 'inputProperties') |
| throw {name: 'expectedError'}; |
| return target[name]; |
| } |
| }); |
| assert_throws({'name': 'expectedError'}, function () { registerPaint('test-rethrow-inputProperties0', proxy); }); |
| }, 'must rethrow an exception thrown while getting "inputProperties" property of the constructor'); |
| |
| test(function () { |
| const calls = []; |
| const proxy = new Proxy(class extends MyPaint { }, { |
| get: function (target, name) { |
| calls.push(name); |
| if (name == 'prototype') |
| throw {name: 'expectedError'}; |
| return target[name]; |
| } |
| }); |
| assert_throws({'name': 'expectedError'}, function () { registerPaint('test-rethrow-proto', proxy); }); |
| }, 'must rethrow an exception thrown while getting "prototype" property of the constructor'); |
| |
| test(function () { |
| let returnedValue; |
| const proxy = new Proxy(class extends MyPaint { }, { |
| get: function (target, name) { |
| if (name == 'prototype') |
| return returnedValue; |
| return target[name]; |
| } |
| }); |
| |
| returnedValue = null; |
| assert_throws({'name': 'TypeError'}, function () { registerPaint('test-rethrow-proto-noobj1', proxy); }, |
| 'must throw when "prototype" property of the constructor is null'); |
| returnedValue = undefined; |
| assert_throws({'name': 'TypeError'}, function () { registerPaint('test-rethrow-proto-noobj2', proxy); }, |
| 'must throw when "prototype" property of the constructor is undefined'); |
| returnedValue = 'hello'; |
| assert_throws({'name': 'TypeError'}, function () { registerPaint('test-rethrow-proto-noobj3', proxy);; }, |
| 'must throw when "prototype" property of the constructor is a string'); |
| returnedValue = 1; |
| assert_throws({'name': 'TypeError'}, function () { registerPaint('test-rethrow-proto-noobj4', proxy);; }, |
| 'must throw when "prototype" property of the constructor is a number'); |
| |
| }, 'must throw when "prototype" property of the constructor is not an object'); |
| |
| test(function () { |
| const constructor = function () {} |
| constructor.prototype.paint = function() {} |
| const calls = []; |
| constructor.prototype = new Proxy(constructor.prototype, { |
| get: function (target, name) { |
| calls.push(name); |
| return target[name]; |
| } |
| }); |
| registerPaint('callbacks', constructor); |
| assert_array_equals(calls, ['paint']); |
| }, 'must get paint callback of the constructor prototype'); |
| |
| test(function () { |
| const constructor = function () {} |
| const calls = []; |
| constructor.prototype = new Proxy(constructor.prototype, { |
| get: function (target, name) { |
| calls.push(name); |
| if (name == 'paint') |
| throw {name: 'expectedError'}; |
| return target[name]; |
| } |
| }); |
| assert_throws({'name': 'expectedError'}, function () { registerPaint('callbacks-throw', constructor); }); |
| assert_array_equals(calls, ['paint']); |
| }, 'must rethrow an exception thrown while getting paint callback on the constructor prototype'); |
| |
| test(function () { |
| const constructor = function () {} |
| const calls = []; |
| constructor.prototype = new Proxy(constructor.prototype, { |
| get: function (target, name) { |
| calls.push(name); |
| if (name == 'paint') |
| return 1; |
| return target[name]; |
| } |
| }); |
| assert_throws({'name': 'TypeError'}, function () { registerPaint('callbacks-throw2', constructor); }); |
| assert_array_equals(calls, ['paint']); |
| }, 'must rethrow an exception thrown while converting paint callback value to Function callback type'); |
| |
| test(function () { |
| const calls = []; |
| const proxy = new Proxy(class extends MyPaint { }, { |
| get: function (target, name) { |
| calls.push(name); |
| if (name == 'inputArguments') |
| return 1; |
| return target[name]; |
| } |
| }); |
| assert_throws({'name': 'TypeError'}, function () { registerPaint('sequence-throw', proxy); }); |
| assert_array_equals(calls, ["inputProperties", "inputArguments"]); |
| }, 'must rethrow an exception thrown while converting the value of inputArguments to sequence<DOMString>'); |
| |
| test(function () { |
| const constructor = function () {} |
| constructor.inputArguments = {[Symbol.iterator]: function *() { |
| yield '<length>'; |
| throw {name: 'SomeError'}; |
| }}; |
| assert_throws({'name': 'SomeError'}, function () { registerPaint('sequence-throw2', constructor); }); |
| }, 'must rethrow an exception thrown while iterating over inputArguments to sequence<DOMString>'); |
| |
| test(function () { |
| const constructor = function () {} |
| constructor.inputArguments = {[Symbol.iterator]: 1}; |
| assert_throws({'name': 'TypeError'}, function () { registerPaint('symbol-iterator-throw2', constructor); }); |
| }, 'must rethrow an exception thrown while retrieving Symbol.iterator on inputArguments'); |
| |
| assert_true(PaintWorkletGlobalScope.hasRunATest); |
| if (PaintWorkletGlobalScope.errors) { |
| console.log("The following (" + PaintWorkletGlobalScope.errors.length + ") tests failed: ") |
| console.log(JSON.stringify(PaintWorkletGlobalScope.errors)); |
| assert_true(false); |
| } |
| |
| class MyPaint2 { |
| paint(ctx, geom, properties) { |
| for (var i = 0; i < 6; i++){ |
| for (var j = 0; j < 6; j++){ |
| ctx.fillStyle = 'rgb(' + Math.floor(255 - 42.5 * i) + ',' + |
| Math.floor(255 - 42.5 * j) + ',0)'; |
| ctx.fillRect(j * 25, i * 25, 25, 25); |
| } |
| } |
| } |
| } |
| registerPaint('my-paint', MyPaint2); |
| </script> |
| |
| <script> |
| importWorklet(CSS.paintWorklet, document.getElementById('code').textContent); |
| </script> |