cmap.go 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. // Copyright 2017 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package sfnt
  5. import (
  6. "golang.org/x/text/encoding/charmap"
  7. )
  8. // Platform IDs and Platform Specific IDs as per
  9. // https://www.microsoft.com/typography/otspec/name.htm
  10. const (
  11. pidUnicode = 0
  12. pidMacintosh = 1
  13. pidWindows = 3
  14. psidUnicode2BMPOnly = 3
  15. psidUnicode2FullRepertoire = 4
  16. // Note that FontForge may generate a bogus Platform Specific ID (value 10)
  17. // for the Unicode Platform ID (value 0). See
  18. // https://github.com/fontforge/fontforge/issues/2728
  19. psidMacintoshRoman = 0
  20. psidWindowsSymbol = 0
  21. psidWindowsUCS2 = 1
  22. psidWindowsUCS4 = 10
  23. )
  24. // platformEncodingWidth returns the number of bytes per character assumed by
  25. // the given Platform ID and Platform Specific ID.
  26. //
  27. // Very old fonts, from before Unicode was widely adopted, assume only 1 byte
  28. // per character: a character map.
  29. //
  30. // Old fonts, from when Unicode meant the Basic Multilingual Plane (BMP),
  31. // assume that 2 bytes per character is sufficient.
  32. //
  33. // Recent fonts naturally support the full range of Unicode code points, which
  34. // can take up to 4 bytes per character. Such fonts might still choose one of
  35. // the legacy encodings if e.g. their repertoire is limited to the BMP, for
  36. // greater compatibility with older software, or because the resultant file
  37. // size can be smaller.
  38. func platformEncodingWidth(pid, psid uint16) int {
  39. switch pid {
  40. case pidUnicode:
  41. switch psid {
  42. case psidUnicode2BMPOnly:
  43. return 2
  44. case psidUnicode2FullRepertoire:
  45. return 4
  46. }
  47. case pidMacintosh:
  48. switch psid {
  49. case psidMacintoshRoman:
  50. return 1
  51. }
  52. case pidWindows:
  53. switch psid {
  54. case psidWindowsSymbol:
  55. return 2
  56. case psidWindowsUCS2:
  57. return 2
  58. case psidWindowsUCS4:
  59. return 4
  60. }
  61. }
  62. return 0
  63. }
  64. // The various cmap formats are described at
  65. // https://www.microsoft.com/typography/otspec/cmap.htm
  66. var supportedCmapFormat = func(format, pid, psid uint16) bool {
  67. switch format {
  68. case 0:
  69. return pid == pidMacintosh && psid == psidMacintoshRoman
  70. case 4:
  71. return true
  72. case 6:
  73. return true
  74. case 12:
  75. return true
  76. }
  77. return false
  78. }
  79. func (f *Font) makeCachedGlyphIndex(buf []byte, offset, length uint32, format uint16) ([]byte, glyphIndexFunc, error) {
  80. switch format {
  81. case 0:
  82. return f.makeCachedGlyphIndexFormat0(buf, offset, length)
  83. case 4:
  84. return f.makeCachedGlyphIndexFormat4(buf, offset, length)
  85. case 6:
  86. return f.makeCachedGlyphIndexFormat6(buf, offset, length)
  87. case 12:
  88. return f.makeCachedGlyphIndexFormat12(buf, offset, length)
  89. }
  90. panic("unreachable")
  91. }
  92. func (f *Font) makeCachedGlyphIndexFormat0(buf []byte, offset, length uint32) ([]byte, glyphIndexFunc, error) {
  93. if length != 6+256 || offset+length > f.cmap.length {
  94. return nil, nil, errInvalidCmapTable
  95. }
  96. var err error
  97. buf, err = f.src.view(buf, int(f.cmap.offset+offset), int(length))
  98. if err != nil {
  99. return nil, nil, err
  100. }
  101. var table [256]byte
  102. copy(table[:], buf[6:])
  103. return buf, func(f *Font, b *Buffer, r rune) (GlyphIndex, error) {
  104. x, ok := charmap.Macintosh.EncodeRune(r)
  105. if !ok {
  106. // The source rune r is not representable in the Macintosh-Roman encoding.
  107. return 0, nil
  108. }
  109. return GlyphIndex(table[x]), nil
  110. }, nil
  111. }
  112. func (f *Font) makeCachedGlyphIndexFormat4(buf []byte, offset, length uint32) ([]byte, glyphIndexFunc, error) {
  113. const headerSize = 14
  114. if offset+headerSize > f.cmap.length {
  115. return nil, nil, errInvalidCmapTable
  116. }
  117. var err error
  118. buf, err = f.src.view(buf, int(f.cmap.offset+offset), headerSize)
  119. if err != nil {
  120. return nil, nil, err
  121. }
  122. offset += headerSize
  123. segCount := u16(buf[6:])
  124. if segCount&1 != 0 {
  125. return nil, nil, errInvalidCmapTable
  126. }
  127. segCount /= 2
  128. if segCount > maxCmapSegments {
  129. return nil, nil, errUnsupportedNumberOfCmapSegments
  130. }
  131. eLength := 8*uint32(segCount) + 2
  132. if offset+eLength > f.cmap.length {
  133. return nil, nil, errInvalidCmapTable
  134. }
  135. buf, err = f.src.view(buf, int(f.cmap.offset+offset), int(eLength))
  136. if err != nil {
  137. return nil, nil, err
  138. }
  139. offset += eLength
  140. entries := make([]cmapEntry16, segCount)
  141. for i := range entries {
  142. entries[i] = cmapEntry16{
  143. end: u16(buf[0*len(entries)+0+2*i:]),
  144. start: u16(buf[2*len(entries)+2+2*i:]),
  145. delta: u16(buf[4*len(entries)+2+2*i:]),
  146. offset: u16(buf[6*len(entries)+2+2*i:]),
  147. }
  148. }
  149. indexesBase := f.cmap.offset + offset
  150. indexesLength := f.cmap.length - offset
  151. return buf, func(f *Font, b *Buffer, r rune) (GlyphIndex, error) {
  152. if uint32(r) > 0xffff {
  153. return 0, nil
  154. }
  155. c := uint16(r)
  156. for i, j := 0, len(entries); i < j; {
  157. h := i + (j-i)/2
  158. entry := &entries[h]
  159. if c < entry.start {
  160. j = h
  161. } else if entry.end < c {
  162. i = h + 1
  163. } else if entry.offset == 0 {
  164. return GlyphIndex(c + entry.delta), nil
  165. } else {
  166. offset := uint32(entry.offset) + 2*uint32(h-len(entries)+int(c-entry.start))
  167. if offset > indexesLength || offset+2 > indexesLength {
  168. return 0, errInvalidCmapTable
  169. }
  170. if b == nil {
  171. b = &Buffer{}
  172. }
  173. x, err := b.view(&f.src, int(indexesBase+offset), 2)
  174. if err != nil {
  175. return 0, err
  176. }
  177. return GlyphIndex(u16(x)), nil
  178. }
  179. }
  180. return 0, nil
  181. }, nil
  182. }
  183. func (f *Font) makeCachedGlyphIndexFormat6(buf []byte, offset, length uint32) ([]byte, glyphIndexFunc, error) {
  184. const headerSize = 10
  185. if offset+headerSize > f.cmap.length {
  186. return nil, nil, errInvalidCmapTable
  187. }
  188. var err error
  189. buf, err = f.src.view(buf, int(f.cmap.offset+offset), headerSize)
  190. if err != nil {
  191. return nil, nil, err
  192. }
  193. offset += headerSize
  194. firstCode := u16(buf[6:])
  195. entryCount := u16(buf[8:])
  196. eLength := 2 * uint32(entryCount)
  197. if offset+eLength > f.cmap.length {
  198. return nil, nil, errInvalidCmapTable
  199. }
  200. if entryCount != 0 {
  201. buf, err = f.src.view(buf, int(f.cmap.offset+offset), int(eLength))
  202. if err != nil {
  203. return nil, nil, err
  204. }
  205. offset += eLength
  206. }
  207. entries := make([]uint16, entryCount)
  208. for i := range entries {
  209. entries[i] = u16(buf[2*i:])
  210. }
  211. return buf, func(f *Font, b *Buffer, r rune) (GlyphIndex, error) {
  212. if uint16(r) < firstCode {
  213. return 0, nil
  214. }
  215. c := int(uint16(r) - firstCode)
  216. if c >= len(entries) {
  217. return 0, nil
  218. }
  219. return GlyphIndex(entries[c]), nil
  220. }, nil
  221. }
  222. func (f *Font) makeCachedGlyphIndexFormat12(buf []byte, offset, _ uint32) ([]byte, glyphIndexFunc, error) {
  223. const headerSize = 16
  224. if offset+headerSize > f.cmap.length {
  225. return nil, nil, errInvalidCmapTable
  226. }
  227. var err error
  228. buf, err = f.src.view(buf, int(f.cmap.offset+offset), headerSize)
  229. if err != nil {
  230. return nil, nil, err
  231. }
  232. length := u32(buf[4:])
  233. if f.cmap.length < offset || length > f.cmap.length-offset {
  234. return nil, nil, errInvalidCmapTable
  235. }
  236. offset += headerSize
  237. numGroups := u32(buf[12:])
  238. if numGroups > maxCmapSegments {
  239. return nil, nil, errUnsupportedNumberOfCmapSegments
  240. }
  241. eLength := 12 * numGroups
  242. if headerSize+eLength != length {
  243. return nil, nil, errInvalidCmapTable
  244. }
  245. buf, err = f.src.view(buf, int(f.cmap.offset+offset), int(eLength))
  246. if err != nil {
  247. return nil, nil, err
  248. }
  249. offset += eLength
  250. entries := make([]cmapEntry32, numGroups)
  251. for i := range entries {
  252. entries[i] = cmapEntry32{
  253. start: u32(buf[0+12*i:]),
  254. end: u32(buf[4+12*i:]),
  255. delta: u32(buf[8+12*i:]),
  256. }
  257. }
  258. return buf, func(f *Font, b *Buffer, r rune) (GlyphIndex, error) {
  259. c := uint32(r)
  260. for i, j := 0, len(entries); i < j; {
  261. h := i + (j-i)/2
  262. entry := &entries[h]
  263. if c < entry.start {
  264. j = h
  265. } else if entry.end < c {
  266. i = h + 1
  267. } else {
  268. return GlyphIndex(c - entry.start + entry.delta), nil
  269. }
  270. }
  271. return 0, nil
  272. }, nil
  273. }
  274. type cmapEntry16 struct {
  275. end, start, delta, offset uint16
  276. }
  277. type cmapEntry32 struct {
  278. start, end, delta uint32
  279. }