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 +}