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