Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Avoid float collision with box establishing formatting context #2260

Merged
merged 2 commits into from
Sep 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading