1
2
3
4
5
6
7
8 package plan9font
9
10 import (
11 "bytes"
12 "errors"
13 "fmt"
14 "image"
15 "image/color"
16 "log"
17 "strconv"
18 "strings"
19
20 "golang.org/x/image/font"
21 "golang.org/x/image/math/fixed"
22 )
23
24
25
26
27
28 type fontchar struct {
29 x uint32
30 top uint8
31 bottom uint8
32 left int8
33 width uint8
34 }
35
36 func parseFontchars(p []byte) []fontchar {
37 fc := make([]fontchar, len(p)/6)
38 for i := range fc {
39 fc[i] = fontchar{
40 x: uint32(p[0]) | uint32(p[1])<<8,
41 top: uint8(p[2]),
42 bottom: uint8(p[3]),
43 left: int8(p[4]),
44 width: uint8(p[5]),
45 }
46 p = p[6:]
47 }
48 return fc
49 }
50
51
52 type subface struct {
53 firstRune rune
54 n int
55 height int
56 ascent int
57 fontchars []fontchar
58 img *image.Alpha
59 }
60
61 func (f *subface) Close() error { return nil }
62 func (f *subface) Kern(r0, r1 rune) fixed.Int26_6 { return 0 }
63
64 func (f *subface) Metrics() font.Metrics {
65
66 xbounds, _, _ := f.GlyphBounds('x')
67
68 hbounds, _, _ := f.GlyphBounds('H')
69 return font.Metrics{
70 Height: fixed.I(f.height),
71 Ascent: fixed.I(f.ascent),
72 Descent: fixed.I(f.height - f.ascent),
73 XHeight: -xbounds.Min.Y,
74 CapHeight: -hbounds.Min.Y,
75 CaretSlope: image.Point{X: 0, Y: 1},
76 }
77 }
78
79 func (f *subface) Glyph(dot fixed.Point26_6, r rune) (
80 dr image.Rectangle, mask image.Image, maskp image.Point, advance fixed.Int26_6, ok bool) {
81
82 r -= f.firstRune
83 if r < 0 || f.n <= int(r) {
84 return image.Rectangle{}, nil, image.Point{}, 0, false
85 }
86 i := &f.fontchars[r+0]
87 j := &f.fontchars[r+1]
88
89 minX := int(dot.X+32)>>6 + int(i.left)
90 minY := int(dot.Y+32)>>6 + int(i.top) - f.ascent
91 dr = image.Rectangle{
92 Min: image.Point{
93 X: minX,
94 Y: minY,
95 },
96 Max: image.Point{
97 X: minX + int(j.x-i.x),
98 Y: minY + int(i.bottom) - int(i.top),
99 },
100 }
101 return dr, f.img, image.Point{int(i.x), int(i.top)}, fixed.Int26_6(i.width) << 6, true
102 }
103
104 func (f *subface) GlyphBounds(r rune) (bounds fixed.Rectangle26_6, advance fixed.Int26_6, ok bool) {
105 r -= f.firstRune
106 if r < 0 || f.n <= int(r) {
107 return fixed.Rectangle26_6{}, 0, false
108 }
109 i := &f.fontchars[r+0]
110 j := &f.fontchars[r+1]
111
112 bounds = fixed.R(
113 int(i.left),
114 int(i.top)-f.ascent,
115 int(i.left)+int(j.x-i.x),
116 int(i.bottom)-f.ascent,
117 )
118 return bounds, fixed.Int26_6(i.width) << 6, true
119 }
120
121 func (f *subface) GlyphAdvance(r rune) (advance fixed.Int26_6, ok bool) {
122 r -= f.firstRune
123 if r < 0 || f.n <= int(r) {
124 return 0, false
125 }
126 return fixed.Int26_6(f.fontchars[r].width) << 6, true
127 }
128
129
130
131 type runeRange struct {
132 lo, hi rune
133 offset rune
134 relFilename string
135 subface *subface
136 bad bool
137 }
138
139
140
141
142
143 type face struct {
144 height int
145 ascent int
146 readFile func(relFilename string) ([]byte, error)
147 runeRanges []runeRange
148 }
149
150 func (f *face) Close() error { return nil }
151 func (f *face) Kern(r0, r1 rune) fixed.Int26_6 { return 0 }
152
153 func (f *face) Metrics() font.Metrics {
154 xbounds, _, _ := f.GlyphBounds('x')
155 hbounds, _, _ := f.GlyphBounds('H')
156 return font.Metrics{
157 Height: fixed.I(f.height),
158 Ascent: fixed.I(f.ascent),
159 Descent: fixed.I(f.height - f.ascent),
160 XHeight: -xbounds.Min.Y,
161 CapHeight: -hbounds.Min.Y,
162 CaretSlope: image.Point{X: 0, Y: 1},
163 }
164 }
165
166 func (f *face) Glyph(dot fixed.Point26_6, r rune) (
167 dr image.Rectangle, mask image.Image, maskp image.Point, advance fixed.Int26_6, ok bool) {
168
169 if s, rr := f.subface(r); s != nil {
170 return s.Glyph(dot, rr)
171 }
172 return image.Rectangle{}, nil, image.Point{}, 0, false
173 }
174
175 func (f *face) GlyphBounds(r rune) (bounds fixed.Rectangle26_6, advance fixed.Int26_6, ok bool) {
176 if s, rr := f.subface(r); s != nil {
177 return s.GlyphBounds(rr)
178 }
179 return fixed.Rectangle26_6{}, 0, false
180 }
181
182 func (f *face) GlyphAdvance(r rune) (advance fixed.Int26_6, ok bool) {
183 if s, rr := f.subface(r); s != nil {
184 return s.GlyphAdvance(rr)
185 }
186 return 0, false
187 }
188
189
190
191
192
193
194 var subfontSuffixes = [...]string{
195 "",
196 ".3",
197 ".2",
198 ".1",
199 ".0",
200 }
201
202 func (f *face) readSubfontFile(name string) ([]byte, error) {
203 var firstErr error
204 for _, suffix := range subfontSuffixes {
205 if b, err := f.readFile(name + suffix); err == nil {
206 return b, nil
207 } else if firstErr == nil {
208 firstErr = err
209 }
210 }
211 return nil, firstErr
212 }
213
214 func (f *face) subface(r rune) (*subface, rune) {
215
216 for _, rr := range [2]rune{r, '\ufffd'} {
217
218
219
220
221
222 for i := range f.runeRanges {
223 x := &f.runeRanges[i]
224 if rr < x.lo || x.hi < rr || x.bad {
225 continue
226 }
227 if x.subface == nil {
228 data, err := f.readSubfontFile(x.relFilename)
229 if err != nil {
230 log.Printf("plan9font: couldn't read subfont %q: %v", x.relFilename, err)
231 x.bad = true
232 continue
233 }
234 sub, err := ParseSubfont(data, x.lo-x.offset)
235 if err != nil {
236 log.Printf("plan9font: couldn't parse subfont %q: %v", x.relFilename, err)
237 x.bad = true
238 continue
239 }
240 x.subface = sub.(*subface)
241 }
242 return x.subface, rr
243 }
244 }
245 return nil, 0
246 }
247
248
249
250
251
252
253 func ParseFont(data []byte, readFile func(relFilename string) ([]byte, error)) (font.Face, error) {
254 f := &face{
255 readFile: readFile,
256 }
257
258 for first := true; len(data) > 0; first = false {
259 i := bytes.IndexByte(data, '\n')
260 if i < 0 {
261 return nil, errors.New("plan9font: invalid font: no final newline")
262 }
263 row := string(data[:i])
264 data = data[i+1:]
265 if first {
266 height, s, ok := nextInt32(row)
267 if !ok {
268 return nil, fmt.Errorf("plan9font: invalid font: invalid header %q", row)
269 }
270 ascent, s, ok := nextInt32(s)
271 if !ok {
272 return nil, fmt.Errorf("plan9font: invalid font: invalid header %q", row)
273 }
274 if height < 0 || 0xffff < height || ascent < 0 || 0xffff < ascent {
275 return nil, fmt.Errorf("plan9font: invalid font: invalid header %q", row)
276 }
277 f.height, f.ascent = int(height), int(ascent)
278 continue
279 }
280 lo, s, ok := nextInt32(row)
281 if !ok {
282 return nil, fmt.Errorf("plan9font: invalid font: invalid row %q", row)
283 }
284 hi, s, ok := nextInt32(s)
285 if !ok {
286 return nil, fmt.Errorf("plan9font: invalid font: invalid row %q", row)
287 }
288 offset, s, _ := nextInt32(s)
289
290 f.runeRanges = append(f.runeRanges, runeRange{
291 lo: lo,
292 hi: hi,
293 offset: offset,
294 relFilename: s,
295 })
296 }
297 return f, nil
298 }
299
300 func nextInt32(s string) (ret int32, remaining string, ok bool) {
301 i := 0
302 for ; i < len(s) && s[i] <= ' '; i++ {
303 }
304 j := i
305 for ; j < len(s) && s[j] > ' '; j++ {
306 }
307 n, err := strconv.ParseInt(s[i:j], 0, 32)
308 if err != nil {
309 return 0, s, false
310 }
311 for ; j < len(s) && s[j] <= ' '; j++ {
312 }
313 return int32(n), s[j:], true
314 }
315
316
317
318
319
320
321 func ParseSubfont(data []byte, firstRune rune) (font.Face, error) {
322 data, m, err := parseImage(data)
323 if err != nil {
324 return nil, err
325 }
326 if len(data) < 3*12 {
327 return nil, errors.New("plan9font: invalid subfont: header too short")
328 }
329 n := atoi(data[0*12:])
330 height := atoi(data[1*12:])
331 ascent := atoi(data[2*12:])
332 data = data[3*12:]
333 if n < 0 || height < 0 || ascent < 0 {
334 return nil, errors.New("plan9font: invalid subfont: dimension too large")
335 } else if len(data) != 6*(n+1) {
336 return nil, errors.New("plan9font: invalid subfont: data length mismatch")
337 }
338
339
340
341 img := image.NewAlpha(m.Bounds())
342 for y := img.Rect.Min.Y; y < img.Rect.Max.Y; y++ {
343 i := img.PixOffset(img.Rect.Min.X, y)
344 for x := img.Rect.Min.X; x < img.Rect.Max.X; x++ {
345 img.Pix[i] = m.at(x, y)
346 i++
347 }
348 }
349
350 return &subface{
351 firstRune: firstRune,
352 n: n,
353 height: height,
354 ascent: ascent,
355 fontchars: parseFontchars(data),
356 img: img,
357 }, nil
358 }
359
360
361
362
363
364
365 type plan9Image struct {
366 depth int
367 width int
368 rect image.Rectangle
369 pix []byte
370 }
371
372 func (m *plan9Image) byteoffset(x, y int) int {
373 x -= m.rect.Min.X
374 y -= m.rect.Min.Y
375 a := y * m.width
376 if m.depth < 8 {
377
378 np := 8 / m.depth
379 if x < 0 {
380 return a + (x-np+1)/np
381 }
382 return a + x/np
383 }
384 return a + x*(m.depth/8)
385 }
386
387 func (m *plan9Image) Bounds() image.Rectangle { return m.rect }
388 func (m *plan9Image) ColorModel() color.Model { return color.AlphaModel }
389
390 func (m *plan9Image) At(x, y int) color.Color {
391 if (image.Point{x, y}).In(m.rect) {
392 return color.Alpha{m.at(x, y)}
393 }
394 return color.Alpha{0x00}
395 }
396
397 func (m *plan9Image) at(x, y int) uint8 {
398 b := m.pix[m.byteoffset(x, y)]
399 switch m.depth {
400 case 1:
401
402 mask := uint8(1 << uint8(7-x&7))
403 if (b & mask) != 0 {
404 return 0xff
405 }
406 return 0
407 case 2:
408
409 shift := uint(x&3) << 1
410
411 y := b << shift
412 y &= 0xc0
413
414 y |= y >> 2
415 y |= y >> 4
416 return y
417 }
418 return 0
419 }
420
421 var compressed = []byte("compressed\n")
422
423 func parseImage(data []byte) (remainingData []byte, m *plan9Image, retErr error) {
424 if !bytes.HasPrefix(data, compressed) {
425 return nil, nil, errors.New("plan9font: unsupported uncompressed format")
426 }
427 data = data[len(compressed):]
428
429 const hdrSize = 5 * 12
430 if len(data) < hdrSize {
431 return nil, nil, errors.New("plan9font: invalid image: header too short")
432 }
433 hdr, data := data[:hdrSize], data[hdrSize:]
434
435
436
437
438 new := false
439 for m := 0; m < 10; m++ {
440 if hdr[m] != ' ' {
441 new = true
442 break
443 }
444 }
445 if hdr[11] != ' ' {
446 return nil, nil, errors.New("plan9font: invalid image: bad header")
447 }
448 if !new {
449 return nil, nil, errors.New("plan9font: unsupported ldepth format")
450 }
451
452 depth := 0
453 switch s := strings.TrimSpace(string(hdr[:1*12])); s {
454 default:
455 return nil, nil, fmt.Errorf("plan9font: unsupported pixel format %q", s)
456 case "k1":
457 depth = 1
458 case "k2":
459 depth = 2
460 }
461 r := ator(hdr[1*12:])
462 if r.Min.X < 0 || r.Max.X < 0 || r.Min.Y < 0 || r.Max.Y < 0 ||
463 r.Min.X > r.Max.X || r.Min.Y > r.Max.Y {
464 return nil, nil, errors.New("plan9font: invalid image: bad rectangle")
465 }
466
467 width := bytesPerLine(r, depth)
468
469
470 if (width > 0xffff) || (r.Dy() > 0x7fff) {
471 return nil, nil, errors.New("plan9font: unsupported dimensions")
472 }
473 m = &plan9Image{
474 depth: depth,
475 width: width,
476 rect: r,
477 pix: make([]byte, width*r.Dy()),
478 }
479
480 miny := r.Min.Y
481 for miny != r.Max.Y {
482 if len(data) < 2*12 {
483 return nil, nil, errors.New("plan9font: invalid image: data band too short")
484 }
485 maxy := atoi(data[0*12:])
486 nb := atoi(data[1*12:])
487 data = data[2*12:]
488 if maxy < 0 || nb < 0 {
489 return nil, nil, errors.New("plan9font: invalid image: dimension too large")
490 } else if len(data) < nb {
491 return nil, nil, errors.New("plan9font: invalid image: data band length mismatch")
492 }
493 buf := data[:nb]
494 data = data[nb:]
495
496 if maxy <= miny || r.Max.Y < maxy {
497 return nil, nil, fmt.Errorf("plan9font: bad maxy %d", maxy)
498 }
499
500
501 rr := r
502 rr.Min.Y = miny
503 rr.Max.Y = maxy
504 if err := decompress(m, rr, buf); err != nil {
505 return nil, nil, err
506 }
507 miny = maxy
508 }
509 return data, m, nil
510 }
511
512
513
514
515 const (
516 compShortestMatch = 3
517 compWindowSize = 1024
518 )
519
520 var (
521 errDecompressBufferTooSmall = errors.New("plan9font: decompress: buffer too small")
522 errDecompressPhaseError = errors.New("plan9font: decompress: phase error")
523 )
524
525 func decompress(m *plan9Image, r image.Rectangle, data []byte) error {
526 if !r.In(m.rect) {
527 return errors.New("plan9font: decompress: bad rectangle")
528 }
529 bpl := bytesPerLine(r, m.depth)
530 mem := make([]byte, compWindowSize)
531 memi := 0
532 omemi := -1
533 y := r.Min.Y
534 linei := m.byteoffset(r.Min.X, y)
535 eline := linei + bpl
536 datai := 0
537 for {
538 if linei == eline {
539 y++
540 if y == r.Max.Y {
541 break
542 }
543 linei = m.byteoffset(r.Min.X, y)
544 eline = linei + bpl
545 }
546 if datai == len(data) {
547 return errDecompressBufferTooSmall
548 }
549 c := data[datai]
550 datai++
551 if c >= 128 {
552 for cnt := c - 128 + 1; cnt != 0; cnt-- {
553 if datai == len(data) {
554 return errDecompressBufferTooSmall
555 }
556 if linei == eline {
557 return errDecompressPhaseError
558 }
559 m.pix[linei] = data[datai]
560 linei++
561 mem[memi] = data[datai]
562 memi++
563 datai++
564 if memi == len(mem) {
565 memi = 0
566 }
567 }
568 } else {
569 if datai == len(data) {
570 return errDecompressBufferTooSmall
571 }
572 offs := int(data[datai]) + ((int(c) & 3) << 8) + 1
573 datai++
574 if memi < offs {
575 omemi = memi + (compWindowSize - offs)
576 } else {
577 omemi = memi - offs
578 }
579 for cnt := (c >> 2) + compShortestMatch; cnt != 0; cnt-- {
580 if linei == eline {
581 return errDecompressPhaseError
582 }
583 m.pix[linei] = mem[omemi]
584 linei++
585 mem[memi] = mem[omemi]
586 memi++
587 omemi++
588 if omemi == len(mem) {
589 omemi = 0
590 }
591 if memi == len(mem) {
592 memi = 0
593 }
594 }
595 }
596 }
597 return nil
598 }
599
600 func ator(b []byte) image.Rectangle {
601 return image.Rectangle{atop(b), atop(b[2*12:])}
602 }
603
604 func atop(b []byte) image.Point {
605 return image.Pt(atoi(b), atoi(b[12:]))
606 }
607
608 func atoi(b []byte) int {
609 i := 0
610 for ; i < len(b) && b[i] == ' '; i++ {
611 }
612 n := 0
613 for ; i < len(b) && '0' <= b[i] && b[i] <= '9'; i++ {
614 n = n*10 + int(b[i]) - '0'
615 if n > 999999 {
616 return -1
617 }
618 }
619 return n
620 }
621
622 func bytesPerLine(r image.Rectangle, depth int) int {
623 if depth <= 0 || 32 < depth {
624 panic("invalid depth")
625 }
626 var l int
627 if r.Min.X >= 0 {
628 l = (r.Max.X*depth + 7) / 8
629 l -= (r.Min.X * depth) / 8
630 } else {
631
632 t := (-r.Min.X*depth + 7) / 8
633 l = t + (r.Max.X*depth+7)/8
634 }
635 return l
636 }
637
View as plain text