unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
From: YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp>
To: "Kévin Le Gouguec" <kevin.legouguec@gmail.com>
Cc: 35781@debbugs.gnu.org, Alex Gramiak <agrambot@gmail.com>
Subject: bug#35781: Discrepancies between xftfont.c and ftcrfont.c
Date: Wed, 22 May 2019 18:24:33 +0900	[thread overview]
Message-ID: <wlsgt6rgdq.wl-mituharu@math.s.chiba-u.ac.jp> (raw)
In-Reply-To: <87zhnfljeq.fsf@gmail.com>

[-- Attachment #1: Type: text/plain, Size: 2046 bytes --]

On Wed, 22 May 2019 04:03:25 +0900,
Kévin Le Gouguec wrote:
> 
> mituharu@math.s.chiba-u.ac.jp writes:
> 
> > I tried making ftcrfont_open look much like xftfont_open.
> > Could you try the attached patch?
> 
> Thank you for this patch!
> 
> I applied it on top of cb367c8e0d, and AFAICT this fixes the issue: on
> both setups where I used to see a difference in hint style[1], the
> fonts now look the same (i.e. with slight hinting).  Things haven't
> deteriorated on the third setup[2].

Thanks for testing.  An updated patch is attached.

> I glanced at your patch to try and get a sense of how things worked;
> from what I can tell you moved some logic from xftfont.c to ftfont.c,
> which is used by ftcrfont.c, so the XFT and Cairo build would use more
> common code?
> 
> (Is there a reason why you left xftfont_add_rendering_parameters in
> xftfont.c despite adding ftfont_add_rendering_parameters in ftfont.c?
> Should this function be added to ftfont.h so that xftfont.c gets rid
> of its duplicate implementation?)

I've overlooked it at the last minute change for xftfont.c.  It is
fixed in the updated one.

> (Also, I see you removed some code related to the bitmap_strike_index
> and ft_size_draw members of struct font_info; is it because whatever
> this code was doing is now handled by… something else in ftfont.c?)

Screening bitmap fonts from passing them to ftfont functions in
ftcrfont_get_bitmap, ftcrfont_anchor_point, and ftcrfont_shape is
resurrected by a new member bitmap_position_unit, which is primarily
introduced for HarfBuzz, in the updated patch.  The member
ft_size_draw is removed because it was a workaround in the previous
design.

In the updated patch, ftfont_open2 is merged into ftfont_open just as
before the introduction of the cairo drawing code, because they are no
longer used in cairo.

I'll push the updated one to master and also adapt it for the harfbuzz
branch in 15 hours or so.

				     YAMAMOTO Mitsuharu
				mituharu@math.s.chiba-u.ac.jp

[-- Attachment #2: xft-like-ftcr.diff --]
[-- Type: application/octet-stream, Size: 32792 bytes --]

diff --git a/src/ftcrfont.c b/src/ftcrfont.c
index 2d5a7665578..9686cec0e8c 100644
--- a/src/ftcrfont.c
+++ b/src/ftcrfont.c
@@ -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,
diff --git a/src/ftfont.c b/src/ftfont.c
index f17bd9ab3f7..d8b510d7032 100644
--- a/src/ftfont.c
+++ b/src/ftfont.c
@@ -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);
 
diff --git a/src/ftfont.h b/src/ftfont.h
index adbda49ff1c..7860469491f 100644
--- a/src/ftfont.h
+++ b/src/ftfont.h
@@ -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;
diff --git a/src/xftfont.c b/src/xftfont.c
index 2edc51fe356..4f0a0d81d85 100644
--- a/src/xftfont.c
+++ b/src/xftfont.c
@@ -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,

  reply	other threads:[~2019-05-22  9:24 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-05-17 17:39 bug#35781: 27.0.50; [PATCH] Improve font display on Cairo builds Kévin Le Gouguec
2019-05-17 17:54 ` Dmitry Gutov
2019-05-17 18:14   ` Kévin Le Gouguec
2019-05-17 18:23     ` Kévin Le Gouguec
2019-05-17 18:24     ` Dmitry Gutov
2019-05-18 20:43 ` bug#35781: Discrepancies between xftfont.c and ftcrfont.c Kévin Le Gouguec
2019-05-19 19:48   ` Alex Gramiak
2019-05-21 10:59     ` mituharu
2019-05-21 19:03       ` Kévin Le Gouguec
2019-05-22  9:24         ` YAMAMOTO Mitsuharu [this message]
2019-05-23  2:00           ` YAMAMOTO Mitsuharu
2019-05-23 17:53             ` Kévin Le Gouguec

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=wlsgt6rgdq.wl-mituharu@math.s.chiba-u.ac.jp \
    --to=mituharu@math.s.chiba-u.ac.jp \
    --cc=35781@debbugs.gnu.org \
    --cc=agrambot@gmail.com \
    --cc=kevin.legouguec@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).