📄 cairo-glitz-surface.c
字号:
/* cairo - a vector graphics library with display and print output * * Copyright © 2004 David Reveman * * Permission to use, copy, modify, distribute, and sell this software * and its documentation for any purpose is hereby granted without * fee, provided that the above copyright notice appear in all copies * and that both that copyright notice and this permission notice * appear in supporting documentation, and that the name of David * Reveman not be used in advertising or publicity pertaining to * distribution of the software without specific, written prior * permission. David Reveman makes no representations about the * suitability of this software for any purpose. It is provided "as * is" without express or implied warranty. * * DAVID REVEMAN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS, IN NO EVENT SHALL DAVID REVEMAN BE LIABLE FOR ANY SPECIAL, * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Author: David Reveman <davidr@novell.com> */#include "cairoint.h"#include "cairo-glitz.h"typedef struct _cairo_glitz_surface { cairo_surface_t base; glitz_surface_t *surface; glitz_format_t *format; pixman_region16_t *clip;} cairo_glitz_surface_t;static const cairo_surface_backend_t *_cairo_glitz_surface_get_backend (void);static cairo_status_t_cairo_glitz_surface_finish (void *abstract_surface){ cairo_glitz_surface_t *surface = abstract_surface; if (surface->clip) { glitz_surface_set_clip_region (surface->surface, 0, 0, NULL, 0); pixman_region_destroy (surface->clip); } glitz_surface_destroy (surface->surface); return CAIRO_STATUS_SUCCESS;}static glitz_format_name_t_glitz_format_from_content (cairo_content_t content){ switch (content) { case CAIRO_CONTENT_COLOR: return GLITZ_STANDARD_RGB24; case CAIRO_CONTENT_ALPHA: return GLITZ_STANDARD_A8; case CAIRO_CONTENT_COLOR_ALPHA: return GLITZ_STANDARD_ARGB32; } ASSERT_NOT_REACHED; return GLITZ_STANDARD_ARGB32;}static cairo_surface_t *_cairo_glitz_surface_create_similar (void *abstract_src, cairo_content_t content, int width, int height){ cairo_glitz_surface_t *src = abstract_src; cairo_surface_t *crsurface; glitz_drawable_t *drawable; glitz_surface_t *surface; glitz_format_t *gformat; drawable = glitz_surface_get_drawable (src->surface); gformat = glitz_find_standard_format (drawable, _glitz_format_from_content (content)); if (!gformat) { _cairo_error (CAIRO_STATUS_NO_MEMORY); return (cairo_surface_t*) &_cairo_surface_nil; } surface = glitz_surface_create (drawable, gformat, width <= 0 ? 1 : width, height <= 0 ? 1 : height, 0, NULL); if (surface == NULL) { _cairo_error (CAIRO_STATUS_NO_MEMORY); return (cairo_surface_t*) &_cairo_surface_nil; } crsurface = cairo_glitz_surface_create (surface); glitz_surface_destroy (surface); return crsurface;}static cairo_status_t_cairo_glitz_surface_get_image (cairo_glitz_surface_t *surface, cairo_rectangle_int16_t *interest, cairo_image_surface_t **image_out, cairo_rectangle_int16_t *rect_out){ cairo_image_surface_t *image; int x1, y1, x2, y2; int width, height; unsigned char *pixels; cairo_format_masks_t format; glitz_buffer_t *buffer; glitz_pixel_format_t pf; x1 = 0; y1 = 0; x2 = glitz_surface_get_width (surface->surface); y2 = glitz_surface_get_height (surface->surface); if (interest) { if (interest->x > x1) x1 = interest->x; if (interest->y > y1) y1 = interest->y; if (interest->x + interest->width < x2) x2 = interest->x + interest->width; if (interest->y + interest->height < y2) y2 = interest->y + interest->height; if (x1 >= x2 || y1 >= y2) { *image_out = NULL; return CAIRO_STATUS_SUCCESS; } } width = x2 - x1; height = y2 - y1; if (rect_out) { rect_out->x = x1; rect_out->y = y1; rect_out->width = width; rect_out->height = height; } if (surface->format->color.fourcc == GLITZ_FOURCC_RGB) { if (surface->format->color.red_size > 0) { format.bpp = 32; if (surface->format->color.alpha_size > 0) format.alpha_mask = 0xff000000; else format.alpha_mask = 0x0; format.red_mask = 0xff0000; format.green_mask = 0xff00; format.blue_mask = 0xff; } else { format.bpp = 8; format.blue_mask = format.green_mask = format.red_mask = 0x0; format.alpha_mask = 0xff; } } else { format.bpp = 32; format.alpha_mask = 0xff000000; format.red_mask = 0xff0000; format.green_mask = 0xff00; format.blue_mask = 0xff; } pf.fourcc = GLITZ_FOURCC_RGB; pf.masks.bpp = format.bpp; pf.masks.alpha_mask = format.alpha_mask; pf.masks.red_mask = format.red_mask; pf.masks.green_mask = format.green_mask; pf.masks.blue_mask = format.blue_mask; pf.xoffset = 0; pf.skip_lines = 0; /* XXX: we should eventually return images with negative stride, need to verify that libpixman have no problem with this first. */ pf.bytes_per_line = (((width * format.bpp) / 8) + 3) & -4; pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_TOP_DOWN; pixels = malloc (height * pf.bytes_per_line); if (!pixels) return CAIRO_STATUS_NO_MEMORY; buffer = glitz_buffer_create_for_data (pixels); if (!buffer) { free (pixels); return CAIRO_STATUS_NO_MEMORY; } /* clear out the glitz clip; the clip affects glitz_get_pixels */ glitz_surface_set_clip_region (surface->surface, 0, 0, NULL, 0); glitz_get_pixels (surface->surface, x1, y1, width, height, &pf, buffer); glitz_buffer_destroy (buffer); /* restore the clip, if any */ surface->base.current_clip_serial = 0; _cairo_surface_set_clip (&surface->base, surface->base.clip); image = (cairo_image_surface_t *) _cairo_image_surface_create_with_masks (pixels, &format, width, height, pf.bytes_per_line); if (image->base.status) { free (pixels); return CAIRO_STATUS_NO_MEMORY; } _cairo_image_surface_assume_ownership_of_data (image); *image_out = image; return CAIRO_STATUS_SUCCESS;}static cairo_status_t_cairo_glitz_surface_set_image (void *abstract_surface, cairo_image_surface_t *image, int x_dst, int y_dst){ cairo_glitz_surface_t *surface = abstract_surface; glitz_buffer_t *buffer; glitz_pixel_format_t pf; pixman_format_t *format; int am, rm, gm, bm; char *data; format = pixman_image_get_format (image->pixman_image); if (!format) return CAIRO_STATUS_NO_MEMORY; pixman_format_get_masks (format, &pf.masks.bpp, &am, &rm, &gm, &bm); pf.fourcc = GLITZ_FOURCC_RGB; pf.masks.alpha_mask = am; pf.masks.red_mask = rm; pf.masks.green_mask = gm; pf.masks.blue_mask = bm; pf.xoffset = 0; pf.skip_lines = 0; /* check for negative stride */ if (image->stride < 0) { pf.bytes_per_line = -image->stride; pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_BOTTOM_UP; data = (char *) image->data + image->stride * (image->height - 1); } else { pf.bytes_per_line = image->stride; pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_TOP_DOWN; data = (char *) image->data; } buffer = glitz_buffer_create_for_data (data); if (!buffer) return CAIRO_STATUS_NO_MEMORY; glitz_set_pixels (surface->surface, x_dst, y_dst, image->width, image->height, &pf, buffer); glitz_buffer_destroy (buffer); return CAIRO_STATUS_SUCCESS;}static cairo_status_t_cairo_glitz_surface_acquire_source_image (void *abstract_surface, cairo_image_surface_t **image_out, void **image_extra){ cairo_glitz_surface_t *surface = abstract_surface; *image_extra = NULL; return _cairo_glitz_surface_get_image (surface, NULL, image_out, NULL);}static void_cairo_glitz_surface_release_source_image (void *abstract_surface, cairo_image_surface_t *image, void *image_extra){ cairo_surface_destroy (&image->base);}static cairo_status_t_cairo_glitz_surface_acquire_dest_image (void *abstract_surface, cairo_rectangle_int16_t *interest_rect, cairo_image_surface_t **image_out, cairo_rectangle_int16_t *image_rect_out, void **image_extra){ cairo_glitz_surface_t *surface = abstract_surface; cairo_image_surface_t *image; cairo_status_t status; status = _cairo_glitz_surface_get_image (surface, interest_rect, &image, image_rect_out); if (status) return status; *image_out = image; *image_extra = NULL; return status;}static void_cairo_glitz_surface_release_dest_image (void *abstract_surface, cairo_rectangle_int16_t *interest_rect, cairo_image_surface_t *image, cairo_rectangle_int16_t *image_rect, void *image_extra){ cairo_glitz_surface_t *surface = abstract_surface; _cairo_glitz_surface_set_image (surface, image, image_rect->x, image_rect->y); cairo_surface_destroy (&image->base);}static cairo_status_t_cairo_glitz_surface_clone_similar (void *abstract_surface, cairo_surface_t *src, cairo_surface_t **clone_out){ cairo_glitz_surface_t *surface = abstract_surface; cairo_glitz_surface_t *clone; if (surface->base.status) return surface->base.status; if (src->backend == surface->base.backend) { *clone_out = cairo_surface_reference (src); return CAIRO_STATUS_SUCCESS; } else if (_cairo_surface_is_image (src)) { cairo_image_surface_t *image_src = (cairo_image_surface_t *) src; cairo_content_t content; content = _cairo_content_from_format (image_src->format); clone = (cairo_glitz_surface_t *) _cairo_glitz_surface_create_similar (surface, content, image_src->width, image_src->height); if (clone->base.status) return CAIRO_STATUS_NO_MEMORY; _cairo_glitz_surface_set_image (clone, image_src, 0, 0); *clone_out = &clone->base; return CAIRO_STATUS_SUCCESS; } return CAIRO_INT_STATUS_UNSUPPORTED;}static void_cairo_glitz_surface_set_matrix (cairo_glitz_surface_t *surface, cairo_matrix_t *matrix){ glitz_transform_t transform; transform.matrix[0][0] = _cairo_fixed_from_double (matrix->xx); transform.matrix[0][1] = _cairo_fixed_from_double (matrix->xy); transform.matrix[0][2] = _cairo_fixed_from_double (matrix->x0); transform.matrix[1][0] = _cairo_fixed_from_double (matrix->yx); transform.matrix[1][1] = _cairo_fixed_from_double (matrix->yy); transform.matrix[1][2] = _cairo_fixed_from_double (matrix->y0); transform.matrix[2][0] = 0; transform.matrix[2][1] = 0; transform.matrix[2][2] = _cairo_fixed_from_double (1); glitz_surface_set_transform (surface->surface, &transform);}static glitz_operator_t_glitz_operator (cairo_operator_t op){ switch (op) { case CAIRO_OPERATOR_CLEAR: return GLITZ_OPERATOR_CLEAR; case CAIRO_OPERATOR_SOURCE: return GLITZ_OPERATOR_SRC; case CAIRO_OPERATOR_OVER: return GLITZ_OPERATOR_OVER; case CAIRO_OPERATOR_IN: return GLITZ_OPERATOR_IN; case CAIRO_OPERATOR_OUT: return GLITZ_OPERATOR_OUT; case CAIRO_OPERATOR_ATOP: return GLITZ_OPERATOR_ATOP; case CAIRO_OPERATOR_DEST: return GLITZ_OPERATOR_DST; case CAIRO_OPERATOR_DEST_OVER: return GLITZ_OPERATOR_OVER_REVERSE; case CAIRO_OPERATOR_DEST_IN: return GLITZ_OPERATOR_IN_REVERSE; case CAIRO_OPERATOR_DEST_OUT: return GLITZ_OPERATOR_OUT_REVERSE; case CAIRO_OPERATOR_DEST_ATOP: return GLITZ_OPERATOR_ATOP_REVERSE; case CAIRO_OPERATOR_XOR: return GLITZ_OPERATOR_XOR; case CAIRO_OPERATOR_ADD: return GLITZ_OPERATOR_ADD; case CAIRO_OPERATOR_SATURATE: /* XXX: This line should never be reached. Glitz backend should bail out earlier if saturate operator is used. OpenGL can't do saturate with pre-multiplied colors. Solid colors can still be done as we can just un-pre-multiply them. However, support for that will have to be added to glitz. */ /* fall-through */ break; } ASSERT_NOT_REACHED; /* Something's very broken if this line of code can be reached, so we want to return something that would give a noticeably incorrect result. The XOR operator seems so rearely desired that it should fit the bill here. */ return CAIRO_OPERATOR_XOR;}#define CAIRO_GLITZ_FEATURE_OK(surface, name) \ (glitz_drawable_get_features (glitz_surface_get_drawable (surface)) & \ (GLITZ_FEATURE_ ## name ## _MASK))static glitz_status_t_glitz_ensure_target (glitz_surface_t *surface){ if (!glitz_surface_get_attached_drawable (surface)) { glitz_drawable_format_t *target_format, templ; glitz_format_t *format; glitz_drawable_t *drawable, *target; unsigned int width, height; unsigned long mask; drawable = glitz_surface_get_drawable (surface); format = glitz_surface_get_format (surface); width = glitz_surface_get_width (surface); height = glitz_surface_get_height (surface); if (format->color.fourcc != GLITZ_FOURCC_RGB) return CAIRO_INT_STATUS_UNSUPPORTED; templ.color = format->color; templ.depth_size = 0; templ.stencil_size = 0; templ.doublebuffer = 0; templ.samples = 1; mask = GLITZ_FORMAT_RED_SIZE_MASK | GLITZ_FORMAT_GREEN_SIZE_MASK | GLITZ_FORMAT_BLUE_SIZE_MASK | GLITZ_FORMAT_ALPHA_SIZE_MASK | GLITZ_FORMAT_DEPTH_SIZE_MASK | GLITZ_FORMAT_STENCIL_SIZE_MASK | GLITZ_FORMAT_DOUBLEBUFFER_MASK | GLITZ_FORMAT_SAMPLES_MASK; target_format = glitz_find_drawable_format (drawable, mask, &templ, 0); if (!target_format) return CAIRO_INT_STATUS_UNSUPPORTED; target = glitz_create_drawable (drawable, target_format, width, height); if (!target) return CAIRO_INT_STATUS_UNSUPPORTED; glitz_surface_attach (surface, target, GLITZ_DRAWABLE_BUFFER_FRONT_COLOR); glitz_drawable_destroy (target); } return CAIRO_STATUS_SUCCESS;}typedef struct _cairo_glitz_surface_attributes { cairo_surface_attributes_t base; glitz_fill_t fill; glitz_filter_t filter; glitz_fixed16_16_t *params; int n_params; cairo_bool_t acquired;} cairo_glitz_surface_attributes_t;static cairo_int_status_t_cairo_glitz_pattern_acquire_surface (cairo_pattern_t *pattern, cairo_glitz_surface_t *dst, int x, int y, unsigned int width, unsigned int height, cairo_glitz_surface_t **surface_out, cairo_glitz_surface_attributes_t *attr){ cairo_glitz_surface_t *src = NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -