Update shaper_usage.md with correct glyph drawing approach
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
parent
fcd2fea870
commit
0f62ef32fa
|
|
@ -159,34 +159,52 @@ func charWidths(gtx layout.Context, shp *text.Shaper, str string, size unit.Sp)
|
|||
|
||||
## 5. Rendering Glyphs Directly
|
||||
|
||||
Instead of using `material.Label()` (which shapes text again), draw glyphs directly:
|
||||
Gio's textView draws glyphs using `shaper.Shape()` (for vector glyphs) and `shaper.Bitmaps()` (for bitmap glyphs like emoji). This is the correct approach to avoid double-shaping.
|
||||
|
||||
### 5.1 Drawing a Single Glyph
|
||||
### 5.1 Drawing Text Using Gio's textView Approach
|
||||
|
||||
```go
|
||||
// After layout, iterate through glyphs
|
||||
for {
|
||||
g, ok := shp.NextGlyph()
|
||||
if !ok {
|
||||
break
|
||||
func drawText(gtx layout.Context, shp *text.Shaper, str string, size unit.Sp, x, y unit.Dp, col color.NRGBA) {
|
||||
// Layout text
|
||||
shp.LayoutString(text.Parameters{PxPerEm: fixed.I(gtx.Sp(size))}, str)
|
||||
|
||||
// Draw glyphs using the same approach as Gio's textView
|
||||
var glyphs [32]text.Glyph
|
||||
line := glyphs[:0]
|
||||
for g, ok := shp.NextGlyph(); ok; g, ok = shp.NextGlyph() {
|
||||
line = append(line, g)
|
||||
if g.Flags&text.FlagLineBreak != 0 || cap(line)-len(line) == 0 {
|
||||
drawLine(gtx, shp, line, x, y, col)
|
||||
line = line[:0]
|
||||
}
|
||||
// Draw glyph at position (g.X, g.Y)
|
||||
// Use shp.DrawGlyph() or manual drawing
|
||||
}
|
||||
if len(line) > 0 {
|
||||
drawLine(gtx, shp, line, x, y, col)
|
||||
}
|
||||
}
|
||||
|
||||
func drawLine(gtx layout.Context, shp *text.Shaper, line []text.Glyph, x, y unit.Dp, col color.NRGBA) {
|
||||
// Apply offset transform
|
||||
off := f32.Point{X: float32(x), Y: float32(y)}
|
||||
t := op.Affine(f32.Affine2D{}.Offset(off)).Push(gtx.Ops)
|
||||
|
||||
// Draw vector glyphs
|
||||
path := shp.Shape(line)
|
||||
outline := clip.Outline{Path: path}.Op().Push(gtx.Ops)
|
||||
paint.ColorOp{Color: col}.Add(gtx.Ops)
|
||||
paint.PaintOp{}.Add(gtx.Ops)
|
||||
outline.Pop()
|
||||
|
||||
// Draw bitmap glyphs (emoji, etc.)
|
||||
if call := shp.Bitmaps(line); call != (op.CallOp{}) {
|
||||
call.Add(gtx.Ops)
|
||||
}
|
||||
|
||||
t.Pop()
|
||||
}
|
||||
```
|
||||
|
||||
### 5.2 Using Shaper's Drawing Functions
|
||||
|
||||
The shaper provides drawing functions that use the already-computed glyph data:
|
||||
|
||||
```go
|
||||
// Draw all laid-out glyphs
|
||||
shp.Draw(gtx, ops, color.NRGBA{R: 0, G: 0, B: 0, A: 255})
|
||||
```
|
||||
|
||||
**Important**: Call `shp.Draw()` AFTER calling `LayoutString()` or `Layout()`. The drawing functions use the glyph data computed during the layout phase.
|
||||
|
||||
### 5.3 Avoiding Double-Shaping
|
||||
### 5.2 Avoiding Double-Shaping
|
||||
|
||||
**WRONG** (shapes text twice):
|
||||
|
||||
|
|
@ -198,14 +216,19 @@ widths := charWidths(gtx, shp, text, size)
|
|||
material.Label(th, size, text).Layout(gtx)
|
||||
```
|
||||
|
||||
**CORRECT** (shapes text once):
|
||||
**CORRECT** (shapes text once for rendering):
|
||||
|
||||
```go
|
||||
// Single pass: layout and draw
|
||||
shp.LayoutString(text.Parameters{PxPerEm: fixed.I(gtx.Sp(size))}, text)
|
||||
shp.Draw(gtx, ops, color.NRGBA{R: 0, G: 0, B: 0, A: 255})
|
||||
// Single pass: layout and draw using shaper.Shape()
|
||||
drawText(gtx, shp, text, size, x, y, col)
|
||||
```
|
||||
|
||||
**NOTE**: For truncation, we may need to layout twice:
|
||||
1. First layout to measure widths and find truncation point
|
||||
2. Second layout to draw the truncated text
|
||||
|
||||
This is acceptable because truncation is only needed when text doesn't fit, and the string is short (filename in StatusBar).
|
||||
|
||||
## 6. Comparison with Gio's textView
|
||||
|
||||
Gio's textView (`widget/text.go`) demonstrates the correct approach:
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user