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.misc.timeTools import timestampNow 6*e1fe3e4aSElliott Hughesfrom fontTools.ttLib.tables.DefaultTable import DefaultTable 7*e1fe3e4aSElliott Hughesfrom functools import reduce 8*e1fe3e4aSElliott Hughesimport operator 9*e1fe3e4aSElliott Hughesimport logging 10*e1fe3e4aSElliott Hughes 11*e1fe3e4aSElliott Hughes 12*e1fe3e4aSElliott Hugheslog = logging.getLogger("fontTools.merge") 13*e1fe3e4aSElliott Hughes 14*e1fe3e4aSElliott Hughes 15*e1fe3e4aSElliott Hughes# General utility functions for merging values from different fonts 16*e1fe3e4aSElliott Hughes 17*e1fe3e4aSElliott Hughes 18*e1fe3e4aSElliott Hughesdef equal(lst): 19*e1fe3e4aSElliott Hughes lst = list(lst) 20*e1fe3e4aSElliott Hughes t = iter(lst) 21*e1fe3e4aSElliott Hughes first = next(t) 22*e1fe3e4aSElliott Hughes assert all(item == first for item in t), "Expected all items to be equal: %s" % lst 23*e1fe3e4aSElliott Hughes return first 24*e1fe3e4aSElliott Hughes 25*e1fe3e4aSElliott Hughes 26*e1fe3e4aSElliott Hughesdef first(lst): 27*e1fe3e4aSElliott Hughes return next(iter(lst)) 28*e1fe3e4aSElliott Hughes 29*e1fe3e4aSElliott Hughes 30*e1fe3e4aSElliott Hughesdef recalculate(lst): 31*e1fe3e4aSElliott Hughes return NotImplemented 32*e1fe3e4aSElliott Hughes 33*e1fe3e4aSElliott Hughes 34*e1fe3e4aSElliott Hughesdef current_time(lst): 35*e1fe3e4aSElliott Hughes return timestampNow() 36*e1fe3e4aSElliott Hughes 37*e1fe3e4aSElliott Hughes 38*e1fe3e4aSElliott Hughesdef bitwise_and(lst): 39*e1fe3e4aSElliott Hughes return reduce(operator.and_, lst) 40*e1fe3e4aSElliott Hughes 41*e1fe3e4aSElliott Hughes 42*e1fe3e4aSElliott Hughesdef bitwise_or(lst): 43*e1fe3e4aSElliott Hughes return reduce(operator.or_, lst) 44*e1fe3e4aSElliott Hughes 45*e1fe3e4aSElliott Hughes 46*e1fe3e4aSElliott Hughesdef avg_int(lst): 47*e1fe3e4aSElliott Hughes lst = list(lst) 48*e1fe3e4aSElliott Hughes return sum(lst) // len(lst) 49*e1fe3e4aSElliott Hughes 50*e1fe3e4aSElliott Hughes 51*e1fe3e4aSElliott Hughesdef onlyExisting(func): 52*e1fe3e4aSElliott Hughes """Returns a filter func that when called with a list, 53*e1fe3e4aSElliott Hughes only calls func on the non-NotImplemented items of the list, 54*e1fe3e4aSElliott Hughes and only so if there's at least one item remaining. 55*e1fe3e4aSElliott Hughes Otherwise returns NotImplemented.""" 56*e1fe3e4aSElliott Hughes 57*e1fe3e4aSElliott Hughes def wrapper(lst): 58*e1fe3e4aSElliott Hughes items = [item for item in lst if item is not NotImplemented] 59*e1fe3e4aSElliott Hughes return func(items) if items else NotImplemented 60*e1fe3e4aSElliott Hughes 61*e1fe3e4aSElliott Hughes return wrapper 62*e1fe3e4aSElliott Hughes 63*e1fe3e4aSElliott Hughes 64*e1fe3e4aSElliott Hughesdef sumLists(lst): 65*e1fe3e4aSElliott Hughes l = [] 66*e1fe3e4aSElliott Hughes for item in lst: 67*e1fe3e4aSElliott Hughes l.extend(item) 68*e1fe3e4aSElliott Hughes return l 69*e1fe3e4aSElliott Hughes 70*e1fe3e4aSElliott Hughes 71*e1fe3e4aSElliott Hughesdef sumDicts(lst): 72*e1fe3e4aSElliott Hughes d = {} 73*e1fe3e4aSElliott Hughes for item in lst: 74*e1fe3e4aSElliott Hughes d.update(item) 75*e1fe3e4aSElliott Hughes return d 76*e1fe3e4aSElliott Hughes 77*e1fe3e4aSElliott Hughes 78*e1fe3e4aSElliott Hughesdef mergeBits(bitmap): 79*e1fe3e4aSElliott Hughes def wrapper(lst): 80*e1fe3e4aSElliott Hughes lst = list(lst) 81*e1fe3e4aSElliott Hughes returnValue = 0 82*e1fe3e4aSElliott Hughes for bitNumber in range(bitmap["size"]): 83*e1fe3e4aSElliott Hughes try: 84*e1fe3e4aSElliott Hughes mergeLogic = bitmap[bitNumber] 85*e1fe3e4aSElliott Hughes except KeyError: 86*e1fe3e4aSElliott Hughes try: 87*e1fe3e4aSElliott Hughes mergeLogic = bitmap["*"] 88*e1fe3e4aSElliott Hughes except KeyError: 89*e1fe3e4aSElliott Hughes raise Exception("Don't know how to merge bit %s" % bitNumber) 90*e1fe3e4aSElliott Hughes shiftedBit = 1 << bitNumber 91*e1fe3e4aSElliott Hughes mergedValue = mergeLogic(bool(item & shiftedBit) for item in lst) 92*e1fe3e4aSElliott Hughes returnValue |= mergedValue << bitNumber 93*e1fe3e4aSElliott Hughes return returnValue 94*e1fe3e4aSElliott Hughes 95*e1fe3e4aSElliott Hughes return wrapper 96*e1fe3e4aSElliott Hughes 97*e1fe3e4aSElliott Hughes 98*e1fe3e4aSElliott Hughesclass AttendanceRecordingIdentityDict(object): 99*e1fe3e4aSElliott Hughes """A dictionary-like object that records indices of items actually accessed 100*e1fe3e4aSElliott Hughes from a list.""" 101*e1fe3e4aSElliott Hughes 102*e1fe3e4aSElliott Hughes def __init__(self, lst): 103*e1fe3e4aSElliott Hughes self.l = lst 104*e1fe3e4aSElliott Hughes self.d = {id(v): i for i, v in enumerate(lst)} 105*e1fe3e4aSElliott Hughes self.s = set() 106*e1fe3e4aSElliott Hughes 107*e1fe3e4aSElliott Hughes def __getitem__(self, v): 108*e1fe3e4aSElliott Hughes self.s.add(self.d[id(v)]) 109*e1fe3e4aSElliott Hughes return v 110*e1fe3e4aSElliott Hughes 111*e1fe3e4aSElliott Hughes 112*e1fe3e4aSElliott Hughesclass GregariousIdentityDict(object): 113*e1fe3e4aSElliott Hughes """A dictionary-like object that welcomes guests without reservations and 114*e1fe3e4aSElliott Hughes adds them to the end of the guest list.""" 115*e1fe3e4aSElliott Hughes 116*e1fe3e4aSElliott Hughes def __init__(self, lst): 117*e1fe3e4aSElliott Hughes self.l = lst 118*e1fe3e4aSElliott Hughes self.s = set(id(v) for v in lst) 119*e1fe3e4aSElliott Hughes 120*e1fe3e4aSElliott Hughes def __getitem__(self, v): 121*e1fe3e4aSElliott Hughes if id(v) not in self.s: 122*e1fe3e4aSElliott Hughes self.s.add(id(v)) 123*e1fe3e4aSElliott Hughes self.l.append(v) 124*e1fe3e4aSElliott Hughes return v 125*e1fe3e4aSElliott Hughes 126*e1fe3e4aSElliott Hughes 127*e1fe3e4aSElliott Hughesclass NonhashableDict(object): 128*e1fe3e4aSElliott Hughes """A dictionary-like object mapping objects to values.""" 129*e1fe3e4aSElliott Hughes 130*e1fe3e4aSElliott Hughes def __init__(self, keys, values=None): 131*e1fe3e4aSElliott Hughes if values is None: 132*e1fe3e4aSElliott Hughes self.d = {id(v): i for i, v in enumerate(keys)} 133*e1fe3e4aSElliott Hughes else: 134*e1fe3e4aSElliott Hughes self.d = {id(k): v for k, v in zip(keys, values)} 135*e1fe3e4aSElliott Hughes 136*e1fe3e4aSElliott Hughes def __getitem__(self, k): 137*e1fe3e4aSElliott Hughes return self.d[id(k)] 138*e1fe3e4aSElliott Hughes 139*e1fe3e4aSElliott Hughes def __setitem__(self, k, v): 140*e1fe3e4aSElliott Hughes self.d[id(k)] = v 141*e1fe3e4aSElliott Hughes 142*e1fe3e4aSElliott Hughes def __delitem__(self, k): 143*e1fe3e4aSElliott Hughes del self.d[id(k)] 144