1package cairo
2
3// #include <stdlib.h>
4// #include <cairo.h>
5// #include <cairo-gobject.h>
6import "C"
7
8import (
9	"reflect"
10	"runtime"
11	"unsafe"
12)
13
14// Context is a representation of Cairo's cairo_t.
15type Context struct {
16	context *C.cairo_t
17}
18
19// native returns a pointer to the underlying cairo_t.
20func (v *Context) native() *C.cairo_t {
21	if v == nil {
22		return nil
23	}
24	return v.context
25}
26
27func (v *Context) GetCContext() *C.cairo_t {
28	return v.native()
29}
30
31// Native returns a pointer to the underlying cairo_t.
32func (v *Context) Native() uintptr {
33	return uintptr(unsafe.Pointer(v.native()))
34}
35
36func marshalContext(p uintptr) (interface{}, error) {
37	c := C.g_value_get_boxed((*C.GValue)(unsafe.Pointer(p)))
38	context := (*C.cairo_t)(unsafe.Pointer(c))
39	return wrapContext(context), nil
40}
41
42func wrapContext(context *C.cairo_t) *Context {
43	return &Context{context}
44}
45
46func WrapContext(p uintptr) *Context {
47	context := (*C.cairo_t)(unsafe.Pointer(p))
48	return wrapContext(context)
49}
50
51// Closes the context. The context must not be used afterwards.
52func (v *Context) Close() {
53	v.destroy()
54}
55
56// Create is a wrapper around cairo_create().
57func Create(target *Surface) *Context {
58	c := C.cairo_create(target.native())
59	ctx := wrapContext(c)
60	runtime.SetFinalizer(ctx, (*Context).destroy)
61	return ctx
62}
63
64// reference is a wrapper around cairo_reference().
65func (v *Context) reference() {
66	v.context = C.cairo_reference(v.native())
67}
68
69// destroy is a wrapper around cairo_destroy().
70func (v *Context) destroy() {
71	if v.context != nil {
72		C.cairo_destroy(v.native())
73		v.context = nil
74	}
75}
76
77// Status is a wrapper around cairo_status().
78func (v *Context) Status() Status {
79	c := C.cairo_status(v.native())
80	return Status(c)
81}
82
83// Save is a wrapper around cairo_save().
84func (v *Context) Save() {
85	C.cairo_save(v.native())
86}
87
88// Restore is a wrapper around cairo_restore().
89func (v *Context) Restore() {
90	C.cairo_restore(v.native())
91}
92
93// GetTarget is a wrapper around cairo_get_target().
94func (v *Context) GetTarget() *Surface {
95	c := C.cairo_get_target(v.native())
96	s := wrapSurface(c)
97	s.reference()
98	runtime.SetFinalizer(s, (*Surface).destroy)
99	return s
100}
101
102// PushGroup is a wrapper around cairo_push_group().
103func (v *Context) PushGroup() {
104	C.cairo_push_group(v.native())
105}
106
107// PushGroupWithContent is a wrapper around cairo_push_group_with_content().
108func (v *Context) PushGroupWithContent(content Content) {
109	C.cairo_push_group_with_content(v.native(), C.cairo_content_t(content))
110}
111
112// TODO(jrick) PopGroup (depends on Pattern)
113// cairo_pop_group
114
115// PopGroupToSource is a wrapper around cairo_pop_group_to_source().
116func (v *Context) PopGroupToSource() {
117	C.cairo_pop_group_to_source(v.native())
118}
119
120// GetGroupTarget is a wrapper around cairo_get_group_target().
121func (v *Context) GetGroupTarget() *Surface {
122	c := C.cairo_get_group_target(v.native())
123	s := wrapSurface(c)
124	s.reference()
125	runtime.SetFinalizer(s, (*Surface).destroy)
126	return s
127}
128
129// SetSource is a wrapper around cairo_set_source().
130func (v *Context) SetSource(p *Pattern) {
131	C.cairo_set_source(v.native(), p.native())
132}
133
134// SetSourceRGB is a wrapper around cairo_set_source_rgb().
135func (v *Context) SetSourceRGB(red, green, blue float64) {
136	C.cairo_set_source_rgb(v.native(), C.double(red), C.double(green),
137		C.double(blue))
138}
139
140// SetSourceRGBA is a wrapper around cairo_set_source_rgba().
141func (v *Context) SetSourceRGBA(red, green, blue, alpha float64) {
142	C.cairo_set_source_rgba(v.native(), C.double(red), C.double(green),
143		C.double(blue), C.double(alpha))
144}
145
146// TODO(jrick) SetSource (depends on Pattern)
147// cairo_set_source
148
149// SetSourceSurface is a wrapper around cairo_set_source_surface().
150func (v *Context) SetSourceSurface(surface *Surface, x, y float64) {
151	C.cairo_set_source_surface(v.native(), surface.native(), C.double(x),
152		C.double(y))
153}
154
155// TODO(jrick) GetSource (depends on Pattern)
156// cairo_get_source
157
158// SetAntialias is a wrapper around cairo_set_antialias().
159func (v *Context) SetAntialias(antialias Antialias) {
160	C.cairo_set_antialias(v.native(), C.cairo_antialias_t(antialias))
161}
162
163// GetAntialias is a wrapper around cairo_get_antialias().
164func (v *Context) GetAntialias() Antialias {
165	c := C.cairo_get_antialias(v.native())
166	return Antialias(c)
167}
168
169// SetDash is a wrapper around cairo_set_dash().
170func (v *Context) SetDash(dashes []float64, offset float64) {
171	header := (*reflect.SliceHeader)(unsafe.Pointer(&dashes))
172	cdashes := (*C.double)(unsafe.Pointer(header.Data))
173	C.cairo_set_dash(v.native(), cdashes, C.int(header.Len),
174		C.double(offset))
175}
176
177// GetDashCount is a wrapper around cairo_get_dash_count().
178func (v *Context) GetDashCount() int {
179	c := C.cairo_get_dash_count(v.native())
180	return int(c)
181}
182
183// GetDash is a wrapper around cairo_get_dash().
184func (v *Context) GetDash() (dashes []float64, offset float64) {
185	dashCount := v.GetDashCount()
186	cdashes := (*C.double)(C.calloc(8, C.size_t(dashCount)))
187	var coffset C.double
188	C.cairo_get_dash(v.native(), cdashes, &coffset)
189	header := (*reflect.SliceHeader)((unsafe.Pointer(&dashes)))
190	header.Data = uintptr(unsafe.Pointer(cdashes))
191	header.Len = dashCount
192	header.Cap = dashCount
193	return dashes, float64(coffset)
194}
195
196// SetFillRule is a wrapper around cairo_set_fill_rule().
197func (v *Context) SetFillRule(fillRule FillRule) {
198	C.cairo_set_fill_rule(v.native(), C.cairo_fill_rule_t(fillRule))
199}
200
201// GetFillRule is a wrapper around cairo_get_fill_rule().
202func (v *Context) GetFillRule() FillRule {
203	c := C.cairo_get_fill_rule(v.native())
204	return FillRule(c)
205}
206
207// SetLineCap is a wrapper around cairo_set_line_cap().
208func (v *Context) SetLineCap(lineCap LineCap) {
209	C.cairo_set_line_cap(v.native(), C.cairo_line_cap_t(lineCap))
210}
211
212// GetLineCap is a wrapper around cairo_get_line_cap().
213func (v *Context) GetLineCap() LineCap {
214	c := C.cairo_get_line_cap(v.native())
215	return LineCap(c)
216}
217
218// SetLineJoin is a wrapper around cairo_set_line_join().
219func (v *Context) SetLineJoin(lineJoin LineJoin) {
220	C.cairo_set_line_join(v.native(), C.cairo_line_join_t(lineJoin))
221}
222
223// GetLineJoin is a wrapper around cairo_get_line_join().
224func (v *Context) GetLineJoin() LineJoin {
225	c := C.cairo_get_line_join(v.native())
226	return LineJoin(c)
227}
228
229// SetLineWidth is a wrapper around cairo_set_line_width().
230func (v *Context) SetLineWidth(width float64) {
231	C.cairo_set_line_width(v.native(), C.double(width))
232}
233
234// GetLineWidth is a wrapper cairo_get_line_width().
235func (v *Context) GetLineWidth() float64 {
236	c := C.cairo_get_line_width(v.native())
237	return float64(c)
238}
239
240// SetMiterLimit is a wrapper around cairo_set_miter_limit().
241func (v *Context) SetMiterLimit(limit float64) {
242	C.cairo_set_miter_limit(v.native(), C.double(limit))
243}
244
245// GetMiterLimit is a wrapper around cairo_get_miter_limit().
246func (v *Context) GetMiterLimit() float64 {
247	c := C.cairo_get_miter_limit(v.native())
248	return float64(c)
249}
250
251// SetOperator is a wrapper around cairo_set_operator().
252func (v *Context) SetOperator(op Operator) {
253	C.cairo_set_operator(v.native(), C.cairo_operator_t(op))
254}
255
256// GetOperator is a wrapper around cairo_get_operator().
257func (v *Context) GetOperator() Operator {
258	c := C.cairo_get_operator(v.native())
259	return Operator(c)
260}
261
262// SetTolerance is a wrapper around cairo_set_tolerance().
263func (v *Context) SetTolerance(tolerance float64) {
264	C.cairo_set_tolerance(v.native(), C.double(tolerance))
265}
266
267// GetTolerance is a wrapper around cairo_get_tolerance().
268func (v *Context) GetTolerance() float64 {
269	c := C.cairo_get_tolerance(v.native())
270	return float64(c)
271}
272
273// Clip is a wrapper around cairo_clip().
274func (v *Context) Clip() {
275	C.cairo_clip(v.native())
276}
277
278// ClipPreserve is a wrapper around cairo_clip_preserve().
279func (v *Context) ClipPreserve() {
280	C.cairo_clip_preserve(v.native())
281}
282
283// ClipExtents is a wrapper around cairo_clip_extents().
284func (v *Context) ClipExtents() (x1, y1, x2, y2 float64) {
285	var cx1, cy1, cx2, cy2 C.double
286	C.cairo_clip_extents(v.native(), &cx1, &cy1, &cx2, &cy2)
287	return float64(cx1), float64(cy1), float64(cx2), float64(cy2)
288}
289
290// InClip is a wrapper around cairo_in_clip().
291func (v *Context) InClip(x, y float64) bool {
292	c := C.cairo_in_clip(v.native(), C.double(x), C.double(y))
293	return gobool(c)
294}
295
296// ResetClip is a wrapper around cairo_reset_clip().
297func (v *Context) ResetClip() {
298	C.cairo_reset_clip(v.native())
299}
300
301// Rectangle is a wrapper around cairo_rectangle().
302func (v *Context) Rectangle(x, y, w, h float64) {
303	C.cairo_rectangle(v.native(), C.double(x), C.double(y), C.double(w), C.double(h))
304}
305
306// Arc is a wrapper around cairo_arc().
307func (v *Context) Arc(xc, yc, radius, angle1, angle2 float64) {
308	C.cairo_arc(v.native(), C.double(xc), C.double(yc), C.double(radius), C.double(angle1), C.double(angle2))
309}
310
311// ArcNegative is a wrapper around cairo_arc_negative().
312func (v *Context) ArcNegative(xc, yc, radius, angle1, angle2 float64) {
313	C.cairo_arc_negative(v.native(), C.double(xc), C.double(yc), C.double(radius), C.double(angle1), C.double(angle2))
314}
315
316// LineTo is a wrapper around cairo_line_to().
317func (v *Context) LineTo(x, y float64) {
318	C.cairo_line_to(v.native(), C.double(x), C.double(y))
319}
320
321// CurveTo is a wrapper around cairo_curve_to().
322func (v *Context) CurveTo(x1, y1, x2, y2, x3, y3 float64) {
323	C.cairo_curve_to(v.native(), C.double(x1), C.double(y1), C.double(x2), C.double(y2), C.double(x3), C.double(y3))
324}
325
326// MoveTo is a wrapper around cairo_move_to().
327func (v *Context) MoveTo(x, y float64) {
328	C.cairo_move_to(v.native(), C.double(x), C.double(y))
329}
330
331// TODO(jrick) CopyClipRectangleList (depends on RectangleList)
332// cairo_copy_clip_rectangle_list
333
334// Fill is a wrapper around cairo_fill().
335func (v *Context) Fill() {
336	C.cairo_fill(v.native())
337}
338
339// ClosePath is a wrapper around cairo_close_path().
340func (v *Context) ClosePath() {
341	C.cairo_close_path(v.native())
342}
343
344// NewPath is a wrapper around cairo_new_path().
345func (v *Context) NewPath() {
346	C.cairo_new_path(v.native())
347}
348
349// GetCurrentPoint is a wrapper around cairo_get_current_point().
350func (v *Context) GetCurrentPoint() (x, y float64) {
351	C.cairo_get_current_point(v.native(), (*C.double)(&x), (*C.double)(&y))
352	return
353}
354
355// FillPreserve is a wrapper around cairo_fill_preserve().
356func (v *Context) FillPreserve() {
357	C.cairo_fill_preserve(v.native())
358}
359
360// FillExtents is a wrapper around cairo_fill_extents().
361func (v *Context) FillExtents() (x1, y1, x2, y2 float64) {
362	var cx1, cy1, cx2, cy2 C.double
363	C.cairo_fill_extents(v.native(), &cx1, &cy1, &cx2, &cy2)
364	return float64(cx1), float64(cy1), float64(cx2), float64(cy2)
365}
366
367// InFill is a wrapper around cairo_in_fill().
368func (v *Context) InFill(x, y float64) bool {
369	c := C.cairo_in_fill(v.native(), C.double(x), C.double(y))
370	return gobool(c)
371}
372
373// TODO(jrick) Mask (depends on Pattern)
374// cairo_mask_surface
375
376// MaskSurface is a wrapper around cairo_mask_surface().
377func (v *Context) MaskSurface(surface *Surface, surfaceX, surfaceY float64) {
378	C.cairo_mask_surface(v.native(), surface.native(), C.double(surfaceX),
379		C.double(surfaceY))
380}
381
382// Paint is a wrapper around cairo_paint().
383func (v *Context) Paint() {
384	C.cairo_paint(v.native())
385}
386
387// PaintWithAlpha is a wrapper around cairo_paint_with_alpha().
388func (v *Context) PaintWithAlpha(alpha float64) {
389	C.cairo_paint_with_alpha(v.native(), C.double(alpha))
390}
391
392// Stroke is a wrapper around cairo_stroke().
393func (v *Context) Stroke() {
394	C.cairo_stroke(v.native())
395}
396
397// StrokePreserve is a wrapper around cairo_stroke_preserve().
398func (v *Context) StrokePreserve() {
399	C.cairo_stroke_preserve(v.native())
400}
401
402// StrokeExtents is a wrapper around cairo_stroke_extents().
403func (v *Context) StrokeExtents() (x1, y1, x2, y2 float64) {
404	var cx1, cy1, cx2, cy2 C.double
405	C.cairo_stroke_extents(v.native(), &cx1, &cy1, &cx2, &cy2)
406	return float64(cx1), float64(cy1), float64(cx2), float64(cy2)
407}
408
409// InStroke is a wrapper around cairo_in_stroke().
410func (v *Context) InStroke(x, y float64) bool {
411	c := C.cairo_in_stroke(v.native(), C.double(x), C.double(y))
412	return gobool(c)
413}
414
415// CopyPage is a wrapper around cairo_copy_page().
416func (v *Context) CopyPage() {
417	C.cairo_copy_page(v.native())
418}
419
420// ShowPage is a wrapper around cairo_show_page().
421func (v *Context) ShowPage() {
422	C.cairo_show_page(v.native())
423}
424