Skip to content

Commit

Permalink
Take care of floats when removing placeholders
Browse files Browse the repository at this point in the history
Removing placeholders is something we have to do when we must discard a part of
the layout that has already been done. It currently removes absolutely
positioned placeholders and footnotes.

The same has to be done with split floats, that’s what this commit is about.

We have to change the structure of the broken_out_of_flow attribute, as we have
to get a reliable way to reach the saved data using from the real element in
the tree. The new structure is thus a dictionary whose keys are the boxes in
the tree (placeholder for absolutes, partial elements for floats) and whose
values are the original_box+parent+resume_at.

Fix #1669.
  • Loading branch information
liZe committed Jun 30, 2022
1 parent 74f367c commit 902bde7
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 19 deletions.
81 changes: 81 additions & 0 deletions tests/draw/test_float.py
Original file line number Diff line number Diff line change
Expand Up @@ -659,3 +659,84 @@ def test_float_split_10(assert_pixels):
<div>bbbbb bbbbb</div>
<div class="split">aa aa</div>
<div>bbb bbb</div>''')


@assert_no_logs
def test_float_split_11(assert_pixels):
assert_pixels('''
BBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBB
BBBBGG______BBBB
BBBBGG______BBBB
BBBB________BBBB
BBBB________BBBB
________________
''', '''
<style>
@font-face {src: url(weasyprint.otf); font-family: weasyprint}
@page {
size: 16px 5px;
}
body {
color: lime;
font-family: weasyprint;
font-size: 2px;
line-height: 1;
}
article {
background: blue;
height: 5px;
}
div {
background: red;
color: blue;
}
</style>
<article></article>
a
<div style="float: left"><p>aa<p>aa</div>
<div style="float: right"><p>bb<p>bb</div>''')


@assert_no_logs
def test_float_split_12(assert_pixels):
assert_pixels('''
BBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBB
BBBBGG______BBBB
BBBBGG______BBBB
BBBB________BBBB
BBBB________BBBB
________________
''', '''
<style>
@font-face {src: url(weasyprint.otf); font-family: weasyprint}
@page {
size: 16px 5px;
}
body {
color: lime;
font-family: weasyprint;
font-size: 2px;
line-height: 1;
}
article {
background: blue;
height: 5px;
}
div {
background: red;
color: blue;
}
</style>
<article></article>
<section>
<div style="float: left"><p>aa<p>aa</div>
a
<div style="float: right"><p>bb<p>bb</div>''')
2 changes: 1 addition & 1 deletion weasyprint/layout/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ def __init__(self, style_for, get_image_from_uri, font_config,
self.running_elements = defaultdict(lambda: defaultdict(lambda: []))
self.current_page = None
self.forced_break = False
self.broken_out_of_flow = []
self.broken_out_of_flow = {}
self.in_column = False

# Cache
Expand Down
3 changes: 2 additions & 1 deletion weasyprint/layout/absolute.py
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,8 @@ def absolute_layout(context, placeholder, containing_block, fixed_boxes,
context, box, containing_block, fixed_boxes, bottom_space, skip_stack)
placeholder.set_laid_out_box(new_box)
if resume_at:
context.broken_out_of_flow.append((box, containing_block, resume_at))
context.broken_out_of_flow[placeholder] = (
box, containing_block, resume_at)


def absolute_box_layout(context, box, containing_block, fixed_boxes,
Expand Down
27 changes: 18 additions & 9 deletions weasyprint/layout/block.py
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ def _out_of_flow_layout(context, box, index, child, new_children,

child.position_y += collapse_margin(adjoining_margins)
if child.is_absolutely_positioned():
placeholder = AbsolutePlaceholder(child)
new_child = placeholder = AbsolutePlaceholder(child)
placeholder.index = index
new_children.append(placeholder)
if child.style['position'] == 'absolute':
Expand Down Expand Up @@ -262,7 +262,7 @@ def _out_of_flow_layout(context, box, index, child, new_children,
page = context.current_page
context.running_elements[running_name][page].append(child)

return stop, resume_at, out_of_flow_resume_at
return stop, resume_at, new_child, out_of_flow_resume_at


def _break_line(context, box, line, new_children, lines_iterator,
Expand Down Expand Up @@ -629,7 +629,7 @@ def block_container_layout(context, box, bottom_space, skip_stack,
new_children = []
next_page = {'break': 'any', 'page': None}
all_footnotes = []
broken_out_of_flow = []
broken_out_of_flow = {}

last_in_flow_child = None

Expand All @@ -649,12 +649,14 @@ def block_container_layout(context, box, bottom_space, skip_stack,

if not child.is_in_normal_flow():
abort = False
stop, resume_at, out_of_flow_resume_at = _out_of_flow_layout(
context, box, index, child, new_children, page_is_empty,
absolute_boxes, fixed_boxes, adjoining_margins,
bottom_space)
stop, resume_at, new_child, out_of_flow_resume_at = (
_out_of_flow_layout(
context, box, index, child, new_children, page_is_empty,
absolute_boxes, fixed_boxes, adjoining_margins,
bottom_space))
if out_of_flow_resume_at:
broken_out_of_flow.append((child, box, out_of_flow_resume_at))
broken_out_of_flow[new_child] = (
child, box, out_of_flow_resume_at)

elif isinstance(child, boxes.LineBox):
(abort, stop, resume_at, position_y,
Expand Down Expand Up @@ -696,6 +698,8 @@ def block_container_layout(context, box, bottom_space, skip_stack,

if abort:
page = child.page_values()[0]
remove_placeholders(
context, box.children[skip:], absolute_boxes, fixed_boxes)
for footnote in new_footnotes:
context.unlayout_footnote(footnote)
return (
Expand All @@ -720,7 +724,8 @@ def block_container_layout(context, box, bottom_space, skip_stack,
return (
None, None, {'break': 'any', 'page': None}, [], False, max_lines)

context.broken_out_of_flow.extend(broken_out_of_flow)
for key, value in broken_out_of_flow.items():
context.broken_out_of_flow[key] = value

if collapsing_with_children:
box.position_y += (
Expand Down Expand Up @@ -1005,6 +1010,8 @@ def remove_placeholders(context, box_list, absolute_boxes, fixed_boxes):
For boxes that have been removed in find_earlier_page_break(), remove the
matching placeholders in absolute_boxes and fixed_boxes.
Also takes care of removed footnotes and floats.
"""
for box in box_list:
if isinstance(box, boxes.ParentBox):
Expand All @@ -1017,6 +1024,8 @@ def remove_placeholders(context, box_list, absolute_boxes, fixed_boxes):
fixed_boxes.remove(box)
if box.footnote:
context.unlayout_footnote(box.footnote)
if box in context.broken_out_of_flow:
context.broken_out_of_flow.pop(box)


def avoid_page_break(page_break, context):
Expand Down
8 changes: 4 additions & 4 deletions weasyprint/layout/inline.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,8 @@ def get_next_linebox(context, linebox, position_y, bottom_space, skip_stack,
fixed_boxes, bottom_space, skip_stack=None)
float_children.append(new_waiting_float)
if waiting_float_resume_at:
context.broken_out_of_flow.append(
(waiting_float, containing_block, waiting_float_resume_at))
context.broken_out_of_flow[new_waiting_float] = (
waiting_float, containing_block, waiting_float_resume_at)
if float_children:
line.children += tuple(float_children)

Expand Down Expand Up @@ -559,8 +559,8 @@ def _out_of_flow_layout(context, box, containing_block, index, child,
context, child, containing_block, absolute_boxes, fixed_boxes,
bottom_space, skip_stack=None)
if float_resume_at:
context.broken_out_of_flow.append(
(child, containing_block, float_resume_at))
context.broken_out_of_flow[child] = (
child, containing_block, float_resume_at)
waiting_children.append((index, new_child, child))
child = new_child

Expand Down
9 changes: 5 additions & 4 deletions weasyprint/layout/page.py
Original file line number Diff line number Diff line change
Expand Up @@ -564,8 +564,9 @@ def make_page(context, root_box, page_type, resume_at, page_number,
adjoining_margins = []
positioned_boxes = [] # Mixed absolute and fixed
out_of_flow_boxes = []
broken_out_of_flow = []
for box, containing_block, skip_stack in context.broken_out_of_flow:
broken_out_of_flow = {}
context_out_of_flow = context.broken_out_of_flow.values()
for box, containing_block, skip_stack in context_out_of_flow:
box.position_y = 0
if box.is_floated():
out_of_flow_box, out_of_flow_resume_at = float_layout(
Expand All @@ -578,8 +579,8 @@ def make_page(context, root_box, page_type, resume_at, page_number,
skip_stack)
out_of_flow_boxes.append(out_of_flow_box)
if out_of_flow_resume_at:
broken_out_of_flow.append(
(box, containing_block, out_of_flow_resume_at))
broken_out_of_flow[out_of_flow_box] = (
box, containing_block, out_of_flow_resume_at)
context.broken_out_of_flow = broken_out_of_flow
root_box, resume_at, next_page, _, _, _ = block_level_layout(
context, root_box, 0, resume_at, initial_containing_block,
Expand Down

0 comments on commit 902bde7

Please sign in to comment.