9fans.net/go@v0.0.5/draw/buildfont.go (about)

     1  package draw
     2  
     3  import (
     4  	"fmt"
     5  	"strconv"
     6  	"unicode"
     7  )
     8  
     9  func skip(b []byte) []byte {
    10  	for len(b) > 0 && (b[0] == ' ' || b[0] == '\t' || b[0] == '\n') {
    11  		b = b[1:]
    12  	}
    13  	return b
    14  }
    15  
    16  func strtol(b []byte) (int, []byte) {
    17  	b = skip(b)
    18  	i := 0
    19  	if len(b) == 0 || b[0] < '0' || '9' < b[0] {
    20  		return 0, b
    21  	}
    22  	for i < len(b) && '0' <= b[i] && b[i] <= '9' || 'A' <= b[i] && b[i] <= 'Z' || 'a' <= b[i] && b[i] <= 'z' {
    23  		i++
    24  	}
    25  	n, _ := strconv.ParseInt(string(b[:i]), 0, 0)
    26  	return int(n), skip(b[i:])
    27  }
    28  
    29  // BuildFont builds a font of the given name using the description
    30  // provided by the buffer, typically the contents of a font file.
    31  func (d *Display) BuildFont(buf []byte, name string) (*Font, error) {
    32  	d.mu.Lock()
    33  	defer d.mu.Unlock()
    34  	return d.buildFont(buf, name)
    35  }
    36  
    37  func (d *Display) buildFont(buf []byte, name string) (*Font, error) {
    38  	fnt := &Font{
    39  		Display: d,
    40  		Scale:   1,
    41  		Name:    name,
    42  		cache:   make([]cacheinfo, _NFCACHE+_NFLOOK),
    43  		subf:    make([]cachesubf, _NFSUBF),
    44  		age:     1,
    45  	}
    46  	s := buf
    47  	fnt.Height, s = strtol(s)
    48  	fnt.Ascent, s = strtol(s)
    49  	if fnt.Height <= 0 || fnt.Ascent <= 0 {
    50  		return nil, fmt.Errorf("bad height or ascent in font file")
    51  	}
    52  	for {
    53  		if len(s) == 0 || s[0] < '0' || '9' < s[0] {
    54  			goto Errbad
    55  		}
    56  		var min, max int
    57  		min, s = strtol(s)
    58  		if len(s) == 0 || s[0] < '0' || '9' < s[0] {
    59  			goto Errbad
    60  		}
    61  		max, s = strtol(s)
    62  		if len(s) == 0 || min > unicode.MaxRune || max > unicode.MaxRune || min > max {
    63  			return nil, fmt.Errorf("illegal subfont range")
    64  		}
    65  		offset, t := strtol(s)
    66  		if len(t) < len(s) {
    67  			s = t
    68  		}
    69  		c := &cachefont{
    70  			min:    rune(min),
    71  			max:    rune(max),
    72  			offset: offset,
    73  		}
    74  		t = s
    75  		for len(s) > 0 && s[0] != ' ' && s[0] != '\n' && s[0] != '\t' {
    76  			s = s[1:]
    77  		}
    78  		c.name = string(t[:len(t)-len(s)])
    79  		fnt.sub = append(fnt.sub, c)
    80  		s = skip(s)
    81  		if len(s) == 0 {
    82  			break
    83  		}
    84  	}
    85  	return fnt, nil
    86  
    87  Errbad:
    88  	return nil, fmt.Errorf("bad font format: number expected (char position %d)", len(buf)-len(s))
    89  }
    90  
    91  // Free frees the server resources for the Font. Fonts have a finalizer that
    92  // calls Free automatically, if necessary, for garbage collected Images, but it
    93  // is more efficient to be explicit.
    94  // TODO: Implement the Finalizer!
    95  func (f *Font) Free() {
    96  	if f == nil {
    97  		return
    98  	}
    99  	f.lock()
   100  	defer f.unlock()
   101  
   102  	if f.ondisplaylist {
   103  		f.ondisplaylist = false
   104  		if f.next != nil {
   105  			f.next.prev = f.prev
   106  		} else {
   107  			f.Display.lastfont = f.prev
   108  		}
   109  		if f.prev != nil {
   110  			f.prev.next = f.next
   111  		} else {
   112  			f.Display.firstfont = f.next
   113  		}
   114  	}
   115  
   116  	if f.lodpi != f {
   117  		f.lodpi.Free()
   118  	}
   119  	if f.hidpi != f {
   120  		f.hidpi.Free()
   121  	}
   122  
   123  	f.free()
   124  }
   125  
   126  func (f *Font) free() {
   127  	if f == nil {
   128  		return
   129  	}
   130  	for _, subf := range f.subf {
   131  		s := subf.f
   132  		if s != nil && (f.Display == nil || s != f.Display.defaultSubfont) {
   133  			s.free()
   134  		}
   135  	}
   136  	f.cacheimage.free()
   137  }