mirror of
https://github.com/Kozea/WeasyPrint.git
synced 2024-10-04 16:07:57 +03:00
Fix all crashes with W3C test suite
This commit is contained in:
parent
1fc10281df
commit
19365e824e
@ -282,9 +282,10 @@ def break_before_after(computer, name, value):
|
||||
@register_computer('padding-left')
|
||||
@register_computer('text-indent')
|
||||
@register_computer('hyphenate-limit-zone')
|
||||
@register_computer('flex-basis')
|
||||
def length(computer, name, value, font_size=None, pixels_only=False):
|
||||
"""Compute a length ``value``."""
|
||||
if value == 'auto':
|
||||
if value in ('auto', 'content'):
|
||||
return value
|
||||
if value.value == 0:
|
||||
return 0 if pixels_only else ZERO_PIXELS
|
||||
|
@ -511,8 +511,9 @@ def draw_border(context, box, enable_hinting):
|
||||
def draw_column_border():
|
||||
"""Draw column borders."""
|
||||
columns = (
|
||||
box.style['column_width'] != 'auto' or
|
||||
box.style['column_count'] != 'auto')
|
||||
isinstance(box, boxes.BlockContainerBox) and (
|
||||
box.style['column_width'] != 'auto' or
|
||||
box.style['column_count'] != 'auto'))
|
||||
if columns and box.style['column_rule_width']:
|
||||
border_widths = (0, 0, 0, box.style['column_rule_width'])
|
||||
for child in box.children[1:]:
|
||||
@ -984,7 +985,8 @@ def draw_replacedbox(context, box):
|
||||
def draw_inline_level(context, page, box, enable_hinting):
|
||||
if isinstance(box, StackingContext):
|
||||
stacking_context = box
|
||||
assert isinstance(stacking_context.box, boxes.InlineBlockBox)
|
||||
assert isinstance(
|
||||
stacking_context.box, (boxes.InlineBlockBox, boxes.InlineFlexBox))
|
||||
draw_stacking_context(context, stacking_context, enable_hinting)
|
||||
else:
|
||||
draw_background(context, box.background, enable_hinting)
|
||||
|
@ -399,7 +399,14 @@ def wrap_improper(box, children, wrapper_type, test=None):
|
||||
# Whitespace either fail the test or were removed earlier,
|
||||
# so there is no need to take special care with the definition
|
||||
# of "consecutive".
|
||||
improper.append(child)
|
||||
if isinstance(box, boxes.FlexContainerBox):
|
||||
# The display value of a flex item must be "blockified", see
|
||||
# https://www.w3.org/TR/css-flexbox-1/#flex-items
|
||||
# TODO: These blocks are currently ignored, we should
|
||||
# "blockify" them and their children.
|
||||
pass
|
||||
else:
|
||||
improper.append(child)
|
||||
if improper:
|
||||
wrapper = wrapper_type.anonymous_from(box, children=[])
|
||||
# Apply the rules again on the new wrapper
|
||||
|
@ -229,6 +229,49 @@ def absolute_block(context, box, containing_block, fixed_boxes):
|
||||
return new_box
|
||||
|
||||
|
||||
def absolute_flex(context, box, containing_block_sizes, fixed_boxes,
|
||||
containing_block):
|
||||
# Avoid a circular import
|
||||
from .flex import flex_layout
|
||||
|
||||
# TODO: this function is really close to absolute_block, we should have
|
||||
# only one function.
|
||||
# TODO: having containing_block_sizes and containing_block is stupid.
|
||||
cb_x, cb_y, cb_width, cb_height = containing_block_sizes
|
||||
|
||||
translate_box_width, translate_x = absolute_width(
|
||||
box, context, containing_block_sizes)
|
||||
translate_box_height, translate_y = absolute_height(
|
||||
box, context, containing_block_sizes)
|
||||
|
||||
# This box is the containing block for absolute descendants.
|
||||
absolute_boxes = []
|
||||
|
||||
if box.is_table_wrapper:
|
||||
table_wrapper_width(context, box, (cb_width, cb_height))
|
||||
|
||||
# TODO: remove device_size everywhere else
|
||||
new_box, _, _, _, _ = flex_layout(
|
||||
context, box, max_position_y=float('inf'), skip_stack=None,
|
||||
containing_block=containing_block, device_size=None,
|
||||
page_is_empty=False, absolute_boxes=absolute_boxes,
|
||||
fixed_boxes=fixed_boxes)
|
||||
|
||||
list_marker_layout(context, new_box)
|
||||
|
||||
for child_placeholder in absolute_boxes:
|
||||
absolute_layout(context, child_placeholder, new_box, fixed_boxes)
|
||||
|
||||
if translate_box_width:
|
||||
translate_x -= new_box.width
|
||||
if translate_box_height:
|
||||
translate_y -= new_box.height
|
||||
|
||||
new_box.translate(translate_x, translate_y)
|
||||
|
||||
return new_box
|
||||
|
||||
|
||||
def absolute_layout(context, placeholder, containing_block, fixed_boxes):
|
||||
"""Set the width of absolute positioned ``box``."""
|
||||
assert not placeholder._layout_done
|
||||
@ -260,6 +303,9 @@ def absolute_box_layout(context, box, containing_block, fixed_boxes):
|
||||
# Absolute tables are wrapped into block boxes
|
||||
if isinstance(box, boxes.BlockBox):
|
||||
new_box = absolute_block(context, box, containing_block, fixed_boxes)
|
||||
elif isinstance(box, boxes.FlexContainerBox):
|
||||
new_box = absolute_flex(
|
||||
context, box, containing_block, fixed_boxes, cb)
|
||||
else:
|
||||
assert isinstance(box, boxes.BlockReplacedBox)
|
||||
new_box = absolute_replaced(context, box, containing_block)
|
||||
|
@ -9,11 +9,13 @@
|
||||
|
||||
"""
|
||||
|
||||
import sys
|
||||
from math import log10
|
||||
|
||||
from ..css.properties import Dimension
|
||||
from ..formatting_structure import boxes
|
||||
from .percentages import resolve_percentages
|
||||
from .markers import list_marker_layout
|
||||
from .percentages import resolve_one_percentage, resolve_percentages
|
||||
from .preferred import max_content_width, min_content_width
|
||||
from .tables import find_in_flow_baseline
|
||||
|
||||
@ -48,8 +50,11 @@ def flex_layout(context, box, max_position_y, skip_stack, containing_block,
|
||||
else:
|
||||
main_space = max_position_y - box.position_y
|
||||
if containing_block.height != 'auto':
|
||||
assert containing_block.height.unit == 'px'
|
||||
main_space = min(main_space, containing_block.height.value)
|
||||
if hasattr(containing_block.height, 'unit'):
|
||||
assert containing_block.height.unit == 'px'
|
||||
main_space = min(main_space, containing_block.height.value)
|
||||
else:
|
||||
main_space = min(main_space, containing_block.height)
|
||||
available_main_space = (
|
||||
main_space -
|
||||
box.margin_top - box.margin_bottom -
|
||||
@ -62,8 +67,11 @@ def flex_layout(context, box, max_position_y, skip_stack, containing_block,
|
||||
if cross == 'height':
|
||||
main_space = max_position_y - box.content_box_y()
|
||||
if containing_block.height != 'auto':
|
||||
assert containing_block.height.unit == 'px'
|
||||
main_space = min(main_space, containing_block.height.value)
|
||||
if hasattr(containing_block.height, 'unit'):
|
||||
assert containing_block.height.unit == 'px'
|
||||
main_space = min(main_space, containing_block.height.value)
|
||||
else:
|
||||
main_space = min(main_space, containing_block.height)
|
||||
available_cross_space = (
|
||||
main_space -
|
||||
box.margin_top - box.margin_bottom -
|
||||
@ -77,6 +85,8 @@ def flex_layout(context, box, max_position_y, skip_stack, containing_block,
|
||||
box.border_left_width - box.border_right_width)
|
||||
|
||||
# Step 3
|
||||
resolve_percentages(box, containing_block)
|
||||
blocks.block_level_width(box, containing_block)
|
||||
children = box.children
|
||||
if skip_stack is not None:
|
||||
assert skip_stack[1] is None
|
||||
@ -90,9 +100,9 @@ def flex_layout(context, box, max_position_y, skip_stack, containing_block,
|
||||
child.position_y = box.content_box_y()
|
||||
|
||||
child.style = child.style.copy()
|
||||
resolve_percentages(box, containing_block)
|
||||
|
||||
flex_basis = child.style['flex_basis']
|
||||
resolve_one_percentage(child, 'flex_basis', available_main_space)
|
||||
flex_basis = child.flex_basis
|
||||
|
||||
# "If a value would resolve to auto for width, it instead resolves
|
||||
# to content for flex-basis." Let's do this for height too.
|
||||
@ -101,13 +111,12 @@ def flex_layout(context, box, max_position_y, skip_stack, containing_block,
|
||||
if child.style[axis] == 'auto':
|
||||
flex_basis = 'content'
|
||||
else:
|
||||
flex_basis = child.style[axis]
|
||||
resolve_one_percentage(child, axis, available_main_space)
|
||||
flex_basis = getattr(child, axis)
|
||||
|
||||
# Step 3.A
|
||||
# TODO: handle percentages
|
||||
if flex_basis != 'content':
|
||||
assert flex_basis.unit == 'px'
|
||||
child.flex_base_size = flex_basis.value
|
||||
child.flex_base_size = flex_basis
|
||||
|
||||
# TODO: Step 3.B
|
||||
# TODO: Step 3.C
|
||||
@ -119,7 +128,7 @@ def flex_layout(context, box, max_position_y, skip_stack, containing_block,
|
||||
if flex_basis == 'content':
|
||||
child.style[axis] = 'max-content'
|
||||
else:
|
||||
child.style[axis] = flex_basis
|
||||
child.style[axis] = Dimension(flex_basis, 'px')
|
||||
|
||||
# TODO: don't set style value, support *-content values instead
|
||||
if child.style[axis] == 'max-content':
|
||||
@ -129,10 +138,10 @@ def flex_layout(context, box, max_position_y, skip_stack, containing_block,
|
||||
else:
|
||||
new_child = child.copy_with_children(child.children)
|
||||
new_child.width = float('inf')
|
||||
new_child = blocks.block_container_layout(
|
||||
new_child = blocks.block_level_layout(
|
||||
context, new_child, float('inf'), skip_stack,
|
||||
device_size, page_is_empty, absolute_boxes,
|
||||
fixed_boxes)[0]
|
||||
box, device_size, page_is_empty, absolute_boxes,
|
||||
fixed_boxes, adjoining_margins=[])[0]
|
||||
child.flex_base_size = new_child.height
|
||||
elif child.style[axis] == 'min-content':
|
||||
child.style[axis] = 'auto'
|
||||
@ -141,10 +150,10 @@ def flex_layout(context, box, max_position_y, skip_stack, containing_block,
|
||||
else:
|
||||
new_child = child.copy_with_children(child.children)
|
||||
new_child.width = 0
|
||||
new_child = blocks.block_container_layout(
|
||||
new_child = blocks.block_level_layout(
|
||||
context, new_child, float('inf'), skip_stack,
|
||||
device_size, page_is_empty, absolute_boxes,
|
||||
fixed_boxes)[0]
|
||||
box, device_size, page_is_empty, absolute_boxes,
|
||||
fixed_boxes, adjoining_margins=[])[0]
|
||||
child.flex_base_size = new_child.height
|
||||
else:
|
||||
assert child.style[axis].unit == 'px'
|
||||
@ -259,11 +268,16 @@ def flex_layout(context, box, max_position_y, skip_stack, containing_block,
|
||||
if unfrozen_factor_sum < 1:
|
||||
initial_free_space *= unfrozen_factor_sum
|
||||
|
||||
if initial_free_space == float('inf'):
|
||||
initial_free_space = sys.maxsize
|
||||
if remaining_free_space == float('inf'):
|
||||
remaining_free_space = sys.maxsize
|
||||
|
||||
initial_magnitude = (
|
||||
int(log10(initial_free_space)) if initial_free_space > 0
|
||||
else -float('inf'))
|
||||
remaining_magnitude = (
|
||||
int(log10(remaining_free_space)) if initial_free_space > 0
|
||||
int(log10(remaining_free_space)) if remaining_free_space > 0
|
||||
else -float('inf'))
|
||||
if initial_magnitude < remaining_magnitude:
|
||||
remaining_free_space = initial_free_space
|
||||
@ -285,7 +299,9 @@ def flex_layout(context, box, max_position_y, skip_stack, containing_block,
|
||||
child.scaled_flex_shrink_factor)
|
||||
for child in line:
|
||||
if not child.frozen:
|
||||
if flex_factor_type == 'grow':
|
||||
if scaled_flex_shrink_factors_sum == 0:
|
||||
child.target_main_size = child.flex_base_size
|
||||
elif flex_factor_type == 'grow':
|
||||
ratio = (
|
||||
child.style['flex_grow'] /
|
||||
scaled_flex_shrink_factors_sum)
|
||||
@ -329,15 +345,35 @@ def flex_layout(context, box, max_position_y, skip_stack, containing_block,
|
||||
for line in flex_lines:
|
||||
new_flex_line = FlexLine()
|
||||
for child in line:
|
||||
# TODO: Find another way than calling block_container_layout to get
|
||||
# baseline and child.height
|
||||
child_copy = child.copy_with_children(child.children)
|
||||
if child_copy.margin_top == 'auto':
|
||||
child_copy.margin_top = 0
|
||||
if child_copy.margin_bottom == 'auto':
|
||||
child_copy.margin_bottom = 0
|
||||
blocks.block_level_width(child_copy, box)
|
||||
new_child = blocks.block_level_layout(
|
||||
context, child_copy,
|
||||
available_cross_space + box.content_box_y(), skip_stack,
|
||||
box, device_size, page_is_empty, absolute_boxes,
|
||||
fixed_boxes, adjoining_margins=[])[0]
|
||||
|
||||
if new_child is None:
|
||||
# TODO: "If the item does not have a baseline in the
|
||||
# necessary axis, then one is synthesized from the flex
|
||||
# item’s border box."
|
||||
child._baseline = 0
|
||||
else:
|
||||
child._baseline = find_in_flow_baseline(new_child)
|
||||
|
||||
if cross == 'height':
|
||||
child = blocks.block_container_layout(
|
||||
context, child,
|
||||
available_cross_space + box.content_box_y(), skip_stack,
|
||||
device_size, page_is_empty, absolute_boxes, fixed_boxes)[0]
|
||||
# TODO: check that
|
||||
child.height = 0 if new_child is None else new_child.height
|
||||
else:
|
||||
child.width = min_content_width(context, child, outer=False)
|
||||
if child is not None:
|
||||
new_flex_line.append(child)
|
||||
|
||||
new_flex_line.append(child)
|
||||
if new_flex_line:
|
||||
new_flex_lines.append(new_flex_line)
|
||||
flex_lines = new_flex_lines
|
||||
@ -362,21 +398,29 @@ def flex_layout(context, box, max_position_y, skip_stack, containing_block,
|
||||
cross_start_distance = 0
|
||||
cross_end_distance = 0
|
||||
for child in collected_items:
|
||||
baseline = find_in_flow_baseline(child)
|
||||
if baseline is None:
|
||||
baseline = 0
|
||||
else:
|
||||
baseline -= child.position_y
|
||||
baseline = child._baseline - child.position_y
|
||||
cross_start_distance = max(cross_start_distance, baseline)
|
||||
cross_end_distance = max(
|
||||
cross_end_distance, child.margin_height() - baseline)
|
||||
collected_cross_size = cross_start_distance + cross_end_distance
|
||||
non_collected_cross_size = 0
|
||||
if not_collected_items:
|
||||
non_collected_cross_size = max(
|
||||
child.margin_height() if cross == 'height'
|
||||
else child.margin_width()
|
||||
for child in not_collected_items)
|
||||
non_collected_cross_size = float('-inf')
|
||||
for child in not_collected_items:
|
||||
if cross == 'height':
|
||||
child_cross_size = child.border_height()
|
||||
if child.margin_top != 'auto':
|
||||
child_cross_size += child.margin_top
|
||||
if child.margin_bottom != 'auto':
|
||||
child_cross_size += child.margin_bottom
|
||||
else:
|
||||
child_cross_size = child.border_width()
|
||||
if child.margin_left != 'auto':
|
||||
child_cross_size += child.margin_left
|
||||
if child.margin_right != 'auto':
|
||||
child_cross_size += child.margin_right
|
||||
non_collected_cross_size = max(
|
||||
child_cross_size, non_collected_cross_size)
|
||||
line.cross_size = max(
|
||||
collected_cross_size, non_collected_cross_size)
|
||||
# TODO: handle min/max height for single-line containers
|
||||
@ -445,44 +489,56 @@ def flex_layout(context, box, max_position_y, skip_stack, containing_block,
|
||||
|
||||
for line in flex_lines:
|
||||
position_axis = original_position_axis
|
||||
free_space = getattr(box, axis) - sum(
|
||||
child.margin_width() if axis == 'width'
|
||||
else child.margin_height() for child in line)
|
||||
if axis == 'width':
|
||||
free_space = box.width
|
||||
for child in line:
|
||||
free_space -= child.border_width()
|
||||
if child.margin_left != 'auto':
|
||||
free_space -= child.margin_left
|
||||
if child.margin_right != 'auto':
|
||||
free_space -= child.margin_right
|
||||
else:
|
||||
free_space = box.height
|
||||
for child in line:
|
||||
free_space -= child.border_height()
|
||||
if child.margin_top != 'auto':
|
||||
free_space -= child.margin_top
|
||||
if child.margin_bottom != 'auto':
|
||||
free_space -= child.margin_bottom
|
||||
|
||||
if free_space > 0:
|
||||
margins = 0
|
||||
margins = 0
|
||||
for child in line:
|
||||
if axis == 'width':
|
||||
if child.margin_left == 'auto':
|
||||
margins += 1
|
||||
if child.margin_right == 'auto':
|
||||
margins += 1
|
||||
else:
|
||||
if child.margin_top == 'auto':
|
||||
margins += 1
|
||||
if child.margin_bottom == 'auto':
|
||||
margins += 1
|
||||
if margins:
|
||||
free_space /= margins
|
||||
for child in line:
|
||||
if axis == 'width':
|
||||
if child.margin_left == 'auto':
|
||||
margins += 1
|
||||
child.margin_left = free_space
|
||||
if child.margin_right == 'auto':
|
||||
margins += 1
|
||||
child.margin_right = free_space
|
||||
else:
|
||||
if child.margin_top == 'auto':
|
||||
margins += 1
|
||||
child.margin_top = free_space
|
||||
if child.margin_bottom == 'auto':
|
||||
margins += 1
|
||||
if margins:
|
||||
free_space /= margins
|
||||
for child in line:
|
||||
if axis == 'width':
|
||||
if child.margin_left == 'auto':
|
||||
child.margin_left = free_space
|
||||
if child.margin_right == 'auto':
|
||||
child.margin_right = free_space
|
||||
else:
|
||||
if child.margin_top == 'auto':
|
||||
child.margin_top = free_space
|
||||
if child.margin_bottom == 'auto':
|
||||
child.margin_bottom = free_space
|
||||
free_space = 0
|
||||
child.margin_bottom = free_space
|
||||
free_space = 0
|
||||
|
||||
if justify_content == 'flex-end':
|
||||
position_axis += free_space
|
||||
elif justify_content == 'center':
|
||||
position_axis += free_space / 2
|
||||
elif justify_content == 'space-around':
|
||||
position_axis += free_space / len(line) / 2
|
||||
if justify_content == 'flex-end':
|
||||
position_axis += free_space
|
||||
elif justify_content == 'center':
|
||||
position_axis += free_space / 2
|
||||
elif justify_content == 'space-around':
|
||||
position_axis += free_space / len(line) / 2
|
||||
|
||||
for child in line:
|
||||
if axis == 'width':
|
||||
@ -511,14 +567,7 @@ def flex_layout(context, box, max_position_y, skip_stack, containing_block,
|
||||
align_self = box.style['align_items']
|
||||
if align_self == 'baseline' and axis == 'width':
|
||||
# TODO: handle vertical text
|
||||
baseline = find_in_flow_baseline(child)
|
||||
if baseline is None:
|
||||
# TODO: "If the item does not have a baseline in the
|
||||
# necessary axis, then one is synthesized from the flex
|
||||
# item’s border box."
|
||||
child.baseline = 0
|
||||
else:
|
||||
child.baseline = baseline - position_cross
|
||||
child.baseline = child._baseline - position_cross
|
||||
lower_baseline = max(lower_baseline, child.baseline)
|
||||
for child in line:
|
||||
cross_margins = (
|
||||
@ -526,10 +575,19 @@ def flex_layout(context, box, max_position_y, skip_stack, containing_block,
|
||||
else (child.margin_left, child.margin_right))
|
||||
auto_margins = sum([margin == 'auto' for margin in cross_margins])
|
||||
if auto_margins:
|
||||
# TODO: take care of margins insead of using margin_*()
|
||||
extra_cross = available_cross_space - (
|
||||
child.margin_height() if cross == 'height'
|
||||
else child.margin_width())
|
||||
extra_cross = available_cross_space
|
||||
if cross == 'height':
|
||||
extra_cross -= child.border_height()
|
||||
if child.margin_top != 'auto':
|
||||
extra_cross -= child.margin_top
|
||||
if child.margin_bottom != 'auto':
|
||||
extra_cross -= child.margin_bottom
|
||||
else:
|
||||
extra_cross -= child.border_width()
|
||||
if child.margin_left != 'auto':
|
||||
extra_cross -= child.margin_left
|
||||
if child.margin_right != 'auto':
|
||||
extra_cross -= child.margin_right
|
||||
if extra_cross > 0:
|
||||
extra_cross /= auto_margins
|
||||
if cross == 'height':
|
||||
@ -636,11 +694,19 @@ def flex_layout(context, box, max_position_y, skip_stack, containing_block,
|
||||
for line in flex_lines:
|
||||
for child in line:
|
||||
if child.is_flex_item:
|
||||
new_child = blocks.block_container_layout(
|
||||
context, child, max_position_y, skip_stack, device_size,
|
||||
page_is_empty, absolute_boxes, fixed_boxes)[0]
|
||||
new_child = blocks.block_level_layout(
|
||||
context, child, max_position_y, skip_stack, box,
|
||||
device_size, page_is_empty, absolute_boxes, fixed_boxes,
|
||||
adjoining_margins=[])[0]
|
||||
if new_child is not None:
|
||||
list_marker_layout(context, new_child)
|
||||
box.children.append(new_child)
|
||||
|
||||
if axis == 'width' and box.height == 'auto':
|
||||
if flex_lines:
|
||||
box.height = sum(line.cross_size for line in flex_lines)
|
||||
else:
|
||||
box.height = 0
|
||||
|
||||
# TODO: check these returned values
|
||||
return box, resume_at, {'break': 'any', 'page': None}, [], False
|
||||
|
@ -16,6 +16,7 @@ from ..css.computed_values import ex_ratio, strut_layout
|
||||
from ..formatting_structure import boxes
|
||||
from ..text import can_break_text, split_first_line
|
||||
from .absolute import AbsolutePlaceholder, absolute_layout
|
||||
from .flex import flex_layout
|
||||
from .float import avoid_collisions, float_layout
|
||||
from .min_max import handle_min_max_height, handle_min_max_width
|
||||
from .percentages import resolve_one_percentage, resolve_percentages
|
||||
@ -609,7 +610,21 @@ def split_inline_level(context, box, position_x, max_x, skip_stack,
|
||||
# Atomic inlines behave like ideographic characters.
|
||||
first_letter = '\u2e80'
|
||||
last_letter = '\u2e80'
|
||||
# else: unexpected box type here
|
||||
elif isinstance(box, boxes.InlineFlexBox):
|
||||
box.position_x = position_x
|
||||
box.position_y = 0
|
||||
box.baseline = 0
|
||||
for side in ['top', 'right', 'bottom', 'left']:
|
||||
if getattr(box, 'margin_' + side) == 'auto':
|
||||
setattr(box, 'margin_' + side, 0)
|
||||
new_box, resume_at, _, _, _ = flex_layout(
|
||||
context, box, float('inf'), skip_stack, containing_block,
|
||||
device_size, False, absolute_boxes, fixed_boxes)
|
||||
preserved_line_break = False
|
||||
first_letter = '\u2e80'
|
||||
last_letter = '\u2e80'
|
||||
else: # pragma: no cover
|
||||
raise TypeError('Layout for %s not handled yet' % type(box).__name__)
|
||||
return new_box, resume_at, preserved_line_break, first_letter, last_letter
|
||||
|
||||
|
||||
@ -741,6 +756,8 @@ def split_inline_box(context, box, position_x, max_x, skip_stack,
|
||||
can_break = None
|
||||
if last_letter is True:
|
||||
last_letter = ' '
|
||||
elif last_letter is False:
|
||||
last_letter = ' ' # no-break space
|
||||
elif box.style['white_space'] in ('pre', 'nowrap'):
|
||||
can_break = False
|
||||
if can_break is None:
|
||||
|
@ -508,7 +508,7 @@ def make_page(context, root_box, page_type, resume_at, page_number=None):
|
||||
|
||||
# TODO: handle cases where the root element is something else.
|
||||
# See http://www.w3.org/TR/CSS21/visuren.html#dis-pos-flo
|
||||
assert isinstance(root_box, boxes.BlockBox)
|
||||
assert isinstance(root_box, (boxes.BlockBox, boxes.FlexContainerBox))
|
||||
context.create_block_formatting_context()
|
||||
page_is_empty = True
|
||||
adjoining_margins = []
|
||||
|
@ -56,6 +56,8 @@ def min_content_width(context, box, outer=True):
|
||||
context, box, outer, is_line_start=True)
|
||||
elif isinstance(box, boxes.ReplacedBox):
|
||||
return replaced_min_content_width(box, outer)
|
||||
elif isinstance(box, boxes.FlexContainerBox):
|
||||
return flex_min_content_width(context, box, outer)
|
||||
else:
|
||||
raise TypeError(
|
||||
'min-content width for %s not handled yet' %
|
||||
@ -81,6 +83,8 @@ def max_content_width(context, box, outer=True):
|
||||
context, box, outer, is_line_start=True)
|
||||
elif isinstance(box, boxes.ReplacedBox):
|
||||
return replaced_max_content_width(box, outer)
|
||||
elif isinstance(box, boxes.FlexContainerBox):
|
||||
return flex_max_content_width(context, box, outer)
|
||||
else:
|
||||
raise TypeError(
|
||||
'max-content width for %s not handled yet' % type(box).__name__)
|
||||
@ -650,6 +654,39 @@ def replaced_max_content_width(box, outer=True):
|
||||
return adjust(box, outer, width)
|
||||
|
||||
|
||||
def flex_min_content_width(context, box, outer=True):
|
||||
"""Return the min-content width for an ``FlexContainerBox``."""
|
||||
# TODO: take care of outer
|
||||
# TODO: use real values, see
|
||||
# https://www.w3.org/TR/css-flexbox-1/#intrinsic-sizes
|
||||
min_contents = [
|
||||
min_content_width(context, child, outer=True)
|
||||
for child in box.children if child.is_flex_item]
|
||||
if not min_contents:
|
||||
return 0
|
||||
if (box.style['flex_direction'].startswith('row') and
|
||||
box.style['flex_wrap'] == 'nowrap'):
|
||||
return sum(min_contents)
|
||||
else:
|
||||
return max(min_contents)
|
||||
|
||||
|
||||
def flex_max_content_width(context, box, outer=True):
|
||||
"""Return the max-content width for an ``FlexContainerBox``."""
|
||||
# TODO: take care of outer
|
||||
# TODO: use real values, see
|
||||
# https://www.w3.org/TR/css-flexbox-1/#intrinsic-sizes
|
||||
max_contents = [
|
||||
max_content_width(context, child, outer=True)
|
||||
for child in box.children if child.is_flex_item]
|
||||
if not max_contents:
|
||||
return 0
|
||||
if box.style['flex_direction'].startswith('row'):
|
||||
return sum(max_contents)
|
||||
else:
|
||||
return max(max_contents)
|
||||
|
||||
|
||||
def trailing_whitespace_size(context, box):
|
||||
"""Return the size of the trailing whitespace of ``box``."""
|
||||
from .inlines import split_text_box, split_first_line
|
||||
|
@ -101,7 +101,8 @@ class StackingContext(object):
|
||||
elif box.is_floated():
|
||||
floats.append(StackingContext.from_box(
|
||||
box, page, child_contexts))
|
||||
elif isinstance(box, boxes.InlineBlockBox):
|
||||
elif isinstance(
|
||||
box, (boxes.InlineBlockBox, boxes.InlineFlexBox)):
|
||||
# Have this fake stacking context be part of the "normal"
|
||||
# box tree, because we need its position in the middle
|
||||
# of a tree of inline boxes.
|
||||
|
Loading…
Reference in New Issue
Block a user