From: Po Lu Date: Thu, 2 May 2024 03:31:37 +0000 (+0800) Subject: Port visible bell to Android X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=fae54e4524a52c12ad0349108adbaacbb19a834c;p=emacs.git Port visible bell to Android * java/org/gnu/emacs/EmacsDrawRectangle.java (perform): Ignore GC_INVERT. * java/org/gnu/emacs/EmacsFillRectangle.java (EmacsFillRectangle) : 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) : 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) --- diff --git a/java/org/gnu/emacs/EmacsDrawRectangle.java b/java/org/gnu/emacs/EmacsDrawRectangle.java index e40a7c16068..ea0f1c28106 100644 --- a/java/org/gnu/emacs/EmacsDrawRectangle.java +++ b/java/org/gnu/emacs/EmacsDrawRectangle.java @@ -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. */ diff --git a/java/org/gnu/emacs/EmacsFillRectangle.java b/java/org/gnu/emacs/EmacsFillRectangle.java index f338a54f97b..7642deed7c3 100644 --- a/java/org/gnu/emacs/EmacsFillRectangle.java +++ b/java/org/gnu/emacs/EmacsFillRectangle.java @@ -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); diff --git a/java/org/gnu/emacs/EmacsGC.java b/java/org/gnu/emacs/EmacsGC.java index ec2b9c9e475..bb11f76c800 100644 --- a/java/org/gnu/emacs/EmacsGC.java +++ b/java/org/gnu/emacs/EmacsGC.java @@ -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 diff --git a/java/org/gnu/emacs/EmacsSafThread.java b/java/org/gnu/emacs/EmacsSafThread.java index 14c3f222833..ee8c2e7e0c3 100644 --- a/java/org/gnu/emacs/EmacsSafThread.java +++ b/java/org/gnu/emacs/EmacsSafThread.java @@ -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 ())) diff --git a/src/android.c b/src/android.c index 2777add5059..c76afdb9bf2 100644 --- a/src/android.c +++ b/src/android.c @@ -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 (); } diff --git a/src/androidgui.h b/src/androidgui.h index 5e4f6ec3989..3b3e08ca024 100644 --- a/src/androidgui.h +++ b/src/androidgui.h @@ -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 diff --git a/src/androidterm.c b/src/androidterm.c index f849f0d9919..2979e5c1401 100644 --- a/src/androidterm.c +++ b/src/androidterm.c @@ -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);