Implement native image rotation and cropping on cairo
* src/dispextern.h (struct image) [USE_CAIRO]: * src/image.c (free_image, image_clear_image_1) (image_set_crop, image_set_size, image_set_rotation) (image_create_x_image_and_pixmap) [USE_CAIRO]: #ifdef out HAVE_XRENDER part. * src/image.c (cr_create_surface_from_pix_containers) [USE_CAIRO]: Rename from cr_create_surface_from_pix_containers. Change arguments to pair of Emacs_Pix_Container:s. Move block_input and unblock_input to caller. (cr_put_image_to_cr_data) [USE_CAIRO]: New function. (prepare_image_for_display) [USE_CAIRO]: Use it. (image_set_transform) [USE_CAIRO]: Create dummy solid color pattern equipped with transformation matrix and set it to img->cr_data. * src/xterm.c (fringe_bmp) [USE_CAIRO]: Change type to cairo_pattern_t **. (x_cr_define_fringe_bitmap, x_cr_destroy_fringe_bitmap) [USE_CAIRO]: Create or destroy cairo pattern. (x_cr_draw_image) [USE_CAIRO]: Remove arguments image_width and image_height. Change type of image to cairo pattern. All callers changed. * src/gtkutil.c (xg_get_image_for_pixmap) [USE_CAIRO]: Get cairo surface from img->cr_data, which is of cairo pattern now.
This commit is contained in:
parent
890a0826f3
commit
88c49ac318
4 changed files with 73 additions and 46 deletions
|
|
@ -3016,7 +3016,7 @@ struct image
|
|||
synchronized to Pixmap. */
|
||||
XImage *ximg, *mask_img;
|
||||
|
||||
# ifdef HAVE_NATIVE_TRANSFORMS
|
||||
# if !defined USE_CAIRO && defined HAVE_XRENDER
|
||||
/* Picture versions of pixmap and mask for compositing. */
|
||||
Picture picture, mask_picture;
|
||||
# endif
|
||||
|
|
|
|||
|
|
@ -394,7 +394,10 @@ xg_get_image_for_pixmap (struct frame *f,
|
|||
certain themes. */
|
||||
|
||||
#ifdef USE_CAIRO
|
||||
surface = img->cr_data;
|
||||
if (cairo_pattern_get_type (img->cr_data) == CAIRO_PATTERN_TYPE_SURFACE)
|
||||
cairo_pattern_get_surface (img->cr_data, &surface);
|
||||
else
|
||||
surface = NULL;
|
||||
|
||||
if (surface)
|
||||
{
|
||||
|
|
|
|||
74
src/image.c
74
src/image.c
|
|
@ -207,12 +207,12 @@ image_pix_container_create_from_bitmap_data (struct frame *f,
|
|||
}
|
||||
|
||||
static cairo_surface_t *
|
||||
cr_create_cr_surface_from_image (struct frame *f, struct image *img)
|
||||
cr_create_surface_from_pix_containers (Emacs_Pix_Container pimg,
|
||||
Emacs_Pix_Container mask)
|
||||
{
|
||||
Emacs_Pix_Container pimg = img->pixmap;
|
||||
cairo_surface_t *surface;
|
||||
|
||||
if (img->mask)
|
||||
if (mask)
|
||||
{
|
||||
int x, y;
|
||||
|
||||
|
|
@ -223,30 +223,49 @@ cr_create_cr_surface_from_image (struct frame *f, struct image *img)
|
|||
int r, g, b;
|
||||
|
||||
color = GET_PIXEL (pimg, x, y);
|
||||
alpha = GET_PIXEL (img->mask, x, y);
|
||||
alpha = GET_PIXEL (mask, x, y);
|
||||
r = (RED_FROM_ULONG (color) * alpha + 0x7f) / 0xff;
|
||||
g = (GREEN_FROM_ULONG (color) * alpha + 0x7f) / 0xff;
|
||||
b = (BLUE_FROM_ULONG (color) * alpha + 0x7f) / 0xff;
|
||||
PUT_PIXEL (pimg, x, y, ARGB_TO_ULONG (alpha, r, g, b));
|
||||
}
|
||||
xfree (img->mask->data);
|
||||
img->mask->data = NULL;
|
||||
xfree (mask->data);
|
||||
mask->data = NULL;
|
||||
}
|
||||
block_input ();
|
||||
surface = cairo_image_surface_create_for_data ((unsigned char *) pimg->data,
|
||||
(img->mask
|
||||
? CAIRO_FORMAT_ARGB32
|
||||
(mask ? CAIRO_FORMAT_ARGB32
|
||||
: CAIRO_FORMAT_RGB24),
|
||||
pimg->width, pimg->height,
|
||||
pimg->bytes_per_line);
|
||||
static const cairo_user_data_key_t key;
|
||||
cairo_surface_set_user_data (surface, &key, pimg->data, xfree);
|
||||
unblock_input ();
|
||||
pimg->data = NULL;
|
||||
|
||||
return surface;
|
||||
}
|
||||
|
||||
static void
|
||||
cr_put_image_to_cr_data (struct image *img)
|
||||
{
|
||||
cairo_pattern_t *pattern = NULL;
|
||||
cairo_surface_t *surface = cr_create_surface_from_pix_containers (img->pixmap,
|
||||
img->mask);
|
||||
if (surface)
|
||||
{
|
||||
pattern = cairo_pattern_create_for_surface (surface);
|
||||
if (img->cr_data)
|
||||
{
|
||||
cairo_matrix_t matrix;
|
||||
cairo_pattern_get_matrix (img->cr_data, &matrix);
|
||||
cairo_pattern_set_matrix (pattern, &matrix);
|
||||
cairo_pattern_destroy (img->cr_data);
|
||||
}
|
||||
cairo_surface_destroy (surface);
|
||||
}
|
||||
|
||||
img->cr_data = pattern;
|
||||
}
|
||||
|
||||
#endif /* USE_CAIRO */
|
||||
|
||||
#ifdef HAVE_NS
|
||||
|
|
@ -1150,7 +1169,7 @@ free_image (struct frame *f, struct image *img)
|
|||
|
||||
c->images[img->id] = NULL;
|
||||
|
||||
#ifdef HAVE_XRENDER
|
||||
#if !defined USE_CAIRO && defined HAVE_XRENDER
|
||||
if (img->picture)
|
||||
XRenderFreePicture (FRAME_X_DISPLAY (f), img->picture);
|
||||
if (img->mask_picture)
|
||||
|
|
@ -1212,14 +1231,20 @@ prepare_image_for_display (struct frame *f, struct image *img)
|
|||
img->load_failed_p = ! img->type->load (f, img);
|
||||
|
||||
#ifdef USE_CAIRO
|
||||
if (!img->load_failed_p && img->cr_data == NULL)
|
||||
if (!img->load_failed_p)
|
||||
{
|
||||
img->cr_data = cr_create_cr_surface_from_image (f, img);
|
||||
if (img->cr_data == NULL)
|
||||
block_input ();
|
||||
if (img->cr_data == NULL || (cairo_pattern_get_type (img->cr_data)
|
||||
!= CAIRO_PATTERN_TYPE_SURFACE))
|
||||
{
|
||||
img->load_failed_p = 1;
|
||||
img->type->free (f, img);
|
||||
cr_put_image_to_cr_data (img);
|
||||
if (img->cr_data == NULL)
|
||||
{
|
||||
img->load_failed_p = 1;
|
||||
img->type->free (f, img);
|
||||
}
|
||||
}
|
||||
unblock_input ();
|
||||
}
|
||||
#elif defined HAVE_X_WINDOWS
|
||||
if (!img->load_failed_p)
|
||||
|
|
@ -1470,7 +1495,7 @@ image_clear_image_1 (struct frame *f, struct image *img, int flags)
|
|||
#ifdef USE_CAIRO
|
||||
if (img->cr_data)
|
||||
{
|
||||
cairo_surface_destroy ((cairo_surface_t *) img->cr_data);
|
||||
cairo_pattern_destroy (img->cr_data);
|
||||
img->cr_data = NULL;
|
||||
}
|
||||
#endif /* USE_CAIRO */
|
||||
|
|
@ -1973,7 +1998,7 @@ image_set_rotation (struct image *img, matrix3x3 tm)
|
|||
return;
|
||||
# endif
|
||||
|
||||
# ifdef HAVE_XRENDER
|
||||
# if !defined USE_CAIRO && defined HAVE_XRENDER
|
||||
if (!img->picture)
|
||||
return;
|
||||
# endif
|
||||
|
|
@ -2064,7 +2089,7 @@ image_set_crop (struct image *img, matrix3x3 tm)
|
|||
return;
|
||||
# endif
|
||||
|
||||
# ifdef HAVE_XRENDER
|
||||
# if !defined USE_CAIRO && defined HAVE_XRENDER
|
||||
if (!img->picture)
|
||||
return;
|
||||
# endif
|
||||
|
|
@ -2156,7 +2181,7 @@ image_set_size (struct image *img, matrix3x3 tm)
|
|||
return;
|
||||
# endif
|
||||
|
||||
# ifdef HAVE_XRENDER
|
||||
# if !defined USE_CAIRO && defined HAVE_XRENDER
|
||||
if (!img->picture)
|
||||
return;
|
||||
# endif
|
||||
|
|
@ -2186,6 +2211,13 @@ image_set_transform (struct frame *f, struct image *img, matrix3x3 matrix)
|
|||
/* Under NS the transform is applied to the drawing surface at
|
||||
drawing time, so store it for later. */
|
||||
ns_image_set_transform (img->pixmap, matrix);
|
||||
# elif defined USE_CAIRO
|
||||
cairo_matrix_t cr_matrix = {matrix[0][0], matrix[0][1], matrix[1][0],
|
||||
matrix[1][1], matrix[2][0], matrix[2][1]};
|
||||
cairo_pattern_t *pattern = cairo_pattern_create_rgb (0, 0, 0);
|
||||
cairo_pattern_set_matrix (pattern, &cr_matrix);
|
||||
/* Dummy solid color pattern just to record pattern matrix. */
|
||||
img->cr_data = pattern;
|
||||
# elif defined (HAVE_XRENDER)
|
||||
if (img->picture)
|
||||
{
|
||||
|
|
@ -2745,7 +2777,7 @@ image_create_x_image_and_pixmap (struct frame *f, struct image *img,
|
|||
eassert ((!mask_p ? img->pixmap : img->mask) == NO_PIXMAP);
|
||||
|
||||
Picture *picture = NULL;
|
||||
#ifdef HAVE_XRENDER
|
||||
#if !defined USE_CAIRO && defined HAVE_XRENDER
|
||||
picture = !mask_p ? &img->picture : &img->mask_picture;
|
||||
#endif
|
||||
return image_create_x_image_and_pixmap_1 (f, width, height, depth, ximg,
|
||||
|
|
|
|||
38
src/xterm.c
38
src/xterm.c
|
|
@ -437,13 +437,14 @@ x_set_cr_source_with_gc_background (struct frame *f, GC gc)
|
|||
/* Fringe bitmaps. */
|
||||
|
||||
static int max_fringe_bmp = 0;
|
||||
static cairo_surface_t **fringe_bmp = 0;
|
||||
static cairo_pattern_t **fringe_bmp = 0;
|
||||
|
||||
static void
|
||||
x_cr_define_fringe_bitmap (int which, unsigned short *bits, int h, int wd)
|
||||
{
|
||||
int i, stride;
|
||||
cairo_surface_t *surface;
|
||||
cairo_pattern_t *pattern;
|
||||
unsigned char *data;
|
||||
|
||||
if (which >= max_fringe_bmp)
|
||||
|
|
@ -468,10 +469,12 @@ x_cr_define_fringe_bitmap (int which, unsigned short *bits, int h, int wd)
|
|||
}
|
||||
|
||||
cairo_surface_mark_dirty (surface);
|
||||
pattern = cairo_pattern_create_for_surface (surface);
|
||||
cairo_surface_destroy (surface);
|
||||
|
||||
unblock_input ();
|
||||
|
||||
fringe_bmp[which] = surface;
|
||||
fringe_bmp[which] = pattern;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -483,15 +486,14 @@ x_cr_destroy_fringe_bitmap (int which)
|
|||
if (fringe_bmp[which])
|
||||
{
|
||||
block_input ();
|
||||
cairo_surface_destroy (fringe_bmp[which]);
|
||||
cairo_pattern_destroy (fringe_bmp[which]);
|
||||
unblock_input ();
|
||||
}
|
||||
fringe_bmp[which] = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
x_cr_draw_image (struct frame *f, GC gc, cairo_surface_t *image,
|
||||
int image_width, int image_height,
|
||||
x_cr_draw_image (struct frame *f, GC gc, cairo_pattern_t *image,
|
||||
int src_x, int src_y, int width, int height,
|
||||
int dest_x, int dest_y, bool overlay_p)
|
||||
{
|
||||
|
|
@ -506,31 +508,22 @@ x_cr_draw_image (struct frame *f, GC gc, cairo_surface_t *image,
|
|||
cairo_fill_preserve (cr);
|
||||
}
|
||||
|
||||
int orig_image_width = cairo_image_surface_get_width (image);
|
||||
if (image_width == 0) image_width = orig_image_width;
|
||||
int orig_image_height = cairo_image_surface_get_height (image);
|
||||
if (image_height == 0) image_height = orig_image_height;
|
||||
cairo_translate (cr, dest_x - src_x, dest_y - src_y);
|
||||
|
||||
cairo_pattern_t *pattern = cairo_pattern_create_for_surface (image);
|
||||
cairo_matrix_t matrix;
|
||||
cairo_matrix_init_scale (&matrix, orig_image_width / (double) image_width,
|
||||
orig_image_height / (double) image_height);
|
||||
cairo_matrix_translate (&matrix, src_x - dest_x, src_y - dest_y);
|
||||
cairo_pattern_set_matrix (pattern, &matrix);
|
||||
|
||||
cairo_format_t format = cairo_image_surface_get_format (image);
|
||||
cairo_surface_t *surface;
|
||||
cairo_pattern_get_surface (image, &surface);
|
||||
cairo_format_t format = cairo_image_surface_get_format (surface);
|
||||
if (format != CAIRO_FORMAT_A8 && format != CAIRO_FORMAT_A1)
|
||||
{
|
||||
cairo_set_source (cr, pattern);
|
||||
cairo_set_source (cr, image);
|
||||
cairo_fill (cr);
|
||||
}
|
||||
else
|
||||
{
|
||||
x_set_cr_source_with_gc_foreground (f, gc);
|
||||
cairo_clip (cr);
|
||||
cairo_mask (cr, pattern);
|
||||
cairo_mask (cr, image);
|
||||
}
|
||||
cairo_pattern_destroy (pattern);
|
||||
|
||||
x_end_cr_clip (f);
|
||||
}
|
||||
|
|
@ -1352,7 +1345,7 @@ x_draw_fringe_bitmap (struct window *w, struct glyph_row *row, struct draw_fring
|
|||
: f->output_data.x->cursor_pixel)
|
||||
: face->foreground));
|
||||
XSetBackground (display, gc, face->background);
|
||||
x_cr_draw_image (f, gc, fringe_bmp[p->which], 0, 0, 0, p->dh,
|
||||
x_cr_draw_image (f, gc, fringe_bmp[p->which], 0, p->dh,
|
||||
p->wd, p->h, p->x, p->y, p->overlay_p);
|
||||
XSetForeground (display, gc, gcv.foreground);
|
||||
XSetBackground (display, gc, gcv.background);
|
||||
|
|
@ -2929,8 +2922,7 @@ x_draw_image_foreground (struct glyph_string *s)
|
|||
if (s->img->cr_data)
|
||||
{
|
||||
x_set_glyph_string_clipping (s);
|
||||
x_cr_draw_image (s->f, s->gc,
|
||||
s->img->cr_data, s->img->width, s->img->height,
|
||||
x_cr_draw_image (s->f, s->gc, s->img->cr_data,
|
||||
s->slice.x, s->slice.y, s->slice.width, s->slice.height,
|
||||
x, y, true);
|
||||
if (!s->img->mask)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue