Repository: googlefonts/ufo2ft
Pull request #787 (2023-10-19 08:41:57)

Add LTR script kerning to DFLT for InDesign default composer
Hello, this is an Adobe-specific "fix" for the following situation: in InDesign, using the default paragraph composer (not World-ready), and having no language selected, InDesign will not bother detecting the actual script of the text runs, and use the appropriate kerning; instead it sticks to only what is registered in the DFLT script.

With the split by script kerning, there's very little kerning under DFLT and it looks as though the font is unkerned.

In this PR I'm registering all the LTR script lookups under DFLT, so that InDesign applies that kerning even when no language is selected. The idea is that for RTL scripts you need to switch to the "good" composer anyway, so no need to bother.


Patch:
diff --git a/Lib/ufo2ft/featureWriters/kernFeatureWriter.py b/Lib/ufo2ft/featureWriters/kernFeatureWriter.py
index a55ac64..0ce7c7e 100644
--- a/Lib/ufo2ft/featureWriters/kernFeatureWriter.py
+++ b/Lib/ufo2ft/featureWriters/kernFeatureWriter.py
@@ -575,11 +575,27 @@ class KernFeatureWriter(BaseFeatureWriter):
     ) -> None:
         # Ensure we have kerning for pure common script runs (e.g. ">1")
         isKernBlock = feature.name == "kern"
+        dfltLookups: list[ast.LookupBlock] = []
         if isKernBlock and COMMON_SCRIPT in lookups:
+            dfltLookups.extend(lookups[COMMON_SCRIPT].values())
+
+        # InDesign bugfix: register kerning lookups for all LTR scripts under DFLT
+        # so that the basic composer, without a language selected, will still kern.
+        # Register LTR lookups if any, otherwise RTL lookups.
+        if isKernBlock:
+            lookupsLTR: list[ast.LookupBlock] = []
+            lookupsRTL: list[ast.LookupBlock] = []
+            for script, scriptLookups in sorted(lookups.items()):
+                if script != COMMON_SCRIPT and script not in DIST_ENABLED_SCRIPTS:
+                    if script_horizontal_direction(script, "LTR") == "LTR":
+                        lookupsLTR.extend(scriptLookups.values())
+                    elif script_horizontal_direction(script, "LTR") == "RTL":
+                        lookupsRTL.extend(scriptLookups.values())
+            dfltLookups.extend(lookupsLTR or lookupsRTL)
+
+        if dfltLookups:
             languages = feaLanguagesByScript.get("DFLT", ["dflt"])
-            ast.addLookupReferences(
-                feature, lookups[COMMON_SCRIPT].values(), "DFLT", languages
-            )
+            ast.addLookupReferences(feature, dfltLookups, "DFLT", languages)
 
         # Feature blocks use script tags to distinguish what to run for a
         # Unicode script.


Test patch:
diff --git a/tests/data/TestFont-CFF-compreffor.ttx b/tests/data/TestFont-CFF-compreffor.ttx
index 49e8a21..ca77ec1 100644
--- a/tests/data/TestFont-CFF-compreffor.ttx
+++ b/tests/data/TestFont-CFF-compreffor.ttx
@@ -390,8 +390,19 @@
   <GPOS>
     <Version value="0x00010000"/>
     <ScriptList>
-      <!-- ScriptCount=1 -->
+      <!-- ScriptCount=2 -->
       <ScriptRecord index="0">
+        <ScriptTag value="DFLT"/>
+        <Script>
+          <DefaultLangSys>
+            <ReqFeatureIndex value="65535"/>
+            <!-- FeatureCount=1 -->
+            <FeatureIndex index="0" value="0"/>
+          </DefaultLangSys>
+          <!-- LangSysCount=0 -->
+        </Script>
+      </ScriptRecord>
+      <ScriptRecord index="1">
         <ScriptTag value="latn"/>
         <Script>
           <DefaultLangSys>
diff --git a/tests/data/TestFont-CFF.ttx b/tests/data/TestFont-CFF.ttx
index 6eec632..8503f51 100644
--- a/tests/data/TestFont-CFF.ttx
+++ b/tests/data/TestFont-CFF.ttx
@@ -406,8 +406,19 @@
   <GPOS>
     <Version value="0x00010000"/>
     <ScriptList>
-      <!-- ScriptCount=1 -->
+      <!-- ScriptCount=2 -->
       <ScriptRecord index="0">
+        <ScriptTag value="DFLT"/>
+        <Script>
+          <DefaultLangSys>
+            <ReqFeatureIndex value="65535"/>
+            <!-- FeatureCount=1 -->
+            <FeatureIndex index="0" value="0"/>
+          </DefaultLangSys>
+          <!-- LangSysCount=0 -->
+        </Script>
+      </ScriptRecord>
+      <ScriptRecord index="1">
         <ScriptTag value="latn"/>
         <Script>
           <DefaultLangSys>
diff --git a/tests/data/TestFont-CFF2-cffsubr.ttx b/tests/data/TestFont-CFF2-cffsubr.ttx
index 7eb0e60..47a52e1 100644
--- a/tests/data/TestFont-CFF2-cffsubr.ttx
+++ b/tests/data/TestFont-CFF2-cffsubr.ttx
@@ -412,8 +412,19 @@
   <GPOS>
     <Version value="0x00010000"/>
     <ScriptList>
-      <!-- ScriptCount=1 -->
+      <!-- ScriptCount=2 -->
       <ScriptRecord index="0">
+        <ScriptTag value="DFLT"/>
+        <Script>
+          <DefaultLangSys>
+            <ReqFeatureIndex value="65535"/>
+            <!-- FeatureCount=1 -->
+            <FeatureIndex index="0" value="0"/>
+          </DefaultLangSys>
+          <!-- LangSysCount=0 -->
+        </Script>
+      </ScriptRecord>
+      <ScriptRecord index="1">
         <ScriptTag value="latn"/>
         <Script>
           <DefaultLangSys>
diff --git a/tests/data/TestFont-CFF2-post3.ttx b/tests/data/TestFont-CFF2-post3.ttx
index 93e056b..c50a145 100644
--- a/tests/data/TestFont-CFF2-post3.ttx
+++ b/tests/data/TestFont-CFF2-post3.ttx
@@ -387,8 +387,19 @@
   <GPOS>
     <Version value="0x00010000"/>
     <ScriptList>
-      <!-- ScriptCount=1 -->
+      <!-- ScriptCount=2 -->
       <ScriptRecord index="0">
+        <ScriptTag value="DFLT"/>
+        <Script>
+          <DefaultLangSys>
+            <ReqFeatureIndex value="65535"/>
+            <!-- FeatureCount=1 -->
+            <FeatureIndex index="0" value="0"/>
+          </DefaultLangSys>
+          <!-- LangSysCount=0 -->
+        </Script>
+      </ScriptRecord>
+      <ScriptRecord index="1">
         <ScriptTag value="latn"/>
         <Script>
           <DefaultLangSys>
diff --git a/tests/data/TestFont-NoOptimize-CFF.ttx b/tests/data/TestFont-NoOptimize-CFF.ttx
index a0ad563..c55776f 100644
--- a/tests/data/TestFont-NoOptimize-CFF.ttx
+++ b/tests/data/TestFont-NoOptimize-CFF.ttx
@@ -409,8 +409,19 @@
   <GPOS>
     <Version value="0x00010000"/>
     <ScriptList>
-      <!-- ScriptCount=1 -->
+      <!-- ScriptCount=2 -->
       <ScriptRecord index="0">
+        <ScriptTag value="DFLT"/>
+        <Script>
+          <DefaultLangSys>
+            <ReqFeatureIndex value="65535"/>
+            <!-- FeatureCount=1 -->
+            <FeatureIndex index="0" value="0"/>
+          </DefaultLangSys>
+          <!-- LangSysCount=0 -->
+        </Script>
+      </ScriptRecord>
+      <ScriptRecord index="1">
         <ScriptTag value="latn"/>
         <Script>
           <DefaultLangSys>
