]> git.eshelyaron.com Git - emacs.git/commitdiff
Make Cairo build obey hint-style font setting (Bug#35781)
authorYAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp>
Thu, 23 May 2019 01:30:59 +0000 (10:30 +0900)
committerYAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp>
Thu, 23 May 2019 01:30:59 +0000 (10:30 +0900)
* src/ftfont.h (ftfont_open2): Remove extern.
(ftfont_fix_match, ftfont_add_rendering_parameters)
(ftfont_entity_pattern): Add externs.
(struct font_info): Remove member bitmap_strike_index.
(struct font_info) [USE_CAIRO]: Remove member ft_size_draw.  All uses removed.
Add member bitmap_position_unit.

* src/xftfont.c (xftfont_fix_match, xftfont_add_rendering_parameters): Move
functions from here ...
* src/ftfont.c (ftfont_fix_match, ftfont_add_rendering_parameters): ... to
here.  All uses changed.
* src/xftfont.c (xftfont_open): Extract FcPattern creation from font entity
from here ...
* src/ftfont.c (ftfont_entity_pattern): ... to here.
* src/xftfont.c (syms_of_xftfont): Move DEFSYMs for Fontconfig's rendering
parameters from here ...
* src/ftfont.c (syms_of_ftfont): ... to here.

* src/ftfont.c (ftfont_open, ftfont_open2): Undo introduction of
bitmap_strike_index.  Merge functions into ftfont_open.

* src/ftcrfont.c (ftcrfont_open): Align code with xftfont_open rather than
ftfont_open.
(ftcrfont_close): Likewise.
(ftcrfont_has_char, ftcrfont_encode_char):
(ftcrfont_otf_capability) [HAVE_LIBOTF]:
(ftcrfont_variation_glyphs) [HAVE_OTF_GET_VARIATION_GLYPHS]: New functions.
(ftcrfont_driver): Register them.
(ftcrfont_get_bitmap, ftcrfont_anchor_point):
(ftcrfont_shape) [HAVE_M17N_FLT && HAVE_LIBOTF]: Use bitmap_position_unit
instead of bitmap_strike_index to screen bitmap fonts.
(ftcrfont_get_bitmap, ftcrfont_anchor_point):
(ftcrfont_otf_capability) [HAVE_LIBOTF]:
(ftcrfont_shape) [HAVE_M17N_FLT && HAVE_LIBOTF]:
(ftcrfont_variation_glyphs) [HAVE_OTF_GET_VARIATION_GLYPHS]: Temporarily
assign ftcrfont_info->ft_size and call corresponding ftfont functions.
(ftcrfont_draw): Don't flush cairo surface when exporting.

src/ftcrfont.c
src/ftfont.c
src/ftfont.h
src/xftfont.c

index 2d5a7665578fe23cb2a15555be287adde2f30178..9686cec0e8c6d4db7bf0a0c8915bd54d104eaa5a 100644 (file)
@@ -79,7 +79,6 @@ ftcrfont_glyph_extents (struct font *font,
       cairo_glyph_t cr_glyph = {.index = glyph};
       cairo_text_extents_t extents;
 
-      FT_Activate_Size (ftcrfont_info->ft_size_draw);
       cairo_scaled_font_glyph_extents (ftcrfont_info->cr_scaled_font,
                                       &cr_glyph, 1, &extents);
       cache->lbearing = floor (extents.x_bearing);
@@ -118,103 +117,159 @@ ftcrfont_match (struct frame *f, Lisp_Object spec)
 static Lisp_Object
 ftcrfont_open (struct frame *f, Lisp_Object entity, int pixel_size)
 {
-  Lisp_Object font_object;
-
-  FT_UInt size = XFIXNUM (AREF (entity, FONT_SIZE_INDEX));
+  FcResult result;
+  Lisp_Object val, filename, font_object;
+  FcPattern *pat, *match;
+  struct font_info *ftcrfont_info;
+  struct font *font;
+  double size = 0;
+  cairo_font_face_t *font_face;
+  cairo_font_extents_t extents;
+  FT_Face ft_face;
+  FcMatrix *matrix;
+
+  val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
+  if (! CONSP (val))
+    return Qnil;
+  val = XCDR (val);
+  filename = XCAR (val);
+  size = XFIXNUM (AREF (entity, FONT_SIZE_INDEX));
   if (size == 0)
     size = pixel_size;
+
+  block_input ();
+
+  pat = ftfont_entity_pattern (entity, pixel_size);
+  FcConfigSubstitute (NULL, pat, FcMatchPattern);
+  FcDefaultSubstitute (pat);
+  match = FcFontMatch (NULL, pat, &result);
+  ftfont_fix_match (pat, match);
+
+  FcPatternDestroy (pat);
+  font_face = cairo_ft_font_face_create_for_pattern (match);
+  if (!font_face)
+    {
+      unblock_input ();
+      FcPatternDestroy (match);
+      return Qnil;
+    }
+  cairo_matrix_t font_matrix, ctm;
+  cairo_matrix_init_scale (&font_matrix, pixel_size, pixel_size);
+  cairo_matrix_init_identity (&ctm);
+  cairo_font_options_t *options = cairo_font_options_create ();
+  cairo_scaled_font_t *scaled_font
+    = cairo_scaled_font_create (font_face, &font_matrix, &ctm, options);
+  cairo_font_face_destroy (font_face);
+  cairo_font_options_destroy (options);
+  unblock_input ();
+
   font_object = font_build_object (VECSIZE (struct font_info),
                                   Qftcr, entity, size);
+  ASET (font_object, FONT_FILE_INDEX, filename);
+  font = XFONT_OBJECT (font_object);
+  font->pixel_size = size;
+  font->driver = &ftcrfont_driver;
+  font->encoding_charset = font->repertory_charset = -1;
+
+  ftcrfont_info = (struct font_info *) font;
+  ftcrfont_info->cr_scaled_font = scaled_font;
+
+  /* This means that there's no need of transformation.  */
+  ftcrfont_info->matrix.xx = 0;
+  if (FcPatternGetMatrix (match, FC_MATRIX, 0, &matrix) == FcResultMatch)
+    {
+      ftcrfont_info->matrix.xx = 0x10000L * matrix->xx;
+      ftcrfont_info->matrix.yy = 0x10000L * matrix->yy;
+      ftcrfont_info->matrix.xy = 0x10000L * matrix->xy;
+      ftcrfont_info->matrix.yx = 0x10000L * matrix->yx;
+    }
+
+  ftcrfont_info->metrics = NULL;
+  ftcrfont_info->metrics_nrows = 0;
+
   block_input ();
-  font_object = ftfont_open2 (f, entity, pixel_size, font_object);
-  if (FONT_OBJECT_P (font_object))
+  cairo_glyph_t stack_glyph;
+  int n = 0;
+  font->min_width = font->average_width = font->space_width = 0;
+  for (char c = 32; c < 127; c++)
     {
-      struct font *font = XFONT_OBJECT (font_object);
-      struct font_info *ftcrfont_info = (struct font_info *) font;
-      FT_Face ft_face = ftcrfont_info->ft_size->face;
-
-      font->driver = &ftcrfont_driver;
-      FT_New_Size (ft_face, &ftcrfont_info->ft_size_draw);
-      FT_Activate_Size (ftcrfont_info->ft_size_draw);
-      if (ftcrfont_info->bitmap_strike_index < 0)
-       FT_Set_Pixel_Sizes (ft_face, 0, font->pixel_size);
-      else
-       FT_Select_Size (ft_face, ftcrfont_info->bitmap_strike_index);
-      cairo_font_face_t *font_face =
-       cairo_ft_font_face_create_for_ft_face (ft_face, 0);
-      cairo_matrix_t font_matrix, ctm;
-      cairo_matrix_init_scale (&font_matrix, pixel_size, pixel_size);
-      cairo_matrix_init_identity (&ctm);
-      cairo_font_options_t *options = cairo_font_options_create ();
-      ftcrfont_info->cr_scaled_font =
-       cairo_scaled_font_create (font_face, &font_matrix, &ctm, options);
-      cairo_font_face_destroy (font_face);
-      cairo_font_options_destroy (options);
-      ftcrfont_info->metrics = NULL;
-      ftcrfont_info->metrics_nrows = 0;
-      if (ftcrfont_info->bitmap_strike_index >= 0)
+      cairo_glyph_t *glyphs = &stack_glyph;
+      int num_glyphs = 1;
+      cairo_status_t status =
+       cairo_scaled_font_text_to_glyphs (ftcrfont_info->cr_scaled_font,
+                                         0, 0, &c, 1, &glyphs, &num_glyphs,
+                                         NULL, NULL, NULL);
+
+      if (status == CAIRO_STATUS_SUCCESS)
        {
-         /* Several members of struct font/font_info set by
-            ftfont_open2 are bogus.  Recalculate them with cairo
-            scaled font functions.  */
-         cairo_font_extents_t extents;
-         cairo_scaled_font_extents (ftcrfont_info->cr_scaled_font, &extents);
-         font->ascent = lround (extents.ascent);
-         Lisp_Object val = assq_no_quit (QCminspace,
-                                         AREF (entity, FONT_EXTRA_INDEX));
-         if (!(CONSP (val) && NILP (XCDR (val))))
-           {
-             font->descent = lround (extents.descent);
-             font->height = font->ascent + font->descent;
-           }
-         else
+         if (glyphs != &stack_glyph)
+           cairo_glyph_free (glyphs);
+         else if (stack_glyph.index)
            {
-             font->height = lround (extents.height);
-             font->descent = font->height - font->ascent;
+             int this_width = ftcrfont_glyph_extents (font, stack_glyph.index,
+                                                      NULL);
+
+             if (this_width > 0
+                 && (! font->min_width
+                     || font->min_width > this_width))
+               font->min_width = this_width;
+             if (c == 32)
+               font->space_width = this_width;
+             font->average_width += this_width;
+             n++;
            }
+       }
+    }
+  if (n > 0)
+    font->average_width /= n;
 
-         cairo_glyph_t stack_glyph;
-         int n = 0;
-         font->min_width = font->average_width = font->space_width = 0;
-         for (char c = 32; c < 127; c++)
-           {
-             cairo_glyph_t *glyphs = &stack_glyph;
-             int num_glyphs = 1;
-             cairo_status_t status =
-               cairo_scaled_font_text_to_glyphs (ftcrfont_info->cr_scaled_font,
-                                                 0, 0, &c, 1,
-                                                 &glyphs, &num_glyphs,
-                                                 NULL, NULL, NULL);
-
-             if (status == CAIRO_STATUS_SUCCESS)
-               {
-                 if (glyphs != &stack_glyph)
-                   cairo_glyph_free (glyphs);
-                 else if (stack_glyph.index)
-                   {
-                     int this_width =
-                       ftcrfont_glyph_extents (font, stack_glyph.index, NULL);
-
-                     if (this_width > 0
-                         && (! font->min_width
-                             || font->min_width > this_width))
-                       font->min_width = this_width;
-                     if (c == 32)
-                       font->space_width = this_width;
-                     font->average_width += this_width;
-                     n++;
-                   }
-               }
-           }
-         if (n > 0)
-           font->average_width /= n;
+  cairo_scaled_font_extents (ftcrfont_info->cr_scaled_font, &extents);
+  font->ascent = lround (extents.ascent);
+  val = assq_no_quit (QCminspace, AREF (entity, FONT_EXTRA_INDEX));
+  if (!(CONSP (val) && NILP (XCDR (val))))
+    {
+      font->descent = lround (extents.descent);
+      font->height = font->ascent + font->descent;
+    }
+  else
+    {
+      font->height = lround (extents.height);
+      font->descent = font->height - font->ascent;
+    }
 
-         font->underline_position = -1;
-         font->underline_thickness = 0;
-       }
+  ft_face = cairo_ft_scaled_font_lock_face (scaled_font);
+  if (XFIXNUM (AREF (entity, FONT_SIZE_INDEX)) == 0)
+    {
+      int upEM = ft_face->units_per_EM;
+
+      font->underline_position = -ft_face->underline_position * size / upEM;
+      font->underline_thickness = ft_face->underline_thickness * size / upEM;
+      if (font->underline_thickness > 2)
+       font->underline_position -= font->underline_thickness / 2;
+    }
+  else
+    {
+      font->underline_position = -1;
+      font->underline_thickness = 0;
     }
+#ifdef HAVE_LIBOTF
+  ftcrfont_info->maybe_otf = (ft_face->face_flags & FT_FACE_FLAG_SFNT) != 0;
+  ftcrfont_info->otf = NULL;
+#endif /* HAVE_LIBOTF */
+  if (ft_face->units_per_EM)
+    ftcrfont_info->bitmap_position_unit = 0;
+  else
+    ftcrfont_info->bitmap_position_unit = (extents.height
+                                          / ft_face->size->metrics.height);
+  cairo_ft_scaled_font_unlock_face (scaled_font);
+  ftcrfont_info->ft_size = NULL;
   unblock_input ();
 
+  font->baseline_offset = 0;
+  font->relative_compose = 0;
+  font->default_ascent = 0;
+  font->vertical_centering = false;
+
   return font_object;
 }
 
@@ -225,19 +280,58 @@ ftcrfont_close (struct font *font)
     return;
 
   struct font_info *ftcrfont_info = (struct font_info *) font;
-  int i;
 
   block_input ();
-  for (i = 0; i < ftcrfont_info->metrics_nrows; i++)
+#ifdef HAVE_LIBOTF
+  if (ftcrfont_info->otf)
+    {
+      OTF_close (ftcrfont_info->otf);
+      ftcrfont_info->otf = NULL;
+    }
+#endif
+  for (int i = 0; i < ftcrfont_info->metrics_nrows; i++)
     if (ftcrfont_info->metrics[i])
       xfree (ftcrfont_info->metrics[i]);
   if (ftcrfont_info->metrics)
     xfree (ftcrfont_info->metrics);
-  FT_Done_Size (ftcrfont_info->ft_size_draw);
   cairo_scaled_font_destroy (ftcrfont_info->cr_scaled_font);
   unblock_input ();
+}
+
+static int
+ftcrfont_has_char (Lisp_Object font, int c)
+{
+  if (FONT_ENTITY_P (font))
+    return ftfont_has_char (font, c);
 
-  ftfont_close (font);
+  return -1;
+}
+
+static unsigned
+ftcrfont_encode_char (struct font *font, int c)
+{
+  struct font_info *ftcrfont_info = (struct font_info *) font;
+  unsigned code = FONT_INVALID_CODE;
+  unsigned char utf8[MAX_MULTIBYTE_LENGTH];
+  unsigned char *p = utf8;
+  cairo_glyph_t stack_glyph;
+  cairo_glyph_t *glyphs = &stack_glyph;
+  int num_glyphs = 1;
+
+  CHAR_STRING_ADVANCE (c, p);
+  if (cairo_scaled_font_text_to_glyphs (ftcrfont_info->cr_scaled_font, 0, 0,
+                                       (char *) utf8, p - utf8,
+                                       &glyphs, &num_glyphs,
+                                       NULL, NULL, NULL)
+      == CAIRO_STATUS_SUCCESS)
+    {
+      if (glyphs != &stack_glyph)
+       cairo_glyph_free (glyphs);
+      else if (stack_glyph.index)
+       code = stack_glyph.index;
+    }
+
+  return code;
 }
 
 static void
@@ -280,10 +374,18 @@ ftcrfont_get_bitmap (struct font *font, unsigned int code,
 {
   struct font_info *ftcrfont_info = (struct font_info *) font;
 
-  if (ftcrfont_info->bitmap_strike_index < 0)
-    return ftfont_get_bitmap (font, code, bitmap, bits_per_pixel);
+  if (ftcrfont_info->bitmap_position_unit)
+    return -1;
 
-  return -1;
+  cairo_scaled_font_t *scaled_font = ftcrfont_info->cr_scaled_font;
+  FT_Face ft_face = cairo_ft_scaled_font_lock_face (scaled_font);
+
+  ftcrfont_info->ft_size = ft_face->size;
+  int result = ftfont_get_bitmap (font, code, bitmap, bits_per_pixel);
+  cairo_ft_scaled_font_unlock_face (scaled_font);
+  ftcrfont_info->ft_size = NULL;
+
+  return result;
 }
 
 static int
@@ -292,25 +394,75 @@ ftcrfont_anchor_point (struct font *font, unsigned int code, int idx,
 {
   struct font_info *ftcrfont_info = (struct font_info *) font;
 
-  if (ftcrfont_info->bitmap_strike_index < 0)
-    return ftfont_anchor_point (font, code, idx, x, y);
+  if (ftcrfont_info->bitmap_position_unit)
+    return -1;
 
-  return -1;
+  cairo_scaled_font_t *scaled_font = ftcrfont_info->cr_scaled_font;
+  FT_Face ft_face = cairo_ft_scaled_font_lock_face (scaled_font);
+
+  ftcrfont_info->ft_size = ft_face->size;
+  int result = ftfont_anchor_point (font, code, idx, x, y);
+  cairo_ft_scaled_font_unlock_face (scaled_font);
+  ftcrfont_info->ft_size = NULL;
+
+  return result;
 }
 
+#ifdef HAVE_LIBOTF
 static Lisp_Object
-ftcrfont_shape (Lisp_Object lgstring)
+ftcrfont_otf_capability (struct font *font)
 {
+  struct font_info *ftcrfont_info = (struct font_info *) font;
+  cairo_scaled_font_t *scaled_font = ftcrfont_info->cr_scaled_font;
+  FT_Face ft_face = cairo_ft_scaled_font_lock_face (scaled_font);
+
+  ftcrfont_info->ft_size = ft_face->size;
+  Lisp_Object result = ftfont_otf_capability (font);
+  cairo_ft_scaled_font_unlock_face (scaled_font);
+  ftcrfont_info->ft_size = NULL;
+
+  return result;
+}
+#endif
+
 #if defined HAVE_M17N_FLT && defined HAVE_LIBOTF
+static Lisp_Object
+ftcrfont_shape (Lisp_Object lgstring)
+{
   struct font *font = CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring));
   struct font_info *ftcrfont_info = (struct font_info *) font;
 
-  if (ftcrfont_info->bitmap_strike_index < 0)
-    return ftfont_shape (lgstring);
+  if (ftcrfont_info->bitmap_position_unit)
+    return make_fixnum (0);
+
+  cairo_scaled_font_t *scaled_font = ftcrfont_info->cr_scaled_font;
+  FT_Face ft_face = cairo_ft_scaled_font_lock_face (scaled_font);
+
+  ftcrfont_info->ft_size = ft_face->size;
+  Lisp_Object result = ftfont_shape (lgstring);
+  cairo_ft_scaled_font_unlock_face (scaled_font);
+  ftcrfont_info->ft_size = NULL;
+
+  return result;
+}
 #endif
 
