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 | }=>=>=> |