git clone https://git.lucas.co/go_mono.git
font/opentype: merge face.go into opentype.go
There's no need for two .go files if one of them is just a placeholder.
If we're only going to have one, it might as well have the same name as
the package.
Change-Id: I0eb639d00e84f0d942adca49b1391987ae77bd7b
Reviewed-on: https://go-review.googlesource.com/c/image/+/257538
Reviewed-by: Hajime Hoshi <[email protected]>
Trust: Nigel Tao <[email protected]>
font/opentype/face.go | 217 -----------------------
font/opentype/opentype.go | 212 ++++++++++++++++++++++
font/opentype/{face_test.go => opentype_test.go} | 0
3 files changed, 212 insertions(+), 217 deletions(-)
diff --git a/font/opentype/face.go b/font/opentype/face.go
deleted file mode 100644
index 72bdae8..0000000
--- a/font/opentype/face.go
+++ /dev/null
@@ -1,217 +0,0 @@
-// Copyright 2017 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package opentype
-
-import (
- "image"
- "image/draw"
-
- "golang.org/x/image/font"
- "golang.org/x/image/font/sfnt"
- "golang.org/x/image/math/fixed"
- "golang.org/x/image/vector"
-)
-
-// FaceOptions describes the possible options given to NewFace when
-// creating a new font.Face from a sfnt.Font.
-type FaceOptions struct {
- Size float64 // Size is the font size in points
- DPI float64 // DPI is the dots per inch resolution
- Hinting font.Hinting // Hinting selects how to quantize a vector font's glyph nodes
-}
-
-func defaultFaceOptions() *FaceOptions {
- return &FaceOptions{
- Size: 12,
- DPI: 72,
- Hinting: font.HintingNone,
- }
-}
-
-// Face implements the font.Face interface for sfnt.Font values.
-type Face struct {
- f *sfnt.Font
- hinting font.Hinting
- scale fixed.Int26_6
-
- metrics font.Metrics
- metricsSet bool
-
- buf sfnt.Buffer
- rast vector.Rasterizer
- mask image.Alpha
-}
-
-// NewFace returns a new font.Face for the given sfnt.Font.
-// if opts is nil, sensible defaults will be used.
-func NewFace(f *sfnt.Font, opts *FaceOptions) (font.Face, error) {
- if opts == nil {
- opts = defaultFaceOptions()
- }
- face := &Face{
- f: f,
- hinting: opts.Hinting,
- scale: fixed.Int26_6(0.5 + (opts.Size * opts.DPI * 64 / 72)),
- }
- return face, nil
-}
-
-// Close satisfies the font.Face interface.
-func (f *Face) Close() error {
- return nil
-}
-
-// Metrics satisfies the font.Face interface.
-func (f *Face) Metrics() font.Metrics {
- if !f.metricsSet {
- var err error
- f.metrics, err = f.f.Metrics(&f.buf, f.scale, f.hinting)
- if err != nil {
- f.metrics = font.Metrics{}
- }
- f.metricsSet = true
- }
- return f.metrics
-}
-
-// Kern satisfies the font.Face interface.
-func (f *Face) Kern(r0, r1 rune) fixed.Int26_6 {
- x0 := f.index(r0)
- x1 := f.index(r1)
- k, err := f.f.Kern(&f.buf, x0, x1, fixed.Int26_6(f.f.UnitsPerEm()), f.hinting)
- if err != nil {
- return 0
- }
- return k
-}
-
-// Glyph satisfies the font.Face interface.
-func (f *Face) Glyph(dot fixed.Point26_6, r rune) (dr image.Rectangle, mask image.Image, maskp image.Point, advance fixed.Int26_6, ok bool) {
- x, err := f.f.GlyphIndex(&f.buf, r)
- if err != nil {
- return image.Rectangle{}, nil, image.Point{}, 0, false
- }
-
- // Call f.f.GlyphAdvance before f.f.LoadGlyph because the LoadGlyph docs
- // say this about the &f.buf argument: the segments become invalid to use
- // once [the buffer] is re-used.
-
- advance, err = f.f.GlyphAdvance(&f.buf, x, f.scale, f.hinting)
- if err != nil {
- return image.Rectangle{}, nil, image.Point{}, 0, false
- }
-
- segments, err := f.f.LoadGlyph(&f.buf, x, f.scale, nil)
- if err != nil {
- return image.Rectangle{}, nil, image.Point{}, 0, false
- }
-
- // Numerical notation used below:
- // - 2 is an integer, "two"
- // - 2:16 is a 26.6 fixed point number, "two and a quarter"
- // - 2.5 is a float32 number, "two and a half"
- // Using 26.6 fixed point numbers means that there are 64 sub-pixel units
- // in 1 integer pixel unit.
-
- // Translate the sub-pixel bounding box from glyph space (where the glyph
- // origin is at (0:00, 0:00)) to dst space (where the glyph origin is at
- // the dot). dst space is the coordinate space that contains both the dot
- // (a sub-pixel position) and dr (an integer-pixel rectangle).
- dBounds := segments.Bounds().Add(dot)
-
- // Quantize the sub-pixel bounds (dBounds) to integer-pixel bounds (dr).
- dr.Min.X = dBounds.Min.X.Floor()
- dr.Min.Y = dBounds.Min.Y.Floor()
- dr.Max.X = dBounds.Max.X.Ceil()
- dr.Max.Y = dBounds.Max.Y.Ceil()
- width := dr.Dx()
- height := dr.Dy()
- if width < 0 || height < 0 {
- return image.Rectangle{}, nil, image.Point{}, 0, false
- }
-
- // Calculate the sub-pixel bias to convert from glyph space to rasterizer
- // space. In glyph space, the segments may be to the left or right and
- // above or below the glyph origin. In rasterizer space, the segments
- // should only be right and below (or equal to) the top-left corner (0.0,
- // 0.0). They should also be left and above (or equal to) the bottom-right
- // corner (width, height), as the rasterizer should enclose the glyph
- // bounding box.
- //
- // For example, suppose that dot.X was at the sub-pixel position 25:48,
- // three quarters of the way into the 26th pixel, and that bounds.Min.X was
- // 1:20. We then have dBounds.Min.X = 1:20 + 25:48 = 27:04, dr.Min.X = 27
- // and biasX = 25:48 - 27:00 = -1:16. A vertical stroke at 1:20 in glyph
- // space becomes (1:20 + -1:16) = 0:04 in rasterizer space. 0:04 as a
- // fixed.Int26_6 value is float32(4)/64.0 = 0.0625 as a float32 value.
- biasX := dot.X - fixed.Int26_6(dr.Min.X<<6)
- biasY := dot.Y - fixed.Int26_6(dr.Min.Y<<6)
-
- // Configure the mask image, re-allocating its buffer if necessary.
- nPixels := width * height
- if cap(f.mask.Pix) < nPixels {
- f.mask.Pix = make([]uint8, 2*nPixels)
- }
- f.mask.Pix = f.mask.Pix[:nPixels]
- f.mask.Stride = width
- f.mask.Rect.Min.X = 0
- f.mask.Rect.Min.Y = 0
- f.mask.Rect.Max.X = width
- f.mask.Rect.Max.Y = height
-
- // Rasterize the biased segments, converting from fixed.Int26_6 to float32.
- f.rast.Reset(width, height)
- f.rast.DrawOp = draw.Src
- for _, seg := range segments {
- switch seg.Op {
- case sfnt.SegmentOpMoveTo:
- f.rast.MoveTo(
- float32(seg.Args[0].X+biasX)/64,
- float32(seg.Args[0].Y+biasY)/64,
- )
- case sfnt.SegmentOpLineTo:
- f.rast.LineTo(
- float32(seg.Args[0].X+biasX)/64,
- float32(seg.Args[0].Y+biasY)/64,
- )
- case sfnt.SegmentOpQuadTo:
- f.rast.QuadTo(
- float32(seg.Args[0].X+biasX)/64,
- float32(seg.Args[0].Y+biasY)/64,
- float32(seg.Args[1].X+biasX)/64,
- float32(seg.Args[1].Y+biasY)/64,
- )
- case sfnt.SegmentOpCubeTo:
- f.rast.CubeTo(
- float32(seg.Args[0].X+biasX)/64,
- float32(seg.Args[0].Y+biasY)/64,
- float32(seg.Args[1].X+biasX)/64,
- float32(seg.Args[1].Y+biasY)/64,
- float32(seg.Args[2].X+biasX)/64,
- float32(seg.Args[2].Y+biasY)/64,
- )
- }
- }
- f.rast.Draw(&f.mask, f.mask.Bounds(), image.Opaque, image.Point{})
-
- return dr, &f.mask, f.mask.Rect.Min, advance, true
-}
-
-// GlyphBounds satisfies the font.Face interface.
-func (f *Face) GlyphBounds(r rune) (bounds fixed.Rectangle26_6, advance fixed.Int26_6, ok bool) {
- bounds, advance, err := f.f.GlyphBounds(&f.buf, f.index(r), f.scale, f.hinting)
- return bounds, advance, err == nil
-}
-
-// GlyphAdvance satisfies the font.Face interface.
-func (f *Face) GlyphAdvance(r rune) (advance fixed.Int26_6, ok bool) {
- advance, err := f.f.GlyphAdvance(&f.buf, f.index(r), f.scale, f.hinting)
- return advance, err == nil
-}
-
-func (f *Face) index(r rune) sfnt.GlyphIndex {
- x, _ := f.f.GlyphIndex(&f.buf, r)
- return x
-}
diff --git a/font/opentype/opentype.go b/font/opentype/opentype.go
index 452e952..4bb10ec 100644
--- a/font/opentype/opentype.go
+++ b/font/opentype/opentype.go
@@ -5,3 +5,215 @@
// Package opentype implements the font.Face interface based on SFNT
// font file formats.
package opentype // import "golang.org/x/image/font/opentype"
+
+import (
+ "image"
+ "image/draw"
+
+ "golang.org/x/image/font"
+ "golang.org/x/image/font/sfnt"
+ "golang.org/x/image/math/fixed"
+ "golang.org/x/image/vector"
+)
+
+// FaceOptions describes the possible options given to NewFace when
+// creating a new font.Face from a sfnt.Font.
+type FaceOptions struct {
+ Size float64 // Size is the font size in points
+ DPI float64 // DPI is the dots per inch resolution
+ Hinting font.Hinting // Hinting selects how to quantize a vector font's glyph nodes
+}
+
+func defaultFaceOptions() *FaceOptions {
+ return &FaceOptions{
+ Size: 12,
+ DPI: 72,
+ Hinting: font.HintingNone,
+ }
+}
+
+// Face implements the font.Face interface for sfnt.Font values.
+type Face struct {
+ f *sfnt.Font
+ hinting font.Hinting
+ scale fixed.Int26_6
+
+ metrics font.Metrics
+ metricsSet bool
+
+ buf sfnt.Buffer
+ rast vector.Rasterizer
+ mask image.Alpha
+}
+
+// NewFace returns a new font.Face for the given sfnt.Font.
+// if opts is nil, sensible defaults will be used.
+func NewFace(f *sfnt.Font, opts *FaceOptions) (font.Face, error) {
+ if opts == nil {
+ opts = defaultFaceOptions()
+ }
+ face := &Face{
+ f: f,
+ hinting: opts.Hinting,
+ scale: fixed.Int26_6(0.5 + (opts.Size * opts.DPI * 64 / 72)),
+ }
+ return face, nil
+}
+
+// Close satisfies the font.Face interface.
+func (f *Face) Close() error {
+ return nil
+}
+
+// Metrics satisfies the font.Face interface.
+func (f *Face) Metrics() font.Metrics {
+ if !f.metricsSet {
+ var err error
+ f.metrics, err = f.f.Metrics(&f.buf, f.scale, f.hinting)
+ if err != nil {
+ f.metrics = font.Metrics{}
+ }
+ f.metricsSet = true
+ }
+ return f.metrics
+}
+
+// Kern satisfies the font.Face interface.
+func (f *Face) Kern(r0, r1 rune) fixed.Int26_6 {
+ x0 := f.index(r0)
+ x1 := f.index(r1)
+ k, err := f.f.Kern(&f.buf, x0, x1, fixed.Int26_6(f.f.UnitsPerEm()), f.hinting)
+ if err != nil {
+ return 0
+ }
+ return k
+}
+
+// Glyph satisfies the font.Face interface.
+func (f *Face) Glyph(dot fixed.Point26_6, r rune) (dr image.Rectangle, mask image.Image, maskp image.Point, advance fixed.Int26_6, ok bool) {
+ x, err := f.f.GlyphIndex(&f.buf, r)
+ if err != nil {
+ return image.Rectangle{}, nil, image.Point{}, 0, false
+ }
+
+ // Call f.f.GlyphAdvance before f.f.LoadGlyph because the LoadGlyph docs
+ // say this about the &f.buf argument: the segments become invalid to use
+ // once [the buffer] is re-used.
+
+ advance, err = f.f.GlyphAdvance(&f.buf, x, f.scale, f.hinting)
+ if err != nil {
+ return image.Rectangle{}, nil, image.Point{}, 0, false
+ }
+
+ segments, err := f.f.LoadGlyph(&f.buf, x, f.scale, nil)
+ if err != nil {
+ return image.Rectangle{}, nil, image.Point{}, 0, false
+ }
+
+ // Numerical notation used below:
+ // - 2 is an integer, "two"
+ // - 2:16 is a 26.6 fixed point number, "two and a quarter"
+ // - 2.5 is a float32 number, "two and a half"
+ // Using 26.6 fixed point numbers means that there are 64 sub-pixel units
+ // in 1 integer pixel unit.
+
+ // Translate the sub-pixel bounding box from glyph space (where the glyph
+ // origin is at (0:00, 0:00)) to dst space (where the glyph origin is at
+ // the dot). dst space is the coordinate space that contains both the dot
+ // (a sub-pixel position) and dr (an integer-pixel rectangle).
+ dBounds := segments.Bounds().Add(dot)
+
+ // Quantize the sub-pixel bounds (dBounds) to integer-pixel bounds (dr).
+ dr.Min.X = dBounds.Min.X.Floor()
+ dr.Min.Y = dBounds.Min.Y.Floor()
+ dr.Max.X = dBounds.Max.X.Ceil()
+ dr.Max.Y = dBounds.Max.Y.Ceil()
+ width := dr.Dx()
+ height := dr.Dy()
+ if width < 0 || height < 0 {
+ return image.Rectangle{}, nil, image.Point{}, 0, false
+ }
+
+ // Calculate the sub-pixel bias to convert from glyph space to rasterizer
+ // space. In glyph space, the segments may be to the left or right and
+ // above or below the glyph origin. In rasterizer space, the segments
+ // should only be right and below (or equal to) the top-left corner (0.0,
+ // 0.0). They should also be left and above (or equal to) the bottom-right
+ // corner (width, height), as the rasterizer should enclose the glyph
+ // bounding box.
+ //
+ // For example, suppose that dot.X was at the sub-pixel position 25:48,
+ // three quarters of the way into the 26th pixel, and that bounds.Min.X was
+ // 1:20. We then have dBounds.Min.X = 1:20 + 25:48 = 27:04, dr.Min.X = 27
+ // and biasX = 25:48 - 27:00 = -1:16. A vertical stroke at 1:20 in glyph
+ // space becomes (1:20 + -1:16) = 0:04 in rasterizer space. 0:04 as a
+ // fixed.Int26_6 value is float32(4)/64.0 = 0.0625 as a float32 value.
+ biasX := dot.X - fixed.Int26_6(dr.Min.X<<6)
+ biasY := dot.Y - fixed.Int26_6(dr.Min.Y<<6)
+
+ // Configure the mask image, re-allocating its buffer if necessary.
+ nPixels := width * height
+ if cap(f.mask.Pix) < nPixels {
+ f.mask.Pix = make([]uint8, 2*nPixels)
+ }
+ f.mask.Pix = f.mask.Pix[:nPixels]
+ f.mask.Stride = width
+ f.mask.Rect.Min.X = 0
+ f.mask.Rect.Min.Y = 0
+ f.mask.Rect.Max.X = width
+ f.mask.Rect.Max.Y = height
+
+ // Rasterize the biased segments, converting from fixed.Int26_6 to float32.
+ f.rast.Reset(width, height)
+ f.rast.DrawOp = draw.Src
+ for _, seg := range segments {
+ switch seg.Op {
+ case sfnt.SegmentOpMoveTo:
+ f.rast.MoveTo(
+ float32(seg.Args[0].X+biasX)/64,
+ float32(seg.Args[0].Y+biasY)/64,
+ )
+ case sfnt.SegmentOpLineTo:
+ f.rast.LineTo(
+ float32(seg.Args[0].X+biasX)/64,
+ float32(seg.Args[0].Y+biasY)/64,
+ )
+ case sfnt.SegmentOpQuadTo:
+ f.rast.QuadTo(
+ float32(seg.Args[0].X+biasX)/64,
+ float32(seg.Args[0].Y+biasY)/64,
+ float32(seg.Args[1].X+biasX)/64,
+ float32(seg.Args[1].Y+biasY)/64,
+ )
+ case sfnt.SegmentOpCubeTo:
+ f.rast.CubeTo(
+ float32(seg.Args[0].X+biasX)/64,
+ float32(seg.Args[0].Y+biasY)/64,
+ float32(seg.Args[1].X+biasX)/64,
+ float32(seg.Args[1].Y+biasY)/64,
+ float32(seg.Args[2].X+biasX)/64,
+ float32(seg.Args[2].Y+biasY)/64,
+ )
+ }
+ }
+ f.rast.Draw(&f.mask, f.mask.Bounds(), image.Opaque, image.Point{})
+
+ return dr, &f.mask, f.mask.Rect.Min, advance, true
+}
+
+// GlyphBounds satisfies the font.Face interface.
+func (f *Face) GlyphBounds(r rune) (bounds fixed.Rectangle26_6, advance fixed.Int26_6, ok bool) {
+ bounds, advance, err := f.f.GlyphBounds(&f.buf, f.index(r), f.scale, f.hinting)
+ return bounds, advance, err == nil
+}
+
+// GlyphAdvance satisfies the font.Face interface.
+func (f *Face) GlyphAdvance(r rune) (advance fixed.Int26_6, ok bool) {
+ advance, err := f.f.GlyphAdvance(&f.buf, f.index(r), f.scale, f.hinting)
+ return advance, err == nil
+}
+
+func (f *Face) index(r rune) sfnt.GlyphIndex {
+ x, _ := f.f.GlyphIndex(&f.buf, r)
+ return x
+}
diff --git a/font/opentype/face_test.go b/font/opentype/opentype_test.go
similarity index 100%
rename from font/opentype/face_test.go
rename to font/opentype/opentype_test.go