]> git.eshelyaron.com Git - emacs.git/commitdiff
Port visible bell to Android
authorPo Lu <luangruo@yahoo.com>
Thu, 2 May 2024 03:31:37 +0000 (11:31 +0800)
committerEshel Yaron <me@eshelyaron.com>
Mon, 6 May 2024 16:32:03 +0000 (18:32 +0200)
* java/org/gnu/emacs/EmacsDrawRectangle.java (perform): Ignore
GC_INVERT.

* java/org/gnu/emacs/EmacsFillRectangle.java
(EmacsFillRectangle) <invertFilter>: New variable.
(perform): If the transfer mode is invert, copy the source
to itself with invertFilter as the color filter.

* java/org/gnu/emacs/EmacsGC.java (EmacsGC) <xorAlu, srcInAlu>:
Delete now-redundant ALUs.
(markDirty): Cease updating the paint's transfermode.

* java/org/gnu/emacs/EmacsSafThread.java (openDocument1): Fix
typo in documentation.

* src/android.c (android_blit_xor): Delete unused function.
(android_copy_area): Remove calls to unused blit functions.

* src/androidgui.h (enum android_gc_function): Rename XOR to
INVERT.

* src/androidterm.c (android_flash): Replace with GXinvert.

(cherry picked from commit b84fa71f8985284560bacda7d407e3559583844f)

java/org/gnu/emacs/EmacsDrawRectangle.java
java/org/gnu/emacs/EmacsFillRectangle.java
java/org/gnu/emacs/EmacsGC.java
java/org/gnu/emacs/EmacsSafThread.java
src/android.c
src/androidgui.h
src/androidterm.c

index e40a7c1606855a3ce24c83deef8bbd4453ee4da0..ea0f1c281068a78ea3371b0553a2efce5ef17342 100644 (file)
@@ -22,13 +22,23 @@ package org.gnu.emacs;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Paint;
+import android.graphics.PorterDuff.Mode;
+import android.graphics.PorterDuffXfermode;
 import android.graphics.Rect;
 import android.graphics.RectF;
