1 /* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
2 /* cairo - a vector graphics library with display and print output
4 * Copyright © 2008 Opened Hand Ltd.
5 * Copyright © 2009 Chris Wilson
7 * This library is free software; you can redistribute it and/or
8 * modify it either under the terms of the GNU Lesser General Public
9 * License version 2.1 as published by the Free Software Foundation
10 * (the "LGPL") or, at your option, under the terms of the Mozilla
11 * Public License Version 1.1 (the "MPL"). If you do not alter this
12 * notice, a recipient may use your version of this file under either
13 * the MPL or the LGPL.
15 * You should have received a copy of the LGPL along with this library
16 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
18 * You should have received a copy of the MPL along with this library
19 * in the file COPYING-MPL-1.1
21 * The contents of this file are subject to the Mozilla Public License
22 * Version 1.1 (the "License"); you may not use this file except in
23 * compliance with the License. You may obtain a copy of the License at
24 * http://www.mozilla.og/MPL/
26 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
27 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
28 * the specific language governing rights and limitations.
31 * Pierre Tardy <tardyp@gmail.com>
32 * Øyvind Kolås <pippin@gimp.org>
33 * Vladimi Vukicevic <vladimir@mozilla.com> (stubbed out base backend)
34 * Chris Wilson <chris@chris-wilson.co.uk>
41 #include "cairo-cache-private.h"
42 #include "cairo-default-context-private.h"
43 #include "cairo-error-private.h"
44 #include "cairo-image-surface-private.h"
45 #include "cairo-path-fixed-private.h"
46 #include "cairo-recording-surface-inline.h"
47 #include "cairo-surface-clipper-private.h"
50 #include <VG/openvg.h>
52 //#define OPENVG_DEBUG
55 * Work that needs to be done:
56 * - Glyph cache / proper font support
59 * Paths are expensive for OpenVG, reuse paths whenever possible.
60 * So add a path cache, and first class paths!
63 typedef struct _cairo_vg_surface cairo_vg_surface_t
;
65 /* XXX need GL specific context control. :( */
66 struct _cairo_vg_context
{
67 cairo_status_t status
;
68 cairo_reference_count_t ref_count
;
70 unsigned long target_id
;
73 cairo_vg_surface_t
*source
;
76 cairo_cache_t snapshot_cache
;
81 cairo_status_t (*create_target
) (cairo_vg_context_t
*,
82 cairo_vg_surface_t
*);
83 cairo_status_t (*set_target
) (cairo_vg_context_t
*,
84 cairo_vg_surface_t
*);
85 void (*destroy_target
) (cairo_vg_context_t
*, cairo_vg_surface_t
*);
88 struct _cairo_vg_surface
{
91 cairo_vg_context_t
*context
;
97 cairo_bool_t own_image
;
99 cairo_cache_entry_t snapshot_cache_entry
;
101 cairo_surface_clipper_t clipper
;
103 unsigned long target_id
;
106 static const cairo_surface_backend_t cairo_vg_surface_backend
;
108 slim_hidden_proto (cairo_vg_surface_create
);
110 static cairo_surface_t
*
111 _vg_surface_create_internal (cairo_vg_context_t
*context
,
113 VGImageFormat format
,
114 int width
, int height
);
116 static cairo_vg_context_t
*
117 _vg_context_reference (cairo_vg_context_t
*context
)
119 assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&context
->ref_count
));
121 _cairo_reference_count_inc (&context
->ref_count
);
126 static cairo_vg_context_t
*
127 _vg_context_lock (cairo_vg_context_t
*context
)
129 /* XXX if we need to add locking, then it has to be recursive */
133 static cairo_int_status_t
134 _vg_context_set_target (cairo_vg_context_t
*context
,
135 cairo_vg_surface_t
*surface
)
137 cairo_status_t status
;
139 if (surface
->target_id
== 0) {
140 status
= context
->create_target (context
, surface
);
141 if (unlikely (status
))
145 if (context
->target_id
== surface
->target_id
)
146 return CAIRO_STATUS_SUCCESS
;
148 context
->target_id
= surface
->target_id
;
150 return context
->set_target (context
, surface
);
154 _vg_context_destroy_target (cairo_vg_context_t
*context
,
155 cairo_vg_surface_t
*surface
)
157 if (surface
->target_id
== 0)
160 if (context
->target_id
== surface
->target_id
)
161 context
->set_target (context
, NULL
);
163 context
->destroy_target (context
, surface
);
167 _vg_snapshot_cache_can_remove (const void *entry
)
173 _vg_snapshot_cache_remove (void *cache_entry
)
175 cairo_vg_surface_t
*surface
= cairo_container_of (cache_entry
,
177 snapshot_cache_entry
);
178 surface
->snapshot_cache_entry
.hash
= 0;
179 cairo_surface_destroy (&surface
->base
);
182 static cairo_status_t
183 _vg_context_init (cairo_vg_context_t
*context
)
185 cairo_status_t status
;
187 context
->status
= CAIRO_STATUS_SUCCESS
;
188 CAIRO_REFERENCE_COUNT_INIT (&context
->ref_count
, 1);
190 status
= _cairo_cache_init (&context
->snapshot_cache
,
192 _vg_snapshot_cache_can_remove
,
193 _vg_snapshot_cache_remove
,
195 if (unlikely (status
))
198 context
->target_id
= 0;
199 context
->source
= NULL
;
200 context
->alpha
= 1.0;
202 context
->paint
= vgCreatePaint ();
205 return CAIRO_STATUS_SUCCESS
;
209 _vg_context_destroy (cairo_vg_context_t
*context
)
211 assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&context
->ref_count
));
213 if (! _cairo_reference_count_dec_and_test (&context
->ref_count
))
216 if (context
->paint
!= VG_INVALID_HANDLE
)
217 vgDestroyPaint (context
->paint
);
219 _cairo_cache_fini (&context
->snapshot_cache
);
224 _vg_context_unlock (cairo_vg_context_t
*context
)
229 static void check_vg_errors(const char*function
,int line
)
231 int err
= vgGetError();
232 if (err
!= VG_NO_ERROR
){
233 printf("%s+%d:vgError detected: 0x%08x.\n",function
, line
,err
);
234 assert(err
== VG_NO_ERROR
);
238 #define CHECK_VG_ERRORS() check_vg_errors(__FILE__,__LINE__)
240 #define CHECK_VG_ERRORS() do{}while(0)
241 #endif //OPENVG_DEBUG
243 static pixman_format_code_t
244 _vg_format_to_pixman (VGImageFormat format
,
245 cairo_bool_t
*needs_premult_fixup
)
247 *needs_premult_fixup
= FALSE
;
249 /* RGB{A,X} channel ordering */
250 case VG_sRGBX_8888
: return PIXMAN_r8g8b8x8
;
251 case VG_sRGBA_8888
: *needs_premult_fixup
= TRUE
; return PIXMAN_r8g8b8a8
;
252 case VG_sRGBA_8888_PRE
: return PIXMAN_r8g8b8a8
;
253 case VG_sRGB_565
: return PIXMAN_r5g6b5
;
254 case VG_sRGBA_5551
: return 0;
255 case VG_sRGBA_4444
: return 0;
256 case VG_sL_8
: return PIXMAN_g8
;
257 case VG_lRGBX_8888
: return 0;
258 case VG_lRGBA_8888
: return 0;
259 case VG_lRGBA_8888_PRE
: return 0;
260 case VG_lL_8
: return 0;
261 case VG_A_8
: return PIXMAN_a8
;
262 case VG_BW_1
: return PIXMAN_a1
;
263 case VG_A_1
: return PIXMAN_a1
;
264 case VG_A_4
: return PIXMAN_a4
;
266 /* {A,X}RGB channel ordering */
267 case VG_sXRGB_8888
: return PIXMAN_x8r8g8b8
;
268 case VG_sARGB_8888
: *needs_premult_fixup
= TRUE
; return PIXMAN_a8r8g8b8
;
269 case VG_sARGB_8888_PRE
: return PIXMAN_a8r8g8b8
;
270 case VG_sARGB_1555
: return 0;
271 case VG_sARGB_4444
: return 0;
272 case VG_lXRGB_8888
: return 0;
273 case VG_lARGB_8888
: return 0;
274 case VG_lARGB_8888_PRE
: return 0;
276 /* BGR{A,X} channel ordering */
277 case VG_sBGRX_8888
: return PIXMAN_b8g8r8x8
;
278 case VG_sBGRA_8888
: *needs_premult_fixup
= TRUE
; return PIXMAN_b8g8r8a8
;
279 case VG_sBGRA_8888_PRE
: return PIXMAN_b8g8r8a8
;
280 case VG_sBGR_565
: return PIXMAN_b5g6r5
;
281 case VG_sBGRA_5551
: return 0;
282 case VG_sBGRA_4444
: return 0;
283 case VG_lBGRX_8888
: return 0;
284 case VG_lBGRA_8888
: return 0;
285 case VG_lBGRA_8888_PRE
: return 0;
287 /* {A,X}BGR channel ordering */
288 case VG_sXBGR_8888
: return PIXMAN_x8b8g8r8
;
289 case VG_sABGR_8888
: *needs_premult_fixup
= TRUE
; return PIXMAN_a8b8g8r8
;
290 case VG_sABGR_8888_PRE
: return PIXMAN_a8b8g8r8
;
291 case VG_sABGR_1555
: return 0;
292 case VG_sABGR_4444
: return 0;
293 case VG_lXBGR_8888
: return 0;
294 case VG_lABGR_8888
: return 0;
295 case VG_lABGR_8888_PRE
: return 0;
300 static pixman_format_code_t
301 _vg_format_to_content (VGImageFormat format
)
303 /* XXX could use more simple bit tests */
305 /* RGB{A,X} channel ordering */
306 case VG_sRGBX_8888
: return CAIRO_CONTENT_COLOR
;
307 case VG_sRGBA_8888
: return CAIRO_CONTENT_COLOR_ALPHA
;
308 case VG_sRGBA_8888_PRE
: return CAIRO_CONTENT_COLOR_ALPHA
;
309 case VG_sRGB_565
: return CAIRO_CONTENT_COLOR
;
310 case VG_sRGBA_5551
: return CAIRO_CONTENT_COLOR_ALPHA
;
311 case VG_sRGBA_4444
: return CAIRO_CONTENT_COLOR_ALPHA
;
312 case VG_sL_8
: return CAIRO_CONTENT_ALPHA
;
313 case VG_lRGBX_8888
: return CAIRO_CONTENT_COLOR
;
314 case VG_lRGBA_8888
: return CAIRO_CONTENT_COLOR_ALPHA
;
315 case VG_lRGBA_8888_PRE
: return CAIRO_CONTENT_COLOR_ALPHA
;
316 case VG_lL_8
: return CAIRO_CONTENT_ALPHA
;
317 case VG_A_8
: return CAIRO_CONTENT_ALPHA
;
318 case VG_A_4
: return CAIRO_CONTENT_ALPHA
;
319 case VG_A_1
: return CAIRO_CONTENT_ALPHA
;
320 case VG_BW_1
: return CAIRO_CONTENT_ALPHA
;
322 /* {A,X}RGB channel ordering */
323 case VG_sXRGB_8888
: return CAIRO_CONTENT_COLOR
;
324 case VG_sARGB_8888
: return CAIRO_CONTENT_COLOR_ALPHA
;
325 case VG_sARGB_8888_PRE
: return CAIRO_CONTENT_COLOR_ALPHA
;
326 case VG_sARGB_1555
: return CAIRO_CONTENT_COLOR_ALPHA
;
327 case VG_sARGB_4444
: return CAIRO_CONTENT_COLOR_ALPHA
;
328 case VG_lXRGB_8888
: return CAIRO_CONTENT_COLOR
;
329 case VG_lARGB_8888
: return CAIRO_CONTENT_COLOR_ALPHA
;
330 case VG_lARGB_8888_PRE
: return CAIRO_CONTENT_COLOR_ALPHA
;
332 /* BGR{A,X} channel ordering */
333 case VG_sBGRX_8888
: return CAIRO_CONTENT_COLOR
;
334 case VG_sBGRA_8888
: return CAIRO_CONTENT_COLOR_ALPHA
;
335 case VG_sBGRA_8888_PRE
: return CAIRO_CONTENT_COLOR_ALPHA
;
336 case VG_sBGR_565
: return CAIRO_CONTENT_COLOR
;
337 case VG_sBGRA_5551
: return CAIRO_CONTENT_COLOR_ALPHA
;
338 case VG_sBGRA_4444
: return CAIRO_CONTENT_COLOR_ALPHA
;
339 case VG_lBGRX_8888
: return CAIRO_CONTENT_COLOR
;
340 case VG_lBGRA_8888
: return CAIRO_CONTENT_COLOR_ALPHA
;
341 case VG_lBGRA_8888_PRE
: return CAIRO_CONTENT_COLOR_ALPHA
;
343 /* {A,X}BGR channel ordering */
344 case VG_sXBGR_8888
: return CAIRO_CONTENT_COLOR
;
345 case VG_sABGR_8888
: return CAIRO_CONTENT_COLOR_ALPHA
;
346 case VG_sABGR_8888_PRE
: return CAIRO_CONTENT_COLOR_ALPHA
;
347 case VG_sABGR_1555
: return CAIRO_CONTENT_COLOR_ALPHA
;
348 case VG_sABGR_4444
: return CAIRO_CONTENT_COLOR_ALPHA
;
349 case VG_lXBGR_8888
: return CAIRO_CONTENT_COLOR
;
350 case VG_lABGR_8888
: return CAIRO_CONTENT_COLOR_ALPHA
;
351 case VG_lABGR_8888_PRE
: return CAIRO_CONTENT_COLOR_ALPHA
;
357 _vg_format_from_pixman (pixman_format_code_t format
)
359 /* XXX _PRE needs fixup */
360 switch ((int) format
) {
361 case PIXMAN_r5g6b5
: return VG_sRGB_565
;
362 case PIXMAN_g8
: return VG_sL_8
;
363 case PIXMAN_a8
: return VG_A_8
;
364 case PIXMAN_a1
: return VG_BW_1
;
365 case PIXMAN_x8r8g8b8
: return VG_sXRGB_8888
;
366 case PIXMAN_a8r8g8b8
: return VG_sARGB_8888
; // _PRE
367 case PIXMAN_b8g8r8x8
: return VG_sBGRX_8888
;
368 case PIXMAN_b8g8r8a8
: return VG_sBGRA_8888
; // _PRE
369 case PIXMAN_b5g6r5
: return VG_sBGR_565
;
370 case PIXMAN_x8b8g8r8
: return VG_sXBGR_8888
;
371 case PIXMAN_a8b8g8r8
: return VG_sABGR_8888
; // _PRE
377 _vg_format_for_content (cairo_content_t content
)
380 case CAIRO_CONTENT_ALPHA
: return VG_A_8
;
381 case CAIRO_CONTENT_COLOR
: return VG_sXRGB_8888
;
382 default: ASSERT_NOT_REACHED
;
383 case CAIRO_CONTENT_COLOR_ALPHA
: return VG_sARGB_8888
; // _PRE
387 static cairo_surface_t
*
388 _vg_surface_create_similar (void *abstract_surface
,
389 cairo_content_t content
,
393 cairo_vg_surface_t
*surface
= abstract_surface
;
395 if (width
> vgGeti (VG_MAX_IMAGE_WIDTH
) ||
396 height
> vgGeti (VG_MAX_IMAGE_HEIGHT
))
401 return cairo_vg_surface_create (surface
->context
, content
, width
, height
);
404 static cairo_status_t
405 _vg_surface_clipper_intersect_clip_path (cairo_surface_clipper_t
*clipper
,
406 cairo_path_fixed_t
*path
,
407 cairo_fill_rule_t fill_rule
,
409 cairo_antialias_t antialias
)
411 cairo_vg_surface_t
*surface
= cairo_container_of (clipper
,
414 cairo_vg_surface_t
*mask
;
415 cairo_status_t status
;
418 vgMask (VG_INVALID_HANDLE
,
419 VG_FILL_MASK
, 0, 0, surface
->width
, surface
->height
);
420 vgSeti (VG_MASKING
, VG_FALSE
);
422 return CAIRO_STATUS_SUCCESS
;
425 mask
= (cairo_vg_surface_t
*)
426 _vg_surface_create_similar (surface
, CAIRO_CONTENT_ALPHA
,
427 surface
->width
, surface
->height
);
428 if (unlikely (mask
== NULL
))
429 return CAIRO_INT_STATUS_UNSUPPORTED
;
430 if (unlikely (mask
->base
.status
))
431 return mask
->base
.status
;
433 status
= _cairo_surface_fill (&mask
->base
,
434 CAIRO_OPERATOR_SOURCE
,
435 &_cairo_pattern_white
.base
,
436 path
, fill_rule
, tolerance
, antialias
,
439 cairo_surface_destroy (&mask
->base
);
443 vgSeti (VG_MASKING
, VG_TRUE
);
444 vgMask (mask
->image
, VG_INTERSECT_MASK
, 0, 0, mask
->width
, mask
->height
);
446 cairo_surface_destroy (&mask
->base
);
449 return CAIRO_STATUS_SUCCESS
;
453 _vg_surface_get_extents (void *abstract_surface
,
454 cairo_rectangle_int_t
*extents
)
456 cairo_vg_surface_t
*surface
= abstract_surface
;
460 extents
->width
= surface
->width
;
461 extents
->height
= surface
->height
;
466 #define MAX_SEG 16 /* max number of knots to upload in a batch */
468 typedef struct _vg_path
{
470 const cairo_matrix_t
*ctm_inverse
;
472 VGubyte gseg
[MAX_SEG
];
473 VGfloat gdata
[MAX_SEG
*3*2];
478 static cairo_status_t
479 _vg_move_to (void *closure
,
480 const cairo_point_t
*point
)
482 vg_path_t
*path
= closure
;
483 double x
= _cairo_fixed_to_double (point
->x
);
484 double y
= _cairo_fixed_to_double (point
->y
);
486 if (path
->ctm_inverse
)
487 cairo_matrix_transform_point (path
->ctm_inverse
, &x
, &y
);
489 path
->gseg
[path
->scount
++] = VG_MOVE_TO
;
490 path
->gdata
[path
->dcount
++] = x
;
491 path
->gdata
[path
->dcount
++] = y
;
493 if (path
->scount
>= MAX_SEG
-1) {
494 vgAppendPathData (path
->path
, path
->scount
, path
->gseg
, path
->gdata
);
500 return CAIRO_STATUS_SUCCESS
;
503 static cairo_status_t
504 _vg_line_to (void *closure
,
505 const cairo_point_t
*point
)
507 vg_path_t
*path
= closure
;
508 double x
= _cairo_fixed_to_double (point
->x
);
509 double y
= _cairo_fixed_to_double (point
->y
);
511 if (path
->ctm_inverse
)
512 cairo_matrix_transform_point (path
->ctm_inverse
, &x
, &y
);
514 path
->gseg
[path
->scount
++] = VG_LINE_TO
;
515 path
->gdata
[path
->dcount
++] = x
;
516 path
->gdata
[path
->dcount
++] = y
;
518 if (path
->scount
>= MAX_SEG
-1) {
519 vgAppendPathData (path
->path
, path
->scount
, path
->gseg
, path
->gdata
);
525 return CAIRO_STATUS_SUCCESS
;
528 static cairo_status_t
529 _vg_curve_to (void *closure
,
530 const cairo_point_t
*p0
,
531 const cairo_point_t
*p1
,
532 const cairo_point_t
*p2
)
534 vg_path_t
*path
= closure
;
535 double x0
= _cairo_fixed_to_double (p0
->x
);
536 double y0
= _cairo_fixed_to_double (p0
->y
);
537 double x1
= _cairo_fixed_to_double (p1
->x
);
538 double y1
= _cairo_fixed_to_double (p1
->y
);
539 double x2
= _cairo_fixed_to_double (p2
->x
);
540 double y2
= _cairo_fixed_to_double (p2
->y
);
542 if (path
->ctm_inverse
) {
543 cairo_matrix_transform_point (path
->ctm_inverse
, &x0
, &y0
);
544 cairo_matrix_transform_point (path
->ctm_inverse
, &x1
, &y1
);
545 cairo_matrix_transform_point (path
->ctm_inverse
, &x2
, &y2
);
548 path
->gseg
[path
->scount
++] = VG_CUBIC_TO
;
549 path
->gdata
[path
->dcount
++] = x0
;
550 path
->gdata
[path
->dcount
++] = y0
;
551 path
->gdata
[path
->dcount
++] = x1
;
552 path
->gdata
[path
->dcount
++] = y1
;
553 path
->gdata
[path
->dcount
++] = x2
;
554 path
->gdata
[path
->dcount
++] = y2
;
556 if (path
->scount
>= MAX_SEG
-1) {
557 vgAppendPathData(path
->path
, path
->scount
, path
->gseg
, path
->gdata
);
563 return CAIRO_STATUS_SUCCESS
;
566 static cairo_status_t
567 _vg_close_path (void *closure
)
569 vg_path_t
*path
= closure
;
571 path
->gseg
[path
->scount
++] = VG_CLOSE_PATH
;
573 if (path
->scount
>= MAX_SEG
-1) {
574 vgAppendPathData (path
->path
, path
->scount
, path
->gseg
, path
->gdata
);
580 return CAIRO_STATUS_SUCCESS
;
584 _vg_path_from_cairo (vg_path_t
*vg_path
,
585 const cairo_path_fixed_t
*path
)
587 cairo_status_t status
;
592 status
= _cairo_path_fixed_interpret (path
,
598 assert (status
== CAIRO_STATUS_SUCCESS
);
600 vgAppendPathData (vg_path
->path
,
601 vg_path
->scount
, vg_path
->gseg
, vg_path
->gdata
);
606 _vg_is_supported_operator (cairo_operator_t op
)
609 case CAIRO_OPERATOR_SOURCE
:
610 case CAIRO_OPERATOR_OVER
:
611 case CAIRO_OPERATOR_IN
:
612 case CAIRO_OPERATOR_DEST_OVER
:
613 case CAIRO_OPERATOR_DEST_IN
:
614 case CAIRO_OPERATOR_ADD
:
623 _vg_operator (cairo_operator_t op
)
626 case CAIRO_OPERATOR_SOURCE
:
628 case CAIRO_OPERATOR_OVER
:
629 return VG_BLEND_SRC_OVER
;
630 case CAIRO_OPERATOR_IN
:
631 return VG_BLEND_SRC_IN
;
632 case CAIRO_OPERATOR_DEST_OVER
:
633 return VG_BLEND_DST_OVER
;
634 case CAIRO_OPERATOR_DEST_IN
:
635 return VG_BLEND_DST_IN
;
636 case CAIRO_OPERATOR_ADD
:
637 return VG_BLEND_ADDITIVE
;
640 return VG_BLEND_SRC_OVER
;
645 _vg_fill_rule_from_cairo (cairo_fill_rule_t rule
)
648 case CAIRO_FILL_RULE_EVEN_ODD
: return VG_EVEN_ODD
;
649 case CAIRO_FILL_RULE_WINDING
: return VG_NON_ZERO
;
656 static VGRenderingQuality
657 _vg_rendering_quality_from_cairo (cairo_antialias_t aa
)
660 case CAIRO_ANTIALIAS_DEFAULT
:
661 case CAIRO_ANTIALIAS_SUBPIXEL
:
662 case CAIRO_ANTIALIAS_GOOD
:
663 case CAIRO_ANTIALIAS_BEST
:
664 return VG_RENDERING_QUALITY_BETTER
;
666 case CAIRO_ANTIALIAS_GRAY
:
667 case CAIRO_ANTIALIAS_FAST
:
668 return VG_RENDERING_QUALITY_FASTER
;
670 case CAIRO_ANTIALIAS_NONE
:
671 return VG_RENDERING_QUALITY_NONANTIALIASED
;
675 return VG_RENDERING_QUALITY_BETTER
;
679 _vg_line_cap_from_cairo (cairo_line_cap_t cap
)
682 case CAIRO_LINE_CAP_BUTT
: return VG_CAP_BUTT
;
683 case CAIRO_LINE_CAP_ROUND
: return VG_CAP_ROUND
;
684 case CAIRO_LINE_CAP_SQUARE
: return VG_CAP_SQUARE
;
692 _vg_line_join_from_cairo (cairo_line_join_t join
)
695 case CAIRO_LINE_JOIN_MITER
: return VG_JOIN_MITER
;
696 case CAIRO_LINE_JOIN_ROUND
: return VG_JOIN_ROUND
;
697 case CAIRO_LINE_JOIN_BEVEL
: return VG_JOIN_BEVEL
;
701 return VG_JOIN_MITER
;
705 _vg_matrix_from_cairo (VGfloat
*dst
, const cairo_matrix_t
*src
)
707 dst
[0] = /* sx */ src
->xx
;
708 dst
[1] = /* shy */ src
->yx
;
710 dst
[3] = /* shx */ src
->xy
;
711 dst
[4] = /* sy */ src
->yy
;
713 dst
[6] = /* tx */ src
->x0
;
714 dst
[7] = /* ty */ src
->y0
;
718 static cairo_status_t
719 _vg_setup_gradient_stops (cairo_vg_context_t
*context
,
720 const cairo_gradient_pattern_t
*pattern
)
722 VGint numstops
= pattern
->n_stops
;
723 VGfloat
*stops
, stack_stops
[CAIRO_STACK_ARRAY_LENGTH (VGfloat
)];
726 if (numstops
*5 < ARRAY_LENGTH (stack_stops
)) {
729 stops
= _cairo_malloc_ab (numstops
, 5*sizeof (VGfloat
));
730 if (unlikely (stops
== NULL
))
731 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
734 for (i
= 0; i
< numstops
; i
++) {
735 stops
[i
*5 + 0] = pattern
->stops
[i
].offset
;
736 stops
[i
*5 + 1] = pattern
->stops
[i
].color
.red
;
737 stops
[i
*5 + 2] = pattern
->stops
[i
].color
.green
;
738 stops
[i
*5 + 3] = pattern
->stops
[i
].color
.blue
;
739 stops
[i
*5 + 4] = pattern
->stops
[i
].color
.alpha
* context
->alpha
;
742 vgSetParameterfv (context
->paint
,
743 VG_PAINT_COLOR_RAMP_STOPS
, numstops
* 5, stops
);
745 if (stops
!= stack_stops
)
749 return CAIRO_STATUS_SUCCESS
;
753 _vg_set_source_matrix (const cairo_pattern_t
*pat
)
756 cairo_status_t status
;
760 status
= cairo_matrix_invert (&mat
);
761 assert (status
== CAIRO_STATUS_SUCCESS
);
763 _vg_matrix_from_cairo (vmat
, &mat
);
765 vgSeti (VG_MATRIX_MODE
, VG_MATRIX_FILL_PAINT_TO_USER
);
767 vgSeti (VG_MATRIX_MODE
, VG_MATRIX_STROKE_PAINT_TO_USER
);
769 vgSeti (VG_MATRIX_MODE
, VG_MATRIX_PATH_USER_TO_SURFACE
);
774 static cairo_status_t
775 _vg_setup_linear_source (cairo_vg_context_t
*context
,
776 const cairo_linear_pattern_t
*lpat
)
780 linear
[0] = lpat
->pd1
.x
;
781 linear
[1] = lpat
->pd1
.y
;
782 linear
[2] = lpat
->pd2
.x
;
783 linear
[3] = lpat
->pd2
.y
;
785 vgSetParameteri (context
->paint
,
786 VG_PAINT_COLOR_RAMP_SPREAD_MODE
,
787 VG_COLOR_RAMP_SPREAD_PAD
);
788 vgSetParameteri (context
->paint
,
790 VG_PAINT_TYPE_LINEAR_GRADIENT
);
791 vgSetParameterfv (context
->paint
,
792 VG_PAINT_LINEAR_GRADIENT
, 4, linear
);
794 _vg_set_source_matrix (&lpat
->base
.base
);
797 return _vg_setup_gradient_stops (context
, &lpat
->base
);
801 static cairo_status_t
802 _vg_setup_radial_source (cairo_vg_context_t
*context
,
803 const cairo_radial_pattern_t
*rpat
)
807 radial
[0] = rpat
->cd1
.center
.x
;
808 radial
[1] = rpat
->cd1
.center
.y
;
809 radial
[2] = rpat
->cd2
.center
.x
;
810 radial
[3] = rpat
->cd2
.center
.y
;
811 radial
[4] = rpat
->cd2
.radius
;
813 vgSetParameteri (context
->paint
,
814 VG_PAINT_COLOR_RAMP_SPREAD_MODE
, VG_COLOR_RAMP_SPREAD_PAD
);
815 vgSetParameteri (context
->paint
,
816 VG_PAINT_TYPE
, VG_PAINT_TYPE_RADIAL_GRADIENT
);
817 vgSetParameterfv (context
->paint
,
818 VG_PAINT_RADIAL_GRADIENT
, 5, radial
);
820 _vg_set_source_matrix (&rpat
->base
.base
);
822 /* FIXME: copy/adapt fixes from SVG backend to add inner radius */
825 return _vg_setup_gradient_stops (context
, &rpat
->base
);
828 static cairo_status_t
829 _vg_setup_solid_source (cairo_vg_context_t
*context
,
830 const cairo_solid_pattern_t
*spat
)
836 spat
->color
.alpha
* context
->alpha
839 vgSetParameteri (context
->paint
, VG_PAINT_TYPE
, VG_PAINT_TYPE_COLOR
);
840 vgSetParameterfv (context
->paint
, VG_PAINT_COLOR
, 4, color
);
843 return CAIRO_STATUS_SUCCESS
;
846 static cairo_vg_surface_t
*
847 _vg_clone_recording_surface (cairo_vg_context_t
*context
,
848 cairo_surface_t
*surface
)
851 VGImageFormat format
;
852 cairo_status_t status
;
853 cairo_rectangle_int_t extents
;
854 cairo_vg_surface_t
*clone
;
856 status
= _cairo_surface_get_extents (surface
, &extents
);
860 if (extents
.width
> vgGeti (VG_MAX_IMAGE_WIDTH
) ||
861 extents
.height
> vgGeti (VG_MAX_IMAGE_HEIGHT
))
866 format
= _vg_format_for_content (surface
->content
);
868 /* NONALIASED, FASTER, BETTER */
869 vg_image
= vgCreateImage (format
,
870 extents
.width
, extents
.height
,
871 VG_IMAGE_QUALITY_FASTER
);
872 clone
= (cairo_vg_surface_t
*)
873 _vg_surface_create_internal (context
, vg_image
, format
,
874 extents
.width
, extents
.height
);
875 cairo_surface_set_device_offset (&clone
->base
, -extents
.x
, -extents
.y
);
877 status
= _cairo_recording_surface_replay (surface
, &clone
->base
);
878 if (unlikely (status
)) {
879 cairo_surface_destroy (&clone
->base
);
880 return (cairo_vg_surface_t
*) _cairo_surface_create_in_error (status
);
886 static cairo_vg_surface_t
*
887 _vg_clone_image_surface (cairo_vg_context_t
*context
,
888 cairo_surface_t
*surface
)
890 cairo_image_surface_t
*image
;
892 cairo_status_t status
;
894 VGImageFormat format
;
895 cairo_rectangle_int_t extents
;
896 cairo_vg_surface_t
*clone
;
898 if (surface
->backend
->acquire_source_image
== NULL
)
901 status
= _cairo_surface_get_extents (surface
, &extents
);
905 if (extents
.width
> vgGeti (VG_MAX_IMAGE_WIDTH
) ||
906 extents
.height
> vgGeti (VG_MAX_IMAGE_HEIGHT
))
911 status
= _cairo_surface_acquire_source_image (surface
,
912 &image
, &image_extra
);
913 if (unlikely (status
))
914 return (cairo_vg_surface_t
*) _cairo_surface_create_in_error (status
);
916 format
= _vg_format_from_pixman (image
->pixman_format
);
918 format
= _vg_format_for_content (image
->base
.content
);
920 /* NONALIASED, FASTER, BETTER */
921 vg_image
= vgCreateImage (format
,
922 image
->width
, image
->height
,
923 VG_IMAGE_QUALITY_FASTER
);
924 clone
= (cairo_vg_surface_t
*)
925 _vg_surface_create_internal (context
, vg_image
, format
,
926 image
->width
, image
->height
);
927 if (unlikely (clone
->base
.status
))
930 vgImageSubData (clone
->image
,
931 image
->data
, image
->stride
,
932 format
, 0, 0, image
->width
, image
->height
);
934 _cairo_surface_release_source_image (surface
, image
, image_extra
);
940 _vg_surface_remove_from_cache (cairo_surface_t
*abstract_surface
)
942 cairo_vg_surface_t
*surface
= (cairo_vg_surface_t
*) abstract_surface
;
944 if (surface
->snapshot_cache_entry
.hash
) {
945 cairo_vg_context_t
*context
;
947 context
= _vg_context_lock (surface
->context
);
948 _cairo_cache_remove (&context
->snapshot_cache
,
949 &surface
->snapshot_cache_entry
);
950 _vg_context_unlock (context
);
952 surface
->snapshot_cache_entry
.hash
= 0;
956 static cairo_status_t
957 _vg_setup_surface_source (cairo_vg_context_t
*context
,
958 const cairo_surface_pattern_t
*spat
)
960 cairo_surface_t
*snapshot
;
961 cairo_vg_surface_t
*clone
;
962 cairo_status_t status
;
964 snapshot
= _cairo_surface_has_snapshot (spat
->surface
,
965 &cairo_vg_surface_backend
);
966 if (snapshot
!= NULL
) {
967 clone
= (cairo_vg_surface_t
*) cairo_surface_reference (snapshot
);
971 if (_cairo_surface_is_recording (spat
->surface
))
972 clone
= _vg_clone_recording_surface (context
, spat
->surface
);
974 clone
= _vg_clone_image_surface (context
, spat
->surface
);
976 return CAIRO_INT_STATUS_UNSUPPORTED
;
977 if (unlikely (clone
->base
.status
))
978 return clone
->base
.status
;
980 clone
->snapshot_cache_entry
.hash
= clone
->base
.unique_id
;
981 status
= _cairo_cache_insert (&context
->snapshot_cache
,
982 &clone
->snapshot_cache_entry
);
983 if (unlikely (status
)) {
984 clone
->snapshot_cache_entry
.hash
= 0;
985 cairo_surface_destroy (&clone
->base
);
989 _cairo_surface_attach_snapshot (spat
->surface
, &clone
->base
,
990 _vg_surface_remove_from_cache
);
993 cairo_surface_destroy (&context
->source
->base
);
994 context
->source
= clone
;
996 vgSetParameteri (context
->paint
, VG_PAINT_TYPE
, VG_PAINT_TYPE_PATTERN
);
998 switch (spat
->base
.extend
) {
999 case CAIRO_EXTEND_PAD
:
1000 vgSetParameteri (context
->paint
,
1001 VG_PAINT_PATTERN_TILING_MODE
,
1005 case CAIRO_EXTEND_NONE
:
1006 vgSetParameteri (context
->paint
,
1007 VG_PAINT_PATTERN_TILING_MODE
,
1010 VGfloat color
[] = {0,0,0,0};
1011 vgSetfv (VG_TILE_FILL_COLOR
, 4, color
);
1015 case CAIRO_EXTEND_REPEAT
:
1016 vgSetParameteri (context
->paint
,
1017 VG_PAINT_PATTERN_TILING_MODE
,
1023 case CAIRO_EXTEND_REFLECT
:
1024 vgSetParameteri (context
->paint
,
1025 VG_PAINT_PATTERN_TILING_MODE
,
1029 vgPaintPattern (context
->paint
, context
->source
->image
);
1031 _vg_set_source_matrix (&spat
->base
);
1034 return CAIRO_STATUS_SUCCESS
;
1037 static cairo_status_t
1038 setup_source (cairo_vg_context_t
*context
,
1039 const cairo_pattern_t
*source
)
1041 switch (source
->type
) {
1042 case CAIRO_PATTERN_TYPE_SOLID
:
1043 return _vg_setup_solid_source (context
,
1044 (cairo_solid_pattern_t
*) source
);
1045 case CAIRO_PATTERN_TYPE_LINEAR
:
1046 return _vg_setup_linear_source (context
,
1047 (cairo_linear_pattern_t
*) source
);
1048 case CAIRO_PATTERN_TYPE_RADIAL
:
1049 return _vg_setup_radial_source (context
,
1050 (cairo_radial_pattern_t
*) source
);
1051 case CAIRO_PATTERN_TYPE_SURFACE
:
1052 return _vg_setup_surface_source (context
,
1053 (cairo_surface_pattern_t
*) source
);
1056 return CAIRO_INT_STATUS_UNSUPPORTED
;
1060 static cairo_int_status_t
1061 _vg_surface_stroke (void *abstract_surface
,
1062 cairo_operator_t op
,
1063 const cairo_pattern_t
*source
,
1064 const cairo_path_fixed_t
*path
,
1065 const cairo_stroke_style_t
*style
,
1066 const cairo_matrix_t
*ctm
,
1067 const cairo_matrix_t
*ctm_inverse
,
1069 cairo_antialias_t antialias
,
1070 const cairo_clip_t
*clip
)
1072 cairo_vg_surface_t
*surface
= abstract_surface
;
1073 cairo_vg_context_t
*context
;
1074 cairo_status_t status
;
1076 VGfloat strokeTransform
[9];
1079 if (! _vg_is_supported_operator (op
))
1080 return CAIRO_INT_STATUS_UNSUPPORTED
;
1082 context
= _vg_context_lock (surface
->context
);
1083 status
= _vg_context_set_target (context
, surface
);
1085 _vg_context_unlock (context
);
1089 status
= setup_source (context
, source
);
1091 _vg_context_unlock (context
);
1095 status
= _cairo_surface_clipper_set_clip (&surface
->clipper
, clip
);
1096 if (unlikely (status
)) {
1097 _vg_context_unlock (context
);
1101 vg_path
.path
= vgCreatePath (VG_PATH_FORMAT_STANDARD
,
1104 VG_PATH_CAPABILITY_ALL
);
1106 vgGetMatrix (state
);
1107 _vg_matrix_from_cairo (strokeTransform
, ctm
);
1108 vgMultMatrix (strokeTransform
);
1110 vg_path
.ctm_inverse
= ctm_inverse
;
1112 _vg_path_from_cairo (&vg_path
, path
);
1114 /* XXX DASH_PATTERN, DASH_PHASE */
1115 vgSetf (VG_STROKE_LINE_WIDTH
, style
->line_width
);
1116 vgSetf (VG_STROKE_MITER_LIMIT
, style
->miter_limit
);
1117 vgSetf (VG_STROKE_JOIN_STYLE
, _vg_line_join_from_cairo (style
->line_join
));
1118 vgSetf (VG_STROKE_CAP_STYLE
, _vg_line_cap_from_cairo (style
->line_cap
));
1120 vgSeti (VG_BLEND_MODE
, _vg_operator (op
));
1122 vgSetPaint (context
->paint
, VG_STROKE_PATH
);
1124 vgDrawPath (vg_path
.path
, VG_STROKE_PATH
);
1126 vgDestroyPath (vg_path
.path
);
1128 vgLoadMatrix (state
);
1131 _vg_context_unlock (context
);
1133 return CAIRO_STATUS_SUCCESS
;
1136 static cairo_int_status_t
1137 _vg_surface_fill (void *abstract_surface
,
1138 cairo_operator_t op
,
1139 const cairo_pattern_t
*source
,
1140 const cairo_path_fixed_t
*path
,
1141 cairo_fill_rule_t fill_rule
,
1143 cairo_antialias_t antialias
,
1144 const cairo_clip_t
*clip
)
1146 cairo_vg_surface_t
*surface
= abstract_surface
;
1147 cairo_vg_context_t
*context
;
1148 cairo_status_t status
;
1151 if (op
== CAIRO_OPERATOR_DEST
)
1152 return CAIRO_STATUS_SUCCESS
;
1154 if (! _vg_is_supported_operator (op
))
1155 return CAIRO_INT_STATUS_UNSUPPORTED
;
1157 context
= _vg_context_lock (surface
->context
);
1158 status
= _vg_context_set_target (context
, surface
);
1160 _vg_context_unlock (context
);
1164 status
= setup_source (context
, source
);
1166 _vg_context_unlock (context
);
1170 status
= _cairo_surface_clipper_set_clip (&surface
->clipper
, clip
);
1171 if (unlikely (status
)) {
1172 _vg_context_unlock (context
);
1176 vg_path
.path
= vgCreatePath (VG_PATH_FORMAT_STANDARD
,
1180 VG_PATH_CAPABILITY_ALL
);
1181 vg_path
.ctm_inverse
= NULL
;
1183 _vg_path_from_cairo (&vg_path
, path
);
1187 vgSeti (VG_BLEND_MODE
, _vg_operator (op
));
1188 vgSetf (VG_FILL_RULE
, _vg_fill_rule_from_cairo (fill_rule
));
1189 vgSetf (VG_RENDERING_QUALITY
, _vg_rendering_quality_from_cairo (antialias
));
1191 vgSetPaint (context
->paint
, VG_FILL_PATH
);
1193 vgDrawPath (vg_path
.path
, VG_FILL_PATH
);
1195 vgDestroyPath (vg_path
.path
);
1197 _vg_context_unlock (context
);
1200 return CAIRO_STATUS_SUCCESS
;
1203 static cairo_int_status_t
1204 _vg_surface_paint (void *abstract_surface
,
1205 cairo_operator_t op
,
1206 const cairo_pattern_t
*source
,
1207 const cairo_clip_t
*clip
)
1209 cairo_vg_surface_t
*surface
= abstract_surface
;
1210 cairo_vg_context_t
*context
;
1211 cairo_status_t status
;
1213 if (op
== CAIRO_OPERATOR_DEST
)
1214 return CAIRO_STATUS_SUCCESS
;
1216 if (! _vg_is_supported_operator (op
))
1217 return CAIRO_INT_STATUS_UNSUPPORTED
;
1219 context
= _vg_context_lock (surface
->context
);
1220 status
= _vg_context_set_target (context
, surface
);
1222 _vg_context_unlock (context
);
1226 status
= setup_source (context
, source
);
1228 _vg_context_unlock (context
);
1232 status
= _cairo_surface_clipper_set_clip (&surface
->clipper
, clip
);
1233 if (unlikely (status
)) {
1234 _vg_context_unlock (context
);
1238 vgSeti (VG_BLEND_MODE
, _vg_operator (op
));
1239 vgSetPaint (context
->paint
, VG_FILL_PATH
);
1241 { /* creating a rectangular path that should cover the extent */
1243 VG_MOVE_TO_ABS
, VG_LINE_TO_ABS
,
1244 VG_LINE_TO_ABS
, VG_LINE_TO_ABS
,
1250 surface
->width
, surface
->height
,
1255 fullext
= vgCreatePath (VG_PATH_FORMAT_STANDARD
, VG_PATH_DATATYPE_F
,
1256 1,0,0,0, VG_PATH_CAPABILITY_ALL
);
1257 vgAppendPathData (fullext
, sizeof(segs
), segs
, data
);
1259 vgDrawPath (fullext
, VG_FILL_PATH
);
1261 vgDestroyPath (fullext
);
1264 _vg_context_unlock (context
);
1267 return CAIRO_STATUS_SUCCESS
;
1270 static cairo_int_status_t
1271 _vg_surface_mask (void *abstract_surface
,
1272 cairo_operator_t op
,
1273 const cairo_pattern_t
*source
,
1274 const cairo_pattern_t
*mask
,
1275 const cairo_clip_t
*clip
)
1277 cairo_vg_surface_t
*surface
= abstract_surface
;
1278 cairo_status_t status
;
1280 if (! _vg_is_supported_operator (op
))
1281 return CAIRO_INT_STATUS_UNSUPPORTED
;
1283 /* Handle paint-with-alpha to do fades cheaply */
1284 if (mask
->type
== CAIRO_PATTERN_TYPE_SOLID
) {
1285 cairo_solid_pattern_t
*solid
= (cairo_solid_pattern_t
*) mask
;
1286 cairo_vg_context_t
*context
= _vg_context_lock (surface
->context
);
1287 double alpha
= context
->alpha
;
1289 context
->alpha
= solid
->color
.alpha
;
1290 status
= _vg_surface_paint (abstract_surface
, op
, source
, clip
);
1291 context
->alpha
= alpha
;
1293 _vg_context_unlock (context
);
1298 return CAIRO_INT_STATUS_UNSUPPORTED
;
1302 _vg_surface_get_font_options (void *abstract_surface
,
1303 cairo_font_options_t
*options
)
1305 _cairo_font_options_init_default (options
);
1307 cairo_font_options_set_hint_metrics (options
, CAIRO_HINT_METRICS_ON
);
1308 _cairo_font_options_set_round_glyph_positions (options
, CAIRO_ROUND_GLYPH_POS_OFF
);
1311 static cairo_int_status_t
1312 _vg_surface_show_glyphs (void *abstract_surface
,
1313 cairo_operator_t op
,
1314 const cairo_pattern_t
*source
,
1315 cairo_glyph_t
*glyphs
,
1317 cairo_scaled_font_t
*scaled_font
,
1318 const cairo_clip_t
*clip
)
1320 cairo_status_t status
= CAIRO_STATUS_SUCCESS
;
1321 cairo_path_fixed_t path
;
1323 if (num_glyphs
<= 0)
1324 return CAIRO_STATUS_SUCCESS
;
1326 _cairo_path_fixed_init (&path
);
1328 /* XXX Glyph cache! OpenVG font support in 1.1? */
1330 status
= _cairo_scaled_font_glyph_path (scaled_font
,
1333 if (unlikely (status
))
1336 status
= _vg_surface_fill (abstract_surface
,
1338 CAIRO_FILL_RULE_WINDING
,
1339 CAIRO_GSTATE_TOLERANCE_DEFAULT
,
1340 CAIRO_ANTIALIAS_DEFAULT
,
1343 _cairo_path_fixed_fini (&path
);
1348 multiply_alpha (int alpha
, int color
)
1350 int temp
= alpha
* color
+ 0x80;
1351 return (temp
+ (temp
>> 8)) >> 8;
1355 premultiply_argb (uint8_t *data
,
1363 uint32_t *row
= (uint32_t *) data
;
1365 for (i
= 0; i
< width
; i
++) {
1366 uint32_t p
= row
[i
];
1372 } else if (alpha
!= 0xff) {
1373 uint8_t r
= multiply_alpha (alpha
, (p
>> 16) & 0xff);
1374 uint8_t g
= multiply_alpha (alpha
, (p
>> 8) & 0xff);
1375 uint8_t b
= multiply_alpha (alpha
, (p
>> 0) & 0xff);
1376 row
[i
] = (alpha
<< 24) | (r
<< 16) | (g
<< 8) | (b
<< 0);
1384 static cairo_int_status_t
1385 _vg_get_image (cairo_vg_surface_t
*surface
,
1387 int width
, int height
,
1388 cairo_image_surface_t
**image_out
)
1390 cairo_image_surface_t
*image
;
1391 pixman_image_t
*pixman_image
;
1392 pixman_format_code_t pixman_format
;
1393 cairo_bool_t needs_premultiply
;
1395 pixman_format
= _vg_format_to_pixman (surface
->format
,
1396 &needs_premultiply
);
1397 if (pixman_format
== 0)
1398 return CAIRO_INT_STATUS_UNSUPPORTED
;
1400 pixman_image
= pixman_image_create_bits (pixman_format
,
1403 if (unlikely (pixman_image
== NULL
))
1404 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
1409 vgGetImageSubData (surface
->image
,
1410 pixman_image_get_data (pixman_image
),
1411 pixman_image_get_stride (pixman_image
),
1413 x
, y
, width
, height
);
1415 image
= (cairo_image_surface_t
*)
1416 _cairo_image_surface_create_for_pixman_image (pixman_image
,
1418 if (unlikely (image
->base
.status
)) {
1419 pixman_image_unref (pixman_image
);
1420 return image
->base
.status
;
1423 if (needs_premultiply
)
1424 premultiply_argb (image
->data
, width
, height
, image
->stride
);
1427 return CAIRO_STATUS_SUCCESS
;
1430 static cairo_status_t
1431 _vg_surface_acquire_source_image (void *abstract_surface
,
1432 cairo_image_surface_t
**image_out
,
1435 cairo_vg_surface_t
*surface
= abstract_surface
;
1438 *image_extra
= NULL
;
1439 return _vg_get_image (surface
,
1440 0, 0, surface
->width
, surface
->height
,
1445 _vg_surface_release_source_image (void *abstract_surface
,
1446 cairo_image_surface_t
*image
,
1449 cairo_surface_destroy (&image
->base
);
1452 static cairo_status_t
1453 _vg_surface_finish (void *abstract_surface
)
1455 cairo_vg_surface_t
*surface
= abstract_surface
;
1456 cairo_vg_context_t
*context
= _vg_context_lock (surface
->context
);
1458 if (surface
->snapshot_cache_entry
.hash
) {
1459 _cairo_cache_remove (&context
->snapshot_cache
,
1460 &surface
->snapshot_cache_entry
);
1462 surface
->snapshot_cache_entry
.hash
= 0;
1465 _cairo_surface_clipper_reset (&surface
->clipper
);
1467 if (surface
->own_image
)
1468 vgDestroyImage (surface
->image
);
1470 _vg_context_destroy_target (context
, surface
);
1472 _vg_context_unlock (context
);
1473 _vg_context_destroy (context
);
1476 return CAIRO_STATUS_SUCCESS
;
1479 static const cairo_surface_backend_t cairo_vg_surface_backend
= {
1480 CAIRO_SURFACE_TYPE_VG
,
1483 _cairo_default_context_create
, /* XXX */
1485 _vg_surface_create_similar
,
1486 NULL
, /* create similar image */
1487 NULL
, /* map to image */
1488 NULL
, /* unmap image */
1490 _cairo_surface_default_source
,
1491 _vg_surface_acquire_source_image
,
1492 _vg_surface_release_source_image
,
1493 NULL
, /* snapshot */
1495 NULL
, /* copy_page */
1496 NULL
, /* show_page */
1498 _vg_surface_get_extents
,
1499 _vg_surface_get_font_options
, /* get_font_options */
1502 NULL
, /* mark dirty */
1508 NULL
, /* fill-stroke */
1509 _vg_surface_show_glyphs
,
1512 static cairo_surface_t
*
1513 _vg_surface_create_internal (cairo_vg_context_t
*context
,
1515 VGImageFormat format
,
1516 int width
, int height
)
1518 cairo_vg_surface_t
*surface
;
1520 surface
= malloc (sizeof (cairo_vg_surface_t
));
1521 if (unlikely (surface
== NULL
))
1522 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY
));
1524 surface
->context
= _vg_context_reference (context
);
1526 surface
->image
= image
;
1527 surface
->format
= format
;
1529 _cairo_surface_init (&surface
->base
,
1530 &cairo_vg_surface_backend
,
1532 _vg_format_to_content (format
));
1534 surface
->width
= width
;
1535 surface
->height
= height
;
1537 _cairo_surface_clipper_init (&surface
->clipper
,
1538 _vg_surface_clipper_intersect_clip_path
);
1540 surface
->snapshot_cache_entry
.hash
= 0;
1542 surface
->target_id
= 0;
1545 return &surface
->base
;
1549 cairo_vg_surface_create_for_image (cairo_vg_context_t
*context
,
1551 VGImageFormat format
,
1552 int width
, int height
)
1554 cairo_bool_t premult
;
1556 if (context
->status
)
1557 return _cairo_surface_create_in_error (context
->status
);
1559 if (image
== VG_INVALID_HANDLE
)
1560 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY
));
1561 if (_vg_format_to_pixman (format
, &premult
) == 0)
1562 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT
));
1564 return _vg_surface_create_internal (context
, image
, format
, width
, height
);
1568 cairo_vg_surface_create (cairo_vg_context_t
*context
,
1569 cairo_content_t content
,
1574 VGImageFormat format
;
1575 cairo_surface_t
*surface
;
1577 if (context
->status
)
1578 return _cairo_surface_create_in_error (context
->status
);
1580 if (! CAIRO_CONTENT_VALID (content
))
1581 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_CONTENT
));
1583 if (width
> vgGeti (VG_MAX_IMAGE_WIDTH
) ||
1584 height
> vgGeti (VG_MAX_IMAGE_HEIGHT
))
1586 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE
));
1590 format
= _vg_format_for_content (content
);
1591 image
= vgCreateImage (format
, width
, height
, VG_IMAGE_QUALITY_BETTER
);
1592 if (image
== VG_INVALID_HANDLE
)
1593 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY
));
1595 surface
= _vg_surface_create_internal (context
,
1596 image
, format
, width
, height
);
1597 if (unlikely (surface
->status
))
1600 ((cairo_vg_surface_t
*) surface
)->own_image
= TRUE
;
1603 slim_hidden_def (cairo_vg_surface_create
);
1606 cairo_vg_surface_get_image (cairo_surface_t
*abstract_surface
)
1608 cairo_vg_surface_t
*surface
;
1610 if (abstract_surface
->backend
!= &cairo_vg_surface_backend
) {
1611 _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH
);
1612 return VG_INVALID_HANDLE
;
1615 surface
= (cairo_vg_surface_t
*) abstract_surface
;
1616 return surface
->image
;
1620 cairo_vg_surface_get_width (cairo_surface_t
*abstract_surface
)
1622 cairo_vg_surface_t
*surface
;
1624 if (abstract_surface
->backend
!= &cairo_vg_surface_backend
) {
1625 _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH
);
1629 surface
= (cairo_vg_surface_t
*) abstract_surface
;
1630 return surface
->width
;
1634 cairo_vg_surface_get_height (cairo_surface_t
*abstract_surface
)
1636 cairo_vg_surface_t
*surface
;
1638 if (abstract_surface
->backend
!= &cairo_vg_surface_backend
) {
1639 _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH
);
1643 surface
= (cairo_vg_surface_t
*) abstract_surface
;
1644 return surface
->height
;
1648 cairo_vg_surface_get_format (cairo_surface_t
*abstract_surface
)
1650 cairo_vg_surface_t
*surface
;
1652 if (abstract_surface
->backend
!= &cairo_vg_surface_backend
) {
1653 _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH
);
1657 surface
= (cairo_vg_surface_t
*) abstract_surface
;
1658 return surface
->format
;
1661 /* GL specific context support :-(
1663 * OpenVG like cairo defers creation of surface (and the necessary
1664 * paraphernalia to the application.
1667 static const cairo_vg_context_t _vg_context_nil
= {
1668 CAIRO_STATUS_NO_MEMORY
,
1669 CAIRO_REFERENCE_COUNT_INVALID
1672 static const cairo_vg_context_t _vg_context_nil_invalid_visual
= {
1673 CAIRO_STATUS_INVALID_VISUAL
,
1674 CAIRO_REFERENCE_COUNT_INVALID
1677 #if CAIRO_HAS_GLX_FUNCTIONS
1680 static cairo_status_t
1681 glx_create_target (cairo_vg_context_t
*context
,
1682 cairo_vg_surface_t
*surface
)
1684 /* XXX hmm, magic required for creating an FBO points to VGImage! */
1685 return CAIRO_INT_STATUS_UNSUPPORTED
;
1688 static cairo_status_t
1689 glx_set_target (cairo_vg_context_t
*context
,
1690 cairo_vg_surface_t
*surface
)
1693 glXMakeContextCurrent (context
->display
,
1694 (GLXDrawable
) surface
->target_id
,
1695 (GLXDrawable
) surface
->target_id
,
1698 return CAIRO_INT_STATUS_UNSUPPORTED
;
1703 glx_destroy_target (cairo_vg_context_t
*context
,
1704 cairo_vg_surface_t
*surface
)
1708 cairo_vg_context_t
*
1709 cairo_vg_context_create_for_glx (Display
*dpy
, GLXContext ctx
)
1711 cairo_vg_context_t
*context
;
1712 cairo_status_t status
;
1714 context
= malloc (sizeof (*context
));
1715 if (unlikely (context
== NULL
))
1716 return (cairo_vg_context_t
*) &_vg_context_nil
;
1718 context
->display
= dpy
;
1719 context
->context
= ctx
;
1721 context
->create_target
= glx_create_target
;
1722 context
->set_target
= glx_set_target
;
1723 context
->destroy_target
= glx_destroy_target
;
1725 status
= _vg_context_init (context
);
1726 if (unlikely (status
)) {
1728 return (cairo_vg_context_t
*) &_vg_context_nil
;
1735 #if CAIRO_HAS_EGL_FUNCTIONS
1736 static cairo_status_t
1737 egl_create_target (cairo_vg_context_t
*context
,
1738 cairo_vg_surface_t
*surface
)
1740 EGLSurface
*egl_surface
;
1750 EGL_SURFACE_TYPE
, EGL_PBUFFER_BIT
,
1751 EGL_RENDERABLE_TYPE
, EGL_OPENVG_BIT
,
1754 pixman_format_code_t pixman_format
;
1756 int num_configs
= 0;
1757 cairo_bool_t needs_premultiply
;
1759 pixman_format
= _vg_format_to_pixman (surface
->format
, &needs_premultiply
);
1760 if (pixman_format
== 0)
1761 return CAIRO_INT_STATUS_UNSUPPORTED
;
1763 /* XXX no control over pixel ordering! */
1764 attribs
[RED
] = PIXMAN_FORMAT_R (pixman_format
);
1765 attribs
[GREEN
] = PIXMAN_FORMAT_G (pixman_format
);
1766 attribs
[BLUE
] = PIXMAN_FORMAT_B (pixman_format
);
1767 attribs
[ALPHA
] = PIXMAN_FORMAT_A (pixman_format
);
1769 if (! eglChooseConfig (context
->display
,
1771 &config
, 1, &num_configs
) ||
1774 fprintf(stderr
, "Error: eglChooseConfig() failed.\n");
1775 return CAIRO_INT_STATUS_UNSUPPORTED
;
1779 eglCreatePbufferFromClientBuffer (context
->display
,
1781 (EGLClientBuffer
) surface
->image
,
1784 surface
->target_id
= (unsigned long) egl_surface
;
1786 return CAIRO_STATUS_SUCCESS
;
1789 static cairo_status_t
1790 egl_set_target (cairo_vg_context_t
*context
,
1791 cairo_vg_surface_t
*surface
)
1793 if (! eglMakeCurrent (context
->display
,
1794 (EGLSurface
*) surface
->target_id
,
1795 (EGLSurface
*) surface
->target_id
,
1798 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
1801 return CAIRO_STATUS_SUCCESS
;
1805 egl_destroy_target (cairo_vg_context_t
*context
,
1806 cairo_vg_surface_t
*surface
)
1808 eglDestroySurface (context
->display
,
1809 (EGLSurface
*) surface
->target_id
);
1812 cairo_vg_context_t
*
1813 cairo_vg_context_create_for_egl (EGLDisplay egl_display
,
1814 EGLContext egl_context
)
1816 cairo_vg_context_t
*context
;
1817 cairo_status_t status
;
1819 context
= malloc (sizeof (*context
));
1820 if (unlikely (context
== NULL
))
1821 return (cairo_vg_context_t
*) &_vg_context_nil
;
1823 status
= _vg_context_init (context
);
1824 if (unlikely (status
)) {
1826 return (cairo_vg_context_t
*) &_vg_context_nil
;
1829 context
->display
= egl_display
;
1830 context
->context
= egl_context
;
1832 context
->create_target
= egl_create_target
;
1833 context
->set_target
= egl_set_target
;
1834 context
->destroy_target
= egl_destroy_target
;
1841 cairo_vg_context_status (cairo_vg_context_t
*context
)
1843 return context
->status
;
1847 cairo_vg_context_destroy (cairo_vg_context_t
*context
)
1849 if (context
== NULL
|| CAIRO_REFERENCE_COUNT_IS_INVALID (&context
->ref_count
))
1852 _vg_context_destroy (context
);