root/src/ftcrfont.c

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

DEFINITIONS

This source file includes following definitions.
  1. ftcrfont_glyph_extents
  2. ftcrfont_list
  3. ftcrfont_match
  4. ftcrfont_open
  5. ftcrfont_close
  6. ftcrfont_has_char
  7. ftcrfont_encode_char
  8. ftcrfont_text_extents
  9. ftcrfont_get_bitmap
  10. ftcrfont_anchor_point
  11. ftcrfont_otf_capability
  12. ftcrfont_shape
  13. ftcrfont_variation_glyphs
  14. ftcrfont_draw
  15. ftcrfont_cached_font_ok
  16. ftcrhbfont_list
  17. ftcrhbfont_match
  18. ftcrhbfont_begin_hb_font
  19. ftcrhbfont_end_hb_font
  20. syms_of_ftcrfont
  21. ftcrfont_get_default_font_options
  22. syms_of_ftcrfont_for_pdumper

     1 /* ftcrfont.c -- FreeType font driver on cairo.
     2    Copyright (C) 2015-2023 Free Software Foundation, Inc.
     3 
     4 This file is part of GNU Emacs.
     5 
     6 GNU Emacs is free software: you can redistribute it and/or modify
     7 it under the terms of the GNU General Public License as published by
     8 the Free Software Foundation, either version 3 of the License, or (at
     9 your option) any later version.
    10 
    11 GNU Emacs is distributed in the hope that it will be useful,
    12 but WITHOUT ANY WARRANTY; without even the implied warranty of
    13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    14 GNU General Public License for more details.
    15 
    16 You should have received a copy of the GNU General Public License
    17 along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
    18 
    19 
    20 #include <config.h>
    21 #include <math.h>
    22 #include <cairo-ft.h>
    23 
    24 #include "lisp.h"
    25 #ifdef HAVE_X_WINDOWS
    26 #include "xterm.h"
    27 #elif HAVE_HAIKU
    28 #include "haikuterm.h"
    29 #include "haiku_support.h"
    30 #include "termchar.h"
    31 #else
    32 #include "pgtkterm.h"
    33 #endif
    34 #include "blockinput.h"
    35 #include "charset.h"
    36 #include "composite.h"
    37 #include "font.h"
    38 #include "ftfont.h"
    39 #include "pdumper.h"
    40 #ifdef HAVE_PGTK
    41 #include "xsettings.h"
    42 #endif
    43 
    44 #ifdef USE_BE_CAIRO
    45 #define RED_FROM_ULONG(color)   (((color) >> 16) & 0xff)
    46 #define GREEN_FROM_ULONG(color) (((color) >> 8) & 0xff)
    47 #define BLUE_FROM_ULONG(color)  ((color) & 0xff)
    48 #endif
    49 
    50 #define METRICS_NCOLS_PER_ROW   (128)
    51 
    52 enum metrics_status
    53   {
    54     METRICS_INVALID = -1,    /* metrics entry is invalid */
    55   };
    56 
    57 #define METRICS_STATUS(metrics) ((metrics)->ascent + (metrics)->descent)
    58 #define METRICS_SET_STATUS(metrics, status) \
    59   ((metrics)->ascent = 0, (metrics)->descent = (status))
    60 
    61 static int
    62 ftcrfont_glyph_extents (struct font *font,
    63                         unsigned glyph,
    64                         struct font_metrics *metrics)
    65 {
    66   struct font_info *ftcrfont_info = (struct font_info *) font;
    67   int row, col;
    68   struct font_metrics *cache;
    69 
    70   row = glyph / METRICS_NCOLS_PER_ROW;
    71   col = glyph % METRICS_NCOLS_PER_ROW;
    72   if (row >= ftcrfont_info->metrics_nrows)
    73     {
    74       ftcrfont_info->metrics =
    75         xrealloc (ftcrfont_info->metrics,
    76                   sizeof (struct font_metrics *) * (row + 1));
    77       memset (ftcrfont_info->metrics + ftcrfont_info->metrics_nrows, 0,
    78               (sizeof (struct font_metrics *)
    79                * (row + 1 - ftcrfont_info->metrics_nrows)));
    80       ftcrfont_info->metrics_nrows = row + 1;
    81     }
    82   if (ftcrfont_info->metrics[row] == NULL)
    83     {
    84       struct font_metrics *new;
    85       int i;
    86 
    87       new = xmalloc (sizeof (struct font_metrics) * METRICS_NCOLS_PER_ROW);
    88       for (i = 0; i < METRICS_NCOLS_PER_ROW; i++)
    89         METRICS_SET_STATUS (new + i, METRICS_INVALID);
    90       ftcrfont_info->metrics[row] = new;
    91     }
    92   cache = ftcrfont_info->metrics[row] + col;
    93 
    94   if (METRICS_STATUS (cache) == METRICS_INVALID)
    95     {
    96       cairo_glyph_t cr_glyph = {.index = glyph};
    97       cairo_text_extents_t extents;
    98 
    99       cairo_scaled_font_glyph_extents (ftcrfont_info->cr_scaled_font,
   100                                        &cr_glyph, 1, &extents);
   101       cache->lbearing = floor (extents.x_bearing);
   102       cache->rbearing = ceil (extents.width + extents.x_bearing);
   103       cache->width = lround (extents.x_advance);
   104       /* The subtraction of a small number is to avoid rounding up due
   105          to floating-point inaccuracies with some fonts, which then
   106          could cause unpleasant effects while scrolling (see bug
   107          #44284), since we then think that a glyph row's ascent is too
   108          small to accommodate a glyph with a higher phys_ascent.  */
   109       cache->ascent = ceil (- extents.y_bearing - 1.0 / 256);
   110       cache->descent = ceil (extents.height + extents.y_bearing);
   111     }
   112 
   113   if (metrics)
   114     *metrics = *cache;
   115 
   116   return cache->width;
   117 }
   118 
   119 static Lisp_Object
   120 ftcrfont_list (struct frame *f, Lisp_Object spec)
   121 {
   122   return ftfont_list2 (f, spec, Qftcr);
   123 }
   124 
   125 static Lisp_Object
   126 ftcrfont_match (struct frame *f, Lisp_Object spec)
   127 {
   128   return ftfont_match2 (f, spec, Qftcr);
   129 }
   130 
   131 static Lisp_Object
   132 ftcrfont_open (struct frame *f, Lisp_Object entity, int pixel_size)
   133 {
   134   FcResult result;
   135   Lisp_Object val, filename, font_object;
   136   FcPattern *pat, *match;
   137   struct font_info *ftcrfont_info;
   138   struct font *font;
   139   double size = 0;
   140   cairo_font_face_t *font_face;
   141   cairo_font_extents_t extents;
   142   FT_Face ft_face;
   143   FcMatrix *matrix;
   144 
   145   val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
   146   if (! CONSP (val))
   147     return Qnil;
   148   val = XCDR (val);
   149   filename = XCAR (val);
   150   size = XFIXNUM (AREF (entity, FONT_SIZE_INDEX));
   151   if (size == 0)
   152     size = pixel_size;
   153 
   154   block_input ();
   155 
   156   pat = ftfont_entity_pattern (entity, pixel_size);
   157   FcConfigSubstitute (NULL, pat, FcMatchPattern);
   158   FcDefaultSubstitute (pat);
   159   match = FcFontMatch (NULL, pat, &result);
   160   ftfont_fix_match (pat, match);
   161 
   162   FcPatternDestroy (pat);
   163   font_face = cairo_ft_font_face_create_for_pattern (match);
   164   if (!font_face
   165       || cairo_font_face_status (font_face) != CAIRO_STATUS_SUCCESS)
   166     {
   167       unblock_input ();
   168       FcPatternDestroy (match);
   169       return Qnil;
   170     }
   171   cairo_matrix_t font_matrix, ctm;
   172   cairo_matrix_init_scale (&font_matrix, pixel_size, pixel_size);
   173   cairo_matrix_init_identity (&ctm);
   174 
   175 #ifdef HAVE_PGTK
   176   cairo_font_options_t *options = xsettings_get_font_options ();
   177 #else
   178   cairo_font_options_t *options = cairo_font_options_create ();
   179 #endif
   180 #ifdef USE_BE_CAIRO
   181   if (be_use_subpixel_antialiasing ())
   182     cairo_font_options_set_antialias (options, CAIRO_ANTIALIAS_SUBPIXEL);
   183 #endif
   184   cairo_scaled_font_t *scaled_font
   185     = cairo_scaled_font_create (font_face, &font_matrix, &ctm, options);
   186   cairo_font_face_destroy (font_face);
   187   cairo_font_options_destroy (options);
   188   unblock_input ();
   189   if (!scaled_font
   190       || cairo_scaled_font_status (scaled_font) != CAIRO_STATUS_SUCCESS)
   191     {
   192       FcPatternDestroy (match);
   193       return Qnil;
   194     }
   195   ft_face = cairo_ft_scaled_font_lock_face (scaled_font);
   196   if (!ft_face)
   197     {
   198       FcPatternDestroy (match);
   199       return Qnil;
   200     }
   201 
   202   font_object = font_build_object (VECSIZE (struct font_info),
   203                                    AREF (entity, FONT_TYPE_INDEX),
   204                                    entity, size);
   205   ASET (font_object, FONT_FILE_INDEX, filename);
   206   font = XFONT_OBJECT (font_object);
   207   font->pixel_size = size;
   208 #ifdef HAVE_HARFBUZZ
   209   if (EQ (AREF (font_object, FONT_TYPE_INDEX), Qftcrhb))
   210     font->driver = &ftcrhbfont_driver;
   211   else
   212 #endif  /* HAVE_HARFBUZZ */
   213   font->driver = &ftcrfont_driver;
   214   font->encoding_charset = font->repertory_charset = -1;
   215 
   216   ftcrfont_info = (struct font_info *) font;
   217   ftcrfont_info->cr_scaled_font = scaled_font;
   218 
   219   /* This means that there's no need of transformation.  */
   220   ftcrfont_info->matrix.xx = 0;
   221   if (FcPatternGetMatrix (match, FC_MATRIX, 0, &matrix) == FcResultMatch)
   222     {
   223       ftcrfont_info->matrix.xx = 0x10000L * matrix->xx;
   224       ftcrfont_info->matrix.yy = 0x10000L * matrix->yy;
   225       ftcrfont_info->matrix.xy = 0x10000L * matrix->xy;
   226       ftcrfont_info->matrix.yx = 0x10000L * matrix->yx;
   227     }
   228 
   229   ftcrfont_info->metrics = NULL;
   230   ftcrfont_info->metrics_nrows = 0;
   231 
   232   block_input ();
   233   cairo_glyph_t stack_glyph;
   234   font->min_width = font->max_width = 0;
   235   font->average_width = font->space_width = 0;
   236   int n = 0;
   237   for (char c = 32; c < 127; c++)
   238     {
   239       cairo_glyph_t *glyphs = &stack_glyph;
   240       int num_glyphs = 1;
   241       cairo_status_t status =
   242         cairo_scaled_font_text_to_glyphs (ftcrfont_info->cr_scaled_font,
   243                                           0, 0, &c, 1, &glyphs, &num_glyphs,
   244                                           NULL, NULL, NULL);
   245 
   246       /* In order to simulate the Xft behavior, we use metrics of
   247          glyph ID 0 if there is no glyph for an ASCII printable.  */
   248       if (status != CAIRO_STATUS_SUCCESS)
   249         stack_glyph.index = 0;
   250       else if (glyphs != &stack_glyph)
   251         {
   252           cairo_glyph_free (glyphs);
   253           stack_glyph.index = 0;
   254         }
   255       int this_width = ftcrfont_glyph_extents (font, stack_glyph.index, NULL);
   256       if (this_width > 0)
   257         {
   258           if (! font->min_width || font->min_width > this_width)
   259             font->min_width = this_width;
   260           if (this_width > font->max_width)
   261             font->max_width = this_width;
   262           if (c == 32)
   263             font->space_width = this_width;
   264           font->average_width += this_width;
   265           n++;
   266         }
   267     }
   268   if (n)
   269     font->average_width /= n;
   270 
   271   cairo_scaled_font_extents (ftcrfont_info->cr_scaled_font, &extents);
   272   font->ascent = lround (extents.ascent);
   273   val = assq_no_quit (QCminspace, AREF (entity, FONT_EXTRA_INDEX));
   274   if (!(CONSP (val) && NILP (XCDR (val))))
   275     {
   276       font->descent = lround (extents.descent);
   277       font->height = font->ascent + font->descent;
   278     }
   279   else
   280     {
   281       font->height = lround (extents.height);
   282       font->descent = font->height - font->ascent;
   283     }
   284 
   285   if (XFIXNUM (AREF (entity, FONT_SIZE_INDEX)) == 0)
   286     {
   287       int upEM = ft_face->units_per_EM;
   288 
   289       font->underline_position = -ft_face->underline_position * size / upEM;
   290       font->underline_thickness = ft_face->underline_thickness * size / upEM;
   291       if (font->underline_thickness > 2)
   292         font->underline_position -= font->underline_thickness / 2;
   293     }
   294   else
   295     {
   296       font->underline_position = -1;
   297       font->underline_thickness = 0;
   298     }
   299 #ifdef HAVE_LIBOTF
   300   ftcrfont_info->maybe_otf = (ft_face->face_flags & FT_FACE_FLAG_SFNT) != 0;
   301   ftcrfont_info->otf = NULL;
   302 #endif  /* HAVE_LIBOTF */
   303 #ifdef HAVE_HARFBUZZ
   304   ftcrfont_info->hb_font = NULL;
   305 #endif  /* HAVE_HARFBUZZ */
   306   if (ft_face->units_per_EM)
   307     ftcrfont_info->bitmap_position_unit = 0;
   308   else
   309     ftcrfont_info->bitmap_position_unit = (extents.height
   310                                            / ft_face->size->metrics.height);
   311   cairo_ft_scaled_font_unlock_face (scaled_font);
   312   ftcrfont_info->ft_size = NULL;
   313   unblock_input ();
   314 
   315   font->baseline_offset = 0;
   316   font->relative_compose = 0;
   317   font->default_ascent = 0;
   318   font->vertical_centering = false;
   319   eassert (font->max_width < 512 * 1024 * 1024);
   320 
   321   return font_object;
   322 }
   323 
   324 static void
   325 ftcrfont_close (struct font *font)
   326 {
   327   if (font_data_structures_may_be_ill_formed ())
   328     return;
   329 
   330   struct font_info *ftcrfont_info = (struct font_info *) font;
   331 
   332   block_input ();
   333 #ifdef HAVE_LIBOTF
   334   if (ftcrfont_info->otf)
   335     {
   336       OTF_close (ftcrfont_info->otf);
   337       ftcrfont_info->otf = NULL;
   338     }
   339 #endif
   340 #ifdef HAVE_HARFBUZZ
   341   if (ftcrfont_info->hb_font)
   342     {
   343       hb_font_destroy (ftcrfont_info->hb_font);
   344       ftcrfont_info->hb_font = NULL;
   345     }
   346 #endif
   347   for (int i = 0; i < ftcrfont_info->metrics_nrows; i++)
   348     if (ftcrfont_info->metrics[i])
   349       xfree (ftcrfont_info->metrics[i]);
   350   if (ftcrfont_info->metrics)
   351     xfree (ftcrfont_info->metrics);
   352   cairo_scaled_font_destroy (ftcrfont_info->cr_scaled_font);
   353   unblock_input ();
   354 }
   355 
   356 static int
   357 ftcrfont_has_char (Lisp_Object font, int c)
   358 {
   359   if (FONT_ENTITY_P (font))
   360     return ftfont_has_char (font, c);
   361 
   362   struct charset *cs = NULL;
   363 
   364   if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qja)
   365       && charset_jisx0208 >= 0)
   366     cs = CHARSET_FROM_ID (charset_jisx0208);
   367   else if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qko)
   368       && charset_ksc5601 >= 0)
   369     cs = CHARSET_FROM_ID (charset_ksc5601);
   370   if (cs)
   371     return (ENCODE_CHAR (cs, c) != CHARSET_INVALID_CODE (cs));
   372 
   373   return -1;
   374 }
   375 
   376 static unsigned
   377 ftcrfont_encode_char (struct font *font, int c)
   378 {
   379   struct font_info *ftcrfont_info = (struct font_info *) font;
   380   unsigned code = FONT_INVALID_CODE;
   381   unsigned char utf8[MAX_MULTIBYTE_LENGTH];
   382   int utf8len = CHAR_STRING (c, utf8);
   383   cairo_glyph_t stack_glyph;
   384   cairo_glyph_t *glyphs = &stack_glyph;
   385   int num_glyphs = 1;
   386 
   387   if (cairo_scaled_font_text_to_glyphs (ftcrfont_info->cr_scaled_font, 0, 0,
   388                                         (char *) utf8, utf8len,
   389                                         &glyphs, &num_glyphs,
   390                                         NULL, NULL, NULL)
   391       == CAIRO_STATUS_SUCCESS)
   392     {
   393       if (glyphs != &stack_glyph)
   394         cairo_glyph_free (glyphs);
   395       else if (stack_glyph.index)
   396         code = stack_glyph.index;
   397     }
   398 
   399   return code;
   400 }
   401 
   402 static void
   403 ftcrfont_text_extents (struct font *font,
   404                        const unsigned *code,
   405                        int nglyphs,
   406                        struct font_metrics *metrics)
   407 {
   408   int width, i;
   409 
   410   block_input ();
   411   width = ftcrfont_glyph_extents (font, code[0], metrics);
   412   for (i = 1; i < nglyphs; i++)
   413     {
   414       struct font_metrics m;
   415       int w = ftcrfont_glyph_extents (font, code[i], metrics ? &m : NULL);
   416 
   417       if (metrics)
   418         {
   419           if (width + m.lbearing < metrics->lbearing)
   420             metrics->lbearing = width + m.lbearing;
   421           if (width + m.rbearing > metrics->rbearing)
   422             metrics->rbearing = width + m.rbearing;
   423           if (m.ascent > metrics->ascent)
   424             metrics->ascent = m.ascent;
   425           if (m.descent > metrics->descent)
   426             metrics->descent = m.descent;
   427         }
   428       width += w;
   429     }
   430   unblock_input ();
   431 
   432   if (metrics)
   433     metrics->width = width;
   434 }
   435 
   436 static int
   437 ftcrfont_get_bitmap (struct font *font, unsigned int code,
   438                      struct font_bitmap *bitmap, int bits_per_pixel)
   439 {
   440   struct font_info *ftcrfont_info = (struct font_info *) font;
   441 
   442   if (ftcrfont_info->bitmap_position_unit)
   443     return -1;
   444 
   445   cairo_scaled_font_t *scaled_font = ftcrfont_info->cr_scaled_font;
   446   FT_Face ft_face = cairo_ft_scaled_font_lock_face (scaled_font);
   447 
   448   ftcrfont_info->ft_size = ft_face->size;
   449   int result = ftfont_get_bitmap (font, code, bitmap, bits_per_pixel);
   450   cairo_ft_scaled_font_unlock_face (scaled_font);
   451   ftcrfont_info->ft_size = NULL;
   452 
   453   return result;
   454 }
   455 
   456 static int
   457 ftcrfont_anchor_point (struct font *font, unsigned int code, int idx,
   458                        int *x, int *y)
   459 {
   460   struct font_info *ftcrfont_info = (struct font_info *) font;
   461 
   462   if (ftcrfont_info->bitmap_position_unit)
   463     return -1;
   464 
   465   cairo_scaled_font_t *scaled_font = ftcrfont_info->cr_scaled_font;
   466   FT_Face ft_face = cairo_ft_scaled_font_lock_face (scaled_font);
   467 
   468   ftcrfont_info->ft_size = ft_face->size;
   469   int result = ftfont_anchor_point (font, code, idx, x, y);
   470   cairo_ft_scaled_font_unlock_face (scaled_font);
   471   ftcrfont_info->ft_size = NULL;
   472 
   473   return result;
   474 }
   475 
   476 #ifdef HAVE_LIBOTF
   477 static Lisp_Object
   478 ftcrfont_otf_capability (struct font *font)
   479 {
   480   struct font_info *ftcrfont_info = (struct font_info *) font;
   481   cairo_scaled_font_t *scaled_font = ftcrfont_info->cr_scaled_font;
   482   FT_Face ft_face = cairo_ft_scaled_font_lock_face (scaled_font);
   483 
   484   ftcrfont_info->ft_size = ft_face->size;
   485   Lisp_Object result = ftfont_otf_capability (font);
   486   cairo_ft_scaled_font_unlock_face (scaled_font);
   487   ftcrfont_info->ft_size = NULL;
   488 
   489   return result;
   490 }
   491 #endif
   492 
   493 #if defined HAVE_M17N_FLT && defined HAVE_LIBOTF
   494 static Lisp_Object
   495 ftcrfont_shape (Lisp_Object lgstring, Lisp_Object direction)
   496 {
   497   struct font *font = CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring));
   498   struct font_info *ftcrfont_info = (struct font_info *) font;
   499 
   500   if (ftcrfont_info->bitmap_position_unit)
   501     return make_fixnum (0);
   502 
   503   cairo_scaled_font_t *scaled_font = ftcrfont_info->cr_scaled_font;
   504   FT_Face ft_face = cairo_ft_scaled_font_lock_face (scaled_font);
   505 
   506   ftcrfont_info->ft_size = ft_face->size;
   507   Lisp_Object result = ftfont_shape (lgstring, direction);
   508   cairo_ft_scaled_font_unlock_face (scaled_font);
   509   ftcrfont_info->ft_size = NULL;
   510 
   511   return result;
   512 }
   513 #endif
   514 
   515 #if defined HAVE_OTF_GET_VARIATION_GLYPHS || defined HAVE_FT_FACE_GETCHARVARIANTINDEX
   516 static int
   517 ftcrfont_variation_glyphs (struct font *font, int c, unsigned variations[256])
   518 {
   519   struct font_info *ftcrfont_info = (struct font_info *) font;
   520   cairo_scaled_font_t *scaled_font = ftcrfont_info->cr_scaled_font;
   521   FT_Face ft_face = cairo_ft_scaled_font_lock_face (scaled_font);
   522 
   523   ftcrfont_info->ft_size = ft_face->size;
   524   int result = ftfont_variation_glyphs (font, c, variations);
   525   cairo_ft_scaled_font_unlock_face (scaled_font);
   526   ftcrfont_info->ft_size = NULL;
   527 
   528   return result;
   529 }
   530 #endif  /* HAVE_OTF_GET_VARIATION_GLYPHS || HAVE_FT_FACE_GETCHARVARIANTINDEX */
   531 
   532 static int
   533 ftcrfont_draw (struct glyph_string *s,
   534                int from, int to, int x, int y, bool with_background)
   535 {
   536   struct frame *f = s->f;
   537   struct font_info *ftcrfont_info = (struct font_info *) s->font;
   538   cairo_t *cr;
   539   cairo_glyph_t *glyphs;
   540   int len = to - from;
   541   int i;
   542 #ifdef USE_BE_CAIRO
   543   unsigned long be_foreground, be_background;
   544 
   545   if (s->hl != DRAW_CURSOR)
   546     {
   547       be_foreground = s->face->foreground;
   548       be_background = s->face->background;
   549     }
   550   else
   551     haiku_merge_cursor_foreground (s, &be_foreground,
   552                                    &be_background);
   553 #endif
   554 
   555   block_input ();
   556 
   557 #ifndef USE_BE_CAIRO
   558 #ifdef HAVE_X_WINDOWS
   559   cr = x_begin_cr_clip (f, s->gc);
   560 #else
   561   cr = pgtk_begin_cr_clip (f);
   562 #endif
   563 #else
   564   /* Presumably the draw lock is already held by
   565      haiku_draw_glyph_string.  */
   566   EmacsWindow_begin_cr_critical_section (FRAME_HAIKU_WINDOW (f));
   567   cr = haiku_begin_cr_clip (f, s);
   568   if (!cr)
   569     {
   570       EmacsWindow_end_cr_critical_section (FRAME_HAIKU_WINDOW (f));
   571       unblock_input ();
   572       return 0;
   573     }
   574   BView_cr_dump_clipping (FRAME_HAIKU_DRAWABLE (f), cr);
   575 #endif
   576 
   577   if (with_background)
   578     {
   579 #ifndef USE_BE_CAIRO
   580 #ifdef HAVE_X_WINDOWS
   581       x_set_cr_source_with_gc_background (f, s->gc, s->hl != DRAW_CURSOR);
   582 #else
   583       pgtk_set_cr_source_with_color (f, s->xgcv.background,
   584                                      s->hl != DRAW_CURSOR);
   585 #endif
   586 #else
   587       uint32_t col = be_background;
   588 
   589       cairo_set_source_rgb (cr, RED_FROM_ULONG (col) / 255.0,
   590                             GREEN_FROM_ULONG (col) / 255.0,
   591                             BLUE_FROM_ULONG (col) / 255.0);
   592 #endif
   593       cairo_rectangle (cr, x, y - FONT_BASE (s->font),
   594                        s->width, FONT_HEIGHT (s->font));
   595       cairo_fill (cr);
   596     }
   597 
   598   glyphs = alloca (sizeof (cairo_glyph_t) * len);
   599   for (i = 0; i < len; i++)
   600     {
   601       glyphs[i].index = s->char2b[from + i];
   602       glyphs[i].x = x;
   603       glyphs[i].y = y;
   604       x += (s->padding_p ? 1 : ftcrfont_glyph_extents (s->font,
   605                                                        glyphs[i].index,
   606                                                        NULL));
   607     }
   608 #ifndef USE_BE_CAIRO
   609 #ifdef HAVE_X_WINDOWS
   610   x_set_cr_source_with_gc_foreground (f, s->gc, false);
   611 #else
   612   pgtk_set_cr_source_with_color (f, s->xgcv.foreground, false);
   613 #endif
   614 #else
   615   uint32_t col = be_foreground;
   616 
   617   cairo_set_source_rgb (cr, RED_FROM_ULONG (col) / 255.0,
   618                         GREEN_FROM_ULONG (col) / 255.0,
   619                         BLUE_FROM_ULONG (col) / 255.0);
   620 #endif
   621   cairo_set_scaled_font (cr, ftcrfont_info->cr_scaled_font);
   622   cairo_show_glyphs (cr, glyphs, len);
   623 #ifndef USE_BE_CAIRO
   624 #ifdef HAVE_X_WINDOWS
   625   x_end_cr_clip (f);
   626 #else
   627   pgtk_end_cr_clip (f);
   628 #endif
   629 #else
   630   haiku_end_cr_clip (cr);
   631   EmacsWindow_end_cr_critical_section (FRAME_HAIKU_WINDOW (f));
   632 #endif
   633   unblock_input ();
   634 
   635   return len;
   636 }
   637 
   638 #ifdef HAVE_PGTK
   639 /* Determine if FONT_OBJECT is a valid cached font for ENTITY by
   640    comparing the options used to open it with the user's current
   641    preferences specified via GSettings.  */
   642 static bool
   643 ftcrfont_cached_font_ok (struct frame *f, Lisp_Object font_object,
   644                          Lisp_Object entity)
   645 {
   646   struct font_info *info = (struct font_info *) XFONT_OBJECT (font_object);
   647 
   648   cairo_font_options_t *options = cairo_font_options_create ();
   649   cairo_scaled_font_get_font_options (info->cr_scaled_font, options);
   650   cairo_font_options_t *gsettings_options = xsettings_get_font_options ();
   651 
   652   bool equal = cairo_font_options_equal (options, gsettings_options);
   653   cairo_font_options_destroy (options);
   654   cairo_font_options_destroy (gsettings_options);
   655 
   656   return equal;
   657 }
   658 #endif
   659 
   660 #ifdef HAVE_HARFBUZZ
   661 
   662 static Lisp_Object
   663 ftcrhbfont_list (struct frame *f, Lisp_Object spec)
   664 {
   665   return ftfont_list2 (f, spec, Qftcrhb);
   666 }
   667 
   668 static Lisp_Object
   669 ftcrhbfont_match (struct frame *f, Lisp_Object spec)
   670 {
   671   return ftfont_match2 (f, spec, Qftcrhb);
   672 }
   673 
   674 static hb_font_t *
   675 ftcrhbfont_begin_hb_font (struct font *font, double *position_unit)
   676 {
   677   struct font_info *ftcrfont_info = (struct font_info *) font;
   678   cairo_scaled_font_t *scaled_font = ftcrfont_info->cr_scaled_font;
   679   FT_Face ft_face = cairo_ft_scaled_font_lock_face (scaled_font);
   680 
   681   ftcrfont_info->ft_size = ft_face->size;
   682   hb_font_t *hb_font = fthbfont_begin_hb_font (font, position_unit);
   683   /* HarfBuzz 5 correctly scales bitmap-only fonts without position
   684      unit adjustment.
   685      (https://github.com/harfbuzz/harfbuzz/issues/489)
   686 
   687      Update: HarfBuzz 5.2.0 no longer does this for an hb_font_t font
   688      object created from a given FT_Face.
   689      (https://github.com/harfbuzz/harfbuzz/issues/3788) */
   690   if ((hb_version_atleast (5, 2, 0) || !hb_version_atleast (5, 0, 0))
   691       && ftcrfont_info->bitmap_position_unit)
   692     *position_unit = ftcrfont_info->bitmap_position_unit;
   693 
   694   return hb_font;
   695 }
   696 
   697 static void
   698 ftcrhbfont_end_hb_font (struct font *font, hb_font_t *hb_font)
   699 {
   700   struct font_info *ftcrfont_info = (struct font_info *) font;
   701   cairo_scaled_font_t *scaled_font = ftcrfont_info->cr_scaled_font;
   702 
   703   cairo_ft_scaled_font_unlock_face (scaled_font);
   704   ftcrfont_info->ft_size = NULL;
   705 }
   706 
   707 #endif  /* HAVE_HARFBUZZ */
   708 
   709 
   710 static void syms_of_ftcrfont_for_pdumper (void);
   711 
   712 struct font_driver const ftcrfont_driver =
   713   {
   714   .type = LISPSYM_INITIALLY (Qftcr),
   715   .get_cache = ftfont_get_cache,
   716   .list = ftcrfont_list,
   717   .match = ftcrfont_match,
   718   .list_family = ftfont_list_family,
   719   .open_font = ftcrfont_open,
   720   .close_font = ftcrfont_close,
   721   .has_char = ftcrfont_has_char,
   722   .encode_char = ftcrfont_encode_char,
   723   .text_extents = ftcrfont_text_extents,
   724   .draw = ftcrfont_draw,
   725   .get_bitmap = ftcrfont_get_bitmap,
   726   .anchor_point = ftcrfont_anchor_point,
   727 #ifdef HAVE_LIBOTF
   728   .otf_capability = ftcrfont_otf_capability,
   729 #endif
   730 #if defined HAVE_M17N_FLT && defined HAVE_LIBOTF
   731   .shape = ftcrfont_shape,
   732 #endif
   733 #if defined HAVE_OTF_GET_VARIATION_GLYPHS || defined HAVE_FT_FACE_GETCHARVARIANTINDEX
   734   .get_variation_glyphs = ftcrfont_variation_glyphs,
   735 #endif
   736   .filter_properties = ftfont_filter_properties,
   737   .combining_capability = ftfont_combining_capability,
   738 #ifdef HAVE_PGTK
   739   .cached_font_ok = ftcrfont_cached_font_ok,
   740 #endif
   741   };
   742 #ifdef HAVE_HARFBUZZ
   743 struct font_driver ftcrhbfont_driver;
   744 #endif  /* HAVE_HARFBUZZ */
   745 
   746 void
   747 syms_of_ftcrfont (void)
   748 {
   749   DEFSYM (Qftcr, "ftcr");
   750 #ifdef HAVE_HARFBUZZ
   751   DEFSYM (Qftcrhb, "ftcrhb");
   752   Fput (Qftcr, Qfont_driver_superseded_by, Qftcrhb);
   753 #endif  /* HAVE_HARFBUZZ */
   754   pdumper_do_now_and_after_load (syms_of_ftcrfont_for_pdumper);
   755 }
   756 
   757 #ifdef HAVE_X_WINDOWS
   758 
   759 /* Place the default font options used by Cairo on the given display
   760    in OPTIONS.  */
   761 
   762 void
   763 ftcrfont_get_default_font_options (struct x_display_info *dpyinfo,
   764                                    cairo_font_options_t *options)
   765 {
   766   Pixmap drawable;
   767   cairo_surface_t *surface;
   768 
   769   /* Cairo doesn't allow fetching the default font options for a
   770      display, so the only option is to create a drawable, and an Xlib
   771      surface for that drawable, and to get the font options from there
   772      instead.  */
   773 
   774   drawable = XCreatePixmap (dpyinfo->display, dpyinfo->root_window,
   775                             1, 1, dpyinfo->n_planes);
   776   surface = cairo_xlib_surface_create (dpyinfo->display, drawable,
   777                                        dpyinfo->visual, 1, 1);
   778 
   779   if (!surface)
   780     {
   781       XFreePixmap (dpyinfo->display, drawable);
   782       return;
   783     }
   784 
   785   cairo_surface_get_font_options (surface, options);
   786   XFreePixmap (dpyinfo->display, drawable);
   787   cairo_surface_destroy (surface);
   788   return;
   789 }
   790 
   791 #endif
   792 
   793 static void
   794 syms_of_ftcrfont_for_pdumper (void)
   795 {
   796   register_font_driver (&ftcrfont_driver, NULL);
   797 #ifdef HAVE_HARFBUZZ
   798   ftcrhbfont_driver = ftcrfont_driver;
   799   ftcrhbfont_driver.type = Qftcrhb;
   800   ftcrhbfont_driver.list = ftcrhbfont_list;
   801   ftcrhbfont_driver.match = ftcrhbfont_match;
   802   ftcrhbfont_driver.otf_capability = hbfont_otf_capability;
   803   ftcrhbfont_driver.shape = hbfont_shape;
   804   ftcrhbfont_driver.combining_capability = hbfont_combining_capability;
   805   ftcrhbfont_driver.begin_hb_font = ftcrhbfont_begin_hb_font;
   806   ftcrhbfont_driver.end_hb_font = ftcrhbfont_end_hb_font;
   807   register_font_driver (&ftcrhbfont_driver, NULL);
   808 #endif  /* HAVE_HARFBUZZ */
   809 }

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