git.lucas.co / go_mono
git clone https://git.lucas.co/go_mono.git

font/font.go (11.2K)

  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 font defines an interface for font faces, for drawing text on an
  6 // image.
  7 //
  8 // Other packages provide font face implementations. For example, a truetype
  9 // package would provide one based on .ttf font files.
 10 package font // import "golang.org/x/image/font"
 11 
 12 import (
 13 	"image"
 14 	"image/draw"
 15 	"io"
 16 	"unicode/utf8"
 17 
 18 	"golang.org/x/image/math/fixed"
 19 )
 20 
 21 // TODO: who is responsible for caches (glyph images, glyph indices, kerns)?
 22 // The Drawer or the Face?
 23 
 24 // Face is a font face. Its glyphs are often derived from a font file, such as
 25 // "Comic_Sans_MS.ttf", but a face has a specific size, style, weight and
 26 // hinting. For example, the 12pt and 18pt versions of Comic Sans are two
 27 // different faces, even if derived from the same font file.
 28 //
 29 // A Face is not safe for concurrent use by multiple goroutines, as its methods
 30 // may re-use implementation-specific caches and mask image buffers.
 31 //
 32 // To create a Face, look to other packages that implement specific font file
 33 // formats.
 34 type Face interface {
 35 	io.Closer
 36 
 37 	// Glyph returns the draw.DrawMask parameters (dr, mask, maskp) to draw r's
 38 	// glyph at the sub-pixel destination location dot, and that glyph's
 39 	// advance width.
 40 	//
 41 	// It returns !ok if the face does not contain a glyph for r. This includes
 42 	// returning !ok for a fallback glyph (such as substituting a U+FFFD glyph
 43 	// or OpenType's .notdef glyph), in which case the other return values may
 44 	// still be non-zero.
 45 	//
 46 	// The contents of the mask image returned by one Glyph call may change
 47 	// after the next Glyph call. Callers that want to cache the mask must make
 48 	// a copy.
 49 	Glyph(dot fixed.Point26_6, r rune) (
 50 		dr image.Rectangle, mask image.Image, maskp image.Point, advance fixed.Int26_6, ok bool)
 51 
 52 	// GlyphBounds returns the bounding box of r's glyph, drawn at a dot equal
 53 	// to the origin, and that glyph's advance width.
 54 	//
 55 	// It returns !ok if the face does not contain a glyph for r. This includes
 56 	// returning !ok for a fallback glyph (such as substituting a U+FFFD glyph
 57 	// or OpenType's .notdef glyph), in which case the other return values may
 58 	// still be non-zero.
 59 	//
 60 	// The glyph's ascent and descent are equal to -bounds.Min.Y and
 61 	// +bounds.Max.Y. The glyph's left-side and right-side bearings are equal
 62 	// to bounds.Min.X and advance-bounds.Max.X. A visual depiction of what
 63 	// these metrics are is at
 64 	// https://developer.apple.com/library/archive/documentation/TextFonts/Conceptual/CocoaTextArchitecture/Art/glyphterms_2x.png
 65 	GlyphBounds(r rune) (bounds fixed.Rectangle26_6, advance fixed.Int26_6, ok bool)
 66 
 67 	// GlyphAdvance returns the advance width of r's glyph.
 68 	//
 69 	// It returns !ok if the face does not contain a glyph for r. This includes
 70 	// returning !ok for a fallback glyph (such as substituting a U+FFFD glyph
 71 	// or OpenType's .notdef glyph), in which case the other return values may
 72 	// still be non-zero.
 73 	GlyphAdvance(r rune) (advance fixed.Int26_6, ok bool)
 74 
 75 	// Kern returns the horizontal adjustment for the kerning pair (r0, r1). A
 76 	// positive kern means to move the glyphs further apart.
 77 	Kern(r0, r1 rune) fixed.Int26_6
 78 
 79 	// Metrics returns the metrics for this Face.
 80 	Metrics() Metrics
 81 
 82 	// TODO: ColoredGlyph for various emoji?
 83 	// TODO: Ligatures? Shaping?
 84 }
 85 
 86 // Metrics holds the metrics for a Face. A visual depiction is at
 87 // https://developer.apple.com/library/mac/documentation/TextFonts/Conceptual/CocoaTextArchitecture/Art/glyph_metrics_2x.png
 88 type Metrics struct {
 89 	// Height is the recommended amount of vertical space between two lines of
 90 	// text.
 91 	Height fixed.Int26_6
 92 
 93 	// Ascent is the distance from the top of a line to its baseline.
 94 	Ascent fixed.Int26_6
 95 
 96 	// Descent is the distance from the bottom of a line to its baseline. The
 97 	// value is typically positive, even though a descender goes below the
 98 	// baseline.
 99 	Descent fixed.Int26_6
100 
101 	// XHeight is the distance from the top of non-ascending lowercase letters
102 	// to the baseline.
103 	XHeight fixed.Int26_6
104 
105 	// CapHeight is the distance from the top of uppercase letters to the
106 	// baseline.
107 	CapHeight fixed.Int26_6
108 
109 	// CaretSlope is the slope of a caret as a vector with the Y axis pointing up.
110 	// The slope {0, 1} is the vertical caret.
111 	CaretSlope image.Point
112 }
113 
114 // Drawer draws text on a destination image.
115 //
116 // A Drawer is not safe for concurrent use by multiple goroutines, since its
117 // Face is not.
118 type Drawer struct {
119 	// Dst is the destination image.
120 	Dst draw.Image
121 	// Src is the source image.
122 	Src image.Image
123 	// Face provides the glyph mask images.
124 	Face Face
125 	// Dot is the baseline location to draw the next glyph. The majority of the
126 	// affected pixels will be above and to the right of the dot, but some may
127 	// be below or to the left. For example, drawing a 'j' in an italic face
128 	// may affect pixels below and to the left of the dot.
129 	Dot fixed.Point26_6
130 
131 	// TODO: Clip image.Image?
132 	// TODO: SrcP image.Point for Src images other than *image.Uniform? How
133 	// does it get updated during DrawString?
134 }
135 
136 // TODO: should DrawString return the last rune drawn, so the next DrawString
137 // call can kern beforehand? Or should that be the responsibility of the caller
138 // if they really want to do that, since they have to explicitly shift d.Dot
139 // anyway? What if ligatures span more than two runes? What if grapheme
140 // clusters span multiple runes?
141 //
142 // TODO: do we assume that the input is in any particular Unicode Normalization
143 // Form?
144 //
145 // TODO: have DrawRunes(s []rune)? DrawRuneReader(io.RuneReader)?? If we take
146 // io.RuneReader, we can't assume that we can rewind the stream.
147 //
148 // TODO: how does this work with line breaking: drawing text up until a
149 // vertical line? Should DrawString return the number of runes drawn?
150 
151 // DrawBytes draws s at the dot and advances the dot's location.
152 //
153 // It is equivalent to DrawString(string(s)) but may be more efficient.
154 func (d *Drawer) DrawBytes(s []byte) {
155 	prevC := rune(-1)
156 	for len(s) > 0 {
157 		c, size := utf8.DecodeRune(s)
158 		s = s[size:]
159 		if prevC >= 0 {
160 			d.Dot.X += d.Face.Kern(prevC, c)
161 		}
162 		dr, mask, maskp, advance, _ := d.Face.Glyph(d.Dot, c)
163 		if !dr.Empty() {
164 			draw.DrawMask(d.Dst, dr, d.Src, image.Point{}, mask, maskp, draw.Over)
165 		}
166 		d.Dot.X += advance
167 		prevC = c
168 	}
169 }
170 
171 // DrawString draws s at the dot and advances the dot's location.
172 func (d *Drawer) DrawString(s string) {
173 	prevC := rune(-1)
174 	for _, c := range s {
175 		if prevC >= 0 {
176 			d.Dot.X += d.Face.Kern(prevC, c)
177 		}
178 		dr, mask, maskp, advance, _ := d.Face.Glyph(d.Dot, c)
179 		if !dr.Empty() {
180 			draw.DrawMask(d.Dst, dr, d.Src, image.Point{}, mask, maskp, draw.Over)
181 		}
182 		d.Dot.X += advance
183 		prevC = c
184 	}
185 }
186 
187 // BoundBytes returns the bounding box of s, drawn at the drawer dot, as well as
188 // the advance.
189 //
190 // It is equivalent to BoundBytes(string(s)) but may be more efficient.
191 func (d *Drawer) BoundBytes(s []byte) (bounds fixed.Rectangle26_6, advance fixed.Int26_6) {
192 	bounds, advance = BoundBytes(d.Face, s)
193 	bounds.Min = bounds.Min.Add(d.Dot)
194 	bounds.Max = bounds.Max.Add(d.Dot)
195 	return
196 }
197 
198 // BoundString returns the bounding box of s, drawn at the drawer dot, as well
199 // as the advance.
200 func (d *Drawer) BoundString(s string) (bounds fixed.Rectangle26_6, advance fixed.Int26_6) {
201 	bounds, advance = BoundString(d.Face, s)
202 	bounds.Min = bounds.Min.Add(d.Dot)
203 	bounds.Max = bounds.Max.Add(d.Dot)
204 	return
205 }
206 
207 // MeasureBytes returns how far dot would advance by drawing s.
208 //
209 // It is equivalent to MeasureString(string(s)) but may be more efficient.
210 func (d *Drawer) MeasureBytes(s []byte) (advance fixed.Int26_6) {
211 	return MeasureBytes(d.Face, s)
212 }
213 
214 // MeasureString returns how far dot would advance by drawing s.
215 func (d *Drawer) MeasureString(s string) (advance fixed.Int26_6) {
216 	return MeasureString(d.Face, s)
217 }
218 
219 // BoundBytes returns the bounding box of s with f, drawn at a dot equal to the
220 // origin, as well as the advance.
221 //
222 // It is equivalent to BoundString(string(s)) but may be more efficient.
223 func BoundBytes(f Face, s []byte) (bounds fixed.Rectangle26_6, advance fixed.Int26_6) {
224 	prevC := rune(-1)
225 	for len(s) > 0 {
226 		c, size := utf8.DecodeRune(s)
227 		s = s[size:]
228 		if prevC >= 0 {
229 			advance += f.Kern(prevC, c)
230 		}
231 		b, a, _ := f.GlyphBounds(c)
232 		if !b.Empty() {
233 			b.Min.X += advance
234 			b.Max.X += advance
235 			bounds = bounds.Union(b)
236 		}
237 		advance += a
238 		prevC = c
239 	}
240 	return
241 }
242 
243 // BoundString returns the bounding box of s with f, drawn at a dot equal to the
244 // origin, as well as the advance.
245 func BoundString(f Face, s string) (bounds fixed.Rectangle26_6, advance fixed.Int26_6) {
246 	prevC := rune(-1)
247 	for _, c := range s {
248 		if prevC >= 0 {
249 			advance += f.Kern(prevC, c)
250 		}
251 		b, a, _ := f.GlyphBounds(c)
252 		if !b.Empty() {
253 			b.Min.X += advance
254 			b.Max.X += advance
255 			bounds = bounds.Union(b)
256 		}
257 		advance += a
258 		prevC = c
259 	}
260 	return
261 }
262 
263 // MeasureBytes returns how far dot would advance by drawing s with f.
264 //
265 // It is equivalent to MeasureString(string(s)) but may be more efficient.
266 func MeasureBytes(f Face, s []byte) (advance fixed.Int26_6) {
267 	prevC := rune(-1)
268 	for len(s) > 0 {
269 		c, size := utf8.DecodeRune(s)
270 		s = s[size:]
271 		if prevC >= 0 {
272 			advance += f.Kern(prevC, c)
273 		}
274 		a, _ := f.GlyphAdvance(c)
275 		advance += a
276 		prevC = c
277 	}
278 	return advance
279 }
280 
281 // MeasureString returns how far dot would advance by drawing s with f.
282 func MeasureString(f Face, s string) (advance fixed.Int26_6) {
283 	prevC := rune(-1)
284 	for _, c := range s {
285 		if prevC >= 0 {
286 			advance += f.Kern(prevC, c)
287 		}
288 		a, _ := f.GlyphAdvance(c)
289 		advance += a
290 		prevC = c
291 	}
292 	return advance
293 }
294 
295 // Hinting selects how to quantize a vector font's glyph nodes.
296 //
297 // Not all fonts support hinting.
298 type Hinting int
299 
300 const (
301 	HintingNone Hinting = iota
302 	HintingVertical
303 	HintingFull
304 )
305 
306 // Stretch selects a normal, condensed, or expanded face.
307 //
308 // Not all fonts support stretches.
309 type Stretch int
310 
311 const (
312 	StretchUltraCondensed Stretch = -4
313 	StretchExtraCondensed Stretch = -3
314 	StretchCondensed      Stretch = -2
315 	StretchSemiCondensed  Stretch = -1
316 	StretchNormal         Stretch = +0
317 	StretchSemiExpanded   Stretch = +1
318 	StretchExpanded       Stretch = +2
319 	StretchExtraExpanded  Stretch = +3
320 	StretchUltraExpanded  Stretch = +4
321 )
322 
323 // Style selects a normal, italic, or oblique face.
324 //
325 // Not all fonts support styles.
326 type Style int
327 
328 const (
329 	StyleNormal Style = iota
330 	StyleItalic
331 	StyleOblique
332 )
333 
334 // Weight selects a normal, light or bold face.
335 //
336 // Not all fonts support weights.
337 //
338 // The named Weight constants (e.g. WeightBold) correspond to CSS' common
339 // weight names (e.g. "Bold"), but the numerical values differ, so that in Go,
340 // the zero value means to use a normal weight. For the CSS names and values,
341 // see https://developer.mozilla.org/en/docs/Web/CSS/font-weight
342 type Weight int
343 
344 const (
345 	WeightThin       Weight = -3 // CSS font-weight value 100.
346 	WeightExtraLight Weight = -2 // CSS font-weight value 200.
347 	WeightLight      Weight = -1 // CSS font-weight value 300.
348 	WeightNormal     Weight = +0 // CSS font-weight value 400.
349 	WeightMedium     Weight = +1 // CSS font-weight value 500.
350 	WeightSemiBold   Weight = +2 // CSS font-weight value 600.
351 	WeightBold       Weight = +3 // CSS font-weight value 700.
352 	WeightExtraBold  Weight = +4 // CSS font-weight value 800.
353 	WeightBlack      Weight = +5 // CSS font-weight value 900.
354 )