diff --git a/tests/data/TestFont-NoOptimize-CFF2.ttx b/tests/data/TestFont-NoOptimize-CFF2.ttx
index fa52e2d..bc37bf0 100644
--- a/tests/data/TestFont-NoOptimize-CFF2.ttx
+++ b/tests/data/TestFont-NoOptimize-CFF2.ttx
@@ -421,8 +421,19 @@
   <GPOS>
     <Version value="0x00010000"/>
     <ScriptList>
-      <!-- ScriptCount=1 -->
+      <!-- ScriptCount=2 -->
       <ScriptRecord index="0">
+        <ScriptTag value="DFLT"/>
+        <Script>
+          <DefaultLangSys>
+            <ReqFeatureIndex value="65535"/>
+            <!-- FeatureCount=1 -->
+            <FeatureIndex index="0" value="0"/>
+          </DefaultLangSys>
+          <!-- LangSysCount=0 -->
+        </Script>
+      </ScriptRecord>
+      <ScriptRecord index="1">
         <ScriptTag value="latn"/>
         <Script>
           <DefaultLangSys>
diff --git a/tests/data/TestFont-NoOverlaps-CFF-pathops.ttx b/tests/data/TestFont-NoOverlaps-CFF-pathops.ttx
index f990dd5..d3188c2 100644
--- a/tests/data/TestFont-NoOverlaps-CFF-pathops.ttx
+++ b/tests/data/TestFont-NoOverlaps-CFF-pathops.ttx
@@ -401,8 +401,19 @@
   <GPOS>
     <Version value="0x00010000"/>
     <ScriptList>
-      <!-- ScriptCount=1 -->
+      <!-- ScriptCount=2 -->
       <ScriptRecord index="0">
+        <ScriptTag value="DFLT"/>
+        <Script>
+          <DefaultLangSys>
+            <ReqFeatureIndex value="65535"/>
+            <!-- FeatureCount=1 -->
+            <FeatureIndex index="0" value="0"/>
+          </DefaultLangSys>
+          <!-- LangSysCount=0 -->
+        </Script>
+      </ScriptRecord>
+      <ScriptRecord index="1">
         <ScriptTag value="latn"/>
         <Script>
           <DefaultLangSys>
diff --git a/tests/data/TestFont-NoOverlaps-CFF.ttx b/tests/data/TestFont-NoOverlaps-CFF.ttx
index 7c32912..ec760bc 100644
--- a/tests/data/TestFont-NoOverlaps-CFF.ttx
+++ b/tests/data/TestFont-NoOverlaps-CFF.ttx
@@ -398,8 +398,19 @@
   <GPOS>
     <Version value="0x00010000"/>
     <ScriptList>
-      <!-- ScriptCount=1 -->
+      <!-- ScriptCount=2 -->
       <ScriptRecord index="0">
+        <ScriptTag value="DFLT"/>
+        <Script>
+          <DefaultLangSys>
+            <ReqFeatureIndex value="65535"/>
+            <!-- FeatureCount=1 -->
+            <FeatureIndex index="0" value="0"/>
+          </DefaultLangSys>
+          <!-- LangSysCount=0 -->
+        </Script>
+      </ScriptRecord>
+      <ScriptRecord index="1">
         <ScriptTag value="latn"/>
         <Script>
           <DefaultLangSys>
diff --git a/tests/data/TestFont-NoOverlaps-TTF-pathops.ttx b/tests/data/TestFont-NoOverlaps-TTF-pathops.ttx
index 0b30acf..5a605c0 100644
--- a/tests/data/TestFont-NoOverlaps-TTF-pathops.ttx
+++ b/tests/data/TestFont-NoOverlaps-TTF-pathops.ttx
@@ -485,8 +485,19 @@
   <GPOS>
     <Version value="0x00010000"/>
     <ScriptList>
-      <!-- ScriptCount=1 -->
+      <!-- ScriptCount=2 -->
       <ScriptRecord index="0">
+        <ScriptTag value="DFLT"/>
+        <Script>
+          <DefaultLangSys>
+            <ReqFeatureIndex value="65535"/>
+            <!-- FeatureCount=1 -->
+            <FeatureIndex index="0" value="0"/>
+          </DefaultLangSys>
+          <!-- LangSysCount=0 -->
+        </Script>
+      </ScriptRecord>
+      <ScriptRecord index="1">
         <ScriptTag value="latn"/>
         <Script>
           <DefaultLangSys>
