mirror of
https://github.com/Kozea/WeasyPrint.git
synced 2024-09-11 20:47:56 +03:00
Handle inheritance for defined elements
This commit is contained in:
parent
419c771331
commit
2b94b922f9
@ -291,6 +291,108 @@ def test_linear_gradient_reflect(assert_pixels):
|
||||
''')
|
||||
|
||||
|
||||
@assert_no_logs
|
||||
def test_linear_gradient_inherit_attributes(assert_pixels):
|
||||
assert_pixels('''
|
||||
BBBBBBBBBB
|
||||
BBBBBBBBBB
|
||||
BBBBBBBBBB
|
||||
BBBBBBBBBB
|
||||
BBBBBBBBBB
|
||||
RRRRRRRRRR
|
||||
RRRRRRRRRR
|
||||
RRRRRRRRRR
|
||||
RRRRRRRRRR
|
||||
RRRRRRRRRR
|
||||
''', '''
|
||||
<style>
|
||||
@page { size: 10px }
|
||||
svg { display: block }
|
||||
</style>
|
||||
<svg width="10px" height="10px" xmlns="https://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<linearGradient id="parent" x1="0" y1="0" x2="0" y2="1"
|
||||
gradientUnits="objectBoundingBox">
|
||||
</linearGradient>
|
||||
<linearGradient id="grad" href="#parent">
|
||||
<stop stop-color="blue" offset="50%"></stop>
|
||||
<stop stop-color="red" offset="50%"></stop>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<rect x="0" y="0" width="10" height="10" fill="url(#grad)" />
|
||||
</svg>
|
||||
''')
|
||||
|
||||
|
||||
@assert_no_logs
|
||||
def test_linear_gradient_inherit_children(assert_pixels):
|
||||
assert_pixels('''
|
||||
BBBBBBBBBB
|
||||
BBBBBBBBBB
|
||||
BBBBBBBBBB
|
||||
BBBBBBBBBB
|
||||
BBBBBBBBBB
|
||||
RRRRRRRRRR
|
||||
RRRRRRRRRR
|
||||
RRRRRRRRRR
|
||||
RRRRRRRRRR
|
||||
RRRRRRRRRR
|
||||
''', '''
|
||||
<style>
|
||||
@page { size: 10px }
|
||||
svg { display: block }
|
||||
</style>
|
||||
<svg width="10px" height="10px" xmlns="https://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<linearGradient id="parent">
|
||||
<stop stop-color="blue" offset="50%"></stop>
|
||||
<stop stop-color="red" offset="50%"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient id="grad" href="#parent"
|
||||
x1="0" y1="0" x2="0" y2="1" gradientUnits="objectBoundingBox">
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<rect x="0" y="0" width="10" height="10" fill="url(#grad)" />
|
||||
</svg>
|
||||
''')
|
||||
|
||||
|
||||
@assert_no_logs
|
||||
def test_linear_gradient_inherit_no_override(assert_pixels):
|
||||
assert_pixels('''
|
||||
BBBBBBBBBB
|
||||
BBBBBBBBBB
|
||||
BBBBBBBBBB
|
||||
BBBBBBBBBB
|
||||
BBBBBBBBBB
|
||||
RRRRRRRRRR
|
||||
RRRRRRRRRR
|
||||
RRRRRRRRRR
|
||||
RRRRRRRRRR
|
||||
RRRRRRRRRR
|
||||
''', '''
|
||||
<style>
|
||||
@page { size: 10px }
|
||||
svg { display: block }
|
||||
</style>
|
||||
<svg width="10px" height="10px" xmlns="https://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<linearGradient id="parent"
|
||||
x1="1" y1="1" x2="1" y2="0" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="red" offset="50%"></stop>
|
||||
<stop stop-color="blue" offset="50%"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient id="grad" href="#parent"
|
||||
x1="0" y1="0" x2="0" y2="1" gradientUnits="objectBoundingBox">
|
||||
<stop stop-color="blue" offset="50%"></stop>
|
||||
<stop stop-color="red" offset="50%"></stop>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<rect x="0" y="0" width="10" height="10" fill="url(#grad)" />
|
||||
</svg>
|
||||
''')
|
||||
|
||||
|
||||
@assert_no_logs
|
||||
def test_radial_gradient(assert_pixels):
|
||||
assert_pixels('''
|
||||
@ -493,7 +595,112 @@ def test_radial_gradient_reflect(assert_pixels):
|
||||
|
||||
|
||||
@assert_no_logs
|
||||
def test_linear_gradient_opacity(assert_pixels):
|
||||
def test_radial_gradient_inherit_attributes(assert_pixels):
|
||||
assert_pixels('''
|
||||
rrrrrrrrrr
|
||||
rrrrrrrrrr
|
||||
rrrrBBrrrr
|
||||
rrrBBBBrrr
|
||||
rrBBBBBBrr
|
||||
rrBBBBBBrr
|
||||
rrrBBBBrrr
|
||||
rrrrBBrrrr
|
||||
rrrrrrrrrr
|
||||
rrrrrrrrrr
|
||||
''', '''
|
||||
<style>
|
||||
@page { size: 10px }
|
||||
svg { display: block }
|
||||
</style>
|
||||
<svg width="10px" height="10px" xmlns="https://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<radialGradient id="parent" cx="0.5" cy="0.5" r="0.5"
|
||||
fx="0.5" fy="0.5" fr="0.2"
|
||||
gradientUnits="objectBoundingBox">
|
||||
</radialGradient>
|
||||
<radialGradient id="grad" href="#parent">
|
||||
<stop stop-color="blue" offset="25%"></stop>
|
||||
<stop stop-color="red" offset="25%"></stop>
|
||||
</radialGradient>
|
||||
</defs>
|
||||
<rect x="0" y="0" width="10" height="10" fill="url(#grad)" />
|
||||
</svg>
|
||||
''')
|
||||
|
||||
|
||||
@assert_no_logs
|
||||
def test_radial_gradient_inherit_children(assert_pixels):
|
||||
assert_pixels('''
|
||||
rrrrrrrrrr
|
||||
rrrrrrrrrr
|
||||
rrrrBBrrrr
|
||||
rrrBBBBrrr
|
||||
rrBBBBBBrr
|
||||
rrBBBBBBrr
|
||||
rrrBBBBrrr
|
||||
rrrrBBrrrr
|
||||
rrrrrrrrrr
|
||||
rrrrrrrrrr
|
||||
''', '''
|
||||
<style>
|
||||
@page { size: 10px }
|
||||
svg { display: block }
|
||||
</style>
|
||||
<svg width="10px" height="10px" xmlns="https://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<radialGradient id="parent">
|
||||
<stop stop-color="blue" offset="25%"></stop>
|
||||
<stop stop-color="red" offset="25%"></stop>
|
||||
</radialGradient>
|
||||
<radialGradient id="grad" href="#parent"
|
||||
cx="0.5" cy="0.5" r="0.5" fx="0.5" fy="0.5" fr="0.2"
|
||||
gradientUnits="objectBoundingBox">
|
||||
</radialGradient>
|
||||
</defs>
|
||||
<rect x="0" y="0" width="10" height="10" fill="url(#grad)" />
|
||||
</svg>
|
||||
''')
|
||||
|
||||
|
||||
@assert_no_logs
|
||||
def test_radial_gradient_inherit_no_override(assert_pixels):
|
||||
assert_pixels('''
|
||||
rrrrrrrrrr
|
||||
rrrrrrrrrr
|
||||
rrrrBBrrrr
|
||||
rrrBBBBrrr
|
||||
rrBBBBBBrr
|
||||
rrBBBBBBrr
|
||||
rrrBBBBrrr
|
||||
rrrrBBrrrr
|
||||
rrrrrrrrrr
|
||||
rrrrrrrrrr
|
||||
''', '''
|
||||
<style>
|
||||
@page { size: 10px }
|
||||
svg { display: block }
|
||||
</style>
|
||||
<svg width="10px" height="10px" xmlns="https://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<radialGradient id="parent" cx="5" cy="5" r="5" fx="5" fy="5" fr="2"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="red" offset="25%"></stop>
|
||||
<stop stop-color="blue" offset="25%"></stop>
|
||||
</radialGradient>
|
||||
<radialGradient id="grad" href="#parent" cx="0.5" cy="0.5" r="0.5"
|
||||
fx="0.5" fy="0.5" fr="0.2"
|
||||
gradientUnits="objectBoundingBox">
|
||||
<stop stop-color="blue" offset="25%"></stop>
|
||||
<stop stop-color="red" offset="25%"></stop>
|
||||
</radialGradient>
|
||||
</defs>
|
||||
<rect x="0" y="0" width="10" height="10" fill="url(#grad)" />
|
||||
</svg>
|
||||
''')
|
||||
|
||||
|
||||
@assert_no_logs
|
||||
def test_gradient_opacity(assert_pixels):
|
||||
assert_pixels('''
|
||||
BBBBBBBBBB
|
||||
BBBBBBBBBB
|
||||
|
@ -129,3 +129,109 @@ def test_pattern_4(assert_pixels):
|
||||
<rect x="0" y="0" width="8" height="8" fill="url(#pat)" />
|
||||
</svg>
|
||||
''')
|
||||
|
||||
|
||||
@assert_no_logs
|
||||
def test_pattern_inherit_attributes(assert_pixels):
|
||||
assert_pixels('''
|
||||
BBrrBBrr
|
||||
BBrrBBrr
|
||||
rrBBrrBB
|
||||
rrBBrrBB
|
||||
BBrrBBrr
|
||||
BBrrBBrr
|
||||
rrBBrrBB
|
||||
rrBBrrBB
|
||||
''', '''
|
||||
<style>
|
||||
@page { size: 8px }
|
||||
svg { display: block }
|
||||
</style>
|
||||
<svg width="8px" height="8px" xmlns="https://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<pattern id="parent" x="0" y="0" width="4" height="4"
|
||||
patternUnits="userSpaceOnUse"
|
||||
patternContentUnits="userSpaceOnUse">
|
||||
</pattern>
|
||||
<pattern id="pat" href="#parent">
|
||||
<rect x="0" y="0" width="2" height="2" fill="blue" />
|
||||
<rect x="0" y="2" width="2" height="2" fill="red" />
|
||||
<rect x="2" y="0" width="2" height="2" fill="red" />
|
||||
<rect x="2" y="2" width="2" height="2" fill="blue" />
|
||||
</pattern>
|
||||
</defs>
|
||||
<rect x="0" y="0" width="8" height="8" fill="url(#pat)" />
|
||||
</svg>
|
||||
''')
|
||||
|
||||
|
||||
@assert_no_logs
|
||||
def test_pattern_inherit_children(assert_pixels):
|
||||
assert_pixels('''
|
||||
BBrrBBrr
|
||||
BBrrBBrr
|
||||
rrBBrrBB
|
||||
rrBBrrBB
|
||||
BBrrBBrr
|
||||
BBrrBBrr
|
||||
rrBBrrBB
|
||||
rrBBrrBB
|
||||
''', '''
|
||||
<style>
|
||||
@page { size: 8px }
|
||||
svg { display: block }
|
||||
</style>
|
||||
<svg width="8px" height="8px" xmlns="https://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<pattern id="parent">
|
||||
<rect x="0" y="0" width="2" height="2" fill="blue" />
|
||||
<rect x="0" y="2" width="2" height="2" fill="red" />
|
||||
<rect x="2" y="0" width="2" height="2" fill="red" />
|
||||
<rect x="2" y="2" width="2" height="2" fill="blue" />
|
||||
</pattern>
|
||||
<pattern id="pat" href="#parent" x="0" y="0" width="4" height="4"
|
||||
patternUnits="userSpaceOnUse" patternContentUnits="userSpaceOnUse">
|
||||
</pattern>
|
||||
</defs>
|
||||
<rect x="0" y="0" width="8" height="8" fill="url(#pat)" />
|
||||
</svg>
|
||||
''')
|
||||
|
||||
|
||||
@assert_no_logs
|
||||
def test_pattern_inherit_no_override(assert_pixels):
|
||||
assert_pixels('''
|
||||
BBrrBBrr
|
||||
BBrrBBrr
|
||||
rrBBrrBB
|
||||
rrBBrrBB
|
||||
BBrrBBrr
|
||||
BBrrBBrr
|
||||
rrBBrrBB
|
||||
rrBBrrBB
|
||||
''', '''
|
||||
<style>
|
||||
@page { size: 8px }
|
||||
svg { display: block }
|
||||
</style>
|
||||
<svg width="8px" height="8px" xmlns="https://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<pattern id="parent" x="1" y="1" width="3" height="3"
|
||||
patternUnits="objectBoundingBox"
|
||||
patternContentUnits="objectBoundingBox">
|
||||
<rect x="0" y="0" width="2" height="2" fill="green" />
|
||||
<rect x="0" y="2" width="2" height="2" fill="green" />
|
||||
<rect x="2" y="0" width="2" height="2" fill="yellow" />
|
||||
<rect x="2" y="2" width="2" height="2" fill="yellow" />
|
||||
</pattern>
|
||||
<pattern id="pat" href="#parent" x="0" y="0" width="4" height="4"
|
||||
patternUnits="userSpaceOnUse" patternContentUnits="userSpaceOnUse">
|
||||
<rect x="0" y="0" width="2" height="2" fill="blue" />
|
||||
<rect x="0" y="2" width="2" height="2" fill="red" />
|
||||
<rect x="2" y="0" width="2" height="2" fill="red" />
|
||||
<rect x="2" y="2" width="2" height="2" fill="blue" />
|
||||
</pattern>
|
||||
</defs>
|
||||
<rect x="0" y="0" width="8" height="8" fill="url(#pat)" />
|
||||
</svg>
|
||||
''')
|
||||
|
@ -182,6 +182,11 @@ class Node:
|
||||
if url:
|
||||
return url
|
||||
|
||||
def del_href(self):
|
||||
"""Remove the href attributes, with or without a namespace."""
|
||||
for attr_name in ('{http://www.w3.org/1999/xlink}href', 'href'):
|
||||
self.attrib.pop(attr_name, None)
|
||||
|
||||
@staticmethod
|
||||
def process_whitespace(string, preserve):
|
||||
"""Replace newlines by spaces, and merge spaces if not preserved."""
|
||||
@ -308,6 +313,7 @@ class SVG:
|
||||
self.text_path_width = 0
|
||||
|
||||
self.parse_defs(self.tree)
|
||||
self.inherit_defs()
|
||||
|
||||
def get_intrinsic_size(self, font_size):
|
||||
"""Get intrinsic size of the image."""
|
||||
@ -710,6 +716,32 @@ class SVG:
|
||||
for child in node:
|
||||
self.parse_defs(child)
|
||||
|
||||
def inherit_defs(self):
|
||||
"""Handle inheritance of different defined elements lists."""
|
||||
for defs in (self.gradients, self.patterns):
|
||||
for element in defs.values():
|
||||
self.inherit_element(element, defs)
|
||||
|
||||
def inherit_element(self, element, defs):
|
||||
"""Recursively handle inheritance of defined element."""
|
||||
href = element.get_href(self.url)
|
||||
if not href:
|
||||
return
|
||||
element.del_href()
|
||||
parent = defs.get(parse_url(href).fragment)
|
||||
if not parent:
|
||||
return
|
||||
self.inherit_element(parent, defs)
|
||||
for key, value in parent.attrib.items():
|
||||
if key not in element.attrib:
|
||||
element.attrib[key] = value
|
||||
if next(iter(element), None) is None:
|
||||
# Override element’s __iter__ with parent’s __iter__. As special
|
||||
# methods are bound to classes and not instances, we have to create
|
||||
# and assign a new type.
|
||||
element.__class__ = type(
|
||||
'Node', (Node,), {'__iter__': lambda self: parent.__iter__()})
|
||||
|
||||
def calculate_bounding_box(self, node, font_size, stroke=True):
|
||||
"""Calculate the bounding box of a node."""
|
||||
if stroke or node.bounding_box is None:
|
||||
|
Loading…
Reference in New Issue
Block a user