-  return make_fixnum (0);
+#ifdef HAVE_OTF_GET_VARIATION_GLYPHS
+static int
+ftcrfont_variation_glyphs (struct font *font, int c, unsigned variations[256])
+{
+  struct font_info *ftcrfont_info = (struct font_info *) font;
+  cairo_scaled_font_t *scaled_font = ftcrfont_info->cr_scaled_font;
+  FT_Face ft_face = cairo_ft_scaled_font_lock_face (scaled_font);
+
+  ftcrfont_info->ft_size = ft_face->size;
+  int result = ftfont_variation_glyphs (font, c, variations);
+  cairo_ft_scaled_font_unlock_face (scaled_font);
+  ftcrfont_info->ft_size = NULL;
+
+  return result;
 }
+#endif /* HAVE_OTF_GET_VARIATION_GLYPHS */
 
 static int
 ftcrfont_draw (struct glyph_string *s,
@@ -321,8 +473,6 @@ ftcrfont_draw (struct glyph_string *s,
   struct font_info *ftcrfont_info = (struct font_info *) s->font;
   cairo_t *cr;
   cairo_glyph_t *glyphs;
-  cairo_surface_t *surface;
-  cairo_surface_type_t surface_type;
   int len = to - from;
   int i;
 
@@ -351,17 +501,7 @@ ftcrfont_draw (struct glyph_string *s,
 
   x_set_cr_source_with_gc_foreground (f, s->gc);
   cairo_set_scaled_font (cr, ftcrfont_info->cr_scaled_font);
-
-  FT_Activate_Size (ftcrfont_info->ft_size_draw);
   cairo_show_glyphs (cr, glyphs, len);
-  surface = cairo_get_target (cr);
-  /* XXX: It used to be necessary to flush when exporting.  It might
-     be the case that this is no longer necessary.  */
-  surface_type = cairo_surface_get_type (surface);
-  if (surface_type != CAIRO_SURFACE_TYPE_XLIB
-      && (surface_type != CAIRO_SURFACE_TYPE_IMAGE
-         || cairo_image_surface_get_format (surface) != CAIRO_FORMAT_ARGB32))
-    cairo_surface_flush (surface);
 
   x_end_cr_clip (f);
 
@@ -383,18 +523,20 @@ struct font_driver const ftcrfont_driver =
   .list_family = ftfont_list_family,
   .open = ftcrfont_open,
   .close = ftcrfont_close,
-  .has_char = ftfont_has_char,
-  .encode_char = ftfont_encode_char,
+  .has_char = ftcrfont_has_char,
+  .encode_char = ftcrfont_encode_char,
   .text_extents = ftcrfont_text_extents,
   .draw = ftcrfont_draw,
   .get_bitmap = ftcrfont_get_bitmap,
   .anchor_point = ftcrfont_anchor_point,
 #ifdef HAVE_LIBOTF
-  .otf_capability = ftfont_otf_capability,
+  .otf_capability = ftcrfont_otf_capability,
 #endif
+#if defined HAVE_M17N_FLT && defined HAVE_LIBOTF
   .shape = ftcrfont_shape,
+#endif
 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
-  .get_variation_glyphs = ftfont_variation_glyphs,
+  .get_variation_glyphs = ftcrfont_variation_glyphs,
 #endif
   .filter_properties = ftfont_filter_properties,
   .combining_capability = ftfont_combining_capability,
index f17bd9ab3f70866d3e36e22531fa75ef74519614..d8b510d70327a5e0380fdcab3fd0c7d40a0aa0c3 100644 (file)
@@ -1079,12 +1079,159 @@ ftfont_list_family (struct frame *f)
   return list;
 }
 
+void
+ftfont_fix_match (FcPattern *pat, FcPattern *match)
+{
+  /*  These values are not used for matching (except antialias), but for
+      rendering, so make sure they are carried over to the match.
+      We also put antialias here because most fonts are antialiased, so
+      the match will have antialias true.  */
+
+  FcBool b = FcTrue;
+  int i;
+  double dpi;
+
+  FcPatternGetBool (pat, FC_ANTIALIAS, 0, &b);
+  if (! b)
+    {
+      FcPatternDel (match, FC_ANTIALIAS);
+      FcPatternAddBool (match, FC_ANTIALIAS, FcFalse);
+    }
+  FcPatternGetBool (pat, FC_HINTING, 0, &b);
+  if (! b)
+    {
+      FcPatternDel (match, FC_HINTING);
+      FcPatternAddBool (match, FC_HINTING, FcFalse);
+    }
+#ifndef FC_HINT_STYLE
+# define FC_HINT_STYLE "hintstyle"
+#endif
+  if (FcResultMatch == FcPatternGetInteger (pat, FC_HINT_STYLE, 0, &i))
+    {
+      FcPatternDel (match, FC_HINT_STYLE);
+      FcPatternAddInteger (match, FC_HINT_STYLE, i);
+    }
+#ifndef FC_LCD_FILTER
+  /* Older fontconfig versions don't have FC_LCD_FILTER. */
+#define FC_LCD_FILTER "lcdfilter"
+#endif
+  if (FcResultMatch == FcPatternGetInteger (pat, FC_LCD_FILTER, 0, &i))
+    {
+      FcPatternDel (match, FC_LCD_FILTER);
+      FcPatternAddInteger (match, FC_LCD_FILTER, i);
+    }
+  if (FcResultMatch == FcPatternGetInteger (pat, FC_RGBA, 0, &i))
+    {
+      FcPatternDel (match, FC_RGBA);
+      FcPatternAddInteger (match, FC_RGBA, i);
+    }
+  if (FcResultMatch == FcPatternGetDouble (pat, FC_DPI, 0, &dpi))
+    {
+      FcPatternDel (match, FC_DPI);
+      FcPatternAddDouble (match, FC_DPI, dpi);
+    }
+}
+
+void
+ftfont_add_rendering_parameters (FcPattern *pat, Lisp_Object entity)
+{
+  Lisp_Object tail;
+  int ival;
+
+  for (tail = AREF (entity, FONT_EXTRA_INDEX); CONSP (tail); tail = XCDR (tail))
+    {
+      Lisp_Object key = XCAR (XCAR (tail));
+      Lisp_Object val = XCDR (XCAR (tail));
+
+      if (EQ (key, QCantialias))
+          FcPatternAddBool (pat, FC_ANTIALIAS, NILP (val) ? FcFalse : FcTrue);
+      else if (EQ (key, QChinting))
+       FcPatternAddBool (pat, FC_HINTING, NILP (val) ? FcFalse : FcTrue);
+      else if (EQ (key, QCautohint))
+       FcPatternAddBool (pat, FC_AUTOHINT, NILP (val) ? FcFalse : FcTrue);
+      else if (EQ (key, QChintstyle))
+       {
+         if (FIXNUMP (val))
+           FcPatternAddInteger (pat, FC_HINT_STYLE, XFIXNUM (val));
+          else if (SYMBOLP (val)
+                   && FcNameConstant (SDATA (SYMBOL_NAME (val)), &ival))
+           FcPatternAddInteger (pat, FC_HINT_STYLE, ival);
+       }
+      else if (EQ (key, QCrgba))
+       {
+         if (FIXNUMP (val))
+           FcPatternAddInteger (pat, FC_RGBA, XFIXNUM (val));
+          else if (SYMBOLP (val)
+                   && FcNameConstant (SDATA (SYMBOL_NAME (val)), &ival))
+           FcPatternAddInteger (pat, FC_RGBA, ival);
+       }
+      else if (EQ (key, QClcdfilter))
+       {
+         if (FIXNUMP (val))
+           FcPatternAddInteger (pat, FC_LCD_FILTER, ival = XFIXNUM (val));
+          else if (SYMBOLP (val)
+                   && FcNameConstant (SDATA (SYMBOL_NAME (val)), &ival))
+           FcPatternAddInteger (pat, FC_LCD_FILTER, ival);
+       }
+#ifdef FC_EMBOLDEN
+      else if (EQ (key, QCembolden))
+       FcPatternAddBool (pat, FC_EMBOLDEN, NILP (val) ? FcFalse : FcTrue);
+#endif
+    }
+}
+
+FcPattern *
+ftfont_entity_pattern (Lisp_Object entity, int pixel_size)
+{
+  Lisp_Object val, filename, idx;
+  FcPattern *pat;
+  int i;
+
+  val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
+  eassert (CONSP (val));
+  val = XCDR (val);
+  filename = XCAR (val);
+  idx = XCDR (val);
+  pat = FcPatternCreate ();
+  FcPatternAddInteger (pat, FC_WEIGHT, FONT_WEIGHT_NUMERIC (entity));
+  i = FONT_SLANT_NUMERIC (entity) - 100;
+  if (i < 0) i = 0;
+  FcPatternAddInteger (pat, FC_SLANT, i);
+  FcPatternAddInteger (pat, FC_WIDTH, FONT_WIDTH_NUMERIC (entity));
+  FcPatternAddDouble (pat, FC_PIXEL_SIZE, pixel_size);
+  val = AREF (entity, FONT_FAMILY_INDEX);
+  if (! NILP (val))
+    FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) SDATA (SYMBOL_NAME (val)));
+  val = AREF (entity, FONT_FOUNDRY_INDEX);
+  if (! NILP (val))
+    FcPatternAddString (pat, FC_FOUNDRY, (FcChar8 *) SDATA (SYMBOL_NAME (val)));
+  val = AREF (entity, FONT_SPACING_INDEX);
+  if (! NILP (val))
+    FcPatternAddInteger (pat, FC_SPACING, XFIXNUM (val));
+  val = AREF (entity, FONT_DPI_INDEX);
+  if (! NILP (val))
+    {
+      double dbl = XFIXNUM (val);
+
+      FcPatternAddDouble (pat, FC_DPI, dbl);
+    }
+  val = AREF (entity, FONT_AVGWIDTH_INDEX);
+  if (FIXNUMP (val) && XFIXNUM (val) == 0)
+    FcPatternAddBool (pat, FC_SCALABLE, FcTrue);
+  /* This is necessary to identify the exact font (e.g. 10x20.pcf.gz
+     over 10x20-ISO8859-1.pcf.gz).  */
+  FcPatternAddCharSet (pat, FC_CHARSET, ftfont_get_fc_charset (entity));
+
+  ftfont_add_rendering_parameters (pat, entity);
+
+  FcPatternAddString (pat, FC_FILE, (FcChar8 *) SDATA (filename));
+  FcPatternAddInteger (pat, FC_INDEX, XFIXNUM (idx));
+
+  return pat;
+}
 
 Lisp_Object
-ftfont_open2 (struct frame *f,
-              Lisp_Object entity,
-              int pixel_size,
-              Lisp_Object font_object)
+ftfont_open (struct frame *f, Lisp_Object entity, int pixel_size)
 {
   struct font_info *ftfont_info;
   struct font *font;
@@ -1092,12 +1239,11 @@ ftfont_open2 (struct frame *f,
   FT_Face ft_face;
   FT_Size ft_size;
   FT_UInt size;
-  Lisp_Object val, filename, idx, cache;
+  Lisp_Object val, filename, idx, cache, font_object;
   bool scalable;
   int spacing;
   int i;
   double upEM;
-  FT_Int strike_index = -1;
 
   val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
   if (! CONSP (val))
@@ -1126,35 +1272,17 @@ ftfont_open2 (struct frame *f,
     size = pixel_size;
   if (FT_Set_Pixel_Sizes (ft_face, size, size) != 0)
     {
-      int min_distance = INT_MAX;
-      bool magnify = true;
-
-      for (FT_Int i = 0; i < ft_face->num_fixed_sizes; i++)
-       {
-         int distance = ft_face->available_sizes[i].height - (int) size;
-
-         /* Prefer down-scaling to upscaling.  */
-         if (magnify == (distance < 0) ? abs (distance) <= min_distance
-             : magnify)
-           {
-             magnify = distance < 0;
-             min_distance = abs (distance);
-             strike_index = i;
-           }
-       }
-
-      if (strike_index < 0 || FT_Select_Size (ft_face, strike_index) != 0)
+      if (cache_data->face_refcount == 0)
        {
-         if (cache_data->face_refcount == 0)
-           {
-             FT_Done_Face (ft_face);
-             cache_data->ft_face = NULL;
-           }
-         return Qnil;
+         FT_Done_Face (ft_face);
+         cache_data->ft_face = NULL;
        }
+      return Qnil;
     }
   cache_data->face_refcount++;
 
+  font_object = font_build_object (VECSIZE (struct font_info),
+                                  Qfreetype, entity, size);
   ASET (font_object, FONT_FILE_INDEX, filename);
   font = XFONT_OBJECT (font_object);
   ftfont_info = (struct font_info *) font;
@@ -1164,7 +1292,6 @@ ftfont_open2 (struct frame *f,
   ftfont_info->maybe_otf = (ft_face->face_flags & FT_FACE_FLAG_SFNT) != 0;
   ftfont_info->otf = NULL;
 #endif /* HAVE_LIBOTF */
-  ftfont_info->bitmap_strike_index = strike_index;
   /* This means that there's no need of transformation.  */
   ftfont_info->matrix.xx = 0;
   font->pixel_size = size;
@@ -1258,31 +1385,6 @@ ftfont_open2 (struct frame *f,
   return font_object;
 }
 
-Lisp_Object
-ftfont_open (struct frame *f, Lisp_Object entity, int pixel_size)
-{
-  Lisp_Object font_object;
-  FT_UInt size;
-  size = XFIXNUM (AREF (entity, FONT_SIZE_INDEX));
-  if (size == 0)
-    size = pixel_size;
-  font_object = font_build_object (VECSIZE (struct font_info),
-                                  Qfreetype, entity, size);
-  font_object = ftfont_open2 (f, entity, pixel_size, font_object);
-  if (FONT_OBJECT_P (font_object))
-    {
-      struct font *font = XFONT_OBJECT (font_object);
-      struct font_info *ftfont_info = (struct font_info *) font;
-
-      if (ftfont_info->bitmap_strike_index >= 0)
-       {
-         ftfont_close (font);
-         font_object = Qnil;
-       }
-    }
-  return font_object;
-}
-
 void
 ftfont_close (struct font *font)
 {
@@ -2789,6 +2891,14 @@ syms_of_ftfont (void)
   /* The boolean-valued font property key specifying the use of leading.  */
   DEFSYM (QCminspace, ":minspace");
 
+  /* Fontconfig's rendering parameters.  */
+  DEFSYM (QChinting, ":hinting");
+  DEFSYM (QCautohint, ":autohint");
+  DEFSYM (QChintstyle, ":hintstyle");
+  DEFSYM (QCrgba, ":rgba");
+  DEFSYM (QCembolden, ":embolden");
+  DEFSYM (QClcdfilter, ":lcdfilter");
+
   staticpro (&freetype_font_cache);
   freetype_font_cache = list1 (Qt);
 
index adbda49ff1c2ed6d98f3f47624606955202822c6..7860469491f441bbd3b3300f4ed1300289b7f0d4 100644 (file)
@@ -37,10 +37,9 @@ along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
 #endif /* HAVE_LIBOTF */
 
 extern FcCharSet *ftfont_get_fc_charset (Lisp_Object);
-extern Lisp_Object ftfont_open2 (struct frame *f,
-                                 Lisp_Object entity,
-                                 int pixel_size,
-                                 Lisp_Object font_object);
+extern void ftfont_fix_match (FcPattern *, FcPattern *);
+extern void ftfont_add_rendering_parameters (FcPattern *, Lisp_Object);
+extern FcPattern *ftfont_entity_pattern (Lisp_Object, int);
 
 /* This struct is shared by the XFT, Freetype, and Cairo font
    backends.  Members up to and including 'matrix' are common, the
@@ -54,17 +53,14 @@ struct font_info
 #endif /* HAVE_LIBOTF */
   FT_Size ft_size;
   int index;
-  /* Index of the bitmap strike used as a fallback for
-     FT_Set_Pixel_Sizes failure.  If the value is non-negative, then
-     ft_size is not of the requested size.  Otherwise it is -1.  */
-  FT_Int bitmap_strike_index;
   FT_Matrix matrix;
 
 #ifdef USE_CAIRO
   cairo_scaled_font_t *cr_scaled_font;
-  /* To prevent cairo from cluttering the activated FT_Size maintained
-     in ftfont.c, we activate this special FT_Size before drawing.  */
-  FT_Size ft_size_draw;
+  /* Scale factor from the bitmap strike metrics in 1/64 pixels, used
+     as the hb_position_t value in HarfBuzz, to those in (scaled)
+     pixels.  The value is 0 for scalable fonts.  */
+  double bitmap_position_unit;
   /* Font metrics cache.  */
   struct font_metrics **metrics;
   short metrics_nrows;
index 2edc51fe356183f208dd1ada584380c8f835161d..4f0a0d81d8515eaf4402d8e17815eac56131d8f9 100644 (file)
@@ -127,120 +127,18 @@ xftfont_match (struct frame *f, Lisp_Object spec)
 
 static FcChar8 ascii_printable[95];
 
-static void
-xftfont_fix_match (FcPattern *pat, FcPattern *match)
-{
-  /*  These values are not used for matching (except antialias), but for
-      rendering, so make sure they are carried over to the match.
-      We also put antialias here because most fonts are antialiased, so
-      the match will have antialias true.  */
-
-  FcBool b = FcTrue;
-  int i;
-  double dpi;
-
-  FcPatternGetBool (pat, FC_ANTIALIAS, 0, &b);
-  if (! b)
-    {
-      FcPatternDel (match, FC_ANTIALIAS);
-      FcPatternAddBool (match, FC_ANTIALIAS, FcFalse);
-    }
-  FcPatternGetBool (pat, FC_HINTING, 0, &b);
-  if (! b)
-    {
-      FcPatternDel (match, FC_HINTING);
-      FcPatternAddBool (match, FC_HINTING, FcFalse);
-    }
-#ifndef FC_HINT_STYLE
-# define FC_HINT_STYLE "hintstyle"
-#endif
-  if (FcResultMatch == FcPatternGetInteger (pat, FC_HINT_STYLE, 0, &i))
-    {
-      FcPatternDel (match, FC_HINT_STYLE);
-      FcPatternAddInteger (match, FC_HINT_STYLE, i);
-    }
-#ifndef FC_LCD_FILTER
-  /* Older fontconfig versions don't have FC_LCD_FILTER. */
-#define FC_LCD_FILTER "lcdfilter"
-#endif
-  if (FcResultMatch == FcPatternGetInteger (pat, FC_LCD_FILTER, 0, &i))
-    {
-      FcPatternDel (match, FC_LCD_FILTER);
-      FcPatternAddInteger (match, FC_LCD_FILTER, i);
-    }
-  if (FcResultMatch == FcPatternGetInteger (pat, FC_RGBA, 0, &i))
-    {
-      FcPatternDel (match, FC_RGBA);
-      FcPatternAddInteger (match, FC_RGBA, i);
-    }
-  if (FcResultMatch == FcPatternGetDouble (pat, FC_DPI, 0, &dpi))
-    {
-      FcPatternDel (match, FC_DPI);
-      FcPatternAddDouble (match, FC_DPI, dpi);
-    }
-}
-
-static void
-xftfont_add_rendering_parameters (FcPattern *pat, Lisp_Object entity)
-{
-  Lisp_Object tail;
-  int ival;
-
-  for (tail = AREF (entity, FONT_EXTRA_INDEX); CONSP (tail); tail = XCDR (tail))
-    {
-      Lisp_Object key = XCAR (XCAR (tail));
-      Lisp_Object val = XCDR (XCAR (tail));
-
-      if (EQ (key, QCantialias))
-          FcPatternAddBool (pat, FC_ANTIALIAS, NILP (val) ? FcFalse : FcTrue);
-      else if (EQ (key, QChinting))
-       FcPatternAddBool (pat, FC_HINTING, NILP (val) ? FcFalse : FcTrue);
-      else if (EQ (key, QCautohint))
-       FcPatternAddBool (pat, FC_AUTOHINT, NILP (val) ? FcFalse : FcTrue);
-      else if (EQ (key, QChintstyle))
-       {
-         if (FIXNUMP (val))
-           FcPatternAddInteger (pat, FC_HINT_STYLE, XFIXNUM (val));
-          else if (SYMBOLP (val)
-                   && FcNameConstant (SDATA (SYMBOL_NAME (val)), &ival))
-           FcPatternAddInteger (pat, FC_HINT_STYLE, ival);
-       }
-      else if (EQ (key, QCrgba))
-       {
-         if (FIXNUMP (val))
-           FcPatternAddInteger (pat, FC_RGBA, XFIXNUM (val));
-          else if (SYMBOLP (val)
-                   && FcNameConstant (SDATA (SYMBOL_NAME (val)), &ival))
-           FcPatternAddInteger (pat, FC_RGBA, ival);
-       }
-      else if (EQ (key, QClcdfilter))
-       {
-         if (FIXNUMP (val))
-           FcPatternAddInteger (pat, FC_LCD_FILTER, ival = XFIXNUM (val));
-          else if (SYMBOLP (val)
-                   && FcNameConstant (SDATA (SYMBOL_NAME (val)), &ival))
-           FcPatternAddInteger (pat, FC_LCD_FILTER, ival);
-       }
-#ifdef FC_EMBOLDEN
-      else if (EQ (key, QCembolden))
-       FcPatternAddBool (pat, FC_EMBOLDEN, NILP (val) ? FcFalse : FcTrue);
-#endif
-    }
-}
-
 static Lisp_Object
 xftfont_open (struct frame *f, Lisp_Object entity, int pixel_size)
 {
   FcResult result;
   Display *display = FRAME_X_DISPLAY (f);
-  Lisp_Object val, filename, idx, font_object;
+  Lisp_Object val, filename, font_object;
   FcPattern *pat = NULL, *match;
   struct font_info *xftfont_info = NULL;
   struct font *font;
   double size = 0;
   XftFont *xftfont = NULL;
   int spacing;
-  int i;
   XGlyphInfo extents;
   FT_Face ft_face;
   FcMatrix *matrix;
@@ -250,52 +148,17 @@ xftfont_open (struct frame *f, Lisp_Object entity, int pixel_size)
     return Qnil;
   val = XCDR (val);
   filename = XCAR (val);
-  idx = XCDR (val);
   size = XFIXNUM (AREF (entity, FONT_SIZE_INDEX));
   if (size == 0)
     size = pixel_size;
-  pat = FcPatternCreate ();
-  FcPatternAddInteger (pat, FC_WEIGHT, FONT_WEIGHT_NUMERIC (entity));
-  i = FONT_SLANT_NUMERIC (entity) - 100;
-  if (i < 0) i = 0;
-  FcPatternAddInteger (pat, FC_SLANT, i);
-  FcPatternAddInteger (pat, FC_WIDTH, FONT_WIDTH_NUMERIC (entity));
-  FcPatternAddDouble (pat, FC_PIXEL_SIZE, pixel_size);
-  val = AREF (entity, FONT_FAMILY_INDEX);
-  if (! NILP (val))
-    FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) SDATA (SYMBOL_NAME (val)));
-  val = AREF (entity, FONT_FOUNDRY_INDEX);
-  if (! NILP (val))
-    FcPatternAddString (pat, FC_FOUNDRY, (FcChar8 *) SDATA (SYMBOL_NAME (val)));
-  val = AREF (entity, FONT_SPACING_INDEX);
-  if (! NILP (val))
-    FcPatternAddInteger (pat, FC_SPACING, XFIXNUM (val));
-  val = AREF (entity, FONT_DPI_INDEX);
-  if (! NILP (val))
-    {
-      double dbl = XFIXNUM (val);
-
-      FcPatternAddDouble (pat, FC_DPI, dbl);
-    }
-  val = AREF (entity, FONT_AVGWIDTH_INDEX);
-  if (FIXNUMP (val) && XFIXNUM (val) == 0)
-    FcPatternAddBool (pat, FC_SCALABLE, FcTrue);
-  /* This is necessary to identify the exact font (e.g. 10x20.pcf.gz
-     over 10x20-ISO8859-1.pcf.gz).  */
-  FcPatternAddCharSet (pat, FC_CHARSET, ftfont_get_fc_charset (entity));
-
-  xftfont_add_rendering_parameters (pat, entity);
-
-  FcPatternAddString (pat, FC_FILE, (FcChar8 *) SDATA (filename));
-  FcPatternAddInteger (pat, FC_INDEX, XFIXNUM (idx));
-
 
   block_input ();
 
+  pat = ftfont_entity_pattern (entity, pixel_size);
   /* Substitute in values from X resources and XftDefaultSet.  */
   XftDefaultSubstitute (display, FRAME_X_SCREEN_NUMBER (f), pat);
   match = XftFontMatch (display, FRAME_X_SCREEN_NUMBER (f), pat, &result);
-  xftfont_fix_match (pat, match);
+  ftfont_fix_match (pat, match);
 
   FcPatternDestroy (pat);
   xftfont = XftFontOpenPattern (display, match);
@@ -695,7 +558,7 @@ xftfont_cached_font_ok (struct frame *f, Lisp_Object font_object,
   bool ok = false;
   int i1, i2, r1, r2;
 
-  xftfont_add_rendering_parameters (pat, entity);
+  ftfont_add_rendering_parameters (pat, entity);
   XftDefaultSubstitute (display, FRAME_X_SCREEN_NUMBER (f), pat);
 
   r1 = FcPatternGetBool (pat, FC_ANTIALIAS, 0, &b1);
@@ -768,12 +631,6 @@ void
 syms_of_xftfont (void)
 {
   DEFSYM (Qxft, "xft");
-  DEFSYM (QChinting, ":hinting");
-  DEFSYM (QCautohint, ":autohint");
-  DEFSYM (QChintstyle, ":hintstyle");
-  DEFSYM (QCrgba, ":rgba");
-  DEFSYM (QCembolden, ":embolden");
-  DEFSYM (QClcdfilter, ":lcdfilter");
 
   DEFVAR_BOOL ("xft-font-ascent-descent-override",
               xft_font_ascent_descent_override,