1*e1fe3e4aSElliott Hughes# Copyright 2013 Google, Inc. All Rights Reserved. 2*e1fe3e4aSElliott Hughes# 3*e1fe3e4aSElliott Hughes# Google Author(s): Behdad Esfahbod, Roozbeh Pournader 4*e1fe3e4aSElliott Hughes 5*e1fe3e4aSElliott Hughesfrom fontTools import ttLib, cffLib 6*e1fe3e4aSElliott Hughesfrom fontTools.misc.psCharStrings import T2WidthExtractor 7*e1fe3e4aSElliott Hughesfrom fontTools.ttLib.tables.DefaultTable import DefaultTable 8*e1fe3e4aSElliott Hughesfrom fontTools.merge.base import add_method, mergeObjects 9*e1fe3e4aSElliott Hughesfrom fontTools.merge.cmap import computeMegaCmap 10*e1fe3e4aSElliott Hughesfrom fontTools.merge.util import * 11*e1fe3e4aSElliott Hughesimport logging 12*e1fe3e4aSElliott Hughes 13*e1fe3e4aSElliott Hughes 14*e1fe3e4aSElliott Hugheslog = logging.getLogger("fontTools.merge") 15*e1fe3e4aSElliott Hughes 16*e1fe3e4aSElliott Hughes 17*e1fe3e4aSElliott HughesttLib.getTableClass("maxp").mergeMap = { 18*e1fe3e4aSElliott Hughes "*": max, 19*e1fe3e4aSElliott Hughes "tableTag": equal, 20*e1fe3e4aSElliott Hughes "tableVersion": equal, 21*e1fe3e4aSElliott Hughes "numGlyphs": sum, 22*e1fe3e4aSElliott Hughes "maxStorage": first, 23*e1fe3e4aSElliott Hughes "maxFunctionDefs": first, 24*e1fe3e4aSElliott Hughes "maxInstructionDefs": first, 25*e1fe3e4aSElliott Hughes # TODO When we correctly merge hinting data, update these values: 26*e1fe3e4aSElliott Hughes # maxFunctionDefs, maxInstructionDefs, maxSizeOfInstructions 27*e1fe3e4aSElliott Hughes} 28*e1fe3e4aSElliott Hughes 29*e1fe3e4aSElliott HughesheadFlagsMergeBitMap = { 30*e1fe3e4aSElliott Hughes "size": 16, 31*e1fe3e4aSElliott Hughes "*": bitwise_or, 32*e1fe3e4aSElliott Hughes 1: bitwise_and, # Baseline at y = 0 33*e1fe3e4aSElliott Hughes 2: bitwise_and, # lsb at x = 0 34*e1fe3e4aSElliott Hughes 3: bitwise_and, # Force ppem to integer values. FIXME? 35*e1fe3e4aSElliott Hughes 5: bitwise_and, # Font is vertical 36*e1fe3e4aSElliott Hughes 6: lambda bit: 0, # Always set to zero 37*e1fe3e4aSElliott Hughes 11: bitwise_and, # Font data is 'lossless' 38*e1fe3e4aSElliott Hughes 13: bitwise_and, # Optimized for ClearType 39*e1fe3e4aSElliott Hughes 14: bitwise_and, # Last resort font. FIXME? equal or first may be better 40*e1fe3e4aSElliott Hughes 15: lambda bit: 0, # Always set to zero 41*e1fe3e4aSElliott Hughes} 42*e1fe3e4aSElliott Hughes 43*e1fe3e4aSElliott HughesttLib.getTableClass("head").mergeMap = { 44*e1fe3e4aSElliott Hughes "tableTag": equal, 45*e1fe3e4aSElliott Hughes "tableVersion": max, 46*e1fe3e4aSElliott Hughes "fontRevision": max, 47*e1fe3e4aSElliott Hughes "checkSumAdjustment": lambda lst: 0, # We need *something* here 48*e1fe3e4aSElliott Hughes "magicNumber": equal, 49*e1fe3e4aSElliott Hughes "flags": mergeBits(headFlagsMergeBitMap), 50*e1fe3e4aSElliott Hughes "unitsPerEm": equal, 51*e1fe3e4aSElliott Hughes "created": current_time, 52*e1fe3e4aSElliott Hughes "modified": current_time, 53*e1fe3e4aSElliott Hughes "xMin": min, 54*e1fe3e4aSElliott Hughes "yMin": min, 55*e1fe3e4aSElliott Hughes "xMax": max, 56*e1fe3e4aSElliott Hughes "yMax": max, 57*e1fe3e4aSElliott Hughes "macStyle": first, 58*e1fe3e4aSElliott Hughes "lowestRecPPEM": max, 59*e1fe3e4aSElliott Hughes "fontDirectionHint": lambda lst: 2, 60*e1fe3e4aSElliott Hughes "indexToLocFormat": first, 61*e1fe3e4aSElliott Hughes "glyphDataFormat": equal, 62*e1fe3e4aSElliott Hughes} 63*e1fe3e4aSElliott Hughes 64*e1fe3e4aSElliott HughesttLib.getTableClass("hhea").mergeMap = { 65*e1fe3e4aSElliott Hughes "*": equal, 66*e1fe3e4aSElliott Hughes "tableTag": equal, 67*e1fe3e4aSElliott Hughes "tableVersion": max, 68*e1fe3e4aSElliott Hughes "ascent": max, 69*e1fe3e4aSElliott Hughes "descent": min, 70*e1fe3e4aSElliott Hughes "lineGap": max, 71*e1fe3e4aSElliott Hughes "advanceWidthMax": max, 72*e1fe3e4aSElliott Hughes "minLeftSideBearing": min, 73*e1fe3e4aSElliott Hughes "minRightSideBearing": min, 74*e1fe3e4aSElliott Hughes "xMaxExtent": max, 75*e1fe3e4aSElliott Hughes "caretSlopeRise": first, 76*e1fe3e4aSElliott Hughes "caretSlopeRun": first, 77*e1fe3e4aSElliott Hughes "caretOffset": first, 78*e1fe3e4aSElliott Hughes "numberOfHMetrics": recalculate, 79*e1fe3e4aSElliott Hughes} 80*e1fe3e4aSElliott Hughes 81*e1fe3e4aSElliott HughesttLib.getTableClass("vhea").mergeMap = { 82*e1fe3e4aSElliott Hughes "*": equal, 83*e1fe3e4aSElliott Hughes "tableTag": equal, 84*e1fe3e4aSElliott Hughes "tableVersion": max, 85*e1fe3e4aSElliott Hughes "ascent": max, 86*e1fe3e4aSElliott Hughes "descent": min, 87*e1fe3e4aSElliott Hughes "lineGap": max, 88*e1fe3e4aSElliott Hughes "advanceHeightMax": max, 89*e1fe3e4aSElliott Hughes "minTopSideBearing": min, 90*e1fe3e4aSElliott Hughes "minBottomSideBearing": min, 91*e1fe3e4aSElliott Hughes "yMaxExtent": max, 92*e1fe3e4aSElliott Hughes "caretSlopeRise": first, 93*e1fe3e4aSElliott Hughes "caretSlopeRun": first, 94*e1fe3e4aSElliott Hughes "caretOffset": first, 95*e1fe3e4aSElliott Hughes "numberOfVMetrics": recalculate, 96*e1fe3e4aSElliott Hughes} 97*e1fe3e4aSElliott Hughes 98*e1fe3e4aSElliott Hughesos2FsTypeMergeBitMap = { 99*e1fe3e4aSElliott Hughes "size": 16, 100*e1fe3e4aSElliott Hughes "*": lambda bit: 0, 101*e1fe3e4aSElliott Hughes 1: bitwise_or, # no embedding permitted 102*e1fe3e4aSElliott Hughes 2: bitwise_and, # allow previewing and printing documents 103*e1fe3e4aSElliott Hughes 3: bitwise_and, # allow editing documents 104*e1fe3e4aSElliott Hughes 8: bitwise_or, # no subsetting permitted 105*e1fe3e4aSElliott Hughes 9: bitwise_or, # no embedding of outlines permitted 106*e1fe3e4aSElliott Hughes} 107*e1fe3e4aSElliott Hughes 108*e1fe3e4aSElliott Hughes 109*e1fe3e4aSElliott Hughesdef mergeOs2FsType(lst): 110*e1fe3e4aSElliott Hughes lst = list(lst) 111*e1fe3e4aSElliott Hughes if all(item == 0 for item in lst): 112*e1fe3e4aSElliott Hughes return 0 113*e1fe3e4aSElliott Hughes 114*e1fe3e4aSElliott Hughes # Compute least restrictive logic for each fsType value 115*e1fe3e4aSElliott Hughes for i in range(len(lst)): 116*e1fe3e4aSElliott Hughes # unset bit 1 (no embedding permitted) if either bit 2 or 3 is set 117*e1fe3e4aSElliott Hughes if lst[i] & 0x000C: 118*e1fe3e4aSElliott Hughes lst[i] &= ~0x0002 119*e1fe3e4aSElliott Hughes # set bit 2 (allow previewing) if bit 3 is set (allow editing) 120*e1fe3e4aSElliott Hughes elif lst[i] & 0x0008: 121*e1fe3e4aSElliott Hughes lst[i] |= 0x0004 122*e1fe3e4aSElliott Hughes # set bits 2 and 3 if everything is allowed 123*e1fe3e4aSElliott Hughes elif lst[i] == 0: 124*e1fe3e4aSElliott Hughes lst[i] = 0x000C 125*e1fe3e4aSElliott Hughes 126*e1fe3e4aSElliott Hughes fsType = mergeBits(os2FsTypeMergeBitMap)(lst) 127*e1fe3e4aSElliott Hughes # unset bits 2 and 3 if bit 1 is set (some font is "no embedding") 128*e1fe3e4aSElliott Hughes if fsType & 0x0002: 129*e1fe3e4aSElliott Hughes fsType &= ~0x000C 130*e1fe3e4aSElliott Hughes return fsType 131*e1fe3e4aSElliott Hughes 132*e1fe3e4aSElliott Hughes 133*e1fe3e4aSElliott HughesttLib.getTableClass("OS/2").mergeMap = { 134*e1fe3e4aSElliott Hughes "*": first, 135*e1fe3e4aSElliott Hughes "tableTag": equal, 136*e1fe3e4aSElliott Hughes "version": max, 137*e1fe3e4aSElliott Hughes "xAvgCharWidth": first, # Will be recalculated at the end on the merged font 138*e1fe3e4aSElliott Hughes "fsType": mergeOs2FsType, # Will be overwritten 139*e1fe3e4aSElliott Hughes "panose": first, # FIXME: should really be the first Latin font 140*e1fe3e4aSElliott Hughes "ulUnicodeRange1": bitwise_or, 141*e1fe3e4aSElliott Hughes "ulUnicodeRange2": bitwise_or, 142*e1fe3e4aSElliott Hughes "ulUnicodeRange3": bitwise_or, 143*e1fe3e4aSElliott Hughes "ulUnicodeRange4": bitwise_or, 144*e1fe3e4aSElliott Hughes "fsFirstCharIndex": min, 145*e1fe3e4aSElliott Hughes "fsLastCharIndex": max, 146*e1fe3e4aSElliott Hughes "sTypoAscender": max, 147*e1fe3e4aSElliott Hughes "sTypoDescender": min, 148*e1fe3e4aSElliott Hughes "sTypoLineGap": max, 149*e1fe3e4aSElliott Hughes "usWinAscent": max, 150*e1fe3e4aSElliott Hughes "usWinDescent": max, 151*e1fe3e4aSElliott Hughes # Version 1 152*e1fe3e4aSElliott Hughes "ulCodePageRange1": onlyExisting(bitwise_or), 153*e1fe3e4aSElliott Hughes "ulCodePageRange2": onlyExisting(bitwise_or), 154*e1fe3e4aSElliott Hughes # Version 2, 3, 4 155*e1fe3e4aSElliott Hughes "sxHeight": onlyExisting(max), 156*e1fe3e4aSElliott Hughes "sCapHeight": onlyExisting(max), 157*e1fe3e4aSElliott Hughes "usDefaultChar": onlyExisting(first), 158*e1fe3e4aSElliott Hughes "usBreakChar": onlyExisting(first), 159*e1fe3e4aSElliott Hughes "usMaxContext": onlyExisting(max), 160*e1fe3e4aSElliott Hughes # version 5 161*e1fe3e4aSElliott Hughes "usLowerOpticalPointSize": onlyExisting(min), 162*e1fe3e4aSElliott Hughes "usUpperOpticalPointSize": onlyExisting(max), 163*e1fe3e4aSElliott Hughes} 164*e1fe3e4aSElliott Hughes 165*e1fe3e4aSElliott Hughes 166*e1fe3e4aSElliott Hughes@add_method(ttLib.getTableClass("OS/2")) 167*e1fe3e4aSElliott Hughesdef merge(self, m, tables): 168*e1fe3e4aSElliott Hughes DefaultTable.merge(self, m, tables) 169*e1fe3e4aSElliott Hughes if self.version < 2: 170*e1fe3e4aSElliott Hughes # bits 8 and 9 are reserved and should be set to zero 171*e1fe3e4aSElliott Hughes self.fsType &= ~0x0300 172*e1fe3e4aSElliott Hughes if self.version >= 3: 173*e1fe3e4aSElliott Hughes # Only one of bits 1, 2, and 3 may be set. We already take 174*e1fe3e4aSElliott Hughes # care of bit 1 implications in mergeOs2FsType. So unset 175*e1fe3e4aSElliott Hughes # bit 2 if bit 3 is already set. 176*e1fe3e4aSElliott Hughes if self.fsType & 0x0008: 177*e1fe3e4aSElliott Hughes self.fsType &= ~0x0004 178*e1fe3e4aSElliott Hughes return self 179*e1fe3e4aSElliott Hughes 180*e1fe3e4aSElliott Hughes 181*e1fe3e4aSElliott HughesttLib.getTableClass("post").mergeMap = { 182*e1fe3e4aSElliott Hughes "*": first, 183*e1fe3e4aSElliott Hughes "tableTag": equal, 184*e1fe3e4aSElliott Hughes "formatType": max, 185*e1fe3e4aSElliott Hughes "isFixedPitch": min, 186*e1fe3e4aSElliott Hughes "minMemType42": max, 187*e1fe3e4aSElliott Hughes "maxMemType42": lambda lst: 0, 188*e1fe3e4aSElliott Hughes "minMemType1": max, 189*e1fe3e4aSElliott Hughes "maxMemType1": lambda lst: 0, 190*e1fe3e4aSElliott Hughes "mapping": onlyExisting(sumDicts), 191*e1fe3e4aSElliott Hughes "extraNames": lambda lst: [], 192*e1fe3e4aSElliott Hughes} 193*e1fe3e4aSElliott Hughes 194*e1fe3e4aSElliott HughesttLib.getTableClass("vmtx").mergeMap = ttLib.getTableClass("hmtx").mergeMap = { 195*e1fe3e4aSElliott Hughes "tableTag": equal, 196*e1fe3e4aSElliott Hughes "metrics": sumDicts, 197*e1fe3e4aSElliott Hughes} 198*e1fe3e4aSElliott Hughes 199*e1fe3e4aSElliott HughesttLib.getTableClass("name").mergeMap = { 200*e1fe3e4aSElliott Hughes "tableTag": equal, 201*e1fe3e4aSElliott Hughes "names": first, # FIXME? Does mixing name records make sense? 202*e1fe3e4aSElliott Hughes} 203*e1fe3e4aSElliott Hughes 204*e1fe3e4aSElliott HughesttLib.getTableClass("loca").mergeMap = { 205*e1fe3e4aSElliott Hughes "*": recalculate, 206*e1fe3e4aSElliott Hughes "tableTag": equal, 207*e1fe3e4aSElliott Hughes} 208*e1fe3e4aSElliott Hughes 209*e1fe3e4aSElliott HughesttLib.getTableClass("glyf").mergeMap = { 210*e1fe3e4aSElliott Hughes "tableTag": equal, 211*e1fe3e4aSElliott Hughes "glyphs": sumDicts, 212*e1fe3e4aSElliott Hughes "glyphOrder": sumLists, 213*e1fe3e4aSElliott Hughes "_reverseGlyphOrder": recalculate, 214*e1fe3e4aSElliott Hughes "axisTags": equal, 215*e1fe3e4aSElliott Hughes} 216*e1fe3e4aSElliott Hughes 217*e1fe3e4aSElliott Hughes 218*e1fe3e4aSElliott Hughes@add_method(ttLib.getTableClass("glyf")) 219*e1fe3e4aSElliott Hughesdef merge(self, m, tables): 220*e1fe3e4aSElliott Hughes for i, table in enumerate(tables): 221*e1fe3e4aSElliott Hughes for g in table.glyphs.values(): 222*e1fe3e4aSElliott Hughes if i: 223*e1fe3e4aSElliott Hughes # Drop hints for all but first font, since 224*e1fe3e4aSElliott Hughes # we don't map functions / CVT values. 225*e1fe3e4aSElliott Hughes g.removeHinting() 226*e1fe3e4aSElliott Hughes # Expand composite glyphs to load their 227*e1fe3e4aSElliott Hughes # composite glyph names. 228*e1fe3e4aSElliott Hughes if g.isComposite() or g.isVarComposite(): 229*e1fe3e4aSElliott Hughes g.expand(table) 230*e1fe3e4aSElliott Hughes return DefaultTable.merge(self, m, tables) 231*e1fe3e4aSElliott Hughes 232*e1fe3e4aSElliott Hughes 233*e1fe3e4aSElliott HughesttLib.getTableClass("prep").mergeMap = lambda self, lst: first(lst) 234*e1fe3e4aSElliott HughesttLib.getTableClass("fpgm").mergeMap = lambda self, lst: first(lst) 235*e1fe3e4aSElliott HughesttLib.getTableClass("cvt ").mergeMap = lambda self, lst: first(lst) 236*e1fe3e4aSElliott HughesttLib.getTableClass("gasp").mergeMap = lambda self, lst: first( 237*e1fe3e4aSElliott Hughes lst 238*e1fe3e4aSElliott Hughes) # FIXME? Appears irreconcilable 239*e1fe3e4aSElliott Hughes 240*e1fe3e4aSElliott Hughes 241*e1fe3e4aSElliott Hughes@add_method(ttLib.getTableClass("CFF ")) 242*e1fe3e4aSElliott Hughesdef merge(self, m, tables): 243*e1fe3e4aSElliott Hughes if any(hasattr(table.cff[0], "FDSelect") for table in tables): 244*e1fe3e4aSElliott Hughes raise NotImplementedError("Merging CID-keyed CFF tables is not supported yet") 245*e1fe3e4aSElliott Hughes 246*e1fe3e4aSElliott Hughes for table in tables: 247*e1fe3e4aSElliott Hughes table.cff.desubroutinize() 248*e1fe3e4aSElliott Hughes 249*e1fe3e4aSElliott Hughes newcff = tables[0] 250*e1fe3e4aSElliott Hughes newfont = newcff.cff[0] 251*e1fe3e4aSElliott Hughes private = newfont.Private 252*e1fe3e4aSElliott Hughes newDefaultWidthX, newNominalWidthX = private.defaultWidthX, private.nominalWidthX 253*e1fe3e4aSElliott Hughes storedNamesStrings = [] 254*e1fe3e4aSElliott Hughes glyphOrderStrings = [] 255*e1fe3e4aSElliott Hughes glyphOrder = set(newfont.getGlyphOrder()) 256*e1fe3e4aSElliott Hughes 257*e1fe3e4aSElliott Hughes for name in newfont.strings.strings: 258*e1fe3e4aSElliott Hughes if name not in glyphOrder: 259*e1fe3e4aSElliott Hughes storedNamesStrings.append(name) 260*e1fe3e4aSElliott Hughes else: 261*e1fe3e4aSElliott Hughes glyphOrderStrings.append(name) 262*e1fe3e4aSElliott Hughes 263*e1fe3e4aSElliott Hughes chrset = list(newfont.charset) 264*e1fe3e4aSElliott Hughes newcs = newfont.CharStrings 265*e1fe3e4aSElliott Hughes log.debug("FONT 0 CharStrings: %d.", len(newcs)) 266*e1fe3e4aSElliott Hughes 267*e1fe3e4aSElliott Hughes for i, table in enumerate(tables[1:], start=1): 268*e1fe3e4aSElliott Hughes font = table.cff[0] 269*e1fe3e4aSElliott Hughes defaultWidthX, nominalWidthX = ( 270*e1fe3e4aSElliott Hughes font.Private.defaultWidthX, 271*e1fe3e4aSElliott Hughes font.Private.nominalWidthX, 272*e1fe3e4aSElliott Hughes ) 273*e1fe3e4aSElliott Hughes widthsDiffer = ( 274*e1fe3e4aSElliott Hughes defaultWidthX != newDefaultWidthX or nominalWidthX != newNominalWidthX 275*e1fe3e4aSElliott Hughes ) 276*e1fe3e4aSElliott Hughes font.Private = private 277*e1fe3e4aSElliott Hughes fontGlyphOrder = set(font.getGlyphOrder()) 278*e1fe3e4aSElliott Hughes for name in font.strings.strings: 279*e1fe3e4aSElliott Hughes if name in fontGlyphOrder: 280*e1fe3e4aSElliott Hughes glyphOrderStrings.append(name) 281*e1fe3e4aSElliott Hughes cs = font.CharStrings 282*e1fe3e4aSElliott Hughes gs = table.cff.GlobalSubrs 283*e1fe3e4aSElliott Hughes log.debug("Font %d CharStrings: %d.", i, len(cs)) 284*e1fe3e4aSElliott Hughes chrset.extend(font.charset) 285*e1fe3e4aSElliott Hughes if newcs.charStringsAreIndexed: 286*e1fe3e4aSElliott Hughes for i, name in enumerate(cs.charStrings, start=len(newcs)): 287*e1fe3e4aSElliott Hughes newcs.charStrings[name] = i 288*e1fe3e4aSElliott Hughes newcs.charStringsIndex.items.append(None) 289*e1fe3e4aSElliott Hughes for name in cs.charStrings: 290*e1fe3e4aSElliott Hughes if widthsDiffer: 291*e1fe3e4aSElliott Hughes c = cs[name] 292*e1fe3e4aSElliott Hughes defaultWidthXToken = object() 293*e1fe3e4aSElliott Hughes extractor = T2WidthExtractor([], [], nominalWidthX, defaultWidthXToken) 294*e1fe3e4aSElliott Hughes extractor.execute(c) 295*e1fe3e4aSElliott Hughes width = extractor.width 296*e1fe3e4aSElliott Hughes if width is not defaultWidthXToken: 297*e1fe3e4aSElliott Hughes c.program.pop(0) 298*e1fe3e4aSElliott Hughes else: 299*e1fe3e4aSElliott Hughes width = defaultWidthX 300*e1fe3e4aSElliott Hughes if width != newDefaultWidthX: 301*e1fe3e4aSElliott Hughes c.program.insert(0, width - newNominalWidthX) 302*e1fe3e4aSElliott Hughes newcs[name] = cs[name] 303*e1fe3e4aSElliott Hughes 304*e1fe3e4aSElliott Hughes newfont.charset = chrset 305*e1fe3e4aSElliott Hughes newfont.numGlyphs = len(chrset) 306*e1fe3e4aSElliott Hughes newfont.strings.strings = glyphOrderStrings + storedNamesStrings 307*e1fe3e4aSElliott Hughes 308*e1fe3e4aSElliott Hughes return newcff 309*e1fe3e4aSElliott Hughes 310*e1fe3e4aSElliott Hughes 311*e1fe3e4aSElliott Hughes@add_method(ttLib.getTableClass("cmap")) 312*e1fe3e4aSElliott Hughesdef merge(self, m, tables): 313*e1fe3e4aSElliott Hughes # TODO Handle format=14. 314*e1fe3e4aSElliott Hughes if not hasattr(m, "cmap"): 315*e1fe3e4aSElliott Hughes computeMegaCmap(m, tables) 316*e1fe3e4aSElliott Hughes cmap = m.cmap 317*e1fe3e4aSElliott Hughes 318*e1fe3e4aSElliott Hughes cmapBmpOnly = {uni: gid for uni, gid in cmap.items() if uni <= 0xFFFF} 319*e1fe3e4aSElliott Hughes self.tables = [] 320*e1fe3e4aSElliott Hughes module = ttLib.getTableModule("cmap") 321*e1fe3e4aSElliott Hughes if len(cmapBmpOnly) != len(cmap): 322*e1fe3e4aSElliott Hughes # format-12 required. 323*e1fe3e4aSElliott Hughes cmapTable = module.cmap_classes[12](12) 324*e1fe3e4aSElliott Hughes cmapTable.platformID = 3 325*e1fe3e4aSElliott Hughes cmapTable.platEncID = 10 326*e1fe3e4aSElliott Hughes cmapTable.language = 0 327*e1fe3e4aSElliott Hughes cmapTable.cmap = cmap 328*e1fe3e4aSElliott Hughes self.tables.append(cmapTable) 329*e1fe3e4aSElliott Hughes # always create format-4 330*e1fe3e4aSElliott Hughes cmapTable = module.cmap_classes[4](4) 331*e1fe3e4aSElliott Hughes cmapTable.platformID = 3 332*e1fe3e4aSElliott Hughes cmapTable.platEncID = 1 333*e1fe3e4aSElliott Hughes cmapTable.language = 0 334*e1fe3e4aSElliott Hughes cmapTable.cmap = cmapBmpOnly 335*e1fe3e4aSElliott Hughes # ordered by platform then encoding 336*e1fe3e4aSElliott Hughes self.tables.insert(0, cmapTable) 337*e1fe3e4aSElliott Hughes self.tableVersion = 0 338*e1fe3e4aSElliott Hughes self.numSubTables = len(self.tables) 339*e1fe3e4aSElliott Hughes return self 340