Repository: Kozea/WeasyPrint
Pull request #2039 (2024-01-14 18:18:52)

Fix table row height calculation to use cell's border-height
This is a fix for #1968.

For rows with a specified height, I changed the code that calculates the maximum of the children cell's heights. It now uses the border-box-height instead of just `height`, similar to how it's done in the `row.height == 'auto'` case.


Patch:
diff --git a/weasyprint/layout/table.py b/weasyprint/layout/table.py
index ca9d8d9c..72764606 100644
--- a/weasyprint/layout/table.py
+++ b/weasyprint/layout/table.py
@@ -244,7 +244,7 @@ def table_layout(context, table, bottom_space, skip_stack, containing_block,
                     row.height = max(row_bottom_y - row.position_y, 0)
                 else:
                     row.height = max(row.height, max(
-                        row_cell.height for row_cell in ending_cells))
+                        row_cell.border_height() for row_cell in ending_cells))
                     row_bottom_y = row.position_y + row.height
             else:
                 row_bottom_y = row.position_y
diff --git a/weasyprint/svg/__init__.py b/weasyprint/svg/__init__.py
index 3dfb90f2..80a07c15 100644
--- a/weasyprint/svg/__init__.py
+++ b/weasyprint/svg/__init__.py
@@ -387,8 +387,6 @@ class SVG:
         # Update font size
         font_size = size(node.get('font-size', '1em'), font_size, font_size)
 
-        original_streams = []
-
         if fill_stroke:
             self.stream.push_state()
 
@@ -403,7 +401,7 @@ class SVG:
         # Create substream for opacity
         opacity = float(node.get('opacity', 1))
         if fill_stroke and 0 <= opacity < 1:
-            original_streams.append(self.stream)
+            original_stream = self.stream
             box = self.calculate_bounding_box(node, font_size)
             if not is_valid_bounding_box(box):
                 box = (0, 0, self.inner_width, self.inner_height)
@@ -440,8 +438,7 @@ class SVG:
         text_anchor = node.get('text-anchor')
         if node.tag == 'text' and text_anchor in ('middle', 'end'):
             group = self.stream.add_group(0, 0, 0, 0)  # BBox set after drawing
-            original_streams.append(self.stream)
-            self.stream = group
+            original_stream, self.stream = self.stream, group
 
         # Draw node
         if visible and node.tag in TAGS:
@@ -464,7 +461,7 @@ class SVG:
         # Handle text anchor
         if node.tag == 'text' and text_anchor in ('middle', 'end'):
             group_id = self.stream.id
-            self.stream = original_streams.pop()
+            self.stream = original_stream
             self.stream.push_state()
             if is_valid_bounding_box(node.text_bounding_box):
                 x, y, width, height = node.text_bounding_box
@@ -489,7 +486,7 @@ class SVG:
         # Apply opacity stream and restore original stream
         if fill_stroke and 0 <= opacity < 1:
             group_id = self.stream.id
-            self.stream = original_streams.pop()
+            self.stream = original_stream
             self.stream.set_alpha(opacity, stroke=True, fill=True)
             self.stream.draw_x_object(group_id)
 


Test patch:
diff --git a/tests/layout/test_table.py b/tests/layout/test_table.py
index 2832ef8c..5c36a08a 100644
--- a/tests/layout/test_table.py
+++ b/tests/layout/test_table.py
@@ -1865,6 +1865,24 @@ def test_table_row_height_3():
     assert row2.height == 0
 
 
+@assert_no_logs
+def test_table_row_height_4():
+    # A row cannot be shorter than the border-height of its tallest cell
+    page, = render_pages('''
+      <table style="border-spacing: 0;">
+        <tr style="height: 4px;">
+          <td style="border: 1px solid; padding: 5px;"></td>
+        </tr>
+      </table>
+    ''')
+    html, = page.children
+    body, = html.children
+    wrapper, = body.children
+    table, = wrapper.children
+    row_group, = table.children
+    assert row_group.height == 12
+
+
 @assert_no_logs
 def test_table_vertical_align(assert_pixels):
     assert_pixels('''