1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 14:37:45 +00:00

LibWeb: Convert Paintable coordinates to new pixel units

This fixes a few sizing issues too. The page size is now correct in most
cases! \o/

We get to remove some of the `to_type<>()` shenanigans, though it
reappears in some other places.
This commit is contained in:
Sam Atkins 2022-10-31 19:46:55 +00:00 committed by Linus Groh
parent 57a69f15ff
commit ab49dbf137
39 changed files with 200 additions and 179 deletions

View file

@ -539,7 +539,7 @@ void BlockFormattingContext::layout_initial_containing_block(LayoutMode layout_m
if (bottom_edge >= viewport_rect.height() || right_edge >= viewport_rect.width()) {
// FIXME: Move overflow data to LayoutState!
auto& overflow_data = icb_state.ensure_overflow_data();
overflow_data.scrollable_overflow_rect = viewport_rect.to_type<float>();
overflow_data.scrollable_overflow_rect = viewport_rect.to_type<CSSPixels>();
// NOTE: The edges are *within* the rectangle, so we add 1 to get the width and height.
overflow_data.scrollable_overflow_rect.set_size(right_edge + 1, bottom_edge + 1);
}

View file

@ -1,6 +1,6 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2021, Sam Atkins <atkinssj@serenityos.org>
* Copyright (c) 2021-2022, Sam Atkins <atkinssj@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@ -31,8 +31,9 @@ Box::~Box()
void Box::set_needs_display()
{
// FIXME: Make `set_needs_display` take CSSPixels
if (paint_box())
browsing_context().set_needs_display(enclosing_int_rect(paint_box()->absolute_rect()));
browsing_context().set_needs_display(enclosing_int_rect(paint_box()->absolute_rect().to_type<float>()));
}
bool Box::is_body() const

View file

@ -919,7 +919,7 @@ Gfx::FloatPoint FormattingContext::calculate_static_position(Box const& box) con
}
}
if (last_fragment) {
y = last_fragment->offset().y() + last_fragment->height();
y = (last_fragment->offset().y() + last_fragment->height()).value();
}
} else {
// Easy case: no previous sibling, we're at the top of the containing block.

View file

@ -33,7 +33,8 @@ void FrameBox::did_set_rect()
ReplacedBox::did_set_rect();
VERIFY(dom_node().nested_browsing_context());
dom_node().nested_browsing_context()->set_size(paint_box()->content_size().to_type<int>());
// FIXME: Pass CSSPixels here instead of int.
dom_node().nested_browsing_context()->set_size(paint_box()->content_size().to_type<float>().to_type<int>());
}
RefPtr<Painting::Paintable> FrameBox::create_paintable() const

View file

@ -94,7 +94,7 @@ bool ImageBox::renders_as_alt_text() const
void ImageBox::browsing_context_did_set_viewport_rect(Gfx::IntRect const& viewport_rect)
{
m_image_loader.set_visible_in_viewport(paint_box() && viewport_rect.to_type<float>().intersects(paint_box()->absolute_rect()));
m_image_loader.set_visible_in_viewport(paint_box() && viewport_rect.to_type<CSSPixels>().intersects(paint_box()->absolute_rect()));
}
RefPtr<Painting::Paintable> ImageBox::create_paintable() const

View file

@ -49,7 +49,7 @@ void InitialContainingBlock::build_stacking_context_tree()
void InitialContainingBlock::paint_all_phases(PaintContext& context)
{
build_stacking_context_tree_if_needed();
context.painter().fill_rect(enclosing_int_rect(paint_box()->absolute_rect()), document().background_color(context.palette()));
context.painter().fill_rect(context.enclosing_device_rect(paint_box()->absolute_rect()).to_type<int>(), document().background_color(context.palette()));
context.painter().translate(-context.device_viewport_rect().location().to_type<int>());
paint_box()->stacking_context()->paint(context);
}

View file

