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
8package plan9font // import "golang.org/x/image/font/plan9font"
9
10import (
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
28type 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
36func 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.
52type 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
61func (f *subface) Close() error                   { return nil }
62func (f *subface) Kern(r0, r1 rune) fixed.Int26_6 { return 0 }
63
64func (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
79func (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
104func (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
121func (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.
131type 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.
143type face struct {
144	height     int
145	ascent     int
146	readFile   func(relFilename string) ([]byte, error)
147	runeRanges []runeRange
148}
149
150func (f *face) Close() error                   { return nil }
151func (f *face) Kern(r0, r1 rune) fixed.Int26_6 { return 0 }
152
153func (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
166func (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
175func (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
182func (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.
194var subfontSuffixes = [...]string{
195	"",
196	".3",
197	".2",
198	".1",
199	".0",
200}
201
202func (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
214func (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.
253func 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
300func 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'.
321func 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 len(data) != 6*(n+1) {
334		return nil, errors.New("plan9font: invalid subfont: data length mismatch")
335	}
336
337	// Convert from plan9Image to image.Alpha, as the standard library's
338	// image/draw package works best when glyph masks are of that type.
339	img := image.NewAlpha(m.Bounds())
340	for y := img.Rect.Min.Y; y < img.Rect.Max.Y; y++ {
341		i := img.PixOffset(img.Rect.Min.X, y)
342		for x := img.Rect.Min.X; x < img.Rect.Max.X; x++ {
343			img.Pix[i] = m.at(x, y)
344			i++
345		}
346	}
347
348	return &subface{
349		firstRune: firstRune,
350		n:         n,
351		height:    height,
352		ascent:    ascent,
353		fontchars: parseFontchars(data),
354		img:       img,
355	}, nil
356}
357
358// plan9Image implements that subset of the Plan 9 image feature set that is
359// used by this font file format.
360//
361// Some features, such as the repl bit and a clip rectangle, are omitted for
362// simplicity.
363type plan9Image struct {
364	depth int             // Depth of the pixels in bits.
365	width int             // Width in bytes of a single scan line.
366	rect  image.Rectangle // Extent of the image.
367	pix   []byte          // Pixel bits.
368}
369
370func (m *plan9Image) byteoffset(x, y int) int {
371	a := y * m.width
372	if m.depth < 8 {
373		// We need to always round down, but Go rounds toward zero.
374		np := 8 / m.depth
375		if x < 0 {
376			return a + (x-np+1)/np
377		}
378		return a + x/np
379	}
380	return a + x*(m.depth/8)
381}
382
383func (m *plan9Image) Bounds() image.Rectangle { return m.rect }
384func (m *plan9Image) ColorModel() color.Model { return color.AlphaModel }
385
386func (m *plan9Image) At(x, y int) color.Color {
387	if (image.Point{x, y}).In(m.rect) {
388		return color.Alpha{m.at(x, y)}
389	}
390	return color.Alpha{0x00}
391}
392
393func (m *plan9Image) at(x, y int) uint8 {
394	b := m.pix[m.byteoffset(x, y)]
395	switch m.depth {
396	case 1:
397		// CGrey, 1.
398		mask := uint8(1 << uint8(7-x&7))
399		if (b & mask) != 0 {
400			return 0xff
401		}
402		return 0
403	case 2:
404		// CGrey, 2.
405		shift := uint(x&3) << 1
406		// Place pixel at top of word.
407		y := b << shift
408		y &= 0xc0
409		// Replicate throughout.
410		y |= y >> 2
411		y |= y >> 4
412		return y
413	}
414	return 0
415}
416
417var compressed = []byte("compressed\n")
418
419func parseImage(data []byte) (remainingData []byte, m *plan9Image, retErr error) {
420	if !bytes.HasPrefix(data, compressed) {
421		return nil, nil, errors.New("plan9font: unsupported uncompressed format")
422	}
423	data = data[len(compressed):]
424
425	const hdrSize = 5 * 12
426	if len(data) < hdrSize {
427		return nil, nil, errors.New("plan9font: invalid image: header too short")
428	}
429	hdr, data := data[:hdrSize], data[hdrSize:]
430
431	// Distinguish new channel descriptor from old ldepth. Channel descriptors
432	// have letters as well as numbers, while ldepths are a single digit
433	// formatted as %-11d.
434	new := false
435	for m := 0; m < 10; m++ {
436		if hdr[m] != ' ' {
437			new = true
438			break
439		}
440	}
441	if hdr[11] != ' ' {
442		return nil, nil, errors.New("plan9font: invalid image: bad header")
443	}
444	if !new {
445		return nil, nil, errors.New("plan9font: unsupported ldepth format")
446	}
447
448	depth := 0
449	switch s := strings.TrimSpace(string(hdr[:1*12])); s {
450	default:
451		return nil, nil, fmt.Errorf("plan9font: unsupported pixel format %q", s)
452	case "k1":
453		depth = 1
454	case "k2":
455		depth = 2
456	}
457	r := ator(hdr[1*12:])
458	if r.Min.X > r.Max.X || r.Min.Y > r.Max.Y {
459		return nil, nil, errors.New("plan9font: invalid image: bad rectangle")
460	}
461
462	width := bytesPerLine(r, depth)
463	m = &plan9Image{
464		depth: depth,
465		width: width,
466		rect:  r,
467		pix:   make([]byte, width*r.Dy()),
468	}
469
470	miny := r.Min.Y
471	for miny != r.Max.Y {
472		if len(data) < 2*12 {
473			return nil, nil, errors.New("plan9font: invalid image: data band too short")
474		}
475		maxy := atoi(data[0*12:])
476		nb := atoi(data[1*12:])
477		data = data[2*12:]
478
479		if len(data) < nb {
480			return nil, nil, errors.New("plan9font: invalid image: data band length mismatch")
481		}
482		buf := data[:nb]
483		data = data[nb:]
484
485		if maxy <= miny || r.Max.Y < maxy {
486			return nil, nil, fmt.Errorf("plan9font: bad maxy %d", maxy)
487		}
488		// An old-format image would flip the bits here, but we don't support
489		// the old format.
490		rr := r
491		rr.Min.Y = miny
492		rr.Max.Y = maxy
493		if err := decompress(m, rr, buf); err != nil {
494			return nil, nil, err
495		}
496		miny = maxy
497	}
498	return data, m, nil
499}
500
501// Compressed data are sequences of byte codes. If the first byte b has the
502// 0x80 bit set, the next (b^0x80)+1 bytes are data. Otherwise, these two bytes
503// specify a previous string to repeat.
504const (
505	compShortestMatch = 3    // shortest match possible.
506	compWindowSize    = 1024 // window size.
507)
508
509var (
510	errDecompressBufferTooSmall = errors.New("plan9font: decompress: buffer too small")
511	errDecompressPhaseError     = errors.New("plan9font: decompress: phase error")
512)
513
514func decompress(m *plan9Image, r image.Rectangle, data []byte) error {
515	if !r.In(m.rect) {
516		return errors.New("plan9font: decompress: bad rectangle")
517	}
518	bpl := bytesPerLine(r, m.depth)
519	mem := make([]byte, compWindowSize)
520	memi := 0
521	omemi := -1
522	y := r.Min.Y
523	linei := m.byteoffset(r.Min.X, y)
524	eline := linei + bpl
525	datai := 0
526	for {
527		if linei == eline {
528			y++
529			if y == r.Max.Y {
530				break
531			}
532			linei = m.byteoffset(r.Min.X, y)
533			eline = linei + bpl
534		}
535		if datai == len(data) {
536			return errDecompressBufferTooSmall
537		}
538		c := data[datai]
539		datai++
540		if c >= 128 {
541			for cnt := c - 128 + 1; cnt != 0; cnt-- {
542				if datai == len(data) {
543					return errDecompressBufferTooSmall
544				}
545				if linei == eline {
546					return errDecompressPhaseError
547				}
548				m.pix[linei] = data[datai]
549				linei++
550				mem[memi] = data[datai]
551				memi++
552				datai++
553				if memi == len(mem) {
554					memi = 0
555				}
556			}
557		} else {
558			if datai == len(data) {
559				return errDecompressBufferTooSmall
560			}
561			offs := int(data[datai]) + ((int(c) & 3) << 8) + 1
562			datai++
563			if memi < offs {
564				omemi = memi + (compWindowSize - offs)
565			} else {
566				omemi = memi - offs
567			}
568			for cnt := (c >> 2) + compShortestMatch; cnt != 0; cnt-- {
569				if linei == eline {
570					return errDecompressPhaseError
571				}
572				m.pix[linei] = mem[omemi]
573				linei++
574				mem[memi] = mem[omemi]
575				memi++
576				omemi++
577				if omemi == len(mem) {
578					omemi = 0
579				}
580				if memi == len(mem) {
581					memi = 0
582				}
583			}
584		}
585	}
586	return nil
587}
588
589func ator(b []byte) image.Rectangle {
590	return image.Rectangle{atop(b), atop(b[2*12:])}
591}
592
593func atop(b []byte) image.Point {
594	return image.Pt(atoi(b), atoi(b[12:]))
595}
596
597func atoi(b []byte) int {
598	i := 0
599	for ; i < len(b) && b[i] == ' '; i++ {
600	}
601	n := 0
602	for ; i < len(b) && '0' <= b[i] && b[i] <= '9'; i++ {
603		n = n*10 + int(b[i]) - '0'
604	}
605	return n
606}
607
608func bytesPerLine(r image.Rectangle, depth int) int {
609	if depth <= 0 || 32 < depth {
610		panic("invalid depth")
611	}
612	var l int
613	if r.Min.X >= 0 {
614		l = (r.Max.X*depth + 7) / 8
615		l -= (r.Min.X * depth) / 8
616	} else {
617		// Make positive before divide.
618		t := (-r.Min.X*depth + 7) / 8
619		l = t + (r.Max.X*depth+7)/8
620	}
621	return l
622}
623