emacs-diffs
[Top][All Lists]
Advanced

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

feature/android 494bedde32 1/2: Bring up the sfnt-android font driver


From: Po Lu
Subject: feature/android 494bedde32 1/2: Bring up the sfnt-android font driver
Date: Wed, 11 Jan 2023 03:07:52 -0500 (EST)

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

    Bring up the sfnt-android font driver
    
    * configure.ac (ANDROID_CFLAGS): Add sfnt-related font objects
    to ANDROID_OBJ when not building stubs.
    * lisp/startup.el (android-fonts-enumerated): New variable.
    (normal-top-level): Set it.  Also enumerate fonts as early as
    possible upon startup.
    
    * src/alloc.c (cleanup_vector): Only finalize Android font
    entities.
    (garbage_collect): Mark sfntfont.c.
    
    * src/android.c (struct android_emacs_drawable): New field
    `damage_rect'.
    (android_init_emacs_drawable): Initialize
    Lorg/gnu/emacs/EmacsDrawable;#damageRect(Landroid/graphics/rect;)V.
    (android_create_gc): Initialize cached GC fields.
    (android_free_gc): Free cached GC clip rectangles.
    (android_change_gc): Cache fields as appropriate.
    (android_set_clip_rectangles): Set cached clip rectangles for
    easy access from C.
    (android_get_gc_values): Use cached values.
    (android_get_image): Remove obsolete comment.
    (android_lock_bitmap, android_damage_window): New functions that
    don't parallel anything on X.
    
    * src/android.h: Update prototypes.
    
    * src/androidfns.c (android_default_font_parameter): Set Droid
    Sans Mono as the default monospace font.
    (Fx_create_frame): Register the sfntfont driver.
    
    * src/androidgui.h (struct android_gc): Add C side caches for
    clip rectangles and the foreground and background colors.
    
    * src/androidterm.h: Update prototypes.
    
    * src/dispextern.h (struct gui_box): New struct.
    (gui_union_rectangles): New function.
    
    * src/emacs.c (android_emacs_init): Initialize Android font
    stuff late.
    * src/font.c (font_make_entity): Clear `is_android' field on
    Android.
    (font_make_entity_android): Set `is_android' field.
    * src/font.h (struct font_entity): New field `is_android'.
    
    * src/print.c (print_vectorlike): Don't print private data,
    which could include Lisp_Misc.
    
    * src/sfnt.c (sfnt_read_cmap_format_0, sfnt_read_cmap_format_2)
    (sfnt_read_cmap_format_4, sfnt_read_cmap_format_6)
    (sfnt_read_cmap_format_8, sfnt_read_cmap_format_12): Remove
    buggy pragmas.
    (sfnt_lookup_glyph_4_1): New function.
    (sfnt_lookup_glyph_4): Handle malformed lookup tables found on
    Android.
    (sfnt_lookup_glyph): Fix overflow problems in glyph checks.
    (sfnt_read_glyph): Handle empty glyphs.  This implements some
    behavior which everyone else seems to as well, but I can't find
    documented in the TrueType Reference Manual.
    (sfnt_free_glyph): Export correctly.
    (sfnt_transform_coordinates): Make faster.
    (sfnt_lerp_half): Fix lerping in some cases.
    (sfnt_decompose_glyph): Handle empty glyphs correctly.  Close
    contours manually instead of waiting for the edge building
    process to do that.  This lets curves be handled correctly.
    (struct sfnt_build_glyph_outline_context): Move internal struct
    back to sfnt.c.
    (sfnt_build_append): Fix detection of initial entry.
    (sfnt_curve_to_and_build_1): Fix De Casteljau implementation.
    (sfnt_curve_to_and_build): Use fixed point arithmetic to scale
    outlines.
    (sfnt_build_glyph_outline): Clear reference counts.  Use fixed
    point arithmetic.
    (sfnt_prepare_raster): Align rasters to 4 bytes,
    SFNT_POLY_ALIGNMENT.  Fix calculation of offx and offy.
    (sfnt_step_edge_by): Step edge by previously computed step_x.
    (sfnt_build_outline_edges): Adjust for already closed contours.
    Ignore edges abandoned after grid fit.  Also precompute step_x
    to avoid multiplication on each span rastered.
    (sfnt_poly_edges): Improve alignment.
    (sfnt_fill_span): Rewrite to avoid control flow in while loop.
    (sfnt_poly_span): Remove unnecessary code.
    (sfnt_raster_glyph_outline): Use raster stride instead of width.
    (sfnt_test_edge, sfnt_test_raster, main): Improve debugging
    code.
    
    * src/sfnt.h (struct sfnt_glyph_outline): Add refcount field to
    outline.
    (struct sfnt_build_glyph_outline_context): Remove private
    struct.
    (struct sfnt_raster): Add refcount field to raster.
    (struct sfnt_edge): Improve doc.  Add `source_x' field used when
    built with TEST.
    (SFNT_CEIL_FIXED): New macro.
    
    * src/sfntfont-android.c (sfntfont_android_saturate32)
    (sfntfont_android_scale32, sfntfont_android_mul8x2)
    (sfntfont_android_blend, U255TO256)
    (sfntfont_android_composite_bitmap, sfntfont_android_union_boxes)
    (sfntfont_android_put_glyphs, sfntfont_android_get_cache): New
    functions.
    (android_sfntfont_driver): New font driver.
    (Fandroid_enumerate_fonts): New function.
    (syms_of_sfntfont_android_for_pdumper, init_sfntfont_android)
    (syms_of_sfntfont_android): Initialize default fonts, special
    family mapping and font driver.
    * src/sfntfont.c (struct sfnt_font_desc): New fields
    `char_cache', `cmap_invalid' and `subtable'.
    (sfnt_setup_coding_system): Improve commentary.  Add default
    branch.  Fix return value.
    (sfnt_safe_encode_coding_object_1)
    (sfnt_safe_encode_coding_object_2):
    (sfnt_safe_encode_coding_object): Use decode_coding_object
    instead of encode_coding_object.
    (sfnt_decode_font_string): Adjust for rename.
    (sfnt_decode_foundry_name): New function.
    (sfnt_weight_descriptions, sfnt_slant_descriptions)
    (sfnt_width_descriptions): Fix definitions.
    (sfnt_parse_style): Make function work.
    (sfnt_enum_font): Initialize designer, char-cache and subtable
    platform ID.
    (sfntfont_charset_for_name, mark_sfntfont)
    (sfntfont_charset_for_cmap): New functions.
    (syms_of_sfntfont): New variable `sfnt-default-family-alist'.
    
    * src/sfntfont.h (_SFNTFONT_H_): Update prototypes.
    
    * src/xdisp.c (gui_union_rectangles): New function.
---
 configure.ac           |    9 +-
 lisp/startup.el        |   13 +
 src/alloc.c            |   12 +-
 src/android.c          |  153 +++-
 src/android.h          |    7 +
 src/androidfns.c       |    4 +-
 src/androidgui.h       |   13 +
 src/androidterm.h      |    2 +
 src/dispextern.h       |   19 +
 src/emacs.c            |   22 +-
 src/font.c             |   10 +
 src/font.h             |    5 +
 src/print.c            |   17 +-
 src/sfnt.c             |  490 +++++++++----
 src/sfnt.h             |   55 +-
 src/sfntfont-android.c |  489 ++++++++++++-
 src/sfntfont.c         | 1822 ++++++++++++++++++++++++++++++++++++++++++++++--
 src/sfntfont.h         |   33 +
 src/xdisp.c            |   49 ++
 19 files changed, 2967 insertions(+), 257 deletions(-)

diff --git a/configure.ac b/configure.ac
index b348c0ad00..68de5f02b9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1360,6 +1360,9 @@ AS_IF([test $gl_gcc_warnings = no],
   nw="$nw -Wsync-nand"              # irrelevant here, and provokes ObjC 
warning
   nw="$nw -Wunsafe-loop-optimizations" # OK to suppress unsafe optimizations
   nw="$nw -Wbad-function-cast"      # These casts are no worse than others.
+  nw="$nw -Wunknown-warning-option" # Let #pragma GCC ignore work properly
+                                   # even when the compiler in use doesn't
+                                   # support the option.
 
   # Emacs doesn't care about shadowing; see
   # <https://lists.gnu.org/r/emacs-diffs/2011-11/msg00265.html>.
@@ -2250,12 +2253,16 @@ for Android, but all API calls need to be stubbed out])
     # requires Emacs be built as a position independent executable.
     ANDROID_CFLAGS="-fPIC -fvisibility=hidden"
 
+    # Graphics code in sfntfont-android.c benefits heavily from
+    # vectorization.
+    ANDROID_CFLAGS="$ANDROID_CFLAGS -ftree-vectorize"
+
     # Link with libraries required for Android support.
     ANDROID_LIBS="-landroid -llog -ljnigraphics"
 
     # Link with the sfnt font library and sfntfont.o, along with
     # sfntfont-android.o.
-    ANDROID_OBJ="sfnt.o sfntfont.o sfntfont-android.o"
+    ANDROID_OBJ="$ANDROID_OBJ sfnt.o sfntfont.o sfntfont-android.o"
   fi
 fi
 
diff --git a/lisp/startup.el b/lisp/startup.el
index fa84985580..5eb53ecc6d 100644
--- a/lisp/startup.el
+++ b/lisp/startup.el
@@ -574,11 +574,24 @@ the updated value."
     (setq startup--original-eln-load-path
           (copy-sequence native-comp-eln-load-path))))
 
+(defvar android-fonts-enumerated nil
+  "Whether or not fonts have been enumerated already.
+On Android, Emacs uses this variable internally at startup.")
+
 (defun normal-top-level ()
   "Emacs calls this function when it first starts up.
 It sets `command-line-processed', processes the command-line,
 reads the initialization files, etc.
 It is the default value of the variable `top-level'."
+  ;; Initialize the Android font driver late.
+  ;; This is done here because it needs the `mac-roman' coding system
+  ;; to be loaded.
+  (when (and (featurep 'android)
+             (fboundp 'android-enumerate-fonts)
+             (not android-fonts-enumerated))
+    (funcall 'android-enumerate-fonts)
+    (setq android-fonts-enumerated t))
+
   ;; Allow disabling automatic .elc->.eln processing.
   (setq inhibit-automatic-native-compilation
         (getenv "EMACS_INHIBIT_AUTOMATIC_NATIVE_COMPILATION"))
diff --git a/src/alloc.c b/src/alloc.c
index 65a49108d8..86e019b931 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -50,6 +50,10 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 #include TERM_HEADER
 #endif /* HAVE_WINDOW_SYSTEM */
 
+#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY
+#include "sfntfont.h"
+#endif
+
 #ifdef HAVE_TREE_SITTER
 #include "treesit.h"
 #endif
@@ -3346,8 +3350,9 @@ cleanup_vector (struct Lisp_Vector *vector)
 #if defined HAVE_ANDROID && !defined ANDROID_STUBIFY
       /* The Android font driver needs the ability to associate extra
         information with font entities.  */
-      if ((vector->header.size & PSEUDOVECTOR_SIZE_MASK)
-         == FONT_ENTITY_MAX)
+      if (((vector->header.size & PSEUDOVECTOR_SIZE_MASK)
+          == FONT_ENTITY_MAX)
+         && PSEUDOVEC_STRUCT (vector, font_entity)->is_android)
        android_finalize_font_entity (PSEUDOVEC_STRUCT (vector, font_entity));
 #endif
     }
@@ -6477,6 +6482,9 @@ garbage_collect (void)
 
 #ifdef HAVE_ANDROID
   mark_androidterm ();
+#ifndef ANDROID_STUBIFY
+  mark_sfntfont ();
+#endif
 #endif
 
 #ifdef HAVE_NS
diff --git a/src/android.c b/src/android.c
index e2056b666d..2f85266200 100644
--- a/src/android.c
+++ b/src/android.c
@@ -101,6 +101,7 @@ struct android_emacs_drawable
 {
   jclass class;
   jmethodID get_bitmap;
+  jmethodID damage_rect;
 };
 
 /* The asset manager being used.  */
@@ -1102,6 +1103,7 @@ android_init_emacs_drawable (void)
   assert (drawable_class.c_name);
 
   FIND_METHOD (get_bitmap, "getBitmap", "()Landroid/graphics/Bitmap;");
+  FIND_METHOD (damage_rect, "damageRect", "(Landroid/graphics/Rect;)V");
 #undef FIND_METHOD
 }
 
@@ -1743,6 +1745,12 @@ android_create_gc (enum android_gc_value_mask mask,
   gc = xmalloc (sizeof *gc);
   prev_max_handle = max_handle;
   gc->gcontext = android_alloc_id ();
+  gc->foreground = 0;
+  gc->background = 0xffffff;
+  gc->clip_rects = NULL;
+
+  /* This means to not apply any clipping.  */
+  gc->num_clip_rects = -1;
 
   if (!gc->gcontext)
     {
@@ -1780,6 +1788,8 @@ void
 android_free_gc (struct android_gc *gc)
 {
   android_destroy_handle (gc->gcontext);
+
+  xfree (gc->clip_rects);
   xfree (gc);
 }
 
@@ -1795,16 +1805,22 @@ android_change_gc (struct android_gc *gc,
                                     ANDROID_HANDLE_GCONTEXT);
 
   if (mask & ANDROID_GC_FOREGROUND)
-    (*android_java_env)->SetIntField (android_java_env,
-                                     gcontext,
-                                     emacs_gc_foreground,
-                                     values->foreground);
+    {
+      (*android_java_env)->SetIntField (android_java_env,
+                                       gcontext,
+                                       emacs_gc_foreground,
+                                       values->foreground);
+      gc->foreground = values->foreground;
+    }
 
   if (mask & ANDROID_GC_BACKGROUND)
-    (*android_java_env)->SetIntField (android_java_env,
-                                     gcontext,
-                                     emacs_gc_background,
-                                     values->background);
+    {
+      (*android_java_env)->SetIntField (android_java_env,
+                                       gcontext,
+                                       emacs_gc_background,
+                                       values->background);
+      gc->background = values->background;
+    }
 
   if (mask & ANDROID_GC_FUNCTION)
     (*android_java_env)->SetIntField (android_java_env,
@@ -1838,6 +1854,10 @@ android_change_gc (struct android_gc *gc,
                                           gcontext,
                                           emacs_gc_clip_rects,
                                           NULL);
+
+      xfree (gc->clip_rects);
+      gc->clip_rects = NULL;
+      gc->num_clip_rects = -1;
     }
 
   if (mask & ANDROID_GC_STIPPLE)
@@ -1943,6 +1963,19 @@ android_set_clip_rectangles (struct android_gc *gc, int 
clip_x_origin,
   (*android_java_env)->CallVoidMethod (android_java_env,
                                       gcontext,
                                       emacs_gc_mark_dirty);
+
+  /* Cache the clip rectangles on the C side for
+     sfntfont-android.c.  */
+  if (gc->clip_rects)
+    xfree (gc->clip_rects);
+
+  /* If gc->num_clip_rects is 0, then no drawing will be performed at
+     all.  */
+  gc->clip_rects = xmalloc (sizeof *gc->clip_rects
+                           * n_clip_rects);
+  gc->num_clip_rects = n_clip_rects;
+  memcpy (gc->clip_rects, clip_rects,
+         n_clip_rects * sizeof *gc->clip_rects);
 }
 
 void
@@ -2098,16 +2131,10 @@ android_get_gc_values (struct android_gc *gc,
   if (mask & ANDROID_GC_FOREGROUND)
     /* GCs never have 32 bit colors, so we don't have to worry about
        sign extension here.  */
-    values->foreground
-      = (*android_java_env)->GetIntField (android_java_env,
-                                         gcontext,
-                                         emacs_gc_foreground);
+    values->foreground = gc->foreground;
 
   if (mask & ANDROID_GC_BACKGROUND)
-    values->background
-      = (*android_java_env)->GetIntField (android_java_env,
-                                         gcontext,
-                                         emacs_gc_background);
+    values->background = gc->background;
 
   if (mask & ANDROID_GC_FUNCTION)
     values->function
@@ -2657,8 +2684,6 @@ android_get_image (android_drawable handle,
   unsigned char *data1, *data2;
   int i, x;
 
-  /* N.B. that supporting windows requires some more work to make
-     EmacsDrawable.getBitmap thread safe.  */
   drawable = android_resolve_handle2 (handle, ANDROID_HANDLE_WINDOW,
                                      ANDROID_HANDLE_PIXMAP);
 
@@ -2881,6 +2906,98 @@ android_put_image (android_pixmap handle, struct 
android_image *image)
 
 
 
+/* Low level drawing primitives.  */
+
+/* Lock the bitmap corresponding to the window WINDOW.  Return the
+   bitmap data upon success, and store the bitmap object in
+   BITMAP_RETURN.  Value is NULL upon failure.
+
+   The caller must take care to unlock the bitmap data afterwards.  */
+
+unsigned char *
+android_lock_bitmap (android_window window,
+                    AndroidBitmapInfo *bitmap_info,
+                    jobject *bitmap_return)
+{
+  jobject drawable, bitmap;
+  void *data;
+
+  drawable = android_resolve_handle (window, ANDROID_HANDLE_WINDOW);
+
+  /* Look up the drawable and get the bitmap corresponding to it.
+     Then, lock the bitmap's bits.  */
+  bitmap = (*android_java_env)->CallObjectMethod (android_java_env,
+                                                 drawable,
+                                                 drawable_class.get_bitmap);
+  if (!bitmap)
+    /* NULL is returned when the bitmap does not currently exist due
+       to ongoing reconfiguration on the main thread.  */
+    return NULL;
+
+  memset (bitmap_info, 0, sizeof *bitmap_info);
+
+  /* Get the bitmap info.  */
+  AndroidBitmap_getInfo (android_java_env, bitmap, bitmap_info);
+
+  if (!bitmap_info->stride)
+    {
+      ANDROID_DELETE_LOCAL_REF (bitmap);
+      return NULL;
+    }
+
+  /* Now lock the image data.  */
+  data = NULL;
+  AndroidBitmap_lockPixels (android_java_env, bitmap, &data);
+
+  if (!data)
+    {
+      ANDROID_DELETE_LOCAL_REF (bitmap);
+      return NULL;
+    }
+
+  /* Give the bitmap to the caller.  */
+  *bitmap_return = bitmap;
+
+  /* The bitmap data is now locked.  */
+  return data;
+}
+
+/* Damage the window HANDLE by the given damage rectangle.  */
+
+void
+android_damage_window (android_drawable handle,
+                      struct android_rectangle *damage)
+{
+  jobject drawable, rect;
+
+  drawable = android_resolve_handle (handle, ANDROID_HANDLE_WINDOW);
+
+  /* Now turn DAMAGE into a Java rectangle.  */
+  rect = (*android_java_env)->NewObject (android_java_env,
+                                        android_rect_class,
+                                        android_rect_constructor,
+                                        (jint) damage->x,
+                                        (jint) damage->y,
+                                        (jint) (damage->x
+                                                + damage->width),
+                                        (jint) (damage->y
+                                                + damage->height));
+  if (!rect)
+    {
+      (*android_java_env)->ExceptionClear (android_java_env);
+      memory_full (0);
+    }
+
+  /* Post the damage to the drawable.  */
+  (*android_java_env)->CallVoidMethod (android_java_env,
+                                      drawable,
+                                      drawable_class.damage_rect,
+                                      rect);
+  ANDROID_DELETE_LOCAL_REF (rect);
+}
+
+
+
 #undef faccessat
 
 /* Replace the system faccessat with one which understands AT_EACCESS.
diff --git a/src/android.h b/src/android.h
index 4d702fe207..4cf194f23c 100644
--- a/src/android.h
+++ b/src/android.h
@@ -29,6 +29,8 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 #include <pwd.h>
 #include <sys/stat.h>
 
+#include <android/bitmap.h>
+
 #include "androidgui.h"
 #endif
 
@@ -64,6 +66,11 @@ enum android_handle_type
 
 extern jobject android_resolve_handle (android_handle,
                                       enum android_handle_type);
+extern unsigned char *android_lock_bitmap (android_window,
+                                          AndroidBitmapInfo *,
+                                          jobject *);
+extern void android_damage_window (android_window,
+                                  struct android_rectangle *);
 
 #endif
 
diff --git a/src/androidfns.c b/src/androidfns.c
index 7fdb2f1414..96c2746a21 100644
--- a/src/androidfns.c
+++ b/src/androidfns.c
@@ -531,8 +531,7 @@ android_default_font_parameter (struct frame *f, 
Lisp_Object parms)
   if (! FONTP (font) && ! STRINGP (font))
     {
       const char *names[] = {
-       /* This will find the normal font.  The default font size on
-          Android is 8.  */
+       "Droid Sans Mono",
        "monospace",
        "DroidSansMono",
        NULL
@@ -772,6 +771,7 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
     }
 
   register_font_driver (&androidfont_driver, f);
+  register_font_driver (&android_sfntfont_driver, f);
 
   image_cache_refcount = (FRAME_IMAGE_CACHE (f)
                          ? FRAME_IMAGE_CACHE (f)->refcount
diff --git a/src/androidgui.h b/src/androidgui.h
index d51b73a764..7d045f7b45 100644
--- a/src/androidgui.h
+++ b/src/androidgui.h
@@ -116,8 +116,21 @@ struct android_gc_values
 
 struct android_gc
 {
+  /* Array of clip rectangles.  */
+  struct android_rectangle *clip_rects;
+
+  /* Number of clip rectangles.  When -1, it means clipping should not
+     be applied.  */
+  int num_clip_rects;
+
   /* The Java-side handle.  */
   android_gcontext gcontext;
+
+  /* Current foreground color.  */
+  unsigned long foreground;
+
+  /* Current background color.  */
+  unsigned long background;
 };
 
 enum android_swap_action
diff --git a/src/androidterm.h b/src/androidterm.h
index 562dcdead1..814bcf9f08 100644
--- a/src/androidterm.h
+++ b/src/androidterm.h
@@ -376,6 +376,8 @@ extern void android_finalize_font_entity (struct 
font_entity *);
 
 /* Defined in sfntfont-android.c.  */
 
+extern const struct font_driver android_sfntfont_driver;
+
 extern void init_sfntfont_android (void);
 extern void syms_of_sfntfont_android (void);
 
diff --git a/src/dispextern.h b/src/dispextern.h
index 770d29f867..2ceed53813 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -177,6 +177,22 @@ typedef void *Emacs_Cursor;
 #define NativeRectangle int
 #endif
 
+#ifdef HAVE_WINDOW_SYSTEM
+
+/* ``box'' structure similar to that found in the X sample server,
+   meaning that X2 and Y2 are not actually the end of the box, but one
+   pixel past the end of the box, which makes checking for overlaps
+   less necessary.  This is convenient to use in every GUI port.  */
+
+struct gui_box
+{
+  /* Bounds of the box.  */
+  int x1, y1;
+  int x2, y2;
+};
+
+#endif
+
 /* Text cursor types.  */
 
 enum text_cursor_kinds
@@ -3525,6 +3541,9 @@ extern void expose_frame (struct frame *, int, int, int, 
int);
 extern bool gui_intersect_rectangles (const Emacs_Rectangle *,
                                       const Emacs_Rectangle *,
                                       Emacs_Rectangle *);
+extern void gui_union_rectangles (const Emacs_Rectangle *,
+                                 const Emacs_Rectangle *,
+                                 Emacs_Rectangle *);
 extern void gui_consider_frame_title (Lisp_Object);
 #endif /* HAVE_WINDOW_SYSTEM */
 
diff --git a/src/emacs.c b/src/emacs.c
index e287ba53e1..e3f6c7d66f 100644
--- a/src/emacs.c
+++ b/src/emacs.c
@@ -2465,12 +2465,6 @@ Using an Emacs configured with --with-x-toolkit=lucid 
does not have this problem
   init_haiku_select ();
 #endif
 
-#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY
-  init_androidfont ();
-  init_sfntfont ();
-  init_sfntfont_android ();
-#endif
-
   init_charset ();
 
   /* This calls putenv and so must precede init_process_emacs.  */
@@ -2505,6 +2499,12 @@ Using an Emacs configured with --with-x-toolkit=lucid 
does not have this problem
   init_window ();
   init_font ();
 
+#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY
+  init_androidfont ();
+  init_sfntfont ();
+  init_sfntfont_android ();
+#endif
+
   if (!initialized)
     {
       char *file;
@@ -2559,6 +2559,16 @@ Using an Emacs configured with --with-x-toolkit=lucid 
does not have this problem
   safe_run_hooks (Qafter_pdump_load_hook);
 #endif
 
+#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY && 0
+  /* This comes very late in the startup process because it requires
+     most of lisp/international to be loaded.  This approach doesn't
+     work because normal-top-level runs and creates the initial frame
+     before fonts are initialized.  So this is done in
+     normal-top-level instead.  */
+  Vtop_level = list3 (Qprogn, Vtop_level,
+                     list1 (Qandroid_enumerate_fonts));
+#endif
+
   /* Enter editor command loop.  This never returns.  */
   set_initial_minibuffer_mode ();
   Frecursive_edit ();
diff --git a/src/font.c b/src/font.c
index b90013d3af..bf561095ef 100644
--- a/src/font.c
+++ b/src/font.c
@@ -177,6 +177,11 @@ font_make_entity (void)
        allocate_pseudovector (VECSIZE (struct font_entity),
                              FONT_ENTITY_MAX, FONT_ENTITY_MAX, PVEC_FONT));
   XSETFONT (font_entity, entity);
+
+#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY
+  entity->is_android = false;
+#endif
+
   return font_entity;
 }
 
@@ -190,6 +195,11 @@ font_make_entity_android (int size)
     = ((struct font_entity *)
        allocate_pseudovector (size, FONT_ENTITY_MAX, FONT_ENTITY_MAX,
                              PVEC_FONT));
+
+#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY
+  entity->is_android = true;
+#endif
+
   XSETFONT (font_entity, entity);
   return font_entity;
 }
diff --git a/src/font.h b/src/font.h
index 297ec4c1e7..ed3b17db99 100644
--- a/src/font.h
+++ b/src/font.h
@@ -260,6 +260,11 @@ struct font_entity
 {
   union vectorlike_header header;
   Lisp_Object props[FONT_ENTITY_MAX];
+
+#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY
+  /* Whether or not this is an Android font entity.  */
+  bool is_android;
+#endif
 };
 
 /* A value which may appear in the member `encoding' of struct font
diff --git a/src/print.c b/src/print.c
index d4a9ff8924..bc6d5487c1 100644
--- a/src/print.c
+++ b/src/print.c
@@ -1913,12 +1913,17 @@ print_vectorlike (Lisp_Object obj, Lisp_Object 
printcharfun, bool escapeflag,
              print_c_string ("#<font-entity", printcharfun);
            for (int i = 0; i < FONT_SPEC_MAX; i++)
              {
-               printchar (' ', printcharfun);
-               if (i < FONT_WEIGHT_INDEX || i > FONT_WIDTH_INDEX)
-                 print_object (AREF (obj, i), printcharfun, escapeflag);
-               else
-                 print_object (font_style_symbolic (obj, i, 0),
-                               printcharfun, escapeflag);
+               /* FONT_EXTRA_INDEX can contain private information in
+                  font entities which isn't safe to print.  */
+               if (i != FONT_EXTRA_INDEX || !FONT_ENTITY_P (obj))
+                 {
+                   printchar (' ', printcharfun);
+                   if (i < FONT_WEIGHT_INDEX || i > FONT_WIDTH_INDEX)
+                     print_object (AREF (obj, i), printcharfun, escapeflag);
+                   else
+                     print_object (font_style_symbolic (obj, i, 0),
+                                   printcharfun, escapeflag);
+                 }
              }
          }
        else
diff --git a/src/sfnt.c b/src/sfnt.c
index dfdc4f7acf..20cf2376d8 100644
--- a/src/sfnt.c
+++ b/src/sfnt.c
@@ -34,6 +34,10 @@ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 
USA.  */
 #include <string.h>
 #include <unistd.h>
 
+#if defined __GNUC__ && !defined __clang__
+#pragma GCC diagnostic ignored "-Wstringop-overflow"
+#endif
+
 #ifdef TEST
 
 #include <time.h>
@@ -221,17 +225,12 @@ sfnt_read_cmap_format_0 (int fd,
   format0->format = header->format;
   format0->length = header->length;
 
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wstringop-overflow"
-
   /* Read the rest.  */
   wanted_size = (sizeof *format0
                 - offsetof (struct sfnt_cmap_format_0,
                             language));
   rc = read (fd, &format0->language, wanted_size);
 
-#pragma GCC diagnostic pop
-
   if (rc < wanted_size)
     {
       xfree (format0);
@@ -267,9 +266,6 @@ sfnt_read_cmap_format_2 (int fd,
   format2->format = header->format;
   format2->length = header->length;
 
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wstringop-overflow"
-
   /* Read the part before the variable length data.  */
   min_bytes -= offsetof (struct sfnt_cmap_format_2, language);
   rc = read (fd, &format2->language, min_bytes);
@@ -313,8 +309,6 @@ sfnt_read_cmap_format_2 (int fd,
       return (struct sfnt_cmap_format_2 *) -1;
     }
 
-#pragma GCC diagnostic pop
-
   /* Check whether or not the data is of the correct size.  */
   if (min_bytes < nsub * sizeof *format2->subheaders)
     {
@@ -377,9 +371,6 @@ sfnt_read_cmap_format_4 (int fd,
   format4->format = header->format;
   format4->length = header->length;
 
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wstringop-overflow"
-
   /* Read the initial data.  */
   min_bytes -= offsetof (struct sfnt_cmap_format_4, language);
   rc = read (fd, &format4->language, min_bytes);
@@ -453,8 +444,6 @@ sfnt_read_cmap_format_4 (int fd,
   for (i = 0; i < format4->glyph_index_size; ++i)
     sfnt_swap16 (&format4->glyph_index_array[i]);
 
-#pragma GCC diagnostic pop
-
   /* Done.  Return the format 4 character map.  */
   return format4;
 }
@@ -486,9 +475,6 @@ sfnt_read_cmap_format_6 (int fd,
   format6->format = header->format;
   format6->length = header->length;
 
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wstringop-overflow"
-
   /* Read the fixed size data.  */
   min_size -= offsetof (struct sfnt_cmap_format_6, language);
   rc = read (fd, &format6->language, min_size);
@@ -522,8 +508,6 @@ sfnt_read_cmap_format_6 (int fd,
       return (struct sfnt_cmap_format_6 *) -1;
     }
 
-#pragma GCC diagnostic pop
-
   /* Set the data pointer and swap everything.  */
   format6->glyph_index_array = (uint16_t *) (format6 + 1);
   for (i = 0; i < format6->entry_count; ++i)
@@ -565,9 +549,6 @@ sfnt_read_cmap_format_8 (int fd,
   format8->reserved = header->length;
   format8->length = length;
 
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wstringop-overflow"
-
   /* Read the fixed length data.  */
   min_size -= offsetof (struct sfnt_cmap_format_8, language);
   rc = read (fd, &format8->language, min_size);
@@ -613,8 +594,6 @@ sfnt_read_cmap_format_8 (int fd,
       return (struct sfnt_cmap_format_8 *) -1;
     }
 
-#pragma GCC diagnostic pop
-
   /* Set the pointer to the variable length data.  */
   format8->groups
     = (struct sfnt_cmap_format_8_or_12_group *) (format8 + 1);
@@ -662,9 +641,6 @@ sfnt_read_cmap_format_12 (int fd,
   format12->reserved = header->length;
   format12->length = length;
 
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wstringop-overflow"
-
   /* Read the fixed length data.  */
   min_size -= offsetof (struct sfnt_cmap_format_12, language);
   rc = read (fd, &format12->language, min_size);
@@ -674,8 +650,6 @@ sfnt_read_cmap_format_12 (int fd,
       return (struct sfnt_cmap_format_12 *) -1;
     }
 
-#pragma GCC diagnostic pop
-
   /* Swap what was read.  */
   sfnt_swap32 (&format12->language);
   sfnt_swap32 (&format12->num_groups);
@@ -991,31 +965,15 @@ sfnt_compare_uint16 (const void *a, const void *b)
   return ((int) *((uint16_t *) a)) - ((int) *((uint16_t *) b));
 }
 
-/* Look up the glyph corresponding to CHARACTER in the format 4 cmap
-   FORMAT4.  Return 0 if no glyph was found.  */
+/* Look up the glyph corresponding to CODE in the format 4 cmap
+   FORMAT4, using the table segment SEGMENT.  Value is 0 if no glyph
+   was found.  */
 
 static sfnt_glyph
-sfnt_lookup_glyph_4 (sfnt_char character,
-                    struct sfnt_cmap_format_4 *format4)
+sfnt_lookup_glyph_4_1 (uint16_t code, uint16_t segment,
+                      struct sfnt_cmap_format_4 *format4)
 {
-  uint16_t *segment_address, *index;
-  uint16_t code, segment;
-
-  if (character > 65535)
-    return 0;
-
-  code = character;
-
-  /* Find the segment above CHARACTER.  */
-  segment_address = sfnt_bsearch_above (&code, format4->end_code,
-                                       format4->seg_count_x2 / 2,
-                                       sizeof code,
-                                       sfnt_compare_uint16);
-  segment = segment_address - format4->end_code;
-
-  /* If the segment starts too late, return 0.  */
-  if (!segment_address || format4->start_code[segment] > character)
-    return 0;
+  uint16_t *index;
 
   if (format4->id_range_offset[segment])
     {
@@ -1040,6 +998,63 @@ sfnt_lookup_glyph_4 (sfnt_char character,
   return (format4->id_delta[segment] + code) % 65536;
 }
 
+/* Look up the glyph corresponding to CHARACTER in the format 4 cmap
+   FORMAT4.  Return 0 if no glyph was found.  */
+
+static sfnt_glyph
+sfnt_lookup_glyph_4 (sfnt_char character,
+                    struct sfnt_cmap_format_4 *format4)
+{
+  uint16_t *segment_address;
+  uint16_t code, segment;
+  sfnt_glyph glyph;
+
+  if (character > 65535)
+    return 0;
+
+  code = character;
+
+  /* Find the segment ending above or at CHARACTER.  */
+  segment_address = sfnt_bsearch_above (&code, format4->end_code,
+                                       format4->seg_count_x2 / 2,
+                                       sizeof code,
+                                       sfnt_compare_uint16);
+  segment = segment_address - format4->end_code;
+
+  /* If the segment starts too late, return 0.  */
+  if (!segment_address || format4->start_code[segment] > character)
+    return 0;
+
+  glyph = sfnt_lookup_glyph_4_1 (character, segment, format4);
+
+  if (glyph)
+    return glyph;
+
+  /* Droid Sans Mono has overlapping segments in its format 4 cmap
+     subtable where the first segment's end code is 32, while the
+     second segment's start code is also 32.  The TrueType Reference
+     Manual says that mapping should begin by searching for the first
+     segment whose end code is greater than or equal to the character
+     being indexed, but that results in the first subtable being
+     found, which doesn't work, while the second table does.  Try to
+     detect this situation and use the second table if possible.  */
+
+  if (!glyph
+      /* The character being looked up is the current segment's end
+        code.  */
+      && code == format4->end_code[segment]
+      /* There is an additional segment.  */
+      && segment + 1 < format4->seg_count_x2 / 2
+      /* That segment's start code is the same as this segment's end
+        code.  */
+      && format4->start_code[segment + 1] == format4->end_code[segment])
+    /* Try the second segment.  */
+    return sfnt_lookup_glyph_4_1 (character, segment + 1, format4);
+
+  /* Fail.  */
+  return 0;
+}
+
 /* Look up the glyph corresponding to CHARACTER in the format 6 cmap
    FORMAT6.  Return 0 if no glyph was found.  */
 
@@ -1107,7 +1122,7 @@ sfnt_lookup_glyph_12 (sfnt_char character,
    which must be in the correct encoding for the cmap table pointed to
    by DATA.  */
 
-static sfnt_glyph
+TEST_STATIC sfnt_glyph
 sfnt_lookup_glyph (sfnt_char character,
                   struct sfnt_cmap_encoding_subtable_data *data)
 {
@@ -1520,7 +1535,7 @@ sfnt_read_simple_glyph (struct sfnt_glyph *glyph,
 
   /* Calculate the minimum size of the glyph data.  This is the size
      of the instruction length field followed by
-     glyf->number_of_contours * sizeof (uint16_t).  */
+     glyph->number_of_contours * sizeof (uint16_t).  */
 
   min_size = (glyph->number_of_contours * sizeof (uint16_t)
              + sizeof (uint16_t));
@@ -2023,26 +2038,51 @@ sfnt_read_glyph (sfnt_glyph glyph_code,
                 struct sfnt_loca_table_long *loca_long)
 {
   struct sfnt_glyph glyph, *memory;
-  ptrdiff_t offset;
+  ptrdiff_t offset, next_offset;
+
+  /* Check the glyph code is within bounds.  */
+  if (glyph_code > 65535)
+    return NULL;
 
   if (loca_short)
     {
-      /* Check that the glyph is within bounds.  */
-      if (glyph_code > loca_short->num_offsets)
+      /* Check that the glyph is within bounds.  glyph_code + 1 is the
+        entry in the table which defines the length of the glyph.  */
+      if (glyph_code + 1 >= loca_short->num_offsets)
        return NULL;
 
       offset = loca_short->offsets[glyph_code] * 2;
+      next_offset = loca_short->offsets[glyph_code + 1] * 2;
     }
   else if (loca_long)
     {
-      if (glyph_code > loca_long->num_offsets)
+      if (glyph_code + 1 >= loca_long->num_offsets)
        return NULL;
 
       offset = loca_long->offsets[glyph_code];
+      next_offset = loca_long->offsets[glyph_code + 1];
     }
   else
     abort ();
 
+  /* If offset - next_offset is 0, then the glyph is empty.  Its
+     horizontal advance may still be provided by the hmtx table.  */
+
+  if (offset == next_offset)
+    {
+      glyph.number_of_contours = 0;
+      glyph.xmin = 0;
+      glyph.ymin = 0;
+      glyph.xmax = 0;
+      glyph.ymax = 0;
+      glyph.simple = xmalloc (sizeof *glyph.simple);
+      glyph.compound = NULL;
+      memset (glyph.simple, 0, sizeof *glyph.simple);
+      memory = xmalloc (sizeof *memory);
+      *memory = glyph;
+      return memory;
+    }
+
   /* Verify that GLYF is big enough to hold a glyph at OFFSET.  */
   if (glyf->size < offset + SFNT_ENDOF (struct sfnt_glyph,
                                        ymax, sfnt_fword))
@@ -2102,7 +2142,7 @@ sfnt_read_glyph (sfnt_glyph glyph_code,
 
 /* Free a glyph returned from sfnt_read_glyph.  GLYPH may be NULL.  */
 
-static void
+TEST_STATIC void
 sfnt_free_glyph (struct sfnt_glyph *glyph)
 {
   if (!glyph)
@@ -2122,7 +2162,7 @@ sfnt_free_glyph (struct sfnt_glyph *glyph)
 
 static void
 sfnt_transform_coordinates (struct sfnt_compound_glyph_component *component,
-                           sfnt_fixed *x, sfnt_fixed *y,
+                           sfnt_fixed *restrict x, sfnt_fixed *restrict y,
                            size_t num_coordinates)
 {
   double m1, m2, m3;
@@ -2516,8 +2556,8 @@ static void
 sfnt_lerp_half (struct sfnt_point *control1, struct sfnt_point *control2,
                struct sfnt_point *result)
 {
-  result->x = (control1->x + control2->x) / 2;
-  result->y = (control1->y + control2->y) / 2;
+  result->x = control1->x + ((control2->x - control1->x) >> 1);
+  result->y = control1->y + ((control2->y - control1->y) >> 1);
 }
 
 /* Decompose GLYPH into its individual components.  Call MOVE_TO to
@@ -2548,7 +2588,7 @@ sfnt_decompose_glyph (struct sfnt_glyph *glyph,
                      sfnt_free_glyph_proc free_glyph,
                      void *dcontext)
 {
-  size_t here, last;
+  size_t here, start, last;
   struct sfnt_point pen, control1, control2;
   struct sfnt_compound_glyph_context context;
   size_t n;
@@ -2556,8 +2596,8 @@ sfnt_decompose_glyph (struct sfnt_glyph *glyph,
   if (glyph->simple)
     {
       if (!glyph->number_of_contours)
-       /* No contours.  */
-       return 1;
+       /* No contours.  Nothing needs to be decomposed.  */
+       return 0;
 
       here = 0;
 
@@ -2573,6 +2613,9 @@ sfnt_decompose_glyph (struct sfnt_glyph *glyph,
          pen.y = glyph->simple->y_coordinates[here] << 16U;
          move_to (pen, dcontext);
 
+         /* Record start so the contour can be closed.  */
+         start = here;
+
          /* If there is only one point in a contour, draw a one pixel
             wide line.  */
          if (last == here)
@@ -2635,6 +2678,39 @@ sfnt_decompose_glyph (struct sfnt_glyph *glyph,
                  curve_to (control1, pen, dcontext);
                }
            }
+
+         /* Now close the contour if there is more than one point
+            inside it.  */
+         if (start != here - 1)
+           {
+             /* Restore here after the for loop increased it.  */
+             here --;
+
+             if (glyph->simple->flags[start] & 01) /* On Curve */
+               {
+                 pen.x = glyph->simple->x_coordinates[start] << 16U;
+                 pen.y = glyph->simple->y_coordinates[start] << 16U;
+
+                 /* See if the last point (in this case, `here') was
+                    on the curve.  If it wasn't, then curve from
+                    there to here.  */
+                 if (!(glyph->simple->flags[here] & 01))
+                   {
+                     control1.x
+                       = glyph->simple->x_coordinates[here] << 16U;
+                     control1.y
+                       = glyph->simple->y_coordinates[here] << 16U;
+                     curve_to (control1, pen, dcontext);
+                   }
+                 else
+                   /* Otherwise, this is an ordinary line from there
+                      to here.  */
+                   line_to (pen, dcontext);
+               }
+
+             /* Restore here to where it was earlier.  */
+             here++;
+           }
        }
 
       return 0;
@@ -2659,7 +2735,7 @@ sfnt_decompose_glyph (struct sfnt_glyph *glyph,
 
   if (!context.num_end_points)
     /* No contours.  */
-    goto fail;
+    goto early;
 
   here = 0;
 
@@ -2675,6 +2751,9 @@ sfnt_decompose_glyph (struct sfnt_glyph *glyph,
       pen.y = context.y_coordinates[here];
       move_to (pen, dcontext);
 
+      /* Record start so the contour can be closed.  */
+      start = here;
+
       /* If there is only one point in a contour, draw a one pixel
         wide line.  */
       if (last == here)
@@ -2735,8 +2814,40 @@ sfnt_decompose_glyph (struct sfnt_glyph *glyph,
              curve_to (control1, pen, dcontext);
            }
        }
+
+      /* Now close the contour if there is more than one point
+        inside it.  */
+      if (start != here - 1)
+       {
+         /* Restore here after the for loop increased it.  */
+         here --;
+
+         if (context.flags[start] & 01) /* On Curve */
+           {
+             pen.x = context.x_coordinates[start];
+             pen.y = context.y_coordinates[start];
+
+             /* See if the last point (in this case, `here') was
+                on the curve.  If it wasn't, then curve from
+                there to here.  */
+             if (!(context.flags[here] & 01))
+               {
+                 control1.x = context.x_coordinates[here];
+                 control1.y = context.y_coordinates[here];
+                 curve_to (control1, pen, dcontext);
+               }
+             else
+               /* Otherwise, this is an ordinary line from there
+                  to here.  */
+               line_to (pen, dcontext);
+           }
+
+         /* Restore here to where it was earlier.  */
+         here++;
+       }
     }
 
+ early:
   xfree (context.x_coordinates);
   xfree (context.y_coordinates);
   xfree (context.flags);
@@ -2751,6 +2862,25 @@ sfnt_decompose_glyph (struct sfnt_glyph *glyph,
   return 1;
 }
 
+struct sfnt_build_glyph_outline_context
+{
+  /* The outline being built.  */
+  struct sfnt_glyph_outline *outline;
+
+  /* The head table.  */
+  struct sfnt_head_table *head;
+
+  /* The pixel size being used, and any extra flags to apply to the
+     outline at this point.  */
+  int pixel_size;
+
+  /* Factor to multiply positions by to get the pixel width.  */
+  sfnt_fixed factor;
+
+  /* The position of the pen in 16.16 fixed point format.  */
+  sfnt_fixed x, y;
+};
+
 /* Global state for sfnt_build_glyph_outline and related
    functions.  */
 static struct sfnt_build_glyph_outline_context build_outline_context;
@@ -2794,7 +2924,7 @@ sfnt_build_append (int flags, sfnt_fixed x, sfnt_fixed y)
 
   /* Extend outline bounding box.  */
 
-  if (outline->outline_used == 3)
+  if (outline->outline_used == 1)
     {
       /* These are the first points in the outline.  */
       outline->xmin = outline->xmax = x;
@@ -2811,40 +2941,6 @@ sfnt_build_append (int flags, sfnt_fixed x, sfnt_fixed y)
   return outline;
 }
 
-/* Set the pen size to the specified point and return.  POINT will be
-   scaled up to the pixel size.  */
-
-static void
-sfnt_move_to_and_build (struct sfnt_point point, void *dcontext)
-{
-  sfnt_fixed x, y;
-
-  x = build_outline_context.factor * point.x;
-  y = build_outline_context.factor * point.y;
-
-  build_outline_context.outline = sfnt_build_append (0, x, y);
-  build_outline_context.x = x;
-  build_outline_context.y = y;
-}
-
-/* Record a line to the specified point and return.  POINT will be
-   scaled up to the pixel size.  */
-
-static void
-sfnt_line_to_and_build (struct sfnt_point point, void *dcontext)
-{
-  sfnt_fixed x, y;
-
-  x = build_outline_context.factor * point.x;
-  y = build_outline_context.factor * point.y;
-
-  build_outline_context.outline
-    = sfnt_build_append (SFNT_GLYPH_OUTLINE_LINETO,
-                        x, y);
-  build_outline_context.x = x;
-  build_outline_context.y = y;
-}
-
 /* Multiply the two 16.16 fixed point numbers X and Y.  Return the
    result regardless of overflow.  */
 
@@ -2878,6 +2974,40 @@ sfnt_mul_fixed (sfnt_fixed x, sfnt_fixed y)
 #endif
 }
 
+/* Set the pen size to the specified point and return.  POINT will be
+   scaled up to the pixel size.  */
+
+static void
+sfnt_move_to_and_build (struct sfnt_point point, void *dcontext)
+{
+  sfnt_fixed x, y;
+
+  x = sfnt_mul_fixed (build_outline_context.factor, point.x);
+  y = sfnt_mul_fixed (build_outline_context.factor, point.y);
+
+  build_outline_context.outline = sfnt_build_append (0, x, y);
+  build_outline_context.x = x;
+  build_outline_context.y = y;
+}
+
+/* Record a line to the specified point and return.  POINT will be
+   scaled up to the pixel size.  */
+
+static void
+sfnt_line_to_and_build (struct sfnt_point point, void *dcontext)
+{
+  sfnt_fixed x, y;
+
+  x = sfnt_mul_fixed (build_outline_context.factor, point.x);
+  y = sfnt_mul_fixed (build_outline_context.factor, point.y);
+
+  build_outline_context.outline
+    = sfnt_build_append (SFNT_GLYPH_OUTLINE_LINETO,
+                        x, y);
+  build_outline_context.x = x;
+  build_outline_context.y = y;
+}
+
 /* Divide the two 16.16 fixed point numbers X and Y.  Return the
    result regardless of overflow.  */
 
@@ -2957,7 +3087,7 @@ sfnt_curve_to_and_build_1 (struct sfnt_point control0,
                           struct sfnt_point control1,
                           struct sfnt_point endpoint)
 {
-  struct sfnt_point ab;
+  struct sfnt_point ab, bc, abbc;
 
   /* control0, control and endpoint make up the spline.  Figure out
      its distance from a line.  */
@@ -2972,15 +3102,17 @@ sfnt_curve_to_and_build_1 (struct sfnt_point control0,
     }
   else
     {
-      /* Split the spline between control0 and control1.
+      /* Calculate new control points.
          Maybe apply a recursion limit here? */
       sfnt_lerp_half (&control0, &control1, &ab);
+      sfnt_lerp_half (&control1, &endpoint, &bc);
+      sfnt_lerp_half (&ab, &bc, &abbc);
 
       /* Keep splitting until a flat enough spline results.  */
-      sfnt_curve_to_and_build_1 (control0, ab, control1);
+      sfnt_curve_to_and_build_1 (control0, ab, abbc);
 
       /* Then go on with the spline between control1 and endpoint.  */
-      sfnt_curve_to_and_build_1 (ab, control1, endpoint);
+      sfnt_curve_to_and_build_1 (abbc, bc, endpoint);
     }
 }
 
@@ -2997,17 +3129,21 @@ sfnt_curve_to_and_build (struct sfnt_point control,
 
   control0.x = build_outline_context.x;
   control0.y = build_outline_context.y;
-  control.x *= build_outline_context.factor;
-  control.y *= build_outline_context.factor;
-  endpoint.x *= build_outline_context.factor;
-  endpoint.y *= build_outline_context.factor;
+  control.x = sfnt_mul_fixed (control.x,
+                             build_outline_context.factor);
+  control.y = sfnt_mul_fixed (control.y,
+                             build_outline_context.factor);
+  endpoint.x = sfnt_mul_fixed (endpoint.x,
+                              build_outline_context.factor);
+  endpoint.y = sfnt_mul_fixed (endpoint.y,
+                              build_outline_context.factor);
 
   sfnt_curve_to_and_build_1 (control0, control, endpoint);
 }
 
 /* Non-reentrantly build the outline for the specified GLYPH at the
-   given pixel size.  Return the outline data upon success, or NULL
-   upon failure.
+   given pixel size.  Return the outline data with a refcount of 0
+   upon success, or NULL upon failure.
 
    Call GET_GLYPH and FREE_GLYPH with the specified DCONTEXT to obtain
    glyphs for compound glyph subcomponents.
@@ -3029,6 +3165,7 @@ sfnt_build_glyph_outline (struct sfnt_glyph *glyph,
   outline = xmalloc (sizeof *outline + 40 * sizeof (*outline->outline));
   outline->outline_size = 40;
   outline->outline_used = 0;
+  outline->refcount = 0;
   outline->outline
     = (struct sfnt_glyph_outline_command *) (outline + 1);
 
@@ -3059,7 +3196,8 @@ sfnt_build_glyph_outline (struct sfnt_glyph *glyph,
      It would be nice to get rid of this floating point arithmetic at
      some point.  */
   build_outline_context.factor
-    = (double) pixel_size / head->units_per_em;
+    = sfnt_div_fixed (pixel_size << 16,
+                     head->units_per_em << 16);
 
   /* Decompose the outline.  */
   rc = sfnt_decompose_glyph (glyph, sfnt_move_to_and_build,
@@ -3108,11 +3246,17 @@ sfnt_poly_grid_ceil (sfnt_fixed f)
           & ~(SFNT_POLY_STEP - 1)) + SFNT_POLY_START);
 }
 
+enum
+  {
+    SFNT_POLY_ALIGNMENT = 4,
+  };
+
 /* Initialize the specified RASTER in preparation for displaying spans
-   for OUTLINE.  The caller must then set RASTER->cells to a zeroed
-   array of size RASTER->width * RASTER->height.  */
+   for OUTLINE, and set RASTER->refcount to 0.  The caller must then
+   set RASTER->cells to a zeroed array of size RASTER->stride *
+   RASTER->height, aligned to RASTER.  */
 
-static void
+TEST_STATIC void
 sfnt_prepare_raster (struct sfnt_raster *raster,
                     struct sfnt_glyph_outline *outline)
 {
@@ -3120,10 +3264,17 @@ sfnt_prepare_raster (struct sfnt_raster *raster,
     = sfnt_ceil_fixed (outline->xmax - outline->xmin) >> 16;
   raster->height
     = sfnt_ceil_fixed (outline->ymax - outline->ymin) >> 16;
+  raster->refcount = 0;
+
+  /* Align the raster to a SFNT_POLY_ALIGNMENT byte boundary.  */
+  raster->stride = ((raster->width
+                    + (SFNT_POLY_ALIGNMENT - 1))
+                   & ~(SFNT_POLY_ALIGNMENT - 1));
+
   raster->offx
-    = sfnt_floor_fixed (outline->xmin);
+    = sfnt_floor_fixed (outline->xmin) >> 16;
   raster->offy
-    = sfnt_floor_fixed (raster->height - outline->ymax);
+    = sfnt_floor_fixed (outline->ymin) >> 16;
 }
 
 typedef void (*sfnt_edge_proc) (struct sfnt_edge *, size_t,
@@ -3131,13 +3282,13 @@ typedef void (*sfnt_edge_proc) (struct sfnt_edge *, 
size_t,
 typedef void (*sfnt_span_proc) (struct sfnt_edge *, sfnt_fixed, void *);
 
 /* Move EDGE->x forward, assuming that the scanline has moved upwards
-   by DY.  */
+   by SFNT_POLY_STEP.  */
 
 static void
-sfnt_step_edge_by (struct sfnt_edge *edge, sfnt_fixed dy)
+sfnt_step_edge (struct sfnt_edge *edge)
 {
   /* Step edge.  */
-  edge->x += sfnt_mul_fixed (edge->step_x, dy);
+  edge->x += edge->step_x;
 }
 
 /* Build a list of edges for each contour in OUTLINE, applying
@@ -3151,31 +3302,26 @@ sfnt_build_outline_edges (struct sfnt_glyph_outline 
*outline,
                          sfnt_edge_proc edge_proc, void *dcontext)
 {
   struct sfnt_edge *edges;
-  size_t i, edge, start, next_vertex, y;
-  sfnt_fixed dx, dy, bot;
+  size_t i, edge, next_vertex;
+  sfnt_fixed dx, dy, bot, step_x;
   int inc_x;
-  size_t top, bottom;
+  size_t top, bottom, y;
 
   edges = alloca (outline->outline_used * sizeof *edges);
   edge = 0;
 
-  /* First outline currently being processed.  */
-  start = 0;
-
-  for (i = 0; i < outline->outline_used; i++)
+  for (i = 0; i < outline->outline_used; ++i)
     {
-      if (!(outline->outline[i].flags & SFNT_GLYPH_OUTLINE_LINETO))
-       /* Flush the edge.  */
-       start = i;
-
       /* Set NEXT_VERTEX to the next point (vertex) in this contour.
-        If i + 3 is the end of the contour, then the next point is
-        its start, so wrap it around to there.  */
+
+        If i is past the end of the contour, then don't build edges
+        for this point.  */
       next_vertex = i + 1;
+
       if (next_vertex == outline->outline_used
          || !(outline->outline[next_vertex].flags
               & SFNT_GLYPH_OUTLINE_LINETO))
-       next_vertex = start;
+       continue;
 
       /* Skip past horizontal vertices.  */
       if (outline->outline[next_vertex].y == outline->outline[i].y)
@@ -3220,6 +3366,10 @@ sfnt_build_outline_edges (struct sfnt_glyph_outline 
*outline,
       dy = abs (outline->outline[top].y
                - outline->outline[bottom].y);
 
+#ifdef TEST
+      edges[edge].source_x = edges[edge].x;
+#endif
+
       /* Compute the increment.  This is which direction X moves in
         for each increase in Y.  */
 
@@ -3233,14 +3383,24 @@ sfnt_build_outline_edges (struct sfnt_glyph_outline 
*outline,
 
       /* Compute the step X.  This is how much X changes for each
         increase in Y.  */
-      edges[edge].step_x = inc_x * sfnt_div_fixed (dx, dy);
+      step_x = inc_x * sfnt_div_fixed (dx, dy);
 
       /* Step to first grid point.  */
       y = sfnt_poly_grid_ceil (bot);
-      sfnt_step_edge_by (&edges[edge], bot - y);
+
+      /* If rounding would make the edge not cover any area, skip this
+        edge.  */
+      if (y > edges[edge].top)
+       continue;
+
+      edges[edge].x += sfnt_mul_fixed (step_x, bot - y);
       edges[edge].bottom = y;
       edges[edge].next = NULL;
 
+      /* Compute the step X scaled to the poly step.  */
+      edges[edge].step_x
+       = sfnt_mul_fixed (step_x, SFNT_POLY_STEP);
+
       edge++;
     }
 
@@ -3344,7 +3504,7 @@ sfnt_poly_edges (struct sfnt_edge *edges, size_t size,
 
       /* Step all edges.  */
       for (a = active; a; a = a->next)
-       sfnt_step_edge_by (a, SFNT_POLY_STEP);
+       sfnt_step_edge (a);
 
       /* Resort on X axis.  */
       for (prev = &active; (a = *prev) && (n = a->next);)
@@ -3380,7 +3540,7 @@ sfnt_fill_span (struct sfnt_raster *raster, sfnt_fixed y,
 {
   unsigned char *start;
   unsigned char *coverage;
-  sfnt_fixed left, right;
+  sfnt_fixed left, right, end;
   unsigned short w, a;
   int row, col;
 
@@ -3408,7 +3568,13 @@ sfnt_fill_span (struct sfnt_raster *raster, sfnt_fixed y,
      right are now 16.2.  */
   left = sfnt_poly_grid_ceil (x0) >> (16 - SFNT_POLY_SHIFT);
   right = sfnt_poly_grid_ceil (x1) >> (16 - SFNT_POLY_SHIFT);
-  start = raster->cells + row * raster->width;
+#if 7 > __GNUC__
+  start = raster->cells + row * raster->stride;
+#else
+  start = __builtin_assume_aligned ((raster->cells
+                                    + row * raster->stride),
+                                   SFNT_POLY_ALIGNMENT);
+#endif
   start += left >> SFNT_POLY_SHIFT;
 
   /* Compute coverage for first pixel, then poly.  */
@@ -3420,7 +3586,10 @@ sfnt_fill_span (struct sfnt_raster *raster, sfnt_fixed y,
         map, unlike row which indexes the raster.  */
       col = 0;
 
-      while (left < right && (left & SFNT_POLY_MASK))
+      /* Precompute this to allow for better optimizations.  */
+      end = ((left + SFNT_POLY_SAMPLE - 1) & ~SFNT_POLY_MASK);
+
+      while (left < right && left < end)
        left++, w += coverage[col++];
 
       a = *start + w;
@@ -3477,10 +3646,6 @@ sfnt_poly_span (struct sfnt_edge *start, sfnt_fixed y,
 
   for (edge = start; edge; edge = edge->next)
     {
-      /* Skip out of bounds spans.  This ought to go away.  */
-      if (!(y >= edge->bottom && y < edge->top))
-       continue;
-
       if (!winding)
        x0 = edge->x;
       else
@@ -3528,10 +3693,10 @@ sfnt_raster_glyph_outline (struct sfnt_glyph_outline 
*outline)
   sfnt_prepare_raster (&raster, outline);
 
   /* Allocate the raster data.  */
-  data = xmalloc (sizeof *data + raster.width * raster.height);
+  data = xmalloc (sizeof *data + raster.stride * raster.height);
   *data = raster;
   data->cells = (unsigned char *) (data + 1);
-  memset (data->cells, 0, raster.width * raster.height);
+  memset (data->cells, 0, raster.stride * raster.height);
 
   /* Generate edges for the outline, polying each array of edges to
      the raster.  */
@@ -4131,16 +4296,25 @@ sfnt_test_edge (struct sfnt_edge *edges, size_t 
num_edges,
 
   for (i = 0; i < num_edges; ++i)
     {
-      printf ("/* edge x, top, bot: %g, %g - %g.  winding: %d */\n",
+      printf ("/* edge x, top, bot: %g, %g - %g.  winding: %d */\n"
+             "/* edge step_x: %g, source_x: %g (%d) */\n",
              sfnt_coerce_fixed (edges[i].x),
              sfnt_coerce_fixed (edges[i].top),
              sfnt_coerce_fixed (edges[i].bottom),
-             edges[i].winding);
+             edges[i].winding,
+             sfnt_coerce_fixed (edges[i].step_x),
+             sfnt_coerce_fixed (edges[i].source_x),
+             edges[i].source_x);
 #ifdef TEST_VERTEX
       printf ("ctx.fillRect (%g, %g, 1, 1);\n",
              sfnt_coerce_fixed (edges[i].x),
              sfnt_coerce_fixed (sfnt_test_max
                                 - edges[i].y));
+#else
+      printf ("ctx.fillRect (%g, %g, 1, 1);\n",
+             sfnt_coerce_fixed (edges[i].x),
+             sfnt_coerce_fixed (sfnt_test_max
+                                - edges[i].bottom));
 #endif
     }
 
@@ -4157,7 +4331,7 @@ sfnt_test_raster (struct sfnt_raster *raster)
   for (y = 0; y < raster->height; ++y)
     {
       for (x = 0; x < raster->width; ++x)
-       printf ("%3d ", (int) raster->cells[y * raster->width + x]);
+       printf ("%3d ", (int) raster->cells[y * raster->stride + x]);
       puts ("");
     }
 }
@@ -4411,7 +4585,7 @@ main (int argc, char **argv)
              /* Time this important bit.  */
              clock_gettime (CLOCK_THREAD_CPUTIME_ID, &start);
              outline = sfnt_build_glyph_outline (glyph, head,
-                                                 40,
+                                                 45,
                                                  sfnt_test_get_glyph,
                                                  sfnt_test_free_glyph,
                                                  &dcontext);
@@ -4449,13 +4623,23 @@ main (int argc, char **argv)
                  sfnt_build_outline_edges (outline, sfnt_test_edge,
                                            NULL);
 
+                 raster = NULL;
+
                  clock_gettime (CLOCK_THREAD_CPUTIME_ID, &start);
-                 raster = sfnt_raster_glyph_outline (outline);
+
+                 for (i = 0; i < 400; ++i)
+                   {
+                     xfree (raster);
+                     raster = sfnt_raster_glyph_outline (outline);
+                   }
+
                  clock_gettime (CLOCK_THREAD_CPUTIME_ID, &end);
                  sub2 = timespec_sub (end, start);
 
                  /* Print out the raster.  */
                  sfnt_test_raster (raster);
+                 printf ("raster offsets: %d, %d\n",
+                         raster->offx, raster->offy);
 
                  xfree (raster);
 
@@ -4468,7 +4652,7 @@ main (int argc, char **argv)
 
              if (hmtx && head)
                {
-                 if (!sfnt_lookup_glyph_metrics (code, 40,
+                 if (!sfnt_lookup_glyph_metrics (code, 36,
                                                  &metrics,
                                                  hmtx, hhea,
                                                  head, maxp))
@@ -4482,7 +4666,7 @@ main (int argc, char **argv)
              printf ("time spent building edges: %lld sec %ld nsec\n",
                      (long long) sub1.tv_sec, sub1.tv_nsec);
              printf ("time spent rasterizing: %lld sec %ld nsec\n",
-                     (long long) sub2.tv_sec, sub2.tv_nsec);
+                     (long long) sub2.tv_sec / 400, sub2.tv_nsec / 400);
 
              xfree (outline);
            }
diff --git a/src/sfnt.h b/src/sfnt.h
index 868d0f9b5a..91d7b261cb 100644
--- a/src/sfnt.h
+++ b/src/sfnt.h
@@ -663,6 +663,9 @@ struct sfnt_glyph_outline
   /* Rectangle defining bounds of the outline.  Namely, the minimum
      and maximum X and Y positions.  */
   sfnt_fixed xmin, ymin, xmax, ymax;
+
+  /* Reference count.  Initially zero.  */
+  short refcount;
 };
 
 enum sfnt_glyph_outline_flags
@@ -670,39 +673,26 @@ enum sfnt_glyph_outline_flags
     SFNT_GLYPH_OUTLINE_LINETO    = (1 << 1),
   };
 
-struct sfnt_build_glyph_outline_context
-{
-  /* The outline being built.  */
-  struct sfnt_glyph_outline *outline;
-
-  /* The head table.  */
-  struct sfnt_head_table *head;
-
-  /* The pixel size being used, and any extra flags to apply to the
-     outline at this point.  */
-  int pixel_size;
-
-  /* Factor to multiply positions by to get the pixel width.  */
-  double factor;
-
-  /* The position of the pen in 16.16 fixed point format.  */
-  sfnt_fixed x, y;
-};
-
 
 
 /* Glyph rasterization.  */
 
 struct sfnt_raster
 {
+  /* Pointer to coverage data.  */
+  unsigned char *cells;
+
   /* Basic dimensions of the raster.  */
   unsigned short width, height;
 
   /* Integer offset to apply to positions in the raster.  */
-  unsigned short offx, offy;
+  short offx, offy;
 
-  /* Pointer to coverage data.  */
-  unsigned char *cells;
+  /* The raster stride.  */
+  unsigned short stride;
+
+  /* Reference count.  Initially zero.  */
+  unsigned short refcount;
 };
 
 struct sfnt_edge
@@ -716,8 +706,15 @@ struct sfnt_edge
   /* X position, top and bottom of edges.  */
   sfnt_fixed x, top, bottom;
 
-  /* step_x is how many pixels to move for each increase in Y.  */
+  /* step_x is how many pixels to move for each increase in Y by
+     SFNT_POLY_STEP.  */
   sfnt_fixed step_x;
+
+#ifdef TEST
+  /* Value of x before initial adjustment of bottom to match the
+     grid.  */
+  sfnt_fixed source_x;
+#endif
 };
 
 
@@ -878,6 +875,12 @@ enum sfnt_meta_data_tag
 
 
 
+#define SFNT_CEIL_FIXED(fixed)                 \
+  (!((fixed) & 0177777) ? (fixed)              \
+   : ((fixed) + 0200000) & 037777600000)
+
+
+
 /* Function declarations.  Keep these sorted by the order in which
    they appear in sfnt.c.  Keep each line no longer than 80
    columns.  */
@@ -890,9 +893,12 @@ extern struct sfnt_offset_subtable 
*sfnt_read_table_directory (int);
   int, struct sfnt_offset_subtable *,          \
   struct sfnt_cmap_encoding_subtable **,       \
   struct sfnt_cmap_encoding_subtable_data ***
-static struct sfnt_cmap_table *sfnt_read_cmap_table (PROTOTYPE);
+extern struct sfnt_cmap_table *sfnt_read_cmap_table (PROTOTYPE);
 #undef PROTOTYPE
 
+extern sfnt_glyph sfnt_lookup_glyph (sfnt_char,
+                                    struct sfnt_cmap_encoding_subtable_data *);
+
 #define PROTOTYPE int, struct sfnt_offset_subtable *
 extern struct sfnt_head_table *sfnt_read_head_table (PROTOTYPE);
 extern struct sfnt_hhea_table *sfnt_read_hhea_table (PROTOTYPE);
@@ -905,6 +911,7 @@ extern struct sfnt_glyf_table *sfnt_read_glyf_table 
(PROTOTYPE);
 extern struct sfnt_glyph *sfnt_read_glyph (sfnt_glyph, struct sfnt_glyf_table 
*,
                                           struct sfnt_loca_table_short *,
                                           struct sfnt_loca_table_long *);
+extern void sfnt_free_glyph (struct sfnt_glyph *);
 
 #define PROTOTYPE              \
   struct sfnt_glyph *,         \
diff --git a/src/sfntfont-android.c b/src/sfntfont-android.c
index d3c05fa4ac..47aa27dc11 100644
--- a/src/sfntfont-android.c
+++ b/src/sfntfont-android.c
@@ -19,18 +19,505 @@ along with GNU Emacs.  If not, write to the Free Software 
Foundation,
 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
 #include <config.h>
+#include <dirent.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <android/api-level.h>
 
 #include "androidterm.h"
 #include "sfntfont.h"
+#include "pdumper.h"
+#include "blockinput.h"
+#include "android.h"
+
+/* Array of directories to search for system fonts.  */
+const char *system_font_directories[] =
+  {
+    "/system/fonts",
+  };
+
+/* The font cache.  */
+static Lisp_Object font_cache;
+
+
+
+static unsigned int
+sfntfont_android_saturate32 (unsigned int a, unsigned int b)
+{
+  unsigned int c;
+
+  c = a + b;
+
+  if (c < a)
+    c = -1;
+
+  return c;
+}
+
+/* Scale each of the four packed bytes in P in the low 16 bits of P by
+   SCALE.  Return the result.
+
+   SCALE is an integer between 0 and 256.  */
+
+static unsigned int
+sfntfont_android_scale32 (unsigned int scale, unsigned int p)
+{
+  uint32_t ag, rb;
+  uint32_t scaled_ag, scaled_rb;
+
+  ag = (p & 0xFF00FF00) >> 8;
+  rb = (p & 0x00FF00FF);
+
+  scaled_ag = (scale * ag) & 0xFF00FF00;
+  scaled_rb = (scale * rb) >> 8 & 0x00FF00FF;
+
+  return scaled_ag | scaled_rb;
+}
+
+static unsigned int
+sfntfont_android_mul8x2 (unsigned int a8, unsigned int b32)
+{
+  unsigned int i;
+
+  b32 &= 0xff00ff;
+  i = a8 * b32 + 0x800080;
+
+  return (i + ((i >> 8) & 0xff00ff)) >> 8 & 0xff00ff;
+}
+
+/* Blend two pixels SRC and DST without utilizing any control flow.
+   SRC must be in premultiplied ARGB8888 format, and DST must be in
+   premultiplied ABGR8888 format.  Value is in premultiplied ABGR8888
+   format.  */
+
+static unsigned int
+sfntfont_android_blend (unsigned int src, unsigned int dst)
+{
+  unsigned int a, br_part, ag_part, src_rb, both;
+
+  a = (src >> 24);
+  br_part = sfntfont_android_mul8x2 (255 - a, dst);
+  ag_part = sfntfont_android_mul8x2 (255 - a, dst >> 8) << 8;
+
+  both = ag_part | br_part;
+
+  /* Swizzle src.  */
+  src_rb = src & 0x00ff00ff;
+  src = src & ~0x00ff00ff;
+  src |= (src_rb >> 16 | src_rb << 16);
+
+  /* Saturating is unnecessary but helps find bugs.  */
+  return sfntfont_android_saturate32 (both, src);
+}
+
+#define U255TO256(x) ((unsigned short) (x) + ((x) >> 7))
+
+/* Blend two pixels SRC and DST without utilizing any control flow.
+   Both SRC and DST are expected to be in premultiplied ARGB8888
+   format.  Value is returned in premultiplied ARGB8888 format.  */
+
+static unsigned int
+sfntfont_android_blendrgb (unsigned int src, unsigned int dst)
+{
+  unsigned int a, rb_part, ag_part, both;
+
+  a = (src >> 24);
+  rb_part = sfntfont_android_mul8x2 (255 - a, dst);
+  ag_part = sfntfont_android_mul8x2 (255 - a, dst >> 8) << 8;
+
+  both = ag_part | rb_part;
+
+  /* Saturating is unnecessary but helps find bugs.  */
+  return sfntfont_android_saturate32 (both, src);
+}
+
+/* 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.  */
+
+static void
+sfntfont_android_composite_bitmap (unsigned char *restrict buffer,
+                                  size_t stride,
+                                  unsigned char *restrict dest,
+                                  AndroidBitmapInfo *bitmap_info,
+                                  struct android_rectangle *text_rectangle,
+                                  struct android_rectangle *rect)
+{
+  unsigned int *src_row;
+  unsigned int *dst_row;
+  unsigned int i, src_y, x, src_x, max_x, dst_x;
+
+  if ((intptr_t) dest & 3 || bitmap_info->stride & 3)
+    /* This shouldn't be possible as Android is supposed to align the
+       bitmap to at least a 4 byte boundary.  */
+    emacs_abort ();
+  else
+    {
+      for (i = 0; i < rect->height; ++i)
+       {
+         if (i + rect->y >= bitmap_info->height)
+           /* Done.  */
+           return;
+
+         src_y = i + (rect->y - text_rectangle->y);
+
+         src_row = (unsigned int *) ((buffer + src_y * stride));
+         dst_row = (unsigned int *) (dest + ((i + rect->y)
+                                             * bitmap_info->stride));
+
+         /* Figure out where the loop below should end.  */
+         max_x = min (rect->width, bitmap_info->width - rect->x);
+
+         /* Keep this loop simple! */
+         for (x = 0; x < max_x; ++x)
+           {
+             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]);
+           }
+       }
+    }
+}
+
+/* Calculate the union containing both A and B, both boxes.  Place the
+   result in RESULT.  */
+
+static void
+sfntfont_android_union_boxes (struct gui_box a, struct gui_box b,
+                             struct gui_box *result)
+{
+  result->x1 = min (a.x1, b.x1);
+  result->y1 = min (a.y1, b.y1);
+  result->x2 = max (a.x2, b.x2);
+  result->y2 = max (a.y2, b.y2);
+}
+
+/* Draw the specified glyph rasters from FROM to TO on behalf of S,
+   using S->gc.  Fill the background if WITH_BACKGROUND is true.
+
+   See init_sfntfont_vendor and sfntfont_draw for more details.  */
+
+static void
+sfntfont_android_put_glyphs (struct glyph_string *s, int from,
+                            int to, int x, int y, bool with_background,
+                            struct sfnt_raster **rasters,
+                            int *x_coords)
+{
+  struct android_rectangle background, text_rectangle, rect;
+  struct gui_box text, character;
+  unsigned int *buffer, *row;
+  unsigned char *restrict raster_row;
+  size_t stride, i;
+  AndroidBitmapInfo bitmap_info;
+  unsigned char *bitmap_data;
+  jobject bitmap;
+  int left, top, temp_y;
+  unsigned int prod, raster_y;
+
+  if (!s->gc->num_clip_rects)
+    /* Clip region is empty.  */
+    return;
+
+  if (from == to)
+    /* Nothing to draw.  */
+    return;
+
+  USE_SAFE_ALLOCA;
+
+  prepare_face_for_display (s->f, s->face);
+
+  /* Build the scanline buffer.  Figure out the bounds of the
+     background.  */
+  memset (&background, 0, sizeof background);
+
+  if (with_background)
+    {
+      background.x = x;
+      background.y = y - FONT_BASE (s->font);
+      background.width = s->width;
+      background.height = FONT_HEIGHT (s->font);
+    }
+
+  /* Now figure out the bounds of the text.  */
+
+  if (rasters[0])
+    {
+      text.x1 = x_coords[0] + rasters[0]->offx;
+      text.x2 = text.x1 + rasters[0]->width;
+      text.y1 = y - (rasters[0]->height + rasters[0]->offy);
+      text.y2 = y - rasters[0]->offy;
+    }
+  else
+    memset (&text, 0, sizeof text);
+
+  for (i = 1; i < to - from; ++i)
+    {
+      /* See if text has to be extended.  */
+
+      if (!rasters[i])
+       continue;
+
+      character.x1 = x_coords[i] + rasters[i]->offx;
+      character.x2 = character.x1 + rasters[i]->width;
+      character.y1 = y - (rasters[i]->height + rasters[i]->offy);
+      character.y2 = y - rasters[i]->offy;
+
+      sfntfont_android_union_boxes (text, character, &text);
+    }
+
+  /* Union the background rect with the text rectangle.  */
+  text_rectangle.x = text.x1;
+  text_rectangle.y = text.y1;
+  text_rectangle.width = text.x2 - text.x1;
+  text_rectangle.height = text.y2 - text.y1;
+  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.  */
+  stride = (text_rectangle.width * sizeof *buffer) + 7 & ~7;
+  SAFE_NALLOCA (buffer, text_rectangle.height, stride);
+  memset (buffer, 0, text_rectangle.height * stride);
+
+  if (with_background)
+    {
+      /* Fill the background.  First, offset the background rectangle
+        to become relative from text_rectangle.x,
+        text_rectangle.y.  */
+      background.x = background.x - text_rectangle.x;
+      background.y = background.y - text_rectangle.y;
+      eassert (background.x >= 0 && background.y >= 0);
+
+      for (temp_y = background.y; (temp_y
+                                  < (background.y
+                                     + background.height));
+          ++temp_y)
+       {
+         row = (unsigned int *) ((unsigned char *) buffer
+                                 + stride * temp_y);
+
+         for (x = background.x; x < background.x + background.width; ++x)
+           row[x] = s->gc->background | 0xff000000;
+       }
+    }
+
+  /* Draw all the rasters onto the buffer.  */
+  for (i = 0; i < to - from; ++i)
+    {
+      if (!rasters[i])
+       continue;
+
+      /* Figure out the top and left of the raster relative to
+        text_rectangle.  */
+      left = x_coords[i] + rasters[i]->offx - text_rectangle.x;
+
+      /* Note that negative offy represents the part of the text that
+        lies below the baseline.  */
+      top = (y - (rasters[i]->height + rasters[i]->offy)
+            - text_rectangle.y);
+      eassert (left >= 0 && top >= 0);
+
+      /* Draw the raster onto the temporary bitmap using the
+        foreground color scaled by the alpha map.  */
+
+      for (raster_y = 0; raster_y < rasters[i]->height; ++raster_y)
+       {
+         row = (unsigned int *) ((unsigned char *) buffer
+                                 + stride * (raster_y + top));
+         raster_row = &rasters[i]->cells[raster_y * rasters[i]->stride];
+
+         for (x = 0; x < rasters[i]->width; ++x)
+           {
+             prod
+               = sfntfont_android_scale32 (U255TO256 (raster_row[x]),
+                                           (s->gc->foreground
+                                            | 0xff000000));
+             row[left + x]
+               = sfntfont_android_blendrgb (prod, row[left + x]);
+           }
+       }
+    }
+
+  /* Lock the bitmap.  It must be unlocked later.  */
+  bitmap_data = android_lock_bitmap (FRAME_ANDROID_WINDOW (s->f),
+                                    &bitmap_info, &bitmap);
+
+  /* If locking the bitmap fails, just discard the data that was
+     allocated.  */
+  if (!bitmap_data)
+    {
+      SAFE_FREE ();
+      return;
+    }
+
+  /* Loop over each clip rect in the GC.  */
+  eassert (bitmap_info.format == ANDROID_BITMAP_FORMAT_RGBA_8888);
+
+  if (s->gc->num_clip_rects > 0)
+    {
+      for (i = 0; i < s->gc->num_clip_rects; ++i)
+       {
+         if (!gui_intersect_rectangles (&s->gc->clip_rects[i],
+                                        &text_rectangle, &rect))
+           /* Outside the clip region.  */
+           continue;
+
+         /* Composite the intersection onto the buffer.  */
+         sfntfont_android_composite_bitmap ((unsigned char *) buffer,
+                                            stride, bitmap_data,
+                                            &bitmap_info,
+                                            &text_rectangle, &rect);
+       }
+    }
+  else /* gc->num_clip_rects < 0 */
+    sfntfont_android_composite_bitmap ((unsigned char *) buffer,
+                                      stride, bitmap_data,
+                                      &bitmap_info,
+                                      &text_rectangle,
+                                      &text_rectangle);
+
+  /* Release the bitmap.  */
+  AndroidBitmap_unlockPixels (android_java_env, bitmap);
+  ANDROID_DELETE_LOCAL_REF (bitmap);
+
+  /* Damage the window by the text rectangle.  */
+  android_damage_window (FRAME_ANDROID_WINDOW (s->f),
+                        &text_rectangle);
+
+  /* Release the temporary scanline buffer.  */
+  SAFE_FREE ();
+}
+
+
+
+/* Font driver definition.  */
+
+/* Return the font cache for this font driver.  F is ignored.  */
+
+static Lisp_Object
+sfntfont_android_get_cache (struct frame *f)
+{
+  return font_cache;
+}
+
+/* The Android sfntfont driver.  */
+const struct font_driver android_sfntfont_driver =
+  {
+    .type = LISPSYM_INITIALLY (Qsfnt_android),
+    .case_sensitive = true,
+    .get_cache = sfntfont_android_get_cache,
+    .list = sfntfont_list,
+    .match = sfntfont_match,
+    .draw = sfntfont_draw,
+    .open_font = sfntfont_open,
+    .close_font = sfntfont_close,
+    .encode_char = sfntfont_encode_char,
+    .text_extents = sfntfont_text_extents,
+    .list_family = sfntfont_list_family,
+
+    /* TODO: list_family, shaping.  */
+  };
+
+
+
+/* This is an ugly hack that should go away, but I can't think of
+   how.  */
+
+DEFUN ("android-enumerate-fonts", Fandroid_enumerate_fonts,
+       Sandroid_enumerate_fonts, 0, 0, 0,
+       doc: /* Enumerate fonts present on the system.
+
+Signal an error if fonts have already been enumerated.  This would
+normally have been done in C, but reading fonts require Lisp to be
+loaded before character sets are made available.  */)
+  (void)
+{
+  DIR *dir;
+  int i;
+  struct dirent *dirent;
+  char name[PATH_MAX * 2];
+  static bool enumerated;
+
+  if (enumerated)
+    error ("Fonts have already been enumerated");
+  enumerated = true;
+
+  block_input ();
+
+  /* Scan through each of the system font directories.  Enumerate each
+     font that looks like a TrueType font.  */
+  for (i = 0; i < ARRAYELTS (system_font_directories); ++i)
+    {
+      dir = opendir (system_font_directories[i]);
+
+      if (!dir)
+       continue;
+
+      while ((dirent = readdir (dir)))
+       {
+         /* If it contains (not ends with!) with .ttf, then enumerate
+            it.  */
+
+         if (strstr (dirent->d_name, ".ttf"))
+           {
+             sprintf (name, "%s/%s", system_font_directories[i],
+                      dirent->d_name);
+             sfnt_enum_font (name);
+           }
+       }
+
+      closedir (dir);
+    }
+
+  unblock_input ();
+
+  return Qnil;
+}
+
+
+
+static void
+syms_of_sfntfont_android_for_pdumper (void)
+{
+  init_sfntfont_vendor (Qsfnt_android, &android_sfntfont_driver,
+                       sfntfont_android_put_glyphs);
+  register_font_driver (&android_sfntfont_driver, NULL);
+}
 
 void
 init_sfntfont_android (void)
 {
-
+  /* Make sure to pick the right Sans Serif font depending on what
+     version of Android the device is running.  */
+  if (android_get_device_api_level () >= 15)
+    Vsfnt_default_family_alist
+      = list2 (Fcons (build_string ("Monospace"),
+                     build_string ("Droid Sans Mono")),
+              Fcons (build_string ("Sans Serif"),
+                     build_string ("Roboto")));
+  else
+    Vsfnt_default_family_alist
+      = list2 (Fcons (build_string ("Monospace"),
+                     build_string ("Droid Sans Mono")),
+              Fcons (build_string ("Sans Serif"),
+                     build_string ("Droid Sans")));
 }
 
 void
 syms_of_sfntfont_android (void)
 {
+  DEFSYM (Qsfnt_android, "sfnt-android");
+  DEFSYM (Qandroid_enumerate_fonts, "android-enumerate-fonts");
+  Fput (Qandroid, Qfont_driver_superseded_by, Qsfnt_android);
+
+  font_cache = list (Qnil);
+  staticpro (&font_cache);
+
+  defsubr (&Sandroid_enumerate_fonts);
 
+  pdumper_do_now_and_after_load (syms_of_sfntfont_android_for_pdumper);
 }
diff --git a/src/sfntfont.c b/src/sfntfont.c
index a9cc6d11b4..9206fbc662 100644
--- a/src/sfntfont.c
+++ b/src/sfntfont.c
@@ -20,12 +20,25 @@ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 
USA.  */
 
 #include <config.h>
 
+#include <fcntl.h>
+
 #include "lisp.h"
-#include "sfnt.h"
+
+#include "blockinput.h"
+#include "charset.h"
 #include "coding.h"
+#include "font.h"
+#include "frame.h"
+#include "math.h"
+#include "sfnt.h"
+#include "sfntfont.h"
+
+/* For FRAME_FONT.  */
+#include TERM_HEADER
 
 /* Generic font driver for sfnt-based fonts (currently TrueType, but
-   it would be easy to add CFF support in the future.)
+   it would be easy to add CFF support in the future with a PostScript
+   renderer.)
 
    This is not a complete font driver.  Hooks must be supplied by the
    platform implementer to draw glyphs.  */
@@ -45,11 +58,25 @@ struct sfnt_font_desc
   /* Style name of the font.  */
   Lisp_Object style;
 
+  /* Designer (foundry) of the font.  */
+  Lisp_Object designer;
+
   /* Numeric width, weight, slant and spacing.  */
   int width, weight, slant, spacing;
 
   /* Path to the font file.  */
   char *path;
+
+  /* char table consisting of characters already known to be
+     present in the font.  */
+  Lisp_Object char_cache;
+
+  /* Whether or not the character map can't be used by Emacs.  */
+  bool cmap_invalid;
+
+  /* The header of the cmap being used.  May be invalid, in which case
+     platform_id will be 500.  */
+  struct sfnt_cmap_encoding_subtable subtable;
 };
 
 /* List of fonts.  */
@@ -94,19 +121,21 @@ sfnt_setup_coding_system (enum sfnt_platform_id id, int 
platform_specific_id,
     case SFNT_PLATFORM_MICROSOFT:
       system = Qutf_16be;
 
-      /* FIXME will someone look at the MS spec and see if this
-        right.  */
-      if (platform_specific_id
-         == SFNT_MICROSOFT_BIG_FIVE)
+      /* Not sure if this is right.  */
+      if (platform_specific_id == SFNT_MICROSOFT_BIG_FIVE)
        system = Qchinese_big5;
 
       break;
+
+    default:
+      system = Qnil;
     }
 
   if (NILP (system))
     return 1;
 
   setup_coding_system (system, coding);
+  return 0;
 }
 
 /* Globals used to communicate inside the condition-case wrapper.  */
@@ -130,9 +159,9 @@ static Lisp_Object sfnt_font_dst_object;
 static bool sfnt_font_signal;
 
 static Lisp_Object
-sfnt_safe_encode_coding_object_1 (void)
+sfnt_safe_decode_coding_object_1 (void)
 {
-  encode_coding_object (sfnt_font_coding,
+  decode_coding_object (sfnt_font_coding,
                        sfnt_font_src_object,
                        sfnt_font_from,
                        sfnt_font_from_byte,
@@ -143,18 +172,18 @@ sfnt_safe_encode_coding_object_1 (void)
 }
 
 static Lisp_Object
-sfnt_safe_encode_coding_object_2 (void)
+sfnt_safe_decode_coding_object_2 (Lisp_Object error)
 {
   sfnt_font_signal = true;
 
   return Qnil;
 }
 
-/* Like encode_coding_object, but return 1 if a signal happens.  Value
+/* Like decode_coding_object, but return 1 if a signal happens.  Value
    is otherwise 0.  */
 
 static int
-sfnt_safe_encode_coding_object (struct coding_system *coding,
+sfnt_safe_decode_coding_object (struct coding_system *coding,
                                Lisp_Object src_object,
                                ptrdiff_t from, ptrdiff_t from_byte,
                                ptrdiff_t to, ptrdiff_t to_byte,
@@ -169,9 +198,9 @@ sfnt_safe_encode_coding_object (struct coding_system 
*coding,
   sfnt_font_dst_object = dst_object;
   sfnt_font_signal = false;
 
-  internal_condition_case (sfnt_safe_encode_coding_object_1,
+  internal_condition_case (sfnt_safe_decode_coding_object_1,
                           Qt,
-                          sfnt_safe_encode_coding_object_2);
+                          sfnt_safe_decode_coding_object_2);
 
   return (int) sfnt_font_signal;
 }
@@ -198,9 +227,8 @@ sfnt_decode_font_string (unsigned char *data, enum 
sfnt_platform_id id,
   coding.common_flags &= ~CODING_ANNOTATION_MASK;
   coding.source = data;
 
-  if (sfnt_safe_encode_coding_object (&coding, Qnil, 0, 0,
-                                     0, 0, length, length,
-                                     Qnil))
+  if (sfnt_safe_decode_coding_object (&coding, Qnil, 0, 0,
+                                     length, length, Qt))
     return Qnil;
 
   return coding.dst_object;
@@ -240,6 +268,28 @@ sfnt_decode_family_style (struct sfnt_name_table *name,
   return (!NILP (*family) && !NILP (*style)) ? 0 : 1;
 }
 
+/* Decode the foundry names from the name table NAME.  Return the
+   foundry name, or nil upon failure.  */
+
+static Lisp_Object
+sfnt_decode_foundry_name (struct sfnt_name_table *name)
+{
+  struct sfnt_name_record designer_rec;
+  unsigned char *designer_data;
+
+  designer_data = sfnt_find_name (name, SFNT_NAME_DESIGNER,
+                                 &designer_rec);
+
+  if (!designer_data)
+    return Qnil;
+
+  return sfnt_decode_font_string (designer_data,
+                                 designer_rec.platform_id,
+                                 designer_rec.platform_specific_id,
+                                 designer_rec.language_id,
+                                 designer_rec.length);
+}
+
 struct sfnt_style_desc
 {
   /* The C string to match against.  */
@@ -250,7 +300,7 @@ struct sfnt_style_desc
 };
 
 /* Array of style descriptions describing weight.  */
-static struct sfnt_style_desc sfnt_weight_descriptions =
+static struct sfnt_style_desc sfnt_weight_descriptions[] =
   {
     { "thin", 0,               },
     { "extralight", 40,                },
@@ -271,14 +321,14 @@ static struct sfnt_style_desc sfnt_weight_descriptions =
   };
 
 /* Array of style descriptions describing slant.  */
-static struct sfnt_style_desc sfnt_slant_descriptions =
+static struct sfnt_style_desc sfnt_slant_descriptions[] =
   {
-    { "italic", 100,   },
-    { "oblique", 110,  },
+    { "italic", 200,   },
+    { "oblique", 210,  },
   };
 
 /* Array of style descriptions describing width.  */
-static struct sfnt_width_desc sfnt_width_descriptions =
+static struct sfnt_style_desc sfnt_width_descriptions[] =
   {
     { "ultracondensed", 50,    },
     { "extracondensed", 63,    },
@@ -291,23 +341,24 @@ static struct sfnt_width_desc sfnt_width_descriptions =
   };
 
 /* Figure out DESC->width, DESC->weight, DESC->slant and DESC->spacing
-   based on the style name passed as STYLE.  */
+   based on the style name passed as STYLE_NAME.  */
 
 static void
-sfnt_parse_style (Lisp_Object style, struct sfnt_font_desc *desc)
+sfnt_parse_style (Lisp_Object style_name, struct sfnt_font_desc *desc)
 {
-  char *style, single, *saveptr;
+  char *style, *single, *saveptr;
   int i;
 
-  /* Fill in default values.  */
+  /* Fill in default values.  slant seems to not be consistent with
+     Fontconfig.  */
   desc->weight = 80;
-  desc->slant = 0;
+  desc->slant = 100;
   desc->width = 100;
 
   /* Split the style into spaces.  As long as no weight, slant, or
      width is encountered, look in the corresponding descriptions
      array.  GC must not happen inside this block.  */
-  style = SSDATA (Fdowncase (style));
+  style = SSDATA (Fdowncase (style_name));
   saveptr = NULL;
 
   while ((single = strtok_r (style, " ", &saveptr)))
@@ -331,18 +382,18 @@ sfnt_parse_style (Lisp_Object style, struct 
sfnt_font_desc *desc)
            }
        }
 
-      if (!desc->slant)
+      if (desc->slant == 100)
        {
          /* Slant hasn't been found yet.  Scan through the slant
             table.  */
          for (i = 0; i < ARRAYELTS (sfnt_slant_descriptions); ++i)
            {
-             if (!strcmp (sfnt_weight_descriptions[i].c_string,
+             if (!strcmp (sfnt_slant_descriptions[i].c_string,
                           single))
                {
                  /* Slant found.  Continue on reading the weight and
                     width.  */
-                 desc->slant = sfnt_weight_descriptions[i].value;
+                 desc->slant = sfnt_slant_descriptions[i].value;
                  goto next;
                }
            }
@@ -359,7 +410,7 @@ sfnt_parse_style (Lisp_Object style, struct sfnt_font_desc 
*desc)
                {
                  /* Width found.  Continue on reading the slant and
                     weight.  */
-                 desc->slant = sfnt_width_descriptions[i].value;
+                 desc->width = sfnt_width_descriptions[i].value;
                  goto next;
                }
            }
@@ -368,7 +419,7 @@ sfnt_parse_style (Lisp_Object style, struct sfnt_font_desc 
*desc)
     next:
 
       /* Break early if everything has been found.  */
-      if (desc->slant && desc->width != 100 && desc->weight != 80)
+      if (desc->slant != 100 && desc->width != 100 && desc->weight != 80)
        break;
 
       continue;
@@ -395,7 +446,10 @@ sfnt_enum_font (const char *file)
   memcpy (desc->path, file, strlen (file) + 1);
 
   /* Now open the font for reading.  */
-  fd = emacs_open (file, O_RDWR);
+  fd = emacs_open (file, O_RDONLY, 0);
+
+  if (fd == -1)
+    goto bail;
 
   /* Read the table directory.  */
   subtables = sfnt_read_table_directory (fd);
@@ -426,6 +480,9 @@ sfnt_enum_font (const char *file)
 
   /* Set the family.  */
   desc->family = family;
+  desc->designer = sfnt_decode_foundry_name (name);
+  desc->char_cache = Qnil;
+  desc->subtable.platform_id = 500;
 
   /* Parse the style.  */
   sfnt_parse_style (style, desc);
@@ -467,27 +524,1704 @@ sfnt_enum_font (const char *file)
   xfree (subtables);
  bail0:
   emacs_close (fd);
+ bail:
+  xfree (desc);
   return 1;
 }
 
 
 
-void
-syms_of_sfntfont (void)
+/* Font discovery and matching.  */
+
+static struct charset *
+sfntfont_charset_for_name (Lisp_Object symbol)
 {
-  DEFSYM (Qutf_16be, "utf-16be");
-  DEFSYM (Qmac_roman, "mac-roman");
+  ptrdiff_t idx;
+  int id;
+
+  idx = CHARSET_SYMBOL_HASH_INDEX (symbol);
+
+  if (idx == -1)
+    return NULL;
+
+  /* Vcharset_hash_table is not a real variable, so Lisp programs
+     can't clobber it.  */
+  id = XFIXNUM (AREF (HASH_VALUE (XHASH_TABLE (Vcharset_hash_table),
+                                 idx),
+                     charset_id));
+
+  return CHARSET_FROM_ID (id);
 }
 
-void
-mark_sfntfont (void)
+/* Return the character set corresponding to a cmap subtable SUBTABLE.
+   Value is NULL if the subtable is not supported.  */
+
+static struct charset *
+sfntfont_charset_for_cmap (struct sfnt_cmap_encoding_subtable subtable)
 {
-  struct sfnt_font_desc *desc;
+  switch (subtable.platform_id)
+    {
+    case SFNT_PLATFORM_UNICODE:
+      /* Reject variation selector and last resort tables.  */
+      if ((subtable.platform_specific_id
+          == SFNT_UNICODE_VARIATION_SEQUENCES)
+         || (subtable.platform_specific_id
+             == SFNT_UNICODE_LAST_RESORT))
+       return NULL;
 
-  /* Mark each font desc.  */
-  for (desc = system_fonts; ++desc; desc = desc->next)
+      /* 1.0, 1.1, ISO-10646-1993, and 2.0_BMP tables are all within
+        the BMP.  */
+      if (subtable.platform_specific_id < SFNT_UNICODE_2_0)
+       return sfntfont_charset_for_name (Qunicode_bmp);
+
+      return sfntfont_charset_for_name (Qunicode);
+
+    case SFNT_PLATFORM_MACINTOSH:
+
+      switch (subtable.platform_specific_id)
+       {
+       case SFNT_MACINTOSH_ROMAN:
+         return sfntfont_charset_for_name (Qmac_roman);
+
+       default:
+         /* Some other Macintosh charset not supported by Emacs.  */
+         return NULL;
+       }
+
+    case SFNT_PLATFORM_MICROSOFT:
+
+      /* Microsoft specific encodings.  */
+
+      switch (subtable.platform_specific_id)
+       {
+       case SFNT_MICROSOFT_SYMBOL:
+         /* Symbols in the Unicode PUA are still Unicode.  */
+         return sfntfont_charset_for_name (Qunicode);
+
+       case SFNT_MICROSOFT_UNICODE_BMP:
+         return sfntfont_charset_for_name (Qunicode_bmp);
+
+       case SFNT_MICROSOFT_SHIFT_JIS:
+         /* PCK aka japanese-jisx0208.  */
+         return sfntfont_charset_for_name (Qjapanese_jisx0208);
+
+       case SFNT_MICROSOFT_PRC:
+         /* GBK, GB2312 or GB18030.  */
+         return sfntfont_charset_for_name (Qgbk);
+
+       case SFNT_MICROSOFT_JOHAB:
+         /* KS C 5601-1992, aka korean-ksc5601.  */
+         return sfntfont_charset_for_name (Qkorean_ksc5601);
+
+       case SFNT_MICROSOFT_UNICODE_UCS_4:
+         /* Unicode past the BMP.  */
+         return sfntfont_charset_for_name (Qucs);
+       }
+
+    default:
+      return NULL;
+    }
+}
+
+/* Return the type of characters that the cmap subtable SUBTABLE maps
+   from.  Value is:
+
+   2 if SUBTABLE maps from Unicode characters, including those outside
+   the Unicode Basic Multilingual Plane (BMP).
+
+   1 if SUBTABLE maps from Unicode characters within the BMP.
+
+   0 if SUBTABLE maps from some other character set that Emacs knows
+   about.
+
+   3 if SUBTABLE cannot be used by Emacs.  */
+
+static int
+sfntfont_identify_cmap (struct sfnt_cmap_encoding_subtable subtable)
+{
+  switch (subtable.platform_id)
     {
-      mark_object (desc->family);
-      mark_object (desc->style);
+    case SFNT_PLATFORM_UNICODE:
+
+      /* Reject variation selector and last resort tables.  */
+      if ((subtable.platform_specific_id
+          == SFNT_UNICODE_VARIATION_SEQUENCES)
+         || (subtable.platform_specific_id
+             == SFNT_UNICODE_LAST_RESORT))
+       return 3;
+
+      /* 1.0, 1.1, ISO-10646-1993, and 2.0_BMP tables are all within
+        the BMP.  */
+      if (subtable.platform_specific_id < SFNT_UNICODE_2_0)
+       return 1;
+
+      return 2;
+
+    case SFNT_PLATFORM_MACINTOSH:
+
+      switch (subtable.platform_specific_id)
+       {
+       case SFNT_MACINTOSH_ROMAN:
+         /* mac-roman */
+         return 0;
+
+       default:
+         /* Some other Macintosh charset not supported by Emacs.  */
+         return 3;
+       }
+
+    case SFNT_PLATFORM_MICROSOFT:
+
+      /* Microsoft specific encodings.  */
+
+      switch (subtable.platform_specific_id)
+       {
+       case SFNT_MICROSOFT_SYMBOL:
+         /* Symbols in the Unicode PUA are still Unicode.  */
+         return 1;
+
+       case SFNT_MICROSOFT_UNICODE_BMP:
+         return 1;
+
+       case SFNT_MICROSOFT_SHIFT_JIS:
+         /* PCK aka japanese-jisx0208.  */
+         return 0;
+
+       case SFNT_MICROSOFT_PRC:
+         /* GBK, GB2312 or GB18030.  */
+         return 0;
+
+       case SFNT_MICROSOFT_JOHAB:
+         /* KS C 5601-1992, aka korean-ksc5601.  */
+         return 0;
+
+       case SFNT_MICROSOFT_UNICODE_UCS_4:
+         /* Unicode past the BMP.  */
+         return 2;
+       }
+
+    default:
+      return 3;
+    }
+}
+
+/* Pick the best character map in the cmap table CMAP.  Use the
+   subtables in SUBTABLES and DATA.  Return the subtable data and the
+   subtable in *SUBTABLE upon success, NULL otherwise.  */
+
+static struct sfnt_cmap_encoding_subtable_data *
+sfntfont_select_cmap (struct sfnt_cmap_table *cmap,
+                     struct sfnt_cmap_encoding_subtable *subtables,
+                     struct sfnt_cmap_encoding_subtable_data **data,
+                     struct sfnt_cmap_encoding_subtable *subtable)
+{
+  int i;
+
+  /* First look for a non-BMP Unicode cmap.  */
+
+  for (i = 0; i < cmap->num_subtables; ++i)
+    {
+      if (data[i] && sfntfont_identify_cmap (subtables[i]) == 2)
+       {
+         *subtable = subtables[i];
+         return data[i];
+       }
+    }
+
+  /* Next, look for a BMP only Unicode cmap.  */
+
+  for (i = 0; i < cmap->num_subtables; ++i)
+    {
+      if (data[i] && sfntfont_identify_cmap (subtables[i]) == 1)
+       {
+         *subtable = subtables[i];
+         return data[i];
+       }
+    }
+
+  /* Finally, use the first cmap that appears and can be
+     identified.  */
+
+  for (i = 0; i < cmap->num_subtables; ++i)
+    {
+      if (data[i] && sfntfont_identify_cmap (subtables[i]) == 0)
+       {
+         *subtable = subtables[i];
+         return data[i];
+       }
+    }
+
+  /* There are no cmaps available to Emacs.  */
+  return NULL;
+}
+
+/* Read the cmap from the font descriptor DESC, and place it in CMAP.
+   Keep *CMAP untouched if opening the cmap fails.  Set SUBTABLE to
+   the cmap's header upon success.  */
+
+static void
+sfntfont_read_cmap (struct sfnt_font_desc *desc,
+                   struct sfnt_cmap_encoding_subtable_data **cmap,
+                   struct sfnt_cmap_encoding_subtable *subtable)
+{
+  struct sfnt_offset_subtable *font;
+  struct sfnt_cmap_encoding_subtable *subtables;
+  struct sfnt_cmap_encoding_subtable_data **data;
+  struct sfnt_cmap_table *table;
+  int fd, i;
+
+  /* Pick a character map and place it in *CMAP.  */
+  fd = emacs_open (desc->path, O_RDONLY, 0);
+
+  if (fd < 1)
+    return;
+
+  font = sfnt_read_table_directory (fd);
+
+  if (!font)
+    {
+      close (fd);
+      return;
+    }
+
+  table = sfnt_read_cmap_table (fd, font, &subtables,
+                               &data);
+  xfree (font);
+
+  if (!table)
+    {
+      close (fd);
+      return;
+    }
+
+  /* Now pick the best character map.  */
+
+  *cmap = sfntfont_select_cmap (table, subtables, data,
+                               subtable);
+
+  /* Free the cmap data.  */
+
+  for (i = 0; i < table->num_subtables; ++i)
+    {
+      if (data[i] != *cmap)
+       xfree (data[i]);
+    }
+
+  xfree (data);
+  xfree (subtables);
+  xfree (table);
+}
+
+/* Look up a character CHARACTER in the font description DESC.  Cache
+   the results.  Return true if the character exists, false otherwise.
+
+   If *CMAP is NULL, select a character map for the font and save it
+   there.  Otherwise, use the character map in *CMAP.  Save data
+   associated with the character map in *SUBTABLE.  */
+
+static bool
+sfntfont_lookup_char (struct sfnt_font_desc *desc, Lisp_Object character,
+                     struct sfnt_cmap_encoding_subtable_data **cmap,
+                     struct sfnt_cmap_encoding_subtable *subtable)
+{
+  Lisp_Object cached;
+  sfnt_char font_character;
+  struct charset *charset;
+  bool present;
+
+  /* Return false for characters that don't fit in a char table.  */
+  if (XFIXNUM (character) > INT_MAX || XFIXNUM (character) < 0)
+    return false;
+
+  if (!NILP (desc->char_cache))
+    {
+      cached = char_table_ref (desc->char_cache,
+                              XFIXNUM (character));
+      if (!NILP (cached))
+       return (EQ (cached, Qlambda) ? false : true);
+    }
+
+  if (!*cmap && !desc->cmap_invalid)
+    sfntfont_read_cmap (desc, cmap, subtable);
+
+  /* Check that a cmap is now present.  */
+  if (!*cmap)
+    {
+      /* Opening the cmap failed.  Set desc->cmap_invalid to avoid
+        opening it again.  */
+      desc->cmap_invalid = true;
+      return false;
+    }
+
+  /* Otherwise, encode the character.  */
+
+  charset = sfntfont_charset_for_cmap (*subtable);
+  if (!charset)
+    /* Emacs missing charsets? */
+    return false;
+
+  font_character = ENCODE_CHAR (charset, XFIXNUM (character));
+
+  if (font_character == CHARSET_INVALID_CODE (charset))
+    return false;
+
+  /* Now return whether or not the glyph is present.  */
+  present = sfnt_lookup_glyph (font_character, *cmap) != 0;
+
+  /* Cache the result.  Store Qlambda when not present, Qt
+     otherwise.  */
+
+  if (NILP (desc->char_cache))
+    desc->char_cache = Fmake_char_table (Qfont_lookup_cache,
+                                        Qnil);
+
+  Fset_char_table_range (desc->char_cache, character,
+                        present ? Qt : Qlambda);
+  return present;
+}
+
+/* Return whether or not the font description DESC satisfactorily
+   matches the font specification FONT_SPEC.  */
+
+static bool
+sfntfont_list_1 (struct sfnt_font_desc *desc, Lisp_Object spec)
+{
+  Lisp_Object tem, extra, tail;
+  struct sfnt_cmap_encoding_subtable_data *cmap;
+  size_t i;
+  struct sfnt_cmap_encoding_subtable subtable;
+
+  /* cmap and subtable are caches for sfntfont_lookup_char.  */
+
+  /* Check that the family name in SPEC matches DESC->family if it is
+     specified.  */
+
+  tem = AREF (spec, FONT_FAMILY_INDEX);
+
+  /* If TEM is a family listed in Vsfnt_default_family_alist,
+     then use that instead.  */
+
+  if (SYMBOLP (tem) && CONSP (Vsfnt_default_family_alist))
+    {
+      tail = Vsfnt_default_family_alist;
+      FOR_EACH_TAIL_SAFE (tail)
+       {
+         if (!CONSP (XCAR (tail)))
+           continue;
+
+         if (STRINGP (XCAR (XCAR (tail)))
+             && STRINGP (XCDR (XCAR (tail)))
+             && Fstring_equal (SYMBOL_NAME (tem),
+                               XCAR (XCAR (tail))))
+           {
+             /* Special family found.  */
+             tem = Fintern (XCDR (XCAR (tail)), Qnil);
+             break;
+           }
+       }
+    }
+
+  if (!NILP (tem) && NILP (Fstring_equal (SYMBOL_NAME (tem),
+                                         desc->family)))
+    return false;
+
+  /* Check that no adstyle has been specified.  That's a relic from
+     the Postscript era.  */
+
+  tem = AREF (spec, FONT_ADSTYLE_INDEX);
+  if (!NILP (tem))
+    return false;
+
+  /* Check the style.  */
+
+  if (FONT_WIDTH_NUMERIC (spec) != -1
+      && FONT_WIDTH_NUMERIC (spec) != desc->width)
+    return false;
+
+  if (FONT_WEIGHT_NUMERIC (spec) != -1
+      && FONT_WEIGHT_NUMERIC (spec) != desc->weight)
+    return false;
+
+  if (FONT_SLANT_NUMERIC (spec) != -1
+      && FONT_SLANT_NUMERIC (spec) != desc->slant)
+    return false;
+
+  /* Handle extras.  */
+  extra = AREF (spec, FONT_EXTRA_INDEX);
+
+  if (NILP (extra))
+    return true;
+
+  tem = assq_no_quit (QCscript, extra);
+  cmap = NULL;
+
+  if (!NILP (tem))
+    {
+      /* If a script has been specified, look up its representative
+        characters and see if they are present in the font.  This
+        requires reading the cmap.  */
+      tem = assq_no_quit (XCDR (tem), Vscript_representative_chars);
+
+      if (CONSP (tem) && VECTORP (XCDR (tem)))
+       {
+         tem = XCDR (tem);
+
+         /* The vector contains characters, of which one must be
+            present in the font.  */
+         for (i = 0; i < ASIZE (tem); ++i)
+           {
+             if (FIXNUMP (AREF (tem, i)))
+               {
+                 if (!sfntfont_lookup_char (desc, AREF (tem, i),
+                                            &cmap, &subtable))
+                   goto fail;
+
+                 /* One character is enough to pass a font.  Don't
+                    look at too many.  */
+                 break;
+               }
+           }
+       }
+      else if (CONSP (tem) && CONSP (XCDR (tem)))
+       {
+         tem = XCDR (tem);
+
+         /* tem is a list of each characters, one of which must be
+            present in the font.  */
+         FOR_EACH_TAIL_SAFE (tem)
+           {
+             if (FIXNUMP (XCAR (tem)))
+               {
+                 if (!sfntfont_lookup_char (desc, XCAR (tem), &cmap,
+                                            &subtable))
+                   goto fail;
+
+                 /* One character is enough to pass a font.  Don't
+                    look at too many.  */
+                 break;
+               }
+           }
+       }
+    }
+
+  /* Set desc->subtable if cmap was specified.  */
+  if (cmap)
+    desc->subtable = subtable;
+
+  xfree (cmap);
+  return true;
+
+ fail:
+  /* The cmap might've been read in and require deallocation.  */
+  xfree (cmap);
+  return false;
+}
+
+/* Type of font entities and font objects created.  */
+static Lisp_Object sfnt_vendor_name;
+
+/* Font driver used in font objects created.  */
+static const struct font_driver *sfnt_font_driver;
+
+/* Return the font registry corresponding to the font descriptor DESC.
+   Under X, the font registry is an atom registered with the Open
+   Group uniquely identifying the organization which defines the
+   font's character set.
+
+   In practice, the registry overlaps with the character set itself.
+   So Emacs just uses the ``registry'' field to represent both
+   instead.  */
+
+static Lisp_Object
+sfntfont_registry_for_desc (struct sfnt_font_desc *desc)
+{
+  struct sfnt_cmap_encoding_subtable_data *cmap;
+
+  cmap = NULL;
+
+  if (desc->cmap_invalid)
+    return Qnil;
+
+  if (desc->subtable.platform_id == 500)
+    {
+      /* Read in the cmap to determine the registry.  */
+      sfntfont_read_cmap (desc, &cmap, &desc->subtable);
+
+      if (!cmap)
+       {
+         desc->cmap_invalid = true;
+         return Qnil;
+       }
+    }
+
+  xfree (cmap);
+
+  if (desc->subtable.platform_id != 500)
+    {
+      /* desc->subtable.platform_id is now set.  CMAP is already free,
+        because it is not actually used.  */
+
+      switch (desc->subtable.platform_id)
+       {
+       case SFNT_PLATFORM_UNICODE:
+         /* Reject variation selector and last resort tables.  */
+         if ((desc->subtable.platform_specific_id
+              == SFNT_UNICODE_VARIATION_SEQUENCES)
+             || (desc->subtable.platform_specific_id
+                 == SFNT_UNICODE_LAST_RESORT))
+           return Qnil;
+
+         return Qiso10646_1;
+
+       case SFNT_PLATFORM_MACINTOSH:
+
+         switch (desc->subtable.platform_specific_id)
+           {
+           case SFNT_MACINTOSH_ROMAN:
+             /* X calls mac-roman ``apple-roman''.  */
+             return Qapple_roman;
+
+           default:
+             /* Some other Macintosh charset not supported by Emacs.  */
+             return Qnil;
+           }
+
+       case SFNT_PLATFORM_MICROSOFT:
+
+         /* Microsoft specific encodings.  */
+
+         switch (desc->subtable.platform_specific_id)
+           {
+           case SFNT_MICROSOFT_SYMBOL:
+           case SFNT_MICROSOFT_UNICODE_BMP:
+             /* Symbols in the Unicode PUA are still Unicode.  */
+             return Qiso10646_1;
+
+           case SFNT_MICROSOFT_SHIFT_JIS:
+             return Qjisx0208_1983_0;
+
+           case SFNT_MICROSOFT_PRC:
+             return Qgbk;
+
+           case SFNT_MICROSOFT_JOHAB:
+             return Qksc5601_1987_0;
+
+           case SFNT_MICROSOFT_UNICODE_UCS_4:
+             return Qiso10646_1;
+           }
+
+       default:
+         return Qnil;
+       }
     }
+
+  return Qnil;
+}
+
+/* Return a font-entity that represents the font descriptor (unopened
+   font) DESC.  */
+
+static Lisp_Object
+sfntfont_desc_to_entity (struct sfnt_font_desc *desc)
+{
+  Lisp_Object entity;
+
+  entity = font_make_entity ();
+
+  ASET (entity, FONT_TYPE_INDEX, sfnt_vendor_name);
+
+  if (!NILP (desc->designer))
+    ASET (entity, FONT_FOUNDRY_INDEX,
+         Fintern (desc->designer, Qnil));
+
+  ASET (entity, FONT_FAMILY_INDEX, Fintern (desc->family, Qnil));
+  ASET (entity, FONT_ADSTYLE_INDEX, Qnil);
+  ASET (entity, FONT_REGISTRY_INDEX,
+       sfntfont_registry_for_desc (desc));
+
+  /* Size of 0 means the font is scalable.  */
+  ASET (entity, FONT_SIZE_INDEX, make_fixnum (0));
+  ASET (entity, FONT_AVGWIDTH_INDEX, make_fixnum (0));
+  ASET (entity, FONT_SPACING_INDEX,
+       make_fixnum (desc->spacing));
+
+  FONT_SET_STYLE (entity, FONT_WIDTH_INDEX,
+                 make_fixnum (desc->width));
+  FONT_SET_STYLE (entity, FONT_WEIGHT_INDEX,
+                 make_fixnum (desc->weight));
+  FONT_SET_STYLE (entity, FONT_SLANT_INDEX,
+                 make_fixnum (desc->slant));
+
+  ASET (entity, FONT_ADSTYLE_INDEX, Qnil);
+
+  /* Set FONT_EXTRA_INDEX to a pointer to the font description.  Font
+     descriptions are never supposed to be freed.  */
+  ASET (entity, FONT_EXTRA_INDEX,
+       list1 (Fcons (Qfont_entity, make_mint_ptr (desc))));
+
+  return entity;
+}
+
+/* Return a list of font-entities matching the specified
+   FONT_SPEC.  */
+
+Lisp_Object
+sfntfont_list (struct frame *f, Lisp_Object font_spec)
+{
+  Lisp_Object matching, tem;
+  struct sfnt_font_desc *desc;
+
+  matching = Qnil;
+
+  block_input ();
+  /* Returning irrelevant results on receiving an OTF form will cause
+     fontset.c to loop over and over, making displaying some
+     characters very slow.  */
+  tem = assq_no_quit (QCotf, AREF (font_spec, FONT_EXTRA_INDEX));
+  if (CONSP (tem) && !NILP (XCDR (tem)))
+    {
+      unblock_input ();
+      return Qnil;
+    }
+
+  /* Loop through known system fonts and add them one-by-one.  */
+  for (desc = system_fonts; desc; desc = desc->next)
+    {
+      if (sfntfont_list_1 (desc, font_spec))
+       matching = Fcons (sfntfont_desc_to_entity (desc), matching);
+    }
+
+  unblock_input ();
+
+  return matching;
+}
+
+/* Return the first font-entity matching the specified FONT_SPEC.  */
+
+Lisp_Object
+sfntfont_match (struct frame *f, Lisp_Object font_spec)
+{
+  Lisp_Object matches;
+
+  matches = sfntfont_list (f, font_spec);
+
+  if (!NILP (matches))
+    return XCAR (matches);
+
+  return Qnil;
+}
+
+
+
+enum
+  {
+    SFNT_OUTLINE_CACHE_SIZE = 128,
+    SFNT_RASTER_CACHE_SIZE  = 100,
+  };
+
+/* Caching subsystem.  Generating outlines from glyphs is expensive,
+   and so is rasterizing them, so two caches are maintained for both
+   glyph outlines and rasters.  */
+
+struct sfnt_outline_cache
+{
+  /* Next and last cache buckets.  */
+  struct sfnt_outline_cache *next, *last;
+
+  /* Pointer to outline.  */
+  struct sfnt_glyph_outline *outline;
+
+  /* What glyph this caches.  */
+  sfnt_glyph glyph;
+};
+
+struct sfnt_raster_cache
+{
+  /* Next and last cache buckets.  */
+  struct sfnt_raster_cache *next, *last;
+
+  /* Pointer to raster.  */
+  struct sfnt_raster *raster;
+
+  /* What glyph this caches.  */
+  sfnt_glyph glyph;
+};
+
+struct sfntfont_get_glyph_outline_dcontext
+{
+  /* Long and short loca tables.  */
+  struct sfnt_loca_table_long *loca_long;
+  struct sfnt_loca_table_short *loca_short;
+
+  /* glyf table.  */
+  struct sfnt_glyf_table *glyf;
+};
+
+/* Return the glyph identified by GLYPH from the glyf and loca table
+   specified in DCONTEXT.  Set *NEED_FREE to true.  */
+
+static struct sfnt_glyph *
+sfntfont_get_glyph (sfnt_glyph glyph, void *dcontext,
+                   bool *need_free)
+{
+  struct sfntfont_get_glyph_outline_dcontext *tables;
+
+  tables = dcontext;
+  *need_free = true;
+
+  return sfnt_read_glyph (glyph, tables->glyf,
+                         tables->loca_short,
+                         tables->loca_long);
+}
+
+/* Free the glyph identified by GLYPH.  */
+
+static void
+sfntfont_free_glyph (struct sfnt_glyph *glyph, void *dcontext)
+{
+  sfnt_free_glyph (glyph);
+}
+
+/* Dereference the outline OUTLINE.  Free it once refcount reaches
+   0.  */
+
+static void
+sfntfont_dereference_outline (struct sfnt_glyph_outline *outline)
+{
+  eassert (outline->refcount > 0);
+
+  if (--outline->refcount)
+    return;
+
+  xfree (outline);
+}
+
+/* Get the outline corresponding to the specified GLYPH_CODE in CACHE.
+   Use the pixel size PIXEL_SIZE, the glyf table GLYF, and the head
+   table HEAD.  Keep *CACHE_SIZE updated with the number of elements
+   in the cache.
+
+   Use the offset information in the long or short loca tables
+   LOCA_LONG and LOCA_SHORT, whichever is set.
+
+   Return the outline with an incremented reference count and enter
+   the generated outline into CACHE upon success, possibly discarding
+   any older outlines, or NULL on failure.  */
+
+static struct sfnt_glyph_outline *
+sfntfont_get_glyph_outline (sfnt_glyph glyph_code,
+                           struct sfnt_outline_cache *cache,
+                           int pixel_size, int *cache_size,
+                           struct sfnt_glyf_table *glyf,
+                           struct sfnt_head_table *head,
+                           struct sfnt_loca_table_short *loca_short,
+                           struct sfnt_loca_table_long *loca_long)
+{
+  struct sfnt_outline_cache *start;
+  struct sfnt_glyph_outline *outline;
+  struct sfnt_glyph *glyph;
+  struct sfntfont_get_glyph_outline_dcontext dcontext;
+
+  start = cache->next;
+
+  /* See if the outline is already cached.  */
+  for (; start != cache; start = start->next)
+    {
+      if (start->glyph == glyph_code)
+       {
+         /* Move start to the start of the ring.  Then increase
+            start->outline->refcount and return it.  */
+
+         start->last->next = start->next;
+         start->next->last = start->last;
+
+         start->next = cache->next;
+         start->last = cache;
+         start->next->last = start;
+         start->last->next = start;
+         start->outline->refcount++;
+
+         return start->outline;
+       }
+    }
+
+  /* Not already cached.  Get the glyph.  */
+  glyph = sfnt_read_glyph (glyph_code, glyf,
+                          loca_short, loca_long);
+
+  if (!glyph)
+    return NULL;
+
+  dcontext.loca_long = loca_long;
+  dcontext.loca_short = loca_short;
+  dcontext.glyf = glyf;
+
+  outline = sfnt_build_glyph_outline (glyph, head, pixel_size,
+                                     sfntfont_get_glyph,
+                                     sfntfont_free_glyph,
+                                     &dcontext);
+  xfree (glyph);
+
+  if (!outline)
+    return NULL;
+
+  start = xmalloc (sizeof *start);
+  start->glyph = glyph_code;
+  start->outline = outline;
+
+  /* One reference goes to the cache.  The second reference goes to
+     the caller.  */
+  outline->refcount = 2;
+
+  /* Link start onto the cache.  */
+  start->next = cache->next;
+  start->last = cache;
+  start->next->last = start;
+  start->last->next = start;
+
+  /* Update the cache size.  */
+  (*cache_size)++;
+
+  /* Figure out if the least recently used element has to be
+     evicted.  */
+  if (*cache_size > SFNT_OUTLINE_CACHE_SIZE)
+    {
+      start = cache->last;
+      eassert (start != cache);
+
+      /* Free the least recently used entry in the cache.  */
+      start->last->next = start->next;
+      start->next->last = start->last;
+      sfntfont_dereference_outline (start->outline);
+      xfree (start);
+
+      (*cache_size)--;
+    }
+
+  /* Return the cached outline.  */
+  return outline;
+}
+
+/* Free the outline cache referred to by CACHE.  Dereference each
+   outline contained therein.  */
+
+static void
+sfntfont_free_outline_cache (struct sfnt_outline_cache *cache)
+{
+  struct sfnt_outline_cache *next, *last;
+
+  /* Handle partly initialized fonts.  */
+  if (!cache->next)
+    return;
+
+  for (next = cache->next; next != cache;)
+    {
+      last = next;
+      next = next->next;
+
+      sfntfont_dereference_outline (last->outline);
+      xfree (last);
+    }
+}
+
+/* Dereference the raster RASTER.  Free it once refcount reaches
+   0.  */
+
+static void
+sfntfont_dereference_raster (struct sfnt_raster *raster)
+{
+  eassert (raster->refcount > 0);
+
+  if (--raster->refcount)
+    return;
+
+  xfree (raster);
+}
+
+/* Get the raster corresponding to the specified GLYPH_CODE in CACHE.
+   Use the outline named OUTLINE.  Keep *CACHE_SIZE updated with the
+   number of elements in the cache.  */
+
+static struct sfnt_raster *
+sfntfont_get_glyph_raster (sfnt_glyph glyph_code,
+                          struct sfnt_raster_cache *cache,
+                          struct sfnt_glyph_outline *outline,
+                          int *cache_size)
+{
+  struct sfnt_raster_cache *start;
+  struct sfnt_raster *raster;
+
+  /* See if the raster is already cached.  */
+  start = cache->next;
+
+  for (; start != cache; start = start->next)
+    {
+      if (start->glyph == glyph_code)
+       {
+         /* Move start to the start of the ring.  Them, increase
+            start->raster->refcount and return it.  */
+
+         start->last->next = start->next;
+         start->next->last = start->last;
+
+         start->next = cache->next;
+         start->last = cache;
+         start->next->last = start;
+         start->last->next = start;
+         start->raster->refcount++;
+
+         return start->raster;
+       }
+    }
+
+  /* Not already cached.  Raster the outline.  */
+  raster = sfnt_raster_glyph_outline (outline);
+
+  if (!raster)
+    return NULL;
+
+  start = xmalloc (sizeof *start);
+  start->glyph = glyph_code;
+  start->raster = raster;
+
+  /* One reference goes to the cache.  The second reference goes to
+     the caller.  */
+  raster->refcount = 2;
+
+  /* Link start onto the cache.  */
+  start->next = cache->next;
+  start->last = cache;
+  start->next->last = start;
+  start->last->next = start;
+
+  /* Update the cache size.  */
+  (*cache_size)++;
+
+  /* Figure out if the least recently used element has to be
+     evicted.  */
+  if (*cache_size > SFNT_OUTLINE_CACHE_SIZE)
+    {
+      start = cache->last;
+      eassert (start != cache);
+
+      /* Free the least recently used entry in the cache.  */
+      start->last->next = start->next;
+      start->next->last = start->last;
+      sfntfont_dereference_raster (start->raster);
+      xfree (start);
+
+      (*cache_size)--;
+    }
+
+  /* Return the cached raster.  */
+  return raster;
+}
+
+/* Free the raster cache referred to by CACHE.  Dereference each
+   raster contained therein.  */
+
+static void
+sfntfont_free_raster_cache (struct sfnt_raster_cache *cache)
+{
+  struct sfnt_raster_cache *next, *last;
+
+  /* Handle partly initialized fonts.  */
+  if (!cache->next)
+    return;
+
+  for (next = cache->next; next != cache;)
+    {
+      last = next;
+      next = next->next;
+
+      sfntfont_dereference_raster (last->raster);
+      xfree (last);
+    }
+}
+
+
+
+/* Opening fonts.  */
+
+struct sfnt_font_info
+{
+  /* Parent font structure.  */
+  struct font font;
+
+  /* Various tables required to use the font.  */
+  struct sfnt_cmap_table *cmap;
+  struct sfnt_hhea_table *hhea;
+  struct sfnt_maxp_table *maxp;
+  struct sfnt_head_table *head;
+  struct sfnt_hmtx_table *hmtx;
+  struct sfnt_glyf_table *glyf;
+  struct sfnt_loca_table_short *loca_short;
+  struct sfnt_loca_table_long *loca_long;
+
+  /* The selected character map.  */
+  struct sfnt_cmap_encoding_subtable_data *cmap_data;
+
+  /* Data identifying that character map.  */
+  struct sfnt_cmap_encoding_subtable cmap_subtable;
+
+  /* Outline cache.  */
+  struct sfnt_outline_cache outline_cache;
+
+  /* Number of elements in the outline cache.  */
+  int outline_cache_size;
+
+  /* Raster cache.  */
+  struct sfnt_raster_cache raster_cache;
+
+  /* Number of elements in the raster cache.  */
+  int raster_cache_size;
+};
+
+/* Look up the glyph corresponding to the character C in FONT.  Return
+   0 upon failure, and the glyph otherwise.  */
+
+static sfnt_glyph
+sfntfont_lookup_glyph (struct sfnt_font_info *font_info, int c)
+{
+  struct charset *charset;
+  sfnt_char character;
+  sfnt_glyph glyph;
+
+  charset = CHARSET_FROM_ID (font_info->font.encoding_charset);
+
+  if (!charset)
+    return 0;
+
+  character = ENCODE_CHAR (charset, c);
+
+  if (character == CHARSET_INVALID_CODE (charset))
+    return 0;
+
+  /* Do the actual lookup with the encoded character.  */
+  glyph = sfnt_lookup_glyph (character, font_info->cmap_data);
+
+  return glyph;
+}
+
+/* Probe and set FONT_INFO->font.average_width,
+   FONT_INFO->font.space_width, and FONT_INFO->font.min_width
+   according to the tables contained therein.  */
+
+static void
+sfntfont_probe_widths (struct sfnt_font_info *font_info)
+{
+  int i, num_characters, total_width;
+  sfnt_glyph glyph;
+  struct sfnt_glyph_metrics metrics;
+
+  num_characters = 0;
+  total_width = 0;
+
+  /* First set some reasonable default values.  */
+  font_info->font.average_width = font_info->font.pixel_size;
+  font_info->font.space_width = font_info->font.pixel_size;
+  font_info->font.min_width = 1;
+
+  /* Next, loop through the common ASCII characters.  Tally up their
+     advance widths and set space_width if necessary.  */
+  for (i = 0; i < 127; ++i)
+    {
+      glyph = sfntfont_lookup_glyph (font_info, i);
+
+      if (!glyph)
+       continue;
+
+      /* Now look up the metrics of this glyph.  */
+      if (sfnt_lookup_glyph_metrics (glyph, font_info->font.pixel_size,
+                                    &metrics, font_info->hmtx,
+                                    font_info->hhea, font_info->head,
+                                    font_info->maxp))
+       continue;
+
+      /* Increase the number of characters.  */
+      num_characters++;
+
+      /* Add the advance to total_width.  */
+      total_width += metrics.advance >> 16;
+
+      /* Update min_width if it hasn't been set yet or is wider.  */
+      if (font_info->font.min_width == 1
+         || font_info->font.min_width > metrics.advance >> 16)
+       font_info->font.min_width = metrics.advance >> 16;
+
+      /* If i is the space character, set the space width.  Make sure
+        to round this up.  */
+      if (i == 32)
+       font_info->font.space_width
+         = SFNT_CEIL_FIXED (metrics.advance) >> 16;
+    }
+
+  /* Now, if characters were found, set average_width.  */
+  if (num_characters)
+    font_info->font.average_width = total_width / num_characters;
+}
+
+/* Open the font corresponding to the font-entity FONT_ENTITY.  Return
+   nil upon failure, else the opened font-object.  */
+
+Lisp_Object
+sfntfont_open (struct frame *f, Lisp_Object font_entity,
+              int pixel_size)
+{
+  struct sfnt_font_info *font_info;
+  struct font *font;
+  struct sfnt_font_desc *desc;
+  Lisp_Object font_object;
+  int fd, i;
+  struct sfnt_offset_subtable *subtable;
+  struct sfnt_cmap_encoding_subtable *subtables;
+  struct sfnt_cmap_encoding_subtable_data **data;
+  struct charset *charset;
+
+  if (XFIXNUM (AREF (font_entity, FONT_SIZE_INDEX)) != 0)
+    pixel_size = XFIXNUM (AREF (font_entity, FONT_SIZE_INDEX));
+  else if (pixel_size == 0)
+    {
+      /* This bit was copied from xfont.c.  The values might need
+        adjustment.  */
+
+      if (FRAME_FONT (f))
+       pixel_size = FRAME_FONT (f)->pixel_size;
+      else
+       pixel_size = 12;
+    }
+
+  /* Now find the font description corresponding to FONT_ENTITY.  */
+
+  if (NILP (AREF (font_entity, FONT_EXTRA_INDEX)))
+    return Qnil;
+
+  desc = xmint_pointer (XCDR (XCAR (AREF (font_entity, FONT_EXTRA_INDEX))));
+
+  /* Build the font object.  */
+  font_object = font_make_object (VECSIZE (struct sfnt_font_info),
+                                 font_entity, pixel_size);
+  font_info = (struct sfnt_font_info *) XFONT_OBJECT (font_object);
+
+  block_input ();
+
+  /* Initialize all the font driver specific data.  */
+
+  font_info->cmap = NULL;
+  font_info->hhea = NULL;
+  font_info->maxp = NULL;
+  font_info->head = NULL;
+  font_info->glyf = NULL;
+  font_info->hmtx = NULL;
+  font_info->loca_short = NULL;
+  font_info->loca_long = NULL;
+  font_info->cmap_data = NULL;
+
+  font_info->outline_cache.next = &font_info->outline_cache;
+  font_info->outline_cache.last = &font_info->outline_cache;
+  font_info->outline_cache_size = 0;
+  font_info->raster_cache.next = &font_info->raster_cache;
+  font_info->raster_cache.last = &font_info->raster_cache;
+  font_info->raster_cache_size = 0;
+
+  /* Open the font.  */
+  fd = emacs_open (desc->path, O_RDONLY, 0);
+
+  if (fd == -1)
+    goto bail;
+
+  /* Read the offset subtable.  */
+  subtable = sfnt_read_table_directory (fd);
+
+  if (!subtable)
+    goto bail1;
+
+  /* Read required tables.  This font backend is supposed to be used
+     mostly on devices with flash memory, so the order in which they
+     are read is insignificant.  */
+
+  /* Select a character map table.  */
+  font_info->cmap = sfnt_read_cmap_table (fd, subtable, &subtables,
+                                         &data);
+  if (!font_info->cmap)
+    goto bail2;
+
+  font_info->cmap_data
+    = sfntfont_select_cmap (font_info->cmap,
+                           subtables, data,
+                           &font_info->cmap_subtable);
+
+  for (i = 0; i < font_info->cmap->num_subtables; ++i)
+    {
+      if (data[i] != font_info->cmap_data)
+       xfree (data[i]);
+    }
+
+  xfree (subtables);
+  xfree (data);
+
+  if (!font_info->cmap_data)
+    goto bail3;
+
+  /* Read the hhea, maxp, glyf, and head tables.  */
+  font_info->hhea = sfnt_read_hhea_table (fd, subtable);
+  font_info->maxp = sfnt_read_maxp_table (fd, subtable);
+  font_info->glyf = sfnt_read_glyf_table (fd, subtable);
+  font_info->head = sfnt_read_head_table (fd, subtable);
+
+  /* If any of those tables couldn't be read, bail.  */
+  if (!font_info->hhea || !font_info->maxp || !font_info->glyf
+      || !font_info->head)
+    goto bail4;
+
+  /* Now figure out which kind of loca table must be read based on
+     head->index_to_loc_format.  */
+  font_info->loca_short = NULL;
+  font_info->loca_long = NULL;
+
+  if (font_info->head->index_to_loc_format)
+    {
+      font_info->loca_long
+       = sfnt_read_loca_table_long (fd, subtable);
+
+      if (!font_info->loca_long)
+       goto bail4;
+    }
+  else
+    {
+      font_info->loca_short
+       = sfnt_read_loca_table_short (fd, subtable);
+
+      if (!font_info->loca_short)
+       goto bail4;
+    }
+
+  /* Read the horizontal metrics table.  */
+  font_info->hmtx = sfnt_read_hmtx_table (fd, subtable,
+                                         font_info->hhea,
+                                         font_info->maxp);
+  if (!font_info->hmtx)
+    goto bail5;
+
+  /* Fill in font data.  */
+  font = &font_info->font;
+  font->pixel_size = pixel_size;
+  font->driver = sfnt_font_driver;
+  font->encoding_charset = font->repertory_charset = -1;
+
+  /* Figure out which character set to use.  */
+  charset = sfntfont_charset_for_cmap (font_info->cmap_subtable);
+
+  if (!charset)
+    goto bail6;
+
+  /* Set the character set IDs.  */
+  font->encoding_charset = charset->id;
+  font->repertory_charset = charset->id;
+
+  /* Figure out the font ascent and descent.  */
+  font->ascent
+    = ceil (font_info->hhea->ascent
+           * pixel_size * 1.0 / font_info->head->units_per_em);
+  font->descent
+    = -floor (font_info->hhea->descent
+             * pixel_size * 1.0 / font_info->head->units_per_em);
+  font->height = font->ascent + font->descent;
+
+  /* Set generic attributes such as type and style.  */
+  ASET (font_object, FONT_TYPE_INDEX, sfnt_vendor_name);
+
+  if (!NILP (desc->designer))
+    ASET (font_object, FONT_FOUNDRY_INDEX,
+         Fintern (desc->designer, Qnil));
+
+  ASET (font_object, FONT_FAMILY_INDEX, Fintern (desc->family, Qnil));
+  ASET (font_object, FONT_ADSTYLE_INDEX, Qnil);
+  ASET (font_object, FONT_REGISTRY_INDEX,
+       sfntfont_registry_for_desc (desc));
+
+  /* Size of 0 means the font is scalable.  */
+  ASET (font_object, FONT_SIZE_INDEX, make_fixnum (0));
+  ASET (font_object, FONT_AVGWIDTH_INDEX, make_fixnum (0));
+  ASET (font_object, FONT_SPACING_INDEX,
+       make_fixnum (desc->spacing));
+
+  FONT_SET_STYLE (font_object, FONT_WIDTH_INDEX,
+                 make_fixnum (desc->width));
+  FONT_SET_STYLE (font_object, FONT_WEIGHT_INDEX,
+                 make_fixnum (desc->weight));
+  FONT_SET_STYLE (font_object, FONT_SLANT_INDEX,
+                 make_fixnum (desc->slant));
+
+  ASET (font_object, FONT_ADSTYLE_INDEX, Qnil);
+
+  /* Find out the minimum, maximum and average widths.  */
+  sfntfont_probe_widths (font_info);
+
+  /* Clear various offsets.  */
+  font_info->font.baseline_offset = 0;
+  font_info->font.relative_compose = 0;
+  font_info->font.default_ascent = 0;
+  font_info->font.vertical_centering = 0;
+  font_info->font.underline_position = -1;
+  font_info->font.underline_thickness = 0;
+
+  /* Calculate the xfld name.  */
+  font->props[FONT_NAME_INDEX] = Ffont_xlfd_name (font_object, Qnil);
+
+  /* All done.  */
+  unblock_input ();
+  return font_object;
+
+ bail6:
+  xfree (font_info->hmtx);
+  font_info->hmtx = NULL;
+ bail5:
+  xfree (font_info->loca_long);
+  xfree (font_info->loca_short);
+  font_info->loca_long = NULL;
+  font_info->loca_short = NULL;
+ bail4:
+  xfree (font_info->hhea);
+  xfree (font_info->maxp);
+  xfree (font_info->glyf);
+  xfree (font_info->head);
+  font_info->hhea = NULL;
+  font_info->maxp = NULL;
+  font_info->glyf = NULL;
+  font_info->head = NULL;
+
+  /* This comes in bail4 due to a peculiarity of how the four tables
+     above are validated.  */
+  xfree (font_info->cmap_data);
+  font_info->cmap_data = NULL;
+ bail3:
+  xfree (font_info->cmap);
+  font_info->cmap = NULL;
+ bail2:
+  xfree (subtable);
+ bail1:
+  close (fd);
+ bail:
+  unblock_input ();
+  return Qnil;
+}
+
+
+
+/* Metrics computation and other similar font backend functions.  */
+
+/* Return the glyph code corresponding to C inside the font-object
+   FONT.  Value is the glyph code upon success, else
+   FONT_INVALID_CODE.  */
+
+unsigned int
+sfntfont_encode_char (struct font *font, int c)
+{
+  sfnt_glyph glyph;
+
+  /* Now look up the glyph.  */
+  glyph = sfntfont_lookup_glyph ((struct sfnt_font_info *) font, c);
+
+  if (!glyph)
+    return FONT_INVALID_CODE;
+
+  return glyph;
+}
+
+/* Measure the single glyph GLYPH in the font FONT and return its
+   metrics in *PCM.  Value is 0 upon success, 1 otherwise.  */
+
+static int
+sfntfont_measure_pcm (struct sfnt_font_info *font, sfnt_glyph glyph,
+                     struct font_metrics *pcm)
+{
+  struct sfnt_glyph_metrics metrics;
+  struct sfnt_glyph_outline *outline;
+
+  /* Get the glyph metrics first.  */
+  if (sfnt_lookup_glyph_metrics (glyph, font->font.pixel_size,
+                                &metrics, font->hmtx, font->hhea,
+                                font->head, font->maxp))
+    return 1;
+
+  /* Now get the glyph outline, which is required to obtain the rsb,
+     ascent and descent.  */
+  outline = sfntfont_get_glyph_outline (glyph, &font->outline_cache,
+                                       font->font.pixel_size,
+                                       &font->outline_cache_size,
+                                       font->glyf, font->head,
+                                       font->loca_short,
+                                       font->loca_long);
+
+  if (!outline)
+    return 1;
+
+  /* How to round lbearing and rbearing? */
+  pcm->lbearing = metrics.lbearing >> 16;
+  pcm->rbearing = outline->xmax >> 16;
+
+  /* Round the advance, ascent and descent upwards.  */
+  pcm->width = SFNT_CEIL_FIXED (metrics.advance) >> 16;
+  pcm->ascent = SFNT_CEIL_FIXED (outline->ymax) >> 16;
+  pcm->descent = SFNT_CEIL_FIXED (-outline->ymin) >> 16;
+
+  sfntfont_dereference_outline (outline);
+  return 0;
+}
+
+/* Return the total text extents of NGLYPHS glyphs given as CODE in
+   the single font metrics array METRICS.  */
+
+void
+sfntfont_text_extents (struct font *font, const unsigned int *code,
+                      int nglyphs, struct font_metrics *metrics)
+{
+  int i, total_width;
+  struct font_metrics pcm;
+
+  total_width = 0;
+
+  /* Get the metrcs one by one, then sum them up.  */
+  for (i = 0; i < nglyphs; ++i)
+    {
+      if (!sfntfont_measure_pcm ((struct sfnt_font_info *) font,
+                                code[i], &pcm))
+       {
+         /* Add the per-char metric (PCM) to the metrics in
+            METRICS.  */
+
+         if (total_width + pcm.lbearing < metrics->lbearing)
+           metrics->lbearing = total_width + pcm.lbearing;
+
+         if (total_width + pcm.rbearing > metrics->rbearing)
+           metrics->rbearing = total_width + pcm.rbearing;
+
+         if (pcm.ascent > metrics->ascent)
+           metrics->ascent = pcm.ascent;
+
+         if (pcm.descent > metrics->descent)
+           metrics->descent = pcm.descent;
+       }
+
+      total_width += pcm.width;
+    }
+
+  metrics->width = total_width;
+}
+
+/* Close the font FONT, discarding all tables inside it and
+   dereferencing all cached outlines and rasters.  */
+
+void
+sfntfont_close (struct font *font)
+{
+  struct sfnt_font_info *info;
+
+  info = (struct sfnt_font_info *) font;
+  xfree (info->cmap);
+  xfree (info->hhea);
+  xfree (info->maxp);
+  xfree (info->head);
+  xfree (info->hmtx);
+  xfree (info->glyf);
+  xfree (info->loca_short);
+  xfree (info->loca_long);
+  xfree (info->cmap_data);
+
+  sfntfont_free_outline_cache (&info->outline_cache);
+  sfntfont_free_raster_cache (&info->raster_cache);
+}
+
+
+
+/* Glyph display.  */
+
+/* Function called to actually draw rasters to the glass.  */
+static sfntfont_put_glyph_proc sfnt_put_glyphs;
+
+/* Draw glyphs in S->char2b starting from FROM to TO, with the origin
+   at X and baseline at Y.  Fill the background from X, Y +
+   FONT_DESCENT to X + S->background_width, Y - FONT_ASCENT with the
+   background color if necessary.  Use the foreground and background
+   colors in S->gc.  */
+
+int
+sfntfont_draw (struct glyph_string *s, int from, int to,
+              int x, int y, bool with_background)
+{
+  int length;
+  struct sfnt_raster **rasters;
+  int *x_coords, current_x, i;
+  struct sfnt_glyph_outline *outline;
+  struct font *font;
+  struct sfnt_font_info *info;
+  struct sfnt_glyph_metrics metrics;
+
+  length = to - from;
+  font = s->face->font;
+  info = (struct sfnt_font_info *) font;
+
+  rasters = alloca (length * sizeof *rasters);
+  x_coords = alloca (length * sizeof *x_coords);
+  current_x = x;
+
+  /* Get rasters and outlines for them.  */
+  for (i = from; i < to; ++i)
+    {
+      /* Look up the metrics for this glyph.  */
+      if (sfnt_lookup_glyph_metrics (s->char2b[i], font->pixel_size,
+                                    &metrics, info->hmtx, info->hhea,
+                                    info->head, info->maxp))
+       {
+         rasters[i - from] = NULL;
+         x_coords[i - from] = 0;
+         continue;
+       }
+
+      /* Look up the outline.  */
+      outline = sfntfont_get_glyph_outline (s->char2b[i],
+                                           &info->outline_cache,
+                                           font->pixel_size,
+                                           &info->outline_cache_size,
+                                           info->glyf, info->head,
+                                           info->loca_short,
+                                           info->loca_long);
+      x_coords[i - from] = 0;
+
+      if (!outline)
+       {
+         rasters[i - from] = NULL;
+         continue;
+       }
+
+      /* Rasterize the outline.  */
+      rasters[i - from] = sfntfont_get_glyph_raster (s->char2b[i],
+                                                    &info->raster_cache,
+                                                    outline,
+                                                    &info->raster_cache_size);
+      sfntfont_dereference_outline (outline);
+
+      if (!rasters[i - from])
+       continue;
+
+      /* Now work out where to put the outline.  */
+      x_coords[i - from] = current_x;
+      current_x += SFNT_CEIL_FIXED (metrics.advance) >> 16;
+    }
+
+  /* Call the window system function to put the glyphs to the
+     frame.  */
+  sfnt_put_glyphs (s, from, to, x, y, with_background,
+                  rasters, x_coords);
+
+  /* Dereference all the rasters.  */
+  for (i = 0; i < from - to; ++i)
+    {
+      if (rasters[i])
+       sfntfont_dereference_raster (rasters[i]);
+    }
+
+  return 1;
+}
+
+
+
+/* Other callbacks.  */
+
+/* Return a list of each font family known to Emacs.  F is supposed to
+   be a frame but is ignored.  */
+
+Lisp_Object
+sfntfont_list_family (struct frame *f)
+{
+  Lisp_Object families;
+  struct sfnt_font_desc *desc;
+
+  families = Qnil;
+
+  for (desc = system_fonts; desc; desc = desc->next)
+    /* Add desc->family to the list.  */
+    families = Fcons (desc->family, families);
+
+  /* Not sure if deleting duplicates is worth it.  Is this ever
+     called? */
+  return families;
+}
+
+
+
+void
+syms_of_sfntfont (void)
+{
+  DEFSYM (Qutf_16be, "utf-16be");
+  DEFSYM (Qmac_roman, "mac-roman");
+  DEFSYM (Qchinese_big5, "chinese-big5");
+  DEFSYM (Qunicode_bmp, "unicode-bmp");
+  DEFSYM (Qucs, "ucs");
+  DEFSYM (Qjapanese_jisx0208, "japanese-jisx0208");
+  DEFSYM (Qgbk, "gbk");
+  DEFSYM (Qkorean_ksc5601, "korean-ksc5601");
+  DEFSYM (Qapple_roman, "apple-roman");
+  DEFSYM (Qjisx0208_1983_0, "jisx0208.1983-0");
+  DEFSYM (Qksc5601_1987_0, "ksc5601.1987-0");
+
+  /* Char-table purpose.  */
+  DEFSYM (Qfont_lookup_cache, "font-lookup-cache");
+
+  /* Set up staticpros.  */
+  sfnt_vendor_name = Qnil;
+  staticpro (&sfnt_vendor_name);
+
+  /* This variable is supposed to be set by the platform specific part
+     of the font backend.  */
+  DEFVAR_LISP ("sfnt-default-family-alist", Vsfnt_default_family_alist,
+    doc: /* Alist between "emulated" and actual font family names.
+
+Much Emacs code assumes that font families named "Monospace" and "Sans
+Serif" exist, and map to the default monospace and Sans Serif fonts on
+a system.  When the `sfnt' font driver is asked to look for a font
+with one of the families in this alist, it uses its value instead.  */);
+  Vsfnt_default_family_alist = Qnil;
+}
+
+void
+mark_sfntfont (void)
+{
+  struct sfnt_font_desc *desc;
+
+  /* Mark each font desc.  */
+  for (desc = system_fonts; desc; desc = desc->next)
+    {
+      mark_object (desc->family);
+      mark_object (desc->style);
+      mark_object (desc->char_cache);
+      mark_object (desc->designer);
+    }
+}
+
+void
+init_sfntfont (void)
+{
+
+}
+
+
+
+/* Initialize the sfntfont font driver.  VENDOR_TYPE is the type of
+   all font entities created.  DRIVER is the font driver that is saved
+   in font objects.  PUT_GLYPHS is a function that is called with 8
+   arguments, S, FROM, TO, X, Y, WITH_BACKGROUND, RASTERS, and
+   X_COORDS, and should draw all the rasters in RASTERS to S->f,
+   originating at X_COORDS[i], Y, along with filling the background if
+   WITH_BACKGROUND is specified.  */
+
+void
+init_sfntfont_vendor (Lisp_Object vendor_name,
+                     const struct font_driver *driver,
+                     sfntfont_put_glyph_proc put_glyphs)
+{
+  sfnt_vendor_name = vendor_name;
+  sfnt_font_driver = driver;
+  sfnt_put_glyphs = put_glyphs;
 }
diff --git a/src/sfntfont.h b/src/sfntfont.h
index 3ce60f8398..f49121438a 100644
--- a/src/sfntfont.h
+++ b/src/sfntfont.h
@@ -21,6 +21,39 @@ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 
USA.  */
 #ifndef _SFNTFONT_H_
 #define _SFNTFONT_H_
 
+#include "lisp.h"
+#include "frame.h"
+#include "font.h"
+#include "sfnt.h"
+
 extern int sfnt_enum_font (const char *);
 
+
+/* Font driver callbacks.  */
+
+extern Lisp_Object sfntfont_list (struct frame *, Lisp_Object);
+extern Lisp_Object sfntfont_match (struct frame *, Lisp_Object);
+extern Lisp_Object sfntfont_open (struct frame *, Lisp_Object, int);
+
+extern unsigned int sfntfont_encode_char (struct font *, int);
+extern void sfntfont_text_extents (struct font *, const unsigned int *,
+                                  int, struct font_metrics *);
+extern void sfntfont_close (struct font *);
+extern int sfntfont_draw (struct glyph_string *, int, int,
+                         int, int, bool);
+extern Lisp_Object sfntfont_list_family (struct frame *);
+
+
+/* Initialization functions.  */
+
+typedef void (*sfntfont_put_glyph_proc) (struct glyph_string *, int, int,
+                                        int, int, bool, struct sfnt_raster **,
+                                        int *);
+
+extern void syms_of_sfntfont (void);
+extern void init_sfntfont (void);
+extern void mark_sfntfont (void);
+extern void init_sfntfont_vendor (Lisp_Object, const struct font_driver *,
+                                 sfntfont_put_glyph_proc);
+
 #endif /* _SFNTFONT_H_ */
diff --git a/src/xdisp.c b/src/xdisp.c
index 845bb4b2fb..b9ee102af2 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -36227,6 +36227,55 @@ gui_intersect_rectangles (const Emacs_Rectangle *r1, 
const Emacs_Rectangle *r2,
   return intersection_p;
 }
 
+/* EXPORT:
+   Determine the union of the rectangles A and B.  Return the smallest
+   rectangle encompassing both the bounds of A and B in *RESULT.  It
+   is safe for all three arguments to point to each other.  */
+
+void
+gui_union_rectangles (const Emacs_Rectangle *a, const Emacs_Rectangle *b,
+                     Emacs_Rectangle *result)
+{
+  struct gui_box a_box, b_box, result_box;
+
+  /* Handle special cases where one of the rectangles is empty.  */
+
+  if (!a->width || !a->height)
+    {
+      *result = *b;
+      return;
+    }
+  else if (!b->width || !b->height)
+    {
+      *result = *a;
+      return;
+    }
+
+  /* Convert A and B to boxes.  */
+  a_box.x1 = a->x;
+  a_box.y1 = a->y;
+  a_box.x2 = a->x + a->width;
+  a_box.y2 = a->y + a->height;
+
+  b_box.x1 = b->x;
+  b_box.y1 = b->y;
+  b_box.x2 = b->x + b->width;
+  b_box.y2 = b->y + b->height;
+
+  /* Compute the union of the boxes.  */
+  result_box.x1 = min (a_box.x1, b_box.x1);
+  result_box.y1 = min (a_box.y1, b_box.y1);
+  result_box.x2 = max (a_box.x2, b_box.x2);
+  result_box.y2 = max (a_box.y2, b_box.y2);
+
+  /* Convert result_box to an XRectangle and put the result in
+     RESULT.  */
+  result->x = result_box.x1;
+  result->y = result_box.y1;
+  result->width = result_box.x2 - result_box.x1;
+  result->height = result_box.y2 - result_box.y1;
+}
+
 #endif /* HAVE_WINDOW_SYSTEM */
 
 



reply via email to

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