]> git.eshelyaron.com Git - emacs.git/commitdiff
Move common HarfBuzz code to a common file hbfont.c
authorEli Zaretskii <eliz@gnu.org>
Sat, 1 Jun 2019 09:53:41 +0000 (12:53 +0300)
committerEli Zaretskii <eliz@gnu.org>
Sat, 1 Jun 2019 09:53:41 +0000 (12:53 +0300)
* src/hbfont.c: New file, with code moved from w32uniscribe.c
and renamed/modified as appropriate.
* src/w32uniscribe.c: Move to hbfont.c DEF_DLL_FN and macro
definitions for HarfBuzz functions used in hbfont.c
(load_harfbuzz_funcs): Move loading of HarfBuzz functions used
by hbfont.c to hbfont.c:hbfont_init_w32_funcs, and call that
function from here.
(syms_of_w32uniscribe_for_pdumper): Fill the 'shape' and
'combining_capability' members with hbfont.c function names.
* src/w32common.h (hbfont_init_w32_funcs) [HAVE_HARFBUZZ]: Add
prototype.
* src/font.h (hbfont_shape, hbfont_combining_capability)
[HAVE_HARFBUZZ]: Add prototypes.
* src/Makefile.in (SOME_MACHINE_OBJECTS): Add hbfont.o.

* configure.ac (FONT_OBJ): Add hbfont.o if HAVE_HARFBUZZ.

configure.ac
src/Makefile.in
src/font.h
src/hbfont.c [new file with mode: 0644]
src/w32common.h
src/w32uniscribe.c

index ab6b03f5462e2e9e580a8fa5879740bac0ea07a3..b228571c177482211928e12b7b70eed46047f541 100644 (file)
@@ -5260,8 +5260,11 @@ if test "${HAVE_X_WINDOWS}" = "yes" ; then
   elif test "$HAVE_FREETYPE" = "yes"; then
     FONT_OBJ="$FONT_OBJ ftfont.o ftxfont.o"
   fi
-  AC_SUBST(FONT_OBJ)
 fi
+if test "${HAVE_HARFBUZZ}" = "yes" ; then
+  FONT_OBJ="$FONT_OBJ hbfont.o"
+fi
+AC_SUBST(FONT_OBJ)
 AC_SUBST(XMENU_OBJ)
 AC_SUBST(XOBJ)
 AC_SUBST(FONT_OBJ)
index 512738840eac36c157ee801e99d7f37b29e4b4fb..be769458d37f385416f94fa4816f01aa5018eccb 100644 (file)
@@ -299,6 +299,7 @@ W32_RES_LINK=@W32_RES_LINK@
 ## xfont.o ftfont.o ftxfont.o if HAVE_FREETYPE
 ## ftfont.o ftcrfont.o if USE_CAIRO
 ## else xfont.o
+## if HAVE_HARFBUZZ, hbfont.o is added regardless of the rest
 FONT_OBJ=@FONT_OBJ@
 
 ## Empty for MinGW, cm.o for the rest.
@@ -431,7 +432,7 @@ SOME_MACHINE_OBJECTS = dosfns.o msdos.o \
   w32.o w32console.o w32cygwinx.o w32fns.o w32heap.o w32inevt.o w32notify.o \
   w32menu.o w32proc.o w32reg.o w32select.o w32term.o w32xfns.o \
   w16select.o widget.o xfont.o ftfont.o xftfont.o ftxfont.o gtkutil.o \
-  xsettings.o xgselect.o termcap.o
+  xsettings.o xgselect.o termcap.o hbfont.o
 
 ## gmalloc.o if !SYSTEM_MALLOC && !DOUG_LEA_MALLOC, else empty.
 GMALLOC_OBJ=@GMALLOC_OBJ@
index 4d1341a0db8a05cbf0086daab4cb2004e753a892..99b95836d7aef9bd7b15e3eaa7cadb771c939ca1 100644 (file)
@@ -890,6 +890,11 @@ extern void font_fill_lglyph_metrics (Lisp_Object, Lisp_Object);
 extern Lisp_Object font_put_extra (Lisp_Object font, Lisp_Object prop,
                                    Lisp_Object val);
 
+#ifdef HAVE_HARFBUZZ
+extern Lisp_Object hbfont_shape (Lisp_Object, Lisp_Object);
+extern Lisp_Object hbfont_combining_capability (struct font *);
+#endif
+
 #if defined (HAVE_XFT) || defined (HAVE_FREETYPE)
 extern void font_put_frame_data (struct frame *, Lisp_Object, void *);
 extern void *font_get_frame_data (struct frame *f, Lisp_Object);
