typeset/drawer.go
2024-09-03 18:38:01 -04:00

85 lines
2.0 KiB
Go

package typeset
import "image"
import "unicode"
import "image/draw"
import "image/color"
import "golang.org/x/image/math/fixed"
// Drawer is an extended TypeSetter that is able to draw text. Much like
// TypeSetter, It has no constructor and its zero value can be used safely.
type Drawer struct { TypeSetter }
// Draw draws the drawer's text onto the specified canvas at the given offset.
func (drawer Drawer) Draw (
destination draw.Image,
col color.Color,
offset image.Point,
) (
updatedRegion image.Rectangle,
) {
source := image.NewUniform(col)
drawer.ForRunes (func (
index int,
char rune,
position fixed.Point26_6,
) bool {
// leave empty space for space characters
if unicode.IsSpace(char) {
return true
}
dot := fixed.P (
offset.X + position.X.Round(),
offset.Y + position.Y.Round())
destinationRectangle,
mask, maskPoint, _, ok := drawer.face.Glyph(dot, char)
// tofu
if !ok {
drawer.drawTofu(char, destination, col, dot)
return true
}
// FIXME:? clip destination rectangle if we are on the cusp of
// the maximum height.
draw.DrawMask (
destination,
destinationRectangle,
source, image.Point { },
mask, maskPoint,
draw.Over)
updatedRegion = updatedRegion.Union(destinationRectangle)
return true
})
return
}
func (drawer Drawer) drawTofu (
char rune,
destination draw.Image,
col color.Color,
position fixed.Point26_6,
) {
bounds, _ := tofuBounds(drawer.face)
rectBounds := image.Rect (
bounds.Min.X.Round(),
bounds.Min.Y.Round(),
bounds.Max.X.Round(),
bounds.Max.Y.Round()).Add(image.Pt(
position.X.Round(),
position.Y.Round()))
for x := rectBounds.Min.X; x < rectBounds.Max.X; x ++ {
destination.Set(x, rectBounds.Min.Y, col)
}
for y := rectBounds.Min.Y; y < rectBounds.Max.Y; y ++ {
destination.Set(rectBounds.Min.X, y, col)
destination.Set(rectBounds.Max.X - 1, y, col)
}
for x := rectBounds.Min.X; x < rectBounds.Max.X; x ++ {
destination.Set(x, rectBounds.Max.Y - 1, col)
}
}