diff options
21 files changed, 185 insertions, 121 deletions
diff --git a/Libraries/LibWeb/Dump.cpp b/Libraries/LibWeb/Dump.cpp index 7d8f3733e8..77c3acc95b 100644 --- a/Libraries/LibWeb/Dump.cpp +++ b/Libraries/LibWeb/Dump.cpp @@ -110,8 +110,8 @@ void dump_tree(const LayoutNode& layout_node) layout_box.class_name(), tag_name.characters(), identifier.characters(), - layout_box.x(), - layout_box.y(), + layout_box.absolute_x(), + layout_box.absolute_y(), layout_box.width(), layout_box.height()); @@ -158,7 +158,7 @@ void dump_tree(const LayoutNode& layout_node) &fragment.layout_node(), fragment.start(), fragment.length(), - fragment.rect().to_string().characters()); + fragment.absolute_rect().to_string().characters()); if (fragment.layout_node().is_text()) { for (size_t i = 0; i < indent; ++i) dbgprintf(" "); diff --git a/Libraries/LibWeb/Forward.h b/Libraries/LibWeb/Forward.h index 7c9d0f0a81..d3f7b19cf1 100644 --- a/Libraries/LibWeb/Forward.h +++ b/Libraries/LibWeb/Forward.h @@ -47,6 +47,8 @@ class HTMLImageElement; class HTMLScriptElement; class PageView; class ImageData; +class LineBox; +class LineBoxFragment; class LayoutBlock; class LayoutDocument; class LayoutNode; @@ -57,6 +59,7 @@ class Node; class Origin; class Page; class PageClient; +class RenderingContext; class Resource; class ResourceLoader; class Selector; diff --git a/Libraries/LibWeb/Layout/LayoutBlock.cpp b/Libraries/LibWeb/Layout/LayoutBlock.cpp index e6422ef685..6b4816d74f 100644 --- a/Libraries/LibWeb/Layout/LayoutBlock.cpp +++ b/Libraries/LibWeb/Layout/LayoutBlock.cpp @@ -86,7 +86,7 @@ void LayoutBlock::layout_block_children(LayoutMode layout_mode) child_block.layout(layout_mode); if (!child_block.is_absolutely_positioned()) - content_height = child_block.rect().bottom() + child_block.box_model().full_margin(*this).bottom - rect().top(); + content_height = max(content_height, child_block.effective_offset().y() + child_block.height() + child_block.box_model().full_margin(*this).bottom); }); if (layout_mode != LayoutMode::Default) { float max_width = 0; @@ -94,9 +94,9 @@ void LayoutBlock::layout_block_children(LayoutMode layout_mode) if (child.is_box() && !child.is_absolutely_positioned()) max_width = max(max_width, to<LayoutBox>(child).width()); }); - rect().set_width(max_width); + set_width(max_width); } - rect().set_height(content_height); + set_height(content_height); } void LayoutBlock::layout_inline_children(LayoutMode layout_mode) @@ -133,10 +133,10 @@ void LayoutBlock::layout_inline_children(LayoutMode layout_mode) for (auto& line_box : m_line_boxes) { float max_height = min_line_height; for (auto& fragment : line_box.fragments()) { - max_height = max(max_height, fragment.rect().height()); + max_height = max(max_height, fragment.height()); } - float x_offset = x(); + float x_offset = 0; float excess_horizontal_space = (float)width() - line_box.width(); switch (text_align) { @@ -158,7 +158,7 @@ void LayoutBlock::layout_inline_children(LayoutMode layout_mode) for (auto& fragment : line_box.fragments()) { if (fragment.is_justifiable_whitespace()) { ++whitespace_count; - excess_horizontal_space_including_whitespace += fragment.rect().width(); + excess_horizontal_space_including_whitespace += fragment.width(); } } } @@ -173,34 +173,32 @@ void LayoutBlock::layout_inline_children(LayoutMode layout_mode) // Vertically align everyone's bottom to the line. // FIXME: Support other kinds of vertical alignment. - fragment.rect().set_x(roundf(x_offset + fragment.rect().x())); - fragment.rect().set_y(y() + content_height + (max_height - fragment.rect().height()) - (line_spacing / 2)); + fragment.set_offset({ roundf(x_offset + fragment.offset().x()), content_height + (max_height - fragment.height()) - (line_spacing / 2) }); if (text_align == CSS::ValueID::Justify) { if (fragment.is_justifiable_whitespace()) { - if (fragment.rect().width() != justified_space_width) { - float diff = justified_space_width - fragment.rect().width(); - fragment.rect().set_width(justified_space_width); + if (fragment.width() != justified_space_width) { + float diff = justified_space_width - fragment.width(); + fragment.set_width(justified_space_width); // Shift subsequent sibling fragments to the right to adjust for change in width. for (size_t j = i + 1; j < line_box.fragments().size(); ++j) { - line_box.fragments()[j].rect().move_by(diff, 0); + auto offset = line_box.fragments()[j].offset(); + offset.move_by(diff, 0); + line_box.fragments()[j].set_offset(offset); } } } } - if (is<LayoutReplaced>(fragment.layout_node())) - const_cast<LayoutReplaced&>(to<LayoutReplaced>(fragment.layout_node())).set_rect(fragment.rect()); - if (fragment.layout_node().is_inline_block()) { auto& inline_block = const_cast<LayoutBlock&>(to<LayoutBlock>(fragment.layout_node())); - inline_block.set_rect(fragment.rect()); + inline_block.set_size(fragment.size()); inline_block.layout(layout_mode); } float final_line_box_width = 0; for (auto& fragment : line_box.fragments()) - final_line_box_width += fragment.rect().width(); + final_line_box_width += fragment.width(); line_box.m_width = final_line_box_width; max_linebox_width = max(max_linebox_width, final_line_box_width); @@ -210,10 +208,10 @@ void LayoutBlock::layout_inline_children(LayoutMode layout_mode) } if (layout_mode != LayoutMode::Default) { - rect().set_width(max_linebox_width); + set_width(max_linebox_width); } - rect().set_height(content_height); + set_height(content_height); } void LayoutBlock::compute_width() @@ -368,7 +366,7 @@ void LayoutBlock::compute_width() } } - rect().set_width(used_width.to_px(*this)); + set_width(used_width.to_px(*this)); box_model().margin().left = margin_left; box_model().margin().right = margin_right; box_model().border().left = border_left; @@ -404,11 +402,6 @@ void LayoutBlock::compute_position() + box_model().padding().left.to_px(*this) + box_model().offset().left.to_px(*this); - if (style.position() != CSS::Position::Absolute || containing_block.style().position() == CSS::Position::Absolute) - position_x += containing_block.x(); - - rect().set_x(position_x); - float position_y = box_model().full_margin(*this).top + box_model().offset().top.to_px(*this); @@ -420,17 +413,14 @@ void LayoutBlock::compute_position() relevant_sibling = relevant_sibling->previous_sibling(); } - if (relevant_sibling == nullptr) { - position_y += containing_block.y(); - } else { - auto& previous_sibling_rect = relevant_sibling->rect(); + if (relevant_sibling) { auto& previous_sibling_style = relevant_sibling->box_model(); - position_y += previous_sibling_rect.y() + previous_sibling_rect.height(); + position_y += relevant_sibling->effective_offset().y() + relevant_sibling->height(); position_y += previous_sibling_style.full_margin(*this).bottom; } } - rect().set_y(position_y); + set_offset({ position_x, position_y }); } void LayoutBlock::compute_height() @@ -438,7 +428,7 @@ void LayoutBlock::compute_height() auto& style = this->style(); auto height = style.length_or_fallback(CSS::PropertyID::Height, Length(), containing_block()->height()); if (height.is_absolute()) - rect().set_height(height.to_px(*this)); + set_height(height.to_px(*this)); } void LayoutBlock::render(RenderingContext& context) @@ -452,7 +442,7 @@ void LayoutBlock::render(RenderingContext& context) for (auto& line_box : m_line_boxes) { for (auto& fragment : line_box.fragments()) { if (context.should_show_line_box_borders()) - context.painter().draw_rect(enclosing_int_rect(fragment.rect()), Color::Green); + context.painter().draw_rect(enclosing_int_rect(fragment.absolute_rect()), Color::Green); fragment.render(context); } } @@ -467,7 +457,7 @@ HitTestResult LayoutBlock::hit_test(const Gfx::Point& position) const HitTestResult result; for (auto& line_box : m_line_boxes) { for (auto& fragment : line_box.fragments()) { - if (enclosing_int_rect(fragment.rect()).contains(position)) { + if (enclosing_int_rect(fragment.absolute_rect()).contains(position)) { if (fragment.layout_node().is_block()) return to<LayoutBlock>(fragment.layout_node()).hit_test(position); return { fragment.layout_node(), fragment.text_index_at(position.x()) }; @@ -477,7 +467,7 @@ HitTestResult LayoutBlock::hit_test(const Gfx::Point& position) const // FIXME: This should be smarter about the text position if we're hitting a block // that has text inside it, but `position` is to the right of the text box. - return { rect().contains(position.x(), position.y()) ? this : nullptr }; + return { absolute_rect().contains(position.x(), position.y()) ? this : nullptr }; } NonnullRefPtr<StyleProperties> LayoutBlock::style_for_anonymous_block() const diff --git a/Libraries/LibWeb/Layout/LayoutBox.cpp b/Libraries/LibWeb/Layout/LayoutBox.cpp index 5aaefa3fee..dc0e513818 100644 --- a/Libraries/LibWeb/Layout/LayoutBox.cpp +++ b/Libraries/LibWeb/Layout/LayoutBox.cpp @@ -203,9 +203,9 @@ void LayoutBox::render(RenderingContext& context) #endif Gfx::FloatRect padded_rect; - padded_rect.set_x(x() - box_model().padding().left.to_px(*this)); + padded_rect.set_x(absolute_x() - box_model().padding().left.to_px(*this)); padded_rect.set_width(width() + box_model().padding().left.to_px(*this) + box_model().padding().right.to_px(*this)); - padded_rect.set_y(y() - box_model().padding().top.to_px(*this)); + padded_rect.set_y(absolute_y() - box_model().padding().top.to_px(*this)); padded_rect.set_height(height() + box_model().padding().top.to_px(*this) + box_model().padding().bottom.to_px(*this)); if (!is_body()) { @@ -237,7 +237,7 @@ void LayoutBox::render(RenderingContext& context) LayoutNodeWithStyleAndBoxModelMetrics::render(context); if (node() && document().inspected_node() == node()) - context.painter().draw_rect(enclosing_int_rect(m_rect), Color::Magenta); + context.painter().draw_rect(enclosing_int_rect(absolute_rect()), Color::Magenta); } HitTestResult LayoutBox::hit_test(const Gfx::Point& position) const @@ -245,7 +245,7 @@ HitTestResult LayoutBox::hit_test(const Gfx::Point& position) const // FIXME: It would be nice if we could confidently skip over hit testing // parts of the layout tree, but currently we can't just check // m_rect.contains() since inline text rects can't be trusted.. - HitTestResult result { m_rect.contains(position.x(), position.y()) ? this : nullptr }; + HitTestResult result { absolute_rect().contains(position.x(), position.y()) ? this : nullptr }; for_each_child([&](auto& child) { auto child_result = child.hit_test(position); if (child_result.layout_node) @@ -260,7 +260,7 @@ void LayoutBox::set_needs_display() ASSERT(frame); if (!is_inline()) { - const_cast<Frame*>(frame)->set_needs_display(enclosing_int_rect(rect())); + const_cast<Frame*>(frame)->set_needs_display(enclosing_int_rect(absolute_rect())); return; } @@ -272,12 +272,41 @@ bool LayoutBox::is_body() const return node() && node() == document().body(); } -void LayoutBox::set_rect(const Gfx::FloatRect& rect) +void LayoutBox::set_offset(const Gfx::FloatPoint& offset) { - if (m_rect == rect) + if (m_offset == offset) return; - m_rect = rect; + m_offset = offset; did_set_rect(); } +void LayoutBox::set_size(const Gfx::FloatSize& size) +{ + if (m_size == size) + return; + m_size = size; + did_set_rect(); +} + +Gfx::FloatPoint LayoutBox::effective_offset() const +{ + if (m_containing_line_box_fragment) + return m_containing_line_box_fragment->offset(); + return m_offset; +} + +const Gfx::FloatRect LayoutBox::absolute_rect() const +{ + Gfx::FloatRect rect { effective_offset(), size() }; + for (auto* block = containing_block(); block; block = block->containing_block()) { + rect.move_by(block->effective_offset()); + } + return rect; +} + +void LayoutBox::set_containing_line_box_fragment(LineBoxFragment& fragment) +{ + m_containing_line_box_fragment = fragment.make_weak_ptr(); +} + } diff --git a/Libraries/LibWeb/Layout/LayoutBox.h b/Libraries/LibWeb/Layout/LayoutBox.h index 6101d29077..d95155af7b 100644 --- a/Libraries/LibWeb/Layout/LayoutBox.h +++ b/Libraries/LibWeb/Layout/LayoutBox.h @@ -33,22 +33,33 @@ namespace Web { class LayoutBox : public LayoutNodeWithStyleAndBoxModelMetrics { public: - const Gfx::FloatRect& rect() const { return m_rect; } - Gfx::FloatRect& rect() { return m_rect; } - void set_rect(const Gfx::FloatRect&); - - float x() const { return rect().x(); } - float y() const { return rect().y(); } - float width() const { return rect().width(); } - float height() const { return rect().height(); } - Gfx::FloatSize size() const { return rect().size(); } - Gfx::FloatPoint position() const { return rect().location(); } - - virtual HitTestResult hit_test(const Gfx::Point& position) const override; + const Gfx::FloatRect absolute_rect() const; + + Gfx::FloatPoint effective_offset() const; + + void set_offset(const Gfx::FloatPoint& offset); + void set_offset(float x, float y) { set_offset({ x, y }); } + + const Gfx::FloatSize& size() const { return m_size; } + void set_size(const Gfx::FloatSize&); + void set_size(float width, float height) { set_size({ width, height }); } + + void set_width(float width) { set_size(width, height()); } + void set_height(float height) { set_size(width(), height); } + float width() const { return m_size.width(); } + float height() const { return m_size.height(); } + + float absolute_x() const { return absolute_rect().x(); } + float absolute_y() const { return absolute_rect().y(); } + Gfx::FloatPoint absolute_position() const { return absolute_rect().location(); } + + virtual HitTestResult hit_test(const Gfx::Point& absolute_position) const override; virtual void set_needs_display() override; bool is_body() const; + void set_containing_line_box_fragment(LineBoxFragment&); + protected: LayoutBox(const Node* node, NonnullRefPtr<StyleProperties> style) : LayoutNodeWithStyleAndBoxModelMetrics(node, move(style)) @@ -57,7 +68,7 @@ protected: virtual void render(RenderingContext&) override; - virtual void did_set_rect() {} + virtual void did_set_rect() { } private: virtual bool is_box() const override { return true; } @@ -70,7 +81,11 @@ private: }; void paint_border(RenderingContext&, Edge, const Gfx::FloatRect&, CSS::PropertyID style_property_id, CSS::PropertyID color_property_id, CSS::PropertyID width_property_id); - Gfx::FloatRect m_rect; + Gfx::FloatPoint m_offset; + Gfx::FloatSize m_size; + + // Some boxes hang off of line box fragments. (inline-block, inline-table, replaced, etc) + WeakPtr<LineBoxFragment> m_containing_line_box_fragment; }; template<> diff --git a/Libraries/LibWeb/Layout/LayoutCanvas.cpp b/Libraries/LibWeb/Layout/LayoutCanvas.cpp index 8d0f9f248d..011ed27058 100644 --- a/Libraries/LibWeb/Layout/LayoutCanvas.cpp +++ b/Libraries/LibWeb/Layout/LayoutCanvas.cpp @@ -55,11 +55,11 @@ void LayoutCanvas::render(RenderingContext& context) return; // FIXME: This should be done at a different level. Also rect() does not include padding etc! - if (!context.viewport_rect().intersects(enclosing_int_rect(rect()))) + if (!context.viewport_rect().intersects(enclosing_int_rect(absolute_rect()))) return; if (node().bitmap()) - context.painter().draw_scaled_bitmap(enclosing_int_rect(rect()), *node().bitmap(), node().bitmap()->rect()); + context.painter().draw_scaled_bitmap(enclosing_int_rect(absolute_rect()), *node().bitmap(), node().bitmap()->rect()); LayoutReplaced::render(context); } diff --git a/Libraries/LibWeb/Layout/LayoutDocument.cpp b/Libraries/LibWeb/Layout/LayoutDocument.cpp index bf6d8c33ec..ca240dd1ff 100644 --- a/Libraries/LibWeb/Layout/LayoutDocument.cpp +++ b/Libraries/LibWeb/Layout/LayoutDocument.cpp @@ -28,6 +28,7 @@ #include <LibWeb/Frame/Frame.h> #include <LibWeb/Layout/LayoutDocument.h> #include <LibWeb/Layout/LayoutImage.h> +#include <LibWeb/Layout/LayoutWidget.h> namespace Web { @@ -43,27 +44,33 @@ LayoutDocument::~LayoutDocument() void LayoutDocument::layout(LayoutMode layout_mode) { ASSERT(document().frame()); - rect().set_width(document().frame()->size().width()); + set_width(document().frame()->size().width()); LayoutNode::layout(layout_mode); ASSERT(!children_are_inline()); - int lowest_bottom = 0; + float lowest_bottom = 0; for_each_child([&](auto& child) { ASSERT(is<LayoutBlock>(child)); auto& child_block = to<LayoutBlock>(child); - if (child_block.rect().bottom() > lowest_bottom) - lowest_bottom = child_block.rect().bottom(); + lowest_bottom = max(lowest_bottom, child_block.absolute_rect().bottom()); + }); + set_height(lowest_bottom); + + // FIXME: This is a total hack. Make sure any GUI::Widgets are moved into place after layout. + // We should stop embedding GUI::Widgets entirely, since that won't work out-of-process. + for_each_in_subtree_of_type<LayoutWidget>([&](auto& widget) { + widget.update_widget(); + return IterationDecision::Continue; }); - rect().set_bottom(lowest_bottom); } void LayoutDocument::did_set_viewport_rect(Badge<Frame>, const Gfx::Rect& a_viewport_rect) { Gfx::FloatRect viewport_rect(a_viewport_rect.x(), a_viewport_rect.y(), a_viewport_rect.width(), a_viewport_rect.height()); for_each_in_subtree_of_type<LayoutImage>([&](auto& layout_image) { - const_cast<HTMLImageElement&>(layout_image.node()).set_visible_in_viewport({}, viewport_rect.intersects(layout_image.rect())); + const_cast<HTMLImageElement&>(layout_image.node()).set_visible_in_viewport({}, viewport_rect.intersects(layout_image.absolute_rect())); return IterationDecision::Continue; }); } diff --git a/Libraries/LibWeb/Layout/LayoutFrame.cpp b/Libraries/LibWeb/Layout/LayoutFrame.cpp index e71ecee7d2..7dbfb75730 100644 --- a/Libraries/LibWeb/Layout/LayoutFrame.cpp +++ b/Libraries/LibWeb/Layout/LayoutFrame.cpp @@ -67,8 +67,8 @@ void LayoutFrame::render(RenderingContext& context) context.painter().save(); auto old_viewport_rect = context.viewport_rect(); - context.painter().add_clip_rect(enclosing_int_rect(rect())); - context.painter().translate(x(), y()); + context.painter().add_clip_rect(enclosing_int_rect(absolute_rect())); + context.painter().translate(absolute_x(), absolute_y()); context.set_viewport_rect({ {}, node().hosted_frame()->size() }); node().hosted_frame()->document()->layout_node()->render(context); @@ -82,7 +82,7 @@ void LayoutFrame::did_set_rect() LayoutReplaced::did_set_rect(); ASSERT(node().hosted_frame()); - node().hosted_frame()->set_size(Gfx::Size(rect().width(), rect().height())); + node().hosted_frame()->set_size(size().to_int_size()); } } diff --git a/Libraries/LibWeb/Layout/LayoutImage.cpp b/Libraries/LibWeb/Layout/LayoutImage.cpp index 5e5109233d..961a5cf49a 100644 --- a/Libraries/LibWeb/Layout/LayoutImage.cpp +++ b/Libraries/LibWeb/Layout/LayoutImage.cpp @@ -52,11 +52,11 @@ void LayoutImage::layout(LayoutMode layout_mode) auto alt = node().alt(); if (alt.is_empty()) alt = node().src(); - rect().set_width(font.width(alt) + 16); - rect().set_height(font.glyph_height() + 16); + set_width(font.width(alt) + 16); + set_height(font.glyph_height() + 16); } else { - rect().set_width(16); - rect().set_height(16); + set_width(16); + set_height(16); } LayoutReplaced::layout(layout_mode); @@ -68,18 +68,18 @@ void LayoutImage::render(RenderingContext& context) return; // FIXME: This should be done at a different level. Also rect() does not include padding etc! - if (!context.viewport_rect().intersects(enclosing_int_rect(rect()))) + if (!context.viewport_rect().intersects(enclosing_int_rect(absolute_rect()))) return; if (renders_as_alt_text()) { context.painter().set_font(Gfx::Font::default_font()); - Gfx::StylePainter::paint_frame(context.painter(), enclosing_int_rect(rect()), context.palette(), Gfx::FrameShape::Container, Gfx::FrameShadow::Sunken, 2); + Gfx::StylePainter::paint_frame(context.painter(), enclosing_int_rect(absolute_rect()), context.palette(), Gfx::FrameShape::Container, Gfx::FrameShadow::Sunken, 2); auto alt = node().alt(); if (alt.is_empty()) alt = node().src(); - context.painter().draw_text(enclosing_int_rect(rect()), alt, Gfx::TextAlignment::Center, style().color_or_fallback(CSS::PropertyID::Color, document(), Color::Black), Gfx::TextElision::Right); + context.painter().draw_text(enclosing_int_rect(absolute_rect()), alt, Gfx::TextAlignment::Center, style().color_or_fallback(CSS::PropertyID::Color, document(), Color::Black), Gfx::TextElision::Right); } else if (node().bitmap()) - context.painter().draw_scaled_bitmap(enclosing_int_rect(rect()), *node().bitmap(), node().bitmap()->rect()); + context.painter().draw_scaled_bitmap(enclosing_int_rect(absolute_rect()), *node().bitmap(), node().bitmap()->rect()); LayoutReplaced::render(context); } diff --git a/Libraries/LibWeb/Layout/LayoutListItem.cpp b/Libraries/LibWeb/Layout/LayoutListItem.cpp index 2a46cae1d8..877c095483 100644 --- a/Libraries/LibWeb/Layout/LayoutListItem.cpp +++ b/Libraries/LibWeb/Layout/LayoutListItem.cpp @@ -58,8 +58,8 @@ void LayoutListItem::layout(LayoutMode layout_mode) append_child(*m_marker); } - Gfx::FloatRect marker_rect { x() - 8, y(), 4, height() }; - m_marker->set_rect(marker_rect); + m_marker->set_offset(-8, 0); + m_marker->set_size(4, height()); } } diff --git a/Libraries/LibWeb/Layout/LayoutListItemMarker.cpp b/Libraries/LibWeb/Layout/LayoutListItemMarker.cpp index 2188ce44aa..fe7582985f 100644 --- a/Libraries/LibWeb/Layout/LayoutListItemMarker.cpp +++ b/Libraries/LibWeb/Layout/LayoutListItemMarker.cpp @@ -41,7 +41,7 @@ LayoutListItemMarker::~LayoutListItemMarker() void LayoutListItemMarker::render(RenderingContext& context) { Gfx::Rect bullet_rect { 0, 0, 4, 4 }; - bullet_rect.center_within(enclosing_int_rect(rect())); + bullet_rect.center_within(enclosing_int_rect(absolute_rect())); // FIXME: It would be nicer to not have to go via the parent here to get our inherited style. auto color = parent()->style().color_or_fallback(CSS::PropertyID::Color, document(), context.palette().base_text()); context.painter().fill_rect(bullet_rect, color); diff --git a/Libraries/LibWeb/Layout/LayoutNode.cpp b/Libraries/LibWeb/Layout/LayoutNode.cpp index e4a21bb3c7..b0133e210b 100644 --- a/Libraries/LibWeb/Layout/LayoutNode.cpp +++ b/Libraries/LibWeb/Layout/LayoutNode.cpp @@ -155,7 +155,7 @@ void LayoutNode::set_needs_display() if (auto* block = containing_block()) { block->for_each_fragment([&](auto& fragment) { if (&fragment.layout_node() == this || is_ancestor_of(fragment.layout_node())) { - const_cast<Frame*>(frame)->set_needs_display(enclosing_int_rect(fragment.rect())); + const_cast<Frame*>(frame)->set_needs_display(enclosing_int_rect(fragment.absolute_rect())); } return IterationDecision::Continue; }); @@ -172,13 +172,13 @@ float LayoutNode::font_size() const Gfx::FloatPoint LayoutNode::box_type_agnostic_position() const { if (is_box()) - return to<LayoutBox>(*this).position(); + return to<LayoutBox>(*this).absolute_position(); ASSERT(is_inline()); Gfx::FloatPoint position; if (auto* block = containing_block()) { block->for_each_fragment([&](auto& fragment) { if (&fragment.layout_node() == this || is_ancestor_of(fragment.layout_node())) { - position = fragment.rect().location(); + position = fragment.absolute_rect().location(); return IterationDecision::Break; } return IterationDecision::Continue; diff --git a/Libraries/LibWeb/Layout/LayoutReplaced.cpp b/Libraries/LibWeb/Layout/LayoutReplaced.cpp index 4aa9b5a259..8c17d33b21 100644 --- a/Libraries/LibWeb/Layout/LayoutReplaced.cpp +++ b/Libraries/LibWeb/Layout/LayoutReplaced.cpp @@ -141,27 +141,24 @@ Gfx::FloatPoint LayoutReplaced::calculate_position() box_model().padding().top = style.length_or_fallback(CSS::PropertyID::PaddingTop, zero_value, containing_block.width()); box_model().padding().bottom = style.length_or_fallback(CSS::PropertyID::PaddingBottom, zero_value, containing_block.width()); - float position_x = box_model().margin().left.to_px(*this) + float x = box_model().margin().left.to_px(*this) + box_model().border().left.to_px(*this) + box_model().padding().left.to_px(*this) + box_model().offset().left.to_px(*this); - if (style.position() != CSS::Position::Absolute || containing_block.style().position() == CSS::Position::Absolute) - position_x += containing_block.x(); + float y = box_model().full_margin(*this).top + box_model().offset().top.to_px(*this); - float position_y = box_model().full_margin(*this).top + box_model().offset().top.to_px(*this); - - return { position_x, position_y }; + return { x, y }; } void LayoutReplaced::layout(LayoutMode layout_mode) { - rect().set_width(calculate_width()); - rect().set_height(calculate_height()); + set_width(calculate_width()); + set_height(calculate_height()); LayoutBox::layout(layout_mode); - rect().set_location(calculate_position()); + set_offset(calculate_position()); } void LayoutReplaced::split_into_lines(LayoutBlock& container, LayoutMode layout_mode) diff --git a/Libraries/LibWeb/Layout/LayoutTableRowGroup.cpp b/Libraries/LibWeb/Layout/LayoutTableRowGroup.cpp index de1be0657f..0f60749847 100644 --- a/Libraries/LibWeb/Layout/LayoutTableRowGroup.cpp +++ b/Libraries/LibWeb/Layout/LayoutTableRowGroup.cpp @@ -53,7 +53,7 @@ void LayoutTableRowGroup::layout(LayoutMode layout_mode) content_height += row.height(); }); - rect().set_height(content_height); + set_height(content_height); } } diff --git a/Libraries/LibWeb/Layout/LayoutText.cpp b/Libraries/LibWeb/Layout/LayoutText.cpp index e4cdd4c4bd..196ffb99e4 100644 --- a/Libraries/LibWeb/Layout/LayoutText.cpp +++ b/Libraries/LibWeb/Layout/LayoutText.cpp @@ -72,17 +72,17 @@ void LayoutText::render_fragment(RenderingContext& context, const LineBoxFragmen auto background_color = style().property(CSS::PropertyID::BackgroundColor); if (background_color.has_value() && background_color.value()->is_color()) - painter.fill_rect(enclosing_int_rect(fragment.rect()), background_color.value()->to_color(document())); + painter.fill_rect(enclosing_int_rect(fragment.absolute_rect()), background_color.value()->to_color(document())); auto color = style().color_or_fallback(CSS::PropertyID::Color, document(), context.palette().base_text()); auto text_decoration = style().string_or_fallback(CSS::PropertyID::TextDecoration, "none"); if (document().inspected_node() == &node()) - context.painter().draw_rect(enclosing_int_rect(fragment.rect()), Color::Magenta); + context.painter().draw_rect(enclosing_int_rect(fragment.absolute_rect()), Color::Magenta); bool is_underline = text_decoration == "underline"; if (is_underline) - painter.draw_line(enclosing_int_rect(fragment.rect()).bottom_left().translated(0, 1), enclosing_int_rect(fragment.rect()).bottom_right().translated(0, 1), color); + painter.draw_line(enclosing_int_rect(fragment.absolute_rect()).bottom_left().translated(0, 1), enclosing_int_rect(fragment.absolute_rect()).bottom_right().translated(0, 1), color); auto text = m_text_for_rendering; auto text_transform = style().string_or_fallback(CSS::PropertyID::TextTransform, "none"); @@ -91,7 +91,7 @@ void LayoutText::render_fragment(RenderingContext& context, const LineBoxFragmen if (text_transform == "lowercase") text = m_text_for_rendering.to_lowercase(); - painter.draw_text(enclosing_int_rect(fragment.rect()), text.substring_view(fragment.start(), fragment.length()), Gfx::TextAlignment::TopLeft, color); + painter.draw_text(enclosing_int_rect(fragment.absolute_rect()), text.substring_view(fragment.start(), fragment.length()), Gfx::TextAlignment::TopLeft, color); } template<typename Callback> diff --git a/Libraries/LibWeb/Layout/LayoutWidget.cpp b/Libraries/LibWeb/Layout/LayoutWidget.cpp index 852a36d218..e6cda54b32 100644 --- a/Libraries/LibWeb/Layout/LayoutWidget.cpp +++ b/Libraries/LibWeb/Layout/LayoutWidget.cpp @@ -59,7 +59,7 @@ void LayoutWidget::did_set_rect() void LayoutWidget::update_widget() { - auto adjusted_widget_position = rect().location().to_int_point(); + auto adjusted_widget_position = absolute_rect().location().to_int_point(); auto& page_view = static_cast<const PageView&>(document().frame()->page().client()); adjusted_widget_position.move_by(-page_view.horizontal_scrollbar().value(), -page_view.vertical_scrollbar().value()); widget().move_to(adjusted_widget_position); diff --git a/Libraries/LibWeb/Layout/LineBox.cpp b/Libraries/LibWeb/Layout/LineBox.cpp index be73e3c5c5..e9842e391f 100644 --- a/Libraries/LibWeb/Layout/LineBox.cpp +++ b/Libraries/LibWeb/Layout/LineBox.cpp @@ -27,6 +27,7 @@ #include <AK/Utf8View.h> #include <LibWeb/Layout/LayoutNode.h> #include <LibWeb/Layout/LayoutText.h> +#include <LibWeb/Layout/LayoutBox.h> #include <LibWeb/Layout/LineBox.h> #include <ctype.h> @@ -39,18 +40,21 @@ void LineBox::add_fragment(const LayoutNode& layout_node, int start, int length, // The fragment we're adding is from the last LayoutNode on the line. // Expand the last fragment instead of adding a new one with the same LayoutNode. m_fragments.last().m_length = (start - m_fragments.last().m_start) + length; - m_fragments.last().m_rect.set_width(m_fragments.last().m_rect.width() + width); + m_fragments.last().set_width(m_fragments.last().width() + width); } else { - m_fragments.empend(layout_node, start, length, Gfx::FloatRect(m_width, 0, width, height)); + m_fragments.append(make<LineBoxFragment>(layout_node, start, length, Gfx::FloatPoint(m_width, 0), Gfx::FloatSize(width, height))); } m_width += width; + + if (is<LayoutBox>(layout_node)) + const_cast<LayoutBox&>(to<LayoutBox>(layout_node)).set_containing_line_box_fragment(m_fragments.last()); } 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(); } if (m_fragments.is_empty()) @@ -64,7 +68,7 @@ void LineBox::trim_trailing_whitespace() int space_width = last_fragment.layout_node().style().font().glyph_width(' '); while (last_fragment.length() && isspace(last_text[last_fragment.length() - 1])) { last_fragment.m_length -= 1; - last_fragment.m_rect.set_width(last_fragment.m_rect.width() - space_width); + last_fragment.set_width(last_fragment.width() - space_width); m_width -= space_width; } } diff --git a/Libraries/LibWeb/Layout/LineBox.h b/Libraries/LibWeb/Layout/LineBox.h index e5322c0e15..67333325ae 100644 --- a/Libraries/LibWeb/Layout/LineBox.h +++ b/Libraries/LibWeb/Layout/LineBox.h @@ -26,6 +26,7 @@ #pragma once +#include <AK/NonnullOwnPtrVector.h> #include <AK/Vector.h> #include <LibWeb/Layout/LineBoxFragment.h> @@ -33,19 +34,20 @@ namespace Web { class LineBox { public: - LineBox() {} + LineBox() { } float width() const { return m_width; } void add_fragment(const LayoutNode& layout_node, int start, int length, int width, int height); - const Vector<LineBoxFragment>& fragments() const { return m_fragments; } - Vector<LineBoxFragment>& fragments() { return m_fragments; } + const NonnullOwnPtrVector<LineBoxFragment>& fragments() const { return m_fragments; } + NonnullOwnPtrVector<LineBoxFragment>& fragments() { return m_fragments; } void trim_trailing_whitespace(); + private: friend class LayoutBlock; - Vector<LineBoxFragment> m_fragments; + NonnullOwnPtrVector<LineBoxFragment> m_fragments; float m_width { 0 }; }; diff --git a/Libraries/LibWeb/Layout/LineBoxFragment.cpp b/Libraries/LibWeb/Layout/LineBoxFragment.cpp index 2d7a60c917..858c0ebe68 100644 --- a/Libraries/LibWeb/Layout/LineBoxFragment.cpp +++ b/Libraries/LibWeb/Layout/LineBoxFragment.cpp @@ -57,6 +57,14 @@ StringView LineBoxFragment::text() const return to<LayoutText>(layout_node()).text_for_rendering().substring_view(m_start, m_length); } +const Gfx::FloatRect LineBoxFragment::absolute_rect() const +{ + Gfx::FloatRect rect { {}, size() }; + rect.set_location(m_layout_node.containing_block()->absolute_position()); + rect.move_by(offset()); + return rect; +} + int LineBoxFragment::text_index_at(float x) const { if (!layout_node().is_text()) @@ -65,7 +73,7 @@ int LineBoxFragment::text_index_at(float x) const auto& font = layout_text.style().font(); Utf8View view(text()); - float relative_x = x - m_rect.location().x(); + float relative_x = x - absolute_x(); float glyph_spacing = font.glyph_spacing(); float width_so_far = 0; diff --git a/Libraries/LibWeb/Layout/LineBoxFragment.h b/Libraries/LibWeb/Layout/LineBoxFragment.h index c22cee77bd..ba64d39468 100644 --- a/Libraries/LibWeb/Layout/LineBoxFragment.h +++ b/Libraries/LibWeb/Layout/LineBoxFragment.h @@ -26,31 +26,39 @@ #pragma once +#include <AK/Weakable.h> #include <LibGfx/FloatRect.h> +#include <LibWeb/Forward.h> namespace Web { -class LayoutNode; -class RenderingContext; - -class LineBoxFragment { +class LineBoxFragment : public Weakable<LineBoxFragment> { friend class LineBox; + public: - LineBoxFragment(const LayoutNode& layout_node, int start, int length, const Gfx::FloatRect& rect) + LineBoxFragment(const LayoutNode& layout_node, int start, int length, const Gfx::FloatPoint& offset, const Gfx::FloatSize& size) : m_layout_node(layout_node) , m_start(start) , m_length(length) - , m_rect(rect) + , m_offset(offset) + , m_size(size) { } const LayoutNode& layout_node() const { return m_layout_node; } int start() const { return m_start; } int length() const { return m_length; } - const Gfx::FloatRect& rect() const { return m_rect; } - Gfx::FloatRect& rect() { return m_rect; } + const Gfx::FloatRect absolute_rect() const; + + const Gfx::FloatPoint& offset() const { return m_offset; } + void set_offset(const Gfx::FloatPoint& offset) { m_offset = offset; } + + const Gfx::FloatSize& size() const { return m_size; } + void set_width(float width) { m_size.set_width(width); } + float width() const { return m_size.width(); } + float height() const { return m_size.height(); } - float width() const { return m_rect.width(); } + float absolute_x() const { return absolute_rect().x(); } void render(RenderingContext&); @@ -63,7 +71,8 @@ private: const LayoutNode& m_layout_node; int m_start { 0 }; int m_length { 0 }; - Gfx::FloatRect m_rect; + Gfx::FloatPoint m_offset; + Gfx::FloatSize m_size; }; } diff --git a/Libraries/LibWeb/PageView.cpp b/Libraries/LibWeb/PageView.cpp index ab85a1d4a5..68ec47dc17 100644 --- a/Libraries/LibWeb/PageView.cpp +++ b/Libraries/LibWeb/PageView.cpp @@ -161,14 +161,14 @@ void PageView::layout_and_sync_size() page().main_frame().set_size(available_size()); document()->layout(); - set_content_size(enclosing_int_rect(layout_root()->rect()).size()); + set_content_size(layout_root()->size().to_int_size()); // NOTE: If layout caused us to gain or lose scrollbars, we have to lay out again // since the scrollbars now take up some of the available space. if (had_vertical_scrollbar != vertical_scrollbar().is_visible() || had_horizontal_scrollbar != horizontal_scrollbar().is_visible()) { page().main_frame().set_size(available_size()); document()->layout(); - set_content_size(enclosing_int_rect(layout_root()->rect()).size()); + set_content_size(layout_root()->size().to_int_size()); } page().main_frame().set_viewport_rect(viewport_rect_in_content_coordinates()); |