-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
LibWeb: Support inserting non-inline elements into inline elements
Our layout tree requires that all containers either have inline or non-inline children. In order to support the layout of non-inline elements inside inline elements, we need to do a bit of tree restructuring. It effectively simulates temporarily closing all inline nodes, appending the block element, and resumes appending to the last open inline node. The acid1.txt expectation needed to be updated to reflect the fact that we now hoist its <p> elements out of the inline <form> they were in. Visually, the before and after situations for acid1.html are identical.
- Loading branch information
Showing
11 changed files
with
375 additions
and
96 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
/* | ||
* Copyright (c) 2018-2024, Andreas Kling <[email protected]> | ||
* Copyright (c) 2025, Jelle Raaijmakers <[email protected]> | ||
* | ||
* SPDX-License-Identifier: BSD-2-Clause | ||
*/ | ||
|
@@ -540,13 +541,17 @@ int HTMLElement::offset_width() const | |
// NOTE: Ensure that layout is up-to-date before looking at metrics. | ||
const_cast<DOM::Document&>(document()).update_layout(); | ||
|
||
// 1. If the element does not have any associated CSS layout box return zero and terminate this algorithm. | ||
if (!paintable_box()) | ||
// 1. If the element does not have any associated box return zero and terminate this algorithm. | ||
auto* current_node = layout_node().ptr(); | ||
if (!is<Layout::NodeWithStyleAndBoxModelMetrics>(current_node)) | ||
return 0; | ||
|
||
// 2. Return the width of the axis-aligned bounding box of the border boxes of all fragments generated by the element’s principal box, | ||
// ignoring any transforms that apply to the element and its ancestors. | ||
return paintable_box()->border_box_width().to_int(); | ||
// 2. Return the unscaled width of the axis-aligned bounding box of the border boxes of all fragments generated by | ||
// the element’s principal box, ignoring any transforms that apply to the element and its ancestors. | ||
// | ||
// If the element’s principal box is an inline-level box which was "split" by a block-level descendant, also | ||
// include fragments generated by the block-level descendants, unless they are zero width or height. | ||
return static_cast<Layout::NodeWithStyleAndBoxModelMetrics const&>(*current_node).absolute_border_box_rect().width().to_int(); | ||
} | ||
|
||
// https://drafts.csswg.org/cssom-view/#dom-htmlelement-offsetheight | ||
|
@@ -555,13 +560,17 @@ int HTMLElement::offset_height() const | |
// NOTE: Ensure that layout is up-to-date before looking at metrics. | ||
const_cast<DOM::Document&>(document()).update_layout(); | ||
|
||
// 1. If the element does not have any associated CSS layout box return zero and terminate this algorithm. | ||
if (!paintable_box()) | ||
// 1. If the element does not have any associated box return zero and terminate this algorithm. | ||
auto* current_node = layout_node().ptr(); | ||
if (!is<Layout::NodeWithStyleAndBoxModelMetrics>(current_node)) | ||
return 0; | ||
|
||
// 2. Return the height of the axis-aligned bounding box of the border boxes of all fragments generated by the element’s principal box, | ||
// ignoring any transforms that apply to the element and its ancestors. | ||
return paintable_box()->border_box_height().to_int(); | ||
// 2. Return the unscaled height of the axis-aligned bounding box of the border boxes of all fragments generated by | ||
// the element’s principal box, ignoring any transforms that apply to the element and its ancestors. | ||
// | ||
// If the element’s principal box is an inline-level box which was "split" by a block-level descendant, also | ||
// include fragments generated by the block-level descendants, unless they are zero width or height. | ||
return static_cast<Layout::NodeWithStyleAndBoxModelMetrics const&>(*current_node).absolute_border_box_rect().height().to_int(); | ||
} | ||
|
||
// https://html.spec.whatwg.org/multipage/links.html#cannot-navigate | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,7 @@ | ||
/* | ||
* Copyright (c) 2018-2023, Andreas Kling <[email protected]> | ||
* Copyright (c) 2021-2023, Sam Atkins <[email protected]> | ||
* Copyright (c) 2025, Jelle Raaijmakers <[email protected]> | ||
* | ||
* SPDX-License-Identifier: BSD-2-Clause | ||
*/ | ||
|
@@ -13,7 +14,6 @@ | |
#include <LibWeb/CSS/StyleValues/CSSKeywordValue.h> | ||
#include <LibWeb/CSS/StyleValues/IntegerStyleValue.h> | ||
#include <LibWeb/CSS/StyleValues/LengthStyleValue.h> | ||
#include <LibWeb/CSS/StyleValues/MathDepthStyleValue.h> | ||
#include <LibWeb/CSS/StyleValues/NumberStyleValue.h> | ||
#include <LibWeb/CSS/StyleValues/PercentageStyleValue.h> | ||
#include <LibWeb/CSS/StyleValues/RatioStyleValue.h> | ||
|
@@ -30,7 +30,6 @@ | |
#include <LibWeb/Layout/TableWrapper.h> | ||
#include <LibWeb/Layout/TextNode.h> | ||
#include <LibWeb/Layout/Viewport.h> | ||
#include <LibWeb/Platform/FontPlugin.h> | ||
|
||
namespace Web::Layout { | ||
|
||
|
@@ -1168,6 +1167,12 @@ bool NodeWithStyle::is_scroll_container() const | |
|| overflow_value_makes_box_a_scroll_container(computed_values().overflow_y()); | ||
} | ||
|
||
void NodeWithStyleAndBoxModelMetrics::visit_edges(Cell::Visitor& visitor) | ||
{ | ||
Base::visit_edges(visitor); | ||
visitor.visit(m_continuation_of_node); | ||
} | ||
|
||
void Node::add_paintable(GC::Ptr<Painting::Paintable> paintable) | ||
{ | ||
if (!paintable) | ||
|
@@ -1275,4 +1280,46 @@ CSS::UserSelect Node::user_select_used_value() const | |
return computed_value; | ||
} | ||
|
||
template<typename Callable> | ||
static CSSPixelRect united_rect_for_continuation_chain(NodeWithStyleAndBoxModelMetrics const& start, Callable get_rect) | ||
{ | ||
// Combine the absolute border box rects of all paintables of all nodes in the continuation chain. Without this, we | ||
// calculate the wrong border box rect for inline nodes that were split because of block elements. | ||
Optional<CSSPixelRect> result; | ||
for (auto* node = &start; node; node = node->continuation_of_node()) { | ||
for (auto const& paintable : node->paintables()) { | ||
if (!is<Painting::PaintableBox>(paintable)) | ||
continue; | ||
auto const& paintable_box = static_cast<Painting::PaintableBox const&>(paintable); | ||
auto paintable_border_box_rect = get_rect(paintable_box); | ||
if (!result.has_value()) | ||
result = paintable_border_box_rect; | ||
else if (!paintable_border_box_rect.is_empty()) | ||
result->unite(paintable_border_box_rect); | ||
} | ||
} | ||
return result.value_or({}); | ||
} | ||
|
||
CSSPixelRect NodeWithStyleAndBoxModelMetrics::absolute_border_box_rect() const | ||
{ | ||
return united_rect_for_continuation_chain(*this, [](auto const& paintable_box) { | ||
return paintable_box.absolute_border_box_rect(); | ||
}); | ||
} | ||
|
||
CSSPixelRect NodeWithStyleAndBoxModelMetrics::absolute_content_rect() const | ||
{ | ||
return united_rect_for_continuation_chain(*this, [](auto const& paintable_box) { | ||
return paintable_box.absolute_rect(); | ||
}); | ||
} | ||
|
||
CSSPixelRect NodeWithStyleAndBoxModelMetrics::absolute_padding_box_rect() const | ||
{ | ||
return united_rect_for_continuation_chain(*this, [](auto const& paintable_box) { | ||
return paintable_box.absolute_padding_box_rect(); | ||
}); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.