unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
* bug#35781: 27.0.50; [PATCH] Improve font display on Cairo builds
@ 2019-05-17 17:39 Kévin Le Gouguec
  2019-05-17 17:54 ` Dmitry Gutov
  2019-05-18 20:43 ` bug#35781: Discrepancies between xftfont.c and ftcrfont.c Kévin Le Gouguec
  0 siblings, 2 replies; 12+ messages in thread
From: Kévin Le Gouguec @ 2019-05-17 17:39 UTC (permalink / raw)
  To: 35781

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

Hi,

The attached patch makes fonts in the Cairo build more readable[1] on
some setups I use.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: cairo-style-hint.patch --]
[-- Type: text/x-diff, Size: 622 bytes --]

diff --git a/src/ftcrfont.c b/src/ftcrfont.c
index e7c73eac4d..51890dc18c 100644
--- a/src/ftcrfont.c
+++ b/src/ftcrfont.c
@@ -146,6 +146,7 @@ ftcrfont_open (struct frame *f, Lisp_Object entity, int pixel_size)
       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_font_options_set_hint_style (options, CAIRO_HINT_STYLE_SLIGHT);
       ftcrfont_info->cr_scaled_font =
 	cairo_scaled_font_create (font_face, &font_matrix, &ctm, options);
       cairo_font_face_destroy (font_face);