diff --git a/src/hbfont.c b/src/hbfont.c
new file mode 100644 (file)
index 0000000..392414e
--- /dev/null
@@ -0,0 +1,484 @@
+/* hbfont.c -- Platform-independent support for HarfBuzz font driver.
+   Copyright (C) 2019 Free Software Foundation, Inc.
+
+This file is part of GNU Emacs.
+
+GNU Emacs is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or (at
+your option) any later version.
+
+GNU Emacs is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+#include <math.h>
+#include <hb.h>
+
+#include "lisp.h"
+#include "frame.h"
+#include "composite.h"
+#include "font.h"
+#include "dispextern.h"
+
+#ifdef HAVE_NTGUI
+
+#include "w32common.h"
+
+/* The w32 implementation calls HarfBuzz functions via function
+   pointers.  We use the below to declare the function pointers and
+   redirect function names to those pointers.  */
+DEF_DLL_FN (hb_unicode_funcs_t *, hb_unicode_funcs_create,
+           (hb_unicode_funcs_t *));
+DEF_DLL_FN (hb_unicode_funcs_t *, hb_unicode_funcs_get_default, (void));
+DEF_DLL_FN (void, hb_unicode_funcs_set_combining_class_func,
+           (hb_unicode_funcs_t *, hb_unicode_combining_class_func_t,
+            void *, hb_destroy_func_t));
+DEF_DLL_FN (void, hb_unicode_funcs_set_general_category_func,
+           (hb_unicode_funcs_t *, hb_unicode_general_category_func_t,
+            void *, hb_destroy_func_t));
+DEF_DLL_FN (void, hb_unicode_funcs_set_mirroring_func,
+           (hb_unicode_funcs_t *, hb_unicode_mirroring_func_t,
+            void *, hb_destroy_func_t));
+DEF_DLL_FN (hb_buffer_t *, hb_buffer_create, (void));
+DEF_DLL_FN (void, hb_buffer_set_unicode_funcs,
+           (hb_buffer_t *, hb_unicode_funcs_t *));
+DEF_DLL_FN (void, hb_buffer_clear_contents, (hb_buffer_t *));
+DEF_DLL_FN (hb_bool_t, hb_buffer_pre_allocate, (hb_buffer_t *, unsigned int));
+DEF_DLL_FN (void, hb_buffer_add, (hb_buffer_t *, hb_codepoint_t, unsigned int));
+DEF_DLL_FN (void, hb_buffer_set_content_type,
+           (hb_buffer_t *, hb_buffer_content_type_t));
+DEF_DLL_FN (void, hb_buffer_set_cluster_level,
+           (hb_buffer_t *, hb_buffer_cluster_level_t));
+DEF_DLL_FN (void, hb_buffer_set_direction, (hb_buffer_t *, hb_direction_t));
+DEF_DLL_FN (void, hb_buffer_set_language, (hb_buffer_t *, hb_language_t));
+DEF_DLL_FN (hb_language_t, hb_language_from_string, (const char *, int));
+DEF_DLL_FN (void, hb_buffer_guess_segment_properties, (hb_buffer_t *));
+DEF_DLL_FN (hb_bool_t, hb_shape_full,
+           (hb_font_t *, hb_buffer_t *, const hb_feature_t *,
+            unsigned int, const char * const *));
+DEF_DLL_FN (unsigned int, hb_buffer_get_length, (hb_buffer_t *));
+DEF_DLL_FN (hb_direction_t, hb_buffer_get_direction, (hb_buffer_t *));
+DEF_DLL_FN (void, hb_buffer_reverse_clusters, (hb_buffer_t *));
+DEF_DLL_FN (hb_glyph_info_t *, hb_buffer_get_glyph_infos,
+           (hb_buffer_t *, unsigned int *));
+DEF_DLL_FN (hb_glyph_position_t *, hb_buffer_get_glyph_positions,
+           (hb_buffer_t *, unsigned int *));
+
+#define hb_unicode_funcs_create fn_hb_unicode_funcs_create
+#define hb_unicode_funcs_get_default fn_hb_unicode_funcs_get_default
+#define hb_unicode_funcs_set_combining_class_func fn_hb_unicode_funcs_set_combining_class_func
+#define hb_unicode_funcs_set_general_category_func fn_hb_unicode_funcs_set_general_category_func
+#define hb_unicode_funcs_set_mirroring_func fn_hb_unicode_funcs_set_mirroring_func
+#define hb_buffer_create fn_hb_buffer_create
+#define hb_buffer_set_unicode_funcs fn_hb_buffer_set_unicode_funcs
+#define hb_buffer_clear_contents fn_hb_buffer_clear_contents
+#define hb_buffer_pre_allocate fn_hb_buffer_pre_allocate
+#define hb_buffer_add fn_hb_buffer_add
+#define hb_buffer_set_content_type fn_hb_buffer_set_content_type
+#define hb_buffer_set_cluster_level fn_hb_buffer_set_cluster_level
+#define hb_buffer_set_direction fn_hb_buffer_set_direction
+#define hb_buffer_set_language fn_hb_buffer_set_language
+#define hb_language_from_string fn_hb_language_from_string
+#define hb_buffer_guess_segment_properties fn_hb_buffer_guess_segment_properties
+#define hb_shape_full fn_hb_shape_full
+#define hb_buffer_get_length fn_hb_buffer_get_length
+#define hb_buffer_get_direction fn_hb_buffer_get_direction
+#define hb_buffer_reverse_clusters fn_hb_buffer_reverse_clusters
+#define hb_buffer_get_glyph_infos fn_hb_buffer_get_glyph_infos
+#define hb_buffer_get_glyph_positions fn_hb_buffer_get_glyph_positions
+
+/* This function is called from syms_of_w32uniscribe_for_pdumper to
+   initialize the above function pointers.  */
+bool
+hbfont_init_w32_funcs (HMODULE library)
+{
+  LOAD_DLL_FN (library, hb_unicode_funcs_create);
+  LOAD_DLL_FN (library, hb_unicode_funcs_get_default);
+  LOAD_DLL_FN (library, hb_unicode_funcs_set_combining_class_func);
+  LOAD_DLL_FN (library, hb_unicode_funcs_set_general_category_func);
+  LOAD_DLL_FN (library, hb_unicode_funcs_set_mirroring_func);
+  LOAD_DLL_FN (library, hb_buffer_create);
+  LOAD_DLL_FN (library, hb_buffer_set_unicode_funcs);
+  LOAD_DLL_FN (library, hb_buffer_clear_contents);
+  LOAD_DLL_FN (library, hb_buffer_pre_allocate);
+  LOAD_DLL_FN (library, hb_buffer_add);
+  LOAD_DLL_FN (library, hb_buffer_set_content_type);
+  LOAD_DLL_FN (library, hb_buffer_set_cluster_level);
+  LOAD_DLL_FN (library, hb_buffer_set_direction);
+  LOAD_DLL_FN (library, hb_buffer_set_language);
+  LOAD_DLL_FN (library, hb_language_from_string);
+  LOAD_DLL_FN (library, hb_buffer_guess_segment_properties);
+  LOAD_DLL_FN (library, hb_shape_full);
+  LOAD_DLL_FN (library, hb_buffer_get_length);
+  LOAD_DLL_FN (library, hb_buffer_get_direction);
+  LOAD_DLL_FN (library, hb_buffer_reverse_clusters);
+  LOAD_DLL_FN (library, hb_buffer_get_glyph_infos);
+  LOAD_DLL_FN (library, hb_buffer_get_glyph_positions);
+  return true;
+}
+#endif /* HAVE_NTGUI */
+
+/* Support functions for HarfBuzz shaper.  */
+
+static bool combining_class_loaded = false;
+static Lisp_Object canonical_combining_class_table;
+
+static hb_unicode_combining_class_t
+uni_combining (hb_unicode_funcs_t *funcs, hb_codepoint_t ch, void *user_data)
+{
+  /* Load the Unicode table first time it is needed.  */
+  if (!combining_class_loaded)
+    {
+      canonical_combining_class_table =
+       uniprop_table (intern ("canonical-combining-class"));
+      if (NILP (canonical_combining_class_table))
+       emacs_abort ();
+      staticpro (&canonical_combining_class_table);
+      combining_class_loaded = true;
+    }
+
+  Lisp_Object combining =
+    get_unicode_property (canonical_combining_class_table, ch);
+  if (FIXNUMP (combining))
+    return (hb_unicode_combining_class_t) XFIXNUM (combining);
+
+  return HB_UNICODE_COMBINING_CLASS_NOT_REORDERED;
+}
+
+static hb_unicode_general_category_t
+uni_general (hb_unicode_funcs_t *funcs, hb_codepoint_t ch, void *user_data)
+{
+  Lisp_Object category = CHAR_TABLE_REF (Vunicode_category_table, ch);
+
+  if (INTEGERP (category))
+    {
+    switch (XFIXNUM (category))
+      {
+      case UNICODE_CATEGORY_Cc:
+        return HB_UNICODE_GENERAL_CATEGORY_CONTROL;
+      case UNICODE_CATEGORY_Cf:
+        return HB_UNICODE_GENERAL_CATEGORY_FORMAT;
+      case UNICODE_CATEGORY_Cn:
+        return HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED;
+      case UNICODE_CATEGORY_Co:
+        return HB_UNICODE_GENERAL_CATEGORY_PRIVATE_USE;
+      case UNICODE_CATEGORY_Cs:
+        return HB_UNICODE_GENERAL_CATEGORY_SURROGATE;
+      case UNICODE_CATEGORY_Ll:
+        return HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER;
+      case UNICODE_CATEGORY_Lm:
+        return HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER;
+      case UNICODE_CATEGORY_Lo:
+        return HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER;
+      case UNICODE_CATEGORY_Lt:
+        return HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER;
+      case UNICODE_CATEGORY_Lu:
+        return HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER;
+      case UNICODE_CATEGORY_Mc:
+        return HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK;
+      case UNICODE_CATEGORY_Me:
+        return HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK;
+      case UNICODE_CATEGORY_Mn:
+        return HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK;
+      case UNICODE_CATEGORY_Nd:
+        return HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER;
+      case UNICODE_CATEGORY_Nl:
+        return HB_UNICODE_GENERAL_CATEGORY_LETTER_NUMBER;
+      case UNICODE_CATEGORY_No:
+        return HB_UNICODE_GENERAL_CATEGORY_OTHER_NUMBER;
+      case UNICODE_CATEGORY_Pc:
+        return HB_UNICODE_GENERAL_CATEGORY_CONNECT_PUNCTUATION;
+      case UNICODE_CATEGORY_Pd:
+        return HB_UNICODE_GENERAL_CATEGORY_DASH_PUNCTUATION;
+      case UNICODE_CATEGORY_Pe:
+        return HB_UNICODE_GENERAL_CATEGORY_CLOSE_PUNCTUATION;
+      case UNICODE_CATEGORY_Pf:
+        return HB_UNICODE_GENERAL_CATEGORY_FINAL_PUNCTUATION;
+      case UNICODE_CATEGORY_Pi:
+        return HB_UNICODE_GENERAL_CATEGORY_INITIAL_PUNCTUATION;
+      case UNICODE_CATEGORY_Po:
+        return HB_UNICODE_GENERAL_CATEGORY_OTHER_PUNCTUATION;
+      case UNICODE_CATEGORY_Ps:
+        return HB_UNICODE_GENERAL_CATEGORY_OPEN_PUNCTUATION;
+      case UNICODE_CATEGORY_Sc:
+        return HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL;
+      case UNICODE_CATEGORY_Sk:
+        return HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL;
+      case UNICODE_CATEGORY_Sm:
+        return HB_UNICODE_GENERAL_CATEGORY_MATH_SYMBOL;
+      case UNICODE_CATEGORY_So:
+        return HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL;
+      case UNICODE_CATEGORY_Zl:
+        return HB_UNICODE_GENERAL_CATEGORY_LINE_SEPARATOR;
+      case UNICODE_CATEGORY_Zp:
+        return HB_UNICODE_GENERAL_CATEGORY_PARAGRAPH_SEPARATOR;
+      case UNICODE_CATEGORY_Zs:
+        return HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR;
+      case UNICODE_CATEGORY_UNKNOWN:
+        return HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED;
+      }
+    }
+
+  return HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED;
+}
+
+static hb_codepoint_t
+uni_mirroring (hb_unicode_funcs_t *funcs, hb_codepoint_t ch, void *user_data)
+{
+  return bidi_mirror_char (ch);
+}
+
+static hb_unicode_funcs_t *
+get_hb_unicode_funcs (void)
+{
+  /* Subclass HarfBuzz's default Unicode functions and override functions that
+   * use data Emacs can provide. This way changing Emacs data is reflected in
+   * the shaped output. */
+  hb_unicode_funcs_t *funcs = hb_unicode_funcs_create (hb_unicode_funcs_get_default ());
+
+  hb_unicode_funcs_set_combining_class_func (funcs, uni_combining, NULL, NULL);
+  hb_unicode_funcs_set_general_category_func (funcs, uni_general, NULL, NULL);
+  hb_unicode_funcs_set_mirroring_func (funcs, uni_mirroring, NULL, NULL);
+
+  /* Use default implmentation for Unicode composition/decomposition, we might
+   * want to revisit this later.
+  hb_unicode_funcs_set_compose_func (funcs, uni_compose, NULL, NULL);
+  hb_unicode_funcs_set_decompose_func (funcs, uni_decompose, NULL, NULL);
+  */
+
+  /* Emacs own script mapping for characters differs from Unicode, so we want
+   * to keep the default HarfBuzz's implementation here.
+  hb_unicode_funcs_set_script_func (funcs, uni_script, NULL, NULL);
+  */
+
+  return funcs;
+}
+
+/* HarfBuzz implementation of shape for font backend.  See the
+   commentary before uniscribe_shape for the meaning of the
+   arguments.
+
+   Shape text in LGSTRING.  See the docstring of
+   'composition-get-gstring' for the format of LGSTRING.  If the
+   (N+1)th element of LGSTRING is nil, input of shaping is from the
+   1st to (N)th elements.  In each input glyph, FROM, TO, CHAR, and
+   CODE are already set, but FROM and TO need adjustments according
+   to the glyphs produced by the shaping fuinction.
+   DIRECTION is either L2R or R2L, or nil if unknown.  During
+   redisplay, this comes from applying the UBA, is passed from
+   composition_reseat_it, and is used by the HarfBuzz shaper.
+
+   This function updates all fields of the input glyphs.  If the
+   output glyphs (M) are more than the input glyphs (N), (N+1)th
+   through (M)th elements of LGSTRING are updated possibly by making
+   a new glyph object and storing it in LGSTRING.  If (M) is greater
+   than the length of LGSTRING, nil should be returned.  In that case,
+   this function is called again with a larger LGSTRING.  */
+Lisp_Object
+hbfont_shape (Lisp_Object lgstring, Lisp_Object direction)
+{
+  struct font *font = CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring));
+  ptrdiff_t glyph_len = 0, text_len = LGSTRING_GLYPH_LEN (lgstring);
+  ptrdiff_t i;
+
+  hb_glyph_info_t *info;
+  hb_glyph_position_t *pos;
+
+  /* Cache the HarfBuzz buffer for better performance and less allocations.
+   * We intentionally never destroy the buffer. */
+  static hb_buffer_t *hb_buffer = NULL;
+  if (! hb_buffer)
+    {
+      hb_buffer = hb_buffer_create ();
+      hb_unicode_funcs_t* ufuncs = get_hb_unicode_funcs();
+      hb_buffer_set_unicode_funcs(hb_buffer, ufuncs);
+    }
+
+  hb_buffer_clear_contents (hb_buffer);
+  hb_buffer_pre_allocate (hb_buffer, text_len);
+
+  /* Copy the characters in their original logical order, so we can
+     assign them to glyphs correctly after shaping.  */
+  int *chars = alloca (text_len * sizeof (int));
+  for (i = 0; i < text_len; i++)
+    {
+      Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
+      int c;
+
+      if (NILP (g))
+       break;
+      c = LGLYPH_CHAR (g);
+      hb_buffer_add (hb_buffer, c, i);
+      chars[i] = c;
+    }
+
+  text_len = i;
+  if (!text_len)
+    return Qnil;
+
+  hb_buffer_set_content_type (hb_buffer, HB_BUFFER_CONTENT_TYPE_UNICODE);
+  hb_buffer_set_cluster_level (hb_buffer,
+                              HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES);
+
+  /* If the caller didn't provide a meaningful DIRECTION, let HarfBuzz
+     guess it. */
+  if (!NILP (direction))
+    {
+      hb_direction_t dir = HB_DIRECTION_LTR;
+      if (EQ (direction, QL2R))
+       dir = HB_DIRECTION_LTR;
+      else if (EQ (direction, QR2L))
+       dir = HB_DIRECTION_RTL;
+      hb_buffer_set_direction (hb_buffer, dir);
+    }
+
+  /* Leave the script determination to HarfBuzz, until Emacs has a
+     better idea of the script of LGSTRING.  FIXME. */
+#if 0
+  hb_buffer_set_script (hb_buffer, XXX);
+#endif
+
+  /* FIXME: This can only handle the single global language, which
+     normally comes from the locale.  In addition, if
+     current-iso639-language is a list, we arbitrarily use the first
+     one.  We should instead have a notion of the language of the text
+     being shaped.  */
+  Lisp_Object lang = Vcurrent_iso639_language;
+  if (CONSP (Vcurrent_iso639_language))
+    lang = XCAR (Vcurrent_iso639_language);
+  if (SYMBOLP (lang))
+    {
+      Lisp_Object lang_str = SYMBOL_NAME (lang);
+      hb_buffer_set_language (hb_buffer,
+                             hb_language_from_string (SSDATA (lang_str),
+                                                      SBYTES (lang_str)));
+    }
+
+  /* Guess the default properties for when they cannot be determined above.
+
+     FIXME: maybe drop this guessing once script and language handling
+     is fixed above; but then will need to guess the direction by
+     ourselves, perhaps by looking at the the characters using
+     bidi_get_type or somesuch.  */
+  hb_buffer_guess_segment_properties (hb_buffer);
+
+  double position_unit;
+  hb_font_t *hb_font
+    = font->driver->begin_hb_font
+    ? font->driver->begin_hb_font (font, &position_unit)
+    : NULL;
+  if (!hb_font)
+    return make_fixnum (0);
+
+  hb_bool_t success = hb_shape_full (hb_font, hb_buffer, NULL, 0, NULL);
+  if (font->driver->end_hb_font)
+    font->driver->end_hb_font (font, hb_font);
+  if (!success)
+    return Qnil;
+
+  glyph_len = hb_buffer_get_length (hb_buffer);
+  if (glyph_len > LGSTRING_GLYPH_LEN (lgstring))
+    return Qnil;
+
+  /* We need the clusters in logical order.  */
+  bool buf_reversed = false;
+  if (HB_DIRECTION_IS_BACKWARD (hb_buffer_get_direction (hb_buffer)))
+    {
+      buf_reversed = true;
+      hb_buffer_reverse_clusters (hb_buffer);
+    }
+  info = hb_buffer_get_glyph_infos (hb_buffer, NULL);
+  pos = hb_buffer_get_glyph_positions (hb_buffer, NULL);
+  int from = -1, to, cluster_offset = 0;
+  int char_idx, incr = buf_reversed ? -1 : 1;
+  for (i = 0; i < glyph_len; i++)
+    {
+      Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
+      struct font_metrics metrics = {.width = 0};
+      int xoff, yoff, wadjust;
+
+      if (NILP (lglyph))
+       {
+         lglyph = LGLYPH_NEW ();
+         LGSTRING_SET_GLYPH (lgstring, i, lglyph);
+       }
+
+      if (info[i].cluster != from)
+       {
+         int j;
+         /* Found a new cluster.  Determine its FROM and TO, and the
+            offset to the first character of the cluster.  */
+         /* FROM is the index of the first character that contributed
+            to this cluster.  */
+         from = info[i].cluster;
+         /* TO is the index of the last character that contributed to
+            this cluster.  */
+         for (j = i; j < glyph_len && info[j].cluster == from; j++)
+           ;
+         to = (j == glyph_len) ? text_len - 1 : info[j].cluster - 1;
+         cluster_offset = 0;
+         /* For RTL buffers, HarfBuzz produces glyphs in a cluster in
+            reverse order, so we need to account for that to record
+            the correct character in each glyph.
+
+            Implementation note: the character codepoint recorded in
+            each glyph is not really used, except when we display the
+            glyphs in descr-text.el.  So this is just an aeasthetic
+            issue.  */
+         if (buf_reversed)
+           cluster_offset = to - from;
+       }
+
+      /* All the glyphs in a cluster have the same values of FROM and TO.  */
+      LGLYPH_SET_FROM (lglyph, from);
+      LGLYPH_SET_TO (lglyph, to);
+
+      /* Not every glyph in a cluster maps directly to a single
+        character; in general, N characters can yield M glyphs, where
+        M could be smaller or greater than N.  However, in many cases
+        there is a one-to-one correspondence, and it would be a pity
+        to lose that information, even if it's sometimes inaccurate.  */
+      char_idx = from + cluster_offset;
+      cluster_offset += incr;
+      if (char_idx > to)
+       char_idx = to;
+      if (char_idx < from)
+       char_idx = from;
+      LGLYPH_SET_CHAR (lglyph, chars[char_idx]);
+      LGLYPH_SET_CODE (lglyph, info[i].codepoint);
+
+      unsigned code = info[i].codepoint;
+      font->driver->text_extents (font, &code, 1, &metrics);
+      LGLYPH_SET_WIDTH (lglyph, metrics.width);
+      LGLYPH_SET_LBEARING (lglyph, metrics.lbearing);
+      LGLYPH_SET_RBEARING (lglyph, metrics.rbearing);
+      LGLYPH_SET_ASCENT (lglyph, metrics.ascent);
+      LGLYPH_SET_DESCENT (lglyph, metrics.descent);
+
+      xoff = lround (pos[i].x_offset * position_unit);
+      yoff = - lround (pos[i].y_offset * position_unit);
+      wadjust = lround (pos[i].x_advance * position_unit);
+      if (xoff || yoff || wadjust != metrics.width)
+       {
+         Lisp_Object vec = make_uninit_vector (3);
+         ASET (vec, 0, make_fixnum (xoff));
+         ASET (vec, 1, make_fixnum (yoff));
+         ASET (vec, 2, make_fixnum (wadjust));
+         LGLYPH_SET_ADJUSTMENT (lglyph, vec);
+       }
+    }
+
+  return make_fixnum (glyph_len);
+}
+
+Lisp_Object
+hbfont_combining_capability (struct font *font)
+{
+  return Qt;
+}
index bca5244caaa302aaa3131f0eba6bca518cf250ad..adde784634affee3dee08710f2fc9e48c38a4385 100644 (file)
@@ -81,4 +81,8 @@ get_proc_addr (HINSTANCE handle, LPCSTR fname)
     }                                                                  \
   while (false)
 
