1 /* Cairo - a vector graphics library with display and print output
2  *
3  * Copyright © 2009 Chris Wilson
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it either under the terms of the GNU Lesser General Public
7  * License version 2.1 as published by the Free Software Foundation
8  * (the "LGPL") or, at your option, under the terms of the Mozilla
9  * Public License Version 1.1 (the "MPL"). If you do not alter this
10  * notice, a recipient may use your version of this file under either
11  * the MPL or the LGPL.
12  *
13  * You should have received a copy of the LGPL along with this library
14  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
15  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
16  * You should have received a copy of the MPL along with this library
17  * in the file COPYING-MPL-1.1
18  *
19  * The contents of this file are subject to the Mozilla Public License
20  * Version 1.1 (the "License"); you may not use this file except in
21  * compliance with the License. You may obtain a copy of the License at
22  * http://www.mozilla.org/MPL/
23  *
24  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
25  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
26  * the specific language governing rights and limitations.
27  *
28  * The Original Code is the cairo graphics library.
29  *
30  * The Initial Developer of the Original Code is Chris Wilson.
31  */
32 
33 #include "cairo-boilerplate-private.h"
34 
35 #include <cairo-cogl.h>
36 #include <cogl/cogl2-experimental.h>
37 
38 typedef struct _cogl_closure {
39     cairo_device_t *device;
40     cairo_surface_t *surface;
41 } cogl_closure_t;
42 
43 static const cairo_user_data_key_t cogl_closure_key;
44 
45 static void
_cairo_boilerplate_cogl_cleanup(void * abstract_closure)46 _cairo_boilerplate_cogl_cleanup (void *abstract_closure)
47 {
48     cogl_closure_t *closure = abstract_closure;
49 
50     cairo_device_finish (closure->device);
51     cairo_device_destroy (closure->device);
52 
53     free (closure);
54 }
55 
56 static cairo_surface_t *
_cairo_boilerplate_cogl_create_offscreen_color_surface(const char * name,cairo_content_t content,double width,double height,double max_width,double max_height,cairo_boilerplate_mode_t mode,void ** abstract_closure)57 _cairo_boilerplate_cogl_create_offscreen_color_surface (const char		*name,
58 							cairo_content_t		 content,
59 							double			 width,
60 							double			 height,
61 							double			 max_width,
62 							double			 max_height,
63 							cairo_boilerplate_mode_t mode,
64 							void		       **abstract_closure)
65 {
66     CoglContext *context;
67     cairo_device_t *device;
68     cogl_closure_t *closure;
69     cairo_status_t status;
70 
71     if (width < 1)
72         width = 1;
73     if (height < 1)
74         height = 1;
75 
76     context = cogl_context_new (NULL, NULL);
77 
78     device = cairo_cogl_device_create (context);
79 
80     /* The device will take a reference on the context */
81     cogl_object_unref (context);
82 
83     closure = malloc (sizeof (cogl_closure_t));
84     *abstract_closure = closure;
85     closure->device = device;
86     closure->surface = cairo_cogl_offscreen_surface_create (device,
87                                                             content,
88                                                             width,
89                                                             height);
90 
91     status = cairo_surface_set_user_data (closure->surface,
92 					  &cogl_closure_key, closure, NULL);
93     if (status == CAIRO_STATUS_SUCCESS)
94 	return closure->surface;
95 
96     _cairo_boilerplate_cogl_cleanup (closure);
97     return cairo_boilerplate_surface_create_in_error (status);
98 }
99 
100 static cairo_surface_t *
_cairo_boilerplate_cogl_create_onscreen_color_surface(const char * name,cairo_content_t content,double width,double height,double max_width,double max_height,cairo_boilerplate_mode_t mode,void ** abstract_closure)101 _cairo_boilerplate_cogl_create_onscreen_color_surface (const char	       *name,
102 						       cairo_content_t		content,
103 						       double			width,
104 						       double			height,
105 						       double			max_width,
106 						       double			max_height,
107 						       cairo_boilerplate_mode_t mode,
108 						       void		      **abstract_closure)
109 {
110     CoglContext *context;
111     cairo_device_t *device;
112     cogl_closure_t *closure;
113     cairo_status_t status;
114 
115     if (width < 1)
116         width = 1;
117     if (height < 1)
118         height = 1;
119 
120     if (content & CAIRO_CONTENT_ALPHA) {
121 	/* A hackish way to ensure that we get a framebuffer with
122 	 * an alpha component */
123 	CoglSwapChain *swap_chain;
124 	CoglOnscreenTemplate *onscreen_template;
125 	CoglRenderer *renderer;
126 	CoglDisplay *display;
127 
128         swap_chain = cogl_swap_chain_new ();
129         cogl_swap_chain_set_has_alpha (swap_chain, TRUE);
130 
131         onscreen_template = cogl_onscreen_template_new (swap_chain);
132         renderer = cogl_renderer_new ();
133         display = cogl_display_new (renderer, onscreen_template);
134 
135         /* References will be taken on the swap chain, renderer, and
136          * onscreen template by the constructors */
137         cogl_object_unref (swap_chain);
138         cogl_object_unref (renderer);
139         cogl_object_unref (onscreen_template);
140 
141         context = cogl_context_new (display, NULL);
142 
143         /* The context will take a reference on the display */
144         cogl_object_unref (display);
145     } else {
146         context = cogl_context_new (NULL, NULL);
147     }
148 
149     device = cairo_cogl_device_create (context);
150 
151     /* The device will take a reference on the context */
152     cogl_object_unref (context);
153 
154     closure = malloc (sizeof (cogl_closure_t));
155     *abstract_closure = closure;
156     closure->device = device;
157     closure->surface = cairo_cogl_onscreen_surface_create (device,
158                                                            content,
159                                                            width,
160                                                            height);
161 
162     status = cairo_surface_set_user_data (closure->surface,
163 					  &cogl_closure_key, closure, NULL);
164     if (status == CAIRO_STATUS_SUCCESS)
165 	return closure->surface;
166 
167     _cairo_boilerplate_cogl_cleanup (closure);
168     return cairo_boilerplate_surface_create_in_error (status);
169 }
170 
171 static cairo_status_t
_cairo_boilerplate_cogl_finish(cairo_surface_t * surface)172 _cairo_boilerplate_cogl_finish (cairo_surface_t *surface)
173 {
174     return cairo_cogl_surface_end_frame (surface);
175 }
176 
177 static void
_cairo_boilerplate_cogl_synchronize(void * abstract_closure)178 _cairo_boilerplate_cogl_synchronize (void *abstract_closure)
179 {
180     cogl_closure_t *closure = abstract_closure;
181     cairo_cogl_surface_synchronize (closure->surface);
182 }
183 
184 static const cairo_boilerplate_target_t targets[] = {
185     {
186 	"cogl-offscreen-color", "cogl", NULL, NULL,
187 	CAIRO_SURFACE_TYPE_COGL, CAIRO_CONTENT_COLOR_ALPHA, 1,
188 	"cairo_cogl_device_create",
189 	_cairo_boilerplate_cogl_create_offscreen_color_surface,
190 	cairo_surface_create_similar,
191 	NULL,
192         _cairo_boilerplate_cogl_finish,
193 	_cairo_boilerplate_get_image_surface,
194 	cairo_surface_write_to_png,
195 	_cairo_boilerplate_cogl_cleanup,
196 	_cairo_boilerplate_cogl_synchronize,
197         NULL,
198 	TRUE, FALSE, FALSE
199     },
200     {
201 	"cogl-onscreen-color", "cogl", NULL, NULL,
202 	CAIRO_SURFACE_TYPE_COGL, CAIRO_CONTENT_COLOR_ALPHA, 1,
203 	"cairo_cogl_device_create",
204 	_cairo_boilerplate_cogl_create_onscreen_color_surface,
205 	cairo_surface_create_similar,
206 	NULL,
207 	_cairo_boilerplate_cogl_finish,
208 	_cairo_boilerplate_get_image_surface,
209 	cairo_surface_write_to_png,
210 	_cairo_boilerplate_cogl_cleanup,
211 	_cairo_boilerplate_cogl_synchronize,
212         NULL,
213 	TRUE, FALSE, FALSE
214     }
215 };
216 CAIRO_BOILERPLATE (cogl, targets)
217