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