def find_earlier_page_break(context, children, absolute_boxes, fixed_boxes):
    """Find the last possible page break in ``children``.

    Because of a `page-break-before: avoid` or a `page-break-after: avoid` we
    need to find an earlier page break opportunity inside `children`.

    Absolute or fixed placeholders removed from children should also be
    removed from `absolute_boxes` or `fixed_boxes`.

    Return (new_children, resume_at).

    """
    if children and isinstance(children[0], boxes.LineBox):
        # Normally `orphans` and `widows` apply to the block container, but
        # line boxes inherit them.
        orphans = children[0].style['orphans']
        widows = children[0].style['widows']
        index = len(children) - widows  # how many lines we keep
        if index < orphans:
            return None
        new_children = children[:index]
        resume_at = {0: new_children[-1].resume_at}
        remove_placeholders(
            context, children[index:], absolute_boxes, fixed_boxes)
        return new_children, resume_at

    previous_in_flow = None
    for index, child in reversed_enumerate(children):
        if isinstance(child, boxes.TableRowGroupBox) and (
                child.is_header or child.is_footer):
            # We don’t want to break pages before table headers or footers.
            continue
        elif child.is_column:
            # We don’t want to break pages between columns.
            continue

        if child.is_in_normal_flow():
            page_break = block_level_page_break(child, previous_in_flow)
            if previous_in_flow is not None and (
                    not avoid_page_break(page_break, context)):
                index += 1  # break after child
                new_children = children[:index]
                # Get the index in the original parent
                resume_at = {children[index].index: None}
                break
            previous_in_flow = child

        if child.is_in_normal_flow() and (
                not avoid_page_break(child.style['break_inside'], context)):
            breakable_box_types = (
                boxes.BlockBox, boxes.TableBox, boxes.TableRowGroupBox)
            if isinstance(child, breakable_box_types):
                result = find_earlier_page_break(
                    context, child.children, absolute_boxes, fixed_boxes)
                if result:
                    new_grand_children, resume_at = result
                    new_child = child.copy_with_children(new_grand_children)
                    new_children = [*children[:index], new_child]

                    # Re-add footer at the end of split table
                    # TODO: fix table height and footer position
                    if isinstance(child, boxes.TableRowGroupBox):
                        for next_child in children[index:]:
                            if next_child.is_footer:
                                new_children.append(next_child)

                    # Index in the original parent
                    resume_at = {new_child.index: resume_at}
                    index += 1  # Remove placeholders after child
                    break
    else:
        return None

    # TODO: don’t remove absolute and fixed placeholders found in table footers
    remove_placeholders(context, children[index:], absolute_boxes, fixed_boxes)
    return new_children, resume_at
Find the last possible page break in ``children``.

Because of a `page-break-before: avoid` or a `page-break-after: avoid` we
need to find an earlier page break opportunity inside `children`.

Absolute or fixed placeholders removed from children should also be
removed from `absolute_boxes` or `fixed_boxes`.

Return (new_children, resume_at).
weasyprint/layout/block.py