+#ifdef HAVE_HARFBUZZ
+extern bool hbfont_init_w32_funcs (HMODULE);
+#endif
+
 #endif /* W32COMMON_H */
index f1e69452160c80787a6d87d884576257af5e4ce6..5372eb1525231f6ad7faac543b1e2697ea6cb20e 100644 (file)
@@ -1,4 +1,5 @@
 /* Font backend for the Microsoft W32 Uniscribe API.
+   Windows-specific parts of the HarfBuzz font backend.
    Copyright (C) 2008-2019 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
@@ -85,42 +86,6 @@ DEF_DLL_FN (void, hb_face_destroy, (hb_face_t *));
 DEF_DLL_FN (unsigned int, hb_face_get_upem, (hb_face_t *));
 DEF_DLL_FN (hb_bool_t, hb_font_get_nominal_glyph,
            (hb_font_t *, hb_codepoint_t, hb_codepoint_t *));
-DEF_DLL_FN (hb_unicode_funcs_t *, hb_unicode_funcs_create,
-           (hb_unicode_funcs_t *));
-DEF_DLL_FN (hb_unicode_funcs_t *, hb_unicode_funcs_get_default, (void));
-DEF_DLL_FN (void, hb_unicode_funcs_set_combining_class_func,
-           (hb_unicode_funcs_t *, hb_unicode_combining_class_func_t,
-            void *, hb_destroy_func_t));
-DEF_DLL_FN (void, hb_unicode_funcs_set_general_category_func,
-           (hb_unicode_funcs_t *, hb_unicode_general_category_func_t,
-            void *, hb_destroy_func_t));
-DEF_DLL_FN (void, hb_unicode_funcs_set_mirroring_func,
-           (hb_unicode_funcs_t *, hb_unicode_mirroring_func_t,
-            void *, hb_destroy_func_t));
-DEF_DLL_FN (hb_buffer_t *, hb_buffer_create, (void));
-DEF_DLL_FN (void, hb_buffer_set_unicode_funcs,
-           (hb_buffer_t *, hb_unicode_funcs_t *));
-DEF_DLL_FN (void, hb_buffer_clear_contents, (hb_buffer_t *));
-DEF_DLL_FN (hb_bool_t, hb_buffer_pre_allocate, (hb_buffer_t *, unsigned int));
-DEF_DLL_FN (void, hb_buffer_add, (hb_buffer_t *, hb_codepoint_t, unsigned int));
-DEF_DLL_FN (void, hb_buffer_set_content_type,
-           (hb_buffer_t *, hb_buffer_content_type_t));
-DEF_DLL_FN (void, hb_buffer_set_cluster_level,
-           (hb_buffer_t *, hb_buffer_cluster_level_t));
-DEF_DLL_FN (void, hb_buffer_set_direction, (hb_buffer_t *, hb_direction_t));
-DEF_DLL_FN (void, hb_buffer_set_language, (hb_buffer_t *, hb_language_t));
-DEF_DLL_FN (hb_language_t, hb_language_from_string, (const char *, int));
-DEF_DLL_FN (void, hb_buffer_guess_segment_properties, (hb_buffer_t *));
-DEF_DLL_FN (hb_bool_t, hb_shape_full,
-           (hb_font_t *, hb_buffer_t *, const hb_feature_t *,
-            unsigned int, const char * const *));
-DEF_DLL_FN (unsigned int, hb_buffer_get_length, (hb_buffer_t *));
-DEF_DLL_FN (hb_direction_t, hb_buffer_get_direction, (hb_buffer_t *));
-DEF_DLL_FN (void, hb_buffer_reverse_clusters, (hb_buffer_t *));
-DEF_DLL_FN (hb_glyph_info_t *, hb_buffer_get_glyph_infos,
-           (hb_buffer_t *, unsigned int *));
-DEF_DLL_FN (hb_glyph_position_t *, hb_buffer_get_glyph_positions,
-           (hb_buffer_t *, unsigned int *));
 
 #define hb_blob_create fn_hb_blob_create
 #define hb_face_create_for_tables fn_hb_face_create_for_tables
@@ -130,28 +95,6 @@ DEF_DLL_FN (hb_glyph_position_t *, hb_buffer_get_glyph_positions,
 #define hb_face_destroy fn_hb_face_destroy
 #define hb_face_get_upem fn_hb_face_get_upem
 #define hb_font_get_nominal_glyph fn_hb_font_get_nominal_glyph
-#define hb_unicode_funcs_create fn_hb_unicode_funcs_create
-#define hb_unicode_funcs_get_default fn_hb_unicode_funcs_get_default
-#define hb_unicode_funcs_set_combining_class_func fn_hb_unicode_funcs_set_combining_class_func
-#define hb_unicode_funcs_set_general_category_func fn_hb_unicode_funcs_set_general_category_func
-#define hb_unicode_funcs_set_mirroring_func fn_hb_unicode_funcs_set_mirroring_func
-#define hb_buffer_create fn_hb_buffer_create
-#define hb_buffer_set_unicode_funcs fn_hb_buffer_set_unicode_funcs
-#define hb_buffer_clear_contents fn_hb_buffer_clear_contents
-#define hb_buffer_pre_allocate fn_hb_buffer_pre_allocate
-#define hb_buffer_add fn_hb_buffer_add
-#define hb_buffer_set_content_type fn_hb_buffer_set_content_type
-#define hb_buffer_set_cluster_level fn_hb_buffer_set_cluster_level
-#define hb_buffer_set_direction fn_hb_buffer_set_direction
-#define hb_buffer_set_language fn_hb_buffer_set_language
-#define hb_language_from_string fn_hb_language_from_string
-#define hb_buffer_guess_segment_properties fn_hb_buffer_guess_segment_properties
-#define hb_shape_full fn_hb_shape_full
-#define hb_buffer_get_length fn_hb_buffer_get_length
-#define hb_buffer_get_direction fn_hb_buffer_get_direction
-#define hb_buffer_reverse_clusters fn_hb_buffer_reverse_clusters
-#define hb_buffer_get_glyph_infos fn_hb_buffer_get_glyph_infos
-#define hb_buffer_get_glyph_positions fn_hb_buffer_get_glyph_positions
 #endif
 
 /* Used by uniscribe_otf_capability.  */
