Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  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
  3.  *
  4.  * Copyright © 2008 Opened Hand Ltd.
  5.  * Copyright © 2009 Chris Wilson
  6.  *
  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.
  14.  *
  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
  20.  *
  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/
  25.  *
  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.
  29.  *
  30.  * Contributor(s):
  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>
  35.  */
  36.  
  37. #include "cairoint.h"
  38.  
  39. #include "cairo-vg.h"
  40.  
  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"
  48.  
  49. #include <pixman.h>
  50. #include <VG/openvg.h>
  51.  
  52. //#define OPENVG_DEBUG
  53.  
  54. /*
  55.  * Work that needs to be done:
  56.  *  - Glyph cache / proper font support
  57.  *
  58.  *  - First-class paths
  59.  *    Paths are expensive for OpenVG, reuse paths whenever possible.
  60.  *    So add a path cache, and first class paths!
  61.  */
  62.  
  63. typedef struct _cairo_vg_surface cairo_vg_surface_t;
  64.  
  65. /* XXX need GL specific context control. :( */
  66. struct _cairo_vg_context {
  67.     cairo_status_t status;
  68.     cairo_reference_count_t ref_count;
  69.  
  70.     unsigned long target_id;
  71.  
  72.     VGPaint             paint;
  73.     cairo_vg_surface_t *source;
  74.     double              alpha;
  75.  
  76.     cairo_cache_t snapshot_cache;
  77.  
  78.     void *display;
  79.     void *context;
  80.  
  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 *);
  86. };
  87.  
  88. struct _cairo_vg_surface {
  89.     cairo_surface_t base;
  90.  
  91.     cairo_vg_context_t *context;
  92.  
  93.     VGImage         image;
  94.     VGImageFormat   format;
  95.     int             width;
  96.     int             height;
  97.     cairo_bool_t    own_image;
  98.  
  99.     cairo_cache_entry_t snapshot_cache_entry;
  100.  
  101.     cairo_surface_clipper_t clipper;
  102.  
  103.     unsigned long target_id;
  104. };
  105.  
  106. static const cairo_surface_backend_t cairo_vg_surface_backend;
  107.  
  108. slim_hidden_proto (cairo_vg_surface_create);
  109.  
  110. static cairo_surface_t *
  111. _vg_surface_create_internal (cairo_vg_context_t *context,
  112.                              VGImage image,
  113.                              VGImageFormat format,
  114.                              int width, int height);
  115.  
  116. static cairo_vg_context_t *
  117. _vg_context_reference (cairo_vg_context_t *context)
  118. {
  119.     assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&context->ref_count));
  120.  
  121.     _cairo_reference_count_inc (&context->ref_count);
  122.  
  123.     return context;
  124. }
  125.  
  126. static cairo_vg_context_t *
  127. _vg_context_lock (cairo_vg_context_t *context)
  128. {
  129.     /* XXX if we need to add locking, then it has to be recursive */
  130.     return context;
  131. }
  132.  
  133. static cairo_int_status_t
  134. _vg_context_set_target (cairo_vg_context_t *context,
  135.                         cairo_vg_surface_t *surface)
  136. {
  137.     cairo_status_t status;
  138.  
  139.     if (surface->target_id == 0) {
  140.         status = context->create_target (context, surface);
  141.         if (unlikely (status))
  142.             return status;
  143.     }
  144.  
  145.     if (context->target_id == surface->target_id)
  146.         return CAIRO_STATUS_SUCCESS;
  147.  
  148.     context->target_id = surface->target_id;
  149.  
  150.     return context->set_target (context, surface);
  151. }
  152.  
  153. static void
  154. _vg_context_destroy_target (cairo_vg_context_t *context,
  155.                             cairo_vg_surface_t *surface)
  156. {
  157.     if (surface->target_id == 0)
  158.         return;
  159.  
  160.     if (context->target_id == surface->target_id)
  161.         context->set_target (context, NULL);
  162.  
  163.     context->destroy_target (context, surface);
  164. }
  165.  
  166. static cairo_bool_t
  167. _vg_snapshot_cache_can_remove (const void *entry)
  168. {
  169.     return TRUE;
  170. }
  171.  
  172. static void
  173. _vg_snapshot_cache_remove (void *cache_entry)
  174. {
  175.     cairo_vg_surface_t *surface = cairo_container_of (cache_entry,
  176.                                                       cairo_vg_surface_t,
  177.                                                       snapshot_cache_entry);
  178.     surface->snapshot_cache_entry.hash = 0;
  179.     cairo_surface_destroy (&surface->base);
  180. }
  181.  
  182. static cairo_status_t
  183. _vg_context_init (cairo_vg_context_t *context)
  184. {
  185.     cairo_status_t status;
  186.  
  187.     context->status = CAIRO_STATUS_SUCCESS;
  188.     CAIRO_REFERENCE_COUNT_INIT (&context->ref_count, 1);
  189.  
  190.     status = _cairo_cache_init (&context->snapshot_cache,
  191.                                 NULL,
  192.                                 _vg_snapshot_cache_can_remove,
  193.                                 _vg_snapshot_cache_remove,
  194.                                 16*1024*1024);
  195.     if (unlikely (status))
  196.         return status;
  197.  
  198.     context->target_id = 0;
  199.     context->source = NULL;
  200.     context->alpha = 1.0;
  201.  
  202.     context->paint = vgCreatePaint ();
  203.     vgLoadIdentity ();
  204.  
  205.     return CAIRO_STATUS_SUCCESS;
  206. }
  207.  
  208. static void
  209. _vg_context_destroy (cairo_vg_context_t *context)
  210. {
  211.     assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&context->ref_count));
  212.  
  213.     if (! _cairo_reference_count_dec_and_test (&context->ref_count))
  214.         return;
  215.  
  216.     if (context->paint != VG_INVALID_HANDLE)
  217.         vgDestroyPaint (context->paint);
  218.  
  219.     _cairo_cache_fini (&context->snapshot_cache);
  220.     free (context);
  221. }
  222.  
  223. static void
  224. _vg_context_unlock (cairo_vg_context_t *context)
  225. {
  226. }
  227.  
  228. #ifdef OPENVG_DEBUG
  229. static void check_vg_errors(const char*function,int line)
  230. {
  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);
  235.     }
  236.  
  237. }
  238. #define CHECK_VG_ERRORS() check_vg_errors(__FILE__,__LINE__)
  239. #else
  240. #define CHECK_VG_ERRORS() do{}while(0)
  241. #endif //OPENVG_DEBUG
  242.  
  243. static pixman_format_code_t
  244. _vg_format_to_pixman (VGImageFormat format,
  245.                       cairo_bool_t *needs_premult_fixup)
  246. {
  247.     *needs_premult_fixup = FALSE;
  248.     switch (format) {
  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;
  265.  
  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;
  275.  
  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;
  286.  
  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;
  296.     default: return 0;
  297.     }
  298. }
  299.  
  300. static pixman_format_code_t
  301. _vg_format_to_content (VGImageFormat format)
  302. {
  303.     /* XXX could use more simple bit tests */
  304.     switch (format) {
  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;
  321.  
  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;
  331.  
  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;
  342.  
  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;
  352.     default: return 0;
  353.     }
  354. }
  355.  
  356. static VGImageFormat
  357. _vg_format_from_pixman (pixman_format_code_t format)
  358. {
  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
  372.     default: return 0;
  373.     }
  374. }
  375.  
  376. static VGImageFormat
  377. _vg_format_for_content (cairo_content_t content)
  378. {
  379.     switch (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
  384.     }
  385. }
  386.  
  387. static cairo_surface_t *
  388. _vg_surface_create_similar (void            *abstract_surface,
  389.                             cairo_content_t  content,
  390.                             int              width,
  391.                             int              height)
  392. {
  393.     cairo_vg_surface_t *surface = abstract_surface;
  394.  
  395.     if (width > vgGeti (VG_MAX_IMAGE_WIDTH) ||
  396.         height > vgGeti (VG_MAX_IMAGE_HEIGHT))
  397.     {
  398.         return NULL;
  399.     }
  400.  
  401.     return cairo_vg_surface_create (surface->context, content, width, height);
  402. }
  403.  
  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,
  408.                                          double              tolerance,
  409.                                          cairo_antialias_t   antialias)
  410. {
  411.     cairo_vg_surface_t *surface = cairo_container_of (clipper,
  412.                                                       cairo_vg_surface_t,
  413.                                                       clipper);
  414.     cairo_vg_surface_t *mask;
  415.     cairo_status_t status;
  416.  
  417.     if (path == NULL) {
  418.         vgMask (VG_INVALID_HANDLE,
  419.                 VG_FILL_MASK, 0, 0, surface->width, surface->height);
  420.         vgSeti (VG_MASKING, VG_FALSE);
  421.         CHECK_VG_ERRORS();
  422.         return CAIRO_STATUS_SUCCESS;
  423.     }
  424.  
  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;
  432.  
  433.     status = _cairo_surface_fill (&mask->base,
  434.                                   CAIRO_OPERATOR_SOURCE,
  435.                                   &_cairo_pattern_white.base,
  436.                                   path, fill_rule, tolerance, antialias,
  437.                                   NULL);
  438.     if (status) {
  439.         cairo_surface_destroy (&mask->base);
  440.         return status;
  441.     }
  442.  
  443.     vgSeti (VG_MASKING, VG_TRUE);
  444.     vgMask (mask->image, VG_INTERSECT_MASK, 0, 0, mask->width, mask->height);
  445.  
  446.     cairo_surface_destroy (&mask->base);
  447.  
  448.     CHECK_VG_ERRORS();
  449.     return CAIRO_STATUS_SUCCESS;
  450. }
  451.  
  452. static cairo_bool_t
  453. _vg_surface_get_extents (void                  *abstract_surface,
  454.                          cairo_rectangle_int_t *extents)
  455. {
  456.     cairo_vg_surface_t *surface = abstract_surface;
  457.  
  458.     extents->x = 0;
  459.     extents->y = 0;
  460.     extents->width  = surface->width;
  461.     extents->height = surface->height;
  462.  
  463.     return TRUE;
  464. }
  465.  
  466. #define MAX_SEG  16  /* max number of knots to upload in a batch */
  467.  
  468. typedef struct _vg_path {
  469.     VGPath path;
  470.     const cairo_matrix_t *ctm_inverse;
  471.  
  472.     VGubyte gseg[MAX_SEG];
  473.     VGfloat gdata[MAX_SEG*3*2];
  474.     int dcount;
  475.     int scount;
  476. } vg_path_t;
  477.  
  478. static cairo_status_t
  479. _vg_move_to (void          *closure,
  480.              const cairo_point_t *point)
  481. {
  482.     vg_path_t *path = closure;
  483.     double x = _cairo_fixed_to_double (point->x);
  484.     double y = _cairo_fixed_to_double (point->y);
  485.  
  486.     if (path->ctm_inverse)
  487.         cairo_matrix_transform_point (path->ctm_inverse, &x, &y);
  488.  
  489.     path->gseg[path->scount++] = VG_MOVE_TO;
  490.     path->gdata[path->dcount++] = x;
  491.     path->gdata[path->dcount++] = y;
  492.  
  493.     if (path->scount >= MAX_SEG-1) {
  494.         vgAppendPathData (path->path, path->scount, path->gseg, path->gdata);
  495.         path->scount = 0;
  496.         path->dcount = 0;
  497.     }
  498.  
  499.     CHECK_VG_ERRORS();
  500.     return CAIRO_STATUS_SUCCESS;
  501. }
  502.  
  503. static cairo_status_t
  504. _vg_line_to (void          *closure,
  505.              const cairo_point_t *point)
  506. {
  507.     vg_path_t *path = closure;
  508.     double x = _cairo_fixed_to_double (point->x);
  509.     double y = _cairo_fixed_to_double (point->y);
  510.  
  511.     if (path->ctm_inverse)
  512.         cairo_matrix_transform_point (path->ctm_inverse, &x, &y);
  513.  
  514.     path->gseg[path->scount++] = VG_LINE_TO;
  515.     path->gdata[path->dcount++] = x;
  516.     path->gdata[path->dcount++] = y;
  517.  
  518.     if (path->scount >= MAX_SEG-1) {
  519.         vgAppendPathData (path->path, path->scount, path->gseg, path->gdata);
  520.         path->scount = 0;
  521.         path->dcount = 0;
  522.     }
  523.  
  524.     CHECK_VG_ERRORS();
  525.     return CAIRO_STATUS_SUCCESS;
  526. }
  527.  
  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)
  533. {
  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);
  541.  
  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);
  546.     }
  547.  
  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;
  555.  
  556.     if (path->scount >= MAX_SEG-1) {
  557.         vgAppendPathData(path->path, path->scount, path->gseg, path->gdata);
  558.         path->scount = 0;
  559.         path->dcount = 0;
  560.     }
  561.  
  562.     CHECK_VG_ERRORS();
  563.     return CAIRO_STATUS_SUCCESS;
  564. }
  565.  
  566. static cairo_status_t
  567. _vg_close_path (void *closure)
  568. {
  569.     vg_path_t *path = closure;
  570.  
  571.     path->gseg[path->scount++] = VG_CLOSE_PATH;
  572.  
  573.     if (path->scount >= MAX_SEG-1) {
  574.         vgAppendPathData (path->path, path->scount, path->gseg, path->gdata);
  575.         path->scount = 0;
  576.         path->dcount = 0;
  577.     }
  578.  
  579.     CHECK_VG_ERRORS();
  580.     return CAIRO_STATUS_SUCCESS;
  581. }
  582.  
  583. static void
  584. _vg_path_from_cairo (vg_path_t    *vg_path,
  585.                      const cairo_path_fixed_t *path)
  586. {
  587.     cairo_status_t status;
  588.  
  589.     vg_path->scount = 0;
  590.     vg_path->dcount = 0;
  591.  
  592.     status = _cairo_path_fixed_interpret (path,
  593.                                           _vg_move_to,
  594.                                           _vg_line_to,
  595.                                           _vg_curve_to,
  596.                                           _vg_close_path,
  597.                                           vg_path);
  598.     assert (status == CAIRO_STATUS_SUCCESS);
  599.  
  600.     vgAppendPathData (vg_path->path,
  601.                       vg_path->scount, vg_path->gseg, vg_path->gdata);
  602.     CHECK_VG_ERRORS();
  603. }
  604.  
  605. static cairo_bool_t
  606. _vg_is_supported_operator (cairo_operator_t op)
  607. {
  608.     switch ((int) 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:
  615.         return TRUE;
  616.  
  617.     default:
  618.         return FALSE;
  619.     }
  620. }
  621.  
  622. static VGBlendMode
  623. _vg_operator (cairo_operator_t op)
  624. {
  625.     switch ((int) op) {
  626.     case CAIRO_OPERATOR_SOURCE:
  627.         return VG_BLEND_SRC;
  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;
  638.     default:
  639.         ASSERT_NOT_REACHED;
  640.         return VG_BLEND_SRC_OVER;
  641.     }
  642. }
  643.  
  644. static VGFillRule
  645. _vg_fill_rule_from_cairo (cairo_fill_rule_t rule)
  646. {
  647.     switch (rule) {
  648.     case CAIRO_FILL_RULE_EVEN_ODD: return VG_EVEN_ODD;
  649.     case CAIRO_FILL_RULE_WINDING: return VG_NON_ZERO;
  650.     }
  651.  
  652.     ASSERT_NOT_REACHED;
  653.     return VG_NON_ZERO;
  654. }
  655.  
  656. static VGRenderingQuality
  657. _vg_rendering_quality_from_cairo (cairo_antialias_t aa)
  658. {
  659.     switch (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;
  665.  
  666.     case CAIRO_ANTIALIAS_GRAY:
  667.     case CAIRO_ANTIALIAS_FAST:
  668.         return VG_RENDERING_QUALITY_FASTER;
  669.  
  670.     case CAIRO_ANTIALIAS_NONE:
  671.         return VG_RENDERING_QUALITY_NONANTIALIASED;
  672.     }
  673.  
  674.     ASSERT_NOT_REACHED;
  675.     return VG_RENDERING_QUALITY_BETTER;
  676. }
  677.  
  678. static VGCapStyle
  679. _vg_line_cap_from_cairo (cairo_line_cap_t cap)
  680. {
  681.     switch (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;
  685.     }
  686.  
  687.     ASSERT_NOT_REACHED;
  688.     return VG_CAP_BUTT;
  689. }
  690.  
  691. static VGJoinStyle
  692. _vg_line_join_from_cairo (cairo_line_join_t join)
  693. {
  694.     switch (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;
  698.     }
  699.  
  700.     ASSERT_NOT_REACHED;
  701.     return VG_JOIN_MITER;
  702. }
  703.  
  704. static void
  705. _vg_matrix_from_cairo (VGfloat *dst, const cairo_matrix_t *src)
  706. {
  707.     dst[0] = /* sx  */ src->xx;
  708.     dst[1] = /* shy */ src->yx;
  709.     dst[2] = /* w0  */ 0;
  710.     dst[3] = /* shx */ src->xy;
  711.     dst[4] = /* sy  */ src->yy;
  712.     dst[5] = /* w1  */ 0;
  713.     dst[6] = /* tx  */ src->x0;
  714.     dst[7] = /* ty  */ src->y0;
  715.     dst[8] = /* w2  */ 0;
  716. }
  717.  
  718. static cairo_status_t
  719. _vg_setup_gradient_stops (cairo_vg_context_t *context,
  720.                           const cairo_gradient_pattern_t *pattern)
  721. {
  722.     VGint numstops = pattern->n_stops;
  723.     VGfloat *stops, stack_stops[CAIRO_STACK_ARRAY_LENGTH (VGfloat)];
  724.     int i;
  725.  
  726.     if (numstops*5 < ARRAY_LENGTH (stack_stops)) {
  727.         stops = stack_stops;
  728.     } else {
  729.         stops = _cairo_malloc_ab (numstops, 5*sizeof (VGfloat));
  730.         if (unlikely (stops == NULL))
  731.             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  732.     }
  733.  
  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;
  740.     }
  741.  
  742.     vgSetParameterfv (context->paint,
  743.                       VG_PAINT_COLOR_RAMP_STOPS, numstops * 5, stops);
  744.  
  745.     if (stops != stack_stops)
  746.         free (stops);
  747.  
  748.     CHECK_VG_ERRORS();
  749.     return CAIRO_STATUS_SUCCESS;
  750. }
  751.  
  752. static void
  753. _vg_set_source_matrix (const cairo_pattern_t *pat)
  754. {
  755.     cairo_matrix_t mat;
  756.     cairo_status_t status;
  757.     VGfloat vmat[9];
  758.  
  759.     mat = pat->matrix;
  760.     status = cairo_matrix_invert (&mat);
  761.     assert (status == CAIRO_STATUS_SUCCESS);
  762.  
  763.     _vg_matrix_from_cairo (vmat, &mat);
  764.  
  765.     vgSeti (VG_MATRIX_MODE, VG_MATRIX_FILL_PAINT_TO_USER);
  766.     vgLoadMatrix (vmat);
  767.     vgSeti (VG_MATRIX_MODE, VG_MATRIX_STROKE_PAINT_TO_USER);
  768.     vgLoadMatrix (vmat);
  769.     vgSeti (VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
  770.  
  771.     CHECK_VG_ERRORS();
  772. }
  773.  
  774. static cairo_status_t
  775. _vg_setup_linear_source (cairo_vg_context_t *context,
  776.                          const cairo_linear_pattern_t *lpat)
  777. {
  778.     VGfloat linear[4];
  779.  
  780.     linear[0] = lpat->pd1.x;
  781.     linear[1] = lpat->pd1.y;
  782.     linear[2] = lpat->pd2.x;
  783.     linear[3] = lpat->pd2.y;
  784.  
  785.     vgSetParameteri (context->paint,
  786.                      VG_PAINT_COLOR_RAMP_SPREAD_MODE,
  787.                      VG_COLOR_RAMP_SPREAD_PAD);
  788.     vgSetParameteri (context->paint,
  789.                      VG_PAINT_TYPE,
  790.                      VG_PAINT_TYPE_LINEAR_GRADIENT);
  791.     vgSetParameterfv (context->paint,
  792.                       VG_PAINT_LINEAR_GRADIENT, 4, linear);
  793.  
  794.     _vg_set_source_matrix (&lpat->base.base);
  795.  
  796.     CHECK_VG_ERRORS();
  797.     return _vg_setup_gradient_stops (context, &lpat->base);
  798.  
  799. }
  800.  
  801. static cairo_status_t
  802. _vg_setup_radial_source (cairo_vg_context_t *context,
  803.                          const cairo_radial_pattern_t *rpat)
  804. {
  805.     VGfloat radial[5];
  806.  
  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;
  812.  
  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);
  819.  
  820.     _vg_set_source_matrix (&rpat->base.base);
  821.  
  822.     /* FIXME: copy/adapt fixes from SVG backend to add inner radius */
  823.  
  824.     CHECK_VG_ERRORS();
  825.     return _vg_setup_gradient_stops (context, &rpat->base);
  826. }
  827.  
  828. static cairo_status_t
  829. _vg_setup_solid_source (cairo_vg_context_t *context,
  830.                         const cairo_solid_pattern_t *spat)
  831. {
  832.     VGfloat color[] = {
  833.         spat->color.red,
  834.         spat->color.green,
  835.         spat->color.blue,
  836.         spat->color.alpha * context->alpha
  837.     };
  838.  
  839.     vgSetParameteri (context->paint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
  840.     vgSetParameterfv (context->paint, VG_PAINT_COLOR, 4, color);
  841.  
  842.     CHECK_VG_ERRORS();
  843.     return CAIRO_STATUS_SUCCESS;
  844. }
  845.  
  846. static cairo_vg_surface_t *
  847. _vg_clone_recording_surface (cairo_vg_context_t *context,
  848.                         cairo_surface_t *surface)
  849. {
  850.     VGImage vg_image;
  851.     VGImageFormat format;
  852.     cairo_status_t status;
  853.     cairo_rectangle_int_t extents;
  854.     cairo_vg_surface_t *clone;
  855.  
  856.     status = _cairo_surface_get_extents (surface, &extents);
  857.     if (status)
  858.         return NULL;
  859.  
  860.     if (extents.width > vgGeti (VG_MAX_IMAGE_WIDTH) ||
  861.         extents.height > vgGeti (VG_MAX_IMAGE_HEIGHT))
  862.     {
  863.         return NULL;
  864.     }
  865.  
  866.     format = _vg_format_for_content (surface->content);
  867.  
  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);
  876.  
  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);
  881.     }
  882.  
  883.     return clone;
  884. }
  885.  
  886. static cairo_vg_surface_t *
  887. _vg_clone_image_surface (cairo_vg_context_t *context,
  888.                          cairo_surface_t *surface)
  889. {
  890.     cairo_image_surface_t *image;
  891.     void *image_extra;
  892.     cairo_status_t status;
  893.     VGImage vg_image;
  894.     VGImageFormat format;
  895.     cairo_rectangle_int_t extents;
  896.     cairo_vg_surface_t *clone;
  897.  
  898.     if (surface->backend->acquire_source_image == NULL)
  899.         return NULL;
  900.  
  901.     status = _cairo_surface_get_extents (surface, &extents);
  902.     if (status)
  903.         return NULL;
  904.  
  905.     if (extents.width > vgGeti (VG_MAX_IMAGE_WIDTH) ||
  906.         extents.height > vgGeti (VG_MAX_IMAGE_HEIGHT))
  907.     {
  908.         return NULL;
  909.     }
  910.  
  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);
  915.  
  916.     format = _vg_format_from_pixman (image->pixman_format);
  917.     if (format == 0)
  918.         format = _vg_format_for_content (image->base.content);
  919.  
  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))
  928.         return clone;
  929.  
  930.     vgImageSubData (clone->image,
  931.                     image->data, image->stride,
  932.                     format, 0, 0, image->width, image->height);
  933.  
  934.     _cairo_surface_release_source_image (surface, image, image_extra);
  935.  
  936.     return clone;
  937. }
  938.  
  939. static void
  940. _vg_surface_remove_from_cache (cairo_surface_t *abstract_surface)
  941. {
  942.     cairo_vg_surface_t *surface = (cairo_vg_surface_t *) abstract_surface;
  943.  
  944.     if (surface->snapshot_cache_entry.hash) {
  945.         cairo_vg_context_t *context;
  946.  
  947.         context = _vg_context_lock (surface->context);
  948.         _cairo_cache_remove (&context->snapshot_cache,
  949.                              &surface->snapshot_cache_entry);
  950.         _vg_context_unlock (context);
  951.  
  952.         surface->snapshot_cache_entry.hash = 0;
  953.     }
  954. }
  955.  
  956. static cairo_status_t
  957. _vg_setup_surface_source (cairo_vg_context_t *context,
  958.                           const cairo_surface_pattern_t *spat)
  959. {
  960.     cairo_surface_t *snapshot;
  961.     cairo_vg_surface_t *clone;
  962.     cairo_status_t status;
  963.  
  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);
  968.         goto DONE;
  969.     }
  970.  
  971.     if (_cairo_surface_is_recording (spat->surface))
  972.         clone = _vg_clone_recording_surface (context, spat->surface);
  973.     else
  974.         clone = _vg_clone_image_surface (context, spat->surface);
  975.     if (clone == NULL)
  976.         return CAIRO_INT_STATUS_UNSUPPORTED;
  977.     if (unlikely (clone->base.status))
  978.         return clone->base.status;
  979.  
  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);
  986.         return status;
  987.     }
  988.  
  989.     _cairo_surface_attach_snapshot (spat->surface, &clone->base,
  990.                                     _vg_surface_remove_from_cache);
  991.  
  992. DONE:
  993.     cairo_surface_destroy (&context->source->base);
  994.     context->source = clone;
  995.  
  996.     vgSetParameteri (context->paint, VG_PAINT_TYPE, VG_PAINT_TYPE_PATTERN);
  997.  
  998.     switch (spat->base.extend) {
  999.     case CAIRO_EXTEND_PAD:
  1000.         vgSetParameteri (context->paint,
  1001.                          VG_PAINT_PATTERN_TILING_MODE,
  1002.                          VG_TILE_PAD);
  1003.         break;
  1004.  
  1005.     case CAIRO_EXTEND_NONE:
  1006.         vgSetParameteri (context->paint,
  1007.                          VG_PAINT_PATTERN_TILING_MODE,
  1008.                          VG_TILE_FILL);
  1009.         {
  1010.             VGfloat color[] = {0,0,0,0};
  1011.             vgSetfv (VG_TILE_FILL_COLOR, 4, color);
  1012.         }
  1013.         break;
  1014.  
  1015.     case CAIRO_EXTEND_REPEAT:
  1016.         vgSetParameteri (context->paint,
  1017.                          VG_PAINT_PATTERN_TILING_MODE,
  1018.                          VG_TILE_REPEAT);
  1019.         break;
  1020.  
  1021.     default:
  1022.         ASSERT_NOT_REACHED;
  1023.     case CAIRO_EXTEND_REFLECT:
  1024.         vgSetParameteri (context->paint,
  1025.                          VG_PAINT_PATTERN_TILING_MODE,
  1026.                          VG_TILE_REFLECT);
  1027.         break;
  1028.     }
  1029.     vgPaintPattern (context->paint, context->source->image);
  1030.  
  1031.     _vg_set_source_matrix (&spat->base);
  1032.  
  1033.     CHECK_VG_ERRORS();
  1034.     return CAIRO_STATUS_SUCCESS;
  1035. }
  1036.  
  1037. static cairo_status_t
  1038. setup_source (cairo_vg_context_t *context,
  1039.               const cairo_pattern_t *source)
  1040. {
  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);
  1054.     default:
  1055.         ASSERT_NOT_REACHED;
  1056.         return CAIRO_INT_STATUS_UNSUPPORTED;
  1057.     }
  1058. }
  1059.  
  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,
  1068.                     double                      tolerance,
  1069.                     cairo_antialias_t           antialias,
  1070.                     const cairo_clip_t         *clip)
  1071. {
  1072.     cairo_vg_surface_t *surface = abstract_surface;
  1073.     cairo_vg_context_t *context;
  1074.     cairo_status_t status;
  1075.     VGfloat state[9];
  1076.     VGfloat strokeTransform[9];
  1077.     vg_path_t vg_path;
  1078.  
  1079.     if (! _vg_is_supported_operator (op))
  1080.         return CAIRO_INT_STATUS_UNSUPPORTED;
  1081.  
  1082.     context = _vg_context_lock (surface->context);
  1083.     status = _vg_context_set_target (context, surface);
  1084.     if (status) {
  1085.         _vg_context_unlock (context);
  1086.         return status;
  1087.     }
  1088.  
  1089.     status = setup_source (context, source);
  1090.     if (status) {
  1091.         _vg_context_unlock (context);
  1092.         return status;
  1093.     }
  1094.  
  1095.     status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
  1096.     if (unlikely (status)) {
  1097.         _vg_context_unlock (context);
  1098.         return status;
  1099.     }
  1100.  
  1101.     vg_path.path = vgCreatePath (VG_PATH_FORMAT_STANDARD,
  1102.                                  VG_PATH_DATATYPE_F,
  1103.                                  1, 0, 0, 0,
  1104.                                  VG_PATH_CAPABILITY_ALL);
  1105.  
  1106.     vgGetMatrix (state);
  1107.     _vg_matrix_from_cairo (strokeTransform, ctm);
  1108.     vgMultMatrix (strokeTransform);
  1109.  
  1110.     vg_path.ctm_inverse = ctm_inverse;
  1111.  
  1112.     _vg_path_from_cairo (&vg_path, path);
  1113.  
  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));
  1119.  
  1120.     vgSeti (VG_BLEND_MODE, _vg_operator (op));
  1121.  
  1122.     vgSetPaint (context->paint, VG_STROKE_PATH);
  1123.  
  1124.     vgDrawPath (vg_path.path, VG_STROKE_PATH);
  1125.  
  1126.     vgDestroyPath (vg_path.path);
  1127.  
  1128.     vgLoadMatrix (state);
  1129.  
  1130.     CHECK_VG_ERRORS();
  1131.     _vg_context_unlock (context);
  1132.  
  1133.     return CAIRO_STATUS_SUCCESS;
  1134. }
  1135.  
  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,
  1142.                   double                    tolerance,
  1143.                   cairo_antialias_t         antialias,
  1144.                   const cairo_clip_t       *clip)
  1145. {
  1146.     cairo_vg_surface_t *surface = abstract_surface;
  1147.     cairo_vg_context_t *context;
  1148.     cairo_status_t status;
  1149.     vg_path_t vg_path;
  1150.  
  1151.     if (op == CAIRO_OPERATOR_DEST)
  1152.         return CAIRO_STATUS_SUCCESS;
  1153.  
  1154.     if (! _vg_is_supported_operator (op))
  1155.         return CAIRO_INT_STATUS_UNSUPPORTED;
  1156.  
  1157.     context = _vg_context_lock (surface->context);
  1158.     status = _vg_context_set_target (context, surface);
  1159.     if (status) {
  1160.         _vg_context_unlock (context);
  1161.         return status;
  1162.     }
  1163.  
  1164.     status = setup_source (context, source);
  1165.     if (status) {
  1166.         _vg_context_unlock (context);
  1167.         return status;
  1168.     }
  1169.  
  1170.     status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
  1171.     if (unlikely (status)) {
  1172.         _vg_context_unlock (context);
  1173.         return status;
  1174.     }
  1175.  
  1176.     vg_path.path = vgCreatePath (VG_PATH_FORMAT_STANDARD,
  1177.                                  VG_PATH_DATATYPE_F,
  1178.                                  1, 0,
  1179.                                  0, 0,
  1180.                                  VG_PATH_CAPABILITY_ALL);
  1181.     vg_path.ctm_inverse = NULL;
  1182.  
  1183.     _vg_path_from_cairo (&vg_path, path);
  1184.  
  1185.     /* XXX tolerance */
  1186.  
  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));
  1190.  
  1191.     vgSetPaint (context->paint, VG_FILL_PATH);
  1192.  
  1193.     vgDrawPath (vg_path.path, VG_FILL_PATH);
  1194.  
  1195.     vgDestroyPath (vg_path.path);
  1196.  
  1197.     _vg_context_unlock (context);
  1198.  
  1199.     CHECK_VG_ERRORS();
  1200.     return CAIRO_STATUS_SUCCESS;
  1201. }
  1202.  
  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)
  1208. {
  1209.     cairo_vg_surface_t *surface = abstract_surface;
  1210.     cairo_vg_context_t *context;
  1211.     cairo_status_t status;
  1212.  
  1213.     if (op == CAIRO_OPERATOR_DEST)
  1214.         return CAIRO_STATUS_SUCCESS;
  1215.  
  1216.     if (! _vg_is_supported_operator (op))
  1217.         return CAIRO_INT_STATUS_UNSUPPORTED;
  1218.  
  1219.     context = _vg_context_lock (surface->context);
  1220.     status = _vg_context_set_target (context, surface);
  1221.     if (status) {
  1222.         _vg_context_unlock (context);
  1223.         return status;
  1224.     }
  1225.  
  1226.     status = setup_source (context, source);
  1227.     if (status) {
  1228.         _vg_context_unlock (context);
  1229.         return status;
  1230.     }
  1231.  
  1232.     status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
  1233.     if (unlikely (status)) {
  1234.         _vg_context_unlock (context);
  1235.         return status;
  1236.     }
  1237.  
  1238.     vgSeti (VG_BLEND_MODE, _vg_operator (op));
  1239.     vgSetPaint (context->paint, VG_FILL_PATH);
  1240.  
  1241.     { /* creating a rectangular path that should cover the extent */
  1242.         VGubyte segs[] = {
  1243.             VG_MOVE_TO_ABS, VG_LINE_TO_ABS,
  1244.             VG_LINE_TO_ABS, VG_LINE_TO_ABS,
  1245.             VG_CLOSE_PATH
  1246.         };
  1247.         VGfloat data[] = {
  1248.             0, 0,
  1249.             surface->width, 0,
  1250.             surface->width, surface->height,
  1251.             0, surface->height
  1252.         };
  1253.         VGPath fullext;
  1254.  
  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);
  1258.  
  1259.         vgDrawPath (fullext, VG_FILL_PATH);
  1260.  
  1261.         vgDestroyPath (fullext);
  1262.     }
  1263.  
  1264.     _vg_context_unlock (context);
  1265.  
  1266.     CHECK_VG_ERRORS();
  1267.     return CAIRO_STATUS_SUCCESS;
  1268. }
  1269.  
  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)
  1276. {
  1277.     cairo_vg_surface_t *surface = abstract_surface;
  1278.     cairo_status_t status;
  1279.  
  1280.     if (! _vg_is_supported_operator (op))
  1281.         return CAIRO_INT_STATUS_UNSUPPORTED;
  1282.  
  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;
  1288.  
  1289.         context->alpha = solid->color.alpha;
  1290.         status = _vg_surface_paint (abstract_surface, op, source, clip);
  1291.         context->alpha = alpha;
  1292.  
  1293.         _vg_context_unlock (context);
  1294.  
  1295.         return status;
  1296.     }
  1297.  
  1298.     return CAIRO_INT_STATUS_UNSUPPORTED;
  1299. }
  1300.  
  1301. static void
  1302. _vg_surface_get_font_options (void                  *abstract_surface,
  1303.                               cairo_font_options_t  *options)
  1304. {
  1305.     _cairo_font_options_init_default (options);
  1306.  
  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);
  1309. }
  1310.  
  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,
  1316.                          int                     num_glyphs,
  1317.                          cairo_scaled_font_t    *scaled_font,
  1318.                          const cairo_clip_t     *clip)
  1319. {
  1320.     cairo_status_t status = CAIRO_STATUS_SUCCESS;
  1321.     cairo_path_fixed_t path;
  1322.  
  1323.     if (num_glyphs <= 0)
  1324.         return CAIRO_STATUS_SUCCESS;
  1325.  
  1326.     _cairo_path_fixed_init (&path);
  1327.  
  1328.     /* XXX Glyph cache! OpenVG font support in 1.1? */
  1329.  
  1330.     status = _cairo_scaled_font_glyph_path (scaled_font,
  1331.                                             glyphs, num_glyphs,
  1332.                                             &path);
  1333.     if (unlikely (status))
  1334.         goto BAIL;
  1335.  
  1336.     status = _vg_surface_fill (abstract_surface,
  1337.                                op, source, &path,
  1338.                                CAIRO_FILL_RULE_WINDING,
  1339.                                CAIRO_GSTATE_TOLERANCE_DEFAULT,
  1340.                                CAIRO_ANTIALIAS_DEFAULT,
  1341.                                clip);
  1342. BAIL:
  1343.     _cairo_path_fixed_fini (&path);
  1344.     return status;
  1345. }
  1346.  
  1347. static inline int
  1348. multiply_alpha (int alpha, int color)
  1349. {
  1350.     int temp = alpha * color + 0x80;
  1351.     return (temp + (temp >> 8)) >> 8;
  1352. }
  1353.  
  1354. static void
  1355. premultiply_argb (uint8_t   *data,
  1356.                   int        width,
  1357.                   int        height,
  1358.                   int        stride)
  1359. {
  1360.     int i;
  1361.  
  1362.     while (height --) {
  1363.         uint32_t *row = (uint32_t *) data;
  1364.  
  1365.         for (i = 0; i < width; i++) {
  1366.             uint32_t p = row[i];
  1367.             uint8_t  alpha;
  1368.  
  1369.             alpha = p >> 24;
  1370.             if (alpha == 0) {
  1371.                  row[i] = 0;
  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);
  1377.             }
  1378.         }
  1379.  
  1380.         data += stride;
  1381.     }
  1382. }
  1383.  
  1384. static cairo_int_status_t
  1385. _vg_get_image (cairo_vg_surface_t *surface,
  1386.                int x, int y,
  1387.                int width, int height,
  1388.                cairo_image_surface_t **image_out)
  1389. {
  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;
  1394.  
  1395.     pixman_format = _vg_format_to_pixman (surface->format,
  1396.                                           &needs_premultiply);
  1397.     if (pixman_format == 0)
  1398.         return CAIRO_INT_STATUS_UNSUPPORTED;
  1399.  
  1400.     pixman_image = pixman_image_create_bits (pixman_format,
  1401.                                              width, height,
  1402.                                              NULL, 0);
  1403.     if (unlikely (pixman_image == NULL))
  1404.         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  1405.  
  1406.     vgFinish ();
  1407.     CHECK_VG_ERRORS();
  1408.  
  1409.     vgGetImageSubData (surface->image,
  1410.                        pixman_image_get_data (pixman_image),
  1411.                        pixman_image_get_stride (pixman_image),
  1412.                        surface->format,
  1413.                        x, y, width, height);
  1414.  
  1415.     image = (cairo_image_surface_t *)
  1416.         _cairo_image_surface_create_for_pixman_image (pixman_image,
  1417.                                                       pixman_format);
  1418.     if (unlikely (image->base.status)) {
  1419.         pixman_image_unref (pixman_image);
  1420.         return image->base.status;
  1421.     }
  1422.  
  1423.     if (needs_premultiply)
  1424.         premultiply_argb (image->data, width, height, image->stride);
  1425.  
  1426.     *image_out = image;
  1427.     return CAIRO_STATUS_SUCCESS;
  1428. }
  1429.  
  1430. static cairo_status_t
  1431. _vg_surface_acquire_source_image (void *abstract_surface,
  1432.                                   cairo_image_surface_t **image_out,
  1433.                                   void                  **image_extra)
  1434. {
  1435.     cairo_vg_surface_t *surface = abstract_surface;
  1436.  
  1437.     CHECK_VG_ERRORS();
  1438.     *image_extra = NULL;
  1439.     return _vg_get_image (surface,
  1440.                           0, 0, surface->width, surface->height,
  1441.                           image_out);
  1442. }
  1443.  
  1444. static void
  1445. _vg_surface_release_source_image (void                    *abstract_surface,
  1446.                                   cairo_image_surface_t   *image,
  1447.                                   void                    *image_extra)
  1448. {
  1449.     cairo_surface_destroy (&image->base);
  1450. }
  1451.  
  1452. static cairo_status_t
  1453. _vg_surface_finish (void *abstract_surface)
  1454. {
  1455.     cairo_vg_surface_t *surface = abstract_surface;
  1456.     cairo_vg_context_t *context = _vg_context_lock (surface->context);
  1457.  
  1458.     if (surface->snapshot_cache_entry.hash) {
  1459.         _cairo_cache_remove (&context->snapshot_cache,
  1460.                              &surface->snapshot_cache_entry);
  1461.  
  1462.         surface->snapshot_cache_entry.hash = 0;
  1463.     }
  1464.  
  1465.     _cairo_surface_clipper_reset (&surface->clipper);
  1466.  
  1467.     if (surface->own_image)
  1468.         vgDestroyImage (surface->image);
  1469.  
  1470.     _vg_context_destroy_target (context, surface);
  1471.  
  1472.     _vg_context_unlock (context);
  1473.     _vg_context_destroy (context);
  1474.  
  1475.     CHECK_VG_ERRORS();
  1476.     return CAIRO_STATUS_SUCCESS;
  1477. }
  1478.  
  1479. static const cairo_surface_backend_t cairo_vg_surface_backend = {
  1480.     CAIRO_SURFACE_TYPE_VG,
  1481.     _vg_surface_finish,
  1482.  
  1483.     _cairo_default_context_create, /* XXX */
  1484.  
  1485.     _vg_surface_create_similar,
  1486.     NULL, /* create similar image */
  1487.     NULL, /* map to image */
  1488.     NULL, /* unmap image */
  1489.  
  1490.     _cairo_surface_default_source,
  1491.     _vg_surface_acquire_source_image,
  1492.     _vg_surface_release_source_image,
  1493.     NULL, /* snapshot */
  1494.  
  1495.     NULL, /* copy_page */
  1496.     NULL, /* show_page */
  1497.  
  1498.     _vg_surface_get_extents,
  1499.     _vg_surface_get_font_options, /* get_font_options */
  1500.  
  1501.     NULL, /* flush */
  1502.     NULL, /* mark dirty */
  1503.  
  1504.     _vg_surface_paint,
  1505.     _vg_surface_mask,
  1506.     _vg_surface_stroke,
  1507.     _vg_surface_fill,
  1508.     NULL, /* fill-stroke */
  1509.     _vg_surface_show_glyphs,
  1510. };
  1511.  
  1512. static cairo_surface_t *
  1513. _vg_surface_create_internal (cairo_vg_context_t *context,
  1514.                              VGImage image,
  1515.                              VGImageFormat format,
  1516.                              int width, int height)
  1517. {
  1518.     cairo_vg_surface_t *surface;
  1519.  
  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));
  1523.  
  1524.     surface->context = _vg_context_reference (context);
  1525.  
  1526.     surface->image  = image;
  1527.     surface->format = format;
  1528.  
  1529.     _cairo_surface_init (&surface->base,
  1530.                          &cairo_vg_surface_backend,
  1531.                          NULL, /* device */
  1532.                          _vg_format_to_content (format));
  1533.  
  1534.     surface->width  = width;
  1535.     surface->height = height;
  1536.  
  1537.     _cairo_surface_clipper_init (&surface->clipper,
  1538.                                  _vg_surface_clipper_intersect_clip_path);
  1539.  
  1540.     surface->snapshot_cache_entry.hash = 0;
  1541.  
  1542.     surface->target_id = 0;
  1543.  
  1544.     CHECK_VG_ERRORS();
  1545.     return &surface->base;
  1546. }
  1547.  
  1548. cairo_surface_t *
  1549. cairo_vg_surface_create_for_image (cairo_vg_context_t *context,
  1550.                                    VGImage image,
  1551.                                    VGImageFormat format,
  1552.                                    int width, int height)
  1553. {
  1554.     cairo_bool_t premult;
  1555.  
  1556.     if (context->status)
  1557.         return _cairo_surface_create_in_error (context->status);
  1558.  
  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));
  1563.  
  1564.     return _vg_surface_create_internal (context, image, format, width, height);
  1565. }
  1566.  
  1567. cairo_surface_t *
  1568. cairo_vg_surface_create (cairo_vg_context_t *context,
  1569.                          cairo_content_t  content,
  1570.                          int              width,
  1571.                          int              height)
  1572. {
  1573.     VGImage image;
  1574.     VGImageFormat format;
  1575.     cairo_surface_t *surface;
  1576.  
  1577.     if (context->status)
  1578.         return _cairo_surface_create_in_error (context->status);
  1579.  
  1580.     if (! CAIRO_CONTENT_VALID (content))
  1581.         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_CONTENT));
  1582.  
  1583.     if (width > vgGeti (VG_MAX_IMAGE_WIDTH) ||
  1584.         height > vgGeti (VG_MAX_IMAGE_HEIGHT))
  1585.     {
  1586.         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
  1587.     }
  1588.  
  1589.  
  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));
  1594.  
  1595.     surface = _vg_surface_create_internal (context,
  1596.                                            image, format, width, height);
  1597.     if (unlikely (surface->status))
  1598.         return surface;
  1599.  
  1600.     ((cairo_vg_surface_t *) surface)->own_image = TRUE;
  1601.     return surface;
  1602. }
  1603. slim_hidden_def (cairo_vg_surface_create);
  1604.  
  1605. VGImage
  1606. cairo_vg_surface_get_image (cairo_surface_t *abstract_surface)
  1607. {
  1608.     cairo_vg_surface_t *surface;
  1609.  
  1610.     if (abstract_surface->backend != &cairo_vg_surface_backend) {
  1611.         _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
  1612.         return VG_INVALID_HANDLE;
  1613.     }
  1614.  
  1615.     surface = (cairo_vg_surface_t *) abstract_surface;
  1616.     return surface->image;
  1617. }
  1618.  
  1619. int
  1620. cairo_vg_surface_get_width (cairo_surface_t *abstract_surface)
  1621. {
  1622.     cairo_vg_surface_t *surface;
  1623.  
  1624.     if (abstract_surface->backend != &cairo_vg_surface_backend) {
  1625.         _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
  1626.         return 0;
  1627.     }
  1628.  
  1629.     surface = (cairo_vg_surface_t *) abstract_surface;
  1630.     return surface->width;
  1631. }
  1632.  
  1633. int
  1634. cairo_vg_surface_get_height (cairo_surface_t *abstract_surface)
  1635. {
  1636.     cairo_vg_surface_t *surface;
  1637.  
  1638.     if (abstract_surface->backend != &cairo_vg_surface_backend) {
  1639.         _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
  1640.         return 0;
  1641.     }
  1642.  
  1643.     surface = (cairo_vg_surface_t *) abstract_surface;
  1644.     return surface->height;
  1645. }
  1646.  
  1647. VGImageFormat
  1648. cairo_vg_surface_get_format (cairo_surface_t *abstract_surface)
  1649. {
  1650.     cairo_vg_surface_t *surface;
  1651.  
  1652.     if (abstract_surface->backend != &cairo_vg_surface_backend) {
  1653.         _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
  1654.         return 0;
  1655.     }
  1656.  
  1657.     surface = (cairo_vg_surface_t *) abstract_surface;
  1658.     return surface->format;
  1659. }
  1660.  
  1661. /* GL specific context support :-(
  1662.  *
  1663.  * OpenVG like cairo defers creation of surface (and the necessary
  1664.  * paraphernalia to the application.
  1665.  */
  1666.  
  1667. static const cairo_vg_context_t _vg_context_nil = {
  1668.     CAIRO_STATUS_NO_MEMORY,
  1669.     CAIRO_REFERENCE_COUNT_INVALID
  1670. };
  1671.  
  1672. static const cairo_vg_context_t _vg_context_nil_invalid_visual = {
  1673.     CAIRO_STATUS_INVALID_VISUAL,
  1674.     CAIRO_REFERENCE_COUNT_INVALID
  1675. };
  1676.  
  1677. #if CAIRO_HAS_GLX_FUNCTIONS
  1678. #include <GL/glx.h>
  1679.  
  1680. static cairo_status_t
  1681. glx_create_target (cairo_vg_context_t *context,
  1682.                    cairo_vg_surface_t *surface)
  1683. {
  1684.     /* XXX hmm, magic required for creating an FBO points to VGImage! */
  1685.     return CAIRO_INT_STATUS_UNSUPPORTED;
  1686. }
  1687.  
  1688. static cairo_status_t
  1689. glx_set_target (cairo_vg_context_t *context,
  1690.                 cairo_vg_surface_t *surface)
  1691. {
  1692. #if 0
  1693.     glXMakeContextCurrent (context->display,
  1694.                            (GLXDrawable) surface->target_id,
  1695.                            (GLXDrawable) surface->target_id,
  1696.                            context->context);
  1697. #else
  1698.     return CAIRO_INT_STATUS_UNSUPPORTED;
  1699. #endif
  1700. }
  1701.  
  1702. static void
  1703. glx_destroy_target (cairo_vg_context_t *context,
  1704.                     cairo_vg_surface_t *surface)
  1705. {
  1706. }
  1707.  
  1708. cairo_vg_context_t *
  1709. cairo_vg_context_create_for_glx (Display *dpy, GLXContext ctx)
  1710. {
  1711.     cairo_vg_context_t *context;
  1712.     cairo_status_t status;
  1713.  
  1714.     context = malloc (sizeof (*context));
  1715.     if (unlikely (context == NULL))
  1716.         return (cairo_vg_context_t *) &_vg_context_nil;
  1717.  
  1718.     context->display = dpy;
  1719.     context->context = ctx;
  1720.  
  1721.     context->create_target  = glx_create_target;
  1722.     context->set_target     = glx_set_target;
  1723.     context->destroy_target = glx_destroy_target;
  1724.  
  1725.     status = _vg_context_init (context);
  1726.     if (unlikely (status)) {
  1727.         free (context);
  1728.         return (cairo_vg_context_t *) &_vg_context_nil;
  1729.     }
  1730.  
  1731.     return context;
  1732. }
  1733. #endif
  1734.  
  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)
  1739. {
  1740.     EGLSurface *egl_surface;
  1741. #define RED 1
  1742. #define GREEN 3
  1743. #define BLUE 5
  1744. #define ALPHA 7
  1745.     int attribs[] = {
  1746.         EGL_RED_SIZE, 0,
  1747.         EGL_GREEN_SIZE, 0,
  1748.         EGL_BLUE_SIZE, 0,
  1749.         EGL_ALPHA_SIZE, 0,
  1750.         EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
  1751.         EGL_RENDERABLE_TYPE, EGL_OPENVG_BIT,
  1752.         EGL_NONE
  1753.     };
  1754.     pixman_format_code_t pixman_format;
  1755.     EGLConfig config;
  1756.     int num_configs = 0;
  1757.     cairo_bool_t needs_premultiply;
  1758.  
  1759.     pixman_format = _vg_format_to_pixman (surface->format, &needs_premultiply);
  1760.     if (pixman_format == 0)
  1761.         return CAIRO_INT_STATUS_UNSUPPORTED;
  1762.  
  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);
  1768.  
  1769.     if (! eglChooseConfig (context->display,
  1770.                            attribs,
  1771.                            &config, 1, &num_configs) ||
  1772.         num_configs != 1)
  1773.     {
  1774.         fprintf(stderr, "Error: eglChooseConfig() failed.\n");
  1775.         return CAIRO_INT_STATUS_UNSUPPORTED;
  1776.     }
  1777.  
  1778.     egl_surface =
  1779.         eglCreatePbufferFromClientBuffer (context->display,
  1780.                                           EGL_OPENVG_IMAGE,
  1781.                                           (EGLClientBuffer) surface->image,
  1782.                                           config,
  1783.                                           NULL);
  1784.     surface->target_id = (unsigned long) egl_surface;
  1785.  
  1786.     return CAIRO_STATUS_SUCCESS;
  1787. }
  1788.  
  1789. static cairo_status_t
  1790. egl_set_target (cairo_vg_context_t *context,
  1791.                 cairo_vg_surface_t *surface)
  1792. {
  1793.     if (! eglMakeCurrent (context->display,
  1794.                           (EGLSurface *) surface->target_id,
  1795.                           (EGLSurface *) surface->target_id,
  1796.                           context->context))
  1797.     {
  1798.         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  1799.     }
  1800.  
  1801.     return CAIRO_STATUS_SUCCESS;
  1802. }
  1803.  
  1804. static void
  1805. egl_destroy_target (cairo_vg_context_t *context,
  1806.                     cairo_vg_surface_t *surface)
  1807. {
  1808.     eglDestroySurface (context->display,
  1809.                        (EGLSurface *) surface->target_id);
  1810. }
  1811.  
  1812. cairo_vg_context_t *
  1813. cairo_vg_context_create_for_egl (EGLDisplay egl_display,
  1814.                                  EGLContext egl_context)
  1815. {
  1816.     cairo_vg_context_t *context;
  1817.     cairo_status_t status;
  1818.  
  1819.     context = malloc (sizeof (*context));
  1820.     if (unlikely (context == NULL))
  1821.         return (cairo_vg_context_t *) &_vg_context_nil;
  1822.  
  1823.     status = _vg_context_init (context);
  1824.     if (unlikely (status)) {
  1825.         free (context);
  1826.         return (cairo_vg_context_t *) &_vg_context_nil;
  1827.     }
  1828.  
  1829.     context->display = egl_display;
  1830.     context->context = egl_context;
  1831.  
  1832.     context->create_target  = egl_create_target;
  1833.     context->set_target     = egl_set_target;
  1834.     context->destroy_target = egl_destroy_target;
  1835.  
  1836.     return context;
  1837. }
  1838. #endif
  1839.  
  1840. cairo_status_t
  1841. cairo_vg_context_status (cairo_vg_context_t *context)
  1842. {
  1843.     return context->status;
  1844. }
  1845.  
  1846. void
  1847. cairo_vg_context_destroy (cairo_vg_context_t *context)
  1848. {
  1849.     if (context == NULL || CAIRO_REFERENCE_COUNT_IS_INVALID (&context->ref_count))
  1850.         return;
  1851.  
  1852.     _vg_context_destroy (context);
  1853. }
  1854.