aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/android.c168
-rw-r--r--src/android.h1
-rw-r--r--src/androidfont.c85
-rw-r--r--src/dired.c13
-rw-r--r--src/fileio.c50
-rw-r--r--src/sfntfont-android.c196
6 files changed, 477 insertions, 36 deletions
diff --git a/src/android.c b/src/android.c
index 3f6e6f4576b..a51d0518484 100644
--- a/src/android.c
+++ b/src/android.c
@@ -852,6 +852,26 @@ android_scan_directory_tree (char *file, size_t *limit_return)
852 return NULL; 852 return NULL;
853} 853}
854 854
855/* Return whether or not the directory tree entry DIR is a
856 directory.
857
858 DIR should be a value returned by
859 `android_scan_directory_tree'. */
860
861static bool
862android_is_directory (const char *dir)
863{
864 /* If the directory is the directory tree, then it is a
865 directory. */
866 if (dir == directory_tree + 5)
867 return true;
868
869 /* Otherwise, look 5 bytes behind. If it is `/', then it is a
870 directory. */
871 return (dir - 6 >= directory_tree
872 && *(dir - 6) == '/');
873}
874
855 875
856 876
857/* Intercept USER_FULL_NAME and return something that makes sense if 877/* Intercept USER_FULL_NAME and return something that makes sense if
@@ -899,8 +919,15 @@ android_fstat (int fd, struct stat *statb)
899 return fstat (fd, statb); 919 return fstat (fd, statb);
900} 920}
901 921
922static int android_lookup_asset_directory_fd (int,
923 const char *restrict *,
924 const char *restrict);
925
902/* Like fstatat. However, if dirfd is AT_FDCWD and PATHNAME is an 926/* Like fstatat. However, if dirfd is AT_FDCWD and PATHNAME is an
903 asset, find the information for the corresponding asset. */ 927 asset, find the information for the corresponding asset, and if
928 dirfd is an offset into directory_tree as returned by
929 `android_dirfd', find the information within the corresponding
930 directory tree entry. */
904 931
905int 932int
906android_fstatat (int dirfd, const char *restrict pathname, 933android_fstatat (int dirfd, const char *restrict pathname,
@@ -908,11 +935,40 @@ android_fstatat (int dirfd, const char *restrict pathname,
908{ 935{
909 AAsset *asset_desc; 936 AAsset *asset_desc;
910 const char *asset; 937 const char *asset;
938 const char *asset_dir;
939
940 /* Look up whether or not DIRFD belongs to an open struct
941 android_dir. */
942
943 if (dirfd != AT_FDCWD)
944 dirfd
945 = android_lookup_asset_directory_fd (dirfd, &pathname,
946 pathname);
911 947
912 if (dirfd == AT_FDCWD 948 if (dirfd == AT_FDCWD
913 && asset_manager 949 && asset_manager
914 && (asset = android_get_asset_name (pathname))) 950 && (asset = android_get_asset_name (pathname)))
915 { 951 {
952 /* Look up whether or not PATHNAME happens to be a
953 directory. */
954 asset_dir = android_scan_directory_tree ((char *) asset,
955 NULL);
956
957 if (!asset_dir)
958 {
959 errno = ENOENT;
960 return -1;
961 }
962
963 if (android_is_directory (asset_dir))
964 {
965 memset (statbuf, 0, sizeof *statbuf);
966
967 /* Fill in the stat buffer. */
968 statbuf->st_mode = S_IFDIR | S_IRUSR | S_IRGRP | S_IROTH;
969 return 0;
970 }
971
916 /* AASSET_MODE_STREAMING is fastest here. */ 972 /* AASSET_MODE_STREAMING is fastest here. */
917 asset_desc = AAssetManager_open (asset_manager, asset, 973 asset_desc = AAssetManager_open (asset_manager, asset,
918 AASSET_MODE_STREAMING); 974 AASSET_MODE_STREAMING);
@@ -923,7 +979,7 @@ android_fstatat (int dirfd, const char *restrict pathname,
923 memset (statbuf, 0, sizeof *statbuf); 979 memset (statbuf, 0, sizeof *statbuf);
924 980
925 /* Fill in the stat buffer. */ 981 /* Fill in the stat buffer. */
926 statbuf->st_mode = S_IFREG; 982 statbuf->st_mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH;
927 statbuf->st_size = AAsset_getLength (asset_desc); 983 statbuf->st_size = AAsset_getLength (asset_desc);
928 984
929 /* Close the asset. */ 985 /* Close the asset. */
@@ -1118,7 +1174,8 @@ android_open (const char *filename, int oflag, int mode)
1118 1174
1119 /* Fill in some information that will be reported to 1175 /* Fill in some information that will be reported to
1120 callers of android_fstat, among others. */ 1176 callers of android_fstat, among others. */
1121 android_table[fd].statb.st_mode = S_IFREG; 1177 android_table[fd].statb.st_mode
1178 = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH;;
1122 1179
1123 /* Owned by root. */ 1180 /* Owned by root. */
1124 android_table[fd].statb.st_uid = 0; 1181 android_table[fd].statb.st_uid = 0;
@@ -4023,8 +4080,21 @@ struct android_dir
4023 4080
4024 /* And the end of the files in asset_dir. */ 4081 /* And the end of the files in asset_dir. */
4025 char *asset_limit; 4082 char *asset_limit;
4083
4084 /* The next struct android_dir. */
4085 struct android_dir *next;
4086
4087 /* Path to the directory relative to /. */
4088 char *asset_file;
4089
4090 /* File descriptor used when asset_dir is set. */
4091 int fd;
4026}; 4092};
4027 4093
4094/* List of all struct android_dir's corresponding to an asset
4095 directory that are currently open. */
4096static struct android_dir *android_dirs;
4097
4028/* Like opendir. However, return an asset directory if NAME points to 4098/* Like opendir. However, return an asset directory if NAME points to
4029 an asset. */ 4099 an asset. */
4030 4100
@@ -4034,7 +4104,7 @@ android_opendir (const char *name)
4034 struct android_dir *dir; 4104 struct android_dir *dir;
4035 char *asset_dir; 4105 char *asset_dir;
4036 const char *asset_name; 4106 const char *asset_name;
4037 size_t limit; 4107 size_t limit, length;
4038 4108
4039 asset_name = android_get_asset_name (name); 4109 asset_name = android_get_asset_name (name);
4040 4110
@@ -4052,10 +4122,19 @@ android_opendir (const char *name)
4052 return NULL; 4122 return NULL;
4053 } 4123 }
4054 4124
4125 length = strlen (name);
4126
4055 dir = xmalloc (sizeof *dir); 4127 dir = xmalloc (sizeof *dir);
4056 dir->dir = NULL; 4128 dir->dir = NULL;
4057 dir->asset_dir = asset_dir; 4129 dir->asset_dir = asset_dir;
4058 dir->asset_limit = (char *) directory_tree + limit; 4130 dir->asset_limit = (char *) directory_tree + limit;
4131 dir->fd = -1;
4132 dir->asset_file = xzalloc (length + 2);
4133
4134 /* Make sure dir->asset_file is terminated with /. */
4135 strcpy (dir->asset_file, name);
4136 if (dir->asset_file[length - 1] != '/')
4137 dir->asset_file[length] = '/';
4059 4138
4060 /* Make sure dir->asset_limit is within bounds. It is a limit, 4139 /* Make sure dir->asset_limit is within bounds. It is a limit,
4061 and as such can be exactly one byte past directory_tree. */ 4140 and as such can be exactly one byte past directory_tree. */
@@ -4069,6 +4148,9 @@ android_opendir (const char *name)
4069 errno = EACCES; 4148 errno = EACCES;
4070 } 4149 }
4071 4150
4151 dir->next = android_dirs;
4152 android_dirs = dir;
4153
4072 return dir; 4154 return dir;
4073 } 4155 }
4074 4156
@@ -4086,6 +4168,26 @@ android_opendir (const char *name)
4086 return dir; 4168 return dir;
4087} 4169}
4088 4170
4171/* Like dirfd. However, value is not a real directory file descriptor
4172 if DIR is an asset directory. */
4173
4174int
4175android_dirfd (struct android_dir *dirp)
4176{
4177 int fd;
4178
4179 if (dirp->dir)
4180 return dirfd (dirp->dir);
4181 else if (dirp->fd != -1)
4182 return dirp->fd;
4183
4184 fd = open ("/dev/null", O_RDONLY | O_CLOEXEC);
4185
4186 /* Record this file descriptor in dirp. */
4187 dirp->fd = fd;
4188 return fd;
4189}
4190
4089/* Like readdir, except it understands asset directories. */ 4191/* Like readdir, except it understands asset directories. */
4090 4192
4091struct dirent * 4193struct dirent *
@@ -4152,8 +4254,29 @@ android_readdir (struct android_dir *dir)
4152void 4254void
4153android_closedir (struct android_dir *dir) 4255android_closedir (struct android_dir *dir)
4154{ 4256{
4257 struct android_dir **next, *tem;
4258
4155 if (dir->dir) 4259 if (dir->dir)
4156 closedir (dir->dir); 4260 closedir (dir->dir);
4261 else
4262 {
4263 if (dir->fd != -1)
4264 close (dir->fd);
4265
4266 /* Unlink this directory from the list of all asset manager
4267 directories. */
4268
4269 for (next = &android_dirs; (tem = *next);)
4270 {
4271 if (tem == dir)
4272 *next = dir->next;
4273 else
4274 next = &(*next)->next;
4275 }
4276
4277 /* Free the asset file name. */
4278 xfree (dir->asset_file);
4279 }
4157 4280
4158 /* There is no need to close anything else, as the directory tree 4281 /* There is no need to close anything else, as the directory tree
4159 lies in statically allocated memory. */ 4282 lies in statically allocated memory. */
@@ -4161,6 +4284,43 @@ android_closedir (struct android_dir *dir)
4161 xfree (dir); 4284 xfree (dir);
4162} 4285}
4163 4286
4287/* Subroutine used by android_fstatat. If DIRFD belongs to an open
4288 asset directory and FILE is a relative file name, then return
4289 AT_FDCWD and the absolute file name of the directory prepended to
4290 FILE in *PATHNAME. Else, return DIRFD. */
4291
4292int
4293android_lookup_asset_directory_fd (int dirfd,
4294 const char *restrict *pathname,
4295 const char *restrict file)
4296{
4297 struct android_dir *dir;
4298 static char *name;
4299
4300 if (file[0] == '/')
4301 return dirfd;
4302
4303 for (dir = android_dirs; dir; dir = dir->next)
4304 {
4305 if (dir->fd == dirfd && dirfd != -1)
4306 {
4307 if (name)
4308 xfree (name);
4309
4310 /* dir->asset_file is always separator terminated. */
4311 name = xzalloc (strlen (dir->asset_file)
4312 + strlen (file) + 1);
4313 strcpy (name, dir->asset_file);
4314 strcpy (name + strlen (dir->asset_file),
4315 file);
4316 *pathname = name;
4317 return AT_FDCWD;
4318 }
4319 }
4320
4321 return dirfd;
4322}
4323
4164 4324
4165 4325
4166/* emacs_abort implementation for Android. This logs a stack 4326/* emacs_abort implementation for Android. This logs a stack
diff --git a/src/android.h b/src/android.h
index 52b3412fb0e..eee3a7a6498 100644
--- a/src/android.h
+++ b/src/android.h
@@ -101,6 +101,7 @@ extern void android_window_updated (android_window, unsigned long);
101struct android_dir; 101struct android_dir;
102 102
103extern struct android_dir *android_opendir (const char *); 103extern struct android_dir *android_opendir (const char *);
104extern int android_dirfd (struct android_dir *);
104extern struct dirent *android_readdir (struct android_dir *); 105extern struct dirent *android_readdir (struct android_dir *);
105extern void android_closedir (struct android_dir *); 106extern void android_closedir (struct android_dir *);
106 107
diff --git a/src/androidfont.c b/src/androidfont.c
index b0a9f994a85..bec5a59ca77 100644
--- a/src/androidfont.c
+++ b/src/androidfont.c
@@ -384,6 +384,41 @@ androidfont_get_cache (struct frame *frame)
384 return font_cache; 384 return font_cache;
385} 385}
386 386
387/* Initialize the Java side of the font driver if it has not already
388 been initialized. This is only done whenever necessary because the
389 font driver otherwise uses a lot of memory, as it has to keep every
390 typeface open. */
391
392static void
393androidfont_check_init (void)
394{
395 jmethodID method;
396 jobject old;
397
398 if (font_driver)
399 return;
400
401 /* Log a loud message. This font driver really should not be
402 used. */
403 __android_log_print (ANDROID_LOG_WARN, __func__,
404 "The Android font driver is being used."
405 " Please investigate why this is so.");
406
407 method = font_driver_class.create_font_driver;
408
409 /* Initialize the font driver on the Java side. */
410 font_driver
411 = (*android_java_env)->CallStaticObjectMethod (android_java_env,
412 font_driver_class.class,
413 method);
414 android_exception_check ();
415
416 old = font_driver;
417 font_driver
418 = (*android_java_env)->NewGlobalRef (android_java_env, font_driver);
419 ANDROID_DELETE_LOCAL_REF (old);
420}
421
387/* Return a local reference to an instance of EmacsFontDriver$FontSpec 422/* Return a local reference to an instance of EmacsFontDriver$FontSpec
388 with the same values as FONT. */ 423 with the same values as FONT. */
389 424
@@ -539,6 +574,9 @@ androidfont_list (struct frame *f, Lisp_Object font_spec)
539 Lisp_Object value, entity; 574 Lisp_Object value, entity;
540 struct androidfont_entity *info; 575 struct androidfont_entity *info;
541 576
577 /* Maybe initialize the font driver. */
578 androidfont_check_init ();
579
542 spec = androidfont_from_lisp (font_spec); 580 spec = androidfont_from_lisp (font_spec);
543 array = (*android_java_env)->CallObjectMethod (android_java_env, 581 array = (*android_java_env)->CallObjectMethod (android_java_env,
544 font_driver, 582 font_driver,
@@ -595,6 +633,9 @@ androidfont_match (struct frame *f, Lisp_Object font_spec)
595 Lisp_Object entity; 633 Lisp_Object entity;
596 struct androidfont_entity *info; 634 struct androidfont_entity *info;
597 635
636 /* Maybe initialize the font driver. */
637 androidfont_check_init ();
638
598 spec = androidfont_from_lisp (font_spec); 639 spec = androidfont_from_lisp (font_spec);
599 result = (*android_java_env)->CallObjectMethod (android_java_env, 640 result = (*android_java_env)->CallObjectMethod (android_java_env,
600 font_driver, 641 font_driver,
@@ -635,6 +676,9 @@ androidfont_draw (struct glyph_string *s, int from, int to,
635 int rc; 676 int rc;
636 jobject gcontext, drawable; 677 jobject gcontext, drawable;
637 678
679 /* Maybe initialize the font driver. */
680 androidfont_check_init ();
681
638 verify (sizeof (unsigned int) == sizeof (jint)); 682 verify (sizeof (unsigned int) == sizeof (jint));
639 info = (struct androidfont_info *) s->font; 683 info = (struct androidfont_info *) s->font;
640 684
@@ -683,6 +727,9 @@ androidfont_open_font (struct frame *f, Lisp_Object font_entity,
683 jobject old; 727 jobject old;
684 jint value; 728 jint value;
685 729
730 /* Maybe initialize the font driver. */
731 androidfont_check_init ();
732
686 if (XFIXNUM (AREF (font_entity, FONT_SIZE_INDEX)) != 0) 733 if (XFIXNUM (AREF (font_entity, FONT_SIZE_INDEX)) != 0)
687 pixel_size = XFIXNUM (AREF (font_entity, FONT_SIZE_INDEX)); 734 pixel_size = XFIXNUM (AREF (font_entity, FONT_SIZE_INDEX));
688 else if (pixel_size == 0) 735 else if (pixel_size == 0)
@@ -778,6 +825,9 @@ androidfont_close_font (struct font *font)
778 struct androidfont_info *info; 825 struct androidfont_info *info;
779 int i; 826 int i;
780 827
828 /* Maybe initialize the font driver. */
829 androidfont_check_init ();
830
781 info = (struct androidfont_info *) font; 831 info = (struct androidfont_info *) font;
782 832
783 /* Free the font metrics cache if it exists. */ 833 /* Free the font metrics cache if it exists. */
@@ -805,6 +855,9 @@ androidfont_has_char (Lisp_Object font, int c)
805 struct androidfont_info *info; 855 struct androidfont_info *info;
806 struct androidfont_entity *entity; 856 struct androidfont_entity *entity;
807 857
858 /* Maybe initialize the font driver. */
859 androidfont_check_init ();
860
808 if (FONT_ENTITY_P (font)) 861 if (FONT_ENTITY_P (font))
809 { 862 {
810 entity = (struct androidfont_entity *) XFONT_ENTITY (font); 863 entity = (struct androidfont_entity *) XFONT_ENTITY (font);
@@ -830,6 +883,9 @@ androidfont_encode_char (struct font *font, int c)
830{ 883{
831 struct androidfont_info *info; 884 struct androidfont_info *info;
832 885
886 /* Maybe initialize the font driver. */
887 androidfont_check_init ();
888
833 info = (struct androidfont_info *) font; 889 info = (struct androidfont_info *) font;
834 890
835 return (*android_java_env)->CallIntMethod (android_java_env, 891 return (*android_java_env)->CallIntMethod (android_java_env,
@@ -891,6 +947,9 @@ androidfont_text_extents (struct font *font, const unsigned int *code,
891 jobject metrics_object; 947 jobject metrics_object;
892 short value; 948 short value;
893 949
950 /* Maybe initialize the font driver. */
951 androidfont_check_init ();
952
894 info = (struct androidfont_info *) font; 953 info = (struct androidfont_info *) font;
895 954
896 if (nglyphs == 1 955 if (nglyphs == 1
@@ -968,6 +1027,9 @@ androidfont_list_family (struct frame *f)
968 jsize i, length; 1027 jsize i, length;
969 const char *family; 1028 const char *family;
970 1029
1030 /* Maybe initialize the font driver. */
1031 androidfont_check_init ();
1032
971 family_array 1033 family_array
972 = (*android_java_env)->CallObjectMethod (android_java_env, 1034 = (*android_java_env)->CallObjectMethod (android_java_env,
973 font_driver, 1035 font_driver,
@@ -1042,33 +1104,14 @@ syms_of_androidfont (void)
1042void 1104void
1043init_androidfont (void) 1105init_androidfont (void)
1044{ 1106{
1045 jmethodID method;
1046 jobject old;
1047
1048 android_init_font_driver (); 1107 android_init_font_driver ();
1049 android_init_font_spec (); 1108 android_init_font_spec ();
1050 android_init_font_metrics (); 1109 android_init_font_metrics ();
1051 android_init_font_object (); 1110 android_init_font_object ();
1052 android_init_integer (); 1111 android_init_integer ();
1053 1112
1054 method = font_driver_class.create_font_driver; 1113 /* The Java font driver is not initialized here because it uses a lot
1055 1114 of memory. */
1056 /* Initialize the font driver on the Java side. */
1057 font_driver
1058 = (*android_java_env)->CallStaticObjectMethod (android_java_env,
1059 font_driver_class.class,
1060 method);
1061
1062 if (!font_driver)
1063 memory_full (0);
1064
1065 old = font_driver;
1066 font_driver
1067 = (*android_java_env)->NewGlobalRef (android_java_env, font_driver);
1068 ANDROID_DELETE_LOCAL_REF (old);
1069
1070 if (!font_driver)
1071 memory_full (0);
1072} 1115}
1073 1116
1074void 1117void
diff --git a/src/dired.c b/src/dired.c
index 57d79b84463..ced08a35643 100644
--- a/src/dired.c
+++ b/src/dired.c
@@ -116,6 +116,9 @@ open_directory (Lisp_Object dirname, Lisp_Object encoded_dirname, int *fdp)
116 d = opendir (name); 116 d = opendir (name);
117#else 117#else
118 d = android_opendir (name); 118 d = android_opendir (name);
119
120 if (d)
121 fd = android_dirfd (d);
119#endif 122#endif
120 opendir_errno = errno; 123 opendir_errno = errno;
121#else 124#else
@@ -216,6 +219,9 @@ directory_files_internal (Lisp_Object directory, Lisp_Object full,
216 Lisp_Object encoded_dirfilename = ENCODE_FILE (dirfilename); 219 Lisp_Object encoded_dirfilename = ENCODE_FILE (dirfilename);
217 220
218 int fd; 221 int fd;
222
223 /* Keep in mind that FD is not always a real file descriptor on
224 Android. */
219 emacs_dir *d = open_directory (dirfilename, encoded_dirfilename, &fd); 225 emacs_dir *d = open_directory (dirfilename, encoded_dirfilename, &fd);
220 226
221 /* Unfortunately, we can now invoke expand-file-name and 227 /* Unfortunately, we can now invoke expand-file-name and
@@ -881,6 +887,13 @@ file_name_completion_dirp (int fd, struct dirent *dp, ptrdiff_t len)
881 char *subdir_name = SAFE_ALLOCA (len + 2); 887 char *subdir_name = SAFE_ALLOCA (len + 2);
882 memcpy (subdir_name, dp->d_name, len); 888 memcpy (subdir_name, dp->d_name, len);
883 strcpy (subdir_name + len, "/"); 889 strcpy (subdir_name + len, "/");
890
891#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY
892 /* Check if subdir_name lies in the assets directory. */
893 if (android_file_access_p (subdir_name, F_OK))
894 return true;
895#endif
896
884 bool dirp = faccessat (fd, subdir_name, F_OK, AT_EACCESS) == 0; 897 bool dirp = faccessat (fd, subdir_name, F_OK, AT_EACCESS) == 0;
885 SAFE_FREE (); 898 SAFE_FREE ();
886 return dirp; 899 return dirp;
diff --git a/src/fileio.c b/src/fileio.c
index b5a79312d88..218c2b01cd2 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -145,6 +145,25 @@ static bool e_write (int, Lisp_Object, ptrdiff_t, ptrdiff_t,
145 struct coding_system *); 145 struct coding_system *);
146 146
147 147
148
149/* Check that ENCODED does not lie on any special directory whose
150 contents are read only. Signal a `file-error' if it does. */
151
152static void
153check_mutable_filename (Lisp_Object encoded)
154{
155#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY
156 if (!strcmp (SSDATA (encoded), "/assets")
157 || !strncmp (SSDATA (encoded), "/assets/",
158 sizeof "/assets/" - 1))
159 xsignal2 (Qfile_error,
160 build_string ("File lies on read-"
161 "only directory"),
162 encoded);
163#endif
164}
165
166
148/* Test whether FILE is accessible for AMODE. 167/* Test whether FILE is accessible for AMODE.
149 Return true if successful, false (setting errno) otherwise. */ 168 Return true if successful, false (setting errno) otherwise. */
150 169
@@ -2215,6 +2234,7 @@ permissions. */)
2215 2234
2216 encoded_file = ENCODE_FILE (file); 2235 encoded_file = ENCODE_FILE (file);
2217 encoded_newname = ENCODE_FILE (newname); 2236 encoded_newname = ENCODE_FILE (newname);
2237 check_mutable_filename (encoded_newname);
2218 2238
2219#ifdef WINDOWSNT 2239#ifdef WINDOWSNT
2220 if (NILP (ok_if_already_exists) 2240 if (NILP (ok_if_already_exists)
@@ -2474,6 +2494,8 @@ DEFUN ("delete-directory-internal", Fdelete_directory_internal,
2474 encoded_dir = ENCODE_FILE (directory); 2494 encoded_dir = ENCODE_FILE (directory);
2475 dir = SSDATA (encoded_dir); 2495 dir = SSDATA (encoded_dir);
2476 2496
2497 check_mutable_filename (encoded_dir);
2498
2477 if (rmdir (dir) != 0) 2499 if (rmdir (dir) != 0)
2478 report_file_error ("Removing directory", directory); 2500 report_file_error ("Removing directory", directory);
2479 2501
@@ -2513,6 +2535,7 @@ With a prefix argument, TRASH is nil. */)
2513 return call1 (Qmove_file_to_trash, filename); 2535 return call1 (Qmove_file_to_trash, filename);
2514 2536
2515 encoded_file = ENCODE_FILE (filename); 2537 encoded_file = ENCODE_FILE (filename);
2538 check_mutable_filename (encoded_file);
2516 2539
2517 if (unlink (SSDATA (encoded_file)) != 0 && errno != ENOENT) 2540 if (unlink (SSDATA (encoded_file)) != 0 && errno != ENOENT)
2518 report_file_error ("Removing old name", filename); 2541 report_file_error ("Removing old name", filename);
@@ -2670,6 +2693,8 @@ This is what happens in interactive use with M-x. */)
2670 2693
2671 encoded_file = ENCODE_FILE (file); 2694 encoded_file = ENCODE_FILE (file);
2672 encoded_newname = ENCODE_FILE (newname); 2695 encoded_newname = ENCODE_FILE (newname);
2696 check_mutable_filename (encoded_file);
2697 check_mutable_filename (encoded_newname);
2673 2698
2674 bool plain_rename = (case_only_rename 2699 bool plain_rename = (case_only_rename
2675 || (!NILP (ok_if_already_exists) 2700 || (!NILP (ok_if_already_exists)
@@ -2781,6 +2806,8 @@ This is what happens in interactive use with M-x. */)
2781 2806
2782 encoded_file = ENCODE_FILE (file); 2807 encoded_file = ENCODE_FILE (file);
2783 encoded_newname = ENCODE_FILE (newname); 2808 encoded_newname = ENCODE_FILE (newname);
2809 check_mutable_filename (encoded_file);
2810 check_mutable_filename (encoded_newname);
2784 2811
2785 if (link (SSDATA (encoded_file), SSDATA (encoded_newname)) == 0) 2812 if (link (SSDATA (encoded_file), SSDATA (encoded_newname)) == 0)
2786 return Qnil; 2813 return Qnil;
@@ -2834,6 +2861,8 @@ This happens for interactive use with M-x. */)
2834 2861
2835 encoded_target = ENCODE_FILE (target); 2862 encoded_target = ENCODE_FILE (target);
2836 encoded_linkname = ENCODE_FILE (linkname); 2863 encoded_linkname = ENCODE_FILE (linkname);
2864 check_mutable_filename (encoded_target);
2865 check_mutable_filename (encoded_linkname);
2837 2866
2838 if (symlink (SSDATA (encoded_target), SSDATA (encoded_linkname)) == 0) 2867 if (symlink (SSDATA (encoded_target), SSDATA (encoded_linkname)) == 0)
2839 return Qnil; 2868 return Qnil;
@@ -3565,6 +3594,8 @@ Interactively, prompt for FILENAME, and read MODE with
3565command from GNU Coreutils. */) 3594command from GNU Coreutils. */)
3566 (Lisp_Object filename, Lisp_Object mode, Lisp_Object flag) 3595 (Lisp_Object filename, Lisp_Object mode, Lisp_Object flag)
3567{ 3596{
3597 Lisp_Object encoded;
3598
3568 CHECK_FIXNUM (mode); 3599 CHECK_FIXNUM (mode);
3569 int nofollow = symlink_nofollow_flag (flag); 3600 int nofollow = symlink_nofollow_flag (flag);
3570 Lisp_Object absname = Fexpand_file_name (filename, 3601 Lisp_Object absname = Fexpand_file_name (filename,
@@ -3576,7 +3607,9 @@ command from GNU Coreutils. */)
3576 if (!NILP (handler)) 3607 if (!NILP (handler))
3577 return call4 (handler, Qset_file_modes, absname, mode, flag); 3608 return call4 (handler, Qset_file_modes, absname, mode, flag);
3578 3609
3579 char *fname = SSDATA (ENCODE_FILE (absname)); 3610 encoded = ENCODE_FILE (absname);
3611 check_mutable_filename (encoded);
3612 char *fname = SSDATA (encoded);
3580 mode_t imode = XFIXNUM (mode) & 07777; 3613 mode_t imode = XFIXNUM (mode) & 07777;
3581 if (fchmodat (AT_FDCWD, fname, imode, nofollow) != 0) 3614 if (fchmodat (AT_FDCWD, fname, imode, nofollow) != 0)
3582 report_file_error ("Doing chmod", absname); 3615 report_file_error ("Doing chmod", absname);
@@ -3648,6 +3681,7 @@ TIMESTAMP is in the format of `current-time'. */)
3648 return call4 (handler, Qset_file_times, absname, timestamp, flag); 3681 return call4 (handler, Qset_file_times, absname, timestamp, flag);
3649 3682
3650 Lisp_Object encoded_absname = ENCODE_FILE (absname); 3683 Lisp_Object encoded_absname = ENCODE_FILE (absname);
3684 check_mutable_filename (encoded_absname);
3651 3685
3652 if (utimensat (AT_FDCWD, SSDATA (encoded_absname), ts, nofollow) != 0) 3686 if (utimensat (AT_FDCWD, SSDATA (encoded_absname), ts, nofollow) != 0)
3653 { 3687 {
@@ -3680,6 +3714,7 @@ otherwise, if FILE2 does not exist, the answer is t. */)
3680 (Lisp_Object file1, Lisp_Object file2) 3714 (Lisp_Object file1, Lisp_Object file2)
3681{ 3715{
3682 struct stat st1, st2; 3716 struct stat st1, st2;
3717 Lisp_Object encoded;
3683 3718
3684 CHECK_STRING (file1); 3719 CHECK_STRING (file1);
3685 CHECK_STRING (file2); 3720 CHECK_STRING (file2);
@@ -3696,8 +3731,11 @@ otherwise, if FILE2 does not exist, the answer is t. */)
3696 if (!NILP (handler)) 3731 if (!NILP (handler))
3697 return call3 (handler, Qfile_newer_than_file_p, absname1, absname2); 3732 return call3 (handler, Qfile_newer_than_file_p, absname1, absname2);
3698 3733
3734 encoded = ENCODE_FILE (absname1);
3735 check_mutable_filename (encoded);
3736
3699 int err1; 3737 int err1;
3700 if (emacs_fstatat (AT_FDCWD, SSDATA (ENCODE_FILE (absname1)), &st1, 0) == 0) 3738 if (emacs_fstatat (AT_FDCWD, SSDATA (encoded), &st1, 0) == 0)
3701 err1 = 0; 3739 err1 = 0;
3702 else 3740 else
3703 { 3741 {
@@ -5853,6 +5891,7 @@ See Info node `(elisp)Modification Time' for more details. */)
5853 return call2 (handler, Qverify_visited_file_modtime, buf); 5891 return call2 (handler, Qverify_visited_file_modtime, buf);
5854 5892
5855 filename = ENCODE_FILE (BVAR (b, filename)); 5893 filename = ENCODE_FILE (BVAR (b, filename));
5894 check_mutable_filename (filename);
5856 5895
5857 mtime = (emacs_fstatat (AT_FDCWD, SSDATA (filename), &st, 0) == 0 5896 mtime = (emacs_fstatat (AT_FDCWD, SSDATA (filename), &st, 0) == 0
5858 ? get_stat_mtime (&st) 5897 ? get_stat_mtime (&st)
@@ -5913,7 +5952,7 @@ in `current-time' or an integer flag as returned by `visited-file-modtime'. */)
5913 error ("An indirect buffer does not have a visited file"); 5952 error ("An indirect buffer does not have a visited file");
5914 else 5953 else
5915 { 5954 {
5916 register Lisp_Object filename; 5955 register Lisp_Object filename, encoded;
5917 struct stat st; 5956 struct stat st;
5918 Lisp_Object handler; 5957 Lisp_Object handler;
5919 5958
@@ -5926,7 +5965,10 @@ in `current-time' or an integer flag as returned by `visited-file-modtime'. */)
5926 /* The handler can find the file name the same way we did. */ 5965 /* The handler can find the file name the same way we did. */
5927 return call2 (handler, Qset_visited_file_modtime, Qnil); 5966 return call2 (handler, Qset_visited_file_modtime, Qnil);
5928 5967
5929 if (emacs_fstatat (AT_FDCWD, SSDATA (ENCODE_FILE (filename)), &st, 0) 5968 encoded = ENCODE_FILE (filename);
5969 check_mutable_filename (encoded);
5970
5971 if (emacs_fstatat (AT_FDCWD, SSDATA (encoded), &st, 0)
5930 == 0) 5972 == 0)
5931 { 5973 {
5932 current_buffer->modtime = get_stat_mtime (&st); 5974 current_buffer->modtime = get_stat_mtime (&st);
diff --git a/src/sfntfont-android.c b/src/sfntfont-android.c
index 37fd81953f6..5c9835fb13e 100644
--- a/src/sfntfont-android.c
+++ b/src/sfntfont-android.c
@@ -22,8 +22,14 @@ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
22#include <dirent.h> 22#include <dirent.h>
23#include <string.h> 23#include <string.h>
24#include <stdio.h> 24#include <stdio.h>
25#include <stdlib.h>
26
27#ifdef __aarch64__
28#include <arm_neon.h>
29#endif
25 30
26#include <android/api-level.h> 31#include <android/api-level.h>
32#include <android/log.h>
27 33
28#include "androidterm.h" 34#include "androidterm.h"
29#include "sfntfont.h" 35#include "sfntfont.h"
@@ -63,6 +69,8 @@ static size_t max_scanline_buffer_size;
63/* Return a temporary buffer for storing scan lines. 69/* Return a temporary buffer for storing scan lines.
64 Set BUFFER to the buffer upon success. */ 70 Set BUFFER to the buffer upon success. */
65 71
72#ifndef __aarch64__
73
66#define GET_SCANLINE_BUFFER(buffer, height, stride) \ 74#define GET_SCANLINE_BUFFER(buffer, height, stride) \
67 do \ 75 do \
68 { \ 76 { \
@@ -94,6 +102,39 @@ static size_t max_scanline_buffer_size;
94 } \ 102 } \
95 } while (false); 103 } while (false);
96 104
105#else
106
107#define GET_SCANLINE_BUFFER(buffer, height, stride) \
108 do \
109 { \
110 size_t _size; \
111 void *_temp; \
112 \
113 if (INT_MULTIPLY_WRAPV (height, stride, &_size)) \
114 memory_full (SIZE_MAX); \
115 \
116 if (_size > scanline_buffer.buffer_size) \
117 { \
118 if (posix_memalign (&_temp, 16, _size)) \
119 memory_full (_size); \
120 free (scanline_buffer.buffer_data); \
121 (buffer) \
122 = scanline_buffer.buffer_data \
123 = _temp; \
124 scanline_buffer.buffer_size = _size; \
125 } \
126 else if (_size <= scanline_buffer.buffer_size) \
127 (buffer) = scanline_buffer.buffer_data; \
128 /* This is unreachable but clang says it is. */ \
129 else \
130 emacs_abort (); \
131 \
132 max_scanline_buffer_size \
133 = max (_size, max_scanline_buffer_size); \
134 } while (false);
135
136#endif
137
97 138
98 139
99/* Scale each of the four packed bytes in P in the low 16 bits of P by 140/* Scale each of the four packed bytes in P in the low 16 bits of P by
@@ -149,6 +190,122 @@ sfntfont_android_blend (unsigned int src, unsigned int dst)
149 return both + src; 190 return both + src;
150} 191}
151 192
193#ifdef __aarch64__
194
195/* Like U255TO256, but operates on vectors. */
196
197static uint16x8_t
198sfntfont_android_u255to256 (uint8x8_t in)
199{
200 return vaddl_u8 (vshr_n_u8 (in, 7), in);
201}
202
203/* Use processor features to efficiently composite four pixels at SRC
204 to DST. */
205
206static void
207sfntfont_android_over_8888_1 (unsigned int *src, unsigned int *dst)
208{
209 uint8x8_t alpha;
210 uint16x8_t alpha_c16, v1, v3, v4;
211 uint8x8_t b, g, r, a, v2, v5;
212 uint8x8x4_t _src, _dst;
213
214 /* Pull in src and dst.
215
216 This loads bytes, not words, so little endian ABGR becomes
217 RGBA. */
218 _src = vld4_u8 ((const uint8_t *) src);
219 _dst = vld4_u8 ((const uint8_t *) dst);
220
221 /* Load constants. */
222 v4 = vdupq_n_u16 (256);
223 v5 = vdup_n_u8 (0);
224
225 /* Load src alpha. */
226 alpha = _src.val[3];
227
228 /* alpha_c16 = 256 - 255TO256 (alpha). */
229 alpha_c16 = sfntfont_android_u255to256 (alpha);
230 alpha_c16 = vsubq_u16 (v4, alpha_c16);
231
232 /* Cout = Csrc + Cdst * alpha_c. */
233 v1 = vaddl_u8 (_dst.val[2], v5);
234 v2 = _src.val[2];
235 v3 = vmulq_u16 (v1, alpha_c16);
236 b = vqadd_u8 (v2, vshrn_n_u16 (v3, 8));
237
238 v1 = vaddl_u8 (_dst.val[1], v5);
239 v2 = _src.val[1];
240 v3 = vmulq_u16 (v1, alpha_c16);
241 g = vqadd_u8 (v2, vshrn_n_u16 (v3, 8));
242
243 v1 = vaddl_u8 (_dst.val[0], v5);
244 v2 = _src.val[0];
245 v3 = vmulq_u16 (v1, alpha_c16);
246 r = vqadd_u8 (v2, vshrn_n_u16 (v3, 8));
247
248#if 0
249 /* Aout = Asrc + Adst * alpha_c. */
250 v1 = vaddl_u8 (_dst.val[3], v5);
251 v2 = _src.val[3];
252 v3 = vmulq_u16 (v1, alpha_c16);
253 a = vqadd_u8 (v2, vshrn_n_u16 (v3, 8));
254#else
255 /* We know that Adst is always 1, so Asrc + Adst * (1 - Asrc) is
256 always 1. */
257 a = vdup_n_u8 (255);
258#endif
259
260 /* Store back in dst. */
261 _dst.val[0] = r;
262 _dst.val[1] = g;
263 _dst.val[2] = b;
264 _dst.val[3] = a;
265 vst4_u8 ((uint8_t *) dst, _dst);
266}
267
268/* Use processor features to efficiently composite the buffer at SRC
269 to DST. Composite at most MAX - SRC words.
270
271 If either SRC or DST are not yet properly aligned, value is 1.
272 Otherwise, value is 0, and *X is incremented to the start of any
273 trailing data which could not be composited due to data alignment
274 constraints. */
275
276static int
277sfntfont_android_over_8888 (unsigned int *src, unsigned int *dst,
278 unsigned int *max, unsigned int *x)
279{
280 size_t i;
281 ptrdiff_t how_much;
282 void *s, *d;
283
284 /* Figure out how much can be composited by this loop. */
285 how_much = (max - src) & ~7;
286
287 /* Return if there is not enough to vectorize. */
288 if (!how_much)
289 return 1;
290
291 /* Now increment *X by that much so the containing loop can process
292 the remaining pixels one-by-one. */
293
294 *x += how_much;
295
296 for (i = 0; i < how_much; i += 8)
297 {
298 s = (src + i);
299 d = (dst + i);
300
301 sfntfont_android_over_8888_1 (s, d);
302 }
303
304 return 0;
305}
306
307#endif
308
152/* Composite the bitmap described by BUFFER, STRIDE and TEXT_RECTANGLE 309/* Composite the bitmap described by BUFFER, STRIDE and TEXT_RECTANGLE
153 onto the native-endian ABGR8888 bitmap described by DEST and 310 onto the native-endian ABGR8888 bitmap described by DEST and
154 BITMAP_INFO. RECT is the subset of the bitmap to composite. */ 311 BITMAP_INFO. RECT is the subset of the bitmap to composite. */
@@ -163,7 +320,7 @@ sfntfont_android_composite_bitmap (unsigned char *restrict buffer,
163{ 320{
164 unsigned int *src_row; 321 unsigned int *src_row;
165 unsigned int *dst_row; 322 unsigned int *dst_row;
166 unsigned int i, src_y, x, src_x, max_x, dst_x; 323 unsigned int i, src_y, x, src_x, max_x, dst_x, lim_x;
167 324
168 if ((intptr_t) dest & 3 || bitmap_info->stride & 3) 325 if ((intptr_t) dest & 3 || bitmap_info->stride & 3)
169 /* This shouldn't be possible as Android is supposed to align the 326 /* This shouldn't be possible as Android is supposed to align the
@@ -196,9 +353,24 @@ sfntfont_android_composite_bitmap (unsigned char *restrict buffer,
196 src_x = x + (rect->x - text_rectangle->x); 353 src_x = x + (rect->x - text_rectangle->x);
197 dst_x = x + rect->x; 354 dst_x = x + rect->x;
198 355
199 dst_row[dst_x] 356 /* This is the largest value of src_x. */
200 = sfntfont_android_blend (src_row[src_x], 357 lim_x = max_x + (rect->x - text_rectangle->x);
201 dst_row[dst_x]); 358
359#ifdef __aarch64__
360 if (!sfntfont_android_over_8888 (src_row + src_x,
361 dst_row + dst_x,
362 src_row + lim_x,
363 &x))
364 {
365 /* Decrement X by one so the for loop can increment
366 it again. */
367 x--;
368 continue;
369 }
370#endif
371 dst_row[dst_x]
372 = sfntfont_android_blend (src_row[src_x],
373 dst_row[dst_x]);
202 } 374 }
203 } 375 }
204 } 376 }
@@ -308,11 +480,21 @@ sfntfont_android_put_glyphs (struct glyph_string *s, int from,
308 gui_union_rectangles (&background, &text_rectangle, 480 gui_union_rectangles (&background, &text_rectangle,
309 &text_rectangle); 481 &text_rectangle);
310 482
311 /* Allocate enough to hold text_rectangle.height, aligned to 8 483 /* Allocate enough to hold text_rectangle.height, aligned to 8 (or
312 bytes. Then fill it with the background. */ 484 16) bytes. Then fill it with the background. */
485#ifndef __aarch64__
313 stride = ((text_rectangle.width * sizeof *buffer) + 7) & ~7; 486 stride = ((text_rectangle.width * sizeof *buffer) + 7) & ~7;
487#else
488 stride = ((text_rectangle.width * sizeof *buffer) + 15) & ~15;
489#endif
314 GET_SCANLINE_BUFFER (buffer, text_rectangle.height, stride); 490 GET_SCANLINE_BUFFER (buffer, text_rectangle.height, stride);
315 memset (buffer, 0, text_rectangle.height * stride); 491
492 /* Try to optimize out this memset if the background rectangle
493 contains the whole text rectangle. */
494
495 if (!with_background || memcmp (&background, &text_rectangle,
496 sizeof text_rectangle))
497 memset (buffer, 0, text_rectangle.height * stride);
316 498
317 if (with_background) 499 if (with_background)
318 { 500 {