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