]> git.eshelyaron.com Git - emacs.git/commitdiff
Work around more problems with Bitmaps
authorPo Lu <luangruo@yahoo.com>
Mon, 29 May 2023 09:46:19 +0000 (17:46 +0800)
committerPo Lu <luangruo@yahoo.com>
Mon, 29 May 2023 09:46:19 +0000 (17:46 +0800)
* java/org/gnu/emacs/EmacsNative.java (EmacsNative): New
function `blitRect'.
* java/org/gnu/emacs/EmacsSurfaceView.java (EmacsSurfaceView):
Use it on Android 8.x.
* src/android.c (blitRect): Implement new function.

java/org/gnu/emacs/EmacsNative.java
java/org/gnu/emacs/EmacsSurfaceView.java
src/android.c

index e699dda9ad407d84d18440159ff1ff85f3c8d5be..56c03ee38dca9767ccd10f4162edad7b4c064244 100644 (file)
@@ -20,6 +20,9 @@ along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
 package org.gnu.emacs;
 
 import android.content.res.AssetManager;
+
+import android.graphics.Bitmap;
+
 import android.view.inputmethod.ExtractedText;
 import android.view.inputmethod.ExtractedTextRequest;
 
@@ -216,6 +219,13 @@ public final class EmacsNative
      failure.  */
   public static native int[] getSelection (short window);
 
+\f
+  /* Graphics functions used as a replacement for potentially buggy
+     Android APIs.  */
+
+  public static native void blitRect (Bitmap src, Bitmap dest, int x1,
+                                     int y1, int x2, int y2);
+
   static
   {
     /* Older versions of Android cannot link correctly with shared
index e0411f7f8b3c29a5bbd3bc296bdf6a88bae02ce9..0deb930c2c2826dee3ff0c018c3e7e5ac12393d4 100644 (file)
@@ -57,11 +57,36 @@ public final class EmacsSurfaceView extends View
   private void
   copyToFrontBuffer (Bitmap bitmap, Rect damageRect)
   {
-    if (damageRect != null)
-      bitmapCanvas.drawBitmap (bitmap, damageRect, damageRect,
-                              bitmapPaint);
+    EmacsService.checkEmacsThread ();
+
+    if (Build.VERSION.SDK_INT != Build.VERSION_CODES.O
+       && Build.VERSION.SDK_INT != Build.VERSION_CODES.O_MR1)
+      {
+       /* If `drawBitmap' can safely be used while a bitmap is locked
+          by another thread, continue here... */
+
+       if (damageRect != null)
+         bitmapCanvas.drawBitmap (bitmap, damageRect, damageRect,
+                                  bitmapPaint);
+       else
+         bitmapCanvas.drawBitmap (bitmap, 0f, 0f, bitmapPaint);
+      }
     else
-      bitmapCanvas.drawBitmap (bitmap, 0f, 0f, bitmapPaint);
+      {
+       /* But if it can not, as on Android 8.0 and 8.1, then use a
+          replacement function.  */
+
+       if (damageRect != null)
+         EmacsNative.blitRect (bitmap, frontBuffer,
+                               damageRect.left,
+                               damageRect.top,
+                               damageRect.right,
+                               damageRect.bottom);
+       else
+         EmacsNative.blitRect (bitmap, frontBuffer, 0, 0,
+                               bitmap.getWidth (),
+                               bitmap.getHeight ());
+      }
   }
 
   private void
index 7b9c478f2124dc1cf19fbe9fc7ad7b0bd675ef57..4184be3086b71ad1562fcaa3420769460cfad67b 100644 (file)
@@ -4754,6 +4754,104 @@ android_copy_area (android_drawable src, android_drawable dest,
 
 \f
 
+JNIEXPORT void JNICALL
+NATIVE_NAME (blitRect) (JNIEnv *env, jobject object,
+                       jobject src, jobject dest,
+                       jint x1, jint y1, jint x2, jint y2)
+{
+  AndroidBitmapInfo src_info, dest_info;
+  unsigned char *src_data_1, *dest_data_1;
+  void *src_data, *dest_data;
+
+  /* N.B. that X2 and Y2 represent the pixel past the edge of the
+     rectangle; thus, the width is x2 - x1 and the height is y2 -
+     y1.  */
+
+  memset (&src_info, 0, sizeof src_info);
+  memset (&dest_info, 0, sizeof dest_info);
+  AndroidBitmap_getInfo (env, src, &src_info);
+  AndroidBitmap_getInfo (env, dest, &dest_info);
+
+  /* If the stride is 0 after a call to `getInfo', assume it
+     failed.  */
+
+  if (!src_info.stride || !dest_info.stride)
+    return;
+
+  /* If formats differ, abort.  */
+  eassert (src_info.format == dest_info.format
+          && src_info.format == ANDROID_BITMAP_FORMAT_RGBA_8888);
+
+  /* Lock the image data.  */
+  src_data = NULL;
+  AndroidBitmap_lockPixels (env, src, &src_data);
+
+  if (!src_data)
+    return;
+
+  dest_data = NULL;
+  AndroidBitmap_lockPixels (env, dest, &dest_data);
+
+  if (!dest_data)
+    goto fail1;
+
+  /* Now clip the rectangle to the bounds of the source and
+     destination bitmap.  */
+
+  x1 = MAX (x1, 0);
+  y1 = MAX (y1, 0);
+  x2 = MAX (x2, 0);
+  y2 = MAX (y2, 0);
+
+
+  if (x1 >= src_info.width
+      || x1 >= dest_info.width)
+    x1 = MIN (dest_info.width - 1, src_info.width - 1);
+
+  if (x2 > src_info.width
+      || x2 > dest_info.width)
+    x2 = MIN (src_info.width, dest_info.width);
+
+  if (y1 >= src_info.height
+      || y1 >= dest_info.height)
+    y1 = MIN (dest_info.height - 1, src_info.height - 1);
+
+  if (y2 > src_info.height
+      || y2 > dest_info.height)
+    y2 = MIN (src_info.height, dest_info.height);
+
+  if (x1 >= x2 || y1 >= y2)
+    goto fail2;
+
+  /* Determine the address of the first line to copy.  */
+
+  src_data_1 = src_data;
+  dest_data_1 = dest_data;
+  src_data_1 += x1 * 4;
+  src_data_1 += y1 * src_info.stride;
+  dest_data_1 += x1 * 4;
+  dest_data_1 += y1 * dest_info.stride;
+
+  /* Start copying each line.  */
+
+  while (y1 != y2)
+    {
+      memcpy (dest_data_1, src_data_1, (x2 - x1) * 4);
+      src_data_1 += src_info.stride;
+      dest_data_1 += dest_info.stride;
+      y1++;
+    }
+
+  /* Complete the copy and unlock the bitmap.  */
+
+ fail2:
+  AndroidBitmap_unlockPixels (env, dest);
+ fail1:
+  AndroidBitmap_unlockPixels (env, src);
+}
+
+\f
+
 void
 android_free_pixmap (android_pixmap pixmap)
 {