diff options
Diffstat (limited to 'src/ftcrfont.c')
-rw-r--r-- | src/ftcrfont.c | 665 |
1 files changed, 559 insertions, 106 deletions
diff --git a/src/ftcrfont.c b/src/ftcrfont.c index ad68ce8cebb..a02ff99870e 100644 --- a/src/ftcrfont.c +++ b/src/ftcrfont.c @@ -1,5 +1,5 @@ /* ftcrfont.c -- FreeType font driver on cairo. - Copyright (C) 2015-2017 Free Software Foundation, Inc. + Copyright (C) 2015-2022 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -18,41 +18,34 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ #include <config.h> -#include <stdio.h> +#include <math.h> #include <cairo-ft.h> #include "lisp.h" +#ifdef HAVE_X_WINDOWS #include "xterm.h" +#elif HAVE_HAIKU +#include "haikuterm.h" +#include "haiku_support.h" +#include "termchar.h" +#else +#include "pgtkterm.h" +#endif #include "blockinput.h" +#include "charset.h" +#include "composite.h" #include "font.h" #include "ftfont.h" +#include "pdumper.h" +#ifdef HAVE_PGTK +#include "xsettings.h" +#endif -/* FTCR font driver. */ - -/* The actual structure for FTCR font. A pointer to this structure - can be cast to struct font *. */ - -struct ftcrfont_info -{ - struct font font; - /* The following six members must be here in this order to be - compatible with struct ftfont_info (in ftfont.c). */ -#ifdef HAVE_LIBOTF - bool maybe_otf; /* Flag to tell if this may be OTF or not. */ - OTF *otf; -#endif /* HAVE_LIBOTF */ - FT_Size ft_size; - int index; - FT_Matrix matrix; - - cairo_font_face_t *cr_font_face; - /* 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; -}; +#ifdef USE_BE_CAIRO +#define RED_FROM_ULONG(color) (((color) >> 16) & 0xff) +#define GREEN_FROM_ULONG(color) (((color) >> 8) & 0xff) +#define BLUE_FROM_ULONG(color) ((color) & 0xff) +#endif #define METRICS_NCOLS_PER_ROW (128) @@ -70,7 +63,7 @@ ftcrfont_glyph_extents (struct font *font, unsigned glyph, struct font_metrics *metrics) { - struct ftcrfont_info *ftcrfont_info = (struct ftcrfont_info *) font; + struct font_info *ftcrfont_info = (struct font_info *) font; int row, col; struct font_metrics *cache; @@ -99,7 +92,23 @@ ftcrfont_glyph_extents (struct font *font, cache = ftcrfont_info->metrics[row] + col; if (METRICS_STATUS (cache) == METRICS_INVALID) - ftfont_text_extents (font, &glyph, 1, cache); + { + cairo_glyph_t cr_glyph = {.index = glyph}; + cairo_text_extents_t extents; + + cairo_scaled_font_glyph_extents (ftcrfont_info->cr_scaled_font, + &cr_glyph, 1, &extents); + cache->lbearing = floor (extents.x_bearing); + cache->rbearing = ceil (extents.width + extents.x_bearing); + cache->width = lround (extents.x_advance); + /* The subtraction of a small number is to avoid rounding up due + to floating-point inaccuracies with some fonts, which then + could cause unpleasant effects while scrolling (see bug + #44284), since we then think that a glyph row's ascent is too + small to accommodate a glyph with a higher phys_ascent. */ + cache->ascent = ceil (- extents.y_bearing - 1.0 / 256); + cache->descent = ceil (extents.height + extents.y_bearing); + } if (metrics) *metrics = *cache; @@ -110,79 +119,285 @@ ftcrfont_glyph_extents (struct font *font, static Lisp_Object ftcrfont_list (struct frame *f, Lisp_Object spec) { - Lisp_Object list = ftfont_list (f, spec), tail; - - for (tail = list; CONSP (tail); tail = XCDR (tail)) - ASET (XCAR (tail), FONT_TYPE_INDEX, Qftcr); - return list; + return ftfont_list2 (f, spec, Qftcr); } static Lisp_Object ftcrfont_match (struct frame *f, Lisp_Object spec) { - Lisp_Object entity = ftfont_match (f, spec); - - if (VECTORP (entity)) - ASET (entity, FONT_TYPE_INDEX, Qftcr); - return entity; + return ftfont_match2 (f, spec, Qftcr); } static Lisp_Object ftcrfont_open (struct frame *f, Lisp_Object entity, int pixel_size) { - Lisp_Object font_object; + FcResult result; + Lisp_Object val, filename, font_object; + FcPattern *pat, *match; + struct font_info *ftcrfont_info; struct font *font; - struct ftcrfont_info *ftcrfont_info; + double size = 0; + cairo_font_face_t *font_face; + cairo_font_extents_t extents; FT_Face ft_face; - FT_UInt size; - - block_input (); - size = XINT (AREF (entity, FONT_SIZE_INDEX)); + 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; - font_object = font_build_object (VECSIZE (struct ftcrfont_info), - Qftcr, entity, size); - font_object = ftfont_open2 (f, entity, pixel_size, font_object); - if (NILP (font_object)) return Qnil; + 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 + || cairo_font_face_status (font_face) != CAIRO_STATUS_SUCCESS) + { + 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); + +#ifdef HAVE_PGTK + cairo_font_options_t *options = xsettings_get_font_options (); +#else + cairo_font_options_t *options = cairo_font_options_create (); +#endif +#ifdef USE_BE_CAIRO + if (be_use_subpixel_antialiasing ()) + cairo_font_options_set_antialias (options, CAIRO_ANTIALIAS_SUBPIXEL); +#endif + 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 (); + if (!scaled_font + || cairo_scaled_font_status (scaled_font) != CAIRO_STATUS_SUCCESS) + { + FcPatternDestroy (match); + return Qnil; + } + ft_face = cairo_ft_scaled_font_lock_face (scaled_font); + if (!ft_face) + { + FcPatternDestroy (match); + return Qnil; + } + + font_object = font_build_object (VECSIZE (struct font_info), + AREF (entity, FONT_TYPE_INDEX), + entity, size); + ASET (font_object, FONT_FILE_INDEX, filename); font = XFONT_OBJECT (font_object); + font->pixel_size = size; +#ifdef HAVE_HARFBUZZ + if (EQ (AREF (font_object, FONT_TYPE_INDEX), Qftcrhb)) + font->driver = &ftcrhbfont_driver; + else +#endif /* HAVE_HARFBUZZ */ font->driver = &ftcrfont_driver; - ftcrfont_info = (struct ftcrfont_info *) font; - ft_face = ftcrfont_info->ft_size->face; - FT_New_Size (ft_face, &ftcrfont_info->ft_size_draw); - FT_Activate_Size (ftcrfont_info->ft_size_draw); - FT_Set_Pixel_Sizes (ft_face, 0, font->pixel_size); - ftcrfont_info->cr_font_face = - cairo_ft_font_face_create_for_ft_face (ft_face, 0); + 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 (); + cairo_glyph_t stack_glyph; + font->min_width = font->max_width = 0; + 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); + + /* In order to simulate the Xft behavior, we use metrics of + glyph ID 0 if there is no glyph for an ASCII printable. */ + if (status != CAIRO_STATUS_SUCCESS) + stack_glyph.index = 0; + else if (glyphs != &stack_glyph) + { + cairo_glyph_free (glyphs); + stack_glyph.index = 0; + } + 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 (this_width > font->max_width) + font->max_width = this_width; + if (c == 32) + font->space_width = this_width; + font->average_width += this_width; + } + font->average_width /= 95; + + 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; + } + + 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 */ +#ifdef HAVE_HARFBUZZ + ftcrfont_info->hb_font = NULL; +#endif /* HAVE_HARFBUZZ */ + 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; + eassert (font->max_width < 512 * 1024 * 1024); + return font_object; } static void ftcrfont_close (struct font *font) { - struct ftcrfont_info *ftcrfont_info = (struct ftcrfont_info *) font; - int i; + if (font_data_structures_may_be_ill_formed ()) + return; + + struct font_info *ftcrfont_info = (struct font_info *) font; 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 +#ifdef HAVE_HARFBUZZ + if (ftcrfont_info->hb_font) + { + hb_font_destroy (ftcrfont_info->hb_font); + ftcrfont_info->hb_font = 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_font_face_destroy (ftcrfont_info->cr_font_face); + 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); + + struct charset *cs = NULL; + + if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qja) + && charset_jisx0208 >= 0) + cs = CHARSET_FROM_ID (charset_jisx0208); + else if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qko) + && charset_ksc5601 >= 0) + cs = CHARSET_FROM_ID (charset_ksc5601); + if (cs) + return (ENCODE_CHAR (cs, c) != CHARSET_INVALID_CODE (cs)); + + 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]; + int utf8len = CHAR_STRING (c, utf8); + cairo_glyph_t stack_glyph; + cairo_glyph_t *glyphs = &stack_glyph; + int num_glyphs = 1; + + if (cairo_scaled_font_text_to_glyphs (ftcrfont_info->cr_scaled_font, 0, 0, + (char *) utf8, utf8len, + &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 ftcrfont_text_extents (struct font *font, - unsigned *code, + const unsigned *code, int nglyphs, struct font_metrics *metrics) { @@ -215,69 +430,282 @@ ftcrfont_text_extents (struct font *font, } static int +ftcrfont_get_bitmap (struct font *font, unsigned int code, + struct font_bitmap *bitmap, int bits_per_pixel) +{ + struct font_info *ftcrfont_info = (struct font_info *) font; + + if (ftcrfont_info->bitmap_position_unit) + 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 +ftcrfont_anchor_point (struct font *font, unsigned int code, int idx, + int *x, int *y) +{ + struct font_info *ftcrfont_info = (struct font_info *) font; + + if (ftcrfont_info->bitmap_position_unit) + 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_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, Lisp_Object direction) +{ + struct font *font = CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring)); + struct font_info *ftcrfont_info = (struct font_info *) font; + + 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, direction); + cairo_ft_scaled_font_unlock_face (scaled_font); + ftcrfont_info->ft_size = NULL; + + return result; +} +#endif + +#if defined HAVE_OTF_GET_VARIATION_GLYPHS || defined HAVE_FT_FACE_GETCHARVARIANTINDEX +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 || HAVE_FT_FACE_GETCHARVARIANTINDEX */ + +static int ftcrfont_draw (struct glyph_string *s, int from, int to, int x, int y, bool with_background) { struct frame *f = s->f; - struct face *face = s->face; - struct ftcrfont_info *ftcrfont_info = (struct ftcrfont_info *) s->font; + 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; +#ifdef USE_BE_CAIRO + unsigned long be_foreground, be_background; + + if (s->hl != DRAW_CURSOR) + { + be_foreground = s->face->foreground; + be_background = s->face->background; + } + else + haiku_merge_cursor_foreground (s, &be_foreground, + &be_background); +#endif block_input (); +#ifndef USE_BE_CAIRO +#ifdef HAVE_X_WINDOWS cr = x_begin_cr_clip (f, s->gc); +#else + cr = pgtk_begin_cr_clip (f); +#endif +#else + /* Presumably the draw lock is already held by + haiku_draw_glyph_string. */ + EmacsWindow_begin_cr_critical_section (FRAME_HAIKU_WINDOW (f)); + cr = haiku_begin_cr_clip (f, s); + if (!cr) + { + EmacsWindow_end_cr_critical_section (FRAME_HAIKU_WINDOW (f)); + unblock_input (); + return 0; + } + BView_cr_dump_clipping (FRAME_HAIKU_DRAWABLE (f), cr); +#endif if (with_background) { - x_set_cr_source_with_gc_background (f, s->gc); - cairo_rectangle (cr, x, y - FONT_BASE (face->font), - s->width, FONT_HEIGHT (face->font)); +#ifndef USE_BE_CAIRO +#ifdef HAVE_X_WINDOWS + x_set_cr_source_with_gc_background (f, s->gc, s->hl != DRAW_CURSOR); +#else + pgtk_set_cr_source_with_color (f, s->xgcv.background, + s->hl != DRAW_CURSOR); +#endif +#else + uint32_t col = be_background; + + cairo_set_source_rgb (cr, RED_FROM_ULONG (col) / 255.0, + GREEN_FROM_ULONG (col) / 255.0, + BLUE_FROM_ULONG (col) / 255.0); +#endif + s->background_filled_p = 1; + cairo_rectangle (cr, x, y - FONT_BASE (s->font), + s->width, FONT_HEIGHT (s->font)); cairo_fill (cr); } glyphs = alloca (sizeof (cairo_glyph_t) * len); for (i = 0; i < len; i++) { - unsigned code = ((XCHAR2B_BYTE1 (s->char2b + from + i) << 8) - | XCHAR2B_BYTE2 (s->char2b + from + i)); - - glyphs[i].index = code; + glyphs[i].index = s->char2b[from + i]; glyphs[i].x = x; glyphs[i].y = y; - x += (s->padding_p ? 1 : ftcrfont_glyph_extents (s->font, code, NULL)); + x += (s->padding_p ? 1 : ftcrfont_glyph_extents (s->font, + glyphs[i].index, + NULL)); } +#ifndef USE_BE_CAIRO +#ifdef HAVE_X_WINDOWS + x_set_cr_source_with_gc_foreground (f, s->gc, false); +#else + pgtk_set_cr_source_with_color (f, s->xgcv.foreground, false); +#endif +#else + uint32_t col = be_foreground; - x_set_cr_source_with_gc_foreground (f, s->gc); - cairo_set_font_face (cr, ftcrfont_info->cr_font_face); - cairo_set_font_size (cr, s->font->pixel_size); - /* cairo_set_font_matrix */ - /* cairo_set_font_options */ - - FT_Activate_Size (ftcrfont_info->ft_size_draw); + cairo_set_source_rgb (cr, RED_FROM_ULONG (col) / 255.0, + GREEN_FROM_ULONG (col) / 255.0, + BLUE_FROM_ULONG (col) / 255.0); +#endif + cairo_set_scaled_font (cr, ftcrfont_info->cr_scaled_font); 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); - +#ifndef USE_BE_CAIRO +#ifdef HAVE_X_WINDOWS x_end_cr_clip (f); - +#else + pgtk_end_cr_clip (f); +#endif +#else + haiku_end_cr_clip (cr); + EmacsWindow_end_cr_critical_section (FRAME_HAIKU_WINDOW (f)); +#endif unblock_input (); return len; } +#ifdef HAVE_PGTK +/* Determine if FONT_OBJECT is a valid cached font for ENTITY by + comparing the options used to open it with the user's current + preferences specified via GSettings. */ +static bool +ftcrfont_cached_font_ok (struct frame *f, Lisp_Object font_object, + Lisp_Object entity) +{ + struct font_info *info = (struct font_info *) XFONT_OBJECT (font_object); + + cairo_font_options_t *options = cairo_font_options_create (); + cairo_scaled_font_get_font_options (info->cr_scaled_font, options); + cairo_font_options_t *gsettings_options = xsettings_get_font_options (); + + bool equal = cairo_font_options_equal (options, gsettings_options); + cairo_font_options_destroy (options); + cairo_font_options_destroy (gsettings_options); + + return equal; +} +#endif + +#ifdef HAVE_HARFBUZZ + +static Lisp_Object +ftcrhbfont_list (struct frame *f, Lisp_Object spec) +{ + return ftfont_list2 (f, spec, Qftcrhb); +} + +static Lisp_Object +ftcrhbfont_match (struct frame *f, Lisp_Object spec) +{ + return ftfont_match2 (f, spec, Qftcrhb); +} + +static hb_font_t * +ftcrhbfont_begin_hb_font (struct font *font, double *position_unit) +{ + 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; + hb_font_t *hb_font = fthbfont_begin_hb_font (font, position_unit); + /* HarfBuzz 5 correctly scales bitmap-only fonts without position + unit adjustment. + (https://github.com/harfbuzz/harfbuzz/issues/489) + + Update: HarfBuzz 5.2.0 no longer does this for an hb_font_t font + object created from a given FT_Face. + (https://github.com/harfbuzz/harfbuzz/issues/3788) */ + if ((hb_version_atleast (5, 2, 0) || !hb_version_atleast (5, 0, 0)) + && ftcrfont_info->bitmap_position_unit) + *position_unit = ftcrfont_info->bitmap_position_unit; + + return hb_font; +} + +static void +ftcrhbfont_end_hb_font (struct font *font, hb_font_t *hb_font) +{ + struct font_info *ftcrfont_info = (struct font_info *) font; + cairo_scaled_font_t *scaled_font = ftcrfont_info->cr_scaled_font; + + cairo_ft_scaled_font_unlock_face (scaled_font); + ftcrfont_info->ft_size = NULL; +} + +#endif /* HAVE_HARFBUZZ */ +static void syms_of_ftcrfont_for_pdumper (void); + struct font_driver const ftcrfont_driver = { .type = LISPSYM_INITIALLY (Qftcr), @@ -285,33 +713,58 @@ struct font_driver const ftcrfont_driver = .list = ftcrfont_list, .match = ftcrfont_match, .list_family = ftfont_list_family, - .open = ftcrfont_open, - .close = ftcrfont_close, - .has_char = ftfont_has_char, - .encode_char = ftfont_encode_char, + .open_font = ftcrfont_open, + .close_font = ftcrfont_close, + .has_char = ftcrfont_has_char, + .encode_char = ftcrfont_encode_char, .text_extents = ftcrfont_text_extents, .draw = ftcrfont_draw, - .get_bitmap = ftfont_get_bitmap, - .anchor_point = ftfont_anchor_point, + .get_bitmap = ftcrfont_get_bitmap, + .anchor_point = ftcrfont_anchor_point, #ifdef HAVE_LIBOTF - .otf_capability = ftfont_otf_capability, + .otf_capability = ftcrfont_otf_capability, #endif #if defined HAVE_M17N_FLT && defined HAVE_LIBOTF - .shape = ftfont_shape, + .shape = ftcrfont_shape, #endif -#ifdef HAVE_OTF_GET_VARIATION_GLYPHS - .get_variation_glyphs = ftfont_variation_glyphs, +#if defined HAVE_OTF_GET_VARIATION_GLYPHS || defined HAVE_FT_FACE_GETCHARVARIANTINDEX + .get_variation_glyphs = ftcrfont_variation_glyphs, #endif .filter_properties = ftfont_filter_properties, .combining_capability = ftfont_combining_capability, +#ifdef HAVE_PGTK + .cached_font_ok = ftcrfont_cached_font_ok +#endif }; +#ifdef HAVE_HARFBUZZ +struct font_driver ftcrhbfont_driver; +#endif /* HAVE_HARFBUZZ */ void syms_of_ftcrfont (void) { - if (ftfont_info_size != offsetof (struct ftcrfont_info, cr_font_face)) - abort (); - DEFSYM (Qftcr, "ftcr"); +#ifdef HAVE_HARFBUZZ + DEFSYM (Qftcrhb, "ftcrhb"); + Fput (Qftcr, Qfont_driver_superseded_by, Qftcrhb); +#endif /* HAVE_HARFBUZZ */ + pdumper_do_now_and_after_load (syms_of_ftcrfont_for_pdumper); +} + +static void +syms_of_ftcrfont_for_pdumper (void) +{ register_font_driver (&ftcrfont_driver, NULL); +#ifdef HAVE_HARFBUZZ + ftcrhbfont_driver = ftcrfont_driver; + ftcrhbfont_driver.type = Qftcrhb; + ftcrhbfont_driver.list = ftcrhbfont_list; + ftcrhbfont_driver.match = ftcrhbfont_match; + ftcrhbfont_driver.otf_capability = hbfont_otf_capability; + ftcrhbfont_driver.shape = hbfont_shape; + ftcrhbfont_driver.combining_capability = hbfont_combining_capability; + ftcrhbfont_driver.begin_hb_font = ftcrhbfont_begin_hb_font; + ftcrhbfont_driver.end_hb_font = ftcrhbfont_end_hb_font; + register_font_driver (&ftcrhbfont_driver, NULL); +#endif /* HAVE_HARFBUZZ */ } |