git clone https://git.lucas.co/go_mono.git
font/plan9font/plan9font.go (16.4K)
1 // Copyright 2015 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
5 // Package plan9font implements font faces for the Plan 9 font and subfont file
6 // formats. These formats are described at
7 // https://9p.io/magic/man2html/6/font
8 package plan9font // import "golang.org/x/image/font/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 // fontchar describes one character glyph in a subfont.
25 //
26 // For more detail, look for "struct Fontchar" in
27 // https://9p.io/magic/man2html/2/cachechars
28 type fontchar struct {
29 x uint32 // X position in the image holding the glyphs.
30 top uint8 // First non-zero scan line.
31 bottom uint8 // Last non-zero scan line.
32 left int8 // Offset of baseline.
33 width uint8 // Width of baseline.
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 // subface implements font.Face for a Plan 9 subfont.
52 type subface struct {
53 firstRune rune // First rune in the subfont.
54 n int // Number of characters in the subfont.
55 height int // Inter-line spacing.
56 ascent int // Height above the baseline.
57 fontchars []fontchar // Character descriptions.
58 img *image.Alpha // Image holding the glyphs.
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 // Approximate XHeight with the ascent of lowercase 'x'.
66 xbounds, _, _ := f.GlyphBounds('x')
67 // The same applies to CapHeight, using the uppercase 'H'.
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 // runeRange maps a single rune range [lo, hi] to a lazily loaded subface. Both
130 // ends of the range are inclusive.
131 type runeRange struct {
132 lo, hi rune
133 offset rune // subfont index that the lo rune maps to.
134 relFilename string
135 subface *subface
136 bad bool
137 }
138
139 // face implements font.Face for a Plan 9 font.
140 //
141 // It maps multiple rune ranges to *subface values. Rune ranges may overlap;
142 // the first match wins.
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 // For subfont files, if reading the given file name fails, we try appending
190 // ".n" where n is the log2 of the grayscale depth in bits (so at most 3) and
191 // then work down to 0. This was done in Plan 9 when antialiased fonts were
192 // introduced so that the 1-bit displays could keep using the 1-bit forms but
193 // higher depth displays could use the antialiased forms.
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 // Fall back on U+FFFD if we can't find r.
216 for _, rr := range [2]rune{r, '\ufffd'} {
217 // We have to do linear, not binary search. plan9port's
218 // lucsans/unicode.8.font says:
219 // 0x2591 0x2593 ../luc/Altshades.7.0
220 // 0x2500 0x25ee ../luc/FormBlock.7.0
221 // and the rune ranges overlap.
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 // ParseFont parses a Plan 9 font file. data is the contents of that font file,
249 // which gives relative filenames for subfont files. readFile returns the
250 // contents of those subfont files. It is similar to io/ioutil's ReadFile
251 // function, except that it takes a relative filename instead of an absolute
252 // one.
253 func ParseFont(data []byte, readFile func(relFilename string) ([]byte, error)) (font.Face, error) {
254 f := &face{
255 readFile: readFile,
256 }
257 // TODO: don't use strconv, to avoid the conversions from []byte to string?
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 // ParseSubfont parses a Plan 9 subfont file.
317 //
318 // firstRune is the first rune in the subfont file. For example, the
319 // Phonetic.6.0 subfont, containing glyphs in the range U+0250 to U+02E9, would
320 // set firstRune to '\u0250'.
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 // Convert from plan9Image to image.Alpha, as the standard library's
340 // image/draw package works best when glyph masks are of that type.
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 // plan9Image implements that subset of the Plan 9 image feature set that is
361 // used by this font file format.
362 //
363 // Some features, such as the repl bit and a clip rectangle, are omitted for
364 // simplicity.
365 type plan9Image struct {
366 depth int // Depth of the pixels in bits.
367 width int // Width in bytes of a single scan line.
368 rect image.Rectangle // Extent of the image.
369 pix []byte // Pixel bits.
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 // We need to always round down, but Go rounds toward zero.
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 // CGrey, 1.
402 mask := uint8(1 << uint8(7-x&7))
403 if (b & mask) != 0 {
404 return 0xff
405 }
406 return 0
407 case 2:
408 // CGrey, 2.
409 shift := uint(x&3) << 1
410 // Place pixel at top of word.
411 y := b << shift
412 y &= 0xc0
413 // Replicate throughout.
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 // Distinguish new channel descriptor from old ldepth. Channel descriptors
436 // have letters as well as numbers, while ldepths are a single digit
437 // formatted as %-11d.
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 // These bounds are somewhat arbitrary, but multiplying them together won't
469 // overflow an int32.
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 // An old-format image would flip the bits here, but we don't support
500 // the old format.
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 // Compressed data are sequences of byte codes. If the first byte b has the
513 // 0x80 bit set, the next (b^0x80)+1 bytes are data. Otherwise, these two bytes
514 // specify a previous string to repeat.
515 const (
516 compShortestMatch = 3 // shortest match possible.
517 compWindowSize = 1024 // window size.
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 // Make positive before divide.
632 t := (-r.Min.X*depth + 7) / 8
633 l = t + (r.Max.X*depth+7)/8
634 }
635 return l
636 }