Permalink
Browse files

Clean and fix a lot of things in tables auto layout

  • Loading branch information...
1 parent 4593b51 commit 0d59b2600f53140904f68850404781b22c9c0bab @liZe liZe committed Apr 7, 2012
Showing with 102 additions and 32 deletions.
  1. +1 −1 weasyprint/layout/blocks.py
  2. +9 −9 weasyprint/layout/preferred.py
  3. +92 −22 weasyprint/layout/tables.py
@@ -387,7 +387,7 @@ def block_table_wrapper(document, wrapper, max_position_y, skip_stack,
block_level_width(table, containing_block)
fixed_table_layout(table)
else:
- auto_table_layout(table, containing_block)
+ auto_table_layout(table, wrapper, containing_block)
# The table margins are on the table wrapper box, not on the table box
table.margin_left = 0
@@ -25,11 +25,11 @@ def shrink_to_fit(box, available_width):
"""
return min(
- max(preferred_mimimum_width(box, outer=False), available_width),
+ max(preferred_minimum_width(box, outer=False), available_width),
preferred_width(box, outer=False))
-def preferred_mimimum_width(box, outer=True):
+def preferred_minimum_width(box, outer=True):
"""Return the preferred minimum width for ``box``.
This is the width by breaking at every line-break opportunity.
@@ -100,7 +100,7 @@ def adjust(box, outer, fixed_width, variable_ratio=0):
def block_preferred_minimum_width(box, outer=True):
"""Return the preferred minimum width for a ``BlockBox``."""
- return _block_preferred_width(box, preferred_mimimum_width, outer)
+ return _block_preferred_width(box, preferred_minimum_width, outer)
def block_preferred_width(box, outer=True):
@@ -111,9 +111,6 @@ def block_preferred_width(box, outer=True):
def inline_preferred_minimum_width(box, outer=True):
"""Return the preferred minimum width for an ``InlineBox``.
- *Warning:* only TextBox and InlineReplacedBox children are supported
- for now. (No recursive InlineBox children.)
-
"""
widest_line = 0
for child in box.children:
@@ -122,6 +119,9 @@ def inline_preferred_minimum_width(box, outer=True):
current_line = replaced_preferred_width(child)
elif isinstance(child, boxes.InlineBlockBox):
current_line = block_preferred_minimum_width(child)
+ elif isinstance(child, boxes.InlineBox):
+ # TODO: handle forced line breaks
+ current_line = inline_preferred_minimum_width(child)
else:
assert isinstance(child, boxes.TextBox)
current_line = max(text_lines_width(child, width=0))
@@ -132,9 +132,6 @@ def inline_preferred_minimum_width(box, outer=True):
def inline_preferred_width(box, outer=True):
"""Return the preferred width for an ``InlineBox``.
- *Warning:* only TextBox and InlineReplacedBox children are supported
- for now. (No recursive InlineBox children.)
-
"""
widest_line = 0
current_line = 0
@@ -144,6 +141,9 @@ def inline_preferred_width(box, outer=True):
current_line += replaced_preferred_width(child)
elif isinstance(child, boxes.InlineBlockBox):
current_line += block_preferred_width(child)
+ elif isinstance(child, boxes.InlineBox):
+ # TODO: handle forced line breaks
+ current_line += inline_preferred_width(child)
else:
assert isinstance(child, boxes.TextBox)
lines = list(text_lines_width(child, width=None))
@@ -16,7 +16,7 @@
from ..logger import LOGGER
from ..formatting_structure import boxes
from .percentages import resolve_percentages, resolve_one_percentage
-from .preferred import preferred_mimimum_width, preferred_width
+from .preferred import preferred_minimum_width, preferred_width
def table_layout(document, table, max_position_y, skip_stack,
@@ -336,33 +336,101 @@ def fixed_table_layout(table):
table.column_widths = column_widths
-def auto_table_layout(table, containing_block):
+def auto_table_layout(table, wrapper, 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))
+ # TODO: change this naive code, don't go through the whole table so many
+ # times
+
+ # First of all, we have to get a grid with cells inside
+ nb_columns = 0
+ rows = []
+ for i, row_group in enumerate(table.children):
+ assert isinstance(row_group, boxes.TableRowGroupBox)
+ for j, row in enumerate(row_group.children):
+ assert isinstance(row, boxes.TableRowBox)
+ rows.append(row)
+ for k, cell in enumerate(row.children):
+ assert isinstance(cell, boxes.TableCellBox)
+ nb_columns = max(nb_columns, k + cell.colspan)
+ nb_rows = len(rows)
+
+ colspan_cells = []
+ grid = [[None] * nb_columns for i in range(nb_rows)]
+ for i, row in enumerate(rows):
+ for cell in row.children:
+ if cell.colspan == 1:
+ grid[i][cell.grid_x] = cell
+ else:
+ cell.grid_y = i
+ colspan_cells.append(cell)
+
+ # Point #1
+ column_preferred_widths = [[0] * nb_rows for i in range(nb_columns)]
+ column_preferred_minimum_widths = [
+ [0] * nb_rows for i in range(nb_columns)]
+ for i, row in enumerate(grid):
+ for j, cell in enumerate(row):
+ if cell:
+ # TODO: when border-collapse: collapse; set outer=False
+ column_preferred_widths[j][i] = \
+ preferred_width(cell)
+ column_preferred_minimum_widths[j][i] = \
+ preferred_minimum_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)
+ # Point #2
+ column_widths = [None] * nb_columns
+ for column_group in table.column_groups:
+ for column in column_group.children:
+ assert isinstance(column, boxes.TableColumnBox)
+ column_widths[column.grid_x] = column.style.width
+
+ # TODO: handle percentages for column widths
+ if column_widths:
+ for widths in (column_preferred_widths,
+ column_preferred_minimum_widths):
+ for i, width in enumerate(widths):
+ column_width = column_widths[i]
+ if (column_width and column_width != 'auto'
+ and column_width.unit != '%'):
+ widths[i] = max(column_width.value, widths[i])
+
+ # Point #3
+ for cell in colspan_cells:
+ column_slice = slice(cell.grid_x, cell.grid_x + cell.colspan)
+
+ # TODO: when border-collapse: collapse; set outer=False
+ cell_width = preferred_width(cell)
+ columns_width = sum(column_preferred_widths[column_slice])
+ if cell_width > columns_width:
+ added_space = (cell_width - columns_width) / cell.colspan
+ for i in range(cell.grid_x, cell.grid_x + cell.colspan):
+ column_preferred_widths[i] += added_space
+
+ # TODO: when border-collapse: collapse; set outer=False
+ cell_minimum_width = preferred_minimum_width(cell)
+ columns_minimum_width = sum(
+ column_preferred_minimum_widths[column_slice])
+ if cell_minimum_width > columns_minimum_width:
+ added_space = (
+ (cell_minimum_width - columns_minimum_width) / cell.colspan)
+ for i in range(cell.grid_x, cell.grid_x + cell.colspan):
+ column_preferred_minimum_widths[i] += added_space
+
+ # TODO: Point #4
+
+ total_border_spacing = (nb_columns + 1) * table.style.border_spacing[0]
+ table_preferred_minimum_width = (
+ sum(column_preferred_minimum_widths) + total_border_spacing)
+ table_preferred_width = sum(column_preferred_widths) + total_border_spacing
table_maximum_width = max(
containing_block.width, table_preferred_minimum_width)
# TODO: handle the border spacings
@@ -380,11 +448,13 @@ def auto_table_layout(table, containing_block):
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)]
+ if lost_width > 0:
+ 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):

0 comments on commit 0d59b26

Please sign in to comment.