[cantarell-fonts/store-gdef-in-lib: 1/2] Modify GDEF updater script to write public.openTypeCategories
- From: Nikolaus Waxweiler <nwaxweiler src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [cantarell-fonts/store-gdef-in-lib: 1/2] Modify GDEF updater script to write public.openTypeCategories
- Date: Thu, 29 Jul 2021 20:01:40 +0000 (UTC)
commit cd132c6164eeb9c189b9ec87d58f05ffb0fb8c58
Author: Nikolaus Waxweiler <madigens gmail com>
Date: Thu Jul 29 21:01:02 2021 +0100
Modify GDEF updater script to write public.openTypeCategories
scripts/update-gdef.py | 97 ++++++++++++++++++++------------------------------
1 file changed, 38 insertions(+), 59 deletions(-)
---
diff --git a/scripts/update-gdef.py b/scripts/update-gdef.py
index daa1f2ab9..510c08f39 100644
--- a/scripts/update-gdef.py
+++ b/scripts/update-gdef.py
@@ -6,88 +6,70 @@ glyphs with anchors.
"""
from pathlib import Path
-from typing import Any, Dict, List
+from typing import Dict, Optional
-import ufoLib2
import glyphsLib.builder.constants
import glyphsLib.glyphdata
import ufo2ft.filters
+import ufoLib2
-# Lifted from glyphsLib and adapted to only recognize Letters as bases and not
-# insert a "# automatic".
-def _build_gdef(ufo) -> List[str]:
- """Build a GDEF table statement (GlyphClassDef and LigatureCaretByPos).
+def opentype_categories(ufo: ufoLib2.Font) -> Dict[str, str]:
+ """Returns a public.openTypeCategories dictionary.
- Building GlyphClassDef requires anchor propagation or user care to work as
+ Building it requires anchor propagation or user care to work as
expected, as Glyphs.app also looks at anchors for classification:
- * Base: any glyph that has an attaching anchor (such as "top"; "_top" does
+ * base: any glyph that has an attaching anchor (such as "top"; "_top" does
not count) and is neither classified as Ligature nor Mark using the
definitions below;
- * Ligature: if subCategory is "Ligature" and the glyph has at least one
+ * ligature: if subCategory is "Ligature" and the glyph has at least one
attaching anchor;
- * Mark: if category is "Mark" and subCategory is either "Nonspacing" or
+ * mark: if category is "Mark" and subCategory is either "Nonspacing" or
"Spacing Combining";
- * Compound: never assigned by Glyphs.app.
+ * composite: never assigned by Glyphs.app.
See:
* https://github.com/googlefonts/glyphsLib/issues/85
* https://github.com/googlefonts/glyphsLib/pull/100#issuecomment-275430289
"""
- bases, ligatures, marks = set(), set(), set()
- carets: Dict[str, Any] = {} # glyph names to anchor objects
+
+ # Drop glyphs that don't exist in font anymore.
+ existing: Dict[str, str] = ufo.lib.get("public.openTypeCategories", {})
+ categories: Dict[str, str] = {k: v for k, v in existing.items() if k in ufo}
+
category_key = glyphsLib.builder.constants.GLYPHLIB_PREFIX + "category"
- subCategory_key = glyphsLib.builder.constants.GLYPHLIB_PREFIX + "subCategory"
+ subcategory_key = glyphsLib.builder.constants.GLYPHLIB_PREFIX + "subCategory"
for glyph in ufo:
+ assert glyph.name is not None
has_attaching_anchor = False
for anchor in glyph.anchors:
name = anchor.name
- if name and not name.startswith("_"):
+ if not name:
+ continue
+ if not name.startswith("_"):
has_attaching_anchor = True
- if name and name.startswith("caret_") and "x" in anchor:
- carets.setdefault(glyph.name, []).append(round(anchor["x"]))
# First check glyph.lib for category/subCategory overrides. Otherwise,
# use global values from GlyphData.
glyphinfo = glyphsLib.glyphdata.get_glyph(glyph.name)
- category = glyph.lib.get(category_key) or glyphinfo.category
- subCategory = glyph.lib.get(subCategory_key) or glyphinfo.subCategory
+ category: Optional[str] = glyph.lib.get(category_key, glyphinfo.category)
+ subcategory: Optional[str] = glyph.lib.get(
+ subcategory_key, glyphinfo.subCategory
+ )
- if subCategory == "Ligature" and has_attaching_anchor:
- ligatures.add(glyph.name)
+ if subcategory == "Ligature" and has_attaching_anchor:
+ categories[glyph.name] = "ligature"
elif category == "Mark" and (
- subCategory == "Nonspacing" or subCategory == "Spacing Combining"
+ subcategory == "Nonspacing" or subcategory == "Spacing Combining"
):
- marks.add(glyph.name)
+ categories[glyph.name] = "mark"
elif category == "Letter" and has_attaching_anchor:
- bases.add(glyph.name)
+ categories[glyph.name] = "base"
- if not any((bases, ligatures, marks, carets)):
- return []
-
- def fmt(g):
- if g:
- glyph_names = " ".join(sorted(g, key=ufo.glyphOrder.index))
- return f"[{glyph_names}]"
- return ""
-
- lines = [
- "table GDEF {",
- " GlyphClassDef",
- f" {fmt(bases)}, # Base",
- f" {fmt(ligatures)}, # Liga",
- f" {fmt(marks)}, # Mark",
- " ;",
- ]
- for glyph, caretPos in sorted(carets.items()):
- caretPos_joined = " ".join(sorted(caretPos))
- lines.append(f" LigatureCaretByPos {glyph} {caretPos_joined};")
- lines.append("} GDEF;")
-
- return lines
+ return categories
# Anchors have to be propagated before we can construct the GDEF table.
@@ -102,15 +84,12 @@ if __name__ == "__main__":
for pf in pre_filter:
pf(font=main_source) # Run propagation filters on main UFO
- # Generate GDEF definition string from processed, in-memory UFO
- gdef_table_lines = [f"{l}\n" for l in _build_gdef(main_source)]
-
- # Update features.fea in all UFOs.
- for feature_file in source_directory.glob("*.ufo/features.fea"):
- with open(feature_file) as fp:
- file_contents = fp.readlines()
- gdef_start = file_contents.index("table GDEF {\n")
- gdef_end = file_contents.index("} GDEF;\n") + 1
- file_contents[gdef_start:gdef_end] = gdef_table_lines
- with open(feature_file, "w+") as fp:
- fp.write("".join(file_contents))
+ ot_categories = opentype_categories(main_source)
+
+ for ufo_path in source_directory.glob("*.ufo"):
+ ufo = ufoLib2.Font.open(ufo_path)
+ if ot_categories:
+ ufo.lib["public.openTypeCategories"] = ot_categories
+ else:
+ ufo.lib.pop("public.openTypeCategories", None)
+ ufo.save()
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]