95
100
glyphs.append(attrs["value"])
103
class LookupList(BaseTable):
104
def preCompile(self):
105
""" This function is used to optimize writing out extension subtables. This is useful
106
when a font has been read in, modified, and we are now writing out a new version. If the
107
the extension subtables have not been touched (proof being that they have not been decompiled)
108
then we can write them out using the original data, and do not have to recompile them. This can save
109
20-30% of the compile time for fonts with large extension tables, such as Japanese Pro fonts."""
111
if hasattr(self, 'LookupCount'): #not defined if loading from xml
112
lookupCount = self.LookupCount
114
return # The optimization of not recompiling extension lookup subtables is not possible
115
# when reading from XML.
117
liRange = range(lookupCount)
120
lookup = self.Lookup[li]
121
if hasattr(lookup, 'SubTableCount'): #not defined if loading from xml
122
subtableCount = lookup.SubTableCount
124
subtableCount = len(lookup.SubTable)
125
siRange = range(subtableCount)
127
subtable = lookup.SubTable[si]
128
if hasattr(subtable, 'ExtSubTable'):
129
extTable = subtable.ExtSubTable
130
extTables.append([extTable.start, extTable] )
132
# Since offsets in one subtable can and do point forward into later
133
# subtables, we can afford to simply copy data only for the last subtables
134
# which were not decompiled. So we start figuring out the
135
# data segments starting with the last subtTable, and work our way towards
136
# the first subtable, and then quit as soon as we see a subtable that was decompiled.
140
lastTable = extTables[0][1]
141
if lastTable.compileStatus == 1:
142
lastTable.end = len(lastTable.reader.data)
143
lastTable.compileStatus = 3
144
for i in range(1, len(extTables)):
145
extTable = extTables[i][1]
146
if extTable.compileStatus != 1:
148
extTable.end = lastTable.start
149
extTable.compileStatus = 3
98
157
class SingleSubst(FormatSwitchingBaseTable):
100
159
def postRead(self, rawTable, font):
102
161
input = _getGlyphsFromCoverageTable(rawTable["Coverage"])
162
lenMapping = len(input)
103
163
if self.Format == 1:
104
164
delta = rawTable["DeltaGlyphID"]
105
for inGlyph in input:
106
glyphID = font.getGlyphID(inGlyph)
107
mapping[inGlyph] = font.getGlyphName(glyphID + delta)
165
inputGIDS = [ font.getGlyphID(name) for name in input ]
166
inputGIDS = map(doModulo, inputGIDS)
167
outGIDS = [ glyphID + delta for glyphID in inputGIDS ]
168
outGIDS = map(doModulo, outGIDS)
169
outNames = [ font.getGlyphName(glyphID) for glyphID in outGIDS ]
170
map(operator.setitem, [mapping]*lenMapping, input, outNames)
108
171
elif self.Format == 2:
109
172
assert len(input) == rawTable["GlyphCount"], \
110
173
"invalid SingleSubstFormat2 table"
111
174
subst = rawTable["Substitute"]
112
for i in range(len(input)):
113
mapping[input[i]] = subst[i]
175
map(operator.setitem, [mapping]*lenMapping, input, subst)
115
177
assert 0, "unknown format: %s" % self.Format
116
178
self.mapping = mapping
400
477
'JstfMax': ('ShrinkageJstfMax', 'ExtensionJstfMax',),
481
# OverFlow logic, to automatically create ExtensionLookups
482
# XXX This should probably move to otBase.py
485
def fixLookupOverFlows(ttf, overflowRecord):
486
""" Either the offset from the LookupList to a lookup overflowed, or
487
an offset from a lookup to a subtable overflowed.
493
Lookup[0] and contents
495
SubTable[0] and contents
497
SubTable[n] and contents
499
Lookup[n] and contents
501
SubTable[0] and contents
503
SubTable[n] and contents
504
If the offset to a lookup overflowed (SubTableIndex == None)
505
we must promote the *previous* lookup to an Extension type.
506
If the offset from a lookup to subtable overflowed, then we must promote it
507
to an Extension Lookup type.
510
lookupIndex = overflowRecord.LookupListIndex
511
if (overflowRecord.SubTableIndex == None):
512
lookupIndex = lookupIndex - 1
515
if overflowRecord.tableType == 'GSUB':
517
elif overflowRecord.tableType == 'GPOS':
520
lookups = ttf[overflowRecord.tableType].table.LookupList.Lookup
521
lookup = lookups[lookupIndex]
522
# If the previous lookup is an extType, look further back. Very unlikely, but possible.
523
while lookup.LookupType == extType:
524
lookupIndex = lookupIndex -1
527
lookup = lookups[lookupIndex]
529
for si in range(len(lookup.SubTable)):
530
subTable = lookup.SubTable[si]
531
extSubTableClass = lookupTypes[overflowRecord.tableType][extType]
532
extSubTable = extSubTableClass()
533
extSubTable.Format = 1
534
extSubTable.ExtensionLookupType = lookup.LookupType
535
extSubTable.ExtSubTable = subTable
536
lookup.SubTable[si] = extSubTable
537
lookup.LookupType = extType
541
def splitAlternateSubst(oldSubTable, newSubTable, overflowRecord):
543
newSubTable.Format = oldSubTable.Format
544
if hasattr(oldSubTable, 'sortCoverageLast'):
545
newSubTable.sortCoverageLast = oldSubTable.sortCoverageLast
547
oldAlts = oldSubTable.alternates.items()
549
oldLen = len(oldAlts)
551
if overflowRecord.itemName in [ 'Coverage', 'RangeRecord']:
552
# Coverage table is written last. overflow is to or within the
553
# the coverage table. We will just cut the subtable in half.
554
newLen = int(oldLen/2)
556
elif overflowRecord.itemName == 'AlternateSet':
557
# We just need to back up by two items
558
# from the overflowed AlternateSet index to make sure the offset
559
# to the Coverage table doesn't overflow.
560
newLen = overflowRecord.itemIndex - 1
562
newSubTable.alternates = {}
563
for i in range(newLen, oldLen):
566
newSubTable.alternates[key] = item[1]
567
del oldSubTable.alternates[key]
573
def splitLigatureSubst(oldSubTable, newSubTable, overflowRecord):
575
newSubTable.Format = oldSubTable.Format
576
oldLigs = oldSubTable.ligatures.items()
578
oldLen = len(oldLigs)
580
if overflowRecord.itemName in [ 'Coverage', 'RangeRecord']:
581
# Coverage table is written last. overflow is to or within the
582
# the coverage table. We will just cut the subtable in half.
583
newLen = int(oldLen/2)
585
elif overflowRecord.itemName == 'LigatureSet':
586
# We just need to back up by two items
587
# from the overflowed AlternateSet index to make sure the offset
588
# to the Coverage table doesn't overflow.
589
newLen = overflowRecord.itemIndex - 1
591
newSubTable.ligatures = {}
592
for i in range(newLen, oldLen):
595
newSubTable.ligatures[key] = item[1]
596
del oldSubTable.ligatures[key]
601
splitTable = { 'GSUB': {
602
# 1: splitSingleSubst,
603
# 2: splitMultipleSubst,
604
3: splitAlternateSubst,
605
4: splitLigatureSubst,
606
# 5: splitContextSubst,
607
# 6: splitChainContextSubst,
608
# 7: splitExtensionSubst,
609
# 8: splitReverseChainSingleSubst,
614
# 3: splitCursivePos,
615
# 4: splitMarkBasePos,
616
# 5: splitMarkLigPos,
617
# 6: splitMarkMarkPos,
618
# 7: splitContextPos,
619
# 8: splitChainContextPos,
620
# 9: splitExtensionPos,
625
def fixSubTableOverFlows(ttf, overflowRecord):
627
An offset has overflowed within a sub-table. We need to divide this subtable into smaller parts.
630
table = ttf[overflowRecord.tableType].table
631
lookup = table.LookupList.Lookup[overflowRecord.LookupListIndex]
632
subIndex = overflowRecord.SubTableIndex
633
subtable = lookup.SubTable[subIndex]
635
if hasattr(subtable, 'ExtSubTable'):
636
# We split the subtable of the Extension table, and add a new Extension table
637
# to contain the new subtable.
639
subTableType = subtable.ExtensionLookupType
640
extSubTable = subtable
641
subtable = extSubTable.ExtSubTable
642
newExtSubTableClass = lookupTypes[overflowRecord.tableType][lookup.LookupType]
643
newExtSubTable = newExtSubTableClass()
644
newExtSubTable.Format = extSubTable.Format
645
newExtSubTable.ExtensionLookupType = extSubTable.ExtensionLookupType
646
lookup.SubTable.insert(subIndex + 1, newExtSubTable)
648
newSubTableClass = lookupTypes[overflowRecord.tableType][subTableType]
649
newSubTable = newSubTableClass()
650
newExtSubTable.ExtSubTable = newSubTable
652
subTableType = lookup.LookupType
653
newSubTableClass = lookupTypes[overflowRecord.tableType][subTableType]
654
newSubTable = newSubTableClass()
655
lookup.SubTable.insert(subIndex + 1, newSubTable)
657
if hasattr(lookup, 'SubTableCount'): # may not be defined yet.
658
lookup.SubTableCount = lookup.SubTableCount + 1
661
splitFunc = splitTable[overflowRecord.tableType][subTableType]
665
ok = splitFunc(subtable, newSubTable, overflowRecord)
668
# End of OverFlow logic
404
671
def _buildClasses():