Esempio n. 1
0
    def buildBinary(self, w, **kwArgs):
        """
        Adds the binary data for the Prop object to the specified LinkedWriter.
        
        >>> GP = Prop.GP
        >>> p1 = GP()
        >>> p2 = GP(floater=True)
        >>> d = Prop.fromkeys(range(20), p1)
        >>> d[12] = d[13] = d[14] = p2
        >>> utilities.hexdump(d.binaryString())
               0 | 0003 0000 0001 0000  0008 000C 0003 8000 |................|
              10 | 8000 8000                                |....            |
        
        >>> d = Prop.fromkeys(range(50), p1)
        >>> d[4] = d[42] = d[43] = d[44] = p2
        >>> utilities.hexdump(d.binaryString())
               0 | 0003 0000 0001 0000  0002 0006 0002 000C |................|
              10 | 0001 0000 0004 0004  8000 002C 002A 8000 |...........,.*..|
              20 | FFFF FFFF 0000                           |......          |
        """

        if 'stakeValue' in kwArgs:
            stakeValue = kwArgs.pop('stakeValue')
            w.stakeCurrentWithValue(stakeValue)
        else:
            stakeValue = w.stakeCurrent()

        w.add("L", self.tableVersion)
        fan = self.GP.asNumber
        d = {k: fan(gp, glyphIndex=k) for k, gp in self.items()}
        valueToCount = collections.defaultdict(int)

        for n in d.values():
            valueToCount[n] += 1

        if len(valueToCount) == 1:
            w.add("2H", 0, next(iter(valueToCount)))
            return

        freq = sorted(valueToCount.items(),
                      key=operator.itemgetter(1),
                      reverse=True)

        default = freq[0][0]
        w.add("2H", 1, default)
        d = {k: n for k, n in d.items() if n != default}
        lookup.Lookup(d).buildBinary(w, sentinelValue=0)
Esempio n. 2
0
    def buildBinary(self, w, **kwArgs):
        """
        Adds the binary data for the Bsln object to the specified LinkedWriter.
        
        >>> utilities.hexdump(_testingValues[0].binaryString())
               0 | 0001 0000 0000 0000  0000 0400 FFEC 0708 |................|
              10 | 0384 0000 0000 0000  0000 0000 0000 0000 |................|
              20 | 0000 0000 0000 0000  0000 0000 0000 0000 |................|
              30 | 0000 0000 0000 0000  0000 0000 0000 0000 |................|
              40 | 0000 0000 0000 0000                      |........        |
        
        >>> utilities.hexdump(_testingValues[1].binaryString())
               0 | 0001 0000 0001 0000  0000 0400 FFEC 0708 |................|
              10 | 0384 0000 0000 0000  0000 0000 0000 0000 |................|
              20 | 0000 0000 0000 0000  0000 0000 0000 0000 |................|
              30 | 0000 0000 0000 0000  0000 0000 0000 0000 |................|
              40 | 0000 0000 0000 0000  0002 0006 0003 000C |................|
              50 | 0001 0006 0006 0004  0001 000B 000B 0004 |................|
              60 | 0014 0013 0001 FFFF  FFFF 0000           |............    |
        
        >>> utilities.hexdump(_testingValues[2].binaryString())
               0 | 0001 0000 0002 0000  0020 0006 0002 0013 |......... ......|
              10 | 0004 000E FFFF FFFF  FFFF FFFF FFFF FFFF |................|
              20 | FFFF FFFF FFFF FFFF  FFFF FFFF FFFF FFFF |................|
              30 | FFFF FFFF FFFF FFFF  FFFF FFFF FFFF FFFF |................|
              40 | FFFF FFFF FFFF FFFF  FFFF                |..........      |
        
        >>> utilities.hexdump(_testingValues[3].binaryString())
               0 | 0001 0000 0003 0000  0020 0006 0002 0013 |......... ......|
              10 | 0004 000E FFFF FFFF  FFFF FFFF FFFF FFFF |................|
              20 | FFFF FFFF FFFF FFFF  FFFF FFFF FFFF FFFF |................|
              30 | FFFF FFFF FFFF FFFF  FFFF FFFF FFFF FFFF |................|
              40 | FFFF FFFF FFFF FFFF  FFFF 0002 0006 0003 |................|
              50 | 000C 0001 0006 0006  0004 0001 000B 000B |................|
              60 | 0004 0014 0013 0001  FFFF FFFF 0000      |..............  |
        """

        if 'stakeValue' in kwArgs:
            stakeValue = kwArgs.pop('stakeValue')
            w.stakeCurrentWithValue(stakeValue)
        else:
            stakeValue = w.stakeCurrent()

        w.add("L", 0x10000)
        dCounts = collections.defaultdict(int)

        for value in self.values():
            dCounts[int(value)] += 1

        format = (0 if len(dCounts) == 1 else 1)

        if not self.positions.isDistance:
            format += 2

        w.add("H", format)
        v = sorted(dCounts.items(), key=operator.itemgetter(1))
        default = v[-1][0]
        w.add("H", default)
        self.positions.buildBinary(w, **kwArgs)

        if len(dCounts) > 1:
            lk = lookup.Lookup({g: n for g, n in self.items() if n != default})
            lk.buildBinary(w, noGaps=True, sentinelValue=0)
Esempio n. 3
0
    def buildBinary(self, w, **kwArgs):
        """
        Adds the binary data for the Contextual object to the specified writer.
        The following keyword arguments are supported:
        
            preferredIOLookupFormat     If you need the actual input glyph to
                                        output glyph lookup to be written in a
                                        specific format, use this keyword. The
                                        default (as usual for Lookup objects)
                                        is to use the smallest one possible.
                                        
                                        Note this keyword is usually specified
                                        in the perTableOptions dict passed into
                                        the Editor's writeFont() method.
        
            stakeValue                  A value that will stake the start of
                                        the data. This is optional.
        
        >>> h = utilities.hexdump
        >>> h(_testingValues[0].binaryString())
               0 | 0000 0006 0000 0034  0000 0052 0000 0076 |.......4...R...v|
              10 | 0000 008E FEED 0002  0553 7761 7368 0754 |.........Swash.T|
              20 | 7269 6767 6572 0001  0B53 6177 2074 7269 |rigger...Saw tri|
              30 | 6767 6572 0002 0006  0002 000C 0001 0000 |gger............|
              40 | 0019 0016 0004 0032  0032 0005 FFFF FFFF |.......2.2......|
              50 | FFFF 0000 0000 0000  0000 0000 0001 0000 |................|
              60 | 0000 0000 0000 0000  0001 0001 0001 0001 |................|
              70 | 0001 0002 0001 0000  0000 FFFF FFFF 0002 |................|
              80 | 0000 FFFF FFFF 0002  0000 FFFF 0000 0000 |................|
              90 | 0004 0008 0016 0004  005F 0060 0061 0062 |........._.`.a.b|
        
        >>> d = {'preferredIOLookupFormat': 2}
        >>> h(_testingValues[0].binaryString(**d))
               0 | 0000 0006 0000 0034  0000 0052 0000 0076 |.......4...R...v|
              10 | 0000 008E FEED 0002  0553 7761 7368 0754 |.........Swash.T|
              20 | 7269 6767 6572 0001  0B53 6177 2074 7269 |rigger...Saw tri|
              30 | 6767 6572 0002 0006  0002 000C 0001 0000 |gger............|
              40 | 0019 0016 0004 0032  0032 0005 FFFF FFFF |.......2.2......|
              50 | FFFF 0000 0000 0000  0000 0000 0001 0000 |................|
              60 | 0000 0000 0000 0000  0001 0001 0001 0001 |................|
              70 | 0001 0002 0001 0000  0000 FFFF FFFF 0002 |................|
              80 | 0000 FFFF FFFF 0002  0000 FFFF 0000 0000 |................|
              90 | 0004 0002 0006 0004  0018 0002 0000 0016 |................|
              A0 | 0016 005F 0017 0017  0060 0018 0018 0061 |..._.....`.....a|
              B0 | 0019 0019 0062 FFFF  FFFF FFFF           |.....b......    |
        """

        if 'stakeValue' in kwArgs:
            stakeValue = kwArgs.pop('stakeValue')
            w.stakeCurrentWithValue(stakeValue)
        else:
            stakeValue = w.stakeCurrent()

        nsObj = namestash.NameStash.fromstatedict(self)
        classNames = nsObj.allClassNames()
        revClassMap = {s: i for i, s in enumerate(classNames)}
        stateNames = nsObj.allStateNames()
        revStateMap = {s: i for i, s in enumerate(stateNames)}
        w.add("L", len(classNames))
        ctStake = w.getNewStake()
        w.addUnresolvedOffset("L", stakeValue, ctStake)
        saStake = w.getNewStake()
        w.addUnresolvedOffset("L", stakeValue, saStake)
        etStake = w.getNewStake()
        w.addUnresolvedOffset("L", stakeValue, etStake)
        gtStake = w.getNewStake()
        w.addUnresolvedOffset("L", stakeValue, gtStake)
        kwArgs.pop('neededAlignment', None)
        kwArgs.pop('classDict', None)
        nsObj.buildBinary(w, neededAlignment=2, **kwArgs)

        self.classTable.buildBinary(w,
                                    stakeValue=ctStake,
                                    classDict=revClassMap,
                                    **kwArgs)

        w.stakeCurrentWithValue(saStake)
        entryPool = {}  # immut -> (entryIndex, obj)

        for stateName in stateNames:
            row = self[stateName]

            for className in classNames:
                thisEntry = row[className]
                immut = thisEntry.asImmutable()

                if immut not in entryPool:
                    entryPool[immut] = (len(entryPool), thisEntry)

                w.add("H", entryPool[immut][0])

        w.stakeCurrentWithValue(etStake)
        lookupPool = {}  # immut -> (lookupIndex, obj)
        it = sorted(entryPool.values(), key=operator.itemgetter(0))

        for entryIndex, obj in it:
            w.add("H", revStateMap[obj.newState])
            flags = (0x8000 if obj.mark else 0)
            flags += (0x4000 if obj.noAdvance else 0)
            w.add("H", flags)
            md = obj.markSubstitutionDict
            cd = obj.currSubstitutionDict

            if md:
                immut = md.asImmutable()

                if immut not in lookupPool:
                    lookupPool[immut] = (len(lookupPool), md)

                w.add("H", lookupPool[immut][0])

            else:
                w.add("h", -1)

            if cd:
                immut = cd.asImmutable()

                if immut not in lookupPool:
                    lookupPool[immut] = (len(lookupPool), cd)

                w.add("H", lookupPool[immut][0])

            else:
                w.add("h", -1)

        w.stakeCurrentWithValue(gtStake)
        v = sorted(lookupPool.values(), key=operator.itemgetter(0))
        lookupStakes = [w.getNewStake() for obj in v]

        for stake in lookupStakes:
            w.addUnresolvedOffset("L", gtStake, stake)

        preferredFormat = kwArgs.get('preferredIOLookupFormat', None)

        for (lookupIndex, gd), stake in zip(v, lookupStakes):
            lkObj = lookup.Lookup(gd)

            if preferredFormat is not None:
                lkObj._preferredFormat = preferredFormat

            lkObj.buildBinary(w, stakeValue=stake)
