Skip to content

Commit

Permalink
Sync source with upstream
Browse files Browse the repository at this point in the history
  • Loading branch information
kygoh committed May 31, 2023
2 parents b3bdff8 + ddd739c commit 16f8410
Show file tree
Hide file tree
Showing 3 changed files with 148 additions and 65 deletions.
28 changes: 28 additions & 0 deletions tests/layout/test_inline.py
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,34 @@ def test_breaking_linebox_regression_14():
assert line2.children[1].children[0].text == 'c'


@assert_no_logs
def test_breaking_linebox_regression_15():
# Regression test for https://github.com/ietf-tools/datatracker/issues/5507
page, = render_pages(
'<style>'
' @font-face {src: url(weasyprint.otf); font-family: weasyprint}'
' body {font-family: weasyprint; font-size: 4px}'
' pre {float: left}'
'</style>'
'<pre>ab©\n'
'déf\n'
'ghïj\n'
'klm</pre>')
html, = page.children
body, = html.children
pre, = body.children
line1, line2, line3, line4 = pre.children
assert line1.children[0].text == 'ab©'
assert line2.children[0].text == 'déf'
assert line3.children[0].text == 'ghïj'
assert line4.children[0].text == 'klm'
assert line1.children[0].width == 4 * 3
assert line2.children[0].width == 4 * 3
assert line3.children[0].width == 4 * 4
assert line4.children[0].width == 4 * 3
assert pre.width == 4 * 4


