mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 04:27:44 +00:00
LibWeb: Factor out compute_y_position
Factor out the code that computes the vertical position of a Box with respect to its siblings so that it can be used when computing the absolutely positioned divs as well.
This commit is contained in:
parent
99ae4fa161
commit
65e7126c48
3 changed files with 58 additions and 51 deletions
|
@ -505,57 +505,7 @@ void BlockFormattingContext::place_block_level_element_in_normal_flow_vertically
|
||||||
|
|
||||||
compute_vertical_box_model_metrics(child_box, containing_block);
|
compute_vertical_box_model_metrics(child_box, containing_block);
|
||||||
|
|
||||||
float y = box_state.border_box_top();
|
auto y = FormattingContext::compute_box_y_position_with_respect_to_siblings(child_box, box_state);
|
||||||
|
|
||||||
Vector<float> collapsible_margins;
|
|
||||||
|
|
||||||
auto* relevant_sibling = child_box.previous_sibling_of_type<Layout::BlockContainer>();
|
|
||||||
while (relevant_sibling != nullptr) {
|
|
||||||
if (!relevant_sibling->is_absolutely_positioned() && !relevant_sibling->is_floating()) {
|
|
||||||
auto const& relevant_sibling_state = m_state.get(*relevant_sibling);
|
|
||||||
collapsible_margins.append(relevant_sibling_state.margin_bottom);
|
|
||||||
// NOTE: Empty (0-height) preceding siblings have their margins collapsed with *their* preceding sibling, etc.
|
|
||||||
if (relevant_sibling_state.border_box_height() > 0)
|
|
||||||
break;
|
|
||||||
collapsible_margins.append(relevant_sibling_state.margin_top);
|
|
||||||
}
|
|
||||||
relevant_sibling = relevant_sibling->previous_sibling_of_type<Layout::BlockContainer>();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (relevant_sibling) {
|
|
||||||
// Collapse top margin with the collapsed margin(s) of preceding siblings.
|
|
||||||
collapsible_margins.append(box_state.margin_top);
|
|
||||||
|
|
||||||
float smallest_margin = 0;
|
|
||||||
float largest_margin = 0;
|
|
||||||
size_t negative_margin_count = 0;
|
|
||||||
for (auto margin : collapsible_margins) {
|
|
||||||
if (margin < 0)
|
|
||||||
++negative_margin_count;
|
|
||||||
largest_margin = max(largest_margin, margin);
|
|
||||||
smallest_margin = min(smallest_margin, margin);
|
|
||||||
}
|
|
||||||
|
|
||||||
float collapsed_margin = 0;
|
|
||||||
if (negative_margin_count == collapsible_margins.size()) {
|
|
||||||
// When all margins are negative, the size of the collapsed margin is the smallest (most negative) margin.
|
|
||||||
collapsed_margin = smallest_margin;
|
|
||||||
} else if (negative_margin_count > 0) {
|
|
||||||
// When negative margins are involved, the size of the collapsed margin is the sum of the largest positive margin and the smallest (most negative) negative margin.
|
|
||||||
collapsed_margin = largest_margin + smallest_margin;
|
|
||||||
} else {
|
|
||||||
// Otherwise, collapse all the adjacent margins by using only the largest one.
|
|
||||||
collapsed_margin = largest_margin;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto const& relevant_sibling_state = m_state.get(*relevant_sibling);
|
|
||||||
y += relevant_sibling_state.offset.y()
|
|
||||||
+ relevant_sibling_state.content_height()
|
|
||||||
+ relevant_sibling_state.border_box_bottom()
|
|
||||||
+ collapsed_margin;
|
|
||||||
} else {
|
|
||||||
y += box_state.margin_top;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto clear_floating_boxes = [&](FloatSideData& float_side) {
|
auto clear_floating_boxes = [&](FloatSideData& float_side) {
|
||||||
if (!float_side.current_boxes.is_empty()) {
|
if (!float_side.current_boxes.is_empty()) {
|
||||||
|
|
|
@ -1089,4 +1089,59 @@ float FormattingContext::containing_block_height_for(Box const& box, LayoutState
|
||||||
VERIFY_NOT_REACHED();
|
VERIFY_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float FormattingContext::compute_box_y_position_with_respect_to_siblings(Box const& child_box, LayoutState::UsedValues const& box_state)
|
||||||
|
{
|
||||||
|
float y = box_state.border_box_top();
|
||||||
|
|
||||||
|
Vector<float> collapsible_margins;
|
||||||
|
|
||||||
|
auto* relevant_sibling = child_box.previous_sibling_of_type<Layout::BlockContainer>();
|
||||||
|
while (relevant_sibling != nullptr) {
|
||||||
|
if (!relevant_sibling->is_absolutely_positioned() && !relevant_sibling->is_floating()) {
|
||||||
|
auto const& relevant_sibling_state = m_state.get(*relevant_sibling);
|
||||||
|
collapsible_margins.append(relevant_sibling_state.margin_bottom);
|
||||||
|
// NOTE: Empty (0-height) preceding siblings have their margins collapsed with *their* preceding sibling, etc.
|
||||||
|
if (relevant_sibling_state.border_box_height() > 0)
|
||||||
|
break;
|
||||||
|
collapsible_margins.append(relevant_sibling_state.margin_top);
|
||||||
|
}
|
||||||
|
relevant_sibling = relevant_sibling->previous_sibling_of_type<Layout::BlockContainer>();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (relevant_sibling) {
|
||||||
|
// Collapse top margin with the collapsed margin(s) of preceding siblings.
|
||||||
|
collapsible_margins.append(box_state.margin_top);
|
||||||
|
|
||||||
|
float smallest_margin = 0;
|
||||||
|
float largest_margin = 0;
|
||||||
|
size_t negative_margin_count = 0;
|
||||||
|
for (auto margin : collapsible_margins) {
|
||||||
|
if (margin < 0)
|
||||||
|
++negative_margin_count;
|
||||||
|
largest_margin = max(largest_margin, margin);
|
||||||
|
smallest_margin = min(smallest_margin, margin);
|
||||||
|
}
|
||||||
|
|
||||||
|
float collapsed_margin = 0;
|
||||||
|
if (negative_margin_count == collapsible_margins.size()) {
|
||||||
|
// When all margins are negative, the size of the collapsed margin is the smallest (most negative) margin.
|
||||||
|
collapsed_margin = smallest_margin;
|
||||||
|
} else if (negative_margin_count > 0) {
|
||||||
|
// When negative margins are involved, the size of the collapsed margin is the sum of the largest positive margin and the smallest (most negative) negative margin.
|
||||||
|
collapsed_margin = largest_margin + smallest_margin;
|
||||||
|
} else {
|
||||||
|
// Otherwise, collapse all the adjacent margins by using only the largest one.
|
||||||
|
collapsed_margin = largest_margin;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto const& relevant_sibling_state = m_state.get(*relevant_sibling);
|
||||||
|
return y + relevant_sibling_state.offset.y()
|
||||||
|
+ relevant_sibling_state.content_height()
|
||||||
|
+ relevant_sibling_state.border_box_bottom()
|
||||||
|
+ collapsed_margin;
|
||||||
|
} else {
|
||||||
|
return y + box_state.margin_top;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,6 +63,8 @@ public:
|
||||||
|
|
||||||
virtual void run_intrinsic_sizing(Box const&);
|
virtual void run_intrinsic_sizing(Box const&);
|
||||||
|
|
||||||
|
float compute_box_y_position_with_respect_to_siblings(Box const&, LayoutState::UsedValues const&);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
FormattingContext(Type, LayoutState&, Box const&, FormattingContext* parent = nullptr);
|
FormattingContext(Type, LayoutState&, Box const&, FormattingContext* parent = nullptr);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue