• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1from fontTools.misc.py23 import bytesjoin
2from fontTools.misc import sstruct
3from fontTools.misc.fixedTools import (
4    fixedToFloat as fi2fl,
5    floatToFixed as fl2fi,
6    floatToFixedToStr as fl2str,
7    strToFixedToFloat as str2fl,
8)
9from fontTools.ttLib import TTLibError
10from . import DefaultTable
11import struct
12import logging
13
14
15log = logging.getLogger(__name__)
16
17# Apple's documentation of 'avar':
18# https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6avar.html
19
20AVAR_HEADER_FORMAT = """
21    > # big endian
22    majorVersion:  H
23    minorVersion:  H
24    reserved:      H
25    axisCount:     H
26"""
27assert sstruct.calcsize(AVAR_HEADER_FORMAT) == 8, sstruct.calcsize(AVAR_HEADER_FORMAT)
28
29
30class table__a_v_a_r(DefaultTable.DefaultTable):
31
32    dependencies = ["fvar"]
33
34    def __init__(self, tag=None):
35        DefaultTable.DefaultTable.__init__(self, tag)
36        self.segments = {}
37
38    def compile(self, ttFont):
39        axisTags = [axis.axisTag for axis in ttFont["fvar"].axes]
40        header = {
41            "majorVersion": 1,
42            "minorVersion": 0,
43            "reserved": 0,
44            "axisCount": len(axisTags)
45        }
46        result = [sstruct.pack(AVAR_HEADER_FORMAT, header)]
47        for axis in axisTags:
48            mappings = sorted(self.segments[axis].items())
49            result.append(struct.pack(">H", len(mappings)))
50            for key, value in mappings:
51                fixedKey = fl2fi(key, 14)
52                fixedValue = fl2fi(value, 14)
53                result.append(struct.pack(">hh", fixedKey, fixedValue))
54        return bytesjoin(result)
55
56    def decompile(self, data, ttFont):
57        axisTags = [axis.axisTag for axis in ttFont["fvar"].axes]
58        header = {}
59        headerSize = sstruct.calcsize(AVAR_HEADER_FORMAT)
60        header = sstruct.unpack(AVAR_HEADER_FORMAT, data[0:headerSize])
61        majorVersion = header["majorVersion"]
62        if majorVersion != 1:
63            raise TTLibError("unsupported 'avar' version %d" % majorVersion)
64        pos = headerSize
65        for axis in axisTags:
66            segments = self.segments[axis] = {}
67            numPairs = struct.unpack(">H", data[pos:pos+2])[0]
68            pos = pos + 2
69            for _ in range(numPairs):
70                fromValue, toValue = struct.unpack(">hh", data[pos:pos+4])
71                segments[fi2fl(fromValue, 14)] = fi2fl(toValue, 14)
72                pos = pos + 4
73
74    def toXML(self, writer, ttFont):
75        axisTags = [axis.axisTag for axis in ttFont["fvar"].axes]
76        for axis in axisTags:
77            writer.begintag("segment", axis=axis)
78            writer.newline()
79            for key, value in sorted(self.segments[axis].items()):
80                key = fl2str(key, 14)
81                value = fl2str(value, 14)
82                writer.simpletag("mapping", **{"from": key, "to": value})
83                writer.newline()
84            writer.endtag("segment")
85            writer.newline()
86
87    def fromXML(self, name, attrs, content, ttFont):
88        if name == "segment":
89            axis = attrs["axis"]
90            segment = self.segments[axis] = {}
91            for element in content:
92                if isinstance(element, tuple):
93                    elementName, elementAttrs, _ = element
94                    if elementName == "mapping":
95                        fromValue = str2fl(elementAttrs["from"], 14)
96                        toValue = str2fl(elementAttrs["to"], 14)
97                        if fromValue in segment:
98                            log.warning("duplicate entry for %s in axis '%s'",
99                                        fromValue, axis)
100                        segment[fromValue] = toValue
101