mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-22 07:30:19 +00:00
LibWeb: Implement abspos for replaced elements
Added implementation and spec comments for sections 10.3.8 and 10.6.5, with an implementation similar to the existing ones for non-replaced elements.
This commit is contained in:
parent
6a66a05809
commit
61fe7c230f
Notes:
sideshowbarker
2024-07-17 08:36:27 +09:00
Author: https://github.com/SebastianZaha Commit: https://github.com/SerenityOS/serenity/commit/61fe7c230f Pull-request: https://github.com/SerenityOS/serenity/pull/19866
1 changed files with 140 additions and 4 deletions
|
@ -734,12 +734,84 @@ void FormattingContext::compute_width_for_absolutely_positioned_non_replaced_ele
|
|||
void FormattingContext::compute_width_for_absolutely_positioned_replaced_element(Box const& box, AvailableSpace const& available_space)
|
||||
{
|
||||
// 10.3.8 Absolutely positioned, replaced elements
|
||||
// The used value of 'width' is determined as for inline replaced elements.
|
||||
// In this case, section 10.3.7 applies up through and including the constraint equation,
|
||||
// but the rest of section 10.3.7 is replaced by the following rules:
|
||||
|
||||
// 1. The used value of 'width' is determined as for inline replaced elements.
|
||||
if (is<ReplacedBox>(box)) {
|
||||
// FIXME: This const_cast is gross.
|
||||
static_cast<ReplacedBox&>(const_cast<Box&>(box)).prepare_for_replaced_layout();
|
||||
}
|
||||
m_state.get_mutable(box).set_content_width(compute_width_for_replaced_element(box, available_space));
|
||||
|
||||
auto width = compute_width_for_replaced_element(box, available_space);
|
||||
auto width_of_containing_block = available_space.width.to_px();
|
||||
auto available = width_of_containing_block - width;
|
||||
auto const& computed_values = box.computed_values();
|
||||
auto left = computed_values.inset().left();
|
||||
auto margin_left = computed_values.margin().left();
|
||||
auto right = computed_values.inset().right();
|
||||
auto margin_right = computed_values.margin().right();
|
||||
auto static_position = calculate_static_position(box);
|
||||
|
||||
auto to_px = [&](const CSS::LengthPercentage& l) {
|
||||
return l.to_px(box, width_of_containing_block);
|
||||
};
|
||||
|
||||
// If 'margin-left' or 'margin-right' is specified as 'auto' its used value is determined by the rules below.
|
||||
// 2. If both 'left' and 'right' have the value 'auto', then if the 'direction' property of the
|
||||
// element establishing the static-position containing block is 'ltr', set 'left' to the static
|
||||
// position; else if 'direction' is 'rtl', set 'right' to the static position.
|
||||
if (left.is_auto() && right.is_auto()) {
|
||||
left = CSS::Length::make_px(static_position.x());
|
||||
}
|
||||
|
||||
// 3. If 'left' or 'right' are 'auto', replace any 'auto' on 'margin-left' or 'margin-right' with '0'.
|
||||
if (left.is_auto() || right.is_auto()) {
|
||||
if (margin_left.is_auto())
|
||||
margin_left = CSS::Length::make_px(0);
|
||||
if (margin_right.is_auto())
|
||||
margin_right = CSS::Length::make_px(0);
|
||||
}
|
||||
|
||||
// 4. If at this point both 'margin-left' and 'margin-right' are still 'auto', solve the equation
|
||||
// under the extra constraint that the two margins must get equal values, unless this would make
|
||||
// them negative, in which case when the direction of the containing block is 'ltr' ('rtl'),
|
||||
// set 'margin-left' ('margin-right') to zero and solve for 'margin-right' ('margin-left').
|
||||
if (margin_left.is_auto() && margin_right.is_auto()) {
|
||||
auto remainder = available - to_px(left) - to_px(right);
|
||||
if (remainder < 0) {
|
||||
margin_left = CSS::Length::make_px(0);
|
||||
margin_right = CSS::Length::make_px(0);
|
||||
} else {
|
||||
margin_left = CSS::Length::make_px(remainder / 2);
|
||||
margin_right = CSS::Length::make_px(remainder / 2);
|
||||
}
|
||||
}
|
||||
|
||||
// 5. If at this point there is an 'auto' left, solve the equation for that value.
|
||||
if (left.is_auto()) {
|
||||
left = CSS::Length::make_px(available - to_px(right) - to_px(margin_left) - to_px(margin_right));
|
||||
} else if (right.is_auto()) {
|
||||
right = CSS::Length::make_px(available - to_px(left) - to_px(margin_left) - to_px(margin_right));
|
||||
} else if (margin_left.is_auto()) {
|
||||
margin_left = CSS::Length::make_px(available - to_px(left) - to_px(right) - to_px(margin_right));
|
||||
} else if (margin_right.is_auto()) {
|
||||
margin_right = CSS::Length::make_px(available - to_px(left) - to_px(margin_left) - to_px(right));
|
||||
}
|
||||
|
||||
// 6. If at this point the values are over-constrained, ignore the value for either 'left'
|
||||
// (in case the 'direction' property of the containing block is 'rtl') or 'right'
|
||||
// (in case 'direction' is 'ltr') and solve for that value.
|
||||
if (0 != available - to_px(left) - to_px(right) - to_px(margin_left) - to_px(margin_right)) {
|
||||
right = CSS::Length::make_px(available - to_px(left) - to_px(margin_left) - to_px(margin_right));
|
||||
}
|
||||
|
||||
auto& box_state = m_state.get_mutable(box);
|
||||
box_state.inset_left = to_px(left);
|
||||
box_state.inset_right = to_px(right);
|
||||
box_state.margin_left = to_px(margin_left);
|
||||
box_state.margin_right = to_px(margin_right);
|
||||
box_state.set_content_width(width);
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/css-position-3/#abs-non-replaced-height
|
||||
|
@ -1093,11 +1165,75 @@ void FormattingContext::layout_absolutely_positioned_element(Box const& box, Ava
|
|||
independent_formatting_context->parent_context_did_dimension_child_root_box();
|
||||
}
|
||||
|
||||
void FormattingContext::compute_height_for_absolutely_positioned_replaced_element(Box const& box, AvailableSpace const& available_space, BeforeOrAfterInsideLayout)
|
||||
void FormattingContext::compute_height_for_absolutely_positioned_replaced_element(Box const& box, AvailableSpace const& available_space, BeforeOrAfterInsideLayout before_or_after_inside_layout)
|
||||
{
|
||||
// 10.6.5 Absolutely positioned, replaced elements
|
||||
// This situation is similar to 10.6.4, except that the element has an intrinsic height.
|
||||
|
||||
// The used value of 'height' is determined as for inline replaced elements.
|
||||
m_state.get_mutable(box).set_content_height(compute_height_for_replaced_element(box, available_space));
|
||||
auto height = compute_height_for_replaced_element(box, available_space);
|
||||
|
||||
auto height_of_containing_block = available_space.height.to_px();
|
||||
auto available = height_of_containing_block - height;
|
||||
auto const& computed_values = box.computed_values();
|
||||
auto top = computed_values.inset().top();
|
||||
auto margin_top = computed_values.margin().top();
|
||||
auto bottom = computed_values.inset().bottom();
|
||||
auto margin_bottom = computed_values.margin().bottom();
|
||||
auto static_position = calculate_static_position(box);
|
||||
|
||||
auto to_px = [&](const CSS::LengthPercentage& l) {
|
||||
return l.to_px(box, height_of_containing_block);
|
||||
};
|
||||
|
||||
// If 'margin-top' or 'margin-bottom' is specified as 'auto' its used value is determined by the rules below.
|
||||
// 2. If both 'top' and 'bottom' have the value 'auto', replace 'top' with the element's static position.
|
||||
if (top.is_auto() && bottom.is_auto()) {
|
||||
top = CSS::Length::make_px(static_position.x());
|
||||
}
|
||||
|
||||
// 3. If 'bottom' is 'auto', replace any 'auto' on 'margin-top' or 'margin-bottom' with '0'.
|
||||
if (bottom.is_auto()) {
|
||||
if (margin_top.is_auto())
|
||||
margin_top = CSS::Length::make_px(0);
|
||||
if (margin_bottom.is_auto())
|
||||
margin_bottom = CSS::Length::make_px(0);
|
||||
}
|
||||
|
||||
// 4. If at this point both 'margin-top' and 'margin-bottom' are still 'auto',
|
||||
// solve the equation under the extra constraint that the two margins must get equal values.
|
||||
if (margin_top.is_auto() && margin_bottom.is_auto()) {
|
||||
auto remainder = available - to_px(top) - to_px(bottom);
|
||||
margin_top = CSS::Length::make_px(remainder / 2);
|
||||
margin_bottom = CSS::Length::make_px(remainder / 2);
|
||||
}
|
||||
|
||||
// 5. If at this point there is an 'auto' left, solve the equation for that value.
|
||||
if (top.is_auto()) {
|
||||
top = CSS::Length::make_px(available - to_px(bottom) - to_px(margin_top) - to_px(margin_bottom));
|
||||
} else if (bottom.is_auto()) {
|
||||
bottom = CSS::Length::make_px(available - to_px(top) - to_px(margin_top) - to_px(margin_bottom));
|
||||
} else if (margin_top.is_auto()) {
|
||||
margin_top = CSS::Length::make_px(available - to_px(top) - to_px(bottom) - to_px(margin_bottom));
|
||||
} else if (margin_bottom.is_auto()) {
|
||||
margin_bottom = CSS::Length::make_px(available - to_px(top) - to_px(margin_top) - to_px(bottom));
|
||||
}
|
||||
|
||||
// 6. If at this point the values are over-constrained, ignore the value for 'bottom' and solve for that value.
|
||||
if (0 != available - to_px(top) - to_px(bottom) - to_px(margin_top) - to_px(margin_bottom)) {
|
||||
bottom = CSS::Length::make_px(available - to_px(top) - to_px(margin_top) - to_px(margin_bottom));
|
||||
}
|
||||
|
||||
auto& box_state = m_state.get_mutable(box);
|
||||
box_state.set_content_height(height);
|
||||
|
||||
// do not set calculated insets or margins on the first pass, there will be a second pass
|
||||
if (before_or_after_inside_layout == BeforeOrAfterInsideLayout::Before)
|
||||
return;
|
||||
box_state.inset_top = to_px(top);
|
||||
box_state.inset_bottom = to_px(bottom);
|
||||
box_state.margin_top = to_px(margin_top);
|
||||
box_state.margin_bottom = to_px(margin_bottom);
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/css-position-3/#relpos-insets
|
||||
|
|
Loading…
Reference in a new issue