[-- Attachment #3: Type: text/plain, Size: 348 bytes --]


More context: I started trying out builds --with-cairo recently to
check out Emacs's support of multicolor fonts.  While these fonts seem
to work fine (emojis! 🙌), I found that the fonts for regular text
look… sharper?  In an aggressive-and-too-contrasted kind of way?

This screenshot shows the difference on one of my desktops[2]:


[-- Attachment #4: desktop.png --]
[-- Type: image/png, Size: 436576 bytes --]

[-- Attachment #5: Type: text/plain, Size: 234 bytes --]


Each frame is a different instance of 'emacs -Q'.  The left one is
configured without Cairo, the middle one --with-cairo *with my patch
applied*, the right one --with-cairo without my patch.

Same visual difference on my laptop[3]:


[-- Attachment #6: laptop.png --]
[-- Type: image/png, Size: 149721 bytes --]

[-- Attachment #7: Type: text/plain, Size: 9527 bytes --]


Each frame is a different instance of 'emacs -Q -fn "DejaVu Sans
Mono-9"'[4].  The left frame is configured --with-cairo, without my
patch; the top-right one is without cairo, the bottom-right
--with-cairo with my patch.

On the third setup I could test[5], all three builds look the same
AFAICT; no idea what this can be attributed to.


Does this patch look like something that can be applied
unconditionally?

- CAIRO_HINT_STYLE_SLIGHT has been available from version 1.0, and we
  require 1.12, so AFAICT the setting can be used without checking for
  any CAIRO_… feature.

- On the other hand, maybe this setting should be conditioned by a
  user option: as far as I could test, …_SLIGHT gives the "best"
  visual result[6], but maybe this is specific to my setups.

  I guess that a customizable option would need to specify a :set
  function tasked with making a few Cairo calls for the change to be
  effective without restarting; I have not spent much time looking at
  ftcrfont.c and its users yet, but I imagine that this hypothetical
  setter function should do something along the lines of:

  1. retrieve all 'struct font_info' objects created with
     ftcrfont_open,
  2. call cairo_scaled_font_get_font_options on their 'cr_scaled_font'
     field,
  3. call …set_hint_style on the returned options.

  (… This is absolutely untested guesswork.)


Caveat: I do not know the first thing about font rendering (or any
kind of rendering for that matter), nor font hinting.  This patch is
the result of me googling around for "cairo smooth font" and trying
out random snippets to tweak cairo_font_options_* knobs.  Some
snippets I have seen call …set_{antialias,subpixel_order} in
conjunction with …set_hint_style; as far as I tested, the former two
have no impact, so I left them out of the patch.


Let me know if I should provide more information (font configuration,
results after tweaking other settings… though I cannot access my
desktops until Monday), and thank you for your time!


[1] Objectively-speaking, the patch merely makes fonts "visually
    equivalent to the non-Cairo build"; whether it makes them "more
    readable" is a matter of taste I guess.

[2] OS: Xubuntu 16.04 (libcairo2: 1.14.6)
    xrandr digest: DP-2 1920x1080 509mm x 286mm
    emacs-repository-version: … probably a commit on master from these
                              past two weeks

[3] OS: Debian stretch (libcairo2: 1.14.8)
    xrandr digest: LVDS1 1024x600 230mm x 140mm
    emacs-repository-version: e0ee41d155b210327eb9c9ad5334f80ed59439f4

[4] emacs -Q defaults to a bigger font size than what I use, and the
    "sharpness" difference is less visible then.

[5] OS: openSUSE Tumbleweed (cairo: 1.16.0)
    xrandr digest: DVI-I-0 1680x1050 474mm x 296mm
    emacs-repository-version: … probably a commit on master from these
                              past two weeks

[6] Compiling with any other enum value looked equivalent to not
    setting this option at all IIRC.



In GNU Emacs 27.0.50 (build 3, i686-pc-linux-gnu, GTK+ Version 3.22.11)
 of 2019-05-13 built on nc10-laptop
Repository revision: d2d4916046e31e46598f0a0edbc65e75b8cb4cc3
Repository branch: master
Windowing system distributor 'The X.Org Foundation', version 11.0.11902000
System Description: BunsenLabs GNU/Linux 9.8 (Helium)

Recent messages:
nnimap read 178k from imap.gmail.com (initial sync of 11 groups; please wait)
nnimap read 222k from imap.gmail.com (initial sync of 11 groups; please wait)
nnimap read 257k from imap.gmail.com (initial sync of 11 groups; please wait)
Reading active file from archive via nnfolder...done
Reading active file via nndraft...done
Checking new news...done
nnimap read 0k from imap.gmail.com
No more unseen articles
Mark set
Quit [2 times]

Configured using:
 'configure --with-xwidgets'

Configured features:
XPM JPEG TIFF GIF PNG RSVG IMAGEMAGICK SOUND GPM DBUS GSETTINGS GLIB
NOTIFY INOTIFY ACL LIBSELINUX GNUTLS LIBXML2 FREETYPE M17N_FLT LIBOTF
XFT ZLIB TOOLKIT_SCROLL_BARS GTK3 X11 XDBE XIM THREADS XWIDGETS JSON
PDUMPER LCMS2 GMP

Important settings:
  value of $LANG: en_US.UTF-8
  locale-coding-system: utf-8-unix

Major mode: Summary

Minor modes in effect:
  global-magit-file-mode: t
  magit-auto-revert-mode: t
  global-git-commit-mode: t
  async-bytecomp-package-mode: t
  shell-dirtrack-mode: t
  show-paren-mode: t
  minibuffer-depth-indicate-mode: t
  icomplete-mode: t
  global-page-break-lines-mode: t
  page-break-lines-mode: t
  electric-pair-mode: t
  diff-hl-flydiff-mode: t
  global-diff-hl-mode: t
  delete-selection-mode: t
  tooltip-mode: t
  global-eldoc-mode: t
  electric-indent-mode: t
  mouse-wheel-mode: t
  file-name-shadow-mode: t
  global-font-lock-mode: t
  font-lock-mode: t
  blink-cursor-mode: t
  auto-composition-mode: t
  auto-encryption-mode: t
  auto-compression-mode: t
  buffer-read-only: t
  column-number-mode: t
  line-number-mode: t
  transient-mark-mode: t

Load-path shadows:
None found.

Features:
(shadow emacsbug rect cl-print debug backtrace magit-extras magit-patch
magit-subtree magit-ediff ediff-merg ediff-wind ediff-diff ediff-mult
ediff-help ediff-init ediff-util ediff org-indent org-rmail org-mhe
org-irc org-info org-gnus org-docview doc-view image-mode org-bibtex
bibtex org-bbdb org-w3m org-element avl-tree org org-macro org-footnote
org-pcomplete org-list org-faces org-entities org-version ob-emacs-lisp
ob ob-tangle org-src ob-ref ob-lob ob-table ob-keys ob-exp ob-comint
ob-core ob-eval org-compat org-macs org-loaddefs cal-menu calendar
cal-loaddefs bug-reference magit-submodule magit-obsolete magit-blame
magit-stash magit-reflog magit-bisect magit-push magit-pull magit-fetch
magit-clone magit-remote magit-commit magit-sequence magit-notes
magit-worktree magit-tag magit-merge magit-branch magit-reset
magit-files magit-refs magit-status magit magit-repos magit-apply
magit-wip magit-log which-func imenu magit-diff smerge-mode magit-core
magit-autorevert autorevert filenotify magit-margin magit-transient
magit-process magit-mode transient git-commit magit-git magit-section
log-edit pcvs-util add-log with-editor async-bytecomp async server
url-util sendmail nnir eieio-opt speedbar sb-image ezimage dframe
gnus-fun shr-color color shr svg dom browse-url sort gnus-cite
mm-archive mail-extr gnus-async gnus-bcklg qp gnus-ml nndraft nnmh
nnfolder utf-7 epa-file gnutls network-stream nsm gnus-agent gnus-srvr
gnus-score score-mode nnvirtual gnus-msg gnus-art mm-uu mml2015 mm-view
mml-smime smime dig mailcap nntp gnus-cache gnus-sum gnus-group
gnus-undo gnus-start gnus-cloud nnimap nnmail mail-source utf7 netrc
nnoo parse-time gnus-spec gnus-int gnus-range gnus-win gnus nnheader
find-func help-fns radix-tree conf-mode magit-utils crm dash jka-compr
pulse find-dired ffap etags fileloop generator xref cus-edit wid-edit
whitespace notifications dbus xml thingatpt noutline outline view
message rmc puny dired dired-loaddefs format-spec rfc822 mml mml-sec epa
derived epg gnus-util rmail rmail-loaddefs text-property-search
time-date mm-decode mm-bodies mm-encode mail-parse rfc2231 rfc2047
rfc2045 mm-util ietf-drums mail-prsvr mailabbrev mail-utils gmm-utils
mailheader flyspell ispell executable shell pcomplete misearch
multi-isearch vc-mtn vc-hg cc-mode cc-fonts cc-guess cc-menus cc-cmds
cc-styles cc-align cc-engine cc-vars cc-defs footnote rx vc-git vc-bzr
vc-src vc-sccs vc-svn vc-cvs vc-rcs project delight advice
eighters-theme quail cl-extra help-mode rg rg-ibuffer rg-result wgrep-rg
wgrep s rg-history rg-header rg-compat ibuf-ext ibuffer ibuffer-loaddefs
grep compile comint ansi-color ring edmacro kmacro disp-table paren
mb-depth icomplete page-break-lines elec-pair diff-hl-flydiff diff
diff-hl vc-dir ewoc vc vc-dispatcher diff-mode easy-mmode delsel
cus-start cus-load mule-util tex-site info package easymenu epg-config
url-handlers url-parse auth-source cl-seq eieio eieio-core cl-macs
eieio-loaddefs password-cache json subr-x map url-vars seq byte-opt gv
bytecomp byte-compile cconv cl-loaddefs cl-lib tooltip eldoc electric
uniquify ediff-hook vc-hooks lisp-float-type mwheel term/x-win x-win
term/common-win x-dnd tool-bar dnd fontset image regexp-opt fringe
tabulated-list replace newcomment text-mode elisp-mode lisp-mode
prog-mode register page menu-bar rfn-eshadow isearch timer select
scroll-bar mouse jit-lock font-lock syntax facemenu font-core
term/tty-colors frame cl-generic cham georgian utf-8-lang misc-lang
vietnamese tibetan thai tai-viet lao korean japanese eucjp-ms cp51932
hebrew greek romanian slovak czech european ethiopic indian cyrillic
chinese composite charscript charprop case-table epa-hook jka-cmpr-hook
help simple abbrev obarray minibuffer cl-preloaded nadvice loaddefs
button faces cus-face macroexp files text-properties overlay sha1 md5
base64 format env code-pages mule custom widget hashtable-print-readable
backquote threads dbusbind inotify lcms2 dynamic-setting
system-font-setting font-render-setting xwidget-internal move-toolbar
gtk x-toolkit x multi-tty make-network-process emacs)

Memory information:
((conses 8 510108 60620)
 (symbols 24 35458 1)
 (strings 16 125803 16010)
 (string-bytes 1 4146628)
 (vectors 8 59808)
 (vector-slots 4 1472134 107810)
 (floats 8 508 454)
 (intervals 28 32090 73)
 (buffers 564 69))

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* bug#35781: 27.0.50; [PATCH] Improve font display on Cairo builds
  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-18 20:43 ` bug#35781: Discrepancies between xftfont.c and ftcrfont.c Kévin Le Gouguec
  1 sibling, 1 reply; 12+ messages in thread
From: Dmitry Gutov @ 2019-05-17 17:54 UTC (permalink / raw)
  To: Kévin Le Gouguec, 35781

On 17.05.2019 20:39, Kévin Le Gouguec wrote:
> - CAIRO_HINT_STYLE_SLIGHT has been available from version 1.0, and we
>    require 1.12, so AFAICT the setting can be used without checking for
>    any CAIRO_… feature.

Isn't font hinting something that the user sets in their global display 
configuration? With different people preferring different levels of hinting.





^ permalink raw reply	[flat|nested] 12+ messages in thread

* bug#35781: 27.0.50; [PATCH] Improve font display on Cairo builds
  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
  0 siblings, 2 replies; 12+ messages in thread
From: Kévin Le Gouguec @ 2019-05-17 18:14 UTC (permalink / raw)
  To: Dmitry Gutov; +Cc: 35781

Dmitry Gutov <dgutov@yandex.ru> writes:

> Isn't font hinting something that the user sets in their global
> display configuration? With different people preferring different
> levels of hinting.

Possibly?  Though AFAICT on my setups, font hinting in Emacs varies just
by enabling --with-cairo; I am fairly sure my "global display
configuration" remained unchanged while testing this (if by global you
mean "system-wide", or "independent of Emacs's configuration").

So naively, if I didn't explicitly change this global configuration, I
would expect any difference in display in Emacs to be Emacs's
responsibility…

Of course, I may be missing something.





^ permalink raw reply	[flat|nested] 12+ messages in thread

* bug#35781: 27.0.50; [PATCH] Improve font display on Cairo builds
  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
  1 sibling, 0 replies; 12+ messages in thread
From: Kévin Le Gouguec @ 2019-05-17 18:23 UTC (permalink / raw)
  To: Dmitry Gutov; +Cc: 35781

Kévin Le Gouguec <kevin.legouguec@gmail.com> writes:

> Dmitry Gutov <dgutov@yandex.ru> writes:
>
>> Isn't font hinting something that the user sets in their global
>> display configuration? With different people preferring different
>> levels of hinting.

Ah-ha!  Just noticed some hint-related code in xftfont.c and xsettings.c
which seems to be responsible for applying this global configuration.
Now to investigate why the end result differs in the Cairo build…





^ permalink raw reply	[flat|nested] 12+ messages in thread

* bug#35781: 27.0.50; [PATCH] Improve font display on Cairo builds
  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
  1 sibling, 0 replies; 12+ messages in thread
From: Dmitry Gutov @ 2019-05-17 18:24 UTC (permalink / raw)
  To: Kévin Le Gouguec; +Cc: 35781

On 17.05.2019 21:14, Kévin Le Gouguec wrote:
> Though AFAICT on my setups, font hinting in Emacs varies just
> by enabling --with-cairo;

That might mean that Cairo doesn't follow the system font hinting 
configuration, and that should be fixed.

Hopefully someone more knowledgeable will tell us more.





^ permalink raw reply	[flat|nested] 12+ messages in thread

* bug#35781: Discrepancies between xftfont.c and ftcrfont.c
  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-18 20:43 ` Kévin Le Gouguec
  2019-05-19 19:48   ` Alex Gramiak
  1 sibling, 1 reply; 12+ messages in thread
From: Kévin Le Gouguec @ 2019-05-18 20:43 UTC (permalink / raw)
  To: 35781

retitle 35781 Make Cairo build obey hint-style font setting
thanks

I am nowhere close to a proper fix, but at least I think I am starting
to get a clearer picture of the situation.

The distribution installed on my laptop sets the "hint-style" font
setting to "slight" in both ~/.config/fontconfig/fonts.conf and
~/.Xresources.  AFAICU fontconfig and X resources are two (competing?)
mechanisms that tell graphical applications what fonts and font
settings they should use.  OK.

I am still studying the lay of the land; I see that xftfont_open in
xftfont.c calls xftfont_add_rendering_parameters, which has a bunch of
hint-style-related code calling fontconfig functions, while
ftcrfont_open in ftcrfont.c seems blissfully unaware of fontconfig.

At this point I am assuming that only ftcrfont.c is used in Cairo
builds, since config.h does not define HAVE_XFT, but my knowledge of
font management in Emacs is pretty lacking so I will have to check this
assumption.

As I said, I am far from being able to cook up any sort of patch at
this point; I still intend to keep digging Soonish™, but since that
may take a while, I figured I would update this report with whatever
information I gathered this far for posterity.





^ permalink raw reply	[flat|nested] 12+ messages in thread

* bug#35781: Discrepancies between xftfont.c and ftcrfont.c
  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
  0 siblings, 1 reply; 12+ messages in thread
From: Alex Gramiak @ 2019-05-19 19:48 UTC (permalink / raw)
  To: Kévin Le Gouguec; +Cc: 35781

Kévin Le Gouguec <kevin.legouguec@gmail.com> writes:

> retitle 35781 Make Cairo build obey hint-style font setting
> thanks
>
> I am nowhere close to a proper fix, but at least I think I am starting
> to get a clearer picture of the situation.
>
> The distribution installed on my laptop sets the "hint-style" font
> setting to "slight" in both ~/.config/fontconfig/fonts.conf and
> ~/.Xresources.  AFAICU fontconfig and X resources are two (competing?)
> mechanisms that tell graphical applications what fonts and font
> settings they should use.  OK.
>
> I am still studying the lay of the land; I see that xftfont_open in
> xftfont.c calls xftfont_add_rendering_parameters, which has a bunch of
> hint-style-related code calling fontconfig functions, while
> ftcrfont_open in ftcrfont.c seems blissfully unaware of fontconfig.
>
> At this point I am assuming that only ftcrfont.c is used in Cairo
> builds, since config.h does not define HAVE_XFT, but my knowledge of
> font management in Emacs is pretty lacking so I will have to check this
> assumption.
>
> As I said, I am far from being able to cook up any sort of patch at
> this point; I still intend to keep digging Soonish™, but since that
> may take a while, I figured I would update this report with whatever
> information I gathered this far for posterity.

Perhaps ftcrfont.c could use FcPatternAddFTFace, FcFontMatch,
cairo_ft_font_face_create_for_pattern, and otherwise the same pattern
building as xftfont.c.





^ permalink raw reply	[flat|nested] 12+ messages in thread

* bug#35781: Discrepancies between xftfont.c and ftcrfont.c
  2019-05-19 19:48   ` Alex Gramiak
@ 2019-05-21 10:59     ` mituharu
  2019-05-21 19:03       ` Kévin Le Gouguec
  0 siblings, 1 reply; 12+ messages in thread
From: mituharu @ 2019-05-21 10:59 UTC (permalink / raw)
  To: Alex Gramiak; +Cc: 35781, K?vin Le Gouguec

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

> Perhaps ftcrfont.c could use FcPatternAddFTFace, FcFontMatch,
> cairo_ft_font_face_create_for_pattern, and otherwise the same pattern
> building as xftfont.c.

I tried making ftcrfont_open look much like xftfont_open.
Could you try the attached patch?

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

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

diff --git a/src/ftcrfont.c b/src/ftcrfont.c
index 2d5a7665578..7a08961847c 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,154 @@ 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);
+  ft_face = cairo_ft_scaled_font_lock_face (scaled_font);
+  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))))
+	  if (glyphs != &stack_glyph)
+	    cairo_glyph_free (glyphs);
+	  else if (stack_glyph.index)
 	    {
-	      font->descent = lround (extents.descent);
-	      font->height = font->ascent + font->descent;
-	    }
-	  else
-	    {
-	      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;
-	}
+  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 */
+  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 +275,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 ();
+}
 
