Fix another crash due to the new line breaking algorithm

Related to #560.
This commit is contained in:
Guillaume Ayoub 2018-02-04 15:40:32 +01:00
parent 9034aa5d58
commit 2e5408c844
2 changed files with 49 additions and 13 deletions

View File

@ -762,7 +762,7 @@ def split_inline_box(context, box, position_x, max_x, skip_stack,
last_letter = last
if new_child is None:
# may be None where we have an empty TextBox
# May be None where we have an empty TextBox.
assert isinstance(child, boxes.TextBox)
else:
if isinstance(box, boxes.LineBox):
@ -785,21 +785,37 @@ def split_inline_box(context, box, position_x, max_x, skip_stack,
break_found = False
while waiting_children_copy:
child_index, child = waiting_children_copy.pop()
# TODO: what about relative children?
# TODO: should we also accept relative children?
if (child.is_in_normal_flow() and
can_break_inside(child)):
broken_child = (
not waiting_children_copy and
initial_skip_stack and initial_skip_stack[1])
# This waiting child is in flow and can be broken,
# let's break it!
break_found = True
max_x = child.position_x + child.margin_width()
# TODO: replace -1, we use it to cut the last word
# of the line.
max_x -= 1
child_skip = None
# We have to check whether the child we're breaking
# is the one broken by the initial skip stack.
broken_child = bool(
initial_skip_stack and
initial_skip_stack[0] == child_index and
initial_skip_stack[1])
if broken_child:
# This child is already broken by the original
# skip stack, let's skip the already rendered
# part before rendering the waiting child
# again.
current_skip, child_skip = (
initial_skip_stack[1])
else:
# This child has to be rendered from its start.
child_skip = None
# We break the waiting child at its last possible
# breaking point.
# TODO: The dirty solution chosen here is to
# decrease the actual size by 1 and render the
# waiting child again with this constraint. We may
# find a better way.
max_x = child.position_x + child.margin_width() - 1
child_new_child, child_resume_at, _, _, _ = (
split_inline_level(
context, child, child.position_x, max_x,
@ -809,20 +825,26 @@ def split_inline_box(context, box, position_x, max_x, skip_stack,
line_children))
children = children + waiting_children_copy
if child_new_child is None:
# may be None where we have an empty TextBox
# May be None where we have an empty TextBox.
assert isinstance(child, boxes.TextBox)
else:
children += [(child_index, child_new_child)]
if broken_child:
# As this child has already been broken
# following the original skip stack, we have to
# add the original skip stack to the partial
# skip stack we get after the new rendering.
child_resume_at = (
child_resume_at[0] + current_skip,
child_resume_at[1])
resume_at = (child_index, child_resume_at)
break
if break_found:
break
if children:
# too wide, can't break waiting children and the inline is
# Too wide, can't break waiting children and the inline is
# non-empty: put child entirely on the next line.
resume_at = (children[-1][0] + 1, None)
break

View File

@ -709,7 +709,7 @@ def test_breaking_linebox():
assert textbox_2.text == 'c def'
assert textbox_3.text == 'g hi'
# Regression test for https://github.com/Kozea/WeasyPrint/issues/560
# Regression test #1 for https://github.com/Kozea/WeasyPrint/issues/560
page, = parse(
'<div style="width: 5.5em; font-family: ahem">'
'aaaa aaaa a [<span>aaa</span>]')
@ -724,6 +724,20 @@ def test_breaking_linebox():
assert text2.text == ']'
assert span.children[0].text == 'aaa'
# Regression test #2 for https://github.com/Kozea/WeasyPrint/issues/560
page, = parse(
'<div style="width: 5.5em; font-family: ahem">'
'aaaa a <span>b c</span>d')
html, = page.children
body, = html.children
pre, = body.children
line1, line2, line3 = pre.children
assert line1.children[0].text == 'aaaa'
assert line2.children[0].text == 'a '
assert line2.children[1].children[0].text == 'b'
assert line3.children[0].children[0].text == 'c'
assert line3.children[1].text == 'd'
@assert_no_logs
def test_linebox_text():