...

Source file src/golang.org/x/image/font/plan9font/plan9font.go

Documentation: golang.org/x/image/font/plan9font

     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  }
   637  

View as plain text