...

Source file src/github.com/golang/freetype/truetype/face.go

Documentation: github.com/golang/freetype/truetype

     1  // Copyright 2015 The Freetype-Go Authors. All rights reserved.
     2  // Use of this source code is governed by your choice of either the
     3  // FreeType License or the GNU General Public License version 2 (or
     4  // any later version), both of which can be found in the LICENSE file.
     5  
     6  package truetype
     7  
     8  import (
     9  	"image"
    10  	"math"
    11  
    12  	"github.com/golang/freetype/raster"
    13  	"golang.org/x/image/font"
    14  	"golang.org/x/image/math/fixed"
    15  )
    16  
    17  func powerOf2(i int) bool {
    18  	return i != 0 && (i&(i-1)) == 0
    19  }
    20  
    21  // Options are optional arguments to NewFace.
    22  type Options struct {
    23  	// Size is the font size in points, as in "a 10 point font size".
    24  	//
    25  	// A zero value means to use a 12 point font size.
    26  	Size float64
    27  
    28  	// DPI is the dots-per-inch resolution.
    29  	//
    30  	// A zero value means to use 72 DPI.
    31  	DPI float64
    32  
    33  	// Hinting is how to quantize the glyph nodes.
    34  	//
    35  	// A zero value means to use no hinting.
    36  	Hinting font.Hinting
    37  
    38  	// GlyphCacheEntries is the number of entries in the glyph mask image
    39  	// cache.
    40  	//
    41  	// If non-zero, it must be a power of 2.
    42  	//
    43  	// A zero value means to use 512 entries.
    44  	GlyphCacheEntries int
    45  
    46  	// SubPixelsX is the number of sub-pixel locations a glyph's dot is
    47  	// quantized to, in the horizontal direction. For example, a value of 8
    48  	// means that the dot is quantized to 1/8th of a pixel. This quantization
    49  	// only affects the glyph mask image, not its bounding box or advance
    50  	// width. A higher value gives a more faithful glyph image, but reduces the
    51  	// effectiveness of the glyph cache.
    52  	//
    53  	// If non-zero, it must be a power of 2, and be between 1 and 64 inclusive.
    54  	//
    55  	// A zero value means to use 4 sub-pixel locations.
    56  	SubPixelsX int
    57  
    58  	// SubPixelsY is the number of sub-pixel locations a glyph's dot is
    59  	// quantized to, in the vertical direction. For example, a value of 8
    60  	// means that the dot is quantized to 1/8th of a pixel. This quantization
    61  	// only affects the glyph mask image, not its bounding box or advance
    62  	// width. A higher value gives a more faithful glyph image, but reduces the
    63  	// effectiveness of the glyph cache.
    64  	//
    65  	// If non-zero, it must be a power of 2, and be between 1 and 64 inclusive.
    66  	//
    67  	// A zero value means to use 1 sub-pixel location.
    68  	SubPixelsY int
    69  }
    70  
    71  func (o *Options) size() float64 {
    72  	if o != nil && o.Size > 0 {
    73  		return o.Size
    74  	}
    75  	return 12
    76  }
    77  
    78  func (o *Options) dpi() float64 {
    79  	if o != nil && o.DPI > 0 {
    80  		return o.DPI
    81  	}
    82  	return 72
    83  }
    84  
    85  func (o *Options) hinting() font.Hinting {
    86  	if o != nil {
    87  		switch o.Hinting {
    88  		case font.HintingVertical, font.HintingFull:
    89  			// TODO: support vertical hinting.
    90  			return font.HintingFull
    91  		}
    92  	}
    93  	return font.HintingNone
    94  }
    95  
    96  func (o *Options) glyphCacheEntries() int {
    97  	if o != nil && powerOf2(o.GlyphCacheEntries) {
    98  		return o.GlyphCacheEntries
    99  	}
   100  	// 512 is 128 * 4 * 1, which lets us cache 128 glyphs at 4 * 1 subpixel
   101  	// locations in the X and Y direction.
   102  	return 512
   103  }
   104  
   105  func (o *Options) subPixelsX() (value uint32, halfQuantum, mask fixed.Int26_6) {
   106  	if o != nil {
   107  		switch o.SubPixelsX {
   108  		case 1, 2, 4, 8, 16, 32, 64:
   109  			return subPixels(o.SubPixelsX)
   110  		}
   111  	}
   112  	// This default value of 4 isn't based on anything scientific, merely as
   113  	// small a number as possible that looks almost as good as no quantization,
   114  	// or returning subPixels(64).
   115  	return subPixels(4)
   116  }
   117  
   118  func (o *Options) subPixelsY() (value uint32, halfQuantum, mask fixed.Int26_6) {
   119  	if o != nil {
   120  		switch o.SubPixelsX {
   121  		case 1, 2, 4, 8, 16, 32, 64:
   122  			return subPixels(o.SubPixelsX)
   123  		}
   124  	}
   125  	// This default value of 1 isn't based on anything scientific, merely that
   126  	// vertical sub-pixel glyph rendering is pretty rare. Baseline locations
   127  	// can usually afford to snap to the pixel grid, so the vertical direction
   128  	// doesn't have the deal with the horizontal's fractional advance widths.
   129  	return subPixels(1)
   130  }
   131  
   132  // subPixels returns q and the bias and mask that leads to q quantized
   133  // sub-pixel locations per full pixel.
   134  //
   135  // For example, q == 4 leads to a bias of 8 and a mask of 0xfffffff0, or -16,
   136  // because we want to round fractions of fixed.Int26_6 as:
   137  //	-  0 to  7 rounds to 0.
   138  //	-  8 to 23 rounds to 16.
   139  //	- 24 to 39 rounds to 32.
   140  //	- 40 to 55 rounds to 48.
   141  //	- 56 to 63 rounds to 64.
   142  // which means to add 8 and then bitwise-and with -16, in two's complement
   143  // representation.
   144  //
   145  // When q ==  1, we want bias == 32 and mask == -64.
   146  // When q ==  2, we want bias == 16 and mask == -32.
   147  // When q ==  4, we want bias ==  8 and mask == -16.
   148  // ...
   149  // When q == 64, we want bias ==  0 and mask ==  -1. (The no-op case).
   150  // The pattern is clear.
   151  func subPixels(q int) (value uint32, bias, mask fixed.Int26_6) {
   152  	return uint32(q), 32 / fixed.Int26_6(q), -64 / fixed.Int26_6(q)
   153  }
   154  
   155  // glyphCacheEntry caches the arguments and return values of rasterize.
   156  type glyphCacheEntry struct {
   157  	key glyphCacheKey
   158  	val glyphCacheVal
   159  }
   160  
   161  type glyphCacheKey struct {
   162  	index  Index
   163  	fx, fy uint8
   164  }
   165  
   166  type glyphCacheVal struct {
   167  	advanceWidth fixed.Int26_6
   168  	offset       image.Point
   169  	gw           int
   170  	gh           int
   171  }
   172  
   173  type indexCacheEntry struct {
   174  	rune  rune
   175  	index Index
   176  }
   177  
   178  // NewFace returns a new font.Face for the given Font.
   179  func NewFace(f *Font, opts *Options) font.Face {
   180  	a := &face{
   181  		f:          f,
   182  		hinting:    opts.hinting(),
   183  		scale:      fixed.Int26_6(0.5 + (opts.size() * opts.dpi() * 64 / 72)),
   184  		glyphCache: make([]glyphCacheEntry, opts.glyphCacheEntries()),
   185  	}
   186  	a.subPixelX, a.subPixelBiasX, a.subPixelMaskX = opts.subPixelsX()
   187  	a.subPixelY, a.subPixelBiasY, a.subPixelMaskY = opts.subPixelsY()
   188  
   189  	// Fill the cache with invalid entries. Valid glyph cache entries have fx
   190  	// and fy in the range [0, 64). Valid index cache entries have rune >= 0.
   191  	for i := range a.glyphCache {
   192  		a.glyphCache[i].key.fy = 0xff
   193  	}
   194  	for i := range a.indexCache {
   195  		a.indexCache[i].rune = -1
   196  	}
   197  
   198  	// Set the rasterizer's bounds to be big enough to handle the largest glyph.
   199  	b := f.Bounds(a.scale)
   200  	xmin := +int(b.Min.X) >> 6
   201  	ymin := -int(b.Max.Y) >> 6
   202  	xmax := +int(b.Max.X+63) >> 6
   203  	ymax := -int(b.Min.Y-63) >> 6
   204  	a.maxw = xmax - xmin
   205  	a.maxh = ymax - ymin
   206  	a.masks = image.NewAlpha(image.Rect(0, 0, a.maxw, a.maxh*len(a.glyphCache)))
   207  	a.r.SetBounds(a.maxw, a.maxh)
   208  	a.p = facePainter{a}
   209  
   210  	return a
   211  }
   212  
   213  type face struct {
   214  	f             *Font
   215  	hinting       font.Hinting
   216  	scale         fixed.Int26_6
   217  	subPixelX     uint32
   218  	subPixelBiasX fixed.Int26_6
   219  	subPixelMaskX fixed.Int26_6
   220  	subPixelY     uint32
   221  	subPixelBiasY fixed.Int26_6
   222  	subPixelMaskY fixed.Int26_6
   223  	masks         *image.Alpha
   224  	glyphCache    []glyphCacheEntry
   225  	r             raster.Rasterizer
   226  	p             raster.Painter
   227  	paintOffset   int
   228  	maxw          int
   229  	maxh          int
   230  	glyphBuf      GlyphBuf
   231  	indexCache    [indexCacheLen]indexCacheEntry
   232  
   233  	// TODO: clip rectangle?
   234  }
   235  
   236  const indexCacheLen = 256
   237  
   238  func (a *face) index(r rune) Index {
   239  	const mask = indexCacheLen - 1
   240  	c := &a.indexCache[r&mask]
   241  	if c.rune == r {
   242  		return c.index
   243  	}
   244  	i := a.f.Index(r)
   245  	c.rune = r
   246  	c.index = i
   247  	return i
   248  }
   249  
   250  // Close satisfies the font.Face interface.
   251  func (a *face) Close() error { return nil }
   252  
   253  // Metrics satisfies the font.Face interface.
   254  func (a *face) Metrics() font.Metrics {
   255  	scale := float64(a.scale)
   256  	fupe := float64(a.f.FUnitsPerEm())
   257  	return font.Metrics{
   258  		Height:  a.scale,
   259  		Ascent:  fixed.Int26_6(math.Ceil(scale * float64(+a.f.ascent) / fupe)),
   260  		Descent: fixed.Int26_6(math.Ceil(scale * float64(-a.f.descent) / fupe)),
   261  	}
   262  }
   263  
   264  // Kern satisfies the font.Face interface.
   265  func (a *face) Kern(r0, r1 rune) fixed.Int26_6 {
   266  	i0 := a.index(r0)
   267  	i1 := a.index(r1)
   268  	kern := a.f.Kern(a.scale, i0, i1)
   269  	if a.hinting != font.HintingNone {
   270  		kern = (kern + 32) &^ 63
   271  	}
   272  	return kern
   273  }
   274  
   275  // Glyph satisfies the font.Face interface.
   276  func (a *face) Glyph(dot fixed.Point26_6, r rune) (
   277  	dr image.Rectangle, mask image.Image, maskp image.Point, advance fixed.Int26_6, ok bool) {
   278  
   279  	// Quantize to the sub-pixel granularity.
   280  	dotX := (dot.X + a.subPixelBiasX) & a.subPixelMaskX
   281  	dotY := (dot.Y + a.subPixelBiasY) & a.subPixelMaskY
   282  
   283  	// Split the coordinates into their integer and fractional parts.
   284  	ix, fx := int(dotX>>6), dotX&0x3f
   285  	iy, fy := int(dotY>>6), dotY&0x3f
   286  
   287  	index := a.index(r)
   288  	cIndex := uint32(index)
   289  	cIndex = cIndex*a.subPixelX - uint32(fx/a.subPixelMaskX)
   290  	cIndex = cIndex*a.subPixelY - uint32(fy/a.subPixelMaskY)
   291  	cIndex &= uint32(len(a.glyphCache) - 1)
   292  	a.paintOffset = a.maxh * int(cIndex)
   293  	k := glyphCacheKey{
   294  		index: index,
   295  		fx:    uint8(fx),
   296  		fy:    uint8(fy),
   297  	}
   298  	var v glyphCacheVal
   299  	if a.glyphCache[cIndex].key != k {
   300  		var ok bool
   301  		v, ok = a.rasterize(index, fx, fy)
   302  		if !ok {
   303  			return image.Rectangle{}, nil, image.Point{}, 0, false
   304  		}
   305  		a.glyphCache[cIndex] = glyphCacheEntry{k, v}
   306  	} else {
   307  		v = a.glyphCache[cIndex].val
   308  	}
   309  
   310  	dr.Min = image.Point{
   311  		X: ix + v.offset.X,
   312  		Y: iy + v.offset.Y,
   313  	}
   314  	dr.Max = image.Point{
   315  		X: dr.Min.X + v.gw,
   316  		Y: dr.Min.Y + v.gh,
   317  	}
   318  	return dr, a.masks, image.Point{Y: a.paintOffset}, v.advanceWidth, true
   319  }
   320  
   321  func (a *face) GlyphBounds(r rune) (bounds fixed.Rectangle26_6, advance fixed.Int26_6, ok bool) {
   322  	if err := a.glyphBuf.Load(a.f, a.scale, a.index(r), a.hinting); err != nil {
   323  		return fixed.Rectangle26_6{}, 0, false
   324  	}
   325  	xmin := +a.glyphBuf.Bounds.Min.X
   326  	ymin := -a.glyphBuf.Bounds.Max.Y
   327  	xmax := +a.glyphBuf.Bounds.Max.X
   328  	ymax := -a.glyphBuf.Bounds.Min.Y
   329  	if xmin > xmax || ymin > ymax {
   330  		return fixed.Rectangle26_6{}, 0, false
   331  	}
   332  	return fixed.Rectangle26_6{
   333  		Min: fixed.Point26_6{
   334  			X: xmin,
   335  			Y: ymin,
   336  		},
   337  		Max: fixed.Point26_6{
   338  			X: xmax,
   339  			Y: ymax,
   340  		},
   341  	}, a.glyphBuf.AdvanceWidth, true
   342  }
   343  
   344  func (a *face) GlyphAdvance(r rune) (advance fixed.Int26_6, ok bool) {
   345  	if err := a.glyphBuf.Load(a.f, a.scale, a.index(r), a.hinting); err != nil {
   346  		return 0, false
   347  	}
   348  	return a.glyphBuf.AdvanceWidth, true
   349  }
   350  
   351  // rasterize returns the advance width, integer-pixel offset to render at, and
   352  // the width and height of the given glyph at the given sub-pixel offsets.
   353  //
   354  // The 26.6 fixed point arguments fx and fy must be in the range [0, 1).
   355  func (a *face) rasterize(index Index, fx, fy fixed.Int26_6) (v glyphCacheVal, ok bool) {
   356  	if err := a.glyphBuf.Load(a.f, a.scale, index, a.hinting); err != nil {
   357  		return glyphCacheVal{}, false
   358  	}
   359  	// Calculate the integer-pixel bounds for the glyph.
   360  	xmin := int(fx+a.glyphBuf.Bounds.Min.X) >> 6
   361  	ymin := int(fy-a.glyphBuf.Bounds.Max.Y) >> 6
   362  	xmax := int(fx+a.glyphBuf.Bounds.Max.X+0x3f) >> 6
   363  	ymax := int(fy-a.glyphBuf.Bounds.Min.Y+0x3f) >> 6
   364  	if xmin > xmax || ymin > ymax {
   365  		return glyphCacheVal{}, false
   366  	}
   367  	// A TrueType's glyph's nodes can have negative co-ordinates, but the
   368  	// rasterizer clips anything left of x=0 or above y=0. xmin and ymin are
   369  	// the pixel offsets, based on the font's FUnit metrics, that let a
   370  	// negative co-ordinate in TrueType space be non-negative in rasterizer
   371  	// space. xmin and ymin are typically <= 0.
   372  	fx -= fixed.Int26_6(xmin << 6)
   373  	fy -= fixed.Int26_6(ymin << 6)
   374  	// Rasterize the glyph's vectors.
   375  	a.r.Clear()
   376  	pixOffset := a.paintOffset * a.maxw
   377  	clear(a.masks.Pix[pixOffset : pixOffset+a.maxw*a.maxh])
   378  	e0 := 0
   379  	for _, e1 := range a.glyphBuf.Ends {
   380  		a.drawContour(a.glyphBuf.Points[e0:e1], fx, fy)
   381  		e0 = e1
   382  	}
   383  	a.r.Rasterize(a.p)
   384  	return glyphCacheVal{
   385  		a.glyphBuf.AdvanceWidth,
   386  		image.Point{xmin, ymin},
   387  		xmax - xmin,
   388  		ymax - ymin,
   389  	}, true
   390  }
   391  
   392  func clear(pix []byte) {
   393  	for i := range pix {
   394  		pix[i] = 0
   395  	}
   396  }
   397  
   398  // drawContour draws the given closed contour with the given offset.
   399  func (a *face) drawContour(ps []Point, dx, dy fixed.Int26_6) {
   400  	if len(ps) == 0 {
   401  		return
   402  	}
   403  
   404  	// The low bit of each point's Flags value is whether the point is on the
   405  	// curve. Truetype fonts only have quadratic Bézier curves, not cubics.
   406  	// Thus, two consecutive off-curve points imply an on-curve point in the
   407  	// middle of those two.
   408  	//
   409  	// See http://chanae.walon.org/pub/ttf/ttf_glyphs.htm for more details.
   410  
   411  	// ps[0] is a truetype.Point measured in FUnits and positive Y going
   412  	// upwards. start is the same thing measured in fixed point units and
   413  	// positive Y going downwards, and offset by (dx, dy).
   414  	start := fixed.Point26_6{
   415  		X: dx + ps[0].X,
   416  		Y: dy - ps[0].Y,
   417  	}
   418  	var others []Point
   419  	if ps[0].Flags&0x01 != 0 {
   420  		others = ps[1:]
   421  	} else {
   422  		last := fixed.Point26_6{
   423  			X: dx + ps[len(ps)-1].X,
   424  			Y: dy - ps[len(ps)-1].Y,
   425  		}
   426  		if ps[len(ps)-1].Flags&0x01 != 0 {
   427  			start = last
   428  			others = ps[:len(ps)-1]
   429  		} else {
   430  			start = fixed.Point26_6{
   431  				X: (start.X + last.X) / 2,
   432  				Y: (start.Y + last.Y) / 2,
   433  			}
   434  			others = ps
   435  		}
   436  	}
   437  	a.r.Start(start)
   438  	q0, on0 := start, true
   439  	for _, p := range others {
   440  		q := fixed.Point26_6{
   441  			X: dx + p.X,
   442  			Y: dy - p.Y,
   443  		}
   444  		on := p.Flags&0x01 != 0
   445  		if on {
   446  			if on0 {
   447  				a.r.Add1(q)
   448  			} else {
   449  				a.r.Add2(q0, q)
   450  			}
   451  		} else {
   452  			if on0 {
   453  				// No-op.
   454  			} else {
   455  				mid := fixed.Point26_6{
   456  					X: (q0.X + q.X) / 2,
   457  					Y: (q0.Y + q.Y) / 2,
   458  				}
   459  				a.r.Add2(q0, mid)
   460  			}
   461  		}
   462  		q0, on0 = q, on
   463  	}
   464  	// Close the curve.
   465  	if on0 {
   466  		a.r.Add1(start)
   467  	} else {
   468  		a.r.Add2(q0, start)
   469  	}
   470  }
   471  
   472  // facePainter is like a raster.AlphaSrcPainter, with an additional Y offset
   473  // (face.paintOffset) to the painted spans.
   474  type facePainter struct {
   475  	a *face
   476  }
   477  
   478  func (p facePainter) Paint(ss []raster.Span, done bool) {
   479  	m := p.a.masks
   480  	b := m.Bounds()
   481  	b.Min.Y = p.a.paintOffset
   482  	b.Max.Y = p.a.paintOffset + p.a.maxh
   483  	for _, s := range ss {
   484  		s.Y += p.a.paintOffset
   485  		if s.Y < b.Min.Y {
   486  			continue
   487  		}
   488  		if s.Y >= b.Max.Y {
   489  			return
   490  		}
   491  		if s.X0 < b.Min.X {
   492  			s.X0 = b.Min.X
   493  		}
   494  		if s.X1 > b.Max.X {
   495  			s.X1 = b.Max.X
   496  		}
   497  		if s.X0 >= s.X1 {
   498  			continue
   499  		}
   500  		base := (s.Y-m.Rect.Min.Y)*m.Stride - m.Rect.Min.X
   501  		p := m.Pix[base+s.X0 : base+s.X1]
   502  		color := uint8(s.Alpha >> 8)
   503  		for i := range p {
   504  			p[i] = color
   505  		}
   506  	}
   507  }
   508  

View as plain text