1
0
mirror of https://git.savannah.gnu.org/git/emacs.git synced 2025-01-31 20:02:42 +00:00

Implement drawing text with DirectWrite on MS-Windows.

This adds support for color fonts.
* configure.ac: Add src/w32drite to W32_OBJ.
* src/w32dwrite.c: New file.
(w32-initialize-direct-write): New function, initialize the
DirectWrite library if it is available, and required global
variables.
(w32_use_direct_write): New function, check if DirectWrite
is available and activated by the user.
(w32_dwrite_encode_char): New function, replacement for HarfBuzz's
'encode_char'.
(w32_dwrite_text_extents): New function, replacement for w32font
text_extents.
(w32_dwrite_draw): New function, replacement for w32font draw.
(w32_dwrite_free_cached_face): New function, used in the font
deletion process to also delete DirectWrite data.
(verify_hr): New function, verify COM method results.
(release_com): New function, release a COM object.
(w32-dwrite-available): New function, returns true if DirectWrite
is available.
(w32-dwrite-reinit): New function, reinitialize DirectWrite,
optionally setting some rendering parameters.
* src/w32font.c (w32font_text_extents): If DirectWrite is enabled,
call 'w32_dwrite_text_extents'.
(w32font_draw): If DirectWrite is enabled, call 'w32_dwrite_draw'.
* src/w32uniscribe.c: (w32hb_encode_char): If DirectWrite is enabled,
call 'w32_dwrite_encode_char'.
(syms_of_w32uniscribe_for_pdumper): Initialize DirectWrite.
(uniscribe_close): Free DirectWrite data for the font.

Bug#73730
This commit is contained in:
Cecilio Pardo 2024-10-09 11:40:28 +02:00 committed by Eli Zaretskii
parent 517711c373
commit edf37e811c
6 changed files with 1184 additions and 26 deletions

View File

@ -3172,7 +3172,7 @@ if test "${HAVE_W32}" = "yes"; then
AC_CHECK_TOOL([WINDRES], [windres],
[AC_MSG_ERROR([No resource compiler found.])])
W32_OBJ="w32fns.o w32menu.o w32reg.o w32font.o w32term.o"
W32_OBJ="$W32_OBJ w32xfns.o w32select.o w32uniscribe.o w32cygwinx.o"
W32_OBJ="$W32_OBJ w32xfns.o w32select.o w32uniscribe.o w32dwrite.o w32cygwinx.o"
EMACSRES="emacs.res"
case "$canonical" in
x86_64-*-*) EMACS_MANIFEST="emacs-x64.manifest" ;;

View File

@ -785,6 +785,14 @@ This is in addition to drag-n-drop of files, that was already
supported. As on X, the user options 'dnd-scroll-margin' and
'dnd-indicate-insertion-point' can be used to customize the process.
---
** Emacs on MS-Windows now supports color fonts.
On Windows 8.1 and later versions Emacs now uses DirectWrite to draw
text, which supports color fonts. This can be disabled by setting the
variable 'w32-inhibit-dwrite' to t. Also see 'w32-dwrite-available' and
'w32-dwrite-reinit' to check availability and to configure render
parameters.
----------------------------------------------------------------------
This file is part of GNU Emacs.

1099
src/w32dwrite.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -452,6 +452,10 @@ w32font_text_extents (struct font *font, const unsigned *code,
memset (metrics, 0, sizeof (struct font_metrics));
if (w32_use_direct_write (w32_font))
if (w32_dwrite_text_extents (font, code, nglyphs, metrics))
return;
for (i = 0, first = true; i < nglyphs; i++)
{
struct w32_metric_cache *char_metric;
@ -706,22 +710,31 @@ w32font_draw (struct glyph_string *s, int from, int to,
int i;
for (i = 0; i < len; i++)
{
WCHAR c = s->char2b[from + i] & 0xFFFF;
ExtTextOutW (s->hdc, x + i, y, options, NULL, &c, 1, NULL);
}
if (!w32_use_direct_write (w32font) ||
!w32_dwrite_draw (s->hdc, x, y, s->char2b + from, 1,
GetTextColor(s->hdc), s->font))
{
WCHAR c = s->char2b[from + i] & 0xFFFF;
ExtTextOutW (s->hdc, x + i, y, options, NULL, &c, 1, NULL);
}
}
else
{
/* The number of glyphs in a glyph_string cannot be larger than
the maximum value of the 'used' member of a glyph_row, so we
are OK using alloca here. */
eassert (len <= SHRT_MAX);
WCHAR *chars = alloca (len * sizeof (WCHAR));
int j;
for (j = 0; j < len; j++)
chars[j] = s->char2b[from + j] & 0xFFFF;
ExtTextOutW (s->hdc, x, y, options, NULL, chars, len, NULL);
if (!w32_use_direct_write (w32font) ||
!w32_dwrite_draw (s->hdc, x, y,
s->char2b + from, len, GetTextColor(s->hdc),
s->font))
{
/* The number of glyphs in a glyph_string cannot be larger than
the maximum value of the 'used' member of a glyph_row, so we
are OK using alloca here. */
eassert (len <= SHRT_MAX);
WCHAR *chars = alloca (len * sizeof (WCHAR));
int j;
for (j = 0; j < len; j++)
chars[j] = s->char2b[from + j] & 0xFFFF;
ExtTextOutW (s->hdc, x, y, options, NULL, chars, len, NULL);
}
}
/* Restore clip region. */

View File

@ -57,6 +57,26 @@ struct w32font_info
HFONT hfont;
};
/* Extension of w32font_info used by Uniscribe and HarfBuzz backends. */
struct uniscribe_font_info
{
struct w32font_info w32_font;
/* 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;
/* This is used by DirectWrite to store the FontFace object.
DirectWrite works on top of the HarfBuzz backend, modifying some
calls. If there are problems manipulating this font,
dwrite_skip_font is set to true. Future operations will not use
DirectWrite and fall back to the HarfBuzz backend. */
void *dwrite_cache;
float dwrite_font_size;
bool dwrite_skip_font;
};
/* Macros for getting OS specific information from a font struct. */
#define FONT_HANDLE(f) (((struct w32font_info *)(f))->hfont)
#define FONT_TEXTMETRIC(f) (((struct w32font_info *)(f))->metrics)
@ -84,6 +104,17 @@ int uniscribe_check_otf (LOGFONT *font, Lisp_Object otf_spec);
Lisp_Object intern_font_name (char *);
/* Function prototypes for DirectWrite. */
void w32_initialize_direct_write (void);
bool w32_use_direct_write (struct w32font_info *w32font);
bool w32_dwrite_draw (HDC hdc, int x, int y, unsigned *glyphs, int len,
COLORREF color, struct font *font );
bool w32_dwrite_text_extents (struct font *font, const unsigned *code,
int nglyphs, struct font_metrics *metrics);
unsigned w32_dwrite_encode_char (struct font *font, int c);
void w32_dwrite_free_cached_face(void *cache);
void syms_of_w32dwrite (void);
extern void globals_of_w32font (void);
#endif

View File

@ -44,18 +44,6 @@ 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;
/* 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;
/* EnumFontFamiliesEx callback. */
@ -200,6 +188,9 @@ uniscribe_open (struct frame *f, Lisp_Object font_entity, int pixel_size)
/* Initialize the cache for this font. */
uniscribe_font->cache = NULL;
uniscribe_font->dwrite_cache = NULL;
uniscribe_font->dwrite_skip_font = false;
/* Uniscribe and HarfBuzz backends use glyph indices. */
uniscribe_font->w32_font.glyph_idx = ETO_GLYPH_INDEX;
@ -221,6 +212,7 @@ uniscribe_close (struct font *font)
= (struct uniscribe_font_info *) font;
#ifdef HAVE_HARFBUZZ
w32_dwrite_free_cached_face (uniscribe_font->dwrite_cache);
if (uniscribe_font->w32_font.font.driver == &harfbuzz_font_driver
&& uniscribe_font->cache)
hb_font_destroy ((hb_font_t *) uniscribe_font->cache);
@ -1372,6 +1364,17 @@ 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);
if (w32_use_direct_write (&uniscribe_font->w32_font))
{
unsigned encoded = w32_dwrite_encode_char (font, c);
/* The call to w32_dwrite_encode_char may fail, disabling
DirectWrite for this font. So check again. */
if (w32_use_direct_write (&uniscribe_font->w32_font))
return encoded;
}
hb_font_t *hb_font = uniscribe_font->cache;
/* First time we use this font with HarfBuzz, create the hb_font_t
@ -1510,6 +1513,7 @@ static void syms_of_w32uniscribe_for_pdumper (void);
void
syms_of_w32uniscribe (void)
{
syms_of_w32dwrite ();
pdumper_do_now_and_after_load (syms_of_w32uniscribe_for_pdumper);
}
@ -1624,5 +1628,8 @@ syms_of_w32uniscribe_for_pdumper (void)
harfbuzz_font_driver.combining_capability = hbfont_combining_capability;
harfbuzz_font_driver.begin_hb_font = w32hb_begin_font;
register_font_driver (&harfbuzz_font_driver, NULL);
w32_initialize_direct_write ();
#endif /* HAVE_HARFBUZZ */
}