Example #1
0
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)
Example #2
0
    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),
                    )
                )