diff --git a/weasyprint/css/utils.py b/weasyprint/css/utils.py index 885936254..6092c9907 100644 --- a/weasyprint/css/utils.py +++ b/weasyprint/css/utils.py @@ -743,4 +743,4 @@ def get_content_list_token(token, base_url): elif name == 'element': if len(args) != 1 or args[0].type != 'ident': return - return ('element()', ('element', args[0])) + return ('element()', args[0]) diff --git a/weasyprint/formatting_structure/boxes.py b/weasyprint/formatting_structure/boxes.py index c5ec414be..46dd76821 100644 --- a/weasyprint/formatting_structure/boxes.py +++ b/weasyprint/formatting_structure/boxes.py @@ -713,3 +713,27 @@ class InlineFlexBox(FlexContainerBox, InlineLevelBox): It behaves as inline on the outside and as a flex container on the inside. """ +from collections import defaultdict + +class RunningPlaceholder(BlockBox): + """A box to anchor a running element within the document flow""" + def __init__(self, identifier, style): + self.position_x = 0 + self.position_y = 0 + self.width = 0 + self.height = 0 + self.padding_left = 0 + self.padding_right = 0 + self.padding_top = 0 + self.padding_bottom = 0 + self.border_left_width = 0 + self.border_right_width = 0 + self.border_top_width = 0 + self.border_bottom_width = 0 + self.identifier = identifier + super(RunningPlaceholder, self).__init__( + None, dict(style, display='block', content=[('running', None)]), children=[], + ) + + def translate(self, dx=0, dy=0, ignore_floats=False): + pass diff --git a/weasyprint/formatting_structure/build.py b/weasyprint/formatting_structure/build.py index 7798b5d36..a8edd3265 100644 --- a/weasyprint/formatting_structure/build.py +++ b/weasyprint/formatting_structure/build.py @@ -407,12 +407,17 @@ def compute_content_list(content_list, parent_box, counter_values, css_token, if is_open: quote_depth[0] += 1 elif type_ == 'element()': - # TODO: understand counter/string recomputation and do that here - # too - if value[1].value not in context.running_elements: + if value.value not in context.running_elements: # TODO: emit warning continue - boxlist.append(context.running_elements[value[1].value]) + new_box = None + for i in range(context.current_page - 1, -1, -1): + if i not in context.running_elements[value.value]: + continue + new_box = context.running_elements[value.value][i].copy() + break + new_box.style['position'] = 'static' + boxlist.append(new_box) text = ''.join(texts) if text: boxlist.append(boxes.TextBox.anonymous_from(parent_box, text)) @@ -1215,7 +1220,7 @@ def inline_in_block(box): ] """ - if not isinstance(box, boxes.ParentBox): + if not isinstance(box, boxes.ParentBox) or box.is_running(): return box box_children = list(box.children) @@ -1350,7 +1355,7 @@ def block_in_inline(box): ] """ - if not isinstance(box, boxes.ParentBox): + if not isinstance(box, boxes.ParentBox) or box.is_running(): return box new_children = [] diff --git a/weasyprint/layout/blocks.py b/weasyprint/layout/blocks.py index a2308155d..d7e15acf1 100644 --- a/weasyprint/layout/blocks.py +++ b/weasyprint/layout/blocks.py @@ -366,9 +366,14 @@ def block_container_layout(context, box, max_position_y, skip_stack, resume_at = (index, None) break elif child.is_running(): - context.running_elements[ - child.style['position'].element - ] = child + placeholder = boxes.RunningPlaceholder( + child.style['position'].element, child.style, + ) + placeholder.index = index + new_children.append(placeholder) + context.running_elements.setdefault( + child.style['position'].element, {} + )[placeholder] = child continue if isinstance(child, boxes.LineBox): diff --git a/weasyprint/layout/pages.py b/weasyprint/layout/pages.py index e621a01bc..631520e3a 100644 --- a/weasyprint/layout/pages.py +++ b/weasyprint/layout/pages.py @@ -347,8 +347,11 @@ def make_box(at_keyword, containing_block): page) # content_to_boxes() only produces inline-level boxes, no need to # run other post-processors from build.build_formatting_structure() - box = build.inline_in_block(box) build.process_whitespace(box) + box = build.anonymous_table_boxes(box) + box = build.flex_boxes(box) + box = build.inline_in_block(box) + box = build.block_in_inline(box) resolve_percentages(box, containing_block) if not box.is_generated: box.width = box.height = 0 @@ -665,6 +668,9 @@ def make_page(context, root_box, page_type, resume_at, page_number, if call_parse_again: remake_state['content_changed'] = True counter_lookup.parse_again(page_counter_values) + if isinstance(child, boxes.RunningPlaceholder): + elements = context.running_elements[child.identifier] + elements[page.page_type.index] = elements[child] if page_type.blank: resume_at = previous_resume_at