Skip to content

Commit

Permalink
Merge pull request #129 from googlefonts/fudge-layernames
Browse files Browse the repository at this point in the history
Work around layer name issue on case-insensitive file systems
  • Loading branch information
justvanrossum authored Nov 28, 2023
2 parents a15b705 + 955e3a4 commit 57d0121
Showing 1 changed file with 56 additions and 0 deletions.
56 changes: 56 additions & 0 deletions src/fontra_rcjk/backend_fs.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import json
import logging
import os
import pathlib

Expand All @@ -16,6 +17,8 @@
unpackAxes,
)

logger = logging.getLogger(__name__)

glyphSetNames = ["characterGlyph", "deepComponent", "atomicElement"]


Expand Down Expand Up @@ -118,6 +121,9 @@ def _populateGlyphCache(self, glyphName):
layerGlyphs = {}
for layerName, glifData in layerGLIFData:
layerGlyphs[layerName] = GLIFGlyph.fromGLIFData(glifData)

layerGlyphs = _fudgeLayerNames(glyphName, layerGlyphs)

self._tempGlyphCache[glyphName] = layerGlyphs

for compoName in layerGlyphs["foreground"].getComponentNames():
Expand Down Expand Up @@ -295,3 +301,53 @@ def deleteGlyph(self, glyphName):
layerPath.unlink()
self.registerWrittenPath(layerPath, deleted=True)
del self.glyphMap[glyphName]


def _fudgeLayerNames(glyphName, layerGlyphs):
#
# The rcjk format does not play well with case-insensitive file systems:
# layer names become folder names, and to read layer names we read folder
# names. Since layer names are global per font, case differences in layer
# names can cause ambiguities. For example, if a layer "s2" exists, a
# folder named "s2" will be written. If "S2" (cap S!) *also* exists, its
# data will be happily written to the "s2" folder on a case-insensitive
# file system. When reading back the project, we find "s2", but not "S2".
#
# The code below tries to detect that situation and work around it. This
# works as long as the layer names *within a single glyph* are not
# ambiguous: "S1" and "s1" should not co-exist in the same glyph.
#
# The problem can also happen when checking out an .rcjk git project on a
# case-insensitive file system: "S2" and "s2" may both exist in the repo,
# but on a macOS/Windows checkout only one of them will be seen.
#
usedLayerNames = set()
for varData in layerGlyphs["foreground"].lib.get("robocjk.variationGlyphs", []):
layerName = varData.get("layerName")
if layerName:
usedLayerNames.add(layerName)
missingLayerNames = usedLayerNames - set(layerGlyphs)

if not missingLayerNames:
return layerGlyphs

if len(usedLayerNames) != len(
{layerName.casefold() for layerName in usedLayerNames}
):
logger.warn(
f"Possible layer name conflict on case-insensitive file system ({glyphName})"
)
return layerGlyphs

renameMap = {}
availableLayerNames = {layerName.casefold(): layerName for layerName in layerGlyphs}
for missingLayerName in missingLayerNames:
folded = missingLayerName.casefold()
fudged = availableLayerNames.get(folded)
if fudged:
renameMap[fudged] = missingLayerName
if renameMap:
logger.warn(f"fudging layer names for {glyphName}: {renameMap}")
layerGlyphs = {renameMap.get(k, k): v for k, v in layerGlyphs.items()}

return layerGlyphs

0 comments on commit 57d0121

Please sign in to comment.