-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Bug 1850735 [wpt PR 41713] - Add canvas-based test for composite mode…
…s., a=testonly Automatic update from web-platform-tests Add canvas-based test for composite modes. This test tests for the current spec, but it is also designed so that we can use it to make progress on changing the spec in w3c/fxtf-drafts#446 and w3c/fxtf-drafts#447 . Change-Id: If0f321a0fef7279fabfba9c613556371f42f9875 Bug: 1477259 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4827182 Auto-Submit: David Baron <dbaron@chromium.org> Reviewed-by: Vladimir Levin <vmpstr@chromium.org> Commit-Queue: Vladimir Levin <vmpstr@chromium.org> Cr-Commit-Position: refs/heads/main@{#1190349} -- wpt-commits: 808ba394dd5f6a6904521f4a5f810fac8e70a8e3 wpt-pr: 41713
- Loading branch information
1 parent
5f431a3
commit bdd0d81
Showing
1 changed file
with
157 additions
and
0 deletions.
There are no files selected for viewing
157 changes: 157 additions & 0 deletions
157
testing/web-platform/tests/css/compositing/canvas-composite-modes.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
<!DOCTYPE HTML> | ||
<meta charset="utf-8"> | ||
<title>Test of <composite-mode> values in canvas globalCompositeOperation</title> | ||
<link rel="help" href="https://html.spec.whatwg.org/multipage/C#compositing"> | ||
<link rel="help" href="https://drafts.fxtf.org/compositing/#canvascompositingandblending"> | ||
<script src="/resources/testharness.js"></script> | ||
<script src="/resources/testharnessreport.js"></script> | ||
|
||
<canvas id="canvas" width="2" height="2"></canvas> | ||
|
||
<script> | ||
|
||
// Test a small set of sRGB color and alpha values in the 0-255 range. | ||
const VALUES = [ 0, 47, 193, 255 ]; | ||
|
||
const COMPOSITE_OPERATORS = { | ||
// Define a "color" function accepting source and destination colors | ||
// and alphas, and an "alpha" function accepting source and | ||
// destination alphas. | ||
"clear": { | ||
"color": (sa, sc, da, dc) => 0, | ||
"alpha": (sa, da) => 0 | ||
}, | ||
"copy": { | ||
"color": (sa, sc, da, dc) => sa * sc, | ||
"alpha": (sa, da) => sa | ||
}, | ||
"destination": { | ||
// TODO(dbaron): The spec says this should work, but none of | ||
// Chromium, Gecko, or WebKit appear to implement it. | ||
"color": (sa, sc, da, dc) => da * dc, | ||
"alpha": (sa, da) => da | ||
}, | ||
"source-over": { | ||
"color": (sa, sc, da, dc) => sa * sc + da * dc * (1 - sa), | ||
"alpha": (sa, da) => sa + da * (1 - sa) | ||
}, | ||
"destination-over": { | ||
"color": (sa, sc, da, dc) => sa * sc * (1 - da) + da * dc, | ||
"alpha": (sa, da) => sa * (1 - da) + da | ||
}, | ||
"source-in": { | ||
"color": (sa, sc, da, dc) => sa * sc * da, | ||
"alpha": (sa, da) => sa * da | ||
}, | ||
"destination-in": { | ||
"color": (sa, sc, da, dc) => da * dc * sa, | ||
"alpha": (sa, da) => da * sa | ||
}, | ||
"source-out": { | ||
"color": (sa, sc, da, dc) => sa * sc * (1 - da), | ||
"alpha": (sa, da) => sa * (1 - da) | ||
}, | ||
"destination-out": { | ||
"color": (sa, sc, da, dc) => da * dc * (1 - sa), | ||
"alpha": (sa, da) => da * (1 - sa) | ||
}, | ||
"source-atop": { | ||
"color": (sa, sc, da, dc) => sa * sc * da + da * dc * (1 - sa), | ||
"alpha": (sa, da) => sa * da + da * (1 - sa) | ||
}, | ||
"destination-atop": { | ||
"color": (sa, sc, da, dc) => sa * sc * (1 - da) + da * dc * sa, | ||
"alpha": (sa, da) => sa * (1 - da) + da * sa | ||
}, | ||
"xor": { | ||
"color": (sa, sc, da, dc) => sa * sc * (1 - da) + da * dc * (1 - sa), | ||
"alpha": (sa, da) => sa * (1 - da) + da * (1 - sa) | ||
}, | ||
"lighter": { | ||
// TODO(https://github.com/w3c/fxtf-drafts/issues/446): All engines | ||
// actually implement 'lighter' using the formula for 'plus-lighter' | ||
// given below; we should update the spec to match! | ||
"color": (sa, sc, da, dc) => sa * sc + da * dc, | ||
"alpha": (sa, da) => sa + da | ||
}, | ||
"plus-darker": { | ||
// TODO(https://github.com/w3c/fxtf-drafts/issues/447): This formula | ||
// is almost certainly wrong. It doesn't make sense, and the one | ||
// engine that implements this value (WebKit) does something very | ||
// different. | ||
"color": (sa, sc, da, dc) => Math.max(0, 1 - sa * sc + 1 - da * dc), | ||
"alpha": (sa, da) => Math.max(0, 1 - sa + 1 - da) | ||
}, | ||
"plus-lighter": { | ||
"color": (sa, sc, da, dc) => Math.min(1, sa * sc + da * dc), | ||
"alpha": (sa, da) => Math.min(1, sa + da) | ||
} | ||
}; | ||
|
||
let canvas = document.getElementById("canvas"); | ||
let cx = canvas.getContext("2d", { willReadFrequently: true }); | ||
|
||
function roundup_255th(n) { | ||
return Math.ceil(n * 255) / 255; | ||
} | ||
|
||
function rounddown_255th(n) { | ||
return Math.floor(n * 255) / 255; | ||
} | ||
|
||
for (let op in COMPOSITE_OPERATORS) { | ||
test(function() { | ||
cx.save(); | ||
this.add_cleanup(() => { cx.restore(); }); | ||
for (let sc of VALUES) { | ||
for (let sa of VALUES) { | ||
for (let dc of VALUES) { | ||
for (let da of VALUES) { | ||
let desc = `g=${sc} a=${sa} ${op} g=${dc} a=${da}`; | ||
cx.restore(); | ||
cx.save(); | ||
cx.clearRect(0, 0, 2, 2); | ||
cx.fillStyle = `rgb(0, ${dc}, 0)`; | ||
cx.globalAlpha = da / 255; | ||
cx.fillRect(0, 0, 2, 2); | ||
cx.globalCompositeOperation = op; | ||
assert_equals(cx.globalCompositeOperation, op, "composite operation"); | ||
cx.fillStyle = `rgb(0, ${sc}, 0)`; | ||
cx.globalAlpha = sa / 255; | ||
cx.fillRect(0, 0, 2, 2); | ||
let imageData = cx.getImageData(0, 0, 1, 1); | ||
assert_equals(imageData.data.length, 4, "length of ImageData"); | ||
assert_equals(imageData.data[0], 0, `red: ${desc}`); | ||
assert_equals(imageData.data[2], 0, `blue: ${desc}`); | ||
let expected_color = COMPOSITE_OPERATORS[op].color(sa/255, sc/255, da/255, dc/255); | ||
let expected_alpha = COMPOSITE_OPERATORS[op].alpha(sa/255, da/255); | ||
let allowed_color_error; | ||
// undo the premultiplication: | ||
if (expected_alpha == 0) { | ||
assert_equals(expected_color, 0, `premultiplication zero check: ${desc}`); | ||
allowed_color_error = 0; | ||
} else { | ||
// We want to allow for the error in the color expectation | ||
// to increase when the expected alpha is small, because | ||
// we want to allow for roughly the same amount of error | ||
// in the (smaller) *premultiplied* value. | ||
let expected_min_color = rounddown_255th(expected_color) / roundup_255th(expected_alpha); | ||
let expected_max_color = roundup_255th(expected_color) / rounddown_255th(expected_alpha); | ||
// Set the expectation to the midpoint of the error range | ||
// rather than the actual accurate expectation. | ||
expected_color = (expected_max_color + expected_min_color) / 2; | ||
allowed_color_error = (expected_max_color - expected_min_color) / 2; | ||
} | ||
expected_color *= 255; | ||
expected_alpha *= 255; | ||
allowed_color_error *= 255; | ||
allowed_color_error += 3.5; | ||
assert_approx_equals(imageData.data[1], expected_color, allowed_color_error, `green: ${desc}`); | ||
assert_approx_equals(imageData.data[3], expected_alpha, 1.01, `alpha: ${desc}`); | ||
} | ||
} | ||
} | ||
} | ||
}, `globalCompositeOperation ${op}`); | ||
} | ||
</script> |