Revert "text/v2: rename Glyph -> Cluster"

This reverts commit f0d23de3d3.

Reason: Cluster doesn't represent a cluster but a part of a cluster.
This commit is contained in:
Hajime Hoshi 2023-12-05 19:44:32 +09:00
parent f0d23de3d3
commit 800835d081
8 changed files with 63 additions and 71 deletions

View File

@ -61,15 +61,15 @@ type Game struct {
counter int counter int
kanjiText []rune kanjiText []rune
kanjiTextColor color.RGBA kanjiTextColor color.RGBA
clusters []text.Cluster glyphs []text.Glyph
} }
func (g *Game) Update() error { func (g *Game) Update() error {
// Initialize the glyphs for special (colorful) rendering. // Initialize the glyphs for special (colorful) rendering.
if len(g.clusters) == 0 { if len(g.glyphs) == 0 {
op := &text.LayoutOptions{} op := &text.LayoutOptions{}
op.LineSpacingInPixels = mplusNormalFace.Size * 1.5 op.LineSpacingInPixels = mplusNormalFace.Size * 1.5
g.clusters = text.AppendClusters(g.clusters, sampleText, mplusNormalFace, op) g.glyphs = text.AppendGlyphs(g.glyphs, sampleText, mplusNormalFace, op)
} }
return nil return nil
} }
@ -121,16 +121,13 @@ func (g *Game) Draw(screen *ebiten.Image) {
{ {
const x, y = 240, 360 const x, y = 240, 360
op := &ebiten.DrawImageOptions{} op := &ebiten.DrawImageOptions{}
// g.glyphs is initialized by text.AppendClusters // g.glyphs is initialized by text.AppendGlyphs.
// You can customize how to render each glyph. // You can customize how to render each glyph.
// In this example, multiple colors are used to render glyphs. // In this example, multiple colors are used to render glyphs.
for i, c := range g.clusters { for i, gl := range g.glyphs {
if c.Image == nil {
continue
}
op.GeoM.Reset() op.GeoM.Reset()
op.GeoM.Translate(x, y) op.GeoM.Translate(x, y)
op.GeoM.Translate(c.X, c.Y) op.GeoM.Translate(gl.X, gl.Y)
op.ColorScale.Reset() op.ColorScale.Reset()
r := float32(1) r := float32(1)
if i%3 == 0 { if i%3 == 0 {
@ -145,7 +142,7 @@ func (g *Game) Draw(screen *ebiten.Image) {
b = 0.5 b = 0.5
} }
op.ColorScale.Scale(r, g, b, 1) op.ColorScale.Scale(r, g, b, 1)
screen.DrawImage(c.Image, op) screen.DrawImage(gl.Image, op)
} }
} }
} }

View File

