From 902f5e20da9c5bf73dc40dc59bd44719772fb55b Mon Sep 17 00:00:00 2001 From: Guillaume Ayoub Date: Sat, 25 Jun 2016 03:29:15 +0200 Subject: [PATCH] Re-add hack to avoid floating points errors Fix #325 and shouldn't reopen #288. Now that fac5ee9 fixes line-cutting bug when drawing, we can use a much lower relative tolerance inspired from PEP 485 (1e-9 instead of 1e-3). Tests have been added with random values, as results highly depend on the version of Pango used and on hinting properties depending on the system used to launch the tests. They are probably longer than required, but they try hard to prevent #288 and #325 from coming back. --- weasyprint/tests/test_layout.py | 47 +++++++++++++++++++++++++++++++++ weasyprint/text.py | 8 ++++++ 2 files changed, 55 insertions(+) diff --git a/weasyprint/tests/test_layout.py b/weasyprint/tests/test_layout.py index f710468e9..8652f1c2a 100644 --- a/weasyprint/tests/test_layout.py +++ b/weasyprint/tests/test_layout.py @@ -5713,3 +5713,50 @@ def layout(gradient_css, type_='radial', init=(), init=(450, 100, 0, 450 * sqrt2), scale_y=200/450) layout('radial-gradient(farthest-corner at 40px 210px, blue, lime)', init=(40, 210, 0, 360 * sqrt2), scale_y=210/360) + + +@assert_no_logs +def test_shrink_to_fit_floating_point_error(): + """Test that no floating point error occurs during shrink to fit. + + See bugs #325 and #288, see commit fac5ee9. + + """ + for margin_left in range(1, 10): + for font_size in range(1, 10): + page, = parse(''' + +

this parrot is dead

+ ''' % (margin_left, font_size)) + html, = page.children + body, = html.children + p, = body.children + assert len(p.children) == 1 + + letters = 1 + for font_size in (1, 5, 10, 50, 100, 1000, 10000): + while True: + page, = parse(''' + +

mmm %s a

+ ''' % (font_size, font_size, font_size, 'i' * letters)) + html, = page.children + body, = html.children + p, = body.children + assert len(p.children) in (1, 2) + assert len(p.children[0].children) == 2 + text = p.children[0].children[1].children[0].text + print(font_size, text, letters) + assert text + if text.endswith('i'): + letters = 1 + break + else: + letters += 1 diff --git a/weasyprint/text.py b/weasyprint/text.py index 1426c42c2..bbf6f4986 100644 --- a/weasyprint/text.py +++ b/weasyprint/text.py @@ -426,6 +426,14 @@ def split_first_line(text, style, hinting, max_width, line_width): if text_wrap: max_width = None + elif max_width is not None: + # In some cases (shrink-to-fit result being the preferred width) + # this value is coming from Pango itself, + # but floating point errors have accumulated: + # width2 = (width + X) - X # in some cases, width2 < width + # Increase the value a bit to compensate and not introduce + # an unexpected line break. The 1e-9 value comes from PEP 485. + max_width *= 1 + 1e-9 # Step #1: Get a draft layout with the first line layout = None