diff --git a/weasyprint/layout/inlines.py b/weasyprint/layout/inlines.py index 67186000..44c3e1ee 100644 --- a/weasyprint/layout/inlines.py +++ b/weasyprint/layout/inlines.py @@ -17,7 +17,7 @@ from .float import avoid_collisions, float_layout from .replaced import image_marker_layout from .min_max import handle_min_max_width, handle_min_max_height from .percentages import resolve_percentages, resolve_one_percentage -from .preferred import (shrink_to_fit, inline_preferred_minimum_width, +from .preferred import (shrink_to_fit, inline_min_content_width, trailing_whitespace_size) from .tables import find_in_flow_baseline, table_wrapper_width from ..text import split_first_line @@ -72,7 +72,7 @@ def get_next_linebox(context, linebox, position_y, skip_stack, if skip_stack == 'continue': return None, None - linebox.width = inline_preferred_minimum_width( + linebox.width = inline_min_content_width( context, linebox, skip_stack=skip_stack, first_line=True) linebox.height, _ = strut_layout(linebox.style, context.enable_hinting) diff --git a/weasyprint/layout/pages.py b/weasyprint/layout/pages.py index fce2dc5e..d64321c4 100644 --- a/weasyprint/layout/pages.py +++ b/weasyprint/layout/pages.py @@ -16,7 +16,7 @@ from ..formatting_structure import boxes, build from .absolute import absolute_layout from .blocks import block_level_layout, block_container_layout from .percentages import resolve_percentages -from .preferred import preferred_minimum_width, preferred_width +from .preferred import min_content_width, max_content_width from .min_max import handle_min_max_width, handle_min_max_height @@ -30,17 +30,18 @@ class OrientedBox(object): return self.sugar + self.inner @property - def outer_minimum(self): + def outer_min_content_size(self): return self.sugar + ( - self.minimum if self.inner == 'auto' else self.inner) + self.min_content_size if self.inner == 'auto' else self.inner) @property - def outer_preferred(self): + def outer_max_content_size(self): return self.sugar + ( - self.preferred if self.inner == 'auto' else self.inner) + self.max_content_size if self.inner == 'auto' else self.inner) def shrink_to_fit(self, available): - self.inner = min(max(self.minimum, available), self.preferred) + self.inner = min( + max(self.min_content_size, available), self.max_content_size) class VerticalBox(OrientedBox): @@ -62,13 +63,13 @@ class VerticalBox(OrientedBox): box.margin_top = self.margin_a box.margin_bottom = self.margin_b - # TODO: preferred (minimum) height??? + # TODO: Define what are the min-content and max-content heights @property - def minimum(self): + def min_content_size(self): return 0 @property - def preferred(self): + def max_content_size(self): return 1e6 @@ -82,8 +83,8 @@ class HorizontalBox(OrientedBox): self.padding_plus_border = ( box.padding_left + box.padding_right + box.border_left_width + box.border_right_width) - self._minimum = None - self._preferred = None + self._min_content_size = None + self._max_content_size = None def restore_box_attributes(self): box = self.box @@ -92,18 +93,18 @@ class HorizontalBox(OrientedBox): box.margin_right = self.margin_b @property - def minimum(self): - if self._minimum is None: - self._minimum = preferred_minimum_width( + def min_content_size(self): + if self._min_content_size is None: + self._min_content_size = min_content_width( self.context, self.box, outer=False) - return self._minimum + return self._min_content_size @property - def preferred(self): - if self._preferred is None: - self._preferred = preferred_width( + def max_content_size(self): + if self._max_content_size is None: + self._max_content_size = max_content_width( self.context, self.box, outer=False) - return self._preferred + return self._max_content_size def compute_fixed_dimension(context, box, outer, vertical, top_or_left): @@ -209,24 +210,28 @@ def compute_variable_dimension(context, side_boxes, vertical, outer_sum): if box_b.box.is_generated: if box_b.inner == 'auto': - ac_preferred = 2 * max( - box_a.outer_preferred, box_c.outer_preferred) - if outer_sum >= box_b.outer_preferred + ac_preferred: - box_b.inner = box_b.preferred + ac_max_content_size = 2 * max( + box_a.outer_max_content_size, box_c.outer_max_content_size) + if outer_sum >= ( + box_b.outer_max_content_size + ac_max_content_size): + box_b.inner = box_b.max_content_size else: - ac_minimum = 2 * max(box_a.outer_minimum, box_c.outer_minimum) - box_b.inner = box_b.minimum - available = outer_sum - box_b.outer - ac_minimum + ac_min_content_size = 2 * max( + box_a.outer_min_content_size, + box_c.outer_min_content_size) + box_b.inner = box_b.min_content_size + available = outer_sum - box_b.outer - ac_min_content_size if available > 0: - weight_ac = ac_preferred - ac_minimum - weight_b = box_b.preferred - box_b.minimum + weight_ac = ac_max_content_size - ac_min_content_size + weight_b = ( + box_b.max_content_size - box_b.min_content_size) weight_sum = weight_ac + weight_b - # By definition of preferred and minimum, weights can - # not be negative. weight_sum == 0 implies that - # preferred == minimum for each box, in which case the - # sum can not be both <= and > outer_sum - # Therefore, one of the last two 'if' statements would - # not have lead us here. + # By definition of max_content_size and min_content_size, + # weights can not be negative. weight_sum == 0 implies that + # max_content_size == min_content_size for each box, in + # which case the sum can not be both <= and > outer_sum + # Therefore, one of the last two 'if' statements would not + # have lead us here. assert weight_sum > 0 box_b.inner += available * weight_b / weight_sum if box_a.inner == 'auto': @@ -237,23 +242,27 @@ def compute_variable_dimension(context, side_boxes, vertical, outer_sum): # Non-generated boxes get zero for every box-model property assert box_b.inner == 0 if box_a.inner == box_c.inner == 'auto': - if box_a.outer_preferred + box_c.outer_preferred <= outer_sum: - box_a.inner = box_a.preferred - box_c.inner = box_c.preferred + if outer_sum >= ( + box_a.outer_max_content_size + + box_c.outer_max_content_size): + box_a.inner = box_a.max_content_size + box_c.inner = box_c.max_content_size else: - box_a.inner = box_a.minimum - box_c.inner = box_c.minimum + box_a.inner = box_a.min_content_size + box_c.inner = box_c.min_content_size available = outer_sum - box_a.outer - box_c.outer if available > 0: - weight_a = box_a.preferred - box_a.minimum - weight_c = box_c.preferred - box_c.minimum + weight_a = ( + box_a.max_content_size - box_a.min_content_size) + weight_c = ( + box_c.max_content_size - box_c.min_content_size) weight_sum = weight_a + weight_c - # By definition of preferred and minimum, weights can - # not be negative. weight_sum == 0 implies that - # preferred == minimum for each box, in which case the - # sum can not be both <= and > outer_sum - # Therefore, one of the last two 'if' statements would - # not have lead us here. + # By definition of max_content_size and min_content_size, + # weights can not be negative. weight_sum == 0 implies that + # max_content_size == min_content_size for each box, in + # which case the sum can not be both <= and > outer_sum + # Therefore, one of the last two 'if' statements would not + # have lead us here. assert weight_sum > 0 box_a.inner += available * weight_a / weight_sum box_c.inner += available * weight_c / weight_sum diff --git a/weasyprint/layout/preferred.py b/weasyprint/layout/preferred.py index 1c6bb6d7..6046f4bb 100644 --- a/weasyprint/layout/preferred.py +++ b/weasyprint/layout/preferred.py @@ -3,9 +3,13 @@ weasyprint.layout.preferred --------------------------- - Preferred and minimum preferred width, aka. the shrink-to-fit algorithm. + Preferred and minimum preferred width, aka. max-content and min-content + width, aka. the shrink-to-fit algorithm. - :copyright: Copyright 2011-2014 Simon Sapin and contributors, see AUTHORS. + Terms used (max-content width, min-content width) are defined in David + Baron's unofficial draft (http://dbaron.org/css/intrinsic/). + + :copyright: Copyright 2011-2016 Simon Sapin and contributors, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -30,55 +34,56 @@ def shrink_to_fit(context, box, available_width): """ return min( max( - preferred_minimum_width(context, box, outer=False), + min_content_width(context, box, outer=False), available_width), - preferred_width(context, box, outer=False)) + max_content_width(context, box, outer=False)) -def preferred_minimum_width(context, box, outer=True): - """Return the preferred minimum width for ``box``. +def min_content_width(context, box, outer=True): + """Return the min-content width for ``box``. This is the width by breaking at every line-break opportunity. """ if isinstance(box, boxes.BlockContainerBox): if box.is_table_wrapper: - return table_preferred_minimum_width(context, box, outer) + return outer_table_min_content_width(context, box, outer) else: - return block_preferred_minimum_width(context, box, outer) + return block_min_content_width(context, box, outer) elif isinstance(box, (boxes.InlineBox, boxes.LineBox)): - return inline_preferred_minimum_width( + return inline_min_content_width( context, box, outer, is_line_start=True) elif isinstance(box, boxes.ReplacedBox): - return replaced_preferred_width(box, outer) + return replaced_max_content_width(box, outer) else: raise TypeError( - 'Preferred minimum width for %s not handled yet' % + 'min-content width for %s not handled yet' % type(box).__name__) -def preferred_width(context, box, outer=True): - """Return the preferred width for ``box``. +def max_content_width(context, box, outer=True): + """Return the max-content width for ``box``. This is the width by only breaking at forced line breaks. """ if isinstance(box, boxes.BlockContainerBox): if box.is_table_wrapper: - return table_preferred_width(context, box, outer) + return outer_table_max_content_width(context, box, outer) else: - return block_preferred_width(context, box, outer) + return block_max_content_width(context, box, outer) elif isinstance(box, (boxes.InlineBox, boxes.LineBox)): - return inline_preferred_width(context, box, outer, is_line_start=True) + return inline_max_content_width( + context, box, outer, is_line_start=True) elif isinstance(box, boxes.ReplacedBox): - return replaced_preferred_width(box, outer) + return replaced_max_content_width(box, outer) else: raise TypeError( - 'Preferred width for %s not handled yet' % type(box).__name__) + 'max-content width for %s not handled yet' % type(box).__name__) -def _block_preferred_width(context, box, function, outer): - """Helper to create ``block_preferred_*_width.``""" +def _block_content_width(context, box, function, outer): + """Helper to create ``block_*_content_width.``""" width = box.style.width if width == 'auto' or width.unit == '%': # "percentages on the following properties are treated instead as @@ -138,47 +143,47 @@ def adjust(box, outer, width, left=True, right=True): return 0 -def block_preferred_minimum_width(context, box, outer=True): - """Return the preferred minimum width for a ``BlockBox``.""" - return _block_preferred_width( - context, box, preferred_minimum_width, outer) +def block_min_content_width(context, box, outer=True): + """Return the min-content width for a ``BlockBox``.""" + return _block_content_width( + context, box, min_content_width, outer) -def block_preferred_width(context, box, outer=True): - """Return the preferred width for a ``BlockBox``.""" - return _block_preferred_width(context, box, preferred_width, outer) +def block_max_content_width(context, box, outer=True): + """Return the max-content width for a ``BlockBox``.""" + return _block_content_width(context, box, max_content_width, outer) -def table_cell_preferred_minimum_width(context, box, table, - resolved_table_width, outer=True): - """Return the preferred minimum width for a ``TableCellBox``.""" +def table_cell_min_content_width(context, box, table, + resolved_table_width, outer=True): + """Return the min-content width for a ``TableCellBox``.""" # Try to solve the cell's width if it is a percentage width = box.style.width if (resolved_table_width and table.width != 'auto' and width != 'auto' and width.unit == '%'): return width.value / 100. * table.width - # Else return standard block's preferred minimum width - return _block_preferred_width( - context, box, preferred_minimum_width, outer) + # Else return standard block's min-content width + return _block_content_width( + context, box, min_content_width, outer) -def table_cell_preferred_width(context, box, table, resolved_table_width, - outer=True): - """Return the preferred width for a ``TableCellBox``.""" +def table_cell_max_content_width(context, box, table, resolved_table_width, + outer=True): + """Return the max-content width for a ``TableCellBox``.""" # Try to solve the cell's width if it is a percentage width = box.style.width if (resolved_table_width and table.width != 'auto' and width != 'auto' and width.unit == '%'): return width.value / 100. * table.width - # Else return standard block's preferred width - return _block_preferred_width(context, box, preferred_width, outer) + # Else return standard block's max-content width + return _block_content_width(context, box, max_content_width, outer) -def inline_preferred_minimum_width(context, box, outer=True, skip_stack=None, - first_line=False, is_line_start=False): - """Return the preferred minimum width for an ``InlineBox``. +def inline_min_content_width(context, box, outer=True, skip_stack=None, + first_line=False, is_line_start=False): + """Return the min-content width for an ``InlineBox``. The width is calculated from the lines from ``skip_stack``. If ``first_line`` is ``True``, only the first line minimum width is @@ -196,8 +201,8 @@ def inline_preferred_minimum_width(context, box, outer=True, skip_stack=None, return adjust(box, outer, max(widths)) -def inline_preferred_width(context, box, outer=True, is_line_start=False): - """Return the preferred width for an ``InlineBox``.""" +def inline_max_content_width(context, box, outer=True, is_line_start=False): + """Return the max-content width for an ``InlineBox``.""" widths = list( inline_line_widths(context, box, outer, is_line_start, minimum=False)) widths[-1] -= trailing_whitespace_size(context, box) @@ -247,9 +252,9 @@ def inline_line_widths(context, box, outer, is_line_start, minimum, # "By default, there is a break opportunity # both before and after any inline object." if minimum: - lines = [0, preferred_width(context, child), 0] + lines = [0, max_content_width(context, child), 0] else: - lines = [preferred_width(context, child)] + lines = [max_content_width(context, child)] # The first text line goes on the current line current_line += lines[0] if len(lines) > 1: @@ -269,14 +274,14 @@ TABLE_CACHE = weakref.WeakKeyDictionary() def table_and_columns_preferred_widths(context, box, outer=True, resolved_table_width=False): - """Return preferred widths for the table and its columns. + """Return max-content widths for the table and its columns. If ``resolved_table_width`` is ``True``, the resolved width (instead of the - one given in ``box.style``) is used to get the preferred widths. + one given in ``box.style``) is used to get the max-content widths. The tuple returned is - ``(table_preferred_minimum_width, table_preferred_width, - column_preferred_minimum_widths, column_preferred_widths)`` + ``(table_min_content_width, table_max_content_width, + column_min_content_widths, column_max_content_widths)`` http://www.w3.org/TR/CSS21/tables.html#auto-table-layout @@ -320,25 +325,25 @@ def table_and_columns_preferred_widths(context, box, outer=True, colspan_cells.append(cell) # Point #1 - column_preferred_widths = [[0] * nb_rows for i in range(nb_columns)] - column_preferred_minimum_widths = [ + column_max_content_widths = [[0] * nb_rows for i in range(nb_columns)] + column_min_content_widths = [ [0] * nb_rows for i in range(nb_columns)] for i, row in enumerate(grid): for j, cell in enumerate(row): if cell: - column_preferred_widths[j][i] = \ - table_cell_preferred_width( + column_max_content_widths[j][i] = \ + table_cell_max_content_width( context, cell, table, resolved_table_width) - column_preferred_minimum_widths[j][i] = \ - table_cell_preferred_minimum_width( + column_min_content_widths[j][i] = \ + table_cell_min_content_width( context, cell, table, resolved_table_width) - column_preferred_widths = [ + column_max_content_widths = [ max(widths) if widths else 0 - for widths in column_preferred_widths] - column_preferred_minimum_widths = [ + for widths in column_max_content_widths] + column_min_content_widths = [ max(widths) if widths else 0 - for widths in column_preferred_minimum_widths] + for widths in column_min_content_widths] # Point #2 column_groups_widths = [] @@ -351,8 +356,8 @@ def table_and_columns_preferred_widths(context, box, outer=True, column_widths[column.grid_x] = column.style.width if column_widths: - for widths in (column_preferred_widths, - column_preferred_minimum_widths): + for widths in (column_max_content_widths, + column_min_content_widths): for i, width in enumerate(widths): column_width = column_widths[i] if column_width and column_width != 'auto': @@ -369,26 +374,26 @@ def table_and_columns_preferred_widths(context, box, outer=True, column_slice = slice(cell.grid_x, cell.grid_x + cell.colspan) cell_width = ( - table_cell_preferred_width( + table_cell_max_content_width( context, cell, table, resolved_table_width) - border_spacing_x * (cell.colspan - 1)) - columns_width = sum(column_preferred_widths[column_slice]) + columns_width = sum(column_max_content_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 + column_max_content_widths[i] += added_space cell_minimum_width = ( - table_cell_preferred_minimum_width( + table_cell_min_content_width( context, cell, table, resolved_table_width) - border_spacing_x * (cell.colspan - 1)) columns_minimum_width = sum( - column_preferred_minimum_widths[column_slice]) + column_min_content_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 + column_min_content_widths[i] += added_space # Point #4 for column_group, column_group_width in column_groups_widths: @@ -397,7 +402,7 @@ def table_and_columns_preferred_widths(context, box, outer=True, column_indexes = [ column.grid_x for column in column_group.children] columns_width = sum( - column_preferred_minimum_widths[index] + column_min_content_widths[index] for index in column_indexes) if column_group_width.unit == '%': column_group_width = ( @@ -408,73 +413,75 @@ def table_and_columns_preferred_widths(context, box, outer=True, added_space = ( (column_group_width - columns_width) / len(column_indexes)) for i in column_indexes: - column_preferred_minimum_widths[i] += added_space + column_min_content_widths[i] += added_space # The spec seems to say that the colgroup's width is just a # hint for column group's columns minimum width, but if the # sum of the preferred maximum width of the colums is lower # or greater than the colgroup's one, then the columns # don't follow the hint. These lines make the preferred - # width equal or greater than the minimum preferred width. - if (column_preferred_widths[i] < - column_preferred_minimum_widths[i]): - column_preferred_widths[i] = \ - column_preferred_minimum_widths[i] + # width equal or greater than the minimum max-content + # width. + if (column_max_content_widths[i] < + column_min_content_widths[i]): + column_max_content_widths[i] = \ + column_min_content_widths[i] total_border_spacing = (nb_columns + 1) * border_spacing_x - table_preferred_minimum_width = ( - sum(column_preferred_minimum_widths) + total_border_spacing) - table_preferred_width = sum(column_preferred_widths) + total_border_spacing + table_min_content_width = ( + sum(column_min_content_widths) + total_border_spacing) + table_max_content_width = ( + sum(column_max_content_widths) + total_border_spacing) captions = [child for child in box.children if child is not table and not child.is_absolutely_positioned()] if captions: caption_width = max( - preferred_minimum_width(context, caption) for caption in captions) + min_content_width(context, caption) for caption in captions) else: caption_width = 0 if table.style.width != 'auto': # Take care of the table width if resolved_table_width: - if table.width > table_preferred_minimum_width: - table_preferred_minimum_width = table.width + if table.width > table_min_content_width: + table_min_content_width = table.width else: if (table.style.width.unit != '%' and - table.style.width.value > table_preferred_minimum_width): - table_preferred_minimum_width = table.style.width.value + table.style.width.value > table_min_content_width): + table_min_content_width = table.style.width.value - if table_preferred_minimum_width < caption_width: - table_preferred_minimum_width = caption_width + if table_min_content_width < caption_width: + table_min_content_width = caption_width - if table_preferred_minimum_width > table_preferred_width: - table_preferred_width = table_preferred_minimum_width + if table_min_content_width > table_max_content_width: + table_max_content_width = table_min_content_width result = ( - table_preferred_minimum_width, table_preferred_width, - column_preferred_minimum_widths, column_preferred_widths) + table_min_content_width, table_max_content_width, + column_min_content_widths, column_max_content_widths) TABLE_CACHE[table] = result return result -def table_preferred_minimum_width(context, box, outer=True): - """Return the preferred minimum width for a ``TableBox``. wrapper""" +def outer_table_min_content_width(context, box, outer=True): + """Return the min-content width for a ``TableBox``. wrapper""" resolved_table_width = box.style.width != 'auto' minimum_width, _, _, _ = table_and_columns_preferred_widths( context, box, resolved_table_width) return adjust(box, outer, minimum_width) -def table_preferred_width(context, box, outer=True): - """Return the preferred width for a ``TableBox`` wrapper.""" +def outer_table_max_content_width(context, box, outer=True): + """Return the max-content width for a ``TableBox`` wrapper.""" resolved_table_width = box.style.width != 'auto' _, width, _, _ = table_and_columns_preferred_widths( context, box, resolved_table_width) return adjust(box, outer, width) -def replaced_preferred_width(box, outer=True): - """Return the preferred minimum width for an ``InlineReplacedBox``.""" +def replaced_max_content_width(box, outer=True): + """Return the min-content width for an ``InlineReplacedBox``.""" width = box.style.width if width == 'auto' or width.unit == '%': height = box.style.height diff --git a/weasyprint/layout/tables.py b/weasyprint/layout/tables.py index 03e94453..be9203a3 100644 --- a/weasyprint/layout/tables.py +++ b/weasyprint/layout/tables.py @@ -5,7 +5,7 @@ Layout for tables and internal table boxes. - :copyright: Copyright 2011-2014 Simon Sapin and contributors, see AUTHORS. + :copyright: Copyright 2011-2016 Simon Sapin and contributors, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -23,11 +23,7 @@ from .preferred import table_and_columns_preferred_widths def table_layout(context, table, max_position_y, skip_stack, containing_block, device_size, page_is_empty, absolute_boxes, fixed_boxes): - """Layout for a table box. - - For now only the fixed layout and separate border model are supported. - - """ + """Layout for a table box.""" # Avoid a circular import from .blocks import block_container_layout @@ -501,8 +497,8 @@ def auto_table_layout(context, box, containing_block): """ table = box.get_wrapped_table() - (table_preferred_minimum_width, table_preferred_width, - column_preferred_minimum_widths, column_preferred_widths) = \ + (table_min_content_width, table_max_content_width, + column_min_content_widths, column_max_content_widths) = \ table_and_columns_preferred_widths( context, box, resolved_table_width=table.width != 'auto') @@ -512,7 +508,7 @@ def auto_table_layout(context, box, containing_block): border_spacing_x = 0 all_border_spacing = ( - border_spacing_x * (len(column_preferred_widths) + 1)) + border_spacing_x * (len(column_max_content_widths) + 1)) margins = 0 if box.margin_left != 'auto': @@ -523,33 +519,33 @@ def auto_table_layout(context, box, containing_block): cb_width, cb_height = containing_block available_width = cb_width - margins if table.width == 'auto': - if available_width < table_preferred_minimum_width: - table.width = table_preferred_minimum_width - table.column_widths = column_preferred_minimum_widths - elif available_width < table_preferred_width: + if available_width < table_min_content_width: + table.width = table_min_content_width + table.column_widths = column_min_content_widths + elif available_width < table_max_content_width: table.width = available_width - table.column_widths = column_preferred_minimum_widths + table.column_widths = column_min_content_widths else: - table.width = table_preferred_width - table.column_widths = column_preferred_widths + table.width = table_max_content_width + table.column_widths = column_max_content_widths else: - if table.width < table_preferred_minimum_width: - table.width = table_preferred_minimum_width - table.column_widths = column_preferred_minimum_widths - elif table.width < table_preferred_width: - table.column_widths = column_preferred_minimum_widths + if table.width < table_min_content_width: + table.width = table_min_content_width + table.column_widths = column_min_content_widths + elif table.width < table_max_content_width: + table.column_widths = column_min_content_widths else: - table.column_widths = column_preferred_widths + table.column_widths = column_max_content_widths lost_width = table.width - sum(table.column_widths) - all_border_spacing if lost_width > 0: - sum_column_preferred_widths = sum(column_preferred_widths) - if sum_column_preferred_widths: + sum_column_max_content_widths = sum(column_max_content_widths) + if sum_column_max_content_widths: table.column_widths = [ - (column_width + lost_width * preferred_column_width / - sum_column_preferred_widths) - for (preferred_column_width, column_width) - in zip(column_preferred_widths, table.column_widths)] + (column_width + lost_width * max_content_column_width / + sum_column_max_content_widths) + for (max_content_column_width, column_width) + in zip(column_max_content_widths, table.column_widths)] else: table.column_widths = [ column_width + lost_width / len(table.column_widths)