Skip to content

Commit

Permalink
Don't copy styles when copying boxes, improve memory management
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
liZe committed Jul 22, 2017
1 parent a9a99f6 commit 344cb08
Show file tree
Hide file tree
Showing 5 changed files with 20 additions and 28 deletions.
6 changes: 3 additions & 3 deletions weasyprint/document.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
16 changes: 5 additions & 11 deletions weasyprint/formatting_structure/boxes.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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):
Expand All @@ -98,18 +99,15 @@ 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
# styles may be kinda expensive, no need to do it again.
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):
Expand Down Expand Up @@ -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')
Expand Down Expand Up @@ -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

Expand Down
20 changes: 10 additions & 10 deletions weasyprint/formatting_structure/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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):
Expand Down
2 changes: 1 addition & 1 deletion weasyprint/layout/pages.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 1 addition & 3 deletions weasyprint/layout/tables.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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):
Expand Down

0 comments on commit 344cb08

Please sign in to comment.