Skip to content

Commit

Permalink
Merge pull request #2260 from Kozea/float-overflow
Browse files Browse the repository at this point in the history
Avoid float collision with box establishing formatting context
  • Loading branch information
liZe authored Sep 27, 2024
2 parents 6169099 + af99050 commit d5a9485
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 32 deletions.
11 changes: 11 additions & 0 deletions weasyprint/formatting_structure/boxes.py
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,17 @@ 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
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):
Expand Down
39 changes: 9 additions & 30 deletions weasyprint/layout/block.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -630,7 +633,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
Expand All @@ -652,7 +655,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
Expand Down Expand Up @@ -800,7 +803,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)
Expand Down Expand Up @@ -837,7 +840,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:
Expand Down Expand Up @@ -875,30 +878,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.
Expand Down
5 changes: 3 additions & 2 deletions weasyprint/layout/float.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit d5a9485

Please sign in to comment.