Tizen 2.0 Release
[framework/graphics/cairo.git] / src / cairo-cogl-context.c
1 /* cairo - a vector graphics library with display and print output
2  *
3  * Copyright © 2011 Intel Corporation.
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.og/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  * Contributor(s):
29  *      Robert Bragg <robert@linux.intel.com>
30  */
31
32 /* so long as we can verify that the ctm doesn't change multiple times
33  * during the construction of a path we can build a shadow
34  * #cairo_path_fixed_t in user coordinates that we can use to create a
35  * hash value for caching tessellations of that path.
36  *
37  * We need to hook into all the points where the ctm can be changed
38  * so we can bump a cr->path_ctm_age counter.
39  *
40  * We need to hook into all the points where the path can be modified
41  * so we can catch the start of a path and reset the cr->path_ctm_age
42  * counter at that point.
43  *
44  * When a draw operation is hit we can then check that the
45  * path_ctm_age == 0 and if so we create a hash of the path.
46  *
47  * We use this hash to lookup a #cairo_cogl_path_meta_t struct which
48  * may contain tessellated triangles for the path or may just contain
49  * a count of how many times the path has been re-seen (we only cache
50  * tessellated triangles if there is evidence that the path is being
51  * used multiple times because there is a cost involved in allocating
52  * a separate buffer for the triangles).
53  */
54
55 #include "cairoint.h"
56
57 #include "cairo-cogl-context-private.h"
58 #include "cairo-freed-pool-private.h"
59 #include "cairo-arc-private.h"
60 #include "cairo-path-fixed-private.h"
61
62 #include <glib.h>
63
64 static freed_pool_t context_pool;
65
66 void
67 _cairo_cogl_context_reset_static_data (void)
68 {
69     _freed_pool_reset (&context_pool);
70 }
71
72 static cairo_status_t
73 _cairo_cogl_context_rectangle_real (cairo_cogl_context_t *cr,
74                                     double x, double y,
75                                     double width, double height)
76 {
77     cairo_status_t status;
78     status = cr->dev->backend_parent.rectangle (cr, x, y, width, height);
79     if (unlikely (status))
80         return status;
81
82     return _cairo_cogl_path_fixed_rectangle (&cr->user_path,
83                                              _cairo_fixed_from_double (x),
84                                              _cairo_fixed_from_double (y),
85                                              _cairo_fixed_from_double (width),
86                                              _cairo_fixed_from_double (height));
87 }
88
89 /* The idea here is that we have a simplified way of tracking rectangle paths
90  * because rectangles are perhaps the most common shape drawn with cairo.
91  *
92  * Basically we have a speculative store for a rectangle path that doesn't
93  * need to use the #cairo_path_fixed_t api to describe a rectangle in terms of
94  * (move_to,rel_line_to,rel_line_to,_rel_line_to,close) because if you profile
95  * heavy rectangle drawing with Cairo that process can be overly expensive.
96  *
97  * If the user asks to add more than just a rectangle to their current path
98  * then we "flush" any speculative rectangle stored into the current path
99  * before continuing to append their operations.
100  *
101  * In addition to the speculative store cairo-cogl also has a fast-path
102  * fill_rectangle drawing operation that further aims to minimize the cost
103  * of drawing rectangles.
104  */
105 static cairo_status_t
106 _flush_cr_rectangle (cairo_cogl_context_t *cr)
107 {
108     if (!cr->path_is_rectangle)
109         return CAIRO_STATUS_SUCCESS;
110
111     cr->path_is_rectangle = FALSE;
112     return _cairo_cogl_context_rectangle_real (cr, cr->x, cr->y, cr->width, cr->height);
113 }
114
115 static cairo_status_t
116 _cairo_cogl_context_restore (void *abstract_cr)
117 {
118     cairo_cogl_context_t *cr = abstract_cr;
119
120     if (cr->path_is_rectangle) {
121         cairo_status_t status = _flush_cr_rectangle (cr);
122         if (unlikely (status))
123             return status;
124     }
125
126     cr->path_ctm_age++;
127     return cr->dev->backend_parent.restore (abstract_cr);
128 }
129
130 static cairo_status_t
131 _cairo_cogl_context_translate (void *abstract_cr, double tx, double ty)
132 {
133     cairo_cogl_context_t *cr = abstract_cr;
134
135     if (cr->path_is_rectangle) {
136         cairo_status_t status = _flush_cr_rectangle (cr);
137         if (unlikely (status))
138             return status;
139     }
140
141     cr->path_ctm_age++;
142     return cr->dev->backend_parent.translate (abstract_cr, tx, ty);
143 }
144
145 static cairo_status_t
146 _cairo_cogl_context_scale (void *abstract_cr, double sx, double sy)
147 {
148     cairo_cogl_context_t *cr = abstract_cr;
149
150     if (cr->path_is_rectangle) {
151         cairo_status_t status = _flush_cr_rectangle (cr);
152         if (unlikely (status))
153             return status;
154     }
155
156     cr->path_ctm_age++;
157     return cr->dev->backend_parent.scale (abstract_cr, sx, sy);
158 }
159
160 static cairo_status_t
161 _cairo_cogl_context_rotate (void *abstract_cr, double theta)
162 {
163     cairo_cogl_context_t *cr = abstract_cr;
164
165     if (cr->path_is_rectangle) {
166         cairo_status_t status = _flush_cr_rectangle (cr);
167         if (unlikely (status))
168             return status;
169     }
170
171     cr->path_ctm_age++;
172     return cr->dev->backend_parent.rotate (abstract_cr, theta);
173 }
174
175 static cairo_status_t
176 _cairo_cogl_context_transform (void *abstract_cr, const cairo_matrix_t *matrix)
177 {
178     cairo_cogl_context_t *cr = abstract_cr;
179
180     if (cr->path_is_rectangle) {
181         cairo_status_t status = _flush_cr_rectangle (cr);
182         if (unlikely (status))
183             return status;
184     }
185
186     cr->path_ctm_age++;
187     return cr->dev->backend_parent.transform (abstract_cr, matrix);
188 }
189
190 static cairo_status_t
191 _cairo_cogl_context_set_matrix (void *abstract_cr, const cairo_matrix_t *matrix)
192 {
193     cairo_cogl_context_t *cr = abstract_cr;
194
195     if (cr->path_is_rectangle) {
196         cairo_status_t status = _flush_cr_rectangle (cr);
197         if (unlikely (status))
198             return status;
199     }
200
201     cr->path_ctm_age++;
202     return cr->dev->backend_parent.set_matrix (abstract_cr, matrix);
203 }
204
205 static cairo_status_t
206 _cairo_cogl_context_set_identity_matrix (void *abstract_cr)
207 {
208     cairo_cogl_context_t *cr = abstract_cr;
209
210     if (cr->path_is_rectangle) {
211         cairo_status_t status = _flush_cr_rectangle (cr);
212         if (unlikely (status))
213             return status;
214     }
215
216     cr->path_ctm_age++;
217     return cr->dev->backend_parent.set_identity_matrix (abstract_cr);
218 }
219
220 static cairo_status_t
221 _cairo_cogl_context_new_path (void *abstract_cr)
222 {
223     cairo_cogl_context_t *cr = abstract_cr;
224     cairo_status_t status;
225
226     if (cr->path_is_rectangle) {
227         status = _flush_cr_rectangle (cr);
228         if (unlikely (status))
229             return status;
230     }
231
232     status = cr->dev->backend_parent.new_path (abstract_cr);
233     if (unlikely (status))
234         return status;
235
236     _cairo_path_fixed_fini (&cr->user_path);
237     _cairo_path_fixed_init (&cr->user_path);
238     cr->path_is_rectangle = FALSE;
239
240     return CAIRO_STATUS_SUCCESS;
241 }
242
243 static cairo_status_t
244 _cairo_cogl_context_new_sub_path (void *abstract_cr)
245 {
246     cairo_cogl_context_t *cr = abstract_cr;
247     cairo_status_t status;
248
249     if (cr->path_is_rectangle) {
250         status = _flush_cr_rectangle (cr);
251         if (unlikely (status))
252             return status;
253     }
254
255     status = cr->dev->backend_parent.new_sub_path (abstract_cr);
256     if (unlikely (status))
257         return status;
258
259     _cairo_path_fixed_new_sub_path (&cr->user_path);
260
261     return CAIRO_STATUS_SUCCESS;
262 }
263
264 static cairo_status_t
265 _cairo_cogl_context_move_to (void *abstract_cr, double x, double y)
266 {
267     cairo_cogl_context_t *cr = abstract_cr;
268     cairo_status_t status;
269     cairo_fixed_t x_fixed, y_fixed;
270
271     if (cr->path_is_rectangle) {
272         status = _flush_cr_rectangle (cr);
273         if (unlikely (status))
274             return status;
275     }
276
277     status = cr->dev->backend_parent.move_to (abstract_cr, x, y);
278     if (unlikely (status))
279         return status;
280
281     x_fixed = _cairo_fixed_from_double (x);
282     y_fixed = _cairo_fixed_from_double (y);
283
284     return _cairo_path_fixed_move_to (&cr->user_path, x_fixed, y_fixed);
285 }
286
287 static cairo_status_t
288 _cairo_cogl_context_line_to (void *abstract_cr, double x, double y)
289 {
290     cairo_cogl_context_t *cr = abstract_cr;
291     cairo_status_t status;
292     cairo_fixed_t x_fixed, y_fixed;
293
294     if (cr->path_is_rectangle) {
295         status = _flush_cr_rectangle (cr);
296         if (unlikely (status))
297             return status;
298     }
299
300     status = cr->dev->backend_parent.line_to (abstract_cr, x, y);
301     if (unlikely (status))
302         return status;
303
304     x_fixed = _cairo_fixed_from_double (x);
305     y_fixed = _cairo_fixed_from_double (y);
306
307     if (cr->user_path.buf.base.num_ops == 0)
308         cr->path_ctm_age = 0;
309
310     return _cairo_path_fixed_line_to (&cr->user_path, x_fixed, y_fixed);
311 }
312
313 static cairo_status_t
314 _cairo_cogl_context_curve_to (void *abstract_cr,
315                                double x1, double y1,
316                                double x2, double y2,
317                                double x3, double y3)
318 {
319     cairo_cogl_context_t *cr = abstract_cr;
320     cairo_status_t status;
321     cairo_fixed_t x1_fixed, y1_fixed;
322     cairo_fixed_t x2_fixed, y2_fixed;
323     cairo_fixed_t x3_fixed, y3_fixed;
324
325     if (cr->path_is_rectangle) {
326         status = _flush_cr_rectangle (cr);
327         if (unlikely (status))
328             return status;
329     }
330
331     status = cr->dev->backend_parent.curve_to (abstract_cr, x1, y1, x2, y2, x3, y3);
332     if (unlikely (status))
333         return status;
334
335     x1_fixed = _cairo_fixed_from_double (x1);
336     y1_fixed = _cairo_fixed_from_double (y1);
337
338     x2_fixed = _cairo_fixed_from_double (x2);
339     y2_fixed = _cairo_fixed_from_double (y2);
340
341     x3_fixed = _cairo_fixed_from_double (x3);
342     y3_fixed = _cairo_fixed_from_double (y3);
343
344     if (cr->user_path.buf.base.num_ops == 0)
345         cr->path_ctm_age = 0;
346
347     return _cairo_path_fixed_curve_to (&cr->user_path,
348                                        x1_fixed, y1_fixed,
349                                        x2_fixed, y2_fixed,
350                                        x3_fixed, y3_fixed);
351 }
352
353 static cairo_status_t
354 _cairo_cogl_context_arc (void *abstract_cr,
355                           double xc, double yc, double radius,
356                           double angle1, double angle2,
357                           cairo_bool_t forward)
358 {
359     cairo_cogl_context_t *cr = abstract_cr;
360     cairo_status_t status;
361
362     if (cr->path_is_rectangle) {
363         status = _flush_cr_rectangle (cr);
364         if (unlikely (status))
365             return status;
366     }
367
368     status = cr->dev->backend_parent.arc (abstract_cr, xc, yc, radius, angle1, angle2, forward);
369     if (unlikely (status))
370         return status;
371
372     if (cr->user_path.buf.base.num_ops == 0)
373         cr->path_ctm_age = 0;
374
375     /* Do nothing, successfully, if radius is <= 0 */
376     if (radius <= 0.0) {
377         cairo_fixed_t x_fixed, y_fixed;
378
379         x_fixed = _cairo_fixed_from_double (xc);
380         y_fixed = _cairo_fixed_from_double (yc);
381         status = _cairo_path_fixed_line_to (&cr->user_path, x_fixed, y_fixed);
382         if (unlikely (status))
383             return status;
384
385         status = _cairo_path_fixed_line_to (&cr->user_path, x_fixed, y_fixed);
386         if (unlikely (status))
387             return status;
388
389         return CAIRO_STATUS_SUCCESS;
390     }
391
392     status = _cairo_cogl_context_line_to (cr,
393                                           xc + radius * cos (angle1),
394                                           yc + radius * sin (angle1));
395
396     if (unlikely (status))
397         return status;
398
399     if (forward)
400         _cairo_arc_path (&cr->base.base, xc, yc, radius, angle1, angle2);
401     else
402         _cairo_arc_path_negative (&cr->base.base, xc, yc, radius, angle1, angle2);
403
404     return CAIRO_STATUS_SUCCESS; /* any error will have already been set on cr */
405 }
406
407 static cairo_status_t
408 _cairo_cogl_context_rel_move_to (void *abstract_cr, double dx, double dy)
409 {
410     cairo_cogl_context_t *cr = abstract_cr;
411     cairo_status_t status;
412     cairo_fixed_t dx_fixed, dy_fixed;
413
414     if (cr->path_is_rectangle) {
415         status = _flush_cr_rectangle (cr);
416         if (unlikely (status))
417             return status;
418     }
419
420     status = cr->dev->backend_parent.rel_move_to (abstract_cr, dx, dy);
421     if (unlikely (status))
422         return status;
423
424     dx_fixed = _cairo_fixed_from_double (dx);
425     dy_fixed = _cairo_fixed_from_double (dy);
426
427     return _cairo_path_fixed_rel_move_to (&cr->user_path, dx_fixed, dy_fixed);
428 }
429
430 static cairo_status_t
431 _cairo_cogl_context_rel_line_to (void *abstract_cr, double dx, double dy)
432 {
433     cairo_cogl_context_t *cr = abstract_cr;
434     cairo_status_t status;
435     cairo_fixed_t dx_fixed, dy_fixed;
436
437     if (cr->path_is_rectangle) {
438         status = _flush_cr_rectangle (cr);
439         if (unlikely (status))
440             return status;
441     }
442
443     status = cr->dev->backend_parent.rel_line_to (abstract_cr, dx, dy);
444     if (unlikely (status))
445         return status;
446
447     dx_fixed = _cairo_fixed_from_double (dx);
448     dy_fixed = _cairo_fixed_from_double (dy);
449
450     if (cr->user_path.buf.base.num_ops == 0)
451         cr->path_ctm_age = 0;
452
453     return _cairo_path_fixed_rel_line_to (&cr->user_path, dx_fixed, dy_fixed);
454 }
455
456
457 static cairo_status_t
458 _cairo_cogl_context_rel_curve_to (void *abstract_cr,
459                                    double dx1, double dy1,
460                                    double dx2, double dy2,
461                                    double dx3, double dy3)
462 {
463     cairo_cogl_context_t *cr = abstract_cr;
464     cairo_status_t status;
465     cairo_fixed_t dx1_fixed, dy1_fixed;
466     cairo_fixed_t dx2_fixed, dy2_fixed;
467     cairo_fixed_t dx3_fixed, dy3_fixed;
468
469     if (cr->path_is_rectangle) {
470         status = _flush_cr_rectangle (cr);
471         if (unlikely (status))
472             return status;
473     }
474
475     status = cr->dev->backend_parent.rel_curve_to (abstract_cr, dx1, dy1, dx2, dy2, dx3, dy3);
476     if (unlikely (status))
477         return status;
478
479     dx1_fixed = _cairo_fixed_from_double (dx1);
480     dy1_fixed = _cairo_fixed_from_double (dy1);
481
482     dx2_fixed = _cairo_fixed_from_double (dx2);
483     dy2_fixed = _cairo_fixed_from_double (dy2);
484
485     dx3_fixed = _cairo_fixed_from_double (dx3);
486     dy3_fixed = _cairo_fixed_from_double (dy3);
487
488     if (cr->user_path.buf.base.num_ops == 0)
489         cr->path_ctm_age = 0;
490
491     return _cairo_path_fixed_rel_curve_to (&cr->user_path,
492                                            dx1_fixed, dy1_fixed,
493                                            dx2_fixed, dy2_fixed,
494                                            dx3_fixed, dy3_fixed);
495 }
496
497 #if 0
498 static cairo_status_t
499 _cairo_cogl_context_arc_to (void *abstract_cr,
500                             double x1, double y1,
501                             double x2, double y2,
502                             double radius)
503 {
504     cairo_cogl_context_t *cr = abstract_cr;
505     cairo_status_t status;
506
507     if (cr->path_is_rectangle) {
508         status = _flush_cr_rectangle (cr);
509         if (unlikely (status))
510             return status;
511     }
512
513     status = cr->dev->backend_parent.arc_to (abstract_cr, x1, y1, x2, y2, radius);
514     if (unlikely (status))
515         return status;
516 #warning "FIXME"
517 }
518
519 static cairo_status_t
520 _cairo_cogl_rel_arc_to (void *cr,
521                         double dx1, double dy1,
522                         double dx2, double dy2,
523                         double radius)
524 {
525     cairo_cogl_context_t *cr = abstract_cr;
526     cairo_status_t status;
527
528     if (cr->path_is_rectangle) {
529         status = _flush_cr_rectangle (cr);
530         if (unlikely (status))
531             return status;
532     }
533
534     status = cr->dev->backend_parent.rel_arc_to (abstract_cr, dx1, dy2, dx2, dy2, radius);
535     if (unlikely (status))
536         return status;
537 #warning "FIXME"
538 }
539 #endif
540
541 static cairo_status_t
542 _cairo_cogl_context_close_path (void *abstract_cr)
543 {
544     cairo_cogl_context_t *cr = abstract_cr;
545     cairo_status_t status;
546
547     if (cr->path_is_rectangle) {
548         status = _flush_cr_rectangle (cr);
549         if (unlikely (status))
550             return status;
551     }
552
553     status = cr->dev->backend_parent.close_path (abstract_cr);
554     if (unlikely (status))
555         return status;
556
557     if (cr->user_path.buf.base.num_ops == 0)
558         cr->path_ctm_age = 0;
559
560     return _cairo_path_fixed_close_path (&cr->user_path);
561 }
562
563 static cairo_status_t
564 _cairo_cogl_context_rectangle (void *abstract_cr,
565                                double x, double y,
566                                double width, double height)
567 {
568     cairo_cogl_context_t *cr = abstract_cr;
569
570     if (cr->user_path.buf.base.num_ops == 0) {
571         cr->path_ctm_age = 0;
572
573 #if 1
574         /* XXX: Since drawing rectangles is so common we have a
575          * fast-path for drawing a single rectangle. */
576         cr->x = x;
577         cr->y = y;
578         cr->width = width;
579         cr->height = height;
580         cr->path_is_rectangle = TRUE;
581         return CAIRO_STATUS_SUCCESS;
582 #endif
583     }
584
585     if (cr->path_is_rectangle) {
586         cairo_status_t status = _flush_cr_rectangle (cr);
587         if (unlikely (status))
588             return status;
589     }
590
591     return _cairo_cogl_context_rectangle_real (cr, x, y, width, height);
592 }
593
594 /* Since the surface backend drawing operator functions don't get
595  * passed the current #cairo_t context we don't have a good way
596  * to get our user-coordinates path into our surface operator
597  * functions.
598  *
599  * For now we use this function to set side band data on the surface
600  * itself.
601  */
602 static void
603 _cairo_cogl_surface_set_side_band_state (cairo_cogl_surface_t *surface,
604                                          cairo_cogl_context_t *cr)
605 {
606
607     if (cr->path_ctm_age <= 1) {
608         surface->user_path = &cr->user_path;
609         surface->ctm = &cr->base.gstate->ctm;
610         surface->ctm_inverse = &cr->base.gstate->ctm_inverse;
611         surface->path_is_rectangle = cr->path_is_rectangle;
612         if (surface->path_is_rectangle) {
613             surface->path_rectangle_x = cr->x;
614             surface->path_rectangle_y = cr->y;
615             surface->path_rectangle_width = cr->width;
616             surface->path_rectangle_height = cr->height;
617         }
618     } else {
619         surface->user_path = NULL;
620         surface->path_is_rectangle = FALSE;
621     }
622 }
623
624 static cairo_status_t
625 _cairo_cogl_context_fill (void *abstract_cr)
626 {
627     cairo_cogl_context_t *cr = abstract_cr;
628     cairo_status_t status;
629     cairo_cogl_surface_t *surface = (cairo_cogl_surface_t *)cr->base.gstate->target;
630
631     if (cr->path_is_rectangle) {
632         status = _cairo_cogl_surface_fill_rectangle (cr->base.gstate->target,
633                                                      cr->base.gstate->op,
634                                                      cr->base.gstate->source,
635                                                      cr->x,
636                                                      cr->y,
637                                                      cr->width,
638                                                      cr->height,
639                                                      &cr->base.gstate->ctm,
640                                                      cr->base.gstate->clip);
641         if (status == CAIRO_STATUS_SUCCESS)
642             goto DONE;
643         _flush_cr_rectangle (cr);
644     }
645
646     _cairo_cogl_surface_set_side_band_state (surface, cr);
647
648     status = cr->dev->backend_parent.fill (abstract_cr);
649     if (unlikely (status))
650         return status;
651
652 DONE:
653     _cairo_path_fixed_fini (&cr->user_path);
654     _cairo_path_fixed_init (&cr->user_path);
655     cr->path_is_rectangle = FALSE;
656
657     return CAIRO_STATUS_SUCCESS;
658 }
659
660 static cairo_status_t
661 _cairo_cogl_context_fill_preserve (void *abstract_cr)
662 {
663     cairo_cogl_context_t *cr = abstract_cr;
664     cairo_status_t status;
665     cairo_cogl_surface_t *surface = (cairo_cogl_surface_t *)cr->base.gstate->target;
666
667     _cairo_cogl_surface_set_side_band_state (surface, cr);
668
669     status = cr->dev->backend_parent.fill_preserve (abstract_cr);
670     if (unlikely (status))
671         return status;
672
673     return CAIRO_STATUS_SUCCESS;
674 }
675
676 static cairo_status_t
677 _cairo_cogl_context_stroke (void *abstract_cr)
678 {
679     cairo_cogl_context_t *cr = abstract_cr;
680     cairo_status_t status;
681     cairo_cogl_surface_t *surface = (cairo_cogl_surface_t *)cr->base.gstate->target;
682
683     _cairo_cogl_surface_set_side_band_state (surface, cr);
684
685     status = cr->dev->backend_parent.stroke (abstract_cr);
686     if (unlikely (status))
687         return status;
688
689     _cairo_path_fixed_fini (&cr->user_path);
690     _cairo_path_fixed_init (&cr->user_path);
691     cr->path_is_rectangle = FALSE;
692
693     return CAIRO_STATUS_SUCCESS;
694 }
695
696 static cairo_status_t
697 _cairo_cogl_context_stroke_preserve (void *abstract_cr)
698 {
699     cairo_cogl_context_t *cr = abstract_cr;
700     cairo_status_t status;
701     cairo_cogl_surface_t *surface = (cairo_cogl_surface_t *)cr->base.gstate->target;
702
703     _cairo_cogl_surface_set_side_band_state (surface, cr);
704
705     status = cr->dev->backend_parent.stroke_preserve (abstract_cr);
706     if (unlikely (status))
707         return status;
708
709     return CAIRO_STATUS_SUCCESS;
710 }
711
712 static cairo_status_t
713 _cairo_cogl_context_clip (void *abstract_cr)
714 {
715     cairo_cogl_context_t *cr = abstract_cr;
716     cairo_status_t status;
717
718     status = cr->dev->backend_parent.clip (abstract_cr);
719     if (unlikely (status))
720         return status;
721
722     _cairo_path_fixed_fini (&cr->user_path);
723     _cairo_path_fixed_init (&cr->user_path);
724     cr->path_is_rectangle = FALSE;
725
726     return CAIRO_STATUS_SUCCESS;
727 }
728
729 static void
730 _cairo_cogl_context_destroy (void *abstract_cr)
731 {
732     cairo_cogl_context_t *cr = abstract_cr;
733
734     _cairo_default_context_fini (&cr->base);
735
736     _cairo_path_fixed_fini (&cr->user_path);
737
738     /* mark the context as invalid to protect against misuse */
739     cr->base.base.status = CAIRO_STATUS_NULL_POINTER;
740     _freed_pool_put (&context_pool, cr);
741 }
742
743 /* We want to hook into the frontend of the path construction APIs so
744  * we can build up a path description in user coordinates instead of
745  * backend coordinates so that we can recognize user coordinate
746  * rectangles and so we can hash a user path independent of its
747  * transform. (With some care to catch unusual cases where the ctm
748  * changes mid-path) */
749 cairo_t *
750 _cairo_cogl_context_create (void *target)
751 {
752     cairo_cogl_surface_t *surface = target;
753     cairo_cogl_context_t *cr;
754     cairo_status_t status;
755
756     cr = _freed_pool_get (&context_pool);
757     if (unlikely (cr == NULL)) {
758         cr = malloc (sizeof (cairo_cogl_context_t));
759         if (unlikely (cr == NULL))
760             return _cairo_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
761     }
762
763     status = _cairo_default_context_init (&cr->base, target);
764     if (unlikely (status)) {
765         _freed_pool_put (&context_pool, cr);
766         return _cairo_create_in_error (status);
767     }
768
769     cr->dev = (cairo_cogl_device_t *)surface->base.device;
770
771     if (unlikely (cr->dev->backend_vtable_initialized == FALSE)) {
772         cairo_backend_t *backend = &cr->dev->backend;
773         memcpy (backend, cr->base.base.backend, sizeof (cairo_backend_t));
774         memcpy (&cr->dev->backend_parent, cr->base.base.backend, sizeof (cairo_backend_t));
775
776         backend->destroy = _cairo_cogl_context_destroy;
777
778         backend->restore = _cairo_cogl_context_restore;
779         backend->translate = _cairo_cogl_context_translate;
780         backend->scale = _cairo_cogl_context_scale;
781         backend->rotate = _cairo_cogl_context_rotate;
782         backend->transform = _cairo_cogl_context_transform;
783         backend->set_matrix = _cairo_cogl_context_set_matrix;
784         backend->set_identity_matrix = _cairo_cogl_context_set_identity_matrix;
785
786         backend->new_path = _cairo_cogl_context_new_path;
787         backend->new_sub_path = _cairo_cogl_context_new_sub_path;
788         backend->move_to = _cairo_cogl_context_move_to;
789         backend->rel_move_to = _cairo_cogl_context_rel_move_to;
790         backend->line_to = _cairo_cogl_context_line_to;
791         backend->rel_line_to = _cairo_cogl_context_rel_line_to;
792         backend->curve_to = _cairo_cogl_context_curve_to;
793         backend->rel_curve_to = _cairo_cogl_context_rel_curve_to;
794 #if 0
795         backend->arc_to = _cairo_cogl_context_arc_to;
796         backend->rel_arc_to = _cairo_cogl_context_rel_arc_to;
797 #endif
798         backend->close_path = _cairo_cogl_context_close_path;
799         //backend->arc = _cairo_cogl_context_arc;
800         backend->rectangle = _cairo_cogl_context_rectangle;
801
802         /* Try to automatically catch if any new path APIs are added that mean
803          * we may need to overload more functions... */
804         assert (((char *)&backend->path_extents - (char *)&backend->device_to_user_distance)
805                 == (sizeof (void *) * 14));
806
807         backend->fill = _cairo_cogl_context_fill;
808         backend->fill_preserve = _cairo_cogl_context_fill_preserve;
809         backend->stroke = _cairo_cogl_context_stroke;
810         backend->stroke_preserve = _cairo_cogl_context_stroke_preserve;
811         backend->clip = _cairo_cogl_context_clip;
812
813         cr->dev->backend_vtable_initialized = TRUE;
814     }
815
816     cr->base.base.backend = &cr->dev->backend;
817
818     _cairo_path_fixed_init (&cr->user_path);
819     cr->path_is_rectangle = FALSE;
820
821     return &cr->base.base;
822 }