emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] master 610fb73: Add native image rotation and cropping


From: Alan Third
Subject: [Emacs-diffs] master 610fb73: Add native image rotation and cropping
Date: Wed, 5 Jun 2019 17:31:16 -0400 (EDT)

branch: master
commit 610fb73ab6d7a22b722f523d6ebc4aa8fa1db7c9
Author: Alan Third <address@hidden>
Commit: Alan Third <address@hidden>

    Add native image rotation and cropping
    
    * lisp/image.el (image--get-imagemagick-and-warn): Only fallback to
    ImageMagick if native transforms aren't available.
    * src/dispextern.h (INIT_MATRIX, COPY_MATRIX, MULT_MATRICES): New
    macros for matrix manipulation.
    (HAVE_NATIVE_SCALING, HAVE_NATIVE_TRANSFORMS): Rename and change all
    relevant locations.
    * src/image.c (x_set_image_rotation):
    (x_set_transform): New functions.
    (x_set_image_size): Use transform matrix for resizing under X and NS.
    (x_set_image_crop): New function.
    (lookup_image): Use the new transform functions.
    (Fimage_scaling_p, Fimage_transforms_p): Rename and update all
    callers.
    * src/nsimage.m (ns_load_image): Remove rotation code.
    (ns_image_set_transform): New function.
    ([EmacsImage dealloc]): Release the saved transform.
    ([EmacsImage rotate:]): Remove unneeded method.
    ([EmacsImage setTransform:]): New method.
    * src/nsterm.h (EmacsImage): Add transform property and update method
    definitions.
    * src/nsterm.m (ns_dumpglyphs_image): Use the transform to draw the
    image correctly.
    * src/xterm.c (x_composite_image): Use PictOpSrc as we don't care
    about alpha values here.
    * doc/lispref/display.texi (Image Descriptors): Add :rotation.
    (ImageMagick Images): Remove :rotation.
---
 doc/lispref/display.texi |  21 ++--
 etc/NEWS                 |   6 +-
 lisp/image.el            |   5 +-
 src/dispextern.h         |  22 +++-
 src/image.c              | 283 ++++++++++++++++++++++++++++++++++++++++++-----
 src/nsimage.m            |  64 +++--------
 src/nsterm.h             |   5 +-
 src/nsterm.m             |  41 ++++---
 src/xterm.c              |   5 +-
 9 files changed, 343 insertions(+), 109 deletions(-)

diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi
index 95985ea..82af02f 100644
--- a/doc/lispref/display.texi
+++ b/doc/lispref/display.texi
@@ -5181,6 +5181,9 @@ values.  If both @code{:scale} and 
@code{:height}/@code{:width} are
 specified, the height/width will be adjusted by the specified scaling
 factor.
 
address@hidden :rotation @var{angle}
+Specifies a rotation angle in degrees.
+
 @item :index @var{frame}
 @xref{Multi-Frame Images}.
 
@@ -5323,14 +5326,15 @@ This function returns @code{t} if image @var{spec} has 
a mask bitmap.
 (@pxref{Input Focus}).
 @end defun
 
address@hidden image-scaling-p &optional frame
-This function returns @code{t} if @var{frame} supports image scaling.
address@hidden @code{nil} or omitted means to use the selected frame
-(@pxref{Input Focus}).
address@hidden image-transforms-p &optional frame
+This function returns @code{t} if @var{frame} supports image scaling
+and rotation.  @var{frame} @code{nil} or omitted means to use the
+selected frame (@pxref{Input Focus}).
 
-If image scaling is not supported, @code{:width}, @code{:height},
address@hidden:scale}, @code{:max-width} and @code{:max-height} will only be
-usable through ImageMagick, if available (@pxref{ImageMagick Images}).
+If image transforms are not supported, @code{:rotation},
address@hidden:width}, @code{:height}, @code{:scale}, @code{:max-width} and
address@hidden:max-height} will only be usable through ImageMagick, if
+available (@pxref{ImageMagick Images}).
 @end defun
 
 @node XBM Images
