diff --git a/weasyprint/pdf/stream.py b/weasyprint/pdf/stream.py index ce309ebf6..0f82ad175 100644 --- a/weasyprint/pdf/stream.py +++ b/weasyprint/pdf/stream.py @@ -11,6 +11,7 @@ from ..logger import LOGGER from ..matrix import Matrix +from ..text.constants import PANGO_STRETCH_PERCENT from ..text.ffi import ffi, harfbuzz, pango, units_to_double @@ -34,8 +35,31 @@ def __init__(self, pango_font): 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) + if variations != ffi.NULL: + self.variations = { + part.split('=')[0]: float(part.split('=')[1]) + for part in ffi.string(variations).decode().split(',')} + if 'wght' in self.variations: + pango.pango_font_description_set_weight( + self.description, int(round(self.variations['wght']))) + if self.variations.get('ital'): + pango.pango_font_description_set_style( + self.description, pango.PANGO_STYLE_ITALIC) + elif self.variations.get('slnt'): + pango.pango_font_description_set_style( + self.description, pango.PANGO_STYLE_OBLIQUE) + if 'wdth' in self.variations: + stretch = min( + PANGO_STRETCH_PERCENT.items(), + key=lambda item: abs(item[0] - self.variations['wdth']))[1] + pango.pango_font_description_set_stretch(self.description, stretch) description_string = ffi.string( pango.pango_font_description_to_string(description)) + # Never use the built-in hash function here: it’s not stable self.hash = ''.join( chr(65 + letter % 26) for letter @@ -122,20 +146,13 @@ def clean(self, cmap, hinting): # Transform variable into static font if 'fvar' in self.ttfont: - variations = pango.pango_font_description_get_variations( - self.description) - if variations == ffi.NULL: - variations = {} - else: - variations = { - part.split('=')[0]: float(part.split('=')[1]) - for part in ffi.string(variations).decode().split(',')} - if 'wght' not in variations: - variations['wght'] = pango.pango_font_description_get_weight( + if 'wght' not in self.variations: + weight = pango.pango_font_description_get_weight( self.description) - if 'opsz' not in variations: - variations['opsz'] = units_to_double(self.font_size) - if 'slnt' not in variations: + self.variations['wght'] = weight + if 'opsz' not in self.variations: + self.variations['opsz'] = units_to_double(self.font_size) + if 'slnt' not in self.variations: slnt = 0 if self.style == 1: for axe in self.ttfont['fvar'].axes: @@ -145,12 +162,12 @@ def clean(self, cmap, hinting): else: slnt = axe.maxValue break - variations['slnt'] = slnt - if 'ital' not in variations: - variations['ital'] = int(self.style == 2) + self.variations['slnt'] = slnt + if 'ital' not in self.variations: + self.variations['ital'] = int(self.style == 2) partial_font = io.BytesIO() try: - ttfont = instantiateVariableFont(self.ttfont, variations) + ttfont = instantiateVariableFont(self.ttfont, self.variations) for key, (advance, bearing) in ttfont['hmtx'].metrics.items(): if advance < 0: ttfont['hmtx'].metrics[key] = (0, bearing) diff --git a/weasyprint/text/constants.py b/weasyprint/text/constants.py index bc88f689e..087e557fc 100644 --- a/weasyprint/text/constants.py +++ b/weasyprint/text/constants.py @@ -19,6 +19,18 @@ 'extra-expanded': pango.PANGO_STRETCH_EXTRA_EXPANDED, 'ultra-expanded': pango.PANGO_STRETCH_ULTRA_EXPANDED, } +# From https://drafts.csswg.org/css-fonts/#font-stretch-prop +PANGO_STRETCH_PERCENT = { + 50: pango.PANGO_STRETCH_ULTRA_CONDENSED, + 62.5: pango.PANGO_STRETCH_EXTRA_CONDENSED, + 75: pango.PANGO_STRETCH_CONDENSED, + 87.5: pango.PANGO_STRETCH_SEMI_CONDENSED, + 100: pango.PANGO_STRETCH_NORMAL, + 112.5: pango.PANGO_STRETCH_SEMI_EXPANDED, + 125: pango.PANGO_STRETCH_EXPANDED, + 150: pango.PANGO_STRETCH_EXTRA_EXPANDED, + 200: pango.PANGO_STRETCH_ULTRA_EXPANDED, +} PANGO_WRAP_MODE = { 'WRAP_WORD': pango.PANGO_WRAP_WORD, 'WRAP_CHAR': pango.PANGO_WRAP_CHAR,