| // Test runner for the paint worklet to test invalidation behaviour. |
| // |
| // Registers an promise_test per test case, which: |
| // - Creates an element. |
| // - Invalidates the style of that element. |
| // - [worklet] Worklet code logs if it got the invalidation. |
| // - Asserts that it got the correct paint invalidation. |
| // |
| // Usage: |
| // testRunnerInvalidationLogging('background-image', [ |
| // { property: 'max-height', value: '100px' }, |
| // { property: 'color', prevValue: '#00F', value: 'blue', noInvalidation: true }, |
| // ]); |
| |
| function testRunnerInvalidationLogging(imageType, tests) { |
| const keys = tests.map(function(obj) { return obj.property; }); |
| const workletCode = 'const properties = ' + JSON.stringify(keys) + ';\n' + ` |
| for (let i = 0; i < properties.length; i++) { |
| registerPaint('paint-' + i, class { |
| static get inputProperties() { return [properties[i]]; } |
| constructor() { this.hasPainted= false; } |
| paint(ctx, geom) { |
| ctx.fillStyle = this.hasPainted ? 'green' : 'blue'; |
| ctx.fillRect(0, 0, geom.width, geom.height); |
| if (this.hasPainted) { |
| console.log('Successful invalidation for: ' + properties[i]); |
| } |
| this.hasPainted = true; |
| } |
| }); |
| } |
| `; |
| |
| paintWorklet.import(URL.createObjectURL(new Blob([workletCode]))).then(function() { |
| for (let i = 0; i < tests.length; i++) { |
| tests[i].paintName = 'paint-' + i; |
| registerTest(imageType, tests[i]); |
| } |
| }); |
| } |
| |
| function registerTest(imageType, test) { |
| const testName = test.property + ': ' + (test.prevValue || '[inline not set]') + ' => ' + test.property + ': ' + (test.value || '[inline not set]'); |
| |
| // We use a promise_test instead of a async_test as they run sequentially. |
| promise_test(function() { |
| return new Promise(function(resolve) { |
| |
| const msg = ['\n\nTest case:', testName]; |
| if (test.noInvalidation) { |
| msg.push('The worklet console should log nothing'); |
| } else { |
| msg.push('The worklet console should log: \'Succussful invalidation for: ' + test.property + '\''); |
| } |
| console.log(msg.join('\n')); |
| |
| // Create the test div. |
| const el = document.createElement('div'); |
| if (test.prevValue) el.style.setProperty(test.property, test.prevValue); |
| el.style[imageType] = 'paint(' + test.paintName + ')'; |
| document.body.appendChild(el); |
| |
| runAfterLayoutAndPaint(function() { |
| if (window.internals) |
| internals.startTrackingRepaints(document); |
| |
| // Keep the BCR for the paint invalidation assertion, and invalidate paint. |
| const rect = el.getBoundingClientRect(); |
| el.style.setProperty(test.property, test.value); |
| |
| runAfterLayoutAndPaint(function() { |
| // Check that the we got the correct paint invalidation. |
| if (window.internals) { |
| const layers = JSON.parse(internals.layerTreeAsText(document, internals.LAYER_TREE_INCLUDES_PAINT_INVALIDATIONS)); |
| const paintInvalidations = layers['children'][0]['paintInvalidations']; |
| assert_equals(!paintInvalidations, !!test.noInvalidation); |
| if (paintInvalidations) { |
| assert_equals(paintInvalidations.length, 1, 'There should be only one paint invalidation.'); |
| assert_array_equals( |
| paintInvalidations[0]['rect'], |
| [rect.left, rect.top, rect.width, rect.height], |
| 'The paint invalidation should cover the entire element.'); |
| } |
| internals.stopTrackingRepaints(document); |
| } |
| |
| // Cleanup. |
| document.body.removeChild(el); |
| resolve(); |
| }); |
| }); |
| |
| }); |
| |
| }, testName); |
| } |