diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/android.c | 168 | ||||
| -rw-r--r-- | src/android.h | 1 | ||||
| -rw-r--r-- | src/androidfont.c | 85 | ||||
| -rw-r--r-- | src/dired.c | 13 | ||||
| -rw-r--r-- | src/fileio.c | 50 | ||||
| -rw-r--r-- | src/sfntfont-android.c | 196 |
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 | |||
| 861 | static bool | ||
| 862 | android_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 | ||
| 922 | static 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 | ||
| 905 | int | 932 | int |
| 906 | android_fstatat (int dirfd, const char *restrict pathname, | 933 | android_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. */ | ||
| 4096 | static 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 | |||
| 4174 | int | ||
| 4175 | android_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 | ||
| 4091 | struct dirent * | 4193 | struct dirent * |
| @@ -4152,8 +4254,29 @@ android_readdir (struct android_dir *dir) | |||
| 4152 | void | 4254 | void |
| 4153 | android_closedir (struct android_dir *dir) | 4255 | android_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 | |||
| 4292 | int | ||
| 4293 | android_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); | |||
| 101 | struct android_dir; | 101 | struct android_dir; |
| 102 | 102 | ||
| 103 | extern struct android_dir *android_opendir (const char *); | 103 | extern struct android_dir *android_opendir (const char *); |
| 104 | extern int android_dirfd (struct android_dir *); | ||
| 104 | extern struct dirent *android_readdir (struct android_dir *); | 105 | extern struct dirent *android_readdir (struct android_dir *); |
| 105 | extern void android_closedir (struct android_dir *); | 106 | extern 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 | |||
| 392 | static void | ||
| 393 | androidfont_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) | |||
| 1042 | void | 1104 | void |
| 1043 | init_androidfont (void) | 1105 | init_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 | ||
| 1074 | void | 1117 | void |
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 | |||
| 152 | static void | ||
| 153 | check_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 | |||
| 3565 | command from GNU Coreutils. */) | 3594 | command 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 | |||
| 197 | static uint16x8_t | ||
| 198 | sfntfont_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 | |||
| 206 | static void | ||
| 207 | sfntfont_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 | |||
| 276 | static int | ||
| 277 | sfntfont_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 | { |