diff --git a/Lib/fontTools/varLib/__init__.py b/Lib/fontTools/varLib/__init__.py index 81b7cef7d..46834f643 100644 --- a/Lib/fontTools/varLib/__init__.py +++ b/Lib/fontTools/varLib/__init__.py @@ -863,7 +863,7 @@ def _add_COLR(font, model, master_fonts, axisTags, colr_layer_reuse=True): colr.VarIndexMap = builder.buildDeltaSetIndexMap(varIdxes) -def load_designspace(designspace): +def load_designspace(designspace, log_enabled=True): # TODO: remove this and always assume 'designspace' is a DesignSpaceDocument, # never a file path, as that's already handled by caller if hasattr(designspace, "sources"): # Assume a DesignspaceDocument @@ -911,10 +911,11 @@ def load_designspace(designspace): axis.labelNames["en"] = tostr(axis_name) axes[axis_name] = axis - log.info("Axes:\n%s", pformat([axis.asdict() for axis in axes.values()])) + if log_enabled: + log.info("Axes:\n%s", pformat([axis.asdict() for axis in axes.values()])) axisMappings = ds.axisMappings - if axisMappings: + if axisMappings and log_enabled: log.info("Mappings:\n%s", pformat(axisMappings)) # Check all master and instance locations are valid and fill in defaults @@ -944,20 +945,23 @@ def load_designspace(designspace): # Normalize master locations internal_master_locs = [o.getFullDesignLocation(ds) for o in masters] - log.info("Internal master locations:\n%s", pformat(internal_master_locs)) + if log_enabled: + log.info("Internal master locations:\n%s", pformat(internal_master_locs)) # TODO This mapping should ideally be moved closer to logic in _add_fvar/avar internal_axis_supports = {} for axis in axes.values(): triple = (axis.minimum, axis.default, axis.maximum) internal_axis_supports[axis.name] = [axis.map_forward(v) for v in triple] - log.info("Internal axis supports:\n%s", pformat(internal_axis_supports)) + if log_enabled: + log.info("Internal axis supports:\n%s", pformat(internal_axis_supports)) normalized_master_locs = [ models.normalizeLocation(m, internal_axis_supports) for m in internal_master_locs ] - log.info("Normalized master locations:\n%s", pformat(normalized_master_locs)) + if log_enabled: + log.info("Normalized master locations:\n%s", pformat(normalized_master_locs)) # Find base master base_idx = None @@ -972,7 +976,8 @@ def load_designspace(designspace): raise VarLibValidationError( "Base master not found; no master at default location?" ) - log.info("Index of base master: %s", base_idx) + if log_enabled: + log.info("Index of base master: %s", base_idx) return _DesignSpaceData( axes, @@ -1308,6 +1313,30 @@ def _feature_variations_tags(ds): return sorted({t.strip() for t in raw_tags.split(",")}) +def addGSUBFeatureVariations(vf, designspace, featureTags=(), *, log_enabled=False): + """Add GSUB FeatureVariations table to variable font, based on DesignSpace rules. + + Args: + vf: A TTFont object representing the variable font. + designspace: A DesignSpaceDocument object. + featureTags: Optional feature tag(s) to use for the FeatureVariations records. + If unset, the key 'com.github.fonttools.varLib.featureVarsFeatureTag' is + looked up in the DS and used; otherwise the default is 'rclt' if + the attribute is set, else 'rvrn'. + See + log_enabled: If True, log info about DS axes and sources. Default is False, as + the same info may have already been logged as part of varLib.build. + """ + ds = load_designspace(designspace, log_enabled=log_enabled) + if not ds.rules: + return + if not featureTags: + featureTags = _feature_variations_tags(ds) + _add_GSUB_feature_variations( + vf, ds.axes, ds.internal_axis_supports, ds.rules, featureTags + ) + + def main(args=None): """Build variable fonts from a designspace file and masters""" from argparse import ArgumentParser diff --git a/Tests/varLib/varLib_test.py b/Tests/varLib/varLib_test.py index 87616ae2e..53acc1653 100644 --- a/Tests/varLib/varLib_test.py +++ b/Tests/varLib/varLib_test.py @@ -1,7 +1,13 @@ from fontTools.colorLib.builder import buildCOLR from fontTools.ttLib import TTFont, newTable from fontTools.ttLib.tables import otTables as ot -from fontTools.varLib import build, build_many, load_designspace, _add_COLR +from fontTools.varLib import ( + build, + build_many, + load_designspace, + _add_COLR, + addGSUBFeatureVariations, +) from fontTools.varLib.errors import VarLibValidationError import fontTools.varLib.errors as varLibErrors from fontTools.varLib.models import VariationModel @@ -1009,6 +1015,32 @@ Expected to see .ScriptCount==1, instead saw 0""", save_before_dump=True, ) + def test_varlib_addGSUBFeatureVariations(self): + ttx_dir = self.get_test_input("master_ttx_interpolatable_ttf") + + ds = DesignSpaceDocument.fromfile( + self.get_test_input("FeatureVars.designspace") + ) + for source in ds.sources: + ttx_dump = TTFont() + ttx_dump.importXML( + os.path.join( + ttx_dir, os.path.basename(source.filename).replace(".ufo", ".ttx") + ) + ) + source.font = ttx_dump + + varfont, _, _ = build(ds, exclude=["GSUB"]) + assert "GSUB" not in varfont + + addGSUBFeatureVariations(varfont, ds) + assert "GSUB" in varfont + + tables = ["fvar", "GSUB"] + expected_ttx_path = self.get_test_output("FeatureVars.ttx") + self.expect_ttx(varfont, expected_ttx_path, tables) + self.check_ttx_dump(varfont, expected_ttx_path, tables, ".ttf") + def test_load_masters_layerName_without_required_font(): ds = DesignSpaceDocument()