Skip to content

Instantly share code, notes, and snippets.

@m4rc1e
Last active August 6, 2021 12:45
Show Gist options
  • Save m4rc1e/131670c91aee6b216150c88be65b4ed2 to your computer and use it in GitHub Desktop.
Save m4rc1e/131670c91aee6b216150c88be65b4ed2 to your computer and use it in GitHub Desktop.
gf draft rearchitecture
@condition
...
def gf_family(ttFont):
from gfcore.font import family_name
from gfcore.site import download_family, family_exists
name = family_name(ttFont)
if family_exists(name):
return download_family(name)
return None
@condition
...
def expected_name_table(ttFont):
from gfcore.font import build_name_table
return build_name_table(ttFont)
@condition
...
def expected_metadata(family_dir):
return gfcore.addfont.MakeMetadata(family_dir)
@check
...
def check_nametable(ttFont, expected_name_table):
current = ttFont['name']
expected = expected_name_table
# Simply compare them. No need for 400 checks
@check
...
def check_metadata(metadata, expected_metadata):
...
## FIXING
# For fixing we use the constants and helper funcs from the gfcore.font
from gfcore.font import *
def fix_fstype(ttFont):
ttFont['OS/2'].fsType = GF_FS_TYPE
def fix_nametable(ttFont):
from gftools.font import family_name, style_name
ttFont['name'] = build_name_table(family_name(ttFont), style_name(ttFont)
# QA
# for gftools QA we can use gfcore.site to fetch fonts from fonts.google.com
from gfcore.site import download_family, family_exists
if family_exists("Comfortaa"):
existing_family = download_family("Comfortaa")
@simoncozens
Copy link

Here's what I was envisioning:

fontdoctor

class FsType(Doctor):
    @classmethod
    def cure_binary(cls, ttFont):
        ttFont["OS/2"].fsType = 0

    @classmethod
    def diagnose_binary(cls, ttFont):
        if ttFont["OS/2"].fsType == 0:
            return (True, None)
        else:
            return (False, "In this font...")

    @classmethod
    def diagnose_glyphs(cls, glyphs):
        pass

gftools fix

fix_fs_type = lambda font: fontdoctor.FsType.cure_binary(font)

fontbakery

@check(
    id = 'com.google.fonts/check/fstype',
    rationale = """
        The fsType in the OS/2 table is a legacy DRM-related field. Fonts in the Google Fonts collection must have it set to zero (also known as "Installable Embedding"). This setting indicates that the fonts can be embedded in documents and permanently installed by applications on remote systems.

        More detailed info is available at:
        https://docs.microsoft.com/en-us/typography/opentype/spec/os2#fstype
    """,
    proposal = 'legacy:check/016'
)
@fontdoctor_wrapper(fontdoctor.FsType)
def com_google_fonts_check_fsType:
   pass

@m4rc1e
Copy link
Author

m4rc1e commented Aug 6, 2021

Nice. I see what you're after now.

This could be taken a step further with cure and diagnose methods which could be format agnostic. Means we could chuck in any source/binary into fb/gftools.

@simoncozens
Copy link

Exactly! Doctor.cure looks at what type it has been passed, and dispatches to .cure_binary, .cure_glyphs, .cure_ufo as appropriate.

Also, I'm only happy with the docs being the single-source-of-truth if those docs are generated from a machine-readable source so that the "truth" can be used in our Python code without having to copy it out of the spec.

Suppose one day we change the desired value of os2.fsType (or some other value, but this is an example we've already seen). We would have to replace the number in the docs and in our implementation. Not exactly a single source of truth.

But if the docs have a python component that says:

gfdocs/desired_values.py

os2_fsType = 0

gfdocs/spec.md

The OS/2 table fsType field must be set to {{{ desired_values.os2_fsType }}}.

We can now do:

fontdoctor

class FsType(Doctor):
    @classmethod
    def cure_binary(cls, ttFont):
        ttFont["OS/2"].fsType = gfdocs.desired_values.os2_fsType
    ...

@m4rc1e
Copy link
Author

m4rc1e commented Aug 6, 2021

Also, I'm only happy with the docs being the single-source-of-truth if those docs are generated from a machine-readable source so that the "truth" can be used in our Python code without having to copy it out of the spec.

Sounds very sensible. I guess something similar to sphinx which is able to generate documentation from func docstrings etc?

@simoncozens
Copy link

More likely some kind of templating to add the Python constants into English prose.

@simoncozens
Copy link

Hmm, backing up a bit (possibly too far):

gfdocs/otspec.yaml

tables:
  - "OS/2": 
     description: "..."
     fields:
       - fsType:
         description: |
              Indicates font embedding licensing rights for the font. 
         glyphs_custom_parameter: fsType
         ufo_info_key: openTypeOS2Type
         values:
           # ...
         gf_requires: 0
         gf_rationale: "No DRM restrictions can be enabled on the Google Fonts collection"

fontdoctor

@doctor_from_otspec("OS/2", "fsType")
class FsType(Doctor):
    pass

@m4rc1e
Copy link
Author

m4rc1e commented Aug 6, 2021

It would be interesting to see how you'd tackle tables which do not have constants such as the name table.

@simoncozens
Copy link

Sure. I don't imagine you would be able to do this for everything. But what you could do it for, you should. I think this is what Dave is getting at here:

...in a way the googlefonts profile is a coded version of the GF Spec...
Given topically-unrelated efforts... - to make better structured docs for the font format spec... - perhaps there's something we can do to deduplicate and pattern things so there's a common approach that makes contribution skills more transferrable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment