[AAT] Support gcid
table with glyph-to-CID mapping
This commit is contained in:
parent
ee1662e57e
commit
0f05f824d2
@ -60,6 +60,7 @@ def _moduleFinderHint():
|
||||
from . import _f_p_g_m
|
||||
from . import _f_v_a_r
|
||||
from . import _g_a_s_p
|
||||
from . import _g_c_i_d
|
||||
from . import _g_l_y_f
|
||||
from . import _g_v_a_r
|
||||
from . import _h_d_m_x
|
||||
|
8
Lib/fontTools/ttLib/tables/_g_c_i_d.py
Normal file
8
Lib/fontTools/ttLib/tables/_g_c_i_d.py
Normal file
@ -0,0 +1,8 @@
|
||||
from __future__ import print_function, division, absolute_import
|
||||
from fontTools.misc.py23 import *
|
||||
from .otBase import BaseTTXConverter
|
||||
|
||||
|
||||
# https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6gcid.html
|
||||
class table__g_c_i_d(BaseTTXConverter):
|
||||
pass
|
@ -5,7 +5,8 @@ from fontTools.misc.fixedTools import (
|
||||
versionToFixed as ve2fi)
|
||||
from fontTools.misc.textTools import pad, safeEval
|
||||
from fontTools.ttLib import getSearchRange
|
||||
from .otBase import ValueRecordFactory, CountReference, OTTableWriter
|
||||
from .otBase import (CountReference, FormatSwitchingBaseTable,
|
||||
OTTableWriter, ValueRecordFactory)
|
||||
from .otTables import (AATStateTable, AATState, AATAction,
|
||||
ContextualMorphAction)
|
||||
from functools import partial
|
||||
@ -42,6 +43,8 @@ def buildConverters(tableSpec, tableNamespace):
|
||||
converterClass = SubStruct
|
||||
elif name == "FeatureParams":
|
||||
converterClass = FeatureParams
|
||||
elif name == "GlyphCIDMapping":
|
||||
converterClass = StructWithLength
|
||||
else:
|
||||
if not tp in converterMapping and '(' not in tp:
|
||||
tableName = tp
|
||||
@ -461,6 +464,8 @@ class StructWithLength(Struct):
|
||||
if conv.name == "StructLength":
|
||||
break
|
||||
lengthIndex = len(writer.items) + convIndex
|
||||
if isinstance(value, FormatSwitchingBaseTable):
|
||||
lengthIndex += 1 # implicit Format field
|
||||
deadbeef = {1:0xDE, 2:0xDEAD, 4:0xDEADBEEF}[conv.staticSize]
|
||||
|
||||
before = writer.getDataLength()
|
||||
@ -1077,6 +1082,52 @@ class STXHeader(BaseConverter):
|
||||
return state
|
||||
|
||||
|
||||
class GlyphCIDMap(BaseConverter):
|
||||
def read(self, reader, font, tableDict):
|
||||
glyphOrder = font.getGlyphOrder()
|
||||
count = reader.readUShort()
|
||||
cids = reader.readUShortArray(count)
|
||||
if count > len(glyphOrder):
|
||||
log.warning("GlyphCIDMap has %d elements, "
|
||||
"but the font has only %d glyphs; "
|
||||
"ignoring the rest" %
|
||||
(count, len(glyphOrder)))
|
||||
result = {}
|
||||
for glyphID in range(min(len(cids), len(glyphOrder))):
|
||||
cid = cids[glyphID]
|
||||
if cid != 0xFFFF:
|
||||
result[glyphOrder[glyphID]] = cids[glyphID]
|
||||
return result
|
||||
|
||||
def write(self, writer, font, tableDict, value, repeatIndex=None):
|
||||
items = {font.getGlyphID(g): cid
|
||||
for g, cid in value.items()
|
||||
if cid is not None and cid != 0xFFFF}
|
||||
count = max(items) + 1 if items else 0
|
||||
writer.writeUShort(count)
|
||||
for glyphID in range(count):
|
||||
writer.writeUShort(items.get(glyphID, 0xFFFF))
|
||||
|
||||
def xmlRead(self, attrs, content, font):
|
||||
result = {}
|
||||
for eName, eAttrs, _eContent in filter(istuple, content):
|
||||
if eName == "CID":
|
||||
result[eAttrs["glyph"]] = \
|
||||
safeEval(eAttrs["value"])
|
||||
return result
|
||||
|
||||
def xmlWrite(self, xmlWriter, font, value, name, attrs):
|
||||
xmlWriter.begintag(name, attrs)
|
||||
xmlWriter.newline()
|
||||
for glyph, cid in sorted(value.items()):
|
||||
if cid is not None and cid != 0xFFFF:
|
||||
xmlWriter.simpletag(
|
||||
"CID", glyph=glyph, value=cid)
|
||||
xmlWriter.newline()
|
||||
xmlWriter.endtag(name)
|
||||
xmlWriter.newline()
|
||||
|
||||
|
||||
class DeltaValue(BaseConverter):
|
||||
|
||||
def read(self, reader, font, tableDict):
|
||||
@ -1243,6 +1294,7 @@ converterMapping = {
|
||||
"VarDataValue": VarDataValue,
|
||||
|
||||
# AAT
|
||||
"GlyphCIDMap": GlyphCIDMap,
|
||||
"MortChain": StructWithLength,
|
||||
"MortSubtable": StructWithLength,
|
||||
"MorxChain": StructWithLength,
|
||||
|
@ -1283,6 +1283,27 @@ otData = [
|
||||
]),
|
||||
|
||||
|
||||
#
|
||||
# gcid
|
||||
#
|
||||
|
||||
('gcid', [
|
||||
('struct', 'GlyphCIDMapping', None, None, 'Glyph to CID mapping table.'),
|
||||
]),
|
||||
|
||||
('GlyphCIDMappingFormat0', [
|
||||
('uint16', 'Format', None, None, 'Format of the glyph-to-CID mapping table, = 0.'),
|
||||
('uint16', 'DataFormat', None, None, 'Currenty unused, set to zero.'),
|
||||
('uint32', 'StructLength', None, None, 'Size of the table in bytes.'),
|
||||
('uint16', 'Registry', None, None, 'The registry ID.'),
|
||||
('char64', 'RegistryName', None, None, 'The registry name in ASCII; unused bytes should be set to 0.'),
|
||||
('uint16', 'Order', None, None, 'The order ID.'),
|
||||
('char64', 'OrderName', None, None, 'The order name in ASCII; unused bytes should be set to 0.'),
|
||||
('uint16', 'SupplementVersion', None, None, 'The supplement version.'),
|
||||
('GlyphCIDMap', 'CIDs', None, None, 'The CIDs for the glyphs in the font, starting with glyph 0. If a glyph does not correspond to a CID in the identified collection, 0xFFFF is used'),
|
||||
]),
|
||||
|
||||
|
||||
#
|
||||
# lcar
|
||||
#
|
||||
|
@ -101,9 +101,9 @@ The following tables are currently supported:
|
||||
GDEF, GMAP, GPKG, GPOS, GSUB, HVAR, JSTF, LTSH, MATH, META, MVAR,
|
||||
OS/2, SING, STAT, SVG, TSI0, TSI1, TSI2, TSI3, TSI5, TSIB, TSID,
|
||||
TSIJ, TSIP, TSIS, TSIV, TTFA, VDMX, VORG, VVAR, ankr, avar, bsln,
|
||||
cmap, cvar, cvt, feat, fpgm, fvar, gasp, glyf, gvar, hdmx, head,
|
||||
hhea, hmtx, kern, lcar, loca, ltag, maxp, meta, mort, morx, name,
|
||||
opbd, post, prep, prop, sbix, trak, vhea and vmtx
|
||||
cmap, cvar, cvt, feat, fpgm, fvar, gasp, gcid, glyf, gvar, hdmx,
|
||||
head, hhea, hmtx, kern, lcar, loca, ltag, maxp, meta, mort, morx,
|
||||
name, opbd, post, prep, prop, sbix, trak, vhea and vmtx
|
||||
.. end table list
|
||||
|
||||
Other tables are dumped as hexadecimal data.
|
||||
|
70
Tests/ttLib/tables/_g_c_i_d_test.py
Normal file
70
Tests/ttLib/tables/_g_c_i_d_test.py
Normal file
@ -0,0 +1,70 @@
|
||||
# coding: utf-8
|
||||
from __future__ import print_function, division, absolute_import, unicode_literals
|
||||
from fontTools.misc.py23 import *
|
||||
from fontTools.misc.testTools import FakeFont, getXML, parseXML
|
||||
from fontTools.misc.textTools import deHexStr, hexStr
|
||||
from fontTools.ttLib import newTable
|
||||
import unittest
|
||||
|
||||
|
||||
# On macOS X 10.12.3, the font /Library/Fonts/AppleGothic.ttf has a ‘gcid’
|
||||
# table with a similar structure as this test data, just more CIDs.
|
||||
GCID_DATA = deHexStr(
|
||||
"0000 0000 " # 0: Format=0, Flags=0
|
||||
"0000 0098 " # 4: Size=152
|
||||
"0000 " # 8: Registry=0
|
||||
"41 64 6F 62 65 " # 10: RegistryName="Adobe"
|
||||
+ ("00" * 59) + # 15: <padding>
|
||||
"0003 " # 74: Order=3
|
||||
"4B 6F 72 65 61 31 " # 76: Order="Korea1"
|
||||
+ ("00" * 58) + # 82: <padding>
|
||||
"0001 " # 140: SupplementVersion
|
||||
"0004 " # 142: Count
|
||||
"1234 " # 144: CIDs[0/.notdef]=4660
|
||||
"FFFF " # 146: CIDs[1/A]=None
|
||||
"0007 " # 148: CIDs[2/B]=7
|
||||
"DEF0 " # 150: CIDs[3/C]=57072
|
||||
) # 152: <end>
|
||||
assert len(GCID_DATA) == 152, len(GCID_DATA)
|
||||
|
||||
|
||||
GCID_XML = [
|
||||
'<GlyphCIDMapping Format="0">',
|
||||
' <DataFormat value="0"/>',
|
||||
' <!-- StructLength=152 -->',
|
||||
' <Registry value="0"/>',
|
||||
' <RegistryName value="Adobe"/>',
|
||||
' <Order value="3"/>',
|
||||
' <OrderName value="Korea1"/>',
|
||||
' <SupplementVersion value="1"/>',
|
||||
' <CIDs>',
|
||||
' <CID glyph=".notdef" value="4660"/>',
|
||||
' <CID glyph="B" value="7"/>',
|
||||
' <CID glyph="C" value="57072"/>',
|
||||
' </CIDs>',
|
||||
'</GlyphCIDMapping>',
|
||||
]
|
||||
|
||||
|
||||
class GCIDTest(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.maxDiff = None
|
||||
cls.font = FakeFont(['.notdef', 'A', 'B', 'C', 'D'])
|
||||
|
||||
def testDecompileToXML(self):
|
||||
table = newTable('gcid')
|
||||
table.decompile(GCID_DATA, self.font)
|
||||
self.assertEqual(getXML(table.toXML, self.font), GCID_XML)
|
||||
|
||||
def testCompileFromXML(self):
|
||||
table = newTable('gcid')
|
||||
for name, attrs, content in parseXML(GCID_XML):
|
||||
table.fromXML(name, attrs, content, font=self.font)
|
||||
self.assertEqual(hexStr(table.compile(self.font)),
|
||||
hexStr(GCID_DATA))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
sys.exit(unittest.main())
|
Loading…
x
Reference in New Issue
Block a user