Skip to content

Commit

Permalink
Fix many different bugs with SVG markers
Browse files Browse the repository at this point in the history
  • Loading branch information
liZe committed Mar 25, 2024
1 parent 9b7550e commit 016bd81
Show file tree
Hide file tree
Showing 2 changed files with 173 additions and 34 deletions.
182 changes: 166 additions & 16 deletions tests/draw/svg/test_markers.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,18 @@
def test_markers(assert_pixels):
assert_pixels('''
___________
____RRR____
____RRR____
____RRR____
___________
____RRR____
____RRR____
____RRR____
_____RRR___
_____RRR___
_____RRR___
___________
____RRR____
____RRR____
____RRR____
_____RRR___
_____RRR___
_____RRR___
___________
_____RRR___
_____RRR___
_____RRR___
''', '''
<style>
@page { size: 11px 13px }
Expand All @@ -27,7 +27,7 @@ def test_markers(assert_pixels):
<svg width="11px" height="13px" xmlns="http://www.w3.org/2000/svg">
<defs>
<marker id="rectangle">
<rect x="-1" y="-1" width="3" height="3" fill="red" />
<rect width="3" height="3" fill="red" />
</marker>
</defs>
<path
Expand Down Expand Up @@ -79,16 +79,16 @@ def test_markers_viewbox(assert_pixels):
def test_markers_size(assert_pixels):
assert_pixels('''
___________
____RRR____
____RRR____
____BBR____
____BBR____
____RRR____
___________
____RRR____
____RRR____
____BBR____
____BBR____
____RRR____
___________
____RRR____
____RRR____
____BBR____
____BBR____
____RRR____
___________
''', '''
Expand All @@ -101,6 +101,7 @@ def test_markers_size(assert_pixels):
<marker id="rectangle"
refX="1" refY="1" markerWidth="3" markerHeight="3">
<rect width="6" height="6" fill="red" />
<rect width="2" height="2" fill="blue" />
</marker>
</defs>
<path
Expand Down Expand Up @@ -147,3 +148,152 @@ def test_markers_viewbox_size(assert_pixels):
marker-end="url(#rectangle)" />
</svg>
''')


def test_markers_overflow(assert_pixels):
assert_pixels('''
___________
____BBRR___
____BBRR___
____RRRR___
____RRRR___
____BBRR___
____BBRR___
____RRRR___
____RRRR___
____BBRR___
____BBRR___
____RRRR___
____RRRR___
''', '''
<style>
@page { size: 11px 13px }
svg { display: block }
</style>
<svg width="11px" height="13px" xmlns="http://www.w3.org/2000/svg">
<defs>
<marker id="rectangle" overflow="visible"
refX="1" refY="1" markerWidth="3" markerHeight="3">
<rect width="4" height="4" fill="red" />
<rect width="2" height="2" fill="blue" />
</marker>
</defs>
<path
d="M 5 2 v 4 v 4"
marker-start="url(#rectangle)"
marker-mid="url(#rectangle)"
marker-end="url(#rectangle)" />
</svg>
''')


@assert_no_logs
def test_markers_userspace(assert_pixels):
assert_pixels('''
___________
___________
_____R_____
___________
___________
___________
_____R_____
___________
___________
___________
_____R_____
___________
___________
''', '''
<style>
@page { size: 11px 13px }
svg { display: block }
</style>
<svg width="11px" height="13px" xmlns="http://www.w3.org/2000/svg">
<defs>
<marker id="rectangle" markerUnits="userSpaceOnUse">
<rect width="1" height="1" fill="red" />
</marker>
</defs>
<path
d="M 5 2 v 4 v 4"
stroke-width="10"
marker-start="url(#rectangle)"
marker-mid="url(#rectangle)"
marker-end="url(#rectangle)" />
</svg>
''')


@assert_no_logs
def test_markers_stroke_width(assert_pixels):
assert_pixels('''
___________
___________
_____RRR___
_____RRR___
_____RRR___
___________
_____RRR___
_____RRR___
_____RRR___
___________
_____RRR___
_____RRR___
_____RRR___
''', '''
<style>
@page { size: 11px 13px }
svg { display: block }
</style>
<svg width="11px" height="13px" xmlns="http://www.w3.org/2000/svg">
<defs>
<marker id="rectangle">
<rect width="1" height="1" fill="red" />
</marker>
</defs>
<path
d="M 5 2 v 4 v 4"
stroke-width="3"
marker-start="url(#rectangle)"
marker-mid="url(#rectangle)"
marker-end="url(#rectangle)" />
</svg>
''')


@assert_no_logs
def test_markers_viewbox_stroke_width(assert_pixels):
assert_pixels('''
___________
____BRR____
____RRR____
____RRR____
___________
____BRR____
____RRR____
____RRR____
___________
____BRR____
____RRR____
____RRR____
___________
''', '''
<style>
@page { size: 11px 13px }
svg { display: block }
</style>
<svg width="11px" height="13px" xmlns="http://www.w3.org/2000/svg">
<defs>
<marker id="rectangle" viewBox="-1 -1 3 3" markerWidth="1.5" markerHeight="1.5">
<rect x="-10" y="-10" width="20" height="20" fill="red" />
<rect x="-1" y="-1" width="1" height="1" fill="blue" />
</marker>
</defs>
<path
d="M 5 2 v 4 v 4"
stroke-width="2"
marker-start="url(#rectangle)"
marker-mid="url(#rectangle)"
marker-end="url(#rectangle)" />
</svg>
''')
25 changes: 7 additions & 18 deletions weasyprint/svg/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -569,11 +569,11 @@ def draw_markers(self, node, font_size, fill_stroke):
translate_x, translate_y = self.point(
marker_node.get('refX'), marker_node.get('refY'),
font_size)
marker_width, marker_height = self.point(
marker_node.get('markerWidth', 3),
marker_node.get('markerHeight', 3),
font_size)
if 'viewBox' in marker_node.attrib:
marker_width, marker_height = self.point(
marker_node.get('markerWidth', 3),
marker_node.get('markerHeight', 3),
font_size)
scale_x, scale_y, _, _ = preserve_ratio(
self, marker_node, font_size, marker_width, marker_height)

Expand Down Expand Up @@ -603,19 +603,8 @@ def draw_markers(self, node, font_size, fill_stroke):
clip_x, clip_y,
marker_width / scale_x, marker_height / scale_y)
else:
marker_width, marker_height = self.point(
marker_node.get('markerWidth', 3),
marker_node.get('markerHeight', 3),
font_size)
box = self.calculate_bounding_box(marker_node, font_size)
if is_valid_bounding_box(box):
scale_x = scale_y = min(
marker_width / box[2], marker_height / box[3])
translate_x /= scale_x
translate_y /= scale_y
else:
scale_x = scale_y = 1
clip_box = None
scale_x = scale_y = 1
clip_box = (0, 0, marker_width, marker_height)

# Scale
if marker_node.get('markerUnits') != 'userSpaceOnUse':
Expand All @@ -641,7 +630,7 @@ def draw_markers(self, node, font_size, fill_stroke):
self.stream.transform(e=-translate_x, f=-translate_y)

overflow = marker_node.get('overflow', 'hidden')
if clip_box and overflow in ('hidden', 'scroll'):
if overflow in ('hidden', 'scroll'):
self.stream.rectangle(*clip_box)
self.stream.clip()
self.stream.end()
Expand Down

0 comments on commit 016bd81

Please sign in to comment.