1
1
mirror of https://github.com/Kozea/WeasyPrint.git synced 2024-10-05 08:27:22 +03:00

Don't store Pango layout between page layout and drawing steps

Creating Pango layouts during page layout and recreating them when drawing
pages is a little bit slower but frees A LOT of memory.
This commit is contained in:
Guillaume Ayoub 2018-11-21 22:16:52 +01:00
parent 3cbb2e6143
commit 4e6d449c5c
3 changed files with 27 additions and 14 deletions

View File

@ -1015,7 +1015,7 @@ def draw_text(context, textbox, enable_hinting):
context.move_to(textbox.position_x, textbox.position_y + textbox.baseline)
context.set_source_rgba(*textbox.style['color'])
show_first_line(context, textbox.pango_layout)
show_first_line(context, textbox)
values = textbox.style['text_decoration']
thickness = textbox.style['font_size'] / 18 # Like other browsers do

View File

@ -970,7 +970,7 @@ def split_text_box(context, box, available_width, skip):
# No need to encode whats after resume_at (if set) or length (if
# resume_at is not set). One code point is one or more byte, so
# UTF-8 indexes are always bigger or equal to Unicode indexes.
new_text = layout.text_bytes.decode('utf8')
new_text = layout.text
encoded = text.encode('utf8')
if resume_at is not None:
between = encoded[length:resume_at].decode('utf8')

View File

@ -139,6 +139,8 @@ ffi.cdef('''
PangoLayout *layout, const PangoFontDescription *desc);
void pango_layout_set_wrap (
PangoLayout *layout, PangoWrapMode wrap);
void pango_layout_set_single_paragraph_mode (
PangoLayout *layout, gboolean setting);
int pango_layout_get_baseline (PangoLayout *layout);
PangoLayoutIter * pango_layout_get_iter (PangoLayout *layout);
@ -600,7 +602,7 @@ def first_line_metrics(first_line, text, layout, resume_at, space_collapse,
if u'\u00ad' in first_line_text:
if first_line_text[0] == u'\u00ad':
length += 2 # len(u'\u00ad'.encode('utf8'))
for i in range(len(layout.text_bytes.decode('utf8'))):
for i in range(len(layout.text)):
while i + soft_hyphens + 1 < len(first_line_text):
if first_line_text[i + soft_hyphens + 1] == u'\u00ad':
soft_hyphens += 1
@ -609,12 +611,16 @@ def first_line_metrics(first_line, text, layout, resume_at, space_collapse,
length += soft_hyphens * 2 # len(u'\u00ad'.encode('utf8'))
width, height = get_size(first_line, style)
baseline = units_to_double(pango.pango_layout_get_baseline(layout.layout))
layout.deactivate()
return layout, length, resume_at, width, height, baseline
class Layout(object):
"""Object holding PangoLayout-related cdata pointers."""
def __init__(self, context, font_size, style):
self.setup(context, font_size, style)
def setup(self, context, font_size, style):
from .fonts import ZERO_FONTSIZE_CRASHES_CAIRO
# Cairo crashes with font-size: 0 when using Win32 API
@ -676,8 +682,7 @@ class Layout(object):
# Keep only the first two lines, we don't need the other ones
text, bytestring = unicode_to_char_p(
'\n'.join(text.split('\n', 3)[:2]))
self.text = text
self.text_bytes = bytestring
self.text = bytestring.decode('utf-8')
pango.pango_layout_set_text(self.layout, text, -1)
def get_font_metrics(self):
@ -705,6 +710,15 @@ class Layout(object):
pango.pango_tab_array_free)
pango.pango_layout_set_tabs(self.layout, array)
def deactivate(self):
del self.layout
del self.font
del self.language
def reactivate(self, style):
self.setup(self.context, style['font_size'], style)
self.set_text(self.text)
class FontMetrics(object):
def __init__(self, context, font, language):
@ -850,7 +864,7 @@ def create_layout(text, style, context, max_width, justification_spacing):
pango.pango_layout_set_width(
layout.layout, units_from_double(max_width))
text_bytes = layout.text_bytes
text_bytes = layout.text.encode('utf-8')
# Word and letter spacings
word_spacing = style['word_spacing'] + justification_spacing
@ -1149,15 +1163,14 @@ def split_first_line(text, style, context, max_width, justification_spacing,
style['hyphenate_character'])
def show_first_line(context, pango_layout):
"""Draw the given ``line`` to the Cairo ``context``."""
def show_first_line(context, textbox):
"""Draw the given ``textbox`` line to the Cairo ``context``."""
textbox.pango_layout.reactivate(textbox.style)
pango.pango_layout_set_single_paragraph_mode(
textbox.pango_layout.layout, True)
first_line, _ = textbox.pango_layout.get_first_line()
context = ffi.cast('cairo_t *', context._pointer)
# Set an infinite width as we don't want to break lines when drawing, the
# lines have already been split and the size may differ for example because
# of hinting.
pango.pango_layout_set_width(pango_layout.layout, -1)
pangocairo.pango_cairo_show_layout_line(
context, pango_layout.get_first_line()[0])
pangocairo.pango_cairo_show_layout_line(context, first_line)
def can_break_text(text, lang):