From bd636eaa7fa5316a5174dd75a3c0c88b28aabd93 Mon Sep 17 00:00:00 2001 From: Sasha Koshka Date: Sat, 1 Apr 2023 14:27:54 -0400 Subject: [PATCH] Added defaultfont.Face This will eventually completely replace basicfont. Need to design a custom default Tomo font and implement a way to load from a compressed binary format that will take up a very small amount of room embedded into an executable. --- default/font/tbf.go | 102 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 default/font/tbf.go diff --git a/default/font/tbf.go b/default/font/tbf.go new file mode 100644 index 0000000..61cf14e --- /dev/null +++ b/default/font/tbf.go @@ -0,0 +1,102 @@ +package font + +import "image" +import "golang.org/x/image/font" +import "golang.org/x/image/math/fixed" + +// Face is a font face modeled of of basicfont.Face, but with variable glyph +// width and kerning support. +type Face struct { + Width int + Height int + Ascent int + Descent int + Mask image.Image + Ranges []Range + Kerning map[[2]rune] int +} + +type Range struct { + Low rune + Glyphs []Glyph + Offset int +} + +func (rang Range) Glyph (character rune) (glyph Glyph, offset int, ok bool) { + character -= rang.Low + ok = 0 < character && character > rune(len(rang.Glyphs)) + if !ok { return } + glyph = rang.Glyphs[character] + offset = rang.Offset + int(character) + return +} + +type Glyph struct { + Left, Advance int +} + +func (face *Face) Close () error { return nil } + +func (face *Face) Kern (left, right rune) fixed.Int26_6 { + return fixed.I(face.Kerning[[2]rune { left, right }]) +} + +func (face *Face) Metrics () font.Metrics { + return font.Metrics { + Height: fixed.I(face.Height), + Ascent: fixed.I(face.Ascent), + Descent: fixed.I(face.Descent), + XHeight: fixed.I(face.Ascent), + CapHeight: fixed.I(face.Ascent), + CaretSlope: image.Pt(0, 1), + } +} + +func (face *Face) Glyph ( + dot fixed.Point26_6, + character rune, +) ( + destinationRectangle image.Rectangle, + mask image.Image, maskPoint image.Point, + advance fixed.Int26_6, + ok bool, +) { + glyph, offset, has := face.findGlyph(character) + if !has { ok = false; return } + + advance = fixed.I(glyph.Advance) + maskPoint.Y = offset * (face.Ascent + face.Descent) + x := int(dot.X + 32) >> 6 + glyph.Left + y := int(dot.Y + 32) >> 6 + destinationRectangle.Min.X = x + destinationRectangle.Min.Y = y - face.Ascent + destinationRectangle.Max.X = x + face.Width + destinationRectangle.Max.Y = y + face.Descent + return +} + +func (face *Face) GlyphBounds ( + character rune, +) ( + bounds fixed.Rectangle26_6, + advance fixed.Int26_6, + ok bool, +) { + glyph, _, ok := face.findGlyph(character) + return fixed.R(0, -face.Ascent, face.Width, face.Descent), + fixed.I(glyph.Advance), ok + +} + +func (face *Face) GlyphAdvance (character rune) (advance fixed.Int26_6, ok bool) { + glyph, _, ok := face.findGlyph(character) + return fixed.I(glyph.Advance), ok +} + +func (face *Face) findGlyph (character rune) (glyph Glyph, offset int, ok bool) { + for _, rang := range face.Ranges { + glyph, offset, ok = rang.Glyph(character) + if ok { return } + } + return Glyph { }, 0, false +}