Back to index

lightning-sunbird  0.9+nobinonly
cairo-glitz-surface.c
Go to the documentation of this file.
00001 /* cairo - a vector graphics library with display and print output
00002  *
00003  * Copyright © 2004 David Reveman
00004  *
00005  * Permission to use, copy, modify, distribute, and sell this software
00006  * and its documentation for any purpose is hereby granted without
00007  * fee, provided that the above copyright notice appear in all copies
00008  * and that both that copyright notice and this permission notice
00009  * appear in supporting documentation, and that the name of David
00010  * Reveman not be used in advertising or publicity pertaining to
00011  * distribution of the software without specific, written prior
00012  * permission. David Reveman makes no representations about the
00013  * suitability of this software for any purpose.  It is provided "as
00014  * is" without express or implied warranty.
00015  *
00016  * DAVID REVEMAN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
00017  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
00018  * FITNESS, IN NO EVENT SHALL DAVID REVEMAN BE LIABLE FOR ANY SPECIAL,
00019  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
00020  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
00021  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
00022  * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00023  *
00024  * Author: David Reveman <davidr@novell.com>
00025  */
00026 
00027 #include "cairoint.h"
00028 #include "cairo-glitz.h"
00029 
00030 typedef struct _cairo_glitz_surface {
00031     cairo_surface_t   base;
00032 
00033     glitz_surface_t   *surface;
00034     glitz_format_t    *format;
00035     pixman_region16_t *clip;
00036 } cairo_glitz_surface_t;
00037 
00038 static cairo_status_t
00039 _cairo_glitz_surface_finish (void *abstract_surface)
00040 {
00041     cairo_glitz_surface_t *surface = abstract_surface;
00042 
00043     if (surface->clip)
00044     {
00045        glitz_surface_set_clip_region (surface->surface, 0, 0, NULL, 0);
00046        pixman_region_destroy (surface->clip);
00047     }
00048     
00049     glitz_surface_destroy (surface->surface);
00050 
00051     return CAIRO_STATUS_SUCCESS;
00052 }
00053 
00054 static glitz_format_name_t
00055 _glitz_format_from_content (cairo_content_t content)
00056 {
00057     switch (content) {
00058     case CAIRO_CONTENT_COLOR:
00059        return GLITZ_STANDARD_RGB24;
00060     case CAIRO_CONTENT_ALPHA:
00061        return GLITZ_STANDARD_A8;
00062     case CAIRO_CONTENT_COLOR_ALPHA:
00063        return GLITZ_STANDARD_ARGB32;
00064     }
00065 
00066     ASSERT_NOT_REACHED;
00067     return GLITZ_STANDARD_ARGB32;
00068 }
00069 
00070 static cairo_surface_t *
00071 _cairo_glitz_surface_create_similar (void     *abstract_src,
00072                                  cairo_content_t content,
00073                                  int           width,
00074                                  int           height)
00075 {
00076     cairo_glitz_surface_t *src = abstract_src;
00077     cairo_surface_t    *crsurface;
00078     glitz_drawable_t   *drawable;
00079     glitz_surface_t    *surface;
00080     glitz_format_t     *gformat;
00081 
00082     drawable = glitz_surface_get_drawable (src->surface);
00083     
00084     gformat = glitz_find_standard_format (drawable,
00085                                      _glitz_format_from_content (content));
00086     if (!gformat) {
00087        _cairo_error (CAIRO_STATUS_NO_MEMORY);
00088        return (cairo_surface_t*) &_cairo_surface_nil;
00089     }
00090     
00091     surface = glitz_surface_create (drawable, gformat, width, height, 0, NULL);
00092     if (surface == NULL) {
00093        _cairo_error (CAIRO_STATUS_NO_MEMORY);
00094        return (cairo_surface_t*) &_cairo_surface_nil;
00095     }
00096 
00097     crsurface = cairo_glitz_surface_create (surface);
00098     
00099     glitz_surface_destroy (surface);
00100 
00101     return crsurface;
00102 }
00103 
00104 static cairo_status_t
00105 _cairo_glitz_surface_get_image (cairo_glitz_surface_t *surface,
00106                             cairo_rectangle_t     *interest,
00107                             cairo_image_surface_t **image_out,
00108                             cairo_rectangle_t     *rect_out)
00109 {
00110     cairo_image_surface_t *image;
00111     int                       x1, y1, x2, y2;
00112     int                       width, height;
00113     unsigned char      *pixels;
00114     cairo_format_masks_t  format;
00115     glitz_buffer_t     *buffer;
00116     glitz_pixel_format_t  pf;
00117 
00118     x1 = 0;
00119     y1 = 0;
00120     x2 = glitz_surface_get_width (surface->surface);
00121     y2 = glitz_surface_get_height (surface->surface);
00122 
00123     if (interest)
00124     {
00125        if (interest->x > x1)
00126            x1 = interest->x;
00127        if (interest->y > y1)
00128            y1 = interest->y;
00129        if (interest->x + interest->width < x2)
00130            x2 = interest->x + interest->width;
00131        if (interest->y + interest->height < y2)
00132            y2 = interest->y + interest->height;
00133 
00134        if (x1 >= x2 || y1 >= y2)
00135        {
00136            *image_out = NULL;
00137            return CAIRO_STATUS_SUCCESS;
00138        }
00139     }
00140 
00141     width  = x2 - x1;
00142     height = y2 - y1;
00143 
00144     if (rect_out)
00145     {
00146        rect_out->x = x1;
00147        rect_out->y = y1;
00148        rect_out->width = width;
00149        rect_out->height = height;
00150     }
00151     
00152     if (surface->format->type == GLITZ_FORMAT_TYPE_COLOR) {
00153        if (surface->format->color.red_size > 0) {
00154            format.bpp = 32;
00155            
00156            if (surface->format->color.alpha_size > 0)
00157               format.alpha_mask = 0xff000000;
00158            else
00159               format.alpha_mask = 0x0;
00160            
00161            format.red_mask = 0xff0000;
00162            format.green_mask = 0xff00;
00163            format.blue_mask = 0xff;
00164        } else {
00165            format.bpp = 8;
00166            format.blue_mask = format.green_mask = format.red_mask = 0x0;
00167            format.alpha_mask = 0xff;
00168        }
00169     } else {
00170        format.bpp = 32;
00171        format.alpha_mask = 0xff000000;
00172        format.red_mask = 0xff0000;
00173        format.green_mask = 0xff00;
00174        format.blue_mask = 0xff;
00175     }
00176 
00177     pf.masks.bpp = format.bpp;
00178     pf.masks.alpha_mask = format.alpha_mask;
00179     pf.masks.red_mask = format.red_mask;
00180     pf.masks.green_mask = format.green_mask;
00181     pf.masks.blue_mask = format.blue_mask;
00182     pf.xoffset = 0;
00183     pf.skip_lines = 0;
00184 
00185     /* XXX: we should eventually return images with negative stride,
00186        need to verify that libpixman have no problem with this first. */
00187     pf.bytes_per_line = (((width * format.bpp) / 8) + 3) & -4;
00188     pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_TOP_DOWN;
00189 
00190     pixels = malloc (height * pf.bytes_per_line);
00191     if (!pixels)
00192        return CAIRO_STATUS_NO_MEMORY;
00193 
00194     buffer = glitz_buffer_create_for_data (pixels);
00195     if (!buffer) {
00196        free (pixels);
00197        return CAIRO_STATUS_NO_MEMORY;
00198     }
00199     
00200     glitz_get_pixels (surface->surface,
00201                     x1, y1,
00202                     width, height,
00203                     &pf,
00204                     buffer);
00205 
00206     glitz_buffer_destroy (buffer);
00207     
00208     image = (cairo_image_surface_t *)
00209         _cairo_image_surface_create_with_masks (pixels,
00210                                           &format,
00211                                           width, height,
00212                                           pf.bytes_per_line);
00213     if (image->base.status)
00214     {
00215        free (pixels);
00216        return CAIRO_STATUS_NO_MEMORY;
00217     }
00218 
00219     _cairo_image_surface_assume_ownership_of_data (image);
00220 
00221     *image_out = image;
00222 
00223     return CAIRO_STATUS_SUCCESS;
00224 }
00225 
00226 static cairo_status_t
00227 _cairo_glitz_surface_set_image (void                   *abstract_surface,
00228                             cairo_image_surface_t *image,
00229                             int                 x_dst,
00230                             int                 y_dst)
00231 {
00232     cairo_glitz_surface_t *surface = abstract_surface;
00233     glitz_buffer_t     *buffer;
00234     glitz_pixel_format_t  pf;
00235     pixman_format_t    *format;
00236     int                       am, rm, gm, bm;
00237     char               *data;
00238     
00239     format = pixman_image_get_format (image->pixman_image);
00240     if (!format)
00241        return CAIRO_STATUS_NO_MEMORY;
00242 
00243     pixman_format_get_masks (format, &pf.masks.bpp, &am, &rm, &gm, &bm);
00244 
00245     pf.masks.alpha_mask = am;
00246     pf.masks.red_mask = rm;
00247     pf.masks.green_mask = gm;
00248     pf.masks.blue_mask = bm;
00249     pf.xoffset = 0;
00250     pf.skip_lines = 0;
00251 
00252     /* check for negative stride */
00253     if (image->stride < 0)
00254     {
00255        pf.bytes_per_line = -image->stride;
00256        pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_BOTTOM_UP;
00257        data = (char *) image->data + image->stride * (image->height - 1);
00258     }
00259     else
00260     {
00261        pf.bytes_per_line = image->stride;
00262        pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_TOP_DOWN;
00263        data = (char *) image->data;
00264     }
00265 
00266     buffer = glitz_buffer_create_for_data (data);
00267     if (!buffer)
00268        return CAIRO_STATUS_NO_MEMORY;
00269     
00270     glitz_set_pixels (surface->surface,
00271                     x_dst, y_dst,
00272                     image->width, image->height,
00273                     &pf,
00274                     buffer);
00275     
00276     glitz_buffer_destroy (buffer);
00277     
00278     return CAIRO_STATUS_SUCCESS;
00279 }
00280 
00281 static cairo_status_t
00282 _cairo_glitz_surface_acquire_source_image (void              *abstract_surface,
00283                                       cairo_image_surface_t **image_out,
00284                                       void                  **image_extra)
00285 {
00286     cairo_glitz_surface_t *surface = abstract_surface;
00287 
00288     *image_extra = NULL;
00289     
00290     return _cairo_glitz_surface_get_image (surface, NULL, image_out, NULL);
00291 }
00292 
00293 static void
00294 _cairo_glitz_surface_release_source_image (void              *abstract_surface,
00295                                       cairo_image_surface_t *image,
00296                                       void                  *image_extra)
00297 {
00298     cairo_surface_destroy (&image->base);
00299 }
00300 
00301 static cairo_status_t
00302 _cairo_glitz_surface_acquire_dest_image (void                *abstract_surface,
00303                                     cairo_rectangle_t     *interest_rect,
00304                                     cairo_image_surface_t **image_out,
00305                                     cairo_rectangle_t     *image_rect_out,
00306                                     void                  **image_extra)
00307 {
00308     cairo_glitz_surface_t *surface = abstract_surface;
00309     cairo_image_surface_t *image;
00310     cairo_status_t     status;
00311 
00312     status = _cairo_glitz_surface_get_image (surface, interest_rect, &image,
00313                                         image_rect_out);
00314     if (status)
00315        return status;
00316 
00317     *image_out   = image;
00318     *image_extra = NULL;
00319 
00320     return status;
00321 }
00322 
00323 static void
00324 _cairo_glitz_surface_release_dest_image (void                *abstract_surface,
00325                                     cairo_rectangle_t     *interest_rect,
00326                                     cairo_image_surface_t *image,
00327                                     cairo_rectangle_t     *image_rect,
00328                                     void                  *image_extra)
00329 {
00330     cairo_glitz_surface_t *surface = abstract_surface;
00331 
00332     _cairo_glitz_surface_set_image (surface, image,
00333                                 image_rect->x, image_rect->y);
00334 
00335     cairo_surface_destroy (&image->base);
00336 }
00337 
00338 
00339 static cairo_status_t
00340 _cairo_glitz_surface_clone_similar (void      *abstract_surface,
00341                                 cairo_surface_t *src,
00342                                 cairo_surface_t **clone_out)
00343 {
00344     cairo_glitz_surface_t *surface = abstract_surface;
00345     cairo_glitz_surface_t *clone;
00346 
00347     if (surface->base.status)
00348        return surface->base.status;
00349 
00350     if (src->backend == surface->base.backend)
00351     {
00352        *clone_out = cairo_surface_reference (src);      
00353        
00354        return CAIRO_STATUS_SUCCESS;
00355     }
00356     else if (_cairo_surface_is_image (src))
00357     {
00358        cairo_image_surface_t *image_src = (cairo_image_surface_t *) src;
00359        cairo_content_t content = _cairo_content_from_format (image_src->format);
00360     
00361        clone = (cairo_glitz_surface_t *)
00362            _cairo_glitz_surface_create_similar (surface, content,
00363                                            image_src->width,
00364                                            image_src->height);
00365        if (clone->base.status)
00366            return CAIRO_STATUS_NO_MEMORY;
00367 
00368        _cairo_glitz_surface_set_image (clone, image_src, 0, 0);
00369        
00370        *clone_out = &clone->base;
00371 
00372        return CAIRO_STATUS_SUCCESS;
00373     }
00374     
00375     return CAIRO_INT_STATUS_UNSUPPORTED;
00376 }
00377 
00378 static void
00379 _cairo_glitz_surface_set_matrix (cairo_glitz_surface_t *surface,
00380                              cairo_matrix_t             *matrix)
00381 {
00382     glitz_transform_t transform;
00383 
00384     transform.matrix[0][0] = _cairo_fixed_from_double (matrix->xx);
00385     transform.matrix[0][1] = _cairo_fixed_from_double (matrix->xy);
00386     transform.matrix[0][2] = _cairo_fixed_from_double (matrix->x0);
00387 
00388     transform.matrix[1][0] = _cairo_fixed_from_double (matrix->yx);
00389     transform.matrix[1][1] = _cairo_fixed_from_double (matrix->yy);
00390     transform.matrix[1][2] = _cairo_fixed_from_double (matrix->y0);
00391 
00392     transform.matrix[2][0] = 0;
00393     transform.matrix[2][1] = 0;
00394     transform.matrix[2][2] = _cairo_fixed_from_double (1);
00395 
00396     glitz_surface_set_transform (surface->surface, &transform);
00397 }
00398 
00399 static glitz_operator_t
00400 _glitz_operator (cairo_operator_t op)
00401 {
00402     switch (op) {
00403     case CAIRO_OPERATOR_CLEAR:
00404        return GLITZ_OPERATOR_CLEAR;
00405 
00406     case CAIRO_OPERATOR_SOURCE:
00407        return GLITZ_OPERATOR_SRC;
00408     case CAIRO_OPERATOR_OVER:
00409        return GLITZ_OPERATOR_OVER;
00410     case CAIRO_OPERATOR_IN:
00411        return GLITZ_OPERATOR_IN;
00412     case CAIRO_OPERATOR_OUT:
00413        return GLITZ_OPERATOR_OUT;
00414     case CAIRO_OPERATOR_ATOP:
00415        return GLITZ_OPERATOR_ATOP;
00416 
00417     case CAIRO_OPERATOR_DEST:
00418        return GLITZ_OPERATOR_DST;
00419     case CAIRO_OPERATOR_DEST_OVER:
00420        return GLITZ_OPERATOR_OVER_REVERSE;
00421     case CAIRO_OPERATOR_DEST_IN:
00422        return GLITZ_OPERATOR_IN_REVERSE;
00423     case CAIRO_OPERATOR_DEST_OUT:
00424        return GLITZ_OPERATOR_OUT_REVERSE;
00425     case CAIRO_OPERATOR_DEST_ATOP:
00426        return GLITZ_OPERATOR_ATOP_REVERSE;
00427 
00428     case CAIRO_OPERATOR_XOR:
00429        return GLITZ_OPERATOR_XOR;
00430     case CAIRO_OPERATOR_ADD:
00431        return GLITZ_OPERATOR_ADD;
00432     case CAIRO_OPERATOR_SATURATE:
00433        /* XXX: OVER is definitely not the right thing here, (but it
00434         * is what the original glitz backend code has always
00435         * done). Cairo's SATURATE operator is the native GL
00436         * compositing mode, (from my understanding). So why isn't
00437         * there a GLITZ_OPERATOR_SATURATE for us to use here? */
00438        return GLITZ_OPERATOR_OVER;
00439     }
00440 
00441     ASSERT_NOT_REACHED;
00442 
00443     /* Something's very broken if this line of code can be reached, so
00444        we want to return something that would give a noticeably
00445        incorrect result. The XOR operator seems so rearely desired
00446        that it should fit the bill here. */
00447     return CAIRO_OPERATOR_XOR;
00448 }
00449 
00450 #define CAIRO_GLITZ_FEATURE_OK(surface, name)                           \
00451     (glitz_drawable_get_features (glitz_surface_get_drawable (surface)) & \
00452      (GLITZ_FEATURE_ ## name ## _MASK))
00453 
00454 static glitz_status_t
00455 _glitz_ensure_target (glitz_surface_t *surface)
00456 {
00457     if (glitz_surface_get_attached_drawable (surface) ||
00458        CAIRO_GLITZ_FEATURE_OK (surface, FRAMEBUFFER_OBJECT))
00459        return CAIRO_STATUS_SUCCESS;
00460 
00461     return CAIRO_INT_STATUS_UNSUPPORTED;
00462 }
00463 
00464 typedef struct _cairo_glitz_surface_attributes {
00465     cairo_surface_attributes_t     base;
00466     
00467     glitz_fill_t            fill;
00468     glitz_filter_t          filter;
00469     glitz_fixed16_16_t             *params;
00470     int                            n_params;
00471     cairo_bool_t            acquired;
00472 } cairo_glitz_surface_attributes_t;
00473 
00474 static cairo_int_status_t
00475 _cairo_glitz_pattern_acquire_surface (cairo_pattern_t                 *pattern,
00476                                   cairo_glitz_surface_t        *dst,
00477                                   int                          x,
00478                                   int                          y,
00479                                   unsigned int                 width,
00480                                   unsigned int                 height,
00481                                   cairo_glitz_surface_t  **surface_out,
00482                                   cairo_glitz_surface_attributes_t *attr)
00483 {
00484     cairo_glitz_surface_t *src = NULL;
00485 
00486     attr->acquired = FALSE;
00487 
00488     switch (pattern->type) {
00489     case CAIRO_PATTERN_LINEAR:
00490     case CAIRO_PATTERN_RADIAL: {
00491        cairo_gradient_pattern_t    *gradient =
00492            (cairo_gradient_pattern_t *) pattern;
00493        char                     *data;
00494        glitz_fixed16_16_t       *params;
00495        int                      n_params;
00496        unsigned int             *pixels;
00497        int                      i;
00498        unsigned char            alpha;
00499        glitz_buffer_t                  *buffer;
00500        static glitz_pixel_format_t format = {
00501             {
00502                 32,
00503                 0xff000000,
00504                 0x00ff0000,
00505                 0x0000ff00,
00506                 0x000000ff
00507             },
00508             0, 0, 0,
00509             GLITZ_PIXEL_SCANLINE_ORDER_BOTTOM_UP
00510         };
00511        
00512        /* XXX: the current color gradient acceleration provided by glitz is
00513         * experimental, it's been proven inappropriate in a number of ways,
00514         * most importantly, it's currently implemented as filters and
00515         * gradients are not filters. eventually, it will be replaced with
00516         * something more appropriate.
00517         */
00518 
00519        if (gradient->n_stops < 2)
00520            break;
00521 
00522        /* glitz doesn't support inner and outer circle with different
00523           center points. */
00524        if (pattern->type == CAIRO_PATTERN_RADIAL)
00525        {
00526            cairo_radial_pattern_t *grad = (cairo_radial_pattern_t *) pattern;
00527            
00528            if (grad->center0.x != grad->center1.x ||
00529               grad->center0.y != grad->center1.y)
00530               break;
00531        }
00532 
00533        if (!CAIRO_GLITZ_FEATURE_OK (dst->surface, FRAGMENT_PROGRAM))
00534            break;
00535        
00536        if (pattern->filter != CAIRO_FILTER_BILINEAR &&
00537            pattern->filter != CAIRO_FILTER_GOOD &&
00538            pattern->filter != CAIRO_FILTER_BEST)
00539            break;
00540 
00541        alpha = gradient->stops[0].color.alpha * 0xff;
00542        for (i = 1; i < gradient->n_stops; i++)
00543        {
00544            unsigned char a;
00545            
00546            a = gradient->stops[i].color.alpha * 0xff;
00547            if (a != alpha)
00548               break;
00549        }
00550 
00551        /* we can't have color stops with different alpha as gradient color
00552           interpolation should be done to unpremultiplied colors. */
00553        if (i < gradient->n_stops)
00554            break;
00555 
00556        n_params = gradient->n_stops * 3 + 4;
00557 
00558        data = malloc (sizeof (glitz_fixed16_16_t) * n_params +
00559                      sizeof (unsigned int) * gradient->n_stops);
00560        if (!data)
00561            return CAIRO_STATUS_NO_MEMORY;
00562 
00563        params = (glitz_fixed16_16_t *) data;
00564        pixels = (unsigned int *)
00565            (data + sizeof (glitz_fixed16_16_t) * n_params);
00566 
00567        buffer = glitz_buffer_create_for_data (pixels);
00568        if (!buffer)
00569        {
00570            free (data);
00571            return CAIRO_STATUS_NO_MEMORY;
00572        }
00573 
00574        src = (cairo_glitz_surface_t *)
00575            _cairo_surface_create_similar_scratch (&dst->base,
00576                                              CAIRO_CONTENT_COLOR_ALPHA,
00577                                              gradient->n_stops, 1);
00578        if (src->base.status)
00579        {
00580            glitz_buffer_destroy (buffer);
00581            free (data);
00582            return CAIRO_STATUS_NO_MEMORY;
00583        }
00584 
00585        for (i = 0; i < gradient->n_stops; i++)
00586        {
00587            pixels[i] =
00588                 (((int) alpha) << 24)                                  |
00589                 (((int) gradient->stops[i].color.red   * alpha) << 16) |
00590                 (((int) gradient->stops[i].color.green * alpha) << 8)  |
00591                 (((int) gradient->stops[i].color.blue  * alpha));
00592            
00593            params[4 + 3 * i] = gradient->stops[i].offset;
00594            params[5 + 3 * i] = i << 16;
00595            params[6 + 3 * i] = 0;
00596        }
00597 
00598        glitz_set_pixels (src->surface, 0, 0, gradient->n_stops, 1,
00599                        &format, buffer);
00600 
00601        glitz_buffer_destroy (buffer);
00602 
00603        if (pattern->type == CAIRO_PATTERN_LINEAR)
00604        {
00605            cairo_linear_pattern_t *grad = (cairo_linear_pattern_t *) pattern;
00606            
00607            params[0] = _cairo_fixed_from_double (grad->point0.x);
00608            params[1] = _cairo_fixed_from_double (grad->point0.y);
00609            params[2] = _cairo_fixed_from_double (grad->point1.x);
00610            params[3] = _cairo_fixed_from_double (grad->point1.y);
00611            attr->filter = GLITZ_FILTER_LINEAR_GRADIENT;
00612        }
00613        else
00614        {
00615            cairo_radial_pattern_t *grad = (cairo_radial_pattern_t *) pattern;
00616            
00617            params[0] = _cairo_fixed_from_double (grad->center0.x);
00618            params[1] = _cairo_fixed_from_double (grad->center0.y);
00619            params[2] = _cairo_fixed_from_double (grad->radius0);
00620            params[3] = _cairo_fixed_from_double (grad->radius1);
00621            attr->filter = GLITZ_FILTER_RADIAL_GRADIENT;
00622        }
00623 
00624        switch (pattern->extend) {
00625        case CAIRO_EXTEND_NONE:
00626            attr->fill = GLITZ_FILL_NEAREST;
00627            break;
00628        case CAIRO_EXTEND_REPEAT:
00629            attr->fill = GLITZ_FILL_REPEAT;
00630            break;
00631        case CAIRO_EXTEND_REFLECT:
00632            attr->fill = GLITZ_FILL_REFLECT;
00633            break;
00634        }
00635 
00636        attr->params      = params;
00637        attr->n_params           = n_params;
00638        attr->base.matrix   = pattern->matrix;
00639        attr->base.x_offset = 0;
00640        attr->base.y_offset = 0;
00641     } break;
00642     default:
00643        break;
00644     }
00645 
00646     if (!src)
00647     {
00648        cairo_int_status_t status;
00649 
00650        status = _cairo_pattern_acquire_surface (pattern, &dst->base,
00651                                            x, y, width, height,
00652                                            (cairo_surface_t **) &src,
00653                                            &attr->base);
00654        if (status)
00655            return status;
00656        
00657        if (src)
00658        {
00659            switch (attr->base.extend) {
00660            case CAIRO_EXTEND_NONE:
00661               attr->fill = GLITZ_FILL_TRANSPARENT;
00662               break;
00663            case CAIRO_EXTEND_REPEAT:
00664               attr->fill = GLITZ_FILL_REPEAT;
00665               break;
00666            case CAIRO_EXTEND_REFLECT:
00667               attr->fill = GLITZ_FILL_REFLECT;
00668               break;
00669            }
00670 
00671            switch (attr->base.filter) {
00672            case CAIRO_FILTER_FAST:
00673            case CAIRO_FILTER_NEAREST:
00674               attr->filter = GLITZ_FILTER_NEAREST;
00675               break;
00676            case CAIRO_FILTER_GOOD:
00677            case CAIRO_FILTER_BEST:
00678            case CAIRO_FILTER_BILINEAR:
00679            default:
00680               attr->filter = GLITZ_FILTER_BILINEAR;
00681               break;
00682            }
00683            
00684            attr->params   = NULL;
00685            attr->n_params = 0;
00686            attr->acquired = TRUE;
00687        }
00688     }
00689 
00690     *surface_out = src;
00691     
00692     return CAIRO_STATUS_SUCCESS;
00693 }
00694 
00695 static void
00696 _cairo_glitz_pattern_release_surface (cairo_pattern_t                *pattern,
00697                                   cairo_glitz_surface_t       *surface,
00698                                   cairo_glitz_surface_attributes_t *attr)
00699 {
00700     if (attr->acquired)
00701        _cairo_pattern_release_surface (pattern, &surface->base, &attr->base);
00702     else
00703        cairo_surface_destroy (&surface->base);
00704 }
00705 
00706 static cairo_int_status_t
00707 _cairo_glitz_pattern_acquire_surfaces (cairo_pattern_t                  *src,
00708                                    cairo_pattern_t                      *mask,
00709                                    cairo_glitz_surface_t               *dst,
00710                                    int                          src_x,
00711                                    int                          src_y,
00712                                    int                          mask_x,
00713                                    int                          mask_y,
00714                                    unsigned int                 width,
00715                                    unsigned int                 height,
00716                                    cairo_glitz_surface_t           **src_out,
00717                                    cairo_glitz_surface_t           **mask_out,
00718                                    cairo_glitz_surface_attributes_t *sattr,
00719                                    cairo_glitz_surface_attributes_t *mattr)
00720 {
00721     cairo_int_status_t        status;
00722     cairo_pattern_union_t tmp;
00723 
00724     /* If src and mask are both solid, then the mask alpha can be
00725      * combined into src and mask can be ignored. */
00726 
00727     /* XXX: This optimization assumes that there is no color
00728      * information in mask, so this will need to change when we
00729      * support RENDER-style 4-channel masks. */
00730 
00731     if (src->type == CAIRO_PATTERN_SOLID &&
00732        mask->type == CAIRO_PATTERN_SOLID)
00733     {
00734        cairo_color_t combined;
00735        cairo_solid_pattern_t *src_solid = (cairo_solid_pattern_t *) src;
00736        cairo_solid_pattern_t *mask_solid = (cairo_solid_pattern_t *) mask;
00737 
00738        combined = src_solid->color;
00739        _cairo_color_multiply_alpha (&combined, mask_solid->color.alpha);
00740 
00741        _cairo_pattern_init_solid (&tmp.solid, &combined);
00742 
00743        mask = NULL;
00744     } else {
00745        _cairo_pattern_init_copy (&tmp.base, src);
00746     }
00747        
00748     status = _cairo_glitz_pattern_acquire_surface (&tmp.base, dst,
00749                                              src_x, src_y,
00750                                              width, height,
00751                                              src_out, sattr);
00752     
00753     _cairo_pattern_fini (&tmp.base);
00754 
00755     if (status)
00756        return status;
00757 
00758     if (mask)
00759     {
00760        _cairo_pattern_init_copy (&tmp.base, mask);
00761        
00762        status = _cairo_glitz_pattern_acquire_surface (&tmp.base, dst,
00763                                                  mask_x, mask_y,
00764                                                  width, height,
00765                                                  mask_out, mattr);
00766     
00767        if (status)
00768            _cairo_glitz_pattern_release_surface (&tmp.base, *src_out, sattr);
00769 
00770        _cairo_pattern_fini (&tmp.base);
00771 
00772        return status;
00773     }
00774     else
00775     {
00776        *mask_out = NULL;
00777     }
00778 
00779     return CAIRO_STATUS_SUCCESS;
00780 }
00781 
00782 static void
00783 _cairo_glitz_surface_set_attributes (cairo_glitz_surface_t           *surface,
00784                                  cairo_glitz_surface_attributes_t *a)
00785 {
00786     _cairo_glitz_surface_set_matrix (surface, &a->base.matrix);
00787     glitz_surface_set_fill (surface->surface, a->fill);
00788     glitz_surface_set_filter (surface->surface, a->filter,
00789                            a->params, a->n_params);
00790 }
00791 
00792 static cairo_int_status_t
00793 _cairo_glitz_surface_composite (cairo_operator_t op,
00794                             cairo_pattern_t  *src_pattern,
00795                             cairo_pattern_t  *mask_pattern,
00796                             void           *abstract_dst,
00797                             int            src_x,
00798                             int            src_y,
00799                             int            mask_x,
00800                             int            mask_y,
00801                             int            dst_x,
00802                             int            dst_y,
00803                             unsigned int   width,
00804                             unsigned int   height)
00805 {
00806     cairo_glitz_surface_attributes_t      src_attr, mask_attr;
00807     cairo_glitz_surface_t          *dst = abstract_dst;
00808     cairo_glitz_surface_t          *src;
00809     cairo_glitz_surface_t          *mask;
00810     cairo_int_status_t                    status;
00811 
00812     if (op == CAIRO_OPERATOR_SATURATE)
00813        return CAIRO_INT_STATUS_UNSUPPORTED;
00814 
00815     if (_glitz_ensure_target (dst->surface))
00816        return CAIRO_INT_STATUS_UNSUPPORTED;
00817 
00818     status = _cairo_glitz_pattern_acquire_surfaces (src_pattern, mask_pattern,
00819                                               dst,
00820                                               src_x, src_y,
00821                                               mask_x, mask_y,
00822                                               width, height,
00823                                               &src, &mask,
00824                                               &src_attr, &mask_attr);
00825     if (status)
00826        return status;
00827 
00828     _cairo_glitz_surface_set_attributes (src, &src_attr);
00829     if (mask)
00830     {
00831        _cairo_glitz_surface_set_attributes (mask, &mask_attr);
00832        glitz_composite (_glitz_operator (op),
00833                       src->surface,
00834                       mask->surface,
00835                       dst->surface,
00836                       src_x + src_attr.base.x_offset,
00837                       src_y + src_attr.base.y_offset,
00838                       mask_x + mask_attr.base.x_offset,
00839                       mask_y + mask_attr.base.y_offset,
00840                       dst_x, dst_y,
00841                       width, height);
00842        
00843        if (mask_attr.n_params)
00844            free (mask_attr.params);
00845        
00846        _cairo_glitz_pattern_release_surface (mask_pattern, mask, &mask_attr);
00847     }
00848     else
00849     {    
00850        glitz_composite (_glitz_operator (op),
00851                       src->surface,
00852                       NULL,
00853                       dst->surface,
00854                       src_x + src_attr.base.x_offset,
00855                       src_y + src_attr.base.y_offset,
00856                       0, 0,
00857                       dst_x, dst_y,
00858                       width, height);
00859     }
00860 
00861     if (src_attr.n_params)
00862        free (src_attr.params);
00863 
00864     _cairo_glitz_pattern_release_surface (src_pattern, src, &src_attr);
00865 
00866     if (glitz_surface_get_status (dst->surface) == GLITZ_STATUS_NOT_SUPPORTED)
00867        return CAIRO_INT_STATUS_UNSUPPORTED;
00868     
00869     return CAIRO_STATUS_SUCCESS;
00870 }
00871 
00872 static cairo_int_status_t
00873 _cairo_glitz_surface_fill_rectangles (void                *abstract_dst,
00874                                   cairo_operator_t        op,
00875                                   const cairo_color_t *color,
00876                                   cairo_rectangle_t       *rects,
00877                                   int              n_rects)
00878 {
00879     cairo_glitz_surface_t *dst = abstract_dst;
00880 
00881     if (op == CAIRO_OPERATOR_SOURCE)
00882     {
00883        glitz_color_t glitz_color;
00884 
00885        glitz_color.red = color->red_short;
00886        glitz_color.green = color->green_short;
00887        glitz_color.blue = color->blue_short;
00888        glitz_color.alpha = color->alpha_short;
00889 
00890        glitz_set_rectangles (dst->surface, &glitz_color,
00891                            (glitz_rectangle_t *) rects, n_rects);
00892     }
00893     else
00894     {
00895        cairo_glitz_surface_t *src;
00896        
00897        if (op == CAIRO_OPERATOR_SATURATE)
00898            return CAIRO_INT_STATUS_UNSUPPORTED;
00899 
00900        if (_glitz_ensure_target (dst->surface))
00901            return CAIRO_INT_STATUS_UNSUPPORTED;
00902 
00903        src = (cairo_glitz_surface_t *)
00904            _cairo_surface_create_similar_solid (&dst->base,
00905                                            CAIRO_CONTENT_COLOR_ALPHA,
00906                                            1, 1,
00907                                            (cairo_color_t *) color);
00908        if (src->base.status)
00909            return CAIRO_STATUS_NO_MEMORY;
00910 
00911        glitz_surface_set_fill (src->surface, GLITZ_FILL_REPEAT);
00912        
00913        while (n_rects--)
00914        {
00915            glitz_composite (_glitz_operator (op),
00916                           src->surface,
00917                           NULL,
00918                           dst->surface,
00919                           0, 0,
00920                           0, 0,
00921                           rects->x, rects->y,
00922                           rects->width, rects->height);
00923            rects++;
00924        }
00925        
00926        cairo_surface_destroy (&src->base);
00927     }
00928 
00929     if (glitz_surface_get_status (dst->surface) == GLITZ_STATUS_NOT_SUPPORTED)
00930        return CAIRO_INT_STATUS_UNSUPPORTED;
00931 
00932     return CAIRO_STATUS_SUCCESS;
00933 }
00934 
00935 static cairo_int_status_t
00936 _cairo_glitz_surface_composite_trapezoids (cairo_operator_t  op,
00937                                       cairo_pattern_t   *pattern,
00938                                       void                   *abstract_dst,
00939                                       cairo_antialias_t antialias,
00940                                       int             src_x,
00941                                       int             src_y,
00942                                       int             dst_x,
00943                                       int             dst_y,
00944                                       unsigned int           width,
00945                                       unsigned int           height,
00946                                       cairo_trapezoid_t *traps,
00947                                       int             n_traps)
00948 {
00949     cairo_pattern_union_t tmp_src_pattern;
00950     cairo_pattern_t *src_pattern;
00951     cairo_glitz_surface_attributes_t attributes;
00952     cairo_glitz_surface_t        *dst = abstract_dst;
00953     cairo_glitz_surface_t        *src;
00954     cairo_glitz_surface_t        *mask = NULL;
00955     glitz_buffer_t               *buffer = NULL;
00956     void                         *data = NULL;
00957     cairo_int_status_t                  status;
00958     unsigned short               alpha;
00959 
00960     if (dst->base.status)
00961        return dst->base.status;
00962 
00963     if (op == CAIRO_OPERATOR_SATURATE)
00964        return CAIRO_INT_STATUS_UNSUPPORTED;
00965 
00966     if (_glitz_ensure_target (dst->surface))
00967        return CAIRO_INT_STATUS_UNSUPPORTED;
00968 
00969     if (pattern->type == CAIRO_PATTERN_SURFACE)
00970     {
00971        _cairo_pattern_init_copy (&tmp_src_pattern.base, pattern);
00972        
00973        status = _cairo_glitz_pattern_acquire_surface (&tmp_src_pattern.base, dst,
00974                                                  src_x, src_y,
00975                                                  width, height,
00976                                                  &src, &attributes);
00977        src_pattern = &tmp_src_pattern.base;
00978     }
00979     else
00980     {
00981        status = _cairo_glitz_pattern_acquire_surface (pattern, dst,
00982                                                  src_x, src_y,
00983                                                  width, height,
00984                                                  &src, &attributes);
00985        src_pattern = pattern;
00986     }
00987     alpha = 0xffff;
00988 
00989     if (status)
00990        return status;
00991 
00992     if (op == CAIRO_OPERATOR_ADD || n_traps <= 1)
00993     {
00994        static glitz_color_t clear_black = { 0, 0, 0, 0 };
00995        glitz_color_t        color;
00996        glitz_geometry_format_t     format;
00997        int                  n_trap_added;
00998        int                  offset = 0;
00999        int                  data_size = 0;
01000        int                  size = 30 * n_traps; /* just a guess */
01001 
01002        format.vertex.primitive = GLITZ_PRIMITIVE_QUADS;
01003        format.vertex.type = GLITZ_DATA_TYPE_FLOAT;
01004        format.vertex.bytes_per_vertex = 3 * sizeof (glitz_float_t);
01005        format.vertex.attributes = GLITZ_VERTEX_ATTRIBUTE_MASK_COORD_MASK;
01006        format.vertex.mask.type = GLITZ_DATA_TYPE_FLOAT;
01007        format.vertex.mask.size = GLITZ_COORDINATE_SIZE_X;
01008        format.vertex.mask.offset = 2 * sizeof (glitz_float_t);
01009 
01010        mask = (cairo_glitz_surface_t *)
01011            _cairo_glitz_surface_create_similar (&dst->base,
01012                                            CAIRO_CONTENT_ALPHA,
01013                                            2, 1);
01014        if (mask->base.status)
01015        {
01016            _cairo_glitz_pattern_release_surface (src_pattern, src, &attributes);
01017            if (src_pattern == &tmp_src_pattern.base)
01018               _cairo_pattern_fini (&tmp_src_pattern.base);
01019 
01020            return CAIRO_STATUS_NO_MEMORY;
01021        }
01022 
01023        color.red = color.green = color.blue = color.alpha = 0xffff;
01024 
01025        glitz_set_rectangle (mask->surface, &clear_black, 0, 0, 1, 1);
01026        glitz_set_rectangle (mask->surface, &color, 1, 0, 1, 1);
01027 
01028        glitz_surface_set_fill (mask->surface, GLITZ_FILL_NEAREST);
01029        glitz_surface_set_filter (mask->surface,
01030                               GLITZ_FILTER_BILINEAR,
01031                               NULL, 0);
01032        
01033        size *= format.vertex.bytes_per_vertex;
01034        
01035        while (n_traps)
01036        {
01037            if (data_size < size)
01038            {
01039               data_size = size;
01040               data = realloc (data, data_size);
01041               if (!data)
01042               {
01043                   _cairo_glitz_pattern_release_surface (src_pattern, src,
01044                                                    &attributes);
01045                   if (src_pattern == &tmp_src_pattern.base)
01046                      _cairo_pattern_fini (&tmp_src_pattern.base);
01047                   return CAIRO_STATUS_NO_MEMORY;
01048               }
01049 
01050               if (buffer)
01051                   glitz_buffer_destroy (buffer);
01052               
01053               buffer = glitz_buffer_create_for_data (data);
01054               if (!buffer) {
01055                   free (data);
01056                   _cairo_glitz_pattern_release_surface (src_pattern, src,
01057                                                    &attributes);
01058                   if (src_pattern == &tmp_src_pattern.base)
01059                      _cairo_pattern_fini (&tmp_src_pattern.base);
01060                   return CAIRO_STATUS_NO_MEMORY;
01061               }
01062            }
01063     
01064            offset +=
01065               glitz_add_trapezoids (buffer,
01066                                   offset, size - offset,
01067                                   format.vertex.type, mask->surface,
01068                                   (glitz_trapezoid_t *) traps, n_traps,
01069                                   &n_trap_added);
01070               
01071            n_traps -= n_trap_added;
01072            traps   += n_trap_added;
01073            size    *= 2;
01074        }
01075     
01076        glitz_set_geometry (dst->surface,
01077                          GLITZ_GEOMETRY_TYPE_VERTEX,
01078                          &format, buffer);
01079        glitz_set_array (dst->surface, 0, 3,
01080                       offset / format.vertex.bytes_per_vertex,
01081                       0, 0);
01082     }
01083     else
01084     {
01085        cairo_image_surface_t *image;
01086        unsigned char       *ptr;
01087        int                 stride;
01088 
01089        stride = (width + 3) & -4;
01090        data = malloc (stride * height);
01091        if (!data)
01092        {
01093            _cairo_glitz_pattern_release_surface (src_pattern, src, &attributes);
01094            if (src_pattern == &tmp_src_pattern.base)
01095               _cairo_pattern_fini (&tmp_src_pattern.base);
01096            return CAIRO_STATUS_NO_MEMORY;
01097        }
01098 
01099        memset (data, 0, stride * height);
01100 
01101        /* using negative stride */
01102        ptr = (unsigned char *) data + stride * (height - 1);
01103        
01104        image = (cairo_image_surface_t *)
01105            cairo_image_surface_create_for_data (ptr,
01106                                            CAIRO_FORMAT_A8,
01107                                            width, height,
01108                                            -stride);
01109        if (image->base.status)
01110        {
01111            cairo_surface_destroy (&src->base);
01112            free (data);
01113            return CAIRO_STATUS_NO_MEMORY;
01114        }
01115 
01116        pixman_add_trapezoids (image->pixman_image, -dst_x, -dst_y,
01117                             (pixman_trapezoid_t *) traps, n_traps);
01118 
01119        mask = (cairo_glitz_surface_t *)
01120            _cairo_surface_create_similar_scratch (&dst->base,
01121                                              CAIRO_CONTENT_ALPHA,
01122                                              width, height);
01123        if (mask->base.status)
01124        {
01125            _cairo_glitz_pattern_release_surface (src_pattern, src, &attributes);
01126            free (data);
01127            cairo_surface_destroy (&image->base);
01128            return CAIRO_STATUS_NO_MEMORY;
01129        }
01130 
01131        _cairo_glitz_surface_set_image (mask, image, 0, 0);
01132     }
01133 
01134     _cairo_glitz_surface_set_attributes (src, &attributes);
01135     
01136     glitz_composite (_glitz_operator (op),
01137                    src->surface,
01138                    mask->surface,
01139                    dst->surface,
01140                    src_x + attributes.base.x_offset,
01141                    src_y + attributes.base.y_offset,
01142                    0, 0,
01143                    dst_x, dst_y,
01144                    width, height);
01145 
01146     if (attributes.n_params)
01147        free (attributes.params);
01148 
01149     glitz_set_geometry (dst->surface,
01150                      GLITZ_GEOMETRY_TYPE_NONE,
01151                      NULL, NULL);
01152 
01153     if (buffer)
01154        glitz_buffer_destroy (buffer);
01155     
01156     free (data);
01157 
01158     _cairo_glitz_pattern_release_surface (src_pattern, src, &attributes);
01159     if (src_pattern == &tmp_src_pattern.base)
01160        _cairo_pattern_fini (&tmp_src_pattern.base);
01161 
01162     if (mask)
01163        cairo_surface_destroy (&mask->base);
01164 
01165     if (glitz_surface_get_status (dst->surface) == GLITZ_STATUS_NOT_SUPPORTED)
01166        return CAIRO_INT_STATUS_UNSUPPORTED;
01167     
01168     return CAIRO_STATUS_SUCCESS;
01169 }
01170 
01171 static cairo_int_status_t
01172 _cairo_glitz_surface_set_clip_region (void              *abstract_surface,
01173                                   pixman_region16_t *region)
01174 {
01175     cairo_glitz_surface_t *surface = abstract_surface;
01176 
01177     if (region)
01178     {
01179        glitz_box_t *box;
01180        int        n;
01181        
01182        if (!surface->clip)
01183        {
01184            surface->clip = pixman_region_create ();
01185            if (!surface->clip)
01186               return CAIRO_STATUS_NO_MEMORY;
01187        }
01188        pixman_region_copy (surface->clip, region);
01189 
01190        box = (glitz_box_t *) pixman_region_rects (surface->clip);
01191        n = pixman_region_num_rects (surface->clip);
01192        glitz_surface_set_clip_region (surface->surface, 0, 0, box, n);
01193     }
01194     else
01195     {
01196        glitz_surface_set_clip_region (surface->surface, 0, 0, NULL, 0);
01197        
01198        if (surface->clip)
01199            pixman_region_destroy (surface->clip);
01200 
01201        surface->clip = NULL;
01202     }
01203     
01204     return CAIRO_STATUS_SUCCESS;
01205 }
01206 
01207 static cairo_int_status_t
01208 _cairo_glitz_surface_get_extents (void               *abstract_surface,
01209                               cairo_rectangle_t *rectangle)
01210 {
01211     cairo_glitz_surface_t *surface = abstract_surface;
01212 
01213     rectangle->x = 0;
01214     rectangle->y = 0;
01215     rectangle->width = glitz_surface_get_width  (surface->surface);
01216     rectangle->height = glitz_surface_get_height (surface->surface);
01217 
01218     return CAIRO_STATUS_SUCCESS;
01219 }
01220 
01221 #define CAIRO_GLITZ_GLYPH_CACHE_MEMORY_DEFAULT 0x100000
01222 
01223 #define CAIRO_GLITZ_AREA_AVAILABLE 0
01224 #define CAIRO_GLITZ_AREA_DIVIDED   1
01225 #define CAIRO_GLITZ_AREA_OCCUPIED  2
01226 
01227 typedef struct _cairo_glitz_root_area cairo_glitz_root_area_t;
01228 
01229 typedef struct _cairo_glitz_area {
01230     int                          state;
01231     int                          level;
01232     int                          x, y;
01233     int                          width, height;
01234     struct _cairo_glitz_area *area[4];
01235     cairo_glitz_root_area_t  *root;
01236     void                  *closure;
01237 } cairo_glitz_area_t;
01238 
01239 static cairo_glitz_area_t _empty_area = {
01240     0, 0, 0, 0, 0, 0,
01241     { NULL, NULL, NULL, NULL },
01242     NULL,
01243     NULL
01244 };
01245 
01246 typedef struct _cairo_glitz_area_funcs {
01247     cairo_status_t (*move_in)          (cairo_glitz_area_t *area,
01248                                  void            *closure);
01249     
01250     void         (*move_out)           (cairo_glitz_area_t *area,
01251                                  void            *closure);
01252     
01253     int                 (*compare_score) (cairo_glitz_area_t *area,
01254                                  void            *closure1,
01255                                  void            *closure2);
01256 } cairo_glitz_area_funcs_t;
01257 
01258 struct _cairo_glitz_root_area {
01259     int                               max_level;
01260     int                               width, height;
01261     cairo_glitz_area_t                *area;
01262     const cairo_glitz_area_funcs_t *funcs;
01263 };
01264 
01265 static cairo_status_t
01266 _cairo_glitz_area_move_in (cairo_glitz_area_t *area,
01267                         void                    *closure)
01268 {
01269     area->closure = closure;
01270     area->state   = CAIRO_GLITZ_AREA_OCCUPIED;
01271     
01272     return (*area->root->funcs->move_in) (area, area->closure);
01273 }
01274 
01275 static void
01276 _cairo_glitz_area_move_out (cairo_glitz_area_t *area)
01277 {
01278     if (area->root)
01279     {
01280        (*area->root->funcs->move_out) (area, area->closure);
01281 
01282        area->closure = NULL;
01283        area->state   = CAIRO_GLITZ_AREA_AVAILABLE;
01284     }
01285 }
01286 
01287 static cairo_glitz_area_t *
01288 _cairo_glitz_area_create (cairo_glitz_root_area_t *root,
01289                        int                  level,
01290                        int                  x,
01291                        int                  y,
01292                        int                  width,
01293                        int                  height)
01294 {
01295     cairo_glitz_area_t *area;
01296     int                     n = 4;
01297     
01298     area = malloc (sizeof (cairo_glitz_area_t));
01299     if (!area)
01300        return NULL;
01301 
01302     area->level   = level;
01303     area->x     = x;
01304     area->y     = y;
01305     area->width   = width;
01306     area->height  = height;
01307     area->root    = root;
01308     area->closure = NULL;
01309     area->state   = CAIRO_GLITZ_AREA_AVAILABLE;
01310     
01311     while (n--)
01312        area->area[n] = NULL;
01313 
01314     return area;
01315 }
01316 
01317 static void
01318 _cairo_glitz_area_destroy (cairo_glitz_area_t *area)
01319 {   
01320     if (area == NULL)
01321        return;
01322 
01323     if (area->state == CAIRO_GLITZ_AREA_OCCUPIED)
01324     {
01325        _cairo_glitz_area_move_out (area);
01326     }
01327     else
01328     {
01329        int n = 4;
01330        
01331        while (n--)
01332            _cairo_glitz_area_destroy (area->area[n]);
01333     }
01334     
01335     free (area);
01336 }
01337 
01338 static cairo_glitz_area_t *
01339 _cairo_glitz_area_get_top_scored_sub_area (cairo_glitz_area_t *area)
01340 {
01341     if (!area)
01342        return NULL;
01343               
01344     switch (area->state) {
01345     case CAIRO_GLITZ_AREA_OCCUPIED:
01346        return area;
01347     case CAIRO_GLITZ_AREA_AVAILABLE:
01348        break;
01349     case CAIRO_GLITZ_AREA_DIVIDED: {
01350        cairo_glitz_area_t *tmp, *top = NULL;
01351        int              i;
01352        
01353        for (i = 0; i < 4; i++)
01354        {
01355            tmp = _cairo_glitz_area_get_top_scored_sub_area (area->area[i]);
01356            if (tmp && top)
01357            {
01358               if ((*area->root->funcs->compare_score) (tmp,
01359                                                   tmp->closure,
01360                                                   top->closure) > 0)
01361                   top = tmp;
01362            }
01363            else if (tmp)
01364            {
01365               top = tmp;
01366            }
01367        }
01368        return top;
01369     }
01370     }
01371     
01372     return NULL;
01373 }
01374 
01375 static cairo_int_status_t
01376 _cairo_glitz_area_find (cairo_glitz_area_t *area,
01377                      int              width,
01378                      int              height,
01379                      cairo_bool_t     kick_out,
01380                      void             *closure)
01381 {
01382     cairo_status_t status;
01383 
01384     if (area->width < width || area->height < height)
01385        return CAIRO_INT_STATUS_UNSUPPORTED;
01386 
01387     switch (area->state) {
01388     case CAIRO_GLITZ_AREA_OCCUPIED:
01389        if (kick_out)
01390        {
01391            if ((*area->root->funcs->compare_score) (area,
01392                                                area->closure,
01393                                                closure) >= 0)
01394               return CAIRO_INT_STATUS_UNSUPPORTED;
01395        
01396            _cairo_glitz_area_move_out (area);
01397        } else {
01398            return CAIRO_INT_STATUS_UNSUPPORTED;
01399        }
01400               
01401     /* fall-through */
01402     case CAIRO_GLITZ_AREA_AVAILABLE: {
01403        if (area->level == area->root->max_level ||
01404            (area->width == width && area->height == height))
01405        {
01406            return _cairo_glitz_area_move_in (area, closure);
01407        }
01408        else
01409        {
01410            int dx[4], dy[4], w[4], h[4], i;
01411            
01412            dx[0] = dx[2] = dy[0] = dy[1] = 0;
01413            
01414            w[0] = w[2] = dx[1] = dx[3] = width;
01415            h[0] = h[1] = dy[2] = dy[3] = height;
01416 
01417            w[1] = w[3] = area->width - width;
01418            h[2] = h[3] = area->height - height;
01419            
01420            for (i = 0; i < 2; i++)
01421            {
01422               if (w[i])
01423                   area->area[i] =
01424                      _cairo_glitz_area_create (area->root,
01425                                             area->level + 1,
01426                                             area->x + dx[i],
01427                                             area->y + dy[i],
01428                                             w[i], h[i]);
01429            }
01430 
01431            for (; i < 4; i++)
01432            {
01433               if (w[i] && h[i])
01434                   area->area[i] =
01435                      _cairo_glitz_area_create (area->root,
01436                                             area->level + 1,
01437                                             area->x + dx[i],
01438                                             area->y + dy[i],
01439                                             w[i], h[i]);
01440            }
01441 
01442            area->state = CAIRO_GLITZ_AREA_DIVIDED;
01443            
01444            status = _cairo_glitz_area_find (area->area[0],
01445                                         width, height,
01446                                         kick_out, closure);
01447            if (status == CAIRO_STATUS_SUCCESS)
01448                 return CAIRO_STATUS_SUCCESS;
01449        }
01450     } break;
01451     case CAIRO_GLITZ_AREA_DIVIDED: {
01452        cairo_glitz_area_t *to_area;
01453        int              i, rejected = FALSE;
01454 
01455        for (i = 0; i < 4; i++)
01456        {
01457            if (area->area[i])
01458            {
01459               if (area->area[i]->width >= width &&
01460                   area->area[i]->height >= height)
01461               {
01462                   status = _cairo_glitz_area_find (area->area[i],
01463                                                width, height,
01464                                                kick_out, closure);
01465                   if (status == CAIRO_STATUS_SUCCESS)
01466                      return CAIRO_STATUS_SUCCESS;
01467                   
01468                   rejected = TRUE;
01469               }
01470            }
01471        }
01472 
01473        if (rejected)
01474            return CAIRO_INT_STATUS_UNSUPPORTED;
01475 
01476        to_area = _cairo_glitz_area_get_top_scored_sub_area (area);
01477        if (to_area)
01478        {
01479            if (kick_out)
01480            {
01481               if ((*area->root->funcs->compare_score) (to_area,
01482                                                   to_area->closure,
01483                                                   closure) >= 0)
01484                   return CAIRO_INT_STATUS_UNSUPPORTED;
01485            } else {
01486               return CAIRO_INT_STATUS_UNSUPPORTED;
01487            }
01488        }
01489 
01490        for (i = 0; i < 4; i++)
01491        {
01492            _cairo_glitz_area_destroy (area->area[i]);
01493            area->area[i] = NULL;
01494        }
01495        
01496        area->closure = NULL;
01497        area->state   = CAIRO_GLITZ_AREA_AVAILABLE;
01498 
01499        status = _cairo_glitz_area_find (area, width, height,
01500                                     TRUE, closure);
01501        if (status == CAIRO_STATUS_SUCCESS)
01502            return CAIRO_STATUS_SUCCESS;
01503        
01504     } break;
01505     }
01506 
01507     return CAIRO_INT_STATUS_UNSUPPORTED;
01508 }
01509 
01510 static cairo_status_t
01511 _cairo_glitz_root_area_init (cairo_glitz_root_area_t        *root,
01512                           int                        max_level,
01513                           int                        width,
01514                           int                        height,
01515                           const cairo_glitz_area_funcs_t *funcs)
01516 {
01517     root->max_level = max_level;
01518     root->funcs     = funcs;
01519 
01520     root->area = _cairo_glitz_area_create (root, 0, 0, 0, width, height);
01521     if (!root->area)
01522        return CAIRO_STATUS_NO_MEMORY;
01523     
01524     return CAIRO_STATUS_SUCCESS;
01525 }
01526 
01527 static void
01528 _cairo_glitz_root_area_fini (cairo_glitz_root_area_t *root)
01529 {
01530     _cairo_glitz_area_destroy (root->area);
01531 }
01532 
01533 #define GLYPH_CACHE_TEXTURE_SIZE 512
01534 #define GLYPH_CACHE_MAX_LEVEL     64
01535 #define GLYPH_CACHE_MAX_HEIGHT    72
01536 #define GLYPH_CACHE_MAX_WIDTH     72
01537 
01538 #define WRITE_VEC2(ptr, _x, _y) \
01539     *(ptr)++ = (_x);        \
01540     *(ptr)++ = (_y)
01541 
01542 #define WRITE_BOX(ptr, _vx1, _vy1, _vx2, _vy2, p1, p2) \
01543     WRITE_VEC2 (ptr, _vx1, _vy1);                \
01544     WRITE_VEC2 (ptr, (p1)->x, (p2)->y);                 \
01545     WRITE_VEC2 (ptr, _vx2, _vy1);                \
01546     WRITE_VEC2 (ptr, (p2)->x, (p2)->y);                 \
01547     WRITE_VEC2 (ptr, _vx2, _vy2);                \
01548     WRITE_VEC2 (ptr, (p2)->x, (p1)->y);                 \
01549     WRITE_VEC2 (ptr, _vx1, _vy2);                \
01550     WRITE_VEC2 (ptr, (p1)->x, (p1)->y)
01551 
01552 typedef struct _cairo_glitz_glyph_cache {
01553     cairo_cache_t        base;
01554     cairo_glitz_root_area_t root;
01555     glitz_surface_t      *surface;
01556 } cairo_glitz_glyph_cache_t;
01557 
01558 typedef struct {
01559     cairo_glyph_cache_key_t key;
01560     int                         ref_count;
01561     cairo_glyph_size_t          size;
01562     cairo_glitz_area_t          *area;
01563     cairo_bool_t         locked;
01564     cairo_point_double_t    p1, p2;
01565 } cairo_glitz_glyph_cache_entry_t;
01566 
01567 static cairo_status_t
01568 _cairo_glitz_glyph_move_in (cairo_glitz_area_t *area,
01569                          void             *closure)
01570 {
01571     cairo_glitz_glyph_cache_entry_t *entry = closure;
01572     
01573     entry->area = area;
01574 
01575     return CAIRO_STATUS_SUCCESS;
01576 }
01577 
01578 static void
01579 _cairo_glitz_glyph_move_out (cairo_glitz_area_t  *area,
01580                           void             *closure)
01581 {
01582     cairo_glitz_glyph_cache_entry_t *entry = closure;
01583     
01584     entry->area = NULL;
01585 }
01586 
01587 static int
01588 _cairo_glitz_glyph_compare (cairo_glitz_area_t *area,
01589                          void             *closure1,
01590                          void             *closure2)
01591 {
01592     cairo_glitz_glyph_cache_entry_t *entry = closure1;
01593     
01594     if (entry->locked)
01595        return 1;
01596 
01597     return -1;
01598 }
01599 
01600 static const cairo_glitz_area_funcs_t _cairo_glitz_area_funcs = {
01601     _cairo_glitz_glyph_move_in,
01602     _cairo_glitz_glyph_move_out,
01603     _cairo_glitz_glyph_compare
01604 };
01605 
01606 static cairo_status_t 
01607 _cairo_glitz_glyph_cache_create_entry (void *abstract_cache,
01608                                    void *abstract_key,
01609                                    void **return_entry)
01610 {
01611     cairo_glitz_glyph_cache_entry_t *entry;
01612     cairo_glyph_cache_key_t     *key = abstract_key;
01613    
01614     cairo_status_t status;
01615     cairo_cache_t *im_cache;
01616     cairo_image_glyph_cache_entry_t *im;
01617 
01618     unsigned long entry_memory = 0;
01619 
01620     entry = malloc (sizeof (cairo_glitz_glyph_cache_entry_t));
01621     if (!entry)
01622        return CAIRO_STATUS_NO_MEMORY;
01623 
01624     _cairo_lock_global_image_glyph_cache ();
01625 
01626     im_cache = _cairo_get_global_image_glyph_cache ();
01627     if (im_cache == NULL) {
01628        _cairo_unlock_global_image_glyph_cache ();
01629        free (entry);
01630        return CAIRO_STATUS_NO_MEMORY;
01631     }
01632 
01633     status = _cairo_cache_lookup (im_cache, key, (void **) (&im), NULL);
01634     if (status != CAIRO_STATUS_SUCCESS || im == NULL) {
01635        _cairo_unlock_global_image_glyph_cache ();
01636        free (entry);
01637        return CAIRO_STATUS_NO_MEMORY;
01638     }
01639 
01640     if (im->image)
01641        entry_memory = im->image->width * im->image->stride;
01642 
01643     _cairo_unlock_global_image_glyph_cache ();
01644 
01645     entry->ref_count = 1;
01646     entry->key           = *key;
01647     entry->key.base.memory = entry_memory;
01648     entry->area          = NULL;
01649     entry->locked   = FALSE;
01650 
01651     _cairo_unscaled_font_reference (entry->key.unscaled);
01652     
01653     *return_entry = entry;
01654 
01655     return CAIRO_STATUS_SUCCESS;
01656 }
01657 
01658 static void 
01659 _cairo_glitz_glyph_cache_destroy_entry (void *abstract_cache,
01660                                    void *abstract_entry)
01661 {
01662     cairo_glitz_glyph_cache_entry_t *entry = abstract_entry;
01663 
01664     entry->ref_count--;
01665     if (entry->ref_count)
01666        return;
01667 
01668     if (entry->area)
01669        _cairo_glitz_area_move_out (entry->area);
01670     
01671     _cairo_unscaled_font_destroy (entry->key.unscaled);
01672 
01673     free (entry);    
01674 }
01675 
01676 static void 
01677 _cairo_glitz_glyph_cache_entry_reference (void *abstract_entry)
01678 {
01679     cairo_glitz_glyph_cache_entry_t *entry = abstract_entry;
01680 
01681     entry->ref_count++;     
01682 }
01683 
01684 static void 
01685 _cairo_glitz_glyph_cache_destroy_cache (void *abstract_cache)
01686 {
01687     cairo_glitz_glyph_cache_t *cache = abstract_cache;
01688 
01689     _cairo_glitz_root_area_fini (&cache->root);
01690        
01691     glitz_surface_destroy (cache->surface);
01692 }
01693 
01694 static const cairo_cache_backend_t _cairo_glitz_glyph_cache_backend = {
01695     _cairo_glyph_cache_hash,
01696     _cairo_glyph_cache_keys_equal,
01697     _cairo_glitz_glyph_cache_create_entry,
01698     _cairo_glitz_glyph_cache_destroy_entry,
01699     _cairo_glitz_glyph_cache_destroy_cache
01700 };
01701 
01702 static cairo_glitz_glyph_cache_t *_cairo_glitz_glyph_caches = NULL;
01703 
01704 static cairo_glitz_glyph_cache_t *
01705 _cairo_glitz_get_glyph_cache (cairo_glitz_surface_t *surface)
01706 {
01707     cairo_glitz_glyph_cache_t *cache;
01708     glitz_drawable_t       *drawable;
01709     glitz_format_t         *format;
01710 
01711     /* 
01712      * FIXME: caches should be thread specific, display specific and screen
01713      * specific. 
01714      */
01715     
01716     if (_cairo_glitz_glyph_caches)
01717        return _cairo_glitz_glyph_caches;
01718 
01719     drawable = glitz_surface_get_drawable (surface->surface);
01720     
01721     format = glitz_find_standard_format (drawable, GLITZ_STANDARD_A8);
01722     if (!format)
01723        return NULL;
01724     
01725     cache = malloc (sizeof (cairo_glitz_glyph_cache_t));
01726     if (!cache)
01727        return NULL;
01728 
01729     cache->surface =
01730        glitz_surface_create (drawable, format,
01731                            GLYPH_CACHE_TEXTURE_SIZE,
01732                            GLYPH_CACHE_TEXTURE_SIZE,
01733                            0, NULL);
01734     if (cache->surface == NULL)
01735     {
01736        free (cache);
01737        return NULL;
01738     }
01739 
01740     if (_cairo_glitz_root_area_init (&cache->root,
01741                                  GLYPH_CACHE_MAX_LEVEL,
01742                                  GLYPH_CACHE_TEXTURE_SIZE,
01743                                  GLYPH_CACHE_TEXTURE_SIZE,
01744                                  &_cairo_glitz_area_funcs))
01745     {
01746        glitz_surface_destroy (cache->surface);
01747        free (cache);
01748        return NULL;
01749     }
01750 
01751     if (_cairo_cache_init (&cache->base,
01752                         &_cairo_glitz_glyph_cache_backend,
01753                         CAIRO_GLITZ_GLYPH_CACHE_MEMORY_DEFAULT))
01754     {
01755        _cairo_glitz_root_area_fini (&cache->root);
01756        glitz_surface_destroy (cache->surface);
01757        free (cache);
01758        return NULL;
01759     }
01760     
01761     _cairo_glitz_glyph_caches = cache;
01762     
01763     return cache;
01764 }
01765 
01766 #define FIXED_TO_FLOAT(f) (((glitz_float_t) (f)) / 65536)
01767 
01768 static cairo_status_t
01769 _cairo_glitz_cache_glyph (cairo_glitz_glyph_cache_t       *cache,
01770                        cairo_glitz_glyph_cache_entry_t *entry,
01771                        cairo_image_glyph_cache_entry_t *image_entry)
01772 {
01773     glitz_point_fixed_t  p1, p2;
01774     glitz_pixel_format_t pf;
01775     glitz_buffer_t    *buffer;
01776     pixman_format_t   *format;
01777     int                      am, rm, gm, bm;
01778 
01779     entry->size = image_entry->size;
01780     
01781     if (entry->size.width  > GLYPH_CACHE_MAX_WIDTH ||
01782        entry->size.height > GLYPH_CACHE_MAX_HEIGHT)
01783        return CAIRO_STATUS_SUCCESS;
01784 
01785     if ((entry->size.width  == 0 && entry->size.height == 0) ||
01786         !image_entry->image)
01787     {
01788        entry->area = &_empty_area;
01789        return CAIRO_STATUS_SUCCESS;
01790     }
01791     
01792     format = pixman_image_get_format (image_entry->image->pixman_image);
01793     if (!format)
01794        return CAIRO_STATUS_NO_MEMORY;
01795        
01796     if (_cairo_glitz_area_find (cache->root.area,
01797                             entry->size.width,
01798                             entry->size.height,
01799                             FALSE, entry))
01800     {
01801        if (_cairo_glitz_area_find (cache->root.area,
01802                                 entry->size.width,
01803                                 entry->size.height,
01804                                 TRUE, entry))
01805            return CAIRO_STATUS_SUCCESS;
01806     }
01807     
01808     buffer = glitz_buffer_create_for_data (image_entry->image->data);
01809     if (!buffer)
01810     {
01811        _cairo_glitz_area_move_out (entry->area);
01812        return CAIRO_STATUS_NO_MEMORY;
01813     }
01814 
01815     pixman_format_get_masks (format, &pf.masks.bpp, &am, &rm, &gm, &bm);
01816 
01817     pf.masks.alpha_mask = am;
01818     pf.masks.red_mask   = rm;
01819     pf.masks.green_mask = gm;
01820     pf.masks.blue_mask  = bm;
01821     
01822     pf.bytes_per_line = image_entry->image->stride;
01823     pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_BOTTOM_UP;
01824     pf.xoffset             = 0;
01825     pf.skip_lines     = 0;
01826     
01827     glitz_set_pixels (cache->surface,
01828                     entry->area->x,
01829                     entry->area->y,
01830                     entry->size.width,
01831                     entry->size.height,
01832                     &pf, buffer);
01833 
01834     glitz_buffer_destroy (buffer);
01835        
01836     p1.x = entry->area->x << 16;
01837     p1.y = entry->area->y << 16;
01838     p2.x = (entry->area->x + entry->size.width)  << 16;
01839     p2.y = (entry->area->y + entry->size.height) << 16;
01840     
01841     glitz_surface_translate_point (cache->surface, &p1, &p1);
01842     glitz_surface_translate_point (cache->surface, &p2, &p2);
01843     
01844     entry->p1.x = FIXED_TO_FLOAT (p1.x);
01845     entry->p1.y = FIXED_TO_FLOAT (p1.y);
01846     entry->p2.x = FIXED_TO_FLOAT (p2.x);
01847     entry->p2.y = FIXED_TO_FLOAT (p2.y);
01848     
01849     return CAIRO_STATUS_SUCCESS;
01850 }
01851 
01852 #define N_STACK_BUF 256
01853 
01854 static cairo_int_status_t
01855 _cairo_glitz_surface_show_glyphs (cairo_scaled_font_t *scaled_font,
01856                               cairo_operator_t    op,
01857                               cairo_pattern_t     *pattern,
01858                               void              *abstract_surface,
01859                               int               src_x,
01860                               int               src_y,
01861                               int               dst_x,
01862                               int               dst_y,
01863                               unsigned int             width,
01864                               unsigned int             height,
01865                               const cairo_glyph_t *glyphs,
01866                               int               num_glyphs)
01867 {
01868     cairo_glitz_surface_attributes_t attributes;
01869     cairo_glitz_surface_t        *dst = abstract_surface;
01870     cairo_glitz_surface_t        *src;
01871     cairo_glitz_glyph_cache_t           *cache;
01872     cairo_glitz_glyph_cache_entry_t  *stack_entries[N_STACK_BUF];
01873     cairo_glitz_glyph_cache_entry_t  **entries;
01874     cairo_glyph_cache_key_t      key;
01875     glitz_float_t                stack_vertices[N_STACK_BUF * 16];
01876     glitz_float_t                *vertices;
01877     glitz_buffer_t               *buffer;
01878     cairo_int_status_t                  status;
01879     int                                 i, cached_glyphs = 0;
01880     int                                 remaining_glyps = num_glyphs;
01881     glitz_float_t                x1, y1, x2, y2;
01882     static glitz_vertex_format_t     format = {
01883        GLITZ_PRIMITIVE_QUADS,
01884        GLITZ_DATA_TYPE_FLOAT,
01885        sizeof (glitz_float_t) * 4,
01886        GLITZ_VERTEX_ATTRIBUTE_MASK_COORD_MASK,
01887        { 0 },
01888        {
01889            GLITZ_DATA_TYPE_FLOAT,
01890            GLITZ_COORDINATE_SIZE_XY,
01891            sizeof (glitz_float_t) * 2,
01892        }
01893     };
01894 
01895     if (op == CAIRO_OPERATOR_SATURATE)
01896        return CAIRO_INT_STATUS_UNSUPPORTED;
01897 
01898     if (_glitz_ensure_target (dst->surface))
01899        return CAIRO_INT_STATUS_UNSUPPORTED;
01900 
01901     status = _cairo_glitz_pattern_acquire_surface (pattern, dst,
01902                                              src_x, src_y,
01903                                              width, height,
01904                                              &src, &attributes);
01905     if (status)
01906        return status;
01907 
01908     _cairo_glitz_surface_set_attributes (src, &attributes);
01909 
01910     if (num_glyphs > N_STACK_BUF)
01911     {
01912        char *data;
01913        
01914        data = malloc (num_glyphs * sizeof (void *) +
01915                      num_glyphs * sizeof (glitz_float_t) * 16);
01916        if (!data)
01917            goto FAIL1;
01918        
01919        entries  = (cairo_glitz_glyph_cache_entry_t **) data;
01920        vertices = (glitz_float_t *) (data + num_glyphs * sizeof (void *));
01921     }
01922     else
01923     {
01924        entries  = stack_entries;
01925        vertices = stack_vertices;
01926     }
01927 
01928     buffer = glitz_buffer_create_for_data (vertices);
01929     if (!buffer)
01930        goto FAIL2;
01931     
01932     cache = _cairo_glitz_get_glyph_cache (dst);
01933     if (!cache)
01934     {
01935        num_glyphs = 0;
01936        goto UNLOCK;
01937     }
01938 
01939     status = _cairo_scaled_font_get_glyph_cache_key (scaled_font, &key);
01940     if (status)
01941        goto UNLOCK;
01942 
01943     for (i = 0; i < num_glyphs; i++)
01944     {
01945        key.index = glyphs[i].index;
01946        
01947        status = _cairo_cache_lookup (&cache->base,
01948                                   &key,
01949                                   (void **) &entries[i],
01950                                   NULL);
01951        if (status)
01952        {
01953            num_glyphs = i;
01954            goto UNLOCK;
01955        }
01956 
01957        _cairo_glitz_glyph_cache_entry_reference (entries[i]);
01958 
01959        if (entries[i]->area)
01960        {
01961            remaining_glyps--;
01962 
01963            if (entries[i]->area->width)
01964            {
01965               x1 = floor (glyphs[i].x + 0.5) + entries[i]->size.x;
01966               y1 = floor (glyphs[i].y + 0.5) + entries[i]->size.y;
01967               x2 = x1 + entries[i]->size.width;
01968               y2 = y1 + entries[i]->size.height;
01969            
01970               WRITE_BOX (vertices, x1, y1, x2, y2,
01971                         &entries[i]->p1, &entries[i]->p2);
01972            
01973               entries[i]->locked = TRUE;
01974               cached_glyphs++;
01975            }
01976        }
01977     }
01978 
01979     if (remaining_glyps)
01980     {
01981        cairo_cache_t               *image_cache;
01982        cairo_image_glyph_cache_entry_t *image_entry;
01983        cairo_surface_t                    *image;
01984        cairo_glitz_surface_t              *clone;
01985        
01986        _cairo_lock_global_image_glyph_cache ();
01987 
01988        image_cache = _cairo_get_global_image_glyph_cache ();
01989        if (!image_cache)
01990        {
01991            _cairo_unlock_global_image_glyph_cache ();
01992            status = CAIRO_STATUS_NO_MEMORY;
01993            goto UNLOCK;
01994        }
01995        
01996        for (i = 0; i < num_glyphs; i++)
01997        {
01998            if (!entries[i]->area)
01999            {
02000               key.index = glyphs[i].index;
02001               
02002               status = _cairo_cache_lookup (image_cache,
02003                                          &key,
02004                                          (void **) &image_entry,
02005                                          NULL);
02006               if (status)
02007               {
02008                   _cairo_unlock_global_image_glyph_cache ();
02009                   goto UNLOCK;
02010               }
02011 
02012               status = _cairo_glitz_cache_glyph (cache,
02013                                              entries[i],
02014                                              image_entry);
02015               if (status)
02016               {
02017                   _cairo_unlock_global_image_glyph_cache ();
02018                   goto UNLOCK;
02019               }
02020            }
02021            
02022            x1 = floor (glyphs[i].x + 0.5);
02023            y1 = floor (glyphs[i].y + 0.5);
02024 
02025            if (entries[i]->area)
02026            {
02027               if (entries[i]->area->width)
02028               {
02029                   x1 += entries[i]->size.x;
02030                   y1 += entries[i]->size.y;
02031                   x2 = x1 + entries[i]->size.width;
02032                   y2 = y1 + entries[i]->size.height;
02033                   
02034                   WRITE_BOX (vertices, x1, y1, x2, y2,
02035                             &entries[i]->p1, &entries[i]->p2);
02036                   
02037                   entries[i]->locked = TRUE;
02038                   cached_glyphs++;
02039               }
02040            }
02041            else
02042            {
02043               x1 += image_entry->size.x;
02044               y1 += image_entry->size.y;
02045 
02046               if (!image_entry->image)
02047                   continue;
02048               
02049               image = &image_entry->image->base;
02050               status =
02051                   _cairo_glitz_surface_clone_similar (abstract_surface,
02052                                                  image,
02053                                                  (cairo_surface_t **)
02054                                                  &clone);
02055               if (status)
02056               {
02057                   _cairo_unlock_global_image_glyph_cache ();
02058                   goto UNLOCK;
02059               }
02060 
02061               glitz_composite (_glitz_operator (op), 
02062                              src->surface, 
02063                              clone->surface,
02064                              dst->surface,
02065                              src_x + attributes.base.x_offset + x1,
02066                              src_y + attributes.base.y_offset + y1,
02067                              0, 0,
02068                              x1, y1,
02069                              image_entry->size.width,
02070                              image_entry->size.height);
02071 
02072               cairo_surface_destroy (&clone->base);
02073 
02074               if (glitz_surface_get_status (dst->surface) ==
02075                   GLITZ_STATUS_NOT_SUPPORTED)
02076               {
02077                   status = CAIRO_INT_STATUS_UNSUPPORTED;
02078                   _cairo_unlock_global_image_glyph_cache ();
02079                   goto UNLOCK;
02080               }
02081            }
02082        }
02083        
02084        _cairo_unlock_global_image_glyph_cache ();
02085     }
02086 
02087     if (cached_glyphs)
02088     {
02089        glitz_set_geometry (dst->surface,
02090                          GLITZ_GEOMETRY_TYPE_VERTEX,
02091                          (glitz_geometry_format_t *) &format,
02092                          buffer);
02093 
02094        glitz_set_array (dst->surface, 0, 4, cached_glyphs * 4, 0, 0);
02095 
02096        glitz_composite (_glitz_operator (op),
02097                       src->surface,
02098                       cache->surface,
02099                       dst->surface,
02100                       src_x + attributes.base.x_offset,
02101                       src_y + attributes.base.y_offset,
02102                       0, 0,
02103                       dst_x, dst_y,
02104                       width, height);
02105 
02106        glitz_set_geometry (dst->surface,
02107                          GLITZ_GEOMETRY_TYPE_NONE,
02108                          NULL, NULL);
02109     }
02110     
02111 UNLOCK:
02112     if (cached_glyphs)
02113     {
02114        for (i = 0; i < num_glyphs; i++)
02115            entries[i]->locked = FALSE;
02116     }
02117     
02118     for (i = 0; i < num_glyphs; i++)
02119        _cairo_glitz_glyph_cache_destroy_entry (cache, entries[i]);
02120 
02121     glitz_buffer_destroy (buffer);
02122 
02123  FAIL2:
02124     if (num_glyphs > N_STACK_BUF)
02125        free (entries);
02126 
02127  FAIL1:
02128     if (attributes.n_params)
02129        free (attributes.params);
02130 
02131     _cairo_glitz_pattern_release_surface (pattern, src, &attributes);
02132 
02133     if (status)
02134        return status;
02135     
02136     if (glitz_surface_get_status (dst->surface) == GLITZ_STATUS_NOT_SUPPORTED)
02137        return CAIRO_INT_STATUS_UNSUPPORTED;
02138     
02139     return CAIRO_STATUS_SUCCESS;
02140 }
02141 
02142 static const cairo_surface_backend_t cairo_glitz_surface_backend = {
02143     _cairo_glitz_surface_create_similar,
02144     _cairo_glitz_surface_finish,
02145     _cairo_glitz_surface_acquire_source_image,
02146     _cairo_glitz_surface_release_source_image,
02147     _cairo_glitz_surface_acquire_dest_image,
02148     _cairo_glitz_surface_release_dest_image,
02149     _cairo_glitz_surface_clone_similar,
02150     _cairo_glitz_surface_composite,
02151     _cairo_glitz_surface_fill_rectangles,
02152     _cairo_glitz_surface_composite_trapezoids,
02153     NULL, /* copy_page */
02154     NULL, /* show_page */
02155     _cairo_glitz_surface_set_clip_region,
02156     NULL, /* intersect_clip_path */
02157     _cairo_glitz_surface_get_extents,
02158     _cairo_glitz_surface_show_glyphs
02159 };
02160 
02161 cairo_surface_t *
02162 cairo_glitz_surface_create (glitz_surface_t *surface)
02163 {
02164     cairo_glitz_surface_t *crsurface;
02165 
02166     if (surface == NULL)
02167        return (cairo_surface_t*) &_cairo_surface_nil;
02168 
02169     crsurface = malloc (sizeof (cairo_glitz_surface_t));
02170     if (crsurface == NULL) {
02171        _cairo_error (CAIRO_STATUS_NO_MEMORY);
02172        return (cairo_surface_t*) &_cairo_surface_nil;
02173     }
02174 
02175     _cairo_surface_init (&crsurface->base, &cairo_glitz_surface_backend);
02176 
02177     glitz_surface_reference (surface);
02178     
02179     crsurface->surface = surface;
02180     crsurface->format  = glitz_surface_get_format (surface);
02181     crsurface->clip    = NULL;
02182     
02183     return (cairo_surface_t *) crsurface;
02184 }