@@ -1434,348 +1377,6 @@ w32hb_begin_font (struct font *font, double *position_unit)
   *position_unit = uniscribe_font->scale;
   return (hb_font_t *) uniscribe_font->cache;
 }
-
-static bool combining_class_loaded = false;
-static Lisp_Object canonical_combining_class_table;
-
-static hb_unicode_combining_class_t
-w32uni_combining (hb_unicode_funcs_t *funcs, hb_codepoint_t ch, void *user_data)
-{
-  /* Load the Unicode table first time it is needed.  */
-  if (!combining_class_loaded)
-    {
-      canonical_combining_class_table =
-       uniprop_table (intern ("canonical-combining-class"));
-      if (NILP (canonical_combining_class_table))
-       emacs_abort ();
-      staticpro (&canonical_combining_class_table);
-      combining_class_loaded = true;
-    }
-
-  Lisp_Object combining =
-    get_unicode_property (canonical_combining_class_table, ch);
-  if (FIXNUMP (combining))
-    return (hb_unicode_combining_class_t) XFIXNUM (combining);
-
-  return HB_UNICODE_COMBINING_CLASS_NOT_REORDERED;
-}
-
-static hb_unicode_general_category_t
-w32uni_general (hb_unicode_funcs_t *funcs, hb_codepoint_t ch, void *user_data)
-{
-  Lisp_Object category = CHAR_TABLE_REF (Vunicode_category_table, ch);
-
-  if (INTEGERP (category))
-    {
-    switch (XFIXNUM (category))
-      {
-      case UNICODE_CATEGORY_Cc:
-        return HB_UNICODE_GENERAL_CATEGORY_CONTROL;
-      case UNICODE_CATEGORY_Cf:
-        return HB_UNICODE_GENERAL_CATEGORY_FORMAT;
-      case UNICODE_CATEGORY_Cn:
-        return HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED;
-      case UNICODE_CATEGORY_Co:
-        return HB_UNICODE_GENERAL_CATEGORY_PRIVATE_USE;
-      case UNICODE_CATEGORY_Cs:
-        return HB_UNICODE_GENERAL_CATEGORY_SURROGATE;
-      case UNICODE_CATEGORY_Ll:
-        return HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER;
-      case UNICODE_CATEGORY_Lm:
-        return HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER;
-      case UNICODE_CATEGORY_Lo:
-        return HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER;
-      case UNICODE_CATEGORY_Lt:
-        return HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER;
-      case UNICODE_CATEGORY_Lu:
-        return HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER;
-      case UNICODE_CATEGORY_Mc:
-        return HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK;
-      case UNICODE_CATEGORY_Me:
-        return HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK;
-      case UNICODE_CATEGORY_Mn:
-        return HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK;
-      case UNICODE_CATEGORY_Nd:
-        return HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER;
-      case UNICODE_CATEGORY_Nl:
-        return HB_UNICODE_GENERAL_CATEGORY_LETTER_NUMBER;
-      case UNICODE_CATEGORY_No:
-        return HB_UNICODE_GENERAL_CATEGORY_OTHER_NUMBER;
-      case UNICODE_CATEGORY_Pc:
-        return HB_UNICODE_GENERAL_CATEGORY_CONNECT_PUNCTUATION;
-      case UNICODE_CATEGORY_Pd:
-        return HB_UNICODE_GENERAL_CATEGORY_DASH_PUNCTUATION;
-      case UNICODE_CATEGORY_Pe:
-        return HB_UNICODE_GENERAL_CATEGORY_CLOSE_PUNCTUATION;
-      case UNICODE_CATEGORY_Pf:
-        return HB_UNICODE_GENERAL_CATEGORY_FINAL_PUNCTUATION;
-      case UNICODE_CATEGORY_Pi:
-        return HB_UNICODE_GENERAL_CATEGORY_INITIAL_PUNCTUATION;
-      case UNICODE_CATEGORY_Po:
-        return HB_UNICODE_GENERAL_CATEGORY_OTHER_PUNCTUATION;
-      case UNICODE_CATEGORY_Ps:
-        return HB_UNICODE_GENERAL_CATEGORY_OPEN_PUNCTUATION;
-      case UNICODE_CATEGORY_Sc:
-        return HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL;
-      case UNICODE_CATEGORY_Sk:
-        return HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL;
-      case UNICODE_CATEGORY_Sm:
-        return HB_UNICODE_GENERAL_CATEGORY_MATH_SYMBOL;
-      case UNICODE_CATEGORY_So:
-        return HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL;
-      case UNICODE_CATEGORY_Zl:
-        return HB_UNICODE_GENERAL_CATEGORY_LINE_SEPARATOR;
-      case UNICODE_CATEGORY_Zp:
-        return HB_UNICODE_GENERAL_CATEGORY_PARAGRAPH_SEPARATOR;
-      case UNICODE_CATEGORY_Zs:
-        return HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR;
-      case UNICODE_CATEGORY_UNKNOWN:
-        return HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED;
-      }
-    }
-
-  return HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED;
-}
-
-static hb_codepoint_t
-w32uni_mirroring (hb_unicode_funcs_t *funcs, hb_codepoint_t ch, void *user_data)
-{
-  return bidi_mirror_char (ch);
-}
-
-static hb_unicode_funcs_t *
-get_hb_unicode_funcs (void)
-{
-  /* Subclass HarfBuzz's default Unicode functions and override functions that
-   * use data Emacs can provide. This way changing Emacs data is reflected in
-   * the shaped output. */
-  hb_unicode_funcs_t *funcs = hb_unicode_funcs_create (hb_unicode_funcs_get_default ());
-
-  hb_unicode_funcs_set_combining_class_func (funcs, w32uni_combining, NULL, NULL);
-  hb_unicode_funcs_set_general_category_func (funcs, w32uni_general, NULL, NULL);
-  hb_unicode_funcs_set_mirroring_func (funcs, w32uni_mirroring, NULL, NULL);
-
-  /* Use default implmentation for Unicode composition/decomposition, we might
-   * want to revisit this later.
-  hb_unicode_funcs_set_compose_func (funcs, uni_compose, NULL, NULL);
-  hb_unicode_funcs_set_decompose_func (funcs, uni_decompose, NULL, NULL);
-  */
-
-  /* Emacs own script mapping for characters differs from Unicode, so we want
-   * to keep the default HarfBuzz's implementation here.
-  hb_unicode_funcs_set_script_func (funcs, uni_script, NULL, NULL);
-  */
-
-  return funcs;
-}
-
-/* HarfBuzz implementation of shape for font backend.  See the
-   commentary before uniscribe_shape for the meaning of the
-   arguments.  */
-static Lisp_Object
-w32hb_shape (Lisp_Object lgstring, Lisp_Object direction)
-{
-  struct font *font = CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring));
-  ptrdiff_t glyph_len = 0, text_len = LGSTRING_GLYPH_LEN (lgstring);
-  ptrdiff_t i;
-
-  hb_glyph_info_t *info;
-  hb_glyph_position_t *pos;
-
-  /* Cache the HarfBuzz buffer for better performance and less allocations.
-   * We intentionally never destroy the buffer. */
-  static hb_buffer_t *hb_buffer = NULL;
-  if (! hb_buffer)
-    {
-      hb_buffer = hb_buffer_create ();
-      hb_unicode_funcs_t* ufuncs = get_hb_unicode_funcs();
-      hb_buffer_set_unicode_funcs(hb_buffer, ufuncs);
-    }
-
-  hb_buffer_clear_contents (hb_buffer);
-  hb_buffer_pre_allocate (hb_buffer, text_len);
-
-  /* Copy the characters in their original logical order, so we can
-     assign them to glyphs correctly after shaping.  */
-  int *chars = alloca (text_len * sizeof (int));
-  for (i = 0; i < text_len; i++)
-    {
-      Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
-      int c;
-
-      if (NILP (g))
-       break;
-      c = LGLYPH_CHAR (g);
-      hb_buffer_add (hb_buffer, c, i);
-      chars[i] = c;
-    }
-
-  text_len = i;
-  if (!text_len)
-    return Qnil;
-
-  hb_buffer_set_content_type (hb_buffer, HB_BUFFER_CONTENT_TYPE_UNICODE);
-  hb_buffer_set_cluster_level (hb_buffer,
-                              HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES);
-
-  /* If the caller didn't provide a meaningful DIRECTION, let HarfBuzz
-     guess it. */
-  if (!NILP (direction))
-    {
-      hb_direction_t dir = HB_DIRECTION_LTR;
-      if (EQ (direction, QL2R))
-       dir = HB_DIRECTION_LTR;
-      else if (EQ (direction, QR2L))
-       dir = HB_DIRECTION_RTL;
-      hb_buffer_set_direction (hb_buffer, dir);
-    }
-
-  /* Leave the script determination to HarfBuzz, until Emacs has a
-     better idea of the script of LGSTRING.  FIXME. */
-#if 0
-  hb_buffer_set_script (hb_buffer, XXX);
-#endif
-
-  /* FIXME: This can only handle the single global language, which
-     normally comes from the locale.  In addition, if
-     current-iso639-language is a list, we arbitrarily use the first
-     one.  We should instead have a notion of the language of the text
-     being shaped.  */
-  Lisp_Object lang = Vcurrent_iso639_language;
-  if (CONSP (Vcurrent_iso639_language))
-    lang = XCAR (Vcurrent_iso639_language);
-  if (SYMBOLP (lang))
-    {
-      Lisp_Object lang_str = SYMBOL_NAME (lang);
-      hb_buffer_set_language (hb_buffer,
-                             hb_language_from_string (SSDATA (lang_str),
-                                                      SBYTES (lang_str)));
-    }
-
-  /* Guess the default properties for when they cannot be determined above.
-
-     FIXME: maybe drop this guessing once script and language handling
-     is fixed above; but then will need to guess the direction by
-     ourselves, perhaps by looking at the the characters using
-     bidi_get_type or somesuch.  */
-  hb_buffer_guess_segment_properties (hb_buffer);
-
-  double position_unit;
-  hb_font_t *hb_font
-    = font->driver->begin_hb_font
-    ? font->driver->begin_hb_font (font, &position_unit)
-    : NULL;
-  if (!hb_font)
-    return make_fixnum (0);
-
-  hb_bool_t success = hb_shape_full (hb_font, hb_buffer, NULL, 0, NULL);
-  if (font->driver->end_hb_font)
-    font->driver->end_hb_font (font, hb_font);
-  if (!success)
-    return Qnil;
-
-  glyph_len = hb_buffer_get_length (hb_buffer);
-  /* FIXME: can't we just grow the lgstring in this case? Giving up is an
-   * overly heavy handed solution. */
-  if (glyph_len > LGSTRING_GLYPH_LEN (lgstring))
-    return Qnil;
-
-  /* We need the clusters in logical order.  */
-  bool buf_reversed = false;
-  if (HB_DIRECTION_IS_BACKWARD (hb_buffer_get_direction (hb_buffer)))
-    {
-      buf_reversed = true;
-      hb_buffer_reverse_clusters (hb_buffer);
-    }
-  info = hb_buffer_get_glyph_infos (hb_buffer, NULL);
-  pos = hb_buffer_get_glyph_positions (hb_buffer, NULL);
-  int from = -1, to, cluster_offset = 0;
-  int char_idx, incr = buf_reversed ? -1 : 1;
-  for (i = 0; i < glyph_len; i++)
-    {
-      Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
-      struct font_metrics metrics = {.width = 0};
-      int xoff, yoff, wadjust;
-
-      if (NILP (lglyph))
-       {
-         lglyph = LGLYPH_NEW ();
-         LGSTRING_SET_GLYPH (lgstring, i, lglyph);
-       }
-
-      if (info[i].cluster != from)
-       {
-         int j;
-         /* Found a new cluster.  Determine its FROM and TO, and the
-            offset to the first character of the cluster.  */
-         /* FROM is the index of the first character that contributed
-            to this cluster.  */
-         from = info[i].cluster;
-         /* TO is the index of the last character that contributed to
-            this cluster.  */
-         for (j = i; j < glyph_len && info[j].cluster == from; j++)
-           ;
-         to = (j == glyph_len) ? text_len - 1 : info[j].cluster - 1;
-         cluster_offset = 0;
-         /* For RTL buffers, HarfBuzz produces glyphs in a cluster in
-            reverse order, so we need to account for that to record
-            the correct character in each glyph.
-
-            Implementation note: the character codepoint recorded in
-            each glyph is not really used, except when we display the
-            glyphs in descr-text.el.  So this is just an aeasthetic
-            issue.  */
-         if (buf_reversed)
-           cluster_offset = to - from;
-       }
-
-      /* All the glyphs in a cluster have the same values of FROM and TO.  */
-      LGLYPH_SET_FROM (lglyph, from);
-      LGLYPH_SET_TO (lglyph, to);
-
-      /* Not every glyph in a cluster maps directly to a single
-        character; in general, N characters can yield M glyphs, where
-        M could be smaller or greater than N.  However, in many cases
-        there is a one-to-one correspondence, and it would be a pity
-        to lose that information, even if it's sometimes inaccurate.  */
-      char_idx = from + cluster_offset;
-      cluster_offset += incr;
-      if (char_idx > to)
-       char_idx = to;
-      if (char_idx < from)
-       char_idx = from;
-      LGLYPH_SET_CHAR (lglyph, chars[char_idx]);
-      LGLYPH_SET_CODE (lglyph, info[i].codepoint);
-
-      unsigned code = info[i].codepoint;
-      font->driver->text_extents (font, &code, 1, &metrics);
-      LGLYPH_SET_WIDTH (lglyph, metrics.width);
-      LGLYPH_SET_LBEARING (lglyph, metrics.lbearing);
-      LGLYPH_SET_RBEARING (lglyph, metrics.rbearing);
-      LGLYPH_SET_ASCENT (lglyph, metrics.ascent);
-      LGLYPH_SET_DESCENT (lglyph, metrics.descent);
-
-      xoff = lround (pos[i].x_offset * position_unit);
-      yoff = - lround (pos[i].y_offset * position_unit);
-      wadjust = lround (pos[i].x_advance * position_unit);
-      if (xoff || yoff || wadjust != metrics.width)
-       {
-         Lisp_Object vec = make_uninit_vector (3);
-         ASET (vec, 0, make_fixnum (xoff));
-         ASET (vec, 1, make_fixnum (yoff));
-         ASET (vec, 2, make_fixnum (wadjust));
-         LGLYPH_SET_ADJUSTMENT (lglyph, vec);
-       }
-    }
-
-  return make_fixnum (glyph_len);
-}
-
-static Lisp_Object
-w32hb_combining_capability (struct font *font)
-{
-  return Qt;
-}
 #endif /* HAVE_HARFBUZZ */
 
 #undef OTF_INT16_VAL
