V_O_R_G_.py 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. from fontTools.misc.textTools import bytesjoin, safeEval
  2. from . import DefaultTable
  3. import struct
  4. class table_V_O_R_G_(DefaultTable.DefaultTable):
  5. """This table is structured so that you can treat it like a dictionary keyed by glyph name.
  6. ``ttFont['VORG'][<glyphName>]`` will return the vertical origin for any glyph.
  7. ``ttFont['VORG'][<glyphName>] = <value>`` will set the vertical origin for any glyph.
  8. """
  9. def decompile(self, data, ttFont):
  10. self.getGlyphName = (
  11. ttFont.getGlyphName
  12. ) # for use in get/set item functions, for access by GID
  13. (
  14. self.majorVersion,
  15. self.minorVersion,
  16. self.defaultVertOriginY,
  17. self.numVertOriginYMetrics,
  18. ) = struct.unpack(">HHhH", data[:8])
  19. assert (
  20. self.majorVersion <= 1
  21. ), "Major version of VORG table is higher than I know how to handle"
  22. data = data[8:]
  23. vids = []
  24. gids = []
  25. pos = 0
  26. for i in range(self.numVertOriginYMetrics):
  27. gid, vOrigin = struct.unpack(">Hh", data[pos : pos + 4])
  28. pos += 4
  29. gids.append(gid)
  30. vids.append(vOrigin)
  31. self.VOriginRecords = vOrig = {}
  32. glyphOrder = ttFont.getGlyphOrder()
  33. try:
  34. names = [glyphOrder[gid] for gid in gids]
  35. except IndexError:
  36. getGlyphName = self.getGlyphName
  37. names = map(getGlyphName, gids)
  38. for name, vid in zip(names, vids):
  39. vOrig[name] = vid
  40. def compile(self, ttFont):
  41. vorgs = list(self.VOriginRecords.values())
  42. names = list(self.VOriginRecords.keys())
  43. nameMap = ttFont.getReverseGlyphMap()
  44. try:
  45. gids = [nameMap[name] for name in names]
  46. except KeyError:
  47. nameMap = ttFont.getReverseGlyphMap(rebuild=True)
  48. gids = [nameMap[name] for name in names]
  49. vOriginTable = list(zip(gids, vorgs))
  50. self.numVertOriginYMetrics = len(vorgs)
  51. vOriginTable.sort() # must be in ascending GID order
  52. dataList = [struct.pack(">Hh", rec[0], rec[1]) for rec in vOriginTable]
  53. header = struct.pack(
  54. ">HHhH",
  55. self.majorVersion,
  56. self.minorVersion,
  57. self.defaultVertOriginY,
  58. self.numVertOriginYMetrics,
  59. )
  60. dataList.insert(0, header)
  61. data = bytesjoin(dataList)
  62. return data
  63. def toXML(self, writer, ttFont):
  64. writer.simpletag("majorVersion", value=self.majorVersion)
  65. writer.newline()
  66. writer.simpletag("minorVersion", value=self.minorVersion)
  67. writer.newline()
  68. writer.simpletag("defaultVertOriginY", value=self.defaultVertOriginY)
  69. writer.newline()
  70. writer.simpletag("numVertOriginYMetrics", value=self.numVertOriginYMetrics)
  71. writer.newline()
  72. vOriginTable = []
  73. glyphNames = self.VOriginRecords.keys()
  74. for glyphName in glyphNames:
  75. try:
  76. gid = ttFont.getGlyphID(glyphName)
  77. except:
  78. assert 0, (
  79. "VORG table contains a glyph name not in ttFont.getGlyphNames(): "
  80. + str(glyphName)
  81. )
  82. vOriginTable.append([gid, glyphName, self.VOriginRecords[glyphName]])
  83. vOriginTable.sort()
  84. for entry in vOriginTable:
  85. vOriginRec = VOriginRecord(entry[1], entry[2])
  86. vOriginRec.toXML(writer, ttFont)
  87. def fromXML(self, name, attrs, content, ttFont):
  88. if not hasattr(self, "VOriginRecords"):
  89. self.VOriginRecords = {}
  90. self.getGlyphName = (
  91. ttFont.getGlyphName
  92. ) # for use in get/set item functions, for access by GID
  93. if name == "VOriginRecord":
  94. vOriginRec = VOriginRecord()
  95. for element in content:
  96. if isinstance(element, str):
  97. continue
  98. name, attrs, content = element
  99. vOriginRec.fromXML(name, attrs, content, ttFont)
  100. self.VOriginRecords[vOriginRec.glyphName] = vOriginRec.vOrigin
  101. elif "value" in attrs:
  102. setattr(self, name, safeEval(attrs["value"]))
  103. def __getitem__(self, glyphSelector):
  104. if isinstance(glyphSelector, int):
  105. # its a gid, convert to glyph name
  106. glyphSelector = self.getGlyphName(glyphSelector)
  107. if glyphSelector not in self.VOriginRecords:
  108. return self.defaultVertOriginY
  109. return self.VOriginRecords[glyphSelector]
  110. def __setitem__(self, glyphSelector, value):
  111. if isinstance(glyphSelector, int):
  112. # its a gid, convert to glyph name
  113. glyphSelector = self.getGlyphName(glyphSelector)
  114. if value != self.defaultVertOriginY:
  115. self.VOriginRecords[glyphSelector] = value
  116. elif glyphSelector in self.VOriginRecords:
  117. del self.VOriginRecords[glyphSelector]
  118. def __delitem__(self, glyphSelector):
  119. del self.VOriginRecords[glyphSelector]
  120. class VOriginRecord(object):
  121. def __init__(self, name=None, vOrigin=None):
  122. self.glyphName = name
  123. self.vOrigin = vOrigin
  124. def toXML(self, writer, ttFont):
  125. writer.begintag("VOriginRecord")
  126. writer.newline()
  127. writer.simpletag("glyphName", value=self.glyphName)
  128. writer.newline()
  129. writer.simpletag("vOrigin", value=self.vOrigin)
  130. writer.newline()
  131. writer.endtag("VOriginRecord")
  132. writer.newline()
  133. def fromXML(self, name, attrs, content, ttFont):
  134. value = attrs["value"]
  135. if name == "glyphName":
  136. setattr(self, name, value)
  137. else:
  138. setattr(self, name, safeEval(value))