emacs-diffs
[Top][All Lists]
Advanced

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

feature/android 7fdde02f321 4/7: Work around more problems with Bitmaps


From: Po Lu
Subject: feature/android 7fdde02f321 4/7: Work around more problems with Bitmaps
Date: Mon, 29 May 2023 06:07:13 -0400 (EDT)

branch: feature/android
commit 7fdde02f3216536aa8977fa4b396bec8fbaf994b
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>

    Work around more problems with Bitmaps
    
    * 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      | 10 ++++
 java/org/gnu/emacs/EmacsSurfaceView.java | 33 +++++++++--
 src/android.c                            | 98 ++++++++++++++++++++++++++++++++
 3 files changed, 137 insertions(+), 4 deletions(-)

diff --git a/java/org/gnu/emacs/EmacsNative.java 
b/java/org/gnu/emacs/EmacsNative.java
index e699dda9ad4..56c03ee38dc 100644
--- a/java/org/gnu/emacs/EmacsNative.java
+++ b/java/org/gnu/emacs/EmacsNative.java
@@ -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);
 
+
+  /* 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
diff --git a/java/org/gnu/emacs/EmacsSurfaceView.java 
b/java/org/gnu/emacs/EmacsSurfaceView.java
index e0411f7f8b3..0deb930c2c2 100644
--- a/java/org/gnu/emacs/EmacsSurfaceView.java
+++ b/java/org/gnu/emacs/EmacsSurfaceView.java
@@ -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
diff --git a/src/android.c b/src/android.c
index 7b9c478f212..4184be3086b 100644
--- a/src/android.c
+++ b/src/android.c
@@ -4754,6 +4754,104 @@ android_copy_area (android_drawable src, 
android_drawable dest,
 
 
 
+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);
+}
+
+
+
 void
 android_free_pixmap (android_pixmap pixmap)
 {



reply via email to

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