mirror of
https://github.com/Kozea/WeasyPrint.git
synced 2024-10-03 23:48:07 +03:00
Simplify (and fix) extra width distribution for auto table layout
Fix #2174.
This commit is contained in:
parent
af118df140
commit
4a5326edbf
@ -1298,11 +1298,14 @@ def test_layout_table_auto_41():
|
||||
def test_layout_table_auto_42():
|
||||
# Cell width as percentage in auto-width table
|
||||
page, = render_pages('''
|
||||
<table>
|
||||
<style>
|
||||
@font-face { src: url(weasyprint.otf); font-family: weasyprint }
|
||||
</style>
|
||||
<table style="font-family: weasyprint">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="width: 70px">a a a a a a a a</td>
|
||||
<td style="width: 30%">a a a a a a a a</td>
|
||||
<td style="width: 70px">aaa</td>
|
||||
<td style="width: 25%">aaa</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@ -1314,9 +1317,9 @@ def test_layout_table_auto_42():
|
||||
row_group, = table.children
|
||||
row, = row_group.children
|
||||
td_1, td_2 = row.children
|
||||
assert td_1.width == 70
|
||||
assert td_2.width == 30
|
||||
assert table.width == 100
|
||||
assert td_2.width == 16 * 3 # Percentage column is set to max-width
|
||||
assert td_1.width == (16 * 3) * 3 # Pixel column constraint is ignored
|
||||
assert table.width == (16 * 3) * 4
|
||||
|
||||
|
||||
@assert_no_logs
|
||||
@ -1554,6 +1557,32 @@ def test_layout_table_auto_50():
|
||||
assert td_21.width == 240 # 15 * font_size
|
||||
|
||||
|
||||
@assert_no_logs
|
||||
def test_layout_table_auto_51():
|
||||
# Test regression:
|
||||
# https://github.com/Kozea/WeasyPrint/issues/2174
|
||||
page, = render_pages('''
|
||||
<style>
|
||||
@font-face { src: url(weasyprint.otf); font-family: weasyprint }
|
||||
</style>
|
||||
<table style="font-family: weasyprint; width: 100px">
|
||||
<tr>
|
||||
<td style="width: 29.9999%">a</td>
|
||||
<td style="width: 70%">a</td>
|
||||
</tr>
|
||||
</table>
|
||||
''')
|
||||
html, = page.children
|
||||
body, = html.children
|
||||
table_wrapper, = body.children
|
||||
table, = table_wrapper.children
|
||||
row_group, = table.children
|
||||
row_1, = row_group.children
|
||||
td_1, td_2 = row_1.children
|
||||
assert abs(td_1.width - 30) < 0.1
|
||||
assert abs(td_2.width - 70) < 0.1
|
||||
|
||||
|
||||
@assert_no_logs
|
||||
@pytest.mark.parametrize(
|
||||
'body_width, table_width, check_width, positions, widths', (
|
||||
|
@ -7,7 +7,7 @@ import tinycss2.color3
|
||||
from ..formatting_structure import boxes
|
||||
from ..logger import LOGGER
|
||||
from .percent import resolve_one_percentage, resolve_percentages
|
||||
from .preferred import max_content_width, table_and_columns_preferred_widths
|
||||
from .preferred import table_and_columns_preferred_widths
|
||||
|
||||
|
||||
def table_layout(context, table, bottom_space, skip_stack, containing_block,
|
||||
@ -797,19 +797,9 @@ def auto_table_layout(context, box, containing_block):
|
||||
else:
|
||||
table.column_widths = max_content_guess
|
||||
excess_width = assignable_width - sum(max_content_guess)
|
||||
excess_width = distribute_excess_width(
|
||||
distribute_excess_width(
|
||||
context, grid, excess_width, table.column_widths, constrainedness,
|
||||
column_intrinsic_percentages, column_max_content_widths)
|
||||
if excess_width:
|
||||
if table_min_content_width < table.width - excess_width:
|
||||
# Reduce the width of the size from the excess width that has
|
||||
# not been distributed.
|
||||
table.width -= excess_width
|
||||
else:
|
||||
# Break rules
|
||||
columns = [i for i, column in enumerate(grid) if any(column)]
|
||||
for i in columns:
|
||||
table.column_widths[i] += excess_width / len(columns)
|
||||
|
||||
|
||||
def table_wrapper_width(context, wrapper, containing_block):
|
||||
@ -866,38 +856,26 @@ def distribute_excess_width(context, grid, excess_width, column_widths,
|
||||
column_slice=slice(0, None)):
|
||||
"""Distribute available width to columns.
|
||||
|
||||
Return excess width left when it's impossible without breaking rules.
|
||||
|
||||
See https://dbaron.org/css/intrinsic/#distributetocols
|
||||
See https://www.w3.org/TR/css-tables-3/#distributing-width-to-columns
|
||||
|
||||
"""
|
||||
# First group
|
||||
columns = [
|
||||
(i + column_slice.start, column)
|
||||
for i, column in enumerate(grid[column_slice])
|
||||
if not constrainedness[i + column_slice.start] and
|
||||
column_intrinsic_percentages[i + column_slice.start] == 0 and
|
||||
column_max_content_widths[i + column_slice.start] > 0]
|
||||
i for i, _ in enumerate(grid[column_slice], start=column_slice.start)
|
||||
if not constrainedness[i] and
|
||||
column_intrinsic_percentages[i] == 0 and
|
||||
column_max_content_widths[i] > 0]
|
||||
if columns:
|
||||
current_widths = [column_widths[i] for i, column in columns]
|
||||
differences = [
|
||||
max(0, width[0] - width[1])
|
||||
for width in zip(column_max_content_widths, current_widths)]
|
||||
if sum(differences) > excess_width:
|
||||
differences = [
|
||||
difference / sum(differences) * excess_width
|
||||
for difference in differences]
|
||||
excess_width -= sum(differences)
|
||||
for i, difference in enumerate(differences):
|
||||
column_widths[columns[i][0]] += difference
|
||||
if excess_width <= 0:
|
||||
sum_max_content_widths = sum(column_max_content_widths[i] for i in columns)
|
||||
ratio = excess_width / sum_max_content_widths
|
||||
for i in columns:
|
||||
column_widths[i] += column_max_content_widths[i] * ratio
|
||||
return
|
||||
|
||||
# Second group
|
||||
columns = [
|
||||
i + column_slice.start for i, column in enumerate(grid[column_slice])
|
||||
if not constrainedness[i + column_slice.start] and
|
||||
column_intrinsic_percentages[i + column_slice.start] == 0]
|
||||
i for i, _ in enumerate(grid[column_slice], start=column_slice.start)
|
||||
if not constrainedness[i] and column_intrinsic_percentages[i] == 0]
|
||||
if columns:
|
||||
for i in columns:
|
||||
column_widths[i] += excess_width / len(columns)
|
||||
@ -905,85 +883,42 @@ def distribute_excess_width(context, grid, excess_width, column_widths,
|
||||
|
||||
# Third group
|
||||
columns = [
|
||||
(i + column_slice.start, column)
|
||||
for i, column in enumerate(grid[column_slice])
|
||||
if constrainedness[i + column_slice.start] and
|
||||
column_intrinsic_percentages[i + column_slice.start] == 0 and
|
||||
column_max_content_widths[i + column_slice.start] > 0]
|
||||
i for i, _ in enumerate(grid[column_slice], start=column_slice.start)
|
||||
if constrainedness[i] and
|
||||
column_intrinsic_percentages[i] == 0 and
|
||||
column_max_content_widths[i] > 0]
|
||||
if columns:
|
||||
current_widths = [column_widths[i] for i, column in columns]
|
||||
differences = [
|
||||
max(0, width[0] - width[1])
|
||||
for width in zip(column_max_content_widths, current_widths)]
|
||||
if sum(differences) > excess_width:
|
||||
differences = [
|
||||
difference / sum(differences) * excess_width
|
||||
for difference in differences]
|
||||
excess_width -= sum(differences)
|
||||
for i, difference in enumerate(differences):
|
||||
column_widths[columns[i][0]] += difference
|
||||
if excess_width <= 0:
|
||||
sum_max_content_widths = sum(column_max_content_widths[i] for i in columns)
|
||||
ratio = excess_width / sum_max_content_widths
|
||||
for i in columns:
|
||||
column_widths[i] += column_max_content_widths[i] * ratio
|
||||
return
|
||||
|
||||
# Fourth group
|
||||
columns = [
|
||||
(i + column_slice.start, column)
|
||||
for i, column in enumerate(grid[column_slice])
|
||||
if column_intrinsic_percentages[i + column_slice.start] > 0]
|
||||
i for i, _ in enumerate(grid[column_slice], start=column_slice.start)
|
||||
if column_intrinsic_percentages[i] > 0 and column_max_content_widths[i] > 0]
|
||||
if columns:
|
||||
fixed_width = sum(
|
||||
column_widths[j] for j in range(len(grid))
|
||||
if j not in [i for i, column in columns])
|
||||
percentage_width = sum(
|
||||
column_intrinsic_percentages[i]
|
||||
for i, column in columns)
|
||||
if fixed_width and percentage_width >= 100:
|
||||
# Sum of the percentages are greater than 100%
|
||||
ratio = excess_width
|
||||
elif fixed_width == 0:
|
||||
# No fixed width, let's take the whole excess width
|
||||
ratio = excess_width
|
||||
else:
|
||||
ratio = fixed_width / (100 - percentage_width)
|
||||
|
||||
widths = [
|
||||
column_intrinsic_percentages[i] * ratio for i, column in columns]
|
||||
current_widths = [column_widths[i] for i, column in columns]
|
||||
# Allow to reduce the size of the columns to respect the percentage
|
||||
differences = [
|
||||
width[0] - width[1]
|
||||
for width in zip(widths, current_widths)]
|
||||
if sum(differences) > excess_width:
|
||||
differences = [
|
||||
difference / sum(differences) * excess_width
|
||||
for difference in differences]
|
||||
excess_width -= sum(differences)
|
||||
for i, difference in enumerate(differences):
|
||||
column_widths[columns[i][0]] += difference
|
||||
if excess_width <= 0:
|
||||
sum_intrinsic_percentages = sum(
|
||||
column_intrinsic_percentages[i] for i in columns)
|
||||
ratio = excess_width / sum_intrinsic_percentages
|
||||
for i in columns:
|
||||
column_widths[i] += column_intrinsic_percentages[i] * ratio
|
||||
return
|
||||
|
||||
# Bonus: we've tried our best to distribute the extra size, but we
|
||||
# failed. Instead of blindly distributing the size among all the colums
|
||||
# and breaking all the rules (as said in the draft), let's try to
|
||||
# change the columns with no constraint at all, then resize the table,
|
||||
# and at least break the rules to make the columns fill the table.
|
||||
|
||||
# Fifth group, part 1
|
||||
# Fifth group
|
||||
columns = [
|
||||
i + column_slice.start for i, column in enumerate(grid[column_slice])
|
||||
if any(column) and
|
||||
column_intrinsic_percentages[i + column_slice.start] == 0 and
|
||||
not any(
|
||||
max_content_width(context, cell)
|
||||
for cell in column if cell)]
|
||||
i for i, column in enumerate(grid[column_slice], start=column_slice.start)
|
||||
if column]
|
||||
if columns:
|
||||
for i in columns:
|
||||
column_widths[i] += excess_width / len(columns)
|
||||
return
|
||||
|
||||
# Fifth group, part 2, aka abort
|
||||
return excess_width
|
||||
# Sixth group
|
||||
columns = [i for i, _ in enumerate(grid[column_slice], start=column_slice.start)]
|
||||
for i in columns:
|
||||
column_widths[i] += excess_width / len(columns)
|
||||
|
||||
|
||||
TRANSPARENT = tinycss2.color3.parse_color('transparent')
|
||||
|
Loading…
Reference in New Issue
Block a user