git.lucas.co / go_mono
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 }