1
1
mirror of https://github.com/Kozea/WeasyPrint.git synced 2024-10-04 07:57:52 +03:00

Take care of floats when removing placeholders

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.
This commit is contained in:
Guillaume Ayoub 2022-06-30 15:29:50 +02:00
parent 74f367c2a3
commit 902bde7d9c
6 changed files with 111 additions and 19 deletions

View File

@ -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>''')

View File

@ -233,7 +233,7 @@ class LayoutContext:
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

View File

@ -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,

View File

@ -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':
@ -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,
@ -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
@ -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(
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)
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,
@ -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 (
@ -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 += (
@ -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):
@ -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):

View File

@ -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)
@ -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

View File

@ -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(
@ -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,