Changes.
[cairo/gpu.git] / src / cairo-glitz-surface.c
blobba15d08c9ec7f8ff21e8564e2de6575dff8ae9f6
1 /* cairo - a vector graphics library with display and print output
3 * Copyright © 2004 David Reveman
5 * Permission to use, copy, modify, distribute, and sell this software
6 * and its documentation for any purpose is hereby granted without
7 * fee, provided that the above copyright notice appear in all copies
8 * and that both that copyright notice and this permission notice
9 * appear in supporting documentation, and that the name of David
10 * Reveman not be used in advertising or publicity pertaining to
11 * distribution of the software without specific, written prior
12 * permission. David Reveman makes no representations about the
13 * suitability of this software for any purpose. It is provided "as
14 * is" without express or implied warranty.
16 * DAVID REVEMAN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
18 * FITNESS, IN NO EVENT SHALL DAVID REVEMAN BE LIABLE FOR ANY SPECIAL,
19 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
20 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
21 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
22 * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24 * Author: David Reveman <davidr@novell.com>
27 #include "cairoint.h"
28 #include "cairo-glitz.h"
29 #include "cairo-glitz-private.h"
31 typedef struct _cairo_glitz_surface {
32 cairo_surface_t base;
34 glitz_surface_t *surface;
35 glitz_format_t *format;
37 cairo_bool_t has_clip;
38 glitz_box_t *clip_boxes;
39 int num_clip_boxes;
40 } cairo_glitz_surface_t;
42 static const cairo_surface_backend_t *
43 _cairo_glitz_surface_get_backend (void);
45 static cairo_status_t
46 _cairo_glitz_surface_finish (void *abstract_surface)
48 cairo_glitz_surface_t *surface = abstract_surface;
50 if (surface->clip_boxes)
51 free (surface->clip_boxes);
53 glitz_surface_destroy (surface->surface);
55 return CAIRO_STATUS_SUCCESS;
58 static glitz_format_name_t
59 _glitz_format_from_content (cairo_content_t content)
61 switch (content) {
62 case CAIRO_CONTENT_COLOR:
63 return GLITZ_STANDARD_RGB24;
64 case CAIRO_CONTENT_ALPHA:
65 return GLITZ_STANDARD_A8;
66 case CAIRO_CONTENT_COLOR_ALPHA:
67 return GLITZ_STANDARD_ARGB32;
70 ASSERT_NOT_REACHED;
71 return GLITZ_STANDARD_ARGB32;
74 static cairo_surface_t *
75 _cairo_glitz_surface_create_similar (void *abstract_src,
76 cairo_content_t content,
77 int width,
78 int height)
80 cairo_glitz_surface_t *src = abstract_src;
81 cairo_surface_t *crsurface;
82 glitz_drawable_t *drawable;
83 glitz_surface_t *surface;
84 glitz_format_t *gformat;
86 drawable = glitz_surface_get_drawable (src->surface);
88 gformat =
89 glitz_find_standard_format (drawable,
90 _glitz_format_from_content (content));
91 if (!gformat)
92 return NULL;
94 surface = glitz_surface_create (drawable, gformat,
95 width <= 0 ? 1 : width,
96 height <= 0 ? 1 : height,
97 0, NULL);
99 if (surface == NULL)
100 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
102 crsurface = cairo_glitz_surface_create (surface);
104 glitz_surface_destroy (surface);
106 return crsurface;
109 static cairo_status_t
110 _cairo_glitz_get_boxes_from_region (cairo_region_t *region,
111 glitz_box_t **boxes,
112 int *nboxes)
114 pixman_box32_t *pboxes;
115 cairo_status_t status = CAIRO_STATUS_SUCCESS;
117 int n, i;
119 n = 0;
120 pboxes = pixman_region32_rectangles (&region->rgn, &n);
121 if (n == 0) {
122 *nboxes = 0;
123 return CAIRO_STATUS_SUCCESS;
126 if (n > *nboxes) {
127 *boxes = _cairo_malloc_ab (n, sizeof (glitz_box_t));
128 if (*boxes == NULL) {
129 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
130 goto done;
134 for (i = 0; i < n; i++) {
135 (*boxes)[i].x1 = pboxes[i].x1;
136 (*boxes)[i].y1 = pboxes[i].y1;
137 (*boxes)[i].x2 = pboxes[i].x2;
138 (*boxes)[i].y2 = pboxes[i].y2;
141 *nboxes = n;
142 done:
143 return status;
146 static cairo_status_t
147 _cairo_glitz_surface_get_image (cairo_glitz_surface_t *surface,
148 cairo_rectangle_int_t *interest,
149 cairo_image_surface_t **image_out,
150 cairo_rectangle_int_t *rect_out)
152 cairo_image_surface_t *image;
153 cairo_rectangle_int_t extents;
154 cairo_format_t format;
155 cairo_format_masks_t masks;
156 glitz_buffer_t *buffer;
157 glitz_pixel_format_t pf;
159 extents.x = 0;
160 extents.y = 0;
161 extents.width = glitz_surface_get_width (surface->surface);
162 extents.height = glitz_surface_get_height (surface->surface);
164 if (interest != NULL) {
165 if (! _cairo_rectangle_intersect (&extents, interest)) {
166 *image_out = NULL;
167 return CAIRO_STATUS_SUCCESS;
171 if (rect_out != NULL)
172 *rect_out = extents;
174 if (surface->format->color.fourcc == GLITZ_FOURCC_RGB) {
175 if (surface->format->color.red_size > 0) {
176 if (surface->format->color.alpha_size > 0)
177 format = CAIRO_FORMAT_ARGB32;
178 else
179 format = CAIRO_FORMAT_RGB24;
180 } else {
181 format = CAIRO_FORMAT_A8;
183 } else
184 format = CAIRO_FORMAT_ARGB32;
186 image = (cairo_image_surface_t*)
187 cairo_image_surface_create (format, extents.width, extents.height);
188 if (image->base.status)
189 return image->base.status;
191 _pixman_format_to_masks (image->pixman_format, &masks);
192 pf.fourcc = GLITZ_FOURCC_RGB;
193 pf.masks.bpp = masks.bpp;
194 pf.masks.alpha_mask = masks.alpha_mask;
195 pf.masks.red_mask = masks.red_mask;
196 pf.masks.green_mask = masks.green_mask;
197 pf.masks.blue_mask = masks.blue_mask;
198 pf.xoffset = 0;
199 pf.skip_lines = 0;
201 /* XXX: we should eventually return images with negative stride,
202 need to verify that libpixman have no problem with this first. */
203 pf.bytes_per_line = image->stride;
204 pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_TOP_DOWN;
206 buffer = glitz_buffer_create_for_data (image->data);
207 if (buffer == NULL) {
208 cairo_surface_destroy (&image->base);
209 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
212 /* clear out the glitz clip; the clip affects glitz_get_pixels */
213 if (surface->has_clip)
214 glitz_surface_set_clip_region (surface->surface,
215 0, 0, NULL, 0);
217 glitz_get_pixels (surface->surface,
218 extents.x, extents.y,
219 extents.width, extents.height,
220 &pf,
221 buffer);
223 glitz_buffer_destroy (buffer);
225 /* restore the clip, if any */
226 if (surface->has_clip) {
227 glitz_surface_set_clip_region (surface->surface,
228 0, 0,
229 surface->clip_boxes,
230 surface->num_clip_boxes);
233 *image_out = image;
235 return CAIRO_STATUS_SUCCESS;
238 static cairo_status_t
239 _cairo_glitz_surface_set_image (void *abstract_surface,
240 cairo_image_surface_t *image,
241 int src_x,
242 int src_y,
243 int width,
244 int height,
245 int x_dst,
246 int y_dst)
248 cairo_glitz_surface_t *surface = abstract_surface;
249 glitz_buffer_t *buffer;
250 glitz_pixel_format_t pf;
251 cairo_format_masks_t masks;
252 char *data;
254 _pixman_format_to_masks (image->pixman_format, &masks);
256 pf.fourcc = GLITZ_FOURCC_RGB;
257 pf.masks.bpp = masks.bpp;
258 pf.masks.alpha_mask = masks.alpha_mask;
259 pf.masks.red_mask = masks.red_mask;
260 pf.masks.green_mask = masks.green_mask;
261 pf.masks.blue_mask = masks.blue_mask;
262 pf.xoffset = src_x;
263 pf.skip_lines = src_y;
265 /* check for negative stride */
266 if (image->stride < 0) {
267 pf.bytes_per_line = -image->stride;
268 pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_BOTTOM_UP;
269 data = (char *) image->data + image->stride * (image->height - 1);
270 } else {
271 pf.bytes_per_line = image->stride;
272 pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_TOP_DOWN;
273 data = (char *) image->data;
276 buffer = glitz_buffer_create_for_data (data);
277 if (buffer == NULL)
278 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
280 glitz_set_pixels (surface->surface,
281 x_dst, y_dst,
282 width, height,
283 &pf,
284 buffer);
286 glitz_buffer_destroy (buffer);
288 return CAIRO_STATUS_SUCCESS;
291 static cairo_status_t
292 _cairo_glitz_surface_acquire_source_image (void *abstract_surface,
293 cairo_image_surface_t **image_out,
294 void **image_extra)
296 cairo_glitz_surface_t *surface = abstract_surface;
298 *image_extra = NULL;
300 return _cairo_glitz_surface_get_image (surface, NULL, image_out, NULL);
303 static cairo_surface_t *
304 _cairo_glitz_surface_snapshot (void *abstract_surface)
306 cairo_glitz_surface_t *surface = abstract_surface;
307 cairo_status_t status;
308 cairo_image_surface_t *image;
310 status = _cairo_glitz_surface_get_image (surface, NULL, &image, NULL);
311 if (unlikely (status))
312 return _cairo_surface_create_in_error (status);
314 return &image->base;
317 static void
318 _cairo_glitz_surface_release_source_image (void *abstract_surface,
319 cairo_image_surface_t *image,
320 void *image_extra)
322 cairo_surface_destroy (&image->base);
325 static cairo_status_t
326 _cairo_glitz_surface_acquire_dest_image (void *abstract_surface,
327 cairo_rectangle_int_t *interest_rect,
328 cairo_image_surface_t **image_out,
329 cairo_rectangle_int_t *image_rect_out,
330 void **image_extra)
332 cairo_glitz_surface_t *surface = abstract_surface;
333 cairo_image_surface_t *image;
334 cairo_status_t status;
336 status = _cairo_glitz_surface_get_image (surface, interest_rect, &image,
337 image_rect_out);
338 if (status)
339 return status;
341 *image_out = image;
342 *image_extra = NULL;
344 return status;
347 static void
348 _cairo_glitz_surface_release_dest_image (void *abstract_surface,
349 cairo_rectangle_int_t *interest_rect,
350 cairo_image_surface_t *image,
351 cairo_rectangle_int_t *image_rect,
352 void *image_extra)
354 cairo_glitz_surface_t *surface = abstract_surface;
355 cairo_status_t status;
357 status = _cairo_glitz_surface_set_image (surface, image, 0, 0,
358 image->width, image->height,
359 image_rect->x, image_rect->y);
360 if (status)
361 status = _cairo_surface_set_error (&surface->base, status);
363 cairo_surface_destroy (&image->base);
366 static cairo_status_t
367 _cairo_glitz_surface_clone_similar (void *abstract_surface,
368 cairo_surface_t *src,
369 cairo_content_t content,
370 int src_x,
371 int src_y,
372 int width,
373 int height,
374 int *clone_offset_x,
375 int *clone_offset_y,
376 cairo_surface_t **clone_out)
378 cairo_glitz_surface_t *surface = abstract_surface;
379 cairo_glitz_surface_t *clone;
380 cairo_status_t status;
382 if (surface->base.status)
383 return surface->base.status;
385 if (src->backend == surface->base.backend)
387 *clone_offset_x = 0;
388 *clone_offset_y = 0;
389 *clone_out = cairo_surface_reference (src);
391 return CAIRO_STATUS_SUCCESS;
393 else if (_cairo_surface_is_image (src))
395 cairo_image_surface_t *image_src = (cairo_image_surface_t *) src;
397 clone = (cairo_glitz_surface_t *)
398 _cairo_glitz_surface_create_similar (surface, src->content,
399 width, height);
400 if (clone == NULL)
401 return CAIRO_INT_STATUS_UNSUPPORTED;
402 if (clone->base.status)
403 return clone->base.status;
405 status = _cairo_glitz_surface_set_image (clone, image_src,
406 src_x, src_y,
407 width, height,
408 0, 0);
409 if (status) {
410 cairo_surface_destroy (&clone->base);
411 return status;
414 *clone_out = &clone->base;
415 *clone_offset_x = src_x;
416 *clone_offset_y = src_y;
417 return CAIRO_STATUS_SUCCESS;
420 return CAIRO_INT_STATUS_UNSUPPORTED;
423 static void
424 _cairo_glitz_surface_set_matrix (cairo_glitz_surface_t *surface,
425 cairo_matrix_t *matrix)
427 glitz_transform_t transform;
429 transform.matrix[0][0] = _cairo_fixed_16_16_from_double (matrix->xx);
430 transform.matrix[0][1] = _cairo_fixed_16_16_from_double (matrix->xy);
431 transform.matrix[0][2] = _cairo_fixed_16_16_from_double (matrix->x0);
433 transform.matrix[1][0] = _cairo_fixed_16_16_from_double (matrix->yx);
434 transform.matrix[1][1] = _cairo_fixed_16_16_from_double (matrix->yy);
435 transform.matrix[1][2] = _cairo_fixed_16_16_from_double (matrix->y0);
437 transform.matrix[2][0] = 0;
438 transform.matrix[2][1] = 0;
439 transform.matrix[2][2] = _cairo_fixed_16_16_from_double (1);
441 glitz_surface_set_transform (surface->surface, &transform);
444 static glitz_operator_t
445 _glitz_operator (cairo_operator_t op)
447 switch (op) {
448 case CAIRO_OPERATOR_CLEAR:
449 return GLITZ_OPERATOR_CLEAR;
451 case CAIRO_OPERATOR_SOURCE:
452 return GLITZ_OPERATOR_SRC;
453 case CAIRO_OPERATOR_OVER:
454 return GLITZ_OPERATOR_OVER;
455 case CAIRO_OPERATOR_IN:
456 return GLITZ_OPERATOR_IN;
457 case CAIRO_OPERATOR_OUT:
458 return GLITZ_OPERATOR_OUT;
459 case CAIRO_OPERATOR_ATOP:
460 return GLITZ_OPERATOR_ATOP;
462 case CAIRO_OPERATOR_DEST:
463 return GLITZ_OPERATOR_DST;
464 case CAIRO_OPERATOR_DEST_OVER:
465 return GLITZ_OPERATOR_OVER_REVERSE;
466 case CAIRO_OPERATOR_DEST_IN:
467 return GLITZ_OPERATOR_IN_REVERSE;
468 case CAIRO_OPERATOR_DEST_OUT:
469 return GLITZ_OPERATOR_OUT_REVERSE;
470 case CAIRO_OPERATOR_DEST_ATOP:
471 return GLITZ_OPERATOR_ATOP_REVERSE;
473 case CAIRO_OPERATOR_XOR:
474 return GLITZ_OPERATOR_XOR;
475 case CAIRO_OPERATOR_ADD:
476 return GLITZ_OPERATOR_ADD;
477 case CAIRO_OPERATOR_SATURATE:
478 /* XXX: This line should never be reached. Glitz backend should bail
479 out earlier if saturate operator is used. OpenGL can't do saturate
480 with pre-multiplied colors. Solid colors can still be done as we
481 can just un-pre-multiply them. However, support for that will have
482 to be added to glitz. */
484 /* fall-through */
485 break;
488 ASSERT_NOT_REACHED;
490 /* Something's very broken if this line of code can be reached, so
491 we want to return something that would give a noticeably
492 incorrect result. The XOR operator seems so rearely desired
493 that it should fit the bill here. */
494 return CAIRO_OPERATOR_XOR;
497 #define CAIRO_GLITZ_FEATURE_OK(surface, name) \
498 (glitz_drawable_get_features (glitz_surface_get_drawable (surface)) & \
499 (GLITZ_FEATURE_ ## name ## _MASK))
501 static glitz_status_t
502 _glitz_ensure_target (glitz_surface_t *surface)
504 if (!glitz_surface_get_attached_drawable (surface))
506 glitz_drawable_format_t *target_format, templ;
507 glitz_format_t *format;
508 glitz_drawable_t *drawable, *target;
509 unsigned int width, height;
510 unsigned long mask;
512 drawable = glitz_surface_get_drawable (surface);
513 format = glitz_surface_get_format (surface);
514 width = glitz_surface_get_width (surface);
515 height = glitz_surface_get_height (surface);
517 if (format->color.fourcc != GLITZ_FOURCC_RGB)
518 return CAIRO_INT_STATUS_UNSUPPORTED;
520 templ.color = format->color;
521 templ.depth_size = 0;
522 templ.stencil_size = 0;
523 templ.doublebuffer = 0;
524 templ.samples = 1;
526 mask =
527 GLITZ_FORMAT_RED_SIZE_MASK |
528 GLITZ_FORMAT_GREEN_SIZE_MASK |
529 GLITZ_FORMAT_BLUE_SIZE_MASK |
530 GLITZ_FORMAT_ALPHA_SIZE_MASK |
531 GLITZ_FORMAT_DEPTH_SIZE_MASK |
532 GLITZ_FORMAT_STENCIL_SIZE_MASK |
533 GLITZ_FORMAT_DOUBLEBUFFER_MASK |
534 GLITZ_FORMAT_SAMPLES_MASK;
536 target_format = glitz_find_drawable_format (drawable, mask, &templ, 0);
537 if (!target_format)
538 return CAIRO_INT_STATUS_UNSUPPORTED;
540 target = glitz_create_drawable (drawable, target_format,
541 width, height);
542 if (!target)
543 return CAIRO_INT_STATUS_UNSUPPORTED;
545 glitz_surface_attach (surface, target,
546 GLITZ_DRAWABLE_BUFFER_FRONT_COLOR);
548 glitz_drawable_destroy (target);
551 return CAIRO_STATUS_SUCCESS;
554 typedef struct _cairo_glitz_surface_attributes {
555 cairo_surface_attributes_t base;
557 glitz_fill_t fill;
558 glitz_filter_t filter;
559 glitz_fixed16_16_t *params;
560 int n_params;
561 cairo_bool_t acquired;
562 } cairo_glitz_surface_attributes_t;
564 static cairo_int_status_t
565 _cairo_glitz_pattern_acquire_surface (const cairo_pattern_t *pattern,
566 cairo_glitz_surface_t *dst,
567 int x,
568 int y,
569 unsigned int width,
570 unsigned int height,
571 cairo_glitz_surface_t **surface_out,
572 cairo_glitz_surface_attributes_t *attr)
574 cairo_glitz_surface_t *src = NULL;
576 attr->acquired = FALSE;
578 switch (pattern->type) {
579 case CAIRO_PATTERN_TYPE_LINEAR:
580 case CAIRO_PATTERN_TYPE_RADIAL: {
581 cairo_gradient_pattern_t *gradient =
582 (cairo_gradient_pattern_t *) pattern;
583 char *data;
584 glitz_fixed16_16_t *params;
585 unsigned int n_params;
586 unsigned int *pixels;
587 unsigned int i, n_base_params;
588 glitz_buffer_t *buffer;
589 static const glitz_pixel_format_t format = {
590 GLITZ_FOURCC_RGB,
593 0xff000000,
594 0x00ff0000,
595 0x0000ff00,
596 0x000000ff
598 0, 0, 0,
599 GLITZ_PIXEL_SCANLINE_ORDER_BOTTOM_UP
602 /* XXX: the current color gradient acceleration provided by glitz is
603 * experimental, it's been proven inappropriate in a number of ways,
604 * most importantly, it's currently implemented as filters and
605 * gradients are not filters. eventually, it will be replaced with
606 * something more appropriate.
609 if (gradient->n_stops < 2)
610 break;
612 if (!CAIRO_GLITZ_FEATURE_OK (dst->surface, FRAGMENT_PROGRAM))
613 break;
615 if (pattern->type == CAIRO_PATTERN_TYPE_RADIAL)
616 n_base_params = 6;
617 else
618 n_base_params = 4;
620 n_params = gradient->n_stops * 3 + n_base_params;
622 /* check for int overflow */
624 int size1, size2;
625 if (n_params >= INT32_MAX / sizeof (glitz_fixed16_16_t) ||
626 gradient->n_stops >= INT32_MAX / sizeof (unsigned int))
627 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
629 size1 = n_params * sizeof (glitz_fixed16_16_t);
630 size2 = gradient->n_stops * sizeof (unsigned int);
632 if (size1 >= INT32_MAX - size2)
633 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
635 data = malloc (size1 + size2);
638 if (!data)
639 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
641 params = (glitz_fixed16_16_t *) data;
642 pixels = (unsigned int *)
643 (data + sizeof (glitz_fixed16_16_t) * n_params);
645 buffer = glitz_buffer_create_for_data (pixels);
646 if (!buffer) {
647 free (data);
648 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
651 src = (cairo_glitz_surface_t *)
652 _cairo_surface_create_similar_scratch (&dst->base,
653 CAIRO_CONTENT_COLOR_ALPHA,
654 gradient->n_stops, 1);
655 if (src->base.status) {
656 glitz_buffer_destroy (buffer);
657 free (data);
658 return src->base.status;
661 for (i = 0; i < gradient->n_stops; i++)
663 pixels[i] =
664 (((int) (gradient->stops[i].color.alpha_short >> 8)) << 24) |
665 (((int) (gradient->stops[i].color.red_short >> 8)) << 16) |
666 (((int) (gradient->stops[i].color.green_short >> 8)) << 8) |
667 (((int) (gradient->stops[i].color.blue_short >> 8)));
669 params[n_base_params + 3 * i + 0] = _cairo_fixed_16_16_from_double (gradient->stops[i].offset);
670 params[n_base_params + 3 * i + 1] = i << 16;
671 params[n_base_params + 3 * i + 2] = 0;
674 glitz_set_pixels (src->surface, 0, 0, gradient->n_stops, 1,
675 (glitz_pixel_format_t *)&format, buffer);
677 glitz_buffer_destroy (buffer);
679 if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR)
681 cairo_linear_pattern_t *grad = (cairo_linear_pattern_t *) pattern;
683 params[0] = _cairo_fixed_to_16_16 (grad->p1.x);
684 params[1] = _cairo_fixed_to_16_16 (grad->p1.y);
685 params[2] = _cairo_fixed_to_16_16 (grad->p2.x);
686 params[3] = _cairo_fixed_to_16_16 (grad->p2.y);
687 attr->filter = GLITZ_FILTER_LINEAR_GRADIENT;
689 else
691 cairo_radial_pattern_t *grad = (cairo_radial_pattern_t *) pattern;
693 params[0] = _cairo_fixed_to_16_16 (grad->c1.x);
694 params[1] = _cairo_fixed_to_16_16 (grad->c1.y);
695 params[2] = _cairo_fixed_to_16_16 (grad->r1);
696 params[3] = _cairo_fixed_to_16_16 (grad->c2.x);
697 params[4] = _cairo_fixed_to_16_16 (grad->c2.y);
698 params[5] = _cairo_fixed_to_16_16 (grad->r2);
699 attr->filter = GLITZ_FILTER_RADIAL_GRADIENT;
702 switch (pattern->extend) {
703 case CAIRO_EXTEND_NONE:
704 attr->fill = GLITZ_FILL_TRANSPARENT;
705 break;
706 case CAIRO_EXTEND_REPEAT:
707 attr->fill = GLITZ_FILL_REPEAT;
708 break;
709 case CAIRO_EXTEND_REFLECT:
710 attr->fill = GLITZ_FILL_REFLECT;
711 break;
712 case CAIRO_EXTEND_PAD:
713 attr->fill = GLITZ_FILL_NEAREST;
714 break;
717 attr->params = params;
718 attr->n_params = n_params;
719 attr->base.matrix = pattern->matrix;
720 attr->base.x_offset = 0;
721 attr->base.y_offset = 0;
722 } break;
723 case CAIRO_PATTERN_TYPE_SOLID:
724 case CAIRO_PATTERN_TYPE_SURFACE:
725 default:
726 break;
729 if (!src)
731 cairo_int_status_t status;
733 status = _cairo_pattern_acquire_surface (pattern, &dst->base,
734 CAIRO_CONTENT_COLOR_ALPHA,
735 x, y, width, height,
736 CAIRO_PATTERN_ACQUIRE_NONE,
737 (cairo_surface_t **) &src,
738 &attr->base);
739 if (status)
740 return status;
742 if (src)
744 switch (attr->base.extend) {
745 case CAIRO_EXTEND_NONE:
746 attr->fill = GLITZ_FILL_TRANSPARENT;
747 break;
748 case CAIRO_EXTEND_REPEAT:
749 attr->fill = GLITZ_FILL_REPEAT;
750 break;
751 case CAIRO_EXTEND_REFLECT:
752 attr->fill = GLITZ_FILL_REFLECT;
753 break;
754 case CAIRO_EXTEND_PAD:
755 default:
756 attr->fill = GLITZ_FILL_NEAREST;
757 break;
760 switch (attr->base.filter) {
761 case CAIRO_FILTER_FAST:
762 case CAIRO_FILTER_NEAREST:
763 attr->filter = GLITZ_FILTER_NEAREST;
764 break;
765 case CAIRO_FILTER_GOOD:
766 case CAIRO_FILTER_BEST:
767 case CAIRO_FILTER_BILINEAR:
768 case CAIRO_FILTER_GAUSSIAN:
769 default:
770 attr->filter = GLITZ_FILTER_BILINEAR;
771 break;
774 attr->params = NULL;
775 attr->n_params = 0;
776 attr->acquired = TRUE;
780 *surface_out = src;
782 return CAIRO_STATUS_SUCCESS;
785 static void
786 _cairo_glitz_pattern_release_surface (const cairo_pattern_t *pattern,
787 cairo_glitz_surface_t *surface,
788 cairo_glitz_surface_attributes_t *attr)
790 if (attr->acquired)
791 _cairo_pattern_release_surface (pattern, &surface->base, &attr->base);
792 else
793 cairo_surface_destroy (&surface->base);
796 static cairo_int_status_t
797 _cairo_glitz_pattern_acquire_surfaces (const cairo_pattern_t *src,
798 const cairo_pattern_t *mask,
799 cairo_glitz_surface_t *dst,
800 int src_x,
801 int src_y,
802 int mask_x,
803 int mask_y,
804 unsigned int width,
805 unsigned int height,
806 cairo_glitz_surface_t **src_out,
807 cairo_glitz_surface_t **mask_out,
808 cairo_glitz_surface_attributes_t *sattr,
809 cairo_glitz_surface_attributes_t *mattr)
811 cairo_int_status_t status;
812 cairo_solid_pattern_t tmp;
814 /* If src and mask are both solid, then the mask alpha can be
815 * combined into src and mask can be ignored. */
817 /* XXX: This optimization assumes that there is no color
818 * information in mask, so this will need to change when we
819 * support RENDER-style 4-channel masks. */
821 if (src->type == CAIRO_PATTERN_TYPE_SOLID &&
822 mask->type == CAIRO_PATTERN_TYPE_SOLID)
824 cairo_color_t combined;
825 cairo_solid_pattern_t *src_solid = (cairo_solid_pattern_t *) src;
826 cairo_solid_pattern_t *mask_solid = (cairo_solid_pattern_t *) mask;
828 combined = src_solid->color;
829 _cairo_color_multiply_alpha (&combined, mask_solid->color.alpha);
831 _cairo_pattern_init_solid (&tmp, &combined, CAIRO_CONTENT_COLOR_ALPHA);
833 mask = NULL;
834 src = &tmp.base;
837 status = _cairo_glitz_pattern_acquire_surface (src, dst,
838 src_x, src_y,
839 width, height,
840 src_out, sattr);
842 if (src == &tmp.base)
843 _cairo_pattern_fini (&tmp.base);
845 if (status)
846 return status;
848 if (mask)
850 status = _cairo_glitz_pattern_acquire_surface (mask, dst,
851 mask_x, mask_y,
852 width, height,
853 mask_out, mattr);
855 if (status) {
856 /* XXX src == &tmp.base -> invalid (currently inconsequential) */
857 _cairo_glitz_pattern_release_surface (src, *src_out, sattr);
860 return status;
862 else
864 *mask_out = NULL;
867 return CAIRO_STATUS_SUCCESS;
870 static void
871 _cairo_glitz_surface_set_attributes (cairo_glitz_surface_t *surface,
872 cairo_glitz_surface_attributes_t *a)
874 _cairo_glitz_surface_set_matrix (surface, &a->base.matrix);
875 glitz_surface_set_fill (surface->surface, a->fill);
876 glitz_surface_set_filter (surface->surface, a->filter,
877 a->params, a->n_params);
880 static cairo_int_status_t
881 _cairo_glitz_surface_composite (cairo_operator_t op,
882 const cairo_pattern_t *src_pattern,
883 const cairo_pattern_t *mask_pattern,
884 void *abstract_dst,
885 int src_x,
886 int src_y,
887 int mask_x,
888 int mask_y,
889 int dst_x,
890 int dst_y,
891 unsigned int width,
892 unsigned int height)
894 cairo_glitz_surface_attributes_t src_attr, mask_attr;
895 cairo_glitz_surface_t *dst = abstract_dst;
896 cairo_glitz_surface_t *src;
897 cairo_glitz_surface_t *mask;
898 cairo_int_status_t status;
900 if (op == CAIRO_OPERATOR_SATURATE)
901 return CAIRO_INT_STATUS_UNSUPPORTED;
903 if (_glitz_ensure_target (dst->surface))
904 return CAIRO_INT_STATUS_UNSUPPORTED;
906 status = _cairo_glitz_pattern_acquire_surfaces (src_pattern, mask_pattern,
907 dst,
908 src_x, src_y,
909 mask_x, mask_y,
910 width, height,
911 &src, &mask,
912 &src_attr, &mask_attr);
913 if (status)
914 return status;
916 _cairo_glitz_surface_set_attributes (src, &src_attr);
917 if (mask)
919 _cairo_glitz_surface_set_attributes (mask, &mask_attr);
920 glitz_composite (_glitz_operator (op),
921 src->surface,
922 mask->surface,
923 dst->surface,
924 src_x + src_attr.base.x_offset,
925 src_y + src_attr.base.y_offset,
926 mask_x + mask_attr.base.x_offset,
927 mask_y + mask_attr.base.y_offset,
928 dst_x, dst_y,
929 width, height);
931 else
933 glitz_composite (_glitz_operator (op),
934 src->surface,
935 NULL,
936 dst->surface,
937 src_x + src_attr.base.x_offset,
938 src_y + src_attr.base.y_offset,
939 0, 0,
940 dst_x, dst_y,
941 width, height);
944 if (glitz_surface_get_status (dst->surface) == GLITZ_STATUS_NOT_SUPPORTED)
945 status = CAIRO_INT_STATUS_UNSUPPORTED;
947 if (status == CAIRO_STATUS_SUCCESS &&
948 ! _cairo_operator_bounded_by_source (op))
950 int src_width, src_height;
951 int mask_width, mask_height;
953 src_width = glitz_surface_get_width (src->surface);
954 src_height = glitz_surface_get_height (src->surface);
955 if (mask)
957 mask_width = glitz_surface_get_width (mask->surface);
958 mask_height = glitz_surface_get_height (mask->surface);
960 else
962 mask_width = 0;
963 mask_height = 0;
965 status = _cairo_surface_composite_fixup_unbounded (&dst->base,
966 &src_attr.base,
967 src_width, src_height,
968 mask ? &mask_attr.base : NULL,
969 mask_width, mask_height,
970 src_x, src_y,
971 mask_x, mask_y,
972 dst_x, dst_y, width, height);
975 if (mask)
977 if (mask_attr.n_params)
978 free (mask_attr.params);
980 _cairo_glitz_pattern_release_surface (mask_pattern, mask, &mask_attr);
983 if (src_attr.n_params)
984 free (src_attr.params);
986 _cairo_glitz_pattern_release_surface (src_pattern, src, &src_attr);
988 return CAIRO_STATUS_SUCCESS;
991 static cairo_int_status_t
992 _cairo_glitz_surface_fill_rectangles (void *abstract_dst,
993 cairo_operator_t op,
994 const cairo_color_t *color,
995 cairo_rectangle_int_t *rects,
996 int n_rects)
998 cairo_glitz_surface_t *dst = abstract_dst;
999 cairo_glitz_surface_t *src;
1000 glitz_rectangle_t stack_rects[CAIRO_STACK_ARRAY_LENGTH (glitz_rectangle_t)];
1001 glitz_rectangle_t *glitz_rects = stack_rects;
1002 glitz_rectangle_t *current_rect;
1003 int i;
1005 if (n_rects > ARRAY_LENGTH (stack_rects)) {
1006 glitz_rects = _cairo_malloc_ab (n_rects, sizeof (glitz_rectangle_t));
1007 if (glitz_rects == NULL)
1008 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1011 for (i = 0; i < n_rects; i++) {
1012 glitz_rects[i].x = rects[i].x;
1013 glitz_rects[i].y = rects[i].y;
1014 glitz_rects[i].width = rects[i].width;
1015 glitz_rects[i].height = rects[i].height;
1018 switch (op) {
1019 case CAIRO_OPERATOR_CLEAR:
1020 case CAIRO_OPERATOR_SOURCE: {
1021 glitz_color_t glitz_color;
1022 glitz_format_t *format;
1024 glitz_color.red = color->red_short;
1025 glitz_color.green = color->green_short;
1026 glitz_color.blue = color->blue_short;
1027 glitz_color.alpha = color->alpha_short;
1030 * XXX even if the dst surface don't have an alpha channel, the
1031 * above alpha still effect the dst surface because the
1032 * underlying glitz drawable may have an alpha channel. So
1033 * replacing the color with an opaque one is needed.
1035 format = glitz_surface_get_format (dst->surface);
1036 if (format->color.alpha_size == 0)
1037 glitz_color.alpha = 0xffff;
1039 glitz_set_rectangles (dst->surface, &glitz_color,
1040 glitz_rects, n_rects);
1041 } break;
1042 case CAIRO_OPERATOR_SATURATE:
1043 return CAIRO_INT_STATUS_UNSUPPORTED;
1044 case CAIRO_OPERATOR_OVER:
1045 case CAIRO_OPERATOR_IN:
1046 case CAIRO_OPERATOR_OUT:
1047 case CAIRO_OPERATOR_ATOP:
1048 case CAIRO_OPERATOR_DEST:
1049 case CAIRO_OPERATOR_DEST_OVER:
1050 case CAIRO_OPERATOR_DEST_IN:
1051 case CAIRO_OPERATOR_DEST_OUT:
1052 case CAIRO_OPERATOR_DEST_ATOP:
1053 case CAIRO_OPERATOR_XOR:
1054 case CAIRO_OPERATOR_ADD:
1055 default:
1056 if (_glitz_ensure_target (dst->surface))
1058 if (glitz_rects != stack_rects)
1059 free (glitz_rects);
1060 return CAIRO_INT_STATUS_UNSUPPORTED;
1063 src = (cairo_glitz_surface_t *)
1064 _cairo_surface_create_similar_solid (&dst->base,
1065 CAIRO_CONTENT_COLOR_ALPHA,
1066 1, 1,
1067 (cairo_color_t *) color);
1068 if (src->base.status)
1070 if (glitz_rects != stack_rects)
1071 free (glitz_rects);
1072 return src->base.status;
1075 glitz_surface_set_fill (src->surface, GLITZ_FILL_REPEAT);
1077 current_rect = glitz_rects;
1078 while (n_rects--)
1080 glitz_composite (_glitz_operator (op),
1081 src->surface,
1082 NULL,
1083 dst->surface,
1084 0, 0,
1085 0, 0,
1086 current_rect->x, current_rect->y,
1087 current_rect->width, current_rect->height);
1088 current_rect++;
1091 cairo_surface_destroy (&src->base);
1092 break;
1095 if (glitz_rects != stack_rects)
1096 free (glitz_rects);
1098 if (glitz_surface_get_status (dst->surface) == GLITZ_STATUS_NOT_SUPPORTED)
1099 return CAIRO_INT_STATUS_UNSUPPORTED;
1101 return CAIRO_STATUS_SUCCESS;
1104 static cairo_int_status_t
1105 _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
1106 const cairo_pattern_t *pattern,
1107 void *abstract_dst,
1108 cairo_antialias_t antialias,
1109 int src_x,
1110 int src_y,
1111 int dst_x,
1112 int dst_y,
1113 unsigned int width,
1114 unsigned int height,
1115 cairo_trapezoid_t *traps,
1116 int n_traps)
1118 cairo_glitz_surface_attributes_t attributes;
1119 cairo_glitz_surface_t *dst = abstract_dst;
1120 cairo_glitz_surface_t *src;
1121 cairo_glitz_surface_t *mask = NULL;
1122 glitz_buffer_t *buffer = NULL;
1123 void *data = NULL;
1124 cairo_int_status_t status;
1125 unsigned short alpha;
1126 pixman_trapezoid_t stack_traps[CAIRO_STACK_ARRAY_LENGTH (pixman_trapezoid_t)];
1127 pixman_trapezoid_t *pixman_traps = stack_traps;
1128 int i;
1130 if (antialias == CAIRO_ANTIALIAS_NONE)
1132 return CAIRO_INT_STATUS_UNSUPPORTED;
1135 if (op == CAIRO_OPERATOR_SATURATE)
1136 return CAIRO_INT_STATUS_UNSUPPORTED;
1138 if (_glitz_ensure_target (dst->surface))
1139 return CAIRO_INT_STATUS_UNSUPPORTED;
1141 /* Convert traps to pixman traps */
1142 if (n_traps > ARRAY_LENGTH (stack_traps)) {
1143 pixman_traps = _cairo_malloc_ab (n_traps, sizeof (pixman_trapezoid_t));
1144 if (pixman_traps == NULL)
1145 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1148 for (i = 0; i < n_traps; i++) {
1149 pixman_traps[i].top = _cairo_fixed_to_16_16 (traps[i].top);
1150 pixman_traps[i].bottom = _cairo_fixed_to_16_16 (traps[i].bottom);
1151 pixman_traps[i].left.p1.x = _cairo_fixed_to_16_16 (traps[i].left.p1.x);
1152 pixman_traps[i].left.p1.y = _cairo_fixed_to_16_16 (traps[i].left.p1.y);
1153 pixman_traps[i].left.p2.x = _cairo_fixed_to_16_16 (traps[i].left.p2.x);
1154 pixman_traps[i].left.p2.y = _cairo_fixed_to_16_16 (traps[i].left.p2.y);
1155 pixman_traps[i].right.p1.x = _cairo_fixed_to_16_16 (traps[i].right.p1.x);
1156 pixman_traps[i].right.p1.y = _cairo_fixed_to_16_16 (traps[i].right.p1.y);
1157 pixman_traps[i].right.p2.x = _cairo_fixed_to_16_16 (traps[i].right.p2.x);
1158 pixman_traps[i].right.p2.y = _cairo_fixed_to_16_16 (traps[i].right.p2.y);
1161 status = _cairo_glitz_pattern_acquire_surface (pattern, dst,
1162 src_x, src_y,
1163 width, height,
1164 &src, &attributes);
1165 if (status)
1166 goto FAIL;
1168 alpha = 0xffff;
1170 if (op == CAIRO_OPERATOR_ADD || n_traps <= 1) {
1171 static const glitz_color_t clear_black = { 0, 0, 0, 0 };
1172 glitz_color_t color;
1173 glitz_geometry_format_t format;
1174 int n_trap_added;
1175 int offset = 0;
1176 int data_size = 0;
1177 int size = 30 * n_traps; /* just a guess */
1179 format.vertex.primitive = GLITZ_PRIMITIVE_QUADS;
1180 format.vertex.type = GLITZ_DATA_TYPE_FLOAT;
1181 format.vertex.bytes_per_vertex = 3 * sizeof (glitz_float_t);
1182 format.vertex.attributes = GLITZ_VERTEX_ATTRIBUTE_MASK_COORD_MASK;
1183 format.vertex.mask.type = GLITZ_DATA_TYPE_FLOAT;
1184 format.vertex.mask.size = GLITZ_COORDINATE_SIZE_X;
1185 format.vertex.mask.offset = 2 * sizeof (glitz_float_t);
1187 mask = (cairo_glitz_surface_t *)
1188 _cairo_glitz_surface_create_similar (&dst->base,
1189 CAIRO_CONTENT_ALPHA,
1190 2, 1);
1191 if (mask == NULL) {
1192 status = CAIRO_INT_STATUS_UNSUPPORTED;
1193 goto FAIL;
1195 if (mask->base.status) {
1196 status = mask->base.status;
1197 goto FAIL;
1200 color.red = color.green = color.blue = color.alpha = 0xffff;
1202 glitz_set_rectangle (mask->surface, &clear_black, 0, 0, 1, 1);
1203 glitz_set_rectangle (mask->surface, &color, 1, 0, 1, 1);
1205 glitz_surface_set_fill (mask->surface, GLITZ_FILL_NEAREST);
1206 glitz_surface_set_filter (mask->surface,
1207 GLITZ_FILTER_BILINEAR,
1208 NULL, 0);
1210 size *= format.vertex.bytes_per_vertex;
1212 while (n_traps) {
1213 if (data_size < size) {
1214 void *p;
1216 data_size = size;
1217 p = realloc (data, data_size);
1218 if (p == NULL) {
1219 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1220 goto FAIL;
1222 data = p;
1224 if (buffer)
1225 glitz_buffer_destroy (buffer);
1227 buffer = glitz_buffer_create_for_data (data);
1228 if (buffer == NULL) {
1229 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1230 free (data);
1231 goto FAIL;
1235 offset +=
1236 glitz_add_trapezoids (buffer,
1237 offset, size - offset,
1238 format.vertex.type, mask->surface,
1239 (glitz_trapezoid_t *) pixman_traps, n_traps,
1240 &n_trap_added);
1242 n_traps -= n_trap_added;
1243 traps += n_trap_added;
1244 size *= 2;
1247 glitz_set_geometry (dst->surface,
1248 GLITZ_GEOMETRY_TYPE_VERTEX,
1249 &format, buffer);
1250 glitz_set_array (dst->surface, 0, 3,
1251 offset / format.vertex.bytes_per_vertex,
1252 0, 0);
1253 } else {
1254 cairo_image_surface_t *image;
1255 unsigned char *ptr;
1256 int stride;
1258 stride = (width + 3) & -4;
1259 data = calloc (stride, height);
1260 if (data == NULL) {
1261 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1262 goto FAIL;
1265 /* using negative stride */
1266 ptr = (unsigned char *) data + stride * (height - 1);
1268 image = (cairo_image_surface_t *)
1269 cairo_image_surface_create_for_data (ptr,
1270 CAIRO_FORMAT_A8,
1271 width, height,
1272 -stride);
1273 status = image->base.status;
1274 if (status) {
1275 free (data);
1276 goto FAIL;
1279 pixman_add_trapezoids (image->pixman_image, -dst_x, -dst_y,
1280 n_traps, (pixman_trapezoid_t *) pixman_traps);
1282 mask = (cairo_glitz_surface_t *)
1283 _cairo_surface_create_similar_scratch (&dst->base,
1284 CAIRO_CONTENT_ALPHA,
1285 width, height);
1286 status = mask->base.status;
1287 if (status) {
1288 free (data);
1289 cairo_surface_destroy (&image->base);
1290 goto FAIL;
1293 status = _cairo_glitz_surface_set_image (mask, image,
1294 0, 0, width, height, 0, 0);
1296 cairo_surface_destroy (&image->base);
1298 if (status)
1299 goto FAIL;
1302 _cairo_glitz_surface_set_attributes (src, &attributes);
1304 glitz_composite (_glitz_operator (op),
1305 src->surface,
1306 mask->surface,
1307 dst->surface,
1308 src_x + attributes.base.x_offset,
1309 src_y + attributes.base.y_offset,
1310 0, 0,
1311 dst_x, dst_y,
1312 width, height);
1314 if (attributes.n_params)
1315 free (attributes.params);
1317 glitz_set_geometry (dst->surface,
1318 GLITZ_GEOMETRY_TYPE_NONE,
1319 NULL, NULL);
1321 if (buffer)
1322 glitz_buffer_destroy (buffer);
1324 free (data);
1326 if (glitz_surface_get_status (dst->surface) == GLITZ_STATUS_NOT_SUPPORTED) {
1327 status = CAIRO_INT_STATUS_UNSUPPORTED;
1328 goto FAIL;
1331 if (! _cairo_operator_bounded_by_mask (op)) {
1332 status = _cairo_surface_composite_shape_fixup_unbounded (&dst->base,
1333 &attributes.base,
1334 glitz_surface_get_width (src->surface),
1335 glitz_surface_get_height (src->surface),
1336 width, height,
1337 src_x, src_y,
1338 0, 0,
1339 dst_x, dst_y,
1340 width, height);
1343 FAIL:
1344 _cairo_glitz_pattern_release_surface (pattern, src, &attributes);
1346 if (mask != NULL)
1347 cairo_surface_destroy (&mask->base);
1349 if (pixman_traps != stack_traps)
1350 free (pixman_traps);
1352 return status;
1355 static cairo_int_status_t
1356 _cairo_glitz_surface_set_clip_region (void *abstract_surface,
1357 cairo_region_t *region)
1359 cairo_glitz_surface_t *surface = abstract_surface;
1361 if (region != NULL) {
1362 cairo_status_t status;
1364 status = _cairo_glitz_get_boxes_from_region (region,
1365 &surface->clip_boxes,
1366 &surface->num_clip_boxes);
1367 if (status)
1368 return status;
1370 glitz_surface_set_clip_region (surface->surface,
1371 0, 0,
1372 surface->clip_boxes,
1373 surface->num_clip_boxes);
1374 surface->has_clip = TRUE;
1375 } else {
1376 glitz_surface_set_clip_region (surface->surface, 0, 0, NULL, 0);
1377 surface->has_clip = FALSE;
1380 return CAIRO_STATUS_SUCCESS;
1383 static cairo_int_status_t
1384 _cairo_glitz_surface_get_extents (void *abstract_surface,
1385 cairo_rectangle_int_t *rectangle)
1387 cairo_glitz_surface_t *surface = abstract_surface;
1389 rectangle->x = 0;
1390 rectangle->y = 0;
1391 rectangle->width = glitz_surface_get_width (surface->surface);
1392 rectangle->height = glitz_surface_get_height (surface->surface);
1394 return CAIRO_STATUS_SUCCESS;
1397 #define CAIRO_GLITZ_AREA_AVAILABLE 0
1398 #define CAIRO_GLITZ_AREA_DIVIDED 1
1399 #define CAIRO_GLITZ_AREA_OCCUPIED 2
1401 typedef struct _cairo_glitz_root_area cairo_glitz_root_area_t;
1403 typedef struct _cairo_glitz_area {
1404 int state;
1405 int level;
1406 int x, y;
1407 int width, height;
1408 struct _cairo_glitz_area *area[4];
1409 cairo_glitz_root_area_t *root;
1410 void *closure;
1411 } cairo_glitz_area_t;
1413 static cairo_glitz_area_t _empty_area = {
1414 0, 0, 0, 0, 0, 0,
1415 { NULL, NULL, NULL, NULL },
1416 NULL,
1417 NULL
1420 typedef struct _cairo_glitz_area_funcs {
1421 cairo_status_t (*move_in) (cairo_glitz_area_t *area,
1422 void *closure);
1424 void (*move_out) (cairo_glitz_area_t *area,
1425 void *closure);
1427 int (*compare_score) (cairo_glitz_area_t *area,
1428 void *closure1,
1429 void *closure2);
1430 } cairo_glitz_area_funcs_t;
1432 struct _cairo_glitz_root_area {
1433 int max_level;
1434 int width, height;
1435 cairo_glitz_area_t *area;
1436 const cairo_glitz_area_funcs_t *funcs;
1439 static cairo_status_t
1440 _cairo_glitz_area_move_in (cairo_glitz_area_t *area,
1441 void *closure)
1443 area->closure = closure;
1444 area->state = CAIRO_GLITZ_AREA_OCCUPIED;
1446 return (*area->root->funcs->move_in) (area, area->closure);
1449 static void
1450 _cairo_glitz_area_move_out (cairo_glitz_area_t *area)
1452 if (area->root)
1454 (*area->root->funcs->move_out) (area, area->closure);
1456 area->closure = NULL;
1457 area->state = CAIRO_GLITZ_AREA_AVAILABLE;
1461 static cairo_glitz_area_t *
1462 _cairo_glitz_area_create (cairo_glitz_root_area_t *root,
1463 int level,
1464 int x,
1465 int y,
1466 int width,
1467 int height)
1469 cairo_glitz_area_t *area;
1470 int n = 4;
1472 area = malloc (sizeof (cairo_glitz_area_t));
1473 if (!area) {
1474 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
1475 return NULL;
1478 area->level = level;
1479 area->x = x;
1480 area->y = y;
1481 area->width = width;
1482 area->height = height;
1483 area->root = root;
1484 area->closure = NULL;
1485 area->state = CAIRO_GLITZ_AREA_AVAILABLE;
1487 while (n--)
1488 area->area[n] = NULL;
1490 return area;
1493 static void
1494 _cairo_glitz_area_destroy (cairo_glitz_area_t *area)
1496 if (area == NULL)
1497 return;
1499 if (area->state == CAIRO_GLITZ_AREA_OCCUPIED)
1501 _cairo_glitz_area_move_out (area);
1503 else
1505 int n = 4;
1507 while (n--)
1508 _cairo_glitz_area_destroy (area->area[n]);
1511 free (area);
1514 static cairo_glitz_area_t *
1515 _cairo_glitz_area_get_top_scored_sub_area (cairo_glitz_area_t *area)
1517 if (!area)
1518 return NULL;
1520 switch (area->state) {
1521 case CAIRO_GLITZ_AREA_OCCUPIED:
1522 return area;
1523 case CAIRO_GLITZ_AREA_AVAILABLE:
1524 break;
1525 case CAIRO_GLITZ_AREA_DIVIDED: {
1526 cairo_glitz_area_t *tmp, *top = NULL;
1527 int i;
1529 for (i = 0; i < 4; i++)
1531 tmp = _cairo_glitz_area_get_top_scored_sub_area (area->area[i]);
1532 if (tmp && top)
1534 if ((*area->root->funcs->compare_score) (tmp,
1535 tmp->closure,
1536 top->closure) > 0)
1537 top = tmp;
1539 else if (tmp)
1541 top = tmp;
1544 return top;
1548 return NULL;
1551 static cairo_int_status_t
1552 _cairo_glitz_area_find (cairo_glitz_area_t *area,
1553 int width,
1554 int height,
1555 cairo_bool_t kick_out,
1556 void *closure)
1558 cairo_status_t status;
1560 if (area->width < width || area->height < height)
1561 return CAIRO_INT_STATUS_UNSUPPORTED;
1563 switch (area->state) {
1564 case CAIRO_GLITZ_AREA_OCCUPIED:
1565 if (kick_out)
1567 if ((*area->root->funcs->compare_score) (area,
1568 area->closure,
1569 closure) >= 0)
1570 return CAIRO_INT_STATUS_UNSUPPORTED;
1572 _cairo_glitz_area_move_out (area);
1573 } else {
1574 return CAIRO_INT_STATUS_UNSUPPORTED;
1577 /* fall-through */
1578 case CAIRO_GLITZ_AREA_AVAILABLE: {
1579 if (area->level == area->root->max_level ||
1580 (area->width == width && area->height == height))
1582 return _cairo_glitz_area_move_in (area, closure);
1584 else
1586 int dx[4], dy[4], w[4], h[4], i;
1588 dx[0] = dx[2] = dy[0] = dy[1] = 0;
1590 w[0] = w[2] = dx[1] = dx[3] = width;
1591 h[0] = h[1] = dy[2] = dy[3] = height;
1593 w[1] = w[3] = area->width - width;
1594 h[2] = h[3] = area->height - height;
1596 for (i = 0; i < 2; i++)
1598 if (w[i])
1599 area->area[i] =
1600 _cairo_glitz_area_create (area->root,
1601 area->level + 1,
1602 area->x + dx[i],
1603 area->y + dy[i],
1604 w[i], h[i]);
1607 for (; i < 4; i++)
1609 if (w[i] && h[i])
1610 area->area[i] =
1611 _cairo_glitz_area_create (area->root,
1612 area->level + 1,
1613 area->x + dx[i],
1614 area->y + dy[i],
1615 w[i], h[i]);
1618 area->state = CAIRO_GLITZ_AREA_DIVIDED;
1620 status = _cairo_glitz_area_find (area->area[0],
1621 width, height,
1622 kick_out, closure);
1623 if (status == CAIRO_STATUS_SUCCESS)
1624 return CAIRO_STATUS_SUCCESS;
1626 } break;
1627 case CAIRO_GLITZ_AREA_DIVIDED: {
1628 cairo_glitz_area_t *to_area;
1629 int i, rejected = FALSE;
1631 for (i = 0; i < 4; i++)
1633 if (area->area[i])
1635 if (area->area[i]->width >= width &&
1636 area->area[i]->height >= height)
1638 status = _cairo_glitz_area_find (area->area[i],
1639 width, height,
1640 kick_out, closure);
1641 if (status == CAIRO_STATUS_SUCCESS)
1642 return CAIRO_STATUS_SUCCESS;
1644 rejected = TRUE;
1649 if (rejected)
1650 return CAIRO_INT_STATUS_UNSUPPORTED;
1652 to_area = _cairo_glitz_area_get_top_scored_sub_area (area);
1653 if (to_area)
1655 if (kick_out)
1657 if ((*area->root->funcs->compare_score) (to_area,
1658 to_area->closure,
1659 closure) >= 0)
1660 return CAIRO_INT_STATUS_UNSUPPORTED;
1661 } else {
1662 return CAIRO_INT_STATUS_UNSUPPORTED;
1666 for (i = 0; i < 4; i++)
1668 _cairo_glitz_area_destroy (area->area[i]);
1669 area->area[i] = NULL;
1672 area->closure = NULL;
1673 area->state = CAIRO_GLITZ_AREA_AVAILABLE;
1675 status = _cairo_glitz_area_find (area, width, height,
1676 TRUE, closure);
1677 if (status == CAIRO_STATUS_SUCCESS)
1678 return CAIRO_STATUS_SUCCESS;
1680 } break;
1683 return CAIRO_INT_STATUS_UNSUPPORTED;
1686 static cairo_status_t
1687 _cairo_glitz_root_area_init (cairo_glitz_root_area_t *root,
1688 int max_level,
1689 int width,
1690 int height,
1691 const cairo_glitz_area_funcs_t *funcs)
1693 root->max_level = max_level;
1694 root->funcs = funcs;
1696 root->area = _cairo_glitz_area_create (root, 0, 0, 0, width, height);
1697 if (!root->area)
1698 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1700 return CAIRO_STATUS_SUCCESS;
1703 static void
1704 _cairo_glitz_root_area_fini (cairo_glitz_root_area_t *root)
1706 _cairo_glitz_area_destroy (root->area);
1709 typedef struct _cairo_glitz_surface_font_private {
1710 cairo_glitz_root_area_t root;
1711 glitz_surface_t *surface;
1712 } cairo_glitz_surface_font_private_t;
1714 typedef struct _cairo_glitz_surface_glyph_private {
1715 cairo_glitz_area_t *area;
1716 cairo_bool_t locked;
1717 cairo_point_double_t p1, p2;
1718 } cairo_glitz_surface_glyph_private_t;
1720 static cairo_status_t
1721 _cairo_glitz_glyph_move_in (cairo_glitz_area_t *area,
1722 void *closure)
1724 cairo_glitz_surface_glyph_private_t *glyph_private = closure;
1726 glyph_private->area = area;
1728 return CAIRO_STATUS_SUCCESS;
1731 static void
1732 _cairo_glitz_glyph_move_out (cairo_glitz_area_t *area,
1733 void *closure)
1735 cairo_glitz_surface_glyph_private_t *glyph_private = closure;
1737 glyph_private->area = NULL;
1740 static int
1741 _cairo_glitz_glyph_compare (cairo_glitz_area_t *area,
1742 void *closure1,
1743 void *closure2)
1745 cairo_glitz_surface_glyph_private_t *glyph_private = closure1;
1747 if (glyph_private->locked)
1748 return 1;
1750 return -1;
1753 static const cairo_glitz_area_funcs_t _cairo_glitz_area_funcs = {
1754 _cairo_glitz_glyph_move_in,
1755 _cairo_glitz_glyph_move_out,
1756 _cairo_glitz_glyph_compare
1759 #define GLYPH_CACHE_TEXTURE_SIZE 512
1760 #define GLYPH_CACHE_MAX_LEVEL 64
1761 #define GLYPH_CACHE_MAX_HEIGHT 96
1762 #define GLYPH_CACHE_MAX_WIDTH 96
1764 #define WRITE_VEC2(ptr, _x, _y) \
1765 *(ptr)++ = (_x); \
1766 *(ptr)++ = (_y)
1768 #define WRITE_BOX(ptr, _vx1, _vy1, _vx2, _vy2, p1, p2) \
1769 WRITE_VEC2 (ptr, _vx1, _vy1); \
1770 WRITE_VEC2 (ptr, (p1)->x, (p2)->y); \
1771 WRITE_VEC2 (ptr, _vx2, _vy1); \
1772 WRITE_VEC2 (ptr, (p2)->x, (p2)->y); \
1773 WRITE_VEC2 (ptr, _vx2, _vy2); \
1774 WRITE_VEC2 (ptr, (p2)->x, (p1)->y); \
1775 WRITE_VEC2 (ptr, _vx1, _vy2); \
1776 WRITE_VEC2 (ptr, (p1)->x, (p1)->y)
1778 static cairo_status_t
1779 _cairo_glitz_surface_font_init (cairo_glitz_surface_t *surface,
1780 cairo_scaled_font_t *scaled_font,
1781 cairo_format_t format)
1783 cairo_glitz_surface_font_private_t *font_private;
1784 glitz_drawable_t *drawable;
1785 glitz_format_t *surface_format = NULL;
1786 cairo_int_status_t status;
1788 drawable = glitz_surface_get_drawable (surface->surface);
1790 switch (format) {
1791 case CAIRO_FORMAT_A1:
1792 case CAIRO_FORMAT_A8:
1793 surface_format =
1794 glitz_find_standard_format (drawable, GLITZ_STANDARD_A8);
1795 break;
1796 case CAIRO_FORMAT_RGB24:
1797 ASSERT_NOT_REACHED;
1798 break;
1799 case CAIRO_FORMAT_ARGB32:
1800 surface_format =
1801 glitz_find_standard_format (drawable, GLITZ_STANDARD_ARGB32);
1802 default:
1803 break;
1806 if (!surface_format)
1807 return CAIRO_INT_STATUS_UNSUPPORTED;
1809 font_private = malloc (sizeof (cairo_glitz_surface_font_private_t));
1810 if (!font_private)
1811 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1813 font_private->surface = glitz_surface_create (drawable, surface_format,
1814 GLYPH_CACHE_TEXTURE_SIZE,
1815 GLYPH_CACHE_TEXTURE_SIZE,
1816 0, NULL);
1817 if (font_private->surface == NULL)
1819 free (font_private);
1821 return CAIRO_INT_STATUS_UNSUPPORTED;
1824 if (format == CAIRO_FORMAT_ARGB32)
1825 glitz_surface_set_component_alpha (font_private->surface, 1);
1827 status = _cairo_glitz_root_area_init (&font_private->root,
1828 GLYPH_CACHE_MAX_LEVEL,
1829 GLYPH_CACHE_TEXTURE_SIZE,
1830 GLYPH_CACHE_TEXTURE_SIZE,
1831 &_cairo_glitz_area_funcs);
1832 if (status != CAIRO_STATUS_SUCCESS)
1834 glitz_surface_destroy (font_private->surface);
1835 free (font_private);
1837 return status;
1840 scaled_font->surface_private = font_private;
1841 scaled_font->surface_backend = _cairo_glitz_surface_get_backend ();
1843 return CAIRO_STATUS_SUCCESS;
1846 static void
1847 _cairo_glitz_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font)
1849 cairo_glitz_surface_font_private_t *font_private;
1851 font_private = scaled_font->surface_private;
1852 if (font_private)
1854 _cairo_glitz_root_area_fini (&font_private->root);
1855 glitz_surface_destroy (font_private->surface);
1856 free (font_private);
1860 static void
1861 _cairo_glitz_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph,
1862 cairo_scaled_font_t *scaled_font)
1864 cairo_glitz_surface_glyph_private_t *glyph_private;
1866 glyph_private = scaled_glyph->surface_private;
1867 if (glyph_private)
1869 if (glyph_private->area)
1870 _cairo_glitz_area_move_out (glyph_private->area);
1872 free (glyph_private);
1876 #define FIXED_TO_FLOAT(f) (((glitz_float_t) (f)) / 65536)
1878 static cairo_status_t
1879 _cairo_glitz_surface_add_glyph (cairo_glitz_surface_t *surface,
1880 cairo_scaled_font_t *scaled_font,
1881 cairo_scaled_glyph_t *scaled_glyph)
1883 cairo_image_surface_t *glyph_surface = scaled_glyph->surface;
1884 cairo_glitz_surface_font_private_t *font_private;
1885 cairo_glitz_surface_glyph_private_t *glyph_private;
1886 glitz_point_fixed_t p1, p2;
1887 glitz_pixel_format_t pf;
1888 glitz_buffer_t *buffer;
1889 cairo_format_masks_t masks;
1890 cairo_int_status_t status;
1892 glyph_private = scaled_glyph->surface_private;
1893 if (glyph_private == NULL)
1895 glyph_private = malloc (sizeof (cairo_glitz_surface_glyph_private_t));
1896 if (!glyph_private)
1897 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1899 glyph_private->area = NULL;
1900 glyph_private->locked = FALSE;
1902 scaled_glyph->surface_private = (void *) glyph_private;
1905 if (glyph_surface->width > GLYPH_CACHE_MAX_WIDTH ||
1906 glyph_surface->height > GLYPH_CACHE_MAX_HEIGHT)
1907 return CAIRO_INT_STATUS_UNSUPPORTED;
1909 if (scaled_font->surface_private == NULL)
1911 status = _cairo_glitz_surface_font_init (surface, scaled_font,
1912 glyph_surface->format);
1913 if (status)
1914 return status;
1917 font_private = scaled_font->surface_private;
1919 if (glyph_surface->width == 0 || glyph_surface->height == 0)
1921 glyph_private->area = &_empty_area;
1922 return CAIRO_STATUS_SUCCESS;
1925 if (_cairo_glitz_area_find (font_private->root.area,
1926 glyph_surface->width,
1927 glyph_surface->height,
1928 FALSE, glyph_private))
1930 if (_cairo_glitz_area_find (font_private->root.area,
1931 glyph_surface->width,
1932 glyph_surface->height,
1933 TRUE, glyph_private))
1934 return CAIRO_STATUS_SUCCESS;
1937 buffer = glitz_buffer_create_for_data (glyph_surface->data);
1938 if (!buffer)
1940 _cairo_glitz_area_move_out (glyph_private->area);
1941 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1944 _pixman_format_to_masks (glyph_surface->pixman_format, &masks);
1946 pf.fourcc = GLITZ_FOURCC_RGB;
1947 pf.masks.bpp = masks.bpp;
1948 pf.masks.alpha_mask = masks.alpha_mask;
1949 pf.masks.red_mask = masks.red_mask;
1950 pf.masks.green_mask = masks.green_mask;
1951 pf.masks.blue_mask = masks.blue_mask;
1953 pf.bytes_per_line = glyph_surface->stride;
1954 pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_BOTTOM_UP;
1955 pf.xoffset = 0;
1956 pf.skip_lines = 0;
1958 glitz_set_pixels (font_private->surface,
1959 glyph_private->area->x,
1960 glyph_private->area->y,
1961 glyph_surface->width,
1962 glyph_surface->height,
1963 &pf, buffer);
1965 glitz_buffer_destroy (buffer);
1967 p1.x = glyph_private->area->x << 16;
1968 p1.y = glyph_private->area->y << 16;
1969 p2.x = (glyph_private->area->x + glyph_surface->width) << 16;
1970 p2.y = (glyph_private->area->y + glyph_surface->height) << 16;
1972 glitz_surface_translate_point (font_private->surface, &p1, &p1);
1973 glitz_surface_translate_point (font_private->surface, &p2, &p2);
1975 glyph_private->p1.x = FIXED_TO_FLOAT (p1.x);
1976 glyph_private->p1.y = FIXED_TO_FLOAT (p1.y);
1977 glyph_private->p2.x = FIXED_TO_FLOAT (p2.x);
1978 glyph_private->p2.y = FIXED_TO_FLOAT (p2.y);
1980 return CAIRO_STATUS_SUCCESS;
1983 #define N_STACK_BUF 256
1985 static cairo_int_status_t
1986 _cairo_glitz_surface_old_show_glyphs (cairo_scaled_font_t *scaled_font,
1987 cairo_operator_t op,
1988 const cairo_pattern_t *pattern,
1989 void *abstract_surface,
1990 int src_x,
1991 int src_y,
1992 int dst_x,
1993 int dst_y,
1994 unsigned int width,
1995 unsigned int height,
1996 cairo_glyph_t *glyphs,
1997 int num_glyphs)
1999 cairo_glitz_surface_attributes_t attributes;
2000 cairo_glitz_surface_glyph_private_t *glyph_private;
2001 cairo_glitz_surface_t *dst = abstract_surface;
2002 cairo_glitz_surface_t *src;
2003 cairo_scaled_glyph_t *stack_scaled_glyphs[N_STACK_BUF];
2004 cairo_scaled_glyph_t **scaled_glyphs;
2005 glitz_float_t stack_vertices[N_STACK_BUF * 16];
2006 glitz_float_t *vertices;
2007 glitz_buffer_t *buffer;
2008 cairo_int_status_t status;
2009 int x_offset, y_offset;
2010 int i, cached_glyphs = 0;
2011 int remaining_glyps = num_glyphs;
2012 glitz_float_t x1, y1, x2, y2;
2013 static const glitz_vertex_format_t format = {
2014 GLITZ_PRIMITIVE_QUADS,
2015 GLITZ_DATA_TYPE_FLOAT,
2016 sizeof (glitz_float_t) * 4,
2017 GLITZ_VERTEX_ATTRIBUTE_MASK_COORD_MASK,
2018 { 0 },
2020 GLITZ_DATA_TYPE_FLOAT,
2021 GLITZ_COORDINATE_SIZE_XY,
2022 sizeof (glitz_float_t) * 2,
2026 if (scaled_font->surface_backend != NULL &&
2027 scaled_font->surface_backend != _cairo_glitz_surface_get_backend ())
2028 return CAIRO_INT_STATUS_UNSUPPORTED;
2030 if (op == CAIRO_OPERATOR_SATURATE)
2031 return CAIRO_INT_STATUS_UNSUPPORTED;
2033 /* XXX Unbounded operators are not handled correctly */
2034 if (! _cairo_operator_bounded_by_mask (op))
2035 return CAIRO_INT_STATUS_UNSUPPORTED;
2037 if (_glitz_ensure_target (dst->surface))
2038 return CAIRO_INT_STATUS_UNSUPPORTED;
2040 status = _cairo_glitz_pattern_acquire_surface (pattern, dst,
2041 src_x, src_y,
2042 width, height,
2043 &src, &attributes);
2044 if (status)
2045 return status;
2047 _cairo_glitz_surface_set_attributes (src, &attributes);
2049 if (num_glyphs > N_STACK_BUF)
2051 char *data;
2052 size_t size1, size2;
2054 if ((size_t)num_glyphs >= INT32_MAX / sizeof(void*) ||
2055 (size_t)num_glyphs >= INT32_MAX / sizeof(glitz_float_t) ||
2056 ((size_t)num_glyphs * sizeof(glitz_float_t)) >= INT32_MAX / 16)
2057 goto FAIL1;
2059 size1 = num_glyphs * sizeof(void *);
2060 size2 = num_glyphs * sizeof(glitz_float_t) * 16;
2061 if (size1 >= INT32_MAX - size2)
2062 goto FAIL1;
2064 data = malloc (size1 + size2);
2065 if (!data) {
2066 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
2067 goto FAIL1;
2070 scaled_glyphs = (cairo_scaled_glyph_t **) data;
2071 vertices = (glitz_float_t *) (data + num_glyphs * sizeof (void *));
2073 else
2075 scaled_glyphs = stack_scaled_glyphs;
2076 vertices = stack_vertices;
2079 buffer = glitz_buffer_create_for_data (vertices);
2080 if (!buffer)
2081 goto FAIL2;
2083 _cairo_scaled_font_freeze_cache (scaled_font);
2085 for (i = 0; i < num_glyphs; i++)
2087 status = _cairo_scaled_glyph_lookup (scaled_font,
2088 glyphs[i].index,
2089 CAIRO_SCALED_GLYPH_INFO_SURFACE,
2090 &scaled_glyphs[i]);
2091 if (status != CAIRO_STATUS_SUCCESS)
2093 num_glyphs = i;
2094 goto UNLOCK;
2097 glyph_private = scaled_glyphs[i]->surface_private;
2098 if (!glyph_private || !glyph_private->area)
2100 status = _cairo_glitz_surface_add_glyph (dst,
2101 scaled_font,
2102 scaled_glyphs[i]);
2103 if (status != CAIRO_STATUS_SUCCESS) {
2104 num_glyphs = i;
2105 goto UNLOCK;
2108 glyph_private = scaled_glyphs[i]->surface_private;
2109 if (glyph_private && glyph_private->area)
2111 remaining_glyps--;
2113 if (glyph_private->area->width)
2115 x_offset = scaled_glyphs[i]->surface->base.device_transform.x0;
2116 y_offset = scaled_glyphs[i]->surface->base.device_transform.y0;
2118 x1 = _cairo_lround (glyphs[i].x - x_offset);
2119 y1 = _cairo_lround (glyphs[i].y - y_offset);
2120 x2 = x1 + glyph_private->area->width;
2121 y2 = y1 + glyph_private->area->height;
2123 WRITE_BOX (vertices, x1, y1, x2, y2,
2124 &glyph_private->p1, &glyph_private->p2);
2126 glyph_private->locked = TRUE;
2128 cached_glyphs++;
2133 if (remaining_glyps)
2135 cairo_surface_t *image;
2136 cairo_glitz_surface_t *clone;
2138 for (i = 0; i < num_glyphs; i++)
2140 glyph_private = scaled_glyphs[i]->surface_private;
2141 if (!glyph_private || !glyph_private->area)
2143 int glyph_width, glyph_height;
2144 int clone_offset_x, clone_offset_y;
2146 image = &scaled_glyphs[i]->surface->base;
2147 glyph_width = scaled_glyphs[i]->surface->width;
2148 glyph_height = scaled_glyphs[i]->surface->height;
2149 status =
2150 _cairo_glitz_surface_clone_similar (abstract_surface,
2151 image,
2152 CAIRO_CONTENT_COLOR_ALPHA,
2155 glyph_width,
2156 glyph_height,
2157 &clone_offset_x,
2158 &clone_offset_y,
2159 (cairo_surface_t **)
2160 &clone);
2161 if (status)
2162 goto UNLOCK;
2164 assert (clone_offset_x == 0);
2165 assert (clone_offset_y == 0);
2167 x_offset = scaled_glyphs[i]->surface->base.device_transform.x0;
2168 y_offset = scaled_glyphs[i]->surface->base.device_transform.y0;
2169 x1 = _cairo_lround (glyphs[i].x - x_offset);
2170 y1 = _cairo_lround (glyphs[i].y - y_offset);
2172 glitz_composite (_glitz_operator (op),
2173 src->surface,
2174 clone->surface,
2175 dst->surface,
2176 src_x + attributes.base.x_offset + x1,
2177 src_y + attributes.base.y_offset + y1,
2178 0, 0,
2179 x1, y1,
2180 glyph_width,
2181 glyph_height);
2183 cairo_surface_destroy (&clone->base);
2185 if (glitz_surface_get_status (dst->surface) ==
2186 GLITZ_STATUS_NOT_SUPPORTED)
2188 status = CAIRO_INT_STATUS_UNSUPPORTED;
2189 goto UNLOCK;
2195 if (cached_glyphs)
2197 cairo_glitz_surface_font_private_t *font_private;
2199 glitz_set_geometry (dst->surface,
2200 GLITZ_GEOMETRY_TYPE_VERTEX,
2201 (glitz_geometry_format_t *) &format,
2202 buffer);
2204 glitz_set_array (dst->surface, 0, 4, cached_glyphs * 4, 0, 0);
2206 font_private = scaled_font->surface_private;
2208 glitz_composite (_glitz_operator (op),
2209 src->surface,
2210 font_private->surface,
2211 dst->surface,
2212 src_x + attributes.base.x_offset,
2213 src_y + attributes.base.y_offset,
2214 0, 0,
2215 dst_x, dst_y,
2216 width, height);
2218 glitz_set_geometry (dst->surface,
2219 GLITZ_GEOMETRY_TYPE_NONE,
2220 NULL, NULL);
2223 UNLOCK:
2224 if (cached_glyphs)
2226 for (i = 0; i < num_glyphs; i++)
2228 glyph_private = scaled_glyphs[i]->surface_private;
2229 if (glyph_private)
2230 glyph_private->locked = FALSE;
2234 _cairo_scaled_font_thaw_cache (scaled_font);
2236 glitz_buffer_destroy (buffer);
2238 FAIL2:
2239 if (num_glyphs > N_STACK_BUF)
2240 free (scaled_glyphs);
2242 FAIL1:
2243 if (attributes.n_params)
2244 free (attributes.params);
2246 _cairo_glitz_pattern_release_surface (pattern, src, &attributes);
2248 if (status)
2249 return status;
2251 if (glitz_surface_get_status (dst->surface) == GLITZ_STATUS_NOT_SUPPORTED)
2252 return CAIRO_INT_STATUS_UNSUPPORTED;
2254 return CAIRO_STATUS_SUCCESS;
2257 static cairo_status_t
2258 _cairo_glitz_surface_flush (void *abstract_surface)
2260 cairo_glitz_surface_t *surface = abstract_surface;
2262 glitz_surface_flush (surface->surface);
2264 return CAIRO_STATUS_SUCCESS;
2267 static cairo_bool_t
2268 _cairo_glitz_surface_is_similar (void *surface_a,
2269 void *surface_b,
2270 cairo_content_t content)
2272 cairo_glitz_surface_t *a = (cairo_glitz_surface_t *) surface_a;
2273 cairo_glitz_surface_t *b = (cairo_glitz_surface_t *) surface_b;
2275 glitz_drawable_t *drawable_a = glitz_surface_get_drawable (a->surface);
2276 glitz_drawable_t *drawable_b = glitz_surface_get_drawable (b->surface);
2278 /* XXX Disable caching of glitz surfaces by the solid pattern cache.
2279 * Until glitz has a mechanism for releasing resources on connection
2280 * closure, we will attempt to access invalid pointers when evicting
2281 * old surfaces from the solid pattern cache.
2283 return FALSE;
2285 return drawable_a == drawable_b;
2288 static cairo_status_t
2289 _cairo_glitz_surface_reset (void *abstract_surface)
2291 cairo_glitz_surface_t *surface = abstract_surface;
2292 cairo_status_t status;
2294 status = _cairo_glitz_surface_set_clip_region (surface, NULL);
2295 if (status)
2296 return status;
2298 return CAIRO_STATUS_SUCCESS;
2301 static const cairo_surface_backend_t cairo_glitz_surface_backend = {
2302 CAIRO_SURFACE_TYPE_GLITZ,
2303 _cairo_glitz_surface_create_similar,
2304 _cairo_glitz_surface_finish,
2305 _cairo_glitz_surface_acquire_source_image,
2306 _cairo_glitz_surface_release_source_image,
2307 _cairo_glitz_surface_acquire_dest_image,
2308 _cairo_glitz_surface_release_dest_image,
2309 _cairo_glitz_surface_clone_similar,
2310 _cairo_glitz_surface_composite,
2311 _cairo_glitz_surface_fill_rectangles,
2312 _cairo_glitz_surface_composite_trapezoids,
2313 NULL, /* create_span_renderer */
2314 NULL, /* check_span_renderer */
2315 NULL, /* copy_page */
2316 NULL, /* show_page */
2317 _cairo_glitz_surface_set_clip_region,
2318 NULL, /* intersect_clip_path */
2319 _cairo_glitz_surface_get_extents,
2320 _cairo_glitz_surface_old_show_glyphs,
2321 NULL, /* get_font_options */
2322 _cairo_glitz_surface_flush,
2323 NULL, /* mark_dirty_rectangle */
2324 _cairo_glitz_surface_scaled_font_fini,
2325 _cairo_glitz_surface_scaled_glyph_fini,
2327 NULL, /* paint */
2328 NULL, /* mask */
2329 NULL, /* stroke */
2330 NULL, /* fill */
2331 NULL, /* show_glyphs */
2333 _cairo_glitz_surface_snapshot,
2334 _cairo_glitz_surface_is_similar,
2336 _cairo_glitz_surface_reset
2339 static const cairo_surface_backend_t *
2340 _cairo_glitz_surface_get_backend (void)
2342 return &cairo_glitz_surface_backend;
2345 static cairo_content_t
2346 _glitz_format_to_content (glitz_format_t * format)
2348 assert (format->color.fourcc == GLITZ_FOURCC_RGB);
2350 if (format->color.alpha_size != 0) {
2351 if (format->color.red_size != 0 &&
2352 format->color.green_size != 0 &&
2353 format->color.blue_size != 0)
2354 return CAIRO_CONTENT_COLOR_ALPHA;
2355 else
2356 return CAIRO_CONTENT_ALPHA;
2358 return CAIRO_CONTENT_COLOR;
2361 cairo_surface_t *
2362 cairo_glitz_surface_create (glitz_surface_t *surface)
2364 cairo_glitz_surface_t *crsurface;
2365 glitz_format_t *format;
2367 if (surface == NULL)
2368 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NULL_POINTER));
2370 crsurface = malloc (sizeof (cairo_glitz_surface_t));
2371 if (crsurface == NULL)
2372 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
2374 format = glitz_surface_get_format (surface);
2375 _cairo_surface_init (&crsurface->base, &cairo_glitz_surface_backend,
2376 _glitz_format_to_content (format));
2378 glitz_surface_reference (surface);
2380 crsurface->surface = surface;
2381 crsurface->format = format;
2383 crsurface->has_clip = FALSE;
2384 crsurface->clip_boxes = NULL;
2385 crsurface->num_clip_boxes = 0;
2387 return &crsurface->base;
2389 slim_hidden_def (cairo_glitz_surface_create);