G_M_A_P_.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. from fontTools.misc import sstruct
  2. from fontTools.misc.textTools import tobytes, tostr, safeEval
  3. from . import DefaultTable
  4. GMAPFormat = """
  5. > # big endian
  6. tableVersionMajor: H
  7. tableVersionMinor: H
  8. flags: H
  9. recordsCount: H
  10. recordsOffset: H
  11. fontNameLength: H
  12. """
  13. # psFontName is a byte string which follows the record above. This is zero padded
  14. # to the beginning of the records array. The recordsOffsst is 32 bit aligned.
  15. GMAPRecordFormat1 = """
  16. > # big endian
  17. UV: L
  18. cid: H
  19. gid: H
  20. ggid: H
  21. name: 32s
  22. """
  23. class GMAPRecord(object):
  24. def __init__(self, uv=0, cid=0, gid=0, ggid=0, name=""):
  25. self.UV = uv
  26. self.cid = cid
  27. self.gid = gid
  28. self.ggid = ggid
  29. self.name = name
  30. def toXML(self, writer, ttFont):
  31. writer.begintag("GMAPRecord")
  32. writer.newline()
  33. writer.simpletag("UV", value=self.UV)
  34. writer.newline()
  35. writer.simpletag("cid", value=self.cid)
  36. writer.newline()
  37. writer.simpletag("gid", value=self.gid)
  38. writer.newline()
  39. writer.simpletag("glyphletGid", value=self.gid)
  40. writer.newline()
  41. writer.simpletag("GlyphletName", value=self.name)
  42. writer.newline()
  43. writer.endtag("GMAPRecord")
  44. writer.newline()
  45. def fromXML(self, name, attrs, content, ttFont):
  46. value = attrs["value"]
  47. if name == "GlyphletName":
  48. self.name = value
  49. else:
  50. setattr(self, name, safeEval(value))
  51. def compile(self, ttFont):
  52. if self.UV is None:
  53. self.UV = 0
  54. nameLen = len(self.name)
  55. if nameLen < 32:
  56. self.name = self.name + "\0" * (32 - nameLen)
  57. data = sstruct.pack(GMAPRecordFormat1, self)
  58. return data
  59. def __repr__(self):
  60. return (
  61. "GMAPRecord[ UV: "
  62. + str(self.UV)
  63. + ", cid: "
  64. + str(self.cid)
  65. + ", gid: "
  66. + str(self.gid)
  67. + ", ggid: "
  68. + str(self.ggid)
  69. + ", Glyphlet Name: "
  70. + str(self.name)
  71. + " ]"
  72. )
  73. class table_G_M_A_P_(DefaultTable.DefaultTable):
  74. dependencies = []
  75. def decompile(self, data, ttFont):
  76. dummy, newData = sstruct.unpack2(GMAPFormat, data, self)
  77. self.psFontName = tostr(newData[: self.fontNameLength])
  78. assert (
  79. self.recordsOffset % 4
  80. ) == 0, "GMAP error: recordsOffset is not 32 bit aligned."
  81. newData = data[self.recordsOffset :]
  82. self.gmapRecords = []
  83. for i in range(self.recordsCount):
  84. gmapRecord, newData = sstruct.unpack2(
  85. GMAPRecordFormat1, newData, GMAPRecord()
  86. )
  87. gmapRecord.name = gmapRecord.name.strip("\0")
  88. self.gmapRecords.append(gmapRecord)
  89. def compile(self, ttFont):
  90. self.recordsCount = len(self.gmapRecords)
  91. self.fontNameLength = len(self.psFontName)
  92. self.recordsOffset = 4 * (((self.fontNameLength + 12) + 3) // 4)
  93. data = sstruct.pack(GMAPFormat, self)
  94. data = data + tobytes(self.psFontName)
  95. data = data + b"\0" * (self.recordsOffset - len(data))
  96. for record in self.gmapRecords:
  97. data = data + record.compile(ttFont)
  98. return data
  99. def toXML(self, writer, ttFont):
  100. writer.comment("Most of this table will be recalculated by the compiler")
  101. writer.newline()
  102. formatstring, names, fixes = sstruct.getformat(GMAPFormat)
  103. for name in names:
  104. value = getattr(self, name)
  105. writer.simpletag(name, value=value)
  106. writer.newline()
  107. writer.simpletag("PSFontName", value=self.psFontName)
  108. writer.newline()
  109. for gmapRecord in self.gmapRecords:
  110. gmapRecord.toXML(writer, ttFont)
  111. def fromXML(self, name, attrs, content, ttFont):
  112. if name == "GMAPRecord":
  113. if not hasattr(self, "gmapRecords"):
  114. self.gmapRecords = []
  115. gmapRecord = GMAPRecord()
  116. self.gmapRecords.append(gmapRecord)
  117. for element in content:
  118. if isinstance(element, str):
  119. continue
  120. name, attrs, content = element
  121. gmapRecord.fromXML(name, attrs, content, ttFont)
  122. else:
  123. value = attrs["value"]
  124. if name == "PSFontName":
  125. self.psFontName = value
  126. else:
  127. setattr(self, name, safeEval(value))