@@ -821,37 +821,73 @@ impl SequentialLayoutState {
821
821
self . current_margin = CollapsedMargin :: zero ( ) ;
822
822
}
823
823
824
- /// Returns the amount of clearance that a block with the given `clear` value at the current
825
- /// `bfc_relative_block_position` (with top margin included in `current_margin` if applicable)
826
- /// needs to have.
824
+ /// Returns the amount of clearance (if any) that a block with the given `clear` value
825
+ /// needs to have at `current_block_position_including_margins()`.
826
+ /// `block_start_margin` is the top margin of the block, after collapsing (if possible)
827
+ /// with the margin of its contents. This must not be included in `current_margin`,
828
+ /// since adding clearance will prevent `current_margin` and `block_start_margin`
829
+ /// from collapsing together.
827
830
///
828
831
/// https://www.w3.org/TR/2011/REC-CSS2-20110607/visuren.html#flow-control
829
- pub ( crate ) fn calculate_clearance ( & self , clear_side : ClearSide ) -> Option < Length > {
832
+ pub ( crate ) fn calculate_clearance (
833
+ & self ,
834
+ clear_side : ClearSide ,
835
+ block_start_margin : & CollapsedMargin ,
836
+ ) -> Option < Length > {
830
837
if clear_side == ClearSide :: None {
831
838
return None ;
832
839
}
833
840
834
- let hypothetical_block_position = self . current_block_position_including_margins ( ) ;
841
+ // Calculate the hypothetical position where the element's top border edge
842
+ // would have been if the element's `clear` property had been `none`.
843
+ let hypothetical_block_position = self . bfc_relative_block_position +
844
+ self . current_margin . adjoin ( & block_start_margin) . solve ( ) ;
845
+
846
+ // Check if the hypothetical position is past the relevant floats,
847
+ // in that case we don't need to add clearance.
835
848
let clear_position = match clear_side {
836
849
ClearSide :: None => unreachable ! ( ) ,
837
- ClearSide :: Left => self
838
- . floats
839
- . clear_left_position
840
- . max ( hypothetical_block_position) ,
841
- ClearSide :: Right => self
842
- . floats
843
- . clear_right_position
844
- . max ( hypothetical_block_position) ,
850
+ ClearSide :: Left => self . floats . clear_left_position ,
851
+ ClearSide :: Right => self . floats . clear_right_position ,
845
852
ClearSide :: Both => self
846
853
. floats
847
854
. clear_left_position
848
- . max ( self . floats . clear_right_position )
849
- . max ( hypothetical_block_position) ,
855
+ . max ( self . floats . clear_right_position ) ,
850
856
} ;
851
857
if hypothetical_block_position >= clear_position {
852
858
return None ;
853
859
}
854
- Some ( clear_position - hypothetical_block_position)
860
+
861
+ // We need to add clearance between `current_margin` and `block_start_margin`,
862
+ // this prevents them from collapsing.
863
+ // Compute the position of the element's top border edge if we added
864
+ // a clearance of 0px.
865
+ let position_with_zero_clearance = self . bfc_relative_block_position +
866
+ self . current_margin . solve ( ) +
867
+ block_start_margin. solve ( ) ;
868
+
869
+ // Set clearance to the amount necessary to place the border edge of the block
870
+ // even with the bottom outer edge of the lowest float that is to be cleared.
871
+ // Note that CSS2 also allows the alternative option of flooring this amount by
872
+ // `hypothetical_block_position - position_with_zero_clearance`,
873
+ // but other browser don't seem to do that.
874
+ Some ( clear_position - position_with_zero_clearance)
875
+ }
876
+
877
+ /// Helper function that computes the clearance and adds `block_start_margin` accordingly.
878
+ /// If there is no clearance, `block_start_margin` can just be adjoined to `current_margin`.
879
+ /// But clearance prevents them from collapsing, so `collapse_margins()` is called.
880
+ pub ( crate ) fn calculate_clearance_and_adjoin_margin (
881
+ & mut self ,
882
+ style : & Arc < ComputedValues > ,
883
+ block_start_margin : & CollapsedMargin ,
884
+ ) -> Option < Length > {
885
+ let clearance = self . calculate_clearance ( ClearSide :: from_style ( style) , & block_start_margin) ;
886
+ if clearance. is_some ( ) {
887
+ self . collapse_margins ( ) ;
888
+ }
889
+ self . adjoin_assign ( & block_start_margin) ;
890
+ clearance
855
891
}
856
892
857
893
/// Adds a new adjoining margin.
0 commit comments