mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-09-21 02:08:12 +03:00
LibWeb: Use rounding instead of enclosing_int_rect() when painting
By using enclosing_int_rect(), borders and backgrounds of boxes were sometimes 1 pixel off, making things slightly larger than they should be. Fix this by using to_rounded() instead of enclosing_int_rect(). There's definitely more of these type of issues lurking in the code, and we'll get to them in time.
This commit is contained in:
parent
e1cf51b0bd
commit
0de488749f
Notes:
sideshowbarker
2024-07-17 16:34:26 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/0de488749f
@ -14,7 +14,7 @@
|
|||||||
namespace Web::Painting {
|
namespace Web::Painting {
|
||||||
|
|
||||||
// https://www.w3.org/TR/css-backgrounds-3/#backgrounds
|
// https://www.w3.org/TR/css-backgrounds-3/#backgrounds
|
||||||
void paint_background(PaintContext& context, Layout::NodeWithStyleAndBoxModelMetrics const& layout_node, Gfx::IntRect const& border_rect, Color background_color, Vector<CSS::BackgroundLayerData> const* background_layers, BorderRadiusData const& border_radius)
|
void paint_background(PaintContext& context, Layout::NodeWithStyleAndBoxModelMetrics const& layout_node, Gfx::FloatRect const& border_rect, Color background_color, Vector<CSS::BackgroundLayerData> const* background_layers, BorderRadiusData const& border_radius)
|
||||||
{
|
{
|
||||||
auto& painter = context.painter();
|
auto& painter = context.painter();
|
||||||
|
|
||||||
@ -41,7 +41,7 @@ void paint_background(PaintContext& context, Layout::NodeWithStyleAndBoxModelMet
|
|||||||
if (background_layers && !background_layers->is_empty())
|
if (background_layers && !background_layers->is_empty())
|
||||||
color_rect = get_box(background_layers->last().clip);
|
color_rect = get_box(background_layers->last().clip);
|
||||||
// FIXME: Support elliptical corners
|
// FIXME: Support elliptical corners
|
||||||
painter.fill_rect_with_rounded_corners(color_rect, background_color, border_radius.top_left, border_radius.top_right, border_radius.bottom_right, border_radius.bottom_left);
|
painter.fill_rect_with_rounded_corners(color_rect.to_rounded<int>(), background_color, border_radius.top_left, border_radius.top_right, border_radius.bottom_right, border_radius.bottom_left);
|
||||||
|
|
||||||
if (!background_layers)
|
if (!background_layers)
|
||||||
return;
|
return;
|
||||||
@ -57,14 +57,14 @@ void paint_background(PaintContext& context, Layout::NodeWithStyleAndBoxModelMet
|
|||||||
// Clip
|
// Clip
|
||||||
auto clip_rect = get_box(layer.clip);
|
auto clip_rect = get_box(layer.clip);
|
||||||
painter.save();
|
painter.save();
|
||||||
painter.add_clip_rect(clip_rect);
|
painter.add_clip_rect(clip_rect.to_rounded<int>());
|
||||||
|
|
||||||
Gfx::IntRect background_positioning_area;
|
Gfx::FloatRect background_positioning_area;
|
||||||
|
|
||||||
// Attachment and Origin
|
// Attachment and Origin
|
||||||
switch (layer.attachment) {
|
switch (layer.attachment) {
|
||||||
case CSS::BackgroundAttachment::Fixed:
|
case CSS::BackgroundAttachment::Fixed:
|
||||||
background_positioning_area = layout_node.root().browsing_context().viewport_rect();
|
background_positioning_area = layout_node.root().browsing_context().viewport_rect().to_type<float>();
|
||||||
break;
|
break;
|
||||||
case CSS::BackgroundAttachment::Local:
|
case CSS::BackgroundAttachment::Local:
|
||||||
case CSS::BackgroundAttachment::Scroll:
|
case CSS::BackgroundAttachment::Scroll:
|
||||||
@ -76,15 +76,15 @@ void paint_background(PaintContext& context, Layout::NodeWithStyleAndBoxModelMet
|
|||||||
Gfx::IntRect image_rect;
|
Gfx::IntRect image_rect;
|
||||||
switch (layer.size_type) {
|
switch (layer.size_type) {
|
||||||
case CSS::BackgroundSize::Contain: {
|
case CSS::BackgroundSize::Contain: {
|
||||||
float max_width_ratio = (float)background_positioning_area.width() / (float)image.width();
|
float max_width_ratio = background_positioning_area.width() / image.width();
|
||||||
float max_height_ratio = (float)background_positioning_area.height() / (float)image.height();
|
float max_height_ratio = background_positioning_area.height() / image.height();
|
||||||
float ratio = min(max_width_ratio, max_height_ratio);
|
float ratio = min(max_width_ratio, max_height_ratio);
|
||||||
image_rect.set_size(roundf(image.width() * ratio), roundf(image.height() * ratio));
|
image_rect.set_size(roundf(image.width() * ratio), roundf(image.height() * ratio));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CSS::BackgroundSize::Cover: {
|
case CSS::BackgroundSize::Cover: {
|
||||||
float max_width_ratio = (float)background_positioning_area.width() / (float)image.width();
|
float max_width_ratio = background_positioning_area.width() / image.width();
|
||||||
float max_height_ratio = (float)background_positioning_area.height() / (float)image.height();
|
float max_height_ratio = background_positioning_area.height() / image.height();
|
||||||
float ratio = max(max_width_ratio, max_height_ratio);
|
float ratio = max(max_width_ratio, max_height_ratio);
|
||||||
image_rect.set_size(roundf(image.width() * ratio), roundf(image.height() * ratio));
|
image_rect.set_size(roundf(image.width() * ratio), roundf(image.height() * ratio));
|
||||||
break;
|
break;
|
||||||
@ -176,7 +176,7 @@ void paint_background(PaintContext& context, Layout::NodeWithStyleAndBoxModelMet
|
|||||||
x_step = image_rect.width();
|
x_step = image_rect.width();
|
||||||
repeat_x = false;
|
repeat_x = false;
|
||||||
} else {
|
} else {
|
||||||
int space = background_positioning_area.width() % image_rect.width();
|
float space = fmodf(background_positioning_area.width(), image_rect.width());
|
||||||
x_step = image_rect.width() + ((float)space / (float)(whole_images - 1));
|
x_step = image_rect.width() + ((float)space / (float)(whole_images - 1));
|
||||||
repeat_x = true;
|
repeat_x = true;
|
||||||
}
|
}
|
||||||
@ -207,7 +207,7 @@ void paint_background(PaintContext& context, Layout::NodeWithStyleAndBoxModelMet
|
|||||||
y_step = image_rect.height();
|
y_step = image_rect.height();
|
||||||
repeat_y = false;
|
repeat_y = false;
|
||||||
} else {
|
} else {
|
||||||
int space = background_positioning_area.height() % image_rect.height();
|
float space = fmodf(background_positioning_area.height(), image_rect.height());
|
||||||
y_step = image_rect.height() + ((float)space / (float)(whole_images - 1));
|
y_step = image_rect.height() + ((float)space / (float)(whole_images - 1));
|
||||||
repeat_y = true;
|
repeat_y = true;
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,6 @@
|
|||||||
|
|
||||||
namespace Web::Painting {
|
namespace Web::Painting {
|
||||||
|
|
||||||
void paint_background(PaintContext&, Layout::NodeWithStyleAndBoxModelMetrics const&, Gfx::IntRect const&, Color background_color, Vector<CSS::BackgroundLayerData> const*, BorderRadiusData const&);
|
void paint_background(PaintContext&, Layout::NodeWithStyleAndBoxModelMetrics const&, Gfx::FloatRect const&, Color background_color, Vector<CSS::BackgroundLayerData> const*, BorderRadiusData const&);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -43,9 +43,7 @@ BorderRadiusData normalized_border_radius_data(Layout::Node const& node, Gfx::Fl
|
|||||||
|
|
||||||
void paint_border(PaintContext& context, BorderEdge edge, Gfx::FloatRect const& a_rect, BorderRadiusData const& border_radius_data, BordersData const& borders_data)
|
void paint_border(PaintContext& context, BorderEdge edge, Gfx::FloatRect const& a_rect, BorderRadiusData const& border_radius_data, BordersData const& borders_data)
|
||||||
{
|
{
|
||||||
// FIXME: This is a hack that snaps the incoming rect to integer pixel values before painting each side.
|
auto rect = a_rect.to_rounded<float>();
|
||||||
// This needs a more general solution.
|
|
||||||
auto rect = enclosing_int_rect(a_rect).to_type<float>();
|
|
||||||
|
|
||||||
const auto& border_data = [&] {
|
const auto& border_data = [&] {
|
||||||
switch (edge) {
|
switch (edge) {
|
||||||
|
@ -55,7 +55,7 @@ void InlinePaintable::paint(PaintContext& context, Painting::PaintPhase phase) c
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto border_radius_data = Painting::normalized_border_radius_data(layout_node(), absolute_fragment_rect, top_left_border_radius, top_right_border_radius, bottom_right_border_radius, bottom_left_border_radius);
|
auto border_radius_data = Painting::normalized_border_radius_data(layout_node(), absolute_fragment_rect, top_left_border_radius, top_right_border_radius, bottom_right_border_radius, bottom_left_border_radius);
|
||||||
Painting::paint_background(context, layout_node(), enclosing_int_rect(absolute_fragment_rect), computed_values().background_color(), &computed_values().background_layers(), border_radius_data);
|
Painting::paint_background(context, layout_node(), absolute_fragment_rect, computed_values().background_color(), &computed_values().background_layers(), border_radius_data);
|
||||||
|
|
||||||
if (auto computed_box_shadow = computed_values().box_shadow(); !computed_box_shadow.is_empty()) {
|
if (auto computed_box_shadow = computed_values().box_shadow(); !computed_box_shadow.is_empty()) {
|
||||||
Vector<Painting::ShadowData> resolved_box_shadow_data;
|
Vector<Painting::ShadowData> resolved_box_shadow_data;
|
||||||
|
@ -184,13 +184,13 @@ void PaintableBox::paint_background(PaintContext& context) const
|
|||||||
if (layout_box().is_body() && document().html_element()->should_use_body_background_properties())
|
if (layout_box().is_body() && document().html_element()->should_use_body_background_properties())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Gfx::IntRect background_rect;
|
Gfx::FloatRect background_rect;
|
||||||
Color background_color = computed_values().background_color();
|
Color background_color = computed_values().background_color();
|
||||||
auto* background_layers = &computed_values().background_layers();
|
auto* background_layers = &computed_values().background_layers();
|
||||||
|
|
||||||
if (layout_box().is_root_element()) {
|
if (layout_box().is_root_element()) {
|
||||||
// CSS 2.1 Appendix E.2: If the element is a root element, paint the background over the entire canvas.
|
// CSS 2.1 Appendix E.2: If the element is a root element, paint the background over the entire canvas.
|
||||||
background_rect = context.viewport_rect();
|
background_rect = context.viewport_rect().to_type<float>();
|
||||||
|
|
||||||
// Section 2.11.2: If the computed value of background-image on the root element is none and its background-color is transparent,
|
// Section 2.11.2: If the computed value of background-image on the root element is none and its background-color is transparent,
|
||||||
// user agents must instead propagate the computed values of the background properties from that element’s first HTML BODY child element.
|
// user agents must instead propagate the computed values of the background properties from that element’s first HTML BODY child element.
|
||||||
@ -199,13 +199,13 @@ void PaintableBox::paint_background(PaintContext& context) const
|
|||||||
background_color = document().background_color(context.palette());
|
background_color = document().background_color(context.palette());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
background_rect = enclosing_int_rect(absolute_padding_box_rect());
|
background_rect = absolute_padding_box_rect();
|
||||||
}
|
}
|
||||||
|
|
||||||
// HACK: If the Box has a border, use the bordered_rect to paint the background.
|
// HACK: If the Box has a border, use the bordered_rect to paint the background.
|
||||||
// This way if we have a border-radius there will be no gap between the filling and actual border.
|
// This way if we have a border-radius there will be no gap between the filling and actual border.
|
||||||
if (computed_values().border_top().width || computed_values().border_right().width || computed_values().border_bottom().width || computed_values().border_left().width)
|
if (computed_values().border_top().width || computed_values().border_right().width || computed_values().border_bottom().width || computed_values().border_left().width)
|
||||||
background_rect = enclosing_int_rect(absolute_border_box_rect());
|
background_rect = absolute_border_box_rect();
|
||||||
|
|
||||||
Painting::paint_background(context, layout_box(), background_rect, background_color, background_layers, normalized_border_radius_data());
|
Painting::paint_background(context, layout_box(), background_rect, background_color, background_layers, normalized_border_radius_data());
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user