diff --git a/tests/data/TestFont-NoOverlaps-TTF.ttx b/tests/data/TestFont-NoOverlaps-TTF.ttx
index 07f028f..90a6a00 100644
--- a/tests/data/TestFont-NoOverlaps-TTF.ttx
+++ b/tests/data/TestFont-NoOverlaps-TTF.ttx
@@ -485,8 +485,19 @@
   <GPOS>
     <Version value="0x00010000"/>
     <ScriptList>
-      <!-- ScriptCount=1 -->
+      <!-- ScriptCount=2 -->
       <ScriptRecord index="0">
+        <ScriptTag value="DFLT"/>
+        <Script>
+          <DefaultLangSys>
+            <ReqFeatureIndex value="65535"/>
+            <!-- FeatureCount=1 -->
+            <FeatureIndex index="0" value="0"/>
+          </DefaultLangSys>
+          <!-- LangSysCount=0 -->
+        </Script>
+      </ScriptRecord>
+      <ScriptRecord index="1">
         <ScriptTag value="latn"/>
         <Script>
           <DefaultLangSys>
diff --git a/tests/data/TestFont-Specialized-CFF.ttx b/tests/data/TestFont-Specialized-CFF.ttx
index 419fdc9..69681ba 100644
--- a/tests/data/TestFont-Specialized-CFF.ttx
+++ b/tests/data/TestFont-Specialized-CFF.ttx
@@ -387,8 +387,19 @@
   <GPOS>
     <Version value="0x00010000"/>
     <ScriptList>
-      <!-- ScriptCount=1 -->
+      <!-- ScriptCount=2 -->
       <ScriptRecord index="0">
+        <ScriptTag value="DFLT"/>
+        <Script>
+          <DefaultLangSys>
+            <ReqFeatureIndex value="65535"/>
+            <!-- FeatureCount=1 -->
+            <FeatureIndex index="0" value="0"/>
+          </DefaultLangSys>
+          <!-- LangSysCount=0 -->
+        </Script>
+      </ScriptRecord>
+      <ScriptRecord index="1">
         <ScriptTag value="latn"/>
         <Script>
           <DefaultLangSys>
diff --git a/tests/data/TestFont-Specialized-CFF2.ttx b/tests/data/TestFont-Specialized-CFF2.ttx
index 6871bbc..ba647b6 100644
--- a/tests/data/TestFont-Specialized-CFF2.ttx
+++ b/tests/data/TestFont-Specialized-CFF2.ttx
@@ -399,8 +399,19 @@
   <GPOS>
     <Version value="0x00010000"/>
     <ScriptList>
-      <!-- ScriptCount=1 -->
+      <!-- ScriptCount=2 -->
       <ScriptRecord index="0">
+        <ScriptTag value="DFLT"/>
+        <Script>
+          <DefaultLangSys>
+            <ReqFeatureIndex value="65535"/>
+            <!-- FeatureCount=1 -->
+            <FeatureIndex index="0" value="0"/>
+          </DefaultLangSys>
+          <!-- LangSysCount=0 -->
+        </Script>
+      </ScriptRecord>
+      <ScriptRecord index="1">
         <ScriptTag value="latn"/>
         <Script>
           <DefaultLangSys>
diff --git a/tests/data/TestFont-TTF-post3.ttx b/tests/data/TestFont-TTF-post3.ttx
index 44ef3ea..e226d62 100644
--- a/tests/data/TestFont-TTF-post3.ttx
+++ b/tests/data/TestFont-TTF-post3.ttx
@@ -458,8 +458,19 @@
   <GPOS>
     <Version value="0x00010000"/>
     <ScriptList>
-      <!-- ScriptCount=1 -->
+      <!-- ScriptCount=2 -->
       <ScriptRecord index="0">
+        <ScriptTag value="DFLT"/>
+        <Script>
+          <DefaultLangSys>
+            <ReqFeatureIndex value="65535"/>
+            <!-- FeatureCount=1 -->
+            <FeatureIndex index="0" value="0"/>
+          </DefaultLangSys>
+          <!-- LangSysCount=0 -->
+        </Script>
+      </ScriptRecord>
+      <ScriptRecord index="1">
         <ScriptTag value="latn"/>
         <Script>
           <DefaultLangSys>
