Skip to content

Commit

Permalink
Avoid getting font descriptions multiple times
Browse files Browse the repository at this point in the history
  • Loading branch information
liZe committed Jan 24, 2025
1 parent 37ad234 commit 6f21a24
Show file tree
Hide file tree
Showing 5 changed files with 29 additions and 31 deletions.
18 changes: 8 additions & 10 deletions weasyprint/draw/text.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ def draw_first_line(stream, textbox, text_overflow, block_ellipsis, matrix):
utf8_text = textbox.pango_layout.text.encode()
previous_utf8_position = 0
stream.set_text_matrix(*matrix.values)
last_font = last_font_size = None
previous_pango_font = None
string = ''
x_advance = 0
emojis = []
Expand All @@ -140,23 +140,21 @@ def draw_first_line(stream, textbox, text_overflow, block_ellipsis, matrix):
offset = glyph_item.item.offset
clusters = glyph_string.log_clusters

# Add font file content and get font size.
pango_font = glyph_item.item.analysis.font
description = pango.pango_font_describe(pango_font)
font_size = pango.pango_font_description_get_size(description) * FROM_UNITS
font = stream.add_font(pango_font)

# Get positions of the glyphs in the UTF-8 string.
utf8_positions = [offset + clusters[i] for i in range(1, num_glyphs)]
utf8_positions.append(offset + glyph_item.item.length)

# Go through the run glyphs.
if (font, font_size) != (last_font, last_font_size):
pango_font = glyph_item.item.analysis.font
if pango_font != previous_pango_font:
# Add font file content and get font size.
previous_pango_font = pango_font
font, font_size = stream.add_font(pango_font)

# Go through the run glyphs.
if string:
stream.show_text(string)
string = ''
stream.set_font_size(font.hash, 1 if font.bitmap else font_size)
last_font, last_font_size = font, font_size
string += '<'
for i in range(num_glyphs):
glyph_info = glyphs[i]
Expand Down
4 changes: 2 additions & 2 deletions weasyprint/pdf/anchors.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ def add_forms(forms, matrix, pdf, page, resources, stream, font_map):
font_description = get_font_description(style)
font = pango.pango_font_map_load_font(
font_map, context, font_description)
font = stream.add_font(font)
font, _ = stream.add_font(font)
font.used_in_forms = True

field_stream.set_font_size(font.hash, font_size)
Expand Down Expand Up @@ -252,7 +252,7 @@ def add_forms(forms, matrix, pdf, page, resources, stream, font_map):
font_description = get_font_description(style)
font = pango.pango_font_map_load_font(
font_map, context, font_description)
font = stream.add_font(font)
font, _ = stream.add_font(font)
font.used_in_forms = True

field_stream.set_font_size(font.hash, font_size)
Expand Down
26 changes: 12 additions & 14 deletions weasyprint/pdf/fonts.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,39 +17,38 @@


class Font:
def __init__(self, pango_font):
def __init__(self, pango_font, description, font_size):
self.hb_font = pango.pango_font_get_hb_font(pango_font)
self.hb_face = get_pango_font_hb_face(pango_font)
self.file_content = get_hb_object_data(self.hb_face)
self.index = harfbuzz.hb_face_get_index(self.hb_face)

pango_metrics = pango.pango_font_get_metrics(pango_font, ffi.NULL)
self.description = description = ffi.gc(
pango.pango_font_describe(pango_font), pango.pango_font_description_free)
self.font_size = pango.pango_font_description_get_size(description)
self.font_size = font_size
self.style = pango.pango_font_description_get_style(description)
self.family = ffi.string(pango.pango_font_description_get_family(description))

