def spread_linear_gradient(spread, positions, colors, x1, y1, x2, y2,
                           bounding_box, matrix):
    """Repeat linear gradient."""
    # TODO: merge with LinearGradient.layout
    from ..images import gradient_average_color, normalize_stop_positions

    first, last, positions = normalize_stop_positions(positions)
    if spread in ('repeat', 'reflect'):
        # Render as a solid color if the first and last positions are equal
        # See https://drafts.csswg.org/css-images-3/#repeating-gradients
        if first == last:
            average_color = gradient_average_color(colors, positions)
            return 1, 'solid', None, [], [average_color]

        # Define defined gradient length and steps between positions
        stop_length = last - first
        position_steps = [
            positions[i + 1] - positions[i]
            for i in range(len(positions) - 1)]

        # Create cycles used to add colors
        if spread == 'repeat':
            next_steps = cycle((0, *position_steps))
            next_colors = cycle(colors)
            previous_steps = cycle((0, *position_steps[::-1]))
            previous_colors = cycle(colors[::-1])
        else:
            assert spread == 'reflect'
            next_steps = cycle((0, *position_steps[::-1], 0, *position_steps))
            next_colors = cycle(colors[::-1] + colors)
            previous_steps = cycle((0, *position_steps, 0, *position_steps[::-1]))
            previous_colors = cycle(colors + colors[::-1])

        # Normalize bounding box
        bx1, by1, bw, bh = bounding_box
        bx1, bx2 = (bx1, bx1 + bw) if bw > 0 else (bx1 + bw, bx1)
        by1, by2 = (by1, by1 + bh) if bh > 0 else (by1 + bh, by1)

        # Transform gradient vector coordinates
        tx1, ty1 = matrix.transform_point(x1, y1)
        tx2, ty2 = matrix.transform_point(x2, y2)

        # Find the extremities of the repeating vector, by projecting the
        # bounding box corners on the gradient vector
        xb, yb = tx1, ty1
        xv, yv = tx2 - tx1, ty2 - ty1
        xa1, xa2 = (bx1, bx2) if tx1 < tx2 else (bx2, bx1)
        ya1, ya2 = (by1, by2) if ty1 < ty2 else (by2, by1)
        min_vector = ((xa1 - xb) * xv + (ya1 - yb) * yv) / hypot(xv, yv) ** 2
        max_vector = ((xa2 - xb) * xv + (ya2 - yb) * yv) / hypot(xv, yv) ** 2

        # Add colors after last step
        while last < max_vector:
            step = next(next_steps)
            colors.append(next(next_colors))
            positions.append(positions[-1] + step)
            last += step * stop_length

        # Add colors before first step
        while first > min_vector:
            step = next(previous_steps)
            colors.insert(0, next(previous_colors))
            positions.insert(0, positions[0] - step)
            first -= step * stop_length

    x1, x2 = x1 + (x2 - x1) * first, x1 + (x2 - x1) * last
    y1, y2 = y1 + (y2 - y1) * first, y1 + (y2 - y1) * last
    coords = (x1, y1, x2, y2)
    return positions, colors, coords
Repeat linear gradient.
weasyprint/svg/defs.py