-  ftfont_close (font);
+static int
+ftcrfont_has_char (Lisp_Object font, int c)
+{
+  if (FONT_ENTITY_P (font))
+    return ftfont_has_char (font, c);
+
+  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
@@ -279,11 +368,15 @@ 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;
+  cairo_scaled_font_t *scaled_font = ftcrfont_info->cr_scaled_font;
+  FT_Face ft_face = cairo_ft_scaled_font_lock_face (scaled_font);
 
-  if (ftcrfont_info->bitmap_strike_index < 0)
-    return ftfont_get_bitmap (font, code, bitmap, bits_per_pixel);
+  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 -1;
+  return result;
 }
 
 static int
@@ -291,26 +384,69 @@ ftcrfont_anchor_point (struct font *font, unsigned int code, int idx,
 		       int *x, int *y)
 {
   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);
 
-  if (ftcrfont_info->bitmap_strike_index < 0)
-    return ftfont_anchor_point (font, code, idx, x, y);
+  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 -1;
+  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);
+  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 +457,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 +485,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 +507,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..639cc6c132e 100644
--- a/src/ftfont.c
+++ b/src/ftfont.c
@@ -1079,6 +1079,156 @@ 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);
+    }
+}
+
+static 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,
@@ -1097,7 +1247,6 @@ 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,32 +1275,12 @@ 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++;
 
