aboutsummaryrefslogtreecommitdiffstats
path: root/src/android.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/android.c')
-rw-r--r--src/android.c627
1 files changed, 583 insertions, 44 deletions
diff --git a/src/android.c b/src/android.c
index dd841cf383a..db12e244275 100644
--- a/src/android.c
+++ b/src/android.c
@@ -24,6 +24,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
24#include <limits.h> 24#include <limits.h>
25#include <signal.h> 25#include <signal.h>
26#include <semaphore.h> 26#include <semaphore.h>
27#include <dlfcn.h>
27 28
28#include <sys/stat.h> 29#include <sys/stat.h>
29#include <sys/mman.h> 30#include <sys/mman.h>
@@ -46,6 +47,7 @@ bool android_init_gui;
46 47
47#include <android/asset_manager.h> 48#include <android/asset_manager.h>
48#include <android/asset_manager_jni.h> 49#include <android/asset_manager_jni.h>
50#include <android/bitmap.h>
49#include <android/log.h> 51#include <android/log.h>
50 52
51#include <linux/ashmem.h> 53#include <linux/ashmem.h>
@@ -86,6 +88,7 @@ struct android_emacs_pixmap
86{ 88{
87 jclass class; 89 jclass class;
88 jmethodID constructor; 90 jmethodID constructor;
91 jmethodID constructor_mutable;
89}; 92};
90 93
91struct android_graphics_point 94struct android_graphics_point
@@ -94,6 +97,12 @@ struct android_graphics_point
94 jmethodID constructor; 97 jmethodID constructor;
95}; 98};
96 99
100struct android_emacs_drawable
101{
102 jclass class;
103 jmethodID get_bitmap;
104};
105
97/* The asset manager being used. */ 106/* The asset manager being used. */
98static AAssetManager *asset_manager; 107static AAssetManager *asset_manager;
99 108
@@ -106,6 +115,12 @@ char *android_site_load_path;
106/* The path used to store native libraries. */ 115/* The path used to store native libraries. */
107char *android_lib_dir; 116char *android_lib_dir;
108 117
118/* The path used to store game files. */
119char *android_game_path;
120
121/* The display's pixel densities. */
122double android_pixel_density_x, android_pixel_density_y;
123
109/* The Android application data directory. */ 124/* The Android application data directory. */
110static char *android_files_dir; 125static char *android_files_dir;
111 126
@@ -149,6 +164,9 @@ static struct android_emacs_pixmap pixmap_class;
149/* Various methods associated with the Point class. */ 164/* Various methods associated with the Point class. */
150static struct android_graphics_point point_class; 165static struct android_graphics_point point_class;
151 166
167/* Various methods associated with the EmacsDrawable class. */
168static struct android_emacs_drawable drawable_class;
169
152 170
153 171
154/* Event handling functions. Events are stored on a (circular) queue 172/* Event handling functions. Events are stored on a (circular) queue
@@ -383,6 +401,10 @@ android_write_event (union android_event *event)
383 if (!container) 401 if (!container)
384 return; 402 return;
385 403
404 /* If the event queue hasn't been initialized yet, return false. */
405 if (!event_queue.events.next)
406 return;
407
386 pthread_mutex_lock (&event_queue.mutex); 408 pthread_mutex_lock (&event_queue.mutex);
387 409
388 /* The event queue is full, wait for events to be read. */ 410 /* The event queue is full, wait for events to be read. */
@@ -451,6 +473,10 @@ android_select (int nfds, fd_set *readfds, fd_set *writefds,
451 /* Unlock the event queue mutex. */ 473 /* Unlock the event queue mutex. */
452 pthread_mutex_unlock (&event_queue.mutex); 474 pthread_mutex_unlock (&event_queue.mutex);
453 475
476 /* This is to shut up process.c when pselect gets EINTR. */
477 if (nfds_return < 0)
478 errno = EINTR;
479
454 return nfds_return; 480 return nfds_return;
455} 481}
456 482
@@ -793,16 +819,20 @@ android_close (int fd)
793{ 819{
794 if (fd < ANDROID_MAX_ASSET_FD 820 if (fd < ANDROID_MAX_ASSET_FD
795 && (android_table[fd].flags & ANDROID_FD_TABLE_ENTRY_IS_VALID)) 821 && (android_table[fd].flags & ANDROID_FD_TABLE_ENTRY_IS_VALID))
796 { 822 android_table[fd].flags = 0;
797 __android_log_print (ANDROID_LOG_INFO, __func__,
798 "closing android file descriptor %d",
799 fd);
800 android_table[fd].flags = 0;
801 }
802 823
803 return close (fd); 824 return close (fd);
804} 825}
805 826
827/* Return the current user's ``home'' directory, which is actually the
828 app data directory on Android. */
829
830const char *
831android_get_home_directory (void)
832{
833 return android_files_dir;
834}
835
806 836
807 837
808/* JNI functions called by Java. */ 838/* JNI functions called by Java. */
@@ -814,6 +844,8 @@ JNIEXPORT void JNICALL
814NATIVE_NAME (setEmacsParams) (JNIEnv *env, jobject object, 844NATIVE_NAME (setEmacsParams) (JNIEnv *env, jobject object,
815 jobject local_asset_manager, 845 jobject local_asset_manager,
816 jobject files_dir, jobject libs_dir, 846 jobject files_dir, jobject libs_dir,
847 jfloat pixel_density_x,
848 jfloat pixel_density_y,
817 jobject emacs_service_object) 849 jobject emacs_service_object)
818{ 850{
819 int pipefd[2]; 851 int pipefd[2];
@@ -829,6 +861,9 @@ NATIVE_NAME (setEmacsParams) (JNIEnv *env, jobject object,
829 return; 861 return;
830 } 862 }
831 863
864 android_pixel_density_x = pixel_density_x;
865 android_pixel_density_y = pixel_density_y;
866
832 __android_log_print (ANDROID_LOG_INFO, __func__, 867 __android_log_print (ANDROID_LOG_INFO, __func__,
833 "Initializing "PACKAGE_STRING"...\nPlease report bugs to " 868 "Initializing "PACKAGE_STRING"...\nPlease report bugs to "
834 PACKAGE_BUGREPORT". Thanks.\n"); 869 PACKAGE_BUGREPORT". Thanks.\n");
@@ -891,15 +926,23 @@ NATIVE_NAME (setEmacsParams) (JNIEnv *env, jobject object,
891 if (!android_site_load_path) 926 if (!android_site_load_path)
892 emacs_abort (); 927 emacs_abort ();
893 928
929 android_game_path = malloc (PATH_MAX + 1);
930
931 if (!android_game_path)
932 emacs_abort ();
933
894 snprintf (android_site_load_path, PATH_MAX, "%s/site-lisp", 934 snprintf (android_site_load_path, PATH_MAX, "%s/site-lisp",
895 android_files_dir); 935 android_files_dir);
936 snprintf (android_game_path, PATH_MAX, "%s/scores", android_files_dir);
937
896 __android_log_print (ANDROID_LOG_INFO, __func__, 938 __android_log_print (ANDROID_LOG_INFO, __func__,
897 "Site-lisp directory: %s\n" 939 "Site-lisp directory: %s\n"
898 "Files directory: %s\n" 940 "Files directory: %s\n"
899 "Native code directory: %s", 941 "Native code directory: %s\n"
942 "Game score path: %s\n",
900 android_site_load_path, 943 android_site_load_path,
901 android_files_dir, 944 android_files_dir,
902 android_lib_dir); 945 android_lib_dir, android_game_path);
903 946
904 /* Make a reference to the Emacs service. */ 947 /* Make a reference to the Emacs service. */
905 emacs_service = (*env)->NewGlobalRef (env, emacs_service_object); 948 emacs_service = (*env)->NewGlobalRef (env, emacs_service_object);
@@ -997,6 +1040,7 @@ android_init_emacs_pixmap (void)
997 assert (pixmap_class.c_name); 1040 assert (pixmap_class.c_name);
998 1041
999 FIND_METHOD (constructor, "<init>", "(S[IIII)V"); 1042 FIND_METHOD (constructor, "<init>", "(S[IIII)V");
1043 FIND_METHOD (constructor_mutable, "<init>", "(SIII)V");
1000 1044
1001#undef FIND_METHOD 1045#undef FIND_METHOD
1002} 1046}
@@ -1031,6 +1075,36 @@ android_init_graphics_point (void)
1031#undef FIND_METHOD 1075#undef FIND_METHOD
1032} 1076}
1033 1077
1078static void
1079android_init_emacs_drawable (void)
1080{
1081 jclass old;
1082
1083 drawable_class.class
1084 = (*android_java_env)->FindClass (android_java_env,
1085 "org/gnu/emacs/EmacsDrawable");
1086 eassert (drawable_class.class);
1087
1088 old = drawable_class.class;
1089 drawable_class.class
1090 = (jclass) (*android_java_env)->NewGlobalRef (android_java_env,
1091 (jobject) old);
1092 ANDROID_DELETE_LOCAL_REF (old);
1093
1094 if (!drawable_class.class)
1095 emacs_abort ();
1096
1097#define FIND_METHOD(c_name, name, signature) \
1098 drawable_class.c_name \
1099 = (*android_java_env)->GetMethodID (android_java_env, \
1100 drawable_class.class, \
1101 name, signature); \
1102 assert (drawable_class.c_name);
1103
1104 FIND_METHOD (get_bitmap, "getBitmap", "()Landroid/graphics/Bitmap;");
1105#undef FIND_METHOD
1106}
1107
1034extern JNIEXPORT void JNICALL 1108extern JNIEXPORT void JNICALL
1035NATIVE_NAME (initEmacs) (JNIEnv *env, jobject object, jarray argv) 1109NATIVE_NAME (initEmacs) (JNIEnv *env, jobject object, jarray argv)
1036{ 1110{
@@ -1063,6 +1137,15 @@ NATIVE_NAME (initEmacs) (JNIEnv *env, jobject object, jarray argv)
1063 android_init_emacs_service (); 1137 android_init_emacs_service ();
1064 android_init_emacs_pixmap (); 1138 android_init_emacs_pixmap ();
1065 android_init_graphics_point (); 1139 android_init_graphics_point ();
1140 android_init_emacs_drawable ();
1141
1142 /* Set HOME to the app data directory. */
1143 setenv ("HOME", android_files_dir, 1);
1144
1145 /* Set the cwd to that directory as well. */
1146 if (chdir (android_files_dir))
1147 __android_log_print (ANDROID_LOG_WARN, __func__,
1148 "chdir: %s", strerror (errno));
1066 1149
1067 /* Initialize the Android GUI. */ 1150 /* Initialize the Android GUI. */
1068 android_init_gui = true; 1151 android_init_gui = true;
@@ -1099,7 +1182,8 @@ NATIVE_NAME (sendConfigureNotify) (JNIEnv *env, jobject object,
1099extern JNIEXPORT void JNICALL 1182extern JNIEXPORT void JNICALL
1100NATIVE_NAME (sendKeyPress) (JNIEnv *env, jobject object, 1183NATIVE_NAME (sendKeyPress) (JNIEnv *env, jobject object,
1101 jshort window, jlong time, 1184 jshort window, jlong time,
1102 jint state, jint keycode) 1185 jint state, jint keycode,
1186 jint unicode_char)
1103{ 1187{
1104 union android_event event; 1188 union android_event event;
1105 1189
@@ -1108,6 +1192,7 @@ NATIVE_NAME (sendKeyPress) (JNIEnv *env, jobject object,
1108 event.xkey.time = time; 1192 event.xkey.time = time;
1109 event.xkey.state = state; 1193 event.xkey.state = state;
1110 event.xkey.keycode = keycode; 1194 event.xkey.keycode = keycode;
1195 event.xkey.unicode_char = unicode_char;
1111 1196
1112 android_write_event (&event); 1197 android_write_event (&event);
1113} 1198}
@@ -1115,7 +1200,8 @@ NATIVE_NAME (sendKeyPress) (JNIEnv *env, jobject object,
1115extern JNIEXPORT void JNICALL 1200extern JNIEXPORT void JNICALL
1116NATIVE_NAME (sendKeyRelease) (JNIEnv *env, jobject object, 1201NATIVE_NAME (sendKeyRelease) (JNIEnv *env, jobject object,
1117 jshort window, jlong time, 1202 jshort window, jlong time,
1118 jint state, jint keycode) 1203 jint state, jint keycode,
1204 jint unicode_char)
1119{ 1205{
1120 union android_event event; 1206 union android_event event;
1121 1207
@@ -1124,6 +1210,46 @@ NATIVE_NAME (sendKeyRelease) (JNIEnv *env, jobject object,
1124 event.xkey.time = time; 1210 event.xkey.time = time;
1125 event.xkey.state = state; 1211 event.xkey.state = state;
1126 event.xkey.keycode = keycode; 1212 event.xkey.keycode = keycode;
1213 event.xkey.unicode_char = unicode_char;
1214
1215 android_write_event (&event);
1216}
1217
1218extern JNIEXPORT void JNICALL
1219NATIVE_NAME (sendFocusIn) (JNIEnv *env, jobject object,
1220 jshort window, jlong time)
1221{
1222 union android_event event;
1223
1224 event.xkey.type = ANDROID_FOCUS_IN;
1225 event.xkey.window = window;
1226 event.xkey.time = time;
1227
1228 android_write_event (&event);
1229}
1230
1231extern JNIEXPORT void JNICALL
1232NATIVE_NAME (sendFocusOut) (JNIEnv *env, jobject object,
1233 jshort window, jlong time)
1234{
1235 union android_event event;
1236
1237 event.xkey.type = ANDROID_FOCUS_OUT;
1238 event.xkey.window = window;
1239 event.xkey.time = time;
1240
1241 android_write_event (&event);
1242}
1243
1244extern JNIEXPORT void JNICALL
1245NATIVE_NAME (sendWindowAction) (JNIEnv *env, jobject object,
1246 jshort window, jint action)
1247{
1248 union android_event event;
1249
1250 event.xaction.type = ANDROID_WINDOW_ACTION;
1251 event.xaction.window = window;
1252 event.xaction.action = action;
1127 1253
1128 android_write_event (&event); 1254 android_write_event (&event);
1129} 1255}
@@ -1142,13 +1268,6 @@ NATIVE_NAME (sendKeyRelease) (JNIEnv *env, jobject object,
1142 1268
1143#define MAX_HANDLE 65535 1269#define MAX_HANDLE 65535
1144 1270
1145enum android_handle_type
1146 {
1147 ANDROID_HANDLE_WINDOW,
1148 ANDROID_HANDLE_GCONTEXT,
1149 ANDROID_HANDLE_PIXMAP,
1150 };
1151
1152struct android_handle_entry 1271struct android_handle_entry
1153{ 1272{
1154 /* The type. */ 1273 /* The type. */
@@ -1245,7 +1364,7 @@ android_destroy_handle (android_handle handle)
1245 android_handles[handle].handle = NULL; 1364 android_handles[handle].handle = NULL;
1246} 1365}
1247 1366
1248static jobject 1367jobject
1249android_resolve_handle (android_handle handle, 1368android_resolve_handle (android_handle handle,
1250 enum android_handle_type type) 1369 enum android_handle_type type)
1251{ 1370{
@@ -1625,14 +1744,15 @@ android_change_gc (struct android_gc *gc,
1625 ANDROID_HANDLE_PIXMAP); 1744 ANDROID_HANDLE_PIXMAP);
1626 (*android_java_env)->SetObjectField (android_java_env, 1745 (*android_java_env)->SetObjectField (android_java_env,
1627 gcontext, 1746 gcontext,
1628 emacs_gc_stipple, 1747 emacs_gc_clip_mask,
1629 what); 1748 what);
1630 1749
1631 /* Clearing GCClipMask also clears the clip rectangles. */ 1750 /* Clearing GCClipMask also clears the clip rectangles. */
1632 (*android_java_env)->SetObjectField (android_java_env, 1751 if (!what)
1633 gcontext, 1752 (*android_java_env)->SetObjectField (android_java_env,
1634 emacs_gc_clip_rects, 1753 gcontext,
1635 NULL); 1754 emacs_gc_clip_rects,
1755 NULL);
1636 } 1756 }
1637 1757
1638 if (mask & ANDROID_GC_STIPPLE) 1758 if (mask & ANDROID_GC_STIPPLE)
@@ -2008,10 +2128,23 @@ android_create_pixmap_from_bitmap_data (char *data, unsigned int width,
2008 { 2128 {
2009 for (x = 0; x < width; ++x) 2129 for (x = 0; x < width; ++x)
2010 { 2130 {
2011 if (data[y / 8] & (1 << (x % 8))) 2131 if (depth == 24)
2012 region[x] = foreground; 2132 {
2133 /* The alpha channels must be set, or otherwise, the
2134 pixmap will be created entirely transparent. */
2135
2136 if (data[y * (width + 7) / 8 + x / 8] & (1 << (x % 8)))
2137 region[x] = foreground | 0xff000000;
2138 else
2139 region[x] = background | 0xff000000;
2140 }
2013 else 2141 else
2014 region[x] = background; 2142 {
2143 if (data[y * (width + 7) / 8 + x / 8] & (1 << (x % 8)))
2144 region[x] = foreground;
2145 else
2146 region[x] = background;
2147 }
2015 } 2148 }
2016 2149
2017 (*android_java_env)->SetIntArrayRegion (android_java_env, 2150 (*android_java_env)->SetIntArrayRegion (android_java_env,
@@ -2236,36 +2369,21 @@ android_create_pixmap (unsigned int width, unsigned int height,
2236{ 2369{
2237 android_handle prev_max_handle; 2370 android_handle prev_max_handle;
2238 jobject object; 2371 jobject object;
2239 jintArray colors;
2240 android_pixmap pixmap; 2372 android_pixmap pixmap;
2241 2373
2242 /* Create the color array holding the data. */
2243 colors = (*android_java_env)->NewIntArray (android_java_env,
2244 width * height);
2245
2246 if (!colors)
2247 {
2248 (*android_java_env)->ExceptionClear (android_java_env);
2249 memory_full (0);
2250 }
2251
2252 /* First, allocate the pixmap handle. */ 2374 /* First, allocate the pixmap handle. */
2253 prev_max_handle = max_handle; 2375 prev_max_handle = max_handle;
2254 pixmap = android_alloc_id (); 2376 pixmap = android_alloc_id ();
2255 2377
2256 if (!pixmap) 2378 if (!pixmap)
2257 { 2379 error ("Out of pixmap handles!");
2258 ANDROID_DELETE_LOCAL_REF ((jobject) colors);
2259 error ("Out of pixmap handles!");
2260 }
2261 2380
2262 object = (*android_java_env)->NewObject (android_java_env, 2381 object = (*android_java_env)->NewObject (android_java_env,
2263 pixmap_class.class, 2382 pixmap_class.class,
2264 pixmap_class.constructor, 2383 pixmap_class.constructor_mutable,
2265 (jshort) pixmap, colors, 2384 (jshort) pixmap,
2266 (jint) width, (jint) height, 2385 (jint) width, (jint) height,
2267 (jint) depth); 2386 (jint) depth);
2268 ANDROID_DELETE_LOCAL_REF ((jobject) colors);
2269 2387
2270 if (!object) 2388 if (!object)
2271 { 2389 {
@@ -2313,6 +2431,387 @@ android_clear_area (android_window handle, int x, int y,
2313 (jint) width, (jint) height); 2431 (jint) width, (jint) height);
2314} 2432}
2315 2433
2434android_pixmap
2435android_create_bitmap_from_data (char *bits, unsigned int width,
2436 unsigned int height)
2437{
2438 return android_create_pixmap_from_bitmap_data (bits, 1, 0,
2439 width, height, 1);
2440}
2441
2442struct android_image *
2443android_create_image (unsigned int depth, enum android_image_format format,
2444 char *data, unsigned int width, unsigned int height)
2445{
2446 struct android_image *image;
2447
2448 image = xmalloc (sizeof *image);
2449
2450 /* Fill in the fields required by image.c. N.B. that
2451 android_destroy_image ostensibly will free data, but image.c
2452 mostly sets and frees data itself. */
2453 image->width = width;
2454 image->height = height;
2455 image->data = data;
2456 image->depth = depth;
2457 image->format = format;
2458
2459 /* Now fill in the image dimensions. There are only two depths
2460 supported by this function. */
2461
2462 if (depth == 1)
2463 {
2464 image->bytes_per_line = (width + 7) / 8;
2465 image->bits_per_pixel = 1;
2466 }
2467 else if (depth == 24)
2468 {
2469 image->bytes_per_line = width * 4;
2470 image->bits_per_pixel = 32;
2471 }
2472 else
2473 emacs_abort ();
2474
2475 return image;
2476}
2477
2478void
2479android_destroy_image (struct android_image *ximg)
2480{
2481 /* If XIMG->data is NULL, then it has already been freed by
2482 image.c. */
2483
2484 if (ximg->data)
2485 xfree (ximg->data);
2486 xfree (ximg);
2487}
2488
2489void
2490android_put_pixel (struct android_image *ximg, int x, int y,
2491 unsigned long pixel)
2492{
2493 char *byte, *word;
2494 unsigned int r, g, b;
2495
2496 /* Ignore out-of-bounds accesses. */
2497
2498 if (x >= ximg->width || y >= ximg->height || x < 0 || y < 0)
2499 return;
2500
2501 switch (ximg->depth)
2502 {
2503 case 1:
2504 byte = ximg->data + y * ximg->bytes_per_line + x / 8;
2505
2506 if (pixel)
2507 *byte |= (1 << x % 8);
2508 else
2509 *byte &= ~(1 << x % 8);
2510 break;
2511
2512 case 24:
2513 /* Unaligned accesses are problematic on Android devices. */
2514 word = ximg->data + y * ximg->bytes_per_line + x * 4;
2515
2516 /* Swizzle the pixel into ABGR format. Android uses Skia's
2517 ``native color type'', which is ABGR. This is despite the
2518 format being named ``ARGB'', and more confusingly
2519 `ANDROID_BITMAP_FORMAT_RGBA_8888' in bitmap.h. */
2520 r = pixel & 0x00ff0000;
2521 g = pixel & 0x0000ff00;
2522 b = pixel & 0x000000ff;
2523 pixel = (r >> 16) | g | (b << 16) | 0xff000000;
2524
2525 memcpy (word, &pixel, sizeof pixel);
2526 break;
2527 }
2528}
2529
2530unsigned long
2531android_get_pixel (struct android_image *ximg, int x, int y)
2532{
2533 char *byte, *word;
2534 unsigned int pixel, r, g, b;
2535
2536 if (x >= ximg->width || y >= ximg->height
2537 || x < 0 || y < 0)
2538 return 0;
2539
2540 switch (ximg->depth)
2541 {
2542 case 1:
2543 byte = ximg->data + y * ximg->bytes_per_line + x / 8;
2544 return (*byte & (1 << x % 8)) ? 1 : 0;
2545
2546 case 24:
2547 word = ximg->data + y * ximg->bytes_per_line + x * 4;
2548 memcpy (&pixel, word, sizeof pixel);
2549
2550 /* Convert the pixel back to RGB. */
2551 b = pixel & 0x00ff0000;
2552 g = pixel & 0x0000ff00;
2553 r = pixel & 0x000000ff;
2554 pixel = ((r << 16) | g | (b >> 16)) & ~0xff000000;
2555
2556 return pixel;
2557 }
2558
2559 emacs_abort ();
2560}
2561
2562struct android_image *
2563android_get_image (android_drawable handle,
2564 enum android_image_format format)
2565{
2566 jobject drawable, bitmap;
2567 AndroidBitmapInfo bitmap_info;
2568 size_t byte_size;
2569 void *data;
2570 struct android_image *image;
2571 unsigned char *data1, *data2;
2572 int i, x;
2573
2574 /* N.B. that supporting windows requires some more work to make
2575 EmacsDrawable.getBitmap thread safe. */
2576 drawable = android_resolve_handle2 (handle, ANDROID_HANDLE_WINDOW,
2577 ANDROID_HANDLE_PIXMAP);
2578
2579 /* Look up the drawable and get the bitmap corresponding to it.
2580 Then, lock the bitmap's bits. */
2581 bitmap = (*android_java_env)->CallObjectMethod (android_java_env,
2582 drawable,
2583 drawable_class.get_bitmap);
2584 if (!bitmap)
2585 {
2586 (*android_java_env)->ExceptionClear (android_java_env);
2587 memory_full (0);
2588 }
2589
2590 memset (&bitmap_info, 0, sizeof bitmap_info);
2591
2592 /* The NDK doc seems to imply this function can fail but doesn't say
2593 what value it gives when it does! */
2594 AndroidBitmap_getInfo (android_java_env, bitmap, &bitmap_info);
2595
2596 if (!bitmap_info.stride)
2597 {
2598 ANDROID_DELETE_LOCAL_REF (bitmap);
2599 memory_full (0);
2600 }
2601
2602 /* Compute how big the image data will be. Fail if it would be too
2603 big. */
2604
2605 if (bitmap_info.format != ANDROID_BITMAP_FORMAT_A_8)
2606 {
2607 if (INT_MULTIPLY_WRAPV ((size_t) bitmap_info.stride,
2608 (size_t) bitmap_info.height,
2609 &byte_size))
2610 {
2611 ANDROID_DELETE_LOCAL_REF (bitmap);
2612 memory_full (0);
2613 }
2614 }
2615 else
2616 /* This A8 image will be packed into A1 later on. */
2617 byte_size = (bitmap_info.width + 7) / 8;
2618
2619 /* Lock the image data. Once again, the NDK documentation says the
2620 call can fail, but does not say how to determine whether or not
2621 it has failed, nor how the address is aligned. */
2622 data = NULL;
2623 AndroidBitmap_lockPixels (android_java_env, bitmap, &data);
2624
2625 if (!data)
2626 {
2627 /* Take a NULL pointer to mean that AndroidBitmap_lockPixels
2628 failed. */
2629 ANDROID_DELETE_LOCAL_REF (bitmap);
2630 memory_full (0);
2631 }
2632
2633 /* Copy the data into a new struct android_image. */
2634 image = xmalloc (sizeof *image);
2635 image->width = bitmap_info.width;
2636 image->height = bitmap_info.height;
2637 image->data = malloc (byte_size);
2638
2639 if (!image->data)
2640 {
2641 ANDROID_DELETE_LOCAL_REF (bitmap);
2642 xfree (image);
2643 memory_full (byte_size);
2644 }
2645
2646 /* Use the format of the bitmap to determine the image depth. */
2647 switch (bitmap_info.format)
2648 {
2649 case ANDROID_BITMAP_FORMAT_RGBA_8888:
2650 image->depth = 24;
2651 image->bits_per_pixel = 32;
2652 break;
2653
2654 /* A8 images are used by Emacs to represent bitmaps. They have
2655 to be packed manually. */
2656 case ANDROID_BITMAP_FORMAT_A_8:
2657 image->depth = 1;
2658 image->bits_per_pixel = 1;
2659 break;
2660
2661 /* Other formats are currently not supported. */
2662 default:
2663 emacs_abort ();
2664 }
2665
2666 image->format = format;
2667
2668 if (image->depth == 24)
2669 {
2670 image->bytes_per_line = bitmap_info.stride;
2671
2672 /* Copy the bitmap data over. */
2673 memcpy (image->data, data, byte_size);
2674 }
2675 else
2676 {
2677 /* Pack the A8 image data into bits manually. */
2678 image->bytes_per_line = (image->width + 7) / 8;
2679
2680 data1 = (unsigned char *) image->data;
2681 data2 = data;
2682
2683 for (i = 0; i < image->height; ++i)
2684 {
2685 for (x = 0; x < image->width; ++x)
2686 /* Some bits in data1 might be initialized at this point,
2687 but they will all be set properly later. */
2688 data1[x / 8] = (data2[x]
2689 ? (data1[x / 8] | (1 << (x % 8)))
2690 : (data1[x / 8] & ~(1 << (x % 8))));
2691
2692 data1 += image->bytes_per_line;
2693 data2 += bitmap_info.stride;
2694 }
2695 }
2696
2697 /* Unlock the bitmap pixels. */
2698 AndroidBitmap_unlockPixels (android_java_env, bitmap);
2699
2700 /* Delete the bitmap reference. */
2701 ANDROID_DELETE_LOCAL_REF (bitmap);
2702 return image;
2703}
2704
2705void
2706android_put_image (android_pixmap handle, struct android_image *image)
2707{
2708 jobject drawable, bitmap;
2709 AndroidBitmapInfo bitmap_info;
2710 void *data;
2711 unsigned char *data_1, *data_2;
2712 int i, x;
2713
2714 drawable = android_resolve_handle (handle, ANDROID_HANDLE_PIXMAP);
2715
2716 /* Look up the drawable and get the bitmap corresponding to it.
2717 Then, lock the bitmap's bits. */
2718 bitmap = (*android_java_env)->CallObjectMethod (android_java_env,
2719 drawable,
2720 drawable_class.get_bitmap);
2721 if (!bitmap)
2722 {
2723 (*android_java_env)->ExceptionClear (android_java_env);
2724 memory_full (0);
2725 }
2726
2727 memset (&bitmap_info, 0, sizeof bitmap_info);
2728
2729 /* The NDK doc seems to imply this function can fail but doesn't say
2730 what value it gives when it does! */
2731 AndroidBitmap_getInfo (android_java_env, bitmap, &bitmap_info);
2732
2733 if (!bitmap_info.stride)
2734 {
2735 ANDROID_DELETE_LOCAL_REF (bitmap);
2736 memory_full (0);
2737 }
2738
2739 if (bitmap_info.width != image->width
2740 || bitmap_info.height != image->height)
2741 /* This is not yet supported. */
2742 emacs_abort ();
2743
2744 /* Make sure the bitmap formats are compatible with each other. */
2745
2746 if ((image->depth == 24
2747 && bitmap_info.format != ANDROID_BITMAP_FORMAT_RGBA_8888)
2748 || (image->depth == 1
2749 && bitmap_info.format != ANDROID_BITMAP_FORMAT_A_8))
2750 emacs_abort ();
2751
2752 /* Lock the image data. Once again, the NDK documentation says the
2753 call can fail, but does not say how to determine whether or not
2754 it has failed, nor how the address is aligned. */
2755 data = NULL;
2756 AndroidBitmap_lockPixels (android_java_env, bitmap, &data);
2757
2758 if (!data)
2759 {
2760 /* Take a NULL pointer to mean that AndroidBitmap_lockPixels
2761 failed. */
2762 ANDROID_DELETE_LOCAL_REF (bitmap);
2763 memory_full (0);
2764 }
2765
2766 data_1 = data;
2767 data_2 = (unsigned char *) image->data;
2768
2769 /* Copy the bitmap data over scanline-by-scanline. */
2770 for (i = 0; i < image->height; ++i)
2771 {
2772 if (image->depth != 1)
2773 memcpy (data_1, data_2,
2774 image->width * (image->bits_per_pixel / 8));
2775 else
2776 {
2777 /* Android internally uses a 1 byte-per-pixel format for
2778 ALPHA_8 images. Expand the image from the 1
2779 bit-per-pixel X format correctly. */
2780
2781 for (x = 0; x < image->width; ++x)
2782 data_1[x] = (data_2[x / 8] & (1 << x % 8)) ? 0xff : 0;
2783 }
2784
2785 data_1 += bitmap_info.stride;
2786 data_2 += image->bytes_per_line;
2787 }
2788
2789 /* Unlock the bitmap pixels. */
2790 AndroidBitmap_unlockPixels (android_java_env, bitmap);
2791
2792 /* Delete the bitmap reference. */
2793 ANDROID_DELETE_LOCAL_REF (bitmap);
2794}
2795
2796
2797
2798#undef faccessat
2799
2800/* Replace the system faccessat with one which understands AT_EACCESS.
2801 Android's faccessat simply fails upon using AT_EACCESS, so repalce
2802 it with zero here. This isn't caught during configuration. */
2803
2804int
2805faccessat (int dirfd, const char *pathname, int mode, int flags)
2806{
2807 static int (*real_faccessat) (int, const char *, int, int);
2808
2809 if (!real_faccessat)
2810 real_faccessat = dlsym (RTLD_NEXT, "faccessat");
2811
2812 return real_faccessat (dirfd, pathname, mode, flags & ~AT_EACCESS);
2813}
2814
2316#else /* ANDROID_STUBIFY */ 2815#else /* ANDROID_STUBIFY */
2317 2816
2318/* X emulation functions for Android. */ 2817/* X emulation functions for Android. */
@@ -2332,4 +2831,44 @@ android_free_gc (struct android_gc *gc)
2332 emacs_abort (); 2831 emacs_abort ();
2333} 2832}
2334 2833
2834struct android_image *
2835android_create_image (unsigned int depth, enum android_image_format format,
2836 char *data, unsigned int width, unsigned int height)
2837{
2838 emacs_abort ();
2839}
2840
2841void
2842android_destroy_image (struct android_image *ximg)
2843{
2844 emacs_abort ();
2845}
2846
2847void
2848android_put_pixel (struct android_image *ximg, int x, int y,
2849 unsigned long pixel)
2850{
2851 emacs_abort ();
2852}
2853
2854unsigned long
2855android_get_pixel (struct android_image *ximg, int x, int y)
2856{
2857 emacs_abort ();
2858}
2859
2860struct android_image *
2861android_get_image (android_drawable drawable,
2862 enum android_image_format format)
2863{
2864 emacs_abort ();
2865}
2866
2867void
2868android_put_image (android_pixmap pixmap,
2869 struct android_image *image)
2870{
2871 emacs_abort ();
2872}
2873
2335#endif 2874#endif