@assert_no_logs
def test_linebox_text():
page, = render_pages('''
Expand Down
175 changes: 115 additions & 60 deletions weasyprint/layout/page.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ def sugar(self):
def outer(self):
return self.sugar + self.inner

@outer.setter
def outer(self, new_outer_width):
self.inner = min(
max(self.min_content_size, new_outer_width - self.sugar),
self.max_content_size)

@property
def outer_min_content_size(self):
return self.sugar + (
Expand All @@ -34,10 +40,6 @@ def outer_max_content_size(self):
return self.sugar + (
self.max_content_size if self.inner == 'auto' else self.inner)

def shrink_to_fit(self, available):
self.inner = min(
max(self.min_content_size, available), self.max_content_size)


class VerticalBox(OrientedBox):
def __init__(self, context, box):
Expand Down Expand Up @@ -173,7 +175,7 @@ def compute_fixed_dimension(context, box, outer, vertical, top_or_left):
box.restore_box_attributes()


def compute_variable_dimension(context, side_boxes, vertical, outer_sum):
def compute_variable_dimension(context, side_boxes, vertical, available_size):
"""Compute and set a margin box fixed dimension on ``box``
Described in: https://drafts.csswg.org/css-page-3/#margin-dimension
Expand All @@ -187,8 +189,8 @@ def compute_variable_dimension(context, side_boxes, vertical, outer_sum):
:param vertical:
``True`` to set height, margin-top and margin-bottom;
``False`` for width, margin-left and margin-right.
:param outer_sum:
The target total outer dimension (max box width or height).
:param available_size:
The distance between the page box’s left right border edges
"""
box_class = VerticalBox if vertical else HorizontalBox
Expand All @@ -201,68 +203,121 @@ def compute_variable_dimension(context, side_boxes, vertical, outer_sum):
if box.margin_b == 'auto':
box.margin_b = 0

if box_b.box.is_generated:
if not box_b.box.is_generated:
# Non-generated boxes get zero for every box-model property
assert box_b.inner == 0
if box_a.inner == box_c.inner == 'auto':
# A and C both have 'width: auto'
if available_size > (
box_a.outer_max_content_size +
box_c.outer_max_content_size):
# sum of the outer max-content widths
# is less than the available width
flex_space = (
available_size -
box_a.outer_max_content_size -
box_c.outer_max_content_size)
flex_factor_a = box_a.outer_max_content_size
flex_factor_c = box_c.outer_max_content_size
flex_factor_sum = flex_factor_a + flex_factor_c
if flex_factor_sum == 0:
flex_factor_sum = 1
box_a.outer = box_a.max_content_size + (
flex_space * flex_factor_a / flex_factor_sum)
box_c.outer = box_c.max_content_size + (
flex_space * flex_factor_c / flex_factor_sum)
elif available_size > (
box_a.outer_min_content_size +
box_c.outer_min_content_size):
# sum of the outer min-content widths
# is less than the available width
flex_space = (
available_size -
box_a.outer_min_content_size -
box_c.outer_min_content_size)
flex_factor_a = (
box_a.max_content_size - box_a.min_content_size)
flex_factor_c = (
box_c.max_content_size - box_c.min_content_size)
flex_factor_sum = flex_factor_a + flex_factor_c
if flex_factor_sum == 0:
flex_factor_sum = 1
box_a.outer = box_a.min_content_size + (
flex_space * flex_factor_a / flex_factor_sum)
box_c.outer = box_c.min_content_size + (
flex_space * flex_factor_c / flex_factor_sum)
else:
# otherwise
flex_space = (
available_size -
box_a.outer_min_content_size -
box_c.outer_min_content_size)
flex_factor_a = box_a.min_content_size
flex_factor_c = box_c.min_content_size
flex_factor_sum = flex_factor_a + flex_factor_c
if flex_factor_sum == 0:
flex_factor_sum = 1
box_a.outer = box_a.min_content_size + (
flex_space * flex_factor_a / flex_factor_sum)
box_c.outer = box_c.min_content_size + (
flex_space * flex_factor_c / flex_factor_sum)
else:
# only one box has 'width: auto'
if box_a.inner == 'auto':
box_a.outer = available_size - box_c.outer
elif box_c.inner == 'auto':
box_c.outer = available_size - box_a.outer
else:
if box_b.inner == 'auto':
# resolve any auto width of the middle box (B)
ac_max_content_size = 2 * max(
box_a.outer_max_content_size, box_c.outer_max_content_size)
if outer_sum >= (
if available_size > (
box_b.outer_max_content_size + ac_max_content_size):
box_b.inner = box_b.max_content_size
flex_space = (
available_size -
box_b.outer_max_content_size -
ac_max_content_size)
flex_factor_b = box_b.outer_max_content_size
flex_factor_ac = ac_max_content_size
flex_factor_sum = flex_factor_b + flex_factor_ac
if flex_factor_sum == 0:
flex_factor_sum = 1
box_b.outer = box_b.max_content_size + (
flex_space * flex_factor_b / flex_factor_sum)
else:
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_max_content_size - ac_min_content_size
weight_b = (
box_a.outer_min_content_size, box_c.outer_min_content_size)
if available_size > (
box_b.outer_min_content_size + ac_min_content_size):
flex_space = (
available_size -
box_b.outer_min_content_size -
ac_min_content_size)
flex_factor_b = (
box_b.max_content_size - box_b.min_content_size)
weight_sum = weight_ac + weight_b
# 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
flex_factor_ac = ac_max_content_size - ac_min_content_size
flex_factor_sum = flex_factor_b + flex_factor_ac
if flex_factor_sum == 0:
flex_factor_sum = 1
box_b.outer = box_b.min_content_size + (
flex_space * flex_factor_b / flex_factor_sum)
else:
flex_space = (
available_size -
box_b.outer_min_content_size -
ac_min_content_size)
flex_factor_b = box_b.min_content_size
flex_factor_ac = ac_min_content_size
flex_factor_sum = flex_factor_b + flex_factor_ac
if flex_factor_sum == 0:
flex_factor_sum = 1
box_b.outer = box_b.min_content_size + (
flex_space * flex_factor_b / flex_factor_sum)
if box_a.inner == 'auto':
box_a.shrink_to_fit((outer_sum - box_b.outer) / 2 - box_a.sugar)
box_a.outer = (available_size - box_b.outer) / 2
if box_c.inner == 'auto':
box_c.shrink_to_fit((outer_sum - box_b.outer) / 2 - box_c.sugar)
else:
# Non-generated boxes get zero for every box-model property
assert box_b.inner == 0
if box_a.inner == box_c.inner == 'auto':
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.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.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 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
elif box_a.inner == 'auto':
box_a.shrink_to_fit(outer_sum - box_c.outer - box_a.sugar)
elif box_c.inner == 'auto':
box_c.shrink_to_fit(outer_sum - box_a.outer - box_c.sugar)
box_c.outer = (available_size - box_b.outer) / 2

# And, we’re done!
assert 'auto' not in [box.inner for box in side_boxes]
Expand Down
10 changes: 5 additions & 5 deletions weasyprint/layout/preferred.py
Original file line number Diff line number Diff line change
Expand Up @@ -296,10 +296,10 @@ def inline_line_widths(context, box, outer, is_line_start, minimum,
else:
(skip, skip_stack), = skip_stack.items()
assert skip_stack is None
child_text = child.text[(skip or 0):]
child_text = child.text.encode()[(skip or 0):]
if is_line_start and space_collapse:
child_text = child_text.lstrip(' ')
if minimum and child_text == ' ':
child_text = child_text.lstrip(b' ')
if minimum and child_text == b' ':
lines = [0, 0]
else:
max_width = 0 if minimum else None
Expand All @@ -309,8 +309,8 @@ def inline_line_widths(context, box, outer, is_line_start, minimum,
resume_index += new_resume_index
_, _, new_resume_index, width, _, _ = (
split_first_line(
child_text[resume_index:], child.style, context,
max_width, child.justification_spacing,
child_text[resume_index:].decode(), child.style,
context, max_width, child.justification_spacing,
is_line_start=is_line_start, minimum=True))
lines.append(width)
if first_line:
Expand Down

0 comments on commit 16f8410

Please sign in to comment.