@@ -1164,7 +1293,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;
@@ -1268,19 +1396,7 @@ 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);
-  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;
+  return ftfont_open2 (f, entity, pixel_size, font_object);
 }
 
 void
@@ -2789,6 +2905,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..de4e60f9aea 100644
--- a/src/ftfont.h
+++ b/src/ftfont.h
@@ -41,6 +41,8 @@ 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 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 +56,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
   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;
   /* Font metrics cache.  */
   struct font_metrics **metrics;
   short metrics_nrows;
diff --git a/src/xftfont.c b/src/xftfont.c
index 2edc51fe356..e5e237d1d4d 100644
--- a/src/xftfont.c
+++ b/src/xftfont.c
@@ -127,59 +127,6 @@ 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)
 {
@@ -233,14 +180,13 @@ 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 +196,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);
@@ -768,12 +679,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,

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* bug#35781: Discrepancies between xftfont.c and ftcrfont.c
  2019-05-21 10:59     ` mituharu
@ 2019-05-21 19:03       ` Kévin Le Gouguec
  2019-05-22  9:24         ` YAMAMOTO Mitsuharu
  0 siblings, 1 reply; 12+ messages in thread
From: Kévin Le Gouguec @ 2019-05-21 19:03 UTC (permalink / raw)
  To: mituharu; +Cc: 35781, Alex Gramiak

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].

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?)

(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?)

(Sorry for these Boeotian questions!)

Again, thanks a lot for this patch!



[1] Debian stretch (cairo 1.14.8) and Xubuntu 16.04 (cairo 1.14.6).

[2] OpenSUSE Tumbleweed (cairo 1.16.0).






^ permalink raw reply	[flat|nested] 12+ messages in thread

* bug#35781: Discrepancies between xftfont.c and ftcrfont.c
  2019-05-21 19:03       ` Kévin Le Gouguec
