123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127 |
- 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
|