diff --git a/tests/data/TestFont.ttx b/tests/data/TestFont.ttx
index dc20d9c..e754bfc 100644
--- a/tests/data/TestFont.ttx
+++ b/tests/data/TestFont.ttx
@@ -483,8 +483,19 @@
   <GPOS>
     <Version value="0x00010000"/>
     <ScriptList>
-      <!-- ScriptCount=1 -->
+      <!-- ScriptCount=2 -->
       <ScriptRecord index="0">
+        <ScriptTag value="DFLT"/>
+        <Script>
+          <DefaultLangSys>
+            <ReqFeatureIndex value="65535"/>
+            <!-- FeatureCount=1 -->
+            <FeatureIndex index="0" value="0"/>
+          </DefaultLangSys>
+          <!-- LangSysCount=0 -->
+        </Script>
+      </ScriptRecord>
+      <ScriptRecord index="1">
         <ScriptTag value="latn"/>
         <Script>
           <DefaultLangSys>
diff --git a/tests/featureWriters/kernFeatureWriter_test.py b/tests/featureWriters/kernFeatureWriter_test.py
index 39eed37..9653c3b 100644
--- a/tests/featureWriters/kernFeatureWriter_test.py
+++ b/tests/featureWriters/kernFeatureWriter_test.py
@@ -154,7 +154,7 @@ class KernFeatureWriterTest(FeatureWriterTest):
 
         # default is ignoreMarks=True
         feaFile = self.writeFeatures(font)
