mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-04-22 04:25:13 +00:00
LibWeb: Prevent paths thinner than 1px from disappearing
SVGs are rendered with subpixel precision. As such it can happen that paths are rendered with less than 1px width or height and that they can have a bounding box thinner than 1px. Due to an optimization such paths were ignored when painting because their bounding box was incorrectly calculated to be empty. As a result horizontal or vertical lines inside SVGs were missing if: * The SVG is displayed at viewbox size but the lines are defined with less than 1px. * The SVG contians 1px-thin lines, but is displayed at a size smaller than viewbox size. To prevent this, the bounding box of the path is now enlarged to contain all pixels that are partially affected.
This commit is contained in:
parent
b08db3dc1e
commit
c790cf2194
Notes:
github-actions[bot]
2025-01-07 09:06:05 +00:00
Author: https://github.com/InvalidUsernameException Commit: https://github.com/LadybirdBrowser/ladybird/commit/c790cf21945 Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/3162 Reviewed-by: https://github.com/AtkinsSJ ✅
4 changed files with 85 additions and 12 deletions
|
@ -49,11 +49,12 @@ void DisplayListRecorder::fill_rect(Gfx::IntRect const& rect, Color color)
|
|||
void DisplayListRecorder::fill_path(FillPathUsingColorParams params)
|
||||
{
|
||||
auto aa_translation = params.translation.value_or(Gfx::FloatPoint {});
|
||||
auto path_bounding_rect = params.path.bounding_box().translated(aa_translation).to_type<int>();
|
||||
if (path_bounding_rect.is_empty())
|
||||
auto path_bounding_rect = params.path.bounding_box().translated(aa_translation);
|
||||
auto path_bounding_int_rect = enclosing_int_rect(path_bounding_rect);
|
||||
if (path_bounding_int_rect.is_empty())
|
||||
return;
|
||||
append(FillPathUsingColor {
|
||||
.path_bounding_rect = path_bounding_rect,
|
||||
.path_bounding_rect = path_bounding_int_rect,
|
||||
.path = move(params.path),
|
||||
.color = params.color,
|
||||
.winding_rule = params.winding_rule,
|
||||
|
@ -64,11 +65,12 @@ void DisplayListRecorder::fill_path(FillPathUsingColorParams params)
|
|||
void DisplayListRecorder::fill_path(FillPathUsingPaintStyleParams params)
|
||||
{
|
||||
auto aa_translation = params.translation.value_or(Gfx::FloatPoint {});
|
||||
auto path_bounding_rect = params.path.bounding_box().translated(aa_translation).to_type<int>();
|
||||
if (path_bounding_rect.is_empty())
|
||||
auto path_bounding_rect = params.path.bounding_box().translated(aa_translation);
|
||||
auto path_bounding_int_rect = enclosing_int_rect(path_bounding_rect);
|
||||
if (path_bounding_int_rect.is_empty())
|
||||
return;
|
||||
append(FillPathUsingPaintStyle {
|
||||
.path_bounding_rect = path_bounding_rect,
|
||||
.path_bounding_rect = path_bounding_int_rect,
|
||||
.path = move(params.path),
|
||||
.paint_style = params.paint_style,
|
||||
.winding_rule = params.winding_rule,
|
||||
|
@ -80,10 +82,11 @@ void DisplayListRecorder::fill_path(FillPathUsingPaintStyleParams params)
|
|||
void DisplayListRecorder::stroke_path(StrokePathUsingColorParams params)
|
||||
{
|
||||
auto aa_translation = params.translation.value_or(Gfx::FloatPoint {});
|
||||
auto path_bounding_rect = params.path.bounding_box().translated(aa_translation).to_type<int>();
|
||||
auto path_bounding_rect = params.path.bounding_box().translated(aa_translation);
|
||||
// Increase path bounding box by `thickness` to account for stroke.
|
||||
path_bounding_rect.inflate(params.thickness, params.thickness);
|
||||
if (path_bounding_rect.is_empty())
|
||||
auto path_bounding_int_rect = enclosing_int_rect(path_bounding_rect);
|
||||
if (path_bounding_int_rect.is_empty())
|
||||
return;
|
||||
append(StrokePathUsingColor {
|
||||
.cap_style = params.cap_style,
|
||||
|
@ -91,7 +94,7 @@ void DisplayListRecorder::stroke_path(StrokePathUsingColorParams params)
|
|||
.miter_limit = params.miter_limit,
|
||||
.dash_array = move(params.dash_array),
|
||||
.dash_offset = params.dash_offset,
|
||||
.path_bounding_rect = path_bounding_rect,
|
||||
.path_bounding_rect = path_bounding_int_rect,
|
||||
.path = move(params.path),
|
||||
.color = params.color,
|
||||
.thickness = params.thickness,
|
||||
|
@ -102,10 +105,11 @@ void DisplayListRecorder::stroke_path(StrokePathUsingColorParams params)
|
|||
void DisplayListRecorder::stroke_path(StrokePathUsingPaintStyleParams params)
|
||||
{
|
||||
auto aa_translation = params.translation.value_or(Gfx::FloatPoint {});
|
||||
auto path_bounding_rect = params.path.bounding_box().translated(aa_translation).to_type<int>();
|
||||
auto path_bounding_rect = params.path.bounding_box().translated(aa_translation);
|
||||
// Increase path bounding box by `thickness` to account for stroke.
|
||||
path_bounding_rect.inflate(params.thickness, params.thickness);
|
||||
if (path_bounding_rect.is_empty())
|
||||
auto path_bounding_int_rect = enclosing_int_rect(path_bounding_rect);
|
||||
if (path_bounding_int_rect.is_empty())
|
||||
return;
|
||||
append(StrokePathUsingPaintStyle {
|
||||
.cap_style = params.cap_style,
|
||||
|
@ -113,7 +117,7 @@ void DisplayListRecorder::stroke_path(StrokePathUsingPaintStyleParams params)
|
|||
.miter_limit = params.miter_limit,
|
||||
.dash_array = move(params.dash_array),
|
||||
.dash_offset = params.dash_offset,
|
||||
.path_bounding_rect = path_bounding_rect,
|
||||
.path_bounding_rect = path_bounding_int_rect,
|
||||
.path = move(params.path),
|
||||
.paint_style = params.paint_style,
|
||||
.thickness = params.thickness,
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
* { margin: 0; }
|
||||
body { background-color: white; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<img src="../images/svg-paths-cardinal-directions-less-than-1px-wide-ref.png">
|
||||
</body>
|
||||
</html>
|
Binary file not shown.
After Width: | Height: | Size: 200 B |
|
@ -0,0 +1,57 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<link rel="match" href="../expected/svg-paths-cardinal-directions-less-than-1px-wide-ref.html"/>
|
||||
<style>
|
||||
img, svg {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- horizontal between two pixels -->
|
||||
<svg viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M4 23.5h40v1h-40z" fill="currentColor"/>
|
||||
</svg>
|
||||
<svg viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M4 24h40" stroke="currentColor" stroke-width="1"/>
|
||||
</svg>
|
||||
<svg viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg">
|
||||
<line x1="4" y1="24" x2="44" y2="24" stroke="currentColor" stroke-width="1"/>
|
||||
</svg>
|
||||
<br>
|
||||
<!-- horizontal on a single pixel -->
|
||||
<svg viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M4 24h40v1h-40z" fill="currentColor"/>
|
||||
</svg>
|
||||
<svg viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M4 24.5h40" stroke="currentColor" stroke-width="1"/>
|
||||
</svg>
|
||||
<svg viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg">
|
||||
<line x1="4" y1="24.5" x2="44" y2="24.5" stroke="currentColor" stroke-width="1"/>
|
||||
</svg>
|
||||
<br>
|
||||
<!-- vertical between two pixels -->
|
||||
<svg viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M23.5 4v40h1v-40z" fill="currentColor"/>
|
||||
</svg>
|
||||
<svg viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M24 4v40" stroke="currentColor" stroke-width="1"/>
|
||||
</svg>
|
||||
<svg viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg">
|
||||
<line x1="24" y1="4" x2="24" y2="44" stroke="currentColor" stroke-width="1"/>
|
||||
</svg>
|
||||
<br>
|
||||
<!-- vertical on a single pixel -->
|
||||
<svg viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M24 4v40h1v-40z" fill="currentColor"/>
|
||||
</svg>
|
||||
<svg viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M24.5 4v40" stroke="currentColor" stroke-width="1"/>
|
||||
</svg>
|
||||
<svg viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg">
|
||||
<line x1="24.5" y1="4" x2="24.5" y2="44" stroke="currentColor" stroke-width="1"/>
|
||||
</svg>
|
||||
</body>
|
||||
</html>
|
Loading…
Add table
Reference in a new issue