From 344cb08f60f82f52e4d8cfcc36c019b2ae5f1947 Mon Sep 17 00:00:00 2001 From: Guillaume Ayoub Date: Sat, 22 Jul 2017 13:51:03 +0200 Subject: [PATCH] Don't copy styles when copying boxes, improve memory management Style is not copied anymore when boxes are duplicated. Style dicts are not modified anymore during the layout, as it was before for some properties: - margins, borders and paddings when the box was split between two pages (useless as these computed values are stored directly in the box), - top borders were changed in tables (useless for the same reason), - bookmark labels and string sets are now stored in the box. This commit can introduce very subtle bugs that are hard to debug. In the future, we should try to freeze the style dicts before the layout. Related to #70. --- weasyprint/document.py | 6 +++--- weasyprint/formatting_structure/boxes.py | 16 +++++----------- weasyprint/formatting_structure/build.py | 20 ++++++++++---------- weasyprint/layout/pages.py | 2 +- weasyprint/layout/tables.py | 4 +--- 5 files changed, 20 insertions(+), 28 deletions(-) diff --git a/weasyprint/document.py b/weasyprint/document.py index ca4d37820..3bda2ff52 100644 --- a/weasyprint/document.py +++ b/weasyprint/document.py @@ -95,11 +95,11 @@ def _gather_links_and_bookmarks(box, bookmarks, links, anchors, matrix): if transform: matrix = transform * matrix if matrix else transform - bookmark_label = box.style.bookmark_label - if box.style.bookmark_level == 'none': + bookmark_label = box.bookmark_label + if box.style['bookmark_level'] == 'none': bookmark_level = None else: - bookmark_level = box.style.bookmark_level + bookmark_level = box.style['bookmark_level'] link = box.style.link anchor_name = box.style.anchor has_bookmark = bookmark_label and bookmark_level diff --git a/weasyprint/formatting_structure/boxes.py b/weasyprint/formatting_structure/boxes.py index ae18fa19b..466d73a9b 100644 --- a/weasyprint/formatting_structure/boxes.py +++ b/weasyprint/formatting_structure/boxes.py @@ -62,7 +62,6 @@ import itertools from ..compat import unichr, xrange -from ..css.computed_values import ZERO_PIXELS # The *Box classes have many attributes and methods, but that's the way it is # pylint: disable=R0904,R0902 @@ -80,6 +79,8 @@ class Box(object): is_table_wrapper = False is_for_root_element = False transformation_matrix = None + bookmark_label = None + string_set = None # Default, overriden on some subclasses def all_children(self): @@ -98,7 +99,7 @@ def anonymous_from(cls, parent, *args, **kwargs): return cls( parent.element_tag, parent.style.inherit_from(), *args, **kwargs) - def copy(self, copy_style=True): + def copy(self): """Return shallow copy of the box.""" cls = type(self) # Create a new instance without calling __init__: initializing @@ -106,10 +107,7 @@ def copy(self, copy_style=True): new_box = cls.__new__(cls) # Copy attributes new_box.__dict__.update(self.__dict__) - if copy_style: - new_box.style = self.style.copy() - else: - new_box.style = self.style + new_box.style = self.style return new_box def translate(self, dx=0, dy=0): @@ -299,10 +297,6 @@ def _reset_spacing(self, side): setattr(self, 'padding_%s' % side, 0) setattr(self, 'border_%s_width' % side, 0) - self.style['margin_%s' % side] = ZERO_PIXELS - self.style['padding_%s' % side] = ZERO_PIXELS - self.style['border_%s_width' % side] = 0 - def _remove_decoration(self, start, end): if start: self._reset_spacing('top') @@ -456,7 +450,7 @@ def __init__(self, element_tag, style, text): def copy_with_text(self, text): """Return a new TextBox identical to this one except for the text.""" assert text - new_box = self.copy(copy_style=False) + new_box = self.copy() new_box.text = text return new_box diff --git a/weasyprint/formatting_structure/build.py b/weasyprint/formatting_structure/build.py index 17b0f9daa..5e2ba1b80 100644 --- a/weasyprint/formatting_structure/build.py +++ b/weasyprint/formatting_structure/build.py @@ -180,7 +180,7 @@ def element_to_box(element, style_for, get_image_from_uri, base_url, box.children = children box.first_letter_style = style_for(element, 'first-letter') - replace_content_lists(element, box, style, counter_values) + set_content_lists(element, box, style, counter_values) # Specific handling for the element. (eg. replaced element) return html.handle_element(element, box, get_image_from_uri, base_url) @@ -289,25 +289,25 @@ def compute_content_list_string(element, box, counter_values, content_list): return string -def replace_content_lists(element, box, style, counter_values): - """Replace the content-lists by strings. +def set_content_lists(element, box, style, counter_values): + """Set the content-lists by strings. These content-lists are used in GCPM properties like ``string-set`` and ``bookmark-label``. """ string_set = [] - if style.string_set != 'none': - for i, (string_name, string_values) in enumerate(style.string_set): + if style['string_set'] != 'none': + for i, (string_name, string_values) in enumerate(style['string_set']): string_set.append((string_name, compute_content_list_string( element, box, counter_values, string_values))) - box.style['string_set'] = string_set + box.string_set = string_set - if style.bookmark_label == 'none': - box.style['bookmark_label'] = '' + if style['bookmark_label'] == 'none': + box.bookmark_label = '' else: - box.style['bookmark_label'] = compute_content_list_string( - element, box, counter_values, style.bookmark_label) + box.bookmark_label = compute_content_list_string( + element, box, counter_values, style['bookmark_label']) def update_counters(state, style): diff --git a/weasyprint/layout/pages.py b/weasyprint/layout/pages.py index 22d99168e..ea6e638e7 100644 --- a/weasyprint/layout/pages.py +++ b/weasyprint/layout/pages.py @@ -526,7 +526,7 @@ def make_page(context, root_box, page_type, resume_at, content_empty, page.children = [root_box] descendants = page.descendants() for child in descendants: - string_sets = child.style.string_set + string_sets = child.string_set if string_sets and string_sets != 'none': for string_set in string_sets: string_name, text = string_set diff --git a/weasyprint/layout/tables.py b/weasyprint/layout/tables.py index 953d439ff..043d6510d 100644 --- a/weasyprint/layout/tables.py +++ b/weasyprint/layout/tables.py @@ -13,7 +13,6 @@ from __future__ import division, unicode_literals from ..compat import xrange -from ..css.properties import Dimension from ..formatting_structure import boxes from ..logger import LOGGER from .percentages import resolve_one_percentage, resolve_percentages @@ -58,7 +57,7 @@ def table_layout(context, table, max_position_y, skip_stack, skipped_rows = 0 _, horizontal_borders = table.collapsed_border_grid if horizontal_borders: - table.style['border_top_width'] = table.border_top_width = max( + table.border_top_width = max( width for _, (_, width, _) in horizontal_borders[skipped_rows]) / 2 @@ -740,7 +739,6 @@ def table_wrapper_width(context, wrapper, containing_block): auto_table_layout(context, wrapper, containing_block) wrapper.width = table.border_width() - wrapper.style['width'] = Dimension(wrapper.width, 'px') def cell_baseline(cell):