Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add --ttf-curves to support building glyf v1 with cubics #1021

Merged
merged 1 commit into from
Jul 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion Lib/fontmake/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@

from fontmake import __version__
from fontmake.errors import FontmakeError
from fontmake.font_project import INTERPOLATABLE_OUTPUTS, FontProject
from fontmake.font_project import INTERPOLATABLE_OUTPUTS, CurveConversion, FontProject


def _loadPlugins(parser, specs, from_string_func, parser_error_message):
Expand Down Expand Up @@ -446,6 +446,17 @@ def main(args=None):
help="Do not reverse contour direction when output is ttf or "
"ttf-interpolatable",
)
contourGroup.add_argument(
"--ttf-curves",
dest="ttf_curves",
default=CurveConversion.default().value,
choices=[e.value for e in CurveConversion],
help="Controls conversion of cubic Bézier curves to TrueType quadratic splines."
" By default ('cu2qu'), all cubics are converted to quadratic (glyf v0). With"
" 'mixed', cubics are converted to quadratic only when more economical."
" If 'keep-quad' or 'keep-cubic', cu2qu is skipped altogether and curves are"
" compiled unchanged. NOTE: cubics in TTF use glyf v1 which is still draft!",
)
contourGroup.add_argument(
"-e",
"--conversion-error",
Expand Down
47 changes: 47 additions & 0 deletions Lib/fontmake/font_project.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

from __future__ import annotations

import enum
import glob
import logging
import math
Expand Down Expand Up @@ -85,6 +86,35 @@
}


class CurveConversion(enum.Enum):
# convert all cubic Bezier curves to quadratic splines: glyf format 0
ALL_CUBIC_TO_QUAD = "cu2qu"
# convert cubic curves to quadratic when more economical: glyf format 1
MIXED_CUBIC_TO_QUAD = "mixed"
# skip conversion, treat original curves as quadratic: glyf format 0
KEEP_QUAD = "keep-quad"
# skip conversion, treat original curves as cubic or mixed: glyf format 1
KEEP_CUBIC = "keep-cubic"

@classmethod
def default(cls):
return cls.ALL_CUBIC_TO_QUAD

@property
def convertCubics(self):
return self in (
CurveConversion.ALL_CUBIC_TO_QUAD,
CurveConversion.MIXED_CUBIC_TO_QUAD,
)

@property
def allQuadratic(self):
return self in (
CurveConversion.ALL_CUBIC_TO_QUAD,
CurveConversion.KEEP_QUAD,
)


def needs_subsetting(ufo):
if KEEP_GLYPHS_OLD_KEY in ufo.lib or KEEP_GLYPHS_NEW_KEY in ufo.lib:
return True
Expand Down Expand Up @@ -295,6 +325,7 @@ def _build_interpolatable_masters(
ttf,
use_production_names=None,
reverse_direction=True,
ttf_curves=CurveConversion.ALL_CUBIC_TO_QUAD,
conversion_error=None,
feature_writers=None,
cff_round_tolerance=None,
Expand All @@ -306,10 +337,13 @@ def _build_interpolatable_masters(
**kwargs,
):
if ttf:
ttf_curves = CurveConversion(ttf_curves)
return ufo2ft.compileInterpolatableTTFsFromDS(
designspace,
useProductionNames=use_production_names,
reverseDirection=reverse_direction,
convertCubics=ttf_curves.convertCubics,
allQuadratic=ttf_curves.allQuadratic,
cubicConversionError=conversion_error,
featureWriters=feature_writers,
debugFeatureFile=debug_feature_file,
Expand Down Expand Up @@ -354,6 +388,7 @@ def build_variable_fonts(
optimize_cff=CFFOptimization.SPECIALIZE,
use_production_names=None,
reverse_direction=True,
ttf_curves=CurveConversion.ALL_CUBIC_TO_QUAD,
conversion_error=None,
feature_writers=None,
cff_round_tolerance=None,
Expand Down Expand Up @@ -411,10 +446,13 @@ def build_variable_fonts(
)

if ttf:
ttf_curves = CurveConversion(ttf_curves)
fonts = ufo2ft.compileVariableTTFs(
designspace,
featureWriters=feature_writers,
useProductionNames=use_production_names,
convertCubics=ttf_curves.convertCubics,
allQuadratic=ttf_curves.allQuadratic,
cubicConversionError=conversion_error,
reverseDirection=reverse_direction,
optimizeGvar=optimize_gvar,
Expand Down Expand Up @@ -456,7 +494,9 @@ def _iter_compile(self, ufos, ttf=False, debugFeatureFile=None, **kwargs):
compile_func, fmt = ufo2ft.compileTTF, "TTF"
else:
for key in (
"convertCubics",
"cubicConversionError",
"allQuadratic",
"reverseDirection",
"flattenComponents",
"autoUseMyMetrics",
Expand Down Expand Up @@ -493,6 +533,7 @@ def save_otfs(
remove_overlaps=True,
overlaps_backend=None,
reverse_direction=True,
ttf_curves=CurveConversion.ALL_CUBIC_TO_QUAD,
conversion_error=None,
feature_writers=None,
interpolate_layout_from=None,
Expand Down Expand Up @@ -540,6 +581,8 @@ def save_otfs(
either "booleanOperations" (default) or "pathops".
reverse_direction: If True, reverse contour directions when
compiling TrueType outlines.
ttf_curves: Choose between "cu2qu" (default), "mixed", "keep-quad" or
"keep-cubic". NOTE: cubics in TTF use glyf v1 which is still draft!
conversion_error: Error to allow when converting cubic CFF contours
to quadratic TrueType contours.
feature_writers: list of ufo2ft-compatible feature writer classes
Expand Down Expand Up @@ -574,6 +617,8 @@ def save_otfs(
if output_path is not None and len(ufos) > 1:
raise ValueError("output_path requires a single input")

ttf_curves = CurveConversion(ttf_curves)

if subroutinize is not None:
import warnings

Expand Down Expand Up @@ -613,6 +658,8 @@ def save_otfs(
roundTolerance=cff_round_tolerance,
useProductionNames=use_production_names,
reverseDirection=reverse_direction,
convertCubics=ttf_curves.convertCubics,
allQuadratic=ttf_curves.allQuadratic,
cubicConversionError=conversion_error,
featureWriters=feature_writers,
debugFeatureFile=debug_feature_file,
Expand Down
Loading