1
1
mirror of https://github.com/Kozea/WeasyPrint.git synced 2024-10-04 07:57:52 +03:00

Avoid floating points errors (almost) everywhere

Related to #1559.
This commit is contained in:
Guillaume Ayoub 2022-02-20 14:41:08 +01:00
parent b33df96de0
commit fe3e3b992f
3 changed files with 22 additions and 22 deletions

View File

@ -241,6 +241,11 @@ class LayoutContext:
self.tables = {}
self.dictionaries = {}
def overflows_page(self, bottom_space, position_y):
# Use a small fudge factor to avoid floating numbers errors.
# The 1e-9 value comes from PEP 485.
return position_y > (self.page_bottom - bottom_space) * (1 + 1e-9)
def create_block_formatting_context(self):
self.excluded_shapes = []
self._excluded_shapes_lists.append(self.excluded_shapes)

View File

@ -234,9 +234,9 @@ def _out_of_flow_layout(context, box, index, child, new_children,
context, child, box, absolute_boxes, fixed_boxes, bottom_space,
skip_stack=None)
# New page if overflow
if (page_is_empty and not new_children) or not (
new_child.position_y + new_child.height >
context.page_bottom - bottom_space):
page_overflow = context.overflows_page(
bottom_space, new_child.position_y + new_child.height)
if (page_is_empty and not new_children) or not page_overflow:
new_child.index = index
new_children.append(new_child)
else:
@ -315,7 +315,7 @@ def _linebox_layout(context, box, index, child, new_children, page_is_empty,
# page and can advance in the context.
overflow = (
(new_children or not page_is_empty) and
(new_position_y + offset_y > context.page_bottom - bottom_space))
context.overflows_page(bottom_space, new_position_y + offset_y))
if overflow:
abort, stop, resume_at = _break_line(
box, new_children, lines_iterator, page_is_empty, index,
@ -327,8 +327,8 @@ def _linebox_layout(context, box, index, child, new_children, page_is_empty,
# "When an unforced page break occurs here, both the adjoining
# margin-top and margin-bottom are set to zero."
# See https://github.com/Kozea/WeasyPrint/issues/115
elif page_is_empty and (
new_position_y > context.page_bottom - bottom_space):
elif page_is_empty and context.overflows_page(
bottom_space, new_position_y):
# Remove the top border when a page is empty and the box is
# too high to be drawn in one page
new_position_y -= box.margin_top
@ -343,9 +343,10 @@ def _linebox_layout(context, box, index, child, new_children, page_is_empty,
for footnote in footnotes:
context.layout_footnote(footnote)
new_footnotes.append(footnote)
overflow = context.reported_footnotes or (
new_position_y + offset_y >
context.page_bottom - bottom_space)
overflow = (
context.reported_footnotes or
context.overflows_page(
bottom_space, new_position_y + offset_y))
if overflow:
context.report_footnote(footnote)
if footnote.style['footnote_policy'] == 'line':
@ -464,22 +465,16 @@ def _in_flow_layout(context, box, index, child, new_children, page_is_empty,
new_position_y = (
new_child.border_box_y() + new_child.border_height())
# Use a small fudge factor on this due to box splitting setting the
# height of some elements to the remaining height of the page:
# https://www.w3.org/TR/css-break-3/#box-splitting
# (Occasionally the order of this calculation would otherwise come
# out with unequal float values, forcing the box to the next page.)
# The 1e-9 value comes from PEP 485.
if (new_content_position_y >
(context.page_bottom - bottom_space) * (1 + 1e-9) and
not page_is_empty_with_no_children):
page_overflow = context.overflows_page(
bottom_space, new_content_position_y)
if page_overflow and not page_is_empty_with_no_children:
# The child content overflows the page area, display it on the
# next page.
remove_placeholders(
context, [new_child], absolute_boxes, fixed_boxes)
new_child = None
elif (new_position_y > context.page_bottom - bottom_space and
not page_is_empty_with_no_children):
elif not page_is_empty_with_no_children and context.overflows_page(
bottom_space, new_position_y):
# The child border/padding overflows the page area, do the
# layout again with a higher bottom_space value.
remove_placeholders(

View File

@ -288,8 +288,8 @@ def table_layout(context, table, bottom_space, skip_stack, containing_block,
# Break if this row overflows the page, unless there is no
# other content on the page.
if not page_is_empty and (
next_position_y > context.page_bottom - bottom_space):
if not page_is_empty and context.overflows_page(
bottom_space, next_position_y):
if new_group_children:
previous_row = new_group_children[-1]
page_break = block_level_page_break(previous_row, row)