]> git.eshelyaron.com Git - emacs.git/commitdiff
Implement native image rotation and cropping on cairo
authorYAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp>
Sat, 8 Jun 2019 04:05:15 +0000 (13:05 +0900)
committerYAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp>
Sat, 8 Jun 2019 04:05:15 +0000 (13:05 +0900)
* 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.

src/dispextern.h
src/gtkutil.c
src/image.c
src/xterm.c

index 9ba8e746b22338c6f09b1ebad0e8d21d56639620..cc2d963a96b4fe8aeca0a342aa3039469cb73081 100644 (file)
@@ -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
index 59e4328a6fc24d16cec547337d4d707f7457e0be..dccee159254ac83904d53a1d62f4c13016b08403 100644 (file)
@@ -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)
     {
index 30f4f4b0bc58808557fa33ceb05d455c5656631a..86f8e8f4bb7387149932d67d181ddc9d2925de12 100644 (file)
@@ -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,
index c064647da0c8936d800226878ae0c501e786bac8..e0edd9c1a40a3ebbf8a5285d29932be510e080e7 100644 (file)
@@ -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_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_translate (cr, dest_x - src_x, dest_y - src_y);
 
-  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)