mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-05-01 05:37:59 +02:00
Virtualized the font and surface backend implementations.
This commit is contained in:
parent
9c964b8f8a
commit
973ee89983
15 changed files with 1871 additions and 1141 deletions
|
|
@ -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
3
TODO
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
125
src/cairo-font.c
125
src/cairo-font.c
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
719
src/cairo-xlib-surface.c
Normal 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
56
src/cairo-xlib.h
Normal 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
|
||||
24
src/cairo.c
24
src/cairo.c
|
|
@ -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,
|
||||
|
|
|
|||
17
src/cairo.h
17
src/cairo.h
|
|
@ -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,
|
||||
|
|
|
|||
125
src/cairo_font.c
125
src/cairo_font.c
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
719
src/cairo_xlib_surface.c
Normal 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;
|
||||
}
|
||||
130
src/cairoint.h
130
src/cairoint.h
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue