# Path: weasyprint/svg/bounding_box.py
# def is_valid_bounding_box(bounding_box):
#     """Check that a bounding box doesn’t have infinite boundaries."""
#     return bounding_box and not isinf(bounding_box[0] + bounding_box[1])
# 
# Path: weasyprint/svg/utils.py
# def color(string):
#     """Safely parse a color string and return a RGBA tuple."""
#     return parse_color(string or '') or (0, 0, 0, 1)
# 
# def parse_url(url):
#     """Parse a URL, possibly in a "url(…)" string."""
#     if url and url.startswith('url(') and url.endswith(')'):
#         url = url[4:-1]
#         if len(url) >= 2:
#             for quote in '\'"':
#                 if url[0] == url[-1]:
#                     url = url[1:-1]
#                     break
#     return urlparse(url or '')
# 
# def size(string, font_size=None, percentage_reference=None):
#     """Compute size from string, resolving units and percentages."""
#     from ..css.utils import LENGTHS_TO_PIXELS
# 
#     if not string:
#         return 0
# 
#     try:
#         return float(string)
#     except ValueError:
#         # Not a float, try something else
#         pass
# 
#     string = normalize(string).split(' ', 1)[0]
#     if string.endswith('%'):
#         assert percentage_reference is not None
#         return float(string[:-1]) * percentage_reference / 100
#     elif string.endswith('em'):
#         assert font_size is not None
#         return font_size * float(string[:-2])
#     elif string.endswith('ex'):
#         # Assume that 1em == 2ex
#         assert font_size is not None
#         return font_size * float(string[:-2]) / 2
# 
#     for unit, coefficient in LENGTHS_TO_PIXELS.items():
#         if string.endswith(unit):
#             return float(string[:-len(unit)]) * coefficient
# 
#     # Unknown size
#     return 0
# 
# def transform(transform_string, font_size, normalized_diagonal):
#     """Get a matrix corresponding to the transform string."""
#     # TODO: merge with Page._gather_links_and_bookmarks and
#     # css.validation.properties.transform
#     from ..document import Matrix
# 
#     transformations = re.findall(
#         r'(\w+) ?\( ?(.*?) ?\)', normalize(transform_string))
#     matrix = Matrix()
# 
#     for transformation_type, transformation in transformations:
#         values = [
#             size(value, font_size, normalized_diagonal)
#             for value in transformation.split(' ')]
#         if transformation_type == 'matrix':
#             matrix = Matrix(*values) @ matrix
#         elif transformation_type == 'rotate':
#             if len(values) == 3:
#                 matrix = Matrix(e=values[1], f=values[2]) @ matrix
#             matrix = Matrix(
#                 cos(radians(float(values[0]))),
#                 sin(radians(float(values[0]))),
#                 -sin(radians(float(values[0]))),
#                 cos(radians(float(values[0])))) @ matrix
#             if len(values) == 3:
#                 matrix = Matrix(e=-values[1], f=-values[2]) @ matrix
#         elif transformation_type.startswith('skew'):
#             if len(values) == 1:
#                 values.append(0)
#             if transformation_type in ('skewX', 'skew'):
#                 matrix = Matrix(
#                     c=tan(radians(float(values.pop(0))))) @ matrix
#             if transformation_type in ('skewY', 'skew'):
#                 matrix = Matrix(
#                     b=tan(radians(float(values.pop(0))))) @ matrix
#         elif transformation_type.startswith('translate'):
#             if len(values) == 1:
#                 values.append(0)
#             if transformation_type in ('translateX', 'translate'):
#                 matrix = Matrix(e=values.pop(0)) @ matrix
#             if transformation_type in ('translateY', 'translate'):
#                 matrix = Matrix(f=values.pop(0)) @ matrix
#         elif transformation_type.startswith('scale'):
#             if len(values) == 1:
#                 values.append(values[0])
#             if transformation_type in ('scaleX', 'scale'):
#                 matrix = Matrix(a=values.pop(0)) @ matrix
#             if transformation_type in ('scaleY', 'scale'):
#                 matrix = Matrix(d=values.pop(0)) @ matrix
# 
#     return matrix


from itertools import cycle
from math import ceil, hypot
from .bounding_box import is_valid_bounding_box
from .utils import color, parse_url, size, transform
    from . import NOT_INHERITED_ATTRIBUTES, SVG
    from ..document import Matrix
    from ..images import gradient_average_color, normalize_stop_positions
    from ..images import gradient_average_color, normalize_stop_positions
    from ..document import Matrix
    from . import Pattern
import pydyf
                zero_color = gradient_average_color(
                    average_colors, average_positions)
                colors = [zero_color] + original_colors[-(i - 1):] + colors
                new_positions = [
                    position - 1 - full_repeat for position
                    in original_positions[-(i - 1):]]
                positions = (
                    [ratio - 1 - full_repeat] + new_positions + positions)

    coords = (fx, fy, fr, cx, cy, r)
    return positions, colors, coords


def draw_pattern(svg, node, pattern, font_size, opacity, stroke):
    """Draw given gradient node."""

    pattern._etree_node.tag = 'svg'

    bounding_box = svg.calculate_bounding_box(node, font_size, stroke)
    if not is_valid_bounding_box(bounding_box):
        return False
    x, y = bounding_box[0], bounding_box[1]
    matrix = Matrix(e=x, f=y)
    if pattern.get('patternUnits') == 'userSpaceOnUse':
        width, height = svg.inner_width, svg.inner_height
    else:
        width, height = bounding_box[2], bounding_box[3]

    if pattern.get('patternUnits') == 'userSpaceOnUse':
        x = size(pattern.get('x'), font_size, 1)

# Path: weasyprint/svg/bounding_box.py
# def is_valid_bounding_box(bounding_box):
#     """Check that a bounding box doesn’t have infinite boundaries."""
#     return bounding_box and not isinf(bounding_box[0] + bounding_box[1])
# 
# Path: weasyprint/svg/utils.py
# def color(string):
#     """Safely parse a color string and return a RGBA tuple."""
#     return parse_color(string or '') or (0, 0, 0, 1)
# 
# def parse_url(url):
#     """Parse a URL, possibly in a "url(…)" string."""
#     if url and url.startswith('url(') and url.endswith(')'):
#         url = url[4:-1]
#         if len(url) >= 2:
#             for quote in '\'"':
#                 if url[0] == url[-1]:
#                     url = url[1:-1]
#                     break
#     return urlparse(url or '')
# 
# def size(string, font_size=None, percentage_reference=None):
#     """Compute size from string, resolving units and percentages."""
#     from ..css.utils import LENGTHS_TO_PIXELS
# 
#     if not string:
#         return 0
# 
#     try:
#         return float(string)
#     except ValueError:
#         # Not a float, try something else
#         pass
# 
#     string = normalize(string).split(' ', 1)[0]
#     if string.endswith('%'):
#         assert percentage_reference is not None
#         return float(string[:-1]) * percentage_reference / 100
#     elif string.endswith('em'):
#         assert font_size is not None
#         return font_size * float(string[:-2])
#     elif string.endswith('ex'):
#         # Assume that 1em == 2ex
#         assert font_size is not None
#         return font_size * float(string[:-2]) / 2
# 
#     for unit, coefficient in LENGTHS_TO_PIXELS.items():
#         if string.endswith(unit):
#             return float(string[:-len(unit)]) * coefficient
# 
#     # Unknown size
#     return 0
# 
# def transform(transform_string, font_size, normalized_diagonal):
#     """Get a matrix corresponding to the transform string."""
#     # TODO: merge with Page._gather_links_and_bookmarks and
#     # css.validation.properties.transform
#     from ..document import Matrix
# 
#     transformations = re.findall(
#         r'(\w+) ?\( ?(.*?) ?\)', normalize(transform_string))
#     matrix = Matrix()
# 
#     for transformation_type, transformation in transformations:
#         values = [
#             size(value, font_size, normalized_diagonal)
#             for value in transformation.split(' ')]
#         if transformation_type == 'matrix':
#             matrix = Matrix(*values) @ matrix
#         elif transformation_type == 'rotate':
#             if len(values) == 3:
#                 matrix = Matrix(e=values[1], f=values[2]) @ matrix
#             matrix = Matrix(
#                 cos(radians(float(values[0]))),
#                 sin(radians(float(values[0]))),
#                 -sin(radians(float(values[0]))),
#                 cos(radians(float(values[0])))) @ matrix
#             if len(values) == 3:
#                 matrix = Matrix(e=-values[1], f=-values[2]) @ matrix
#         elif transformation_type.startswith('skew'):
#             if len(values) == 1:
#                 values.append(0)
#             if transformation_type in ('skewX', 'skew'):
#                 matrix = Matrix(
#                     c=tan(radians(float(values.pop(0))))) @ matrix
#             if transformation_type in ('skewY', 'skew'):
#                 matrix = Matrix(
#                     b=tan(radians(float(values.pop(0))))) @ matrix
#         elif transformation_type.startswith('translate'):
#             if len(values) == 1:
#                 values.append(0)
#             if transformation_type in ('translateX', 'translate'):
#                 matrix = Matrix(e=values.pop(0)) @ matrix
#             if transformation_type in ('translateY', 'translate'):
#                 matrix = Matrix(f=values.pop(0)) @ matrix
#         elif transformation_type.startswith('scale'):
#             if len(values) == 1:
#                 values.append(values[0])
#             if transformation_type in ('scaleX', 'scale'):
#                 matrix = Matrix(a=values.pop(0)) @ matrix
#             if transformation_type in ('scaleY', 'scale'):
#                 matrix = Matrix(d=values.pop(0)) @ matrix
# 
#     return matrix


# Path: weasyprint/svg/defs.py
from itertools import cycle
from math import ceil, hypot
from .bounding_box import is_valid_bounding_box
from .utils import color, parse_url, size, transform
    from . import NOT_INHERITED_ATTRIBUTES, SVG
    from ..document import Matrix
    from ..images import gradient_average_color, normalize_stop_positions
    from ..images import gradient_average_color, normalize_stop_positions
    from ..document import Matrix
    from . import Pattern
import pydyf

                zero_color = gradient_average_color(
                    average_colors, average_positions)
                colors = [zero_color] + original_colors[-(i - 1):] + colors
                new_positions = [
                    position - 1 - full_repeat for position
                    in original_positions[-(i - 1):]]
                positions = (
                    [ratio - 1 - full_repeat] + new_positions + positions)

    coords = (fx, fy, fr, cx, cy, r)
    return positions, colors, coords


def draw_pattern(svg, node, pattern, font_size, opacity, stroke):
    """Draw given gradient node."""

    pattern._etree_node.tag = 'svg'

    bounding_box = svg.calculate_bounding_box(node, font_size, stroke)
    if not is_valid_bounding_box(bounding_box):
        return False
    x, y = bounding_box[0], bounding_box[1]
    matrix = Matrix(e=x, f=y)
    if pattern.get('patternUnits') == 'userSpaceOnUse':
        width, height = svg.inner_width, svg.inner_height
    else:
        width, height = bounding_box[2], bounding_box[3]

    if pattern.get('patternUnits') == 'userSpaceOnUse':
        x = size(pattern.get('x'), font_size, 1)

        y = size(pattern.get('y'), font_size, 1)