github.com/Kintar/etxt@v0.0.0-20221224033739-2fc69f000137/emask/impl_default.go (about)

     1  package emask
     2  
     3  import "image"
     4  import "image/draw"
     5  
     6  import "golang.org/x/image/vector"
     7  import "golang.org/x/image/math/fixed"
     8  import "golang.org/x/image/font/sfnt"
     9  
    10  // The DefaultRasterizer is a wrapper to make [golang.org/x/image/vector.Rasterizer]
    11  // conform to the [Rasterizer] interface.
    12  type DefaultRasterizer struct {
    13  	rasterizer vector.Rasterizer
    14  	rectOffset image.Point     // offset to align the final mask rect to the bounds
    15  	normOffset fixed.Point26_6 // offset to normalize points to the positive
    16  	// quadrant starting from the fractional coords
    17  
    18  	cacheSignature uint64
    19  	onChange       func(Rasterizer)
    20  
    21  	// Notice that the x/image/vector rasterizer expects coords in the
    22  	// positive quadrant, which is why we need so many offsets here.
    23  }
    24  
    25  // Satisfies the [UserCfgCacheSignature] interface.
    26  func (self *DefaultRasterizer) SetHighByte(value uint8) {
    27  	self.cacheSignature = uint64(value) << 56
    28  	if self.onChange != nil {
    29  		self.onChange(self)
    30  	}
    31  }
    32  
    33  // Satisfies the [Rasterizer] interface.
    34  func (self *DefaultRasterizer) SetOnChangeFunc(onChange func(Rasterizer)) {
    35  	self.onChange = onChange
    36  }
    37  
    38  // Satisfies the [Rasterizer] interface.
    39  func (self *DefaultRasterizer) CacheSignature() uint64 {
    40  	return self.cacheSignature
    41  }
    42  
    43  // Moves the current position to the given point.
    44  func (self *DefaultRasterizer) MoveTo(point fixed.Point26_6) {
    45  	x, y := self.fixedToFloat32Coords(point)
    46  	self.rasterizer.MoveTo(x, y)
    47  }
    48  
    49  // Creates a straight boundary from the current position to the given point.
    50  func (self *DefaultRasterizer) LineTo(point fixed.Point26_6) {
    51  	x, y := self.fixedToFloat32Coords(point)
    52  	self.rasterizer.LineTo(x, y)
    53  }
    54  
    55  // Creates a quadratic Bézier curve (also known as a conic Bézier curve)
    56  // to the given target passing through the given control point.
    57  func (self *DefaultRasterizer) QuadTo(control, target fixed.Point26_6) {
    58  	cx, cy := self.fixedToFloat32Coords(control)
    59  	tx, ty := self.fixedToFloat32Coords(target)
    60  	self.rasterizer.QuadTo(cx, cy, tx, ty)
    61  }
    62  
    63  // Creates a cubic Bézier curve to the given target passing through
    64  // the given control points.
    65  func (self *DefaultRasterizer) CubeTo(controlA, controlB, target fixed.Point26_6) {
    66  	cax, cay := self.fixedToFloat32Coords(controlA)
    67  	cbx, cby := self.fixedToFloat32Coords(controlB)
    68  	tx, ty := self.fixedToFloat32Coords(target)
    69  	self.rasterizer.CubeTo(cax, cay, cbx, cby, tx, ty)
    70  }
    71  
    72  // Satisfies the Rasterizer interface.
    73  func (self *DefaultRasterizer) Rasterize(outline sfnt.Segments, fract fixed.Point26_6) (*image.Alpha, error) {
    74  	// prepare rasterizer
    75  	var size image.Point
    76  	size, self.normOffset, self.rectOffset = figureOutBounds(outline.Bounds(), fract)
    77  	self.rasterizer.Reset(size.X, size.Y)
    78  	self.rasterizer.DrawOp = draw.Src
    79  
    80  	// allocate glyph mask
    81  	mask := image.NewAlpha(self.rasterizer.Bounds())
    82  
    83  	// process outline
    84  	processOutline(self, outline)
    85  
    86  	// since the source texture is a uniform (an image that returns the same
    87  	// color for any coordinate), the value of the point at which we want to
    88  	// start sampling the texture (the fourth parameter) is unimportant.
    89  	self.rasterizer.Draw(mask, mask.Bounds(), image.Opaque, image.Point{})
    90  
    91  	// translate the mask to its final position
    92  	mask.Rect = mask.Rect.Add(self.rectOffset)
    93  	return mask, nil
    94  }
    95  
    96  func (self *DefaultRasterizer) fixedToFloat32Coords(point fixed.Point26_6) (float32, float32) {
    97  	x := float32(point.X+self.normOffset.X) / 64
    98  	y := float32(point.Y+self.normOffset.Y) / 64
    99  	return x, y
   100  }