Virtualized the font and surface backend implementations.

This commit is contained in:
Jamey Sharp 2003-09-30 18:56:22 +00:00
parent 9c964b8f8a
commit 973ee89983
15 changed files with 1871 additions and 1141 deletions

View file

@ -1,3 +1,10 @@
2003-09-30 Jamey Sharp <jamey@minilop.net>
* src/Makefile.am, src/cairo.c, src/cairo.h, src/cairo_font.c,
src/cairo_gstate.c, src/cairo_surface.c, src/cairoint.h:
Virtualized font and surface backends. All Xlib/Xft calls are in
cairo_xlib_surface.c/cairo-xlib.h now. Resolves a TODO item.
2003-09-30 Carl Worth <cworth@east.isi.edu>
* src/cairo.c (cairo_copy): Don't copy a gstate if src->status != 0.

3
TODO
View file

@ -4,9 +4,6 @@
* Re-implement pattern support with a more PostScript-like API.
* Virtualize the backend interface so that the various backends can be
compiled conditionally.
* Verification, profiling, optimization.
A comparison with PostScript

View file

@ -1,5 +1,5 @@
lib_LTLIBRARIES = libcairo.la
include_HEADERS = cairo.h
include_HEADERS = cairo.h cairo-xlib.h
libcairo_la_SOURCES = \
cairo.c \
@ -18,6 +18,7 @@ libcairo_la_SOURCES = \
cairo_slope.c \
cairo_spline.c \
cairo_surface.c \
cairo_xlib_surface.c \
cairo_traps.c \
cairoint.h

View file

@ -25,41 +25,41 @@
* Author: Carl D. Worth <cworth@isi.edu>
*/
#include <string.h>
#include "cairoint.h"
void
_cairo_font_init (cairo_font_t *font)
_cairo_font_init (cairo_font_t *font, const struct cairo_font_backend *backend)
{
font->key = (unsigned char *) strdup (CAIRO_FONT_KEY_DEFAULT);
font->dpy = NULL;
font->xft_font = NULL;
cairo_matrix_set_identity (&font->matrix);
font->backend = backend;
}
cairo_status_t
_cairo_font_init_copy (cairo_font_t *font, cairo_font_t *other)
{
*font = *other;
if (other->key) {
font->key = (unsigned char *) strdup ((char *) other->key);
if (font->key == NULL)
return CAIRO_STATUS_NO_MEMORY;
}
font->matrix = other->matrix;
if (other->xft_font) {
font->xft_font = XftFontCopy (other->dpy, other->xft_font);
if (font->xft_font == NULL)
return CAIRO_STATUS_NO_MEMORY;
}
font->backend = other->backend;
return CAIRO_STATUS_SUCCESS;
}
cairo_font_t *
_cairo_font_copy (cairo_font_t *font)
{
if (!font->backend->copy)
return 0;
return font->backend->copy (font);
}
void
_cairo_font_fini (cairo_font_t *font)
{
@ -69,18 +69,15 @@ _cairo_font_fini (cairo_font_t *font)
_cairo_matrix_fini (&font->matrix);
if (font->xft_font)
XftFontClose (font->dpy, font->xft_font);
font->xft_font = NULL;
if (font->backend->close)
font->backend->close (font);
}
cairo_status_t
_cairo_font_select (cairo_font_t *font, const char *key)
{
if (font->xft_font)
XftFontClose (font->dpy, font->xft_font);
font->xft_font = NULL;
if (font->backend->close)
font->backend->close (font);
if (font->key)
free (font->key);
@ -114,69 +111,31 @@ _cairo_font_transform (cairo_font_t *font,
}
cairo_status_t
_cairo_font_resolve_xft_font (cairo_font_t *font, cairo_gstate_t *gstate, XftFont **xft_font)
_cairo_font_text_extents (cairo_font_t *font,
cairo_matrix_t *ctm,
const unsigned char *utf8,
double *x, double *y,
double *width, double *height,
double *dx, double *dy)
{
FcPattern *pattern;
FcPattern *match;
FcResult result;
cairo_matrix_t matrix;
FcMatrix fc_matrix;
double expansion;
double font_size;
if (font->xft_font) {
*xft_font = font->xft_font;
if (!font->backend->text_extents)
return CAIRO_STATUS_SUCCESS;
}
pattern = FcNameParse (font->key);
matrix = gstate->ctm;
cairo_matrix_multiply (&matrix, &font->matrix, &matrix);
/* Pull the scale factor out of the final matrix and use it to set
the direct pixelsize of the font. This enables freetype to
perform proper hinting at any size. */
/* XXX: The determinant gives an area expansion factor, so the
math below should be correct for the (common) case of uniform
X/Y scaling. Is there anything different we would want to do
for non-uniform X/Y scaling?
XXX: Actually, the reasoning above is bogus. A transformation
such as scale (N, 1/N) will give an expansion_factor of 1. So,
with the code below we'll end up with font_size == 1 instead of
N, (so the hinting will be all wrong). I think we want to use
the maximum eigen value rather than the square root of the
determinant.
*/
_cairo_matrix_compute_determinant (&matrix, &expansion);
font_size = sqrt (fabs (expansion));
FcPatternAddDouble (pattern, "pixelsize", font_size);
cairo_matrix_scale (&matrix, 1.0 / font_size, 1.0 / font_size);
fc_matrix.xx = matrix.m[0][0];
fc_matrix.xy = matrix.m[0][1];
fc_matrix.yx = matrix.m[1][0];
fc_matrix.yy = matrix.m[1][1];
FcPatternAddMatrix (pattern, "matrix", &fc_matrix);
/* XXX: Need to make a generic (non-Xft) backend for text. */
/* When I do that I can throw away these Display pointers */
font->dpy = gstate->surface->dpy;
match = XftFontMatch (font->dpy, DefaultScreen (font->dpy), pattern, &result);
if (!match)
return 0;
font->xft_font = XftFontOpenPattern (font->dpy, match);
*xft_font = font->xft_font;
FcPatternDestroy (pattern);
return CAIRO_STATUS_SUCCESS;
return font->backend->text_extents (font, ctm, utf8, x, y, width, height, dx, dy);
}
cairo_status_t
_cairo_font_show_text (cairo_font_t *font,
cairo_matrix_t *ctm,
cairo_operator_t operator,
cairo_surface_t *source,
cairo_surface_t *surface,
double x,
double y,
const unsigned char *utf8)
{
if (!font->backend->show_text)
return CAIRO_STATUS_SUCCESS;
return font->backend->show_text (font, ctm, operator, source, surface, x, y, utf8);
}

View file

@ -74,7 +74,7 @@ _cairo_gstate_init (cairo_gstate_t *gstate)
gstate->num_dashes = 0;
gstate->dash_offset = 0.0;
_cairo_font_init (&gstate->font);
gstate->font = NULL;
gstate->surface = NULL;
gstate->source = NULL;
@ -121,9 +121,11 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other)
memcpy (gstate->dash, other->dash, other->num_dashes * sizeof (double));
}
status = _cairo_font_init_copy (&gstate->font, &other->font);
if (status)
gstate->font = _cairo_font_copy (other->font);
if (!gstate->font) {
status = CAIRO_STATUS_NO_MEMORY;
goto CLEANUP_DASHES;
}
cairo_surface_reference (gstate->surface);
cairo_surface_reference (gstate->source);
@ -142,7 +144,7 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other)
CLEANUP_PATH:
_cairo_path_fini (&gstate->path);
CLEANUP_FONT:
_cairo_font_fini (&gstate->font);
_cairo_font_fini (gstate->font);
CLEANUP_DASHES:
free (gstate->dash);
gstate->dash = NULL;
@ -153,7 +155,7 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other)
void
_cairo_gstate_fini (cairo_gstate_t *gstate)
{
_cairo_font_fini (&gstate->font);
_cairo_font_fini (gstate->font);
cairo_surface_destroy (gstate->surface);
gstate->surface = NULL;
@ -1353,13 +1355,13 @@ _cairo_gstate_clip (cairo_gstate_t *gstate)
cairo_status_t
_cairo_gstate_select_font (cairo_gstate_t *gstate, const char *key)
{
return _cairo_font_select (&gstate->font, key);
return _cairo_font_select (gstate->font, key);
}
cairo_status_t
_cairo_gstate_scale_font (cairo_gstate_t *gstate, double scale)
{
return _cairo_font_scale (&gstate->font, scale);
return _cairo_font_scale (gstate->font, scale);
}
cairo_status_t
@ -1367,7 +1369,7 @@ _cairo_gstate_transform_font (cairo_gstate_t *gstate,
double a, double b,
double c, double d)
{
return _cairo_font_transform (&gstate->font,
return _cairo_font_transform (gstate->font,
a, b, c, d);
}
@ -1378,45 +1380,17 @@ _cairo_gstate_text_extents (cairo_gstate_t *gstate,
double *width, double *height,
double *dx, double *dy)
{
XftFont *xft_font;
XGlyphInfo extents;
if (gstate->surface->dpy == 0)
return CAIRO_STATUS_SUCCESS;
_cairo_font_resolve_xft_font (&gstate->font, gstate, &xft_font);
/* XXX: Need to make a generic (non-Xft) backend for text. */
XftTextExtentsUtf8 (gstate->surface->dpy,
xft_font,
utf8,
strlen ((char *) utf8),
&extents);
/* XXX: What are the semantics of XftTextExtents? Specifically,
what does it do with x/y? I think we actually need to use the
gstate's current point in here somewhere. */
*x = extents.x;
*y = extents.y;
*width = extents.width;
*height = extents.height;
*dx = extents.xOff;
*dy = extents.yOff;
return CAIRO_STATUS_SUCCESS;
return _cairo_font_text_extents (gstate->font, &gstate->ctm, utf8,
x, y, width, height, dx, dy);
}
cairo_status_t
_cairo_gstate_show_text (cairo_gstate_t *gstate, const unsigned char *utf8)
{
cairo_status_t status;
XftFont *xft_font;
double x, y;
cairo_matrix_t user_to_source, device_to_source;
if (gstate->surface->dpy == 0)
return CAIRO_STATUS_SUCCESS;
/* XXX: I believe this is correct, but it would be much more clear
to have some explicit current_point accesor functions, (one for
user- and one for device-space). */
@ -1429,8 +1403,6 @@ _cairo_gstate_show_text (cairo_gstate_t *gstate, const unsigned char *utf8)
cairo_matrix_transform_point (&gstate->ctm, &x, &y);
}
_cairo_font_resolve_xft_font (&gstate->font, gstate, &xft_font);
status = _cairo_gstate_ensure_source (gstate);
if (status)
return status;
@ -1444,22 +1416,15 @@ _cairo_gstate_show_text (cairo_gstate_t *gstate, const unsigned char *utf8)
cairo_surface_set_matrix (gstate->source, &device_to_source);
}
/* XXX: Need to make a generic (non-Xft) backend for text. */
XftTextRenderUtf8 (gstate->surface->dpy,
gstate->operator,
gstate->source->picture,
xft_font,
gstate->surface->picture,
0, 0,
x, y,
utf8,
strlen ((char *) utf8));
status = _cairo_font_show_text (gstate->font, &gstate->ctm,
gstate->operator, gstate->source,
gstate->surface, x, y, utf8);
/* restore the matrix originally in the source surface */
if (! gstate->source_is_solid)
cairo_surface_set_matrix (gstate->source, &user_to_source);
return CAIRO_STATUS_SUCCESS;
return status;
}
cairo_status_t

View file

@ -37,35 +37,6 @@ static const XTransform CAIRO_XTRANSFORM_IDENTITY = {
}
};
#define CAIRO_SURFACE_RENDER_AT_LEAST(surface, major, minor) \
(((surface)->render_major > major) ? 1 \
: ((surface)->render_major == major) ? ((surface)->render_minor >= minor) : 0)
#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)
static IcFormat *
_create_icformat_for_visual (Visual *visual)
{
return IcFormatCreateMasks (32, 0,
visual->red_mask,
visual->green_mask,
visual->blue_mask);
}
static IcFormat *
_create_icformat_for_format (cairo_format_t format)
{
@ -87,67 +58,31 @@ _create_icformat_for_format (cairo_format_t format)
}
}
cairo_surface_t *
cairo_surface_create_for_drawable (Display *dpy,
Drawable drawable,
Visual *visual,
cairo_format_t format,
Colormap colormap)
void
_cairo_surface_init (cairo_surface_t *surface,
int width,
int height,
cairo_format_t format,
const struct cairo_surface_backend *backend)
{
cairo_surface_t *surface;
surface->width = width;
surface->height = height;
surface = malloc (sizeof (cairo_surface_t));
if (surface == NULL)
return NULL;
surface->image_data = NULL;
/* XXX: We should really get this value from somewhere like Xft.dpy */
/* Assume a default until the user lets us know otherwise */
surface->ppm = 3780;
surface->ref_count = 1;
surface->repeat = 0;
surface->dpy = dpy;
surface->image_data = NULL;
surface->icimage = NULL;
surface->type = CAIRO_SURFACE_TYPE_DRAWABLE;
surface->xtransform = CAIRO_XTRANSFORM_IDENTITY;
surface->gc = 0;
surface->drawable = drawable;
surface->owns_pixmap = 0;
surface->visual = visual;
surface->icimage = NULL;
surface->icformat = _create_icformat_for_format (format);
if (! XRenderQueryVersion (dpy, &surface->render_major, &surface->render_minor)) {
surface->render_major = -1;
surface->render_minor = -1;
}
if (visual)
surface->icformat = _create_icformat_for_visual (visual);
else
surface->icformat = _create_icformat_for_format (format);
/* XXX: I'm currently ignoring the colormap. Is that bad? */
if (CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE (surface))
surface->picture = XRenderCreatePicture (dpy, drawable,
visual ?
XRenderFindVisualFormat (dpy, visual) :
XRenderFindStandardFormat (dpy, format),
0, NULL);
else
surface->picture = 0;
surface->ximage = NULL;
/* XXX: How to get the proper width/height? Force a roundtrip? And
how can we track the width/height properly? Shall we give up on
supporting Windows and only allow drawing to pixmaps? */
surface->width = 0;
surface->height = 0;
return surface;
surface->backend = backend;
}
slim_hidden_def(cairo_surface_create_for_drawable);
static int
cairo_format_bpp (cairo_format_t format)
@ -167,6 +102,8 @@ cairo_format_bpp (cairo_format_t format)
}
}
static const struct cairo_surface_backend cairo_icimage_surface_backend;
cairo_surface_t *
cairo_surface_create_for_image (char *data,
cairo_format_t format,
@ -180,18 +117,7 @@ cairo_surface_create_for_image (char *data,
if (surface == NULL)
return NULL;
surface->icformat = _create_icformat_for_format (format);
/* Assume a default until the user lets us know otherwise */
surface->ppm = 3780;
surface->ref_count = 1;
surface->repeat = 0;
surface->dpy = NULL;
surface->image_data = NULL;
surface->width = width;
surface->height = height;
_cairo_surface_init (surface, width, height, format, &cairo_icimage_surface_backend);
surface->icimage = IcImageCreateForData ((IcBits *) data,
surface->icformat,
@ -203,19 +129,6 @@ cairo_surface_create_for_image (char *data,
return NULL;
}
surface->type = CAIRO_SURFACE_TYPE_ICIMAGE;
surface->xtransform = CAIRO_XTRANSFORM_IDENTITY;
surface->gc = 0;
surface->drawable = 0;
surface->owns_pixmap = 0;
surface->visual = NULL;
surface->render_major = -1;
surface->render_minor = -1;
surface->picture = 0;
surface->ximage = NULL;
return surface;
}
slim_hidden_def(cairo_surface_create_for_image);
@ -229,22 +142,6 @@ cairo_surface_create_similar (cairo_surface_t *other,
return cairo_surface_create_similar_solid (other, format, width, height, 0, 0, 0, 0);
}
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;
}
}
cairo_surface_t *
cairo_surface_create_similar_solid (cairo_surface_t *other,
cairo_format_t format,
@ -258,28 +155,10 @@ cairo_surface_create_similar_solid (cairo_surface_t *other,
cairo_surface_t *surface = NULL;
cairo_color_t color;
/* XXX: There's a pretty lame heuristic here. This assumes that
* all non-Render X servers do not support depth-32 pixmaps, (and
* that they do support depths 1, 8, and 24). Obviously, it would
* be much better to check the depths that are actually
* supported. */
if (other->dpy
&& (CAIRO_SURFACE_RENDER_HAS_COMPOSITE (other)
|| format != CAIRO_FORMAT_ARGB32)) {
Display *dpy = other->dpy;
int scr = DefaultScreen (dpy);
if (other->backend->create_similar)
surface = other->backend->create_similar (other, format, width, height);
Pixmap pix = XCreatePixmap (dpy,
DefaultRootWindow (dpy),
width, height,
_CAIRO_FORMAT_DEPTH (format));
surface = cairo_surface_create_for_drawable (dpy, pix,
NULL,
format,
DefaultColormap (dpy, scr));
surface->owns_pixmap = 1;
} else {
if (!surface) {
char *data;
int stride;
@ -325,149 +204,35 @@ cairo_surface_destroy (cairo_surface_t *surface)
if (surface->ref_count)
return;
if (surface->picture)
XRenderFreePicture (surface->dpy, surface->picture);
if (surface->owns_pixmap)
XFreePixmap (surface->dpy, surface->drawable);
if (surface->icformat)
IcFormatDestroy (surface->icformat);
if (surface->icimage)
IcImageDestroy (surface->icimage);
if (surface->backend->destroy)
surface->backend->destroy (surface);
if (surface->image_data)
free (surface->image_data);
surface->image_data = NULL;
surface->dpy = 0;
free (surface);
}
slim_hidden_def(cairo_surface_destroy);
static void
_cairo_surface_ensure_gc (cairo_surface_t *surface)
{
if (surface->gc)
return;
surface->gc = XCreateGC (surface->dpy, surface->drawable, 0, NULL);
}
static cairo_status_t
_cairo_x11_surface_put_image (cairo_surface_t *surface,
char *data,
int width,
int height,
int stride)
{
if (surface->picture) {
XImage *image;
unsigned bitmap_pad;
/* XXX: This is obviously bogus. depth needs to be figured out for real */
int depth = 32;
if (depth > 16)
bitmap_pad = 32;
else if (depth > 8)
bitmap_pad = 16;
else
bitmap_pad = 8;
image = XCreateImage(surface->dpy,
DefaultVisual(surface->dpy, DefaultScreen(surface->dpy)),
depth, ZPixmap, 0,
data, width, height,
bitmap_pad,
stride);
if (image == NULL)
return CAIRO_STATUS_NO_MEMORY;
_cairo_surface_ensure_gc (surface);
XPutImage(surface->dpy, surface->drawable, surface->gc,
image, 0, 0, 0, 0, width, height);
/* Foolish XDestroyImage thinks it can free my data, but I won't
stand for it. */
image->data = NULL;
XDestroyImage(image);
} else {
/* XXX: Need to implement the IcImage method of setting a picture. memcpy? */
}
return CAIRO_STATUS_SUCCESS;
}
void
_cairo_surface_pull_image (cairo_surface_t *surface)
{
Window root_ignore;
int x_ignore, y_ignore, bwidth_ignore, depth_ignore;
if (surface == NULL)
return;
if (surface->type == CAIRO_SURFACE_TYPE_ICIMAGE)
return;
if (surface->icimage) {
IcImageDestroy (surface->icimage);
surface->icimage = NULL;
}
XGetGeometry(surface->dpy,
surface->drawable,
&root_ignore, &x_ignore, &y_ignore,
&surface->width, &surface->height,
&bwidth_ignore, &depth_ignore);
surface->ximage = XGetImage (surface->dpy,
surface->drawable,
0, 0,
surface->width, surface->height,
AllPlanes, ZPixmap);
surface->icimage = IcImageCreateForData ((IcBits *)(surface->ximage->data),
surface->icformat,
surface->ximage->width,
surface->ximage->height,
surface->ximage->bits_per_pixel,
surface->ximage->bytes_per_line);
IcImageSetRepeat (surface->icimage, surface->repeat);
/* XXX: Evil cast here... */
IcImageSetTransform (surface->icimage, (IcTransform *) &(surface->xtransform));
/* XXX: Add support here for pictures with external alpha. */
if (surface->backend->pull_image)
surface->backend->pull_image (surface);
}
void
_cairo_surface_push_image (cairo_surface_t *surface)
{
if (surface == NULL)
return;
if (surface->type == CAIRO_SURFACE_TYPE_ICIMAGE)
return;
if (surface->ximage == NULL)
return;
_cairo_surface_ensure_gc (surface);
XPutImage (surface->dpy,
surface->drawable,
surface->gc,
surface->ximage,
0, 0,
0, 0,
surface->width,
surface->height);
XDestroyImage(surface->ximage);
surface->ximage = NULL;
if (surface->backend->push_image)
surface->backend->push_image (surface);
}
/* XXX: We may want to move to projective matrices at some point. If
@ -476,6 +241,7 @@ _cairo_surface_push_image (cairo_surface_t *surface)
cairo_status_t
cairo_surface_set_matrix (cairo_surface_t *surface, cairo_matrix_t *matrix)
{
cairo_status_t ret = CAIRO_STATUS_SUCCESS;
XTransform *xtransform = &surface->xtransform;
xtransform->matrix[0][0] = XDoubleToFixed (matrix->m[0][0]);
@ -490,19 +256,15 @@ cairo_surface_set_matrix (cairo_surface_t *surface, cairo_matrix_t *matrix)
xtransform->matrix[2][1] = 0;
xtransform->matrix[2][2] = XDoubleToFixed (1);
if (surface->picture) {
if (CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM (surface))
XRenderSetPictureTransform (surface->dpy, surface->picture, xtransform);
/* XXX: Need support here if using an old RENDER without support
for SetPictureTransform */
}
if (surface->backend->set_matrix)
ret = surface->backend->set_matrix (surface);
/* XXX: This cast should only occur with a #define hint from libic that it is OK */
if (surface->icimage) {
IcImageSetTransform (surface->icimage, (IcTransform *) xtransform);
}
return CAIRO_STATUS_SUCCESS;
return ret;
}
slim_hidden_def(cairo_surface_set_matrix);
@ -523,41 +285,17 @@ cairo_surface_get_matrix (cairo_surface_t *surface, cairo_matrix_t *matrix)
}
slim_hidden_def(cairo_surface_get_matrix);
/* XXX: The Render specification has capitalized versions of these
strings. However, the current implementation is case-sensitive and
expects lowercase versions. */
static char *
_render_filter_name (cairo_filter_t filter)
{
switch (filter) {
case CAIRO_FILTER_FAST:
return "fast";
case CAIRO_FILTER_GOOD:
return "good";
case CAIRO_FILTER_BEST:
return "best";
case CAIRO_FILTER_NEAREST:
return "nearest";
case CAIRO_FILTER_BILINEAR:
return "bilinear";
default:
return "best";
}
}
cairo_status_t
cairo_surface_set_filter (cairo_surface_t *surface, cairo_filter_t filter)
{
if (surface->picture) {
XRenderSetPictureFilter (surface->dpy, surface->picture,
_render_filter_name (filter), NULL, 0);
}
if (surface->icimage) {
IcImageSetFilter (surface->icimage, filter);
}
return CAIRO_STATUS_SUCCESS;
if (!surface->backend->set_filter)
return CAIRO_STATUS_SUCCESS;
return surface->backend->set_filter (surface, filter);
}
/* XXX: NYI
@ -580,21 +318,14 @@ cairo_surface_set_repeat (cairo_surface_t *surface, int repeat)
{
surface->repeat = repeat;
if (surface->picture) {
unsigned long mask;
XRenderPictureAttributes pa;
mask = CPRepeat;
pa.repeat = repeat;
XRenderChangePicture (surface->dpy, surface->picture, mask, &pa);
}
if (surface->icimage) {
IcImageSetRepeat (surface->icimage, repeat);
}
return CAIRO_STATUS_SUCCESS;
if (!surface->backend->set_repeat)
return CAIRO_STATUS_SUCCESS;
return surface->backend->set_repeat (surface, repeat);
}
slim_hidden_def(cairo_surface_set_repeat);
@ -612,58 +343,25 @@ _cairo_surface_composite (cairo_operator_t operator,
unsigned int width,
unsigned int height)
{
if (dst->type == CAIRO_SURFACE_TYPE_DRAWABLE
&& CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst)
&& (mask == NULL || mask->dpy == dst->dpy)
&& (src->type == CAIRO_SURFACE_TYPE_ICIMAGE || src->dpy == dst->dpy)) {
if (dst->backend->composite
&& (dst->backend->composite (operator, src, mask, dst, src_x, src_y, mask_x, mask_y, dst_x, dst_y, width, height) >= 0))
return;
cairo_surface_t *src_on_server = NULL;
_cairo_surface_pull_image (src);
if (mask)
_cairo_surface_pull_image (mask);
_cairo_surface_pull_image (dst);
if (src->type == CAIRO_SURFACE_TYPE_ICIMAGE) {
cairo_matrix_t matrix;
src_on_server = cairo_surface_create_similar (dst, CAIRO_FORMAT_ARGB32,
IcImageGetWidth (src->icimage),
IcImageGetHeight (src->icimage));
if (src_on_server == NULL)
return;
IcComposite (operator,
src->icimage,
mask ? mask->icimage : NULL,
dst->icimage,
src_x, src_y,
mask_x, mask_y,
dst_x, dst_y,
width, height);
cairo_surface_get_matrix (src, &matrix);
cairo_surface_set_matrix (src_on_server, &matrix);
_cairo_x11_surface_put_image (src_on_server,
(char *) IcImageGetData (src->icimage),
IcImageGetWidth (src->icimage),
IcImageGetHeight (src->icimage),
IcImageGetStride (src->icimage));
}
XRenderComposite (dst->dpy, operator,
src_on_server ? src_on_server->picture : src->picture,
mask ? mask->picture : 0,
dst->picture,
src_x, src_y,
mask_x, mask_y,
dst_x, dst_y,
width, height);
} else {
_cairo_surface_pull_image (src);
if (mask)
_cairo_surface_pull_image (mask);
_cairo_surface_pull_image (dst);
IcComposite (operator,
src->icimage,
mask ? mask->icimage : NULL,
dst->icimage,
src_x, src_y,
mask_x, mask_y,
dst_x, dst_y,
width, height);
_cairo_surface_push_image (dst);
}
_cairo_surface_push_image (dst);
}
void
@ -692,38 +390,27 @@ _cairo_surface_fill_rectangles (cairo_surface_t *surface,
cairo_rectangle_t *rects,
int num_rects)
{
IcColor ic_color;
if (num_rects == 0)
return;
if (surface->type == CAIRO_SURFACE_TYPE_DRAWABLE
&& CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLE (surface)) {
if (surface->backend->fill_rectangles
&& (surface->backend->fill_rectangles (surface, operator, color, rects, num_rects) >= 0))
return;
XRenderColor render_color;
render_color.red = color->red_short;
render_color.green = color->green_short;
render_color.blue = color->blue_short;
render_color.alpha = color->alpha_short;
ic_color.red = color->red_short;
ic_color.green = color->green_short;
ic_color.blue = color->blue_short;
ic_color.alpha = color->alpha_short;
/* XXX: This XRectangle cast is evil... it needs to go away somehow. */
XRenderFillRectangles (surface->dpy, operator, surface->picture,
&render_color, (XRectangle *) rects, num_rects);
_cairo_surface_pull_image (surface);
} else {
IcColor ic_color;
/* XXX: The IcRectangle cast is evil... it needs to go away somehow. */
IcFillRectangles (operator, surface->icimage,
&ic_color, (IcRectangle *) rects, num_rects);
ic_color.red = color->red_short;
ic_color.green = color->green_short;
ic_color.blue = color->blue_short;
ic_color.alpha = color->alpha_short;
_cairo_surface_pull_image (surface);
/* XXX: The IcRectangle cast is evil... it needs to go away somehow. */
IcFillRectangles (operator, surface->icimage,
&ic_color, (IcRectangle *) rects, num_rects);
_cairo_surface_push_image (surface);
}
_cairo_surface_push_image (surface);
}
void
@ -735,23 +422,17 @@ _cairo_surface_composite_trapezoids (cairo_operator_t operator,
cairo_trapezoid_t *traps,
int num_traps)
{
if (dst->type == CAIRO_SURFACE_TYPE_DRAWABLE
&& CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS (dst)
&& src->dpy == dst->dpy) {
if (dst->backend->composite_trapezoids
&& (dst->backend->composite_trapezoids (operator, src, dst, xSrc, ySrc, traps, num_traps) >= 0))
return;
/* XXX: The XTrapezoid cast is evil and needs to go away somehow. */
XRenderCompositeTrapezoids (dst->dpy, operator, src->picture, dst->picture,
XRenderFindStandardFormat (dst->dpy, PictStandardA8),
xSrc, ySrc, (XTrapezoid *) traps, num_traps);
} else {
_cairo_surface_pull_image (src);
_cairo_surface_pull_image (dst);
_cairo_surface_pull_image (src);
_cairo_surface_pull_image (dst);
/* XXX: The IcTrapezoid cast is evil and needs to go away somehow. */
IcCompositeTrapezoids (operator, src->icimage, dst->icimage,
xSrc, ySrc, (IcTrapezoid *) traps, num_traps);
/* XXX: The IcTrapezoid cast is evil and needs to go away somehow. */
IcCompositeTrapezoids (operator, src->icimage, dst->icimage,
xSrc, ySrc, (IcTrapezoid *) traps, num_traps);
_cairo_surface_push_image (dst);
}
_cairo_surface_push_image (dst);
}

719
src/cairo-xlib-surface.c Normal file
View file

@ -0,0 +1,719 @@
/*
* Copyright © 2002 USC, Information Sciences Institute
*
* 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 the
* University of Southern California not be used in advertising or
* publicity pertaining to distribution of the software without
* specific, written prior permission. The University of Southern
* California makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without express
* or implied warranty.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
* SOUTHERN CALIFORNIA 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: Carl D. Worth <cworth@isi.edu>
*/
#include <X11/Xft/Xft.h>
#include "cairoint.h"
#include "cairo-xlib.h"
#include <X11/Xlibint.h>
static cairo_font_t *
_cairo_xlib_font_create (Display *dpy);
void
cairo_set_target_drawable (cairo_t *cr,
Display *dpy,
Drawable drawable)
{
cairo_surface_t *surface;
if (cr->status && cr->status != CAIRO_STATUS_NO_TARGET_SURFACE)
return;
surface = cairo_xlib_surface_create (dpy, drawable,
DefaultVisual (dpy, DefaultScreen (dpy)),
0,
DefaultColormap (dpy, DefaultScreen (dpy)));
if (surface == NULL) {
cr->status = CAIRO_STATUS_NO_MEMORY;
return;
}
cairo_set_target_surface (cr, surface);
cr->gstate->font = _cairo_xlib_font_create (dpy);
cairo_surface_destroy (surface);
}
typedef struct cairo_xlib_surface {
cairo_surface_t base;
Display *dpy;
GC gc;
Drawable drawable;
int owns_pixmap;
Visual *visual;
int render_major;
int render_minor;
Picture picture;
XImage *ximage;
} cairo_xlib_surface;
#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)
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_xlib_surface *
_cairo_xlib_surface_create_similar (cairo_xlib_surface *other,
cairo_format_t format,
int width,
int height)
{
Display *dpy = other->dpy;
int scr;
Pixmap pix;
cairo_xlib_surface *surface;
/* XXX: There's a pretty lame heuristic here. This assumes that
* all non-Render X servers do not support depth-32 pixmaps, (and
* that they do support depths 1, 8, and 24). Obviously, it would
* be much better to check the depths that are actually
* supported. */
if (!dpy
|| (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (other)
&& format == CAIRO_FORMAT_ARGB32))
return 0;
scr = DefaultScreen (dpy);
pix = XCreatePixmap (dpy, DefaultRootWindow (dpy),
width, height,
_CAIRO_FORMAT_DEPTH (format));
surface = (cairo_xlib_surface *)
cairo_xlib_surface_create (dpy, pix, NULL, format, DefaultColormap (dpy, scr));
surface->owns_pixmap = 1;
return surface;
}
static void
_cairo_xlib_surface_destroy (cairo_xlib_surface *surface)
{
if (surface->picture)
XRenderFreePicture (surface->dpy, surface->picture);
if (surface->owns_pixmap)
XFreePixmap (surface->dpy, surface->drawable);
surface->dpy = 0;
}
static void
_cairo_xlib_surface_pull_image (cairo_xlib_surface *surface)
{
Window root_ignore;
int x_ignore, y_ignore, bwidth_ignore, depth_ignore;
if (surface == NULL)
return;
if (surface->base.icimage) {
IcImageDestroy (surface->base.icimage);
surface->base.icimage = NULL;
}
XGetGeometry(surface->dpy,
surface->drawable,
&root_ignore, &x_ignore, &y_ignore,
&surface->base.width, &surface->base.height,
&bwidth_ignore, &depth_ignore);
surface->ximage = XGetImage (surface->dpy,
surface->drawable,
0, 0,
surface->base.width, surface->base.height,
AllPlanes, ZPixmap);
surface->base.icimage = IcImageCreateForData ((IcBits *)(surface->ximage->data),
surface->base.icformat,
surface->ximage->width,
surface->ximage->height,
surface->ximage->bits_per_pixel,
surface->ximage->bytes_per_line);
IcImageSetRepeat (surface->base.icimage, surface->base.repeat);
/* XXX: Evil cast here... */
IcImageSetTransform (surface->base.icimage, (IcTransform *) &(surface->base.xtransform));
/* XXX: Add support here for pictures with external alpha. */
}
static void
_cairo_xlib_surface_ensure_gc (cairo_xlib_surface *surface)
{
if (surface->gc)
return;
surface->gc = XCreateGC (surface->dpy, surface->drawable, 0, NULL);
}
static void
_cairo_xlib_surface_push_image (cairo_xlib_surface *surface)
{
if (surface == NULL)
return;
if (surface->ximage == NULL)
return;
_cairo_xlib_surface_ensure_gc (surface);
XPutImage (surface->dpy,
surface->drawable,
surface->gc,
surface->ximage,
0, 0,
0, 0,
surface->base.width,
surface->base.height);
XDestroyImage(surface->ximage);
surface->ximage = NULL;
}
static cairo_status_t
_cairo_xlib_surface_set_matrix (cairo_xlib_surface *surface)
{
if (!surface->picture)
return CAIRO_STATUS_SUCCESS;
if (CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM (surface))
{
XRenderSetPictureTransform (surface->dpy, surface->picture, &surface->base.xtransform);
} else {
/* XXX: Need support here if using an old RENDER without support
for SetPictureTransform */
}
return CAIRO_STATUS_SUCCESS;
}
/* XXX: The Render specification has capitalized versions of these
strings. However, the current implementation is case-sensitive and
expects lowercase versions. */
static char *
_render_filter_name (cairo_filter_t filter)
{
switch (filter) {
case CAIRO_FILTER_FAST:
return "fast";
case CAIRO_FILTER_GOOD:
return "good";
case CAIRO_FILTER_BEST:
return "best";
case CAIRO_FILTER_NEAREST:
return "nearest";
case CAIRO_FILTER_BILINEAR:
return "bilinear";
default:
return "best";
}
}
static cairo_status_t
_cairo_xlib_surface_set_filter (cairo_xlib_surface *surface, cairo_filter_t filter)
{
if (!surface->picture)
return CAIRO_STATUS_SUCCESS;
XRenderSetPictureFilter (surface->dpy, surface->picture,
_render_filter_name (filter), NULL, 0);
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_xlib_surface_set_repeat (cairo_xlib_surface *surface, int repeat)
{
unsigned long mask;
XRenderPictureAttributes pa;
if (!surface->picture)
return CAIRO_STATUS_SUCCESS;
mask = CPRepeat;
pa.repeat = repeat;
XRenderChangePicture (surface->dpy, surface->picture, mask, &pa);
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_xlib_surface_put_image (cairo_xlib_surface *surface,
char *data,
int width,
int height,
int stride)
{
XImage *image;
unsigned bitmap_pad;
if (!surface->picture)
return CAIRO_STATUS_SUCCESS;
/* XXX: This is obviously bogus. depth needs to be figured out for real */
int depth = 32;
if (depth > 16)
bitmap_pad = 32;
else if (depth > 8)
bitmap_pad = 16;
else
bitmap_pad = 8;
image = XCreateImage(surface->dpy,
DefaultVisual(surface->dpy, DefaultScreen(surface->dpy)),
depth, ZPixmap, 0,
data, width, height,
bitmap_pad,
stride);
if (image == NULL)
return CAIRO_STATUS_NO_MEMORY;
_cairo_xlib_surface_ensure_gc (surface);
XPutImage(surface->dpy, surface->drawable, surface->gc,
image, 0, 0, 0, 0, width, height);
/* Foolish XDestroyImage thinks it can free my data, but I won't
stand for it. */
image->data = NULL;
XDestroyImage(image);
return CAIRO_STATUS_SUCCESS;
}
static cairo_xlib_surface *
_cairo_xlib_surface_clone_from (cairo_surface_t *src, cairo_xlib_surface *tmpl)
{
cairo_matrix_t matrix;
cairo_xlib_surface *src_on_server;
_cairo_surface_pull_image (src);
src_on_server = _cairo_xlib_surface_create_similar (tmpl, CAIRO_FORMAT_ARGB32,
IcImageGetWidth (src->icimage),
IcImageGetHeight (src->icimage));
if (src_on_server == NULL)
return NULL;
cairo_surface_get_matrix (src, &matrix);
cairo_surface_set_matrix (&src_on_server->base, &matrix);
_cairo_xlib_surface_put_image (src_on_server,
(char *) IcImageGetData (src->icimage),
IcImageGetWidth (src->icimage),
IcImageGetHeight (src->icimage),
IcImageGetStride (src->icimage));
return src_on_server;
}
static int
_cairo_xlib_surface_composite (cairo_operator_t operator,
cairo_xlib_surface *src,
cairo_xlib_surface *mask,
cairo_xlib_surface *dst,
int src_x,
int src_y,
int mask_x,
int mask_y,
int dst_x,
int dst_y,
unsigned int width,
unsigned int height)
{
if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst))
return -1;
if (src->base.backend != dst->base.backend || src->dpy != dst->dpy) {
src = _cairo_xlib_surface_clone_from (&src->base, dst);
if (!src)
return -1;
}
if (mask && (mask->base.backend != dst->base.backend || mask->dpy != dst->dpy)) {
mask = _cairo_xlib_surface_clone_from (&mask->base, dst);
if (!mask)
return -1;
}
XRenderComposite (dst->dpy, operator,
src->picture,
mask ? mask->picture : 0,
dst->picture,
src_x, src_y,
mask_x, mask_y,
dst_x, dst_y,
width, height);
return 0;
}
static int
_cairo_xlib_surface_fill_rectangles (cairo_xlib_surface *surface,
cairo_operator_t operator,
const cairo_color_t *color,
cairo_rectangle_t *rects,
int num_rects)
{
XRenderColor render_color;
if (!CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLE (surface))
return -1;
render_color.red = color->red_short;
render_color.green = color->green_short;
render_color.blue = color->blue_short;
render_color.alpha = color->alpha_short;
/* XXX: This XRectangle cast is evil... it needs to go away somehow. */
XRenderFillRectangles (surface->dpy, operator, surface->picture,
&render_color, (XRectangle *) rects, num_rects);
return 0;
}
static int
_cairo_xlib_surface_composite_trapezoids (cairo_operator_t operator,
cairo_xlib_surface *src,
cairo_xlib_surface *dst,
int xSrc,
int ySrc,
cairo_trapezoid_t *traps,
int num_traps)
{
if (!CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS (dst))
return -1;
if (src->base.backend != dst->base.backend || src->dpy != dst->dpy) {
src = _cairo_xlib_surface_clone_from (&src->base, dst);
if (!src)
return -1;
}
/* XXX: The XTrapezoid cast is evil and needs to go away somehow. */
XRenderCompositeTrapezoids (dst->dpy, operator, src->picture, dst->picture,
XRenderFindStandardFormat (dst->dpy, PictStandardA8),
xSrc, ySrc, (XTrapezoid *) traps, num_traps);
return 0;
}
static const struct cairo_surface_backend cairo_xlib_surface_backend = {
create_similar: (void *) _cairo_xlib_surface_create_similar,
destroy: (void *) _cairo_xlib_surface_destroy,
pull_image: (void *) _cairo_xlib_surface_pull_image,
push_image: (void *) _cairo_xlib_surface_push_image,
set_matrix: (void *) _cairo_xlib_surface_set_matrix,
set_filter: (void *) _cairo_xlib_surface_set_filter,
set_repeat: (void *) _cairo_xlib_surface_set_repeat,
composite: (void *) _cairo_xlib_surface_composite,
fill_rectangles: (void *) _cairo_xlib_surface_fill_rectangles,
composite_trapezoids: (void *) _cairo_xlib_surface_composite_trapezoids,
};
Picture
_cairo_xlib_surface_get_picture (cairo_surface_t *surface)
{
if (surface->backend != &cairo_xlib_surface_backend)
return 0;
return ((cairo_xlib_surface *) surface)->picture;
}
cairo_surface_t *
cairo_xlib_surface_create (Display *dpy,
Drawable drawable,
Visual *visual,
cairo_format_t format,
Colormap colormap)
{
cairo_xlib_surface *surface;
surface = malloc (sizeof (cairo_xlib_surface));
if (surface == NULL)
return NULL;
/* XXX: How to get the proper width/height? Force a roundtrip? And
how can we track the width/height properly? Shall we give up on
supporting Windows and only allow drawing to pixmaps? */
_cairo_surface_init (&surface->base, 0, 0, format, &cairo_xlib_surface_backend);
if (visual) {
if (surface->base.icformat)
IcFormatDestroy (surface->base.icformat);
surface->base.icformat = IcFormatCreateMasks (32, 0,
visual->red_mask,
visual->green_mask,
visual->blue_mask);
}
surface->dpy = dpy;
surface->gc = 0;
surface->drawable = drawable;
surface->owns_pixmap = 0;
surface->visual = visual;
if (! XRenderQueryVersion (dpy, &surface->render_major, &surface->render_minor)) {
surface->render_major = -1;
surface->render_minor = -1;
}
/* XXX: I'm currently ignoring the colormap. Is that bad? */
if (CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE (surface))
surface->picture = XRenderCreatePicture (dpy, drawable,
visual ?
XRenderFindVisualFormat (dpy, visual) :
XRenderFindStandardFormat (dpy, format),
0, NULL);
else
surface->picture = 0;
surface->ximage = NULL;
return (cairo_surface_t *) surface;
}
DEPRECATE (cairo_surface_create_for_drawable, cairo_xlib_surface_create);
typedef struct cairo_xlib_font {
cairo_font_t base;
Display *dpy;
XftFont *xft_font;
} cairo_xlib_font_t;
static cairo_font_t *
_cairo_xlib_font_copy (cairo_xlib_font_t *other)
{
cairo_xlib_font_t *font;
font = malloc (sizeof (cairo_xlib_font_t));
if (!font)
return 0;
if (_cairo_font_init_copy (&font->base, &other->base))
goto abort;
font->dpy = other->dpy;
if (other->xft_font) {
font->xft_font = XftFontCopy (other->dpy, other->xft_font);
if (font->xft_font == NULL)
goto abort;
} else
font->xft_font = NULL;
return &font->base;
abort:
_cairo_font_fini (&font->base);
return 0;
}
static void
_cairo_xlib_font_close (cairo_xlib_font_t *font)
{
if (font->xft_font)
XftFontClose (font->dpy, font->xft_font);
font->xft_font = NULL;
}
static cairo_status_t
_cairo_xlib_font_resolve (cairo_xlib_font_t *font, cairo_matrix_t *ctm)
{
FcPattern *pattern;
FcPattern *match;
FcResult result;
cairo_matrix_t matrix;
FcMatrix fc_matrix;
double expansion;
double font_size;
if (font->xft_font)
return CAIRO_STATUS_SUCCESS;
pattern = FcNameParse (font->base.key);
matrix = *ctm;
cairo_matrix_multiply (&matrix, &font->base.matrix, &matrix);
/* Pull the scale factor out of the final matrix and use it to set
the direct pixelsize of the font. This enables freetype to
perform proper hinting at any size. */
/* XXX: The determinant gives an area expansion factor, so the
math below should be correct for the (common) case of uniform
X/Y scaling. Is there anything different we would want to do
for non-uniform X/Y scaling?
XXX: Actually, the reasoning above is bogus. A transformation
such as scale (N, 1/N) will give an expansion_factor of 1. So,
with the code below we'll end up with font_size == 1 instead of
N, (so the hinting will be all wrong). I think we want to use
the maximum eigen value rather than the square root of the
determinant. */
_cairo_matrix_compute_determinant (&matrix, &expansion);
font_size = sqrt (fabs (expansion));
FcPatternAddDouble (pattern, "pixelsize", font_size);
cairo_matrix_scale (&matrix, 1.0 / font_size, 1.0 / font_size);
fc_matrix.xx = matrix.m[0][0];
fc_matrix.xy = matrix.m[0][1];
fc_matrix.yx = matrix.m[1][0];
fc_matrix.yy = matrix.m[1][1];
FcPatternAddMatrix (pattern, "matrix", &fc_matrix);
match = XftFontMatch (font->dpy, DefaultScreen (font->dpy), pattern, &result);
if (!match)
return 0;
font->xft_font = XftFontOpenPattern (font->dpy, match);
FcPatternDestroy (pattern);
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_xlib_font_text_extents (cairo_xlib_font_t *font,
cairo_matrix_t *ctm,
const unsigned char *utf8,
double *x, double *y,
double *width, double *height,
double *dx, double *dy)
{
XGlyphInfo extents;
_cairo_xlib_font_resolve (font, ctm);
XftTextExtentsUtf8 (font->dpy,
font->xft_font,
utf8,
strlen ((char *) utf8),
&extents);
/* XXX: What are the semantics of XftTextExtents? Specifically,
what does it do with x/y? I think we actually need to use the
gstate's current point in here somewhere. */
*x = extents.x;
*y = extents.y;
*width = extents.width;
*height = extents.height;
*dx = extents.xOff;
*dy = extents.yOff;
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_xlib_font_show_text (cairo_xlib_font_t *font,
cairo_matrix_t *ctm,
cairo_operator_t operator,
cairo_surface_t *source,
cairo_surface_t *surface,
double x,
double y,
const unsigned char *utf8)
{
Picture source_picture, surface_picture;
_cairo_xlib_font_resolve (font, ctm);
source_picture = _cairo_xlib_surface_get_picture (source);
surface_picture = _cairo_xlib_surface_get_picture (surface);
XftTextRenderUtf8 (font->dpy,
operator,
source_picture,
font->xft_font,
surface_picture,
0, 0,
x, y,
utf8,
strlen ((char *) utf8));
return CAIRO_STATUS_SUCCESS;
}
static const struct cairo_font_backend cairo_xlib_font_backend = {
copy: (void *) _cairo_xlib_font_copy,
close: (void *) _cairo_xlib_font_close,
text_extents: (void *) _cairo_xlib_font_text_extents,
show_text: (void *) _cairo_xlib_font_show_text,
};
static cairo_font_t *
_cairo_xlib_font_create (Display *dpy)
{
cairo_xlib_font_t *font;
font = malloc (sizeof (cairo_xlib_font_t));
if (!font)
return 0;
_cairo_font_init (&font->base, &cairo_xlib_font_backend);
font->dpy = dpy;
font->xft_font = NULL;
return &font->base;
}

56
src/cairo-xlib.h Normal file
View file

@ -0,0 +1,56 @@
/*
* Copyright © 2002 USC, Information Sciences Institute
*
* 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 the
* University of Southern California not be used in advertising or
* publicity pertaining to distribution of the software without
* specific, written prior permission. The University of Southern
* California makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without express
* or implied warranty.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
* SOUTHERN CALIFORNIA 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: Carl D. Worth <cworth@isi.edu>
*/
#ifndef _CAIRO_XLIB_H_
#define _CAIRO_XLIB_H_
#include "cairo.h"
#ifdef _CAIROINT_H_
#include <slim_export.h>
#else
#include <slim_import.h>
#endif
/* XXX: This is a mess from the user's POV. Should the Visual or the
cairo_format_t control what render format is used? Maybe I can have
cairo_surface_create_for_window with a visual, and
cairo_surface_create_for_pixmap with a cairo_format_t. Would that work?
*/
extern cairo_surface_t * __external_linkage
cairo_xlib_surface_create (Display *dpy,
Drawable drawable,
Visual *visual,
cairo_format_t format,
Colormap colormap);
extern void __external_linkage
cairo_set_target_drawable (cairo_t *cr,
Display *dpy,
Drawable drawable);
#endif

View file

@ -171,30 +171,6 @@ cairo_set_target_surface (cairo_t *cr, cairo_surface_t *surface)
}
slim_hidden_def(cairo_set_target_surface);
void
cairo_set_target_drawable (cairo_t *cr,
Display *dpy,
Drawable drawable)
{
cairo_surface_t *surface;
if (cr->status && cr->status != CAIRO_STATUS_NO_TARGET_SURFACE)
return;
surface = cairo_surface_create_for_drawable (dpy, drawable,
DefaultVisual (dpy, DefaultScreen (dpy)),
0,
DefaultColormap (dpy, DefaultScreen (dpy)));
if (surface == NULL) {
cr->status = CAIRO_STATUS_NO_MEMORY;
return;
}
cairo_set_target_surface (cr, surface);
cairo_surface_destroy (surface);
}
void
cairo_set_target_image (cairo_t *cr,
char *data,

View file

@ -84,11 +84,6 @@ typedef enum cairo_format {
CAIRO_FORMAT_A1 = PictStandardA1
} cairo_format_t;
extern void __external_linkage
cairo_set_target_drawable (cairo_t *cr,
Display *dpy,
Drawable drawable);
extern void __external_linkage
cairo_set_target_image (cairo_t *cr,
char *data,
@ -427,18 +422,6 @@ cairo_status_string (cairo_t *cr);
/* Surface mainpulation */
/* XXX: This is a mess from the user's POV. Should the Visual or the
cairo_format_t control what render format is used? Maybe I can have
cairo_surface_create_for_window with a visual, and
cairo_surface_create_for_pixmap with a cairo_format_t. Would that work?
*/
extern cairo_surface_t * __external_linkage
cairo_surface_create_for_drawable (Display *dpy,
Drawable drawable,
Visual *visual,
cairo_format_t format,
Colormap colormap);
extern cairo_surface_t * __external_linkage
cairo_surface_create_for_image (char *data,
cairo_format_t format,

View file

@ -25,41 +25,41 @@
* Author: Carl D. Worth <cworth@isi.edu>
*/
#include <string.h>
#include "cairoint.h"
void
_cairo_font_init (cairo_font_t *font)
_cairo_font_init (cairo_font_t *font, const struct cairo_font_backend *backend)
{
font->key = (unsigned char *) strdup (CAIRO_FONT_KEY_DEFAULT);
font->dpy = NULL;
font->xft_font = NULL;
cairo_matrix_set_identity (&font->matrix);
font->backend = backend;
}
cairo_status_t
_cairo_font_init_copy (cairo_font_t *font, cairo_font_t *other)
{
*font = *other;
if (other->key) {
font->key = (unsigned char *) strdup ((char *) other->key);
if (font->key == NULL)
return CAIRO_STATUS_NO_MEMORY;
}
font->matrix = other->matrix;
if (other->xft_font) {
font->xft_font = XftFontCopy (other->dpy, other->xft_font);
if (font->xft_font == NULL)
return CAIRO_STATUS_NO_MEMORY;
}
font->backend = other->backend;
return CAIRO_STATUS_SUCCESS;
}
cairo_font_t *
_cairo_font_copy (cairo_font_t *font)
{
if (!font->backend->copy)
return 0;
return font->backend->copy (font);
}
void
_cairo_font_fini (cairo_font_t *font)
{
@ -69,18 +69,15 @@ _cairo_font_fini (cairo_font_t *font)
_cairo_matrix_fini (&font->matrix);
if (font->xft_font)
XftFontClose (font->dpy, font->xft_font);
font->xft_font = NULL;
if (font->backend->close)
font->backend->close (font);
}
cairo_status_t
_cairo_font_select (cairo_font_t *font, const char *key)
{
if (font->xft_font)
XftFontClose (font->dpy, font->xft_font);
font->xft_font = NULL;
if (font->backend->close)
font->backend->close (font);
if (font->key)
free (font->key);
@ -114,69 +111,31 @@ _cairo_font_transform (cairo_font_t *font,
}
cairo_status_t
_cairo_font_resolve_xft_font (cairo_font_t *font, cairo_gstate_t *gstate, XftFont **xft_font)
_cairo_font_text_extents (cairo_font_t *font,
cairo_matrix_t *ctm,
const unsigned char *utf8,
double *x, double *y,
double *width, double *height,
double *dx, double *dy)
{
FcPattern *pattern;
FcPattern *match;
FcResult result;
cairo_matrix_t matrix;
FcMatrix fc_matrix;
double expansion;
double font_size;
if (font->xft_font) {
*xft_font = font->xft_font;
if (!font->backend->text_extents)
return CAIRO_STATUS_SUCCESS;
}
pattern = FcNameParse (font->key);
matrix = gstate->ctm;
cairo_matrix_multiply (&matrix, &font->matrix, &matrix);
/* Pull the scale factor out of the final matrix and use it to set
the direct pixelsize of the font. This enables freetype to
perform proper hinting at any size. */
/* XXX: The determinant gives an area expansion factor, so the
math below should be correct for the (common) case of uniform
X/Y scaling. Is there anything different we would want to do
for non-uniform X/Y scaling?
XXX: Actually, the reasoning above is bogus. A transformation
such as scale (N, 1/N) will give an expansion_factor of 1. So,
with the code below we'll end up with font_size == 1 instead of
N, (so the hinting will be all wrong). I think we want to use
the maximum eigen value rather than the square root of the
determinant.
*/
_cairo_matrix_compute_determinant (&matrix, &expansion);
font_size = sqrt (fabs (expansion));
FcPatternAddDouble (pattern, "pixelsize", font_size);
cairo_matrix_scale (&matrix, 1.0 / font_size, 1.0 / font_size);
fc_matrix.xx = matrix.m[0][0];
fc_matrix.xy = matrix.m[0][1];
fc_matrix.yx = matrix.m[1][0];
fc_matrix.yy = matrix.m[1][1];
FcPatternAddMatrix (pattern, "matrix", &fc_matrix);
/* XXX: Need to make a generic (non-Xft) backend for text. */
/* When I do that I can throw away these Display pointers */
font->dpy = gstate->surface->dpy;
match = XftFontMatch (font->dpy, DefaultScreen (font->dpy), pattern, &result);
if (!match)
return 0;
font->xft_font = XftFontOpenPattern (font->dpy, match);
*xft_font = font->xft_font;
FcPatternDestroy (pattern);
return CAIRO_STATUS_SUCCESS;
return font->backend->text_extents (font, ctm, utf8, x, y, width, height, dx, dy);
}
cairo_status_t
_cairo_font_show_text (cairo_font_t *font,
cairo_matrix_t *ctm,
cairo_operator_t operator,
cairo_surface_t *source,
cairo_surface_t *surface,
double x,
double y,
const unsigned char *utf8)
{
if (!font->backend->show_text)
return CAIRO_STATUS_SUCCESS;
return font->backend->show_text (font, ctm, operator, source, surface, x, y, utf8);
}

View file

@ -74,7 +74,7 @@ _cairo_gstate_init (cairo_gstate_t *gstate)
gstate->num_dashes = 0;
gstate->dash_offset = 0.0;
_cairo_font_init (&gstate->font);
gstate->font = NULL;
gstate->surface = NULL;
gstate->source = NULL;
@ -121,9 +121,11 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other)
memcpy (gstate->dash, other->dash, other->num_dashes * sizeof (double));
}
status = _cairo_font_init_copy (&gstate->font, &other->font);
if (status)
gstate->font = _cairo_font_copy (other->font);
if (!gstate->font) {
status = CAIRO_STATUS_NO_MEMORY;
goto CLEANUP_DASHES;
}
cairo_surface_reference (gstate->surface);
cairo_surface_reference (gstate->source);
@ -142,7 +144,7 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other)
CLEANUP_PATH:
_cairo_path_fini (&gstate->path);
CLEANUP_FONT:
_cairo_font_fini (&gstate->font);
_cairo_font_fini (gstate->font);
CLEANUP_DASHES:
free (gstate->dash);
gstate->dash = NULL;
@ -153,7 +155,7 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other)
void
_cairo_gstate_fini (cairo_gstate_t *gstate)
{
_cairo_font_fini (&gstate->font);
_cairo_font_fini (gstate->font);
cairo_surface_destroy (gstate->surface);
gstate->surface = NULL;
@ -1353,13 +1355,13 @@ _cairo_gstate_clip (cairo_gstate_t *gstate)
cairo_status_t
_cairo_gstate_select_font (cairo_gstate_t *gstate, const char *key)
{
return _cairo_font_select (&gstate->font, key);
return _cairo_font_select (gstate->font, key);
}
cairo_status_t
_cairo_gstate_scale_font (cairo_gstate_t *gstate, double scale)
{
return _cairo_font_scale (&gstate->font, scale);
return _cairo_font_scale (gstate->font, scale);
}
cairo_status_t
@ -1367,7 +1369,7 @@ _cairo_gstate_transform_font (cairo_gstate_t *gstate,
double a, double b,
double c, double d)
{
return _cairo_font_transform (&gstate->font,
return _cairo_font_transform (gstate->font,
a, b, c, d);
}
@ -1378,45 +1380,17 @@ _cairo_gstate_text_extents (cairo_gstate_t *gstate,
double *width, double *height,
double *dx, double *dy)
{
XftFont *xft_font;
XGlyphInfo extents;
if (gstate->surface->dpy == 0)
return CAIRO_STATUS_SUCCESS;
_cairo_font_resolve_xft_font (&gstate->font, gstate, &xft_font);
/* XXX: Need to make a generic (non-Xft) backend for text. */
XftTextExtentsUtf8 (gstate->surface->dpy,
xft_font,
utf8,
strlen ((char *) utf8),
&extents);
/* XXX: What are the semantics of XftTextExtents? Specifically,
what does it do with x/y? I think we actually need to use the
gstate's current point in here somewhere. */
*x = extents.x;
*y = extents.y;
*width = extents.width;
*height = extents.height;
*dx = extents.xOff;
*dy = extents.yOff;
return CAIRO_STATUS_SUCCESS;
return _cairo_font_text_extents (gstate->font, &gstate->ctm, utf8,
x, y, width, height, dx, dy);
}
cairo_status_t
_cairo_gstate_show_text (cairo_gstate_t *gstate, const unsigned char *utf8)
{
cairo_status_t status;
XftFont *xft_font;
double x, y;
cairo_matrix_t user_to_source, device_to_source;
if (gstate->surface->dpy == 0)
return CAIRO_STATUS_SUCCESS;
/* XXX: I believe this is correct, but it would be much more clear
to have some explicit current_point accesor functions, (one for
user- and one for device-space). */
@ -1429,8 +1403,6 @@ _cairo_gstate_show_text (cairo_gstate_t *gstate, const unsigned char *utf8)
cairo_matrix_transform_point (&gstate->ctm, &x, &y);
}
_cairo_font_resolve_xft_font (&gstate->font, gstate, &xft_font);
status = _cairo_gstate_ensure_source (gstate);
if (status)
return status;
@ -1444,22 +1416,15 @@ _cairo_gstate_show_text (cairo_gstate_t *gstate, const unsigned char *utf8)
cairo_surface_set_matrix (gstate->source, &device_to_source);
}
/* XXX: Need to make a generic (non-Xft) backend for text. */
XftTextRenderUtf8 (gstate->surface->dpy,
gstate->operator,
gstate->source->picture,
xft_font,
gstate->surface->picture,
0, 0,
x, y,
utf8,
strlen ((char *) utf8));
status = _cairo_font_show_text (gstate->font, &gstate->ctm,
gstate->operator, gstate->source,
gstate->surface, x, y, utf8);
/* restore the matrix originally in the source surface */
if (! gstate->source_is_solid)
cairo_surface_set_matrix (gstate->source, &user_to_source);
return CAIRO_STATUS_SUCCESS;
return status;
}
cairo_status_t

View file

@ -37,35 +37,6 @@ static const XTransform CAIRO_XTRANSFORM_IDENTITY = {
}
};
#define CAIRO_SURFACE_RENDER_AT_LEAST(surface, major, minor) \
(((surface)->render_major > major) ? 1 \
: ((surface)->render_major == major) ? ((surface)->render_minor >= minor) : 0)
#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)
static IcFormat *
_create_icformat_for_visual (Visual *visual)
{
return IcFormatCreateMasks (32, 0,
visual->red_mask,
visual->green_mask,
visual->blue_mask);
}
static IcFormat *
_create_icformat_for_format (cairo_format_t format)
{
@ -87,67 +58,31 @@ _create_icformat_for_format (cairo_format_t format)
}
}
cairo_surface_t *
cairo_surface_create_for_drawable (Display *dpy,
Drawable drawable,
Visual *visual,
cairo_format_t format,
Colormap colormap)
void
_cairo_surface_init (cairo_surface_t *surface,
int width,
int height,
cairo_format_t format,
const struct cairo_surface_backend *backend)
{
cairo_surface_t *surface;
surface->width = width;
surface->height = height;
surface = malloc (sizeof (cairo_surface_t));
if (surface == NULL)
return NULL;
surface->image_data = NULL;
/* XXX: We should really get this value from somewhere like Xft.dpy */
/* Assume a default until the user lets us know otherwise */
surface->ppm = 3780;
surface->ref_count = 1;
surface->repeat = 0;
surface->dpy = dpy;
surface->image_data = NULL;
surface->icimage = NULL;
surface->type = CAIRO_SURFACE_TYPE_DRAWABLE;
surface->xtransform = CAIRO_XTRANSFORM_IDENTITY;
surface->gc = 0;
surface->drawable = drawable;
surface->owns_pixmap = 0;
surface->visual = visual;
surface->icimage = NULL;
surface->icformat = _create_icformat_for_format (format);
if (! XRenderQueryVersion (dpy, &surface->render_major, &surface->render_minor)) {
surface->render_major = -1;
surface->render_minor = -1;
}
if (visual)
surface->icformat = _create_icformat_for_visual (visual);
else
surface->icformat = _create_icformat_for_format (format);
/* XXX: I'm currently ignoring the colormap. Is that bad? */
if (CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE (surface))
surface->picture = XRenderCreatePicture (dpy, drawable,
visual ?
XRenderFindVisualFormat (dpy, visual) :
XRenderFindStandardFormat (dpy, format),
0, NULL);
else
surface->picture = 0;
surface->ximage = NULL;
/* XXX: How to get the proper width/height? Force a roundtrip? And
how can we track the width/height properly? Shall we give up on
supporting Windows and only allow drawing to pixmaps? */
surface->width = 0;
surface->height = 0;
return surface;
surface->backend = backend;
}
slim_hidden_def(cairo_surface_create_for_drawable);
static int
cairo_format_bpp (cairo_format_t format)
@ -167,6 +102,8 @@ cairo_format_bpp (cairo_format_t format)
}
}
static const struct cairo_surface_backend cairo_icimage_surface_backend;
cairo_surface_t *
cairo_surface_create_for_image (char *data,
cairo_format_t format,
@ -180,18 +117,7 @@ cairo_surface_create_for_image (char *data,
if (surface == NULL)
return NULL;
surface->icformat = _create_icformat_for_format (format);
/* Assume a default until the user lets us know otherwise */
surface->ppm = 3780;
surface->ref_count = 1;
surface->repeat = 0;
surface->dpy = NULL;
surface->image_data = NULL;
surface->width = width;
surface->height = height;
_cairo_surface_init (surface, width, height, format, &cairo_icimage_surface_backend);
surface->icimage = IcImageCreateForData ((IcBits *) data,
surface->icformat,
@ -203,19 +129,6 @@ cairo_surface_create_for_image (char *data,
return NULL;
}
surface->type = CAIRO_SURFACE_TYPE_ICIMAGE;
surface->xtransform = CAIRO_XTRANSFORM_IDENTITY;
surface->gc = 0;
surface->drawable = 0;
surface->owns_pixmap = 0;
surface->visual = NULL;
surface->render_major = -1;
surface->render_minor = -1;
surface->picture = 0;
surface->ximage = NULL;
return surface;
}
slim_hidden_def(cairo_surface_create_for_image);
@ -229,22 +142,6 @@ cairo_surface_create_similar (cairo_surface_t *other,
return cairo_surface_create_similar_solid (other, format, width, height, 0, 0, 0, 0);
}
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;
}
}
cairo_surface_t *
cairo_surface_create_similar_solid (cairo_surface_t *other,
cairo_format_t format,
@ -258,28 +155,10 @@ cairo_surface_create_similar_solid (cairo_surface_t *other,
cairo_surface_t *surface = NULL;
cairo_color_t color;
/* XXX: There's a pretty lame heuristic here. This assumes that
* all non-Render X servers do not support depth-32 pixmaps, (and
* that they do support depths 1, 8, and 24). Obviously, it would
* be much better to check the depths that are actually
* supported. */
if (other->dpy
&& (CAIRO_SURFACE_RENDER_HAS_COMPOSITE (other)
|| format != CAIRO_FORMAT_ARGB32)) {
Display *dpy = other->dpy;
int scr = DefaultScreen (dpy);
if (other->backend->create_similar)
surface = other->backend->create_similar (other, format, width, height);
Pixmap pix = XCreatePixmap (dpy,
DefaultRootWindow (dpy),
width, height,
_CAIRO_FORMAT_DEPTH (format));
surface = cairo_surface_create_for_drawable (dpy, pix,
NULL,
format,
DefaultColormap (dpy, scr));
surface->owns_pixmap = 1;
} else {
if (!surface) {
char *data;
int stride;
@ -325,149 +204,35 @@ cairo_surface_destroy (cairo_surface_t *surface)
if (surface->ref_count)
return;
if (surface->picture)
XRenderFreePicture (surface->dpy, surface->picture);
if (surface->owns_pixmap)
XFreePixmap (surface->dpy, surface->drawable);
if (surface->icformat)
IcFormatDestroy (surface->icformat);
if (surface->icimage)
IcImageDestroy (surface->icimage);
if (surface->backend->destroy)
surface->backend->destroy (surface);
if (surface->image_data)
free (surface->image_data);
surface->image_data = NULL;
surface->dpy = 0;
free (surface);
}
slim_hidden_def(cairo_surface_destroy);
static void
_cairo_surface_ensure_gc (cairo_surface_t *surface)
{
if (surface->gc)
return;
surface->gc = XCreateGC (surface->dpy, surface->drawable, 0, NULL);
}
static cairo_status_t
_cairo_x11_surface_put_image (cairo_surface_t *surface,
char *data,
int width,
int height,
int stride)
{
if (surface->picture) {
XImage *image;
unsigned bitmap_pad;
/* XXX: This is obviously bogus. depth needs to be figured out for real */
int depth = 32;
if (depth > 16)
bitmap_pad = 32;
else if (depth > 8)
bitmap_pad = 16;
else
bitmap_pad = 8;
image = XCreateImage(surface->dpy,
DefaultVisual(surface->dpy, DefaultScreen(surface->dpy)),
depth, ZPixmap, 0,
data, width, height,
bitmap_pad,
stride);
if (image == NULL)
return CAIRO_STATUS_NO_MEMORY;
_cairo_surface_ensure_gc (surface);
XPutImage(surface->dpy, surface->drawable, surface->gc,
image, 0, 0, 0, 0, width, height);
/* Foolish XDestroyImage thinks it can free my data, but I won't
stand for it. */
image->data = NULL;
XDestroyImage(image);
} else {
/* XXX: Need to implement the IcImage method of setting a picture. memcpy? */
}
return CAIRO_STATUS_SUCCESS;
}
void
_cairo_surface_pull_image (cairo_surface_t *surface)
{
Window root_ignore;
int x_ignore, y_ignore, bwidth_ignore, depth_ignore;
if (surface == NULL)
return;
if (surface->type == CAIRO_SURFACE_TYPE_ICIMAGE)
return;
if (surface->icimage) {
IcImageDestroy (surface->icimage);
surface->icimage = NULL;
}
XGetGeometry(surface->dpy,
surface->drawable,
&root_ignore, &x_ignore, &y_ignore,
&surface->width, &surface->height,
&bwidth_ignore, &depth_ignore);
surface->ximage = XGetImage (surface->dpy,
surface->drawable,
0, 0,
surface->width, surface->height,
AllPlanes, ZPixmap);
surface->icimage = IcImageCreateForData ((IcBits *)(surface->ximage->data),
surface->icformat,
surface->ximage->width,
surface->ximage->height,
surface->ximage->bits_per_pixel,
surface->ximage->bytes_per_line);
IcImageSetRepeat (surface->icimage, surface->repeat);
/* XXX: Evil cast here... */
IcImageSetTransform (surface->icimage, (IcTransform *) &(surface->xtransform));
/* XXX: Add support here for pictures with external alpha. */
if (surface->backend->pull_image)
surface->backend->pull_image (surface);
}
void
_cairo_surface_push_image (cairo_surface_t *surface)
{
if (surface == NULL)
return;
if (surface->type == CAIRO_SURFACE_TYPE_ICIMAGE)
return;
if (surface->ximage == NULL)
return;
_cairo_surface_ensure_gc (surface);
XPutImage (surface->dpy,
surface->drawable,
surface->gc,
surface->ximage,
0, 0,
0, 0,
surface->width,
surface->height);
XDestroyImage(surface->ximage);
surface->ximage = NULL;
if (surface->backend->push_image)
surface->backend->push_image (surface);
}
/* XXX: We may want to move to projective matrices at some point. If
@ -476,6 +241,7 @@ _cairo_surface_push_image (cairo_surface_t *surface)
cairo_status_t
cairo_surface_set_matrix (cairo_surface_t *surface, cairo_matrix_t *matrix)
{
cairo_status_t ret = CAIRO_STATUS_SUCCESS;
XTransform *xtransform = &surface->xtransform;
xtransform->matrix[0][0] = XDoubleToFixed (matrix->m[0][0]);
@ -490,19 +256,15 @@ cairo_surface_set_matrix (cairo_surface_t *surface, cairo_matrix_t *matrix)
xtransform->matrix[2][1] = 0;
xtransform->matrix[2][2] = XDoubleToFixed (1);
if (surface->picture) {
if (CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM (surface))
XRenderSetPictureTransform (surface->dpy, surface->picture, xtransform);
/* XXX: Need support here if using an old RENDER without support
for SetPictureTransform */
}
if (surface->backend->set_matrix)
ret = surface->backend->set_matrix (surface);
/* XXX: This cast should only occur with a #define hint from libic that it is OK */
if (surface->icimage) {
IcImageSetTransform (surface->icimage, (IcTransform *) xtransform);
}
return CAIRO_STATUS_SUCCESS;
return ret;
}
slim_hidden_def(cairo_surface_set_matrix);
@ -523,41 +285,17 @@ cairo_surface_get_matrix (cairo_surface_t *surface, cairo_matrix_t *matrix)
}
slim_hidden_def(cairo_surface_get_matrix);
/* XXX: The Render specification has capitalized versions of these
strings. However, the current implementation is case-sensitive and
expects lowercase versions. */
static char *
_render_filter_name (cairo_filter_t filter)
{
switch (filter) {
case CAIRO_FILTER_FAST:
return "fast";
case CAIRO_FILTER_GOOD:
return "good";
case CAIRO_FILTER_BEST:
return "best";
case CAIRO_FILTER_NEAREST:
return "nearest";
case CAIRO_FILTER_BILINEAR:
return "bilinear";
default:
return "best";
}
}
cairo_status_t
cairo_surface_set_filter (cairo_surface_t *surface, cairo_filter_t filter)
{
if (surface->picture) {
XRenderSetPictureFilter (surface->dpy, surface->picture,
_render_filter_name (filter), NULL, 0);
}
if (surface->icimage) {
IcImageSetFilter (surface->icimage, filter);
}
return CAIRO_STATUS_SUCCESS;
if (!surface->backend->set_filter)
return CAIRO_STATUS_SUCCESS;
return surface->backend->set_filter (surface, filter);
}
/* XXX: NYI
@ -580,21 +318,14 @@ cairo_surface_set_repeat (cairo_surface_t *surface, int repeat)
{
surface->repeat = repeat;
if (surface->picture) {
unsigned long mask;
XRenderPictureAttributes pa;
mask = CPRepeat;
pa.repeat = repeat;
XRenderChangePicture (surface->dpy, surface->picture, mask, &pa);
}
if (surface->icimage) {
IcImageSetRepeat (surface->icimage, repeat);
}
return CAIRO_STATUS_SUCCESS;
if (!surface->backend->set_repeat)
return CAIRO_STATUS_SUCCESS;
return surface->backend->set_repeat (surface, repeat);
}
slim_hidden_def(cairo_surface_set_repeat);
@ -612,58 +343,25 @@ _cairo_surface_composite (cairo_operator_t operator,
unsigned int width,
unsigned int height)
{
if (dst->type == CAIRO_SURFACE_TYPE_DRAWABLE
&& CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst)
&& (mask == NULL || mask->dpy == dst->dpy)
&& (src->type == CAIRO_SURFACE_TYPE_ICIMAGE || src->dpy == dst->dpy)) {
if (dst->backend->composite
&& (dst->backend->composite (operator, src, mask, dst, src_x, src_y, mask_x, mask_y, dst_x, dst_y, width, height) >= 0))
return;
cairo_surface_t *src_on_server = NULL;
_cairo_surface_pull_image (src);
if (mask)
_cairo_surface_pull_image (mask);
_cairo_surface_pull_image (dst);
if (src->type == CAIRO_SURFACE_TYPE_ICIMAGE) {
cairo_matrix_t matrix;
src_on_server = cairo_surface_create_similar (dst, CAIRO_FORMAT_ARGB32,
IcImageGetWidth (src->icimage),
IcImageGetHeight (src->icimage));
if (src_on_server == NULL)
return;
IcComposite (operator,
src->icimage,
mask ? mask->icimage : NULL,
dst->icimage,
src_x, src_y,
mask_x, mask_y,
dst_x, dst_y,
width, height);
cairo_surface_get_matrix (src, &matrix);
cairo_surface_set_matrix (src_on_server, &matrix);
_cairo_x11_surface_put_image (src_on_server,
(char *) IcImageGetData (src->icimage),
IcImageGetWidth (src->icimage),
IcImageGetHeight (src->icimage),
IcImageGetStride (src->icimage));
}
XRenderComposite (dst->dpy, operator,
src_on_server ? src_on_server->picture : src->picture,
mask ? mask->picture : 0,
dst->picture,
src_x, src_y,
mask_x, mask_y,
dst_x, dst_y,
width, height);
} else {
_cairo_surface_pull_image (src);
if (mask)
_cairo_surface_pull_image (mask);
_cairo_surface_pull_image (dst);
IcComposite (operator,
src->icimage,
mask ? mask->icimage : NULL,
dst->icimage,
src_x, src_y,
mask_x, mask_y,
dst_x, dst_y,
width, height);
_cairo_surface_push_image (dst);
}
_cairo_surface_push_image (dst);
}
void
@ -692,38 +390,27 @@ _cairo_surface_fill_rectangles (cairo_surface_t *surface,
cairo_rectangle_t *rects,
int num_rects)
{
IcColor ic_color;
if (num_rects == 0)
return;
if (surface->type == CAIRO_SURFACE_TYPE_DRAWABLE
&& CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLE (surface)) {
if (surface->backend->fill_rectangles
&& (surface->backend->fill_rectangles (surface, operator, color, rects, num_rects) >= 0))
return;
XRenderColor render_color;
render_color.red = color->red_short;
render_color.green = color->green_short;
render_color.blue = color->blue_short;
render_color.alpha = color->alpha_short;
ic_color.red = color->red_short;
ic_color.green = color->green_short;
ic_color.blue = color->blue_short;
ic_color.alpha = color->alpha_short;
/* XXX: This XRectangle cast is evil... it needs to go away somehow. */
XRenderFillRectangles (surface->dpy, operator, surface->picture,
&render_color, (XRectangle *) rects, num_rects);
_cairo_surface_pull_image (surface);
} else {
IcColor ic_color;
/* XXX: The IcRectangle cast is evil... it needs to go away somehow. */
IcFillRectangles (operator, surface->icimage,
&ic_color, (IcRectangle *) rects, num_rects);
ic_color.red = color->red_short;
ic_color.green = color->green_short;
ic_color.blue = color->blue_short;
ic_color.alpha = color->alpha_short;
_cairo_surface_pull_image (surface);
/* XXX: The IcRectangle cast is evil... it needs to go away somehow. */
IcFillRectangles (operator, surface->icimage,
&ic_color, (IcRectangle *) rects, num_rects);
_cairo_surface_push_image (surface);
}
_cairo_surface_push_image (surface);
}
void
@ -735,23 +422,17 @@ _cairo_surface_composite_trapezoids (cairo_operator_t operator,
cairo_trapezoid_t *traps,
int num_traps)
{
if (dst->type == CAIRO_SURFACE_TYPE_DRAWABLE
&& CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS (dst)
&& src->dpy == dst->dpy) {
if (dst->backend->composite_trapezoids
&& (dst->backend->composite_trapezoids (operator, src, dst, xSrc, ySrc, traps, num_traps) >= 0))
return;
/* XXX: The XTrapezoid cast is evil and needs to go away somehow. */
XRenderCompositeTrapezoids (dst->dpy, operator, src->picture, dst->picture,
XRenderFindStandardFormat (dst->dpy, PictStandardA8),
xSrc, ySrc, (XTrapezoid *) traps, num_traps);
} else {
_cairo_surface_pull_image (src);
_cairo_surface_pull_image (dst);
_cairo_surface_pull_image (src);
_cairo_surface_pull_image (dst);
/* XXX: The IcTrapezoid cast is evil and needs to go away somehow. */
IcCompositeTrapezoids (operator, src->icimage, dst->icimage,
xSrc, ySrc, (IcTrapezoid *) traps, num_traps);
/* XXX: The IcTrapezoid cast is evil and needs to go away somehow. */
IcCompositeTrapezoids (operator, src->icimage, dst->icimage,
xSrc, ySrc, (IcTrapezoid *) traps, num_traps);
_cairo_surface_push_image (dst);
}
_cairo_surface_push_image (dst);
}

