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	// XHeight is the distance from the top of non-ascending lowercase letters
91	// to the baseline.
92	XHeight fixed.Int26_6
93
94	// CapHeight is the distance from the top of uppercase letters to the
95	// baseline.
96	CapHeight fixed.Int26_6
97
98	// CaretSlope is the slope of a caret as a vector with the Y axis pointing up.
99	// The slope {0, 1} is the vertical caret.
100	CaretSlope image.Point
101}
102
103// Drawer draws text on a destination image.
104//
105// A Drawer is not safe for concurrent use by multiple goroutines, since its
106// Face is not.
107type Drawer struct {
108	// Dst is the destination image.
109	Dst draw.Image
110	// Src is the source image.
111	Src image.Image
112	// Face provides the glyph mask images.
113	Face Face
114	// Dot is the baseline location to draw the next glyph. The majority of the
115	// affected pixels will be above and to the right of the dot, but some may
116	// be below or to the left. For example, drawing a 'j' in an italic face
117	// may affect pixels below and to the left of the dot.
118	Dot fixed.Point26_6
119
120	// TODO: Clip image.Image?
121	// TODO: SrcP image.Point for Src images other than *image.Uniform? How
122	// does it get updated during DrawString?
123}
124
125// TODO: should DrawString return the last rune drawn, so the next DrawString
126// call can kern beforehand? Or should that be the responsibility of the caller
127// if they really want to do that, since they have to explicitly shift d.Dot
128// anyway? What if ligatures span more than two runes? What if grapheme
129// clusters span multiple runes?
130//
131// TODO: do we assume that the input is in any particular Unicode Normalization
132// Form?
133//
134// TODO: have DrawRunes(s []rune)? DrawRuneReader(io.RuneReader)?? If we take
135// io.RuneReader, we can't assume that we can rewind the stream.
136//
137// TODO: how does this work with line breaking: drawing text up until a
138// vertical line? Should DrawString return the number of runes drawn?
139
140// DrawBytes draws s at the dot and advances the dot's location.
141//
142// It is equivalent to DrawString(string(s)) but may be more efficient.
143func (d *Drawer) DrawBytes(s []byte) {
144	prevC := rune(-1)
145	for len(s) > 0 {
146		c, size := utf8.DecodeRune(s)
147		s = s[size:]
148		if prevC >= 0 {
149			d.Dot.X += d.Face.Kern(prevC, c)
150		}
151		dr, mask, maskp, advance, ok := d.Face.Glyph(d.Dot, c)
152		if !ok {
153			// TODO: is falling back on the U+FFFD glyph the responsibility of
154			// the Drawer or the Face?
155			// TODO: set prevC = '\ufffd'?
156			continue
157		}
158		draw.DrawMask(d.Dst, dr, d.Src, image.Point{}, mask, maskp, draw.Over)
159		d.Dot.X += advance
160		prevC = c
161	}
162}
163
164// DrawString draws s at the dot and advances the dot's location.
165func (d *Drawer) DrawString(s string) {
166	prevC := rune(-1)
167	for _, c := range s {
168		if prevC >= 0 {
169			d.Dot.X += d.Face.Kern(prevC, c)
170		}
171		dr, mask, maskp, advance, ok := d.Face.Glyph(d.Dot, c)
172		if !ok {
173			// TODO: is falling back on the U+FFFD glyph the responsibility of
174			// the Drawer or the Face?
175			// TODO: set prevC = '\ufffd'?
176			continue
177		}
178		draw.DrawMask(d.Dst, dr, d.Src, image.Point{}, mask, maskp, draw.Over)
179		d.Dot.X += advance
180		prevC = c
181	}
182}
183
184// BoundBytes returns the bounding box of s, drawn at the drawer dot, as well as
185// the advance.
186//
187// It is equivalent to BoundBytes(string(s)) but may be more efficient.
188func (d *Drawer) BoundBytes(s []byte) (bounds fixed.Rectangle26_6, advance fixed.Int26_6) {
189	bounds, advance = BoundBytes(d.Face, s)
190	bounds.Min = bounds.Min.Add(d.Dot)
191	bounds.Max = bounds.Max.Add(d.Dot)
192	return
193}
194
195// BoundString returns the bounding box of s, drawn at the drawer dot, as well
196// as the advance.
197func (d *Drawer) BoundString(s string) (bounds fixed.Rectangle26_6, advance fixed.Int26_6) {
198	bounds, advance = BoundString(d.Face, s)
199	bounds.Min = bounds.Min.Add(d.Dot)
200	bounds.Max = bounds.Max.Add(d.Dot)
201	return
202}
203
204// MeasureBytes returns how far dot would advance by drawing s.
205//
206// It is equivalent to MeasureString(string(s)) but may be more efficient.
207func (d *Drawer) MeasureBytes(s []byte) (advance fixed.Int26_6) {
208	return MeasureBytes(d.Face, s)
209}
210
211// MeasureString returns how far dot would advance by drawing s.
212func (d *Drawer) MeasureString(s string) (advance fixed.Int26_6) {
213	return MeasureString(d.Face, s)
214}
215
216// BoundBytes returns the bounding box of s with f, drawn at a dot equal to the
217// origin, as well as the advance.
218//
219// It is equivalent to BoundString(string(s)) but may be more efficient.
220func BoundBytes(f Face, s []byte) (bounds fixed.Rectangle26_6, advance fixed.Int26_6) {
221	prevC := rune(-1)
222	for len(s) > 0 {
223		c, size := utf8.DecodeRune(s)
224		s = s[size:]
225		if prevC >= 0 {
226			advance += f.Kern(prevC, c)
227		}
228		b, a, ok := f.GlyphBounds(c)
229		if !ok {
230			// TODO: is falling back on the U+FFFD glyph the responsibility of
231			// the Drawer or the Face?
232			// TODO: set prevC = '\ufffd'?
233			continue
234		}
235		b.Min.X += advance
236		b.Max.X += advance
237		bounds = bounds.Union(b)
238		advance += a
239		prevC = c
240	}
241	return
242}
243
244// BoundString returns the bounding box of s with f, drawn at a dot equal to the
245// origin, as well as the advance.
246func BoundString(f Face, s string) (bounds fixed.Rectangle26_6, advance fixed.Int26_6) {
247	prevC := rune(-1)
248	for _, c := range s {
249		if prevC >= 0 {
250			advance += f.Kern(prevC, c)
251		}
252		b, a, ok := f.GlyphBounds(c)
253		if !ok {
254			// TODO: is falling back on the U+FFFD glyph the responsibility of
255			// the Drawer or the Face?
256			// TODO: set prevC = '\ufffd'?
257			continue
258		}
259		b.Min.X += advance
260		b.Max.X += advance
261		bounds = bounds.Union(b)
262		advance += a
263		prevC = c
264	}
265	return
266}
267
268// MeasureBytes returns how far dot would advance by drawing s with f.
269//
270// It is equivalent to MeasureString(string(s)) but may be more efficient.
271func MeasureBytes(f Face, s []byte) (advance fixed.Int26_6) {
272	prevC := rune(-1)
273	for len(s) > 0 {
274		c, size := utf8.DecodeRune(s)
275		s = s[size:]
276		if prevC >= 0 {
277			advance += f.Kern(prevC, c)
278		}
279		a, ok := f.GlyphAdvance(c)
280		if !ok {
281			// TODO: is falling back on the U+FFFD glyph the responsibility of
282			// the Drawer or the Face?
283			// TODO: set prevC = '\ufffd'?
284			continue
285		}
286		advance += a
287		prevC = c
288	}
289	return advance
290}
291
292// MeasureString returns how far dot would advance by drawing s with f.
293func MeasureString(f Face, s string) (advance fixed.Int26_6) {
294	prevC := rune(-1)
295	for _, c := range s {
296		if prevC >= 0 {
297			advance += f.Kern(prevC, c)
298		}
299		a, ok := f.GlyphAdvance(c)
300		if !ok {
301			// TODO: is falling back on the U+FFFD glyph the responsibility of
302			// the Drawer or the Face?
303			// TODO: set prevC = '\ufffd'?
304			continue
305		}
306		advance += a
307		prevC = c
308	}
309	return advance
310}
311
312// Hinting selects how to quantize a vector font's glyph nodes.
313//
314// Not all fonts support hinting.
315type Hinting int
316
317const (
318	HintingNone Hinting = iota
319	HintingVertical
320	HintingFull
321)
322
323// Stretch selects a normal, condensed, or expanded face.
324//
325// Not all fonts support stretches.
326type Stretch int
327
328const (
329	StretchUltraCondensed Stretch = -4
330	StretchExtraCondensed Stretch = -3
331	StretchCondensed      Stretch = -2
332	StretchSemiCondensed  Stretch = -1
333	StretchNormal         Stretch = +0
334	StretchSemiExpanded   Stretch = +1
335	StretchExpanded       Stretch = +2
336	StretchExtraExpanded  Stretch = +3
337	StretchUltraExpanded  Stretch = +4
338)
339
340// Style selects a normal, italic, or oblique face.
341//
342// Not all fonts support styles.
343type Style int
344
345const (
346	StyleNormal Style = iota
347	StyleItalic
348	StyleOblique
349)
350
351// Weight selects a normal, light or bold face.
352//
353// Not all fonts support weights.
354//
355// The named Weight constants (e.g. WeightBold) correspond to CSS' common
356// weight names (e.g. "Bold"), but the numerical values differ, so that in Go,
357// the zero value means to use a normal weight. For the CSS names and values,
358// see https://developer.mozilla.org/en/docs/Web/CSS/font-weight
359type Weight int
360
361const (
362	WeightThin       Weight = -3 // CSS font-weight value 100.
363	WeightExtraLight Weight = -2 // CSS font-weight value 200.
364	WeightLight      Weight = -1 // CSS font-weight value 300.
365	WeightNormal     Weight = +0 // CSS font-weight value 400.
366	WeightMedium     Weight = +1 // CSS font-weight value 500.
367	WeightSemiBold   Weight = +2 // CSS font-weight value 600.
368	WeightBold       Weight = +3 // CSS font-weight value 700.
369	WeightExtraBold  Weight = +4 // CSS font-weight value 800.
370	WeightBlack      Weight = +5 // CSS font-weight value 900.
371)
372