1package cairo
2
3// #include <stdlib.h>
4// #include <cairo.h>
5// #include <cairo-gobject.h>
6// #include <cairo-pdf.h>
7import "C"
8
9import (
10	"runtime"
11	"unsafe"
12)
13
14/*
15 * cairo_surface_t
16 */
17
18// Surface is a representation of Cairo's cairo_surface_t.
19type Surface struct {
20	surface *C.cairo_surface_t
21}
22
23func NewSurfaceFromPNG(fileName string) (*Surface, error) {
24
25	cstr := C.CString(fileName)
26	defer C.free(unsafe.Pointer(cstr))
27
28	surfaceNative := C.cairo_image_surface_create_from_png(cstr)
29
30	status := Status(C.cairo_surface_status(surfaceNative))
31	if status != STATUS_SUCCESS {
32		return nil, ErrorStatus(status)
33	}
34
35	return &Surface{surfaceNative}, nil
36}
37
38// CreateImageSurfaceForData is a wrapper around cairo_image_surface_create_for_data().
39func CreateImageSurfaceForData(data []byte, format Format, width, height, stride int) (*Surface, error) {
40	surfaceNative := C.cairo_image_surface_create_for_data((*C.uchar)(unsafe.Pointer(&data[0])),
41		C.cairo_format_t(format), C.int(width), C.int(height), C.int(stride))
42
43	status := Status(C.cairo_surface_status(surfaceNative))
44	if status != STATUS_SUCCESS {
45		return nil, ErrorStatus(status)
46	}
47
48	s := wrapSurface(surfaceNative)
49
50	runtime.SetFinalizer(s, (*Surface).destroy)
51
52	return s, nil
53}
54
55// CreateImageSurface is a wrapper around cairo_image_surface_create().
56func CreateImageSurface(format Format, width, height int) *Surface {
57	c := C.cairo_image_surface_create(C.cairo_format_t(format),
58		C.int(width), C.int(height))
59	s := wrapSurface(c)
60	runtime.SetFinalizer(s, (*Surface).destroy)
61	return s
62}
63
64/// Create a new PDF surface.
65func CreatePDFSurface(fileName string, width float64, height float64) (*Surface, error) {
66	cstr := C.CString(fileName)
67	defer C.free(unsafe.Pointer(cstr))
68
69	surfaceNative := C.cairo_pdf_surface_create(cstr, C.double(width), C.double(height))
70
71	status := Status(C.cairo_surface_status(surfaceNative))
72	if status != STATUS_SUCCESS {
73		return nil, ErrorStatus(status)
74	}
75
76	s := wrapSurface(surfaceNative)
77
78	runtime.SetFinalizer(s, (*Surface).destroy)
79
80	return s, nil
81}
82
83// native returns a pointer to the underlying cairo_surface_t.
84func (v *Surface) native() *C.cairo_surface_t {
85	if v == nil {
86		return nil
87	}
88	return v.surface
89}
90
91// Native returns a pointer to the underlying cairo_surface_t.
92func (v *Surface) Native() uintptr {
93	return uintptr(unsafe.Pointer(v.native()))
94}
95
96func (v *Surface) GetCSurface() *C.cairo_surface_t {
97	return v.native()
98}
99
100func marshalSurface(p uintptr) (interface{}, error) {
101	c := C.g_value_get_boxed((*C.GValue)(unsafe.Pointer(p)))
102	return WrapSurface(uintptr(c)), nil
103}
104
105func wrapSurface(surface *C.cairo_surface_t) *Surface {
106	return &Surface{surface}
107}
108
109// NewSurface creates a gotk3 cairo Surface from a pointer to a
110// C cairo_surface_t.  This is primarily designed for use with other
111// gotk3 packages and should be avoided by applications.
112func NewSurface(s uintptr, needsRef bool) *Surface {
113	surface := WrapSurface(s)
114	if needsRef {
115		surface.reference()
116	}
117	runtime.SetFinalizer(surface, (*Surface).destroy)
118	return surface
119}
120
121func WrapSurface(s uintptr) *Surface {
122	ptr := (*C.cairo_surface_t)(unsafe.Pointer(s))
123	return wrapSurface(ptr)
124}
125
126// Closes the surface. The surface must not be used afterwards.
127func (v *Surface) Close() {
128	v.destroy()
129}
130
131// CreateSimilar is a wrapper around cairo_surface_create_similar().
132func (v *Surface) CreateSimilar(content Content, width, height int) *Surface {
133	c := C.cairo_surface_create_similar(v.native(),
134		C.cairo_content_t(content), C.int(width), C.int(height))
135	s := wrapSurface(c)
136	runtime.SetFinalizer(s, (*Surface).destroy)
137	return s
138}
139
140// TODO cairo_surface_create_similar_image (since 1.12)
141
142// CreateForRectangle is a wrapper around cairo_surface_create_for_rectangle().
143func (v *Surface) CreateForRectangle(x, y, width, height float64) *Surface {
144	c := C.cairo_surface_create_for_rectangle(v.native(), C.double(x),
145		C.double(y), C.double(width), C.double(height))
146	s := wrapSurface(c)
147	runtime.SetFinalizer(s, (*Surface).destroy)
148	return s
149}
150
151// reference is a wrapper around cairo_surface_reference().
152func (v *Surface) reference() {
153	v.surface = C.cairo_surface_reference(v.native())
154}
155
156// destroy is a wrapper around cairo_surface_destroy().
157func (v *Surface) destroy() {
158	if v.surface != nil {
159		C.cairo_surface_destroy(v.native())
160		v.surface = nil
161	}
162}
163
164// Status is a wrapper around cairo_surface_status().
165func (v *Surface) Status() Status {
166	c := C.cairo_surface_status(v.native())
167	return Status(c)
168}
169
170// Flush is a wrapper around cairo_surface_flush().
171func (v *Surface) Flush() {
172	C.cairo_surface_flush(v.native())
173}
174
175// TODO(jrick) GetDevice (requires Device bindings)
176// cairo_surface_get_device
177
178// TODO(jrick) GetFontOptions (require FontOptions bindings)
179// cairo_surface_get_font_options
180
181// TODO(jrick) GetContent (requires Content bindings)
182// cairo_surface_get_content
183
184// MarkDirty is a wrapper around cairo_surface_mark_dirty().
185func (v *Surface) MarkDirty() {
186	C.cairo_surface_mark_dirty(v.native())
187}
188
189// MarkDirtyRectangle is a wrapper around cairo_surface_mark_dirty_rectangle().
190func (v *Surface) MarkDirtyRectangle(x, y, width, height int) {
191	C.cairo_surface_mark_dirty_rectangle(v.native(), C.int(x), C.int(y),
192		C.int(width), C.int(height))
193}
194
195// SetDeviceOffset is a wrapper around cairo_surface_set_device_offset().
196func (v *Surface) SetDeviceOffset(x, y float64) {
197	C.cairo_surface_set_device_offset(v.native(), C.double(x), C.double(y))
198}
199
200// GetDeviceOffset is a wrapper around cairo_surface_get_device_offset().
201func (v *Surface) GetDeviceOffset() (x, y float64) {
202	var xOffset, yOffset C.double
203	C.cairo_surface_get_device_offset(v.native(), &xOffset, &yOffset)
204	return float64(xOffset), float64(yOffset)
205}
206
207// SetFallbackResolution is a wrapper around
208// cairo_surface_set_fallback_resolution().
209func (v *Surface) SetFallbackResolution(xPPI, yPPI float64) {
210	C.cairo_surface_set_fallback_resolution(v.native(), C.double(xPPI),
211		C.double(yPPI))
212}
213
214// GetFallbackResolution is a wrapper around cairo_surface_get_fallback_resolution().
215func (v *Surface) GetFallbackResolution() (xPPI, yPPI float64) {
216	var x, y C.double
217	C.cairo_surface_get_fallback_resolution(v.native(), &x, &y)
218	return float64(x), float64(y)
219}
220
221// GetType is a wrapper around cairo_surface_get_type().
222func (v *Surface) GetType() SurfaceType {
223	c := C.cairo_surface_get_type(v.native())
224	return SurfaceType(c)
225}
226
227// TODO(jrick) SetUserData (depends on UserDataKey and DestroyFunc)
228// cairo_surface_set_user_data
229
230// TODO(jrick) GetUserData (depends on UserDataKey)
231// cairo_surface_get_user_data
232
233// CopyPage is a wrapper around cairo_surface_copy_page().
234func (v *Surface) CopyPage() {
235	C.cairo_surface_copy_page(v.native())
236}
237
238// ShowPage is a wrapper around cairo_surface_show_page().
239func (v *Surface) ShowPage() {
240	C.cairo_surface_show_page(v.native())
241}
242
243// HasShowTextGlyphs is a wrapper around cairo_surface_has_show_text_glyphs().
244func (v *Surface) HasShowTextGlyphs() bool {
245	c := C.cairo_surface_has_show_text_glyphs(v.native())
246	return gobool(c)
247}
248
249// TODO(jrick) SetMimeData (depends on DestroyFunc)
250// cairo_surface_set_mime_data
251
252// GetMimeData is a wrapper around cairo_surface_get_mime_data().  The
253// returned mimetype data is returned as a Go byte slice.
254func (v *Surface) GetMimeData(mimeType MimeType) []byte {
255	cstr := C.CString(string(mimeType))
256	defer C.free(unsafe.Pointer(cstr))
257	var data *C.uchar
258	var length C.ulong
259	C.cairo_surface_get_mime_data(v.native(), cstr, &data, &length)
260	return C.GoBytes(unsafe.Pointer(data), C.int(length))
261}
262
263// WriteToPNG is a wrapper around cairo_surface_write_png(). It writes the Cairo
264// surface to the given file in PNG format.
265func (v *Surface) WriteToPNG(fileName string) error {
266	cstr := C.CString(fileName)
267	defer C.free(unsafe.Pointer(cstr))
268
269	status := Status(C.cairo_surface_write_to_png(v.surface, cstr))
270
271	if status != STATUS_SUCCESS {
272		return ErrorStatus(status)
273	}
274
275	return nil
276}
277
278// TODO(jrick) SupportsMimeType (since 1.12)
279// cairo_surface_supports_mime_type
280
281// TODO(jrick) MapToImage (since 1.12)
282// cairo_surface_map_to_image
283
284// TODO(jrick) UnmapImage (since 1.12)
285// cairo_surface_unmap_image
286
287// GetHeight is a wrapper around cairo_image_surface_get_height().
288func (v *Surface) GetHeight() int {
289	return int(C.cairo_image_surface_get_height(v.surface))
290}
291
292// GetWidth is a wrapper around cairo_image_surface_get_width().
293func (v *Surface) GetWidth() int {
294	return int(C.cairo_image_surface_get_width(v.surface))
295}
296
297// GetData is a wrapper around cairo_image_surface_get_data().
298func (v *Surface) GetData() unsafe.Pointer {
299	return unsafe.Pointer(C.cairo_image_surface_get_data(v.surface))
300}
301