Move common HarfBuzz code to a common file hbfont.c
* 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.
This commit is contained in:
parent
b7730c259b
commit
4363777d5c
6 changed files with 503 additions and 427 deletions
|
@ -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)
|
||||
|
|
|
@ -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@
|
||||
|
|
|
@ -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);
|
||||
|
|
484
src/hbfont.c
Normal file
484
src/hbfont.c
Normal file
|
@ -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;
|
||||
}
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Add table
Reference in a new issue