@@ -5474,9 +5478,6 @@ The value, @var{type}, should be a symbol specifying the 
type of the
 image data, as found in @code{image-format-suffixes}.  This is used
 when the image does not have an associated file name, to provide a
 hint to ImageMagick to help it detect the image type.
-
address@hidden :rotation @var{angle}
-Specifies a rotation angle in degrees.
 @end table
 
 @node SVG Images
diff --git a/etc/NEWS b/etc/NEWS
index d123952..e47c305 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -2051,14 +2051,14 @@ buffer's 'default-directory' and invoke that file name 
handler to make
 the process.  That way 'make-process' can start remote processes.
 
 +++
-** Emacs now supports resizing (scaling) of images without ImageMagick.
+** Emacs now supports resizing and rotating images without ImageMagick.
 All modern systems are supported by this feature.  (On GNU and Unix
 systems, Cairo drawing or the XRender extension to X11 is required for
 this to be available; the configure script will test for it and, if
 found, enable scaling.)
 
-The new function 'image-scaling-p' can be used to test whether any
-given frame supports resizing.
+The new function 'image-transforms-p' can be used to test whether any
+given frame supports this capability.
 
 +++
 ** '(locale-info 'paper)' now returns the paper size on systems that support 
it.
diff --git a/lisp/image.el b/lisp/image.el
index db11302..b58b1dc 100644
--- a/lisp/image.el
+++ b/lisp/image.el
@@ -992,11 +992,12 @@ default is 20%."
     image))
 
 (defun image--get-imagemagick-and-warn ()
-  (unless (or (fboundp 'imagemagick-types) (image-scaling-p))
+  (unless (or (fboundp 'imagemagick-types) (image-transforms-p))
     (error "Cannot rescale images on this terminal"))
   (let ((image (image--get-image)))
     (image-flush image)
-    (when (fboundp 'imagemagick-types)
+    (when (and (fboundp 'imagemagick-types)
+               (not (image-transforms-p)))
       (plist-put (cdr image) :type 'imagemagick))
     image))
 
diff --git a/src/dispextern.h b/src/dispextern.h
index 70ae96b..a21edd8 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -2989,7 +2989,25 @@ struct redisplay_interface
 #ifdef HAVE_WINDOW_SYSTEM
 
 # if defined USE_CAIRO || defined HAVE_XRENDER || defined HAVE_NS || defined 
HAVE_NTGUI
-#  define HAVE_NATIVE_SCALING
+#  define HAVE_NATIVE_TRANSFORMS
+
+#  define INIT_MATRIX(m)                          \
+  for (int i = 0 ; i < 3 ; i++)                   \
+    for (int j = 0 ; j < 3 ; j++)                 \
+      m[i][j] = (i == j) ? 1 : 0;
+
+#  define COPY_MATRIX(a, b)                       \
+  for (int i = 0 ; i < 3 ; i++)                   \
+    for (int j = 0 ; j < 3 ; j++)                 \
+      b[i][j] = a[i][j];
+
+#  define MULT_MATRICES(a, b, result)             \
+  for (int i = 0 ; i < 3 ; i++)                   \
+    for (int j = 0 ; j < 3 ; j++) {               \
+      double sum = 0;                             \
+      for (int k = 0 ; k < 3 ; k++)               \
+        sum += a[k][j] * b[i][k];                 \
+      result[i][j] = sum;}
 # endif
 
 /* Structure describing an image.  Specific image formats like XBM are
@@ -3015,7 +3033,7 @@ struct image
      synchronized to Pixmap.  */
   XImage *ximg, *mask_img;
 
-# ifdef HAVE_NATIVE_SCALING
+# ifdef HAVE_NATIVE_TRANSFORMS
   /* Picture versions of pixmap and mask for compositing.  */
   Picture picture, mask_picture;
 # endif
diff --git a/src/image.c b/src/image.c
index 9b00801..a95a7bf 100644
--- a/src/image.c
+++ b/src/image.c
@@ -1841,7 +1841,7 @@ postprocess_image (struct frame *f, struct image *img)
     }
 }
 
-#if defined (HAVE_IMAGEMAGICK) || defined (HAVE_NATIVE_SCALING)
+#if defined (HAVE_IMAGEMAGICK) || defined (HAVE_NATIVE_TRANSFORMS)
 /* Scale an image size by returning SIZE / DIVISOR * MULTIPLIER,
    safely rounded and clipped to int range.  */
 
@@ -1940,49 +1940,241 @@ compute_image_size (size_t width, size_t height,
   *d_width = desired_width;
   *d_height = desired_height;
 }
-#endif /* HAVE_IMAGEMAGICK || HAVE_NATIVE_SCALING */
+#endif /* HAVE_IMAGEMAGICK || HAVE_NATIVE_TRANSFORMS */
 
 static void
-image_set_image_size (struct frame *f, struct image *img)
+image_set_rotation (struct image *img, double tm[3][3])
 {
-#ifdef HAVE_NATIVE_SCALING
+#ifdef HAVE_NATIVE_TRANSFORMS
 # ifdef HAVE_IMAGEMAGICK
-  /* ImageMagick images are already the correct size.  */
+  /* ImageMagick images are already rotated.  */
   if (EQ (image_spec_value (img->spec, QCtype, NULL), Qimagemagick))
     return;
 # endif
 
-  int width, height;
-  compute_image_size (img->width, img->height, img->spec, &width, &height);
+# ifdef HAVE_XRENDER
+  if (!img->picture)
+    return;
+# endif
+
+  Lisp_Object value;
+  double t[3][3], rot[3][3], tmp[3][3], tmp2[3][3];
+  int rotation, cos_r, sin_r, width, height;
+
+  value = image_spec_value (img->spec, QCrotation, NULL);
+  if (! NUMBERP (value))
+    return;
+
+  rotation = XFLOATINT (value);
+  rotation = rotation % 360;
+
+  if (rotation < 0)
+    rotation += 360;
+
+  if (rotation == 0)
+    return;
+
+  if (rotation == 90)
+    {
+      width = img->height;
+      height = img->width;
+
+      cos_r = 0;
+      sin_r = 1;
+    }
+  else if (rotation == 180)
+    {
+      width = img->width;
+      height = img->height;
+
+      cos_r = -1;
+      sin_r = 0;
+    }
+  else if (rotation == 270)
+    {
+      width = img->height;
+      height = img->width;
+
+      cos_r = 0;
+      sin_r = -1;
+    }
+  else
+    {
+      image_error ("Native image rotation only supports multiples of 90 
degrees");
+      return;
+    }
+
+  /* Translate so (0, 0) is in the centre of the image.  */
+  INIT_MATRIX (t);
+  t[2][0] = img->width/2;
+  t[2][1] = img->height/2;
+
+  MULT_MATRICES (tm, t, tmp);
+
+  /* Rotate.  */
+  INIT_MATRIX (rot);
+  rot[0][0] = cos_r;
+  rot[1][0] = sin_r;
+  rot[0][1] = - sin_r;
+  rot[1][1] = cos_r;
+
+  MULT_MATRICES (tmp, rot, tmp2);
+
+  /* Translate back.  */
+  INIT_MATRIX (t);
+  t[2][0] = - width/2;
+  t[2][1] = - height/2;
+
+  MULT_MATRICES (tmp2, t, tm);
 
-# ifdef HAVE_NS
-  ns_image_set_size (img->pixmap, width, height);
   img->width = width;
   img->height = height;
+#endif
+}
+
+static void
+image_set_crop (struct image *img, double tm[3][3])
+{
+#ifdef HAVE_NATIVE_TRANSFORMS
+# ifdef HAVE_IMAGEMAGICK
+  /* ImageMagick images are already cropped.  */
+  if (EQ (image_spec_value (img->spec, QCtype, NULL), Qimagemagick))
+    return;
 # endif
 
 # ifdef USE_CAIRO
   img->width = width;
   img->height = height;
 # elif defined HAVE_XRENDER
-  if (img->picture)
+  if (!img->picture)
+    return;
+# endif
+
+  double m[3][3], tmp[3][3];
+  int left, top, width, height;
+  Lisp_Object x = Qnil;
+  Lisp_Object y = Qnil;
+  Lisp_Object w = Qnil;
+  Lisp_Object h = Qnil;
+  Lisp_Object crop = image_spec_value (img->spec, QCcrop, NULL);
+
+  if (!CONSP (crop))
+    return;
+  else
     {
-      double xscale = img->width / (double) width;
-      double yscale = img->height / (double) height;
+      w = XCAR (crop);
+      crop = XCDR (crop);
+      if (CONSP (crop))
+       {
+          h = XCAR (crop);
+         crop = XCDR (crop);
+         if (CONSP (crop))
+           {
+              x = XCAR (crop);
+             crop = XCDR (crop);
+             if (CONSP (crop))
+                y = XCAR (crop);
+           }
+       }
+    }
 
-      XTransform tmat
-       = {{{XDoubleToFixed (xscale), XDoubleToFixed (0), XDoubleToFixed (0)},
-           {XDoubleToFixed (0), XDoubleToFixed (yscale), XDoubleToFixed (0)},
-           {XDoubleToFixed (0), XDoubleToFixed (0), XDoubleToFixed (1)}}};
+  if (FIXNATP (w) && XFIXNAT (w) < img->width)
+    width = XFIXNAT (w);
+  else
+    width = img->width;
 
-      XRenderSetPictureFilter (FRAME_X_DISPLAY (f), img->picture, FilterBest,
-                              0, 0);
-      XRenderSetPictureTransform (FRAME_X_DISPLAY (f), img->picture, &tmat);
+  if (TYPE_RANGED_FIXNUMP (int, x))
+    {
+      left = XFIXNUM (x);
+      if (left < 0)
+        left = img->width - width + left;
+    }
+  else
+    left = (img->width - width)/2;
+
+  if (FIXNATP (h) && XFIXNAT (h) < img->height)
+    height = XFIXNAT (h);
+  else
+    height = img->height;
+
+  if (TYPE_RANGED_FIXNUMP (int, y))
+    {
+      top = XFIXNUM (y);
+      if (top < 0)
+        top = img->height - height + top;
+    }
+  else
+    top = (img->height - height)/2;
+
+  /* Negative values operate from the right and bottom of the image
+     instead of the left and top.  */
+  if (left < 0)
+    {
+      width = img->width + left;
+      left = 0;
+    }
+
+  if (width + left > img->width)
+    width = img->width - left;
 
-      img->width = width;
-      img->height = height;
+  if (top < 0)
+    {
+      height = img->height + top;
+      top = 0;
     }
+
+  if (height + top > img->height)
+    height = img->height - top;
+
+  INIT_MATRIX (m);
+  m[2][0] = left;
+  m[2][1] = top;
+
+  MULT_MATRICES (tm, m, tmp);
+  COPY_MATRIX (tmp, tm);
+
+  img->width = width;
+  img->height = height;
+#endif
+}
+
+static void
+image_set_size (struct image *img, double tm[3][3])
+{
+#ifdef HAVE_NATIVE_TRANSFORMS
+# ifdef HAVE_IMAGEMAGICK
+  /* ImageMagick images are already the correct size.  */
+  if (EQ (image_spec_value (img->spec, QCtype, NULL), Qimagemagick))
+    return;
+# endif
+
+# ifdef HAVE_XRENDER
+  if (!img->picture)
+    return;
+# endif
+
+  int width, height;
+
+  compute_image_size (img->width, img->height, img->spec, &width, &height);
+
+# if defined (HAVE_NS) || defined (HAVE_XRENDER)
+  double rm[3][3], tmp[3][3];
+  double xscale, yscale;
+
+  xscale = img->width / (double) width;
+  yscale = img->height / (double) height;
+
+  INIT_MATRIX (rm);
+  rm[0][0] = xscale;
+  rm[1][1] = yscale;
+
+  MULT_MATRICES (tm, rm, tmp);
+  COPY_MATRIX (tmp, tm);
+
+  img->width = width;
+  img->height = height;
 # endif
+
 # ifdef HAVE_NTGUI
   /* Under HAVE_NTGUI, we will scale the image on the fly, when we
      draw it.  See w32term.c:x_draw_image_foreground.  */
@@ -1992,6 +2184,36 @@ image_set_image_size (struct frame *f, struct image *img)
 #endif
 }
 
+static void
+image_set_transform (struct frame *f, struct image *img, double matrix[3][3])
+{
+  /* TODO: Add MS Windows support.  */
+#ifdef HAVE_NATIVE_TRANSFORMS
+# if defined (HAVE_NS)
+  /* 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 (HAVE_XRENDER)
+  if (img->picture)
+    {
+      XTransform tmat
+       = {{{XDoubleToFixed (matrix[0][0]),
+             XDoubleToFixed (matrix[1][0]),
+             XDoubleToFixed (matrix[2][0])},
+           {XDoubleToFixed (matrix[0][1]),
+             XDoubleToFixed (matrix[1][1]),
+             XDoubleToFixed (matrix[2][1])},
+           {XDoubleToFixed (matrix[0][2]),
+             XDoubleToFixed (matrix[1][2]),
+             XDoubleToFixed (matrix[2][2])}}};
+
+      XRenderSetPictureFilter (FRAME_X_DISPLAY (f), img->picture, FilterBest,
+                              0, 0);
+      XRenderSetPictureTransform (FRAME_X_DISPLAY (f), img->picture, &tmat);
+    }
+# endif
+#endif
+}
 
 /* Return the id of image with Lisp specification SPEC on frame F.
    SPEC must be a valid Lisp image specification (see valid_image_p).  */
@@ -2047,7 +2269,16 @@ lookup_image (struct frame *f, Lisp_Object spec)
             `:background COLOR'.  */
          Lisp_Object ascent, margin, relief, bg;
          int relief_bound;
-          image_set_image_size (f, img);
+
+#ifdef HAVE_NATIVE_TRANSFORMS
+          double transform_matrix[3][3];
+
+          INIT_MATRIX (transform_matrix);
+          image_set_size (img, transform_matrix);
+          image_set_crop (img, transform_matrix);
+          image_set_rotation (img, transform_matrix);
+          image_set_transform (f, img, transform_matrix);
+#endif
 
          ascent = image_spec_value (spec, QCascent, NULL);
          if (FIXNUMP (ascent))
@@ -9673,9 +9904,9 @@ DEFUN ("lookup-image", Flookup_image, Slookup_image, 1, 
1, 0,
                            Initialization
  ***********************************************************************/
 
-DEFUN ("image-scaling-p", Fimage_scaling_p, Simage_scaling_p, 0, 1, 0,
-       doc: /* Test whether FRAME supports resizing images.
-Return t if FRAME supports native scaling, nil otherwise.  */)
+DEFUN ("image-transforms-p", Fimage_transforms_p, Simage_transforms_p, 0, 1, 0,
+       doc: /* Test whether FRAME supports image transformation.
+Return t if FRAME supports native transforms, nil otherwise.  */)
      (Lisp_Object frame)
 {
 #if defined (USE_CAIRO) || defined (HAVE_NS) || defined (HAVE_NTGUI)
@@ -9935,7 +10166,7 @@ non-numeric, there is no explicit limit on the size of 
images.  */);
   defsubr (&Slookup_image);
 #endif
 
-  defsubr (&Simage_scaling_p);
+  defsubr (&Simage_transforms_p);
 
   DEFVAR_BOOL ("cross-disabled-images", cross_disabled_images,
     doc: /* Non-nil means always draw a cross over disabled images.
diff --git a/src/nsimage.m b/src/nsimage.m
index 0249d22..7268e66 100644
--- a/src/nsimage.m
+++ b/src/nsimage.m
@@ -76,9 +76,8 @@ ns_load_image (struct frame *f, struct image *img,
 {
   EmacsImage *eImg = nil;
   NSSize size;
-  Lisp_Object lisp_index, lisp_rotation;
+  Lisp_Object lisp_index;
   unsigned int index;
-  double rotation;
 
   NSTRACE ("ns_load_image");
 
@@ -87,9 +86,6 @@ ns_load_image (struct frame *f, struct image *img,
   lisp_index = Fplist_get (XCDR (img->spec), QCindex);
   index = FIXNUMP (lisp_index) ? XFIXNAT (lisp_index) : 0;
 
-  lisp_rotation = Fplist_get (XCDR (img->spec), QCrotation);
-  rotation = NUMBERP (lisp_rotation) ? XFLOATINT (lisp_rotation) : 0;
-
   if (STRINGP (spec_file))
     {
       eImg = [EmacsImage allocInitFromFile: spec_file];
@@ -119,13 +115,6 @@ ns_load_image (struct frame *f, struct image *img,
 
   img->lisp_data = [eImg getMetadata];
 
-  if (rotation != 0)
-    {
-      EmacsImage *temp = [eImg rotate:rotation];
-      [eImg release];
-      eImg = temp;
-    }
-
   size = [eImg size];
   img->width = size.width;
   img->height = size.height;
@@ -155,6 +144,12 @@ ns_image_set_size (void *img, int width, int height)
   [(EmacsImage *)img setSize:NSMakeSize (width, height)];
 }
 
+void
+ns_image_set_transform (void *img, double m[3][3])
+{
+  [(EmacsImage *)img setTransform:m];
+}
+
 unsigned long
 ns_get_pixel (void *img, int x, int y)
 {
@@ -225,6 +220,7 @@ ns_set_alpha (void *img, int x, int y, unsigned char a)
 {
   [stippleMask release];
   [bmRep release];
+  [transform release];
   [super dealloc];
 }
 
@@ -528,42 +524,16 @@ ns_set_alpha (void *img, int x, int y, unsigned char a)
   return YES;
 }
 
-- (instancetype)rotate: (double)rotation
+- (void)setTransform: (double[3][3]) m
 {
-  EmacsImage *new_image;
-  NSPoint new_origin;
-  NSSize new_size, size = [self size];
-  NSRect rect = { NSZeroPoint, [self size] };
-
-  /* Create a bezier path of the outline of the image and do the
-   * rotation on it.  */
-  NSBezierPath *bounds_path = [NSBezierPath bezierPathWithRect:rect];
-  NSAffineTransform *transform = [NSAffineTransform transform];
-  [transform rotateByDegrees: rotation * -1];
-  [bounds_path transformUsingAffineTransform:transform];
-
-  /* Now we can find out how large the rotated image needs to be.  */
-  new_size = [bounds_path bounds].size;
-  new_image = [[EmacsImage alloc] initWithSize:new_size];
-
-  new_origin = NSMakePoint((new_size.width - size.width)/2,
-                           (new_size.height - size.height)/2);
-
-  [new_image lockFocus];
-
-  /* Create the final transform.  */
-  transform = [NSAffineTransform transform];
-  [transform translateXBy:new_size.width/2 yBy:new_size.height/2];
-  [transform rotateByDegrees: rotation * -1];
-  [transform translateXBy:-new_size.width/2 yBy:-new_size.height/2];
-
-  [transform concat];
-  [self drawAtPoint:new_origin fromRect:NSZeroRect
-          operation:NSCompositingOperationCopy fraction:1];
-
-  [new_image unlockFocus];
-
-  return new_image;
+  transform = [[NSAffineTransform transform] retain];
+  NSAffineTransformStruct tm
+    = { m[0][0], m[0][1], m[1][0], m[1][1], m[2][0], m[2][1]};
+  [transform setTransformStruct:tm];
+
+  /* Because the transform is applied to the drawing surface, and not
+     the image itself, we need to invert it.  */
+  [transform invert];
 }
 
 @end
diff --git a/src/nsterm.h b/src/nsterm.h
index 1e56276..567f462 100644
--- a/src/nsterm.h
+++ b/src/nsterm.h
@@ -632,6 +632,8 @@ typedef id instancetype;
   unsigned char *pixmapData[5]; /* shortcut to access pixel data */
   NSColor *stippleMask;
   unsigned long xbm_fg;
address@hidden
+  NSAffineTransform *transform;
 }
 + (instancetype)allocInitFromFile: (Lisp_Object)file;
 - (void)dealloc;
@@ -648,7 +650,7 @@ typedef id instancetype;
 - (NSColor *)stippleMask;
 - (Lisp_Object)getMetadata;
 - (BOOL)setFrame: (unsigned int) index;
-- (instancetype)rotate: (double)rotation;
+- (void)setTransform: (double[3][3]) m;
 @end
 
 
@@ -1201,6 +1203,7 @@ extern bool ns_load_image (struct frame *f, struct image 
*img,
 extern int ns_image_width (void *img);
 extern int ns_image_height (void *img);
 extern void ns_image_set_size (void *img, int width, int height);
+extern void ns_image_set_transform (void *img, double m[3][3]);
 extern unsigned long ns_get_pixel (void *img, int x, int y);
 extern void ns_put_pixel (void *img, int x, int y, unsigned long argb);
 extern void ns_set_alpha (void *img, int x, int y, unsigned char a);
diff --git a/src/nsterm.m b/src/nsterm.m
index 0cae5e9..f12e98e 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -3813,21 +3813,34 @@ ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
   /* Draw the image... do we need to draw placeholder if img == nil?  */
   if (img != nil)
     {
-#ifdef NS_IMPL_COCOA
+      /* The idea here is that the clipped area is set in the normal
+         view coordinate system, then we transform the coordinate
+         system so that when we draw the image it is rotated, resized
+         or whatever as required.  This is kind of backwards, but
+         there's no way to apply the transform to the image without
+         creating a whole new bitmap.  */
       NSRect dr = NSMakeRect (x, y, s->slice.width, s->slice.height);
-      NSRect ir = NSMakeRect (s->slice.x,
-                              s->img->height - s->slice.y - s->slice.height,
-                              s->slice.width, s->slice.height);
-      [img drawInRect: dr
-             fromRect: ir
-             operation: NSCompositingOperationSourceOver
-              fraction: 1.0
-           respectFlipped: YES
-                hints: nil];
-#else
-      [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
-                  operation: NSCompositingOperationSourceOver];
-#endif
+      NSRect ir = NSMakeRect (0, 0, [img size].width, [img size].height);
+
+      NSAffineTransform *setOrigin = [NSAffineTransform transform];
+
+      [[NSGraphicsContext currentContext] saveGraphicsState];
+
+      /* Because of the transforms it's far too difficult to work out
+         what portion of the original, untransformed, image will be
+         drawn, so the clipping area will ensure we draw only the
+         correct bit.  */
+      NSRectClip (dr);
+
+      [setOrigin translateXBy:x - s->slice.x yBy:y - s->slice.y];
+      [setOrigin concat];
+      [img->transform concat];
+
+      [img drawInRect:ir fromRect:ir
+            operation:NSCompositingOperationSourceOver
+             fraction:1.0 respectFlipped:YES hints:nil];
+
+      [[NSGraphicsContext currentContext] restoreGraphicsState];
     }
 
   if (s->hl == DRAW_CURSOR)
diff --git a/src/xterm.c b/src/xterm.c
index ccc84dc..c064647 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -2883,10 +2883,7 @@ x_composite_image (struct glyph_string *s, Pixmap dest,
       destination = XRenderCreatePicture (display, dest,
                                           default_format, 0, &attr);
 
-      /* FIXME: It may make sense to use PictOpSrc instead of
-         PictOpOver, as I don't know if we care about alpha values too
-         much here.  */
-      XRenderComposite (display, PictOpOver,
+      XRenderComposite (display, PictOpSrc,
                         s->img->picture, s->img->mask_picture, destination,
                         srcX, srcY,
                         srcX, srcY,



reply via email to

[Prev in Thread] Current Thread [Next in Thread]