encoder.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532
  1. // Copyright ©2021 The star-tex 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-STAR-TEX file.
  4. package tfm
  5. import (
  6. "encoding/binary"
  7. "fmt"
  8. "io"
  9. "sort"
  10. "strings"
  11. "modernc.org/knuth/font/fixed"
  12. )
  13. type label struct {
  14. cc int16
  15. rr int
  16. }
  17. const (
  18. ligsize = 5000
  19. actUnreachable = 0
  20. actPassthrough = 1
  21. actAccessible = 2
  22. )
  23. var (
  24. ascii04 = []byte(" !\"#$%&'()*+,-./0123456789:;<=>?")
  25. ascii10 = []byte("@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_")
  26. ascii14 = []byte("`abcdefghijklmnopqrstuvwxyz{|}~ ")
  27. )
  28. type textEncoder struct {
  29. w io.Writer
  30. err error
  31. lvl int
  32. fntType int
  33. labels []label
  34. act []uint8
  35. boundarychar int16
  36. }
  37. func newTextEncoder(w io.Writer) *textEncoder {
  38. return &textEncoder{
  39. w: w,
  40. fntType: 0,
  41. labels: make([]label, 0, 259),
  42. act: make([]uint8, ligsize),
  43. boundarychar: 256,
  44. }
  45. }
  46. func (te *textEncoder) indent() {
  47. for i := 0; i < te.lvl; i++ {
  48. fmt.Fprintf(te.w, " ")
  49. }
  50. }
  51. func (te *textEncoder) left() {
  52. te.indent()
  53. te.inc()
  54. fmt.Fprintf(te.w, "(")
  55. }
  56. func (te *textEncoder) right() { fmt.Fprintf(te.w, ")\n"); te.dec() }
  57. func (te *textEncoder) inc() { te.lvl++ }
  58. func (te *textEncoder) dec() { te.lvl-- }
  59. func (te *textEncoder) line(vs ...string) {
  60. te.left()
  61. fmt.Fprintf(te.w, strings.Join(vs, " "))
  62. te.right()
  63. }
  64. func (te *textEncoder) bcpl(s string) string {
  65. return s // FIXME(sbinet)
  66. }
  67. func (te *textEncoder) octU32(v uint32) string {
  68. return fmt.Sprintf("O %o", v)
  69. }
  70. func (te *textEncoder) face(v byte) string {
  71. if v >= 18 {
  72. return fmt.Sprintf("O %o", v)
  73. }
  74. const (
  75. mblString = "MBL"
  76. riString = "RI "
  77. rceString = "RCE"
  78. )
  79. s := v & 1
  80. b := v / 2
  81. return "F " + string(mblString[b%3]) + string(riString[s]) + string(rceString[b/3])
  82. }
  83. func (te *textEncoder) fword(v fixed.Int12_20) string {
  84. var (
  85. j byte
  86. delta = int32(10)
  87. raw [4]byte
  88. str string
  89. dig = make([]byte, 0, 12)
  90. )
  91. binary.BigEndian.PutUint32(raw[:], uint32(v))
  92. a := int16(raw[0])*16 + int16(raw[1])/16
  93. f := int32(int(raw[1]&15)*256+int(raw[2]))*256 + int32(raw[3])
  94. if a > 2047 {
  95. str = "-"
  96. a = 4096 - a
  97. if f > 0 {
  98. f = 1048576 - f
  99. a--
  100. }
  101. }
  102. for {
  103. dig = append(dig, 48+byte(a%10))
  104. a /= 10
  105. j++
  106. if a == 0 {
  107. break
  108. }
  109. }
  110. dig = dig[:j]
  111. for i := len(dig)/2 - 1; i >= 0; i-- {
  112. opp := len(dig) - 1 - i
  113. dig[i], dig[opp] = dig[opp], dig[i]
  114. }
  115. str += string(dig[:j]) + "."
  116. f = (f * 10) + 5
  117. for f > delta {
  118. if delta > 1048576 {
  119. f += 524288 - (delta / 2)
  120. }
  121. str += fmt.Sprintf("%d", f/1048576)
  122. f = (f & 1048575) * 10
  123. delta *= 10
  124. }
  125. if strings.HasSuffix(str, ".") {
  126. str += "0"
  127. }
  128. return "R " + str
  129. }
  130. func (te *textEncoder) char(v byte) string {
  131. if te.fntType > 0 {
  132. return fmt.Sprintf(" O %o", v)
  133. }
  134. switch {
  135. case 48 <= v && v <= 57:
  136. return fmt.Sprintf(" C %d", v-48)
  137. case 65 <= v && v <= 90:
  138. return fmt.Sprintf(" C %c", ascii10[v-64])
  139. case 97 <= v && v <= 122:
  140. return fmt.Sprintf(" C %c", ascii14[v-96])
  141. default:
  142. return fmt.Sprintf(" O %o", v)
  143. }
  144. }
  145. func (te *textEncoder) encodeStr(s string) {
  146. fmt.Fprintf(te.w, s)
  147. }
  148. func (te *textEncoder) encode(fnt *Font) error {
  149. te.encodeHeader(fnt)
  150. te.encodeChars(fnt)
  151. return te.err
  152. }
  153. func (te *textEncoder) encodeHeader(fnt *Font) {
  154. if te.err != nil {
  155. return
  156. }
  157. if fnt.hdr.lh < 12 {
  158. return
  159. }
  160. scheme := strings.ToUpper(fnt.body.header.codingScheme)
  161. fntType := fontFamily(scheme)
  162. switch fntType {
  163. case fontTypeMathSym:
  164. te.fntType = 1
  165. case fontTypeMathExt:
  166. te.fntType = 2
  167. default:
  168. fntType = fontTypeVanilla
  169. }
  170. if fnt.hdr.lh >= 17 {
  171. te.line("FAMILY", te.bcpl(strings.ToUpper(fnt.Name())))
  172. if fnt.hdr.lh >= 18 {
  173. te.line("FACE", te.face(fnt.body.header.face))
  174. for i, v := range fnt.body.header.extra {
  175. te.line(fmt.Sprintf("HEADER D %d", i+18), te.octU32(uint32(v)))
  176. }
  177. // for i := 18; i < int(fnt.hdr.lh); i++ {
  178. // te.line(fmt.Sprintf("HEADER D %d", i), te.octU32(uint32(i*4)+24))
  179. // }
  180. }
  181. te.line("CODINGSCHEME", te.bcpl(scheme))
  182. }
  183. te.line("DESIGNSIZE", te.fword(fnt.DesignSize()))
  184. te.line("COMMENT", "DESIGNSIZE IS IN POINTS")
  185. te.line("COMMENT", "OTHER SIZES ARE MULTIPLES OF DESIGNSIZE")
  186. te.line("CHECKSUM", te.octU32(fnt.body.header.chksum))
  187. if fnt.body.header.sevenBitSafe {
  188. te.line("SEVENBITSAFEFLAG", "TRUE")
  189. }
  190. te.encodeFontDimen(fnt, fntType)
  191. te.encodeLigTable(fnt)
  192. }
  193. func (te *textEncoder) encodeFontDimen(fnt *Font, fntType fontFamily) {
  194. if te.err != nil {
  195. return
  196. }
  197. if fnt.hdr.np == 0 {
  198. return
  199. }
  200. te.left()
  201. te.encodeStr("FONTDIMEN\n")
  202. names := []string{
  203. "SLANT", "SPACE", "STRETCH", "SHRINK",
  204. "XHEIGHT", "QUAD", "EXTRASPACE",
  205. }
  206. switch n := len(fnt.body.param); {
  207. case n <= 7:
  208. // ok.
  209. case n <= 22 && fntType == fontTypeMathSym:
  210. names = append(names,
  211. "NUM1", "NUM2", "NUM3",
  212. "DENOM1", "DENOM2",
  213. "SUP1", "SUP2", "SUP3",
  214. "SUB1", "SUB2",
  215. "SUPDROP", "SUBDROP",
  216. "DELIM1", "DELIM2",
  217. "AXISHEIGHT",
  218. )
  219. case n <= 13 && fntType == fontTypeMathExt:
  220. names = append(names,
  221. "DEFAULTRULETHICKNESS",
  222. "BIGOPSPACING1",
  223. "BIGOPSPACING2",
  224. "BIGOPSPACING3",
  225. "BIGOPSPACING4",
  226. "BIGOPSPACING5",
  227. )
  228. default:
  229. panic("invalid np")
  230. }
  231. for i, p := range fnt.body.param {
  232. name := names[i]
  233. te.line(name, te.fword(p))
  234. }
  235. te.indent()
  236. te.right()
  237. switch {
  238. case fntType == fontTypeMathSym && fnt.hdr.np != 22:
  239. panic("invalid math-sym TFM")
  240. case fntType == fontTypeMathExt && fnt.hdr.np != 13:
  241. panic("invalid math-ext TFM")
  242. }
  243. }
  244. func (te *textEncoder) encodeLigTable(fnt *Font) {
  245. if te.err != nil {
  246. return
  247. }
  248. if fnt.hdr.nl == 0 {
  249. return
  250. }
  251. if lk := fnt.body.ligKern[0]; lk.raw[0] == 255 {
  252. te.boundarychar = int16(lk.raw[1])
  253. te.line("BOUNDARYCHAR" + te.char(byte(te.boundarychar)))
  254. te.act[0] = actPassthrough
  255. }
  256. te.buildLabels(fnt)
  257. te.left()
  258. te.encodeStr("LIGTABLE\n")
  259. il := 0
  260. for i, lk := range fnt.body.ligKern {
  261. for i == te.labels[il].rr {
  262. str := ""
  263. switch cc := te.labels[il].cc; cc {
  264. case 256:
  265. str = " BOUNDARYCHAR"
  266. default:
  267. str = te.char(byte(cc))
  268. }
  269. te.line("LABEL" + str)
  270. il++
  271. }
  272. switch {
  273. case lk.raw[0] > 128:
  274. // FIXME(sbinet): check unconditional stop command.
  275. case lk.op() == krnCmd:
  276. line := "KRN" + te.char(byte(lk.nextChar()))
  277. ii := lk.nextIndex()
  278. vv := fnt.body.kern[ii]
  279. line += " " + te.fword(vv)
  280. te.line(line)
  281. case lk.op() == ligCmd:
  282. nxt := lk.nextChar()
  283. switch {
  284. case int(fnt.hdr.bc) <= nxt && nxt < int(fnt.hdr.ec)+1:
  285. // if int(nxt) != int(te.boundarychar) {
  286. // panic(fmt.Errorf("not implemented: BOUNDARYCHAR (%d)", nxt))
  287. // }
  288. case int(lk.raw[3]) < int(fnt.hdr.bc) || int(lk.raw[3]) > int(fnt.hdr.ec):
  289. // FIXME(sbinet): add recover procedure
  290. panic("not implemented: non-existent character")
  291. }
  292. r := lk.raw[2]
  293. if r == 4 || (r > 7 && r != 11) {
  294. // non standard code changed to LIG.
  295. r = 0
  296. }
  297. name := ""
  298. if r&3 > 1 {
  299. name += "/"
  300. }
  301. name += "LIG"
  302. if r&1 != 0 {
  303. name += "/"
  304. }
  305. for r > 3 {
  306. name += ">"
  307. r -= 4
  308. }
  309. te.line(name + te.char(lk.raw[1]) + te.char(lk.raw[3]))
  310. default:
  311. panic("impossible")
  312. }
  313. if lk.raw[0] > 0 {
  314. switch {
  315. case lk.raw[0] >= 128:
  316. te.line("STOP")
  317. default:
  318. // FIXME(sbinet): skip.
  319. te.line("SKIP", "D", "???")
  320. }
  321. }
  322. }
  323. te.indent()
  324. te.right()
  325. }
  326. func (te *textEncoder) buildLabels(fnt *Font) {
  327. te.labels = te.labels[:0]
  328. for i, ci := range fnt.body.glyphs {
  329. kind, rem := ci.kind()
  330. if kind != gkLigKern {
  331. continue
  332. }
  333. if rem < len(fnt.body.ligKern) {
  334. lk := fnt.body.ligKern[rem]
  335. if lk.skipByte() {
  336. rem = int(lk.raw[2])*256 + int(lk.raw[3])
  337. if rem < len(fnt.body.ligKern) {
  338. if te.act[int(ci.raw[3])] == actUnreachable {
  339. te.act[int(ci.raw[3])] = actPassthrough
  340. }
  341. }
  342. }
  343. }
  344. if rem >= len(fnt.body.ligKern) {
  345. panic(fmt.Errorf(
  346. "ligature/kern starting index for character %q is too large",
  347. i,
  348. ))
  349. }
  350. te.act[rem] = actAccessible
  351. te.labels = append(te.labels, label{
  352. cc: int16(i),
  353. rr: rem,
  354. })
  355. }
  356. sort.SliceStable(te.labels, func(i, j int) bool {
  357. return te.labels[i].rr < te.labels[j].rr
  358. })
  359. te.labels = append(te.labels, label{
  360. rr: ligsize,
  361. })
  362. }
  363. func (te *textEncoder) encodeChars(fnt *Font) {
  364. for i, g := range fnt.body.glyphs {
  365. x := byte(i + int(fnt.hdr.bc))
  366. te.left()
  367. te.encodeStr("CHARACTER" + te.char(x) + "\n")
  368. te.line("CHARWD", te.fword(fnt.body.width[g.wd()]))
  369. if i := g.ht(); i > 0 {
  370. te.line("CHARHT", te.fword(fnt.body.height[i]))
  371. }
  372. if i := g.dp(); i > 0 {
  373. te.line("CHARDP", te.fword(fnt.body.depth[i]))
  374. }
  375. if i := g.ic(); i > 0 {
  376. te.line("CHARIC", te.fword(fnt.body.italic[i]))
  377. }
  378. switch g.raw[2] & 3 {
  379. case 0:
  380. // blank case
  381. case 1:
  382. te.left()
  383. te.encodeStr("COMMENT\n")
  384. ii := int(g.raw[3])
  385. rr := fnt.body.ligKern[ii]
  386. if rr.raw[0] > 128 {
  387. ii = int(rr.raw[2])*256 + int(rr.raw[3])
  388. }
  389. for {
  390. lk := fnt.body.ligKern[ii]
  391. switch {
  392. case lk.raw[0] > 128:
  393. // FIXME(sinet): test for unconditional stop cmd address.
  394. case lk.raw[2] >= 128:
  395. line := "KRN" + te.char(lk.raw[1])
  396. rr := lk.nextIndex()
  397. if rr >= len(fnt.body.kern) {
  398. panic("Bad TFM file: Kern index too large.")
  399. }
  400. te.line(line, te.fword(fnt.body.kern[rr]))
  401. default:
  402. // FIXME(sbinet): test ligature step for non-existent char.
  403. // FIXME(sbinet): test lig-step producing non-existent char.
  404. r := int(lk.raw[2])
  405. if r == 4 || (r > 7 && r != 11) {
  406. r = 0
  407. }
  408. name := ""
  409. if r&3 > 1 {
  410. name += "/"
  411. }
  412. name += "LIG"
  413. if r&1 != 0 {
  414. name += "/"
  415. }
  416. for r > 3 {
  417. name += ">"
  418. r -= 4
  419. }
  420. te.line(name + te.char(lk.raw[1]) + te.char(lk.raw[3]))
  421. }
  422. switch {
  423. case lk.raw[0] >= 128:
  424. ii = len(fnt.body.ligKern)
  425. default:
  426. ii += int(lk.raw[0]) + 1
  427. }
  428. if ii >= len(fnt.body.ligKern) {
  429. break
  430. }
  431. }
  432. te.indent()
  433. te.right()
  434. case 2:
  435. // r := int(g.raw[3])
  436. // FIXME(sbinet): test character list to nonexistent character.
  437. // FIXME(sbinet): test cycle in character list.
  438. // for r < i && g.raw[2]&3 == 2 {
  439. // r = int(fnt.body.charInfos[r].raw[3])
  440. // }
  441. // if r == i {
  442. // panic("Bad TFM file: cycle in a character list")
  443. // }
  444. te.line("NEXTLARGER" + te.char(g.raw[3]))
  445. case 3:
  446. if int(g.raw[3]) >= int(fnt.hdr.ne) {
  447. panic("Extensible index for character " + te.octU32(uint32(x)) + " is too large")
  448. }
  449. te.left()
  450. te.encodeStr("VARCHAR\n")
  451. for k := 0; k < 4; k++ {
  452. ik := int(g.raw[3])
  453. ext := fnt.body.exten[ik].raw[k]
  454. if !(k == 3 || ext > 0) {
  455. continue
  456. }
  457. name := [...]string{"TOP", "MID", "BOT", "REP"}[k]
  458. var v byte
  459. switch {
  460. case int(ext) < int(fnt.hdr.bc),
  461. int(ext) > int(fnt.hdr.ec),
  462. ext == 0:
  463. v = g.raw[0] // ? FIXME(sbinet)
  464. default:
  465. v = ext
  466. }
  467. te.line(name + te.char(v))
  468. }
  469. te.indent()
  470. te.right()
  471. }
  472. te.indent()
  473. te.right()
  474. }
  475. }