Esempio n. 4
0
    def buildBinary(self, w, **kwArgs):
        """
        Adds the binary data for the Format2 object to the specified
        LinkedWriter.
        
        >>> _testingValues[1].pprint()
        ClassPair((1, 1)): -25
        ClassPair((1, 2)): -10
        ClassPair((2, 1)): 15
        Left-hand classes:
          15: 1
          25: 1
          35: 2
        Right-hand classes:
          9: 1
          12: 1
          15: 1
          40: 2
        Header information:
          Horizontal
          With-stream
          No variation kerning
          Process forward
        
        >>> utilities.hexdump(_testingValues[1].binaryString())
               0 | 0000 0006 0000 001C  0000 0038 0000 0058 |...........8...X|
              10 | 0006 0004 0003 0008  0001 0004 000F 0006 |................|
              20 | 0019 0006 0023 000C  FFFF FFFF 0006 0004 |.....#..........|
              30 | 0004 0010 0002 0000  0009 0002 000C 0002 |................|
              40 | 000F 0002 0028 0004  FFFF FFFF 0000 0000 |.....(..........|
              50 | 0000 0000 FFE7 FFF6  0000 000F 0000      |..............  |
        """

        if 'stakeValue' in kwArgs:
            stakeValue = kwArgs.pop('stakeValue')
            w.stakeCurrentWithValue(stakeValue)
        else:
            stakeValue = w.stakeCurrent()

        self = self._keysCompacted()
        leftUniques = set(self.leftClassDef.values())
        rightUniques = set(self.rightClassDef.values())
        nRows = 1 + len(leftUniques)
        nCols = 1 + len(rightUniques)
        rowBytes = nCols * 2
        w.add("L", rowBytes)
        headerAdj = 12

        leftLookup = lookup.Lookup(
            {i: j * rowBytes
             for i, j in self.leftClassDef.items()})

        rightLookup = lookup.Lookup(
            {i: j * 2
             for i, j in self.rightClassDef.items()})

        leftStake = w.getNewStake()
        rightStake = w.getNewStake()
        arrayStake = w.getNewStake()

        w.addUnresolvedOffset("L",
                              stakeValue,
                              leftStake,
                              offsetByteDelta=headerAdj)
        w.addUnresolvedOffset("L",
                              stakeValue,
                              rightStake,
                              offsetByteDelta=headerAdj)
        w.addUnresolvedOffset("L",
                              stakeValue,
                              arrayStake,
                              offsetByteDelta=headerAdj)

        leftLookup.buildBinary(w, stakeValue=leftStake, **kwArgs)
        rightLookup.buildBinary(w, stakeValue=rightStake, **kwArgs)
        v = [0] * (nRows * nCols)
        CP = classpair.ClassPair

        for leftIndex in leftUniques:
            for rightIndex in rightUniques:
                key = CP([leftIndex, rightIndex])

                if key in self:
                    v[leftIndex * nCols + rightIndex] = self[key]

        w.stakeCurrentWithValue(arrayStake)
        w.addGroup("h", v)
