root/src/sfntfont-android.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sfntfont_android_scale32
  2. sfntfont_android_mul8x2
  3. sfntfont_android_blend
  4. sfntfont_android_u255to256
  5. sfntfont_android_over_8888_1
  6. sfntfont_android_over_8888
  7. sfntfont_android_composite_bitmap
  8. sfntfont_android_union_boxes
  9. sfntfont_android_put_glyphs
  10. sfntfont_android_shrink_scanline_buffer
  11. sfntfont_android_get_cache
  12. DEFUN
  13. syms_of_sfntfont_android_for_pdumper
  14. init_sfntfont_android
  15. syms_of_sfntfont_android

     1 /* sfnt format font driver for Android.
     2 
     3 Copyright (C) 2023 Free Software Foundation, Inc.
     4 
     5 This file is part of GNU Emacs.
     6 
     7 GNU Emacs is free software: you can redistribute it and/or modify
     8 it under the terms of the GNU General Public License as published by
     9 the Free Software Foundation, either version 3 of the License, or (at
    10 your option) any later version.
    11 
    12 GNU Emacs is distributed in the hope that it will be useful,
    13 but WITHOUT ANY WARRANTY; without even the implied warranty of
    14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    15 GNU General Public License for more details.
    16 
    17 You should have received a copy of the GNU General Public License
    18 along with GNU Emacs.  If not, write to the Free Software Foundation,
    19 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
    20 
    21 #include <config.h>
    22 #include <dirent.h>
    23 #include <string.h>
    24 #include <stdio.h>
    25 #include <stdlib.h>
    26 
    27 #ifdef __aarch64__
    28 #include <arm_neon.h>
    29 #endif
    30 
    31 #include <android/api-level.h>
    32 #include <android/log.h>
    33 
    34 #include "androidterm.h"
    35 #include "sfntfont.h"
    36 #include "pdumper.h"
    37 #include "blockinput.h"
    38 #include "android.h"
    39 
    40 /* Structure describing a temporary buffer.  */
    41 
    42 struct sfntfont_android_scanline_buffer
    43 {
    44   /* Size of this buffer.  */
    45   size_t buffer_size;
    46 
    47   /* Pointer to the buffer data.  */
    48   void *buffer_data;
    49 };
    50 
    51 /* Array of directories to search for system fonts.  */
    52 static char *system_font_directories[] =
    53   {
    54     (char *) "/system/fonts",
    55     (char *) "/product/fonts",
    56     /* This should be filled in by init_sfntfont_android.  */
    57     (char[PATH_MAX]) { },
    58   };
    59 
    60 /* The font cache.  */
    61 static Lisp_Object font_cache;
    62 
    63 /* The scanline buffer.  */
    64 static struct sfntfont_android_scanline_buffer scanline_buffer;
    65 
    66 /* The largest size of the scanline buffer since the last window
    67    update.  */
    68 static size_t max_scanline_buffer_size;
    69 
    70 
    71 
    72 /* Return a temporary buffer for storing scan lines.
    73    Set BUFFER to the buffer upon success.  */
    74 
    75 #ifndef __aarch64__
    76 
    77 #define GET_SCANLINE_BUFFER(buffer, height, stride)             \
    78   do                                                            \
    79     {                                                           \
    80       size_t _size;                                             \
    81                                                                 \
    82       if (INT_MULTIPLY_WRAPV (height, stride, &_size))          \
    83         memory_full (SIZE_MAX);                                 \
    84                                                                 \
    85       if (_size < MAX_ALLOCA)                                   \
    86         (buffer) = alloca (_size);                              \
    87       else                                                      \
    88         {                                                       \
    89           if (_size > scanline_buffer.buffer_size)              \
    90             {                                                   \
    91               (buffer)                                          \
    92                 = scanline_buffer.buffer_data                   \
    93                 = xrealloc (scanline_buffer.buffer_data,        \
    94                             _size);                             \
    95               scanline_buffer.buffer_size = _size;              \
    96             }                                                   \
    97           else if (_size <= scanline_buffer.buffer_size)        \
    98             (buffer) = scanline_buffer.buffer_data;             \
    99           /* This is unreachable but clang says it is.  */      \
   100           else                                                  \
   101             emacs_abort ();                                     \
   102                                                                 \
   103           max_scanline_buffer_size                              \
   104             = max (_size, max_scanline_buffer_size);            \
   105         }                                                       \
   106     } while (false);
   107 
   108 #else
   109 
   110 #define GET_SCANLINE_BUFFER(buffer, height, stride)             \
   111   do                                                            \
   112     {                                                           \
   113       size_t _size;                                             \
   114       void *_temp;                                              \
   115                                                                 \
   116       if (INT_MULTIPLY_WRAPV (height, stride, &_size))          \
   117         memory_full (SIZE_MAX);                                 \
   118                                                                 \
   119       if (_size > scanline_buffer.buffer_size)                  \
   120         {                                                       \
   121           if (posix_memalign (&_temp, 16, _size))               \
   122             memory_full (_size);                                \
   123           free (scanline_buffer.buffer_data);                   \
   124           (buffer)                                              \
   125             = scanline_buffer.buffer_data                       \
   126             = _temp;                                            \
   127           scanline_buffer.buffer_size = _size;                  \
   128         }                                                       \
   129       else if (_size <= scanline_buffer.buffer_size)            \
   130         (buffer) = scanline_buffer.buffer_data;                 \
   131       /* This is unreachable but clang says it is.  */          \
   132       else                                                      \
   133         emacs_abort ();                                         \
   134                                                                 \
   135       max_scanline_buffer_size                                  \
   136       = max (_size, max_scanline_buffer_size);                  \
   137     } while (false);
   138 
   139 #endif
   140 
   141 
   142 
   143 /* Scale each of the four packed bytes in P in the low 16 bits of P by
   144    SCALE.  Return the result.
   145 
   146    SCALE is an integer between 0 and 256.  */
   147 
   148 static unsigned int
   149 sfntfont_android_scale32 (unsigned int scale, unsigned int p)
   150 {
   151   uint32_t ag, rb;
   152   uint32_t scaled_ag, scaled_rb;
   153 
   154   ag = (p & 0xFF00FF00) >> 8;
   155   rb = (p & 0x00FF00FF);
   156 
   157   scaled_ag = (scale * ag) & 0xFF00FF00;
   158   scaled_rb = (scale * rb) >> 8 & 0x00FF00FF;
   159 
   160   return scaled_ag | scaled_rb;
   161 }
   162 
   163 static unsigned int
   164 sfntfont_android_mul8x2 (unsigned int a8, unsigned int b32)
   165 {
   166   unsigned int i;
   167 
   168   b32 &= 0xff00ff;
   169   i = a8 * b32 + 0x800080;
   170 
   171   return (i + ((i >> 8) & 0xff00ff)) >> 8 & 0xff00ff;
   172 }
   173 
   174 #define U255TO256(x) ((unsigned short) (x) + ((x) >> 7))
   175 
   176 /* Blend two pixels SRC and DST without utilizing any control flow.
   177    Both SRC and DST are expected to be in premultiplied ABGB8888
   178    format.  Value is returned in premultiplied ARGB8888 format.  */
   179 
   180 static unsigned int
   181 sfntfont_android_blend (unsigned int src, unsigned int dst)
   182 {
   183   unsigned int a, br_part, ag_part, both;
   184 
   185   a = (src >> 24);
   186   br_part = sfntfont_android_mul8x2 (255 - a, dst);
   187   ag_part = sfntfont_android_mul8x2 (255 - a, dst >> 8) << 8;
   188 
   189   both = ag_part | br_part;
   190 
   191   /* This addition need not be saturating because both has already
   192      been multiplied by 255 - a.  */
   193   return both + src;
   194 }
   195 
   196 #ifdef __aarch64__
   197 
   198 /* Like U255TO256, but operates on vectors.  */
   199 
   200 static uint16x8_t
   201 sfntfont_android_u255to256 (uint8x8_t in)
   202 {
   203   return vaddl_u8 (vshr_n_u8 (in, 7), in);
   204 }
   205 
   206 /* Use processor features to efficiently composite four pixels at SRC
   207    to DST.  */
   208 
   209 static void
   210 sfntfont_android_over_8888_1 (unsigned int *src, unsigned int *dst)
   211 {
   212   uint8x8_t alpha;
   213   uint16x8_t alpha_c16, v1, v3, v4;
   214   uint8x8_t b, g, r, a, v2, v5;
   215   uint8x8x4_t _src, _dst;
   216 
   217   /* Pull in src and dst.
   218 
   219      This loads bytes, not words, so little endian ABGR becomes
   220      RGBA.  */
   221   _src = vld4_u8 ((const uint8_t *) src);
   222   _dst = vld4_u8 ((const uint8_t *) dst);
   223 
   224   /* Load constants.  */
   225   v4 = vdupq_n_u16 (256);
   226   v5 = vdup_n_u8 (0);
   227 
   228   /* Load src alpha.  */
   229   alpha = _src.val[3];
   230 
   231   /* alpha_c16 = 256 - 255TO256 (alpha).  */
   232   alpha_c16 = sfntfont_android_u255to256 (alpha);
   233   alpha_c16 = vsubq_u16 (v4, alpha_c16);
   234 
   235   /* Cout = Csrc + Cdst * alpha_c.  */
   236   v1 = vaddl_u8 (_dst.val[2], v5);
   237   v2 = _src.val[2];
   238   v3 = vmulq_u16 (v1, alpha_c16);
   239   b = vqadd_u8 (v2, vshrn_n_u16 (v3, 8));
   240 
   241   v1 = vaddl_u8 (_dst.val[1], v5);
   242   v2 = _src.val[1];
   243   v3 = vmulq_u16 (v1, alpha_c16);
   244   g = vqadd_u8 (v2, vshrn_n_u16 (v3, 8));
   245 
   246   v1 = vaddl_u8 (_dst.val[0], v5);
   247   v2 = _src.val[0];
   248   v3 = vmulq_u16 (v1, alpha_c16);
   249   r = vqadd_u8 (v2, vshrn_n_u16 (v3, 8));
   250 
   251 #if 0
   252   /* Aout = Asrc + Adst * alpha_c.  */
   253   v1 = vaddl_u8 (_dst.val[3], v5);
   254   v2 = _src.val[3];
   255   v3 = vmulq_u16 (v1, alpha_c16);
   256   a = vqadd_u8 (v2, vshrn_n_u16 (v3, 8));
   257 #else
   258   /* We know that Adst is always 1, so Asrc + Adst * (1 - Asrc) is
   259      always 1.  */
   260   a = vdup_n_u8 (255);
   261 #endif
   262 
   263   /* Store back in dst.  */
   264   _dst.val[0] = r;
   265   _dst.val[1] = g;
   266   _dst.val[2] = b;
   267   _dst.val[3] = a;
   268   vst4_u8 ((uint8_t *) dst, _dst);
   269 }
   270 
   271 /* Use processor features to efficiently composite the buffer at SRC
   272    to DST.  Composite at most MAX - SRC words.
   273 
   274    If either SRC or DST are not yet properly aligned, value is 1.
   275    Otherwise, value is 0, and *X is incremented to the start of any
   276    trailing data which could not be composited due to data alignment
   277    constraints.  */
   278 
   279 static int
   280 sfntfont_android_over_8888 (unsigned int *src, unsigned int *dst,
   281                             unsigned int *max, unsigned int *x)
   282 {
   283   size_t i;
   284   ptrdiff_t how_much;
   285   void *s, *d;
   286 
   287   /* Figure out how much can be composited by this loop.  */
   288   how_much = (max - src) & ~7;
   289 
   290   /* Return if there is not enough to vectorize.  */
   291   if (!how_much)
   292     return 1;
   293 
   294   /* Now increment *X by that much so the containing loop can process
   295      the remaining pixels one-by-one.  */
   296 
   297   *x += how_much;
   298 
   299   for (i = 0; i < how_much; i += 8)
   300     {
   301       s = (src + i);
   302       d = (dst + i);
   303 
   304       sfntfont_android_over_8888_1 (s, d);
   305     }
   306 
   307   return 0;
   308 }
   309 
   310 #endif
   311 
   312 /* Composite the bitmap described by BUFFER, STRIDE and TEXT_RECTANGLE
   313    onto the native-endian ABGR8888 bitmap described by DEST and
   314    BITMAP_INFO.  RECT is the subset of the bitmap to composite.  */
   315 
   316 static void
   317 sfntfont_android_composite_bitmap (unsigned char *restrict buffer,
   318                                    size_t stride,
   319                                    unsigned char *restrict dest,
   320                                    AndroidBitmapInfo *bitmap_info,
   321                                    struct android_rectangle *text_rectangle,
   322                                    struct android_rectangle *rect)
   323 {
   324   unsigned int *src_row;
   325   unsigned int *dst_row;
   326   unsigned int i, src_y, x, src_x, max_x, dst_x;
   327 #ifdef __aarch64__
   328   unsigned int lim_x;
   329 #endif
   330 
   331   if ((intptr_t) dest & 3 || bitmap_info->stride & 3)
   332     /* This shouldn't be possible as Android is supposed to align the
   333        bitmap to at least a 4 byte boundary.  */
   334     emacs_abort ();
   335   else
   336     {
   337       for (i = 0; i < rect->height; ++i)
   338         {
   339           if (i + rect->y >= bitmap_info->height)
   340             /* Done.  */
   341             return;
   342 
   343           src_y = i + (rect->y - text_rectangle->y);
   344 
   345           if (src_y > text_rectangle->height)
   346             /* Huh? */
   347             return;
   348 
   349           src_row = (unsigned int *) ((buffer + src_y * stride));
   350           dst_row = (unsigned int *) (dest + ((i + rect->y)
   351                                               * bitmap_info->stride));
   352 
   353           /* Figure out where the loop below should end.  */
   354           max_x = min (rect->width, bitmap_info->width - rect->x);
   355 
   356           /* Keep this loop simple! */
   357           for (x = 0; x < max_x; ++x)
   358             {
   359               src_x = x + (rect->x - text_rectangle->x);
   360               dst_x = x + rect->x;
   361 
   362 #ifdef __aarch64__
   363               /* This is the largest value of src_x.  */
   364               lim_x = max_x + (rect->x - text_rectangle->x);
   365 
   366               if (!sfntfont_android_over_8888 (src_row + src_x,
   367                                                dst_row + dst_x,
   368                                                src_row + lim_x,
   369                                                &x))
   370                 {
   371                   /* Decrement X by one so the for loop can increment
   372                      it again.  */
   373                   x--;
   374                   continue;
   375                 }
   376 #endif
   377                 dst_row[dst_x]
   378                   = sfntfont_android_blend (src_row[src_x],
   379                                             dst_row[dst_x]);
   380             }
   381         }
   382     }
   383 }
   384 
   385 /* Calculate the union containing both A and B, both boxes.  Place the
   386    result in RESULT.  */
   387 
   388 static void
   389 sfntfont_android_union_boxes (struct gui_box a, struct gui_box b,
   390                               struct gui_box *result)
   391 {
   392   result->x1 = min (a.x1, b.x1);
   393   result->y1 = min (a.y1, b.y1);
   394   result->x2 = max (a.x2, b.x2);
   395   result->y2 = max (a.y2, b.y2);
   396 }
   397 
   398 /* Draw the specified glyph rasters from FROM to TO on behalf of S,
   399    using S->gc.  Fill the background if WITH_BACKGROUND is true.
   400 
   401    See init_sfntfont_vendor and sfntfont_draw for more details.  */
   402 
   403 static void
   404 sfntfont_android_put_glyphs (struct glyph_string *s, int from,
   405                              int to, int x, int y, bool with_background,
   406                              struct sfnt_raster **rasters,
   407                              int *x_coords)
   408 {
   409   struct android_rectangle background, text_rectangle, rect;
   410   struct gui_box text, character;
   411   unsigned int *buffer, *row;
   412   unsigned char *restrict raster_row;
   413   size_t stride, i;
   414   AndroidBitmapInfo bitmap_info;
   415   unsigned char *bitmap_data;
   416   jobject bitmap;
   417   int left, top, temp_y;
   418   unsigned int prod, raster_y;
   419   unsigned long foreground, back_pixel, rb;
   420 
   421   if (!s->gc->num_clip_rects)
   422     /* Clip region is empty.  */
   423     return;
   424 
   425   if (from == to)
   426     /* Nothing to draw.  */
   427     return;
   428 
   429   /* Swizzle the foreground and background in s->gc into BGR, then add
   430      an alpha channel.  */
   431   foreground = s->gc->foreground;
   432   back_pixel = s->gc->background;
   433   rb = foreground & 0x00ff00ff;
   434   foreground &= ~0x00ff00ff;
   435   foreground |= rb >> 16 | rb << 16 | 0xff000000;
   436   rb = back_pixel & 0x00ff00ff;
   437   back_pixel &= ~0x00ff00ff;
   438   back_pixel |= rb >> 16 | rb << 16 | 0xff000000;
   439 
   440   prepare_face_for_display (s->f, s->face);
   441 
   442   /* Build the scanline buffer.  Figure out the bounds of the
   443      background.  */
   444   memset (&background, 0, sizeof background);
   445 
   446   if (with_background)
   447     {
   448       background.x = x;
   449       background.y = y - FONT_BASE (s->font);
   450       background.width = s->width;
   451       background.height = FONT_HEIGHT (s->font);
   452     }
   453 
   454   /* Now figure out the bounds of the text.  */
   455 
   456   if (rasters[0])
   457     {
   458       text.x1 = x_coords[0] + rasters[0]->offx;
   459       text.x2 = text.x1 + rasters[0]->width;
   460       text.y1 = y - rasters[0]->height - rasters[0]->offy;
   461       text.y2 = y - rasters[0]->offy;
   462     }
   463   else
   464     memset (&text, 0, sizeof text);
   465 
   466   for (i = 1; i < to - from; ++i)
   467     {
   468       /* See if text has to be extended.  */
   469 
   470       if (!rasters[i])
   471         continue;
   472 
   473       character.x1 = x_coords[i] + rasters[i]->offx;
   474       character.x2 = character.x1 + rasters[i]->width;
   475       character.y1 = y - rasters[i]->height - rasters[i]->offy;
   476       character.y2 = y - rasters[i]->offy;
   477 
   478       sfntfont_android_union_boxes (text, character, &text);
   479     }
   480 
   481   /* Union the background rect with the text rectangle.  */
   482   text_rectangle.x = text.x1;
   483   text_rectangle.y = text.y1;
   484   text_rectangle.width = text.x2 - text.x1;
   485   text_rectangle.height = text.y2 - text.y1;
   486   gui_union_rectangles (&background, &text_rectangle,
   487                         &text_rectangle);
   488 
   489   /* Allocate enough to hold text_rectangle.height, aligned to 8 (or
   490      16) bytes.  Then fill it with the background.  */
   491 #ifndef __aarch64__
   492   stride = ((text_rectangle.width * sizeof *buffer) + 7) & ~7;
   493 #else
   494   stride = ((text_rectangle.width * sizeof *buffer) + 15) & ~15;
   495 #endif
   496   GET_SCANLINE_BUFFER (buffer, text_rectangle.height, stride);
   497 
   498   /* Try to optimize out this memset if the background rectangle
   499      contains the whole text rectangle.  */
   500 
   501   if (!with_background || memcmp (&background, &text_rectangle,
   502                                   sizeof text_rectangle))
   503     memset (buffer, 0, text_rectangle.height * stride);
   504 
   505   if (with_background)
   506     {
   507       /* Fill the background.  First, offset the background rectangle
   508          to become relative from text_rectangle.x,
   509          text_rectangle.y.  */
   510       background.x = background.x - text_rectangle.x;
   511       background.y = background.y - text_rectangle.y;
   512       eassert (background.x >= 0 && background.y >= 0);
   513 
   514       for (temp_y = background.y; (temp_y
   515                                    < (background.y
   516                                       + background.height));
   517            ++temp_y)
   518         {
   519           row = (unsigned int *) ((unsigned char *) buffer
   520                                   + stride * temp_y);
   521 
   522           for (x = background.x; x < background.x + background.width; ++x)
   523             row[x] = back_pixel;
   524         }
   525     }
   526 
   527   /* Draw all the rasters onto the buffer.  */
   528   for (i = 0; i < to - from; ++i)
   529     {
   530       if (!rasters[i])
   531         continue;
   532 
   533       /* Figure out the top and left of the raster relative to
   534          text_rectangle.  */
   535       left = x_coords[i] + rasters[i]->offx - text_rectangle.x;
   536 
   537       /* Note that negative offy represents the part of the text that
   538          lies below the baseline.  */
   539       top = (y - (rasters[i]->height + rasters[i]->offy)
   540              - text_rectangle.y);
   541       eassert (left >= 0 && top >= 0);
   542 
   543       /* Draw the raster onto the temporary bitmap using the
   544          foreground color scaled by the alpha map.  */
   545 
   546       for (raster_y = 0; raster_y < rasters[i]->height; ++raster_y)
   547         {
   548           row = (unsigned int *) ((unsigned char *) buffer
   549                                   + stride * (raster_y + top));
   550           raster_row = &rasters[i]->cells[raster_y * rasters[i]->stride];
   551 
   552           for (x = 0; x < rasters[i]->width; ++x)
   553             {
   554               prod
   555                 = sfntfont_android_scale32 (U255TO256 (raster_row[x]),
   556                                             foreground);
   557               row[left + x]
   558                 = sfntfont_android_blend (prod, row[left + x]);
   559             }
   560         }
   561     }
   562 
   563   /* Lock the bitmap.  It must be unlocked later.  */
   564   bitmap_data = android_lock_bitmap (FRAME_ANDROID_DRAWABLE (s->f),
   565                                      &bitmap_info, &bitmap);
   566 
   567   /* If locking the bitmap fails, just discard the data that was
   568      allocated.  */
   569   if (!bitmap_data)
   570     return;
   571 
   572   /* Loop over each clip rect in the GC.  */
   573   eassert (bitmap_info.format == ANDROID_BITMAP_FORMAT_RGBA_8888);
   574 
   575   if (s->gc->num_clip_rects > 0)
   576     {
   577       for (i = 0; i < s->gc->num_clip_rects; ++i)
   578         {
   579           if (!gui_intersect_rectangles (&s->gc->clip_rects[i],
   580                                          &text_rectangle, &rect))
   581             /* Outside the clip region.  */
   582             continue;
   583 
   584           /* Composite the intersection onto the buffer.  */
   585           sfntfont_android_composite_bitmap ((unsigned char *) buffer,
   586                                              stride, bitmap_data,
   587                                              &bitmap_info,
   588                                              &text_rectangle, &rect);
   589         }
   590     }
   591   else /* gc->num_clip_rects < 0 */
   592     sfntfont_android_composite_bitmap ((unsigned char *) buffer,
   593                                        stride, bitmap_data,
   594                                        &bitmap_info,
   595                                        &text_rectangle,
   596                                        &text_rectangle);
   597 
   598   /* Release the bitmap.  */
   599   AndroidBitmap_unlockPixels (android_java_env, bitmap);
   600   ANDROID_DELETE_LOCAL_REF (bitmap);
   601 
   602   /* Damage the window by the text rectangle.  */
   603   android_damage_window (FRAME_ANDROID_DRAWABLE (s->f),
   604                          &text_rectangle);
   605 
   606 #undef MAX_ALLOCA
   607 }
   608 
   609 
   610 
   611 /* Shrink the scanline buffer after a window update.  If
   612    max_scanline_buffer_size is not zero, and is less than
   613    scanline_buffer.buffer_size / 2, then resize the scanline buffer to
   614    max_scanline_buffer_size.  */
   615 
   616 void
   617 sfntfont_android_shrink_scanline_buffer (void)
   618 {
   619   if (!max_scanline_buffer_size)
   620     return;
   621 
   622   if (max_scanline_buffer_size
   623       < scanline_buffer.buffer_size / 2)
   624     {
   625       scanline_buffer.buffer_size
   626         = max_scanline_buffer_size;
   627       scanline_buffer.buffer_data
   628         = xrealloc (scanline_buffer.buffer_data,
   629                     max_scanline_buffer_size);
   630     }
   631 
   632   max_scanline_buffer_size = 0;
   633 }
   634 
   635 
   636 
   637 /* Font driver definition.  */
   638 
   639 /* Return the font cache for this font driver.  F is ignored.  */
   640 
   641 static Lisp_Object
   642 sfntfont_android_get_cache (struct frame *f)
   643 {
   644   return font_cache;
   645 }
   646 
   647 /* The Android sfntfont driver.  */
   648 const struct font_driver android_sfntfont_driver =
   649   {
   650     .type = LISPSYM_INITIALLY (Qsfnt_android),
   651     .case_sensitive = true,
   652     .get_cache = sfntfont_android_get_cache,
   653     .list = sfntfont_list,
   654     .match = sfntfont_match,
   655     .draw = sfntfont_draw,
   656     .open_font = sfntfont_open,
   657     .close_font = sfntfont_close,
   658     .encode_char = sfntfont_encode_char,
   659     .text_extents = sfntfont_text_extents,
   660     .list_family = sfntfont_list_family,
   661     .get_variation_glyphs = sfntfont_get_variation_glyphs,
   662 
   663 #ifdef HAVE_HARFBUZZ
   664     /* HarfBuzz support is enabled transparently on Android without
   665        using a separate font driver.  */
   666     .begin_hb_font = sfntfont_begin_hb_font,
   667     .combining_capability = hbfont_combining_capability,
   668     .shape = hbfont_shape,
   669     .otf_capability = hbfont_otf_capability,
   670 #endif /* HAVE_HARFBUZZ */
   671   };
   672 
   673 
   674 
   675 /* This is an ugly hack that should go away, but I can't think of
   676    how.  */
   677 
   678 DEFUN ("android-enumerate-fonts", Fandroid_enumerate_fonts,
   679        Sandroid_enumerate_fonts, 0, 0, 0,
   680        doc: /* Enumerate fonts present on the system.
   681 
   682 Signal an error if fonts have already been enumerated.  This would
   683 normally have been done in C, but reading fonts require Lisp to be
   684 loaded before character sets are made available.  */)
   685   (void)
   686 {
   687   DIR *dir;
   688   int i;
   689   struct dirent *dirent;
   690   char name[PATH_MAX * 2];
   691   static bool enumerated;
   692 
   693   if (enumerated)
   694     error ("Fonts have already been enumerated");
   695   enumerated = true;
   696 
   697   block_input ();
   698 
   699   /* Scan through each of the system font directories.  Enumerate each
   700      font that looks like a TrueType font.  */
   701   for (i = 0; i < ARRAYELTS (system_font_directories); ++i)
   702     {
   703       dir = opendir (system_font_directories[i]);
   704 
   705       __android_log_print (ANDROID_LOG_VERBOSE, __func__,
   706                            "Loading fonts from: %s",
   707                            system_font_directories[i]);
   708 
   709       if (!dir)
   710         continue;
   711 
   712       while ((dirent = readdir (dir)))
   713         {
   714           /* If it contains (not ends with!) with .ttf or .ttc, then
   715              enumerate it.  */
   716 
   717           if ((strstr (dirent->d_name, ".ttf")
   718                || strstr (dirent->d_name, ".ttc"))
   719               /* Ignore the non-variable Roboto font.  */
   720               && (i != 0 || strcmp (dirent->d_name,
   721                                     "RobotoStatic-Regular.ttf")))
   722             {
   723               sprintf (name, "%s/%s", system_font_directories[i],
   724                        dirent->d_name);
   725               sfnt_enum_font (name);
   726             }
   727         }
   728 
   729       closedir (dir);
   730     }
   731 
   732   unblock_input ();
   733 
   734   return Qnil;
   735 }
   736 
   737 
   738 
   739 static void
   740 syms_of_sfntfont_android_for_pdumper (void)
   741 {
   742   init_sfntfont_vendor (Qsfnt_android, &android_sfntfont_driver,
   743                         sfntfont_android_put_glyphs);
   744   register_font_driver (&android_sfntfont_driver, NULL);
   745 }
   746 
   747 void
   748 init_sfntfont_android (void)
   749 {
   750   if (!android_init_gui)
   751     return;
   752 
   753   /* Make sure to pick the right Sans Serif font depending on what
   754      version of Android the device is running.  */
   755   if (android_get_current_api_level () >= 15)
   756     Vsfnt_default_family_alist
   757       = list3 (Fcons (build_string ("Monospace"),
   758                       build_string ("Droid Sans Mono")),
   759                /* Android doesn't come with a Monospace Serif font, so
   760                   this will have to do.  */
   761                Fcons (build_string ("Monospace Serif"),
   762                       build_string ("Droid Sans Mono")),
   763                Fcons (build_string ("Sans Serif"),
   764                       build_string ("Roboto")));
   765   else
   766     Vsfnt_default_family_alist
   767       = list3 (Fcons (build_string ("Monospace"),
   768                       build_string ("Droid Sans Mono")),
   769                Fcons (build_string ("Monospace Serif"),
   770                       build_string ("Droid Sans Mono")),
   771                Fcons (build_string ("Sans Serif"),
   772                       build_string ("Droid Sans")));
   773 
   774   /* Set up the user fonts directory.  This directory is ``fonts'' in
   775      the Emacs files directory.  */
   776   snprintf (system_font_directories[2], PATH_MAX, "%s/fonts",
   777             android_get_home_directory ());
   778 }
   779 
   780 void
   781 syms_of_sfntfont_android (void)
   782 {
   783   DEFSYM (Qsfnt_android, "sfnt-android");
   784   DEFSYM (Qandroid_enumerate_fonts, "android-enumerate-fonts");
   785   Fput (Qandroid, Qfont_driver_superseded_by, Qsfnt_android);
   786 
   787   font_cache = list (Qnil);
   788   staticpro (&font_cache);
   789 
   790   defsubr (&Sandroid_enumerate_fonts);
   791 
   792   pdumper_do_now_and_after_load (syms_of_sfntfont_android_for_pdumper);
   793 }

/* [<][>][^][v][top][bottom][index][help] */