Merge remote-tracking branch 'origin/harfbuzz'
This commit is contained in:
commit
4ebfec02f0
36 changed files with 1516 additions and 224 deletions
|
@ -53,13 +53,14 @@ def extract_deps():
|
|||
# This list derives from the features we want Emacs to compile with.
|
||||
PKG_REQ='''mingw-w64-x86_64-giflib
|
||||
mingw-w64-x86_64-gnutls
|
||||
mingw-w64-x86_64-harfbuzz
|
||||
mingw-w64-x86_64-lcms2
|
||||
mingw-w64-x86_64-libjpeg-turbo
|
||||
mingw-w64-x86_64-libpng
|
||||
mingw-w64-x86_64-librsvg
|
||||
mingw-w64-x86_64-libtiff
|
||||
mingw-w64-x86_64-libxml2
|
||||
mingw-w64-x86_64-xpm-nox
|
||||
mingw-w64-x86_64-lcms2'''.split()
|
||||
mingw-w64-x86_64-xpm-nox'''.split()
|
||||
|
||||
# Get a list of all dependencies needed for packages mentioned above.
|
||||
# Run `pactree -lu' for each element of $PKG_REQ.
|
||||
|
|
106
configure.ac
106
configure.ac
|
@ -436,6 +436,7 @@ OPTION_DEFAULT_OFF([imagemagick],[compile with ImageMagick image support])
|
|||
OPTION_DEFAULT_ON([json], [don't compile with native JSON support])
|
||||
|
||||
OPTION_DEFAULT_ON([xft],[don't use XFT for anti aliased fonts])
|
||||
OPTION_DEFAULT_ON([harfbuzz],[don't use HarfBuzz for text shaping])
|
||||
OPTION_DEFAULT_ON([libotf],[don't use libotf for OpenType font support])
|
||||
OPTION_DEFAULT_ON([m17n-flt],[don't use m17n-flt for text shaping])
|
||||
|
||||
|
@ -3408,53 +3409,84 @@ if test "${HAVE_X11}" = "yes"; then
|
|||
fi
|
||||
fi # $HAVE_CAIRO != yes
|
||||
|
||||
HAVE_LIBOTF=no
|
||||
if test "${HAVE_FREETYPE}" = "yes"; then
|
||||
AC_DEFINE(HAVE_FREETYPE, 1,
|
||||
[Define to 1 if using the freetype and fontconfig libraries.])
|
||||
if test "${with_libotf}" != "no"; then
|
||||
EMACS_CHECK_MODULES([LIBOTF], [libotf])
|
||||
if test "$HAVE_LIBOTF" = "yes"; then
|
||||
AC_DEFINE(HAVE_LIBOTF, 1, [Define to 1 if using libotf.])
|
||||
AC_CHECK_LIB(otf, OTF_get_variation_glyphs,
|
||||
HAVE_OTF_GET_VARIATION_GLYPHS=yes,
|
||||
HAVE_OTF_GET_VARIATION_GLYPHS=no)
|
||||
if test "${HAVE_OTF_GET_VARIATION_GLYPHS}" = "yes"; then
|
||||
AC_DEFINE(HAVE_OTF_GET_VARIATION_GLYPHS, 1,
|
||||
[Define to 1 if libotf has OTF_get_variation_glyphs.])
|
||||
fi
|
||||
if ! $PKG_CONFIG --atleast-version=0.9.16 libotf; then
|
||||
AC_DEFINE(HAVE_OTF_KANNADA_BUG, 1,
|
||||
HAVE_LIBOTF=no
|
||||
if test "${HAVE_FREETYPE}" = "yes"; then
|
||||
AC_DEFINE(HAVE_FREETYPE, 1,
|
||||
[Define to 1 if using the freetype and fontconfig libraries.])
|
||||
OLD_CFLAGS=$CFLAGS
|
||||
OLD_LIBS=$LIBS
|
||||
CFLAGS="$CFLAGS $FREETYPE_CFLAGS"
|
||||
LIBS="$FREETYPE_LIBS $LIBS"
|
||||
AC_CHECK_FUNCS(FT_Face_GetCharVariantIndex)
|
||||
CFLAGS=$OLD_CFLAGS
|
||||
LIBS=$OLD_LIBS
|
||||
if test "${with_libotf}" != "no"; then
|
||||
EMACS_CHECK_MODULES([LIBOTF], [libotf])
|
||||
if test "$HAVE_LIBOTF" = "yes"; then
|
||||
AC_DEFINE(HAVE_LIBOTF, 1, [Define to 1 if using libotf.])
|
||||
AC_CHECK_LIB(otf, OTF_get_variation_glyphs,
|
||||
HAVE_OTF_GET_VARIATION_GLYPHS=yes,
|
||||
HAVE_OTF_GET_VARIATION_GLYPHS=no)
|
||||
if test "${HAVE_OTF_GET_VARIATION_GLYPHS}" = "yes"; then
|
||||
AC_DEFINE(HAVE_OTF_GET_VARIATION_GLYPHS, 1,
|
||||
[Define to 1 if libotf has OTF_get_variation_glyphs.])
|
||||
fi
|
||||
if ! $PKG_CONFIG --atleast-version=0.9.16 libotf; then
|
||||
AC_DEFINE(HAVE_OTF_KANNADA_BUG, 1,
|
||||
[Define to 1 if libotf is affected by https://debbugs.gnu.org/28110.])
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
dnl FIXME should there be an error if HAVE_FREETYPE != yes?
|
||||
dnl Does the new font backend require it, or can it work without it?
|
||||
fi
|
||||
dnl FIXME should there be an error if HAVE_FREETYPE != yes?
|
||||
dnl Does the new font backend require it, or can it work without it?
|
||||
fi
|
||||
|
||||
HAVE_M17N_FLT=no
|
||||
if test "${HAVE_LIBOTF}" = yes; then
|
||||
if test "${with_m17n_flt}" != "no"; then
|
||||
EMACS_CHECK_MODULES([M17N_FLT], [m17n-flt])
|
||||
if test "$HAVE_M17N_FLT" = "yes"; then
|
||||
AC_DEFINE(HAVE_M17N_FLT, 1, [Define to 1 if using libm17n-flt.])
|
||||
fi
|
||||
HAVE_M17N_FLT=no
|
||||
if test "${HAVE_LIBOTF}" = yes; then
|
||||
if test "${with_m17n_flt}" != "no"; then
|
||||
EMACS_CHECK_MODULES([M17N_FLT], [m17n-flt])
|
||||
if test "$HAVE_M17N_FLT" = "yes"; then
|
||||
AC_DEFINE(HAVE_M17N_FLT, 1, [Define to 1 if using libm17n-flt.])
|
||||
fi
|
||||
fi
|
||||
else
|
||||
HAVE_XFT=no
|
||||
HAVE_FREETYPE=no
|
||||
HAVE_LIBOTF=no
|
||||
HAVE_M17N_FLT=no
|
||||
fi
|
||||
else # "${HAVE_X11}" != "yes"
|
||||
HAVE_XFT=no
|
||||
HAVE_FREETYPE=no
|
||||
HAVE_LIBOTF=no
|
||||
HAVE_M17N_FLT=no
|
||||
fi # "${HAVE_X11}" != "yes"
|
||||
|
||||
HAVE_HARFBUZZ=no
|
||||
if test "${HAVE_X11}" = "yes" && test "${HAVE_FREETYPE}" = "yes" \
|
||||
|| test "${HAVE_W32}" = "yes"; then
|
||||
if test "${with_harfbuzz}" != "no"; then
|
||||
### On MS-Windows we use hb_font_get_nominal_glyph, which appeared
|
||||
### in HarfBuzz version 1.2.3
|
||||
if test "${HAVE_W32}" = "yes"; then
|
||||
EMACS_CHECK_MODULES([HARFBUZZ], [harfbuzz >= 1.2.3])
|
||||
else
|
||||
EMACS_CHECK_MODULES([HARFBUZZ], [harfbuzz >= 0.9.42])
|
||||
fi
|
||||
if test "$HAVE_HARFBUZZ" = "yes"; then
|
||||
AC_DEFINE(HAVE_HARFBUZZ, 1, [Define to 1 if using HarfBuzz.])
|
||||
### mingw32 and Cygwin-w32 don't use -lharfbuzz, since they load
|
||||
### the library dynamically.
|
||||
if test "${HAVE_W32}" = "yes"; then
|
||||
HARFBUZZ_LIBS=
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
### End of font-backend (under X11) section.
|
||||
### End of font-backend section.
|
||||
|
||||
AC_SUBST(FREETYPE_CFLAGS)
|
||||
AC_SUBST(FREETYPE_LIBS)
|
||||
AC_SUBST(FONTCONFIG_CFLAGS)
|
||||
AC_SUBST(FONTCONFIG_LIBS)
|
||||
AC_SUBST(HARFBUZZ_CFLAGS)
|
||||
AC_SUBST(HARFBUZZ_LIBS)
|
||||
AC_SUBST(LIBOTF_CFLAGS)
|
||||
AC_SUBST(LIBOTF_LIBS)
|
||||
AC_SUBST(M17N_FLT_CFLAGS)
|
||||
|
@ -5235,8 +5267,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)
|
||||
|
@ -5587,7 +5622,7 @@ Configured for '${canonical}'.
|
|||
optsep=
|
||||
emacs_config_features=
|
||||
for opt in XAW3D XPM JPEG TIFF GIF PNG RSVG CAIRO IMAGEMAGICK SOUND GPM DBUS \
|
||||
GCONF GSETTINGS GLIB NOTIFY ACL LIBSELINUX GNUTLS LIBXML2 FREETYPE M17N_FLT \
|
||||
GCONF GSETTINGS GLIB NOTIFY ACL LIBSELINUX GNUTLS LIBXML2 FREETYPE HARFBUZZ M17N_FLT \
|
||||
LIBOTF XFT ZLIB TOOLKIT_SCROLL_BARS X_TOOLKIT OLDXMENU X11 XDBE XIM \
|
||||
NS MODULES THREADS XWIDGETS LIBSYSTEMD JSON PDUMPER UNEXEC LCMS2 GMP; do
|
||||
|
||||
|
@ -5647,6 +5682,7 @@ AS_ECHO([" Does Emacs use -lXaw3d? ${HAVE_XAW3D
|
|||
Does Emacs use -lgnutls? ${HAVE_GNUTLS}
|
||||
Does Emacs use -lxml2? ${HAVE_LIBXML2}
|
||||
Does Emacs use -lfreetype? ${HAVE_FREETYPE}
|
||||
Does Emacs use HarfBuzz? ${HAVE_HARFBUZZ}
|
||||
Does Emacs use -lm17n-flt? ${HAVE_M17N_FLT}
|
||||
Does Emacs use -lotf? ${HAVE_LIBOTF}
|
||||
Does Emacs use -lxft? ${HAVE_XFT}
|
||||
|
|
|
@ -985,21 +985,34 @@ fontconfig library used in modern Free desktops:
|
|||
The old XLFD based format is also supported for backwards compatibility.
|
||||
|
||||
@cindex font backend selection (MS-Windows)
|
||||
Emacs 23 and later supports a number of font backends. Currently,
|
||||
the @code{gdi} and @code{uniscribe} backends are supported on Windows.
|
||||
The @code{gdi} font backend is available on all versions of Windows,
|
||||
and supports all fonts that are natively supported by Windows. The
|
||||
@code{uniscribe} font backend is available on Windows 2000 and later,
|
||||
and supports TrueType and OpenType fonts. Some languages requiring
|
||||
complex layout can only be properly supported by the Uniscribe
|
||||
backend. By default, both backends are enabled if supported, with
|
||||
@code{uniscribe} taking priority over @code{gdi}. To override that
|
||||
and use the GDI backend even if Uniscribe is available, invoke Emacs
|
||||
with the @kbd{-xrm Emacs.fontBackend:gdi} command-line argument, or
|
||||
add a @code{Emacs.fontBackend} resource with the value @code{gdi} in
|
||||
the Registry under either the
|
||||
Emacs on MS-Windows supports a number of font backends. Currently,
|
||||
the @code{gdi}, @code{uniscribe}, and @code{harfbuzz} backends are
|
||||
available. The @code{gdi} font backend is available on all versions
|
||||
of Windows, and supports all fonts that are natively supported by
|
||||
Windows. The @code{uniscribe} font backend is available on Windows
|
||||
2000 and later, and supports TrueType and OpenType fonts. The
|
||||
@code{harfbuzz} font backend is available if Emacs was built with
|
||||
HarfBuzz support, and if the HarfBuzz DLL is installed on your system;
|
||||
like @code{uniscribe}, this backend supports only TrueType and
|
||||
OpenType fonts. Some languages requiring complex layout can only be
|
||||
properly supported by the Uniscribe or HarfBuzz backends. By default,
|
||||
two backends are enabled for each frame: @code{gdi} and either
|
||||
@code{harfbuzz} or @code{uniscribe}, depending on which one is
|
||||
available (if both are available, only @code{harfbuzz} is enabled by
|
||||
default). The @code{harfbuzz} and @code{uniscribe} backends take
|
||||
priority over @code{gdi} when Emacs looks for a suitable font. To
|
||||
override that and use the GDI backend even if Uniscribe is available,
|
||||
invoke Emacs with the @kbd{-xrm Emacs.fontBackend:gdi} command-line
|
||||
argument, or add a @code{Emacs.fontBackend} resource with the value
|
||||
@code{gdi} in the Registry under either the
|
||||
@samp{HKEY_CURRENT_USER\SOFTWARE\GNU\Emacs} or the
|
||||
@samp{HKEY_LOCAL_MACHINE\SOFTWARE\GNU\Emacs} key (@pxref{Resources}).
|
||||
Similarly, to use the Uniscribe backend even if HarfBuzz is available,
|
||||
use @kbd{-xrm Emacs.fontBackend:uniscribe} on the command line that
|
||||
invokes Emacs. You can also request all the 3 backends via the
|
||||
@code{font-backend} frame parameter, but be warned that in that case
|
||||
font searches for characters for which no fonts are available on the
|
||||
system will take longer.
|
||||
|
||||
@cindex font properties (MS Windows)
|
||||
@noindent
|
||||
|
|
|
@ -2278,13 +2278,21 @@ variable do not take effect immediately, only when you specify the
|
|||
@vindex font-backend@r{, a frame parameter}
|
||||
@item font-backend
|
||||
A list of symbols, specifying the @dfn{font backends} to use for
|
||||
drawing fonts in the frame, in order of priority. On X, there are
|
||||
currently two available font backends: @code{x} (the X core font
|
||||
driver) and @code{xft} (the Xft font driver). On MS-Windows, there are
|
||||
currently two available font backends: @code{gdi} and
|
||||
@code{uniscribe} (@pxref{Windows Fonts,,, emacs, The GNU Emacs
|
||||
Manual}). On other systems, there is only one available font backend,
|
||||
so it does not make sense to modify this frame parameter.
|
||||
drawing characters on the frame, in order of priority. In Emacs built
|
||||
without Cairo drawing on X, there are currently three available font
|
||||
backends: @code{x} (the X core font driver), @code{xft} (the Xft font
|
||||
driver), and @code{xfthb} (the Xft font driver with HarfBuzz text
|
||||
shaping). If built with the Cairo drawing, there are two available
|
||||
font backends on X: @code{ftcr} (the FreeType font driver on Cairo)
|
||||
and @code{ftcrhb} (the FreeType font driver on Cairo with HarfBuzz
|
||||
text shaping). On MS-Windows, there are currently three available
|
||||
font backends: @code{gdi} (the core MS-Windows font driver),
|
||||
@code{uniscribe} (font driver for OTF and TTF fonts with text shaping
|
||||
by the Uniscribe engine), and @code{harfbuzz} (font driver for OTF and
|
||||
TTF fonts with HarfBuzz text shaping) (@pxref{Windows Fonts,,, emacs,
|
||||
The GNU Emacs Manual}). On other systems, there is only one available
|
||||
font backend, so it does not make sense to modify this frame
|
||||
parameter.
|
||||
|
||||
@vindex background-mode@r{, a frame parameter}
|
||||
@item background-mode
|
||||
|
|
|
@ -10,7 +10,7 @@ Non-ASCII examples:
|
|||
Europe: <x-charset><param>latin-iso8859-1</param>¡Hola!, Grüß Gott, Hyvää päivää,</x-charset><x-charset><param>latin-iso8859-15</param> Tere õhtust,</x-charset><x-charset><param>latin-iso8859-3</param> Bonġu
|
||||
Cześć!,</x-charset><x-charset><param>latin-iso8859-2</param> Dobrý den,</x-charset><x-charset><param>cyrillic-iso8859-5</param> Здравствуйте!,</x-charset><x-charset><param>greek-iso8859-7</param> Γειά σας,</x-charset><x-charset><param>mule-unicode-0100-24ff</param> გამარჯობა</x-charset>
|
||||
Africa:<x-charset><param>mule-unicode-0100-24ff</param> </x-charset><x-charset><param>ethiopic</param>ሠላም</x-charset>
|
||||
Middle/Near East:<x-charset><param>hebrew-iso8859-8</param> שלום,</x-charset><x-charset><param>mule-unicode-0100-24ff</param> السّلام عليكم</x-charset>
|
||||
Middle/Near East:<x-charset><param>hebrew-iso8859-8</param> שָׁלוֹם,</x-charset><x-charset><param>mule-unicode-0100-24ff</param> السّلام عليكم</x-charset>
|
||||
South Asia:<x-charset><param>mule-unicode-0100-24ff</param> નમસ્તે, नमस्ते, ನಮಸ್ಕಾರ, നമസ്കാരം, ଶୁଣିବେ,
|
||||
ආයුබෝවන්, வணக்கம், నమస్కారం,</x-charset><x-charset><param>tibetan</param> བཀྲ་ཤིས་བདེ་ལེགས༎</x-charset>
|
||||
South East Asia:<x-charset><param>mule-unicode-0100-24ff</param> ជំរាបសួរ,</x-charset><x-charset><param>lao</param> ສະບາຍດີ,</x-charset><x-charset><param>mule-unicode-0100-24ff</param> မင်္ဂလာပါ,</x-charset><x-charset><param>thai-tis620</param> สวัสดีครับ,</x-charset><x-charset><param>vietnamese-viscii-lower</param> </x-charset><x-charset><param>vietnamese-viscii-upper</param>C</x-charset><x-charset><param>vietnamese-viscii-lower</param>hào bạn</x-charset>
|
||||
|
@ -52,7 +52,7 @@ French (français) Bonjour / Salut
|
|||
</x-charset><x-charset><param>greek-iso8859-7</param>Greek (ελληνικά) Γειά σας
|
||||
</x-charset><x-charset><param>mule-unicode-0100-24ff</param>Greek, ancient (ἑλληνική) Οὖλέ τε καὶ μέγα χαῖρε
|
||||
Gujarati (ગુજરાતી) નમસ્તે
|
||||
</x-charset><x-charset><param>hebrew-iso8859-8</param>Hebrew (עברית) שלום
|
||||
</x-charset><x-charset><param>hebrew-iso8859-8</param>Hebrew (עִבְרִית) שָׁלוֹם
|
||||
</x-charset><x-charset><param>latin-iso8859-2</param>Hungarian (magyar) Szép jó napot!
|
||||
</x-charset><x-charset><param>mule-unicode-0100-24ff</param>Hindi (हिंदी) नमस्ते / नमस्कार ।
|
||||
</x-charset><x-charset><param>unicode</param>Inuktitut (ᐃᓄᒃᑎᑐᑦ) ᐊᐃ
|
||||
|
|
11
etc/NEWS
11
etc/NEWS
|
@ -30,6 +30,17 @@ arranges for the included mini-gmp library to be built and used.
|
|||
The new 'configure' option '--without-libgmp' uses mini-gmp even if a
|
||||
suitable libgmp is available.
|
||||
|
||||
** The new configure option '--with-harfbuzz' adds support for the
|
||||
HarfBuzz text shaping engine. It is on by default; use './configure
|
||||
--without-harfbuzz' to build without it. The HarfBuzz text shaping is
|
||||
available via new font backend drivers 'xfthb' and 'ftcrhb' for Xft
|
||||
and Cairo drawings, respectively, and via the 'harfbuzz' backend on
|
||||
MS-Windows. The Harfbuzz text shaping is preferred to the previously
|
||||
supported ones, so the font backends that use older shaping engines
|
||||
(FLT on GNU and Unix systems and Uniscribe on MS-Windows) are not
|
||||
enabled by default; they can be enabled via the 'font-backend' frame
|
||||
parameter or via X resources.
|
||||
|
||||
** The new configure option '--with-json' adds support for JSON using
|
||||
the Jansson library. It is on by default; use './configure
|
||||
--with-json=no' to build without Jansson support. The new JSON
|
||||
|
|
|
@ -382,8 +382,8 @@ This function is the default value of `compose-chars-after-function'."
|
|||
(looking-at pattern))
|
||||
(<= (match-end 0) limit))
|
||||
(setq result
|
||||
(funcall func pos (match-end 0) font-obj object)))
|
||||
(setq result (funcall func pos limit font-obj object)))
|
||||
(funcall func pos (match-end 0) font-obj object nil)))
|
||||
(setq result (funcall func pos limit font-obj object nil)))
|
||||
(if result (setq tail nil))))))
|
||||
result))
|
||||
|
||||
|
@ -524,8 +524,9 @@ after a sequence of character events."
|
|||
(setq from (1+ from)))
|
||||
gstring))
|
||||
|
||||
(defun compose-gstring-for-graphic (gstring)
|
||||
"Compose glyph-string GSTRING for graphic display.
|
||||
(defun compose-gstring-for-graphic (gstring direction)
|
||||
"Compose glyph-string GSTRING under bidi DIRECTION for graphic display.
|
||||
DIRECTION is either L2R or R2L, or nil if unknown.
|
||||
Combining characters are composed with the preceding base
|
||||
character. If the preceding character is not a base character,
|
||||
each combining character is composed as a spacing character by
|
||||
|
@ -559,7 +560,7 @@ All non-spacing characters have this function in
|
|||
|
||||
;; A base character and the following non-spacing characters.
|
||||
(t
|
||||
(let ((gstr (font-shape-gstring gstring)))
|
||||
(let ((gstr (font-shape-gstring gstring direction)))
|
||||
(if (and gstr
|
||||
(> (lglyph-to (lgstring-glyph gstr 0)) 0))
|
||||
gstr
|
||||
|
@ -686,12 +687,12 @@ All non-spacing characters have this function in
|
|||
(setq i (1+ i))))
|
||||
gstring))))))
|
||||
|
||||
(defun compose-gstring-for-dotted-circle (gstring)
|
||||
(defun compose-gstring-for-dotted-circle (gstring direction)
|
||||
(let* ((dc (lgstring-glyph gstring 0)) ; glyph of dotted-circle
|
||||
(dc-id (lglyph-code dc))
|
||||
(fc (lgstring-glyph gstring 1)) ; glyph of the following char
|
||||
(fc-id (lglyph-code fc))
|
||||
(gstr (and nil (font-shape-gstring gstring))))
|
||||
(gstr (and nil (font-shape-gstring gstring direction))))
|
||||
(if (and gstr
|
||||
(or (= (lgstring-glyph-len gstr) 1)
|
||||
(and (= (lgstring-glyph-len gstr) 2)
|
||||
|
@ -742,7 +743,7 @@ All non-spacing characters have this function in
|
|||
(aset composition-function-table #x25CC
|
||||
`([,(purecopy ".\\c^") 0 compose-gstring-for-dotted-circle])))
|
||||
|
||||
(defun compose-gstring-for-terminal (gstring)
|
||||
(defun compose-gstring-for-terminal (gstring _direction)
|
||||
"Compose glyph-string GSTRING for terminal display.
|
||||
Non-spacing characters are composed with the preceding base
|
||||
character. If the preceding character is not a base character,
|
||||
|
@ -799,10 +800,11 @@ prepending a space before it."
|
|||
gstring))
|
||||
|
||||
|
||||
(defun auto-compose-chars (func from to font-object string)
|
||||
(defun auto-compose-chars (func from to font-object string direction)
|
||||
"Compose the characters at FROM by FUNC.
|
||||
FUNC is called with one argument GSTRING which is built for characters
|
||||
in the region FROM (inclusive) and TO (exclusive).
|
||||
FUNC is called with two arguments: GSTRING, which is built for
|
||||
characters in the region FROM (inclusive) and TO (exclusive);
|
||||
and DIRECTION, which is the bidi directionality of the characters.
|
||||
|
||||
If the character are composed on a graphic display, FONT-OBJECT
|
||||
is a font to use. Otherwise, FONT-OBJECT is nil, and the function
|
||||
|
@ -819,7 +821,7 @@ This function is the default value of `auto-composition-function' (which see)."
|
|||
gstring
|
||||
(or (fontp font-object 'font-object)
|
||||
(setq func 'compose-gstring-for-terminal))
|
||||
(funcall func gstring))))
|
||||
(funcall func gstring direction))))
|
||||
|
||||
(put 'auto-composition-mode 'permanent-local t)
|
||||
|
||||
|
|
|
@ -1014,7 +1014,7 @@ With ARG, insert that many delimiters."
|
|||
;;
|
||||
|
||||
;;;###autoload
|
||||
(defun ethio-composition-function (pos to font-object string)
|
||||
(defun ethio-composition-function (pos to font-object string _direction)
|
||||
(setq pos (1- pos))
|
||||
(let ((pattern "\\ce\\(፟\\|<7C><><EFBFBD><EFBFBD>\\)"))
|
||||
(if string
|
||||
|
|
|
@ -152,7 +152,7 @@ Bidirectional editing is supported.")))
|
|||
;; (3) If the font has precomposed glyphs, use them as far as
|
||||
;; possible. Adjust the remaining glyphs artificially.
|
||||
|
||||
(defun hebrew-shape-gstring (gstring)
|
||||
(defun hebrew-shape-gstring (gstring direction)
|
||||
(let* ((font (lgstring-font gstring))
|
||||
(otf (font-get font :otf))
|
||||
(nchars (lgstring-char-len gstring))
|
||||
|
@ -172,7 +172,7 @@ Bidirectional editing is supported.")))
|
|||
|
||||
((or (assq 'hebr (car otf)) (assq 'hebr (cdr otf)))
|
||||
;; FONT has OpenType features for Hebrew.
|
||||
(font-shape-gstring gstring))
|
||||
(font-shape-gstring gstring direction))
|
||||
|
||||
(t
|
||||
;; FONT doesn't have OpenType features for Hebrew.
|
||||
|
@ -217,7 +217,7 @@ Bidirectional editing is supported.")))
|
|||
;; Now IDX is an index to the first non-precomposed glyph.
|
||||
;; Adjust positions of the remaining glyphs artificially.
|
||||
(if (font-get font :combining-capability)
|
||||
(font-shape-gstring gstring)
|
||||
(font-shape-gstring gstring direction)
|
||||
(setq base-width (lglyph-width (lgstring-glyph gstring 0)))
|
||||
(while (< idx nglyphs)
|
||||
(setq glyph (lgstring-glyph gstring idx))
|
||||
|
|
|
@ -828,6 +828,9 @@ Returns new end position."
|
|||
(let ((pos from) newpos func (max to))
|
||||
(narrow-to-region from to)
|
||||
(while (< pos max)
|
||||
;; FIXME: The below seems to assume
|
||||
;; composition-function-table holds functions? That is no
|
||||
;; longer true, since long ago.
|
||||
(setq func (aref composition-function-table (char-after pos)))
|
||||
(if (fboundp func)
|
||||
(setq newpos (funcall func pos nil)
|
||||
|
|
|
@ -248,7 +248,7 @@ eucJP-ms is defined in <http://www.opengroup.or.jp/jvc/cde/appendix.html>."
|
|||
(define-translation-table 'unicode-to-jisx0213
|
||||
(char-table-extra-slot table 0)))
|
||||
|
||||
(defun compose-gstring-for-variation-glyph (gstring)
|
||||
(defun compose-gstring-for-variation-glyph (gstring _direction)
|
||||
"Compose glyph-string GSTRING for graphic display.
|
||||
GSTRING must have two glyphs; the first is a glyph for a han character,
|
||||
and the second is a glyph for a variation selector."
|
||||
|
|
|
@ -489,10 +489,10 @@ syllable. In that case, FROM and TO are indexes to STR."
|
|||
lao-str)))
|
||||
|
||||
;;;###autoload
|
||||
(defun lao-composition-function (gstring)
|
||||
(defun lao-composition-function (gstring direction)
|
||||
(if (= (lgstring-char-len gstring) 1)
|
||||
(compose-gstring-for-graphic gstring)
|
||||
(or (font-shape-gstring gstring)
|
||||
(compose-gstring-for-graphic gstring direction)
|
||||
(or (font-shape-gstring gstring direction)
|
||||
(let ((glyph-len (lgstring-glyph-len gstring))
|
||||
(i 0)
|
||||
glyph)
|
||||
|
|
|
@ -101,8 +101,8 @@ thin (i.e. 1-dot width) space."
|
|||
;; Record error in arabic-change-gstring.
|
||||
(defvar arabic-shape-log nil)
|
||||
|
||||
(defun arabic-shape-gstring (gstring)
|
||||
(setq gstring (font-shape-gstring gstring))
|
||||
(defun arabic-shape-gstring (gstring direction)
|
||||
(setq gstring (font-shape-gstring gstring direction))
|
||||
(condition-case err
|
||||
(when arabic-shaper-ZWNJ-handling
|
||||
(let ((font (lgstring-font gstring))
|
||||
|
|
|
@ -225,10 +225,10 @@ positions (integers or markers) specifying the region."
|
|||
(thai-compose-region (point-min) (point-max)))
|
||||
|
||||
;;;###autoload
|
||||
(defun thai-composition-function (gstring)
|
||||
(defun thai-composition-function (gstring direction)
|
||||
(if (= (lgstring-char-len gstring) 1)
|
||||
(compose-gstring-for-graphic gstring)
|
||||
(or (font-shape-gstring gstring)
|
||||
(compose-gstring-for-graphic gstring direction)
|
||||
(or (font-shape-gstring gstring direction)
|
||||
(let ((glyph-len (lgstring-glyph-len gstring))
|
||||
(last-char (lgstring-char gstring
|
||||
(1- (lgstring-char-len gstring))))
|
||||
|
|
|
@ -128,7 +128,7 @@
|
|||
|
||||
|
||||
;;;###autoload
|
||||
(defun tai-viet-composition-function (from to font-object string)
|
||||
(defun tai-viet-composition-function (from to font-object string _direction)
|
||||
(if string
|
||||
(if (string-match tai-viet-re string from)
|
||||
(tai-viet-compose-string from (match-end 0) string))
|
||||
|
|
|
@ -132,6 +132,8 @@ FONTCONFIG_CFLAGS = @FONTCONFIG_CFLAGS@
|
|||
FONTCONFIG_LIBS = @FONTCONFIG_LIBS@
|
||||
FREETYPE_CFLAGS = @FREETYPE_CFLAGS@
|
||||
FREETYPE_LIBS = @FREETYPE_LIBS@
|
||||
HARFBUZZ_CFLAGS = @HARFBUZZ_CFLAGS@
|
||||
HARFBUZZ_LIBS = @HARFBUZZ_LIBS@
|
||||
LIBOTF_CFLAGS = @LIBOTF_CFLAGS@
|
||||
LIBOTF_LIBS = @LIBOTF_LIBS@
|
||||
M17N_FLT_CFLAGS = @M17N_FLT_CFLAGS@
|
||||
|
@ -297,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.
|
||||
|
@ -380,7 +383,7 @@ EMACS_CFLAGS=-Demacs $(MYCPPFLAGS) -I. -I$(srcdir) \
|
|||
$(XRANDR_CFLAGS) $(XINERAMA_CFLAGS) $(XFIXES_CFLAGS) $(XDBE_CFLAGS) \
|
||||
$(WEBKIT_CFLAGS) $(LCMS2_CFLAGS) \
|
||||
$(SETTINGS_CFLAGS) $(FREETYPE_CFLAGS) $(FONTCONFIG_CFLAGS) \
|
||||
$(LIBOTF_CFLAGS) $(M17N_FLT_CFLAGS) $(DEPFLAGS) \
|
||||
$(HARFBUZZ_CFLAGS) $(LIBOTF_CFLAGS) $(M17N_FLT_CFLAGS) $(DEPFLAGS) \
|
||||
$(LIBSYSTEMD_CFLAGS) $(JSON_CFLAGS) \
|
||||
$(LIBGNUTLS_CFLAGS) $(NOTIFY_CFLAGS) $(CAIRO_CFLAGS) \
|
||||
$(WERROR_CFLAGS)
|
||||
|
@ -429,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@
|
||||
|
@ -520,7 +523,7 @@ LIBES = $(LIBS) $(W32_LIBS) $(LIBS_GNUSTEP) $(LIBX_BASE) $(LIBIMAGE) \
|
|||
$(XDBE_LIBS) \
|
||||
$(LIBXML2_LIBS) $(LIBGPM) $(LIBS_SYSTEM) $(CAIRO_LIBS) \
|
||||
$(LIBS_TERMCAP) $(GETLOADAVG_LIBS) $(SETTINGS_LIBS) $(LIBSELINUX_LIBS) \
|
||||
$(FREETYPE_LIBS) $(FONTCONFIG_LIBS) $(LIBOTF_LIBS) $(M17N_FLT_LIBS) \
|
||||
$(FREETYPE_LIBS) $(FONTCONFIG_LIBS) $(HARFBUZZ_LIBS) $(LIBOTF_LIBS) $(M17N_FLT_LIBS) \
|
||||
$(LIBGNUTLS_LIBS) $(LIB_PTHREAD) $(GETADDRINFO_A_LIBS) $(LCMS2_LIBS) \
|
||||
$(NOTIFY_LIBS) $(LIB_MATH) $(LIBZ) $(LIBMODULES) $(LIBSYSTEMD_LIBS) \
|
||||
$(JSON_LIBS) $(GMP_LIB)
|
||||
|
|
|
@ -1321,22 +1321,25 @@ and put an element value. */)
|
|||
return Fcdr (Fassq (prop, Vchar_code_property_alist));
|
||||
}
|
||||
|
||||
Lisp_Object
|
||||
get_unicode_property (Lisp_Object char_table, int ch)
|
||||
{
|
||||
Lisp_Object val = CHAR_TABLE_REF (char_table, ch);
|
||||
uniprop_decoder_t decoder = uniprop_get_decoder (char_table);
|
||||
return (decoder ? decoder (char_table, val) : val);
|
||||
}
|
||||
|
||||
DEFUN ("get-unicode-property-internal", Fget_unicode_property_internal,
|
||||
Sget_unicode_property_internal, 2, 2, 0,
|
||||
doc: /* Return an element of CHAR-TABLE for character CH.
|
||||
CHAR-TABLE must be what returned by `unicode-property-table-internal'. */)
|
||||
(Lisp_Object char_table, Lisp_Object ch)
|
||||
{
|
||||
Lisp_Object val;
|
||||
uniprop_decoder_t decoder;
|
||||
|
||||
CHECK_CHAR_TABLE (char_table);
|
||||
CHECK_CHARACTER (ch);
|
||||
if (! UNIPROP_TABLE_P (char_table))
|
||||
error ("Invalid Unicode property table");
|
||||
val = CHAR_TABLE_REF (char_table, XFIXNUM (ch));
|
||||
decoder = uniprop_get_decoder (char_table);
|
||||
return (decoder ? decoder (char_table, val) : val);
|
||||
return get_unicode_property (char_table, XFIXNUM (ch));
|
||||
}
|
||||
|
||||
DEFUN ("put-unicode-property-internal", Fput_unicode_property_internal,
|
||||
|
|
|
@ -865,7 +865,7 @@ fill_gstring_body (Lisp_Object gstring)
|
|||
static Lisp_Object
|
||||
autocmp_chars (Lisp_Object rule, ptrdiff_t charpos, ptrdiff_t bytepos,
|
||||
ptrdiff_t limit, struct window *win, struct face *face,
|
||||
Lisp_Object string)
|
||||
Lisp_Object string, Lisp_Object direction)
|
||||
{
|
||||
ptrdiff_t count = SPECPDL_INDEX ();
|
||||
Lisp_Object pos = make_fixnum (charpos);
|
||||
|
@ -912,8 +912,9 @@ autocmp_chars (Lisp_Object rule, ptrdiff_t charpos, ptrdiff_t bytepos,
|
|||
if (NILP (string))
|
||||
record_unwind_protect (restore_point_unwind,
|
||||
build_marker (current_buffer, pt, pt_byte));
|
||||
lgstring = safe_call (6, Vauto_composition_function, AREF (rule, 2),
|
||||
pos, make_fixnum (to), font_object, string);
|
||||
lgstring = safe_call (7, Vauto_composition_function, AREF (rule, 2),
|
||||
pos, make_fixnum (to), font_object, string,
|
||||
direction);
|
||||
}
|
||||
return unbind_to (count, lgstring);
|
||||
}
|
||||
|
@ -1158,7 +1159,9 @@ composition_compute_stop_pos (struct composition_it *cmp_it, ptrdiff_t charpos,
|
|||
characters to be composed. FACE, if non-NULL, is a base face of
|
||||
the character. If STRING is not nil, it is a string containing the
|
||||
character to check, and CHARPOS and BYTEPOS are indices in the
|
||||
string. In that case, FACE must not be NULL.
|
||||
string. In that case, FACE must not be NULL. BIDI_LEVEL is the bidi
|
||||
embedding level of the current paragraph, and is used to calculate the
|
||||
direction argument to pass to the font shaper.
|
||||
|
||||
If the character is composed, setup members of CMP_IT (id, nglyphs,
|
||||
from, to, reversed_p), and return true. Otherwise, update
|
||||
|
@ -1167,7 +1170,7 @@ composition_compute_stop_pos (struct composition_it *cmp_it, ptrdiff_t charpos,
|
|||
bool
|
||||
composition_reseat_it (struct composition_it *cmp_it, ptrdiff_t charpos,
|
||||
ptrdiff_t bytepos, ptrdiff_t endpos, struct window *w,
|
||||
struct face *face, Lisp_Object string)
|
||||
signed char bidi_level, struct face *face, Lisp_Object string)
|
||||
{
|
||||
if (cmp_it->ch == -2)
|
||||
{
|
||||
|
@ -1197,13 +1200,17 @@ composition_reseat_it (struct composition_it *cmp_it, ptrdiff_t charpos,
|
|||
else if (w)
|
||||
{
|
||||
Lisp_Object lgstring = Qnil;
|
||||
Lisp_Object val, elt;
|
||||
Lisp_Object val, elt, direction = Qnil;
|
||||
|
||||
val = CHAR_TABLE_REF (Vcomposition_function_table, cmp_it->ch);
|
||||
for (EMACS_INT i = 0; i < cmp_it->rule_idx; i++, val = XCDR (val))
|
||||
continue;
|
||||
if (charpos < endpos)
|
||||
{
|
||||
if ((bidi_level & 1) == 0)
|
||||
direction = QL2R;
|
||||
else
|
||||
direction = QR2L;
|
||||
for (; CONSP (val); val = XCDR (val))
|
||||
{
|
||||
elt = XCAR (val);
|
||||
|
@ -1213,7 +1220,7 @@ composition_reseat_it (struct composition_it *cmp_it, ptrdiff_t charpos,
|
|||
if (XFIXNAT (AREF (elt, 1)) != cmp_it->lookback)
|
||||
goto no_composition;
|
||||
lgstring = autocmp_chars (elt, charpos, bytepos, endpos,
|
||||
w, face, string);
|
||||
w, face, string, direction);
|
||||
if (composition_gstring_p (lgstring))
|
||||
break;
|
||||
lgstring = Qnil;
|
||||
|
@ -1237,8 +1244,12 @@ composition_reseat_it (struct composition_it *cmp_it, ptrdiff_t charpos,
|
|||
else
|
||||
bpos = CHAR_TO_BYTE (cpos);
|
||||
}
|
||||
if ((bidi_level & 1) == 0)
|
||||
direction = QL2R;
|
||||
else
|
||||
direction = QR2L;
|
||||
lgstring = autocmp_chars (elt, cpos, bpos, charpos + 1, w, face,
|
||||
string);
|
||||
string, direction);
|
||||
if (! composition_gstring_p (lgstring)
|
||||
|| cpos + LGSTRING_CHAR_LEN (lgstring) - 1 != charpos)
|
||||
/* Composition failed or didn't cover the current
|
||||
|
@ -1558,7 +1569,7 @@ find_automatic_composition (ptrdiff_t pos, ptrdiff_t limit,
|
|||
for (check = cur; check_pos < check.pos; )
|
||||
BACKWARD_CHAR (check, stop);
|
||||
*gstring = autocmp_chars (elt, check.pos, check.pos_byte,
|
||||
tail, w, NULL, string);
|
||||
tail, w, NULL, string, Qnil);
|
||||
need_adjustment = 1;
|
||||
if (NILP (*gstring))
|
||||
{
|
||||
|
@ -1935,15 +1946,24 @@ Use the command `auto-composition-mode' to change this variable. */);
|
|||
|
||||
DEFVAR_LISP ("auto-composition-function", Vauto_composition_function,
|
||||
doc: /* Function to call to compose characters automatically.
|
||||
This function is called from the display routine with four arguments:
|
||||
FROM, TO, WINDOW, and STRING.
|
||||
This function is called from the display engine with 6 arguments:
|
||||
FUNC, FROM, TO, FONT-OBJECT, STRING, and DIRECTION.
|
||||
|
||||
FUNC is the function to compose characters. On text-mode display,
|
||||
FUNC is ignored and `compose-gstring-for-terminal' is used instead.
|
||||
|
||||
If STRING is nil, the function must compose characters in the region
|
||||
between FROM and TO in the current buffer.
|
||||
|
||||
Otherwise, STRING is a string, and FROM and TO are indices into the
|
||||
string. In this case, the function must compose characters in the
|
||||
string. */);
|
||||
string.
|
||||
|
||||
FONT-OBJECT is the font to use, or nil if characters are to be
|
||||
composed on a text-mode display.
|
||||
|
||||
DIRECTION is the bidi directionality of the text to shape. It could
|
||||
be L2R or R2L, or nil if unknown. */);
|
||||
Vauto_composition_function = Qnil;
|
||||
|
||||
DEFVAR_LISP ("composition-function-table", Vcomposition_function_table,
|
||||
|
|
|
@ -26,6 +26,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
|||
#define EMACS_COMPOSITE_H
|
||||
|
||||
#include "font.h"
|
||||
#include "dispextern.h"
|
||||
|
||||
INLINE_HEADER_BEGIN
|
||||
|
||||
|
@ -321,7 +322,7 @@ extern void composition_compute_stop_pos (struct composition_it *,
|
|||
Lisp_Object);
|
||||
extern bool composition_reseat_it (struct composition_it *, ptrdiff_t,
|
||||
ptrdiff_t, ptrdiff_t, struct window *,
|
||||
struct face *, Lisp_Object);
|
||||
signed char, struct face *, Lisp_Object);
|
||||
extern int composition_update_it (struct composition_it *,
|
||||
ptrdiff_t, ptrdiff_t, Lisp_Object);
|
||||
|
||||
|
|
22
src/font.c
22
src/font.c
|
@ -4397,18 +4397,22 @@ font_fill_lglyph_metrics (Lisp_Object glyph, Lisp_Object font_object)
|
|||
}
|
||||
|
||||
|
||||
DEFUN ("font-shape-gstring", Ffont_shape_gstring, Sfont_shape_gstring, 1, 1, 0,
|
||||
doc: /* Shape the glyph-string GSTRING.
|
||||
DEFUN ("font-shape-gstring", Ffont_shape_gstring, Sfont_shape_gstring, 2, 2, 0,
|
||||
doc: /* Shape the glyph-string GSTRING subject to bidi DIRECTION.
|
||||
Shaping means substituting glyphs and/or adjusting positions of glyphs
|
||||
to get the correct visual image of character sequences set in the
|
||||
header of the glyph-string.
|
||||
|
||||
DIRECTION should be produced by the UBA, the Unicode Bidirectional
|
||||
Algorithm, and should be a symbol, either L2R or R2L. It can also
|
||||
be nil if the bidi context is unknown.
|
||||
|
||||
If the shaping was successful, the value is GSTRING itself or a newly
|
||||
created glyph-string. Otherwise, the value is nil.
|
||||
|
||||
See the documentation of `composition-get-gstring' for the format of
|
||||
GSTRING. */)
|
||||
(Lisp_Object gstring)
|
||||
(Lisp_Object gstring, Lisp_Object direction)
|
||||
{
|
||||
struct font *font;
|
||||
Lisp_Object font_object, n, glyph;
|
||||
|
@ -4427,7 +4431,7 @@ GSTRING. */)
|
|||
/* Try at most three times with larger gstring each time. */
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
n = font->driver->shape (gstring);
|
||||
n = font->driver->shape (gstring, direction);
|
||||
if (FIXNUMP (n))
|
||||
break;
|
||||
gstring = larger_vector (gstring,
|
||||
|
@ -4478,11 +4482,11 @@ GSTRING. */)
|
|||
|
||||
DEFUN ("font-variation-glyphs", Ffont_variation_glyphs, Sfont_variation_glyphs,
|
||||
2, 2, 0,
|
||||
doc: /* Return a list of variation glyphs for CHAR in FONT-OBJECT.
|
||||
doc: /* Return a list of variation glyphs for CHARACTER in FONT-OBJECT.
|
||||
Each element of the value is a cons (VARIATION-SELECTOR . GLYPH-ID),
|
||||
where
|
||||
VARIATION-SELECTOR is a character code of variation selection
|
||||
(#xFE00..#xFE0F or #xE0100..#xE01EF)
|
||||
VARIATION-SELECTOR is a character code of variation selector
|
||||
(#xFE00..#xFE0F or #xE0100..#xE01EF).
|
||||
GLYPH-ID is a glyph code of the corresponding variation glyph,
|
||||
a fixnum, if it's small enough, otherwise a bignum. */)
|
||||
(Lisp_Object font_object, Lisp_Object character)
|
||||
|
@ -5351,6 +5355,10 @@ syms_of_font (void)
|
|||
|
||||
DEFSYM (QCuser_spec, ":user-spec");
|
||||
|
||||
/* For shapers that need to know text directionality. */
|
||||
DEFSYM (QL2R, "L2R");
|
||||
DEFSYM (QR2L, "R2L");
|
||||
|
||||
scratch_font_spec = Ffont_spec (0, NULL);
|
||||
staticpro (&scratch_font_spec);
|
||||
scratch_font_prefer = Ffont_spec (0, NULL);
|
||||
|
|
53
src/font.h
53
src/font.h
|
@ -22,6 +22,10 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
|||
#ifndef EMACS_FONT_H
|
||||
#define EMACS_FONT_H
|
||||
|
||||
#ifdef HAVE_HARFBUZZ
|
||||
#include <hb.h>
|
||||
#endif /* HAVE_HARFBUZZ */
|
||||
|
||||
struct composition_it;
|
||||
struct face;
|
||||
struct glyph_string;
|
||||
|
@ -703,7 +707,11 @@ struct font_driver
|
|||
|
||||
Return the number of output codes. If none of the features are
|
||||
applicable to the input data, return 0. If GSTRING-OUT is too
|
||||
short, return -1. */
|
||||
short, return -1.
|
||||
|
||||
Note: This method is currently not implemented by any font
|
||||
back-end, and is only called by 'font-drive-otf' and
|
||||
'font-otf-alternates', which are themselves ifdef'ed away. */
|
||||
int (*otf_drive) (struct font *font, Lisp_Object features,
|
||||
Lisp_Object gstring_in, int from, int to,
|
||||
Lisp_Object gstring_out, int idx, bool alternate_subst);
|
||||
|
@ -725,6 +733,9 @@ struct font_driver
|
|||
(N+1)th element of GSTRING 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.
|
||||
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
|
||||
|
@ -732,7 +743,7 @@ struct font_driver
|
|||
a new glyph object and storing it in GSTRING. If (M) is greater
|
||||
than the length of GSTRING, this method should return nil. In
|
||||
that case, the method is called again with a larger GSTRING. */
|
||||
Lisp_Object (*shape) (Lisp_Object lgstring);
|
||||
Lisp_Object (*shape) (Lisp_Object lgstring, Lisp_Object direction);
|
||||
|
||||
/* Optional.
|
||||
If FONT is usable on frame F, return 0. Otherwise return -1.
|
||||
|
@ -773,6 +784,21 @@ struct font_driver
|
|||
relies on this hook to throw away its old XftDraw (which won't
|
||||
work after the size change) and get a new one. */
|
||||
void (*drop_xrender_surfaces) (struct frame *f);
|
||||
|
||||
#ifdef HAVE_HARFBUZZ
|
||||
/* Optional.
|
||||
Return a HarfBuzz font object for FONT and store to
|
||||
*POSITION_UNIT the scale factor to convert a hb_position_t value
|
||||
to the number of pixels. Return NULL if HarfBuzz font object is
|
||||
not available for FONT. */
|
||||
hb_font_t *(*begin_hb_font) (struct font *font, double *position_unit);
|
||||
|
||||
/* Optional.
|
||||
Called when the return value (passed as HB_FONT) of begin_hb_font
|
||||
above is no longer used. Not called if the return value of
|
||||
begin_hb_font was NULL. */
|
||||
void (*end_hb_font) (struct font *font, hb_font_t *hb_font);
|
||||
#endif /* HAVE_HARFBUZZ */
|
||||
};
|
||||
|
||||
|
||||
|
@ -864,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);
|
||||
|
@ -885,17 +916,20 @@ extern int ftfont_has_char (Lisp_Object, int);
|
|||
extern int ftfont_variation_glyphs (struct font *, int, unsigned[256]);
|
||||
extern Lisp_Object ftfont_combining_capability (struct font *);
|
||||
extern Lisp_Object ftfont_get_cache (struct frame *);
|
||||
extern Lisp_Object ftfont_list (struct frame *, Lisp_Object);
|
||||
extern Lisp_Object ftfont_list2 (struct frame *, Lisp_Object, Lisp_Object);
|
||||
extern Lisp_Object ftfont_list_family (struct frame *);
|
||||
extern Lisp_Object ftfont_match (struct frame *, Lisp_Object);
|
||||
extern Lisp_Object ftfont_match2 (struct frame *, Lisp_Object, Lisp_Object);
|
||||
extern Lisp_Object ftfont_open (struct frame *, Lisp_Object, int);
|
||||
extern Lisp_Object ftfont_otf_capability (struct font *);
|
||||
extern Lisp_Object ftfont_shape (Lisp_Object);
|
||||
extern Lisp_Object ftfont_shape (Lisp_Object, Lisp_Object);
|
||||
extern unsigned ftfont_encode_char (struct font *, int);
|
||||
extern void ftfont_close (struct font *);
|
||||
extern void ftfont_filter_properties (Lisp_Object, Lisp_Object);
|
||||
extern void ftfont_text_extents (struct font *, const unsigned *, int,
|
||||
struct font_metrics *);
|
||||
#ifdef HAVE_HARFBUZZ
|
||||
extern hb_font_t *fthbfont_begin_hb_font (struct font *, double *);
|
||||
#endif /* HAVE_HARFBUZZ */
|
||||
extern void syms_of_ftfont (void);
|
||||
#endif /* HAVE_FREETYPE */
|
||||
#ifdef HAVE_X_WINDOWS
|
||||
|
@ -905,6 +939,9 @@ extern void syms_of_xfont (void);
|
|||
extern void syms_of_ftxfont (void);
|
||||
#ifdef HAVE_XFT
|
||||
extern struct font_driver const xftfont_driver;
|
||||
#ifdef HAVE_HARFBUZZ
|
||||
extern struct font_driver xfthbfont_driver;
|
||||
#endif /* HAVE_HARFBUZZ */
|
||||
#endif
|
||||
#if defined HAVE_FREETYPE || defined HAVE_XFT
|
||||
extern struct font_driver const ftxfont_driver;
|
||||
|
@ -917,6 +954,9 @@ extern void syms_of_bdffont (void);
|
|||
#ifdef HAVE_NTGUI
|
||||
extern struct font_driver w32font_driver;
|
||||
extern struct font_driver uniscribe_font_driver;
|
||||
#ifdef HAVE_HARFBUZZ
|
||||
extern struct font_driver harfbuzz_font_driver;
|
||||
#endif
|
||||
extern void syms_of_w32font (void);
|
||||
#endif /* HAVE_NTGUI */
|
||||
#ifdef HAVE_NS
|
||||
|
@ -926,6 +966,9 @@ extern void syms_of_macfont (void);
|
|||
#endif /* HAVE_NS */
|
||||
#ifdef USE_CAIRO
|
||||
extern struct font_driver const ftcrfont_driver;
|
||||
#ifdef HAVE_HARFBUZZ
|
||||
extern struct font_driver ftcrhbfont_driver;
|
||||
#endif /* HAVE_HARFBUZZ */
|
||||
extern void syms_of_ftcrfont (void);
|
||||
#endif
|
||||
|
||||
|
|
|
@ -97,21 +97,13 @@ 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
|
||||
|
@ -164,10 +156,16 @@ ftcrfont_open (struct frame *f, Lisp_Object entity, int pixel_size)
|
|||
unblock_input ();
|
||||
|
||||
font_object = font_build_object (VECSIZE (struct font_info),
|
||||
Qftcr, entity, size);
|
||||
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;
|
||||
font->encoding_charset = font->repertory_charset = -1;
|
||||
|
||||
|
@ -256,6 +254,9 @@ ftcrfont_open (struct frame *f, Lisp_Object entity, int pixel_size)
|
|||
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
|
||||
|
@ -288,6 +289,13 @@ ftcrfont_close (struct font *font)
|
|||
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])
|
||||
|
@ -427,7 +435,7 @@ ftcrfont_otf_capability (struct font *font)
|
|||
|
||||
#if defined HAVE_M17N_FLT && defined HAVE_LIBOTF
|
||||
static Lisp_Object
|
||||
ftcrfont_shape (Lisp_Object lgstring)
|
||||
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;
|
||||
|
@ -439,7 +447,7 @@ ftcrfont_shape (Lisp_Object lgstring)
|
|||
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);
|
||||
Lisp_Object result = ftfont_shape (lgstring, direction);
|
||||
cairo_ft_scaled_font_unlock_face (scaled_font);
|
||||
ftcrfont_info->ft_size = NULL;
|
||||
|
||||
|
@ -447,7 +455,7 @@ ftcrfont_shape (Lisp_Object lgstring)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_OTF_GET_VARIATION_GLYPHS
|
||||
#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])
|
||||
{
|
||||
|
@ -462,7 +470,7 @@ ftcrfont_variation_glyphs (struct font *font, int c, unsigned variations[256])
|
|||
|
||||
return result;
|
||||
}
|
||||
#endif /* HAVE_OTF_GET_VARIATION_GLYPHS */
|
||||
#endif /* HAVE_OTF_GET_VARIATION_GLYPHS || HAVE_FT_FACE_GETCHARVARIANTINDEX */
|
||||
|
||||
static int
|
||||
ftcrfont_draw (struct glyph_string *s,
|
||||
|
@ -510,6 +518,46 @@ ftcrfont_draw (struct glyph_string *s,
|
|||
return len;
|
||||
}
|
||||
|
||||
#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);
|
||||
if (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);
|
||||
|
@ -535,17 +583,23 @@ struct font_driver const ftcrfont_driver =
|
|||
#if defined HAVE_M17N_FLT && defined HAVE_LIBOTF
|
||||
.shape = ftcrfont_shape,
|
||||
#endif
|
||||
#ifdef HAVE_OTF_GET_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_HARFBUZZ
|
||||
struct font_driver ftcrhbfont_driver;
|
||||
#endif /* HAVE_HARFBUZZ */
|
||||
|
||||
void
|
||||
syms_of_ftcrfont (void)
|
||||
{
|
||||
DEFSYM (Qftcr, "ftcr");
|
||||
#ifdef HAVE_HARFBUZZ
|
||||
DEFSYM (Qftcrhb, "ftcrhb");
|
||||
#endif /* HAVE_HARFBUZZ */
|
||||
pdumper_do_now_and_after_load (syms_of_ftcrfont_for_pdumper);
|
||||
}
|
||||
|
||||
|
@ -553,4 +607,15 @@ 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.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 */
|
||||
}
|
||||
|
|
146
src/ftfont.c
146
src/ftfont.c
|
@ -48,6 +48,9 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
|||
#include "pdumper.h"
|
||||
|
||||
static struct font_driver const ftfont_driver;
|
||||
#ifdef HAVE_HARFBUZZ
|
||||
static struct font_driver fthbfont_driver;
|
||||
#endif /* HAVE_HARFBUZZ */
|
||||
|
||||
/* Flag to tell if FcInit is already called or not. */
|
||||
static bool fc_initialized;
|
||||
|
@ -788,7 +791,7 @@ ftfont_spec_pattern (Lisp_Object spec, char *otlayout, struct OpenTypeSpec **ots
|
|||
return pattern;
|
||||
}
|
||||
|
||||
Lisp_Object
|
||||
static Lisp_Object
|
||||
ftfont_list (struct frame *f, Lisp_Object spec)
|
||||
{
|
||||
Lisp_Object val = Qnil, family, adstyle;
|
||||
|
@ -988,6 +991,16 @@ ftfont_list (struct frame *f, Lisp_Object spec)
|
|||
}
|
||||
|
||||
Lisp_Object
|
||||
ftfont_list2 (struct frame *f, Lisp_Object spec, Lisp_Object type)
|
||||
{
|
||||
Lisp_Object list = ftfont_list (f, spec);
|
||||
|
||||
for (Lisp_Object tail = list; CONSP (tail); tail = XCDR (tail))
|
||||
ASET (XCAR (tail), FONT_TYPE_INDEX, type);
|
||||
return list;
|
||||
}
|
||||
|
||||
static Lisp_Object
|
||||
ftfont_match (struct frame *f, Lisp_Object spec)
|
||||
{
|
||||
Lisp_Object entity = Qnil;
|
||||
|
@ -1037,6 +1050,16 @@ ftfont_match (struct frame *f, Lisp_Object spec)
|
|||
return entity;
|
||||
}
|
||||
|
||||
Lisp_Object
|
||||
ftfont_match2 (struct frame *f, Lisp_Object spec, Lisp_Object type)
|
||||
{
|
||||
Lisp_Object entity = ftfont_match (f, spec);
|
||||
|
||||
if (! NILP (entity))
|
||||
ASET (entity, FONT_TYPE_INDEX, type);
|
||||
return entity;
|
||||
}
|
||||
|
||||
Lisp_Object
|
||||
ftfont_list_family (struct frame *f)
|
||||
{
|
||||
|
@ -1292,9 +1315,17 @@ ftfont_open (struct frame *f, Lisp_Object entity, int pixel_size)
|
|||
ftfont_info->maybe_otf = (ft_face->face_flags & FT_FACE_FLAG_SFNT) != 0;
|
||||
ftfont_info->otf = NULL;
|
||||
#endif /* HAVE_LIBOTF */
|
||||
#ifdef HAVE_HARFBUZZ
|
||||
ftfont_info->hb_font = NULL;
|
||||
#endif /* HAVE_HARFBUZZ */
|
||||
/* This means that there's no need of transformation. */
|
||||
ftfont_info->matrix.xx = 0;
|
||||
font->pixel_size = size;
|
||||
#ifdef HAVE_HARFBUZZ
|
||||
if (EQ (AREF (font_object, FONT_TYPE_INDEX), Qfreetypehb))
|
||||
font->driver = &fthbfont_driver;
|
||||
else
|
||||
#endif /* HAVE_HARFBUZZ */
|
||||
font->driver = &ftfont_driver;
|
||||
font->encoding_charset = font->repertory_charset = -1;
|
||||
|
||||
|
@ -1406,6 +1437,10 @@ ftfont_close (struct font *font)
|
|||
#ifdef HAVE_LIBOTF
|
||||
if (ftfont_info->otf)
|
||||
OTF_close (ftfont_info->otf);
|
||||
#endif
|
||||
#ifdef HAVE_HARFBUZZ
|
||||
if (ftfont_info->hb_font)
|
||||
hb_font_destroy (ftfont_info->hb_font);
|
||||
#endif
|
||||
cache_data->ft_face = NULL;
|
||||
}
|
||||
|
@ -1454,6 +1489,24 @@ ftfont_encode_char (struct font *font, int c)
|
|||
return (code > 0 ? code : FONT_INVALID_CODE);
|
||||
}
|
||||
|
||||
static bool
|
||||
ftfont_glyph_metrics (FT_Face ft_face, int c, int *advance, int *lbearing,
|
||||
int *rbearing, int *ascent, int *descent)
|
||||
{
|
||||
if (FT_Load_Glyph (ft_face, c, FT_LOAD_DEFAULT) == 0)
|
||||
{
|
||||
FT_Glyph_Metrics *m = &ft_face->glyph->metrics;
|
||||
*advance = m->horiAdvance >> 6;
|
||||
*lbearing = m->horiBearingX >> 6;
|
||||
*rbearing = (m->horiBearingX + m->width) >> 6;
|
||||
*ascent = m->horiBearingY >> 6;
|
||||
*descent = (m->height - m->horiBearingY) >> 6;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
ftfont_text_extents (struct font *font, const unsigned int *code,
|
||||
int nglyphs, struct font_metrics *metrics)
|
||||
|
@ -1468,29 +1521,27 @@ ftfont_text_extents (struct font *font, const unsigned int *code,
|
|||
|
||||
for (i = 0, first = 1; i < nglyphs; i++)
|
||||
{
|
||||
if (FT_Load_Glyph (ft_face, code[i], FT_LOAD_DEFAULT) == 0)
|
||||
int advance, lbearing, rbearing, ascent, descent;
|
||||
if (ftfont_glyph_metrics (ft_face, code[i], &advance, &lbearing,
|
||||
&rbearing, &ascent, &descent))
|
||||
{
|
||||
FT_Glyph_Metrics *m = &ft_face->glyph->metrics;
|
||||
|
||||
if (first)
|
||||
{
|
||||
metrics->lbearing = m->horiBearingX >> 6;
|
||||
metrics->rbearing = (m->horiBearingX + m->width) >> 6;
|
||||
metrics->ascent = m->horiBearingY >> 6;
|
||||
metrics->descent = (m->height - m->horiBearingY) >> 6;
|
||||
metrics->lbearing = lbearing;
|
||||
metrics->rbearing = rbearing;
|
||||
metrics->ascent = ascent;
|
||||
metrics->descent = descent;
|
||||
first = 0;
|
||||
}
|
||||
if (metrics->lbearing > width + (m->horiBearingX >> 6))
|
||||
metrics->lbearing = width + (m->horiBearingX >> 6);
|
||||
if (metrics->rbearing
|
||||
< width + ((m->horiBearingX + m->width) >> 6))
|
||||
metrics->rbearing
|
||||
= width + ((m->horiBearingX + m->width) >> 6);
|
||||
if (metrics->ascent < (m->horiBearingY >> 6))
|
||||
metrics->ascent = m->horiBearingY >> 6;
|
||||
if (metrics->descent > ((m->height - m->horiBearingY) >> 6))
|
||||
metrics->descent = (m->height - m->horiBearingY) >> 6;
|
||||
width += m->horiAdvance >> 6;
|
||||
if (metrics->lbearing > width + lbearing)
|
||||
metrics->lbearing = width + lbearing;
|
||||
if (metrics->rbearing < width + rbearing)
|
||||
metrics->rbearing = width + rbearing;
|
||||
if (metrics->ascent < ascent)
|
||||
metrics->ascent = ascent;
|
||||
if (metrics->descent > descent)
|
||||
metrics->descent = descent;
|
||||
width += advance;
|
||||
}
|
||||
else
|
||||
width += font->space_width;
|
||||
|
@ -2757,7 +2808,7 @@ ftfont_shape_by_flt (Lisp_Object lgstring, struct font *font,
|
|||
}
|
||||
|
||||
Lisp_Object
|
||||
ftfont_shape (Lisp_Object lgstring)
|
||||
ftfont_shape (Lisp_Object lgstring, Lisp_Object direction)
|
||||
{
|
||||
struct font *font = CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring));
|
||||
struct font_info *ftfont_info = (struct font_info *) font;
|
||||
|
@ -2769,21 +2820,57 @@ ftfont_shape (Lisp_Object lgstring)
|
|||
|
||||
#endif /* HAVE_M17N_FLT */
|
||||
|
||||
#ifdef HAVE_OTF_GET_VARIATION_GLYPHS
|
||||
#endif /* HAVE_LIBOTF */
|
||||
|
||||
#if defined HAVE_OTF_GET_VARIATION_GLYPHS || defined HAVE_FT_FACE_GETCHARVARIANTINDEX
|
||||
int
|
||||
ftfont_variation_glyphs (struct font *font, int c, unsigned variations[256])
|
||||
{
|
||||
struct font_info *ftfont_info = (struct font_info *) font;
|
||||
#ifdef HAVE_OTF_GET_VARIATION_GLYPHS
|
||||
OTF *otf = ftfont_get_otf (ftfont_info);
|
||||
|
||||
if (! otf)
|
||||
return 0;
|
||||
return OTF_get_variation_glyphs (otf, c, variations);
|
||||
#else /* !HAVE_OTF_GET_VARIATION_GLYPHS */
|
||||
FT_Face ft_face = ftfont_info->ft_size->face;
|
||||
int i, n = 0;
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
variations[i] = FT_Face_GetCharVariantIndex (ft_face, c, 0xFE00 + i);
|
||||
if (variations[i])
|
||||
n++;
|
||||
}
|
||||
for (; i < 256; i++)
|
||||
{
|
||||
variations[i] = FT_Face_GetCharVariantIndex (ft_face, c,
|
||||
0xE0100 + (i - 16));
|
||||
if (variations[i])
|
||||
n++;
|
||||
}
|
||||
|
||||
return n;
|
||||
#endif /* !HAVE_OTF_GET_VARIATION_GLYPHS */
|
||||
}
|
||||
#endif /* HAVE_OTF_GET_VARIATION_GLYPHS || HAVE_FT_FACE_GETCHARVARIANTINDEX */
|
||||
|
||||
#ifdef HAVE_HARFBUZZ
|
||||
|
||||
hb_font_t *
|
||||
fthbfont_begin_hb_font (struct font *font, double *position_unit)
|
||||
{
|
||||
struct font_info *ftfont_info = (struct font_info *) font;
|
||||
|
||||
*position_unit = 1.0 / (1 << 6);
|
||||
if (! ftfont_info->hb_font)
|
||||
ftfont_info->hb_font
|
||||
= hb_ft_font_create_referenced (ftfont_info->ft_size->face);
|
||||
return ftfont_info->hb_font;
|
||||
}
|
||||
|
||||
#endif /* HAVE_OTF_GET_VARIATION_GLYPHS */
|
||||
#endif /* HAVE_LIBOTF */
|
||||
#endif /* HAVE_HARFBUZZ */
|
||||
|
||||
static const char *const ftfont_booleans [] = {
|
||||
":antialias",
|
||||
|
@ -2869,7 +2956,7 @@ static struct font_driver const ftfont_driver =
|
|||
#if defined HAVE_M17N_FLT && defined HAVE_LIBOTF
|
||||
.shape = ftfont_shape,
|
||||
#endif
|
||||
#ifdef HAVE_OTF_GET_VARIATION_GLYPHS
|
||||
#if defined HAVE_OTF_GET_VARIATION_GLYPHS || defined HAVE_FT_FACE_GETCHARVARIANTINDEX
|
||||
.get_variation_glyphs = ftfont_variation_glyphs,
|
||||
#endif
|
||||
.filter_properties = ftfont_filter_properties,
|
||||
|
@ -2881,6 +2968,9 @@ syms_of_ftfont (void)
|
|||
{
|
||||
/* Symbolic type of this font-driver. */
|
||||
DEFSYM (Qfreetype, "freetype");
|
||||
#ifdef HAVE_HARFBUZZ
|
||||
DEFSYM (Qfreetypehb, "freetypehb");
|
||||
#endif /* HAVE_HARFBUZZ */
|
||||
|
||||
/* Fontconfig's generic families and their aliases. */
|
||||
DEFSYM (Qmonospace, "monospace");
|
||||
|
@ -2918,4 +3008,12 @@ syms_of_ftfont_for_pdumper (void)
|
|||
{
|
||||
PDUMPER_RESET_LV (ft_face_cache, Qnil);
|
||||
register_font_driver (&ftfont_driver, NULL);
|
||||
#ifdef HAVE_HARFBUZZ
|
||||
fthbfont_driver = ftfont_driver;
|
||||
fthbfont_driver.type = Qfreetypehb;
|
||||
fthbfont_driver.shape = hbfont_shape;
|
||||
fthbfont_driver.combining_capability = hbfont_combining_capability;
|
||||
fthbfont_driver.begin_hb_font = fthbfont_begin_hb_font;
|
||||
register_font_driver (&fthbfont_driver, NULL);
|
||||
#endif /* HAVE_HARFBUZZ */
|
||||
}
|
||||
|
|
|
@ -29,6 +29,11 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
|||
# include FT_BDF_H
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_HARFBUZZ
|
||||
#include <hb.h>
|
||||
#include <hb-ft.h>
|
||||
#endif /* HAVE_HARFBUZZ */
|
||||
|
||||
#ifdef HAVE_LIBOTF
|
||||
# include <otf.h>
|
||||
#ifdef HAVE_M17N_FLT
|
||||
|
@ -54,6 +59,9 @@ struct font_info
|
|||
FT_Size ft_size;
|
||||
int index;
|
||||
FT_Matrix matrix;
|
||||
#ifdef HAVE_HARFBUZZ
|
||||
hb_font_t *hb_font;
|
||||
#endif /* HAVE_HARFBUZZ */
|
||||
|
||||
#ifdef USE_CAIRO
|
||||
cairo_scaled_font_t *cr_scaled_font;
|
||||
|
|
|
@ -209,21 +209,13 @@ ftxfont_draw_background (struct frame *f, struct font *font, GC gc, int x, int y
|
|||
static Lisp_Object
|
||||
ftxfont_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, Qftx);
|
||||
return list;
|
||||
return ftfont_list2 (f, spec, Qftx);
|
||||
}
|
||||
|
||||
static Lisp_Object
|
||||
ftxfont_match (struct frame *f, Lisp_Object spec)
|
||||
{
|
||||
Lisp_Object entity = ftfont_match (f, spec);
|
||||
|
||||
if (VECTORP (entity))
|
||||
ASET (entity, FONT_TYPE_INDEX, Qftx);
|
||||
return entity;
|
||||
return ftfont_match2 (f, spec, Qftx);
|
||||
}
|
||||
|
||||
static Lisp_Object
|
||||
|
@ -359,7 +351,7 @@ struct font_driver const ftxfont_driver =
|
|||
#if defined HAVE_M17N_FLT && defined HAVE_LIBOTF
|
||||
.shape = ftfont_shape,
|
||||
#endif
|
||||
#ifdef HAVE_OTF_GET_VARIATION_GLYPHS
|
||||
#if defined HAVE_OTF_GET_VARIATION_GLYPHS || defined HAVE_FT_FACE_GETCHARVARIANTINDEX
|
||||
.get_variation_glyphs = ftfont_variation_glyphs,
|
||||
#endif
|
||||
.filter_properties = ftfont_filter_properties,
|
||||
|
|
482
src/hbfont.c
Normal file
482
src/hbfont.c
Normal file
|
@ -0,0 +1,482 @@
|
|||
/* 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.
|
||||
|
||||
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 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);
|
||||
ptrdiff_t from = -1, to UNINIT, cluster_offset UNINIT;
|
||||
int 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. */
|
||||
ptrdiff_t 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;
|
||||
}
|
|
@ -599,7 +599,7 @@ scan_for_column (ptrdiff_t *endpos, EMACS_INT *goalcol, ptrdiff_t *prevcol)
|
|||
if (cmp_it.id >= 0
|
||||
|| (scan == cmp_it.stop_pos
|
||||
&& composition_reseat_it (&cmp_it, scan, scan_byte, end,
|
||||
w, NULL, Qnil)))
|
||||
w, NEUTRAL_DIR, NULL, Qnil)))
|
||||
composition_update_it (&cmp_it, scan, scan_byte, Qnil);
|
||||
if (cmp_it.id >= 0)
|
||||
{
|
||||
|
@ -1507,7 +1507,7 @@ compute_motion (ptrdiff_t from, ptrdiff_t frombyte, EMACS_INT fromvpos,
|
|||
if (cmp_it.id >= 0
|
||||
|| (pos == cmp_it.stop_pos
|
||||
&& composition_reseat_it (&cmp_it, pos, pos_byte, to, win,
|
||||
NULL, Qnil)))
|
||||
NEUTRAL_DIR, NULL, Qnil)))
|
||||
composition_update_it (&cmp_it, pos, pos_byte, Qnil);
|
||||
if (cmp_it.id >= 0)
|
||||
{
|
||||
|
|
|
@ -3994,6 +3994,7 @@ extern void map_char_table_for_charset (void (*c_function) (Lisp_Object, Lisp_Ob
|
|||
Lisp_Object, struct charset *,
|
||||
unsigned, unsigned);
|
||||
extern Lisp_Object uniprop_table (Lisp_Object);
|
||||
extern Lisp_Object get_unicode_property (Lisp_Object, int);
|
||||
extern void syms_of_chartab (void);
|
||||
|
||||
/* Defined in print.c. */
|
||||
|
|
|
@ -39,6 +39,12 @@
|
|||
|
||||
#include <libkern/OSByteOrder.h>
|
||||
|
||||
/* Values for `dir' argument to shaper functions. */
|
||||
enum lgstring_direction
|
||||
{
|
||||
DIR_R2L = -1, DIR_UNKNOWN = 0, DIR_L2R = 1,
|
||||
};
|
||||
|
||||
static double mac_font_get_advance_width_for_glyph (CTFontRef, CGGlyph);
|
||||
static CGRect mac_font_get_bounding_rect_for_glyph (CTFontRef, CGGlyph);
|
||||
static CFArrayRef mac_font_create_available_families (void);
|
||||
|
@ -49,7 +55,8 @@ static Boolean mac_font_descriptor_supports_languages (CTFontDescriptorRef,
|
|||
CFArrayRef);
|
||||
static CFStringRef mac_font_create_preferred_family_for_attributes (CFDictionaryRef);
|
||||
static CFIndex mac_font_shape (CTFontRef, CFStringRef,
|
||||
struct mac_glyph_layout *, CFIndex);
|
||||
struct mac_glyph_layout *, CFIndex,
|
||||
enum lgstring_direction);
|
||||
static CFArrayRef mac_font_copy_default_descriptors_for_language (CFStringRef);
|
||||
static CFStringRef mac_font_copy_default_name_for_charset_and_languages (CFCharacterSetRef, CFArrayRef);
|
||||
#if USE_CT_GLYPH_INFO
|
||||
|
@ -318,7 +325,8 @@ static void mac_font_get_glyphs_for_variants (CFDataRef, UTF32Char,
|
|||
|
||||
static CFIndex
|
||||
mac_font_shape_1 (NSFont *font, NSString *string,
|
||||
struct mac_glyph_layout *glyph_layouts, CFIndex glyph_len)
|
||||
struct mac_glyph_layout *glyph_layouts, CFIndex glyph_len,
|
||||
enum lgstring_direction dir)
|
||||
{
|
||||
NSUInteger i;
|
||||
CFIndex result = 0;
|
||||
|
@ -582,11 +590,11 @@ static void mac_font_get_glyphs_for_variants (CFDataRef, UTF32Char,
|
|||
static CFIndex
|
||||
mac_screen_font_shape (ScreenFontRef font, CFStringRef string,
|
||||
struct mac_glyph_layout *glyph_layouts,
|
||||
CFIndex glyph_len)
|
||||
CFIndex glyph_len, enum lgstring_direction dir)
|
||||
{
|
||||
return mac_font_shape_1 ([(NSFont *)font printerFont],
|
||||
(NSString *) string,
|
||||
glyph_layouts, glyph_len);
|
||||
glyph_layouts, glyph_len, dir);
|
||||
}
|
||||
|
||||
static CGColorRef
|
||||
|
@ -1642,7 +1650,7 @@ static CGGlyph macfont_get_glyph_for_cid (struct font *font,
|
|||
static void macfont_text_extents (struct font *, const unsigned int *, int,
|
||||
struct font_metrics *);
|
||||
static int macfont_draw (struct glyph_string *, int, int, int, int, bool);
|
||||
static Lisp_Object macfont_shape (Lisp_Object);
|
||||
static Lisp_Object macfont_shape (Lisp_Object, Lisp_Object);
|
||||
static int macfont_variation_glyphs (struct font *, int c,
|
||||
unsigned variations[256]);
|
||||
static void macfont_filter_properties (Lisp_Object, Lisp_Object);
|
||||
|
@ -2926,7 +2934,7 @@ So we use CTFontDescriptorCreateMatchingFontDescriptor (no
|
|||
}
|
||||
|
||||
static Lisp_Object
|
||||
macfont_shape (Lisp_Object lgstring)
|
||||
macfont_shape (Lisp_Object lgstring, Lisp_Object direction)
|
||||
{
|
||||
struct font *font = CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring));
|
||||
struct macfont_info *macfont_info = (struct macfont_info *) font;
|
||||
|
@ -2976,12 +2984,18 @@ So we use CTFontDescriptorCreateMatchingFontDescriptor (no
|
|||
kCFAllocatorNull);
|
||||
if (string)
|
||||
{
|
||||
enum lgstring_direction dir = DIR_UNKNOWN;
|
||||
|
||||
if (EQ (direction, QL2R))
|
||||
dir = DIR_L2R;
|
||||
else if (EQ (direction, QR2L))
|
||||
dir = DIR_R2L;
|
||||
glyph_layouts = alloca (sizeof (struct mac_glyph_layout) * glyph_len);
|
||||
if (macfont_info->screen_font)
|
||||
used = mac_screen_font_shape (macfont_info->screen_font, string,
|
||||
glyph_layouts, glyph_len);
|
||||
glyph_layouts, glyph_len, dir);
|
||||
else
|
||||
used = mac_font_shape (macfont, string, glyph_layouts, glyph_len);
|
||||
used = mac_font_shape (macfont, string, glyph_layouts, glyph_len, dir);
|
||||
CFRelease (string);
|
||||
}
|
||||
|
||||
|
@ -3662,7 +3676,8 @@ So we use CTFontDescriptorCreateMatchingFontDescriptor (no
|
|||
|
||||
static CFIndex
|
||||
mac_font_shape (CTFontRef font, CFStringRef string,
|
||||
struct mac_glyph_layout *glyph_layouts, CFIndex glyph_len)
|
||||
struct mac_glyph_layout *glyph_layouts, CFIndex glyph_len,
|
||||
enum lgstring_direction dir)
|
||||
{
|
||||
CFIndex used, result = 0;
|
||||
CTLineRef ctline = mac_font_create_line_with_string_and_font (string, font);
|
||||
|
|
|
@ -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 */
|
||||
|
|
81
src/w32fns.c
81
src/w32fns.c
|
@ -221,6 +221,7 @@ int menubar_in_use = 0;
|
|||
/* From w32uniscribe.c */
|
||||
extern void syms_of_w32uniscribe (void);
|
||||
extern int uniscribe_available;
|
||||
extern int harfbuzz_available;
|
||||
|
||||
#ifdef WINDOWSNT
|
||||
/* From w32inevt.c */
|
||||
|
@ -5843,7 +5844,45 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
|
|||
specbind (Qx_resource_name, name);
|
||||
}
|
||||
|
||||
if (uniscribe_available)
|
||||
bool register_uniscribe = uniscribe_available;
|
||||
#ifdef HAVE_HARFBUZZ
|
||||
/* Register Uniscribe only if HarfBuzz is not available or if
|
||||
explicitly requested. If Uniscribe is registered, register
|
||||
HarfBuzz only if explicitly requested. */
|
||||
bool register_harfbuzz = harfbuzz_available;
|
||||
if (register_harfbuzz)
|
||||
register_uniscribe = false;
|
||||
Lisp_Object dflt_backends
|
||||
= gui_display_get_arg (dpyinfo, parameters, Qfont_backend,
|
||||
"fontBackend", "FontBackend", RES_TYPE_STRING);
|
||||
if (!EQ (dflt_backends, Qunbound))
|
||||
{
|
||||
bool harfbuzz_requested = false, uniscribe_requested = false;
|
||||
if (CONSP (dflt_backends))
|
||||
{
|
||||
if (!NILP (Fmemq (Quniscribe, dflt_backends)))
|
||||
uniscribe_requested = true;
|
||||
if (!NILP (Fmemq (Qharfbuzz, dflt_backends)))
|
||||
harfbuzz_requested = true;
|
||||
}
|
||||
else if (STRINGP (dflt_backends))
|
||||
{
|
||||
if (strcmp (SSDATA (dflt_backends), "uniscribe") == 0)
|
||||
uniscribe_requested = true;
|
||||
else if (strcmp (SSDATA (dflt_backends), "harfbuzz") == 0)
|
||||
harfbuzz_requested = true;
|
||||
}
|
||||
if (uniscribe_requested)
|
||||
{
|
||||
register_uniscribe = uniscribe_available;
|
||||
if (!harfbuzz_requested)
|
||||
register_harfbuzz = false;
|
||||
}
|
||||
}
|
||||
if (register_harfbuzz)
|
||||
register_font_driver (&harfbuzz_font_driver, f);
|
||||
#endif
|
||||
if (register_uniscribe)
|
||||
register_font_driver (&uniscribe_font_driver, f);
|
||||
register_font_driver (&w32font_driver, f);
|
||||
|
||||
|
@ -6896,7 +6935,45 @@ w32_create_tip_frame (struct w32_display_info *dpyinfo, Lisp_Object parms)
|
|||
specbind (Qx_resource_name, name);
|
||||
}
|
||||
|
||||
if (uniscribe_available)
|
||||
bool register_uniscribe = uniscribe_available;
|
||||
#ifdef HAVE_HARFBUZZ
|
||||
/* Register Uniscribe only if HarfBuzz is not available or if
|
||||
explicitly requested. If Uniscribe is registered, register
|
||||
HarfBuzz only if explicitly requested. */
|
||||
bool register_harfbuzz = harfbuzz_available;
|
||||
if (register_harfbuzz)
|
||||
register_uniscribe = false;
|
||||
Lisp_Object dflt_backends
|
||||
= gui_display_get_arg (dpyinfo, parms, Qfont_backend,
|
||||
"fontBackend", "FontBackend", RES_TYPE_STRING);
|
||||
if (!EQ (dflt_backends, Qunbound))
|
||||
{
|
||||
bool harfbuzz_requested = false, uniscribe_requested = false;
|
||||
if (CONSP (dflt_backends))
|
||||
{
|
||||
if (!NILP (Fmemq (Quniscribe, dflt_backends)))
|
||||
uniscribe_requested = true;
|
||||
if (!NILP (Fmemq (Qharfbuzz, dflt_backends)))
|
||||
harfbuzz_requested = true;
|
||||
}
|
||||
else if (STRINGP (dflt_backends))
|
||||
{
|
||||
if (strcmp (SSDATA (dflt_backends), "uniscribe") == 0)
|
||||
uniscribe_requested = true;
|
||||
else if (strcmp (SSDATA (dflt_backends), "harfbuzz") == 0)
|
||||
harfbuzz_requested = true;
|
||||
}
|
||||
if (uniscribe_requested)
|
||||
{
|
||||
register_uniscribe = uniscribe_available;
|
||||
if (!harfbuzz_requested)
|
||||
register_harfbuzz = false;
|
||||
}
|
||||
}
|
||||
if (register_harfbuzz)
|
||||
register_font_driver (&harfbuzz_font_driver, f);
|
||||
#endif
|
||||
if (register_uniscribe)
|
||||
register_font_driver (&uniscribe_font_driver, f);
|
||||
register_font_driver (&w32font_driver, f);
|
||||
|
||||
|
|
|
@ -2646,6 +2646,7 @@ syms_of_w32font (void)
|
|||
{
|
||||
DEFSYM (Qgdi, "gdi");
|
||||
DEFSYM (Quniscribe, "uniscribe");
|
||||
DEFSYM (Qharfbuzz, "harfbuzz");
|
||||
DEFSYM (QCformat, ":format");
|
||||
|
||||
/* Generic font families. */
|
||||
|
|
|
@ -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.
|
||||
|
@ -29,6 +30,14 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
|||
#define _WIN32_WINNT 0x0600
|
||||
#include <windows.h>
|
||||
#include <usp10.h>
|
||||
#ifdef HAVE_HARFBUZZ
|
||||
# include <hb.h>
|
||||
# if GNUC_PREREQ (4, 3, 0)
|
||||
# define bswap_32(v) __builtin_bswap32(v)
|
||||
# else
|
||||
# include <byteswap.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include "lisp.h"
|
||||
#include "w32term.h"
|
||||
|
@ -39,10 +48,16 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
|||
#include "pdumper.h"
|
||||
#include "w32common.h"
|
||||
|
||||
/* Extension of w32font_info used by Uniscribe and HarfBuzz backends. */
|
||||
struct uniscribe_font_info
|
||||
{
|
||||
struct w32font_info w32_font;
|
||||
SCRIPT_CACHE cache;
|
||||
/* This is used by the Uniscribe backend as a pointer to the script
|
||||
cache, and by the HarfBuzz backend as a pointer to a hb_font_t
|
||||
object. */
|
||||
void *cache;
|
||||
/* This is used by the HarfBuzz backend to store the font scale. */
|
||||
double scale;
|
||||
};
|
||||
|
||||
int uniscribe_available = 0;
|
||||
|
@ -51,6 +66,39 @@ int uniscribe_available = 0;
|
|||
static int CALLBACK ALIGN_STACK add_opentype_font_name_to_list (ENUMLOGFONTEX *,
|
||||
NEWTEXTMETRICEX *,
|
||||
DWORD, LPARAM);
|
||||
#ifdef HAVE_HARFBUZZ
|
||||
|
||||
struct font_driver harfbuzz_font_driver;
|
||||
int harfbuzz_available = 0;
|
||||
|
||||
/* Typedefs for HarfBuzz functions which we call through function
|
||||
pointers initialized after we load the HarfBuzz DLL. */
|
||||
DEF_DLL_FN (hb_blob_t *, hb_blob_create,
|
||||
(const char *, unsigned int, hb_memory_mode_t, void *,
|
||||
hb_destroy_func_t));
|
||||
DEF_DLL_FN (hb_face_t *, hb_face_create_for_tables,
|
||||
(hb_reference_table_func_t, void *, hb_destroy_func_t));
|
||||
DEF_DLL_FN (unsigned, hb_face_get_glyph_count, (const hb_face_t *));
|
||||
DEF_DLL_FN (hb_font_t *, hb_font_create, (hb_face_t *));
|
||||
DEF_DLL_FN (void, hb_font_destroy, (hb_font_t *));
|
||||
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_bool_t, hb_font_get_variation_glyph,
|
||||
(hb_font_t *, hb_codepoint_t, hb_codepoint_t, hb_codepoint_t *));
|
||||
|
||||
#define hb_blob_create fn_hb_blob_create
|
||||
#define hb_face_create_for_tables fn_hb_face_create_for_tables
|
||||
#define hb_face_get_glyph_count fn_hb_face_get_glyph_count
|
||||
#define hb_font_create fn_hb_font_create
|
||||
#define hb_font_destroy fn_hb_font_destroy
|
||||
#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_font_get_variation_glyph fn_hb_font_get_variation_glyph
|
||||
#endif
|
||||
|
||||
/* Used by uniscribe_otf_capability. */
|
||||
static Lisp_Object otf_features (HDC context, const char *table);
|
||||
|
||||
|
@ -117,7 +165,10 @@ uniscribe_open (struct frame *f, Lisp_Object font_entity, int pixel_size)
|
|||
struct uniscribe_font_info *uniscribe_font
|
||||
= (struct uniscribe_font_info *) XFONT_OBJECT (font_object);
|
||||
|
||||
ASET (font_object, FONT_TYPE_INDEX, Quniscribe);
|
||||
if (!NILP (AREF (font_entity, FONT_TYPE_INDEX)))
|
||||
ASET (font_object, FONT_TYPE_INDEX, AREF (font_entity, FONT_TYPE_INDEX));
|
||||
else /* paranoia: this should never happen */
|
||||
ASET (font_object, FONT_TYPE_INDEX, Quniscribe);
|
||||
|
||||
if (!w32font_open_internal (f, font_entity, pixel_size, font_object))
|
||||
{
|
||||
|
@ -127,10 +178,15 @@ uniscribe_open (struct frame *f, Lisp_Object font_entity, int pixel_size)
|
|||
/* Initialize the cache for this font. */
|
||||
uniscribe_font->cache = NULL;
|
||||
|
||||
/* Uniscribe backend uses glyph indices. */
|
||||
/* Uniscribe and HarfBuzz backends use glyph indices. */
|
||||
uniscribe_font->w32_font.glyph_idx = ETO_GLYPH_INDEX;
|
||||
|
||||
uniscribe_font->w32_font.font.driver = &uniscribe_font_driver;
|
||||
#ifdef HAVE_HARFBUZZ
|
||||
if (EQ (AREF (font_object, FONT_TYPE_INDEX), Qharfbuzz))
|
||||
uniscribe_font->w32_font.font.driver = &harfbuzz_font_driver;
|
||||
else
|
||||
#endif /* HAVE_HARFBUZZ */
|
||||
uniscribe_font->w32_font.font.driver = &uniscribe_font_driver;
|
||||
|
||||
return font_object;
|
||||
}
|
||||
|
@ -141,8 +197,16 @@ uniscribe_close (struct font *font)
|
|||
struct uniscribe_font_info *uniscribe_font
|
||||
= (struct uniscribe_font_info *) font;
|
||||
|
||||
#ifdef HAVE_HARFBUZZ
|
||||
if (uniscribe_font->w32_font.font.driver == &harfbuzz_font_driver
|
||||
&& uniscribe_font->cache)
|
||||
hb_font_destroy ((hb_font_t *) uniscribe_font->cache);
|
||||
else
|
||||
#endif
|
||||
if (uniscribe_font->cache)
|
||||
ScriptFreeCache (&(uniscribe_font->cache));
|
||||
ScriptFreeCache ((SCRIPT_CACHE) &(uniscribe_font->cache));
|
||||
|
||||
uniscribe_font->cache = NULL;
|
||||
|
||||
w32font_close (font);
|
||||
}
|
||||
|
@ -205,6 +269,9 @@ uniscribe_otf_capability (struct font *font)
|
|||
(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.
|
||||
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
|
||||
|
@ -213,7 +280,7 @@ uniscribe_otf_capability (struct font *font)
|
|||
than the length of LGSTRING, nil should be returned. In that case,
|
||||
this function is called again with a larger LGSTRING. */
|
||||
static Lisp_Object
|
||||
uniscribe_shape (Lisp_Object lgstring)
|
||||
uniscribe_shape (Lisp_Object lgstring, Lisp_Object direction)
|
||||
{
|
||||
struct font *font = CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring));
|
||||
struct uniscribe_font_info *uniscribe_font
|
||||
|
@ -287,7 +354,7 @@ uniscribe_shape (Lisp_Object lgstring)
|
|||
|
||||
/* Context may be NULL here, in which case the cache should be
|
||||
used without needing to select the font. */
|
||||
result = ScriptShape (context, &(uniscribe_font->cache),
|
||||
result = ScriptShape (context, (SCRIPT_CACHE) &(uniscribe_font->cache),
|
||||
chars + items[i].iCharPos, nchars_in_run,
|
||||
max_glyphs - done_glyphs, &(items[i].a),
|
||||
glyphs, clusters, attributes, &nglyphs);
|
||||
|
@ -301,7 +368,7 @@ uniscribe_shape (Lisp_Object lgstring)
|
|||
context = get_frame_dc (f);
|
||||
old_font = SelectObject (context, FONT_HANDLE (font));
|
||||
|
||||
result = ScriptShape (context, &(uniscribe_font->cache),
|
||||
result = ScriptShape (context, (SCRIPT_CACHE) &(uniscribe_font->cache),
|
||||
chars + items[i].iCharPos, nchars_in_run,
|
||||
max_glyphs - done_glyphs, &(items[i].a),
|
||||
glyphs, clusters, attributes, &nglyphs);
|
||||
|
@ -326,7 +393,7 @@ uniscribe_shape (Lisp_Object lgstring)
|
|||
}
|
||||
else
|
||||
{
|
||||
result = ScriptPlace (context, &(uniscribe_font->cache),
|
||||
result = ScriptPlace (context, (SCRIPT_CACHE) &(uniscribe_font->cache),
|
||||
glyphs, nglyphs, attributes, &(items[i].a),
|
||||
advances, offsets, &overall_metrics);
|
||||
if (result == E_PENDING && !context)
|
||||
|
@ -336,13 +403,15 @@ uniscribe_shape (Lisp_Object lgstring)
|
|||
context = get_frame_dc (f);
|
||||
old_font = SelectObject (context, FONT_HANDLE (font));
|
||||
|
||||
result = ScriptPlace (context, &(uniscribe_font->cache),
|
||||
result = ScriptPlace (context,
|
||||
(SCRIPT_CACHE) &(uniscribe_font->cache),
|
||||
glyphs, nglyphs, attributes, &(items[i].a),
|
||||
advances, offsets, &overall_metrics);
|
||||
}
|
||||
if (SUCCEEDED (result))
|
||||
{
|
||||
int j, from, to, adj_offset = 0;
|
||||
int cluster_offset = 0;
|
||||
|
||||
from = 0;
|
||||
to = from;
|
||||
|
@ -386,6 +455,7 @@ uniscribe_shape (Lisp_Object lgstring)
|
|||
}
|
||||
}
|
||||
}
|
||||
cluster_offset = 0;
|
||||
|
||||
/* For RTL text, the Uniscribe shaper prepares
|
||||
the values in ADVANCES array for layout in
|
||||
|
@ -401,6 +471,8 @@ uniscribe_shape (Lisp_Object lgstring)
|
|||
adjustment for the base character, which is
|
||||
then updated for each successive glyph in the
|
||||
grapheme cluster. */
|
||||
/* FIXME: Should we use DIRECTION here instead
|
||||
of what ScriptItemize guessed? */
|
||||
if (items[i].a.fRTL)
|
||||
{
|
||||
int j1 = j;
|
||||
|
@ -414,8 +486,11 @@ uniscribe_shape (Lisp_Object lgstring)
|
|||
}
|
||||
}
|
||||
|
||||
LGLYPH_SET_CHAR (lglyph, chars[items[i].iCharPos
|
||||
+ from]);
|
||||
int char_idx = items[i].iCharPos + from + cluster_offset;
|
||||
if (from + cluster_offset > to)
|
||||
char_idx = items[i].iCharPos + to;
|
||||
cluster_offset++;
|
||||
LGLYPH_SET_CHAR (lglyph, chars[char_idx]);
|
||||
LGLYPH_SET_FROM (lglyph, items[i].iCharPos + from);
|
||||
LGLYPH_SET_TO (lglyph, items[i].iCharPos + to);
|
||||
|
||||
|
@ -424,18 +499,18 @@ uniscribe_shape (Lisp_Object lgstring)
|
|||
LGLYPH_SET_ASCENT (lglyph, font->ascent);
|
||||
LGLYPH_SET_DESCENT (lglyph, font->descent);
|
||||
|
||||
result = ScriptGetGlyphABCWidth (context,
|
||||
&(uniscribe_font->cache),
|
||||
glyphs[j], &char_metric);
|
||||
result = ScriptGetGlyphABCWidth
|
||||
(context, (SCRIPT_CACHE) &(uniscribe_font->cache),
|
||||
glyphs[j], &char_metric);
|
||||
if (result == E_PENDING && !context)
|
||||
{
|
||||
/* Cache incomplete... */
|
||||
f = XFRAME (selected_frame);
|
||||
context = get_frame_dc (f);
|
||||
old_font = SelectObject (context, FONT_HANDLE (font));
|
||||
result = ScriptGetGlyphABCWidth (context,
|
||||
&(uniscribe_font->cache),
|
||||
glyphs[j], &char_metric);
|
||||
result = ScriptGetGlyphABCWidth
|
||||
(context, (SCRIPT_CACHE) &(uniscribe_font->cache),
|
||||
glyphs[j], &char_metric);
|
||||
}
|
||||
|
||||
if (SUCCEEDED (result))
|
||||
|
@ -567,7 +642,8 @@ uniscribe_encode_char (struct font *font, int c)
|
|||
order. */
|
||||
items[0].a.fLogicalOrder = 1;
|
||||
|
||||
result = ScriptShape (context, &(uniscribe_font->cache),
|
||||
result = ScriptShape (context,
|
||||
(SCRIPT_CACHE) &(uniscribe_font->cache),
|
||||
ch, len, 2, &(items[0].a),
|
||||
glyphs, clusters, attrs, &nglyphs);
|
||||
|
||||
|
@ -578,7 +654,8 @@ uniscribe_encode_char (struct font *font, int c)
|
|||
f = XFRAME (selected_frame);
|
||||
context = get_frame_dc (f);
|
||||
old_font = SelectObject (context, FONT_HANDLE (font));
|
||||
result = ScriptShape (context, &(uniscribe_font->cache),
|
||||
result = ScriptShape (context,
|
||||
(SCRIPT_CACHE) &(uniscribe_font->cache),
|
||||
ch, len, 2, &(items[0].a),
|
||||
glyphs, clusters, attrs, &nglyphs);
|
||||
}
|
||||
|
@ -596,7 +673,8 @@ uniscribe_encode_char (struct font *font, int c)
|
|||
when shaped. But we still need the return from here
|
||||
to be valid for the shaping engine to be invoked
|
||||
later. */
|
||||
result = ScriptGetCMap (context, &(uniscribe_font->cache),
|
||||
result = ScriptGetCMap (context,
|
||||
(SCRIPT_CACHE) &(uniscribe_font->cache),
|
||||
ch, len, 0, glyphs);
|
||||
if (SUCCEEDED (result) && glyphs[0])
|
||||
code = glyphs[0];
|
||||
|
@ -1143,6 +1221,210 @@ otf_features (HDC context, const char *table)
|
|||
return Qnil;
|
||||
}
|
||||
|
||||
#ifdef HAVE_HARFBUZZ
|
||||
|
||||
/* W32 implementation of the 'list' method for HarfBuzz backend. */
|
||||
static Lisp_Object
|
||||
w32hb_list (struct frame *f, Lisp_Object font_spec)
|
||||
{
|
||||
Lisp_Object fonts = w32font_list_internal (f, font_spec, true);
|
||||
FONT_ADD_LOG ("harfbuzz-list", font_spec, fonts);
|
||||
|
||||
for (Lisp_Object tail = fonts; CONSP (tail); tail = XCDR (tail))
|
||||
ASET (XCAR (tail), FONT_TYPE_INDEX, Qharfbuzz);
|
||||
|
||||
return fonts;
|
||||
}
|
||||
|
||||
/* W32 implementation of the 'match' method for HarfBuzz backend. */
|
||||
static Lisp_Object
|
||||
w32hb_match (struct frame *f, Lisp_Object font_spec)
|
||||
{
|
||||
Lisp_Object entity = w32font_match_internal (f, font_spec, true);
|
||||
FONT_ADD_LOG ("harfbuzz-match", font_spec, entity);
|
||||
|
||||
if (! NILP (entity))
|
||||
ASET (entity, FONT_TYPE_INDEX, Qharfbuzz);
|
||||
return entity;
|
||||
}
|
||||
|
||||
/* Callback function to free memory. We need this so we could pass it
|
||||
to HarfBuzz as the function to call to destroy objects for which we
|
||||
allocated data by calling our 'malloc' (as opposed to 'malloc' from
|
||||
the MS CRT, against which HarfBuzz was linked). */
|
||||
static void
|
||||
free_cb (void *ptr)
|
||||
{
|
||||
free (ptr);
|
||||
}
|
||||
|
||||
/* A function used as reference_table_func for HarfBuzz. It returns
|
||||
the data of a specified table of a font as a blob. */
|
||||
static hb_blob_t *
|
||||
w32hb_get_font_table (hb_face_t *face, hb_tag_t tag, void *data)
|
||||
{
|
||||
struct frame *f = XFRAME (selected_frame);
|
||||
HDC context = get_frame_dc (f);
|
||||
HFONT old_font = SelectObject (context, (HFONT) data);
|
||||
char *font_data = NULL;
|
||||
DWORD font_data_size = 0, val;
|
||||
DWORD table = bswap_32 (tag);
|
||||
hb_blob_t *blob = NULL;
|
||||
|
||||
val = GetFontData (context, table, 0, font_data, font_data_size);
|
||||
if (val != GDI_ERROR)
|
||||
{
|
||||
font_data_size = val;
|
||||
/* Don't call xmalloc, because it can signal an error, while
|
||||
we are inside a critical section established by get_frame_dc. */
|
||||
font_data = malloc (font_data_size);
|
||||
if (font_data)
|
||||
{
|
||||
val = GetFontData (context, table, 0, font_data, font_data_size);
|
||||
if (val != GDI_ERROR)
|
||||
blob = hb_blob_create (font_data, font_data_size,
|
||||
HB_MEMORY_MODE_READONLY, font_data, free_cb);
|
||||
}
|
||||
}
|
||||
|
||||
/* Restore graphics context. */
|
||||
SelectObject (context, old_font);
|
||||
release_frame_dc (f, context);
|
||||
|
||||
return blob;
|
||||
}
|
||||
|
||||
/* Helper function used by the HarfBuzz implementations of the
|
||||
encode_char, has_char, and begin_hb_font methods. It creates an
|
||||
hb_font_t object for a given Emacs font. */
|
||||
static hb_font_t *
|
||||
w32hb_get_font (struct font *font, double *scale)
|
||||
{
|
||||
hb_font_t *hb_font = NULL;
|
||||
HFONT font_handle = FONT_HANDLE (font);
|
||||
hb_face_t *hb_face =
|
||||
hb_face_create_for_tables (w32hb_get_font_table, font_handle, NULL);
|
||||
if (hb_face_get_glyph_count (hb_face) > 0)
|
||||
hb_font = hb_font_create (hb_face);
|
||||
|
||||
struct uniscribe_font_info *uniscribe_font =
|
||||
(struct uniscribe_font_info *) font;
|
||||
unsigned upem = hb_face_get_upem (hb_face);
|
||||
eassert (upem > 0);
|
||||
/* https://support.microsoft.com/en-sg/help/74299/info-calculating-the-logical-height-and-point-size-of-a-font. */
|
||||
LONG font_point_size =
|
||||
uniscribe_font->w32_font.metrics.tmHeight
|
||||
- uniscribe_font->w32_font.metrics.tmInternalLeading;
|
||||
/* https://docs.microsoft.com/en-us/typography/opentype/spec/ttch01,
|
||||
under "Converting FUnits to pixels". */
|
||||
*scale = font_point_size * 1.0 / upem;
|
||||
|
||||
hb_face_destroy (hb_face);
|
||||
|
||||
/* FIXME: Can hb_font be non-NULL and yet invalid? Compare to get_empty? */
|
||||
return hb_font;
|
||||
}
|
||||
|
||||
/* W32 implementation of encode_char method for HarfBuzz backend. */
|
||||
static unsigned
|
||||
w32hb_encode_char (struct font *font, int c)
|
||||
{
|
||||
struct uniscribe_font_info *uniscribe_font
|
||||
= (struct uniscribe_font_info *) font;
|
||||
eassert (uniscribe_font->w32_font.font.driver == &harfbuzz_font_driver);
|
||||
hb_font_t *hb_font = uniscribe_font->cache;
|
||||
|
||||
/* First time we use this font with HarfBuzz, create the hb_font_t
|
||||
object and cache it. */
|
||||
if (!hb_font)
|
||||
{
|
||||
double scale;
|
||||
hb_font = w32hb_get_font (font, &scale);
|
||||
if (!hb_font)
|
||||
return FONT_INVALID_CODE;
|
||||
|
||||
uniscribe_font->cache = hb_font;
|
||||
eassert (scale > 0.0);
|
||||
uniscribe_font->scale = scale;
|
||||
}
|
||||
hb_codepoint_t glyph;
|
||||
if (hb_font_get_nominal_glyph (hb_font, c, &glyph))
|
||||
return glyph;
|
||||
return FONT_INVALID_CODE;
|
||||
}
|
||||
|
||||
/* W32 implementation of HarfBuzz begin_hb_font and end_hb_font
|
||||
methods. */
|
||||
|
||||
/* Return a HarfBuzz font object for FONT and store in POSITION_UNIT
|
||||
the scale factor to convert a hb_position_t value to the number of
|
||||
pixels. Return NULL if HarfBuzz font object is not available for
|
||||
FONT. */
|
||||
static hb_font_t *
|
||||
w32hb_begin_font (struct font *font, double *position_unit)
|
||||
{
|
||||
struct uniscribe_font_info *uniscribe_font
|
||||
= (struct uniscribe_font_info *) font;
|
||||
eassert (uniscribe_font->w32_font.font.driver == &harfbuzz_font_driver);
|
||||
|
||||
/* First time we use this font with HarfBuzz, create the hb_font_t
|
||||
object and cache it. */
|
||||
if (!uniscribe_font->cache)
|
||||
{
|
||||
double scale;
|
||||
uniscribe_font->cache = w32hb_get_font (font, &scale);
|
||||
eassert (scale > 0.0);
|
||||
uniscribe_font->scale = scale;
|
||||
}
|
||||
*position_unit = uniscribe_font->scale;
|
||||
return (hb_font_t *) uniscribe_font->cache;
|
||||
}
|
||||
|
||||
/* W32 implementation of get_variation_glyphs method for HarfBuzz.
|
||||
|
||||
Return the number of variation glyphs of character C supported by
|
||||
FONT. VARIATIONS is an array of 256 elements. If the variation
|
||||
selector N (1..256) defines a glyph, that glyph code is stored in
|
||||
the (N-1)th element of VARIATIONS. */
|
||||
static int
|
||||
w32hb_get_variation_glyphs (struct font *font, int c, unsigned variations[256])
|
||||
{
|
||||
struct uniscribe_font_info *uniscribe_font
|
||||
= (struct uniscribe_font_info *) font;
|
||||
eassert (uniscribe_font->w32_font.font.driver == &harfbuzz_font_driver);
|
||||
|
||||
/* First time we use this font with HarfBuzz, create the hb_font_t
|
||||
object and cache it. */
|
||||
if (!uniscribe_font->cache)
|
||||
{
|
||||
double scale;
|
||||
uniscribe_font->cache = w32hb_get_font (font, &scale);
|
||||
eassert (scale > 0.0);
|
||||
uniscribe_font->scale = scale;
|
||||
}
|
||||
|
||||
int i, n = 0;
|
||||
hb_font_t *hb_font = uniscribe_font->cache;
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
if (hb_font_get_variation_glyph (hb_font, c, 0xFE00 + i, &variations[i]))
|
||||
n++;
|
||||
else
|
||||
variations[i] = 0;
|
||||
}
|
||||
for ( ; i < 256; i++)
|
||||
{
|
||||
if (hb_font_get_variation_glyph (hb_font, c, 0xE0100 + (i - 16),
|
||||
&variations[i]))
|
||||
n++;
|
||||
else
|
||||
variations[i] = 0;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
#endif /* HAVE_HARFBUZZ */
|
||||
|
||||
#undef OTF_INT16_VAL
|
||||
#undef OTF_TAG_VAL
|
||||
#undef OTF_TAG
|
||||
|
@ -1191,17 +1473,32 @@ syms_of_w32uniscribe (void)
|
|||
pdumper_do_now_and_after_load (syms_of_w32uniscribe_for_pdumper);
|
||||
}
|
||||
|
||||
#ifdef HAVE_HARFBUZZ
|
||||
static bool
|
||||
load_harfbuzz_funcs (HMODULE library)
|
||||
{
|
||||
LOAD_DLL_FN (library, hb_blob_create);
|
||||
LOAD_DLL_FN (library, hb_face_create_for_tables);
|
||||
LOAD_DLL_FN (library, hb_face_get_glyph_count);
|
||||
LOAD_DLL_FN (library, hb_font_create);
|
||||
LOAD_DLL_FN (library, hb_font_destroy);
|
||||
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_font_get_variation_glyph);
|
||||
return hbfont_init_w32_funcs (library);
|
||||
}
|
||||
#endif /* HAVE_HARFBUZZ */
|
||||
|
||||
static void
|
||||
syms_of_w32uniscribe_for_pdumper (void)
|
||||
{
|
||||
HMODULE uniscribe;
|
||||
|
||||
/* Don't init uniscribe when dumping */
|
||||
/* Don't init Uniscribe and HarfBuzz when dumping */
|
||||
if (!initialized)
|
||||
return;
|
||||
|
||||
/* Don't register if uniscribe is not available. */
|
||||
uniscribe = GetModuleHandle ("usp10");
|
||||
/* Don't register if Uniscribe is not available. */
|
||||
HMODULE uniscribe = GetModuleHandle ("usp10");
|
||||
if (!uniscribe)
|
||||
return;
|
||||
|
||||
|
@ -1221,4 +1518,31 @@ syms_of_w32uniscribe_for_pdumper (void)
|
|||
uniscribe_new_apis = true;
|
||||
else
|
||||
uniscribe_new_apis = false;
|
||||
|
||||
#ifdef HAVE_HARFBUZZ
|
||||
/* Currently, HarfBuzz DLLs are always named libharfbuzz-0.dll, as
|
||||
the project keeps the ABI backward-compatible. So we can
|
||||
hard-code the name of the library here, for now. If they ever
|
||||
break ABI compatibility, we may need to load the DLL that
|
||||
corresponds to the HarfBuzz version for which Emacs was built. */
|
||||
HMODULE harfbuzz = LoadLibrary ("libharfbuzz-0.dll");
|
||||
/* Don't register if HarfBuzz is not available. */
|
||||
if (!harfbuzz)
|
||||
return;
|
||||
|
||||
if (!load_harfbuzz_funcs (harfbuzz))
|
||||
return;
|
||||
|
||||
harfbuzz_available = 1;
|
||||
harfbuzz_font_driver = uniscribe_font_driver;
|
||||
harfbuzz_font_driver.type = Qharfbuzz;
|
||||
harfbuzz_font_driver.list = w32hb_list;
|
||||
harfbuzz_font_driver.match = w32hb_match;
|
||||
harfbuzz_font_driver.encode_char = w32hb_encode_char;
|
||||
harfbuzz_font_driver.shape = hbfont_shape;
|
||||
harfbuzz_font_driver.get_variation_glyphs = w32hb_get_variation_glyphs;
|
||||
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 */
|
||||
}
|
||||
|
|
|
@ -6955,6 +6955,7 @@ static next_element_function const get_next_element[NUM_IT_METHODS] =
|
|||
|| ((IT)->cmp_it.stop_pos == (CHARPOS) \
|
||||
&& composition_reseat_it (&(IT)->cmp_it, CHARPOS, BYTEPOS, \
|
||||
END_CHARPOS, (IT)->w, \
|
||||
(IT)->bidi_it.resolved_level, \
|
||||
FACE_FROM_ID_OR_NULL ((IT)->f, \
|
||||
(IT)->face_id), \
|
||||
(IT)->string)))
|
||||
|
|
14
src/xfns.c
14
src/xfns.c
|
@ -3780,10 +3780,16 @@ This function is an internal primitive--use `make-frame' instead. */)
|
|||
|
||||
#ifdef USE_CAIRO
|
||||
register_font_driver (&ftcrfont_driver, f);
|
||||
#ifdef HAVE_HARFBUZZ
|
||||
register_font_driver (&ftcrhbfont_driver, f);
|
||||
#endif /* HAVE_HARFBUZZ */
|
||||
#else
|
||||
#ifdef HAVE_FREETYPE
|
||||
#ifdef HAVE_XFT
|
||||
register_font_driver (&xftfont_driver, f);
|
||||
#ifdef HAVE_HARFBUZZ
|
||||
register_font_driver (&xfthbfont_driver, f);
|
||||
#endif
|
||||
#else /* not HAVE_XFT */
|
||||
register_font_driver (&ftxfont_driver, f);
|
||||
#endif /* not HAVE_XFT */
|
||||
|
@ -6205,15 +6211,21 @@ x_create_tip_frame (struct x_display_info *dpyinfo, Lisp_Object parms)
|
|||
|
||||
#ifdef USE_CAIRO
|
||||
register_font_driver (&ftcrfont_driver, f);
|
||||
#ifdef HAVE_HARFBUZZ
|
||||
register_font_driver (&ftcrhbfont_driver, f);
|
||||
#endif /* HAVE_HARFBUZZ */
|
||||
#else
|
||||
register_font_driver (&xfont_driver, f);
|
||||
#ifdef HAVE_FREETYPE
|
||||
#ifdef HAVE_XFT
|
||||
register_font_driver (&xftfont_driver, f);
|
||||
#ifdef HAVE_HARFBUZZ
|
||||
register_font_driver (&xfthbfont_driver, f);
|
||||
#endif
|
||||
#else /* not HAVE_XFT */
|
||||
register_font_driver (&ftxfont_driver, f);
|
||||
#endif /* not HAVE_XFT */
|
||||
#endif /* HAVE_FREETYPE */
|
||||
register_font_driver (&xfont_driver, f);
|
||||
#endif /* not USE_CAIRO */
|
||||
|
||||
image_cache_refcount =
|
||||
|
|
|
@ -108,21 +108,13 @@ xftfont_get_colors (struct frame *f, struct face *face, GC gc,
|
|||
static Lisp_Object
|
||||
xftfont_list (struct frame *f, Lisp_Object spec)
|
||||
{
|
||||
Lisp_Object list = ftfont_list (f, spec);
|
||||
|
||||
for (Lisp_Object tail = list; CONSP (tail); tail = XCDR (tail))
|
||||
ASET (XCAR (tail), FONT_TYPE_INDEX, Qxft);
|
||||
return list;
|
||||
return ftfont_list2 (f, spec, Qxft);
|
||||
}
|
||||
|
||||
static Lisp_Object
|
||||
xftfont_match (struct frame *f, Lisp_Object spec)
|
||||
{
|
||||
Lisp_Object entity = ftfont_match (f, spec);
|
||||
|
||||
if (! NILP (entity))
|
||||
ASET (entity, FONT_TYPE_INDEX, Qxft);
|
||||
return entity;
|
||||
return ftfont_match2 (f, spec, Qxft);
|
||||
}
|
||||
|
||||
static FcChar8 ascii_printable[95];
|
||||
|
@ -174,10 +166,16 @@ xftfont_open (struct frame *f, Lisp_Object entity, int pixel_size)
|
|||
/* We should not destroy PAT here because it is kept in XFTFONT and
|
||||
destroyed automatically when XFTFONT is closed. */
|
||||
font_object = font_build_object (VECSIZE (struct font_info),
|
||||
Qxft, entity, size);
|
||||
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), Qxfthb))
|
||||
font->driver = &xfthbfont_driver;
|
||||
else
|
||||
#endif /* HAVE_HARFBUZZ */
|
||||
font->driver = &xftfont_driver;
|
||||
font->encoding_charset = font->repertory_charset = -1;
|
||||
|
||||
|
@ -273,6 +271,9 @@ xftfont_open (struct frame *f, Lisp_Object entity, int pixel_size)
|
|||
xftfont_info->maybe_otf = (ft_face->face_flags & FT_FACE_FLAG_SFNT) != 0;
|
||||
xftfont_info->otf = NULL;
|
||||
#endif /* HAVE_LIBOTF */
|
||||
#ifdef HAVE_HARFBUZZ
|
||||
xftfont_info->hb_font = NULL;
|
||||
#endif /* HAVE_HARFBUZZ */
|
||||
xftfont_info->ft_size = ft_face->size;
|
||||
|
||||
font->baseline_offset = 0;
|
||||
|
@ -312,6 +313,13 @@ xftfont_close (struct font *font)
|
|||
xftfont_info->otf = NULL;
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_HARFBUZZ
|
||||
if (xftfont_info->hb_font)
|
||||
{
|
||||
hb_font_destroy (xftfont_info->hb_font);
|
||||
xftfont_info->hb_font = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* See comment in xfont_close. */
|
||||
if (xftfont_info->xftfont
|
||||
|
@ -503,13 +511,13 @@ xftfont_draw (struct glyph_string *s, int from, int to, int x, int y,
|
|||
|
||||
#if defined HAVE_M17N_FLT && defined HAVE_LIBOTF
|
||||
static Lisp_Object
|
||||
xftfont_shape (Lisp_Object lgstring)
|
||||
xftfont_shape (Lisp_Object lgstring, Lisp_Object direction)
|
||||
{
|
||||
struct font *font = CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring));
|
||||
struct font_info *xftfont_info = (struct font_info *) font;
|
||||
FT_Face ft_face = XftLockFace (xftfont_info->xftfont);
|
||||
xftfont_info->ft_size = ft_face->size;
|
||||
Lisp_Object val = ftfont_shape (lgstring);
|
||||
Lisp_Object val = ftfont_shape (lgstring, direction);
|
||||
XftUnlockFace (xftfont_info->xftfont);
|
||||
return val;
|
||||
}
|
||||
|
@ -591,6 +599,41 @@ xftfont_cached_font_ok (struct frame *f, Lisp_Object font_object,
|
|||
return ok;
|
||||
}
|
||||
|
||||
#ifdef HAVE_HARFBUZZ
|
||||
|
||||
static Lisp_Object
|
||||
xfthbfont_list (struct frame *f, Lisp_Object spec)
|
||||
{
|
||||
return ftfont_list2 (f, spec, Qxfthb);
|
||||
}
|
||||
|
||||
static Lisp_Object
|
||||
xfthbfont_match (struct frame *f, Lisp_Object spec)
|
||||
{
|
||||
return ftfont_match2 (f, spec, Qxfthb);
|
||||
}
|
||||
|
||||
static hb_font_t *
|
||||
xfthbfont_begin_hb_font (struct font *font, double *position_unit)
|
||||
{
|
||||
struct font_info *xftfont_info = (struct font_info *) font;
|
||||
FT_Face ft_face = XftLockFace (xftfont_info->xftfont);
|
||||
|
||||
xftfont_info->ft_size = ft_face->size;
|
||||
|
||||
return fthbfont_begin_hb_font (font, position_unit);
|
||||
}
|
||||
|
||||
static void
|
||||
xfthbfont_end_hb_font (struct font *font, hb_font_t *hb_font)
|
||||
{
|
||||
struct font_info *xftfont_info = (struct font_info *) font;
|
||||
|
||||
XftUnlockFace (xftfont_info->xftfont);
|
||||
}
|
||||
|
||||
#endif /* HAVE_HARFBUZZ */
|
||||
|
||||
static void syms_of_xftfont_for_pdumper (void);
|
||||
|
||||
struct font_driver const xftfont_driver =
|
||||
|
@ -618,7 +661,7 @@ struct font_driver const xftfont_driver =
|
|||
#if defined HAVE_M17N_FLT && defined HAVE_LIBOTF
|
||||
.shape = xftfont_shape,
|
||||
#endif
|
||||
#ifdef HAVE_OTF_GET_VARIATION_GLYPHS
|
||||
#if defined HAVE_OTF_GET_VARIATION_GLYPHS || defined HAVE_FT_FACE_GETCHARVARIANTINDEX
|
||||
.get_variation_glyphs = ftfont_variation_glyphs,
|
||||
#endif
|
||||
.filter_properties = ftfont_filter_properties,
|
||||
|
@ -626,11 +669,17 @@ struct font_driver const xftfont_driver =
|
|||
.combining_capability = ftfont_combining_capability,
|
||||
.drop_xrender_surfaces = xftfont_drop_xrender_surfaces,
|
||||
};
|
||||
#ifdef HAVE_HARFBUZZ
|
||||
struct font_driver xfthbfont_driver;
|
||||
#endif /* HAVE_HARFBUZZ */
|
||||
|
||||
void
|
||||
syms_of_xftfont (void)
|
||||
{
|
||||
DEFSYM (Qxft, "xft");
|
||||
#ifdef HAVE_HARFBUZZ
|
||||
DEFSYM (Qxfthb, "xfthb");
|
||||
#endif /* HAVE_HARFBUZZ */
|
||||
|
||||
DEFVAR_BOOL ("xft-font-ascent-descent-override",
|
||||
xft_font_ascent_descent_override,
|
||||
|
@ -645,4 +694,15 @@ static void
|
|||
syms_of_xftfont_for_pdumper (void)
|
||||
{
|
||||
register_font_driver (&xftfont_driver, NULL);
|
||||
#ifdef HAVE_HARFBUZZ
|
||||
xfthbfont_driver = xftfont_driver;
|
||||
xfthbfont_driver.type = Qxfthb;
|
||||
xfthbfont_driver.list = xfthbfont_list;
|
||||
xfthbfont_driver.match = xfthbfont_match;
|
||||
xfthbfont_driver.shape = hbfont_shape;
|
||||
xfthbfont_driver.combining_capability = hbfont_combining_capability;
|
||||
xfthbfont_driver.begin_hb_font = xfthbfont_begin_hb_font;
|
||||
xfthbfont_driver.end_hb_font = xfthbfont_end_hb_font;
|
||||
register_font_driver (&xfthbfont_driver, NULL);
|
||||
#endif /* HAVE_HARFBUZZ */
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue