From 902bde7d9c1e9c88ed014ee0a57435ff023437dc Mon Sep 17 00:00:00 2001 From: Guillaume Ayoub Date: Thu, 30 Jun 2022 15:29:50 +0200 Subject: [PATCH] Take care of floats when removing placeholders MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- tests/draw/test_float.py | 81 +++++++++++++++++++++++++++++++++++ weasyprint/layout/__init__.py | 2 +- weasyprint/layout/absolute.py | 3 +- weasyprint/layout/block.py | 27 ++++++++---- weasyprint/layout/inline.py | 8 ++-- weasyprint/layout/page.py | 9 ++-- 6 files changed, 111 insertions(+), 19 deletions(-) diff --git a/tests/draw/test_float.py b/tests/draw/test_float.py index 49665d83..f31326f5 100644 --- a/tests/draw/test_float.py +++ b/tests/draw/test_float.py @@ -659,3 +659,84 @@ def test_float_split_10(assert_pixels):
bbbbb bbbbb
aa aa
bbb bbb
''') + + +@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 + ________________ + ''', ''' + +
+ a +

aa

aa

+

bb

bb

''') + + +@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 + ________________ + ''', ''' + +
+
+

aa

aa

+ a +

bb

bb

''') diff --git a/weasyprint/layout/__init__.py b/weasyprint/layout/__init__.py index d9774b16..7fdda763 100644 --- a/weasyprint/layout/__init__.py +++ b/weasyprint/layout/__init__.py @@ -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 diff --git a/weasyprint/layout/absolute.py b/weasyprint/layout/absolute.py index f7d82e03..6640c09c 100644 --- a/weasyprint/layout/absolute.py +++ b/weasyprint/layout/absolute.py @@ -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, diff --git a/weasyprint/layout/block.py b/weasyprint/layout/block.py index b3406f29..951622ed 100644 --- a/weasyprint/layout/block.py +++ b/weasyprint/layout/block.py @@ -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( - 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, @@ -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): diff --git a/weasyprint/layout/inline.py b/weasyprint/layout/inline.py index b6171543..e818da2d 100644 --- a/weasyprint/layout/inline.py +++ b/weasyprint/layout/inline.py @@ -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 diff --git a/weasyprint/layout/page.py b/weasyprint/layout/page.py index 054364e1..8865e68b 100644 --- a/weasyprint/layout/page.py +++ b/weasyprint/layout/page.py @@ -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,