[merge] Update 'head', 'hhea', 'OS/2', and 'post' tables with new logic.
diff --git a/Lib/fontTools/merge.py b/Lib/fontTools/merge.py
index 5c926da..03c066d 100644
--- a/Lib/fontTools/merge.py
+++ b/Lib/fontTools/merge.py
@@ -8,7 +8,7 @@
from __future__ import print_function, division
from fontTools.misc.py23 import *
from fontTools import ttLib, cffLib
-from fontTools.ttLib.tables import otTables
+from fontTools.ttLib.tables import otTables, _h_e_a_d
from functools import reduce
import sys
import time
@@ -31,10 +31,26 @@
def assert_equal(lst):
first = lst[0]
assert all([item == first for item in lst])
+ return first
def first(lst):
return lst[0]
+def recalculate(lst):
+ # Just return the first value, assume will be recalculated when saved
+ return lst[0]
+
+def current_time(lst):
+ return long(time.time() - _h_e_a_d.mac_epoch_diff)
+
+def bitwise_or(lst):
+ ret = 0
+ for item in lst:
+ ret |= item
+ return ret
+
+def ignore(lst):
+ assert False, "This function should not be called."
@_add_method(ttLib.getTableClass('maxp'))
def merge(self, m):
@@ -53,74 +69,88 @@
@_add_method(ttLib.getTableClass('head'))
def merge(self, m):
- # TODO Check that unitsPerEm are the same.
- # TODO Use bitwise ops for flags, macStyle, fontDirectionHint
- minMembers = ['xMin', 'yMin']
- # Negate some members
- for key in minMembers:
- for table in m.tables:
- setattr(table, key, -getattr(table, key))
- # Get max over members
- allKeys = reduce(set.union, (list(vars(table).keys()) for table in m.tables), set())
- for key in allKeys:
- setattr(self, key, max(getattr(table, key) for table in m.tables))
- # Negate them back
- for key in minMembers:
- for table in m.tables:
- setattr(table, key, -getattr(table, key))
- setattr(self, key, -getattr(self, key))
+ logic = {
+ 'tableVersion': max,
+ 'fontRevision': max,
+ 'checkSumAdjustment': recalculate,
+ 'magicNumber': assert_equal,
+ 'flags': first, # FIXME: replace with bit-sensitive code
+ 'unitsPerEm': assert_equal,
+ 'created': current_time,
+ 'modified': current_time,
+ 'xMin': min,
+ 'yMin': min,
+ 'xMax': max,
+ 'yMax': max,
+ 'macStyle': first,
+ 'lowestRecPPEM': max,
+ 'fontDirectionHint': lambda lst: 2,
+ 'indexToLocFormat': recalculate,
+ 'glyphDataFormat': assert_equal,
+ }
+ m._mergeKeys(self, logic)
return True
@_add_method(ttLib.getTableClass('hhea'))
def merge(self, m):
- # TODO Check that ascent, descent, slope, etc are the same.
- minMembers = ['descent', 'minLeftSideBearing', 'minRightSideBearing']
- # Negate some members
- for key in minMembers:
- for table in m.tables:
- setattr(table, key, -getattr(table, key))
- # Get max over members
- allKeys = reduce(set.union, (list(vars(table).keys()) for table in m.tables), set())
- for key in allKeys:
- setattr(self, key, max(getattr(table, key) for table in m.tables))
- # Negate them back
- for key in minMembers:
- for table in m.tables:
- setattr(table, key, -getattr(table, key))
- setattr(self, key, -getattr(self, key))
+ logic = {
+ '*': assert_equal,
+ 'tableVersion': max,
+ 'ascent': max,
+ 'descent': min,
+ 'lineGap': max,
+ 'advanceWidthMax': max,
+ 'minLeftSideBearing': min,
+ 'minRightSideBearing': min,
+ 'xMaxExtent': max,
+ 'caretSlopeRise': first, # FIXME
+ 'caretSlopeRun': first, # FIXME
+ 'caretOffset': first, # FIXME
+ 'numberOfHMetrics': recalculate,
+ }
+ m._mergeKeys(self, logic)
return True
@_add_method(ttLib.getTableClass('OS/2'))
def merge(self, m):
- # TODO Check that weight/width/subscript/superscript/etc are the same.
- # TODO Bitwise ops for UnicodeRange/CodePageRange.
- # TODO Pretty much all fields generated here have bogus values.
- # Get max over members
- allKeys = reduce(set.union, (list(vars(table).keys()) for table in m.tables), set())
- for key in allKeys:
- setattr(self, key, max(getattr(table, key) for table in m.tables))
+ logic = {
+ '*': first,
+ 'version': max,
+ 'xAvgCharWidth': recalculate,
+ 'fsType': first, # FIXME
+ 'panose': first, # FIXME?
+ 'ulUnicodeRange1': bitwise_or,
+ 'ulUnicodeRange2': bitwise_or,
+ 'ulUnicodeRange3': bitwise_or,
+ 'ulUnicodeRange4': bitwise_or,
+ 'fsFirstCharIndex': min,
+ 'fsLastCharIndex': max,
+ 'sTypoAscender': max,
+ 'sTypoDescender': min,
+ 'sTypoLineGap': max,
+ 'usWinAscent': max,
+ 'usWinDescent': max,
+ 'ulCodePageRange1': bitwise_or,
+ 'ulCodePageRange2': bitwise_or,
+ 'usMaxContex': max,
+ }
+ m._mergeKeys(self, logic)
return True
@_add_method(ttLib.getTableClass('post'))
def merge(self, m):
- # TODO Check that italicAngle, underlinePosition, underlineThickness are the same.
- minMembers = ['underlinePosition', 'minMemType42', 'minMemType1']
- # Negate some members
- for key in minMembers:
- for table in m.tables:
- setattr(table, key, -getattr(table, key))
- # Get max over members
- allKeys = reduce(set.union, (list(vars(table).keys()) for table in m.tables), set())
- if 'mapping' in allKeys:
- allKeys.remove('mapping')
- allKeys.remove('extraNames')
- for key in allKeys:
- setattr(self, key, max(getattr(table, key) for table in m.tables))
- # Negate them back
- for key in minMembers:
- for table in m.tables:
- setattr(table, key, -getattr(table, key))
- setattr(self, key, -getattr(self, key))
+ logic = {
+ '*': first,
+ 'formatType': max,
+ 'isFixedPitch': min,
+ 'minMemType42': max,
+ 'maxMemType42': lambda lst: 0,
+ 'minMemType1': max,
+ 'maxMemType1': lambda lst: 0,
+ 'mapping': ignore,
+ 'extraNames': ignore
+ }
+ m._mergeKeys(self, logic)
self.mapping = {}
for table in m.tables:
if hasattr(table, 'mapping'):
@@ -400,7 +430,12 @@
logic['tableTag'] = assert_equal
allKeys = set.union(set(), *(vars(table).keys() for table in self.tables))
for key in allKeys:
- merge_logic = logic.get(key, logic['*'])
+ try:
+ merge_logic = logic[key]
+ except KeyError:
+ merge_logic = logic['*']
+ if merge_logic == ignore:
+ continue
key_value = merge_logic([getattr(table, key) for table in self.tables])
setattr(return_table, key, key_value)