xref: /aosp_15_r20/external/fonttools/Lib/fontTools/ttLib/tables/_m_a_x_p.py (revision e1fe3e4ad2793916b15cccdc4a7da52a7e1dd0e9)
1from fontTools.misc import sstruct
2from fontTools.misc.textTools import safeEval
3from . import DefaultTable
4
5maxpFormat_0_5 = """
6		>	# big endian
7		tableVersion:           i
8		numGlyphs:              H
9"""
10
11maxpFormat_1_0_add = """
12		>	# big endian
13		maxPoints:              H
14		maxContours:            H
15		maxCompositePoints:     H
16		maxCompositeContours:   H
17		maxZones:               H
18		maxTwilightPoints:      H
19		maxStorage:             H
20		maxFunctionDefs:        H
21		maxInstructionDefs:     H
22		maxStackElements:       H
23		maxSizeOfInstructions:  H
24		maxComponentElements:   H
25		maxComponentDepth:      H
26"""
27
28
29class table__m_a_x_p(DefaultTable.DefaultTable):
30    dependencies = ["glyf"]
31
32    def decompile(self, data, ttFont):
33        dummy, data = sstruct.unpack2(maxpFormat_0_5, data, self)
34        self.numGlyphs = int(self.numGlyphs)
35        if self.tableVersion != 0x00005000:
36            dummy, data = sstruct.unpack2(maxpFormat_1_0_add, data, self)
37        assert len(data) == 0
38
39    def compile(self, ttFont):
40        if "glyf" in ttFont:
41            if ttFont.isLoaded("glyf") and ttFont.recalcBBoxes:
42                self.recalc(ttFont)
43        else:
44            pass  # CFF
45        self.numGlyphs = len(ttFont.getGlyphOrder())
46        if self.tableVersion != 0x00005000:
47            self.tableVersion = 0x00010000
48        data = sstruct.pack(maxpFormat_0_5, self)
49        if self.tableVersion == 0x00010000:
50            data = data + sstruct.pack(maxpFormat_1_0_add, self)
51        return data
52
53    def recalc(self, ttFont):
54        """Recalculate the font bounding box, and most other maxp values except
55        for the TT instructions values. Also recalculate the value of bit 1
56        of the flags field and the font bounding box of the 'head' table.
57        """
58        glyfTable = ttFont["glyf"]
59        hmtxTable = ttFont["hmtx"]
60        headTable = ttFont["head"]
61        self.numGlyphs = len(glyfTable)
62        INFINITY = 100000
63        xMin = +INFINITY
64        yMin = +INFINITY
65        xMax = -INFINITY
66        yMax = -INFINITY
67        maxPoints = 0
68        maxContours = 0
69        maxCompositePoints = 0
70        maxCompositeContours = 0
71        maxComponentElements = 0
72        maxComponentDepth = 0
73        allXMinIsLsb = 1
74        for glyphName in ttFont.getGlyphOrder():
75            g = glyfTable[glyphName]
76            if g.numberOfContours:
77                if hmtxTable[glyphName][1] != g.xMin:
78                    allXMinIsLsb = 0
79                xMin = min(xMin, g.xMin)
80                yMin = min(yMin, g.yMin)
81                xMax = max(xMax, g.xMax)
82                yMax = max(yMax, g.yMax)
83                if g.numberOfContours > 0:
84                    nPoints, nContours = g.getMaxpValues()
85                    maxPoints = max(maxPoints, nPoints)
86                    maxContours = max(maxContours, nContours)
87                elif g.isComposite():
88                    nPoints, nContours, componentDepth = g.getCompositeMaxpValues(
89                        glyfTable
90                    )
91                    maxCompositePoints = max(maxCompositePoints, nPoints)
92                    maxCompositeContours = max(maxCompositeContours, nContours)
93                    maxComponentElements = max(maxComponentElements, len(g.components))
94                    maxComponentDepth = max(maxComponentDepth, componentDepth)
95        if xMin == +INFINITY:
96            headTable.xMin = 0
97            headTable.yMin = 0
98            headTable.xMax = 0
99            headTable.yMax = 0
100        else:
101            headTable.xMin = xMin
102            headTable.yMin = yMin
103            headTable.xMax = xMax
104            headTable.yMax = yMax
105        self.maxPoints = maxPoints
106        self.maxContours = maxContours
107        self.maxCompositePoints = maxCompositePoints
108        self.maxCompositeContours = maxCompositeContours
109        self.maxComponentElements = maxComponentElements
110        self.maxComponentDepth = maxComponentDepth
111        if allXMinIsLsb:
112            headTable.flags = headTable.flags | 0x2
113        else:
114            headTable.flags = headTable.flags & ~0x2
115
116    def testrepr(self):
117        items = sorted(self.__dict__.items())
118        print(". . . . . . . . .")
119        for combo in items:
120            print("  %s: %s" % combo)
121        print(". . . . . . . . .")
122
123    def toXML(self, writer, ttFont):
124        if self.tableVersion != 0x00005000:
125            writer.comment("Most of this table will be recalculated by the compiler")
126            writer.newline()
127        formatstring, names, fixes = sstruct.getformat(maxpFormat_0_5)
128        if self.tableVersion != 0x00005000:
129            formatstring, names_1_0, fixes = sstruct.getformat(maxpFormat_1_0_add)
130            names = names + names_1_0
131        for name in names:
132            value = getattr(self, name)
133            if name == "tableVersion":
134                value = hex(value)
135            writer.simpletag(name, value=value)
136            writer.newline()
137
138    def fromXML(self, name, attrs, content, ttFont):
139        setattr(self, name, safeEval(attrs["value"]))
140