font: add a []byte flavor of string methods.
Change-Id: I2506067ba6ac12c275b65c3a52cb38579d4b9dca Reviewed-on: https://go-review.googlesource.com/23464 Reviewed-by: David Crawshaw <crawshaw@golang.org>
This commit is contained in:
parent
51ddfee6f3
commit
97680175a5
79
font/font.go
79
font/font.go
|
@ -13,6 +13,7 @@ import (
|
||||||
"image"
|
"image"
|
||||||
"image/draw"
|
"image/draw"
|
||||||
"io"
|
"io"
|
||||||
|
"unicode/utf8"
|
||||||
|
|
||||||
"golang.org/x/image/math/fixed"
|
"golang.org/x/image/math/fixed"
|
||||||
)
|
)
|
||||||
|
@ -87,9 +88,6 @@ type Metrics struct {
|
||||||
Descent fixed.Int26_6
|
Descent fixed.Int26_6
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Drawer.Layout or Drawer.Measure methods to measure text without
|
|
||||||
// drawing?
|
|
||||||
|
|
||||||
// Drawer draws text on a destination image.
|
// Drawer draws text on a destination image.
|
||||||
//
|
//
|
||||||
// A Drawer is not safe for concurrent use by multiple goroutines, since its
|
// A Drawer is not safe for concurrent use by multiple goroutines, since its
|
||||||
|
@ -115,19 +113,25 @@ type Drawer struct {
|
||||||
// TODO: should DrawString return the last rune drawn, so the next DrawString
|
// TODO: should DrawString return the last rune drawn, so the next DrawString
|
||||||
// call can kern beforehand? Or should that be the responsibility of the caller
|
// call can kern beforehand? Or should that be the responsibility of the caller
|
||||||
// if they really want to do that, since they have to explicitly shift d.Dot
|
// if they really want to do that, since they have to explicitly shift d.Dot
|
||||||
// anyway?
|
// anyway? What if ligatures span more than two runes? What if grapheme
|
||||||
|
// clusters span multiple runes?
|
||||||
//
|
//
|
||||||
// In general, we'd have a DrawBytes([]byte) and DrawRuneReader(io.RuneReader)
|
// TODO: do we assume that the input is in any particular Unicode Normalization
|
||||||
// and the last case can't assume that you can rewind the stream.
|
// Form?
|
||||||
|
//
|
||||||
|
// TODO: have DrawRunes(s []rune)? DrawRuneReader(io.RuneReader)?? If we take
|
||||||
|
// io.RuneReader, we can't assume that we can rewind the stream.
|
||||||
//
|
//
|
||||||
// TODO: how does this work with line breaking: drawing text up until a
|
// TODO: how does this work with line breaking: drawing text up until a
|
||||||
// vertical line? Should DrawString return the number of runes drawn?
|
// vertical line? Should DrawString return the number of runes drawn?
|
||||||
|
|
||||||
// DrawString draws s at the dot and advances the dot's location.
|
// DrawBytes draws s at the dot and advances the dot's location.
|
||||||
func (d *Drawer) DrawString(s string) {
|
func (d *Drawer) DrawBytes(s []byte) {
|
||||||
var prevC rune
|
prevC := rune(-1)
|
||||||
for i, c := range s {
|
for len(s) > 0 {
|
||||||
if i != 0 {
|
c, size := utf8.DecodeRune(s)
|
||||||
|
s = s[size:]
|
||||||
|
if prevC >= 0 {
|
||||||
d.Dot.X += d.Face.Kern(prevC, c)
|
d.Dot.X += d.Face.Kern(prevC, c)
|
||||||
}
|
}
|
||||||
dr, mask, maskp, advance, ok := d.Face.Glyph(d.Dot, c)
|
dr, mask, maskp, advance, ok := d.Face.Glyph(d.Dot, c)
|
||||||
|
@ -143,16 +147,63 @@ func (d *Drawer) DrawString(s string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DrawString draws s at the dot and advances the dot's location.
|
||||||
|
func (d *Drawer) DrawString(s string) {
|
||||||
|
prevC := rune(-1)
|
||||||
|
for _, c := range s {
|
||||||
|
if prevC >= 0 {
|
||||||
|
d.Dot.X += d.Face.Kern(prevC, c)
|
||||||
|
}
|
||||||
|
dr, mask, maskp, advance, ok := d.Face.Glyph(d.Dot, c)
|
||||||
|
if !ok {
|
||||||
|
// TODO: is falling back on the U+FFFD glyph the responsibility of
|
||||||
|
// the Drawer or the Face?
|
||||||
|
// TODO: set prevC = '\ufffd'?
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
draw.DrawMask(d.Dst, dr, d.Src, image.Point{}, mask, maskp, draw.Over)
|
||||||
|
d.Dot.X += advance
|
||||||
|
prevC = c
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MeasureBytes returns how far dot would advance by drawing s.
|
||||||
|
func (d *Drawer) MeasureBytes(s []byte) (advance fixed.Int26_6) {
|
||||||
|
return MeasureBytes(d.Face, s)
|
||||||
|
}
|
||||||
|
|
||||||
// MeasureString returns how far dot would advance by drawing s.
|
// MeasureString returns how far dot would advance by drawing s.
|
||||||
func (d *Drawer) MeasureString(s string) (advance fixed.Int26_6) {
|
func (d *Drawer) MeasureString(s string) (advance fixed.Int26_6) {
|
||||||
return MeasureString(d.Face, s)
|
return MeasureString(d.Face, s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MeasureBytes returns how far dot would advance by drawing s with f.
|
||||||
|
func MeasureBytes(f Face, s []byte) (advance fixed.Int26_6) {
|
||||||
|
prevC := rune(-1)
|
||||||
|
for len(s) > 0 {
|
||||||
|
c, size := utf8.DecodeRune(s)
|
||||||
|
s = s[size:]
|
||||||
|
if prevC >= 0 {
|
||||||
|
advance += f.Kern(prevC, c)
|
||||||
|
}
|
||||||
|
a, ok := f.GlyphAdvance(c)
|
||||||
|
if !ok {
|
||||||
|
// TODO: is falling back on the U+FFFD glyph the responsibility of
|
||||||
|
// the Drawer or the Face?
|
||||||
|
// TODO: set prevC = '\ufffd'?
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
advance += a
|
||||||
|
prevC = c
|
||||||
|
}
|
||||||
|
return advance
|
||||||
|
}
|
||||||
|
|
||||||
// MeasureString returns how far dot would advance by drawing s with f.
|
// MeasureString returns how far dot would advance by drawing s with f.
|
||||||
func MeasureString(f Face, s string) (advance fixed.Int26_6) {
|
func MeasureString(f Face, s string) (advance fixed.Int26_6) {
|
||||||
var prevC rune
|
prevC := rune(-1)
|
||||||
for i, c := range s {
|
for _, c := range s {
|
||||||
if i != 0 {
|
if prevC >= 0 {
|
||||||
advance += f.Kern(prevC, c)
|
advance += f.Kern(prevC, c)
|
||||||
}
|
}
|
||||||
a, ok := f.GlyphAdvance(c)
|
a, ok := f.GlyphAdvance(c)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user