aboutsummaryrefslogtreecommitdiffstats
path: root/src/android.c
diff options
context:
space:
mode:
authorPo Lu2023-01-19 22:19:06 +0800
committerPo Lu2023-01-19 22:19:06 +0800
commita496509cedb17109d0e6297a74e2ff8ed526333c (patch)
tree46f3db2be263de7074675a5188796e25f21d4888 /src/android.c
parent6253e7e74249c7cdfa86723f0b91a1d207cb143e (diff)
downloademacs-a496509cedb17109d0e6297a74e2ff8ed526333c.tar.gz
emacs-a496509cedb17109d0e6297a74e2ff8ed526333c.zip
Update Android port
* .gitignore: Add new files. * INSTALL.android: Explain how to build Emacs for ancient versions of Android. * admin/merge-gnulib (GNULIB_MODULES): Add getdelim. * build-aux/config.guess (timestamp, version): * build-aux/config.sub (timestamp, version): Autoupdate. * configure.ac (BUILD_DETAILS, ANDROID_MIN_SDK): (ANDROID_STUBIFY): Allow specifying CFLAGS via ANDROID_CFLAGS. Add new configure tests for Android API version when not explicitly specified. * doc/emacs/android.texi (Android): Add reference to ``Other Input Devices''. (Android File System): Remove restrictions on directory-files on the assets directory. * doc/emacs/emacs.texi (Top): Add Other Input Devices to menu. * doc/emacs/input.texi (Other Input Devices): New node. * doc/lispref/commands.texi (Touchscreen Events): Document changes to touchscreen input events. * doc/lispref/frames.texi (Pop-Up Menus): Likewise. * etc/NEWS: Announce changes. * java/Makefile.in: Use lib-src/asset-directory-tool to generate an `directory-tree' file placed in /assets. * java/debug.sh: Large adjustments to support Android 2.2 and later. * java/org/gnu/emacs/EmacsContextMenu.java (inflateMenuItems): * java/org/gnu/emacs/EmacsCopyArea.java (perform): * java/org/gnu/emacs/EmacsDialog.java (toAlertDialog): * java/org/gnu/emacs/EmacsDrawLine.java (perform): * java/org/gnu/emacs/EmacsDrawRectangle.java (perform): * java/org/gnu/emacs/EmacsDrawable.java (EmacsDrawable): * java/org/gnu/emacs/EmacsFillPolygon.java (perform): * java/org/gnu/emacs/EmacsFillRectangle.java (perform): * java/org/gnu/emacs/EmacsGC.java (EmacsGC): * java/org/gnu/emacs/EmacsPixmap.java (EmacsPixmap): (destroyHandle): * java/org/gnu/emacs/EmacsSdk7FontDriver.java (draw): Avoid redundant canvas saves and restores. * java/org/gnu/emacs/EmacsService.java (run): * java/org/gnu/emacs/EmacsView.java (EmacsView): (handleDirtyBitmap): * java/org/gnu/emacs/EmacsWindow.java (changeWindowBackground) (EmacsWindow): Make compatible with Android 2.2 and later. * lib-src/Makefile.in (DONT_INSTALL): Add asset-directory-tool on Android.:(asset-directory-tool{EXEEXT}): New target. * lib-src/asset-directory-tool.c (struct directory_tree, xmalloc) (main_1, main_2, main): New file. * lib, m4: Merge from gnulib. This will be reverted before merging to master. * lisp/button.el (button-map): (push-button): * lisp/frame.el (display-popup-menus-p): Improve touchscreen support. * lisp/subr.el (event-start): (event-end): Handle touchscreen events. * lisp/touch-screen.el (touch-screen-handle-timeout): (touch-screen-handle-point-update): (touch-screen-handle-point-up): (touch-screen-track-tap): (touch-screen-track-drag): (touch-screen-drag-mode-line-1): (touch-screen-drag-mode-line): New functions. ([mode-line touchscreen-begin]): ([bottom-divider touchscreen-begin]): Bind new events. * lisp/wid-edit.el (widget-event-point): (widget-keymap): (widget-event-start): (widget-button--check-and-call-button): (widget-button-click): Improve touchscreen support. * src/alloc.c (make_lisp_symbol): Avoid ICE on Android NDK GCC. (mark_pinned_symbols): Likewise. * src/android.c (struct android_emacs_window): New struct. (window_class): New variable. (android_run_select_thread): Add workaround for Android platform bug. (android_extract_long, android_scan_directory_tree): New functions. (android_file_access_p): Use those functions instead. (android_init_emacs_window): New function. (android_init_emacs_gc_class): Update signature of `markDirty'. (android_change_gc, android_set_clip_rectangles): Tell the GC whether or not clip rects were dirtied. (android_swap_buffers): Do not look up method every time. (struct android_dir): Adjust for new directory tree lookup. (android_opendir, android_readdir, android_closedir): Likewise. (android_four_corners_bilinear): Fix coding style. (android_ftruncate): New function. * src/android.h: Update prototypes. Replace ftruncate with android_ftruncate when necessary. * src/androidterm.c (handle_one_android_event): Pacify GCC. Fix touch screen tool bar bug. * src/emacs.c (using_utf8): Fix compilation error. * src/fileio.c (Ffile_system_info): Return Qnil when fsusage.o is not built. * src/filelock.c (BOOT_TIME_FILE): Fix definition for Android. * src/frame.c (Fx_parse_geometry): Fix uninitialized variable uses. * src/keyboard.c (lispy_function_keys): Fix `back'. * src/menu.c (x_popup_menu_1): Handle touch screen events. (Fx_popup_menu): Document changes. * src/sfnt.c (main): Improve tests. * src/sfntfont-android.c (sfntfont_android_put_glyphs): Fix minor problem. (init_sfntfont_android): Check for HAVE_DECL_ANDROID_GET_DEVICE_API_LEVEL. * src/sfntfont.c (struct sfnt_font_desc): New fields `adstyle' and `languages'. (sfnt_parse_style): Append tokens to adstyle. (sfnt_parse_languages): New function. (sfnt_enum_font_1): Parse supported languages and adstyle. (sfntfont_list_1): Handle new fields. (sfntfont_text_extents): Fix uninitialized variable use. (syms_of_sfntfont, mark_sfntfont): Adjust accordingly.
Diffstat (limited to 'src/android.c')
-rw-r--r--src/android.c569
1 files changed, 455 insertions, 114 deletions
diff --git a/src/android.c b/src/android.c
index cfb79045c0b..eb9c404f1a3 100644
--- a/src/android.c
+++ b/src/android.c
@@ -54,6 +54,9 @@ bool android_init_gui;
54#include <android/log.h> 54#include <android/log.h>
55 55
56#include <linux/ashmem.h> 56#include <linux/ashmem.h>
57#include <linux/unistd.h>
58
59#include <sys/syscall.h>
57 60
58#define ANDROID_THROW(env, class, msg) \ 61#define ANDROID_THROW(env, class, msg) \
59 ((*(env))->ThrowNew ((env), (*(env))->FindClass ((env), class), msg)) 62 ((*(env))->ThrowNew ((env), (*(env))->FindClass ((env), class), msg))
@@ -114,6 +117,12 @@ struct android_emacs_drawable
114 jmethodID damage_rect; 117 jmethodID damage_rect;
115}; 118};
116 119
120struct android_emacs_window
121{
122 jclass class;
123 jmethodID swap_buffers;
124};
125
117/* The asset manager being used. */ 126/* The asset manager being used. */
118static AAssetManager *asset_manager; 127static AAssetManager *asset_manager;
119 128
@@ -181,6 +190,9 @@ static struct android_graphics_point point_class;
181/* Various methods associated with the EmacsDrawable class. */ 190/* Various methods associated with the EmacsDrawable class. */
182static struct android_emacs_drawable drawable_class; 191static struct android_emacs_drawable drawable_class;
183 192
193/* Various methods associated with the EmacsWindow class. */
194static struct android_emacs_window window_class;
195
184 196
185 197
186/* Event handling functions. Events are stored on a (circular) queue 198/* Event handling functions. Events are stored on a (circular) queue
@@ -247,10 +259,21 @@ android_run_select_thread (void *data)
247 259
248 sigfillset (&signals); 260 sigfillset (&signals);
249 261
262#if __ANDROID_API__ < 16
263 /* sigprocmask must be used instead of pthread_sigmask due to a bug
264 in Android versions earlier than 16. It only affects the calling
265 thread on Android anyhow. */
266
267 if (sigprocmask (SIG_BLOCK, &signals, NULL))
268 __android_log_print (ANDROID_LOG_FATAL, __func__,
269 "sigprocmask: %s",
270 strerror (errno));
271#else
250 if (pthread_sigmask (SIG_BLOCK, &signals, NULL)) 272 if (pthread_sigmask (SIG_BLOCK, &signals, NULL))
251 __android_log_print (ANDROID_LOG_FATAL, __func__, 273 __android_log_print (ANDROID_LOG_FATAL, __func__,
252 "pthread_sigmask: %s", 274 "pthread_sigmask: %s",
253 strerror (errno)); 275 strerror (errno));
276#endif
254 277
255 sigdelset (&signals, SIGUSR1); 278 sigdelset (&signals, SIGUSR1);
256 sigemptyset (&waitset); 279 sigemptyset (&waitset);
@@ -292,6 +315,8 @@ android_run_select_thread (void *data)
292 still be locked, so this must come before. */ 315 still be locked, so this must come before. */
293 sem_post (&android_pselect_sem); 316 sem_post (&android_pselect_sem);
294 } 317 }
318
319 return NULL;
295} 320}
296 321
297static void 322static void
@@ -538,6 +563,200 @@ android_run_debug_thread (void *data)
538 563
539 564
540 565
566/* Asset directory handling functions. ``directory-tree'' is a file in
567 the root of the assets directory describing its contents.
568
569 See lib-src/asset-directory-tool for more details. */
570
571/* The Android directory tree. */
572static const char *directory_tree;
573
574/* The size of the directory tree. */
575static size_t directory_tree_size;
576
577/* Read an unaligned (32-bit) long from the address POINTER. */
578
579static unsigned int
580android_extract_long (char *pointer)
581{
582 unsigned int number;
583
584 memcpy (&number, pointer, sizeof number);
585 return number;
586}
587
588/* Scan to the file FILE in the asset directory tree. Return a
589 pointer to the end of that file (immediately before any children)
590 in the directory tree, or NULL if that file does not exist.
591
592 If returning non-NULL, also return the offset to the end of the
593 last subdirectory or file in *LIMIT_RETURN. LIMIT_RETURN may be
594 NULL.
595
596 FILE must have less than 11 levels of nesting. If it ends with a
597 trailing slash, then NULL will be returned if it is not actually a
598 directory. */
599
600static const char *
601android_scan_directory_tree (char *file, size_t *limit_return)
602{
603 char *token, *saveptr, *copy, *copy1, *start, *max, *limit;
604 size_t token_length, ntokens, i;
605 char *tokens[10];
606
607 USE_SAFE_ALLOCA;
608
609 /* Skip past the 5 byte header. */
610 start = (char *) directory_tree + 5;
611
612 /* Figure out the current limit. */
613 limit = (char *) directory_tree + directory_tree_size;
614
615 /* Now, split `file' into tokens, with the delimiter being the file
616 name separator. Look for the file and seek past it. */
617
618 ntokens = 0;
619 saveptr = NULL;
620 copy = copy1 = xstrdup (file);
621 memset (tokens, 0, sizeof tokens);
622
623 while ((token = strtok_r (copy, "/", &saveptr)))
624 {
625 copy = NULL;
626
627 /* Make sure ntokens is within bounds. */
628 if (ntokens == ARRAYELTS (tokens))
629 {
630 xfree (copy1);
631 goto fail;
632 }
633
634 tokens[ntokens] = SAFE_ALLOCA (strlen (token) + 1);
635 memcpy (tokens[ntokens], token, strlen (token) + 1);
636 ntokens++;
637 }
638
639 /* Free the copy created for strtok_r. */
640 xfree (copy1);
641
642 /* If there are no tokens, just return the start of the directory
643 tree. */
644 if (!ntokens)
645 {
646 SAFE_FREE ();
647
648 /* Subtract the initial header bytes. */
649 if (limit_return)
650 *limit_return = directory_tree_size - 5;
651
652 return start;
653 }
654
655 /* Loop through tokens, indexing the directory tree each time. */
656
657 for (i = 0; i < ntokens; ++i)
658 {
659 token = tokens[i];
660
661 /* Figure out how many bytes to compare. */
662 token_length = strlen (token);
663
664 again:
665
666 /* If this would be past the directory, return NULL. */
667 if (start + token_length > limit)
668 goto fail;
669
670 /* Now compare the file name. */
671 if (!memcmp (start, token, token_length))
672 {
673 /* They probably match. Find the NULL byte. It must be
674 either one byte past start + token_length, with the last
675 byte a trailing slash (indicating that it is a
676 directory), or just start + token_length. Return 4 bytes
677 past the next NULL byte. */
678
679 max = memchr (start, 0, limit - start);
680
681 if (max != start + token_length
682 && !(max == start + token_length + 1
683 && *(max - 1) == '/'))
684 goto false_positive;
685
686 /* Return it if it exists and is in range, and this is the
687 last token. Otherwise, set it as start and the limit as
688 start + the offset and continue the loop. */
689
690 if (max && max + 5 <= limit)
691 {
692 if (i < ntokens - 1)
693 {
694 start = max + 5;
695 limit = ((char *) directory_tree
696 + android_extract_long (max + 1));
697
698 /* Make sure limit is still in range. */
699 if (limit > directory_tree + directory_tree_size
700 || start > directory_tree + directory_tree_size)
701 goto fail;
702
703 continue;
704 }
705
706 /* Now see if max is not a directory and file is. If
707 file is a directory, then return NULL. */
708 if (*(max - 1) != '/' && file[strlen (file) - 1] == '/')
709 max = NULL;
710 else
711 {
712 /* Figure out the limit. */
713 if (limit_return)
714 *limit_return = android_extract_long (max + 1);
715
716 /* Go to the end of this file. */
717 max += 5;
718 }
719
720 SAFE_FREE ();
721 return max;
722 }
723
724 /* Return NULL otherwise. */
725 __android_log_print (ANDROID_LOG_WARN, __func__,
726 "could not scan to end of directory tree"
727 ": %s", file);
728 goto fail;
729 }
730
731 false_positive:
732
733 /* No match was found. Set start to the next sibling and try
734 again. */
735
736 start = memchr (start, 0, limit - start);
737
738 if (!start || start + 5 > limit)
739 goto fail;
740
741 start = ((char *) directory_tree
742 + android_extract_long (start + 1));
743
744 /* Make sure start is still in bounds. */
745
746 if (start > limit)
747 goto fail;
748
749 /* Continue the loop. */
750 goto again;
751 }
752
753 fail:
754 SAFE_FREE ();
755 return NULL;
756}
757
758
759
541/* Intercept USER_FULL_NAME and return something that makes sense if 760/* Intercept USER_FULL_NAME and return something that makes sense if
542 pw->pw_gecos is NULL. */ 761 pw->pw_gecos is NULL. */
543 762
@@ -624,10 +843,6 @@ android_fstatat (int dirfd, const char *restrict pathname,
624bool 843bool
625android_file_access_p (const char *name, int amode) 844android_file_access_p (const char *name, int amode)
626{ 845{
627 AAsset *asset;
628 AAssetDir *directory;
629 int length;
630
631 if (!asset_manager) 846 if (!asset_manager)
632 return false; 847 return false;
633 848
@@ -637,50 +852,11 @@ android_file_access_p (const char *name, int amode)
637 /* /assets always exists. */ 852 /* /assets always exists. */
638 return true; 853 return true;
639 854
640 /* Check if the asset exists by opening it. Suboptimal! */ 855 /* Check if the file exists by looking in the ``directory tree''
641 asset = AAssetManager_open (asset_manager, name, 856 asset generated during the build process. This is used
642 AASSET_MODE_UNKNOWN); 857 instead of the AAsset functions, because the latter are
643 858 buggy and treat directories inconsistently. */
644 if (!asset) 859 return android_scan_directory_tree ((char *) name, NULL) != NULL;
645 {
646 /* See if it's a directory as well. To open a directory
647 with the asset manager, the trailing slash (if specified)
648 must be removed. */
649 directory = AAssetManager_openDir (asset_manager, name);
650
651 if (directory)
652 {
653 /* Make sure the directory actually has files in it. */
654
655 if (!AAssetDir_getNextFileName (directory))
656 {
657 AAssetDir_close (directory);
658 errno = ENOENT;
659 return false;
660 }
661
662 AAssetDir_close (directory);
663 return true;
664 }
665
666 errno = ENOENT;
667 return false;
668 }
669
670 AAsset_close (asset);
671
672 /* If NAME is a directory name, but it was a regular file, set
673 errno to ENOTDIR and return false. This is to behave like
674 faccessat. */
675
676 length = strlen (name);
677 if (name[length - 1] == '/')
678 {
679 errno = ENOTDIR;
680 return false;
681 }
682
683 return true;
684 } 860 }
685 861
686 return false; 862 return false;
@@ -908,8 +1084,13 @@ android_get_home_directory (void)
908 1084
909/* JNI functions called by Java. */ 1085/* JNI functions called by Java. */
910 1086
1087#ifdef __clang__
911#pragma clang diagnostic push 1088#pragma clang diagnostic push
912#pragma clang diagnostic ignored "-Wmissing-prototypes" 1089#pragma clang diagnostic ignored "-Wmissing-prototypes"
1090#else
1091#pragma GCC diagnostic push
1092#pragma GCC diagnostic ignored "-Wmissing-prototypes"
1093#endif
913 1094
914JNIEXPORT void JNICALL 1095JNIEXPORT void JNICALL
915NATIVE_NAME (setEmacsParams) (JNIEnv *env, jobject object, 1096NATIVE_NAME (setEmacsParams) (JNIEnv *env, jobject object,
@@ -923,6 +1104,7 @@ NATIVE_NAME (setEmacsParams) (JNIEnv *env, jobject object,
923 int pipefd[2]; 1104 int pipefd[2];
924 pthread_t thread; 1105 pthread_t thread;
925 const char *java_string; 1106 const char *java_string;
1107 AAsset *asset;
926 1108
927 /* This may be called from multiple threads. setEmacsParams should 1109 /* This may be called from multiple threads. setEmacsParams should
928 only ever be called once. */ 1110 only ever be called once. */
@@ -943,6 +1125,33 @@ NATIVE_NAME (setEmacsParams) (JNIEnv *env, jobject object,
943 /* Set the asset manager. */ 1125 /* Set the asset manager. */
944 asset_manager = AAssetManager_fromJava (env, local_asset_manager); 1126 asset_manager = AAssetManager_fromJava (env, local_asset_manager);
945 1127
1128 /* Initialize the directory tree. */
1129 asset = AAssetManager_open (asset_manager, "directory-tree",
1130 AASSET_MODE_BUFFER);
1131
1132 if (!asset)
1133 {
1134 __android_log_print (ANDROID_LOG_FATAL, __func__,
1135 "Failed to open directory tree");
1136 emacs_abort ();
1137 }
1138
1139 directory_tree = AAsset_getBuffer (asset);
1140
1141 if (!directory_tree)
1142 emacs_abort ();
1143
1144 /* Now figure out how big the directory tree is, and compare the
1145 first few bytes. */
1146 directory_tree_size = AAsset_getLength (asset);
1147 if (directory_tree_size < 5
1148 || memcmp (directory_tree, "EMACS", 5))
1149 {
1150 __android_log_print (ANDROID_LOG_FATAL, __func__,
1151 "Directory tree has bad magic");
1152 emacs_abort ();
1153 }
1154
946 /* Hold a VM reference to the asset manager to prevent the native 1155 /* Hold a VM reference to the asset manager to prevent the native
947 object from being deleted. */ 1156 object from being deleted. */
948 (*env)->NewGlobalRef (env, local_asset_manager); 1157 (*env)->NewGlobalRef (env, local_asset_manager);
@@ -1199,6 +1408,36 @@ android_init_emacs_drawable (void)
1199#undef FIND_METHOD 1408#undef FIND_METHOD
1200} 1409}
1201 1410
1411static void
1412android_init_emacs_window (void)
1413{
1414 jclass old;
1415
1416 window_class.class
1417 = (*android_java_env)->FindClass (android_java_env,
1418 "org/gnu/emacs/EmacsWindow");
1419 eassert (window_class.class);
1420
1421 old = window_class.class;
1422 window_class.class
1423 = (jclass) (*android_java_env)->NewGlobalRef (android_java_env,
1424 (jobject) old);
1425 ANDROID_DELETE_LOCAL_REF (old);
1426
1427 if (!window_class.class)
1428 emacs_abort ();
1429
1430#define FIND_METHOD(c_name, name, signature) \
1431 window_class.c_name \
1432 = (*android_java_env)->GetMethodID (android_java_env, \
1433 window_class.class, \
1434 name, signature); \
1435 assert (window_class.c_name);
1436
1437 FIND_METHOD (swap_buffers, "swapBuffers", "()V");
1438#undef FIND_METHOD
1439}
1440
1202extern JNIEXPORT void JNICALL 1441extern JNIEXPORT void JNICALL
1203NATIVE_NAME (initEmacs) (JNIEnv *env, jobject object, jarray argv) 1442NATIVE_NAME (initEmacs) (JNIEnv *env, jobject object, jarray argv)
1204{ 1443{
@@ -1232,6 +1471,7 @@ NATIVE_NAME (initEmacs) (JNIEnv *env, jobject object, jarray argv)
1232 android_init_emacs_pixmap (); 1471 android_init_emacs_pixmap ();
1233 android_init_graphics_point (); 1472 android_init_graphics_point ();
1234 android_init_emacs_drawable (); 1473 android_init_emacs_drawable ();
1474 android_init_emacs_window ();
1235 1475
1236 /* Set HOME to the app data directory. */ 1476 /* Set HOME to the app data directory. */
1237 setenv ("HOME", android_files_dir, 1); 1477 setenv ("HOME", android_files_dir, 1);
@@ -1545,7 +1785,11 @@ NATIVE_NAME (sendContextMenu) (JNIEnv *env, jobject object,
1545 android_write_event (&event); 1785 android_write_event (&event);
1546} 1786}
1547 1787
1788#ifdef __clang__
1548#pragma clang diagnostic pop 1789#pragma clang diagnostic pop
1790#else
1791#pragma GCC diagnostic pop
1792#endif
1549 1793
1550 1794
1551 1795
@@ -1557,8 +1801,6 @@ NATIVE_NAME (sendContextMenu) (JNIEnv *env, jobject object,
1557 This means that every local reference must be explicitly destroyed 1801 This means that every local reference must be explicitly destroyed
1558 with DeleteLocalRef. A helper macro is provided to do this. */ 1802 with DeleteLocalRef. A helper macro is provided to do this. */
1559 1803
1560#define MAX_HANDLE 65535
1561
1562struct android_handle_entry 1804struct android_handle_entry
1563{ 1805{
1564 /* The type. */ 1806 /* The type. */
@@ -1883,7 +2125,7 @@ android_init_emacs_gc_class (void)
1883 emacs_gc_mark_dirty 2125 emacs_gc_mark_dirty
1884 = (*android_java_env)->GetMethodID (android_java_env, 2126 = (*android_java_env)->GetMethodID (android_java_env,
1885 emacs_gc_class, 2127 emacs_gc_class,
1886 "markDirty", "()V"); 2128 "markDirty", "(Z)V");
1887 assert (emacs_gc_mark_dirty); 2129 assert (emacs_gc_mark_dirty);
1888 2130
1889 old = emacs_gc_class; 2131 old = emacs_gc_class;
@@ -2011,6 +2253,9 @@ android_change_gc (struct android_gc *gc,
2011 struct android_gc_values *values) 2253 struct android_gc_values *values)
2012{ 2254{
2013 jobject what, gcontext; 2255 jobject what, gcontext;
2256 jboolean clip_changed;
2257
2258 clip_changed = false;
2014 2259
2015 android_init_emacs_gc_class (); 2260 android_init_emacs_gc_class ();
2016 gcontext = android_resolve_handle (gc->gcontext, 2261 gcontext = android_resolve_handle (gc->gcontext,
@@ -2041,16 +2286,22 @@ android_change_gc (struct android_gc *gc,
2041 values->function); 2286 values->function);
2042 2287
2043 if (mask & ANDROID_GC_CLIP_X_ORIGIN) 2288 if (mask & ANDROID_GC_CLIP_X_ORIGIN)
2044 (*android_java_env)->SetIntField (android_java_env, 2289 {
2045 gcontext, 2290 (*android_java_env)->SetIntField (android_java_env,
2046 emacs_gc_clip_x_origin, 2291 gcontext,
2047 values->clip_x_origin); 2292 emacs_gc_clip_x_origin,
2293 values->clip_x_origin);
2294 clip_changed = true;
2295 }
2048 2296
2049 if (mask & ANDROID_GC_CLIP_Y_ORIGIN) 2297 if (mask & ANDROID_GC_CLIP_Y_ORIGIN)
2050 (*android_java_env)->SetIntField (android_java_env, 2298 {
2051 gcontext, 2299 (*android_java_env)->SetIntField (android_java_env,
2052 emacs_gc_clip_y_origin, 2300 gcontext,
2053 values->clip_y_origin); 2301 emacs_gc_clip_y_origin,
2302 values->clip_y_origin);
2303 clip_changed = true;
2304 }
2054 2305
2055 if (mask & ANDROID_GC_CLIP_MASK) 2306 if (mask & ANDROID_GC_CLIP_MASK)
2056 { 2307 {
@@ -2070,6 +2321,7 @@ android_change_gc (struct android_gc *gc,
2070 xfree (gc->clip_rects); 2321 xfree (gc->clip_rects);
2071 gc->clip_rects = NULL; 2322 gc->clip_rects = NULL;
2072 gc->num_clip_rects = -1; 2323 gc->num_clip_rects = -1;
2324 clip_changed = true;
2073 } 2325 }
2074 2326
2075 if (mask & ANDROID_GC_STIPPLE) 2327 if (mask & ANDROID_GC_STIPPLE)
@@ -2103,7 +2355,8 @@ android_change_gc (struct android_gc *gc,
2103 if (mask) 2355 if (mask)
2104 (*android_java_env)->CallVoidMethod (android_java_env, 2356 (*android_java_env)->CallVoidMethod (android_java_env,
2105 gcontext, 2357 gcontext,
2106 emacs_gc_mark_dirty); 2358 emacs_gc_mark_dirty,
2359 (jboolean) clip_changed);
2107} 2360}
2108 2361
2109void 2362void
@@ -2174,7 +2427,8 @@ android_set_clip_rectangles (struct android_gc *gc, int clip_x_origin,
2174 2427
2175 (*android_java_env)->CallVoidMethod (android_java_env, 2428 (*android_java_env)->CallVoidMethod (android_java_env,
2176 gcontext, 2429 gcontext,
2177 emacs_gc_mark_dirty); 2430 emacs_gc_mark_dirty,
2431 (jboolean) true);
2178 2432
2179 /* Cache the clip rectangles on the C side for 2433 /* Cache the clip rectangles on the C side for
2180 sfntfont-android.c. */ 2434 sfntfont-android.c. */
@@ -2327,18 +2581,15 @@ android_swap_buffers (struct android_swap_info *swap_info,
2327 int num_windows) 2581 int num_windows)
2328{ 2582{
2329 jobject window; 2583 jobject window;
2330 jmethodID swap_buffers;
2331 int i; 2584 int i;
2332 2585
2333 swap_buffers = android_lookup_method ("org/gnu/emacs/EmacsWindow",
2334 "swapBuffers", "()V");
2335
2336 for (i = 0; i < num_windows; ++i) 2586 for (i = 0; i < num_windows; ++i)
2337 { 2587 {
2338 window = android_resolve_handle (swap_info[i].swap_window, 2588 window = android_resolve_handle (swap_info[i].swap_window,
2339 ANDROID_HANDLE_WINDOW); 2589 ANDROID_HANDLE_WINDOW);
2340 (*android_java_env)->CallVoidMethod (android_java_env, 2590 (*android_java_env)->CallVoidMethod (android_java_env,
2341 window, swap_buffers); 2591 window,
2592 window_class.swap_buffers);
2342 } 2593 }
2343} 2594}
2344 2595
@@ -3555,11 +3806,17 @@ android_sync (void)
3555 3806
3556 3807
3557 3808
3809#if __ANDROID_API__ >= 17
3810
3558#undef faccessat 3811#undef faccessat
3559 3812
3560/* Replace the system faccessat with one which understands AT_EACCESS. 3813/* Replace the system faccessat with one which understands AT_EACCESS.
3561 Android's faccessat simply fails upon using AT_EACCESS, so repalce 3814 Android's faccessat simply fails upon using AT_EACCESS, so repalce
3562 it with zero here. This isn't caught during configuration. */ 3815 it with zero here. This isn't caught during configuration.
3816
3817 This replacement is only done when building for Android 17 or
3818 later, because earlier versions use the gnulib replacement that
3819 lacks these issues. */
3563 3820
3564int 3821int
3565faccessat (int dirfd, const char *pathname, int mode, int flags) 3822faccessat (int dirfd, const char *pathname, int mode, int flags)
@@ -3572,6 +3829,8 @@ faccessat (int dirfd, const char *pathname, int mode, int flags)
3572 return real_faccessat (dirfd, pathname, mode, flags & ~AT_EACCESS); 3829 return real_faccessat (dirfd, pathname, mode, flags & ~AT_EACCESS);
3573} 3830}
3574 3831
3832#endif /* __ANDROID_API__ < 16 */
3833
3575 3834
3576 3835
3577/* Directory listing emulation. */ 3836/* Directory listing emulation. */
@@ -3581,8 +3840,11 @@ struct android_dir
3581 /* The real DIR *, if it exists. */ 3840 /* The real DIR *, if it exists. */
3582 DIR *dir; 3841 DIR *dir;
3583 3842
3584 /* Otherwise, the AAssetDir. */ 3843 /* Otherwise, the pointer to the directory in directory_tree. */
3585 void *asset_dir; 3844 char *asset_dir;
3845
3846 /* And the end of the files in asset_dir. */
3847 char *asset_limit;
3586}; 3848};
3587 3849
3588/* Like opendir. However, return an asset directory if NAME points to 3850/* Like opendir. However, return an asset directory if NAME points to
@@ -3592,8 +3854,9 @@ struct android_dir *
3592android_opendir (const char *name) 3854android_opendir (const char *name)
3593{ 3855{
3594 struct android_dir *dir; 3856 struct android_dir *dir;
3595 AAssetDir *asset_dir; 3857 char *asset_dir;
3596 const char *asset_name; 3858 const char *asset_name;
3859 size_t limit;
3597 3860
3598 asset_name = android_get_asset_name (name); 3861 asset_name = android_get_asset_name (name);
3599 3862
@@ -3601,8 +3864,9 @@ android_opendir (const char *name)
3601 directory. */ 3864 directory. */
3602 if (asset_manager && asset_name) 3865 if (asset_manager && asset_name)
3603 { 3866 {
3604 asset_dir = AAssetManager_openDir (asset_manager, 3867 asset_dir
3605 asset_name); 3868 = (char *) android_scan_directory_tree ((char *) asset_name,
3869 &limit);
3606 3870
3607 if (!asset_dir) 3871 if (!asset_dir)
3608 { 3872 {
@@ -3613,6 +3877,20 @@ android_opendir (const char *name)
3613 dir = xmalloc (sizeof *dir); 3877 dir = xmalloc (sizeof *dir);
3614 dir->dir = NULL; 3878 dir->dir = NULL;
3615 dir->asset_dir = asset_dir; 3879 dir->asset_dir = asset_dir;
3880 dir->asset_limit = (char *) directory_tree + limit;
3881
3882 /* Make sure dir->asset_limit is within bounds. It is a limit,
3883 and as such can be exactly one byte past directory_tree. */
3884 if (dir->asset_limit > directory_tree + directory_tree_size)
3885 {
3886 xfree (dir);
3887 __android_log_print (ANDROID_LOG_VERBOSE, __func__,
3888 "Invalid dir tree, limit %zu, size %zu\n",
3889 limit, directory_tree_size);
3890 dir = NULL;
3891 errno = EACCES;
3892 }
3893
3616 return dir; 3894 return dir;
3617 } 3895 }
3618 3896
@@ -3636,23 +3914,55 @@ struct dirent *
3636android_readdir (struct android_dir *dir) 3914android_readdir (struct android_dir *dir)
3637{ 3915{
3638 static struct dirent dirent; 3916 static struct dirent dirent;
3639 const char *filename; 3917 const char *last;
3640 3918
3641 if (dir->asset_dir) 3919 if (dir->asset_dir)
3642 { 3920 {
3643 filename = AAssetDir_getNextFileName (dir->asset_dir); 3921 /* There are no more files to read. */
3644 errno = 0; 3922 if (dir->asset_dir >= dir->asset_limit)
3923 return NULL;
3924
3925 /* Otherwise, scan forward looking for the next NULL byte. */
3926 last = memchr (dir->asset_dir, 0,
3927 dir->asset_limit - dir->asset_dir);
3928
3929 /* No more NULL bytes remain. */
3930 if (!last)
3931 return NULL;
3932
3933 /* Forward last past the NULL byte. */
3934 last++;
3645 3935
3646 if (!filename) 3936 /* Make sure it is still within the directory tree. */
3937 if (last >= directory_tree + directory_tree_size)
3647 return NULL; 3938 return NULL;
3648 3939
3940 /* Now, fill in the dirent with the name. */
3649 memset (&dirent, 0, sizeof dirent); 3941 memset (&dirent, 0, sizeof dirent);
3650 dirent.d_ino = 0; 3942 dirent.d_ino = 0;
3651 dirent.d_off = 0; 3943 dirent.d_off = 0;
3652 dirent.d_reclen = sizeof dirent; 3944 dirent.d_reclen = sizeof dirent;
3653 dirent.d_type = DT_UNKNOWN; 3945 dirent.d_type = DT_UNKNOWN;
3654 strncpy (dirent.d_name, filename, 3946
3655 sizeof dirent.d_name - 1); 3947 /* Note that dir->asset_dir is actually a NULL terminated
3948 string. */
3949 memcpy (dirent.d_name, dir->asset_dir,
3950 MIN (sizeof dirent.d_name,
3951 last - dir->asset_dir));
3952 dirent.d_name[sizeof dirent.d_name - 1] = '\0';
3953
3954 /* Strip off the trailing slash, if any. */
3955 if (dirent.d_name[MIN (sizeof dirent.d_name,
3956 last - dir->asset_dir)
3957 - 2] == '/')
3958 dirent.d_name[MIN (sizeof dirent.d_name,
3959 last - dir->asset_dir)
3960 - 2] = '\0';
3961
3962 /* Finally, forward dir->asset_dir to the file past last. */
3963 dir->asset_dir = ((char *) directory_tree
3964 + android_extract_long ((char *) last));
3965
3656 return &dirent; 3966 return &dirent;
3657 } 3967 }
3658 3968
@@ -3666,8 +3976,9 @@ android_closedir (struct android_dir *dir)
3666{ 3976{
3667 if (dir->dir) 3977 if (dir->dir)
3668 closedir (dir->dir); 3978 closedir (dir->dir);
3669 else 3979
3670 AAssetDir_close (dir->asset_dir); 3980 /* There is no need to close anything else, as the directory tree
3981 lies in statically allocated memory. */
3671 3982
3672 xfree (dir); 3983 xfree (dir);
3673} 3984}
@@ -3795,40 +4106,40 @@ android_four_corners_bilinear (unsigned int tl, unsigned int tr,
3795 unsigned int bl, unsigned int br, 4106 unsigned int bl, unsigned int br,
3796 int distx, int disty) 4107 int distx, int disty)
3797{ 4108{
3798 int distxy, distxiy, distixy, distixiy; 4109 int distxy, distxiy, distixy, distixiy;
3799 uint32_t f, r; 4110 uint32_t f, r;
3800 4111
3801 distxy = distx * disty; 4112 distxy = distx * disty;
3802 distxiy = (distx << 8) - distxy; 4113 distxiy = (distx << 8) - distxy;
3803 distixy = (disty << 8) - distxy; 4114 distixy = (disty << 8) - distxy;
3804 distixiy = (256 * 256 - (disty << 8) 4115 distixiy = (256 * 256 - (disty << 8)
3805 - (distx << 8) + distxy); 4116 - (distx << 8) + distxy);
3806 4117
3807 /* Red */ 4118 /* Red */
3808 r = ((tl & 0x000000ff) * distixiy + (tr & 0x000000ff) * distxiy 4119 r = ((tl & 0x000000ff) * distixiy + (tr & 0x000000ff) * distxiy
3809 + (bl & 0x000000ff) * distixy + (br & 0x000000ff) * distxy); 4120 + (bl & 0x000000ff) * distixy + (br & 0x000000ff) * distxy);
3810 4121
3811 /* Green */ 4122 /* Green */
3812 f = ((tl & 0x0000ff00) * distixiy + (tr & 0x0000ff00) * distxiy 4123 f = ((tl & 0x0000ff00) * distixiy + (tr & 0x0000ff00) * distxiy
3813 + (bl & 0x0000ff00) * distixy + (br & 0x0000ff00) * distxy); 4124 + (bl & 0x0000ff00) * distixy + (br & 0x0000ff00) * distxy);
3814 r |= f & 0xff000000; 4125 r |= f & 0xff000000;
3815 4126
3816 /* Now do the upper two components. */ 4127 /* Now do the upper two components. */
3817 tl >>= 16; 4128 tl >>= 16;
3818 tr >>= 16; 4129 tr >>= 16;
3819 bl >>= 16; 4130 bl >>= 16;
3820 br >>= 16; 4131 br >>= 16;
3821 r >>= 16; 4132 r >>= 16;
3822 4133
3823 /* Blue */ 4134 /* Blue */
3824 f = ((tl & 0x000000ff) * distixiy + (tr & 0x000000ff) * distxiy 4135 f = ((tl & 0x000000ff) * distixiy + (tr & 0x000000ff) * distxiy
3825 + (bl & 0x000000ff) * distixy + (br & 0x000000ff) * distxy); 4136 + (bl & 0x000000ff) * distixy + (br & 0x000000ff) * distxy);
3826 r |= f & 0x00ff0000; 4137 r |= f & 0x00ff0000;
3827 4138
3828 /* Alpha */ 4139 /* Alpha */
3829 f = ((tl & 0x0000ff00) * distixiy + (tr & 0x0000ff00) * distxiy 4140 f = ((tl & 0x0000ff00) * distixiy + (tr & 0x0000ff00) * distxiy
3830 + (bl & 0x0000ff00) * distixy + (br & 0x0000ff00) * distxy); 4141 + (bl & 0x0000ff00) * distixy + (br & 0x0000ff00) * distxy);
3831 r |= f & 0xff000000; 4142 r |= f & 0xff000000;
3832 4143
3833 return r; 4144 return r;
3834} 4145}
@@ -4010,6 +4321,36 @@ android_project_image_nearest (struct android_image *image,
4010 } 4321 }
4011} 4322}
4012 4323
4324
4325
4326/* System call wrappers for stuff missing in bionic. */
4327
4328#ifndef HAVE_FTRUNCATE
4329
4330/* ftruncate wrapper for Android, for systems without ftruncate in the
4331 C library.
4332
4333 Such systems are always 32 bit systems, since Android 21 and later
4334 all support ftruncate. In addition, ARM and MIPS require registers
4335 used to store long long parameters to be aligned to an even
4336 register pair. */
4337
4338int
4339android_ftruncate (int fd, off_t length)
4340{
4341 int rc;
4342
4343#if defined __arm__ || defined __mips__
4344 return syscall (SYS_ftruncate64, fd, 0,
4345 (unsigned int) (length & 0xffffffff),
4346 (unsigned int) (length >> 32));
4347#else
4348 return syscall (SYS_ftruncate64, fd, length);
4349#endif
4350}
4351
4352#endif
4353
4013#else /* ANDROID_STUBIFY */ 4354#else /* ANDROID_STUBIFY */
4014 4355
4015/* X emulation functions for Android. */ 4356/* X emulation functions for Android. */