@ -291,8 +291,8 @@ func (g *GoTextFace) hasGlyph(r rune) bool {
return ok return ok
} }
// appendClustersForLine implements Face. // appendGlyphsForLine implements Face.
func (g *GoTextFace) appendClustersForLine(clusters []Cluster, line string, indexOffset int, originX, originY float64) []Cluster { func (g *GoTextFace) appendGlyphsForLine(glyphs []Glyph, line string, indexOffset int, originX, originY float64) []Glyph {
origin := fixed.Point26_6{ origin := fixed.Point26_6{
X: float64ToFixed26_6(originX), X: float64ToFixed26_6(originX),
Y: float64ToFixed26_6(originY), Y: float64ToFixed26_6(originY),
@ -300,9 +300,8 @@ func (g *GoTextFace) appendClustersForLine(clusters []Cluster, line string, inde
_, gs := g.Source.shape(line, g) _, gs := g.Source.shape(line, g)
for _, glyph := range gs { for _, glyph := range gs {
img, imgX, imgY := g.glyphImage(glyph, origin) img, imgX, imgY := g.glyphImage(glyph, origin)
// Append a glyph even if img is nil. if img != nil {
// This is necessary to return index information for control characters. glyphs = append(glyphs, Glyph{
clusters = append(clusters, Cluster{
StartIndexInBytes: indexOffset + glyph.startIndex, StartIndexInBytes: indexOffset + glyph.startIndex,
EndIndexInBytes: indexOffset + glyph.endIndex, EndIndexInBytes: indexOffset + glyph.endIndex,
GID: uint32(glyph.shapingGlyph.GlyphID), GID: uint32(glyph.shapingGlyph.GlyphID),
@ -310,13 +309,14 @@ func (g *GoTextFace) appendClustersForLine(clusters []Cluster, line string, inde
X: float64(imgX), X: float64(imgX),
Y: float64(imgY), Y: float64(imgY),
}) })
}
origin = origin.Add(fixed.Point26_6{ origin = origin.Add(fixed.Point26_6{
X: glyph.shapingGlyph.XAdvance, X: glyph.shapingGlyph.XAdvance,
Y: -glyph.shapingGlyph.YAdvance, Y: -glyph.shapingGlyph.YAdvance,
}) })
} }
return clusters return glyphs
} }
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) {

View File

@ -105,10 +105,7 @@ func Draw(dst *ebiten.Image, text string, face Face, options *DrawOptions) {
} }
geoM := options.GeoM geoM := options.GeoM
for _, g := range AppendClusters(nil, text, face, &options.LayoutOptions) { for _, g := range AppendGlyphs(nil, text, face, &options.LayoutOptions) {
if g.Image == nil {
continue
}
op := &options.DrawImageOptions op := &options.DrawImageOptions
op.GeoM.Reset() op.GeoM.Reset()
op.GeoM.Translate(g.X, g.Y) op.GeoM.Translate(g.X, g.Y)
@ -117,16 +114,16 @@ func Draw(dst *ebiten.Image, text string, face Face, options *DrawOptions) {
} }
} }
// AppendClusters appends glyphs to the given slice and returns a slice. // AppendGlyphs appends glyphs to the given slice and returns a slice.
// //
// AppendClusters is a low-level API, and you can use AppendClusters to have more control than Draw. // AppendGlyphs is a low-level API, and you can use AppendGlyphs to have more control than Draw.
// AppendClusters is also available to precache glyphs. // AppendGlyphs is also available to precache glyphs.
// //
// For the details of options, see Draw function. // For the details of options, see Draw function.
// //
// AppendClusters is concurrent-safe. // AppendGlyphs is concurrent-safe.
func AppendClusters(glyphs []Cluster, text string, face Face, options *LayoutOptions) []Cluster { func AppendGlyphs(glyphs []Glyph, text string, face Face, options *LayoutOptions) []Glyph {
return appendClusters(glyphs, text, face, 0, 0, options) return appendGlyphs(glyphs, text, face, 0, 0, options)
} }
// AppndVectorPath appends a vector path for glyphs to the given path. // AppndVectorPath appends a vector path for glyphs to the given path.
@ -139,13 +136,13 @@ func AppendVectorPath(path *vector.Path, text string, face Face, options *Layout
}) })
} }
// appendClusters appends glyphs to the given slice and returns a slice. // appendGlyphs appends glyphs to the given slice and returns a slice.
// //
// appendClusters assumes the text is rendered with the position (x, y). // appendGlyphs assumes the text is rendered with the position (x, y).
// (x, y) might affect the subpixel rendering results. // (x, y) might affect the subpixel rendering results.
func appendClusters(glyphs []Cluster, text string, face Face, x, y float64, options *LayoutOptions) []Cluster { func appendGlyphs(glyphs []Glyph, text string, face Face, x, y float64, options *LayoutOptions) []Glyph {
forEachLine(text, face, options, func(line string, indexOffset int, originX, originY float64) { forEachLine(text, face, options, func(line string, indexOffset int, originX, originY float64) {
glyphs = face.appendClustersForLine(glyphs, line, indexOffset, originX+x, originY+y) glyphs = face.appendGlyphsForLine(glyphs, line, indexOffset, originX+x, originY+y)
}) })
return glyphs return glyphs
} }

