diff --git a/paint/renderers/rasterx/textsvg.go b/paint/renderers/rasterx/textsvg.go index 381e18a486..85d4a99e46 100644 --- a/paint/renderers/rasterx/textsvg.go +++ b/paint/renderers/rasterx/textsvg.go @@ -25,29 +25,31 @@ func (rs *Renderer) GlyphSVG(ctx *render.Context, run *shapedgt.Run, g *shaping. if svgGlyphCache == nil { svgGlyphCache = make(map[glyphKey]image.Image) } - size := run.Size.Floor() - fsize := image.Point{X: size, Y: size} - scale := 82.0 / float32(run.Face.Upem()) + size := float32(run.Size.Floor()) fam := run.Font.Style(&ctx.Style.Text).Family - if fam == rich.Monospace { - scale *= 0.8 - } - gk := glyphKey{gid: g.GlyphID, sx: uint8(size / 256), sy: uint8(size % 256), ox: uint8(fam)} + desc := run.Output.LineBounds.Descent + fsize := math32.Vec2(size, size) + gk := glyphKey{gid: g.GlyphID, sx: uint8(int(size) / 256), sy: uint8(int(size) % 256), ox: uint8(fam)} img, ok := svgGlyphCache[gk] if !ok { - sv := svg.NewSVG(math32.FromPoint(fsize)) + hadv := run.Face.HorizontalAdvance(g.GlyphID) + scale := size / hadv + if fam == rich.Monospace { + scale *= 0.8 + } + sv := svg.NewSVG(fsize) sv.GroupFilter = fmt.Sprintf("glyph%d", g.GlyphID) // critical: for filtering items with many glyphs b := bytes.NewBuffer(svgCmds) err := sv.ReadXML(b) errors.Log(err) - sv.Translate.Y = float32(run.Face.Upem()) + sv.Translate.Y = size + math32.FromFixed(desc) sv.Scale = scale + sv.Root.ViewBox.Size.SetScalar(size) img = sv.RenderImage() svgGlyphCache[gk] = img } left := int(math32.Round(pos.X + math32.FromFixed(g.XBearing))) - desc := run.Output.LineBounds.Descent - top := int(math32.Round(pos.Y - math32.FromFixed(g.YBearing+desc) - float32(fsize.Y))) + top := int(math32.Round(pos.Y - math32.FromFixed(g.YBearing+desc) - fsize.Y)) dbb := img.Bounds().Add(image.Point{left, top}) ibb := dbb.Intersect(ctx.Bounds.Rect.ToRect()) if ibb == (image.Rectangle{}) { diff --git a/svg/svg_test.go b/svg/svg_test.go index 2c5da57d6c..2ce2f9529a 100644 --- a/svg/svg_test.go +++ b/svg/svg_test.go @@ -144,6 +144,9 @@ func TestFontEmoji(t *testing.T) { faces, err := font.ParseTTC(bytes.NewReader(b)) assert.NoError(t, err) face := faces[0] + size := float32(512) + hext, _ := face.FontHExtents() + ctr := 0 for r := rune(0); r < math.MaxInt32; r++ { gid, has := face.NominalGlyph(r) if !has { @@ -155,12 +158,15 @@ func TestFontEmoji(t *testing.T) { continue } fn := fmt.Sprintf("femoji-%x", r) - if !strings.Contains(fn, "203c") { - continue - } - sv := NewSVG(math32.Vec2(512, 512)) - sv.Translate.Y = 1024 - sv.Scale = 0.080078125 + // if !strings.Contains(fn, "203c") { + // continue + // } + sv := NewSVG(math32.Vec2(size, size)) + hadv := face.HorizontalAdvance(gid) + scale := size / hadv + sv.Scale = scale + sv.Translate.Y = size + scale*hext.Descender + sv.Root.ViewBox.Size.SetScalar(size) sv.GroupFilter = fmt.Sprintf("glyph%d", gid) sfn := filepath.Join("testdata/font-emoji-src", fn+".svg") fmt.Println(sfn, "gid:", sv.GroupFilter, "len:", len(gd.Source)) @@ -172,5 +178,9 @@ func TestFontEmoji(t *testing.T) { imagex.Assert(t, img, imfn) // sv.SaveXML(sfn) // os.WriteFile(sfn, gd.Source, 0666) + ctr++ + if ctr > 100 { + break + } } } diff --git a/text/fonts/fontbrowser/glyph.go b/text/fonts/fontbrowser/glyph.go index d8e46ba7ab..329cc77d9f 100644 --- a/text/fonts/fontbrowser/glyph.go +++ b/text/fonts/fontbrowser/glyph.go @@ -135,9 +135,7 @@ func (gi *Glyph) drawShaped(pc *paint.Painter) { off := math32.Vec2(0, 0) if msz > 200 { o := 0.2 * float32(msz) - if gi.Browser.IsEmoji { - off = math32.Vec2(0.5*o, -o) - } else { // for bitmap fonts, kinda random + if !gi.Browser.IsEmoji { // for bitmap fonts, kinda random off = math32.Vec2(o, o) } }