Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
  2. /* cairo - a vector graphics library with display and print output
  3.  *
  4.  * Copyright © 2002 University of Southern California
  5.  * Copyright © 2005 Red Hat, Inc.
  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.org/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.  * The Original Code is the cairo graphics library.
  31.  *
  32.  * The Initial Developer of the Original Code is University of Southern
  33.  * California.
  34.  *
  35.  * Contributor(s):
  36.  *      Carl D. Worth <cworth@cworth.org>
  37.  *      Behdad Esfahbod <behdad@behdad.org>
  38.  *      Chris Wilson <chris@chris-wilson.co.uk>
  39.  *      Karl Tomlinson <karlt+@karlt.net>, Mozilla Corporation
  40.  */
  41. #include "cairoint.h"
  42.  
  43. #if !CAIRO_HAS_XLIB_XCB_FUNCTIONS
  44.  
  45. #include "cairo-xlib-private.h"
  46. #include "cairo-xlib-surface-private.h"
  47.  
  48. #include "cairo-error-private.h"
  49. #include "cairo-image-surface-inline.h"
  50. #include "cairo-paginated-private.h"
  51. #include "cairo-pattern-inline.h"
  52. #include "cairo-recording-surface-private.h"
  53. #include "cairo-surface-backend-private.h"
  54. #include "cairo-surface-offset-private.h"
  55. #include "cairo-surface-observer-private.h"
  56. #include "cairo-surface-snapshot-inline.h"
  57. #include "cairo-surface-subsurface-inline.h"
  58.  
  59. #define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */
  60.  
  61. static cairo_xlib_surface_t *
  62. unwrap_source (const cairo_surface_pattern_t *pattern)
  63. {
  64.     cairo_rectangle_int_t limits;
  65.     return (cairo_xlib_surface_t *)_cairo_pattern_get_source (pattern, &limits);
  66. }
  67.  
  68. static cairo_status_t
  69. _cairo_xlib_source_finish (void *abstract_surface)
  70. {
  71.     cairo_xlib_source_t *source = abstract_surface;
  72.  
  73.     XRenderFreePicture (source->dpy, source->picture);
  74.     if (source->pixmap)
  75.             XFreePixmap (source->dpy, source->pixmap);
  76.     return CAIRO_STATUS_SUCCESS;
  77. }
  78.  
  79. static const cairo_surface_backend_t cairo_xlib_source_backend = {
  80.     CAIRO_SURFACE_TYPE_XLIB,
  81.     _cairo_xlib_source_finish,
  82.     NULL, /* read-only wrapper */
  83. };
  84.  
  85. static cairo_status_t
  86. _cairo_xlib_proxy_finish (void *abstract_surface)
  87. {
  88.     cairo_xlib_proxy_t *proxy = abstract_surface;
  89.  
  90.     _cairo_xlib_shm_surface_mark_active (proxy->owner);
  91.     XRenderFreePicture (proxy->source.dpy, proxy->source.picture);
  92.     if (proxy->source.pixmap)
  93.             XFreePixmap (proxy->source.dpy, proxy->source.pixmap);
  94.     cairo_surface_destroy (proxy->owner);
  95.     return CAIRO_STATUS_SUCCESS;
  96. }
  97.  
  98. static const cairo_surface_backend_t cairo_xlib_proxy_backend = {
  99.     CAIRO_SURFACE_TYPE_XLIB,
  100.     _cairo_xlib_proxy_finish,
  101.     NULL, /* read-only wrapper */
  102. };
  103.  
  104. static cairo_surface_t *
  105. source (cairo_xlib_surface_t *dst, Picture picture, Pixmap pixmap)
  106. {
  107.     cairo_xlib_source_t *source;
  108.  
  109.     if (picture == None)
  110.         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
  111.  
  112.     source = malloc (sizeof (*source));
  113.     if (unlikely (source == NULL)) {
  114.         XRenderFreePicture (dst->display->display, picture);
  115.         if (pixmap)
  116.                 XFreePixmap (dst->display->display, pixmap);
  117.         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
  118.     }
  119.  
  120.     _cairo_surface_init (&source->base,
  121.                          &cairo_xlib_source_backend,
  122.                          NULL, /* device */
  123.                          CAIRO_CONTENT_COLOR_ALPHA);
  124.  
  125.     /* The source exists only within an operation */
  126.     source->picture = picture;
  127.     source->pixmap = pixmap;
  128.     source->dpy = dst->display->display;
  129.  
  130.     return &source->base;
  131. }
  132.  
  133. static uint32_t
  134. hars_petruska_f54_1_random (void)
  135. {
  136. #define rol(x,k) ((x << k) | (x >> (32-k)))
  137.     static uint32_t x;
  138.     return x = (x ^ rol (x, 5) ^ rol (x, 24)) + 0x37798849;
  139. #undef rol
  140. }
  141.  
  142. static const XTransform identity = {
  143.     {
  144.         { 1 << 16, 0x00000, 0x00000 },
  145.         { 0x00000, 1 << 16, 0x00000 },
  146.         { 0x00000, 0x00000, 1 << 16 },
  147.     }
  148. };
  149.  
  150. static cairo_bool_t
  151. picture_set_matrix (cairo_xlib_display_t *display,
  152.                     Picture picture,
  153.                     const cairo_matrix_t *matrix,
  154.                     cairo_filter_t        filter,
  155.                     double                xc,
  156.                     double                yc,
  157.                     int                  *x_offset,
  158.                     int                  *y_offset)
  159. {
  160.     XTransform xtransform;
  161.     pixman_transform_t *pixman_transform;
  162.     cairo_int_status_t status;
  163.  
  164.     /* Casting between pixman_transform_t and XTransform is safe because
  165.      * they happen to be the exact same type.
  166.      */
  167.     pixman_transform = (pixman_transform_t *) &xtransform;
  168.     status = _cairo_matrix_to_pixman_matrix_offset (matrix, filter, xc, yc,
  169.                                                     pixman_transform,
  170.                                                     x_offset, y_offset);
  171.     if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
  172.         return TRUE;
  173.     if (unlikely (status != CAIRO_INT_STATUS_SUCCESS))
  174.         return FALSE;
  175.  
  176.     if (memcmp (&xtransform, &identity, sizeof (XTransform)) == 0)
  177.         return TRUE;
  178.  
  179.     /* a late check in case we perturb the matrix too far */
  180.     if (! CAIRO_RENDER_HAS_PICTURE_TRANSFORM (display))
  181.         return FALSE;
  182.  
  183.     XRenderSetPictureTransform (display->display, picture, &xtransform);
  184.     return TRUE;
  185. }
  186.  
  187. static cairo_status_t
  188. picture_set_filter (Display *dpy,
  189.                     Picture picture,
  190.                     cairo_filter_t filter)
  191. {
  192.     const char *render_filter;
  193.  
  194.     switch (filter) {
  195.     case CAIRO_FILTER_FAST:
  196.         render_filter = FilterFast;
  197.         break;
  198.     case CAIRO_FILTER_GOOD:
  199.         render_filter = FilterGood;
  200.         break;
  201.     case CAIRO_FILTER_BEST:
  202.         render_filter = FilterBest;
  203.         break;
  204.     case CAIRO_FILTER_NEAREST:
  205.         render_filter = FilterNearest;
  206.         break;
  207.     case CAIRO_FILTER_BILINEAR:
  208.         render_filter = FilterBilinear;
  209.         break;
  210.     case CAIRO_FILTER_GAUSSIAN:
  211.         /* XXX: The GAUSSIAN value has no implementation in cairo
  212.          * whatsoever, so it was really a mistake to have it in the
  213.          * API. We could fix this by officially deprecating it, or
  214.          * else inventing semantics and providing an actual
  215.          * implementation for it. */
  216.     default:
  217.         render_filter = FilterBest;
  218.         break;
  219.     }
  220.  
  221.     XRenderSetPictureFilter (dpy, picture, (char *) render_filter, NULL, 0);
  222.     return CAIRO_STATUS_SUCCESS;
  223. }
  224.  
  225. static int
  226. extend_to_repeat (cairo_extend_t extend)
  227. {
  228.     switch (extend) {
  229.     default:
  230.         ASSERT_NOT_REACHED;
  231.     case CAIRO_EXTEND_NONE:
  232.         return RepeatNone;
  233.     case CAIRO_EXTEND_REPEAT:
  234.         return RepeatNormal;
  235.     case CAIRO_EXTEND_REFLECT:
  236.         return RepeatReflect;
  237.     case CAIRO_EXTEND_PAD:
  238.         return RepeatPad;
  239.     }
  240. }
  241.  
  242. static cairo_bool_t
  243. picture_set_properties (cairo_xlib_display_t *display,
  244.                         Picture picture,
  245.                         const cairo_pattern_t *pattern,
  246.                         const cairo_matrix_t *matrix,
  247.                         const cairo_rectangle_int_t *extents,
  248.                         int *x_off, int *y_off)
  249. {
  250.     XRenderPictureAttributes pa;
  251.     int mask = 0;
  252.  
  253.     if (! picture_set_matrix (display, picture, matrix, pattern->filter,
  254.                               extents->x + extents->width / 2,
  255.                               extents->y + extents->height / 2,
  256.                               x_off, y_off))
  257.         return FALSE;
  258.  
  259.     picture_set_filter (display->display, picture, pattern->filter);
  260.  
  261.     if (pattern->has_component_alpha) {
  262.         pa.component_alpha = 1;
  263.         mask |= CPComponentAlpha;
  264.     }
  265.  
  266.     if (pattern->extend != CAIRO_EXTEND_NONE) {
  267.         pa.repeat = extend_to_repeat (pattern->extend);
  268.         mask |= CPRepeat;
  269.     }
  270.  
  271.     if (mask)
  272.         XRenderChangePicture (display->display, picture, mask, &pa);
  273.  
  274.     return TRUE;
  275. }
  276.  
  277. static cairo_surface_t *
  278. render_pattern (cairo_xlib_surface_t *dst,
  279.                 const cairo_pattern_t *pattern,
  280.                 cairo_bool_t is_mask,
  281.                 const cairo_rectangle_int_t *extents,
  282.                 int *src_x, int *src_y)
  283. {
  284.     Display *dpy = dst->display->display;
  285.     cairo_xlib_surface_t *src;
  286.     cairo_image_surface_t *image;
  287.     cairo_status_t status;
  288.     cairo_rectangle_int_t map_extents;
  289.  
  290.     src = (cairo_xlib_surface_t *)
  291.         _cairo_surface_create_similar_scratch (&dst->base,
  292.                                                is_mask ? CAIRO_CONTENT_ALPHA : CAIRO_CONTENT_COLOR_ALPHA,
  293.                                                extents->width,
  294.                                                extents->height);
  295.     if (src->base.type != CAIRO_SURFACE_TYPE_XLIB) {
  296.         cairo_surface_destroy (&src->base);
  297.         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
  298.     }
  299.  
  300.     map_extents = *extents;
  301.     map_extents.x = map_extents.y = 0;
  302.  
  303.     image = _cairo_surface_map_to_image (&src->base, &map_extents);
  304.     status = _cairo_surface_offset_paint (&image->base, extents->x, extents->y,
  305.                                           CAIRO_OPERATOR_SOURCE, pattern,
  306.                                           NULL);
  307.     status = _cairo_surface_unmap_image (&src->base, image);
  308.     if (unlikely (status)) {
  309.         cairo_surface_destroy (&src->base);
  310.         return _cairo_surface_create_in_error (status);
  311.     }
  312.  
  313.     status = _cairo_xlib_surface_put_shm (src);
  314.     if (unlikely (status)) {
  315.         cairo_surface_destroy (&src->base);
  316.         return _cairo_surface_create_in_error (status);
  317.     }
  318.  
  319.     src->picture = XRenderCreatePicture (dpy,
  320.                                          src->drawable, src->xrender_format,
  321.                                          0, NULL);
  322.  
  323.     *src_x = -extents->x;
  324.     *src_y = -extents->y;
  325.     return &src->base;
  326. }
  327.  
  328. static cairo_surface_t *
  329. gradient_source (cairo_xlib_surface_t *dst,
  330.                  const cairo_gradient_pattern_t *gradient,
  331.                  cairo_bool_t is_mask,
  332.                  const cairo_rectangle_int_t *extents,
  333.                  int *src_x, int *src_y)
  334. {
  335.     cairo_xlib_display_t *display = dst->display;
  336.     cairo_matrix_t matrix = gradient->base.matrix;
  337.     char buf[CAIRO_STACK_BUFFER_SIZE];
  338.     cairo_circle_double_t extremes[2];
  339.     XFixed *stops;
  340.     XRenderColor *colors;
  341.     Picture picture;
  342.     unsigned int i, n_stops;
  343.  
  344.     /* The RENDER specification says that the inner circle has
  345.      * to be completely contained inside the outer one. */
  346.     if (gradient->base.type == CAIRO_PATTERN_TYPE_RADIAL &&
  347.         ! _cairo_radial_pattern_focus_is_inside ((cairo_radial_pattern_t *) gradient))
  348.         return render_pattern (dst, &gradient->base, is_mask, extents, src_x, src_y);
  349.  
  350.     assert (gradient->n_stops > 0);
  351.     n_stops = MAX (gradient->n_stops, 2);
  352.  
  353.     if (n_stops < sizeof (buf) / (sizeof (XFixed) + sizeof (XRenderColor)))
  354.     {
  355.         stops = (XFixed *) buf;
  356.     }
  357.     else
  358.     {
  359.         stops =
  360.             _cairo_malloc_ab (n_stops,
  361.                               sizeof (XFixed) + sizeof (XRenderColor));
  362.         if (unlikely (stops == NULL))
  363.             return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
  364.     }
  365.  
  366.     colors = (XRenderColor *) (stops + n_stops);
  367.     for (i = 0; i < gradient->n_stops; i++) {
  368.         stops[i] =
  369.             _cairo_fixed_16_16_from_double (gradient->stops[i].offset);
  370.  
  371.         colors[i].red   = gradient->stops[i].color.red_short;
  372.         colors[i].green = gradient->stops[i].color.green_short;
  373.         colors[i].blue  = gradient->stops[i].color.blue_short;
  374.         colors[i].alpha = gradient->stops[i].color.alpha_short;
  375.     }
  376.  
  377.     /* RENDER does not support gradients with less than 2
  378.      * stops. If a gradient has only a single stop, duplicate
  379.      * it to make RENDER happy. */
  380.     if (gradient->n_stops == 1) {
  381.         stops[1] =
  382.             _cairo_fixed_16_16_from_double (gradient->stops[0].offset);
  383.  
  384.         colors[1].red   = gradient->stops[0].color.red_short;
  385.         colors[1].green = gradient->stops[0].color.green_short;
  386.         colors[1].blue  = gradient->stops[0].color.blue_short;
  387.         colors[1].alpha = gradient->stops[0].color.alpha_short;
  388.     }
  389.  
  390. #if 0
  391.     /* For some weird reason the X server is sometimes getting
  392.      * CreateGradient requests with bad length. So far I've only seen
  393.      * XRenderCreateLinearGradient request with 4 stops sometime end up
  394.      * with length field matching 0 stops at the server side. I've
  395.      * looked at the libXrender code and I can't see anything that
  396.      * could cause this behavior. However, for some reason having a
  397.      * XSync call here seems to avoid the issue so I'll keep it here
  398.      * until it's solved.
  399.      */
  400.     XSync (display->display, False);
  401. #endif
  402.  
  403.     _cairo_gradient_pattern_fit_to_range (gradient, PIXMAN_MAX_INT >> 1, &matrix, extremes);
  404.  
  405.     if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
  406.         XLinearGradient grad;
  407.  
  408.         grad.p1.x = _cairo_fixed_16_16_from_double (extremes[0].center.x);
  409.         grad.p1.y = _cairo_fixed_16_16_from_double (extremes[0].center.y);
  410.         grad.p2.x = _cairo_fixed_16_16_from_double (extremes[1].center.x);
  411.         grad.p2.y = _cairo_fixed_16_16_from_double (extremes[1].center.y);
  412.  
  413.         picture = XRenderCreateLinearGradient (display->display, &grad,
  414.                                                stops, colors,
  415.                                                n_stops);
  416.     } else {
  417.         XRadialGradient grad;
  418.  
  419.         grad.inner.x      = _cairo_fixed_16_16_from_double (extremes[0].center.x);
  420.         grad.inner.y      = _cairo_fixed_16_16_from_double (extremes[0].center.y);
  421.         grad.inner.radius = _cairo_fixed_16_16_from_double (extremes[0].radius);
  422.         grad.outer.x      = _cairo_fixed_16_16_from_double (extremes[1].center.x);
  423.         grad.outer.y      = _cairo_fixed_16_16_from_double (extremes[1].center.y);
  424.         grad.outer.radius = _cairo_fixed_16_16_from_double (extremes[1].radius);
  425.  
  426.         picture = XRenderCreateRadialGradient (display->display, &grad,
  427.                                                stops, colors,
  428.                                                n_stops);
  429.     }
  430.  
  431.     if (stops != (XFixed *) buf)
  432.         free (stops);
  433.  
  434.     *src_x = *src_y = 0;
  435.     if (! picture_set_properties (display, picture,
  436.                                   &gradient->base, &gradient->base.matrix,
  437.                                   extents,
  438.                                   src_x, src_y)) {
  439.         XRenderFreePicture (display->display, picture);
  440.         return render_pattern (dst, &gradient->base, is_mask, extents, src_x, src_y);
  441.     }
  442.  
  443.     return source (dst, picture, None);
  444. }
  445.  
  446. static cairo_surface_t *
  447. color_source (cairo_xlib_surface_t *dst, const cairo_color_t *color)
  448. {
  449.     Display *dpy = dst->display->display;
  450.     XRenderColor xcolor;
  451.     Picture picture;
  452.     Pixmap pixmap = None;
  453.  
  454.     xcolor.red   = color->red_short;
  455.     xcolor.green = color->green_short;
  456.     xcolor.blue  = color->blue_short;
  457.     xcolor.alpha = color->alpha_short;
  458.  
  459.     if (CAIRO_RENDER_HAS_GRADIENTS(dst->display)) {
  460.         picture = XRenderCreateSolidFill (dpy, &xcolor);
  461.     } else {
  462.         XRenderPictureAttributes pa;
  463.         int mask = 0;
  464.  
  465.         pa.repeat = RepeatNormal;
  466.         mask |= CPRepeat;
  467.  
  468.         pixmap = XCreatePixmap (dpy, dst->drawable, 1, 1, 32);
  469.         picture = XRenderCreatePicture (dpy, pixmap,
  470.                                         _cairo_xlib_display_get_xrender_format (dst->display, CAIRO_FORMAT_ARGB32),
  471.                                         mask, &pa);
  472.  
  473.         if (CAIRO_RENDER_HAS_FILL_RECTANGLES(dst->display)) {
  474.             XRectangle r = { 0, 0, 1, 1};
  475.             XRenderFillRectangles (dpy, PictOpSrc, picture, &xcolor, &r, 1);
  476.         } else {
  477.             XGCValues gcv;
  478.             GC gc;
  479.  
  480.             gc = _cairo_xlib_screen_get_gc (dst->display, dst->screen,
  481.                                             32, pixmap);
  482.             if (unlikely (gc == NULL)) {
  483.                 XFreePixmap (dpy, pixmap);
  484.                 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
  485.             }
  486.  
  487.             gcv.foreground = 0;
  488.             gcv.foreground |= color->alpha_short >> 8 << 24;
  489.             gcv.foreground |= color->red_short   >> 8 << 16;
  490.             gcv.foreground |= color->green_short >> 8 << 8;
  491.             gcv.foreground |= color->blue_short  >> 8 << 0;
  492.             gcv.fill_style = FillSolid;
  493.  
  494.             XChangeGC (dpy, gc, GCFillStyle | GCForeground, &gcv);
  495.             XFillRectangle (dpy, pixmap, gc, 0, 0, 1, 1);
  496.  
  497.             _cairo_xlib_screen_put_gc (dst->display, dst->screen, 32, gc);
  498.         }
  499.     }
  500.  
  501.     return source (dst, picture, pixmap);
  502. }
  503.  
  504. static cairo_surface_t *
  505. alpha_source (cairo_xlib_surface_t *dst, uint8_t alpha)
  506. {
  507.     cairo_xlib_display_t *display = dst->display;
  508.  
  509.     if (display->alpha[alpha] == NULL) {
  510.         cairo_color_t color;
  511.  
  512.         color.red_short = color.green_short = color.blue_short = 0;
  513.         color.alpha_short = alpha << 8 | alpha;
  514.  
  515.         display->alpha[alpha] = color_source (dst, &color);
  516.     }
  517.  
  518.     return cairo_surface_reference (display->alpha[alpha]);
  519. }
  520.  
  521. static cairo_surface_t *
  522. white_source (cairo_xlib_surface_t *dst)
  523. {
  524.     cairo_xlib_display_t *display = dst->display;
  525.  
  526.     if (display->white == NULL)
  527.         display->white = color_source (dst, CAIRO_COLOR_WHITE);
  528.  
  529.     return cairo_surface_reference (display->white);
  530. }
  531.  
  532. static cairo_surface_t *
  533. opaque_source (cairo_xlib_surface_t *dst, const cairo_color_t *color)
  534. {
  535.     cairo_xlib_display_t *display = dst->display;
  536.     uint32_t pixel =
  537.         0xff000000 |
  538.         color->red_short   >> 8 << 16 |
  539.         color->green_short >> 8 << 8 |
  540.         color->blue_short  >> 8 << 0;
  541.     int i;
  542.  
  543.     if (display->last_solid_cache[0].color == pixel)
  544.         return cairo_surface_reference (display->solid[display->last_solid_cache[0].index]);
  545.  
  546.     for (i = 0; i < 16; i++) {
  547.         if (display->solid_cache[i] == pixel)
  548.             goto done;
  549.     }
  550.  
  551.     i = hars_petruska_f54_1_random () % 16;
  552.     cairo_surface_destroy (display->solid[i]);
  553.  
  554.     display->solid[i] = color_source (dst, color);
  555.     display->solid_cache[i] = pixel;
  556.  
  557. done:
  558.     display->last_solid_cache[0].color = pixel;
  559.     display->last_solid_cache[0].index = i;
  560.     return cairo_surface_reference (display->solid[i]);
  561. }
  562.  
  563. static cairo_surface_t *
  564. transparent_source (cairo_xlib_surface_t *dst, const cairo_color_t *color)
  565. {
  566.     cairo_xlib_display_t *display = dst->display;
  567.     uint32_t pixel =
  568.         color->alpha_short >> 8 << 24 |
  569.         color->red_short   >> 8 << 16 |
  570.         color->green_short >> 8 << 8 |
  571.         color->blue_short  >> 8 << 0;
  572.     int i;
  573.  
  574.     if (display->last_solid_cache[1].color == pixel) {
  575.     assert (display->solid[display->last_solid_cache[1].index]);
  576.         return cairo_surface_reference (display->solid[display->last_solid_cache[1].index]);
  577.     }
  578.  
  579.     for (i = 16; i < 32; i++) {
  580.         if (display->solid_cache[i] == pixel)
  581.             goto done;
  582.     }
  583.  
  584.     i = 16 + (hars_petruska_f54_1_random () % 16);
  585.     cairo_surface_destroy (display->solid[i]);
  586.  
  587.     display->solid[i] = color_source (dst, color);
  588.     display->solid_cache[i] = pixel;
  589.  
  590. done:
  591.     display->last_solid_cache[1].color = pixel;
  592.     display->last_solid_cache[1].index = i;
  593.     assert (display->solid[i]);
  594.     return cairo_surface_reference (display->solid[i]);
  595. }
  596.  
  597. static cairo_surface_t *
  598. solid_source (cairo_xlib_surface_t *dst,
  599.               const cairo_color_t *color)
  600. {
  601.     if ((color->red_short | color->green_short | color->blue_short) <= 0xff)
  602.         return alpha_source (dst, color->alpha_short >> 8);
  603.  
  604.     if (CAIRO_ALPHA_SHORT_IS_OPAQUE (color->alpha_short)) {
  605.         if (color->red_short >= 0xff00 && color->green_short >= 0xff00 && color->blue_short >= 0xff00)
  606.             return white_source (dst);
  607.  
  608.         return opaque_source (dst, color);
  609.     } else
  610.         return transparent_source (dst, color);
  611. }
  612.  
  613. static cairo_xlib_source_t *init_source (cairo_xlib_surface_t *dst,
  614.                                          cairo_xlib_surface_t *src)
  615. {
  616.     Display *dpy = dst->display->display;
  617.     cairo_xlib_source_t *source = &src->embedded_source;
  618.  
  619.     /* As these are frequent and meant to be fast, we track pictures for
  620.      * native surface and minimise update requests.
  621.      */
  622.     if (source->picture == None) {
  623.         XRenderPictureAttributes pa;
  624.  
  625.         _cairo_surface_init (&source->base,
  626.                              &cairo_xlib_source_backend,
  627.                              NULL, /* device */
  628.                              CAIRO_CONTENT_COLOR_ALPHA);
  629.  
  630.         pa.subwindow_mode = IncludeInferiors;
  631.         source->picture = XRenderCreatePicture (dpy,
  632.                                                 src->drawable,
  633.                                                 src->xrender_format,
  634.                                                 CPSubwindowMode, &pa);
  635.  
  636.         source->has_component_alpha = 0;
  637.         source->has_matrix = 0;
  638.         source->filter = CAIRO_FILTER_NEAREST;
  639.         source->extend = CAIRO_EXTEND_NONE;
  640.     }
  641.  
  642.     return (cairo_xlib_source_t *) cairo_surface_reference (&source->base);
  643. }
  644.  
  645. static cairo_surface_t *
  646. embedded_source (cairo_xlib_surface_t *dst,
  647.                  const cairo_surface_pattern_t *pattern,
  648.                  const cairo_rectangle_int_t *extents,
  649.                  int *src_x, int *src_y,
  650.                  cairo_xlib_source_t *source)
  651. {
  652.     Display *dpy = dst->display->display;
  653.     cairo_int_status_t status;
  654.     XTransform xtransform;
  655.     XRenderPictureAttributes pa;
  656.     unsigned mask = 0;
  657.  
  658.     status = _cairo_matrix_to_pixman_matrix_offset (&pattern->base.matrix,
  659.                                                     pattern->base.filter,
  660.                                                     extents->x + extents->width / 2,
  661.                                                     extents->y + extents->height / 2,
  662.                                                     (pixman_transform_t *)&xtransform,
  663.                                                     src_x, src_y);
  664.  
  665.     if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) {
  666.         if (source->has_matrix) {
  667.             source->has_matrix = 0;
  668.             memcpy (&xtransform, &identity, sizeof (identity));
  669.             status = CAIRO_INT_STATUS_SUCCESS;
  670.         }
  671.     } else
  672.         source->has_matrix = 1;
  673.     if (status == CAIRO_INT_STATUS_SUCCESS)
  674.         XRenderSetPictureTransform (dpy, source->picture, &xtransform);
  675.  
  676.     if (source->filter != pattern->base.filter) {
  677.         picture_set_filter (dpy, source->picture, pattern->base.filter);
  678.         source->filter = pattern->base.filter;
  679.     }
  680.  
  681.     if (source->has_component_alpha != pattern->base.has_component_alpha) {
  682.         pa.component_alpha = pattern->base.has_component_alpha;
  683.         mask |= CPComponentAlpha;
  684.         source->has_component_alpha = pattern->base.has_component_alpha;
  685.     }
  686.  
  687.     if (source->extend != pattern->base.extend) {
  688.         pa.repeat = extend_to_repeat (pattern->base.extend);
  689.         mask |= CPRepeat;
  690.         source->extend = pattern->base.extend;
  691.     }
  692.  
  693.     if (mask)
  694.         XRenderChangePicture (dpy, source->picture, mask, &pa);
  695.  
  696.     return &source->base;
  697. }
  698.  
  699. static cairo_surface_t *
  700. subsurface_source (cairo_xlib_surface_t *dst,
  701.                    const cairo_surface_pattern_t *pattern,
  702.                    cairo_bool_t is_mask,
  703.                    const cairo_rectangle_int_t *extents,
  704.                    const cairo_rectangle_int_t *sample,
  705.                    int *src_x, int *src_y)
  706. {
  707.     cairo_surface_subsurface_t *sub;
  708.     cairo_xlib_surface_t *src;
  709.     cairo_xlib_source_t *source;
  710.     Display *dpy = dst->display->display;
  711.     cairo_int_status_t status;
  712.     cairo_surface_pattern_t local_pattern;
  713.     XTransform xtransform;
  714.     XRenderPictureAttributes pa;
  715.     unsigned mask = 0;
  716.  
  717.     sub = (cairo_surface_subsurface_t *) pattern->surface;
  718.  
  719.     if (sample->x >= 0 && sample->y >= 0 &&
  720.         sample->x + sample->width  <= sub->extents.width &&
  721.         sample->y + sample->height <= sub->extents.height)
  722.     {
  723.         src = (cairo_xlib_surface_t *) sub->target;
  724.         status = _cairo_surface_flush (&src->base, 0);
  725.         if (unlikely (status))
  726.             return _cairo_surface_create_in_error (status);
  727.  
  728.         if (pattern->base.filter == CAIRO_FILTER_NEAREST &&
  729.             _cairo_matrix_is_translation (&pattern->base.matrix))
  730.         {
  731.             *src_x += pattern->base.matrix.x0 + sub->extents.x;
  732.             *src_y += pattern->base.matrix.y0 + sub->extents.y;
  733.  
  734.             _cairo_xlib_surface_ensure_picture (src);
  735.             return cairo_surface_reference (&src->base);
  736.         }
  737.         else
  738.         {
  739.             cairo_surface_pattern_t local_pattern = *pattern;
  740.             local_pattern.base.matrix.x0 += sub->extents.x;
  741.             local_pattern.base.matrix.y0 += sub->extents.y;
  742.             local_pattern.base.extend = CAIRO_EXTEND_NONE;
  743.             return embedded_source (dst, &local_pattern, extents,
  744.                                     src_x, src_y, init_source (dst, src));
  745.         }
  746.     }
  747.  
  748.     if (sub->snapshot && sub->snapshot->type == CAIRO_SURFACE_TYPE_XLIB) {
  749.         src = (cairo_xlib_surface_t *) cairo_surface_reference (sub->snapshot);
  750.         source = &src->embedded_source;
  751.     } else {
  752.         src = (cairo_xlib_surface_t *)
  753.             _cairo_surface_create_similar_scratch (&dst->base,
  754.                                                    sub->base.content,
  755.                                                    sub->extents.width,
  756.                                                    sub->extents.height);
  757.         if (src->base.type != CAIRO_SURFACE_TYPE_XLIB) {
  758.             cairo_surface_destroy (&src->base);
  759.             return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
  760.         }
  761.  
  762.         _cairo_pattern_init_for_surface (&local_pattern, sub->target);
  763.         cairo_matrix_init_translate (&local_pattern.base.matrix,
  764.                                      sub->extents.x, sub->extents.y);
  765.         local_pattern.base.filter = CAIRO_FILTER_NEAREST;
  766.         status = _cairo_surface_paint (&src->base,
  767.                                        CAIRO_OPERATOR_SOURCE,
  768.                                        &local_pattern.base,
  769.                                        NULL);
  770.         _cairo_pattern_fini (&local_pattern.base);
  771.  
  772.         if (unlikely (status)) {
  773.             cairo_surface_destroy (&src->base);
  774.             return _cairo_surface_create_in_error (status);
  775.         }
  776.  
  777.         _cairo_xlib_surface_ensure_picture (src);
  778.         _cairo_surface_subsurface_set_snapshot (&sub->base, &src->base);
  779.  
  780.         source = &src->embedded_source;
  781.         source->has_component_alpha = 0;
  782.         source->has_matrix = 0;
  783.         source->filter = CAIRO_FILTER_NEAREST;
  784.         source->extend = CAIRO_EXTEND_NONE;
  785.     }
  786.  
  787.     status = _cairo_matrix_to_pixman_matrix_offset (&pattern->base.matrix,
  788.                                                     pattern->base.filter,
  789.                                                     extents->x + extents->width / 2,
  790.                                                     extents->y + extents->height / 2,
  791.                                                     (pixman_transform_t *)&xtransform,
  792.                                                     src_x, src_y);
  793.     if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) {
  794.         if (source->has_matrix) {
  795.             source->has_matrix = 0;
  796.             memcpy (&xtransform, &identity, sizeof (identity));
  797.             status = CAIRO_INT_STATUS_SUCCESS;
  798.         }
  799.     } else
  800.         source->has_matrix = 1;
  801.     if (status == CAIRO_INT_STATUS_SUCCESS)
  802.         XRenderSetPictureTransform (dpy, src->picture, &xtransform);
  803.  
  804.     if (source->filter != pattern->base.filter) {
  805.         picture_set_filter (dpy, src->picture, pattern->base.filter);
  806.         source->filter = pattern->base.filter;
  807.     }
  808.  
  809.     if (source->has_component_alpha != pattern->base.has_component_alpha) {
  810.         pa.component_alpha = pattern->base.has_component_alpha;
  811.         mask |= CPComponentAlpha;
  812.         source->has_component_alpha = pattern->base.has_component_alpha;
  813.     }
  814.  
  815.     if (source->extend != pattern->base.extend) {
  816.         pa.repeat = extend_to_repeat (pattern->base.extend);
  817.         mask |= CPRepeat;
  818.         source->extend = pattern->base.extend;
  819.     }
  820.  
  821.     if (mask)
  822.         XRenderChangePicture (dpy, src->picture, mask, &pa);
  823.  
  824.     return &src->base;
  825. }
  826.  
  827. static cairo_surface_t *
  828. native_source (cairo_xlib_surface_t *dst,
  829.                const cairo_surface_pattern_t *pattern,
  830.                cairo_bool_t is_mask,
  831.                const cairo_rectangle_int_t *extents,
  832.                const cairo_rectangle_int_t *sample,
  833.                int *src_x, int *src_y)
  834. {
  835.     cairo_xlib_surface_t *src;
  836.     cairo_int_status_t status;
  837.  
  838.     if (_cairo_surface_is_subsurface (pattern->surface))
  839.         return subsurface_source (dst, pattern, is_mask,
  840.                                   extents, sample,
  841.                                   src_x, src_y);
  842.  
  843.     src = unwrap_source (pattern);
  844.     status = _cairo_surface_flush (&src->base, 0);
  845.     if (unlikely (status))
  846.         return _cairo_surface_create_in_error (status);
  847.  
  848.     if (pattern->base.filter == CAIRO_FILTER_NEAREST &&
  849.         sample->x >= 0 && sample->y >= 0 &&
  850.         sample->x + sample->width  <= src->width &&
  851.         sample->y + sample->height <= src->height &&
  852.         _cairo_matrix_is_translation (&pattern->base.matrix))
  853.     {
  854.         *src_x += pattern->base.matrix.x0;
  855.         *src_y += pattern->base.matrix.y0;
  856.         _cairo_xlib_surface_ensure_picture (src);
  857.         return cairo_surface_reference (&src->base);
  858.     }
  859.  
  860.     return embedded_source (dst, pattern, extents, src_x, src_y,
  861.                             init_source (dst, src));
  862. }
  863.  
  864. static cairo_surface_t *
  865. recording_pattern_get_surface (const cairo_pattern_t *pattern)
  866. {
  867.     cairo_surface_t *surface;
  868.  
  869.     surface = ((const cairo_surface_pattern_t *) pattern)->surface;
  870.     if (_cairo_surface_is_paginated (surface))
  871.         surface = _cairo_paginated_surface_get_recording (surface);
  872.     if (_cairo_surface_is_snapshot (surface))
  873.         surface = _cairo_surface_snapshot_get_target (surface);
  874.     return surface;
  875. }
  876.  
  877. static cairo_surface_t *
  878. record_source (cairo_xlib_surface_t *dst,
  879.                const cairo_surface_pattern_t *pattern,
  880.                cairo_bool_t is_mask,
  881.                const cairo_rectangle_int_t *extents,
  882.                const cairo_rectangle_int_t *sample,
  883.                int *src_x, int *src_y)
  884. {
  885.     cairo_xlib_surface_t *src;
  886.     cairo_matrix_t matrix, m;
  887.     cairo_status_t status;
  888.     cairo_rectangle_int_t upload, limit;
  889.  
  890.     upload = *sample;
  891.     if (_cairo_surface_get_extents (pattern->surface, &limit) &&
  892.         ! _cairo_rectangle_intersect (&upload, &limit))
  893.     {
  894.         if (pattern->base.extend == CAIRO_EXTEND_NONE)
  895.             return alpha_source (dst, 0);
  896.  
  897.         upload = limit;
  898.     }
  899.  
  900.     src = (cairo_xlib_surface_t *)
  901.         _cairo_surface_create_similar_scratch (&dst->base,
  902.                                                pattern->surface->content,
  903.                                                upload.width,
  904.                                                upload.height);
  905.     if (src->base.type != CAIRO_SURFACE_TYPE_XLIB) {
  906.         cairo_surface_destroy (&src->base);
  907.         return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
  908.     }
  909.  
  910.     cairo_matrix_init_translate (&matrix, upload.x, upload.y);
  911.     status = _cairo_recording_surface_replay_with_clip (recording_pattern_get_surface (&pattern->base),
  912.                                                         &matrix, &src->base,
  913.                                                         NULL);
  914.     if (unlikely (status)) {
  915.         cairo_surface_destroy (&src->base);
  916.         return _cairo_surface_create_in_error (status);
  917.     }
  918.  
  919.     matrix = pattern->base.matrix;
  920.     if (upload.x | upload.y) {
  921.         cairo_matrix_init_translate (&m, -upload.x, -upload.y);
  922.         cairo_matrix_multiply (&matrix, &matrix, &m);
  923.     }
  924.  
  925.     _cairo_xlib_surface_ensure_picture (src);
  926.     if (! picture_set_properties (src->display, src->picture,
  927.                                   &pattern->base, &matrix, extents,
  928.                                   src_x, src_y))
  929.     {
  930.         cairo_surface_destroy (&src->base);
  931.         return render_pattern (dst, &pattern->base, is_mask,
  932.                                extents, src_x, src_y);
  933.     }
  934.  
  935.     return &src->base;
  936. }
  937.  
  938. static cairo_surface_t *
  939. surface_source (cairo_xlib_surface_t *dst,
  940.                 const cairo_surface_pattern_t *pattern,
  941.                 cairo_bool_t is_mask,
  942.                 const cairo_rectangle_int_t *extents,
  943.                 const cairo_rectangle_int_t *sample,
  944.                 int *src_x, int *src_y)
  945. {
  946.     cairo_surface_t *src;
  947.     cairo_xlib_surface_t *xsrc;
  948.     cairo_surface_pattern_t local_pattern;
  949.     cairo_status_t status;
  950.     cairo_rectangle_int_t upload, limit;
  951.  
  952.     src = pattern->surface;
  953.     if (src->type == CAIRO_SURFACE_TYPE_IMAGE &&
  954.         src->device == dst->base.device &&
  955.         _cairo_xlib_shm_surface_get_pixmap (src)) {
  956.         cairo_xlib_proxy_t *proxy;
  957.  
  958.         proxy = malloc (sizeof(*proxy));
  959.         if (unlikely (proxy == NULL))
  960.             return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
  961.  
  962.         _cairo_surface_init (&proxy->source.base,
  963.                              &cairo_xlib_proxy_backend,
  964.                              dst->base.device,
  965.                              src->content);
  966.  
  967.         proxy->source.dpy = dst->display->display;
  968.         proxy->source.picture = XRenderCreatePicture (proxy->source.dpy,
  969.                                                       _cairo_xlib_shm_surface_get_pixmap (src),
  970.                                                       _cairo_xlib_shm_surface_get_xrender_format (src),
  971.                                                       0, NULL);
  972.         proxy->source.pixmap = None;
  973.  
  974.         proxy->source.has_component_alpha = 0;
  975.         proxy->source.has_matrix = 0;
  976.         proxy->source.filter = CAIRO_FILTER_NEAREST;
  977.         proxy->source.extend = CAIRO_EXTEND_NONE;
  978.         proxy->owner = cairo_surface_reference (src);
  979.  
  980.         return embedded_source (dst, pattern, extents, src_x, src_y,
  981.                                 &proxy->source);
  982.     }
  983.  
  984.     upload = *sample;
  985.     if (_cairo_surface_get_extents (pattern->surface, &limit)) {
  986.         if (pattern->base.extend == CAIRO_EXTEND_NONE) {
  987.             if (! _cairo_rectangle_intersect (&upload, &limit))
  988.                 return alpha_source (dst, 0);
  989.         } else if (pattern->base.extend == CAIRO_EXTEND_PAD) {
  990.             if (! _cairo_rectangle_intersect (&upload, &limit))
  991.                 upload = limit;
  992.         } else {
  993.             if (upload.x < limit.x ||
  994.                 upload.x + upload.width > limit.x + limit.width ||
  995.                 upload.y < limit.y ||
  996.                 upload.y + upload.height > limit.y + limit.height)
  997.             {
  998.                 upload = limit;
  999.             }
  1000.         }
  1001.     }
  1002.  
  1003.     xsrc = (cairo_xlib_surface_t *)
  1004.             _cairo_surface_create_similar_scratch (&dst->base,
  1005.                                                    src->content,
  1006.                                                    upload.width,
  1007.                                                    upload.height);
  1008.     if (xsrc->base.type != CAIRO_SURFACE_TYPE_XLIB) {
  1009.         cairo_surface_destroy (src);
  1010.         cairo_surface_destroy (&xsrc->base);
  1011.         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
  1012.     }
  1013.  
  1014.     if (_cairo_surface_is_image (src)) {
  1015.         status = _cairo_xlib_surface_draw_image (xsrc, (cairo_image_surface_t *)src,
  1016.                                                  upload.x, upload.y,
  1017.                                                  upload.width, upload.height,
  1018.                                                  0, 0);
  1019.     } else {
  1020.         cairo_image_surface_t *image;
  1021.         cairo_rectangle_int_t map_extents = { 0,0, upload.width,upload.height };
  1022.  
  1023.         image = _cairo_surface_map_to_image (&xsrc->base, &map_extents);
  1024.  
  1025.         _cairo_pattern_init_for_surface (&local_pattern, pattern->surface);
  1026.         cairo_matrix_init_translate (&local_pattern.base.matrix,
  1027.                                      upload.x, upload.y);
  1028.  
  1029.         status = _cairo_surface_paint (&image->base,
  1030.                                        CAIRO_OPERATOR_SOURCE,
  1031.                                        &local_pattern.base,
  1032.                                        NULL);
  1033.         _cairo_pattern_fini (&local_pattern.base);
  1034.  
  1035.         status = _cairo_surface_unmap_image (&xsrc->base, image);
  1036.         if (unlikely (status)) {
  1037.             cairo_surface_destroy (&xsrc->base);
  1038.             return _cairo_surface_create_in_error (status);
  1039.         }
  1040.  
  1041.         status = _cairo_xlib_surface_put_shm (xsrc);
  1042.         if (unlikely (status)) {
  1043.             cairo_surface_destroy (&xsrc->base);
  1044.             return _cairo_surface_create_in_error (status);
  1045.         }
  1046.     }
  1047.  
  1048.     _cairo_pattern_init_static_copy (&local_pattern.base, &pattern->base);
  1049.     if (upload.x | upload.y) {
  1050.         cairo_matrix_t m;
  1051.         cairo_matrix_init_translate (&m, -upload.x, -upload.y);
  1052.         cairo_matrix_multiply (&local_pattern.base.matrix,
  1053.                                &local_pattern.base.matrix,
  1054.                                &m);
  1055.     }
  1056.  
  1057.     *src_x = *src_y = 0;
  1058.     _cairo_xlib_surface_ensure_picture (xsrc);
  1059.     if (! picture_set_properties (xsrc->display,
  1060.                                   xsrc->picture,
  1061.                                   &local_pattern.base,
  1062.                                   &local_pattern.base.matrix,
  1063.                                   extents,
  1064.                                   src_x, src_y))
  1065.     {
  1066.         cairo_surface_destroy (&xsrc->base);
  1067.         return render_pattern (dst, &pattern->base,
  1068.                                is_mask, extents,
  1069.                                src_x, src_y);
  1070.     }
  1071.  
  1072.     return &xsrc->base;
  1073. }
  1074.  
  1075. static cairo_bool_t
  1076. pattern_is_supported (cairo_xlib_display_t *display,
  1077.                       const cairo_pattern_t *pattern)
  1078. {
  1079.     if (pattern->type == CAIRO_PATTERN_TYPE_MESH)
  1080.         return FALSE;
  1081.  
  1082.     if (display->buggy_pad_reflect) {
  1083.         if (pattern->extend == CAIRO_EXTEND_REPEAT || pattern->extend == CAIRO_EXTEND_PAD)
  1084.             return FALSE;
  1085.     }
  1086.  
  1087.     if (display->buggy_gradients) {
  1088.         if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR || pattern->type == CAIRO_PATTERN_TYPE_RADIAL)
  1089.             return FALSE;
  1090.     }
  1091.  
  1092.     if (! CAIRO_RENDER_HAS_PICTURE_TRANSFORM (display)) {
  1093.         if (!_cairo_matrix_is_integer_translation (&pattern->matrix, NULL, NULL))
  1094.             return FALSE;
  1095.     }
  1096.  
  1097.     if (! CAIRO_RENDER_HAS_FILTERS (display)) {
  1098.             /* No filters implies no transforms, so we optimise away BILINEAR */
  1099.     }
  1100.  
  1101.     return TRUE;
  1102. }
  1103. cairo_surface_t *
  1104. _cairo_xlib_source_create_for_pattern (cairo_surface_t *_dst,
  1105.                                        const cairo_pattern_t *pattern,
  1106.                                        cairo_bool_t is_mask,
  1107.                                        const cairo_rectangle_int_t *extents,
  1108.                                        const cairo_rectangle_int_t *sample,
  1109.                                        int *src_x, int *src_y)
  1110. {
  1111.     cairo_xlib_surface_t *dst = (cairo_xlib_surface_t *)_dst;
  1112.  
  1113.     *src_x = *src_y = 0;
  1114.  
  1115.     if (pattern == NULL || pattern->type == CAIRO_PATTERN_TYPE_SOLID) {
  1116.         if (pattern == NULL)
  1117.             pattern = &_cairo_pattern_white.base;
  1118.  
  1119.         return solid_source (dst, &((cairo_solid_pattern_t *)pattern)->color);
  1120.     }
  1121.  
  1122.     if (pattern_is_supported (dst->display, pattern)) {
  1123.         if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
  1124.             cairo_surface_pattern_t *spattern = (cairo_surface_pattern_t *)pattern;
  1125.             if (spattern->surface->type == CAIRO_SURFACE_TYPE_XLIB &&
  1126.                 _cairo_xlib_surface_same_screen (dst,
  1127.                                                  unwrap_source (spattern)))
  1128.                 return native_source (dst, spattern, is_mask,
  1129.                                       extents, sample,
  1130.                                       src_x, src_y);
  1131.  
  1132.             if (spattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING)
  1133.                 return record_source (dst, spattern, is_mask,
  1134.                                       extents, sample,
  1135.                                       src_x, src_y);
  1136.  
  1137.             return surface_source (dst, spattern, is_mask,
  1138.                                    extents, sample,
  1139.                                    src_x, src_y);
  1140.         }
  1141.  
  1142.         if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR ||
  1143.             pattern->type == CAIRO_PATTERN_TYPE_RADIAL)
  1144.         {
  1145.             cairo_gradient_pattern_t *gpattern = (cairo_gradient_pattern_t *)pattern;
  1146.             return gradient_source (dst, gpattern, is_mask, extents, src_x, src_y);
  1147.         }
  1148.     }
  1149.  
  1150.     return render_pattern (dst, pattern, is_mask, extents, src_x, src_y);
  1151. }
  1152.  
  1153. #endif /* !CAIRO_HAS_XLIB_XCB_FUNCTIONS */
  1154.