Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4349 Serge 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 
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 
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
}