@ 2019-05-22  9:24         ` YAMAMOTO Mitsuharu
  2019-05-23  2:00           ` YAMAMOTO Mitsuharu
  0 siblings, 1 reply; 12+ messages in thread
From: YAMAMOTO Mitsuharu @ 2019-05-22  9:24 UTC (permalink / raw)
  To: Kévin Le Gouguec; +Cc: 35781, Alex Gramiak

[-- 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,

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* bug#35781: Discrepancies between xftfont.c and ftcrfont.c
  2019-05-22  9:24         ` YAMAMOTO Mitsuharu
@ 2019-05-23  2:00           ` YAMAMOTO Mitsuharu
  2019-05-23 17:53             ` Kévin Le Gouguec
  0 siblings, 1 reply; 12+ messages in thread
From: YAMAMOTO Mitsuharu @ 2019-05-23  2:00 UTC (permalink / raw)
  To: Kévin Le Gouguec; +Cc: Alex Gramiak, 35781-done

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

Done at 03feb9376b5 and b40dde705af.

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





^ permalink raw reply	[flat|nested] 12+ messages in thread

* bug#35781: Discrepancies between xftfont.c and ftcrfont.c
  2019-05-23  2:00           ` YAMAMOTO Mitsuharu
@ 2019-05-23 17:53             ` Kévin Le Gouguec
  0 siblings, 0 replies; 12+ messages in thread
From: Kévin Le Gouguec @ 2019-05-23 17:53 UTC (permalink / raw)
  To: YAMAMOTO Mitsuharu; +Cc: Alex Gramiak, 35781-done

YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp> writes:

>> I'll push the updated one to master and also adapt it for the harfbuzz
>> branch in 15 hours or so.
>
> Done at 03feb9376b5 and b40dde705af.
>
> 				     YAMAMOTO Mitsuharu
> 				mituharu@math.s.chiba-u.ac.jp

I've built the master and harfbuzz branches on my Debian stretch and
Xubuntu 16.04 setups, and everything looks peachy.

Thanks a lot for this patch, and for keeping the harfbuzz branch
up-to-date!





^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2019-05-23 17:53 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
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
2019-05-23  2:00           ` YAMAMOTO Mitsuharu
2019-05-23 17:53             ` Kévin Le Gouguec

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).