-        assert str(feaFile) == dedent(
+        assert dedent(str(feaFile)) == dedent(
             """\
             lookup kern_Latn {
                 lookupflag IgnoreMarks;
@@ -166,6 +166,11 @@ class KernFeatureWriterTest(FeatureWriterTest):
             } kern_Latn_marks;
 
             feature kern {
+                script DFLT;
+                language dflt;
+                lookup kern_Latn;
+                lookup kern_Latn_marks;
+                
                 script latn;
                 language dflt;
                 lookup kern_Latn;
@@ -175,7 +180,7 @@ class KernFeatureWriterTest(FeatureWriterTest):
         )
 
         feaFile = self.writeFeatures(font, ignoreMarks=False)
-        assert str(feaFile) == dedent(
+        assert dedent(str(feaFile)) == dedent(
             """\
             lookup kern_Latn {
                 pos A acutecomb -55;
@@ -183,6 +188,10 @@ class KernFeatureWriterTest(FeatureWriterTest):
             } kern_Latn;
 
             feature kern {
+                script DFLT;
+                language dflt;
+                lookup kern_Latn;
+                
                 script latn;
                 language dflt;
                 lookup kern_Latn;
@@ -567,6 +576,10 @@ class KernFeatureWriterTest(FeatureWriterTest):
             } kern_Arab;
 
             feature kern {
+                script DFLT;
+                language dflt;
+                lookup kern_Arab;
+
                 script arab;
                 language dflt;
                 lookup kern_Arab;
@@ -593,6 +606,11 @@ class KernFeatureWriterTest(FeatureWriterTest):
             } kern_Thaa;
 
             feature kern {
+                script DFLT;
+                language dflt;
+                lookup kern_Arab;
+                lookup kern_Thaa;
+
                 script arab;
                 language dflt;
                 lookup kern_Arab;
@@ -615,6 +633,10 @@ class KernFeatureWriterTest(FeatureWriterTest):
             } kern_Thaa;
 
             feature kern {
+                script DFLT;
+                language dflt;
+                lookup kern_Thaa;
+
                 script thaa;
                 language dflt;
                 lookup kern_Thaa;
@@ -664,6 +686,10 @@ class KernFeatureWriterTest(FeatureWriterTest):
             } kern_Latn;
 
             feature kern {
+                script DFLT;
+                language dflt;
+                lookup kern_Latn;
+
                 script latn;
                 language dflt;
                 lookup kern_Latn;
@@ -713,6 +739,10 @@ class KernFeatureWriterTest(FeatureWriterTest):
             } kern_Latn;
 
             feature kern {
+                script DFLT;
+                language dflt;
+                lookup kern_Latn;
+
                 script latn;
                 language dflt;
                 lookup kern_Latn;
@@ -807,6 +837,7 @@ class KernFeatureWriterTest(FeatureWriterTest):
                 script DFLT;
                 language dflt;
                 lookup kern_Default;
+                lookup kern_Latn;
 
                 script arab;
                 language dflt;
@@ -932,6 +963,8 @@ class KernFeatureWriterTest(FeatureWriterTest):
                 script DFLT;
                 language dflt;
                 lookup kern_Default;
+                lookup kern_Latn;
+                lookup kern_Latn_marks;
 
                 script arab;
                 language dflt;
@@ -1023,6 +1056,11 @@ class KernFeatureWriterTest(FeatureWriterTest):
             } kern_Arab_marks;
 
             feature kern {
+                script DFLT;
+                language dflt;
+                lookup kern_Arab;
+                lookup kern_Arab_marks;
+
                 script arab;
                 language dflt;
                 lookup kern_Arab;
@@ -1052,6 +1090,10 @@ class KernFeatureWriterTest(FeatureWriterTest):
             } kern_Latn;
 
             feature kern {
+                script DFLT;
+                language dflt;
+                lookup kern_Latn;
+ 
                 script arab;
                 language dflt;
                 lookup kern_Arab;
@@ -1260,6 +1302,7 @@ class KernFeatureWriterTest(FeatureWriterTest):
                 script DFLT;
                 language dflt;
                 lookup kern_Default;
+                lookup kern_Hebr;
 
                 script hebr;
                 language dflt;
@@ -1397,6 +1440,7 @@ def test_kern_split_multi_glyph_class(FontClass):
             script DFLT;
             language dflt;
             lookup kern_Default;
+            lookup kern_Latn;
 
             script latn;
             language dflt;
@@ -1480,6 +1524,11 @@ def test_kern_split_and_drop(FontClass, caplog):
         } kern_Orya;
 
         feature kern {
+            script DFLT;
+            language dflt;
+            lookup kern_Grek;
+            lookup kern_Latn;
+
             script grek;
             language dflt;
             lookup kern_Grek;
@@ -1538,6 +1587,10 @@ def test_kern_split_and_drop_mixed(caplog, FontClass):
         } kern_Latn;
 
         feature kern {
+            script DFLT;
+            language dflt;
+            lookup kern_Latn;
+
             script latn;
             language dflt;
             lookup kern_Latn;
@@ -1575,6 +1628,10 @@ def test_kern_split_and_mix_common(FontClass):
         } kern_Nkoo;
 
         feature kern {
+            script DFLT;
+            language dflt;
+            lookup kern_Latn;
+
             script latn;
             language dflt;
             lookup kern_Latn;
@@ -1639,6 +1696,11 @@ def test_kern_multi_script(FontClass):
         } kern_Nkoo;
 
         feature kern {
+            script DFLT;
+            language dflt;
+            lookup kern_Arab;
+            lookup kern_Nkoo;
+
             script arab;
             language dflt;
             lookup kern_Arab;
@@ -1707,6 +1769,7 @@ def test_kern_mixed_bidis(caplog, FontClass):
             script DFLT;
             language dflt;
             lookup kern_Default;
+            lookup kern_Latn;
 
             script arab;
             language dflt;
@@ -1825,6 +1888,9 @@ def test_kern_zyyy_zinh(FontClass):
             script DFLT;
             language dflt;
             lookup kern_Default;
+            lookup kern_Grek;
+            lookup kern_Hani;
+            lookup kern_Hrkt;
 
             script grek;
             language dflt;
@@ -1903,6 +1969,7 @@ def test_kern_hira_kana_hrkt(FontClass):
             script DFLT;
             language dflt;
             lookup kern_Default;
+            lookup kern_Hrkt;
 
             script kana;
             language dflt;
@@ -2164,6 +2231,7 @@ def test_dflt_language(FontClass):
             script DFLT;
             language dflt;
             lookup kern_Default;
+            lookup kern_Latn;
             language ZND;
 
             script latn;