@ -202,7 +202,7 @@ void InlineFormattingContext::apply_justification_to_fragments(CSS::TextJustify
for (auto& fragment : line_box.fragments()) {
if (fragment.is_justifiable_whitespace()) {
++whitespace_count;
excess_horizontal_space_including_whitespace += fragment.width();
excess_horizontal_space_including_whitespace += fragment.width().value();
}
}
@ -221,7 +221,7 @@ void InlineFormattingContext::apply_justification_to_fragments(CSS::TextJustify
if (fragment.is_justifiable_whitespace()
&& fragment.width() != justified_space_width) {
running_diff += justified_space_width - fragment.width();
running_diff += justified_space_width - fragment.width().value();
fragment.set_width(justified_space_width);
}
}

View file

@ -39,8 +39,8 @@ void Label::handle_mouseup_on_label(Badge<Painting::TextPaintable>, CSSPixelPoin
return;
if (auto* control = labeled_control(); control) {
bool is_inside_control = enclosing_int_rect(control->paint_box()->absolute_rect()).to_type<CSSPixels>().contains(position);
bool is_inside_label = enclosing_int_rect(paint_box()->absolute_rect()).to_type<CSSPixels>().contains(position);
bool is_inside_control = control->paint_box()->absolute_rect().contains(position);
bool is_inside_label = paint_box()->absolute_rect().contains(position);
if (is_inside_control || is_inside_label)
control->paintable()->handle_associated_label_mouseup({});
@ -55,8 +55,8 @@ void Label::handle_mousemove_on_label(Badge<Painting::TextPaintable>, CSSPixelPo
return;
if (auto* control = labeled_control(); control) {
bool is_inside_control = enclosing_int_rect(control->paint_box()->absolute_rect()).to_type<CSSPixels>().contains(position);
bool is_inside_label = enclosing_int_rect(paint_box()->absolute_rect()).to_type<CSSPixels>().contains(position);
bool is_inside_control = control->paint_box()->absolute_rect().contains(position);
bool is_inside_label = paint_box()->absolute_rect().contains(position);
control->paintable()->handle_associated_label_mousemove({}, is_inside_control || is_inside_label);
}
@ -65,7 +65,7 @@ void Label::handle_mousemove_on_label(Badge<Painting::TextPaintable>, CSSPixelPo
bool Label::is_inside_associated_label(LabelableNode const& control, CSSPixelPoint position)
{
if (auto* label = label_for_control_node(control); label)
return enclosing_int_rect(label->paint_box()->absolute_rect()).to_type<CSSPixels>().contains(position);
return label->paint_box()->absolute_rect().contains(position);
return false;
}

View file

@ -76,7 +76,7 @@ void LayoutState::commit()
if (is<Layout::Box>(node)) {
auto& box = static_cast<Layout::Box const&>(node);
auto& paint_box = const_cast<Painting::PaintableBox&>(*box.paint_box());
paint_box.set_offset(used_values.offset);
paint_box.set_offset(used_values.offset.to_type<CSSPixels>());
paint_box.set_content_size(used_values.content_width(), used_values.content_height());
paint_box.set_overflow_data(move(used_values.overflow_data));
paint_box.set_containing_line_box_fragment(used_values.containing_line_box_fragment);

View file

@ -26,7 +26,7 @@ void LineBox::add_fragment(Node const& layout_node, int start, int length, float
} else {
float x_offset = leading_margin + leading_size + m_width;
float y_offset = 0.0f;
m_fragments.append(LineBoxFragment { layout_node, start, length, Gfx::FloatPoint(x_offset, y_offset), Gfx::FloatSize(content_width, content_height), border_box_top, border_box_bottom, fragment_type });
m_fragments.append(LineBoxFragment { layout_node, start, length, CSSPixelPoint(x_offset, y_offset), CSSPixelSize(content_width, content_height), border_box_top, border_box_bottom, fragment_type });
}
m_width += leading_margin + leading_size + content_width + trailing_size + trailing_margin;
}
@ -35,7 +35,7 @@ void LineBox::trim_trailing_whitespace()
{
while (!m_fragments.is_empty() && m_fragments.last().is_justifiable_whitespace()) {
auto fragment = m_fragments.take_last();
m_width -= fragment.width();
m_width -= fragment.width().value();
}
if (m_fragments.is_empty())

View file

@ -33,15 +33,15 @@ StringView LineBoxFragment::text() const
return verify_cast<TextNode>(layout_node()).text_for_rendering().substring_view(m_start, m_length);
}
const Gfx::FloatRect LineBoxFragment::absolute_rect() const
CSSPixelRect const LineBoxFragment::absolute_rect() const
{
Gfx::FloatRect rect { {}, size() };
CSSPixelRect rect { {}, size() };
rect.set_location(m_layout_node.containing_block()->paint_box()->absolute_position());
rect.translate_by(offset());
return rect;
}
int LineBoxFragment::text_index_at(float x) const
int LineBoxFragment::text_index_at(CSSPixels x) const
{
if (!is<TextNode>(layout_node()))
return 0;
@ -49,15 +49,15 @@ int LineBoxFragment::text_index_at(float x) const
auto& font = layout_text.font();
Utf8View view(text());
float relative_x = x - absolute_x();
CSSPixels relative_x = x - absolute_x();
float glyph_spacing = font.glyph_spacing();
if (relative_x < 0)
return 0;
float width_so_far = 0;
CSSPixels width_so_far = 0;
for (auto it = view.begin(); it != view.end(); ++it) {
float glyph_width = font.glyph_or_emoji_width(*it);
CSSPixels glyph_width = font.glyph_or_emoji_width(*it);
if ((width_so_far + (glyph_width + glyph_spacing) / 2) > relative_x)
return m_start + view.byte_offset_of(it);
width_so_far += glyph_width + glyph_spacing;
@ -65,7 +65,7 @@ int LineBoxFragment::text_index_at(float x) const
return m_start + m_length;
}
Gfx::FloatRect LineBoxFragment::selection_rect(Gfx::Font const& font) const
CSSPixelRect LineBoxFragment::selection_rect(Gfx::Font const& font) const
{
if (layout_node().selection_state() == Node::SelectionState::None)
return {};

View file

@ -6,9 +6,9 @@
#pragma once
#include <LibGfx/Forward.h>
#include <LibGfx/Rect.h>
#include <LibWeb/Forward.h>
#include <LibWeb/PixelUnits.h>
namespace Web::Layout {
@ -22,7 +22,7 @@ public:
Trailing,
};
LineBoxFragment(Node const& layout_node, int start, int length, Gfx::FloatPoint offset, Gfx::FloatSize size, float border_box_top, float border_box_bottom, Type type)
LineBoxFragment(Node const& layout_node, int start, int length, CSSPixelPoint offset, CSSPixelSize size, CSSPixels border_box_top, CSSPixels border_box_bottom, Type type)
: m_layout_node(layout_node)
, m_start(start)
, m_length(length)
@ -37,45 +37,54 @@ public:
Node const& layout_node() const { return m_layout_node; }
int start() const { return m_start; }
int length() const { return m_length; }
const Gfx::FloatRect absolute_rect() const;
CSSPixelRect const absolute_rect() const;
Type type() const { return m_type; }
Gfx::FloatPoint offset() const { return m_offset; }
void set_offset(Gfx::FloatPoint offset) { m_offset = offset; }
CSSPixelPoint offset() const
{
return m_offset;
}
void set_offset(CSSPixelPoint offset) { m_offset = offset; }
// The baseline of a fragment is the number of pixels from the top to the text baseline.
void set_baseline(float y) { m_baseline = y; }
float baseline() const { return m_baseline; }
void set_baseline(CSSPixels y) { m_baseline = y; }
CSSPixels baseline() const { return m_baseline; }
Gfx::FloatSize size() const { return m_size; }
void set_width(float width) { m_size.set_width(width); }
void set_height(float height) { m_size.set_height(height); }
float width() const { return m_size.width(); }
float height() const { return m_size.height(); }
CSSPixelSize size() const
{
return m_size;
}
void set_width(CSSPixels width) { m_size.set_width(width); }
void set_height(CSSPixels height) { m_size.set_height(height); }
CSSPixels width() const { return m_size.width(); }
CSSPixels height() const { return m_size.height(); }
float border_box_height() const { return m_border_box_top + height() + m_border_box_bottom; }
float border_box_top() const { return m_border_box_top; }
float border_box_bottom() const { return m_border_box_bottom; }
CSSPixels border_box_height() const
{
return m_border_box_top + height() + m_border_box_bottom;
}
CSSPixels border_box_top() const { return m_border_box_top; }
CSSPixels border_box_bottom() const { return m_border_box_bottom; }
float absolute_x() const { return absolute_rect().x(); }
CSSPixels absolute_x() const { return absolute_rect().x(); }
bool ends_in_whitespace() const;
bool is_justifiable_whitespace() const;
StringView text() const;
int text_index_at(float x) const;
int text_index_at(CSSPixels x) const;
Gfx::FloatRect selection_rect(Gfx::Font const&) const;
CSSPixelRect selection_rect(Gfx::Font const&) const;
private:
Node const& m_layout_node;
int m_start { 0 };
int m_length { 0 };
Gfx::FloatPoint m_offset;
Gfx::FloatSize m_size;
float m_border_box_top { 0 };
float m_border_box_bottom { 0 };
float m_baseline { 0 };
CSSPixelPoint m_offset;
CSSPixelSize m_size;
CSSPixels m_border_box_top { 0 };
CSSPixels m_border_box_bottom { 0 };
CSSPixels m_baseline { 0 };
Type m_type { Type::Normal };
};

View file

@ -227,15 +227,15 @@ void LineBuilder::update_last_line()
for (size_t i = 0; i < line_box.fragments().size(); ++i) {
auto& fragment = line_box.fragments()[i];
float new_fragment_x = roundf(x_offset + fragment.offset().x());
float new_fragment_x = roundf(x_offset + fragment.offset().x().value());
float new_fragment_y = 0;
auto y_value_for_alignment = [&](CSS::VerticalAlign vertical_align) {
switch (vertical_align) {
case CSS::VerticalAlign::Baseline:
return m_current_y + line_box_baseline - fragment.baseline() + fragment.border_box_top();
return m_current_y + line_box_baseline - fragment.baseline().value() + fragment.border_box_top().value();
case CSS::VerticalAlign::Top:
return m_current_y + fragment.border_box_top();
return m_current_y + fragment.border_box_top().value();
case CSS::VerticalAlign::Middle:
case CSS::VerticalAlign::Bottom:
case CSS::VerticalAlign::Sub:
@ -243,7 +243,7 @@ void LineBuilder::update_last_line()
case CSS::VerticalAlign::TextBottom:
case CSS::VerticalAlign::TextTop:
// FIXME: These are all 'baseline'
return m_current_y + line_box_baseline - fragment.baseline() + fragment.border_box_top();
return m_current_y + line_box_baseline - fragment.baseline().value() + fragment.border_box_top().value();
}
VERIFY_NOT_REACHED();
};
@ -266,15 +266,15 @@ void LineBuilder::update_last_line()
// FIXME: Support inline-table elements.
if (fragment.layout_node().is_replaced_box() || (fragment.layout_node().display().is_inline_outside() && !fragment.layout_node().display().is_flow_inside())) {
auto const& fragment_box_state = m_layout_state.get(static_cast<Box const&>(fragment.layout_node()));
top_of_inline_box = fragment.offset().y() - fragment_box_state.margin_box_top();
bottom_of_inline_box = fragment.offset().y() + fragment_box_state.content_height() + fragment_box_state.margin_box_bottom();
top_of_inline_box = (fragment.offset().y() - fragment_box_state.margin_box_top()).value();
bottom_of_inline_box = (fragment.offset().y() + fragment_box_state.content_height() + fragment_box_state.margin_box_bottom()).value();
} else {
auto font_metrics = fragment.layout_node().font().pixel_metrics();
auto typographic_height = font_metrics.ascent + font_metrics.descent;
auto leading = fragment.layout_node().line_height() - typographic_height;
auto half_leading = leading / 2;
top_of_inline_box = fragment.offset().y() + fragment.baseline() - font_metrics.ascent - half_leading;
bottom_of_inline_box = fragment.offset().y() + fragment.baseline() + font_metrics.descent + half_leading;
top_of_inline_box = (fragment.offset().y() + fragment.baseline() - font_metrics.ascent - half_leading).value();
bottom_of_inline_box = (fragment.offset().y() + fragment.baseline() + font_metrics.descent + half_leading).value();
}
if (auto length_percentage = fragment.layout_node().computed_values().vertical_align().template get_pointer<CSS::LengthPercentage>(); length_percentage && length_percentage->is_length())
bottom_of_inline_box += length_percentage->length().to_px(fragment.layout_node());

View file

@ -158,7 +158,7 @@ void Node::set_needs_display()
return;
containing_block->paint_box()->for_each_fragment([&](auto& fragment) {
if (&fragment.layout_node() == this || is_ancestor_of(fragment.layout_node())) {
browsing_context().set_needs_display(enclosing_int_rect(fragment.absolute_rect()));
browsing_context().set_needs_display(fragment.absolute_rect().template to_type<float>().template to_type<int>());
}
return IterationDecision::Continue;
});
@ -167,13 +167,13 @@ void Node::set_needs_display()
Gfx::FloatPoint Node::box_type_agnostic_position() const
{
if (is<Box>(*this))
return verify_cast<Box>(*this).paint_box()->absolute_position();
return verify_cast<Box>(*this).paint_box()->absolute_position().to_type<float>();
VERIFY(is_inline());
Gfx::FloatPoint position;
if (auto* block = containing_block()) {
block->paint_box()->for_each_fragment([&](auto& fragment) {
if (&fragment.layout_node() == this || is_ancestor_of(fragment.layout_node())) {
position = fragment.absolute_rect().location();
position = fragment.absolute_rect().location().template to_type<float>();
return IterationDecision::Break;
}
return IterationDecision::Continue;

View file

@ -27,10 +27,10 @@ float SVGGeometryBox::viewbox_scaling() const
auto view_box = svg_box->view_box().value();
bool has_specified_width = svg_box->has_attribute(HTML::AttributeNames::width);
auto specified_width = paint_box()->content_width();
auto specified_width = paint_box()->content_width().value();
bool has_specified_height = svg_box->has_attribute(HTML::AttributeNames::height);
auto specified_height = paint_box()->content_height();
auto specified_height = paint_box()->content_height().value();
auto scale_width = has_specified_width ? specified_width / view_box.width : 1;
auto scale_height = has_specified_height ? specified_height / view_box.height : 1;