+import android.graphics.Xfermode;
 
 import android.util.Log;
 
 public final class EmacsDrawRectangle
 {
+  private static final Xfermode srcInAlu;
+
+  static
+  {
+    srcInAlu = new PorterDuffXfermode (Mode.SRC_IN);
+  };
+
   public static void
   perform (EmacsDrawable drawable, EmacsGC gc,
           int x, int y, int width, int height)
@@ -40,8 +50,10 @@ public final class EmacsDrawRectangle
     Canvas canvas;
     Bitmap clipBitmap;
 
-    /* TODO implement stippling.  */
-    if (gc.fill_style == EmacsGC.GC_FILL_OPAQUE_STIPPLED)
+    /* TODO implement stippling for this request.  */
+    if (gc.fill_style == EmacsGC.GC_FILL_OPAQUE_STIPPLED
+       /* And GC_INVERT also.  */
+       || gc.fill_style == EmacsGC.GC_INVERT)
       return;
 
     canvas = drawable.lockCanvas (gc);
@@ -103,7 +115,7 @@ public final class EmacsDrawRectangle
        /* Set the transfer mode to SRC_IN to preserve only the parts
           of the source that overlap with the mask.  */
        maskPaint = new Paint ();
-       maskPaint.setXfermode (EmacsGC.srcInAlu);
+       maskPaint.setXfermode (srcInAlu);
        maskPaint.setStyle (Paint.Style.STROKE);
 
        /* Draw the source.  */
index f338a54f97b110e52376ce0bb225c249f407e1d6..7642deed7c3e42148d8c918f49aeb30cd6b1fde9 100644 (file)
@@ -21,6 +21,8 @@ package org.gnu.emacs;
 
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.ColorMatrixColorFilter;
 import android.graphics.Paint;
 import android.graphics.Rect;
 
@@ -28,30 +30,42 @@ import android.util.Log;
 
 public final class EmacsFillRectangle
 {
+  /* Color filter that inverts colors from the source.  */
+  private static final ColorFilter invertFilter;
+
+  static
+  {
+    invertFilter = new ColorMatrixColorFilter (new float[] {
+       -1f, 0f, 0f, 0f, 255f,
+       0f, -1f, 0f, 0f, 255f,
+       0f, 0f, -1f, 0f, 255f,
+       0f, 0f, 0f, 1f, 0f,
+      });
+  };
+
   public static void
   perform (EmacsDrawable drawable, EmacsGC gc,
           int x, int y, int width, int height)
   {
-    Paint maskPaint, paint;
-    Canvas maskCanvas;
-    Bitmap maskBitmap;
+    Paint paint;
     Rect rect;
-    Rect maskRect, dstRect;
     Canvas canvas;
-    Bitmap clipBitmap;
+    Bitmap invertBitmap;
 
     canvas = drawable.lockCanvas (gc);
 
-    if (canvas == null)
+    /* Clip masks are not respected or implemented when specified with
+       this request.  */
+    if (canvas == null || gc.clip_mask != null)
       return;
 
     rect = new Rect (x, y, x + width, y + height);
 
-    paint = gc.gcPaint;
-    paint.setStyle (Paint.Style.FILL);
-
-    if (gc.clip_mask == null)
+    if (gc.function != EmacsGC.GC_INVERT)
       {
+       paint = gc.gcPaint;
+       paint.setStyle (Paint.Style.FILL);
+
        if (gc.fill_style != EmacsGC.GC_FILL_OPAQUE_STIPPLED)
          canvas.drawRect (rect, paint);
        else
@@ -59,57 +73,17 @@ public final class EmacsFillRectangle
       }
     else
       {
-       /* Drawing with a clip mask involves calculating the
-          intersection of the clip mask with the dst rect, and
-          extrapolating the corresponding part of the src rect.  */
-
-       clipBitmap = gc.clip_mask.bitmap;
-       dstRect = new Rect (x, y, x + width, y + height);
-       maskRect = new Rect (gc.clip_x_origin,
-                            gc.clip_y_origin,
-                            (gc.clip_x_origin
-                             + clipBitmap.getWidth ()),
-                            (gc.clip_y_origin
-                             + clipBitmap.getHeight ()));
-
-       if (!maskRect.setIntersect (dstRect, maskRect))
-         /* There is no intersection between the clip mask and the
-            dest rect.  */
-         return;
-
-       /* Finally, create a temporary bitmap that is the size of
-          maskRect.  */
-
-       maskBitmap
-         = Bitmap.createBitmap (maskRect.width (), maskRect.height (),
-                                Bitmap.Config.ARGB_8888);
-
-       /* Draw the mask onto the maskBitmap.  */
-       maskCanvas = new Canvas (maskBitmap);
-       maskRect.offset (-gc.clip_x_origin,
-                        -gc.clip_y_origin);
-       maskCanvas.drawBitmap (gc.clip_mask.bitmap,
-                              maskRect, new Rect (0, 0,
-                                                  maskRect.width (),
-                                                  maskRect.height ()),
-                              paint);
-       maskRect.offset (gc.clip_x_origin,
-                        gc.clip_y_origin);
-
-       /* Set the transfer mode to SRC_IN to preserve only the parts
-          of the source that overlap with the mask.  */
-       maskPaint = new Paint ();
-       maskPaint.setXfermode (EmacsGC.srcInAlu);
-
-       /* Draw the source.  */
-       maskCanvas.drawRect (maskRect, maskPaint);
-
-       /* Finally, draw the mask bitmap to the destination.  */
-       paint.setXfermode (null);
-       canvas.drawBitmap (maskBitmap, null, maskRect, paint);
-
-       /* Recycle this unused bitmap.  */
-       maskBitmap.recycle ();
+       paint = new Paint ();
+
+       /* Simply invert the destination, which is only implemented for
+          this request.  As Android doesn't permit copying a bitmap to
+          itself, a copy of the source must be procured beforehand.  */
+       invertBitmap = Bitmap.createBitmap (drawable.getBitmap (),
+                                           x, y, width, height);
+        paint.setColorFilter (invertFilter);
+       canvas.drawBitmap (invertBitmap, null, rect, paint);
+        paint.setColorFilter (null);
+       invertBitmap.recycle ();
       }
 
     drawable.damageRect (rect);
index ec2b9c9e475e3a18eff3761ccfaffdb5fa8af988..bb11f76c80001dfe68868f90ec5b25cc1891d072 100644 (file)
@@ -27,9 +27,7 @@ import android.graphics.Canvas;
 import android.graphics.ColorFilter;
 import android.graphics.PorterDuff.Mode;
 import android.graphics.PorterDuffColorFilter;
-import android.graphics.PorterDuffXfermode;
 import android.graphics.Shader.TileMode;
-import android.graphics.Xfermode;
 
 import android.graphics.drawable.BitmapDrawable;
 
@@ -40,8 +38,8 @@ import android.os.Build;
 
 public final class EmacsGC extends EmacsHandleObject
 {
-  public static final int GC_COPY = 0;
-  public static final int GC_XOR  = 1;
+  public static final int GC_COPY    = 0;
+  public static final int GC_INVERT  = 1;
 
   public static final int GC_FILL_SOLID                        = 0;
   public static final int GC_FILL_OPAQUE_STIPPLED      = 1;
@@ -49,8 +47,6 @@ public final class EmacsGC extends EmacsHandleObject
   public static final int GC_LINE_SOLID                        = 0;
   public static final int GC_LINE_ON_OFF_DASH          = 1;
 
-  public static final Xfermode xorAlu, srcInAlu;
-
   public int function, fill_style;
   public int foreground, background;
   public int clip_x_origin, clip_y_origin;
@@ -72,12 +68,6 @@ public final class EmacsGC extends EmacsHandleObject
      rectangles changed.  0 if there are no clip rectangles.  */
   public long clipRectID;
 
-  static
-  {
-    xorAlu = new PorterDuffXfermode (Mode.XOR);
-    srcInAlu = new PorterDuffXfermode (Mode.SRC_IN);
-  }
-
   /* The following fields are only set on immutable GCs.  */
 
   public
@@ -131,8 +121,6 @@ public final class EmacsGC extends EmacsHandleObject
     /* A line_width of 0 is equivalent to that of 1.  */
     gcPaint.setStrokeWidth (line_width < 1 ? 1 : line_width);
     gcPaint.setColor (foreground | 0xff000000);
-    gcPaint.setXfermode (function == GC_XOR
-                        ? xorAlu : srcInAlu);
 
     /* Update the stipple object with the new stipple bitmap, or delete
        it if the stipple has been cleared on systems too old to support
index 14c3f222833d1ded37c4f8596487808cf7b04a1c..ee8c2e7e0c396ea404f4b26adb7fa069aa4f3eac 100644 (file)
@@ -1623,10 +1623,10 @@ public final class EmacsSafThread extends HandlerThread
        mode is merely w.
 
        This may be ascribed to a mix-up in Android's documentation
-       regardin DocumentsProvider: the `openDocument' function is only
-       documented to accept r or rw, whereas the default
-       implementation of the `openFile' function (which documents rwt)
-       delegates to `openDocument'.  */
+       regarding DocumentsProvider: the `openDocument' function is only
+       documented to accept r or rw, whereas the default implementation
+       of the `openFile' function (which documents rwt) delegates to
+       `openDocument'.  */
 
     if (read && write && truncate && fileDescriptor != null
        && !EmacsNative.ftruncate (fileDescriptor.getFd ()))
index 2777add50592a95bb16081ac86c005f9cb83dccb..c76afdb9bf274f21b68a6e4c09e27a6dfd297826 100644 (file)
@@ -4381,286 +4381,6 @@ android_blit_copy (int src_x, int src_y, int width, int height,
 }
 
 
-/* Xor a rectangle SRC_X, SRC_Y, WIDTH and HEIGHT from SRC, described
-   by SRC_INFO, to DST_X and DST_Y in DST, as described by DST_INFO.
-
-   Ignore the alpha channel when computing the exclusive-or of the
-   destination pixel.
-
-   If MASK is set, mask the source data using MASK_INFO, translating
-   it by GC->clip_x_origin and GC->clip_y_origin.  MASK must be a
-   pixmap of depth 1.
-
-   N.B. that currently only copies between bitmaps of depth 24 are
-   implemented.  */
-
-static void
-android_blit_xor (int src_x, int src_y, int width, int height,
-                 int dst_x, int dst_y, struct android_gc *gc,
-                 unsigned char *src, AndroidBitmapInfo *src_info,
-                 unsigned char *dst, AndroidBitmapInfo *dst_info,
-                 unsigned char *mask, AndroidBitmapInfo *mask_info)
-{
-#if 0
-  uintptr_t start, end;
-  int mask_offset;
-  size_t pixel, offset, offset1;
-  unsigned char *src_current, *dst_current;
-  unsigned char *mask_current;
-  int overflow, temp, i;
-  bool backwards;
-  unsigned int *long_src, *long_dst;
-#endif /* 0 */
-
-  /* Note that this alu hasn't been tested -- it probably does not
-     work! */
-  emacs_abort ();
-
-#if 0
-  /* Assert that the specified coordinates are within bounds.  */
-  eassert (src_x >= 0 && src_y >= 0
-          && dst_x >= 0 && dst_y >= 0);
-  eassert (src_x + width <= src_info->width);
-  eassert (src_y + height <= src_info->height);
-  eassert (dst_x + width <= dst_info->width);
-  eassert (dst_y + height <= dst_info->height);
-
-  /* Now check that each bitmap has the correct format.  */
-  eassert (src_info->format == dst_info->format
-          && src_info->format == ANDROID_BITMAP_FORMAT_RGBA_8888);
-  pixel = sizeof (unsigned int);
-
-  /* Android doesn't have A1 bitmaps, so A8 is used to represent
-     packed bitmaps of depth 1.  */
-  eassert (!mask || mask_info->format == ANDROID_BITMAP_FORMAT_A_8);
-
-  /* Calculate the address of the first pixel of the first row to be
-     copied in both src and dst.  Compare them to determine the
-     direction in which the copy is to take place.  */
-
-  overflow  = ckd_mul (&start, src_y, src_info->stride);
-  overflow |= ckd_mul (&end, src_x, pixel);
-  overflow |= ckd_add (&start, (uintptr_t) src, start);
-
-  if (overflow)
-    return;
-
-  src_current = (unsigned char *) start;
-
-  overflow  = ckd_mul (&start, dst_y, src_info->stride);
-  overflow |= ckd_mul (&end, dst_x, pixel);
-  overflow |= ckd_add (&start, (uintptr_t) dst, start);
-
-  if (overflow)
-    return;
-
-  dst_current = (unsigned char *) start;
-  backwards = false;
-
-  /* Now see if copying should proceed from the bottom up.  */
-
-  if (src == dst && dst_current >= src_current)
-    {
-      backwards = true;
-
-      /* Walk src and dst from bottom to top, in order to avoid
-        overlap.  Calculate the coordinate of the last pixel of the
-        last row in both src and dst.  */
-
-      overflow  = ckd_mul (&start, src_y + height - 1,
-                          src_info->stride);
-      if (mask) /* If a mask is set, put the pointers before the end
-                  of the row.  */
-       overflow |= ckd_mul (&end, src_x + width - 1, pixel);
-      else
-       overflow |= ckd_mul (&end, src_x, pixel);
-      overflow |= ckd_add (&start, start, end);
-      overflow |= ckd_add (&start, (uintptr_t) src, start);
-
-      if (overflow)
-       return;
-
-      src_current = (unsigned char *) start;
-
-      overflow  = ckd_mul (&start, dst_y + height - 1,
-                          dst_info->stride);
-      if (mask) /* If a mask is set, put the pointers before the end
-                  of the row.  */
-       overflow |= ckd_mul (&end, dst_x + width - 1, pixel);
-      else
-       overflow |= ckd_mul (&end, dst_x, pixel);
-      overflow |= ckd_add (&start, start, end);
-      overflow |= ckd_add (&start, (uintptr_t) dst, start);
-
-      if (overflow)
-       return;
-
-      dst_current = (unsigned char *) start;
-    }
-
-  if (!mask)
-    {
-      /* Change the direction of the copy depending on how SRC and DST
-        overlap.  */
-
-      for (i = 0; i < height; ++i)
-       {
-         if (backwards)
-           {
-             for (i = width - 1; i <= 0; --i)
-               (((unsigned int *) dst_current)[i])
-                 /* Keep the alpha channel intact.  */
-                 ^= (((unsigned int *) src_current)[i]) & 0xffffff;
-
-             /* Proceed to the last row.  */
-             src_current -= src_info->stride;
-             dst_current -= dst_info->stride;
-           }
-         else
-           {
-             for (i = 0; i < width; ++i)
-               (((unsigned int *) dst_current)[i])
-                 /* Keep the alpha channel intact.  */
-                 ^= (((unsigned int *) src_current)[i]) & 0xffffff;
-
-             /* Proceed to the next row.  */
-             src_current += src_info->stride;
-             dst_current += dst_info->stride;
-           }
-       }
-    }
-  else
-    {
-      /* Adjust the source and destination Y.  The start is MAX
-         (dst_y, gc->clip_y_origin); the difference between that value
-         and dst_y is the offset to apply to src_y. */
-
-      temp    = dst_y;
-      dst_y   = MAX (dst_y, gc->clip_y_origin);
-      src_y  += dst_y - temp;
-      height -= dst_y - temp;
-
-      /* Verify that the bounds are correct.  */
-      eassert (dst_y + height
-              <= gc->clip_y_origin + mask_info->height);
-      eassert (dst_y >= gc->clip_y_origin);
-
-      /* There is a mask.  For each scan line... */
-
-      if (backwards)
-       {
-         /* Calculate the number of pixels at the end of the
-            mask.  */
-
-         mask_offset  = dst_x + width;
-         mask_offset -= mask_info->width + gc->clip_x_origin;
-
-         if (mask_info < 0)
-           mask_info = 0;
-
-         /* Calculate the last column of the mask that will be
-            consulted.  */
-
-         temp = dst_x - gc->clip_x_origin;
-         temp += MIN (mask_info->width - temp,
-                      width - mask_offset);
-
-         if (temp < 0)
-           return;
-
-         /* Now calculate the last row of the mask that will be
-            consulted.  */
-         i = dst_y - gc->clip_y_origin + height;
-
-         /* Turn both into offsets.  */
-
-         if (ckd_mul (&offset, temp, pixel)
-             || ckd_mul (&offset1, i, mask_info->stride)
-             || ckd_add (&offset, offset, offset1)
-             || ckd_add (&start, (uintptr_t) mask, offset))
-           return;
-
-         mask = mask_current = (unsigned char *) start;
-
-         for (i = 0; i < height; ++i)
-           {
-             /* Skip backwards past the end of the mask.  */
-
-             long_src = (unsigned int *) (src_current - mask_offset * pixel);
-             long_dst = (unsigned int *) (dst_current - mask_offset * pixel);
-             mask = mask_current;
-
-             /* For each pixel covered by the mask... */
-             temp = MIN (mask_info->width - temp, width - mask_offset);
-             while (temp--)
-               /* XOR the source to the destination, masked by the
-                  mask.  */
-               *long_dst-- ^= ((*(long_src--) & (0u - (*(mask--) & 1)))
-                               & 0xffffff);
-
-             /* Return to the last row.  */
-             src_current -= src_info->stride;
-             dst_current -= dst_info->stride;
-             mask_current -= mask_info->stride;
-           }
-       }
-      else
-       {
-         /* Calculate the first column of the mask that will be
-            consulted.  */
-
-         mask_offset = dst_x - gc->clip_x_origin;
-
-         /* Adjust the mask by that much.  */
-
-         if (mask_offset > 0)
-           mask += mask_offset;
-         else
-           {
-             /* Offset src and dst by the mask offset.  */
-             src_current += -mask_offset * pixel;
-             dst_current += -mask_offset * pixel;
-             width -= mask_offset;
-           }
-
-         /* Now move mask to the position of the first row.  */
-
-         mask += gc->clip_y_origin * mask_info->stride;
-
-         for (i = 0; i < height; ++i)
-           {
-             long_src = (unsigned int *) src_current;
-             long_dst = (unsigned int *) dst_current;
-             mask_current = mask;
-
-             if (mask_offset > 0)
-               {
-                 /* Copy bytes according to the mask.  */
-                 temp = MIN (mask_info->width - mask_offset, width);
-                 while (temp--)
-                   *long_dst++ ^= ((*(long_src++)
-                                    & (0u - (*(mask_current++) & 1)))
-                                   & 0xffffff);
-               }
-             else
-               {
-                 /* Copy bytes according to the mask.  */
-                 temp = MIN (mask_info->width, width);
-                 while (temp--)
-                   *long_dst++ = ((*(long_src++)
-                                   & (0u - (*(mask_current++) & 1)))
-                                  & 0xffffff);
-               }
-
-             src_current += src_info->stride;
-             dst_current += dst_info->stride;
-             mask        += mask_info->stride;
-           }
-       }
-    }
-#endif /* 0 */
-}
-
 void
 android_copy_area (android_drawable src, android_drawable dest,
                   struct android_gc *gc, int src_x, int src_y,
@@ -4763,10 +4483,10 @@ android_copy_area (android_drawable src, android_drawable dest,
       do_blit = android_blit_copy;
       break;
 
-    case ANDROID_GC_XOR:
-      do_blit = android_blit_xor;
-      break;
-
+ /* case ANDROID_GC_INVERT: */
+   /* do_blit = android_blit_invert; */
+      /* A GC with its operation set to ANDROID_GC_INVERT is never given
+        to CopyArea.  */
     default:
       emacs_abort ();
     }
index 5e4f6ec39894b23898139dad9279d93cbbc6d4b2..3b3e08ca024eb9e40b6c536e55ef41fbf5d15789 100644 (file)
@@ -56,7 +56,7 @@ struct android_point
 enum android_gc_function
   {
     ANDROID_GC_COPY    = 0,
-    ANDROID_GC_XOR     = 1,
+    ANDROID_GC_INVERT  = 1,
   };
 
 enum android_gc_value_mask
index f849f0d99196174a0595de62b2a9692e56b2593a..2979e5c1401a4630f287ba04666757c7cf780eea 100644 (file)
@@ -151,14 +151,8 @@ android_flash (struct frame *f)
   fd_set fds;
 
   block_input ();
-
-  values.function = ANDROID_GC_XOR;
-  values.foreground = (FRAME_FOREGROUND_PIXEL (f)
-                      ^ FRAME_BACKGROUND_PIXEL (f));
-
-  gc = android_create_gc ((ANDROID_GC_FUNCTION
-                          | ANDROID_GC_FOREGROUND),
-                         &values);
+  values.function = ANDROID_GC_INVERT;
+  gc = android_create_gc (ANDROID_GC_FUNCTION, &values);
 
   /* Get the height not including a menu bar widget.  */
   int height = FRAME_PIXEL_HEIGHT (f);