Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle svg tags with no size #2242

Merged
merged 6 commits into from
Sep 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions tests/draw/svg/test_bounding_box.py
Original file line number Diff line number Diff line change
Expand Up @@ -309,3 +309,22 @@ def test_bounding_box_path_s(assert_pixels):
</g>
</svg>
''')


@assert_no_logs
def test_svg_empty_size(assert_pixels):
assert_pixels('''
BBB__
BBB__
BBB__
BBB__
_____
''', '''
<style>
@page { size: 5px }
svg { display: block }
</style>
<svg xmlns="http://www.w3.org/2000/svg">
<rect x="0" y="0" width="3" height="4" fill="blue" />
</svg>
''')
39 changes: 25 additions & 14 deletions weasyprint/svg/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@
'mask',
'path',
'pattern',
'symbol',
))


Expand Down Expand Up @@ -306,6 +307,19 @@ def override_iter(self, iterator):
self.__class__ = type(
'Node', (Node,), {'__iter__': lambda _: iterator})

def set_svg_size(self, svg, concrete_width, concrete_height):
""""Set SVG concrete and inner widths and heights from svg node."""
svg.concrete_width = concrete_width
svg.concrete_height = concrete_height
svg.normalized_diagonal = hypot(concrete_width, concrete_height) / sqrt(2)

if viewbox := self.get_viewbox():
svg.inner_width, svg.inner_height = viewbox[2], viewbox[3]
else:
svg.inner_width, svg.inner_height = svg.concrete_width, svg.concrete_height
svg.inner_diagonal = hypot(svg.inner_width, svg.inner_height) / sqrt(2)



class SVG:
"""An SVG document."""
Expand Down Expand Up @@ -368,19 +382,7 @@ def draw(self, stream, concrete_width, concrete_height, base_url,
"""Draw image on a stream."""
self.stream = stream

self.concrete_width = concrete_width
self.concrete_height = concrete_height
self.normalized_diagonal = (
hypot(concrete_width, concrete_height) / sqrt(2))

viewbox = self.get_viewbox()
if viewbox:
self.inner_width, self.inner_height = viewbox[2], viewbox[3]
else:
self.inner_width = self.concrete_width
self.inner_height = self.concrete_height
self.inner_diagonal = (
hypot(self.inner_width, self.inner_height) / sqrt(2))
self.tree.set_svg_size(self, concrete_width, concrete_height)

self.base_url = base_url
self.url_fetcher = url_fetcher
Expand All @@ -390,7 +392,7 @@ def draw(self, stream, concrete_width, concrete_height, base_url,

def draw_node(self, node, font_size, fill_stroke=True):
"""Draw a node."""
if node.tag in ('defs', 'symbol'):
if node.tag == 'defs':
return

# Update font size
Expand Down Expand Up @@ -456,6 +458,11 @@ def draw_node(self, node, font_size, fill_stroke=True):
if node.display and TAGS.get(node.tag) == text:
node.text_bounding_box = EMPTY_BOUNDING_BOX

# Save concrete size of root svg tag
if node.tag == 'svg':
concrete_width = self.concrete_width
concrete_height = self.concrete_height

# Draw node
if node.visible and node.tag in TAGS:
with suppress(PointError):
Expand All @@ -478,6 +485,10 @@ def draw_node(self, node, font_size, fill_stroke=True):
node.text_bounding_box = extend_bounding_box(
node.text_bounding_box, ((x1, y1), (x2, y2)))

# Restore concrete and inner size of root svg tag
if node.tag == 'svg':
self.tree.set_svg_size(svg, concrete_width, concrete_height)

# Handle text anchor
if node.tag == 'text' and text_anchor in ('middle', 'end'):
group_id = self.stream.id
Expand Down
16 changes: 14 additions & 2 deletions weasyprint/svg/images.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""Draw image and svg tags."""

from .bounding_box import bounding_box, is_valid_bounding_box
from .utils import preserve_ratio


Expand All @@ -10,8 +11,19 @@ def svg(svg, node, font_size):
if svg.tree == node:
width, height = svg.concrete_width, svg.concrete_height
else:
width, height = svg.point(
node.get('width'), node.get('height'), font_size)
width, height = node.get('width'), node.get('height')
if None in (width, height):
node._etree_node.tag = 'g'
box = bounding_box(svg, node, font_size, stroke=True)
if is_valid_bounding_box(box):
width = box[0] + box[2]
height = box[1] + box[3]
else:
width = height = 0
node._etree_node.tag = 'svg'
else:
width, height = svg.point(width, height, font_size)
node.set_svg_size(svg, width, height)
scale_x, scale_y, translate_x, translate_y = preserve_ratio(
svg, node, font_size, width, height)
if svg.tree != node and node.get('overflow', 'hidden') == 'hidden':
Expand Down
Loading