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