root/src/androidfont.c

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

DEFINITIONS

This source file includes following definitions.
  1. android_init_font_driver
  2. android_init_font_spec
  3. android_init_font_metrics
  4. android_init_integer
  5. android_init_font_object
  6. androidfont_get_cache
  7. androidfont_check_init
  8. androidfont_from_lisp
  9. androidfont_from_java
  10. androidfont_list
  11. androidfont_match
  12. androidfont_draw
  13. androidfont_open_font
  14. androidfont_close_font
  15. androidfont_has_char
  16. androidfont_encode_char
  17. androidfont_cache_text_extents
  18. androidfont_check_cached_extents
  19. androidfont_text_extents
  20. androidfont_list_family
  21. syms_of_androidfont_for_pdumper
  22. syms_of_androidfont
  23. init_androidfont
  24. android_finalize_font_entity

     1 /* Android fallback font driver.
     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 /* Due to the terrible nature of the Android Typeface subsystems, this
    21    font driver is only used as a fallback when sfntfont-android.c
    22    fails to enumerate any fonts at all.  */
    23 
    24 #include <config.h>
    25 
    26 #include "lisp.h"
    27 #include "dispextern.h"
    28 #include "composite.h"
    29 #include "blockinput.h"
    30 #include "charset.h"
    31 #include "frame.h"
    32 #include "window.h"
    33 #include "fontset.h"
    34 #include "androidterm.h"
    35 #include "character.h"
    36 #include "coding.h"
    37 #include "font.h"
    38 #include "termchar.h"
    39 #include "pdumper.h"
    40 #include "android.h"
    41 
    42 #ifndef ANDROID_STUBIFY
    43 
    44 #include <android/log.h>
    45 
    46 struct android_emacs_font_driver
    47 {
    48   jclass class;
    49   jmethodID list;
    50   jmethodID match;
    51   jmethodID list_families;
    52   jmethodID open_font;
    53   jmethodID has_char;
    54   jmethodID text_extents;
    55   jmethodID encode_char;
    56   jmethodID draw;
    57 
    58   /* Static methods.  */
    59   jmethodID create_font_driver;
    60 };
    61 
    62 struct android_emacs_font_spec
    63 {
    64   jclass class;
    65   jfieldID foundry;
    66   jfieldID family;
    67   jfieldID adstyle;
    68   jfieldID registry;
    69   jfieldID width;
    70   jfieldID weight;
    71   jfieldID slant;
    72   jfieldID size;
    73   jfieldID spacing;
    74   jfieldID avgwidth;
    75   jfieldID dpi;
    76 };
    77 
    78 struct android_emacs_font_metrics
    79 {
    80   jclass class;
    81   jfieldID lbearing;
    82   jfieldID rbearing;
    83   jfieldID width;
    84   jfieldID ascent;
    85   jfieldID descent;
    86 };
    87 
    88 struct android_emacs_font_object
    89 {
    90   jclass class;
    91   jfieldID min_width;
    92   jfieldID max_width;
    93   jfieldID pixel_size;
    94   jfieldID height;
    95   jfieldID space_width;
    96   jfieldID average_width;
    97   jfieldID ascent;
    98   jfieldID descent;
    99   jfieldID underline_thickness;
   100   jfieldID underline_position;
   101   jfieldID baseline_offset;
   102   jfieldID relative_compose;
   103   jfieldID default_ascent;
   104   jfieldID encoding_charset;
   105   jfieldID repertory_charset;
   106 };
   107 
   108 struct android_integer
   109 {
   110   jclass class;
   111   jmethodID constructor;
   112   jmethodID int_value;
   113 };
   114 
   115 struct androidfont_info
   116 {
   117   /* The font pseudo-vector object.  */
   118   struct font font;
   119 
   120   /* The Java-side font.  */
   121   jobject object;
   122 
   123   /* Cached glyph metrics arranged in a two dimensional array.  */
   124   struct font_metrics **metrics;
   125 };
   126 
   127 struct androidfont_entity
   128 {
   129   /* The font entity pvec.  */
   130   struct font_entity font;
   131 
   132   /* The Java-side font entity.  */
   133   jobject object;
   134 };
   135 
   136 /* Method and class identifiers associated with the EmacsFontDriver
   137    class.  */
   138 
   139 struct android_emacs_font_driver font_driver_class;
   140 
   141 /* Field and class identifiers associated with the
   142    EmacsFontDriver$FontSpec class.  */
   143 
   144 struct android_emacs_font_spec font_spec_class;
   145 
   146 /* Method and class identifiers associated with the Integer class.  */
   147 
   148 struct android_integer integer_class;
   149 
   150 /* Field and class identifiers associated with the
   151    EmacsFontDriver$FontMetrics class.  */
   152 
   153 struct android_emacs_font_metrics font_metrics_class;
   154 
   155 /* Field and class identifiers associated with the
   156    EmacsFontDriver$FontObject class.  */
   157 
   158 struct android_emacs_font_object font_object_class;
   159 
   160 /* The font cache.  */
   161 
   162 static Lisp_Object font_cache;
   163 
   164 /* The Java-side font driver.  */
   165 
   166 static jobject font_driver;
   167 
   168 
   169 
   170 /* Initialize the class and method identifiers for functions in the
   171    EmacsFontDriver class, and place them in `font_driver_class'.  */
   172 
   173 static void
   174 android_init_font_driver (void)
   175 {
   176   jclass old;
   177 
   178   font_driver_class.class
   179     = (*android_java_env)->FindClass (android_java_env,
   180                                       "org/gnu/emacs/EmacsFontDriver");
   181   eassert (font_driver_class.class);
   182 
   183   old = font_driver_class.class;
   184   font_driver_class.class
   185     = (jclass) (*android_java_env)->NewGlobalRef (android_java_env,
   186                                                   (jobject) old);
   187   ANDROID_DELETE_LOCAL_REF (old);
   188 
   189   if (!font_driver_class.class)
   190     emacs_abort ();
   191 
   192 #define FIND_METHOD(c_name, name, signature)                                    \
   193   font_driver_class.c_name                                                      \
   194     = (*android_java_env)->GetMethodID (android_java_env,                       \
   195                                         font_driver_class.class,                \
   196                                         name, signature);                       \
   197   eassert (font_driver_class.c_name);
   198 
   199   FIND_METHOD (list, "list", "(Lorg/gnu/emacs/EmacsFontDriver$FontSpec;)"
   200                "[Lorg/gnu/emacs/EmacsFontDriver$FontEntity;");
   201   FIND_METHOD (match, "match", "(Lorg/gnu/emacs/EmacsFontDriver$FontSpec;)"
   202                "Lorg/gnu/emacs/EmacsFontDriver$FontEntity;");
   203   FIND_METHOD (list_families, "listFamilies", "()[Ljava/lang/String;");
   204   FIND_METHOD (open_font, "openFont", "(Lorg/gnu/emacs/EmacsFontDriver$Font"
   205                "Entity;I)Lorg/gnu/emacs/EmacsFontDriver$FontObject;");
   206   FIND_METHOD (has_char, "hasChar", "(Lorg/gnu/emacs/EmacsFontDriver$Font"
   207                "Spec;C)I");
   208   FIND_METHOD (text_extents, "textExtents", "(Lorg/gnu/emacs/EmacsFontDriver"
   209                "$FontObject;[ILorg/gnu/emacs/EmacsFontDriver$FontMetrics;)V");
   210   FIND_METHOD (encode_char, "encodeChar", "(Lorg/gnu/emacs/EmacsFontDriver"
   211                "$FontObject;C)I");
   212   FIND_METHOD (draw, "draw", "(Lorg/gnu/emacs/EmacsFontDriver$FontObject;"
   213                "Lorg/gnu/emacs/EmacsGC;Lorg/gnu/emacs/EmacsDrawable;[IIIIZ)I");
   214 
   215   font_driver_class.create_font_driver
   216     = (*android_java_env)->GetStaticMethodID (android_java_env,
   217                                               font_driver_class.class,
   218                                               "createFontDriver",
   219                                               "()Lorg/gnu/emacs/"
   220                                               "EmacsFontDriver;");
   221   eassert (font_driver_class.create_font_driver);
   222 #undef FIND_METHOD
   223 }
   224 
   225 /* Initialize the class and field identifiers for functions in the
   226    EmacsFontDriver$FontSpec class, and place them in
   227    `font_spec_class'.  */
   228 
   229 static void
   230 android_init_font_spec (void)
   231 {
   232   jclass old;
   233 
   234   font_spec_class.class
   235     = (*android_java_env)->FindClass (android_java_env,
   236                                       "org/gnu/emacs/EmacsFontDriver"
   237                                       "$FontSpec");
   238   eassert (font_spec_class.class);
   239 
   240   old = font_spec_class.class;
   241   font_spec_class.class
   242     = (jclass) (*android_java_env)->NewGlobalRef (android_java_env,
   243                                                   (jobject) old);
   244   ANDROID_DELETE_LOCAL_REF (old);
   245 
   246   if (!font_spec_class.class)
   247     emacs_abort ();
   248 
   249 #define FIND_FIELD(c_name, name, signature)                                     \
   250   font_spec_class.c_name                                                        \
   251     = (*android_java_env)->GetFieldID (android_java_env,                        \
   252                                        font_spec_class.class,                   \
   253                                        name, signature);                        \
   254   eassert (font_spec_class.c_name);
   255 
   256   FIND_FIELD (foundry, "foundry", "Ljava/lang/String;");
   257   FIND_FIELD (family, "family", "Ljava/lang/String;");
   258   FIND_FIELD (adstyle, "adstyle", "Ljava/lang/String;");
   259   FIND_FIELD (registry, "registry", "Ljava/lang/String;");
   260   FIND_FIELD (width, "width", "Ljava/lang/Integer;");
   261   FIND_FIELD (weight, "weight", "Ljava/lang/Integer;");
   262   FIND_FIELD (slant, "slant", "Ljava/lang/Integer;");
   263   FIND_FIELD (size, "size", "Ljava/lang/Integer;");
   264   FIND_FIELD (spacing, "spacing", "Ljava/lang/Integer;");
   265   FIND_FIELD (avgwidth, "avgwidth", "Ljava/lang/Integer;");
   266   FIND_FIELD (dpi, "dpi", "Ljava/lang/Integer;");
   267 #undef FIND_FIELD
   268 }
   269 
   270 static void
   271 android_init_font_metrics (void)
   272 {
   273   jclass old;
   274 
   275   font_metrics_class.class
   276     = (*android_java_env)->FindClass (android_java_env,
   277                                       "org/gnu/emacs/EmacsFontDriver"
   278                                       "$FontMetrics");
   279   eassert (font_metrics_class.class);
   280 
   281   old = font_metrics_class.class;
   282   font_metrics_class.class
   283     = (jclass) (*android_java_env)->NewGlobalRef (android_java_env,
   284                                                   (jobject) old);
   285   ANDROID_DELETE_LOCAL_REF (old);
   286 
   287   if (!font_metrics_class.class)
   288     emacs_abort ();
   289 
   290 #define FIND_FIELD(c_name, name, signature)                                     \
   291   font_metrics_class.c_name                                                     \
   292     = (*android_java_env)->GetFieldID (android_java_env,                        \
   293                                        font_metrics_class.class,                \
   294                                        name, signature);                        \
   295   eassert (font_metrics_class.c_name);
   296 
   297   FIND_FIELD (lbearing, "lbearing", "S");
   298   FIND_FIELD (rbearing, "rbearing", "S");
   299   FIND_FIELD (width, "width", "S");
   300   FIND_FIELD (ascent, "ascent", "S");
   301   FIND_FIELD (descent, "descent", "S");
   302 #undef FIND_FIELD
   303 }
   304 
   305 static void
   306 android_init_integer (void)
   307 {
   308   jclass old;
   309 
   310   integer_class.class
   311     = (*android_java_env)->FindClass (android_java_env,
   312                                       "java/lang/Integer");
   313   eassert (integer_class.class);
   314 
   315   old = integer_class.class;
   316   integer_class.class
   317     = (jclass) (*android_java_env)->NewGlobalRef (android_java_env,
   318                                                   (jobject) old);
   319   ANDROID_DELETE_LOCAL_REF (old);
   320 
   321   if (!integer_class.class)
   322     emacs_abort ();
   323 
   324 #define FIND_METHOD(c_name, name, signature)                                    \
   325   integer_class.c_name                                                          \
   326     = (*android_java_env)->GetMethodID (android_java_env,                       \
   327                                         integer_class.class,                    \
   328                                         name, signature);                       \
   329   eassert (integer_class.c_name);
   330 
   331   FIND_METHOD (constructor, "<init>", "(I)V");
   332   FIND_METHOD (int_value, "intValue", "()I");
   333 #undef FIND_METHOD
   334 }
   335 
   336 static void
   337 android_init_font_object (void)
   338 {
   339   jclass old;
   340 
   341   font_object_class.class
   342     = (*android_java_env)->FindClass (android_java_env,
   343                                       "org/gnu/emacs/EmacsFontDriver"
   344                                       "$FontObject");
   345   eassert (font_object_class.class);
   346 
   347   old = font_object_class.class;
   348   font_object_class.class
   349     = (jclass) (*android_java_env)->NewGlobalRef (android_java_env,
   350                                                   (jobject) old);
   351   ANDROID_DELETE_LOCAL_REF (old);
   352 
   353   if (!font_object_class.class)
   354     emacs_abort ();
   355 
   356 #define FIND_FIELD(c_name, name, signature)                                     \
   357   font_object_class.c_name                                                      \
   358     = (*android_java_env)->GetFieldID (android_java_env,                        \
   359                                        font_object_class.class,                 \
   360                                        name, signature);                        \
   361   eassert (font_object_class.c_name);
   362 
   363   FIND_FIELD (min_width, "minWidth", "I");
   364   FIND_FIELD (max_width, "maxWidth", "I");
   365   FIND_FIELD (pixel_size, "pixelSize", "I");
   366   FIND_FIELD (height, "height", "I");
   367   FIND_FIELD (space_width, "spaceWidth", "I");
   368   FIND_FIELD (average_width, "averageWidth", "I");
   369   FIND_FIELD (ascent, "ascent", "I");
   370   FIND_FIELD (descent, "descent", "I");
   371   FIND_FIELD (underline_thickness, "underlineThickness", "I");
   372   FIND_FIELD (underline_position, "underlinePosition", "I");
   373   FIND_FIELD (baseline_offset, "baselineOffset", "I");
   374   FIND_FIELD (relative_compose, "relativeCompose", "I");
   375   FIND_FIELD (default_ascent, "defaultAscent", "I");
   376   FIND_FIELD (encoding_charset, "encodingCharset", "I");
   377   FIND_FIELD (repertory_charset, "repertoryCharset", "I");
   378 #undef FIND_FIELD
   379 }
   380 
   381 static Lisp_Object
   382 androidfont_get_cache (struct frame *frame)
   383 {
   384   return font_cache;
   385 }
   386 
   387 /* Initialize the Java side of the font driver if it has not already
   388    been initialized.  This is only done whenever necessary because the
   389    font driver otherwise uses a lot of memory, as it has to keep every
   390    typeface open.  */
   391 
   392 static void
   393 androidfont_check_init (void)
   394 {
   395   jmethodID method;
   396   jobject old;
   397 
   398   if (font_driver)
   399     return;
   400 
   401   /* Log a loud message.  This font driver really should not be
   402      used.  */
   403   __android_log_print (ANDROID_LOG_WARN, __func__,
   404                        "The Android font driver is being used."
   405                        "  Please investigate why this is so.");
   406 
   407   method = font_driver_class.create_font_driver;
   408 
   409   /* Initialize the font driver on the Java side.  */
   410   font_driver
   411     = (*android_java_env)->CallStaticObjectMethod (android_java_env,
   412                                                    font_driver_class.class,
   413                                                    method);
   414   android_exception_check ();
   415 
   416   old = font_driver;
   417   font_driver
   418     = (*android_java_env)->NewGlobalRef (android_java_env, font_driver);
   419   ANDROID_DELETE_LOCAL_REF (old);
   420 }
   421 
   422 /* Return a local reference to an instance of EmacsFontDriver$FontSpec
   423    with the same values as FONT.  */
   424 
   425 static jobject
   426 androidfont_from_lisp (Lisp_Object font)
   427 {
   428   jobject spec, integer;
   429   jstring string;
   430   Lisp_Object tem;
   431 
   432   spec = (*android_java_env)->AllocObject (android_java_env,
   433                                            font_spec_class.class);
   434   android_exception_check ();
   435 
   436 #define DO_SYMBOL_FIELD(field, index)                                           \
   437   tem = AREF (font, index);                                                     \
   438   if (SYMBOLP (tem))                                                            \
   439     {                                                                           \
   440       /* Java seems to DTRT with the Emacs string encoding, so this does        \
   441          not matter at all.  */                                                 \
   442       string = (*android_java_env)->NewStringUTF (android_java_env,             \
   443                                                   SSDATA (SYMBOL_NAME (tem)));  \
   444       android_exception_check_1 (spec);                                         \
   445                                                                                 \
   446       (*android_java_env)->SetObjectField (android_java_env, spec,              \
   447                                            font_spec_class.field,               \
   448                                            string);                             \
   449       ANDROID_DELETE_LOCAL_REF (string);                                        \
   450     }                                                                           \
   451 
   452   DO_SYMBOL_FIELD (foundry, FONT_FOUNDRY_INDEX);
   453   DO_SYMBOL_FIELD (family, FONT_FAMILY_INDEX);
   454   DO_SYMBOL_FIELD (adstyle, FONT_ADSTYLE_INDEX);
   455   DO_SYMBOL_FIELD (registry, FONT_REGISTRY_INDEX);
   456 
   457 #undef DO_SYMBOL_FIELD
   458 
   459 #define DO_CARDINAL_FIELD(field, value)                                         \
   460   if (value != -1)                                                              \
   461     {                                                                           \
   462       integer = (*android_java_env)->NewObject (android_java_env,               \
   463                                                 integer_class.class,            \
   464                                                 integer_class.constructor,      \
   465                                                 (jint) value);                  \
   466       android_exception_check_1 (spec);                                         \
   467                                                                                 \
   468       (*android_java_env)->SetObjectField (android_java_env, spec,              \
   469                                            font_spec_class.field,               \
   470                                            integer);                            \
   471       ANDROID_DELETE_LOCAL_REF (integer);                                       \
   472     }
   473 
   474   DO_CARDINAL_FIELD (width, FONT_WIDTH_NUMERIC (font));
   475   DO_CARDINAL_FIELD (weight, FONT_WEIGHT_NUMERIC (font));
   476   DO_CARDINAL_FIELD (slant, FONT_SLANT_NUMERIC (font));
   477   DO_CARDINAL_FIELD (size, (FIXNUMP (AREF (font, FONT_SIZE_INDEX))
   478                             ? XFIXNUM (AREF (font, FONT_SIZE_INDEX))
   479                             : -1));
   480   DO_CARDINAL_FIELD (spacing, (FIXNUMP (AREF (font, FONT_SPACING_INDEX))
   481                                ? XFIXNUM (AREF (font, FONT_SPACING_INDEX))
   482                                : -1));
   483   DO_CARDINAL_FIELD (avgwidth, (FIXNUMP (AREF (font, FONT_AVGWIDTH_INDEX))
   484                                 ? XFIXNUM (AREF (font, FONT_AVGWIDTH_INDEX))
   485                                 : -1));
   486   DO_CARDINAL_FIELD (dpi, (FIXNUMP (AREF (font, FONT_DPI_INDEX))
   487                            ? XFIXNUM (AREF (font, FONT_DPI_INDEX))
   488                            : -1));
   489 
   490 #undef DO_CARDINAL_FIELD
   491 
   492   return spec;
   493 }
   494 
   495 static void
   496 androidfont_from_java (jobject spec, Lisp_Object entity)
   497 {
   498   jobject tem;
   499   jint value;
   500   const char *string;
   501 
   502 #define DO_SYMBOL_FIELD(field, index)                                           \
   503   tem = (*android_java_env)->GetObjectField (android_java_env,                  \
   504                                              spec,                              \
   505                                              font_spec_class.field);            \
   506   if (tem)                                                                      \
   507     {                                                                           \
   508       string = (*android_java_env)->GetStringUTFChars (android_java_env,        \
   509                                                        tem, NULL);              \
   510       if (!string)                                                              \
   511         memory_full (0);                                                        \
   512       ASET (entity, index, intern (string));                                    \
   513       (*android_java_env)->ReleaseStringUTFChars (android_java_env,             \
   514                                                   tem, string);                 \
   515       ANDROID_DELETE_LOCAL_REF (tem);                                           \
   516     }
   517 
   518   DO_SYMBOL_FIELD (foundry, FONT_FOUNDRY_INDEX);
   519   DO_SYMBOL_FIELD (family, FONT_FAMILY_INDEX);
   520   DO_SYMBOL_FIELD (adstyle, FONT_ADSTYLE_INDEX);
   521   DO_SYMBOL_FIELD (registry, FONT_REGISTRY_INDEX);
   522 
   523 #undef DO_SYMBOL_FIELD
   524 #define DO_CARDINAL_FIELD(field, index, is_style)                       \
   525   tem = (*android_java_env)->GetObjectField (android_java_env,          \
   526                                              spec,                      \
   527                                              font_spec_class.field);    \
   528   if (tem)                                                              \
   529     {                                                                   \
   530       value                                                             \
   531         = (*android_java_env)->CallIntMethod (android_java_env,         \
   532                                               tem,                      \
   533                                               integer_class.int_value); \
   534       if (!is_style)                                                    \
   535         ASET (entity, index, make_fixnum (value));                      \
   536       else                                                              \
   537         FONT_SET_STYLE (entity, index, make_fixnum (value));            \
   538       ANDROID_DELETE_LOCAL_REF (tem);                                   \
   539     }
   540 
   541   DO_CARDINAL_FIELD (width, FONT_WIDTH_INDEX, true);
   542   DO_CARDINAL_FIELD (weight, FONT_WEIGHT_INDEX, true);
   543   DO_CARDINAL_FIELD (slant, FONT_SLANT_INDEX, true);
   544   DO_CARDINAL_FIELD (size, FONT_SIZE_INDEX, false);
   545   DO_CARDINAL_FIELD (spacing, FONT_SPACING_INDEX, false);
   546   DO_CARDINAL_FIELD (avgwidth, FONT_AVGWIDTH_INDEX, false);
   547   DO_CARDINAL_FIELD (dpi, FONT_DPI_INDEX, false);
   548 
   549 #undef DO_CARDINAL_FIELD
   550 }
   551 
   552 /* Transfer the values from FONT, which must be some kind of font
   553    entity, */
   554 
   555 static Lisp_Object
   556 androidfont_list (struct frame *f, Lisp_Object font_spec)
   557 {
   558   jobject spec, array, tem;
   559   jarray entities;
   560   jsize i, size;
   561   Lisp_Object value, entity;
   562   struct androidfont_entity *info;
   563 
   564   /* Maybe initialize the font driver.  */
   565   androidfont_check_init ();
   566 
   567   spec = androidfont_from_lisp (font_spec);
   568   array = (*android_java_env)->CallObjectMethod (android_java_env,
   569                                                  font_driver,
   570                                                  font_driver_class.list,
   571                                                  spec);
   572   android_exception_check_1 (spec);
   573   ANDROID_DELETE_LOCAL_REF (spec);
   574 
   575   entities = (jarray) array;
   576   size = (*android_java_env)->GetArrayLength (android_java_env,
   577                                               entities);
   578   value = Qnil;
   579 
   580   for (i = 0; i < size; ++i)
   581     {
   582       entity = font_make_entity_android (VECSIZE (struct androidfont_entity));
   583       info = (struct androidfont_entity *) XFONT_ENTITY (entity);
   584 
   585       /* The type must be set correctly, or font_open_entity won't be
   586          able to find the right font driver.  */
   587       ASET (entity, FONT_TYPE_INDEX, Qandroid);
   588 
   589       /* Clear this now in case GC happens without it set, which can
   590          happen if androidfont_from_java runs out of memory.  */
   591       info->object = NULL;
   592 
   593       tem = (*android_java_env)->GetObjectArrayElement (android_java_env,
   594                                                         entities, i);
   595       androidfont_from_java (tem, entity);
   596 
   597       /* Now, make a global reference to the Java font entity.  */
   598       info->object = (*android_java_env)->NewGlobalRef (android_java_env,
   599                                                         (jobject) tem);
   600       android_exception_check_2 (tem, entities);
   601       ANDROID_DELETE_LOCAL_REF (tem);
   602 
   603       value = Fcons (entity, value);
   604     }
   605 
   606   ANDROID_DELETE_LOCAL_REF (entities);
   607   return Fnreverse (value);
   608 }
   609 
   610 static Lisp_Object
   611 androidfont_match (struct frame *f, Lisp_Object font_spec)
   612 {
   613   jobject spec, result;
   614   Lisp_Object entity;
   615   struct androidfont_entity *info;
   616 
   617   /* Maybe initialize the font driver.  */
   618   androidfont_check_init ();
   619 
   620   spec = androidfont_from_lisp (font_spec);
   621   result = (*android_java_env)->CallObjectMethod (android_java_env,
   622                                                   font_driver,
   623                                                   font_driver_class.match,
   624                                                   spec);
   625   android_exception_check_1 (spec);
   626   ANDROID_DELETE_LOCAL_REF (spec);
   627 
   628   entity = font_make_entity_android (VECSIZE (struct androidfont_entity));
   629   info = (struct androidfont_entity *) XFONT_ENTITY (entity);
   630 
   631   /* The type must be set correctly, or font_open_entity won't be able
   632      to find the right font driver.  */
   633   ASET (entity, FONT_TYPE_INDEX, Qandroid);
   634 
   635   info->object = NULL;
   636   androidfont_from_java (result, entity);
   637   info->object = (*android_java_env)->NewGlobalRef (android_java_env,
   638                                                     (jobject) result);
   639   android_exception_check_1 (result);
   640   ANDROID_DELETE_LOCAL_REF (result);
   641 
   642   return entity;
   643 }
   644 
   645 static int
   646 androidfont_draw (struct glyph_string *s, int from, int to,
   647                   int x, int y, bool with_background)
   648 {
   649   struct androidfont_info *info;
   650   jarray chars;
   651   int rc;
   652   jobject gcontext, drawable;
   653 
   654   /* Maybe initialize the font driver.  */
   655   androidfont_check_init ();
   656 
   657   verify (sizeof (unsigned int) == sizeof (jint));
   658   info = (struct androidfont_info *) s->font;
   659 
   660   gcontext = android_resolve_handle (s->gc->gcontext,
   661                                      ANDROID_HANDLE_GCONTEXT);
   662   drawable = android_resolve_handle (FRAME_ANDROID_DRAWABLE (s->f),
   663                                      ANDROID_HANDLE_WINDOW);
   664   chars = (*android_java_env)->NewIntArray (android_java_env,
   665                                             to - from);
   666   android_exception_check ();
   667 
   668   (*android_java_env)->SetIntArrayRegion (android_java_env, chars,
   669                                           0, to - from,
   670                                           (jint *) s->char2b + from);
   671 
   672   info = (struct androidfont_info *) s->font;
   673   prepare_face_for_display (s->f, s->face);
   674 
   675   rc = (*android_java_env)->CallIntMethod (android_java_env,
   676                                            font_driver,
   677                                            font_driver_class.draw,
   678                                            info->object,
   679                                            gcontext, drawable,
   680                                            chars, (jint) x, (jint) y,
   681                                            (jint) s->width,
   682                                            (jboolean) with_background);
   683   android_exception_check_1 (chars);
   684   ANDROID_DELETE_LOCAL_REF (chars);
   685 
   686   return rc;
   687 }
   688 
   689 static Lisp_Object
   690 androidfont_open_font (struct frame *f, Lisp_Object font_entity,
   691                        int pixel_size)
   692 {
   693   struct androidfont_info *font_info;
   694   struct androidfont_entity *entity;
   695   struct font *font;
   696   Lisp_Object font_object;
   697   jobject old;
   698   jint value;
   699 
   700   /* Maybe initialize the font driver.  */
   701   androidfont_check_init ();
   702 
   703   if (XFIXNUM (AREF (font_entity, FONT_SIZE_INDEX)) != 0)
   704     pixel_size = XFIXNUM (AREF (font_entity, FONT_SIZE_INDEX));
   705   else if (pixel_size == 0)
   706     {
   707       /* This bit was copied from xfont.c.  The values might need
   708          adjustment.  */
   709 
   710       if (FRAME_FONT (f))
   711         pixel_size = FRAME_FONT (f)->pixel_size;
   712       else
   713         pixel_size = 12;
   714     }
   715 
   716   entity = (struct androidfont_entity *) XFONT_ENTITY (font_entity);
   717 
   718   block_input ();
   719   font_object = font_make_object (VECSIZE (struct androidfont_info),
   720                                   font_entity, pixel_size);
   721   ASET (font_object, FONT_TYPE_INDEX, Qandroid);
   722   font_info = (struct androidfont_info *) XFONT_OBJECT (font_object);
   723   font = &font_info->font;
   724   font->driver = &androidfont_driver;
   725 
   726   /* Clear font_info->object and font_info->metrics early in case GC
   727      happens later on! */
   728   font_info->object = NULL;
   729   font_info->metrics = NULL;
   730   unblock_input ();
   731 
   732   font_info->object
   733     = (*android_java_env)->CallObjectMethod (android_java_env,
   734                                              font_driver,
   735                                              font_driver_class.open_font,
   736                                              entity->object,
   737                                              (jint) pixel_size);
   738   android_exception_check ();
   739 
   740   old = font_info->object;
   741   font_info->object
   742     = (*android_java_env)->NewGlobalRef (android_java_env, old);
   743   android_exception_check_1 (old);
   744   ANDROID_DELETE_LOCAL_REF (old);
   745 
   746   if (!font_info->object)
   747     return Qnil;
   748 
   749   /* Copy the font attributes from the Java object.  */
   750   androidfont_from_java (font_info->object, font_object);
   751 
   752   /* Copy font attributes inside EmacsFontDriver$FontObject.  */
   753 #define DO_CARDINAL_FIELD(field)                                        \
   754   value                                                                 \
   755     = (*android_java_env)->GetIntField (android_java_env,               \
   756                                         font_info->object,              \
   757                                         font_object_class.field);       \
   758   font->field = value;
   759 
   760   DO_CARDINAL_FIELD (min_width);
   761   DO_CARDINAL_FIELD (max_width);
   762   DO_CARDINAL_FIELD (pixel_size);
   763   DO_CARDINAL_FIELD (height);
   764   DO_CARDINAL_FIELD (space_width);
   765   DO_CARDINAL_FIELD (average_width);
   766   DO_CARDINAL_FIELD (ascent);
   767   DO_CARDINAL_FIELD (descent);
   768   DO_CARDINAL_FIELD (underline_thickness);
   769   DO_CARDINAL_FIELD (underline_position);
   770   DO_CARDINAL_FIELD (baseline_offset);
   771   DO_CARDINAL_FIELD (relative_compose);
   772   DO_CARDINAL_FIELD (default_ascent);
   773   DO_CARDINAL_FIELD (encoding_charset);
   774   DO_CARDINAL_FIELD (repertory_charset);
   775 
   776 #undef DO_CARDINAL_FIELD
   777 
   778   /* This should eventually become unnecessary.  */
   779   font->props[FONT_NAME_INDEX] = Ffont_xlfd_name (font_object, Qnil);
   780 
   781   return font_object;
   782 }
   783 
   784 static void
   785 androidfont_close_font (struct font *font)
   786 {
   787   struct androidfont_info *info;
   788   int i;
   789 
   790   /* Maybe initialize the font driver.  */
   791   androidfont_check_init ();
   792 
   793   info = (struct androidfont_info *) font;
   794 
   795   /* Free the font metrics cache if it exists.  */
   796 
   797   if (info->metrics)
   798     {
   799       for (i = 0; i < 256; ++i)
   800         xfree (info->metrics[i]);
   801       xfree (info->metrics);
   802     }
   803 
   804   info->metrics = NULL;
   805 
   806   /* If info->object is NULL, then FONT was unsuccessfully created,
   807      and there is no global reference that has to be deleted.
   808 
   809      Alternatively, FONT may have been closed by font_close_object,
   810      with this function called from GC.  */
   811 
   812   if (!info->object)
   813     return;
   814 
   815   (*android_java_env)->DeleteGlobalRef (android_java_env,
   816                                         info->object);
   817   info->object = NULL;
   818 }
   819 
   820 static int
   821 androidfont_has_char (Lisp_Object font, int c)
   822 {
   823   struct androidfont_info *info;
   824   struct androidfont_entity *entity;
   825 
   826   /* Maybe initialize the font driver.  */
   827   androidfont_check_init ();
   828 
   829   if (FONT_ENTITY_P (font))
   830     {
   831       entity = (struct androidfont_entity *) XFONT_ENTITY (font);
   832 
   833       return (*android_java_env)->CallIntMethod (android_java_env,
   834                                                  font_driver,
   835                                                  font_driver_class.has_char,
   836                                                  entity->object, (jint) c);
   837     }
   838   else
   839     {
   840       info = (struct androidfont_info *) XFONT_OBJECT (font);
   841 
   842       return (*android_java_env)->CallIntMethod (android_java_env,
   843                                                  font_driver,
   844                                                  font_driver_class.has_char,
   845                                                  info->object, (jint) c);
   846     }
   847 }
   848 
   849 static unsigned
   850 androidfont_encode_char (struct font *font, int c)
   851 {
   852   struct androidfont_info *info;
   853 
   854   /* Maybe initialize the font driver.  */
   855   androidfont_check_init ();
   856 
   857   info = (struct androidfont_info *) font;
   858 
   859   return (*android_java_env)->CallIntMethod (android_java_env,
   860                                              font_driver,
   861                                              font_driver_class.encode_char,
   862                                              info->object, (jchar) c);
   863 }
   864 
   865 static void
   866 androidfont_cache_text_extents (struct androidfont_info *info,
   867                                 unsigned int glyph,
   868                                 struct font_metrics *metrics)
   869 {
   870   int i;
   871 
   872   /* Glyphs larger than 65535 can't be cached.  */
   873   if (glyph >= 256 * 256)
   874     return;
   875 
   876   if (!info->metrics)
   877     info->metrics = xzalloc (256 * sizeof *info->metrics);
   878 
   879   if (!info->metrics[glyph / 256])
   880     {
   881       info->metrics[glyph / 256]
   882         = xnmalloc (256, sizeof **info->metrics);
   883 
   884       /* Now, all the metrics in that array as invalid by setting
   885          lbearing to SHRT_MAX.  */
   886       for (i = 0; i < 256; ++i)
   887         info->metrics[glyph / 256][i].lbearing = SHRT_MAX;
   888     }
   889 
   890   /* Finally, cache the glyph.  */
   891   info->metrics[glyph / 256][glyph % 256] = *metrics;
   892 }
   893 
   894 static bool
   895 androidfont_check_cached_extents (struct androidfont_info *info,
   896                                   unsigned int glyph,
   897                                   struct font_metrics *metrics)
   898 {
   899   if (info->metrics && info->metrics[glyph / 256]
   900       && info->metrics[glyph / 256][glyph % 256].lbearing != SHRT_MAX)
   901     {
   902       *metrics = info->metrics[glyph / 256][glyph % 256];
   903       return true;
   904     }
   905 
   906   return false;
   907 }
   908 
   909 static void
   910 androidfont_text_extents (struct font *font, const unsigned int *code,
   911                           int nglyphs, struct font_metrics *metrics)
   912 {
   913   struct androidfont_info *info;
   914   jarray codepoint_array;
   915   jobject metrics_object;
   916   short value;
   917 
   918   /* Maybe initialize the font driver.  */
   919   androidfont_check_init ();
   920 
   921   info = (struct androidfont_info *) font;
   922 
   923   if (nglyphs == 1
   924       && androidfont_check_cached_extents (info, *code, metrics))
   925     return;
   926 
   927   /* Allocate the arrays of code points and font metrics.  */
   928   codepoint_array
   929     = (*android_java_env)->NewIntArray (android_java_env,
   930                                         nglyphs);
   931   if (!codepoint_array)
   932     {
   933       (*android_java_env)->ExceptionClear (android_java_env);
   934       memory_full (0);
   935     }
   936 
   937   verify (sizeof (unsigned int) == sizeof (jint));
   938 
   939   /* Always true on every Android device.  */
   940   (*android_java_env)->SetIntArrayRegion (android_java_env,
   941                                           codepoint_array,
   942                                           0, nglyphs,
   943                                           (jint *) code);
   944 
   945   metrics_object
   946     = (*android_java_env)->AllocObject (android_java_env,
   947                                         font_metrics_class.class);
   948 
   949   (*android_java_env)->CallVoidMethod (android_java_env,
   950                                        font_driver,
   951                                        font_driver_class.text_extents,
   952                                        info->object, codepoint_array,
   953                                        metrics_object);
   954 
   955   if ((*android_java_env)->ExceptionCheck (android_java_env))
   956     {
   957       (*android_java_env)->ExceptionClear (android_java_env);
   958       ANDROID_DELETE_LOCAL_REF (metrics_object);
   959       ANDROID_DELETE_LOCAL_REF (codepoint_array);
   960       memory_full (0);
   961     }
   962 
   963 #define DO_CARDINAL_FIELD(field)                                        \
   964   value                                                                 \
   965     = (*android_java_env)->GetShortField (android_java_env,             \
   966                                           metrics_object,               \
   967                                           font_metrics_class.field);    \
   968   metrics->field = value;
   969 
   970   DO_CARDINAL_FIELD (lbearing);
   971   DO_CARDINAL_FIELD (rbearing);
   972   DO_CARDINAL_FIELD (width);
   973   DO_CARDINAL_FIELD (ascent);
   974   DO_CARDINAL_FIELD (descent);
   975 
   976 #undef DO_CARDINAL_FIELD
   977 
   978   ANDROID_DELETE_LOCAL_REF (metrics_object);
   979   ANDROID_DELETE_LOCAL_REF (codepoint_array);
   980 
   981   /* Emacs spends a lot of time in androidfont_text_extents, which
   982      makes calling JNI too slow.  Cache the metrics for this single
   983      glyph.  */
   984 
   985   if (nglyphs == 1)
   986     androidfont_cache_text_extents (info, *code, metrics);
   987 }
   988 
   989 static Lisp_Object
   990 androidfont_list_family (struct frame *f)
   991 {
   992   Lisp_Object families;
   993   jarray family_array;
   994   jobject string;
   995   jsize i, length;
   996   const char *family;
   997 
   998   /* Return if the Android font driver is not initialized.  Loading
   999      every font under Android takes a non trivial amount of memory,
  1000      and is not something that should be done when the user tries to
  1001      list all of the font families.  */
  1002 
  1003   if (!font_driver)
  1004     return Qnil;
  1005 
  1006   family_array
  1007     = (*android_java_env)->CallObjectMethod (android_java_env,
  1008                                              font_driver,
  1009                                              font_driver_class.list_families);
  1010   android_exception_check ();
  1011 
  1012   length = (*android_java_env)->GetArrayLength (android_java_env,
  1013                                                 family_array);
  1014   families = Qnil;
  1015 
  1016   for (i = 0; i < length; ++i)
  1017     {
  1018       string = (*android_java_env)->GetObjectArrayElement (android_java_env,
  1019                                                            family_array, i);
  1020       family = (*android_java_env)->GetStringUTFChars (android_java_env,
  1021                                                        (jstring) string, NULL);
  1022 
  1023       if (!family)
  1024         {
  1025           ANDROID_DELETE_LOCAL_REF (string);
  1026           ANDROID_DELETE_LOCAL_REF (family_array);
  1027         }
  1028 
  1029       families = Fcons (build_string_from_utf8 (string), families);
  1030       (*android_java_env)->ReleaseStringUTFChars (android_java_env,
  1031                                                   (jstring) string,
  1032                                                   family);
  1033       ANDROID_DELETE_LOCAL_REF (string);
  1034     }
  1035 
  1036   ANDROID_DELETE_LOCAL_REF (family_array);
  1037   return Fnreverse (families);
  1038 }
  1039 
  1040 struct font_driver androidfont_driver =
  1041   {
  1042     .type = LISPSYM_INITIALLY (Qandroid),
  1043     .case_sensitive = true,
  1044     .get_cache = androidfont_get_cache,
  1045     .list = androidfont_list,
  1046     .match = androidfont_match,
  1047     .draw = androidfont_draw,
  1048     .open_font = androidfont_open_font,
  1049     .close_font = androidfont_close_font,
  1050     .has_char = androidfont_has_char,
  1051     .encode_char = androidfont_encode_char,
  1052     .text_extents = androidfont_text_extents,
  1053     .list_family = androidfont_list_family,
  1054   };
  1055 
  1056 static void
  1057 syms_of_androidfont_for_pdumper (void)
  1058 {
  1059   register_font_driver (&androidfont_driver, NULL);
  1060 }
  1061 
  1062 void
  1063 syms_of_androidfont (void)
  1064 {
  1065   DEFSYM (Qfontsize, "fontsize");
  1066 
  1067   pdumper_do_now_and_after_load (syms_of_androidfont_for_pdumper);
  1068 
  1069   font_cache = list (Qnil);
  1070   staticpro (&font_cache);
  1071 }
  1072 
  1073 void
  1074 init_androidfont (void)
  1075 {
  1076   if (!android_init_gui)
  1077     return;
  1078 
  1079   android_init_font_driver ();
  1080   android_init_font_spec ();
  1081   android_init_font_metrics ();
  1082   android_init_font_object ();
  1083   android_init_integer ();
  1084 
  1085   /* The Java font driver is not initialized here because it uses a lot
  1086      of memory.  */
  1087 }
  1088 
  1089 void
  1090 android_finalize_font_entity (struct font_entity *entity)
  1091 {
  1092   struct androidfont_entity *info;
  1093 
  1094   info = (struct androidfont_entity *) entity;
  1095 
  1096   if (info->object)
  1097     (*android_java_env)->DeleteGlobalRef (android_java_env,
  1098                                           info->object);
  1099 
  1100   /* Not sure if this can be called twice.  */
  1101   info->object = NULL;
  1102 }
  1103 
  1104 #endif

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