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