Repository: googlefonts/ufo2ft

Issue:
Add support for dlng and slng
Now that UFO3 spec includes `public.openTypeMeta` in [lib.plist](http://unifiedfontobject.org/versions/ufo3/lib.plist/), could we get support for `dlng` and `slng` [metadata tags](https://docs.microsoft.com/en-us/typography/opentype/spec/meta#metadata-tags)?

Discussion:

Patch:
diff --git a/Lib/ufo2ft/constants.py b/Lib/ufo2ft/constants.py
index 662ed16..0028eac 100644
--- a/Lib/ufo2ft/constants.py
+++ b/Lib/ufo2ft/constants.py
@@ -21,5 +21,6 @@ COLOR_PALETTES_KEY = UFO2FT_PREFIX + "colorPalettes"
 COLOR_LAYER_MAPPING_KEY = UFO2FT_PREFIX + "colorLayerMapping"
 
 OPENTYPE_CATEGORIES_KEY = "public.openTypeCategories"
+OPENTYPE_META_KEY = "public.openTypeMeta"
 
 UNICODE_VARIATION_SEQUENCES_KEY = "public.unicodeVariationSequences"
diff --git a/Lib/ufo2ft/outlineCompiler.py b/Lib/ufo2ft/outlineCompiler.py
index c3c2d1b..f3aff92 100644
--- a/Lib/ufo2ft/outlineCompiler.py
+++ b/Lib/ufo2ft/outlineCompiler.py
@@ -27,6 +27,7 @@ from fontTools.ttLib.tables.O_S_2f_2 import Panose
 from ufo2ft.constants import (
     COLOR_LAYERS_KEY,
     COLOR_PALETTES_KEY,
+    OPENTYPE_META_KEY,
     UNICODE_VARIATION_SEQUENCES_KEY,
 )
 from ufo2ft.errors import InvalidFontData
@@ -86,6 +87,7 @@ class BaseOutlineCompiler:
             "vhea",
             "COLR",
             "CPAL",
+            "meta",
         ]
     )
 
@@ -135,6 +137,7 @@ class BaseOutlineCompiler:
         self.colorLayers = (
             COLOR_LAYERS_KEY in self.ufo.lib and COLOR_PALETTES_KEY in self.ufo.lib
         )
+        self.meta = OPENTYPE_META_KEY in self.ufo.lib
 
         # write the glyph order
         self.otf.setGlyphOrder(self.glyphOrder)
@@ -154,6 +157,8 @@ class BaseOutlineCompiler:
         if self.colorLayers:
             self.setupTable_COLR()
             self.setupTable_CPAL()
+        if self.meta:
+            self.setupTable_meta()
         self.setupOtherTables()
         self.importTTX()
 
@@ -978,6 +983,45 @@ class BaseOutlineCompiler:
         except ColorLibError as e:
             raise InvalidFontData("Failed to build CPAL table") from e
 
+    def setupTable_meta(self):
+        """
+        Make the meta table.
+
+        ***This should not be called externally.** Sublcasses
+        may override or supplement this method to handle the
+        table creation in a different way if desired.
+        """
+        if "meta" not in self.tables:
+            return
+
+        font = self.ufo
+        self.otf["meta"] = meta = newTable("meta")
+        ufo_meta = font.lib.get(OPENTYPE_META_KEY)
+        for key, value in ufo_meta.items():
+            if key in ["dlng", "slng"]:
+                if not isinstance(value, list) or not all(
+                    isinstance(string, str) for string in value
+                ):
+                    raise TypeError(
+                        f"public.openTypeMeta '{key}' value should "
+                        "be a list of strings"
+                    )
+                meta.data[key] = ",".join(value)
+            elif key in ["appl", "bild"]:
+                if not isinstance(value, bytes):
+                    raise TypeError(
+                        f"public.openTypeMeta '{key}' value should be bytes."
+                    )
+                meta.data[key] = value
+            elif isinstance(value, bytes):
+                meta.data[key] = value
+            elif isinstance(value, str):
+                meta.data[key] = value.encode("utf-8")
+            else:
+                raise TypeError(
+                    f"public.openTypeMeta '{key}' value should be bytes or a string."
+                )
+
     def setupOtherTables(self):
         """
         Make the other tables. The default implementation does nothing.


Test patch:
diff --git a/tests/outlineCompiler_test.py b/tests/outlineCompiler_test.py
index 03ee1d9..cc9abc4 100644
--- a/tests/outlineCompiler_test.py
+++ b/tests/outlineCompiler_test.py
@@ -205,6 +205,29 @@ class OutlineTTFCompilerTest:
         assert endPts == [4]
         assert list(flags) == [0, 0, 0, 0, 1]
 
+    def test_setupTable_meta(self, testufo):
+        testufo.lib["public.openTypeMeta"] = {
+            "appl": b"BEEF",
+            "bild": b"AAAA",
+            "dlng": ["en-Latn", "nl-Latn"],
+            "slng": ["Latn"],
+            "PRIB": b"Some private bytes",
+            "PRIA": "Some private ascii string",
+            "PRIU": "Some private unicode string…",
+        }
+
+        compiler = OutlineTTFCompiler(testufo)
+        ttFont = compiler.compile()
+        meta = ttFont["meta"]
+
+        assert meta.data["appl"] == b"BEEF"
+        assert meta.data["bild"] == b"AAAA"
+        assert meta.data["dlng"] == "en-Latn,nl-Latn"
+        assert meta.data["slng"] == "Latn"
+        assert meta.data["PRIB"] == b"Some private bytes"
+        assert meta.data["PRIA"] == b"Some private ascii string"
+        assert meta.data["PRIU"] == "Some private unicode string…".encode("utf-8")
+
 
 class OutlineOTFCompilerTest:
     def test_setupTable_CFF_all_blues_defined(self, testufo):