gpos.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550
  1. // Copyright 2019 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. "sort"
  7. )
  8. const (
  9. hexScriptLatn = uint32(0x6c61746e) // latn
  10. hexScriptDFLT = uint32(0x44464c54) // DFLT
  11. hexFeatureKern = uint32(0x6b65726e) // kern
  12. )
  13. // kernFunc returns the unscaled kerning value for kerning pair a+b.
  14. // Returns ErrNotFound if no kerning is specified for this pair.
  15. type kernFunc func(a, b GlyphIndex) (int16, error)
  16. func (f *Font) parseGPOSKern(buf []byte) ([]byte, []kernFunc, error) {
  17. // https://docs.microsoft.com/en-us/typography/opentype/spec/gpos
  18. if f.gpos.length == 0 {
  19. return buf, nil, nil
  20. }
  21. const headerSize = 10 // GPOS header v1.1 is 14 bytes, but we don't support FeatureVariations
  22. if f.gpos.length < headerSize {
  23. return buf, nil, errInvalidGPOSTable
  24. }
  25. buf, err := f.src.view(buf, int(f.gpos.offset), headerSize)
  26. if err != nil {
  27. return buf, nil, err
  28. }
  29. // check for version 1.0/1.1
  30. if u16(buf) != 1 || u16(buf[2:]) > 1 {
  31. return buf, nil, errUnsupportedGPOSTable
  32. }
  33. scriptListOffset := u16(buf[4:])
  34. featureListOffset := u16(buf[6:])
  35. lookupListOffset := u16(buf[8:])
  36. // get all feature indices for latn script
  37. buf, featureIdxs, err := f.parseGPOSScriptFeatures(buf, int(f.gpos.offset)+int(scriptListOffset), hexScriptLatn)
  38. if err != nil {
  39. return buf, nil, err
  40. }
  41. if len(featureIdxs) == 0 {
  42. // get all feature indices for DFLT script
  43. buf, featureIdxs, err = f.parseGPOSScriptFeatures(buf, int(f.gpos.offset)+int(scriptListOffset), hexScriptDFLT)
  44. if err != nil {
  45. return buf, nil, err
  46. }
  47. if len(featureIdxs) == 0 {
  48. return buf, nil, nil
  49. }
  50. }
  51. // get all lookup indices for kern features
  52. buf, lookupIdx, err := f.parseGPOSFeaturesLookup(buf, int(f.gpos.offset)+int(featureListOffset), featureIdxs, hexFeatureKern)
  53. if err != nil {
  54. return buf, nil, err
  55. }
  56. // LookupTableList: lookupCount,[]lookups
  57. buf, numLookupTables, err := f.src.varLenView(buf, int(f.gpos.offset)+int(lookupListOffset), 2, 0, 2)
  58. if err != nil {
  59. return buf, nil, err
  60. }
  61. var kernFuncs []kernFunc
  62. lookupTables:
  63. for _, n := range lookupIdx {
  64. if n > numLookupTables {
  65. return buf, nil, errInvalidGPOSTable
  66. }
  67. tableOffset := int(f.gpos.offset) + int(lookupListOffset) + int(u16(buf[2+n*2:]))
  68. // LookupTable: lookupType, lookupFlag, subTableCount, []subtableOffsets, markFilteringSet
  69. buf, numSubTables, err := f.src.varLenView(buf, tableOffset, 8, 4, 2)
  70. if err != nil {
  71. return buf, nil, err
  72. }
  73. flags := u16(buf[2:])
  74. subTableOffsets := make([]int, numSubTables)
  75. for i := 0; i < int(numSubTables); i++ {
  76. subTableOffsets[i] = int(tableOffset) + int(u16(buf[6+i*2:]))
  77. }
  78. switch lookupType := u16(buf); lookupType {
  79. case 2: // PairPos table
  80. case 9:
  81. // Extension Positioning table defines an additional u32 offset
  82. // to allow subtables to exceed the 16-bit limit.
  83. for i := range subTableOffsets {
  84. buf, err = f.src.view(buf, subTableOffsets[i], 8)
  85. if err != nil {
  86. return buf, nil, err
  87. }
  88. if format := u16(buf); format != 1 {
  89. return buf, nil, errUnsupportedExtensionPosFormat
  90. }
  91. if lookupType := u16(buf[2:]); lookupType != 2 {
  92. continue lookupTables
  93. }
  94. subTableOffsets[i] += int(u32(buf[4:]))
  95. }
  96. default: // other types are not supported
  97. continue
  98. }
  99. if flags&0x0010 > 0 {
  100. // useMarkFilteringSet enabled, skip as it is not supported
  101. continue
  102. }
  103. for _, subTableOffset := range subTableOffsets {
  104. buf, err = f.src.view(buf, int(subTableOffset), 4)
  105. if err != nil {
  106. return buf, nil, err
  107. }
  108. format := u16(buf)
  109. var lookupIndex indexLookupFunc
  110. buf, lookupIndex, err = f.makeCachedCoverageLookup(buf, subTableOffset+int(u16(buf[2:])))
  111. if err != nil {
  112. return buf, nil, err
  113. }
  114. switch format {
  115. case 1: // Adjustments for Glyph Pairs
  116. buf, kern, err := f.parsePairPosFormat1(buf, subTableOffset, lookupIndex)
  117. if err != nil {
  118. return buf, nil, err
  119. }
  120. if kern != nil {
  121. kernFuncs = append(kernFuncs, kern)
  122. }
  123. case 2: // Class Pair Adjustment
  124. buf, kern, err := f.parsePairPosFormat2(buf, subTableOffset, lookupIndex)
  125. if err != nil {
  126. return buf, nil, err
  127. }
  128. if kern != nil {
  129. kernFuncs = append(kernFuncs, kern)
  130. }
  131. }
  132. }
  133. }
  134. return buf, kernFuncs, nil
  135. }
  136. func (f *Font) parsePairPosFormat1(buf []byte, offset int, lookupIndex indexLookupFunc) ([]byte, kernFunc, error) {
  137. // PairPos Format 1: posFormat, coverageOffset, valueFormat1,
  138. // valueFormat2, pairSetCount, []pairSetOffsets
  139. var err error
  140. var nPairs int
  141. buf, nPairs, err = f.src.varLenView(buf, offset, 10, 8, 2)
  142. if err != nil {
  143. return buf, nil, err
  144. }
  145. // check valueFormat1 and valueFormat2 flags
  146. if u16(buf[4:]) != 0x04 || u16(buf[6:]) != 0x00 {
  147. // we only support kerning with X_ADVANCE for first glyph
  148. return buf, nil, nil
  149. }
  150. // PairPos table contains an array of offsets to PairSet
  151. // tables, which contains an array of PairValueRecords.
  152. // Calculate length of complete PairPos table by jumping to
  153. // last PairSet.
  154. // We need to iterate all offsets to find the last pair as
  155. // offsets are not sorted and can be repeated.
  156. var lastPairSetOffset int
  157. for n := 0; n < nPairs; n++ {
  158. pairOffset := int(u16(buf[10+n*2:]))
  159. if pairOffset > lastPairSetOffset {
  160. lastPairSetOffset = pairOffset
  161. }
  162. }
  163. buf, err = f.src.view(buf, offset+lastPairSetOffset, 2)
  164. if err != nil {
  165. return buf, nil, err
  166. }
  167. pairValueCount := int(u16(buf))
  168. // Each PairSet contains the secondGlyph (u16) and one or more value records (all u16).
  169. // We only support lookup tables with one value record (X_ADVANCE, see valueFormat1/2 above).
  170. lastPairSetLength := 2 + pairValueCount*4
  171. length := lastPairSetOffset + lastPairSetLength
  172. buf, err = f.src.view(buf, offset, length)
  173. if err != nil {
  174. return buf, nil, err
  175. }
  176. kern := makeCachedPairPosGlyph(lookupIndex, nPairs, buf)
  177. return buf, kern, nil
  178. }
  179. func (f *Font) parsePairPosFormat2(buf []byte, offset int, lookupIndex indexLookupFunc) ([]byte, kernFunc, error) {
  180. // PairPos Format 2:
  181. // posFormat, coverageOffset, valueFormat1, valueFormat2,
  182. // classDef1Offset, classDef2Offset, class1Count, class2Count,
  183. // []class1Records
  184. var err error
  185. buf, err = f.src.view(buf, offset, 16)
  186. if err != nil {
  187. return buf, nil, err
  188. }
  189. // check valueFormat1 and valueFormat2 flags
  190. if u16(buf[4:]) != 0x04 || u16(buf[6:]) != 0x00 {
  191. // we only support kerning with X_ADVANCE for first glyph
  192. return buf, nil, nil
  193. }
  194. numClass1 := int(u16(buf[12:]))
  195. numClass2 := int(u16(buf[14:]))
  196. cdef1Offset := offset + int(u16(buf[8:]))
  197. cdef2Offset := offset + int(u16(buf[10:]))
  198. var cdef1, cdef2 classLookupFunc
  199. buf, cdef1, err = f.makeCachedClassLookup(buf, cdef1Offset)
  200. if err != nil {
  201. return buf, nil, err
  202. }
  203. buf, cdef2, err = f.makeCachedClassLookup(buf, cdef2Offset)
  204. if err != nil {
  205. return buf, nil, err
  206. }
  207. buf, err = f.src.view(buf, offset+16, numClass1*numClass2*2)
  208. if err != nil {
  209. return buf, nil, err
  210. }
  211. kern := makeCachedPairPosClass(
  212. lookupIndex,
  213. numClass1,
  214. numClass2,
  215. cdef1,
  216. cdef2,
  217. buf,
  218. )
  219. return buf, kern, nil
  220. }
  221. // parseGPOSScriptFeatures returns all indices of features in FeatureTable that
  222. // are valid for the given script.
  223. // Returns features from DefaultLangSys, different languages are not supported.
  224. // However, all observed fonts either do not use different languages or use the
  225. // same features as DefaultLangSys.
  226. func (f *Font) parseGPOSScriptFeatures(buf []byte, offset int, script uint32) ([]byte, []int, error) {
  227. // ScriptList table: scriptCount, []scriptRecords{scriptTag, scriptOffset}
  228. buf, numScriptTables, err := f.src.varLenView(buf, offset, 2, 0, 6)
  229. if err != nil {
  230. return buf, nil, err
  231. }
  232. // Search ScriptTables for script
  233. var scriptTableOffset uint16
  234. for i := 0; i < numScriptTables; i++ {
  235. scriptTag := u32(buf[2+i*6:])
  236. if scriptTag == script {
  237. scriptTableOffset = u16(buf[2+i*6+4:])
  238. break
  239. }
  240. }
  241. if scriptTableOffset == 0 {
  242. return buf, nil, nil
  243. }
  244. // Script table: defaultLangSys, langSysCount, []langSysRecords{langSysTag, langSysOffset}
  245. buf, err = f.src.view(buf, offset+int(scriptTableOffset), 2)
  246. if err != nil {
  247. return buf, nil, err
  248. }
  249. defaultLangSysOffset := u16(buf)
  250. if defaultLangSysOffset == 0 {
  251. return buf, nil, nil
  252. }
  253. // LangSys table: lookupOrder (reserved), requiredFeatureIndex, featureIndexCount, []featureIndices
  254. buf, numFeatures, err := f.src.varLenView(buf, offset+int(scriptTableOffset)+int(defaultLangSysOffset), 6, 4, 2)
  255. if err != nil {
  256. return buf, nil, err
  257. }
  258. featureIdxs := make([]int, numFeatures)
  259. for i := range featureIdxs {
  260. featureIdxs[i] = int(u16(buf[6+i*2:]))
  261. }
  262. return buf, featureIdxs, nil
  263. }
  264. func (f *Font) parseGPOSFeaturesLookup(buf []byte, offset int, featureIdxs []int, feature uint32) ([]byte, []int, error) {
  265. // FeatureList table: featureCount, []featureRecords{featureTag, featureOffset}
  266. buf, numFeatureTables, err := f.src.varLenView(buf, offset, 2, 0, 6)
  267. if err != nil {
  268. return buf, nil, err
  269. }
  270. lookupIdx := make([]int, 0, 4)
  271. for _, fidx := range featureIdxs {
  272. if fidx > numFeatureTables {
  273. return buf, nil, errInvalidGPOSTable
  274. }
  275. featureTag := u32(buf[2+fidx*6:])
  276. if featureTag != feature {
  277. continue
  278. }
  279. featureOffset := u16(buf[2+fidx*6+4:])
  280. buf, numLookups, err := f.src.varLenView(nil, offset+int(featureOffset), 4, 2, 2)
  281. if err != nil {
  282. return buf, nil, err
  283. }
  284. for i := 0; i < numLookups; i++ {
  285. lookupIdx = append(lookupIdx, int(u16(buf[4+i*2:])))
  286. }
  287. }
  288. return buf, lookupIdx, nil
  289. }
  290. func makeCachedPairPosGlyph(cov indexLookupFunc, num int, buf []byte) kernFunc {
  291. glyphs := make([]byte, len(buf))
  292. copy(glyphs, buf)
  293. return func(a, b GlyphIndex) (int16, error) {
  294. idx, found := cov(a)
  295. if !found {
  296. return 0, ErrNotFound
  297. }
  298. if idx >= num {
  299. return 0, ErrNotFound
  300. }
  301. offset := int(u16(glyphs[10+idx*2:]))
  302. if offset+1 >= len(glyphs) {
  303. return 0, errInvalidGPOSTable
  304. }
  305. count := int(u16(glyphs[offset:]))
  306. for i := 0; i < count; i++ {
  307. secondGlyphIndex := GlyphIndex(int(u16(glyphs[offset+2+i*4:])))
  308. if secondGlyphIndex == b {
  309. return int16(u16(glyphs[offset+2+i*4+2:])), nil
  310. }
  311. if secondGlyphIndex > b {
  312. return 0, ErrNotFound
  313. }
  314. }
  315. return 0, ErrNotFound
  316. }
  317. }
  318. func makeCachedPairPosClass(cov indexLookupFunc, num1, num2 int, cdef1, cdef2 classLookupFunc, buf []byte) kernFunc {
  319. glyphs := make([]byte, len(buf))
  320. copy(glyphs, buf)
  321. return func(a, b GlyphIndex) (int16, error) {
  322. // check coverage to avoid selection of default class 0
  323. _, found := cov(a)
  324. if !found {
  325. return 0, ErrNotFound
  326. }
  327. idxa := cdef1(a)
  328. idxb := cdef2(b)
  329. return int16(u16(glyphs[(idxb+idxa*num2)*2:])), nil
  330. }
  331. }
  332. // indexLookupFunc returns the index into a PairPos table for the provided glyph.
  333. // Returns false if the glyph is not covered by this lookup.
  334. type indexLookupFunc func(GlyphIndex) (int, bool)
  335. func (f *Font) makeCachedCoverageLookup(buf []byte, offset int) ([]byte, indexLookupFunc, error) {
  336. var err error
  337. buf, err = f.src.view(buf, offset, 2)
  338. if err != nil {
  339. return buf, nil, err
  340. }
  341. switch u16(buf) {
  342. case 1:
  343. // Coverage Format 1: coverageFormat, glyphCount, []glyphArray
  344. buf, _, err = f.src.varLenView(buf, offset, 4, 2, 2)
  345. if err != nil {
  346. return buf, nil, err
  347. }
  348. return buf, makeCachedCoverageList(buf[2:]), nil
  349. case 2:
  350. // Coverage Format 2: coverageFormat, rangeCount, []rangeRecords{startGlyphID, endGlyphID, startCoverageIndex}
  351. buf, _, err = f.src.varLenView(buf, offset, 4, 2, 6)
  352. if err != nil {
  353. return buf, nil, err
  354. }
  355. return buf, makeCachedCoverageRange(buf[2:]), nil
  356. default:
  357. return buf, nil, errUnsupportedCoverageFormat
  358. }
  359. }
  360. func makeCachedCoverageList(buf []byte) indexLookupFunc {
  361. num := int(u16(buf))
  362. list := make([]byte, len(buf)-2)
  363. copy(list, buf[2:])
  364. return func(gi GlyphIndex) (int, bool) {
  365. idx := sort.Search(num, func(i int) bool {
  366. return gi <= GlyphIndex(u16(list[i*2:]))
  367. })
  368. if idx < num && GlyphIndex(u16(list[idx*2:])) == gi {
  369. return idx, true
  370. }
  371. return 0, false
  372. }
  373. }
  374. func makeCachedCoverageRange(buf []byte) indexLookupFunc {
  375. num := int(u16(buf))
  376. ranges := make([]byte, len(buf)-2)
  377. copy(ranges, buf[2:])
  378. return func(gi GlyphIndex) (int, bool) {
  379. if num == 0 {
  380. return 0, false
  381. }
  382. // ranges is an array of startGlyphID, endGlyphID and startCoverageIndex
  383. // Ranges are non-overlapping.
  384. // The following GlyphIDs/index pairs are stored as follows:
  385. // pairs: 130=0, 131=1, 132=2, 133=3, 134=4, 135=5, 137=6
  386. // ranges: 130, 135, 0 137, 137, 6
  387. // startCoverageIndex is used to calculate the index without counting
  388. // the length of the preceding ranges
  389. idx := sort.Search(num, func(i int) bool {
  390. return gi <= GlyphIndex(u16(ranges[i*6:]))
  391. })
  392. // idx either points to a matching start, or to the next range (or idx==num)
  393. // e.g. with the range example from above: 130 points to 130-135 range, 133 points to 137-137 range
  394. // check if gi is the start of a range, but only if sort.Search returned a valid result
  395. if idx < num {
  396. if start := u16(ranges[idx*6:]); gi == GlyphIndex(start) {
  397. return int(u16(ranges[idx*6+4:])), true
  398. }
  399. }
  400. // check if gi is in previous range
  401. if idx > 0 {
  402. idx--
  403. start, end := u16(ranges[idx*6:]), u16(ranges[idx*6+2:])
  404. if gi >= GlyphIndex(start) && gi <= GlyphIndex(end) {
  405. return int(u16(ranges[idx*6+4:]) + uint16(gi) - start), true
  406. }
  407. }
  408. return 0, false
  409. }
  410. }
  411. // classLookupFunc returns the class ID for the provided glyph. Returns 0
  412. // (default class) for glyphs not covered by this lookup.
  413. type classLookupFunc func(GlyphIndex) int
  414. func (f *Font) makeCachedClassLookup(buf []byte, offset int) ([]byte, classLookupFunc, error) {
  415. var err error
  416. buf, err = f.src.view(buf, offset, 2)
  417. if err != nil {
  418. return buf, nil, err
  419. }
  420. switch u16(buf) {
  421. case 1:
  422. // ClassDefFormat 1: classFormat, startGlyphID, glyphCount, []classValueArray
  423. buf, _, err = f.src.varLenView(buf, offset, 6, 4, 2)
  424. if err != nil {
  425. return buf, nil, err
  426. }
  427. return buf, makeCachedClassLookupFormat1(buf), nil
  428. case 2:
  429. // ClassDefFormat 2: classFormat, classRangeCount, []classRangeRecords
  430. buf, _, err = f.src.varLenView(buf, offset, 4, 2, 6)
  431. if err != nil {
  432. return buf, nil, err
  433. }
  434. return buf, makeCachedClassLookupFormat2(buf), nil
  435. default:
  436. return buf, nil, errUnsupportedClassDefFormat
  437. }
  438. }
  439. func makeCachedClassLookupFormat1(buf []byte) classLookupFunc {
  440. startGI := u16(buf[2:])
  441. num := u16(buf[4:])
  442. classIDs := make([]byte, len(buf)-4)
  443. copy(classIDs, buf[6:])
  444. return func(gi GlyphIndex) int {
  445. // classIDs is an array of target class IDs. gi is the index into that array (minus startGI).
  446. if gi < GlyphIndex(startGI) || gi >= GlyphIndex(startGI+num) {
  447. // default to class 0
  448. return 0
  449. }
  450. return int(u16(classIDs[(int(gi)-int(startGI))*2:]))
  451. }
  452. }
  453. func makeCachedClassLookupFormat2(buf []byte) classLookupFunc {
  454. num := int(u16(buf[2:]))
  455. classRanges := make([]byte, len(buf)-2)
  456. copy(classRanges, buf[4:])
  457. return func(gi GlyphIndex) int {
  458. if num == 0 {
  459. return 0 // default to class 0
  460. }
  461. // classRange is an array of startGlyphID, endGlyphID and target class ID.
  462. // Ranges are non-overlapping.
  463. // E.g. 130, 135, 1 137, 137, 5 etc
  464. idx := sort.Search(num, func(i int) bool {
  465. return gi <= GlyphIndex(u16(classRanges[i*6:]))
  466. })
  467. // idx either points to a matching start, or to the next range (or idx==num)
  468. // e.g. with the range example from above: 130 points to 130-135 range, 133 points to 137-137 range
  469. // check if gi is the start of a range, but only if sort.Search returned a valid result
  470. if idx < num {
  471. if start := u16(classRanges[idx*6:]); gi == GlyphIndex(start) {
  472. return int(u16(classRanges[idx*6+4:]))
  473. }
  474. }
  475. // check if gi is in previous range
  476. if idx > 0 {
  477. idx--
  478. start, end := u16(classRanges[idx*6:]), u16(classRanges[idx*6+2:])
  479. if gi >= GlyphIndex(start) && gi <= GlyphIndex(end) {
  480. return int(u16(classRanges[idx*6+4:]))
  481. }
  482. }
  483. // default to class 0
  484. return 0
  485. }
  486. }