Skip to content

Commit 76d174f

Browse files
committed
Fix split table headers’ top border when rows are split
1 parent cb9540b commit 76d174f

File tree

2 files changed

+99
-17
lines changed

2 files changed

+99
-17
lines changed

tests/draw/test_table.py

+69-1
Original file line numberDiff line numberDiff line change
@@ -728,6 +728,7 @@ def test_tables_9(assert_pixels):
728728
______________________
729729
______________________
730730
______________________
731+
______________________
731732
_BBBBBBBBBBBBBBBBBBBB_
732733
_BBBBBBBBBBBBBBBBBBBB_
733734
_BBBBBBBBBBBBBBBBBBBB_
@@ -745,7 +746,6 @@ def test_tables_9(assert_pixels):
745746
______________________
746747
______________________
747748
______________________
748-
______________________
749749
''', '''
750750
<style>
751751
@page { size: 22px 18px; margin: 1px }
@@ -1235,3 +1235,71 @@ def test_tables_21(assert_pixels):
12351235
<table>
12361236
<tr><td>abc</td><td>abc</td></tr>
12371237
<tr><td>abc</td><td></td></tr>''')
1238+
1239+
1240+
@assert_no_logs
1241+
def test_tables_22(assert_pixels):
1242+
assert_pixels('''
1243+
_________________________
1244+
_rrrrrrrrrrrrrrrrrrrrrrr_
1245+
_rKKKKKKKKKKrKKKKKKKKKKr_
1246+
_rKKKKKKKKKKrKKKKKKKKKKr_
1247+
_rrrrrrrrrrrrrrrrrrrrrrr_
1248+
_rKKKKKKBBBBrBBBBBBBBBBr_
1249+
_rKKKKKKBBBBrBBBBBBBBBBr_
1250+
_rBBBBBBBBBBrBBBBBBBBBBr_
1251+
_________________________
1252+
_________________________
1253+
_rrrrrrrrrrrrrrrrrrrrrrr_
1254+
_rKKKKKKKKKKrKKKKKKKKKKr_
1255+
_rKKKKKKKKKKrKKKKKKKKKKr_
1256+
_rrrrrrrrrrrrrrrrrrrrrrr_
1257+
_rKKKKKKBBBBrBBBBBBBBBBr_
1258+
_rKKKKKKBBBBrBBBBBBBBBBr_
1259+
_rrrrrrrrrrrrrrrrrrrrrrr_
1260+
_________________________
1261+
''', '''
1262+
<style>
1263+
@font-face { src: url(weasyprint.otf); font-family: weasyprint }
1264+
@page { size: 25px 9px; margin: 1px }
1265+
table { border-collapse: collapse; font: 2px/1 weasyprint }
1266+
td { background: blue; border: 1px solid red }
1267+
</style>
1268+
<table>
1269+
<thead><tr><td>abcde</td><td>abcde</td></tr></thead>
1270+
<tbody><tr><td>abc abc</td><td></td></tr></tbody>''')
1271+
1272+
1273+
@pytest.mark.xfail
1274+
@assert_no_logs
1275+
def test_tables_23(assert_pixels):
1276+
assert_pixels('''
1277+
_________________________
1278+
_rrrrrrrrrrrrrrrrrrrrrrr_
1279+
_rKKKKKKKKKKrKKKKKKKKKKr_
1280+
_rKKKKKKKKKKrKKKKKKKKKKr_
1281+
_rrrrrrrrrrrrrrrrrrrrrrr_
1282+
_rKKKKKKBBBBrBBBBBBBBBBr_
1283+
_rKKKKKKBBBBrBBBBBBBBBBr_
1284+
_rBBBBBBBBBBrBBBBBBBBBBr_
1285+
_________________________
1286+
_________________________
1287+
_rrrrrrrrrrrrrrrrrrrrrrr_
1288+
_rKKKKKKKKKKrKKKKKKKKKKr_
1289+
_rKKKKKKKKKKrKKKKKKKKKKr_
1290+
_rKKKKKKBBBBrBBBBBBBBBBr_
1291+
_rKKKKKKBBBBrBBBBBBBBBBr_
1292+
_rrrrrrrrrrrrrrrrrrrrrrr_
1293+
_________________________
1294+
_________________________
1295+
''', '''
1296+
<style>
1297+
@font-face { src: url(weasyprint.otf); font-family: weasyprint }
1298+
@page { size: 25px 9px; margin: 1px }
1299+
table { border-collapse: collapse; font: 2px/1 weasyprint }
1300+
td { background: blue; border: 1px solid red }
1301+
thead td { border-bottom: none }
1302+
</style>
1303+
<table>
1304+
<thead><tr><td>abcde</td><td>abcde</td></tr></thead>
1305+
<tbody><tr><td>abc abc</td><td></td></tr></tbody>''')

weasyprint/layout/table.py

+30-16
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,18 @@ def table_layout(context, table, bottom_space, skip_stack, containing_block,
1515
avoid_page_break, block_container_layout, block_level_page_break,
1616
find_earlier_page_break, force_page_break)
1717

18-
table.remove_decoration(start=skip_stack is not None, end=False)
18+
has_header = table.children and table.children[0].is_header
19+
has_footer = table.children and table.children[-1].is_footer
20+
collapse = table.style['border_collapse'] == 'collapse'
21+
remove_start_decoration = skip_stack is not None and not has_header
22+
table.remove_decoration(remove_start_decoration, end=False)
1923

2024
column_widths = table.column_widths
2125

22-
if table.style['border_collapse'] == 'separate':
23-
border_spacing_x, border_spacing_y = table.style['border_spacing']
26+
if collapse:
27+
border_spacing_x = border_spacing_y = 0
2428
else:
25-
border_spacing_x = 0
26-
border_spacing_y = 0
29+
border_spacing_x, border_spacing_y = table.style['border_spacing']
2730

2831
column_positions = table.column_positions = []
2932
rows_left_x = table.content_box_x() + border_spacing_x
@@ -44,7 +47,7 @@ def table_layout(context, table, bottom_space, skip_stack, containing_block,
4447
column_positions.append(position_x)
4548
rows_width = rows_x - position_x
4649

47-
if table.style['border_collapse'] == 'collapse':
50+
if collapse:
4851
table.skip_cell_border_top = False
4952
table.skip_cell_border_bottom = False
5053
split_cells = False
@@ -60,7 +63,7 @@ def table_layout(context, table, bottom_space, skip_stack, containing_block,
6063
skipped_rows += len(group.children)
6164
else:
6265
skipped_rows = 0
63-
if not split_cells:
66+
if not split_cells and not has_header:
6467
_, horizontal_borders = table.collapsed_border_grid
6568
if horizontal_borders:
6669
table.border_top_width = max(
@@ -149,9 +152,20 @@ def group_layout(group, position_y, bottom_space, page_is_empty,
149152
cell_skip_stack = {len(cell.children): None}
150153
else:
151154
cell_skip_stack = None
152-
if cell_skip_stack:
153-
cell.remove_decoration(start=True, end=False)
154-
if table.style['border_collapse'] == 'collapse':
155+
156+
# Adapt cell and table collapsing borders when a row is split
157+
if cell_skip_stack and collapse:
158+
if has_header:
159+
# We have a header, we have to adapt the position of
160+
# the split cell to match the header’s bottom border
161+
header_rows = table.children[0].children
162+
if header_rows and header_rows[-1].children:
163+
cell.position_y += max(
164+
header.border_bottom_width
165+
for header in header_rows[-1].children)
166+
else:
167+
# We don’t have a header, we have to skip the
168+
# decoration at the top of the table when it’s drawn
155169
table.skip_cell_border_top = True
156170

157171
# First try to render content as if there was already something
@@ -308,7 +322,7 @@ def group_layout(group, position_y, bottom_space, page_is_empty,
308322
page_is_empty = False
309323
skip_stack = None
310324

311-
if break_cell and table.style['border_collapse'] == 'collapse':
325+
if break_cell and collapse and not has_footer:
312326
table.skip_cell_border_bottom = True
313327

314328
if break_cell or resume_at:
@@ -422,7 +436,7 @@ def all_groups_layout():
422436
else:
423437
header_footer_bottom_space = -inf
424438

425-
if table.children and table.children[0].is_header:
439+
if has_header:
426440
header = table.children[0]
427441
header, resume_at, next_page = group_layout(
428442
header, position_y, header_footer_bottom_space,
@@ -434,7 +448,7 @@ def all_groups_layout():
434448
else:
435449
header = None
436450

437-
if table.children and table.children[-1].is_footer:
451+
if has_footer:
438452
footer = table.children[-1]
439453
footer, resume_at, next_page = group_layout(
440454
footer, position_y, header_footer_bottom_space,
@@ -536,9 +550,9 @@ def get_column_cells(table, column):
536550
([header] if header is not None else []) +
537551
new_table_children +
538552
([footer] if footer is not None else []))
539-
table.remove_decoration(
540-
start=skip_stack is not None, end=resume_at is not None)
541-
if table.style['border_collapse'] == 'collapse':
553+
remove_end_decoration = resume_at is not None and not has_footer
554+
table.remove_decoration(remove_start_decoration, remove_end_decoration)
555+
if collapse:
542556
table.skipped_rows = skipped_rows
543557

544558
# If the height property has a bigger value, just add blank space

0 commit comments

Comments
 (0)