text/v2: improve rendering quality for small faces

Closes #2843
This commit is contained in:
Hajime Hoshi 2023-11-16 12:00:15 +09:00
parent 006777220c
commit 2e60c67ec9
3 changed files with 22 additions and 9 deletions

View File

@ -325,11 +325,11 @@ func (g *GoTextFace) appendGlyphs(glyphs []Glyph, text string, indexOffset int,
func (g *GoTextFace) glyphImage(glyph glyph, origin fixed.Point26_6) (*ebiten.Image, int, int) { func (g *GoTextFace) glyphImage(glyph glyph, origin fixed.Point26_6) (*ebiten.Image, int, int) {
if g.direction().isHorizontal() { if g.direction().isHorizontal() {
origin.X = adjustGranularity(origin.X) origin.X = adjustGranularity(origin.X, g)
origin.Y &^= ((1 << 6) - 1) origin.Y &^= ((1 << 6) - 1)
} else { } else {
origin.X &^= ((1 << 6) - 1) origin.X &^= ((1 << 6) - 1)
origin.Y = adjustGranularity(origin.Y) origin.Y = adjustGranularity(origin.Y, g)
} }
b := segmentsToBounds(glyph.scaledSegments) b := segmentsToBounds(glyph.scaledSegments)

View File

@ -130,7 +130,7 @@ func (s *StdFace) appendGlyphs(glyphs []Glyph, text string, indexOffset int, ori
func (s *StdFace) glyphImage(r rune, origin fixed.Point26_6) (*ebiten.Image, int, int, fixed.Int26_6) { func (s *StdFace) glyphImage(r rune, origin fixed.Point26_6) (*ebiten.Image, int, int, fixed.Int26_6) {
// Assume that StdFace's direction is always horizontal. // Assume that StdFace's direction is always horizontal.
origin.X = adjustGranularity(origin.X) origin.X = adjustGranularity(origin.X, s)
origin.Y &^= ((1 << 6) - 1) origin.Y &^= ((1 << 6) - 1)
b, a, _ := s.f.GlyphBounds(r) b, a, _ := s.f.GlyphBounds(r)

View File

@ -95,10 +95,21 @@ func float64ToFixed26_6(x float64) fixed.Int26_6 {
return fixed.Int26_6(i)<<6 + fixed.Int26_6(frac*(1<<6)) return fixed.Int26_6(i)<<6 + fixed.Int26_6(frac*(1<<6))
} }
const glyphVariationCount = 4 func glyphVariationCount(face Face) int {
m := face.Metrics()
if (m.HAscent != 0 || m.HDescent != 0) && m.HAscent+m.HDescent < 16 {
return 8
}
if (m.VAscent != 0 || m.VDescent != 0) && m.VAscent+m.VDescent < 16 {
return 8
}
// TODO: For big faces, a smaller value might be enough.
return 4
}
func adjustGranularity(x fixed.Int26_6) fixed.Int26_6 { func adjustGranularity(x fixed.Int26_6, face Face) fixed.Int26_6 {
return x / ((1 << 6) / glyphVariationCount) * ((1 << 6) / glyphVariationCount) c := glyphVariationCount(face)
return x / ((1 << 6) / fixed.Int26_6(c)) * ((1 << 6) / fixed.Int26_6(c))
} }
// Glyph represents one glyph to render. // Glyph represents one glyph to render.
@ -227,16 +238,18 @@ func Measure(text string, face Face, lineHeight float64) (width, height float64)
func CacheGlyphs(text string, face Face) { func CacheGlyphs(text string, face Face) {
var x, y float64 var x, y float64
c := glyphVariationCount(face)
var buf []Glyph var buf []Glyph
// Create all the possible variations (#2528). // Create all the possible variations (#2528).
for i := 0; i < 4; i++ { for i := 0; i < c; i++ {
buf = appendGlyphs(buf, text, face, x, y, nil) buf = appendGlyphs(buf, text, face, x, y, nil)
buf = buf[:0] buf = buf[:0]
if face.direction().isHorizontal() { if face.direction().isHorizontal() {
x += 1.0 / glyphVariationCount x += 1.0 / float64(c)
} else { } else {
y += 1.0 / glyphVariationCount y += 1.0 / float64(c)
} }
} }
} }