summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Libraries/LibWeb/Dump.cpp6
-rw-r--r--Libraries/LibWeb/Forward.h3
-rw-r--r--Libraries/LibWeb/Layout/LayoutBlock.cpp60
-rw-r--r--Libraries/LibWeb/Layout/LayoutBox.cpp45
-rw-r--r--Libraries/LibWeb/Layout/LayoutBox.h43
-rw-r--r--Libraries/LibWeb/Layout/LayoutCanvas.cpp4
-rw-r--r--Libraries/LibWeb/Layout/LayoutDocument.cpp19
-rw-r--r--Libraries/LibWeb/Layout/LayoutFrame.cpp6
-rw-r--r--Libraries/LibWeb/Layout/LayoutImage.cpp16
-rw-r--r--Libraries/LibWeb/Layout/LayoutListItem.cpp4
-rw-r--r--Libraries/LibWeb/Layout/LayoutListItemMarker.cpp2
-rw-r--r--Libraries/LibWeb/Layout/LayoutNode.cpp6
-rw-r--r--Libraries/LibWeb/Layout/LayoutReplaced.cpp15
-rw-r--r--Libraries/LibWeb/Layout/LayoutTableRowGroup.cpp2
-rw-r--r--Libraries/LibWeb/Layout/LayoutText.cpp8
-rw-r--r--Libraries/LibWeb/Layout/LayoutWidget.cpp2
-rw-r--r--Libraries/LibWeb/Layout/LineBox.cpp12
-rw-r--r--Libraries/LibWeb/Layout/LineBox.h10
-rw-r--r--Libraries/LibWeb/Layout/LineBoxFragment.cpp10
-rw-r--r--Libraries/LibWeb/Layout/LineBoxFragment.h29
-rw-r--r--Libraries/LibWeb/PageView.cpp4
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());