summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibWeb/Layout/FormattingContext.cpp
diff options
context:
space:
mode:
authorAndreas Kling <kling@serenityos.org>2022-03-27 16:07:19 +0200
committerAndreas Kling <kling@serenityos.org>2022-03-27 18:16:09 +0200
commit27c68624b6c30e91063ee97cb037f66e6f3931db (patch)
tree46f8e149c4bd7f8809307a2f9e2ebe96e1df1f44 /Userland/Libraries/LibWeb/Layout/FormattingContext.cpp
parentfa71401bec52561614164fddd5a71971ccb56921 (diff)
downloadserenity-27c68624b6c30e91063ee97cb037f66e6f3931db.zip
LibWeb: Resolve top/bottom inset properties for position:relative
This patch reimplements inset property resolution based on the new CSS Positioned Layout specification. Nothing should change for left/right insets, but we gain support for top/bottom. :^)
Diffstat (limited to 'Userland/Libraries/LibWeb/Layout/FormattingContext.cpp')
-rw-r--r--Userland/Libraries/LibWeb/Layout/FormattingContext.cpp61
1 files changed, 32 insertions, 29 deletions
diff --git a/Userland/Libraries/LibWeb/Layout/FormattingContext.cpp b/Userland/Libraries/LibWeb/Layout/FormattingContext.cpp
index e76036cd3a..1eae1eec02 100644
--- a/Userland/Libraries/LibWeb/Layout/FormattingContext.cpp
+++ b/Userland/Libraries/LibWeb/Layout/FormattingContext.cpp
@@ -766,42 +766,45 @@ void FormattingContext::compute_height_for_absolutely_positioned_replaced_elemen
m_state.get_mutable(box).content_height = compute_height_for_replaced_element(m_state, box);
}
+// https://www.w3.org/TR/css-position-3/#relpos-insets
void FormattingContext::compute_inset(Box const& box)
{
- // 9.4.3 Relative positioning
- // Once a box has been laid out according to the normal flow or floated, it may be shifted relative to this position.
-
if (box.computed_values().position() != CSS::Position::Relative)
return;
+ auto resolve_two_opposing_insets = [&](CSS::LengthPercentage const& computed_start, CSS::LengthPercentage const& computed_end, float& used_start, float& used_end, float reference_for_percentage) {
+ auto resolved_first = computed_start.resolved(box, CSS::Length::make_px(reference_for_percentage)).resolved(box);
+ auto resolved_second = computed_end.resolved(box, CSS::Length::make_px(reference_for_percentage)).resolved(box);
+
+ if (resolved_first.is_auto() && resolved_second.is_auto()) {
+ // If opposing inset properties in an axis both compute to auto (their initial values),
+ // their used values are zero (i.e., the boxes stay in their original position in that axis).
+ used_start = 0;
+ used_end = 0;
+ } else if (resolved_first.is_auto() || resolved_second.is_auto()) {
+ // If only one is auto, its used value becomes the negation of the other, and the box is shifted by the specified amount.
+ if (resolved_first.is_auto()) {
+ used_end = resolved_second.to_px(box);
+ used_start = 0 - used_end;
+ } else {
+ used_start = resolved_first.to_px(box);
+ used_end = 0 - used_start;
+ }
+ } else {
+ // If neither is auto, the position is over-constrained; (with respect to the writing mode of its containing block)
+ // the computed end side value is ignored, and its used value becomes the negation of the start side.
+ used_start = resolved_first.to_px(box);
+ used_end = 0 - used_start;
+ }
+ };
+
auto& box_state = m_state.get_mutable(box);
auto const& computed_values = box.computed_values();
- float width_of_containing_block = m_state.get(*box.containing_block()).content_width;
- auto width_of_containing_block_as_length = CSS::Length::make_px(width_of_containing_block);
-
- auto specified_left = computed_values.inset().left.resolved(box, width_of_containing_block_as_length).resolved(box);
- auto specified_right = computed_values.inset().right.resolved(box, width_of_containing_block_as_length).resolved(box);
-
- if (specified_left.is_auto() && specified_right.is_auto()) {
- // If both 'left' and 'right' are 'auto' (their initial values), the used values are '0' (i.e., the boxes stay in their original position).
- box_state.inset_left = 0;
- box_state.inset_right = 0;
- } else if (specified_left.is_auto()) {
- // If 'left' is 'auto', its used value is minus the value of 'right' (i.e., the boxes move to the left by the value of 'right').
- box_state.inset_right = specified_right.to_px(box);
- box_state.inset_left = 0 - box_state.inset_right;
- } else if (specified_right.is_auto()) {
- // If 'right' is specified as 'auto', its used value is minus the value of 'left'.
- box_state.inset_left = specified_left.to_px(box);
- box_state.inset_right = 0 - box_state.inset_left;
- } else {
- // If neither 'left' nor 'right' is 'auto', the position is over-constrained, and one of them has to be ignored.
- // If the 'direction' property of the containing block is 'ltr', the value of 'left' wins and 'right' becomes -'left'.
- // If 'direction' of the containing block is 'rtl', 'right' wins and 'left' is ignored.
- // FIXME: Check direction (assuming 'ltr' for now).
- box_state.inset_left = specified_left.to_px(box);
- box_state.inset_right = 0 - box_state.inset_left;
- }
+ auto const& containing_block_state = m_state.get(*box.containing_block());
+
+ // FIXME: Respect the containing block's writing-mode.
+ resolve_two_opposing_insets(computed_values.inset().left, computed_values.inset().right, box_state.inset_left, box_state.inset_right, containing_block_state.content_width);
+ resolve_two_opposing_insets(computed_values.inset().top, computed_values.inset().bottom, box_state.inset_top, box_state.inset_bottom, containing_block_state.content_height);
}
FormattingState::IntrinsicSizes FormattingContext::calculate_intrinsic_sizes(Layout::Box const& box) const