LibWeb: Account for paint style and global alpha when drawing shadows

This commit is contained in:
Tim Ledbetter 2025-10-21 10:09:46 +01:00 committed by Jelle Raaijmakers
parent 553a7a9278
commit b99c0c6a7f
15 changed files with 216 additions and 2 deletions

View File

@ -1062,12 +1062,19 @@ void CanvasRenderingContext2D::paint_shadow_for_fill_internal(Gfx::Path const& p
if (state.current_compositing_and_blending_operator == Gfx::CompositingAndBlendingOperator::Copy)
return;
auto alpha = state.global_alpha * (state.shadow_color.alpha() / 255.0f);
auto fill_style_color = state.fill_style.as_color();
if (fill_style_color.has_value() && fill_style_color->alpha() > 0)
alpha = (fill_style_color->alpha() / 255.0f) * state.global_alpha;
if (alpha == 0.0f)
return;
painter->save();
Gfx::AffineTransform transform;
transform.translate(state.shadow_offset_x, state.shadow_offset_y);
painter->set_transform(transform);
painter->fill_path(path, state.shadow_color.with_opacity(state.global_alpha), winding_rule, state.shadow_blur, state.current_compositing_and_blending_operator);
painter->fill_path(path, state.shadow_color.with_opacity(alpha), winding_rule, state.shadow_blur, state.current_compositing_and_blending_operator);
painter->restore();
@ -1085,12 +1092,19 @@ void CanvasRenderingContext2D::paint_shadow_for_stroke_internal(Gfx::Path const&
if (state.current_compositing_and_blending_operator == Gfx::CompositingAndBlendingOperator::Copy)
return;
auto alpha = state.global_alpha * (state.shadow_color.alpha() / 255.0f);
auto fill_style_color = state.fill_style.as_color();
if (fill_style_color.has_value() && fill_style_color->alpha() > 0)
alpha = (fill_style_color->alpha() / 255.0f) * state.global_alpha;
if (alpha == 0.0f)
return;
painter->save();
Gfx::AffineTransform transform;
transform.translate(state.shadow_offset_x, state.shadow_offset_y);
painter->set_transform(transform);
painter->stroke_path(path, state.shadow_color.with_opacity(state.global_alpha), state.line_width, state.shadow_blur, state.current_compositing_and_blending_operator);
painter->stroke_path(path, state.shadow_color.with_opacity(alpha), state.line_width, state.shadow_blur, state.current_compositing_and_blending_operator);
painter->restore();

View File

@ -0,0 +1,6 @@
Harness status: OK
Found 1 tests
1 Pass
Pass Shadow color alpha components are used

View File

@ -0,0 +1,6 @@
Harness status: OK
Found 1 tests
1 Pass
Pass Shadow color alpha components are used

View File

@ -0,0 +1,6 @@
Harness status: OK
Found 1 tests
1 Pass
Pass Shadows are affected by globalAlpha

View File

@ -0,0 +1,6 @@
Harness status: OK
Found 1 tests
1 Pass
Pass Shadows with alpha components are correctly affected by globalAlpha

View File

@ -0,0 +1,6 @@
Harness status: OK
Found 1 tests
1 Pass
Pass Shadows of shapes with alpha components are drawn correctly

View File

@ -0,0 +1,33 @@
<!DOCTYPE html>
<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
<meta charset="UTF-8">
<title>Canvas test: 2d.shadow.alpha.1</title>
<script src="../../../../resources/testharness.js"></script>
<script src="../../../../resources/testharnessreport.js"></script>
<script src="../../../../html/canvas/resources/canvas-tests.js"></script>
<link rel="stylesheet" href="../../../../html/canvas/resources/canvas-tests.css">
<body class="show_output">
<h1>2d.shadow.alpha.1</h1>
<p class="desc">Shadow color alpha components are used</p>
<p class="output">Actual output:</p>
<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
<p class="output expectedtext">Expected output:<p><img src="../../../../images/green-100x50.png" class="output expected" id="expected" alt="">
<ul id="d"></ul>
<script>
var t = async_test("Shadow color alpha components are used");
_addTest(function(canvas, ctx) {
ctx.fillStyle = '#0f0';
ctx.fillRect(0, 0, 100, 50);
ctx.shadowColor = 'rgba(255, 0, 0, 0.01)';
ctx.shadowOffsetY = 50;
ctx.fillRect(0, -50, 100, 50);
_assertPixelApprox(canvas, 50,25, 0,255,0,255, 4);
});
</script>

View File

@ -0,0 +1,33 @@
<!DOCTYPE html>
<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
<meta charset="UTF-8">
<title>Canvas test: 2d.shadow.alpha.2</title>
<script src="../../../../resources/testharness.js"></script>
<script src="../../../../resources/testharnessreport.js"></script>
<script src="../../../../html/canvas/resources/canvas-tests.js"></script>
<link rel="stylesheet" href="../../../../html/canvas/resources/canvas-tests.css">
<body class="show_output">
<h1>2d.shadow.alpha.2</h1>
<p class="desc">Shadow color alpha components are used</p>
<p class="output">Actual output:</p>
<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
<p class="output expectedtext">Expected output:<p><img src="2d.shadow.alpha.2.png" class="output expected" id="expected" alt="">
<ul id="d"></ul>
<script>
var t = async_test("Shadow color alpha components are used");
_addTest(function(canvas, ctx) {
ctx.fillStyle = '#f00';
ctx.fillRect(0, 0, 100, 50);
ctx.shadowColor = 'rgba(0, 0, 255, 0.5)';
ctx.shadowOffsetY = 50;
ctx.fillRect(0, -50, 100, 50);
_assertPixelApprox(canvas, 50,25, 127,0,127,255, 2);
});
</script>

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 B

View File

@ -0,0 +1,35 @@
<!DOCTYPE html>
<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
<meta charset="UTF-8">
<title>Canvas test: 2d.shadow.alpha.3</title>
<script src="../../../../resources/testharness.js"></script>
<script src="../../../../resources/testharnessreport.js"></script>
<script src="../../../../html/canvas/resources/canvas-tests.js"></script>
<link rel="stylesheet" href="../../../../html/canvas/resources/canvas-tests.css">
<body class="show_output">
<h1>2d.shadow.alpha.3</h1>
<p class="desc">Shadows are affected by globalAlpha</p>
<p class="output">Actual output:</p>
<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
<p class="output expectedtext">Expected output:<p><img src="2d.shadow.alpha.3.png" class="output expected" id="expected" alt="">
<ul id="d"></ul>
<script>
var t = async_test("Shadows are affected by globalAlpha");
_addTest(function(canvas, ctx) {
ctx.fillStyle = '#f00';
ctx.fillRect(0, 0, 100, 50);
ctx.fillStyle = '#f00'; // (work around broken Firefox globalAlpha caching)
ctx.shadowColor = '#00f';
ctx.shadowOffsetY = 50;
ctx.globalAlpha = 0.5;
ctx.fillRect(0, -50, 100, 50);
_assertPixelApprox(canvas, 50,25, 127,0,127,255, 2);
});
</script>

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 B

View File

@ -0,0 +1,35 @@
<!DOCTYPE html>
<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
<meta charset="UTF-8">
<title>Canvas test: 2d.shadow.alpha.4</title>
<script src="../../../../resources/testharness.js"></script>
<script src="../../../../resources/testharnessreport.js"></script>
<script src="../../../../html/canvas/resources/canvas-tests.js"></script>
<link rel="stylesheet" href="../../../../html/canvas/resources/canvas-tests.css">
<body class="show_output">
<h1>2d.shadow.alpha.4</h1>
<p class="desc">Shadows with alpha components are correctly affected by globalAlpha</p>
<p class="output">Actual output:</p>
<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
<p class="output expectedtext">Expected output:<p><img src="2d.shadow.alpha.4.png" class="output expected" id="expected" alt="">
<ul id="d"></ul>
<script>
var t = async_test("Shadows with alpha components are correctly affected by globalAlpha");
_addTest(function(canvas, ctx) {
ctx.fillStyle = '#f00';
ctx.fillRect(0, 0, 100, 50);
ctx.fillStyle = '#f00'; // (work around broken Firefox globalAlpha caching)
ctx.shadowColor = 'rgba(0, 0, 255, 0.707)';
ctx.shadowOffsetY = 50;
ctx.globalAlpha = 0.707;
ctx.fillRect(0, -50, 100, 50);
_assertPixelApprox(canvas, 50,25, 127,0,127,255, 2);
});
</script>

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 B

View File

@ -0,0 +1,34 @@
<!DOCTYPE html>
<!-- DO NOT EDIT! This test has been generated by /html/canvas/tools/gentest.py. -->
<meta charset="UTF-8">
<title>Canvas test: 2d.shadow.alpha.5</title>
<script src="../../../../resources/testharness.js"></script>
<script src="../../../../resources/testharnessreport.js"></script>
<script src="../../../../html/canvas/resources/canvas-tests.js"></script>
<link rel="stylesheet" href="../../../../html/canvas/resources/canvas-tests.css">
<body class="show_output">
<h1>2d.shadow.alpha.5</h1>
<p class="desc">Shadows of shapes with alpha components are drawn correctly</p>
<p class="output">Actual output:</p>
<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
<p class="output expectedtext">Expected output:<p><img src="2d.shadow.alpha.5.png" class="output expected" id="expected" alt="">
<ul id="d"></ul>
<script>
var t = async_test("Shadows of shapes with alpha components are drawn correctly");
_addTest(function(canvas, ctx) {
ctx.fillStyle = '#f00';
ctx.fillRect(0, 0, 100, 50);
ctx.fillStyle = 'rgba(64, 0, 0, 0.5)';
ctx.shadowColor = '#00f';
ctx.shadowOffsetY = 50;
ctx.fillRect(0, -50, 100, 50);
_assertPixelApprox(canvas, 50,25, 127,0,127,255, 2);
});
</script>

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 B