-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtext.go
More file actions
254 lines (226 loc) · 6.74 KB
/
text.go
File metadata and controls
254 lines (226 loc) · 6.74 KB
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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
// SPDX-License-Identifier: Unlicense OR MIT
package text
import (
"io"
"gioui.org/io/system"
"gioui.org/op/clip"
"github.com/go-text/typesetting/font"
"golang.org/x/image/math/fixed"
)
// A Line contains the measurements of a line of text.
type Line struct {
Layout Layout
// Width is the width of the line.
Width fixed.Int26_6
// Ascent is the height above the baseline.
Ascent fixed.Int26_6
// Descent is the height below the baseline, including
// the line gap.
Descent fixed.Int26_6
// Bounds is the visible bounds of the line.
Bounds fixed.Rectangle26_6
}
// Range describes the position and quantity of a range of text elements
// within a larger slice. The unit is usually runes of unicode data or
// glyphs of shaped font data.
type Range struct {
// Count describes the number of items represented by the Range.
Count int
// Offset describes the start position of the represented
// items within a larger list.
Offset int
}
// GlyphID uniquely identifies a glyph within a specific font.
type GlyphID = font.GID
// Glyph contains the metadata needed to render a glyph.
type Glyph struct {
// ID is this glyph's identifier within the font it was shaped with.
ID GlyphID
// ClusterIndex is the identifier for the text shaping cluster that
// this glyph is part of.
ClusterIndex int
// GlyphCount is the number of glyphs in the same cluster as this glyph.
GlyphCount int
// RuneCount is the quantity of runes in the source text that this glyph
// corresponds to.
RuneCount int
// XAdvance and YAdvance describe the distance the dot moves when
// laying out the glyph on the X or Y axis.
XAdvance, YAdvance fixed.Int26_6
// XOffset and YOffset describe offsets from the dot that should be
// applied when rendering the glyph.
XOffset, YOffset fixed.Int26_6
}
// GlyphCluster provides metadata about a sequence of indivisible shaped
// glyphs.
type GlyphCluster struct {
// Advance is the cumulative advance of all glyphs in the cluster.
Advance fixed.Int26_6
// Runes indicates the position and quantity of the runes represented by
// this cluster within the text.
Runes Range
// Glyphs indicates the position and quantity of the glyphs within this
// cluster in a Layout's Glyphs slice.
Glyphs Range
}
// RuneWidth returns the effective width of one rune for this cluster.
// If the cluster contains multiple runes, the width of the glyphs of
// the cluster is divided evenly among the runes.
func (c GlyphCluster) RuneWidth() fixed.Int26_6 {
if c.Runes.Count == 0 {
return 0
}
return c.Advance / fixed.Int26_6(c.Runes.Count)
}
type Layout struct {
// Glyphs are the actual font characters for the text. They are ordered
// from left to right regardless of the text direction of the underlying
// text.
Glyphs []Glyph
// Clusters are metadata about the shaped glyphs. They are mostly useful for
// interactive text widgets like editors. The order of clusters is logical,
// so the first cluster will describe the beginning of the text and may
// refer to the final glyphs in the Glyphs field if the text is RTL.
Clusters []GlyphCluster
// Runes describes the position of the text data this layout represents
// within the overall body of text being shaped.
Runes Range
// Direction is the layout direction of the text.
Direction system.TextDirection
}
// Slice returns a layout starting at the glyph cluster index start
// and running through the glyph cluster index end. The Offsets field
// of the returned layout is adjusted to reflect the new rune range
// covered by the layout. The returned layout will have no Clusters.
func (l Layout) Slice(start, end int) Layout {
if start == end || end == 0 || start == len(l.Clusters) {
return Layout{}
}
newRuneStart := l.Clusters[start].Runes.Offset
runesBefore := newRuneStart - l.Runes.Offset
endCluster := l.Clusters[end-1]
startCluster := l.Clusters[start]
runesAfter := l.Runes.Offset + l.Runes.Count - (endCluster.Runes.Offset + endCluster.Runes.Count)
if l.Direction.Progression() == system.TowardOrigin {
startCluster, endCluster = endCluster, startCluster
}
glyphStart := startCluster.Glyphs.Offset
glyphEnd := endCluster.Glyphs.Offset + endCluster.Glyphs.Count
out := l
out.Clusters = nil
out.Glyphs = out.Glyphs[glyphStart:glyphEnd]
out.Runes.Offset = newRuneStart
out.Runes.Count -= runesBefore + runesAfter
return out
}
// Style is the font style.
type Style int
// Weight is a font weight, in CSS units subtracted 400 so the zero value
// is normal text weight.
type Weight int
// Font specify a particular typeface variant, style and weight.
type Font struct {
Typeface Typeface
Variant Variant
Style Style
// Weight is the text weight. If zero, Normal is used instead.
Weight Weight
}
// Face implements text layout and shaping for a particular font. All
// methods must be safe for concurrent use.
type Face interface {
Layout(ppem fixed.Int26_6, maxWidth int, lc system.Locale, txt io.RuneReader) ([]Line, error)
Shape(ppem fixed.Int26_6, str Layout) clip.PathSpec
}
// Typeface identifies a particular typeface design. The empty
// string denotes the default typeface.
type Typeface string
// Variant denotes a typeface variant such as "Mono" or "Smallcaps".
type Variant string
type Alignment uint8
const (
Start Alignment = iota
End
Middle
)
const (
Regular Style = iota
Italic
)
const (
Thin Weight = 100 - 400
Hairline Weight = Thin
ExtraLight Weight = 200 - 400
UltraLight Weight = ExtraLight
Light Weight = 300 - 400
Normal Weight = 400 - 400
Medium Weight = 500 - 400
SemiBold Weight = 600 - 400
DemiBold Weight = SemiBold
Bold Weight = 700 - 400
ExtraBold Weight = 800 - 400
UltraBold Weight = ExtraBold
Black Weight = 900 - 400
Heavy Weight = Black
ExtraBlack Weight = 950 - 400
UltraBlack Weight = ExtraBlack
)
func (a Alignment) String() string {
switch a {
case Start:
return "Start"
case End:
return "End"
case Middle:
return "Middle"
default:
panic("invalid Alignment")
}
}
func (s Style) String() string {
switch s {
case Regular:
return "Regular"
case Italic:
return "Italic"
default:
panic("invalid Style")
}
}
func (w Weight) String() string {
switch w {
case Thin:
return "Thin"
case ExtraLight:
return "ExtraLight"
case Light:
return "Light"
case Normal:
return "Normal"
case Medium:
return "Medium"
case SemiBold:
return "SemiBold"
case Bold:
return "Bold"
case ExtraBold:
return "ExtraBold"
case Black:
return "Black"
case ExtraBlack:
return "ExtraBlack"
default:
panic("invalid Weight")
}
}
// weightDistance returns the distance value between two font weights.
func weightDistance(wa Weight, wb Weight) int {
// Avoid dealing with negative Weight values.
a := int(wa) + 400
b := int(wb) + 400
diff := a - b
if diff < 0 {
return -diff
}
return diff
}