719
src/cairo_xlib_surface.c Normal file
View file

@ -0,0 +1,719 @@
/*
* Copyright © 2002 USC, Information Sciences Institute
*
* 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 the
* University of Southern California not be used in advertising or
* publicity pertaining to distribution of the software without
* specific, written prior permission. The University of Southern
* California makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without express
* or implied warranty.
*
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
* SOUTHERN CALIFORNIA 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: Carl D. Worth <cworth@isi.edu>
*/
#include <X11/Xft/Xft.h>
#include "cairoint.h"
#include "cairo-xlib.h"
#include <X11/Xlibint.h>
static cairo_font_t *
_cairo_xlib_font_create (Display *dpy);
void
cairo_set_target_drawable (cairo_t *cr,
Display *dpy,
Drawable drawable)
{
cairo_surface_t *surface;
if (cr->status && cr->status != CAIRO_STATUS_NO_TARGET_SURFACE)
return;
surface = cairo_xlib_surface_create (dpy, drawable,
DefaultVisual (dpy, DefaultScreen (dpy)),
0,
DefaultColormap (dpy, DefaultScreen (dpy)));
if (surface == NULL) {
cr->status = CAIRO_STATUS_NO_MEMORY;
return;
}
cairo_set_target_surface (cr, surface);
cr->gstate->font = _cairo_xlib_font_create (dpy);
cairo_surface_destroy (surface);
}
typedef struct cairo_xlib_surface {
cairo_surface_t base;
Display *dpy;
GC gc;
Drawable drawable;
int owns_pixmap;
Visual *visual;
int render_major;
int render_minor;
Picture picture;
XImage *ximage;
} cairo_xlib_surface;
#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)
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_xlib_surface *
_cairo_xlib_surface_create_similar (cairo_xlib_surface *other,
cairo_format_t format,
int width,
int height)
{
Display *dpy = other->dpy;
int scr;
Pixmap pix;
cairo_xlib_surface *surface;
/* XXX: There's a pretty lame heuristic here. This assumes that
* all non-Render X servers do not support depth-32 pixmaps, (and
* that they do support depths 1, 8, and 24). Obviously, it would
* be much better to check the depths that are actually
* supported. */
if (!dpy
|| (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (other)
&& format == CAIRO_FORMAT_ARGB32))
return 0;
scr = DefaultScreen (dpy);
pix = XCreatePixmap (dpy, DefaultRootWindow (dpy),
width, height,
_CAIRO_FORMAT_DEPTH (format));
surface = (cairo_xlib_surface *)
cairo_xlib_surface_create (dpy, pix, NULL, format, DefaultColormap (dpy, scr));
surface->owns_pixmap = 1;
return surface;
}
static void
_cairo_xlib_surface_destroy (cairo_xlib_surface *surface)
{
if (surface->picture)
XRenderFreePicture (surface->dpy, surface->picture);
if (surface->owns_pixmap)
XFreePixmap (surface->dpy, surface->drawable);
surface->dpy = 0;
}
static void
_cairo_xlib_surface_pull_image (cairo_xlib_surface *surface)
{
Window root_ignore;
int x_ignore, y_ignore, bwidth_ignore, depth_ignore;
if (surface == NULL)
return;
if (surface->base.icimage) {
IcImageDestroy (surface->base.icimage);
surface->base.icimage = NULL;
}
XGetGeometry(surface->dpy,
surface->drawable,
&root_ignore, &x_ignore, &y_ignore,
&surface->base.width, &surface->base.height,
&bwidth_ignore, &depth_ignore);
surface->ximage = XGetImage (surface->dpy,
surface->drawable,
0, 0,
surface->base.width, surface->base.height,
AllPlanes, ZPixmap);
surface->base.icimage = IcImageCreateForData ((IcBits *)(surface->ximage->data),
surface->base.icformat,
surface->ximage->width,
surface->ximage->height,
surface->ximage->bits_per_pixel,
surface->ximage->bytes_per_line);
IcImageSetRepeat (surface->base.icimage, surface->base.repeat);
/* XXX: Evil cast here... */
IcImageSetTransform (surface->base.icimage, (IcTransform *) &(surface->base.xtransform));
/* XXX: Add support here for pictures with external alpha. */
}
static void
_cairo_xlib_surface_ensure_gc (cairo_xlib_surface *surface)
{
if (surface->gc)
return;
surface->gc = XCreateGC (surface->dpy, surface->drawable, 0, NULL);
}
static void
_cairo_xlib_surface_push_image (cairo_xlib_surface *surface)
{
if (surface == NULL)
return;
if (surface->ximage == NULL)
return;
_cairo_xlib_surface_ensure_gc (surface);
XPutImage (surface->dpy,
surface->drawable,
surface->gc,
surface->ximage,
0, 0,
0, 0,
surface->base.width,
surface->base.height);
XDestroyImage(surface->ximage);
surface->ximage = NULL;
}
static cairo_status_t
_cairo_xlib_surface_set_matrix (cairo_xlib_surface *surface)
{
if (!surface->picture)
return CAIRO_STATUS_SUCCESS;
if (CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM (surface))
{
XRenderSetPictureTransform (surface->dpy, surface->picture, &surface->base.xtransform);
} else {
/* XXX: Need support here if using an old RENDER without support
for SetPictureTransform */
}
return CAIRO_STATUS_SUCCESS;
}
/* XXX: The Render specification has capitalized versions of these
strings. However, the current implementation is case-sensitive and
expects lowercase versions. */
static char *
_render_filter_name (cairo_filter_t filter)
{
switch (filter) {
case CAIRO_FILTER_FAST:
return "fast";
case CAIRO_FILTER_GOOD:
return "good";
case CAIRO_FILTER_BEST:
return "best";
case CAIRO_FILTER_NEAREST:
return "nearest";
case CAIRO_FILTER_BILINEAR:
return "bilinear";
default:
return "best";
}
}
static cairo_status_t
_cairo_xlib_surface_set_filter (cairo_xlib_surface *surface, cairo_filter_t filter)
{
if (!surface->picture)
return CAIRO_STATUS_SUCCESS;
XRenderSetPictureFilter (surface->dpy, surface->picture,
_render_filter_name (filter), NULL, 0);
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_xlib_surface_set_repeat (cairo_xlib_surface *surface, int repeat)
{
unsigned long mask;
XRenderPictureAttributes pa;
if (!surface->picture)
return CAIRO_STATUS_SUCCESS;
mask = CPRepeat;
pa.repeat = repeat;
XRenderChangePicture (surface->dpy, surface->picture, mask, &pa);
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_xlib_surface_put_image (cairo_xlib_surface *surface,
char *data,
int width,
int height,
int stride)
{
XImage *image;
unsigned bitmap_pad;
if (!surface->picture)
return CAIRO_STATUS_SUCCESS;
/* XXX: This is obviously bogus. depth needs to be figured out for real */
int depth = 32;
if (depth > 16)
bitmap_pad = 32;
else if (depth > 8)
bitmap_pad = 16;
else
bitmap_pad = 8;
image = XCreateImage(surface->dpy,
DefaultVisual(surface->dpy, DefaultScreen(surface->dpy)),
depth, ZPixmap, 0,
data, width, height,
bitmap_pad,
stride);
if (image == NULL)
return CAIRO_STATUS_NO_MEMORY;
_cairo_xlib_surface_ensure_gc (surface);
XPutImage(surface->dpy, surface->drawable, surface->gc,
image, 0, 0, 0, 0, width, height);
/* Foolish XDestroyImage thinks it can free my data, but I won't
stand for it. */
image->data = NULL;
XDestroyImage(image);
return CAIRO_STATUS_SUCCESS;
}
static cairo_xlib_surface *
_cairo_xlib_surface_clone_from (cairo_surface_t *src, cairo_xlib_surface *tmpl)
{
cairo_matrix_t matrix;
cairo_xlib_surface *src_on_server;
_cairo_surface_pull_image (src);
src_on_server = _cairo_xlib_surface_create_similar (tmpl, CAIRO_FORMAT_ARGB32,
IcImageGetWidth (src->icimage),
IcImageGetHeight (src->icimage));
if (src_on_server == NULL)
return NULL;
cairo_surface_get_matrix (src, &matrix);
cairo_surface_set_matrix (&src_on_server->base, &matrix);
_cairo_xlib_surface_put_image (src_on_server,
(char *) IcImageGetData (src->icimage),
IcImageGetWidth (src->icimage),
IcImageGetHeight (src->icimage),
IcImageGetStride (src->icimage));
return src_on_server;
}
static int
_cairo_xlib_surface_composite (cairo_operator_t operator,
cairo_xlib_surface *src,
cairo_xlib_surface *mask,
cairo_xlib_surface *dst,
int src_x,
int src_y,
int mask_x,
int mask_y,
int dst_x,
int dst_y,
unsigned int width,
unsigned int height)
{
if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst))
return -1;
if (src->base.backend != dst->base.backend || src->dpy != dst->dpy) {
src = _cairo_xlib_surface_clone_from (&src->base, dst);
if (!src)
return -1;
}
if (mask && (mask->base.backend != dst->base.backend || mask->dpy != dst->dpy)) {
mask = _cairo_xlib_surface_clone_from (&mask->base, dst);
if (!mask)
return -1;
}
XRenderComposite (dst->dpy, operator,
src->picture,
mask ? mask->picture : 0,
dst->picture,
src_x, src_y,
mask_x, mask_y,
dst_x, dst_y,
width, height);
return 0;
}
static int
_cairo_xlib_surface_fill_rectangles (cairo_xlib_surface *surface,
cairo_operator_t operator,
const cairo_color_t *color,
cairo_rectangle_t *rects,
int num_rects)
{
XRenderColor render_color;
if (!CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLE (surface))
return -1;
render_color.red = color->red_short;
render_color.green = color->green_short;
render_color.blue = color->blue_short;
render_color.alpha = color->alpha_short;
/* XXX: This XRectangle cast is evil... it needs to go away somehow. */
XRenderFillRectangles (surface->dpy, operator, surface->picture,
&render_color, (XRectangle *) rects, num_rects);
return 0;
}
static int
_cairo_xlib_surface_composite_trapezoids (cairo_operator_t operator,
cairo_xlib_surface *src,
cairo_xlib_surface *dst,
int xSrc,
int ySrc,
cairo_trapezoid_t *traps,
int num_traps)
{
if (!CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS (dst))
return -1;
if (src->base.backend != dst->base.backend || src->dpy != dst->dpy) {
src = _cairo_xlib_surface_clone_from (&src->base, dst);
if (!src)
return -1;
}
/* XXX: The XTrapezoid cast is evil and needs to go away somehow. */
XRenderCompositeTrapezoids (dst->dpy, operator, src->picture, dst->picture,
XRenderFindStandardFormat (dst->dpy, PictStandardA8),
xSrc, ySrc, (XTrapezoid *) traps, num_traps);
return 0;
}
static const struct cairo_surface_backend cairo_xlib_surface_backend = {
create_similar: (void *) _cairo_xlib_surface_create_similar,
destroy: (void *) _cairo_xlib_surface_destroy,
pull_image: (void *) _cairo_xlib_surface_pull_image,
push_image: (void *) _cairo_xlib_surface_push_image,
set_matrix: (void *) _cairo_xlib_surface_set_matrix,
set_filter: (void *) _cairo_xlib_surface_set_filter,
set_repeat: (void *) _cairo_xlib_surface_set_repeat,
composite: (void *) _cairo_xlib_surface_composite,
fill_rectangles: (void *) _cairo_xlib_surface_fill_rectangles,
composite_trapezoids: (void *) _cairo_xlib_surface_composite_trapezoids,
};
Picture
_cairo_xlib_surface_get_picture (cairo_surface_t *surface)
{
if (surface->backend != &cairo_xlib_surface_backend)
return 0;
return ((cairo_xlib_surface *) surface)->picture;
}
cairo_surface_t *
cairo_xlib_surface_create (Display *dpy,
Drawable drawable,
Visual *visual,
cairo_format_t format,
Colormap colormap)
{
cairo_xlib_surface *surface;
surface = malloc (sizeof (cairo_xlib_surface));
if (surface == NULL)
return NULL;
/* XXX: How to get the proper width/height? Force a roundtrip? And
how can we track the width/height properly? Shall we give up on
supporting Windows and only allow drawing to pixmaps? */
_cairo_surface_init (&surface->base, 0, 0, format, &cairo_xlib_surface_backend);
if (visual) {
if (surface->base.icformat)
IcFormatDestroy (surface->base.icformat);
surface->base.icformat = IcFormatCreateMasks (32, 0,
visual->red_mask,
visual->green_mask,
visual->blue_mask);
}
surface->dpy = dpy;
surface->gc = 0;
surface->drawable = drawable;
surface->owns_pixmap = 0;
surface->visual = visual;
if (! XRenderQueryVersion (dpy, &surface->render_major, &surface->render_minor)) {
surface->render_major = -1;
surface->render_minor = -1;
}
/* XXX: I'm currently ignoring the colormap. Is that bad? */
if (CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE (surface))
surface->picture = XRenderCreatePicture (dpy, drawable,
visual ?
XRenderFindVisualFormat (dpy, visual) :
XRenderFindStandardFormat (dpy, format),
0, NULL);
else
surface->picture = 0;
surface->ximage = NULL;
return (cairo_surface_t *) surface;
}
DEPRECATE (cairo_surface_create_for_drawable, cairo_xlib_surface_create);
typedef struct cairo_xlib_font {
cairo_font_t base;
Display *dpy;
XftFont *xft_font;
} cairo_xlib_font_t;
static cairo_font_t *
_cairo_xlib_font_copy (cairo_xlib_font_t *other)
{
cairo_xlib_font_t *font;
font = malloc (sizeof (cairo_xlib_font_t));
if (!font)
return 0;
if (_cairo_font_init_copy (&font->base, &other->base))
goto abort;
font->dpy = other->dpy;
if (other->xft_font) {
font->xft_font = XftFontCopy (other->dpy, other->xft_font);
if (font->xft_font == NULL)
goto abort;
} else
font->xft_font = NULL;
return &font->base;
abort:
_cairo_font_fini (&font->base);
return 0;
}
static void
_cairo_xlib_font_close (cairo_xlib_font_t *font)
{
if (font->xft_font)
XftFontClose (font->dpy, font->xft_font);
font->xft_font = NULL;
}
static cairo_status_t
_cairo_xlib_font_resolve (cairo_xlib_font_t *font, cairo_matrix_t *ctm)
{
FcPattern *pattern;
FcPattern *match;
FcResult result;
cairo_matrix_t matrix;
FcMatrix fc_matrix;
double expansion;
double font_size;
if (font->xft_font)
return CAIRO_STATUS_SUCCESS;
pattern = FcNameParse (font->base.key);
matrix = *ctm;
cairo_matrix_multiply (&matrix, &font->base.matrix, &matrix);
/* Pull the scale factor out of the final matrix and use it to set
the direct pixelsize of the font. This enables freetype to
perform proper hinting at any size. */
/* XXX: The determinant gives an area expansion factor, so the
math below should be correct for the (common) case of uniform
X/Y scaling. Is there anything different we would want to do
for non-uniform X/Y scaling?
XXX: Actually, the reasoning above is bogus. A transformation
such as scale (N, 1/N) will give an expansion_factor of 1. So,
with the code below we'll end up with font_size == 1 instead of
N, (so the hinting will be all wrong). I think we want to use
the maximum eigen value rather than the square root of the
determinant. */
_cairo_matrix_compute_determinant (&matrix, &expansion);
font_size = sqrt (fabs (expansion));
FcPatternAddDouble (pattern, "pixelsize", font_size);
cairo_matrix_scale (&matrix, 1.0 / font_size, 1.0 / font_size);
fc_matrix.xx = matrix.m[0][0];
fc_matrix.xy = matrix.m[0][1];
fc_matrix.yx = matrix.m[1][0];
fc_matrix.yy = matrix.m[1][1];
FcPatternAddMatrix (pattern, "matrix", &fc_matrix);
match = XftFontMatch (font->dpy, DefaultScreen (font->dpy), pattern, &result);
if (!match)
return 0;
font->xft_font = XftFontOpenPattern (font->dpy, match);
FcPatternDestroy (pattern);
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_xlib_font_text_extents (cairo_xlib_font_t *font,
cairo_matrix_t *ctm,
const unsigned char *utf8,
double *x, double *y,
double *width, double *height,
double *dx, double *dy)
{
XGlyphInfo extents;
_cairo_xlib_font_resolve (font, ctm);
XftTextExtentsUtf8 (font->dpy,
font->xft_font,
utf8,
strlen ((char *) utf8),
&extents);
/* XXX: What are the semantics of XftTextExtents? Specifically,
what does it do with x/y? I think we actually need to use the
gstate's current point in here somewhere. */
*x = extents.x;
*y = extents.y;
*width = extents.width;
*height = extents.height;
*dx = extents.xOff;
*dy = extents.yOff;
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_xlib_font_show_text (cairo_xlib_font_t *font,
cairo_matrix_t *ctm,
cairo_operator_t operator,
cairo_surface_t *source,
cairo_surface_t *surface,
double x,
double y,
const unsigned char *utf8)
{
Picture source_picture, surface_picture;
_cairo_xlib_font_resolve (font, ctm);
source_picture = _cairo_xlib_surface_get_picture (source);
surface_picture = _cairo_xlib_surface_get_picture (surface);
XftTextRenderUtf8 (font->dpy,
operator,
source_picture,
font->xft_font,
surface_picture,
0, 0,
x, y,
utf8,
strlen ((char *) utf8));
return CAIRO_STATUS_SUCCESS;
}
static const struct cairo_font_backend cairo_xlib_font_backend = {
copy: (void *) _cairo_xlib_font_copy,
close: (void *) _cairo_xlib_font_close,
text_extents: (void *) _cairo_xlib_font_text_extents,
show_text: (void *) _cairo_xlib_font_show_text,
};
static cairo_font_t *
_cairo_xlib_font_create (Display *dpy)
{
cairo_xlib_font_t *font;
font = malloc (sizeof (cairo_xlib_font_t));
if (!font)
return 0;
_cairo_font_init (&font->base, &cairo_xlib_font_backend);
font->dpy = dpy;
font->xft_font = NULL;
return &font->base;
}

View file

@ -37,10 +37,9 @@
#define _CAIROINT_H_
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <X11/Xlibint.h>
#include <X11/Xft/Xft.h>
#include "cairo.h"
@ -226,10 +225,44 @@ typedef struct cairo_pen {
cairo_pen_vertex_t *vertex;
} cairo_pen_t;
typedef enum cairo_surface_type {
CAIRO_SURFACE_TYPE_DRAWABLE,
CAIRO_SURFACE_TYPE_ICIMAGE
} cairo_surface_type_t;
typedef struct cairo_color cairo_color_t;
struct cairo_surface_backend {
cairo_surface_t *(*create_similar) (cairo_surface_t *surface,
cairo_format_t format,
int width,
int height);
void (*destroy) (cairo_surface_t *surface);
void (*pull_image) (cairo_surface_t *surface);
void (*push_image) (cairo_surface_t *surface);
cairo_status_t (*set_matrix) (cairo_surface_t *surface);
cairo_status_t (*set_filter) (cairo_surface_t *surface, cairo_filter_t filter);
cairo_status_t (*set_repeat) (cairo_surface_t *surface, int repeat);
int (*composite) (cairo_operator_t operator,
cairo_surface_t *src,
cairo_surface_t *mask,
cairo_surface_t *dst,
int src_x,
int src_y,
int mask_x,
int mask_y,
int dst_x,
int dst_y,
unsigned int width,
unsigned int height);
int (*fill_rectangles) (cairo_surface_t *surface,
cairo_operator_t operator,
const cairo_color_t *color,
cairo_rectangle_t *rects,
int num_rects);
int (*composite_trapezoids) (cairo_operator_t operator,
cairo_surface_t *src,
cairo_surface_t *dst,
int xSrc,
int ySrc,
cairo_trapezoid_t *traps,
int num_traps);
};
struct cairo_surface {
int width;
@ -241,25 +274,12 @@ struct cairo_surface {
unsigned int ref_count;
int repeat;
cairo_surface_type_t type;
XTransform xtransform;
/* For TYPE_DRAWABLE */
Display *dpy;
GC gc;
Drawable drawable;
Visual *visual;
int owns_pixmap;
int render_major;
int render_minor;
Picture picture;
XImage *ximage;
/* For TYPE_ICIMAGE */
IcImage *icimage;
IcFormat *icformat;
const struct cairo_surface_backend *backend;
};
/* XXX: Right now, the cairo_color structure puts unpremultiplied
@ -268,7 +288,7 @@ struct cairo_surface {
madness). I'm still working on a cleaner API, but in the meantime,
at least this does prevent precision loss in color when changing
alpha. */
typedef struct cairo_color {
struct cairo_color {
double red;
double green;
double blue;
@ -278,7 +298,7 @@ typedef struct cairo_color {
unsigned short green_short;
unsigned short blue_short;
unsigned short alpha_short;
} cairo_color_t;
};
struct cairo_matrix {
double m[3][2];
@ -290,17 +310,35 @@ typedef struct cairo_traps {
int traps_size;
} cairo_traps_t;
typedef struct cairo_font cairo_font_t;
struct cairo_font_backend {
cairo_font_t *(*copy) (cairo_font_t *other);
void (*close) (cairo_font_t *font);
cairo_status_t (*text_extents) (cairo_font_t *font,
cairo_matrix_t *ctm,
const unsigned char *utf8,
double *x, double *y,
double *width, double *height,
double *dx, double *dy);
cairo_status_t (*show_text) (cairo_font_t *font,
cairo_matrix_t *ctm,
cairo_operator_t operator,
cairo_surface_t *source,
cairo_surface_t *surface,
double x,
double y,
const unsigned char *utf8);
};
#define CAIRO_FONT_KEY_DEFAULT "serif"
typedef struct cairo_font {
struct cairo_font {
unsigned char *key;
double scale;
cairo_matrix_t matrix;
Display *dpy;
XftFont *xft_font;
} cairo_font_t;
const struct cairo_font_backend *backend;
};
#define CAIRO_GSTATE_OPERATOR_DEFAULT CAIRO_OPERATOR_OVER
#define CAIRO_GSTATE_TOLERANCE_DEFAULT 0.1
@ -336,7 +374,7 @@ typedef struct cairo_gstate {
int num_dashes;
double dash_offset;
cairo_font_t font;
cairo_font_t *font;
cairo_surface_t *surface;
@ -636,11 +674,14 @@ _cairo_color_set_alpha (cairo_color_t *color, double alpha);
/* cairo_font.c */
extern void __internal_linkage
_cairo_font_init (cairo_font_t *font);
_cairo_font_init (cairo_font_t *font, const struct cairo_font_backend *backend);
extern cairo_status_t __internal_linkage
_cairo_font_init_copy (cairo_font_t *font, cairo_font_t *other);
extern cairo_font_t * __internal_linkage
_cairo_font_copy (cairo_font_t *font);
extern void __internal_linkage
_cairo_font_fini (cairo_font_t *font);
@ -656,7 +697,22 @@ _cairo_font_transform (cairo_font_t *font,
double c, double d);
extern cairo_status_t __internal_linkage
_cairo_font_resolve_xft_font (cairo_font_t *font, cairo_gstate_t *gstate, XftFont **xft_font);
_cairo_font_text_extents (cairo_font_t *font,
cairo_matrix_t *ctm,
const unsigned char *utf8,
double *x, double *y,
double *width, double *height,
double *dx, double *dy);
extern cairo_status_t __internal_linkage
_cairo_font_show_text (cairo_font_t *font,
cairo_matrix_t *ctm,
cairo_operator_t operator,
cairo_surface_t *source,
cairo_surface_t *surface,
double x,
double y,
const unsigned char *utf8);
/* cairo_path.c */
extern void __internal_linkage
@ -701,6 +757,13 @@ extern cairo_status_t __internal_linkage
_cairo_path_stroke_to_traps (cairo_path_t *path, cairo_gstate_t *gstate, cairo_traps_t *traps);
/* cairo_surface.c */
extern void __internal_linkage
_cairo_surface_init (cairo_surface_t *surface,
int width,
int height,
cairo_format_t format,
const struct cairo_surface_backend *backend);
extern void __internal_linkage
_cairo_surface_fill_rectangle (cairo_surface_t *surface,
cairo_operator_t operator,
@ -889,7 +952,6 @@ slim_hidden_proto(cairo_rel_line_to)
slim_hidden_proto(cairo_restore)
slim_hidden_proto(cairo_save)
slim_hidden_proto(cairo_set_target_surface)
slim_hidden_proto(cairo_surface_create_for_drawable)
slim_hidden_proto(cairo_surface_create_for_image)
slim_hidden_proto(cairo_surface_create_similar_solid)
slim_hidden_proto(cairo_surface_destroy)