/
font.go
622 lines (565 loc) · 17.2 KB
/
font.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
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
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
package cairo
//#cgo pkg-config: cairo
//#include <stdlib.h>
//#include <cairo/cairo.h>
import "C"
import (
"runtime"
"unsafe"
)
//FontOptions specify how fonts should be rendered.
//Most of the time the font options implied by a surface are just right
//and do not need changes, but, for pixel-based targets, tweaking font options
//may result in superior output on a particular display.
//
//Originally cairo_font_options_t.
type FontOptions struct {
fo *C.cairo_font_options_t
}
//NewFontOptions creates a new FontOptions with the default values.
//
//Originally cairo_font_options_create.
func NewFontOptions() *FontOptions {
return initFontOptions(C.cairo_font_options_create())
}
func initFontOptions(opt *C.cairo_font_options_t) *FontOptions {
fo := &FontOptions{opt}
runtime.SetFinalizer(fo, (*FontOptions).Close)
return fo
}
//Close destroys the FontOptions. Close is idempotent.
//
//Originally cairo_font_options_destroy.
func (f *FontOptions) Close() error {
if f == nil || f.fo == nil {
return nil
}
err := f.Err()
C.cairo_font_options_destroy(f.fo)
f.fo = nil
runtime.SetFinalizer(f, nil)
return err
}
//Err queries f to see if there is an error.
//
//Originally cairo_font_options_status.
func (f *FontOptions) Err() error {
if f.fo == nil {
return ErrInvalidLibcairoHandle
}
return toerr(C.cairo_font_options_status(f.fo))
}
//Merge merges non-default options from o into f and return f.
//
//Originally cairo_font_options_merge.
func (f *FontOptions) Merge(o *FontOptions) *FontOptions {
C.cairo_font_options_merge(f.fo, o.fo)
return f
}
//Clone creates a new FontOptions with the same values as f.
//
//Originally cairo_font_options_copy.
func (f *FontOptions) Clone() *FontOptions {
return &FontOptions{C.cairo_font_options_copy(f.fo)}
}
//Equal compares f with o.
//
//Originally cairo_font_options_equal.
func (f *FontOptions) Equal(o *FontOptions) bool {
return C.cairo_font_options_equal(f.fo, o.fo) == 1
}
//SetAntialiasMode sets the antialiasing mode of f and returns f.
//
//Originally cairo_font_options_set_antialias.
func (f *FontOptions) SetAntialiasMode(a antialias) *FontOptions {
C.cairo_font_options_set_antialias(f.fo, C.cairo_antialias_t(a))
return f
}
//AntialiasMode reports the antialiasing mode of f.
//
//Originally cairo_font_topns_get_antialias.
func (f *FontOptions) AntialiasMode() antialias {
return antialias(C.cairo_font_options_get_antialias(f.fo))
}
//SetSubpixelOrder sets the subpixel ordering of f and returns f.
//
//Originally cairo_font_options_set_subpixel_order.
func (f *FontOptions) SetSubpixelOrder(s subpixelOrder) *FontOptions {
C.cairo_font_options_set_subpixel_order(f.fo, C.cairo_subpixel_order_t(s))
return f
}
//SubpixelOrder reports the subpixel ordering of f.
//
//Originally cairo_font_options_get_subpixel_order.
func (f *FontOptions) SubpixelOrder() subpixelOrder {
return subpixelOrder(C.cairo_font_options_get_subpixel_order(f.fo))
}
//SetHintStyle sets the hint style of f and returns f.
//
//Originally cairo_font_options_set_hint_style.
func (f *FontOptions) SetHintStyle(h hintStyle) *FontOptions {
C.cairo_font_options_set_hint_style(f.fo, C.cairo_hint_style_t(h))
return f
}
//HintStyle reports the hint style of f.
//
//Originally cairo_font_options_get_hint_style.
func (f *FontOptions) HintStyle() hintStyle {
return hintStyle(C.cairo_font_options_get_hint_style(f.fo))
}
//SetHintMetrics sets the hint metrics of f and returns f.
//
//Originally cairo_font_options_set_hint_metrics.
func (f *FontOptions) SetHintMetrics(h hintMetrics) *FontOptions {
C.cairo_font_options_set_hint_metrics(f.fo, C.cairo_hint_metrics_t(h))
return f
}
//HintMetrics reports the hint metrics of f.
//
//Originally cairo_font_options_get_hint_metrics.
func (f *FontOptions) HintMetrics() hintMetrics {
return hintMetrics(C.cairo_font_options_get_hint_metrics(f.fo))
}
//FontExtents stores metric information for a font.
//Values are given in the current user-space coordinate system.
//
//Because font metrics are in user-space coordinates, they are mostly,
//but not entirely, independent of the current transformation matrix.
//They will, however, change slightly due to hinting but otherwise remain
//unchanged.
//
//Originally cairo_font_extents_t.
type FontExtents struct {
//Ascent is the distance the font extends above the baseline.
Ascent float64
//Descent is the distance the font extends below the baseline.
Descent float64
//Height is the recommended vertical distance between baselines
//when setting consecutive lines of text with the font.
Height float64
//MaxAdvanceX is the maximum distance in the X direction that
//the origin is advanced for any glyph in the font.
//
//Originally max_y_advance.
MaxAdvanceX float64
//MaxAdvanceY is the maximum distance in the Y direction that
//the origin is advanced for any glyph in the font.
//
//This will be zero for most fonts used for horizontal writing.
//
//Originally max_x_advance.
MaxAdvanceY float64
}
//XtensionFontExtentsCtoGo converts a cairo_font_extent_t into a FontExtents
//value.
func XtensionFontExtentsCtoGo(fe C.cairo_font_extents_t) FontExtents {
return FontExtents{
float64(fe.ascent),
float64(fe.descent),
float64(fe.height),
float64(fe.max_x_advance),
float64(fe.max_y_advance),
}
}
//XtensionRaw returns f as a cairo_font_extents_t.
func (f FontExtents) XtensionRaw() C.cairo_font_extents_t {
return C.cairo_font_extents_t{
C.double(f.Ascent),
C.double(f.Descent),
C.double(f.Height),
C.double(f.MaxAdvanceX),
C.double(f.MaxAdvanceY),
}
}
//ExternalLeading reports the difference between the Height and the sum
//of the Ascent and Descent. Also known as "line spacing".
func (f FontExtents) ExternalLeading() float64 {
return f.Height - (f.Ascent + f.Descent)
}
//TextExtents stores the extents of a single glyph or string of glyphs
//in user-space coordinates.
//Because text extents are in user-space coordinates, they are mostly,
//but not entirely, independent of the current transformation matrix.
//They will, however, change slightly due to hinting.
//
//Originally cairo_text_extents_t.
type TextExtents struct {
//The horizontal distance from the origin to the leftmost part of the glyhps
//as drawn.
//Positive if the glyphs lie entirely to the right of the origin.
//
//Originally x_bearing.
BearingX float64
//The vertical distance from the origin to the topmost part of the glyhps
//as drawn.
//Positive if the glyphs lie entirely below the origin.
//
//Originally y_bearing.
BearingY float64
//Width of the glyphs as drawn.
Width float64
//Height of the glyphs as drawn.
Height float64
//AdvanceX is the distance in the X direction to advance after drawing
//these glyphs.
//
//Originally x_advance.
AdvanceX float64
//AdvanceY is the distance in the Y direction to advance after drawing
//these glyphs.
//
//This will be zero for most fonts used for horizontal writing.
//
//Originally y_advance.
AdvanceY float64
}
//XtensionNewTextExtents converts a cairo_text_extents_t into a TextExtents.
func XtensionNewTextExtents(te C.cairo_text_extents_t) TextExtents {
return TextExtents{
BearingX: float64(te.x_bearing),
BearingY: float64(te.y_bearing),
Width: float64(te.width),
Height: float64(te.height),
AdvanceX: float64(te.x_advance),
AdvanceY: float64(te.y_advance),
}
}
//XtensionRaw returns t as a cairo_text_extents_t.
func (t TextExtents) XtensionRaw() C.cairo_text_extents_t {
return C.cairo_text_extents_t{
C.double(t.BearingX),
C.double(t.BearingY),
C.double(t.Width),
C.double(t.Height),
C.double(t.AdvanceX),
C.double(t.AdvanceY),
}
}
//Glyph holds information about a single glyph when drawing or measuring text.
//A font is (in simple terms) a collection of shapes used to draw text.
//A glyph is one of these shapes.
//There can be multiple glyphs for a single character (alternates to be used
//in different contexts, for example), or a glyph can be a ligature of multiple
//characters.
//Cairo doesn't expose any way of converting input text into glyphs,
//so in order to use the Cairo interfaces that take arrays of glyphs, you must
//directly access the appropriate underlying font system.
//
//Note that the offsets given by Point.X and Point.Y are not cumulative.
//When drawing or measuring text, each glyph is individually positioned with respect to the overall origin
//
//Originally cairo_glyph_t.
type Glyph struct {
Index uint64
Point Point
}
func cGlyph(g C.cairo_glyph_t) Glyph {
return Glyph{
Index: uint64(g.index),
Point: cPt(g.x, g.y),
}
}
//XtensionGlyphsCtoGo converts an array of cario_glyph_t to a []Glyph.
func XtensionGlyphsCtoGo(glyphs *C.cairo_glyph_t, N C.int) []Glyph {
n := int(N)
gs := (*[1 << 30]C.cairo_glyph_t)(unsafe.Pointer(glyphs))[:n:n]
out := make([]Glyph, n)
for i, v := range gs {
out[i] = cGlyph(v)
}
return out
}
//XtensionGlyphsGotoC converts a []Glyph into an array of cairo_glyph_t.
//
//The returned array has been created with malloc unless useGlyphAllocate
//is true, in which case cairo_glyph_allocate is used instead.
//Unless the cairo_glyph_t is meant to be used with a user font,
//useGlyphAllocate must be false.
func XtensionGlyphsGotoC(gs []Glyph, useGlyphAllocate bool) (glyphs *C.cairo_glyph_t, N C.int) {
n := len(gs)
N = C.int(n)
var t C.cairo_glyph_t
if useGlyphAllocate {
glyphs = C.cairo_glyph_allocate(N)
} else {
glyphs = (*C.cairo_glyph_t)(C.malloc(C.size_t(uintptr(n) * unsafe.Sizeof(t))))
}
iter := (*[1 << 30]C.cairo_glyph_t)(unsafe.Pointer(glyphs))[:n:n]
for i, g := range gs {
iter[i] = g.c()
}
return
}
func (g Glyph) c() C.cairo_glyph_t {
out := C.cairo_glyph_t{}
out.index = C.ulong(g.Index)
out.x, out.y = g.Point.c()
return out
}
//Font specifies all aspects of a font other than the size or font matrix.
//
//All methods are documented on XtensionFont
//
//Originally cairo_font_face_t.
type Font interface {
Type() fontType
Close() error
Err() error
Subtype() string
XtensionRaw() *C.cairo_font_face_t
}
//XtensionFont is the "base class" of cairo fonts.
//
//It is meant only for embedding in new font types and should NEVER
//be used directly.
type XtensionFont struct {
f *C.cairo_font_face_t
}
//XtensionNewFont creates a base go font from a c font face.
//
//This is only for extension builders.
func XtensionNewFont(f *C.cairo_font_face_t) *XtensionFont {
x := &XtensionFont{
f: f,
}
runtime.SetFinalizer(f, (*XtensionFont).Close)
return x
}
var cfonttogofont = map[fontType]func(*C.cairo_font_face_t) (Font, error){
FontTypeToy: newToyFont,
FontTypeUser: userFont,
}
//XtensionRegisterRawToFont registers a factory to convert a libcairo
//font face into a properly formed cairo Font of the appropriate
//underlying type.
//
//It is mandatory for extensions defining new font types to call this
//during init, otherwise users will get random not implemented panics
//for your font.
//
//For user fonts you must use XtensionRegisterUserAlienFontSubtype.
func XtensionRegisterRawToFont(t fontType, f func(*C.cairo_font_face_t) (Font, error)) {
cfonttogofont[t] = f
}
func userFont(f *C.cairo_font_face_t) (Font, error) {
id := fontGetSubtypeID(f)
t, ok := fontsubtypes[id]
if !ok {
panic("user font subtype not registered")
}
F, err := t.fac(f)
if err != nil {
return nil, err
}
err = F.Err()
if err != nil {
return nil, err
}
return F, nil
}
func cFont(f *C.cairo_font_face_t) (Font, error) {
t := fontType(C.cairo_font_face_get_type(f))
fac, ok := cfonttogofont[t]
if !ok {
panic("No C → Go font converter registered for " + t.String())
}
F, err := fac(f)
if err != nil {
return nil, err
}
err = F.Err()
if err != nil {
return nil, err
}
return F, nil
}
//Type reports the type of the font.
//
//Originally cairo_font_face_get_type.
func (f *XtensionFont) Type() fontType {
return fontType(C.cairo_font_face_get_type(f.f))
}
//Subtype reports the subtype of the font.
//
//This returns "" unless Type reports FontTypeUser.
func (f *XtensionFont) Subtype() string {
if f.Type() != FontTypeUser {
return ""
}
return fontsubtypes[fontGetSubtypeID(f.f)].name
}
//Close frees the resources used by this font.
//
//Originally cairo_font_face_destroy.
func (f *XtensionFont) Close() error {
if f == nil || f.f == nil {
return nil
}
err := f.Err()
C.cairo_font_face_destroy(f.f)
f.f = nil
runtime.SetFinalizer(f, nil)
return err
}
//Err reports any errors on this font.
//
//Originally cairo_font_face_status.
func (f *XtensionFont) Err() error {
if f.f == nil {
return ErrInvalidLibcairoHandle
}
return toerr(C.cairo_font_face_status(f.f))
}
//XtensionRaw return the raw cairo_font_face_t pointer.
//
//XtensionRaw is only meant for creating new font types and should NEVER
//be used directly.
func (f *XtensionFont) XtensionRaw() *C.cairo_font_face_t {
return f.f
}
//ToyFont is a Font created by the libcairo "toy" font API.
//
//See Context.SelectFace for more details.
type ToyFont struct {
*XtensionFont
slant slant
weight weight
family string
}
func cNewToyFont(f *C.cairo_font_face_t, family string, s slant, w weight) ToyFont {
return ToyFont{
XtensionFont: XtensionNewFont(f),
slant: s,
weight: w,
family: family,
}
}
func newToyFont(f *C.cairo_font_face_t) (Font, error) {
family := C.GoString(C.cairo_toy_font_face_get_family(f))
s := slant(C.cairo_toy_font_face_get_slant(f))
w := weight(C.cairo_toy_font_face_get_weight(f))
F := cNewToyFont(f, family, s, w)
return F, F.Err()
}
//NewToyFont creates a toy font of the given family, slant, and weight.
//
//If family is "", the default toy font for the given platform will be used,
//typically sans-serif.
//
//See Context.SelectFont for more details.
//
//Originally cairo_toy_font_face_create.
func NewToyFont(family string, slant slant, weight weight) ToyFont {
s := C.CString(family)
f := C.cairo_toy_font_face_create(s, slant.c(), weight.c())
C.free(unsafe.Pointer(s))
return cNewToyFont(f, family, slant, weight)
}
//A ScaledFont is a font scaled to a particular size and device resolution.
//
//ScaledFont is most useful for low-level font usage where a library
//or application wants to cache a reference to a scaled font to speed up
//computation of metrics.
//
//Originally cairo_scaled_font_t.
type ScaledFont struct {
f *C.cairo_scaled_font_t
}
func cNewScaledFont(f *C.cairo_scaled_font_t) *ScaledFont {
s := &ScaledFont{f}
runtime.SetFinalizer(f, (*ScaledFont).Close)
return s
}
//NewScaledFont creates a scaled font of f.
//
//The fontMatrix is the the font space to user space transformation matrix
//for the font.
//
//The CTM is the user to device coordinate transformation matrix.
//
//Originally cairo_scaled_font_create.
func NewScaledFont(f Font, fontMatrix, CTM Matrix, opts *FontOptions) (*ScaledFont, error) {
s := C.cairo_scaled_font_create(f.XtensionRaw(), &fontMatrix.m, &CTM.m, opts.fo)
S := cNewScaledFont(s)
return S, S.Err()
}
//Err reports any error on s.
//
//Originally cairo_scaled_font_status.
func (s *ScaledFont) Err() error {
if s.f == nil {
return ErrInvalidLibcairoHandle
}
return toerr(C.cairo_scaled_font_status(s.f))
}
//Close frees the resources of s.
//
//Originally cairo_scaled_font_destroy.
func (s *ScaledFont) Close() error {
if s == nil || s.f == nil {
return nil
}
err := s.Err()
runtime.SetFinalizer(s, nil)
C.cairo_scaled_font_destroy(s.f)
return err
}
//Font returns the Font s was created with.
func (s *ScaledFont) Font() (Font, error) {
return cFont(C.cairo_scaled_font_get_font_face(s.f))
}
//XtensionRaw returns the underlying C value of s.
func (s *ScaledFont) XtensionRaw() *C.cairo_scaled_font_t {
return s.f
}
//TextCluster holds information about a single text cluster.
//A text cluster is a minimal mapping of some glyphs to some runes.
//
//For a cluster to be valid, RuneLength and NumGlyphs should be non-negative
//and at least one non-zero.
//Note that clusters with zero glyphs are not as well supported as normal
//clusters.
//For example, PDF rendering applications typically ignore those clusters when
//PDF text is being selected.
//
//Originally cairo_text_cluster_t.
type TextCluster struct {
RuneLength, NumGlyphs int
}
//XtensionTextClustersCtoGo converts an array of cairo_text_cluster_t into
//a []TextCluster.
func XtensionTextClustersCtoGo(clusters *C.cairo_text_cluster_t, N C.int) []TextCluster {
n := int(N)
ts := (*[1 << 30]C.cairo_text_cluster_t)(unsafe.Pointer(clusters))[:n:n]
out := make([]TextCluster, n)
for i, v := range ts {
out[i] = TextCluster{
RuneLength: int(v.num_bytes),
NumGlyphs: int(v.num_glyphs),
}
}
return out
}
//XtensionTextClustersGotoC converts a []TextCluster
//into an array of cairo_text_cluster_t.
//
//The returned array has been created with malloc
//unless useTextClusterAllocator is true, in which case
//cairo_text_cluster_allocate is used instead.
//Unless the resultant array is to be used with a user font,
//useTextClusterAllocator must be false.
func XtensionTextClustersGotoC(tcs []TextCluster, useTextClusterAllocator bool) (cs *C.cairo_text_cluster_t, N C.int) {
n := len(tcs)
N = C.int(n)
var t C.cairo_text_cluster_t
if useTextClusterAllocator {
cs = C.cairo_text_cluster_allocate(N)
} else {
cs = (*C.cairo_text_cluster_t)(C.malloc(C.size_t(uintptr(n) * unsafe.Sizeof(t))))
}
iter := (*[1 << 30]C.cairo_text_cluster_t)(unsafe.Pointer(cs))[:n:n]
for i, t := range tcs {
iter[i] = C.cairo_text_cluster_t{C.int(t.RuneLength), C.int(t.NumGlyphs)}
}
return
}