emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

feature/android aaacf24ca25 1/2: Update Android port


From: Po Lu
Subject: feature/android aaacf24ca25 1/2: Update Android port
Date: Sat, 21 Jan 2023 07:07:17 -0500 (EST)

branch: feature/android
commit aaacf24ca25fc284038ec9f17be358067309a8cf
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>

    Update Android port
    
    * doc/emacs/android.texi (Android File System): Document that
    ls-lisp is now used by default.
    * java/org/gnu/emacs/EmacsThread.java (EmacsThread): Name the
    thread something meaningful.
    * lisp/loadup.el (featurep): Load ls-lisp on Android.
    * lisp/ls-lisp.el (ls-lisp-use-insert-directory-program):
    Default to off on Android.
    * src/android.c (android_is_directory): New fucntion.
    (android_fstatat): Handle directories created by
    `android_opendir'.
    (android_open): Return meaningful file mode.
    (struct android_dir): New fields `next', `asset_file' and `fd'.
    (android_opendir): Populate those fields.
    (android_dirfd): New function.
    (android_closedir): Close file descriptor if set.
    (android_lookup_asset_directory_fd): New function.
    
    * src/android.h: Update prototypes.
    * src/androidfont.c (androidfont_check_init): New function.
    (androidfont_list, androidfont_match, androidfont_draw)
    (androidfont_open_font, androidfont_close_font)
    (androidfont_has_char, androidfont_encode_char)
    (androidfont_text_extents, androidfont_list_family): Initialize
    font driver if necessary.
    (init_androidfont): Don't initialize Java font if necessary.
    
    * src/dired.c (open_directory): Return android_dirfd if
    appropriate.
    (directory_files_internal, file_name_completion_dirp): Implement
    correctly for Android.
    
    * src/fileio.c (check_mutable_filename): New function.
    (Fcopy_file, Fdelete_directory_internal, Fdelete_file)
    (Frename_file, Fadd_name_to_file, Fmake_symbolic_link)
    (Fset_file_modes, Fset_file_times, Ffile_newer_than_file_p)
    (Fverify_visited_file_modtime, Fset_visited_file_modtime): Check
    that files being written to do not lie in /assets.
    
    * src/sfntfont-android.c (GET_SCANLINE_BUFFER)
    (sfntfont_android_u255to256, sfntfont_android_over_8888_1)
    (sfntfont_android_over_8888, sfntfont_android_composite_bitmap):
    Optimize on 64-bit ARM devices.
    (sfntfont_android_put_glyphs): Optimize away memset if
    background need not be filled.
---
 doc/emacs/android.texi              |  21 ++--
 java/org/gnu/emacs/EmacsThread.java |   1 +
 lisp/loadup.el                      |   1 +
 lisp/ls-lisp.el                     |   2 +-
 src/android.c                       | 168 ++++++++++++++++++++++++++++++-
 src/android.h                       |   1 +
 src/androidfont.c                   |  85 ++++++++++++----
 src/dired.c                         |  13 +++
 src/fileio.c                        |  50 ++++++++-
 src/sfntfont-android.c              | 196 ++++++++++++++++++++++++++++++++++--
 10 files changed, 493 insertions(+), 45 deletions(-)

diff --git a/doc/emacs/android.texi b/doc/emacs/android.texi
index ba5d2ca3e09..223e9dbf8ef 100644
--- a/doc/emacs/android.texi
+++ b/doc/emacs/android.texi
@@ -99,21 +99,26 @@ this varies by device.
   Emacs exposes a special directory on Android systems: the name of
 the directory is @file{/assets}, and it contains the @file{etc},
 @file{lisp} and @file{info} directories which are normally installed
-in @file{/usr/share/emacs} directory on GNU and Unix systems.
+in @file{/usr/share/emacs} directory on GNU and Unix systems.  On
+Android systems, the Lisp emulation of @command{ls} (@pxref{ls in
+Lisp}) is also enabled by default, as the @command{ls} binary which
+comes with the system varies by manufacturer and usually does not
+support all of the features required by Emacs.  One copy of
+@command{ls} shipped with some Android devices is even known to lack
+support for the @code{-l} flag.
 
 @cindex limitations of the /assets directory
 
-This directory exists because Android does not extract the contents of
-application packages on to the file system while unpacking them, but
-instead requires programs like Emacs to access its contents using a
-special ``asset manager'' interface.  Here are the peculiarities that
-result from such an implementation:
+  This directory exists because Android does not extract the contents
+of application packages on to the file system while unpacking them,
+but instead requires programs like Emacs to access its contents using
+a special ``asset manager'' interface.  Here are the peculiarities
+that result from such an implementation:
 
 @itemize @bullet
 @item
 Subprocesses (such as @command{ls}) can not run from the
-@file{/assets} directory, so Dired, and functions such as
-@code{list-directory} do not work.
+@file{/assets} directory.
 
 @item
 There are no @file{.} and @file{..} directories inside the
diff --git a/java/org/gnu/emacs/EmacsThread.java 
b/java/org/gnu/emacs/EmacsThread.java
index f9bc132f354..21d8612703a 100644
--- a/java/org/gnu/emacs/EmacsThread.java
+++ b/java/org/gnu/emacs/EmacsThread.java
@@ -29,6 +29,7 @@ public class EmacsThread extends Thread
   public
   EmacsThread (EmacsService service, boolean startDashQ)
   {
+    super ("Emacs main thread");
     this.startDashQ = startDashQ;
   }
 
diff --git a/lisp/loadup.el b/lisp/loadup.el
index 3b48d5fe1b5..b9ae8212d2d 100644
--- a/lisp/loadup.el
+++ b/lisp/loadup.el
@@ -312,6 +312,7 @@
 
 (if (featurep 'android)
     (progn
+      (load "ls-lisp")
       (load "term/common-win")
       (load "term/android-win")))
 
diff --git a/lisp/ls-lisp.el b/lisp/ls-lisp.el
index 81ff14932c6..8f5948cefb9 100644
--- a/lisp/ls-lisp.el
+++ b/lisp/ls-lisp.el
@@ -184,7 +184,7 @@ if emulation is GNU then default is `(links uid gid)'."
   :group 'ls-lisp)
 
 (defcustom ls-lisp-use-insert-directory-program
-  (not (memq system-type '(ms-dos windows-nt)))
+  (not (memq system-type '(ms-dos windows-nt android)))
   "Non-nil causes ls-lisp to revert back to using `insert-directory-program'.
 This is useful on platforms where ls-lisp is dumped into Emacs, such as
 Microsoft Windows, but you would still like to use a program to list
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)
   return NULL;
 }
 
+/* Return whether or not the directory tree entry DIR is a
+   directory.
+
+   DIR should be a value returned by
+   `android_scan_directory_tree'.  */
+
+static bool
+android_is_directory (const char *dir)
+{
+  /* If the directory is the directory tree, then it is a
+     directory.  */
+  if (dir == directory_tree + 5)
+    return true;
+
+  /* Otherwise, look 5 bytes behind.  If it is `/', then it is a
+     directory.  */
+  return (dir - 6 >= directory_tree
+         && *(dir - 6) == '/');
+}
+
 
 
 /* Intercept USER_FULL_NAME and return something that makes sense if
@@ -899,8 +919,15 @@ android_fstat (int fd, struct stat *statb)
   return fstat (fd, statb);
 }
 
+static int android_lookup_asset_directory_fd (int,
+                                             const char *restrict *,
+                                             const char *restrict);
+
 /* Like fstatat.  However, if dirfd is AT_FDCWD and PATHNAME is an
-   asset, find the information for the corresponding asset.  */
+   asset, find the information for the corresponding asset, and if
+   dirfd is an offset into directory_tree as returned by
+   `android_dirfd', find the information within the corresponding
+   directory tree entry.  */
 
 int
 android_fstatat (int dirfd, const char *restrict pathname,
@@ -908,11 +935,40 @@ android_fstatat (int dirfd, const char *restrict pathname,
 {
   AAsset *asset_desc;
   const char *asset;
+  const char *asset_dir;
+
+  /* Look up whether or not DIRFD belongs to an open struct
+     android_dir.  */
+
+  if (dirfd != AT_FDCWD)
+    dirfd
+      = android_lookup_asset_directory_fd (dirfd, &pathname,
+                                          pathname);
 
   if (dirfd == AT_FDCWD
       && asset_manager
       && (asset = android_get_asset_name (pathname)))
     {
+      /* Look up whether or not PATHNAME happens to be a
+        directory.  */
+      asset_dir = android_scan_directory_tree ((char *) asset,
+                                              NULL);
+
+      if (!asset_dir)
+       {
+         errno = ENOENT;
+         return -1;
+       }
+
+      if (android_is_directory (asset_dir))
+       {
+         memset (statbuf, 0, sizeof *statbuf);
+
+         /* Fill in the stat buffer.  */
+         statbuf->st_mode = S_IFDIR | S_IRUSR | S_IRGRP | S_IROTH;
+         return 0;
+       }
+
       /* AASSET_MODE_STREAMING is fastest here.  */
       asset_desc = AAssetManager_open (asset_manager, asset,
                                       AASSET_MODE_STREAMING);
@@ -923,7 +979,7 @@ android_fstatat (int dirfd, const char *restrict pathname,
       memset (statbuf, 0, sizeof *statbuf);
 
       /* Fill in the stat buffer.  */
-      statbuf->st_mode = S_IFREG;
+      statbuf->st_mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH;
       statbuf->st_size = AAsset_getLength (asset_desc);
 
       /* Close the asset.  */
@@ -1118,7 +1174,8 @@ android_open (const char *filename, int oflag, int mode)
 
          /* Fill in some information that will be reported to
             callers of android_fstat, among others.  */
-         android_table[fd].statb.st_mode = S_IFREG;
+         android_table[fd].statb.st_mode
+           = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH;;
 
          /* Owned by root.  */
          android_table[fd].statb.st_uid = 0;
@@ -4023,8 +4080,21 @@ struct android_dir
 
   /* And the end of the files in asset_dir.  */
   char *asset_limit;
+
+  /* The next struct android_dir.  */
+  struct android_dir *next;
+
+  /* Path to the directory relative to /.  */
+  char *asset_file;
+
+  /* File descriptor used when asset_dir is set.  */
+  int fd;
 };
 
+/* List of all struct android_dir's corresponding to an asset
+   directory that are currently open.  */
+static struct android_dir *android_dirs;
+
 /* Like opendir.  However, return an asset directory if NAME points to
    an asset.  */
 
@@ -4034,7 +4104,7 @@ android_opendir (const char *name)
   struct android_dir *dir;
   char *asset_dir;
   const char *asset_name;
-  size_t limit;
+  size_t limit, length;
 
   asset_name = android_get_asset_name (name);
 
@@ -4052,10 +4122,19 @@ android_opendir (const char *name)
          return NULL;
        }
 
+      length = strlen (name);
+
       dir = xmalloc (sizeof *dir);
       dir->dir = NULL;
       dir->asset_dir = asset_dir;
       dir->asset_limit = (char *) directory_tree + limit;
+      dir->fd = -1;
+      dir->asset_file = xzalloc (length + 2);
+
+      /* Make sure dir->asset_file is terminated with /.  */
+      strcpy (dir->asset_file, name);
+      if (dir->asset_file[length - 1] != '/')
+       dir->asset_file[length] = '/';
 
       /* Make sure dir->asset_limit is within bounds.  It is a limit,
         and as such can be exactly one byte past directory_tree.  */
@@ -4069,6 +4148,9 @@ android_opendir (const char *name)
          errno = EACCES;
        }
 
+      dir->next = android_dirs;
+      android_dirs = dir;
+
       return dir;
     }
 
@@ -4086,6 +4168,26 @@ android_opendir (const char *name)
   return dir;
 }
 
+/* Like dirfd.  However, value is not a real directory file descriptor
+   if DIR is an asset directory.  */
+
+int
+android_dirfd (struct android_dir *dirp)
+{
+  int fd;
+
+  if (dirp->dir)
+    return dirfd (dirp->dir);
+  else if (dirp->fd != -1)
+    return dirp->fd;
+
+  fd = open ("/dev/null", O_RDONLY | O_CLOEXEC);
+
+  /* Record this file descriptor in dirp.  */
+  dirp->fd = fd;
+  return fd;
+}
+
 /* Like readdir, except it understands asset directories.  */
 
 struct dirent *
@@ -4152,8 +4254,29 @@ android_readdir (struct android_dir *dir)
 void
 android_closedir (struct android_dir *dir)
 {
+  struct android_dir **next, *tem;
+
   if (dir->dir)
     closedir (dir->dir);
+  else
+    {
+      if (dir->fd != -1)
+       close (dir->fd);
+
+      /* Unlink this directory from the list of all asset manager
+        directories.  */
+
+      for (next = &android_dirs; (tem = *next);)
+       {
+         if (tem == dir)
+           *next = dir->next;
+         else
+           next = &(*next)->next;
+       }
+
+      /* Free the asset file name.  */
+      xfree (dir->asset_file);
+    }
 
   /* There is no need to close anything else, as the directory tree
      lies in statically allocated memory.  */
@@ -4161,6 +4284,43 @@ android_closedir (struct android_dir *dir)
   xfree (dir);
 }
 
+/* Subroutine used by android_fstatat.  If DIRFD belongs to an open
+   asset directory and FILE is a relative file name, then return
+   AT_FDCWD and the absolute file name of the directory prepended to
+   FILE in *PATHNAME.  Else, return DIRFD.  */
+
+int
+android_lookup_asset_directory_fd (int dirfd,
+                                  const char *restrict *pathname,
+                                  const char *restrict file)
+{
+  struct android_dir *dir;
+  static char *name;
+
+  if (file[0] == '/')
+    return dirfd;
+
+  for (dir = android_dirs; dir; dir = dir->next)
+    {
+      if (dir->fd == dirfd && dirfd != -1)
+       {
+         if (name)
+           xfree (name);
+
+         /* dir->asset_file is always separator terminated.  */
+         name = xzalloc (strlen (dir->asset_file)
+                         + strlen (file) + 1);
+         strcpy (name, dir->asset_file);
+         strcpy (name + strlen (dir->asset_file),
+                 file);
+         *pathname = name;
+         return AT_FDCWD;
+       }
+    }
+
+  return dirfd;
+}
+
 
 
 /* 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);
 struct android_dir;
 
 extern struct android_dir *android_opendir (const char *);
+extern int android_dirfd (struct android_dir *);
 extern struct dirent *android_readdir (struct android_dir *);
 extern void android_closedir (struct android_dir *);
 
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)
   return font_cache;
 }
 
+/* Initialize the Java side of the font driver if it has not already
+   been initialized.  This is only done whenever necessary because the
+   font driver otherwise uses a lot of memory, as it has to keep every
+   typeface open.  */
+
+static void
+androidfont_check_init (void)
+{
+  jmethodID method;
+  jobject old;
+
+  if (font_driver)
+    return;
+
+  /* Log a loud message.  This font driver really should not be
+     used.  */
+  __android_log_print (ANDROID_LOG_WARN, __func__,
+                      "The Android font driver is being used."
+                      "  Please investigate why this is so.");
+
+  method = font_driver_class.create_font_driver;
+
+  /* Initialize the font driver on the Java side.  */
+  font_driver
+    = (*android_java_env)->CallStaticObjectMethod (android_java_env,
+                                                  font_driver_class.class,
+                                                  method);
+  android_exception_check ();
+
+  old = font_driver;
+  font_driver
+    = (*android_java_env)->NewGlobalRef (android_java_env, font_driver);
+  ANDROID_DELETE_LOCAL_REF (old);
+}
+
 /* Return a local reference to an instance of EmacsFontDriver$FontSpec
    with the same values as FONT.  */
 
@@ -539,6 +574,9 @@ androidfont_list (struct frame *f, Lisp_Object font_spec)
   Lisp_Object value, entity;
   struct androidfont_entity *info;
 
+  /* Maybe initialize the font driver.  */
+  androidfont_check_init ();
+
   spec = androidfont_from_lisp (font_spec);
   array = (*android_java_env)->CallObjectMethod (android_java_env,
                                                 font_driver,
@@ -595,6 +633,9 @@ androidfont_match (struct frame *f, Lisp_Object font_spec)
   Lisp_Object entity;
   struct androidfont_entity *info;
 
+  /* Maybe initialize the font driver.  */
+  androidfont_check_init ();
+
   spec = androidfont_from_lisp (font_spec);
   result = (*android_java_env)->CallObjectMethod (android_java_env,
                                                  font_driver,
@@ -635,6 +676,9 @@ androidfont_draw (struct glyph_string *s, int from, int to,
   int rc;
   jobject gcontext, drawable;
 
+  /* Maybe initialize the font driver.  */
+  androidfont_check_init ();
+
   verify (sizeof (unsigned int) == sizeof (jint));
   info = (struct androidfont_info *) s->font;
 
@@ -683,6 +727,9 @@ androidfont_open_font (struct frame *f, Lisp_Object 
font_entity,
   jobject old;
   jint value;
 
+  /* Maybe initialize the font driver.  */
+  androidfont_check_init ();
+
   if (XFIXNUM (AREF (font_entity, FONT_SIZE_INDEX)) != 0)
     pixel_size = XFIXNUM (AREF (font_entity, FONT_SIZE_INDEX));
   else if (pixel_size == 0)
@@ -778,6 +825,9 @@ androidfont_close_font (struct font *font)
   struct androidfont_info *info;
   int i;
 
+  /* Maybe initialize the font driver.  */
+  androidfont_check_init ();
+
   info = (struct androidfont_info *) font;
 
   /* Free the font metrics cache if it exists.  */
@@ -805,6 +855,9 @@ androidfont_has_char (Lisp_Object font, int c)
   struct androidfont_info *info;
   struct androidfont_entity *entity;
 
+  /* Maybe initialize the font driver.  */
+  androidfont_check_init ();
+
   if (FONT_ENTITY_P (font))
     {
       entity = (struct androidfont_entity *) XFONT_ENTITY (font);
@@ -830,6 +883,9 @@ androidfont_encode_char (struct font *font, int c)
 {
   struct androidfont_info *info;
 
+  /* Maybe initialize the font driver.  */
+  androidfont_check_init ();
+
   info = (struct androidfont_info *) font;
 
   return (*android_java_env)->CallIntMethod (android_java_env,
@@ -891,6 +947,9 @@ androidfont_text_extents (struct font *font, const unsigned 
int *code,
   jobject metrics_object;
   short value;
 
+  /* Maybe initialize the font driver.  */
+  androidfont_check_init ();
+
   info = (struct androidfont_info *) font;
 
   if (nglyphs == 1
@@ -968,6 +1027,9 @@ androidfont_list_family (struct frame *f)
   jsize i, length;
   const char *family;
 
+  /* Maybe initialize the font driver.  */
+  androidfont_check_init ();
+
   family_array
     = (*android_java_env)->CallObjectMethod (android_java_env,
                                             font_driver,
@@ -1042,33 +1104,14 @@ syms_of_androidfont (void)
 void
 init_androidfont (void)
 {
-  jmethodID method;
-  jobject old;
-
   android_init_font_driver ();
   android_init_font_spec ();
   android_init_font_metrics ();
   android_init_font_object ();
   android_init_integer ();
 
-  method = font_driver_class.create_font_driver;
-
-  /* Initialize the font driver on the Java side.  */
-  font_driver
-    = (*android_java_env)->CallStaticObjectMethod (android_java_env,
-                                                  font_driver_class.class,
-                                                  method);
-
-  if (!font_driver)
-    memory_full (0);
-
-  old = font_driver;
-  font_driver
-    = (*android_java_env)->NewGlobalRef (android_java_env, font_driver);
-  ANDROID_DELETE_LOCAL_REF (old);
-
-  if (!font_driver)
-    memory_full (0);
+  /* The Java font driver is not initialized here because it uses a lot
+     of memory.  */
 }
 
 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)
   d = opendir (name);
 #else
   d = android_opendir (name);
+
+  if (d)
+    fd = android_dirfd (d);
 #endif
   opendir_errno = errno;
 #else
@@ -216,6 +219,9 @@ directory_files_internal (Lisp_Object directory, 
Lisp_Object full,
   Lisp_Object encoded_dirfilename = ENCODE_FILE (dirfilename);
 
   int fd;
+
+  /* Keep in mind that FD is not always a real file descriptor on
+     Android.  */
   emacs_dir *d = open_directory (dirfilename, encoded_dirfilename, &fd);
 
   /* 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)
   char *subdir_name = SAFE_ALLOCA (len + 2);
   memcpy (subdir_name, dp->d_name, len);
   strcpy (subdir_name + len, "/");
+
+#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY
+  /* Check if subdir_name lies in the assets directory.  */
+  if (android_file_access_p (subdir_name, F_OK))
+    return true;
+#endif
+
   bool dirp = faccessat (fd, subdir_name, F_OK, AT_EACCESS) == 0;
   SAFE_FREE ();
   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,
                     struct coding_system *);
 
 
+
+/* Check that ENCODED does not lie on any special directory whose
+   contents are read only.  Signal a `file-error' if it does.  */
+
+static void
+check_mutable_filename (Lisp_Object encoded)
+{
+#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY
+  if (!strcmp (SSDATA (encoded), "/assets")
+      || !strncmp (SSDATA (encoded), "/assets/",
+                  sizeof "/assets/" - 1))
+    xsignal2 (Qfile_error,
+             build_string ("File lies on read-"
+                           "only directory"),
+             encoded);
+#endif
+}
+
+
 /* Test whether FILE is accessible for AMODE.
    Return true if successful, false (setting errno) otherwise.  */
 
@@ -2215,6 +2234,7 @@ permissions.  */)
 
   encoded_file = ENCODE_FILE (file);
   encoded_newname = ENCODE_FILE (newname);
+  check_mutable_filename (encoded_newname);
 
 #ifdef WINDOWSNT
   if (NILP (ok_if_already_exists)
@@ -2474,6 +2494,8 @@ DEFUN ("delete-directory-internal", 
Fdelete_directory_internal,
   encoded_dir = ENCODE_FILE (directory);
   dir = SSDATA (encoded_dir);
 
+  check_mutable_filename (encoded_dir);
+
   if (rmdir (dir) != 0)
     report_file_error ("Removing directory", directory);
 
@@ -2513,6 +2535,7 @@ With a prefix argument, TRASH is nil.  */)
     return call1 (Qmove_file_to_trash, filename);
 
   encoded_file = ENCODE_FILE (filename);
+  check_mutable_filename (encoded_file);
 
   if (unlink (SSDATA (encoded_file)) != 0 && errno != ENOENT)
     report_file_error ("Removing old name", filename);
@@ -2670,6 +2693,8 @@ This is what happens in interactive use with M-x.  */)
 
   encoded_file = ENCODE_FILE (file);
   encoded_newname = ENCODE_FILE (newname);
+  check_mutable_filename (encoded_file);
+  check_mutable_filename (encoded_newname);
 
   bool plain_rename = (case_only_rename
                       || (!NILP (ok_if_already_exists)
@@ -2781,6 +2806,8 @@ This is what happens in interactive use with M-x.  */)
 
   encoded_file = ENCODE_FILE (file);
   encoded_newname = ENCODE_FILE (newname);
+  check_mutable_filename (encoded_file);
+  check_mutable_filename (encoded_newname);
 
   if (link (SSDATA (encoded_file), SSDATA (encoded_newname)) == 0)
     return Qnil;
@@ -2834,6 +2861,8 @@ This happens for interactive use with M-x.  */)
 
   encoded_target = ENCODE_FILE (target);
   encoded_linkname = ENCODE_FILE (linkname);
+  check_mutable_filename (encoded_target);
+  check_mutable_filename (encoded_linkname);
 
   if (symlink (SSDATA (encoded_target), SSDATA (encoded_linkname)) == 0)
     return Qnil;
@@ -3565,6 +3594,8 @@ Interactively, prompt for FILENAME, and read MODE with
 command from GNU Coreutils.  */)
   (Lisp_Object filename, Lisp_Object mode, Lisp_Object flag)
 {
+  Lisp_Object encoded;
+
   CHECK_FIXNUM (mode);
   int nofollow = symlink_nofollow_flag (flag);
   Lisp_Object absname = Fexpand_file_name (filename,
@@ -3576,7 +3607,9 @@ command from GNU Coreutils.  */)
   if (!NILP (handler))
     return call4 (handler, Qset_file_modes, absname, mode, flag);
 
-  char *fname = SSDATA (ENCODE_FILE (absname));
+  encoded = ENCODE_FILE (absname);
+  check_mutable_filename (encoded);
+  char *fname = SSDATA (encoded);
   mode_t imode = XFIXNUM (mode) & 07777;
   if (fchmodat (AT_FDCWD, fname, imode, nofollow) != 0)
     report_file_error ("Doing chmod", absname);
@@ -3648,6 +3681,7 @@ TIMESTAMP is in the format of `current-time'. */)
     return call4 (handler, Qset_file_times, absname, timestamp, flag);
 
   Lisp_Object encoded_absname = ENCODE_FILE (absname);
+  check_mutable_filename (encoded_absname);
 
   if (utimensat (AT_FDCWD, SSDATA (encoded_absname), ts, nofollow) != 0)
     {
@@ -3680,6 +3714,7 @@ otherwise, if FILE2 does not exist, the answer is t.  */)
   (Lisp_Object file1, Lisp_Object file2)
 {
   struct stat st1, st2;
+  Lisp_Object encoded;
 
   CHECK_STRING (file1);
   CHECK_STRING (file2);
@@ -3696,8 +3731,11 @@ otherwise, if FILE2 does not exist, the answer is t.  */)
   if (!NILP (handler))
     return call3 (handler, Qfile_newer_than_file_p, absname1, absname2);
 
+  encoded = ENCODE_FILE (absname1);
+  check_mutable_filename (encoded);
+
   int err1;
-  if (emacs_fstatat (AT_FDCWD, SSDATA (ENCODE_FILE (absname1)), &st1, 0) == 0)
+  if (emacs_fstatat (AT_FDCWD, SSDATA (encoded), &st1, 0) == 0)
     err1 = 0;
   else
     {
@@ -5853,6 +5891,7 @@ See Info node `(elisp)Modification Time' for more 
details.  */)
     return call2 (handler, Qverify_visited_file_modtime, buf);
 
   filename = ENCODE_FILE (BVAR (b, filename));
+  check_mutable_filename (filename);
 
   mtime = (emacs_fstatat (AT_FDCWD, SSDATA (filename), &st, 0) == 0
           ? get_stat_mtime (&st)
@@ -5913,7 +5952,7 @@ in `current-time' or an integer flag as returned by 
`visited-file-modtime'.  */)
     error ("An indirect buffer does not have a visited file");
   else
     {
-      register Lisp_Object filename;
+      register Lisp_Object filename, encoded;
       struct stat st;
       Lisp_Object handler;
 
@@ -5926,7 +5965,10 @@ in `current-time' or an integer flag as returned by 
`visited-file-modtime'.  */)
        /* The handler can find the file name the same way we did.  */
        return call2 (handler, Qset_visited_file_modtime, Qnil);
 
-      if (emacs_fstatat (AT_FDCWD, SSDATA (ENCODE_FILE (filename)), &st, 0)
+      encoded = ENCODE_FILE (filename);
+      check_mutable_filename (encoded);
+
+      if (emacs_fstatat (AT_FDCWD, SSDATA (encoded), &st, 0)
          == 0)
         {
          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.  */
 #include <dirent.h>
 #include <string.h>
 #include <stdio.h>
+#include <stdlib.h>
+
+#ifdef __aarch64__
+#include <arm_neon.h>
+#endif
 
 #include <android/api-level.h>
+#include <android/log.h>
 
 #include "androidterm.h"
 #include "sfntfont.h"
@@ -63,6 +69,8 @@ static size_t max_scanline_buffer_size;
 /* Return a temporary buffer for storing scan lines.
    Set BUFFER to the buffer upon success.  */
 
+#ifndef __aarch64__
+
 #define GET_SCANLINE_BUFFER(buffer, height, stride)            \
   do                                                           \
     {                                                          \
@@ -94,6 +102,39 @@ static size_t max_scanline_buffer_size;
        }                                                       \
     } while (false);
 
+#else
+
+#define GET_SCANLINE_BUFFER(buffer, height, stride)            \
+  do                                                           \
+    {                                                          \
+      size_t _size;                                            \
+      void *_temp;                                             \
+                                                               \
+      if (INT_MULTIPLY_WRAPV (height, stride, &_size))         \
+       memory_full (SIZE_MAX);                                 \
+                                                               \
+      if (_size > scanline_buffer.buffer_size)                 \
+       {                                                       \
+         if (posix_memalign (&_temp, 16, _size))               \
+           memory_full (_size);                                \
+         free (scanline_buffer.buffer_data);                   \
+         (buffer)                                              \
+           = scanline_buffer.buffer_data                       \
+           = _temp;                                            \
+         scanline_buffer.buffer_size = _size;                  \
+       }                                                       \
+      else if (_size <= scanline_buffer.buffer_size)           \
+       (buffer) = scanline_buffer.buffer_data;                 \
+      /* This is unreachable but clang says it is.  */         \
+      else                                                     \
+       emacs_abort ();                                         \
+                                                               \
+      max_scanline_buffer_size                                 \
+      = max (_size, max_scanline_buffer_size);                 \
+    } while (false);
+
+#endif
+
 
 
 /* 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)
   return both + src;
 }
 
+#ifdef __aarch64__
+
+/* Like U255TO256, but operates on vectors.  */
+
+static uint16x8_t
+sfntfont_android_u255to256 (uint8x8_t in)
+{
+  return vaddl_u8 (vshr_n_u8 (in, 7), in);
+}
+
+/* Use processor features to efficiently composite four pixels at SRC
+   to DST.  */
+
+static void
+sfntfont_android_over_8888_1 (unsigned int *src, unsigned int *dst)
+{
+  uint8x8_t alpha;
+  uint16x8_t alpha_c16, v1, v3, v4;
+  uint8x8_t b, g, r, a, v2, v5;
+  uint8x8x4_t _src, _dst;
+
+  /* Pull in src and dst.
+
+     This loads bytes, not words, so little endian ABGR becomes
+     RGBA.  */
+  _src = vld4_u8 ((const uint8_t *) src);
+  _dst = vld4_u8 ((const uint8_t *) dst);
+
+  /* Load constants.  */
+  v4 = vdupq_n_u16 (256);
+  v5 = vdup_n_u8 (0);
+
+  /* Load src alpha.  */
+  alpha = _src.val[3];
+
+  /* alpha_c16 = 256 - 255TO256 (alpha).  */
+  alpha_c16 = sfntfont_android_u255to256 (alpha);
+  alpha_c16 = vsubq_u16 (v4, alpha_c16);
+
+  /* Cout = Csrc + Cdst * alpha_c.  */
+  v1 = vaddl_u8 (_dst.val[2], v5);
+  v2 = _src.val[2];
+  v3 = vmulq_u16 (v1, alpha_c16);
+  b = vqadd_u8 (v2, vshrn_n_u16 (v3, 8));
+
+  v1 = vaddl_u8 (_dst.val[1], v5);
+  v2 = _src.val[1];
+  v3 = vmulq_u16 (v1, alpha_c16);
+  g = vqadd_u8 (v2, vshrn_n_u16 (v3, 8));
+
+  v1 = vaddl_u8 (_dst.val[0], v5);
+  v2 = _src.val[0];
+  v3 = vmulq_u16 (v1, alpha_c16);
+  r = vqadd_u8 (v2, vshrn_n_u16 (v3, 8));
+
+#if 0
+  /* Aout = Asrc + Adst * alpha_c.  */
+  v1 = vaddl_u8 (_dst.val[3], v5);
+  v2 = _src.val[3];
+  v3 = vmulq_u16 (v1, alpha_c16);
+  a = vqadd_u8 (v2, vshrn_n_u16 (v3, 8));
+#else
+  /* We know that Adst is always 1, so Asrc + Adst * (1 - Asrc) is
+     always 1.  */
+  a = vdup_n_u8 (255);
+#endif
+
+  /* Store back in dst.  */
+  _dst.val[0] = r;
+  _dst.val[1] = g;
+  _dst.val[2] = b;
+  _dst.val[3] = a;
+  vst4_u8 ((uint8_t *) dst, _dst);
+}
+
+/* Use processor features to efficiently composite the buffer at SRC
+   to DST.  Composite at most MAX - SRC words.
+
+   If either SRC or DST are not yet properly aligned, value is 1.
+   Otherwise, value is 0, and *X is incremented to the start of any
+   trailing data which could not be composited due to data alignment
+   constraints.  */
+
+static int
+sfntfont_android_over_8888 (unsigned int *src, unsigned int *dst,
+                           unsigned int *max, unsigned int *x)
+{
+  size_t i;
+  ptrdiff_t how_much;
+  void *s, *d;
+
+  /* Figure out how much can be composited by this loop.  */
+  how_much = (max - src) & ~7;
+
+  /* Return if there is not enough to vectorize.  */
+  if (!how_much)
+    return 1;
+
+  /* Now increment *X by that much so the containing loop can process
+     the remaining pixels one-by-one.  */
+
+  *x += how_much;
+
+  for (i = 0; i < how_much; i += 8)
+    {
+      s = (src + i);
+      d = (dst + i);
+
+      sfntfont_android_over_8888_1 (s, d);
+    }
+
+  return 0;
+}
+
+#endif
+
 /* Composite the bitmap described by BUFFER, STRIDE and TEXT_RECTANGLE
    onto the native-endian ABGR8888 bitmap described by DEST and
    BITMAP_INFO.  RECT is the subset of the bitmap to composite.  */
@@ -163,7 +320,7 @@ sfntfont_android_composite_bitmap (unsigned char *restrict 
buffer,
 {
   unsigned int *src_row;
   unsigned int *dst_row;
-  unsigned int i, src_y, x, src_x, max_x, dst_x;
+  unsigned int i, src_y, x, src_x, max_x, dst_x, lim_x;
 
   if ((intptr_t) dest & 3 || bitmap_info->stride & 3)
     /* This shouldn't be possible as Android is supposed to align the
@@ -196,9 +353,24 @@ sfntfont_android_composite_bitmap (unsigned char *restrict 
buffer,
              src_x = x + (rect->x - text_rectangle->x);
              dst_x = x + rect->x;
 
-             dst_row[dst_x]
-               = sfntfont_android_blend (src_row[src_x],
-                                         dst_row[dst_x]);
+             /* This is the largest value of src_x.  */
+             lim_x = max_x + (rect->x - text_rectangle->x);
+
+#ifdef __aarch64__
+             if (!sfntfont_android_over_8888 (src_row + src_x,
+                                              dst_row + dst_x,
+                                              src_row + lim_x,
+                                              &x))
+               {
+                 /* Decrement X by one so the for loop can increment
+                    it again.  */
+                 x--;
+                 continue;
+               }
+#endif
+               dst_row[dst_x]
+                 = sfntfont_android_blend (src_row[src_x],
+                                           dst_row[dst_x]);
            }
        }
     }
@@ -308,11 +480,21 @@ sfntfont_android_put_glyphs (struct glyph_string *s, int 
from,
   gui_union_rectangles (&background, &text_rectangle,
                        &text_rectangle);
 
-  /* Allocate enough to hold text_rectangle.height, aligned to 8
-     bytes.  Then fill it with the background.  */
+  /* Allocate enough to hold text_rectangle.height, aligned to 8 (or
+     16) bytes.  Then fill it with the background.  */
+#ifndef __aarch64__
   stride = ((text_rectangle.width * sizeof *buffer) + 7) & ~7;
+#else
+  stride = ((text_rectangle.width * sizeof *buffer) + 15) & ~15;
+#endif
   GET_SCANLINE_BUFFER (buffer, text_rectangle.height, stride);
-  memset (buffer, 0, text_rectangle.height * stride);
+
+  /* Try to optimize out this memset if the background rectangle
+     contains the whole text rectangle.  */
+
+  if (!with_background || memcmp (&background, &text_rectangle,
+                                 sizeof text_rectangle))
+    memset (buffer, 0, text_rectangle.height * stride);
 
   if (with_background)
     {



reply via email to

[Prev in Thread] Current Thread [Next in Thread]