mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-07-29 12:19:54 +00:00
LibWeb/Canvas: Correctly return globalCompositeOperation
This fixes a bug that caused the retrieved `globalCompositeOperation` to contain quotes.
This commit is contained in:
parent
f672c57ca7
commit
64a234c0df
Notes:
github-actions[bot]
2025-02-24 13:57:03 +00:00
Author: https://github.com/skyz1
Commit: 64a234c0df
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/3678
Reviewed-by: https://github.com/tcl3 ✅
3 changed files with 179 additions and 1 deletions
|
@ -796,7 +796,7 @@ String CanvasRenderingContext2D::global_composite_operation() const
|
|||
#undef __ENUMERATE
|
||||
#define __ENUMERATE(operation, compositing_and_blending_operator) \
|
||||
case Gfx::CompositingAndBlendingOperator::compositing_and_blending_operator: \
|
||||
return #operation##_string;
|
||||
return operation##_string;
|
||||
ENUMERATE_COMPOSITE_OPERATIONS(__ENUMERATE)
|
||||
#undef __ENUMERATE
|
||||
default:
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
Harness status: OK
|
||||
|
||||
Found 15 tests
|
||||
|
||||
8 Pass
|
||||
7 Fail
|
||||
Pass globalCompositeOperation clear
|
||||
Pass globalCompositeOperation copy
|
||||
Fail globalCompositeOperation destination
|
||||
Pass globalCompositeOperation source-over
|
||||
Pass globalCompositeOperation destination-over
|
||||
Fail globalCompositeOperation source-in
|
||||
Fail globalCompositeOperation destination-in
|
||||
Fail globalCompositeOperation source-out
|
||||
Pass globalCompositeOperation destination-out
|
||||
Pass globalCompositeOperation source-atop
|
||||
Fail globalCompositeOperation destination-atop
|
||||
Pass globalCompositeOperation xor
|
||||
Fail globalCompositeOperation lighter
|
||||
Fail globalCompositeOperation plus-darker
|
||||
Pass globalCompositeOperation plus-lighter
|
|
@ -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>
|
Loading…
Add table
Add a link
Reference in a new issue