]> git.eshelyaron.com Git - emacs.git/commitdiff
Use bitmap strikes as fallbacks for ftcr font backend
authorYAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp>
Sat, 20 Apr 2019 03:43:45 +0000 (12:43 +0900)
committerYAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp>
Sat, 20 Apr 2019 03:43:45 +0000 (12:43 +0900)
* src/ftfont.h (struct font_info): New member bitmap_strike_index.
* src/ftfont.c (ftfont_open2): Try bitmap strikes as fallbacks.
(ftfont_open): Discard bitmap strikes.
* src/ftcrfont.c (ftcrfont_open): Recalculate metrics for bitmap strikes.
(ftcrfont_get_bitmap, ftcrfont_anchor_point, ftcrfont_shape): New functions.
(struct font_driver): Use them.

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

index 4845ee4cf3db8be6220826a2137d47de8d65f2d8..e341c409b1e18928b2bd846d3f2890b3538469d1 100644 (file)
@@ -135,7 +135,10 @@ ftcrfont_open (struct frame *f, Lisp_Object entity, int pixel_size)
       font->driver = &ftcrfont_driver;
       FT_New_Size (ft_face, &ftcrfont_info->ft_size_draw);
       FT_Activate_Size (ftcrfont_info->ft_size_draw);
-      FT_Set_Pixel_Sizes (ft_face, 0, font->pixel_size);
+      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;
@@ -148,6 +151,56 @@ ftcrfont_open (struct frame *f, Lisp_Object entity, int pixel_size)
       cairo_font_options_destroy (options);
       ftcrfont_info->metrics = NULL;
       ftcrfont_info->metrics_nrows = 0;
+      if (ftcrfont_info->bitmap_strike_index >= 0)
+       {
+         /* 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);
+         font->descent = lround (extents.descent);
+         font->height = lround (extents.height);
+
+         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
+                   {
+                     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;
+
+         font->underline_position = -1;
+         font->underline_thickness = 0;
+       }
     }
   unblock_input ();
 
@@ -210,6 +263,43 @@ ftcrfont_text_extents (struct font *font,
     metrics->width = width;
 }
 
+static int
+ftcrfont_get_bitmap (struct font *font, unsigned int code,
+                    struct font_bitmap *bitmap, int bits_per_pixel)
+{
+  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);
+
+  return -1;
+}
+
+static int
+ftcrfont_anchor_point (struct font *font, unsigned int code, int idx,
+                      int *x, int *y)
+{
+  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);
+
+  return -1;
+}
+
+static Lisp_Object
+ftcrfont_shape (Lisp_Object lgstring)
+{
+#if defined HAVE_M17N_FLT && defined HAVE_LIBOTF
+  struct font_info *ftcrfont_info = (struct font_info *) font;
+
+  if (ftcrfont_info->bitmap_strike_index < 0)
+    return ftfont_shape (lgstring);
+#endif
+
+  return make_fixnum (0);
+}
+
 static int
 ftcrfont_draw (struct glyph_string *s,
                int from, int to, int x, int y, bool with_background)
@@ -286,14 +376,12 @@ struct font_driver const ftcrfont_driver =
   .encode_char = ftfont_encode_char,
   .text_extents = ftcrfont_text_extents,
   .draw = ftcrfont_draw,
-  .get_bitmap = ftfont_get_bitmap,
-  .anchor_point = ftfont_anchor_point,
+  .get_bitmap = ftcrfont_get_bitmap,
+  .anchor_point = ftcrfont_anchor_point,
 #ifdef HAVE_LIBOTF
   .otf_capability = ftfont_otf_capability,
 #endif
-#if defined HAVE_M17N_FLT && defined HAVE_LIBOTF
-  .shape = ftfont_shape,
-#endif
+  .shape = ftcrfont_shape,
 #ifdef HAVE_OTF_GET_VARIATION_GLYPHS
   .get_variation_glyphs = ftfont_variation_glyphs,
 #endif
index 3e820f583ff0c7d222984e39608aac40f9f7d2d5..d0078a37701ad0fe4d446ae920f60a758172c1c7 100644 (file)
@@ -1097,6 +1097,7 @@ ftfont_open2 (struct frame *f,
   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,12 +1127,32 @@ ftfont_open2 (struct frame *f,
     size = pixel_size;
   if (FT_Set_Pixel_Sizes (ft_face, size, size) != 0)
     {
-      if (cache_data->face_refcount == 0)
+      int min_distance = INT_MAX;
+      bool magnify = true;
+
+      for (FT_Int i = 0; i < ft_face->num_fixed_sizes; i++)
        {
-         FT_Done_Face (ft_face);
-         cache_data->ft_face = NULL;
+         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)
+           {
+             FT_Done_Face (ft_face);
+             cache_data->ft_face = NULL;
+           }
+         return Qnil;
        }
-      return Qnil;
     }
   cache_data->face_refcount++;
 
@@ -1144,6 +1165,7 @@ 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;
@@ -1229,7 +1251,19 @@ ftfont_open (struct frame *f, Lisp_Object entity, int pixel_size)
     size = pixel_size;
   font_object = font_build_object (VECSIZE (struct font_info),
                                   Qfreetype, entity, size);
-  return ftfont_open2 (f, entity, pixel_size, font_object);
+  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
index 327cd085acf9e94442546c80e0b5081c6c30c18e..adbda49ff1c2ed6d98f3f47624606955202822c6 100644 (file)
@@ -54,6 +54,10 @@ 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