@@ -1838,29 +1439,7 @@ load_harfbuzz_funcs (HMODULE library)
   LOAD_DLL_FN (library, hb_face_get_upem);
   LOAD_DLL_FN (library, hb_face_destroy);
   LOAD_DLL_FN (library, hb_font_get_nominal_glyph);
-  LOAD_DLL_FN (library, hb_unicode_funcs_create);
-  LOAD_DLL_FN (library, hb_unicode_funcs_get_default);
-  LOAD_DLL_FN (library, hb_unicode_funcs_set_combining_class_func);
-  LOAD_DLL_FN (library, hb_unicode_funcs_set_general_category_func);
-  LOAD_DLL_FN (library, hb_unicode_funcs_set_mirroring_func);
-  LOAD_DLL_FN (library, hb_buffer_create);
-  LOAD_DLL_FN (library, hb_buffer_set_unicode_funcs);
-  LOAD_DLL_FN (library, hb_buffer_clear_contents);
-  LOAD_DLL_FN (library, hb_buffer_pre_allocate);
-  LOAD_DLL_FN (library, hb_buffer_add);
-  LOAD_DLL_FN (library, hb_buffer_set_content_type);
-  LOAD_DLL_FN (library, hb_buffer_set_cluster_level);
-  LOAD_DLL_FN (library, hb_buffer_set_direction);
-  LOAD_DLL_FN (library, hb_buffer_set_language);
-  LOAD_DLL_FN (library, hb_language_from_string);
-  LOAD_DLL_FN (library, hb_buffer_guess_segment_properties);
-  LOAD_DLL_FN (library, hb_shape_full);
-  LOAD_DLL_FN (library, hb_buffer_get_length);
-  LOAD_DLL_FN (library, hb_buffer_get_direction);
-  LOAD_DLL_FN (library, hb_buffer_reverse_clusters);
-  LOAD_DLL_FN (library, hb_buffer_get_glyph_infos);
-  LOAD_DLL_FN (library, hb_buffer_get_glyph_positions);
-  return true;
+  return hbfont_init_w32_funcs (library);
 }
 #endif /* HAVE_HARFBUZZ */
 
@@ -1913,8 +1492,8 @@ syms_of_w32uniscribe_for_pdumper (void)
   harfbuzz_font_driver.list = w32hb_list;
   harfbuzz_font_driver.match = w32hb_match;
   harfbuzz_font_driver.encode_char = w32hb_encode_char;
-  harfbuzz_font_driver.shape = w32hb_shape;
-  harfbuzz_font_driver.combining_capability = w32hb_combining_capability;
+  harfbuzz_font_driver.shape = hbfont_shape;
+  harfbuzz_font_driver.combining_capability = hbfont_combining_capability;
   harfbuzz_font_driver.begin_hb_font = w32hb_begin_font;
   register_font_driver (&harfbuzz_font_driver, NULL);
 #endif /* HAVE_HARFBUZZ */