LibWeb: Introduce struct to hold border radii and normalize once

The struct BorderRadiusData contains the four radii of the box.
In case the specified borders are too large for the dimensions of the
box, they get scaled down.
This commit is contained in:
Tobias Christiansen 2021-05-16 00:15:37 +02:00 committed by Andreas Kling
parent c31046d952
commit 7a566e54e5
Notes: sideshowbarker 2024-07-18 17:41:13 +09:00
2 changed files with 44 additions and 10 deletions

View file

@ -60,13 +60,13 @@ void Box::paint_border(PaintContext& context)
auto bordered_rect = this->bordered_rect(); auto bordered_rect = this->bordered_rect();
auto border_rect = enclosing_int_rect(bordered_rect); auto border_rect = enclosing_int_rect(bordered_rect);
// FIXME: Support elliptical border radii. auto border_radius_data = normalized_border_radius_data();
auto top_left_radius = border_radius_data.top_left;
auto top_right_radius = border_radius_data.top_right;
auto bottom_right_radius = border_radius_data.bottom_right;
auto bottom_left_radius = border_radius_data.bottom_left;
// FIXME: some values should be relative to the height() if specified, but which? For now, all relative values are relative to the width. // FIXME: Support elliptical border radii.
auto bottom_left_radius = computed_values().border_bottom_left_radius().resolved_or_zero(*this, width()).to_px(*this);
auto bottom_right_radius = computed_values().border_bottom_right_radius().resolved_or_zero(*this, width()).to_px(*this);
auto top_left_radius = computed_values().border_top_left_radius().resolved_or_zero(*this, width()).to_px(*this);
auto top_right_radius = computed_values().border_top_right_radius().resolved_or_zero(*this, width()).to_px(*this);
Gfx::FloatRect top_border_rect = { Gfx::FloatRect top_border_rect = {
border_rect.x() + top_left_radius, border_rect.x() + top_left_radius,
@ -202,10 +202,11 @@ void Box::paint_background(PaintContext& context)
} }
// FIXME: some values should be relative to the height() if specified, but which? For now, all relative values are relative to the width. // FIXME: some values should be relative to the height() if specified, but which? For now, all relative values are relative to the width.
auto bottom_left_radius = computed_values().border_bottom_left_radius().resolved_or_zero(*this, width()).to_px(*this); auto border_radius_data = normalized_border_radius_data();
auto bottom_right_radius = computed_values().border_bottom_right_radius().resolved_or_zero(*this, width()).to_px(*this); auto top_left_radius = border_radius_data.top_left;
auto top_left_radius = computed_values().border_top_left_radius().resolved_or_zero(*this, width()).to_px(*this); auto top_right_radius = border_radius_data.top_right;
auto top_right_radius = computed_values().border_top_right_radius().resolved_or_zero(*this, width()).to_px(*this); auto bottom_right_radius = border_radius_data.bottom_right;
auto bottom_left_radius = border_radius_data.bottom_left;
context.painter().fill_rect_with_rounded_corners(background_rect, move(background_color), top_left_radius, top_right_radius, bottom_right_radius, bottom_left_radius); context.painter().fill_rect_with_rounded_corners(background_rect, move(background_color), top_left_radius, top_right_radius, bottom_right_radius, bottom_left_radius);
@ -247,6 +248,29 @@ void Box::paint_background_image(
context.painter().blit_tiled(background_rect, background_image, background_image.rect()); context.painter().blit_tiled(background_rect, background_image, background_image.rect());
} }
Box::BorderRadiusData Box::normalized_border_radius_data()
{
// FIXME: some values should be relative to the height() if specified, but which? For now, all relative values are relative to the width.
auto bottom_left_radius = computed_values().border_bottom_left_radius().resolved_or_zero(*this, width()).to_px(*this);
auto bottom_right_radius = computed_values().border_bottom_right_radius().resolved_or_zero(*this, width()).to_px(*this);
auto top_left_radius = computed_values().border_top_left_radius().resolved_or_zero(*this, width()).to_px(*this);
auto top_right_radius = computed_values().border_top_right_radius().resolved_or_zero(*this, width()).to_px(*this);
// Scale overlapping curves according to https://www.w3.org/TR/css-backgrounds-3/#corner-overlap
auto f = 1.0f;
f = min(f, bordered_rect().width() / (float)(top_left_radius + top_right_radius));
f = min(f, bordered_rect().height() / (float)(top_right_radius + bottom_right_radius));
f = min(f, bordered_rect().width() / (float)(bottom_left_radius + bottom_right_radius));
f = min(f, bordered_rect().height() / (float)(top_left_radius + bottom_left_radius));
top_left_radius = (int)(top_left_radius * f);
top_right_radius = (int)(top_right_radius * f);
bottom_right_radius = (int)(bottom_right_radius * f);
bottom_left_radius = (int)(bottom_left_radius * f);
return { (int)top_left_radius, (int)top_right_radius, (int)bottom_right_radius, (int)bottom_left_radius };
}
HitTestResult Box::hit_test(const Gfx::IntPoint& position, HitTestType type) const HitTestResult Box::hit_test(const Gfx::IntPoint& position, HitTestType type) const
{ {
// FIXME: It would be nice if we could confidently skip over hit testing // FIXME: It would be nice if we could confidently skip over hit testing

View file

@ -121,6 +121,16 @@ public:
virtual float width_of_logical_containing_block() const; virtual float width_of_logical_containing_block() const;
struct BorderRadiusData {
// FIXME: Use floats here
int top_left { 0 };
int top_right { 0 };
int bottom_right { 0 };
int bottom_left { 0 };
};
BorderRadiusData normalized_border_radius_data();
protected: protected:
Box(DOM::Document& document, DOM::Node* node, NonnullRefPtr<CSS::StyleProperties> style) Box(DOM::Document& document, DOM::Node* node, NonnullRefPtr<CSS::StyleProperties> style)
: NodeWithStyleAndBoxModelMetrics(document, node, move(style)) : NodeWithStyleAndBoxModelMetrics(document, node, move(style))