Spaces:
Running
Running
File size: 5,545 Bytes
b72ab63 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
# Copyright 2013 Google, Inc. All Rights Reserved.
#
# Google Author(s): Behdad Esfahbod, Roozbeh Pournader
from fontTools.merge.unicode import is_Default_Ignorable
from fontTools.pens.recordingPen import DecomposingRecordingPen
import logging
log = logging.getLogger("fontTools.merge")
def computeMegaGlyphOrder(merger, glyphOrders):
"""Modifies passed-in glyphOrders to reflect new glyph names.
Stores merger.glyphOrder."""
megaOrder = {}
for glyphOrder in glyphOrders:
for i, glyphName in enumerate(glyphOrder):
if glyphName in megaOrder:
n = megaOrder[glyphName]
while (glyphName + "." + repr(n)) in megaOrder:
n += 1
megaOrder[glyphName] = n
glyphName += "." + repr(n)
glyphOrder[i] = glyphName
megaOrder[glyphName] = 1
merger.glyphOrder = megaOrder = list(megaOrder.keys())
def _glyphsAreSame(
glyphSet1,
glyphSet2,
glyph1,
glyph2,
advanceTolerance=0.05,
advanceToleranceEmpty=0.20,
):
pen1 = DecomposingRecordingPen(glyphSet1)
pen2 = DecomposingRecordingPen(glyphSet2)
g1 = glyphSet1[glyph1]
g2 = glyphSet2[glyph2]
g1.draw(pen1)
g2.draw(pen2)
if pen1.value != pen2.value:
return False
# Allow more width tolerance for glyphs with no ink
tolerance = advanceTolerance if pen1.value else advanceToleranceEmpty
# TODO Warn if advances not the same but within tolerance.
if abs(g1.width - g2.width) > g1.width * tolerance:
return False
if hasattr(g1, "height") and g1.height is not None:
if abs(g1.height - g2.height) > g1.height * tolerance:
return False
return True
# Valid (format, platformID, platEncID) triplets for cmap subtables containing
# Unicode BMP-only and Unicode Full Repertoire semantics.
# Cf. OpenType spec for "Platform specific encodings":
# https://docs.microsoft.com/en-us/typography/opentype/spec/name
class _CmapUnicodePlatEncodings:
BMP = {(4, 3, 1), (4, 0, 3), (4, 0, 4), (4, 0, 6)}
FullRepertoire = {(12, 3, 10), (12, 0, 4), (12, 0, 6)}
def computeMegaCmap(merger, cmapTables):
"""Sets merger.cmap and merger.glyphOrder."""
# TODO Handle format=14.
# Only merge format 4 and 12 Unicode subtables, ignores all other subtables
# If there is a format 12 table for a font, ignore the format 4 table of it
chosenCmapTables = []
for fontIdx, table in enumerate(cmapTables):
format4 = None
format12 = None
for subtable in table.tables:
properties = (subtable.format, subtable.platformID, subtable.platEncID)
if properties in _CmapUnicodePlatEncodings.BMP:
format4 = subtable
elif properties in _CmapUnicodePlatEncodings.FullRepertoire:
format12 = subtable
else:
log.warning(
"Dropped cmap subtable from font '%s':\t"
"format %2s, platformID %2s, platEncID %2s",
fontIdx,
subtable.format,
subtable.platformID,
subtable.platEncID,
)
if format12 is not None:
chosenCmapTables.append((format12, fontIdx))
elif format4 is not None:
chosenCmapTables.append((format4, fontIdx))
# Build the unicode mapping
merger.cmap = cmap = {}
fontIndexForGlyph = {}
glyphSets = [None for f in merger.fonts] if hasattr(merger, "fonts") else None
for table, fontIdx in chosenCmapTables:
# handle duplicates
for uni, gid in table.cmap.items():
oldgid = cmap.get(uni, None)
if oldgid is None:
cmap[uni] = gid
fontIndexForGlyph[gid] = fontIdx
elif is_Default_Ignorable(uni) or uni in (0x25CC,): # U+25CC DOTTED CIRCLE
continue
elif oldgid != gid:
# Char previously mapped to oldgid, now to gid.
# Record, to fix up in GSUB 'locl' later.
if merger.duplicateGlyphsPerFont[fontIdx].get(oldgid) is None:
if glyphSets is not None:
oldFontIdx = fontIndexForGlyph[oldgid]
for idx in (fontIdx, oldFontIdx):
if glyphSets[idx] is None:
glyphSets[idx] = merger.fonts[idx].getGlyphSet()
# if _glyphsAreSame(glyphSets[oldFontIdx], glyphSets[fontIdx], oldgid, gid):
# continue
merger.duplicateGlyphsPerFont[fontIdx][oldgid] = gid
elif merger.duplicateGlyphsPerFont[fontIdx][oldgid] != gid:
# Char previously mapped to oldgid but oldgid is already remapped to a different
# gid, because of another Unicode character.
# TODO: Try harder to do something about these.
log.warning(
"Dropped mapping from codepoint %#06X to glyphId '%s'", uni, gid
)
def renameCFFCharStrings(merger, glyphOrder, cffTable):
"""Rename topDictIndex charStrings based on glyphOrder."""
td = cffTable.cff.topDictIndex[0]
charStrings = {}
for i, v in enumerate(td.CharStrings.charStrings.values()):
glyphName = glyphOrder[i]
charStrings[glyphName] = v
td.CharStrings.charStrings = charStrings
td.charset = list(glyphOrder)
|