def first_letter_to_box(box, skip_stack, first_letter_style):
    """Create a box for the ::first-letter selector."""
    if first_letter_style and box.children:
        # Some properties must be ignored in first-letter boxes.
        # https://drafts.csswg.org/selectors-3/#application-in-css
        # At least, position is ignored to avoid layout troubles.
        first_letter_style['position'] = 'static'

        first_letter = ''
        child = box.children[0]
        if isinstance(child, boxes.TextBox):
            letter_style = computed_from_cascaded(
                cascaded={}, parent_style=first_letter_style, element=None)
            if child.element_tag.endswith('::first-letter'):
                letter_box = boxes.InlineBox(
                    f'{box.element_tag}::first-letter', letter_style,
                    box.element, [child])
                box.children = ((letter_box, *box.children[1:]))
            elif child.text:
                character_found = False
                if skip_stack:
                    child_skip_stack, = skip_stack.values()
                    if child_skip_stack:
                        index, = child_skip_stack
                        child.text = child.text[index:]
                        skip_stack = None
                while child.text:
                    next_letter = child.text[0]
                    category = unicodedata.category(next_letter)
                    if category not in ('Ps', 'Pe', 'Pi', 'Pf', 'Po'):
                        if character_found:
                            break
                        character_found = True
                    first_letter += next_letter
                    child.text = child.text[1:]
                if first_letter.lstrip('\n'):
                    # "This type of initial letter is similar to an
                    # inline-level element if its 'float' property is 'none',
                    # otherwise it is similar to a floated element."
                    if first_letter_style['float'] == 'none':
                        letter_box = boxes.InlineBox(
                            f'{box.element_tag}::first-letter',
                            first_letter_style, box.element, [])
                        text_box = boxes.TextBox(
                            f'{box.element_tag}::first-letter', letter_style,
                            box.element, first_letter)
                        letter_box.children = (text_box,)
                        box.children = (letter_box, *box.children)
                    else:
                        letter_box = boxes.BlockBox(
                            f'{box.element_tag}::first-letter',
                            first_letter_style, box.element, [])
                        letter_box.first_letter_style = None
                        line_box = boxes.LineBox(
                            f'{box.element_tag}::first-letter', letter_style,
                            box.element, [])
                        letter_box.children = (line_box,)
                        text_box = boxes.TextBox(
                            f'{box.element_tag}::first-letter', letter_style,
                            box.element, first_letter)
                        line_box.children = (text_box,)
                        box.children = (letter_box, *box.children)
                    build.process_text_transform(text_box)
                    if skip_stack and child_skip_stack:
                        index, = skip_stack
                        (child_index, grandchild_skip_stack), = (
                            child_skip_stack.items())
                        skip_stack = {
                            index: {child_index + 1: grandchild_skip_stack}}
        elif isinstance(child, boxes.ParentBox):
            if skip_stack:
                child_skip_stack, = skip_stack.values()
            else:
                child_skip_stack = None
            child_skip_stack = first_letter_to_box(
                child, child_skip_stack, first_letter_style)
            if skip_stack:
                index, = skip_stack
                skip_stack = {index: child_skip_stack}
    return skip_stack
Create a box for the ::first-letter selector.
weasyprint/layout/inline.py