|
@@ -329,9 +329,8 @@ void BlockFormattingContext::compute_height(Box const& box, FormattingState& sta
|
|
|
|
|
|
auto& box_state = state.get_mutable(box);
|
|
|
|
|
|
- // FIXME: While negative values are generally allowed for margins, for now just ignore those for height calculation
|
|
|
- box_state.margin_top = max(computed_values.margin().top.resolved(box, width_of_containing_block_as_length).to_px(box), 0);
|
|
|
- box_state.margin_bottom = max(computed_values.margin().bottom.resolved(box, width_of_containing_block_as_length).to_px(box), 0);
|
|
|
+ box_state.margin_top = computed_values.margin().top.resolved(box, width_of_containing_block_as_length).to_px(box);
|
|
|
+ box_state.margin_bottom = computed_values.margin().bottom.resolved(box, width_of_containing_block_as_length).to_px(box);
|
|
|
|
|
|
box_state.border_top = computed_values.border_top().width;
|
|
|
box_state.border_bottom = computed_values.border_bottom().width;
|
|
@@ -439,42 +438,57 @@ void BlockFormattingContext::place_block_level_element_in_normal_flow_vertically
|
|
|
|
|
|
compute_vertical_box_model_metrics(child_box, containing_block);
|
|
|
|
|
|
- float y = box_state.margin_box_top()
|
|
|
+ float y = box_state.border_box_top()
|
|
|
+ box_state.offset_top;
|
|
|
|
|
|
- // NOTE: Empty (0-height) preceding siblings have their margins collapsed with *their* preceding sibling, etc.
|
|
|
- float collapsed_bottom_margin_of_preceding_siblings = 0;
|
|
|
+ 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);
|
|
|
- collapsed_bottom_margin_of_preceding_siblings = max(collapsed_bottom_margin_of_preceding_siblings, relevant_sibling_state.margin_bottom);
|
|
|
+ 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();
|
|
|
-
|
|
|
- // Collapse top margin with bottom margin of preceding siblings if needed
|
|
|
- float my_margin_top = box_state.margin_top;
|
|
|
-
|
|
|
- if (my_margin_top < 0 || collapsed_bottom_margin_of_preceding_siblings < 0) {
|
|
|
- // Negative margins present.
|
|
|
- float largest_negative_margin = -min(my_margin_top, collapsed_bottom_margin_of_preceding_siblings);
|
|
|
- float largest_positive_margin = (my_margin_top < 0 && collapsed_bottom_margin_of_preceding_siblings < 0) ? 0 : max(my_margin_top, collapsed_bottom_margin_of_preceding_siblings);
|
|
|
- float final_margin = largest_positive_margin - largest_negative_margin;
|
|
|
- y += final_margin - my_margin_top;
|
|
|
- } else if (collapsed_bottom_margin_of_preceding_siblings > my_margin_top) {
|
|
|
- // Sibling's margin is larger than mine, adjust so we use sibling's.
|
|
|
- y += collapsed_bottom_margin_of_preceding_siblings - my_margin_top;
|
|
|
- }
|
|
|
+ + relevant_sibling_state.border_box_bottom()
|
|
|
+ + collapsed_margin;
|
|
|
+ } else {
|
|
|
+ y += box_state.margin_top;
|
|
|
}
|
|
|
|
|
|
auto clear_floating_boxes = [&](FloatSideData& float_side) {
|