📄 cairo-xcb-surface.c
字号:
/* cairo - a vector graphics library with display and print output * * Copyright © 2002 University of Southern California * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * (the "LGPL") or, at your option, under the terms of the Mozilla * Public License Version 1.1 (the "MPL"). If you do not alter this * notice, a recipient may use your version of this file under either * the MPL or the LGPL. * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * * The contents of this file are subject to the Mozilla Public License * Version 1.1 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY * OF ANY KIND, either express or implied. See the LGPL or the MPL for * the specific language governing rights and limitations. * * The Original Code is the cairo graphics library. * * The Initial Developer of the Original Code is University of Southern * California. * * Contributor(s): * Carl D. Worth <cworth@cworth.org> */#include "cairoint.h"#include "cairo-xcb.h"#include "cairo-xcb-xrender.h"#define AllPlanes ((unsigned long)~0L)static XCBRenderPICTFORMATformat_from_visual(XCBConnection *c, XCBVISUALID visual){ static const XCBRenderPICTFORMAT nil = { 0 }; XCBRenderQueryPictFormatsRep *r; XCBRenderPICTSCREENIter si; XCBRenderPICTDEPTHIter di; XCBRenderPICTVISUALIter vi; r = XCBRenderQueryPictFormatsReply(c, XCBRenderQueryPictFormats(c), 0); if(!r) return nil; for(si = XCBRenderQueryPictFormatsScreensIter(r); si.rem; XCBRenderPICTSCREENNext(&si)) for(di = XCBRenderPICTSCREENDepthsIter(si.data); di.rem; XCBRenderPICTDEPTHNext(&di)) for(vi = XCBRenderPICTDEPTHVisualsIter(di.data); vi.rem; XCBRenderPICTVISUALNext(&vi)) if(vi.data->visual.id == visual.id) { XCBRenderPICTFORMAT ret = vi.data->format; free(r); return ret; } return nil;}static cairo_content_t_xcb_render_format_to_content (XCBRenderPICTFORMINFO *xrender_format){ cairo_bool_t xrender_format_has_alpha; cairo_bool_t xrender_format_has_color; /* This only happens when using a non-Render server. Let's punt * and say there's no alpha here. */ if (xrender_format == NULL) return CAIRO_CONTENT_COLOR; xrender_format_has_alpha = (xrender_format->direct.alpha_mask != 0); xrender_format_has_color = (xrender_format->direct.red_mask != 0 || xrender_format->direct.green_mask != 0 || xrender_format->direct.blue_mask != 0); if (xrender_format_has_alpha) if (xrender_format_has_color) return CAIRO_CONTENT_COLOR_ALPHA; else return CAIRO_CONTENT_ALPHA; else return CAIRO_CONTENT_COLOR;}/* XXX: Why is this ridiculously complex compared to the equivalent * function in cairo-xlib-surface.c */static XCBRenderPICTFORMINFO_format_from_cairo(XCBConnection *c, cairo_format_t fmt){ XCBRenderPICTFORMINFO ret = {{ 0 }}; struct tmpl_t { XCBRenderDIRECTFORMAT direct; CARD8 depth; }; static const struct tmpl_t templates[] = { /* CAIRO_FORMAT_ARGB32 */ { { 16, 0xff, 8, 0xff, 0, 0xff, 24, 0xff }, 32 }, /* CAIRO_FORMAT_RGB24 */ { { 16, 0xff, 8, 0xff, 0, 0xff, 0, 0x00 }, 24 }, /* CAIRO_FORMAT_A8 */ { { 0, 0x00, 0, 0x00, 0, 0x00, 0, 0xff }, 8 }, /* CAIRO_FORMAT_A1 */ { { 0, 0x00, 0, 0x00, 0, 0x00, 0, 0x01 }, 1 }, }; const struct tmpl_t *tmpl; XCBRenderQueryPictFormatsRep *r; XCBRenderPICTFORMINFOIter fi; if(fmt < 0 || fmt >= (sizeof(templates) / sizeof(*templates))) return ret; tmpl = templates + fmt; r = XCBRenderQueryPictFormatsReply(c, XCBRenderQueryPictFormats(c), 0); if(!r) return ret; for(fi = XCBRenderQueryPictFormatsFormatsIter(r); fi.rem; XCBRenderPICTFORMINFONext(&fi)) { const XCBRenderDIRECTFORMAT *t, *f; if(fi.data->type != XCBRenderPictTypeDirect) continue; if(fi.data->depth != tmpl->depth) continue; t = &tmpl->direct; f = &fi.data->direct; if(t->red_mask && (t->red_mask != f->red_mask || t->red_shift != f->red_shift)) continue; if(t->green_mask && (t->green_mask != f->green_mask || t->green_shift != f->green_shift)) continue; if(t->blue_mask && (t->blue_mask != f->blue_mask || t->blue_shift != f->blue_shift)) continue; if(t->alpha_mask && (t->alpha_mask != f->alpha_mask || t->alpha_shift != f->alpha_shift)) continue; ret = *fi.data; } free(r); return ret;}/* * Instead of taking two round trips for each blending request, * assume that if a particular drawable fails GetImage that it will * fail for a "while"; use temporary pixmaps to avoid the errors */#define CAIRO_ASSUME_PIXMAP 20typedef struct cairo_xcb_surface { cairo_surface_t base; XCBConnection *dpy; XCBSCREEN *screen; XCBGCONTEXT gc; XCBDRAWABLE drawable; int owns_pixmap; XCBVISUALTYPE *visual; int use_pixmap; int render_major; int render_minor; int width; int height; int depth; XCBRenderPICTURE picture; XCBRenderPICTFORMINFO format; int has_format;} cairo_xcb_surface_t;#define CAIRO_SURFACE_RENDER_AT_LEAST(surface, major, minor) \ (((surface)->render_major > major) || \ (((surface)->render_major == major) && ((surface)->render_minor >= minor)))#define CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0)#define CAIRO_SURFACE_RENDER_HAS_COMPOSITE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0)#define CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 1)#define CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLES(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 1)#define CAIRO_SURFACE_RENDER_HAS_DISJOINT(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 2)#define CAIRO_SURFACE_RENDER_HAS_CONJOINT(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 2)#define CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)#define CAIRO_SURFACE_RENDER_HAS_TRIANGLES(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)#define CAIRO_SURFACE_RENDER_HAS_TRISTRIP(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)#define CAIRO_SURFACE_RENDER_HAS_TRIFAN(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)#define CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6)#define CAIRO_SURFACE_RENDER_HAS_FILTERS(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6)static void_cairo_xcb_surface_ensure_gc (cairo_xcb_surface_t *surface);static int_CAIRO_FORMAT_DEPTH (cairo_format_t format){ switch (format) { case CAIRO_FORMAT_A1: return 1; case CAIRO_FORMAT_A8: return 8; case CAIRO_FORMAT_RGB24: return 24; case CAIRO_FORMAT_ARGB32: default: return 32; }}static cairo_surface_t *_cairo_xcb_surface_create_similar (void *abstract_src, cairo_content_t content, int width, int height){ cairo_xcb_surface_t *src = abstract_src; XCBConnection *dpy = src->dpy; XCBDRAWABLE d; cairo_xcb_surface_t *surface; cairo_format_t format = _cairo_format_from_content (content); XCBRenderPICTFORMINFO xrender_format = _format_from_cairo (dpy, format); /* As a good first approximation, if the display doesn't have COMPOSITE, * we're better off using image surfaces for all temporary operations */ if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (src)) { return cairo_image_surface_create (format, width, height); } d.pixmap = XCBPIXMAPNew (dpy); XCBCreatePixmap (dpy, _CAIRO_FORMAT_DEPTH (format), d.pixmap, src->drawable, width <= 0 ? 1 : width, height <= 0 ? 1 : height); surface = (cairo_xcb_surface_t *) cairo_xcb_surface_create_with_xrender_format (dpy, d, src->screen, &xrender_format, width, height); if (surface->base.status) { _cairo_error (CAIRO_STATUS_NO_MEMORY); return (cairo_surface_t*) &_cairo_surface_nil; } surface->owns_pixmap = TRUE; return &surface->base;}static cairo_status_t_cairo_xcb_surface_finish (void *abstract_surface){ cairo_xcb_surface_t *surface = abstract_surface; if (surface->picture.xid) XCBRenderFreePicture (surface->dpy, surface->picture); if (surface->owns_pixmap) XCBFreePixmap (surface->dpy, surface->drawable.pixmap); if (surface->gc.xid) XCBFreeGC (surface->dpy, surface->gc); surface->dpy = NULL; return CAIRO_STATUS_SUCCESS;}static int_bits_per_pixel(XCBConnection *c, int depth){ XCBFORMAT *fmt = XCBSetupPixmapFormats(XCBGetSetup(c)); XCBFORMAT *fmtend = fmt + XCBSetupPixmapFormatsLength(XCBGetSetup(c)); for(; fmt != fmtend; ++fmt) if(fmt->depth == depth) return fmt->bits_per_pixel; if(depth <= 4) return 4; if(depth <= 8) return 8; if(depth <= 16) return 16; return 32;}static int_bytes_per_line(XCBConnection *c, int width, int bpp){ int bitmap_pad = XCBGetSetup(c)->bitmap_format_scanline_pad; return ((bpp * width + bitmap_pad - 1) & -bitmap_pad) >> 3;}static cairo_bool_t_CAIRO_MASK_FORMAT (cairo_format_masks_t *masks, cairo_format_t *format){ switch (masks->bpp) { case 32: if (masks->alpha_mask == 0xff000000 && masks->red_mask == 0x00ff0000 && masks->green_mask == 0x0000ff00 && masks->blue_mask == 0x000000ff) { *format = CAIRO_FORMAT_ARGB32; return TRUE; } if (masks->alpha_mask == 0x00000000 && masks->red_mask == 0x00ff0000 && masks->green_mask == 0x0000ff00 && masks->blue_mask == 0x000000ff) { *format = CAIRO_FORMAT_RGB24; return TRUE; } break; case 8: if (masks->alpha_mask == 0xff) { *format = CAIRO_FORMAT_A8; return TRUE; } break; case 1: if (masks->alpha_mask == 0x1) { *format = CAIRO_FORMAT_A1; return TRUE; } break; } return FALSE;}static cairo_status_t_get_image_surface (cairo_xcb_surface_t *surface, cairo_rectangle_int16_t *interest_rect, cairo_image_surface_t **image_out, cairo_rectangle_int16_t *image_rect){ cairo_image_surface_t *image; XCBGetImageRep *imagerep; int bpp, bytes_per_line; int x1, y1, x2, y2; unsigned char *data; cairo_format_t format; cairo_format_masks_t masks; x1 = 0; y1 = 0; x2 = surface->width; y2 = surface->height; if (interest_rect) { cairo_rectangle_int16_t rect; rect.x = interest_rect->x; rect.y = interest_rect->y; rect.width = interest_rect->width; rect.height = interest_rect->height; if (rect.x > x1) x1 = rect.x; if (rect.y > y1) y1 = rect.y; if (rect.x + rect.width < x2) x2 = rect.x + rect.width; if (rect.y + rect.height < y2) y2 = rect.y + rect.height; if (x1 >= x2 || y1 >= y2) { *image_out = NULL; return CAIRO_STATUS_SUCCESS; } } if (image_rect) { image_rect->x = x1; image_rect->y = y1; image_rect->width = x2 - x1; image_rect->height = y2 - y1; } /* XXX: This should try to use the XShm extension if available */ if (surface->use_pixmap == 0) { XCBGenericError *error; imagerep = XCBGetImageReply(surface->dpy, XCBGetImage(surface->dpy, XCBImageFormatZPixmap, surface->drawable, x1, y1, x2 - x1, y2 - y1, AllPlanes), &error); /* If we get an error, the surface must have been a window, * so retry with the safe code path. */ if (error) surface->use_pixmap = CAIRO_ASSUME_PIXMAP; } else { surface->use_pixmap--; imagerep = NULL; } if (!imagerep) { /* XCBGetImage from a window is dangerous because it can * produce errors if the window is unmapped or partially * outside the screen. We could check for errors and
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -