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

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