From d5d71afb01d1a58c513c9e1dd22719c41a301231 Mon Sep 17 00:00:00 2001 From: Guillaume Ayoub Date: Fri, 27 Sep 2024 20:14:26 +0200 Subject: [PATCH 1/2] Add method on boxes testing if they establish a formatting context MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit That’s more consistent with other equivalent methods. --- weasyprint/formatting_structure/boxes.py | 13 ++++++++++ weasyprint/layout/block.py | 32 +++--------------------- 2 files changed, 17 insertions(+), 28 deletions(-) diff --git a/weasyprint/formatting_structure/boxes.py b/weasyprint/formatting_structure/boxes.py index 82fe683cb..3031e0cfd 100644 --- a/weasyprint/formatting_structure/boxes.py +++ b/weasyprint/formatting_structure/boxes.py @@ -310,6 +310,19 @@ def is_monolithic(self): (self.style['overflow'] == 'hidden' and self.style['height'] != 'auto')) + def establishes_formatting_context(self): + """Return whether this box establishes a block formatting context.""" + # See https://www.w3.org/TR/CSS2/visuren.html#block-formatting + # TODO: columns shouldn't be block boxes, this condition would then be + # useless when this is fixed + return ( + self.is_floated() or + self.is_absolutely_positioned() or + self.is_column or + (isinstance(self, BlockContainerBox) and not isinstance(self, BlockBox)) or + (isinstance(self, BlockBox) and self.style['overflow'] != 'visible') or + 'flow-root' in self.style['display']) + # Start and end page values for named pages def page_values(self): diff --git a/weasyprint/layout/block.py b/weasyprint/layout/block.py index 86f45ddf7..0bec3e428 100644 --- a/weasyprint/layout/block.py +++ b/weasyprint/layout/block.py @@ -630,7 +630,7 @@ def block_container_layout(context, box, bottom_space, skip_stack, # block_container_layout, there's probably a better solution. assert isinstance(box, (boxes.BlockContainerBox, boxes.FlexBox)) - if establishes_formatting_context(box): + if box.establishes_formatting_context(): context.create_block_formatting_context() is_start = skip_stack is None @@ -652,7 +652,7 @@ def block_container_layout(context, box, bottom_space, skip_stack, collapsing_with_children = not ( box.border_top_width or box.padding_top or box.is_flex_item or - box.is_grid_item or establishes_formatting_context(box) or + box.is_grid_item or box.establishes_formatting_context() or box.is_for_root_element) if collapsing_with_children: # Not counting margins in adjoining_margins, if any @@ -800,7 +800,7 @@ def block_container_layout(context, box, bottom_space, skip_stack, if (box.border_bottom_width or box.padding_bottom or - establishes_formatting_context(box) or + box.establishes_formatting_context() or box.is_for_root_element or box.is_table_wrapper): position_y += collapse_margin(adjoining_margins) @@ -837,7 +837,7 @@ def block_container_layout(context, box, bottom_space, skip_stack, for child in new_box.children: relative_positioning(child, (new_box.width, new_box.height)) - if establishes_formatting_context(new_box): + if new_box.establishes_formatting_context(): context.finish_block_formatting_context(new_box) if discard or not box_is_fragmented: @@ -875,30 +875,6 @@ def collapse_margin(adjoining_margins): return max(positives) + min(negatives) -def establishes_formatting_context(box): - """Return whether a box establishes a block formatting context. - - See https://www.w3.org/TR/CSS2/visuren.html#block-formatting - - """ - return ( - box.is_floated() - ) or ( - box.is_absolutely_positioned() - ) or ( - # TODO: columns shouldn't be block boxes, this condition would then be - # useless when this is fixed - box.is_column - ) or ( - isinstance(box, boxes.BlockContainerBox) and - not isinstance(box, boxes.BlockBox) - ) or ( - isinstance(box, boxes.BlockBox) and box.style['overflow'] != 'visible' - ) or ( - 'flow-root' in box.style['display'] - ) - - def block_level_page_break(sibling_before, sibling_after): """Get the correct page break value between siblings. From af990507bc102cbb7a13ae8a5e2f045f7fd363e8 Mon Sep 17 00:00:00 2001 From: Guillaume Ayoub Date: Fri, 27 Sep 2024 20:22:09 +0200 Subject: [PATCH 2/2] Avoid float collision with box establishing formatting context Related to #2019. --- weasyprint/formatting_structure/boxes.py | 2 -- weasyprint/layout/block.py | 7 +++++-- weasyprint/layout/float.py | 5 +++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/weasyprint/formatting_structure/boxes.py b/weasyprint/formatting_structure/boxes.py index 3031e0cfd..548e6be3d 100644 --- a/weasyprint/formatting_structure/boxes.py +++ b/weasyprint/formatting_structure/boxes.py @@ -313,8 +313,6 @@ def is_monolithic(self): def establishes_formatting_context(self): """Return whether this box establishes a block formatting context.""" # See https://www.w3.org/TR/CSS2/visuren.html#block-formatting - # TODO: columns shouldn't be block boxes, this condition would then be - # useless when this is fixed return ( self.is_floated() or self.is_absolutely_positioned() or diff --git a/weasyprint/layout/block.py b/weasyprint/layout/block.py index 0bec3e428..8cc2a87e3 100644 --- a/weasyprint/layout/block.py +++ b/weasyprint/layout/block.py @@ -124,8 +124,11 @@ def block_box_layout(context, box, bottom_space, skip_stack, result = block_container_layout( context, box, bottom_space, skip_stack, page_is_empty, absolute_boxes, fixed_boxes, adjoining_margins, discard, max_lines) - new_box = result[0] - if new_box and new_box.is_table_wrapper: + # TODO: columns shouldn't be block boxes, this condition would then be + # useless when this is fixed. + if not (new_box := result[0]) or new_box.is_column: + return result + if new_box.is_table_wrapper or new_box.establishes_formatting_context(): # Don't collide with floats # https://www.w3.org/TR/CSS21/visuren.html#floats position_x, position_y, _ = avoid_collisions( diff --git a/weasyprint/layout/float.py b/weasyprint/layout/float.py index 2a5bf8205..94369db74 100644 --- a/weasyprint/layout/float.py +++ b/weasyprint/layout/float.py @@ -195,12 +195,13 @@ def avoid_collisions(context, box, containing_block, outer=True): # - line boxes # - table wrappers # - block-level replaced box - # - element establishing new formatting contexts (not handled) + # - element establishing new formatting contexts assert ( (box.style['float'] in ('right', 'left')) or isinstance(box, boxes.LineBox) or box.is_table_wrapper or - isinstance(box, boxes.BlockReplacedBox)) + isinstance(box, boxes.BlockReplacedBox) or + box.establishes_formatting_context()) # The x-position of the box depends on its type. position_x = max_left_bound