123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135 |
- 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
- hheaFormat = """
- > # big endian
- tableVersion: L
- ascent: h
- descent: h
- lineGap: h
- advanceWidthMax: H
- minLeftSideBearing: h
- minRightSideBearing: h
- xMaxExtent: h
- caretSlopeRise: h
- caretSlopeRun: h
- caretOffset: h
- reserved0: h
- reserved1: h
- reserved2: h
- reserved3: h
- metricDataFormat: h
- numberOfHMetrics: H
- """
- class table__h_h_e_a(DefaultTable.DefaultTable):
- # Note: Keep in sync with table__v_h_e_a
- dependencies = ["hmtx", "glyf", "CFF ", "CFF2"]
- # OpenType spec renamed these, add aliases for compatibility
- @property
- def ascender(self):
- return self.ascent
- @ascender.setter
- def ascender(self, value):
- self.ascent = value
- @property
- def descender(self):
- return self.descent
- @descender.setter
- def descender(self, value):
- self.descent = value
- def decompile(self, data, ttFont):
- sstruct.unpack(hheaFormat, 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(hheaFormat, self)
- def recalc(self, ttFont):
- if "hmtx" not in ttFont:
- return
- hmtxTable = ttFont["hmtx"]
- self.advanceWidthMax = max(adv for adv, _ in hmtxTable.metrics.values())
- boundsWidthDict = {}
- 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, "xMax"):
- # Composite glyph without extents set.
- # Calculate those.
- g.recalcBounds(glyfTable)
- boundsWidthDict[name] = g.xMax - g.xMin
- 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:
- boundsWidthDict[name] = int(
- math.ceil(bounds[2]) - math.floor(bounds[0])
- )
- if boundsWidthDict:
- minLeftSideBearing = float("inf")
- minRightSideBearing = float("inf")
- xMaxExtent = -float("inf")
- for name, boundsWidth in boundsWidthDict.items():
- advanceWidth, lsb = hmtxTable[name]
- rsb = advanceWidth - lsb - boundsWidth
- extent = lsb + boundsWidth
- minLeftSideBearing = min(minLeftSideBearing, lsb)
- minRightSideBearing = min(minRightSideBearing, rsb)
- xMaxExtent = max(xMaxExtent, extent)
- self.minLeftSideBearing = minLeftSideBearing
- self.minRightSideBearing = minRightSideBearing
- self.xMaxExtent = xMaxExtent
- else: # No glyph has outlines.
- self.minLeftSideBearing = 0
- self.minRightSideBearing = 0
- self.xMaxExtent = 0
- def toXML(self, writer, ttFont):
- formatstring, names, fixes = sstruct.getformat(hheaFormat)
- 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"]))
|