-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathtext_shaping.go
104 lines (83 loc) · 2.32 KB
/
text_shaping.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
package pdf
import (
"github.com/go-text/typesetting/font"
"github.com/go-text/typesetting/fontscan"
"github.com/go-text/typesetting/opentype/api/metadata"
"github.com/go-text/typesetting/shaping"
"golang.org/x/image/math/fixed"
"rogchap.com/skia"
)
type textRun struct {
glyphs []*shapedGlyph
face font.Face
size float32
ascent float32
descent float32
lineThickness float32
}
type shapedGlyph struct {
glyphID uint16
position skia.Point
width float32
parentRun *textRun
}
// TODO: Do we need to consider concurrency?
var shaper = shaping.HarfbuzzShaper{}
func shape(text string, style TextStyle) []*textRun {
var fontSize float32 = 16 // default
if style.FontSize != 0 {
fontSize = style.FontSize
}
// TODO: should the FontMap be per-doc otherwise we will have race conditions
// with setting the query
fmap := defaultFontMgr.hbFontMgr
aspect := metadata.Aspect{}
aspect.SetDefaults()
aspect.Weight = metadata.Weight(style.FontWeight)
if style.Italic {
aspect.Style = metadata.StyleItalic
}
fmap.SetQuery(fontscan.Query{Families: style.FontFamily, Aspect: aspect})
runes := []rune(text)
in := shaping.Input{
Text: runes,
RunStart: 0,
RunEnd: len(runes),
Direction: style.Direction,
Size: float32ToFixed266(fontSize),
}
ins := shaping.SplitByFace(in, fmap)
var x, y float32
var runs []*textRun
for _, in := range ins {
out := shaper.Shape(in)
run := textRun{
face: out.Face,
size: fixed266ToFloat32(out.Size),
ascent: fixed266ToFloat32(out.LineBounds.Ascent),
descent: fixed266ToFloat32(out.LineBounds.Descent),
lineThickness: fixed266ToFloat32(out.LineBounds.LineThickness()),
}
for _, g := range out.Glyphs {
run.glyphs = append(run.glyphs, &shapedGlyph{
glyphID: uint16(g.GlyphID),
position: skia.NewPoint(
x+fixed266ToFloat32(g.XOffset),
y-fixed266ToFloat32(g.YOffset),
),
width: fixed266ToFloat32(g.XAdvance),
parentRun: &run,
})
x += fixed266ToFloat32(g.XAdvance)
y += fixed266ToFloat32(g.YAdvance)
}
runs = append(runs, &run)
}
return runs
}
func fixed266ToFloat32(i fixed.Int26_6) float32 {
return float32(float64(i) / (1 << 6))
}
func float32ToFixed266(f float32) fixed.Int26_6 {
return fixed.Int26_6(float64(f) * (1 << 6))
}