Skip to content

Commit

Permalink
Handle parallel flows for floats in simple cases
Browse files Browse the repository at this point in the history
  • Loading branch information
liZe committed Nov 2, 2021
1 parent ecedc16 commit dbec957
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 48 deletions.
6 changes: 3 additions & 3 deletions weasyprint/layout/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,11 +218,11 @@ def __init__(self, style_for, get_image_from_uri, font_config,
self.target_collector = target_collector
self._excluded_shapes_lists = []
self.excluded_shapes = None # Not initialized yet
self.string_set = defaultdict(lambda: defaultdict(lambda: list()))
self.running_elements = defaultdict(
lambda: defaultdict(lambda: list()))
self.string_set = defaultdict(lambda: defaultdict(lambda: []))
self.running_elements = defaultdict(lambda: defaultdict(lambda: []))
self.current_page = None
self.forced_break = False
self.broken_out_of_flow = []

# Cache
self.strut_layouts = {}
Expand Down
17 changes: 11 additions & 6 deletions weasyprint/layout/block.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ def _out_of_flow_layout(context, box, index, child, new_children,
adjoining_margins, max_position_y):
stop = False
resume_at = None
out_of_flow_resume_at = None

child.position_y += collapse_margin(adjoining_margins)
if child.is_absolutely_positioned():
Expand All @@ -228,8 +229,9 @@ def _out_of_flow_layout(context, box, index, child, new_children,
else:
fixed_boxes.append(placeholder)
elif child.is_floated():
new_child = float_layout(
context, child, box, absolute_boxes, fixed_boxes)
new_child, out_of_flow_resume_at = float_layout(
context, child, box, absolute_boxes, fixed_boxes, max_position_y,
skip_stack=None)
# New page if overflow
if (page_is_empty and not new_children) or not (
new_child.position_y + new_child.height > max_position_y):
Expand All @@ -250,7 +252,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
return stop, resume_at, out_of_flow_resume_at


def _linebox_layout(context, box, index, child, new_children, page_is_empty,
Expand All @@ -266,8 +268,8 @@ def _linebox_layout(context, box, index, child, new_children, page_is_empty,
position_y += collapse_margin(adjoining_margins)
new_containing_block = box
lines_iterator = iter_line_boxes(
context, child, position_y, skip_stack, new_containing_block,
absolute_boxes, fixed_boxes, first_letter_style)
context, child, position_y, max_position_y, skip_stack,
new_containing_block, absolute_boxes, fixed_boxes, first_letter_style)
for i, (line, resume_at) in enumerate(lines_iterator):
line.resume_at = resume_at
new_position_y = line.position_y + line.height
Expand Down Expand Up @@ -567,10 +569,13 @@ def block_container_layout(context, box, max_position_y, skip_stack,

if not child.is_in_normal_flow():
abort = False
stop, resume_at = _out_of_flow_layout(
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,
allowed_max_position_y)
if out_of_flow_resume_at:
context.broken_out_of_flow.append(
(child, box, out_of_flow_resume_at))

elif isinstance(child, boxes.LineBox):
abort, stop, resume_at, position_y = _linebox_layout(
Expand Down
20 changes: 11 additions & 9 deletions weasyprint/layout/float.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ def float_width(box, context, containing_block):
box.width = shrink_to_fit(context, box, containing_block.width)


def float_layout(context, box, containing_block, absolute_boxes, fixed_boxes):
def float_layout(context, box, containing_block, absolute_boxes, fixed_boxes,
max_position_y, skip_stack):
"""Set the width and position of floating ``box``."""
from .block import block_container_layout
from .flex import flex_layout
Expand Down Expand Up @@ -61,26 +62,27 @@ def float_layout(context, box, containing_block, absolute_boxes, fixed_boxes):

if isinstance(box, boxes.BlockContainerBox):
context.create_block_formatting_context()
box, _, _, _, _ = block_container_layout(
context, box, max_position_y=float('inf'),
skip_stack=None, page_is_empty=False,
box, resume_at, _, _, _ = block_container_layout(
context, box, max_position_y=max_position_y,
skip_stack=skip_stack, page_is_empty=True,
absolute_boxes=absolute_boxes, fixed_boxes=fixed_boxes,
adjoining_margins=None, discard=False)
context.finish_block_formatting_context(box)
elif isinstance(box, boxes.FlexContainerBox):
box, _, _, _, _ = flex_layout(
context, box, max_position_y=float('inf'),
skip_stack=None, containing_block=containing_block,
page_is_empty=False, absolute_boxes=absolute_boxes,
box, resume_at, _, _, _ = flex_layout(
context, box, max_position_y=max_position_y,
skip_stack=skip_stack, containing_block=containing_block,
page_is_empty=True, absolute_boxes=absolute_boxes,
fixed_boxes=fixed_boxes)
else:
assert isinstance(box, boxes.BlockReplacedBox)
resume_at = None

box = find_float_position(context, box, containing_block)

context.excluded_shapes.append(box)

return box
return box, resume_at


def find_float_position(context, box, containing_block):
Expand Down
70 changes: 40 additions & 30 deletions weasyprint/layout/inline.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@
from .table import find_in_flow_baseline, table_wrapper_width


def iter_line_boxes(context, box, position_y, skip_stack, containing_block,
absolute_boxes, fixed_boxes, first_letter_style):
def iter_line_boxes(context, box, position_y, max_y, skip_stack,
containing_block, absolute_boxes, fixed_boxes,
first_letter_style):
"""Return an iterator of ``(line, resume_at)``.
``line`` is a laid-out LineBox with as much content as possible that
Expand All @@ -40,7 +41,7 @@ def iter_line_boxes(context, box, position_y, skip_stack, containing_block,
box.text_indent = 0
while True:
line, resume_at = get_next_linebox(
context, box, position_y, skip_stack, containing_block,
context, box, position_y, max_y, skip_stack, containing_block,
absolute_boxes, fixed_boxes, first_letter_style)
if line:
handle_leader(context, line, containing_block)
Expand All @@ -55,7 +56,7 @@ def iter_line_boxes(context, box, position_y, skip_stack, containing_block,
first_letter_style = None


def get_next_linebox(context, linebox, position_y, skip_stack,
def get_next_linebox(context, linebox, position_y, max_y, skip_stack,
containing_block, absolute_boxes, fixed_boxes,
first_letter_style):
"""Return ``(line, resume_at)``."""
Expand Down Expand Up @@ -93,12 +94,13 @@ def get_next_linebox(context, linebox, position_y, skip_stack,
line_absolutes = []
line_fixed = []
waiting_floats = []
line_children = []

(line, resume_at, preserved_line_break, first_letter,
last_letter, float_width) = split_inline_box(
context, linebox, position_x, max_x, skip_stack, containing_block,
line_absolutes, line_fixed, line_placeholders, waiting_floats,
line_children=[])
context, linebox, position_x, max_x, max_y, skip_stack,
containing_block, line_absolutes, line_fixed, line_placeholders,
waiting_floats, line_children)
linebox.width, linebox.height = line.width, line.height

if is_phantom_linebox(line) and not preserved_line_break:
Expand Down Expand Up @@ -167,10 +169,13 @@ def get_next_linebox(context, linebox, position_y, skip_stack,
waiting_floats_y = line.position_y + line.height
for waiting_float in waiting_floats:
waiting_float.position_y = waiting_floats_y
waiting_float = float_layout(
new_waiting_float, waiting_float_resume_at = float_layout(
context, waiting_float, containing_block, absolute_boxes,
fixed_boxes)
float_children.append(waiting_float)
fixed_boxes, max_y, 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))
if float_children:
line.children += tuple(float_children)

Expand Down Expand Up @@ -440,7 +445,7 @@ def inline_block_width(box, context, containing_block):
box.width = shrink_to_fit(context, box, available_content_width)


def split_inline_level(context, box, position_x, max_x, skip_stack,
def split_inline_level(context, box, position_x, max_x, max_y, skip_stack,
containing_block, absolute_boxes, fixed_boxes,
line_placeholders, waiting_floats, line_children):
"""Fit as much content as possible from an inline-level box in a width.
Expand Down Expand Up @@ -488,9 +493,9 @@ def split_inline_level(context, box, position_x, max_x, skip_stack,
box.margin_right = 0
(new_box, resume_at, preserved_line_break, first_letter,
last_letter, float_widths) = split_inline_box(
context, box, position_x, max_x, skip_stack, containing_block,
absolute_boxes, fixed_boxes, line_placeholders, waiting_floats,
line_children)
context, box, position_x, max_x, max_y, skip_stack,
containing_block, absolute_boxes, fixed_boxes, line_placeholders,
waiting_floats, line_children)
elif isinstance(box, boxes.AtomicInlineLevelBox):
new_box = atomic_box(
context, box, position_x, skip_stack, containing_block,
Expand Down Expand Up @@ -524,8 +529,8 @@ def split_inline_level(context, box, position_x, max_x, skip_stack,
def _out_of_flow_layout(context, box, containing_block, index, child,
children, line_children, waiting_children,
waiting_floats, absolute_boxes, fixed_boxes,
line_placeholders, float_widths, max_position_x,
position_x):
line_placeholders, float_widths, max_x, position_x,
max_y):
if child.is_absolutely_positioned():
child.position_x = position_x
placeholder = AbsolutePlaceholder(child)
Expand All @@ -549,13 +554,18 @@ def _out_of_flow_layout(context, box, containing_block, index, child,
float_width -= trailing_whitespace_size(
context, non_floating_children[-1])

if float_width > max_position_x - position_x or waiting_floats:
if float_width > max_x - position_x or waiting_floats:
# TODO: the absolute and fixed boxes in the floats must be
# added here, and not in iter_line_boxes
waiting_floats.append(child)
else:
child = float_layout(
context, child, containing_block, absolute_boxes, fixed_boxes)
new_child, float_resume_at = float_layout(
context, child, containing_block, absolute_boxes, fixed_boxes,
max_y, skip_stack=None)
if float_resume_at:
context.broken_out_of_flow.append(
(child, containing_block, float_resume_at))
child = new_child
waiting_children.append((index, child))

# Translate previous line children
Expand All @@ -571,7 +581,7 @@ def _out_of_flow_layout(context, box, containing_block, index, child,
position_x += dx
elif child.style['float'] == 'right':
# Update the maximum x position for the next children
max_position_x -= dx
max_x -= dx
for _, old_child in line_children:
if not old_child.is_in_normal_flow():
continue
Expand All @@ -587,7 +597,7 @@ def _out_of_flow_layout(context, box, containing_block, index, child,
context.running_elements[running_name][page].append(child)


def _break_waiting_children(context, box, max_x, initial_skip_stack,
def _break_waiting_children(context, box, max_x, max_y, initial_skip_stack,
absolute_boxes, fixed_boxes, line_placeholders,
waiting_floats, line_children, children,
waiting_children):
Expand All @@ -605,7 +615,7 @@ def _break_waiting_children(context, box, max_x, initial_skip_stack,
# constraint. We may find a better way.
max_x = child.position_x + child.margin_width() - 1
new_child, child_resume_at, _, _, _, _ = split_inline_level(
context, child, child.position_x, max_x, None, box,
context, child, child.position_x, max_x, max_y, None, box,
absolute_boxes, fixed_boxes, line_placeholders,
waiting_floats, line_children)

Expand Down Expand Up @@ -658,7 +668,7 @@ def _break_waiting_children(context, box, max_x, initial_skip_stack,
return {children[-1][0] + 1: None}


def split_inline_box(context, box, position_x, max_x, skip_stack,
def split_inline_box(context, box, position_x, max_x, max_y, skip_stack,
containing_block, absolute_boxes, fixed_boxes,
line_placeholders, waiting_floats, line_children):
"""Same behavior as split_inline_level."""
Expand Down Expand Up @@ -706,7 +716,7 @@ def split_inline_box(context, box, position_x, max_x, skip_stack,
context, box, containing_block, index, child, children,
line_children, waiting_children, waiting_floats,
absolute_boxes, fixed_boxes, line_placeholders, float_widths,
max_x, position_x)
max_x, position_x, max_y)
if child.is_floated():
float_resume_index = index + 1
if child not in waiting_floats:
Expand All @@ -718,7 +728,7 @@ def split_inline_box(context, box, position_x, max_x, skip_stack,
child_waiting_floats = []
new_child, resume_at, preserved, first, last, new_float_widths = (
split_inline_level(
context, child, position_x, available_width, skip_stack,
context, child, position_x, available_width, max_y, skip_stack,
containing_block, absolute_boxes, fixed_boxes,
line_placeholders, child_waiting_floats, line_children))
if box.style['direction'] == 'rtl':
Expand All @@ -733,8 +743,8 @@ def split_inline_box(context, box, position_x, max_x, skip_stack,
available_width -= end_spacing
new_child, resume_at, preserved, first, last, new_float_widths = (
split_inline_level(
context, child, position_x, available_width, skip_stack,
containing_block, absolute_boxes, fixed_boxes,
context, child, position_x, available_width, max_y,
skip_stack, containing_block, absolute_boxes, fixed_boxes,
line_placeholders, child_waiting_floats, line_children))

skip_stack = None
Expand Down Expand Up @@ -782,9 +792,9 @@ def split_inline_box(context, box, position_x, max_x, skip_stack,

if new_position_x > max_x and not trailing_whitespace:
previous_resume_at = _break_waiting_children(
context, box, max_x, initial_skip_stack, absolute_boxes,
fixed_boxes, line_placeholders, waiting_floats,
line_children, children, waiting_children)
context, box, max_x, max_y, initial_skip_stack,
absolute_boxes, fixed_boxes, line_placeholders,
waiting_floats, line_children, children, waiting_children)
if previous_resume_at:
resume_at = previous_resume_at
break
Expand Down
14 changes: 14 additions & 0 deletions weasyprint/layout/page.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from ..logger import PROGRESS_LOGGER
from .absolute import absolute_layout
from .block import block_container_layout, block_level_layout
from .float import float_layout
from .min_max import handle_min_max_height, handle_min_max_width
from .percent import resolve_percentages
from .preferred import max_content_width, min_content_width
Expand Down Expand Up @@ -547,11 +548,24 @@ def make_page(context, root_box, page_type, resume_at, page_number,
page_is_empty = True
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:
box.position_y = 0
out_of_flow_box, out_of_flow_resume_at = float_layout(
context, box, containing_block, positioned_boxes, positioned_boxes,
page_content_bottom, 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))
context.broken_out_of_flow = broken_out_of_flow
root_box, resume_at, next_page, _, _ = block_level_layout(
context, root_box, page_content_bottom, resume_at,
initial_containing_block, page_is_empty, positioned_boxes,
positioned_boxes, adjoining_margins, discard=False)
assert root_box
root_box.children = tuple(out_of_flow_boxes) + root_box.children

page.fixed_boxes = [
placeholder._box for placeholder in positioned_boxes
Expand Down

0 comments on commit dbec957

Please sign in to comment.