aboutsummaryrefslogtreecommitdiff
path: root/Lib/fontTools/ttLib/tables/_v_h_e_a.py
blob: de7ce245ad61246cb75000f9c6a208d0dbc984b3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
from fontTools.misc import sstruct
from fontTools.misc.textTools import safeEval
from fontTools.misc.fixedTools import (
    ensureVersionIsLong as fi2ve,
    versionToFixed as ve2fi,
)
from . import DefaultTable
import math


vheaFormat = """
		>	# big endian
		tableVersion:		L
		ascent:			h
		descent:		h
		lineGap:		h
		advanceHeightMax:	H
		minTopSideBearing:	h
		minBottomSideBearing:	h
		yMaxExtent:		h
		caretSlopeRise:		h
		caretSlopeRun:		h
		caretOffset:		h
		reserved1:		h
		reserved2:		h
		reserved3:		h
		reserved4:		h
		metricDataFormat:	h
		numberOfVMetrics:	H
"""


class table__v_h_e_a(DefaultTable.DefaultTable):
    # Note: Keep in sync with table__h_h_e_a

    dependencies = ["vmtx", "glyf", "CFF ", "CFF2"]

    def decompile(self, data, ttFont):
        sstruct.unpack(vheaFormat, data, self)

    def compile(self, ttFont):
        if ttFont.recalcBBoxes and (
            ttFont.isLoaded("glyf")
            or ttFont.isLoaded("CFF ")
            or ttFont.isLoaded("CFF2")
        ):
            self.recalc(ttFont)
        self.tableVersion = fi2ve(self.tableVersion)
        return sstruct.pack(vheaFormat, self)

    def recalc(self, ttFont):
        if "vmtx" not in ttFont:
            return

        vmtxTable = ttFont["vmtx"]
        self.advanceHeightMax = max(adv for adv, _ in vmtxTable.metrics.values())

        boundsHeightDict = {}
        if "glyf" in ttFont:
            glyfTable = ttFont["glyf"]
            for name in ttFont.getGlyphOrder():
                g = glyfTable[name]
                if g.numberOfContours == 0:
                    continue
                if g.numberOfContours < 0 and not hasattr(g, "yMax"):
                    # Composite glyph without extents set.
                    # Calculate those.
                    g.recalcBounds(glyfTable)
                boundsHeightDict[name] = g.yMax - g.yMin
        elif "CFF " in ttFont or "CFF2" in ttFont:
            if "CFF " in ttFont:
                topDict = ttFont["CFF "].cff.topDictIndex[0]
            else:
                topDict = ttFont["CFF2"].cff.topDictIndex[0]
            charStrings = topDict.CharStrings
            for name in ttFont.getGlyphOrder():
                cs = charStrings[name]
                bounds = cs.calcBounds(charStrings)
                if bounds is not None:
                    boundsHeightDict[name] = int(
                        math.ceil(bounds[3]) - math.floor(bounds[1])
                    )

        if boundsHeightDict:
            minTopSideBearing = float("inf")
            minBottomSideBearing = float("inf")
            yMaxExtent = -float("inf")
            for name, boundsHeight in boundsHeightDict.items():
                advanceHeight, tsb = vmtxTable[name]
                bsb = advanceHeight - tsb - boundsHeight
                extent = tsb + boundsHeight
                minTopSideBearing = min(minTopSideBearing, tsb)
                minBottomSideBearing = min(minBottomSideBearing, bsb)
                yMaxExtent = max(yMaxExtent, extent)
            self.minTopSideBearing = minTopSideBearing
            self.minBottomSideBearing = minBottomSideBearing
            self.yMaxExtent = yMaxExtent

        else:  # No glyph has outlines.
            self.minTopSideBearing = 0
            self.minBottomSideBearing = 0
            self.yMaxExtent = 0

    def toXML(self, writer, ttFont):
        formatstring, names, fixes = sstruct.getformat(vheaFormat)
        for name in names:
            value = getattr(self, name)
            if name == "tableVersion":
                value = fi2ve(value)
                value = "0x%08x" % value
            writer.simpletag(name, value=value)
            writer.newline()

    def fromXML(self, name, attrs, content, ttFont):
        if name == "tableVersion":
            setattr(self, name, ve2fi(attrs["value"]))
            return
        setattr(self, name, safeEval(attrs["value"]))

    # reserved0 is caretOffset for legacy reasons
    @property
    def reserved0(self):
        return self.caretOffset

    @reserved0.setter
    def reserved0(self, value):
        self.caretOffset = value