-
Notifications
You must be signed in to change notification settings - Fork 70
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1047 from googlefonts/fontc-flag-sketch
Support for fontc and crater
- Loading branch information
Showing
9 changed files
with
260 additions
and
28 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
"""functionality for running fontc via gftools | ||
gftools has a few special flags that allow it to use fontc, an alternative | ||
font compiler (https://github.com/googlefonts/fontc). | ||
This module exists to keep the logic related to fontc in one place, and not | ||
dirty up everything else. | ||
""" | ||
|
||
from argparse import Namespace | ||
from pathlib import Path | ||
from typing import Union | ||
|
||
from gftools.builder.file import File | ||
from gftools.builder.operations.fontc import set_global_fontc_path | ||
|
||
|
||
class FontcArgs: | ||
# init with 'None' returns a default obj where everything is None | ||
def __init__(self, args: Union[Namespace, None]) -> None: | ||
if not args: | ||
self.simple_output_path = None | ||
self.fontc_bin_path = None | ||
self.single_source = None | ||
return | ||
self.simple_output_path = abspath(args.experimental_simple_output) | ||
self.fontc_bin_path = abspath(args.experimental_fontc) | ||
self.single_source = args.experimental_single_source | ||
if self.fontc_bin_path: | ||
if not self.fontc_bin_path.is_file(): | ||
raise ValueError(f"fontc does not exist at {self.fontc_bin_path}") | ||
set_global_fontc_path(self.fontc_bin_path) | ||
|
||
@property | ||
def use_fontc(self) -> bool: | ||
return self.fontc_bin_path is not None | ||
|
||
# update the config dictionary based on our special needs | ||
def modify_config(self, config: dict): | ||
if self.single_source: | ||
filtered_sources = [s for s in config["sources"] if self.single_source in s] | ||
n_sources = len(filtered_sources) | ||
if n_sources != 1: | ||
raise ValueError( | ||
f"--exerimental-single-source {self.single_source} must match exactly one of {config['sources']} (matched {n_sources}) " | ||
) | ||
config["sources"] = filtered_sources | ||
|
||
if self.fontc_bin_path or self.simple_output_path: | ||
# we stash this flag here to pass it down to the recipe provider | ||
config["use_fontc"] = self.fontc_bin_path | ||
config["buildWebfont"] = False | ||
config["buildSmallCap"] = False | ||
config["splitItalic"] = False | ||
# set --no-production-names, because it's easier to debug | ||
extra_args = config.get("extraFontmakeArgs") or "" | ||
extra_args += " --no-production-names --drop-implied-oncurves" | ||
config["extraFontmakeArgs"] = extra_args | ||
# override config to turn not build instances if we're variable | ||
if self.will_build_variable_font(config): | ||
config["buildStatic"] = False | ||
# if the font doesn't explicitly request CFF, just build TT outlines | ||
# if the font _only_ wants CFF outlines, we will try to build them | ||
# ( but fail on fontc for now) (but is this even a thing?) | ||
elif config.get("buildTTF", True): | ||
config["buildOTF"] = False | ||
if self.simple_output_path: | ||
output_dir = str(self.simple_output_path) | ||
# we dump everything into one dir in this case | ||
config["outputDir"] = str(output_dir) | ||
config["ttDir"] = str(output_dir) | ||
config["otDir"] = str(output_dir) | ||
config["vfDir"] = str(output_dir) | ||
|
||
def will_build_variable_font(self, config: dict) -> bool: | ||
# if config explicitly says dont build variable, believe it | ||
if not config.get("buildVariable", True): | ||
return False | ||
|
||
source = File(config["sources"][0]) | ||
return source.is_variable | ||
|
||
|
||
def abspath(path: Union[Path, None]) -> Union[Path, None]: | ||
return path.resolve() if path else None |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
from pathlib import Path | ||
from typing import List | ||
from gftools.builder.operations import OperationBase | ||
|
||
_FONTC_PATH = None | ||
|
||
|
||
# should only be called once, from main, before doing anything else. This is a | ||
# relatively non-invasive way to smuggle this value into FontcOperationBase | ||
def set_global_fontc_path(path: Path): | ||
global _FONTC_PATH | ||
assert _FONTC_PATH is None, "set_global_fontc_path should only be called once" | ||
_FONTC_PATH = path | ||
|
||
|
||
class FontcOperationBase(OperationBase): | ||
@property | ||
def variables(self): | ||
vars = super().variables | ||
vars["fontc_path"] = _FONTC_PATH | ||
args = vars.get("args") | ||
if args: | ||
vars["args"] = rewrite_fontmake_args_for_fontc(args) | ||
|
||
return vars | ||
|
||
|
||
def rewrite_fontmake_args_for_fontc(args: str) -> str: | ||
out_args = [] | ||
arg_list = args.split() | ||
# reverse so we can pop in order | ||
arg_list.reverse() | ||
while arg_list: | ||
out_args.append(rewrite_one_arg(arg_list)) | ||
return " ".join(out_args) | ||
|
||
|
||
# remove next arg from the front of the list and return its fontc equivalent | ||
def rewrite_one_arg(args: List[str]) -> str: | ||
next_ = args.pop() | ||
if next_ == "--filter": | ||
filter_ = args.pop() | ||
# this means 'retain filters defined in UFO', which... do we even support | ||
# that in fontc? | ||
if filter_ == "...": | ||
pass | ||
elif filter_ == "FlattenComponentsFilter": | ||
return "--flatten-components" | ||
elif filter_ == "DecomposeTransformedComponentsFilter": | ||
return "--decompose-transformed-components" | ||
else: | ||
# glue the filter back together for better reporting below | ||
next_ = f"{next_} {filter_}" | ||
elif next_ == "--no-production-names": | ||
return next_ | ||
elif next_ == "--drop-implied-oncurves": | ||
# this is our default behaviour so no worries | ||
return "" | ||
else: | ||
raise ValueError(f"unknown fontmake arg '{next_}'") | ||
return "" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
from gftools.builder.operations.fontc import FontcOperationBase | ||
|
||
|
||
class FontcBuildOTF(FontcOperationBase): | ||
description = "Build an OTF from a source file (with fontc)" | ||
# the '--cff-outlines' flag does not exit in fontc, so this will | ||
# error, which we want | ||
rule = "$fontc_path -o $out $in $args --cff-outlines" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
from gftools.builder.operations.fontc import FontcOperationBase | ||
|
||
|
||
class FontcBuildTTF(FontcOperationBase): | ||
description = "Build a TTF from a source file (with fontc)" | ||
rule = "$fontc_path -o $out $in $args" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
from gftools.builder.operations.fontc import FontcOperationBase | ||
|
||
|
||
class FontcBuildVariable(FontcOperationBase): | ||
description = "Build a variable font from a source file (with fontc)" | ||
rule = f"$fontc_path -o $out $in $args" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters