def visual_inherit_vertical_metrics(font, ttfs_gf): """Inherit vertical metrics from family hosted on GF. Approach will ensure metrics look the same as the previous release and across all platforms, whilst avoiding clipping in MS applications.""" masters = font.masters # ExtraBold Italic - ExtraBoldItalic masters_h = {str(m.name.replace(' ', '')): m for m in masters} ttfs_gf_h = {style_from_ttf(f): f for f in ttfs_gf} # Masters which match downloaded ttf mm_styles = set(masters_h.keys()) & set(ttfs_gf_h.keys()) for style in mm_styles: master = masters_h[style] ttf_gf = ttfs_gf_h[style] # Is Use Typo Metrics enabled? master_use_typo_metrics = master.customParameters['Use Typo Metrics'] \ if master.customParameters['Use Typo Metrics'] \ else font.customParameters['Use Typo Metrics'] ttf_gf_use_typo_metrics = ttf_gf['OS/2'].fsSelection & 0b10000000 # Get upms master_upm = master.customParameters['Scale to UPM'] \ if master.customParameters['Scale to UPM']\ else font.upm ttf_gf_upm = ttf_gf['head'].unitsPerEm if master_use_typo_metrics and ttf_gf_use_typo_metrics: master.customParameters['typoAscender'] = norm_m( ttf_gf['OS/2'].sTypoAscender, ttf_gf_upm, master_upm) master.customParameters['typoDescender'] = norm_m( ttf_gf['OS/2'].sTypoDescender, ttf_gf_upm, master_upm) master.customParameters['typoLineGap'] = norm_m( ttf_gf['OS/2'].sTypoLineGap, ttf_gf_upm, master_upm) elif master_use_typo_metrics and not ttf_gf_use_typo_metrics: master.customParameters['typoAscender'] = norm_m( ttf_gf['OS/2'].usWinAscent, ttf_gf_upm, master_upm) master.customParameters['typoDescender'] = norm_m( ttf_gf['OS/2'].usWinDescent, ttf_gf_upm, master_upm) master.customParameters['typoLineGap'] = 0 master.customParameters['hheaAscender'] = norm_m( ttf_gf['hhea'].ascent, ttf_gf_upm, master_upm) master.customParameters['hheaDescender'] = norm_m( ttf_gf['hhea'].descent, ttf_gf_upm, master_upm) master.customParameters['hheaLineGap'] = norm_m( ttf_gf['hhea'].lineGap, ttf_gf_upm, master_upm)
def test_vert_metrics_visually_match(self): """Test vertical metrics visually match GF version Vertical metrics must visually match the version hosted on fonts.google.com. If the hosted family doesn't have the fsSelection bit 7 enabled, we can use this to our advantage. By setting this bit, the typo metrics are used instead of the win metrics. This allows us to add taller scripts, without affecting the line leading. The win metrics can then be set freely. This scenario is common when upgrading legacy families. If both the hosted family and the local family have fsSelection bit 7 enabled, the typo and hhea values must be the same. The win values can be changed freely to accomodate the families bbox ymin and ymax values to avoid clipping.""" if self.remote_font: local_fonts = self._hash_fonts(self.ttfs) remote_fonts = self._hash_fonts(self.remote_font) shared_styles = set(local_fonts.keys()) & set(remote_fonts.keys()) for style in shared_styles: l_font = local_fonts[style] r_font = remote_fonts[style] # Check if Use Typo metrics bit 7 is enabled # https://www.microsoft.com/typography/OTSpec/os2.htm#fss l_use_typo_metrics = l_font['OS/2'].fsSelection & 0b10000000 r_use_typo_metrics = r_font['OS/2'].fsSelection & 0b10000000 l_upm = l_font['head'].unitsPerEm r_upm = r_font['head'].unitsPerEm if r_use_typo_metrics and l_use_typo_metrics: self.assertEqual( l_font['OS/2'].sTypoAscender, norm_m(r_font['OS/2'].sTypoAscender, r_upm, l_upm), "Local %s typoAscender %s is not equal to remote %s typoAscender %s" % ( style, l_font['OS/2'].sTypoAscender, norm_m(r_font['OS/2'].sTypoAscender, r_upm, l_upm), ) ) self.assertEqual( l_font['OS/2'].sTypoDescender, norm_m(r_font['OS/2'].sTypoDescender, r_upm, l_upm), "Local %s typoDescender %s is not equal to remote %s typoDescender %s" % ( style, l_font['OS/2'].sTypoDescender, norm_m(r_font['OS/2'].sTypoDescender, r_upm, l_upm), ) ) self.assertEqual( l_font['OS/2'].sTypoLineGap, norm_m(r_font['OS/2'].sTypoLineGap, r_upm, l_upm), "Local %s typoLineGap %s is not equal to remote %s typoLineGap %s" % ( style, l_font['OS/2'].sTypoLineGap, style, norm_m(r_font['OS/2'].sTypoLineGap, r_upm, l_upm), ) ) elif l_use_typo_metrics and not r_use_typo_metrics: self.assertEqual( l_font['OS/2'].sTypoAscender, norm_m(r_font['OS/2'].usWinAscent, r_upm, l_upm), "Local %s typoAscender %s is not equal to remote %s winAscent %s" % ( style, l_font['OS/2'].sTypoAscender, style, norm_m(r_font['OS/2'].usWinAscent, r_upm, l_upm), ) ) self.assertEqual( l_font['OS/2'].sTypoDescender, - norm_m(r_font['OS/2'].usWinDescent, r_upm, l_upm), "Local %s typoDescender %s is not equal to remote %s winDescent -%s" % ( style, l_font['OS/2'].sTypoDescender, style, norm_m(r_font['OS/2'].usWinDescent, r_upm, l_upm), ) ) self.assertEqual( l_font['OS/2'].sTypoLineGap, 0, "Local %s typoLineGap %s is not equal to 0" % ( style, l_font['OS/2'].sTypoLineGap ) ) self.assertEqual( l_font['hhea'].ascent, norm_m(r_font['hhea'].ascent, r_upm, l_upm), "Local %s hheaAscender %s is not equal to remote %s hheaAscender %s" % ( style, l_font['hhea'].ascent, style, norm_m(r_font['hhea'].ascent, r_upm, l_upm), ) ) self.assertEqual( l_font['hhea'].descent, norm_m(r_font['hhea'].descent, r_upm, l_upm), "Local %s hheaDescender %s is not equal to remote %s hheaDescender %s" % ( style, l_font['hhea'].descent, style, norm_m(r_font['hhea'].descent, r_upm, l_upm), ) ) self.assertEqual( l_font['hhea'].lineGap, norm_m(r_font['hhea'].lineGap, r_upm, l_upm), "Local %s hheaLineGap %s is not equal to remote %s hheaLineGap %s" % ( style, l_font['hhea'].lineGap, style, norm_m(r_font['hhea'].lineGap, r_upm, l_upm), ) )