_m_a_x_p.py 4.9 KB

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