diff options
Diffstat (limited to 'src/android.c')
| -rw-r--r-- | src/android.c | 627 |
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 | ||
| 91 | struct android_graphics_point | 94 | struct android_graphics_point |
| @@ -94,6 +97,12 @@ struct android_graphics_point | |||
| 94 | jmethodID constructor; | 97 | jmethodID constructor; |
| 95 | }; | 98 | }; |
| 96 | 99 | ||
| 100 | struct 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. */ |
| 98 | static AAssetManager *asset_manager; | 107 | static 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. */ |
| 107 | char *android_lib_dir; | 116 | char *android_lib_dir; |
| 108 | 117 | ||
| 118 | /* The path used to store game files. */ | ||
| 119 | char *android_game_path; | ||
| 120 | |||
| 121 | /* The display's pixel densities. */ | ||
| 122 | double android_pixel_density_x, android_pixel_density_y; | ||
| 123 | |||
| 109 | /* The Android application data directory. */ | 124 | /* The Android application data directory. */ |
| 110 | static char *android_files_dir; | 125 | static 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. */ |
| 150 | static struct android_graphics_point point_class; | 165 | static struct android_graphics_point point_class; |
| 151 | 166 | ||
| 167 | /* Various methods associated with the EmacsDrawable class. */ | ||
| 168 | static 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 | |||
| 830 | const char * | ||
| 831 | android_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 | |||
| 814 | NATIVE_NAME (setEmacsParams) (JNIEnv *env, jobject object, | 844 | NATIVE_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 | ||
| 1078 | static void | ||
| 1079 | android_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 | |||
| 1034 | extern JNIEXPORT void JNICALL | 1108 | extern JNIEXPORT void JNICALL |
| 1035 | NATIVE_NAME (initEmacs) (JNIEnv *env, jobject object, jarray argv) | 1109 | NATIVE_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, | |||
| 1099 | extern JNIEXPORT void JNICALL | 1182 | extern JNIEXPORT void JNICALL |
| 1100 | NATIVE_NAME (sendKeyPress) (JNIEnv *env, jobject object, | 1183 | NATIVE_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, | |||
| 1115 | extern JNIEXPORT void JNICALL | 1200 | extern JNIEXPORT void JNICALL |
| 1116 | NATIVE_NAME (sendKeyRelease) (JNIEnv *env, jobject object, | 1201 | NATIVE_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 | |||
| 1218 | extern JNIEXPORT void JNICALL | ||
| 1219 | NATIVE_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 | |||
| 1231 | extern JNIEXPORT void JNICALL | ||
| 1232 | NATIVE_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 | |||
| 1244 | extern JNIEXPORT void JNICALL | ||
| 1245 | NATIVE_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 | ||
| 1145 | enum android_handle_type | ||
| 1146 | { | ||
| 1147 | ANDROID_HANDLE_WINDOW, | ||
| 1148 | ANDROID_HANDLE_GCONTEXT, | ||
| 1149 | ANDROID_HANDLE_PIXMAP, | ||
| 1150 | }; | ||
| 1151 | |||
| 1152 | struct android_handle_entry | 1271 | struct 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 | ||
| 1248 | static jobject | 1367 | jobject |
| 1249 | android_resolve_handle (android_handle handle, | 1368 | android_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 | ||
| 2434 | android_pixmap | ||
| 2435 | android_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 | |||
| 2442 | struct android_image * | ||
| 2443 | android_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 | |||
| 2478 | void | ||
| 2479 | android_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 | |||
| 2489 | void | ||
| 2490 | android_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 | |||
| 2530 | unsigned long | ||
| 2531 | android_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 | |||
| 2562 | struct android_image * | ||
| 2563 | android_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 | |||
| 2705 | void | ||
| 2706 | android_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 | |||
| 2804 | int | ||
| 2805 | faccessat (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 | ||
| 2834 | struct android_image * | ||
| 2835 | android_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 | |||
| 2841 | void | ||
| 2842 | android_destroy_image (struct android_image *ximg) | ||
| 2843 | { | ||
| 2844 | emacs_abort (); | ||
| 2845 | } | ||
| 2846 | |||
| 2847 | void | ||
| 2848 | android_put_pixel (struct android_image *ximg, int x, int y, | ||
| 2849 | unsigned long pixel) | ||
| 2850 | { | ||
| 2851 | emacs_abort (); | ||
| 2852 | } | ||
| 2853 | |||
| 2854 | unsigned long | ||
| 2855 | android_get_pixel (struct android_image *ximg, int x, int y) | ||
| 2856 | { | ||
| 2857 | emacs_abort (); | ||
| 2858 | } | ||
| 2859 | |||
| 2860 | struct android_image * | ||
| 2861 | android_get_image (android_drawable drawable, | ||
| 2862 | enum android_image_format format) | ||
| 2863 | { | ||
| 2864 | emacs_abort (); | ||
| 2865 | } | ||
| 2866 | |||
| 2867 | void | ||
| 2868 | android_put_image (android_pixmap pixmap, | ||
| 2869 | struct android_image *image) | ||
| 2870 | { | ||
| 2871 | emacs_abort (); | ||
| 2872 | } | ||
| 2873 | |||
| 2335 | #endif | 2874 | #endif |