self.variations = {}
variations = pango.pango_font_description_get_variations(self.description)
variations = pango.pango_font_description_get_variations(description)
if variations != ffi.NULL:
self.variations = {
part.split('=')[0]: float(part.split('=')[1])
for part in ffi.string(variations).decode().split(',')}
if weight := self.variations.get('weight'):
pango.pango_font_description_set_weight(
self.description, int(round(weight)))
self.weight = int(round(weight))
pango.pango_font_description_set_weight(description, weight)
else:
self.weight = pango.pango_font_description_get_weight(description)
if self.variations.get('ital'):
pango.pango_font_description_set_style(
self.description, pango.PANGO_STYLE_ITALIC)
description, pango.PANGO_STYLE_ITALIC)
elif self.variations.get('slnt'):
pango.pango_font_description_set_style(
self.description, pango.PANGO_STYLE_OBLIQUE)
description, pango.PANGO_STYLE_OBLIQUE)
if (width := self.variations.get('wdth')) is not None:
stretch = min(
PANGO_STRETCH_PERCENT.items(),
key=lambda item: abs(item[0] - width))[1]
pango.pango_font_description_set_stretch(self.description, stretch)
pango.pango_font_description_set_stretch(description, stretch)
description_string = ffi.string(
pango.pango_font_description_to_string(description))

Expand All @@ -70,6 +69,7 @@ def __init__(self, pango_font):

# Set ascent and descent.
if self.font_size:
pango_metrics = pango.pango_font_get_metrics(pango_font, ffi.NULL)
self.ascent = int(
pango.pango_font_metrics_get_ascent(pango_metrics) /
self.font_size * 1000)
Expand Down Expand Up @@ -126,9 +126,7 @@ def clean(self, cmap, hinting):
full_font = io.BytesIO(self.file_content)
ttfont = TTFont(full_font, fontNumber=self.index)
if 'wght' not in self.variations:
weight = pango.pango_font_description_get_weight(
self.description)
self.variations['wght'] = weight
self.variations['wght'] = self.weight
if 'opsz' not in self.variations:
self.variations['opsz'] = self.font_size * FROM_UNITS
if 'slnt' not in self.variations:
Expand Down
6 changes: 3 additions & 3 deletions weasyprint/pdf/stream.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,10 +161,10 @@ def set_blend_mode(self, mode):
}))

def add_font(self, pango_font):
key = get_pango_font_key(pango_font)
key, description, font_size = get_pango_font_key(pango_font)
if key not in self._fonts:
self._fonts[key] = Font(pango_font)
return self._fonts[key]
self._fonts[key] = Font(pango_font, description, font_size)
return self._fonts[key], font_size

def add_group(self, x, y, width, height):
resources = pydyf.Dictionary({
Expand Down
6 changes: 4 additions & 2 deletions weasyprint/text/fonts.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
CAPS_KEYS, EAST_ASIAN_KEYS, FONTCONFIG_STRETCH, FONTCONFIG_STYLE, FONTCONFIG_WEIGHT,
LIGATURE_KEYS, NUMERIC_KEYS, PANGO_STRETCH, PANGO_STYLE, PANGO_VARIANT)
from .ffi import ( # isort:skip
TO_UNITS, ffi, fontconfig, gobject, harfbuzz, pango, pangoft2, unicode_to_char_p)
FROM_UNITS, TO_UNITS, ffi, fontconfig, gobject, harfbuzz, pango, pangoft2,
unicode_to_char_p)


def _check_font_configuration(font_config): # pragma: no cover
Expand Down Expand Up @@ -364,6 +365,7 @@ def get_pango_font_key(pango_font):
# FontConfiguration object. See https://github.com/Kozea/WeasyPrint/issues/2144
description = ffi.gc(
pango.pango_font_describe(pango_font), pango.pango_font_description_free)
font_size = pango.pango_font_description_get_size(description) * FROM_UNITS
mask = pango.PANGO_FONT_MASK_SIZE + pango.PANGO_FONT_MASK_GRAVITY
pango.pango_font_description_unset_fields(description, mask)
return pango.pango_font_description_hash(description)
return pango.pango_font_description_hash(description), description, font_size

0 comments on commit 6f21a24

Please sign in to comment.