Esempio n. 5
0
    def buildBinary(self, w, **kwArgs):
        """
        Adds the binary data for the Ankr object to the specified writer. The
        following keyword arguments are supported:
        
            preferredIOLookupFormat     If you need the actual input glyph to
                                        output glyph lookup to be written in a
                                        specific format, use this keyword. The
                                        default (as usual for Lookup objects)
                                        is to use the smallest one possible.
                                        
                                        Note this keyword is usually specified
                                        in the perTableOptions dict passed into
                                        the Editor's writeFont() method.
        
            stakeValue                  A value that will stake the start of
                                        the data. This is optional.
        
        >>> utilities.hexdump(_testingValues[1].binaryString())
               0 | 0000 0000 0000 000C  0000 0030 0006 0004 |...........0....|
              10 | 0005 0010 0002 0004  000A 001C 000B 0010 |................|
              20 | 000E 001C 000F 001C  0064 0000 FFFF FFFF |.........d......|
              30 | 0000 0003 FF38 0000  0000 0096 0000 FF06 |.....8..........|
              40 | 0000 0002 0000 0000  0064 0000 0000 0002 |.........d......|
              50 | 0064 FF9C 0102 0304                      |.d......        |
        
        >>> d = {'preferredIOLookupFormat': 2}
        >>> utilities.hexdump(_testingValues[1].binaryString(**d))
               0 | 0000 0000 0000 000C  0000 003A 0002 0006 |...........:....|
              10 | 0004 0018 0002 0000  000A 000A 001C 000B |................|
              20 | 000B 0010 000F 000E  001C 0064 0064 0000 |...........d.d..|
              30 | FFFF FFFF FFFF FFFF  FFFF 0000 0003 FF38 |...............8|
              40 | 0000 0000 0096 0000  FF06 0000 0002 0000 |................|
              50 | 0000 0064 0000 0000  0002 0064 FF9C 0102 |...d.......d....|
              60 | 0304                                     |..              |
        """

        if 'stakeValue' in kwArgs:
            stakeValue = kwArgs.pop('stakeValue')
            w.stakeCurrentWithValue(stakeValue)
        else:
            stakeValue = w.stakeCurrent()

        w.add("2H", 0, 0)  # version, flags
        lookupStake = w.getNewStake()
        w.addUnresolvedOffset("L", stakeValue, lookupStake)
        dataStake = w.getNewStake()
        w.addUnresolvedOffset("L", stakeValue, dataStake)
        w.stakeCurrentWithValue(lookupStake)

        # To build the lookup we first need to determine which format is
        # smallest.

        d = {}

        for glyph, obj in self.items():
            immut = obj.asImmutable()
            d.setdefault(immut, set()).add(glyph)

        stakeDict = {}

        for immut, glyphSet in d.items():
            sv = w.getNewStake()

            for glyph in glyphSet:
                stakeDict[glyph] = sv

        # For now, raise an error if the largest stake is >64K; if this ever
        # actually arises, we could remap the stakes temporarily.

        if max(stakeDict.values()) > 65535:
            raise ValueError("Too many stakes!")

        lk = lookup.Lookup(stakeDict)
        preferredFormat = kwArgs.get('preferredIOLookupFormat', None)

        if preferredFormat is None:
            bestFormat = lk.binaryString(noGaps=True)[1]
            lk._preferredFormat = bestFormat

        else:
            lk._preferredFormat = preferredFormat

        lk.buildBinary(w, baseStake=dataStake)

        # Now add the actual data

        w.stakeCurrentWithValue(dataStake)
        it = sorted(d.items(), key=operator.itemgetter(0))

        for immut, glyphSet in it:
            glyph = glyphSet.pop()
            self[glyph].buildBinary(w, stakeValue=stakeDict[glyph])