mirror of
https://github.com/Kozea/WeasyPrint.git
synced 2024-10-05 00:21:15 +03:00
Add a basic shrink to fit for tables
This commit is contained in:
parent
82db8a421c
commit
42e25e1e3c
@ -638,6 +638,14 @@ def quotes(values):
|
|||||||
return strings[::2], strings[1::2]
|
return strings[::2], strings[1::2]
|
||||||
|
|
||||||
|
|
||||||
|
@validator()
|
||||||
|
@single_keyword
|
||||||
|
def table_layout(keyword):
|
||||||
|
"""Validation for the ``table-layout`` property"""
|
||||||
|
if keyword in ('fixed', 'auto'):
|
||||||
|
return keyword
|
||||||
|
|
||||||
|
|
||||||
@validator()
|
@validator()
|
||||||
@single_keyword
|
@single_keyword
|
||||||
def text_align(keyword):
|
def text_align(keyword):
|
||||||
|
@ -14,7 +14,7 @@ from __future__ import division, unicode_literals
|
|||||||
|
|
||||||
from .inlines import iter_line_boxes, replaced_box_width, replaced_box_height
|
from .inlines import iter_line_boxes, replaced_box_width, replaced_box_height
|
||||||
from .markers import list_marker_layout
|
from .markers import list_marker_layout
|
||||||
from .tables import table_layout, fixed_table_layout
|
from .tables import table_layout, fixed_table_layout, auto_table_layout
|
||||||
from .percentages import resolve_percentages
|
from .percentages import resolve_percentages
|
||||||
from ..formatting_structure import boxes
|
from ..formatting_structure import boxes
|
||||||
|
|
||||||
@ -377,15 +377,21 @@ def block_table_wrapper(document, wrapper, max_position_y, skip_stack,
|
|||||||
raise ValueError('Table wrapper without a table')
|
raise ValueError('Table wrapper without a table')
|
||||||
resolve_percentages(wrapper, containing_block)
|
resolve_percentages(wrapper, containing_block)
|
||||||
resolve_percentages(table, containing_block)
|
resolve_percentages(table, containing_block)
|
||||||
|
|
||||||
# Count the wrapper margins in case of `width: auto`
|
# Count the wrapper margins in case of `width: auto`
|
||||||
table.margin_left = wrapper.margin_left
|
table.margin_left = wrapper.margin_left
|
||||||
table.margin_right = wrapper.margin_right
|
table.margin_right = wrapper.margin_right
|
||||||
block_level_width(table, containing_block)
|
|
||||||
|
if table.style.table_layout == 'fixed':
|
||||||
|
block_level_width(table, containing_block)
|
||||||
|
fixed_table_layout(table)
|
||||||
|
else:
|
||||||
|
auto_table_layout(table, containing_block)
|
||||||
|
|
||||||
# The table margins are on the table wrapper box, not on the table box
|
# The table margins are on the table wrapper box, not on the table box
|
||||||
table.margin_left = 0
|
table.margin_left = 0
|
||||||
table.margin_right = 0
|
table.margin_right = 0
|
||||||
|
|
||||||
fixed_table_layout(table)
|
|
||||||
wrapper.width = wrapper.style.width = table.border_width()
|
wrapper.width = wrapper.style.width = table.border_width()
|
||||||
return block_box_layout(document, wrapper, max_position_y, skip_stack,
|
return block_box_layout(document, wrapper, max_position_y, skip_stack,
|
||||||
containing_block, device_size, page_is_empty,
|
containing_block, device_size, page_is_empty,
|
||||||
|
@ -290,8 +290,7 @@ def inline_block_box_layout(document, box, position_x, skip_stack,
|
|||||||
box.margin_right = 0
|
box.margin_right = 0
|
||||||
|
|
||||||
if box.width == 'auto':
|
if box.width == 'auto':
|
||||||
preferred, minimum = shrink_to_fit(box)
|
box.width = shrink_to_fit(box, containing_block.width)
|
||||||
box.width = min(max(minimum, containing_block.width), preferred)
|
|
||||||
|
|
||||||
box.position_x = position_x
|
box.position_x = position_x
|
||||||
box.position_y = 0
|
box.position_y = 0
|
||||||
|
@ -49,9 +49,15 @@ def variable_and_fixed_widths(box, width=None):
|
|||||||
return variable_ratio, fixed_width
|
return variable_ratio, fixed_width
|
||||||
|
|
||||||
|
|
||||||
def shrink_to_fit(box):
|
def shrink_to_fit(box, available_width):
|
||||||
"""Return ``(preferred_width, preferred_mimimum_width)`` for ``box``."""
|
"""Return the shrink-to-fit width of ``box``.
|
||||||
return preferred_width(box), preferred_mimimum_width(box)
|
|
||||||
|
http://www.w3.org/TR/CSS21/visudet.html#float-width
|
||||||
|
|
||||||
|
"""
|
||||||
|
return min(
|
||||||
|
max(preferred_mimimum_width(box), available_width),
|
||||||
|
preferred_width(box))
|
||||||
|
|
||||||
|
|
||||||
def preferred_mimimum_width(box):
|
def preferred_mimimum_width(box):
|
||||||
|
@ -16,6 +16,7 @@ from ..compat import xrange
|
|||||||
from ..logger import LOGGER
|
from ..logger import LOGGER
|
||||||
from ..formatting_structure import boxes
|
from ..formatting_structure import boxes
|
||||||
from .percentages import resolve_percentages, resolve_one_percentage
|
from .percentages import resolve_percentages, resolve_one_percentage
|
||||||
|
from .preferred import preferred_mimimum_width, preferred_width
|
||||||
|
|
||||||
|
|
||||||
def table_layout(document, table, max_position_y, skip_stack,
|
def table_layout(document, table, max_position_y, skip_stack,
|
||||||
@ -333,7 +334,57 @@ def fixed_table_layout(table):
|
|||||||
# with possible floating point rounding errors.
|
# with possible floating point rounding errors.
|
||||||
# (unless there is zero column)
|
# (unless there is zero column)
|
||||||
table.column_widths = column_widths
|
table.column_widths = column_widths
|
||||||
return column_widths
|
|
||||||
|
|
||||||
|
def auto_table_layout(table, containing_block):
|
||||||
|
"""Run the auto table layout and return a list of column widths.
|
||||||
|
|
||||||
|
http://www.w3.org/TR/CSS21/tables.html#auto-table-layout
|
||||||
|
|
||||||
|
"""
|
||||||
|
column_preferred_widths = []
|
||||||
|
column_preferred_minimum_widths = []
|
||||||
|
for i, row in enumerate(table.children):
|
||||||
|
# TODO: handle row groups
|
||||||
|
for j, row_group in enumerate(row.children):
|
||||||
|
for k, cell in enumerate(row_group.children):
|
||||||
|
assert k <= len(column_preferred_widths)
|
||||||
|
if k == len(column_preferred_widths):
|
||||||
|
column_preferred_widths.append([0] * i)
|
||||||
|
column_preferred_minimum_widths.append([0] * i)
|
||||||
|
column_preferred_widths[k].append(preferred_width(cell))
|
||||||
|
column_preferred_minimum_widths[k].append(
|
||||||
|
preferred_mimimum_width(cell))
|
||||||
|
|
||||||
|
column_preferred_widths = [
|
||||||
|
max(widths) for widths in column_preferred_widths]
|
||||||
|
column_preferred_minimum_widths = [
|
||||||
|
max(widths) for widths in column_preferred_minimum_widths]
|
||||||
|
|
||||||
|
table_preferred_minimum_width = sum(column_preferred_minimum_widths)
|
||||||
|
table_preferred_width = sum(column_preferred_widths)
|
||||||
|
table_maximum_width = max(
|
||||||
|
containing_block.width, table_preferred_minimum_width)
|
||||||
|
# TODO: handle the border spacings
|
||||||
|
table.width = min(table_preferred_width, table_maximum_width)
|
||||||
|
|
||||||
|
# TODO: find a better algorithm
|
||||||
|
if table_preferred_width == table.width:
|
||||||
|
# Preferred width fits in the containing block
|
||||||
|
table.column_widths = column_preferred_widths
|
||||||
|
else:
|
||||||
|
# Preferred width is too large for the containing block
|
||||||
|
# Use the minimum widths and add the lost space to the columns
|
||||||
|
# according to their preferred widths
|
||||||
|
table.column_widths = column_preferred_minimum_widths
|
||||||
|
lost_width = (
|
||||||
|
min(containing_block.width, table_preferred_width) -
|
||||||
|
table_preferred_minimum_width)
|
||||||
|
table.column_widths = [
|
||||||
|
(column_width + lost_width *
|
||||||
|
preferred_column_width / table_preferred_width)
|
||||||
|
for (preferred_column_width, column_width)
|
||||||
|
in zip(column_preferred_widths, column_preferred_minimum_widths)]
|
||||||
|
|
||||||
|
|
||||||
def cell_baseline(cell):
|
def cell_baseline(cell):
|
||||||
|
@ -1049,7 +1049,7 @@ def test_tables():
|
|||||||
_+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+_,
|
_+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+_,
|
||||||
_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_,
|
_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_,
|
||||||
], source % {'extra_css': '''
|
], source % {'extra_css': '''
|
||||||
table { border-color: #00f }
|
table { border-color: #00f; table-layout: fixed }
|
||||||
td { border-color: rgba(255, 0, 0, 0.5) }
|
td { border-color: rgba(255, 0, 0, 0.5) }
|
||||||
'''})
|
'''})
|
||||||
|
|
||||||
@ -1083,7 +1083,7 @@ def test_tables():
|
|||||||
_+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+_,
|
_+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+_,
|
||||||
_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_,
|
_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_,
|
||||||
], source % {'extra_css': '''
|
], source % {'extra_css': '''
|
||||||
table { border-color: #00f }
|
table { border-color: #00f; table-layout: fixed }
|
||||||
td { background: rgba(255, 0, 0, 0.5) }
|
td { background: rgba(255, 0, 0, 0.5) }
|
||||||
'''})
|
'''})
|
||||||
|
|
||||||
@ -1120,7 +1120,7 @@ def test_tables():
|
|||||||
_+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+_,
|
_+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+_,
|
||||||
_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_,
|
_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_,
|
||||||
], source % {'extra_css': '''
|
], source % {'extra_css': '''
|
||||||
table { border-color: #00f }
|
table { border-color: #00f; table-layout: fixed }
|
||||||
colgroup { background: rgba(255, 0, 0, 0.5) }
|
colgroup { background: rgba(255, 0, 0, 0.5) }
|
||||||
col { background: rgba(0, 255, 0, 0.5) }
|
col { background: rgba(0, 255, 0, 0.5) }
|
||||||
'''})
|
'''})
|
||||||
@ -1155,7 +1155,7 @@ def test_tables():
|
|||||||
_+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+_,
|
_+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+B+_,
|
||||||
_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_,
|
_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_+_,
|
||||||
], source % {'extra_css': '''
|
], source % {'extra_css': '''
|
||||||
table { border-color: #00f }
|
table { border-color: #00f; table-layout: fixed }
|
||||||
thead { background: rgba(255, 0, 0, 0.5) }
|
thead { background: rgba(255, 0, 0, 0.5) }
|
||||||
tr { background: rgba(0, 255, 0, 0.5) }
|
tr { background: rgba(0, 255, 0, 0.5) }
|
||||||
'''})
|
'''})
|
||||||
|
@ -713,7 +713,8 @@ def test_table_page_breaks():
|
|||||||
rows_per_page, rows_position_y = run('''
|
rows_per_page, rows_position_y = run('''
|
||||||
<style>
|
<style>
|
||||||
@page { -weasy-size: 120px }
|
@page { -weasy-size: 120px }
|
||||||
h1 { height: 30px}
|
table { table-layout: fixed }
|
||||||
|
h1 { height: 30px }
|
||||||
td { height: 40px }
|
td { height: 40px }
|
||||||
</style>
|
</style>
|
||||||
<h1>Dummy title</h1>
|
<h1>Dummy title</h1>
|
||||||
@ -739,7 +740,7 @@ def test_table_page_breaks():
|
|||||||
@page { -weasy-size: 120px }
|
@page { -weasy-size: 120px }
|
||||||
h1 { height: 30px}
|
h1 { height: 30px}
|
||||||
td { height: 40px }
|
td { height: 40px }
|
||||||
table { page-break-inside: avoid }
|
table { page-break-inside: avoid; table-layout: fixed }
|
||||||
</style>
|
</style>
|
||||||
<h1>Dummy title</h1>
|
<h1>Dummy title</h1>
|
||||||
<table>
|
<table>
|
||||||
@ -758,7 +759,7 @@ def test_table_page_breaks():
|
|||||||
@page { -weasy-size: 120px }
|
@page { -weasy-size: 120px }
|
||||||
h1 { height: 30px}
|
h1 { height: 30px}
|
||||||
td { height: 40px }
|
td { height: 40px }
|
||||||
table { page-break-inside: avoid }
|
table { page-break-inside: avoid; table-layout: fixed }
|
||||||
</style>
|
</style>
|
||||||
<h1>Dummy title</h1>
|
<h1>Dummy title</h1>
|
||||||
<table>
|
<table>
|
||||||
@ -779,6 +780,7 @@ def test_table_page_breaks():
|
|||||||
@page { -weasy-size: 120px }
|
@page { -weasy-size: 120px }
|
||||||
h1 { height: 30px}
|
h1 { height: 30px}
|
||||||
td { height: 40px }
|
td { height: 40px }
|
||||||
|
table { table-layout: fixed }
|
||||||
</style>
|
</style>
|
||||||
<h1>Dummy title</h1>
|
<h1>Dummy title</h1>
|
||||||
<table>
|
<table>
|
||||||
@ -1577,7 +1579,10 @@ def test_table_column_width():
|
|||||||
source = '''
|
source = '''
|
||||||
<style>
|
<style>
|
||||||
body { width: 20000px; margin: 0 }
|
body { width: 20000px; margin: 0 }
|
||||||
table { width: 10000px; margin: 0 auto; border-spacing: 100px 0 }
|
table {
|
||||||
|
width: 10000px; margin: 0 auto; border-spacing: 100px 0;
|
||||||
|
table-layout: fixed
|
||||||
|
}
|
||||||
td { border: 10px solid; padding: 1px }
|
td { border: 10px solid; padding: 1px }
|
||||||
</style>
|
</style>
|
||||||
<table>
|
<table>
|
||||||
@ -1603,7 +1608,7 @@ def test_table_column_width():
|
|||||||
page, = parse(source)
|
page, = parse(source)
|
||||||
assert len(logs) == 1
|
assert len(logs) == 1
|
||||||
assert logs[0] == ('WARNING: This table row has more columns than '
|
assert logs[0] == ('WARNING: This table row has more columns than '
|
||||||
'the table, ignored 1 cells: (<TableCellBox td 22>,)')
|
'the table, ignored 1 cells: (<TableCellBox td 25>,)')
|
||||||
html, = page.children
|
html, = page.children
|
||||||
body, = html.children
|
body, = html.children
|
||||||
wrapper, = body.children
|
wrapper, = body.children
|
||||||
@ -1669,7 +1674,7 @@ def test_table_column_width():
|
|||||||
|
|
||||||
page, = parse('''
|
page, = parse('''
|
||||||
<style>
|
<style>
|
||||||
table { width: 1000px; border-spacing: 100px }
|
table { width: 1000px; border-spacing: 100px; table-layout: fixed }
|
||||||
</style>
|
</style>
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
@ -1697,7 +1702,10 @@ def test_table_column_width():
|
|||||||
page, = parse('''
|
page, = parse('''
|
||||||
<style>
|
<style>
|
||||||
body { width: %(body_width)s }
|
body { width: %(body_width)s }
|
||||||
table { width: %(table_width)s; border-spacing: 100px }
|
table {
|
||||||
|
width: %(table_width)s; border-spacing: 100px;
|
||||||
|
table-layout: fixed
|
||||||
|
}
|
||||||
td { width: %(td_width)s }
|
td { width: %(td_width)s }
|
||||||
</style>
|
</style>
|
||||||
<table>
|
<table>
|
||||||
@ -1725,7 +1733,7 @@ def test_table_column_width():
|
|||||||
def test_table_row_height():
|
def test_table_row_height():
|
||||||
page, = parse('''
|
page, = parse('''
|
||||||
<table style="width: 1000px; border-spacing: 0 100px;
|
<table style="width: 1000px; border-spacing: 0 100px;
|
||||||
font: 20px/1em serif; margin: 3px">
|
font: 20px/1em serif; margin: 3px; table-layout: fixed">
|
||||||
<tr>
|
<tr>
|
||||||
<td rowspan=0 style="height: 420px; vertical-align: top">
|
<td rowspan=0 style="height: 420px; vertical-align: top">
|
||||||
<td>X<br>X<br>X
|
<td>X<br>X<br>X
|
||||||
@ -1808,7 +1816,7 @@ def test_table_wrapper():
|
|||||||
page, = parse('''
|
page, = parse('''
|
||||||
<style>
|
<style>
|
||||||
@page { -weasy-size: 1000px }
|
@page { -weasy-size: 1000px }
|
||||||
table { /* width: auto; */ height: 500px;
|
table { /* width: auto; */ height: 500px; table-layout: fixed;
|
||||||
padding: 1px; border: 10px solid; margin: 100px; }
|
padding: 1px; border: 10px solid; margin: 100px; }
|
||||||
</style>
|
</style>
|
||||||
<table></table>
|
<table></table>
|
||||||
|
Loading…
Reference in New Issue
Block a user