mirror of
https://github.com/Kozea/WeasyPrint.git
synced 2024-10-05 08:27:22 +03:00
Replace "*-content width" by "preferred * width"
This commit is contained in:
parent
b617122af0
commit
4898ad980b
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user