View File

@ -55,9 +55,9 @@ func (l *LimitedFace) hasGlyph(r rune) bool {
return l.unicodeRanges.contains(r) && l.face.hasGlyph(r) return l.unicodeRanges.contains(r) && l.face.hasGlyph(r)
} }
// appendClustersForLine implements Face. // appendGlyphsForLine implements Face.
func (l *LimitedFace) appendClustersForLine(clusters []Cluster, line string, indexOffset int, originX, originY float64) []Cluster { func (l *LimitedFace) appendGlyphsForLine(glyphs []Glyph, line string, indexOffset int, originX, originY float64) []Glyph {
return l.face.appendClustersForLine(clusters, l.unicodeRanges.filter(line), indexOffset, originX, originY) return l.face.appendGlyphsForLine(glyphs, l.unicodeRanges.filter(line), indexOffset, originX, originY)
} }
// appendVectorPathForLine implements Face. // appendVectorPathForLine implements Face.

View File

@ -102,15 +102,15 @@ func (m *MultiFace) hasGlyph(r rune) bool {
return false return false
} }
// appendClustersForLine implements Face. // appendGlyphsForLine implements Face.
func (m *MultiFace) appendClustersForLine(clusters []Cluster, line string, indexOffset int, originX, originY float64) []Cluster { func (m *MultiFace) appendGlyphsForLine(glyphs []Glyph, line string, indexOffset int, originX, originY float64) []Glyph {
for _, c := range m.splitText(line) { for _, c := range m.splitText(line) {
if c.faceIndex == -1 { if c.faceIndex == -1 {
continue continue
} }
f := m.faces[c.faceIndex] f := m.faces[c.faceIndex]
t := line[c.textStartIndex:c.textEndIndex] t := line[c.textStartIndex:c.textEndIndex]
clusters = f.appendClustersForLine(clusters, t, indexOffset, originX, originY) glyphs = f.appendGlyphsForLine(glyphs, t, indexOffset, originX, originY)
if a := f.advance(t); f.direction().isHorizontal() { if a := f.advance(t); f.direction().isHorizontal() {
originX += a originX += a
} else { } else {
@ -118,7 +118,7 @@ func (m *MultiFace) appendClustersForLine(clusters []Cluster, line string, index
} }
indexOffset += len(t) indexOffset += len(t)
} }
return clusters return glyphs
} }
// appendVectorPathForLine implements Face. // appendVectorPathForLine implements Face.

View File

@ -93,8 +93,8 @@ func (s *StdFace) hasGlyph(r rune) bool {
return ok return ok
} }
// appendClustersForLine implements Face. // appendGlyphsForLine implements Face.
func (s *StdFace) appendClustersForLine(clusters []Cluster, line string, indexOffset int, originX, originY float64) []Cluster { func (s *StdFace) appendGlyphsForLine(glyphs []Glyph, line string, indexOffset int, originX, originY float64) []Glyph {
s.copyCheck() s.copyCheck()
origin := fixed.Point26_6{ origin := fixed.Point26_6{
@ -108,25 +108,23 @@ func (s *StdFace) appendClustersForLine(clusters []Cluster, line string, indexOf
origin.X += s.f.Kern(prevR, r) origin.X += s.f.Kern(prevR, r)
} }
img, imgX, imgY, a := s.glyphImage(r, origin) img, imgX, imgY, a := s.glyphImage(r, origin)
if img != nil {
// Adjust the position to the integers. // Adjust the position to the integers.
// The current glyph images assume that they are rendered on integer positions so far. // The current glyph images assume that they are rendered on integer positions so far.
_, size := utf8.DecodeRuneInString(line[i:]) _, size := utf8.DecodeRuneInString(line[i:])
glyphs = append(glyphs, Glyph{
// Append a glyph even if img is nil.
// This is necessary to return index information for control characters.
clusters = append(clusters, Cluster{
StartIndexInBytes: indexOffset + i, StartIndexInBytes: indexOffset + i,
EndIndexInBytes: indexOffset + i + size, EndIndexInBytes: indexOffset + i + size,
Image: img, Image: img,
X: float64(imgX), X: float64(imgX),
Y: float64(imgY), Y: float64(imgY),
}) })
}
origin.X += a origin.X += a
prevR = r prevR = r
} }
return clusters return glyphs
} }
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) {

View File

@ -36,7 +36,7 @@ type Face interface {
hasGlyph(r rune) bool hasGlyph(r rune) bool
appendClustersForLine(glyphs []Cluster, line string, indexOffset int, originX, originY float64) []Cluster appendGlyphsForLine(glyphs []Glyph, line string, indexOffset int, originX, originY float64) []Glyph
appendVectorPathForLine(path *vector.Path, line string, originX, originY float64) appendVectorPathForLine(path *vector.Path, line string, originX, originY float64)
direction() Direction direction() Direction
@ -117,12 +117,12 @@ func adjustGranularity(x fixed.Int26_6, face Face) fixed.Int26_6 {
return x / factor * factor return x / factor * factor
} }
// Cluster represents one grapheme cluster. // Glyph represents one glyph to render.
type Cluster struct { type Glyph struct {
// StartIndexInBytes is the start index in bytes for the given string at AppendClusters. // StartIndexInBytes is the start index in bytes for the given string at AppendGlyphs.
StartIndexInBytes int StartIndexInBytes int
// EndIndexInBytes is the end index in bytes for the given string at AppendClusters. // EndIndexInBytes is the end index in bytes for the given string at AppendGlyphs.
EndIndexInBytes int EndIndexInBytes int
// GID is an ID for a glyph of TrueType or OpenType font. GID is valid when the face is GoTextFace. // GID is an ID for a glyph of TrueType or OpenType font. GID is valid when the face is GoTextFace.
@ -134,12 +134,12 @@ type Cluster struct {
Image *ebiten.Image Image *ebiten.Image
// X is the X position to render this glyph. // X is the X position to render this glyph.
// The position is determined in a sequence of characters given at AppendClusters. // The position is determined in a sequence of characters given at AppendGlyphs.
// The position's origin is the first character's origin position. // The position's origin is the first character's origin position.
X float64 X float64
// Y is the Y position to render this glyph. // Y is the Y position to render this glyph.
// The position is determined in a sequence of characters given at AppendClusters. // The position is determined in a sequence of characters given at AppendGlyphs.
// The position's origin is the first character's origin position. // The position's origin is the first character's origin position.
Y float64 Y float64
} }
@ -245,10 +245,10 @@ func CacheGlyphs(text string, face Face) {
c := glyphVariationCount(face) c := glyphVariationCount(face)
var buf []Cluster var buf []Glyph
// Create all the possible variations (#2528). // Create all the possible variations (#2528).
for i := 0; i < c; i++ { for i := 0; i < c; i++ {
buf = appendClusters(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() {

View File

@ -40,7 +40,7 @@ over the lazy dog.`
f := text.NewStdFace(bitmapfont.Face) f := text.NewStdFace(bitmapfont.Face)
got := sampleText got := sampleText
for _, g := range text.AppendClusters(nil, sampleText, f, nil) { for _, g := range text.AppendGlyphs(nil, sampleText, f, nil) {
got = got[:g.StartIndexInBytes] + strings.Repeat(" ", g.EndIndexInBytes-g.StartIndexInBytes) + got[g.EndIndexInBytes:] got = got[:g.StartIndexInBytes] + strings.Repeat(" ", g.EndIndexInBytes-g.StartIndexInBytes) + got[g.EndIndexInBytes:]
} }
want := regexp.MustCompile(`\S`).ReplaceAllString(sampleText, " ") want := regexp.MustCompile(`\S`).ReplaceAllString(sampleText, " ")