go-text / typesetting

High quality text shaping in pure Go.
Other
88 stars 11 forks source link

`NotoSansJP-VF.otf` (OpenType) didn't work, while `NotoSansJP-VF.ttf` (TrueType) worked #118

Closed hajimehoshi closed 6 months ago

hajimehoshi commented 7 months ago

https://github.com/notofonts/noto-cjk/releases/tag/Sans2.004

I tested NotoSansJP-VF.ttf in "All Variable TTF/OTC" and NotoSansJP-VF.otf in "All Variable OTF/OTC", and apparently the OpenType version didn't work. go-text couldn't render any glyphs. I found this in my game engine using go-text, so it is a little hard to create a minimized test case, but this is just a quick note.

Confirmed version of go-text: v0.0.0-20231120180320-af78120ccb13

Thanks,

benoitkugler commented 7 months ago

Thank you for the bug report.

Could elaborate on "couldn't render any glyphs" ? Is that a visual problem or are the runs (Output) also corrupted ? You could perhaps extract an input string so that we can investigate ?

hajimehoshi commented 7 months ago

Nothing was rendered actually. Apparently no glyphs were obtained for any texts. As I said, this happened in my game engine, so I'll write down a reproducible code with this engine. I'll try to make a minimal code without the engine to reproduce the issue later.

package main

import (
    "bytes"
    _ "embed"

    // The version is 6a7688d3ac4b6fdc264758885465f20833848c10
    "github.com/hajimehoshi/ebiten/v2/text/v2"
)

//go:embed NotoSansJP-VF.otf
var f []byte

func main() {
    src, err := text.NewGoTextFaceSource(bytes.NewReader(f))
    if err != nil {
        panic(err)
    }
    glyphs := text.AppendGlyphs(nil, "abcあいう", &text.GoTextFace{
        Source: src,
        Size:   10,
    }, nil)
    println(len(glyphs)) // 0 was printed unexpectedly. This means no glyphs were obtained.
}
hajimehoshi commented 7 months ago

Here is the minimal reproducible test case:

package main

import (
    "bytes"
    _ "embed"
    "fmt"

    "github.com/go-text/typesetting/di"
    "github.com/go-text/typesetting/opentype/api/font"
    "github.com/go-text/typesetting/opentype/loader"
    "github.com/go-text/typesetting/shaping"
    "golang.org/x/image/math/fixed"
)

//go:embed NotoSansJP-VF.otf
var noto []byte

func main() {
    l, err := loader.NewLoader(bytes.NewReader(noto))
    if err != nil {
        panic(err)
    }
    f, err := font.NewFont(l)
    if err != nil {
        panic(err)
    }

    str := []rune("abcあいう")

    input := shaping.Input{
        Text:      str,
        RunStart:  0,
        RunEnd:    len(str),
        Direction: di.DirectionLTR,
        Face:      &font.Face{Font: f},
        Size:      fixed.I(10),
    }
    out := (&shaping.HarfbuzzShaper{}).Shape(input)

    for _, g := range out.Glyphs {
        fmt.Printf("%#v\n", g)
    }
}

Result:

shaping.Glyph{Width:0, Height:0, XBearing:0, YBearing:0, XAdvance:0, YAdvance:0, XOffset:0, YOffset:0, ClusterIndex:0, RuneCount:1, GlyphCount:1, GlyphID:0x42, Mask:0x80000000}
shaping.Glyph{Width:0, Height:0, XBearing:0, YBearing:0, XAdvance:0, YAdvance:0, XOffset:0, YOffset:0, ClusterIndex:1, RuneCount:1, GlyphCount:1, GlyphID:0x43, Mask:0x80000000}
shaping.Glyph{Width:0, Height:0, XBearing:0, YBearing:0, XAdvance:0, YAdvance:0, XOffset:0, YOffset:0, ClusterIndex:2, RuneCount:1, GlyphCount:1, GlyphID:0x44, Mask:0x80000000}
shaping.Glyph{Width:0, Height:0, XBearing:0, YBearing:0, XAdvance:0, YAdvance:0, XOffset:0, YOffset:0, ClusterIndex:3, RuneCount:1, GlyphCount:1, GlyphID:0x4b5, Mask:0x80000000}
shaping.Glyph{Width:0, Height:0, XBearing:0, YBearing:0, XAdvance:0, YAdvance:0, XOffset:0, YOffset:0, ClusterIndex:4, RuneCount:1, GlyphCount:1, GlyphID:0x4b7, Mask:0x80000000}
shaping.Glyph{Width:0, Height:0, XBearing:0, YBearing:0, XAdvance:0, YAdvance:0, XOffset:0, YOffset:0, ClusterIndex:5, RuneCount:1, GlyphCount:1, GlyphID:0x4b9, Mask:0x80000000}

So apparently glyph IDs were correctly assigned, but the other data were not found.

EDIT: Specifying a language and a script didn't change the result.

benoitkugler commented 7 months ago

Here is the minimal reproducible test case:

Excellent reproducer, thanks a lot. I'll look into it as soon as possible :)

benoitkugler commented 7 months ago

The NotoSansJP-VF.otf font uses the CFF2 table to describe its glyphs. This table is not yet supported by go-text (also not broadly used, but will probably gain popularity since it supports variations). We should support it : I've created this branch to do so (WIP).