emacs/src/w32font.c

2954 lines
92 KiB
C

/* Font backend for the Microsoft Windows API.
Copyright (C) 2007-2024 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 <windows.h>
#include <stdio.h>
#include <math.h>
#include <ctype.h>
#include <commdlg.h>
#include "lisp.h"
#include "w32term.h"
#include "frame.h"
#include "coding.h" /* for ENCODE_SYSTEM, DECODE_SYSTEM */
#include "w32font.h"
#ifdef WINDOWSNT
#include "w32common.h"
#include "w32.h"
#endif
#include "pdumper.h"
/* Cleartype available on Windows XP, cleartype_natural from XP SP1.
The latter does not try to fit cleartype smoothed fonts into the
same bounding box as the non-antialiased version of the font.
*/
#ifndef CLEARTYPE_QUALITY
#define CLEARTYPE_QUALITY 5
#endif
#ifndef CLEARTYPE_NATURAL_QUALITY
#define CLEARTYPE_NATURAL_QUALITY 6
#endif
/* VIETNAMESE_CHARSET and JOHAB_CHARSET are not defined in some versions
of MSVC headers. */
#ifndef VIETNAMESE_CHARSET
#define VIETNAMESE_CHARSET 163
#endif
#ifndef JOHAB_CHARSET
#define JOHAB_CHARSET 130
#endif
static void fill_in_logfont (struct frame *, LOGFONT *, Lisp_Object);
static BYTE w32_antialias_type (Lisp_Object);
static Lisp_Object lispy_antialias_type (BYTE);
static Lisp_Object font_supported_scripts (FONTSIGNATURE *);
static int w32font_full_name (LOGFONT *, Lisp_Object, int, char *, int);
static void compute_metrics (HDC, struct w32font_info *, unsigned int,
struct w32_metric_cache *);
static Lisp_Object w32_registry (LONG, DWORD);
/* EnumFontFamiliesEx callbacks. */
static int CALLBACK ALIGN_STACK add_font_entity_to_list (ENUMLOGFONTEX *,
NEWTEXTMETRICEX *,
DWORD, LPARAM);
static int CALLBACK ALIGN_STACK add_one_font_entity_to_list (ENUMLOGFONTEX *,
NEWTEXTMETRICEX *,
DWORD, LPARAM);
static int CALLBACK ALIGN_STACK add_font_name_to_list (ENUMLOGFONTEX *,
NEWTEXTMETRICEX *,
DWORD, LPARAM);
/* struct passed in as LPARAM arg to EnumFontFamiliesEx, for keeping track
of what we really want. */
struct font_callback_data
{
/* The logfont we are matching against. EnumFontFamiliesEx only matches
face name and charset, so we need to manually match everything else
in the callback function. */
LOGFONT pattern;
/* The original font spec or entity. */
Lisp_Object orig_font_spec;
/* The frame the font is being loaded on. */
Lisp_Object frame;
/* Fonts known to support the font spec, or nil if none. */
Lisp_Object known_fonts;
/* The list to add matches to. */
Lisp_Object list;
/* Whether to match only opentype fonts. */
bool opentype_only;
};
/* Handles the problem that EnumFontFamiliesEx will not return all
style variations if the font name is not specified. */
static void list_all_matching_fonts (struct font_callback_data *);
#ifdef WINDOWSNT
static BOOL g_b_init_get_outline_metrics_w;
static BOOL g_b_init_get_text_metrics_w;
static BOOL g_b_init_get_glyph_outline_w;
static BOOL g_b_init_get_char_width_32_w;
typedef UINT (WINAPI * GetOutlineTextMetricsW_Proc) (
HDC hdc,
UINT cbData,
LPOUTLINETEXTMETRICW lpotmw);
typedef BOOL (WINAPI * GetTextMetricsW_Proc) (
HDC hdc,
LPTEXTMETRICW lptmw);
typedef DWORD (WINAPI * GetGlyphOutlineW_Proc) (
HDC hdc,
UINT uChar,
UINT uFormat,
LPGLYPHMETRICS lpgm,
DWORD cbBuffer,
LPVOID lpvBuffer,
const MAT2 *lpmat2);
typedef BOOL (WINAPI * GetCharWidth32W_Proc) (
HDC hdc,
UINT uFirstChar,
UINT uLastChar,
LPINT lpBuffer);
/* Several "wide" functions we use to support the font backends are
unavailable on Windows 9X, unless UNICOWS.DLL is installed (their
versions in the default libraries are non-functional stubs). On NT
and later systems, these functions are in GDI32.DLL. The following
helper function attempts to load UNICOWS.DLL on Windows 9X, and
refuses to let Emacs start up if that library is not found. On NT
and later versions, it simply loads GDI32.DLL, which should always
be available. */
static HMODULE
w32_load_unicows_or_gdi32 (void)
{
return maybe_load_unicows_dll ();
}
/* The following 3 functions call the problematic "wide" APIs via
function pointers, to avoid linking against the non-standard
libunicows on W9X. */
static UINT WINAPI
get_outline_metrics_w(HDC hdc, UINT cbData, LPOUTLINETEXTMETRICW lpotmw)
{
static GetOutlineTextMetricsW_Proc s_pfn_Get_Outline_Text_MetricsW = NULL;
HMODULE hm_unicows = NULL;
if (g_b_init_get_outline_metrics_w == 0)
{
g_b_init_get_outline_metrics_w = 1;
hm_unicows = w32_load_unicows_or_gdi32 ();
if (hm_unicows)
s_pfn_Get_Outline_Text_MetricsW = (GetOutlineTextMetricsW_Proc)
get_proc_addr (hm_unicows, "GetOutlineTextMetricsW");
}
eassert (s_pfn_Get_Outline_Text_MetricsW != NULL);
return s_pfn_Get_Outline_Text_MetricsW (hdc, cbData, lpotmw);
}
static BOOL WINAPI
get_text_metrics_w(HDC hdc, LPTEXTMETRICW lptmw)
{
static GetTextMetricsW_Proc s_pfn_Get_Text_MetricsW = NULL;
HMODULE hm_unicows = NULL;
if (g_b_init_get_text_metrics_w == 0)
{
g_b_init_get_text_metrics_w = 1;
hm_unicows = w32_load_unicows_or_gdi32 ();
if (hm_unicows)
s_pfn_Get_Text_MetricsW = (GetTextMetricsW_Proc)
get_proc_addr (hm_unicows, "GetTextMetricsW");
}
eassert (s_pfn_Get_Text_MetricsW != NULL);
return s_pfn_Get_Text_MetricsW (hdc, lptmw);
}
static DWORD WINAPI
get_glyph_outline_w (HDC hdc, UINT uChar, UINT uFormat, LPGLYPHMETRICS lpgm,
DWORD cbBuffer, LPVOID lpvBuffer, const MAT2 *lpmat2)
{
static GetGlyphOutlineW_Proc s_pfn_Get_Glyph_OutlineW = NULL;
HMODULE hm_unicows = NULL;
if (g_b_init_get_glyph_outline_w == 0)
{
g_b_init_get_glyph_outline_w = 1;
hm_unicows = w32_load_unicows_or_gdi32 ();
if (hm_unicows)
s_pfn_Get_Glyph_OutlineW = (GetGlyphOutlineW_Proc)
get_proc_addr (hm_unicows, "GetGlyphOutlineW");
}
eassert (s_pfn_Get_Glyph_OutlineW != NULL);
return s_pfn_Get_Glyph_OutlineW (hdc, uChar, uFormat, lpgm, cbBuffer,
lpvBuffer, lpmat2);
}
static DWORD WINAPI
get_char_width_32_w (HDC hdc, UINT uFirstChar, UINT uLastChar, LPINT lpBuffer)
{
static GetCharWidth32W_Proc s_pfn_Get_Char_Width_32W = NULL;
HMODULE hm_unicows = NULL;
if (g_b_init_get_char_width_32_w == 0)
{
g_b_init_get_char_width_32_w = 1;
hm_unicows = w32_load_unicows_or_gdi32 ();
if (hm_unicows)
s_pfn_Get_Char_Width_32W = (GetCharWidth32W_Proc)
get_proc_addr (hm_unicows, "GetCharWidth32W");
}
eassert (s_pfn_Get_Char_Width_32W != NULL);
return s_pfn_Get_Char_Width_32W (hdc, uFirstChar, uLastChar, lpBuffer);
}
#else /* Cygwin */
/* Cygwin doesn't support Windows 9X, and links against GDI32.DLL, so
it can just call these functions directly. */
#define get_outline_metrics_w(h,d,o) GetOutlineTextMetricsW(h,d,o)
#define get_text_metrics_w(h,t) GetTextMetricsW(h,t)
#define get_glyph_outline_w(h,uc,f,gm,b,v,m) \
GetGlyphOutlineW(h,uc,f,gm,b,v,m)
#define get_char_width_32_w(h,fc,lc,b) GetCharWidth32W(h,fc,lc,b)
#endif /* Cygwin */
static int
memq_no_quit (Lisp_Object elt, Lisp_Object list)
{
while (CONSP (list) && ! EQ (XCAR (list), elt))
list = XCDR (list);
return (CONSP (list));
}
Lisp_Object
intern_font_name (char * string)
{
Lisp_Object str = DECODE_SYSTEM (build_string (string));
ptrdiff_t len = SCHARS (str);
Lisp_Object obarray = check_obarray (Vobarray);
Lisp_Object tem = oblookup (obarray, SSDATA (str), len, len);
/* This code is similar to intern function from lread.c. */
return SYMBOLP (tem) ? tem : intern_driver (str, obarray, tem);
}
/* w32 implementation of get_cache for font backend.
Return a cache of font-entities on FRAME. The cache must be a
cons whose cdr part is the actual cache area. */
Lisp_Object
w32font_get_cache (struct frame *f)
{
struct w32_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
return (dpyinfo->name_list_element);
}
/* w32 implementation of list for font backend.
List fonts exactly matching with FONT_SPEC on FRAME. The value
is a vector of font-entities. This is the sole API that
allocates font-entities. */
static Lisp_Object
w32font_list (struct frame *f, Lisp_Object font_spec)
{
Lisp_Object fonts = w32font_list_internal (f, font_spec, 0);
FONT_ADD_LOG ("w32font-list", font_spec, fonts);
return fonts;
}
/* w32 implementation of match for font backend.
Return a font entity most closely matching with FONT_SPEC on
FRAME. The closeness is determined by the font backend, thus
`face-font-selection-order' is ignored here. */
static Lisp_Object
w32font_match (struct frame *f, Lisp_Object font_spec)
{
Lisp_Object entity = w32font_match_internal (f, font_spec, 0);
FONT_ADD_LOG ("w32font-match", font_spec, entity);
return entity;
}
/* w32 implementation of list_family for font backend.
List available families. The value is a list of family names
(symbols). */
static Lisp_Object
w32font_list_family (struct frame *f)
{
Lisp_Object list = Qnil;
Lisp_Object prev_quit = Vinhibit_quit;
LOGFONT font_match_pattern;
HDC dc;
memset (&font_match_pattern, 0, sizeof (font_match_pattern));
font_match_pattern.lfCharSet = DEFAULT_CHARSET;
/* Prevent quitting while EnumFontFamiliesEx runs and conses the
list it will return. That's because get_frame_dc acquires the
critical section, so we cannot quit before we release it in
release_frame_dc. */
Vinhibit_quit = Qt;
dc = get_frame_dc (f);
EnumFontFamiliesEx (dc, &font_match_pattern,
(FONTENUMPROC) add_font_name_to_list,
(LPARAM) &list, 0);
release_frame_dc (f, dc);
Vinhibit_quit = prev_quit;
return list;
}
/* w32 implementation of open for font backend.
Open a font specified by FONT_ENTITY on frame F.
If the font is scalable, open it with PIXEL_SIZE. */
static Lisp_Object
w32font_open (struct frame *f, Lisp_Object font_entity, int pixel_size)
{
Lisp_Object font_object
= font_make_object (VECSIZE (struct w32font_info),
font_entity, pixel_size);
struct w32font_info *w32_font
= (struct w32font_info *) XFONT_OBJECT (font_object);
ASET (font_object, FONT_TYPE_INDEX, Qgdi);
if (!w32font_open_internal (f, font_entity, pixel_size, font_object))
{
return Qnil;
}
/* GDI backend does not use glyph indices. */
w32_font->glyph_idx = 0;
return font_object;
}
/* w32 implementation of close for font_backend. */
void
w32font_close (struct font *font)
{
struct w32font_info *w32_font = (struct w32font_info *) font;
if (w32_font->hfont)
{
/* Delete the GDI font object. */
DeleteObject (w32_font->hfont);
w32_font->hfont = NULL;
/* Free all the cached metrics. */
if (w32_font->cached_metrics)
{
int i;
for (i = 0; i < w32_font->n_cache_blocks; i++)
xfree (w32_font->cached_metrics[i]);
xfree (w32_font->cached_metrics);
w32_font->cached_metrics = NULL;
}
}
}
/* w32 implementation of has_char for font backend.
Optional.
If FONT_ENTITY has a glyph for character C (Unicode code point),
return 1. If not, return 0. If a font must be opened to check
it, return -1. */
int
w32font_has_char (Lisp_Object entity, int c)
{
/* We can't be certain about which characters a font will support until
we open it. Checking the scripts that the font supports turns out
to not be reliable. */
return -1;
#if 0
Lisp_Object supported_scripts, extra, script;
DWORD mask;
extra = AREF (entity, FONT_EXTRA_INDEX);
if (!CONSP (extra))
return -1;
supported_scripts = assq_no_quit (QCscript, extra);
/* If font doesn't claim to support any scripts, then we can't be certain
until we open it. */
if (!CONSP (supported_scripts))
return -1;
supported_scripts = XCDR (supported_scripts);
script = CHAR_TABLE_REF (Vchar_script_table, c);
/* If we don't know what script the character is from, then we can't be
certain until we open it. Also if the font claims support for the script
the character is from, it may only have partial coverage, so we still
can't be certain until we open the font. */
if (NILP (script) || memq_no_quit (script, supported_scripts))
return -1;
/* Font reports what scripts it supports, and none of them are the script
the character is from. But we still can't be certain, as some fonts
will contain some/most/all of the characters in that script without
claiming support for it. */
return -1;
#endif
}
/* w32 implementation of encode_char for font backend.
Return a glyph code of FONT for character C (Unicode code point).
If FONT doesn't have such a glyph, return FONT_INVALID_CODE.
For speed, the gdi backend uses Unicode (Emacs calls encode_char
far too often for it to be efficient). But we still need to detect
which characters are not supported by the font.
*/
static unsigned
w32font_encode_char (struct font *font, int c)
{
struct w32font_info * w32_font = (struct w32font_info *)font;
if (c < w32_font->metrics.tmFirstChar
|| c > w32_font->metrics.tmLastChar)
return FONT_INVALID_CODE;
else
return c;
}
/* w32 implementation of text_extents for font backend.
Perform the size computation of glyphs of FONT and fillin members
of METRICS. The glyphs are specified by their glyph codes in
CODE (length NGLYPHS). Apparently metrics can be NULL, in this
case just return the overall width. */
void
w32font_text_extents (struct font *font, const unsigned *code,
int nglyphs, struct font_metrics *metrics)
{
int i;
HFONT old_font = NULL;
HDC dc = NULL;
struct frame * f UNINIT;
int total_width = 0;
WORD *wcode;
SIZE size;
bool first;
Lisp_Object prev_quit = Vinhibit_quit;
struct w32font_info *w32_font = (struct w32font_info *) font;
memset (metrics, 0, sizeof (struct font_metrics));
for (i = 0, first = true; i < nglyphs; i++)
{
struct w32_metric_cache *char_metric;
int block = *(code + i) / CACHE_BLOCKSIZE;
int pos_in_block = *(code + i) % CACHE_BLOCKSIZE;
if (block >= w32_font->n_cache_blocks)
{
if (!w32_font->cached_metrics)
w32_font->cached_metrics
= xmalloc ((block + 1)
* sizeof (struct w32_metric_cache *));
else
w32_font->cached_metrics
= xrealloc (w32_font->cached_metrics,
(block + 1)
* sizeof (struct w32_metric_cache *));
memset (w32_font->cached_metrics + w32_font->n_cache_blocks, 0,
((block + 1 - w32_font->n_cache_blocks)
* sizeof (struct w32_metric_cache *)));
w32_font->n_cache_blocks = block + 1;
}
if (!w32_font->cached_metrics[block])
{
w32_font->cached_metrics[block]
= xzalloc (CACHE_BLOCKSIZE * sizeof (struct w32_metric_cache));
}
char_metric = w32_font->cached_metrics[block] + pos_in_block;
if (char_metric->status == W32METRIC_NO_ATTEMPT)
{
if (dc == NULL)
{
/* TODO: Frames can come and go, and their fonts
outlive them. So we can't cache the frame in the
font structure. Use selected_frame until the API
is updated to pass in a frame. */
f = XFRAME (selected_frame);
/* Prevent quitting while EnumFontFamiliesEx runs and
conses the list it will return. That's because
get_frame_dc acquires the critical section, so we
cannot quit before we release it in release_frame_dc. */
prev_quit = Vinhibit_quit;
Vinhibit_quit = Qt;
dc = get_frame_dc (f);
old_font = SelectObject (dc, w32_font->hfont);
}
compute_metrics (dc, w32_font, *(code + i), char_metric);
}
if (char_metric->status == W32METRIC_SUCCESS)
{
if (first)
{
metrics->lbearing = char_metric->lbearing;
metrics->rbearing = char_metric->rbearing;
metrics->width = 0;
metrics->ascent = char_metric->ascent;
metrics->descent = char_metric->descent;
first = false;
}
if (metrics->lbearing > char_metric->lbearing)
metrics->lbearing = char_metric->lbearing;
if (metrics->rbearing < char_metric->rbearing)
metrics->rbearing = char_metric->rbearing;
metrics->width += char_metric->width;
if (metrics->ascent < char_metric->ascent)
metrics->ascent = char_metric->ascent;
if (metrics->descent < char_metric->descent)
metrics->descent = char_metric->descent;
}
else
/* If we couldn't get metrics for a char,
use alternative method. */
break;
}
/* If we got through everything, return. */
if (i == nglyphs)
{
if (dc != NULL)
{
/* Restore state and release DC. */
SelectObject (dc, old_font);
release_frame_dc (f, dc);
Vinhibit_quit = prev_quit;
}
return;
}
/* For non-truetype fonts, GetGlyphOutlineW is not supported, so
fallback on other methods that will at least give some of the metric
information. */
/* Make array big enough to hold surrogates. */
eassume (0 <= nglyphs); /* pacify GCC warning on next line */
wcode = alloca (nglyphs * sizeof (WORD) * 2);
for (i = 0; i < nglyphs; i++)
{
if (code[i] < 0x10000)
wcode[i] = code[i];
else
{
DWORD surrogate = code[i] - 0x10000;
/* High surrogate: U+D800 - U+DBFF. */
wcode[i++] = 0xD800 + ((surrogate >> 10) & 0x03FF);
/* Low surrogate: U+DC00 - U+DFFF. */
wcode[i] = 0xDC00 + (surrogate & 0x03FF);
/* An extra glyph. wcode is already double the size of code to
cope with this. */
nglyphs++;
}
}
if (dc == NULL)
{
/* TODO: Frames can come and go, and their fonts outlive
them. So we can't cache the frame in the font structure. Use
selected_frame until the API is updated to pass in a
frame. */
f = XFRAME (selected_frame);
/* Prevent quitting while EnumFontFamiliesEx runs and conses the
list it will return. That's because get_frame_dc acquires
the critical section, so we cannot quit before we release it
in release_frame_dc. */
prev_quit = Vinhibit_quit;
Vinhibit_quit = Qt;
dc = get_frame_dc (f);
old_font = SelectObject (dc, w32_font->hfont);
}
if (GetTextExtentPoint32W (dc, wcode, nglyphs, &size))
{
total_width = size.cx;
}
/* On 95/98/ME, only some Unicode functions are available, so fallback
on doing a dummy draw to find the total width. */
if (!total_width)
{
RECT rect;
rect.top = 0; rect.bottom = font->height; rect.left = 0; rect.right = 1;
DrawTextW (dc, wcode, nglyphs, &rect,
DT_CALCRECT | DT_NOPREFIX | DT_SINGLELINE);
total_width = rect.right;
}
/* Give our best estimate of the metrics, based on what we know. */
metrics->width = total_width - w32_font->metrics.tmOverhang;
metrics->lbearing = 0;
metrics->rbearing = total_width;
metrics->ascent = font->ascent;
metrics->descent = font->descent;
/* Restore state and release DC. */
SelectObject (dc, old_font);
release_frame_dc (f, dc);
Vinhibit_quit = prev_quit;
}
/* w32 implementation of draw for font backend.
Optional.
Draw glyphs between FROM and TO of S->char2b at (X Y) pixel
position of frame F with S->FACE and S->GC. If WITH_BACKGROUND,
fill the background in advance. It is assured that WITH_BACKGROUND
is false when (FROM > 0 || TO < S->nchars).
TODO: Currently this assumes that the colors and fonts are already
set in the DC. This seems to be true now, but maybe only due to
the old font code setting it up. It may be safer to resolve faces
and fonts in here and set them explicitly
*/
int
w32font_draw (struct glyph_string *s, int from, int to,
int x, int y, bool with_background)
{
UINT options;
HRGN orig_clip = NULL;
int len = to - from;
struct w32font_info *w32font = (struct w32font_info *) s->font;
options = w32font->glyph_idx;
if (s->num_clips > 0)
{
HRGN new_clip = CreateRectRgnIndirect (s->clip);
/* Save clip region for later restoration. */
orig_clip = CreateRectRgn (0, 0, 0, 0);
if (!GetClipRgn (s->hdc, orig_clip))
{
DeleteObject (orig_clip);
orig_clip = NULL;
}
if (s->num_clips > 1)
{
HRGN clip2 = CreateRectRgnIndirect (s->clip + 1);
CombineRgn (new_clip, new_clip, clip2, RGN_OR);
DeleteObject (clip2);
}
SelectClipRgn (s->hdc, new_clip);
DeleteObject (new_clip);
}
/* Using OPAQUE background mode can clear more background than expected
when Cleartype is used. Draw the background manually to avoid this. */
SetBkMode (s->hdc, TRANSPARENT);
if (with_background)
{
HBRUSH brush;
RECT rect;
struct font *font = s->font;
int ascent = font->ascent, descent = font->descent;
/* Font's global ascent and descent values might be
preposterously large for some fonts. We fix here the case
when those fonts are used for display of glyphless
characters, because drawing background with font dimensions
in those cases makes the display illegible. There's only one
more call to the draw method with with_background set to
true, and that's in w32_draw_glyph_string_foreground, when
drawing the cursor, where we have no such heuristics
available. FIXME. */
if (s->first_glyph->type == GLYPHLESS_GLYPH
&& (s->first_glyph->u.glyphless.method == GLYPHLESS_DISPLAY_HEX_CODE
|| s->first_glyph->u.glyphless.method == GLYPHLESS_DISPLAY_ACRONYM))
{
ascent =
s->first_glyph->slice.glyphless.lower_yoff
- s->first_glyph->slice.glyphless.upper_yoff;
descent = 0;
}
brush = CreateSolidBrush (s->gc->background);
rect.left = x;
rect.top = y - ascent;
rect.right = x + s->width;
rect.bottom = y + descent;
FillRect (s->hdc, &rect, brush);
DeleteObject (brush);
}
if (s->padding_p)
{
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);
}
}
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);
}
/* Restore clip region. */
if (s->num_clips > 0)
SelectClipRgn (s->hdc, orig_clip);
if (orig_clip)
DeleteObject (orig_clip);
return len;
}
/* w32 implementation of free_entity for font backend.
Optional.
Free FONT_EXTRA_INDEX field of FONT_ENTITY.
static void
w32font_free_entity (Lisp_Object entity);
*/
/* w32 implementation of prepare_face for font backend.
Optional (if FACE->extra is not used).
Prepare FACE for displaying characters by FONT on frame F by
storing some data in FACE->extra. If successful, return 0.
Otherwise, return -1.
static int
w32font_prepare_face (struct frame *f, struct face *face);
*/
/* w32 implementation of done_face for font backend.
Optional.
Done FACE for displaying characters by FACE->font on frame F.
static void
w32font_done_face (struct frame *f, struct face *face); */
/* w32 implementation of get_bitmap for font backend.
Optional.
Store bitmap data for glyph-code CODE of FONT in BITMAP. It is
intended that this method is called from the other font-driver
for actual drawing.
static int
w32font_get_bitmap (struct font *font, unsigned code,
struct font_bitmap *bitmap, int bits_per_pixel);
*/
/* w32 implementation of free_bitmap for font backend.
Optional.
Free bitmap data in BITMAP.
static void
w32font_free_bitmap (struct font *font, struct font_bitmap *bitmap);
*/
/* w32 implementation of anchor_point for font backend.
Optional.
Get coordinates of the INDEXth anchor point of the glyph whose
code is CODE. Store the coordinates in *X and *Y. Return 0 if
the operations was successful. Otherwise return -1.
static int
w32font_anchor_point (struct font *font, unsigned code,
int index, int *x, int *y);
*/
/* w32 implementation of otf_capability for font backend.
Optional.
Return a list describing which scripts/languages FONT
supports by which GSUB/GPOS features of OpenType tables.
static Lisp_Object
w32font_otf_capability (struct font *font);
*/
/* w32 implementation of otf_drive for font backend.
Optional.
Apply FONT's OTF-FEATURES to the glyph string.
FEATURES specifies which OTF features to apply in this format:
(SCRIPT LANGSYS GSUB-FEATURE GPOS-FEATURE)
See the documentation of `font-drive-otf' for the detail.
This method applies the specified features to the codes in the
elements of GSTRING-IN (between FROMth and TOth). The output
codes are stored in GSTRING-OUT at the IDXth element and the
following elements.
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.
static int
w32font_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);
*/
/* Internal implementation of w32font_list.
Additional parameter opentype_only restricts the returned fonts to
opentype fonts, which can be used with the Uniscribe backend. */
Lisp_Object
w32font_list_internal (struct frame *f, Lisp_Object font_spec,
bool opentype_only)
{
struct font_callback_data match_data;
HDC dc;
match_data.orig_font_spec = font_spec;
match_data.list = Qnil;
XSETFRAME (match_data.frame, f);
memset (&match_data.pattern, 0, sizeof (LOGFONT));
fill_in_logfont (f, &match_data.pattern, font_spec);
/* If the charset is unrecognized, then we won't find a font, so don't
waste time looking for one. */
if (match_data.pattern.lfCharSet == DEFAULT_CHARSET)
{
Lisp_Object spec_charset = AREF (font_spec, FONT_REGISTRY_INDEX);
if (!NILP (spec_charset)
&& !EQ (spec_charset, Qiso10646_1)
&& !EQ (spec_charset, Qunicode_bmp)
&& !EQ (spec_charset, Qunicode_sip)
&& !EQ (spec_charset, Qunknown)
&& !EQ (spec_charset, Qascii_0))
return Qnil;
}
match_data.opentype_only = opentype_only;
if (opentype_only)
match_data.pattern.lfOutPrecision = OUT_OUTLINE_PRECIS;
match_data.known_fonts = Qnil;
Lisp_Object vw32_non_USB_fonts = Fsymbol_value (Qw32_non_USB_fonts), val;
if (CONSP (vw32_non_USB_fonts))
{
Lisp_Object extra;
for (extra = AREF (font_spec, FONT_EXTRA_INDEX);
CONSP (extra); extra = XCDR (extra))
{
Lisp_Object tem = XCAR (extra);
if (CONSP (tem)
&& EQ (XCAR (tem), QCscript)
&& SYMBOLP (XCDR (tem))
&& !NILP (val = assq_no_quit (XCDR (tem), vw32_non_USB_fonts)))
{
match_data.known_fonts = XCDR (val);
break;
}
}
}
if (match_data.pattern.lfFaceName[0] == '\0')
{
/* EnumFontFamiliesEx does not take other fields into account if
font name is blank, so need to use two passes. */
list_all_matching_fonts (&match_data);
}
else
{
Lisp_Object prev_quit = Vinhibit_quit;
/* Prevent quitting while EnumFontFamiliesEx runs and conses the
list it will return. That's because get_frame_dc acquires
the critical section, so we cannot quit before we release it
in release_frame_dc. */
Vinhibit_quit = Qt;
dc = get_frame_dc (f);
EnumFontFamiliesEx (dc, &match_data.pattern,
(FONTENUMPROC) add_font_entity_to_list,
(LPARAM) &match_data, 0);
release_frame_dc (f, dc);
Vinhibit_quit = prev_quit;
}
return match_data.list;
}
/* Internal implementation of w32font_match.
Additional parameter opentype_only restricts the returned fonts to
opentype fonts, which can be used with the Uniscribe backend. */
Lisp_Object
w32font_match_internal (struct frame *f, Lisp_Object font_spec,
bool opentype_only)
{
struct font_callback_data match_data;
HDC dc;
match_data.orig_font_spec = font_spec;
XSETFRAME (match_data.frame, f);
match_data.list = Qnil;
memset (&match_data.pattern, 0, sizeof (LOGFONT));
fill_in_logfont (f, &match_data.pattern, font_spec);
match_data.opentype_only = opentype_only;
if (opentype_only)
match_data.pattern.lfOutPrecision = OUT_OUTLINE_PRECIS;
match_data.known_fonts = Qnil;
Lisp_Object vw32_non_USB_fonts = Fsymbol_value (Qw32_non_USB_fonts), val;
if (CONSP (vw32_non_USB_fonts))
{
Lisp_Object extra;
for (extra = AREF (font_spec, FONT_EXTRA_INDEX);
CONSP (extra); extra = XCDR (extra))
{
Lisp_Object tem = XCAR (extra);
if (CONSP (tem)
&& EQ (XCAR (tem), QCscript)
&& SYMBOLP (XCDR (tem))
&& !NILP (val = assq_no_quit (XCDR (tem), vw32_non_USB_fonts)))
{
match_data.known_fonts = XCDR (val);
break;
}
}
}
/* Prevent quitting while EnumFontFamiliesEx runs and conses the
list it will return. That's because get_frame_dc acquires the
critical section, so we cannot quit before we release it in
release_frame_dc. */
Lisp_Object prev_quit = Vinhibit_quit;
Vinhibit_quit = Qt;
dc = get_frame_dc (f);
EnumFontFamiliesEx (dc, &match_data.pattern,
(FONTENUMPROC) add_one_font_entity_to_list,
(LPARAM) &match_data, 0);
release_frame_dc (f, dc);
Vinhibit_quit = prev_quit;
return NILP (match_data.list) ? Qnil : XCAR (match_data.list);
}
int
w32font_open_internal (struct frame *f, Lisp_Object font_entity,
int pixel_size, Lisp_Object font_object)
{
int len, size;
LOGFONT logfont;
HDC dc;
HFONT hfont, old_font;
Lisp_Object val;
struct w32font_info *w32_font;
struct font * font;
OUTLINETEXTMETRICW* metrics = NULL;
w32_font = (struct w32font_info *) XFONT_OBJECT (font_object);
font = (struct font *) w32_font;
if (!font)
return 0;
memset (&logfont, 0, sizeof (logfont));
fill_in_logfont (f, &logfont, font_entity);
/* Prefer truetype fonts, to avoid known problems with type1 fonts, and
limitations in bitmap fonts. */
val = AREF (font_entity, FONT_FOUNDRY_INDEX);
if (!EQ (val, Qraster))
logfont.lfOutPrecision = OUT_TT_PRECIS;
size = XFIXNUM (AREF (font_entity, FONT_SIZE_INDEX));
if (!size)
size = pixel_size;
logfont.lfHeight = -size;
hfont = CreateFontIndirect (&logfont);
if (hfont == NULL)
return 0;
/* Get the metrics for this font. */
dc = get_frame_dc (f);
old_font = SelectObject (dc, hfont);
/* Try getting the outline metrics (only works for truetype fonts). */
len = get_outline_metrics_w (dc, 0, NULL);
if (len)
{
metrics = (OUTLINETEXTMETRICW *) alloca (len);
if (get_outline_metrics_w (dc, len, metrics))
memcpy (&w32_font->metrics, &metrics->otmTextMetrics,
sizeof (TEXTMETRICW));
else
metrics = NULL;
}
if (!metrics)
get_text_metrics_w (dc, &w32_font->metrics);
w32_font->cached_metrics = NULL;
w32_font->n_cache_blocks = 0;
SelectObject (dc, old_font);
release_frame_dc (f, dc);
w32_font->hfont = hfont;
{
char *name;
/* We don't know how much space we need for the full name, so start with
96 bytes and go up in steps of 32. */
len = 96;
name = alloca (len);
while (name && w32font_full_name (&logfont, font_entity, pixel_size,
name, len) < 0)
{
len += 32;
name = alloca (len);
}
if (name)
font->props[FONT_FULLNAME_INDEX]
= DECODE_SYSTEM (build_string (name));
else
font->props[FONT_FULLNAME_INDEX]
= DECODE_SYSTEM (build_string (logfont.lfFaceName));
}
font->max_width = w32_font->metrics.tmMaxCharWidth;
/* Parts of Emacs display assume that height = ascent + descent...
so height is defined later, after ascent and descent.
font->height = w32_font->metrics.tmHeight
+ w32_font->metrics.tmExternalLeading;
*/
font->space_width = font->average_width = w32_font->metrics.tmAveCharWidth;
font->vertical_centering = 0;
font->baseline_offset = 0;
font->relative_compose = 0;
font->default_ascent = w32_font->metrics.tmAscent;
font->pixel_size = size;
font->driver = &w32font_driver;
font->encoding_charset = -1;
font->repertory_charset = -1;
/* TODO: do we really want the minimum width here, which could be negative? */
font->min_width = font->space_width;
font->ascent = w32_font->metrics.tmAscent;
font->descent = w32_font->metrics.tmDescent;
font->height = font->ascent + font->descent;
if (metrics)
{
font->underline_thickness = metrics->otmsUnderscoreSize;
font->underline_position = -metrics->otmsUnderscorePosition;
}
else
{
font->underline_thickness = 0;
font->underline_position = -1;
}
/* For temporary compatibility with legacy code that expects the
name to be usable in x-list-fonts. Eventually we expect to change
x-list-fonts and other places that use fonts so that this can be
an fcname or similar. */
font->props[FONT_NAME_INDEX] = Ffont_xlfd_name (font_object, Qnil, Qt);
return 1;
}
/* Callback function for EnumFontFamiliesEx.
* Adds the name of a font to a Lisp list (passed in as the lParam arg). */
static int CALLBACK ALIGN_STACK
add_font_name_to_list (ENUMLOGFONTEX *logical_font,
NEWTEXTMETRICEX *physical_font,
DWORD font_type, LPARAM list_object)
{
Lisp_Object* list = (Lisp_Object *) list_object;
Lisp_Object family;
/* Skip vertical fonts (intended only for printing) */
if (logical_font->elfLogFont.lfFaceName[0] == '@')
return 1;
family = intern_font_name (logical_font->elfLogFont.lfFaceName);
if (! memq_no_quit (family, *list))
*list = Fcons (family, *list);
return 1;
}
static int w32_decode_weight (int);
static int w32_encode_weight (int);
/* Convert an enumerated Windows font to an Emacs font entity. */
static Lisp_Object
w32_enumfont_pattern_entity (Lisp_Object frame,
ENUMLOGFONTEX *logical_font,
NEWTEXTMETRICEX *physical_font,
DWORD font_type,
LOGFONT *requested_font,
Lisp_Object backend)
{
Lisp_Object entity, tem;
LOGFONT *lf = (LOGFONT*) logical_font;
BYTE generic_type;
DWORD full_type = physical_font->ntmTm.ntmFlags;
entity = font_make_entity ();
ASET (entity, FONT_TYPE_INDEX, backend);
ASET (entity, FONT_REGISTRY_INDEX, w32_registry (lf->lfCharSet, font_type));
ASET (entity, FONT_OBJLIST_INDEX, Qnil);
/* Foundry is difficult to get in readable form on Windows.
But Emacs crashes if it is not set, so set it to something more
generic. These values make xlfds compatible with Emacs 22. */
if (lf->lfOutPrecision == OUT_STRING_PRECIS)
tem = Qraster;
else if (lf->lfOutPrecision == OUT_STROKE_PRECIS)
tem = Qoutline;
else
tem = Qunknown;
ASET (entity, FONT_FOUNDRY_INDEX, tem);
/* Save the generic family in the extra info, as it is likely to be
useful to users looking for a close match. */
generic_type = physical_font->ntmTm.tmPitchAndFamily & 0xF0;
if (generic_type == FF_DECORATIVE)
tem = Qdecorative;
else if (generic_type == FF_MODERN)
tem = Qmono;
else if (generic_type == FF_ROMAN)
tem = Qserif;
else if (generic_type == FF_SCRIPT)
tem = Qscript;
else if (generic_type == FF_SWISS)
tem = Qsans;
else
tem = Qnil;
ASET (entity, FONT_ADSTYLE_INDEX, tem);
if (physical_font->ntmTm.tmPitchAndFamily & 0x01)
ASET (entity, FONT_SPACING_INDEX, make_fixnum (FONT_SPACING_PROPORTIONAL));
else
ASET (entity, FONT_SPACING_INDEX, make_fixnum (FONT_SPACING_CHARCELL));
if (requested_font->lfQuality != DEFAULT_QUALITY)
{
font_put_extra (entity, QCantialias,
lispy_antialias_type (requested_font->lfQuality));
}
ASET (entity, FONT_FAMILY_INDEX,
intern_font_name (lf->lfFaceName));
FONT_SET_STYLE (entity, FONT_WEIGHT_INDEX,
make_fixnum (w32_decode_weight (lf->lfWeight)));
FONT_SET_STYLE (entity, FONT_SLANT_INDEX,
make_fixnum (lf->lfItalic ? 200 : 100));
/* TODO: PANOSE struct has this info, but need to call GetOutlineTextMetrics
to get it. */
FONT_SET_STYLE (entity, FONT_WIDTH_INDEX, make_fixnum (100));
if (font_type & RASTER_FONTTYPE)
ASET (entity, FONT_SIZE_INDEX,
make_fixnum (physical_font->ntmTm.tmHeight
+ physical_font->ntmTm.tmExternalLeading));
else
ASET (entity, FONT_SIZE_INDEX, make_fixnum (0));
/* Cache Unicode codepoints covered by this font, as there is no other way
of getting this information easily. */
if (font_type & TRUETYPE_FONTTYPE)
{
tem = font_supported_scripts (&physical_font->ntmFontSig);
if (!NILP (tem))
font_put_extra (entity, QCscript, tem);
}
/* This information is not fully available when opening fonts, so
save it here. Only Windows 2000 and later return information
about opentype and type1 fonts, so need a fallback for detecting
truetype so that this information is not any worse than we could
have obtained later. */
if (EQ (backend, Quniscribe) && (full_type & NTMFLAGS_OPENTYPE))
tem = Qopentype;
else if (font_type & TRUETYPE_FONTTYPE)
tem = Qtruetype;
else if (full_type & NTM_PS_OPENTYPE)
tem = Qpostscript;
else if (full_type & NTM_TYPE1)
tem = Qtype1;
else if (font_type & RASTER_FONTTYPE)
tem = Qw32bitmap;
else
tem = Qw32vector;
font_put_extra (entity, QCformat, tem);
return entity;
}
/* Convert generic families to the family portion of lfPitchAndFamily. */
static BYTE
w32_generic_family (Lisp_Object name)
{
/* Generic families. */
if (EQ (name, Qmonospace) || EQ (name, Qmono))
return FF_MODERN;
else if (EQ (name, Qsans) || EQ (name, Qsans_serif) || EQ (name, Qsansserif))
return FF_SWISS;
else if (EQ (name, Qserif))
return FF_ROMAN;
else if (EQ (name, Qdecorative))
return FF_DECORATIVE;
else if (EQ (name, Qscript))
return FF_SCRIPT;
else
return FF_DONTCARE;
}
static int
logfonts_match (LOGFONT *font, LOGFONT *pattern)
{
/* Only check height for raster fonts. */
if (pattern->lfHeight && font->lfOutPrecision == OUT_STRING_PRECIS
&& font->lfHeight != pattern->lfHeight)
return 0;
/* Have some flexibility with weights. */
if (pattern->lfWeight
&& ((font->lfWeight < (pattern->lfWeight - 150))
|| font->lfWeight > (pattern->lfWeight + 150)))
return 0;
/* Charset and face should be OK. Italic has to be checked
against the original spec, in case we don't have any preference. */
return 1;
}
/* Codepage Bitfields in FONTSIGNATURE struct. */
#define CSB_JAPANESE (1 << 17)
#define CSB_KOREAN ((1 << 19) | (1 << 21))
#define CSB_CHINESE ((1 << 18) | (1 << 20))
static int
font_matches_spec (DWORD type, NEWTEXTMETRICEX *font,
Lisp_Object spec, Lisp_Object backend,
LOGFONT *logfont)
{
Lisp_Object extra, val;
/* Check italic. Can't check logfonts, since it is a boolean field,
so there is no difference between "non-italic" and "don't care". */
{
int slant = FONT_SLANT_NUMERIC (spec);
if (slant >= 0
&& ((slant > 150 && !font->ntmTm.tmItalic)
|| (slant <= 150 && font->ntmTm.tmItalic)))
return 0;
}
/* Check adstyle against generic family. */
val = AREF (spec, FONT_ADSTYLE_INDEX);
if (!NILP (val))
{
BYTE family = w32_generic_family (val);
if (family != FF_DONTCARE
&& family != (font->ntmTm.tmPitchAndFamily & 0xF0))
return 0;
}
/* Check spacing */
val = AREF (spec, FONT_SPACING_INDEX);
if (FIXNUMP (val))
{
int spacing = XFIXNUM (val);
int proportional = (spacing < FONT_SPACING_MONO);
if ((proportional && !(font->ntmTm.tmPitchAndFamily & 0x01))
|| (!proportional && (font->ntmTm.tmPitchAndFamily & 0x01)))
return 0;
}
/* Check extra parameters. */
for (extra = AREF (spec, FONT_EXTRA_INDEX);
CONSP (extra); extra = XCDR (extra))
{
Lisp_Object extra_entry;
extra_entry = XCAR (extra);
if (CONSP (extra_entry))
{
Lisp_Object key = XCAR (extra_entry);
val = XCDR (extra_entry);
if (EQ (key, QCscript) && SYMBOLP (val))
{
/* Only truetype fonts will have information about what
scripts they support. This probably means the user
will have to force Emacs to use raster, PostScript
or ATM fonts for non-ASCII text. */
if (type & TRUETYPE_FONTTYPE)
{
Lisp_Object support
= font_supported_scripts (&font->ntmFontSig);
if (! memq_no_quit (val, support))
return 0;
/* Avoid using non-Japanese fonts for Japanese, even
if they claim they are capable, due to known
breakage in Vista and Windows 7 fonts
(bug#6029). */
if (EQ (val, Qkana)
&& (font->ntmTm.tmCharSet != SHIFTJIS_CHARSET
|| !(font->ntmFontSig.fsCsb[0] & CSB_JAPANESE)))
return 0;
}
else
{
/* Return specific matches, but play it safe. Fonts
that cover more than their charset would suggest
are likely to be truetype or opentype fonts,
covered above. */
if (EQ (val, Qlatin))
{
/* Although every charset but symbol, thai and
arabic contains the basic ASCII set of latin
characters, Emacs expects much more. */
if (font->ntmTm.tmCharSet != ANSI_CHARSET)
return 0;
}
else if (EQ (val, Qsymbol))
{
if (font->ntmTm.tmCharSet != SYMBOL_CHARSET)
return 0;
}
else if (EQ (val, Qcyrillic))
{
if (font->ntmTm.tmCharSet != RUSSIAN_CHARSET)
return 0;
}
else if (EQ (val, Qgreek))
{
if (font->ntmTm.tmCharSet != GREEK_CHARSET)
return 0;
}
else if (EQ (val, Qarabic))
{
if (font->ntmTm.tmCharSet != ARABIC_CHARSET)
return 0;
}
else if (EQ (val, Qhebrew))
{
if (font->ntmTm.tmCharSet != HEBREW_CHARSET)
return 0;
}
else if (EQ (val, Qthai))
{
if (font->ntmTm.tmCharSet != THAI_CHARSET)
return 0;
}
else if (EQ (val, Qkana))
{
if (font->ntmTm.tmCharSet != SHIFTJIS_CHARSET)
return 0;
}
else if (EQ (val, Qbopomofo))
{
if (font->ntmTm.tmCharSet != CHINESEBIG5_CHARSET)
return 0;
}
else if (EQ (val, Qhangul))
{
if (font->ntmTm.tmCharSet != HANGUL_CHARSET
&& font->ntmTm.tmCharSet != JOHAB_CHARSET)
return 0;
}
else if (EQ (val, Qhan))
{
if (font->ntmTm.tmCharSet != CHINESEBIG5_CHARSET
&& font->ntmTm.tmCharSet != GB2312_CHARSET
&& font->ntmTm.tmCharSet != HANGUL_CHARSET
&& font->ntmTm.tmCharSet != JOHAB_CHARSET
&& font->ntmTm.tmCharSet != SHIFTJIS_CHARSET)
return 0;
}
else
/* Other scripts unlikely to be handled by non-truetype
fonts. */
return 0;
}
}
else if (EQ (key, QClang) && SYMBOLP (val))
{
/* Just handle the CJK languages here, as the lang
parameter is used to select a font with appropriate
glyphs in the cjk unified ideographs block. Other fonts
support for a language can be solely determined by
its character coverage. */
if (EQ (val, Qja))
{
if (!(font->ntmFontSig.fsCsb[0] & CSB_JAPANESE))
return 0;
}
else if (EQ (val, Qko))
{
if (!(font->ntmFontSig.fsCsb[0] & CSB_KOREAN))
return 0;
}
else if (EQ (val, Qzh))
{
if (!(font->ntmFontSig.fsCsb[0] & CSB_CHINESE))
return 0;
}
else
/* Any other language, we don't recognize it. Only the above
currently appear in fontset.el, so it isn't worth
creating a mapping table of codepages/scripts to languages
or opening the font to see if there are any language tags
in it that the Windows API does not expose. Fontset
spec should have a fallback, as some backends do
not recognize language at all. */
return 0;
}
else if (EQ (key, QCotf) && CONSP (val))
{
/* OTF features only supported by the uniscribe backend. */
if (EQ (backend, Quniscribe))
{
if (!uniscribe_check_otf (logfont, val))
return 0;
}
else
return 0;
}
}
}
return 1;
}
static int
w32font_coverage_ok (FONTSIGNATURE * coverage, BYTE charset)
{
DWORD subrange1 = coverage->fsUsb[1];
#define SUBRANGE1_HAN_MASK 0x08000000
#define SUBRANGE1_HANGEUL_MASK 0x01000000
#define SUBRANGE1_JAPANESE_MASK (0x00060000 | SUBRANGE1_HAN_MASK)
if (charset == GB2312_CHARSET || charset == CHINESEBIG5_CHARSET)
{
return (subrange1 & SUBRANGE1_HAN_MASK) == SUBRANGE1_HAN_MASK;
}
else if (charset == SHIFTJIS_CHARSET)
{
return (subrange1 & SUBRANGE1_JAPANESE_MASK) == SUBRANGE1_JAPANESE_MASK;
}
else if (charset == HANGEUL_CHARSET)
{
return (subrange1 & SUBRANGE1_HANGEUL_MASK) == SUBRANGE1_HANGEUL_MASK;
}
return 1;
}
#ifndef WINDOWSNT
#define _strlwr strlwr
#endif /* !WINDOWSNT */
static int
check_face_name (LOGFONT *font, char *full_name)
{
char full_iname[LF_FULLFACESIZE+1];
/* Just check for names known to cause problems, since the full name
can contain expanded abbreviations, prefixed foundry, postfixed
style, the latter of which sometimes differs from the style indicated
in the shorter name (eg Lt becomes Light or even Extra Light) */
/* Helvetica is mapped to Arial in Windows, but if a Type-1 Helvetica is
installed, we run into problems with the Uniscribe backend which tries
to avoid non-truetype fonts, and ends up mixing the Type-1 Helvetica
with Arial's characteristics, since that attempt to use TrueType works
some places, but not others. */
if (!xstrcasecmp (font->lfFaceName, "helvetica"))
{
strncpy (full_iname, full_name, LF_FULLFACESIZE);
full_iname[LF_FULLFACESIZE] = 0;
_strlwr (full_iname);
return strstr ("helvetica", full_iname) != NULL;
}
/* Same for Helv. */
if (!xstrcasecmp (font->lfFaceName, "helv"))
{
strncpy (full_iname, full_name, LF_FULLFACESIZE);
full_iname[LF_FULLFACESIZE] = 0;
_strlwr (full_iname);
return strstr ("helv", full_iname) != NULL;
}
/* Since Times is mapped to Times New Roman, a substring
match is not sufficient to filter out the bogus match. */
else if (!xstrcasecmp (font->lfFaceName, "times"))
return xstrcasecmp (full_name, "times") == 0;
return 1;
}
/* Callback function for EnumFontFamiliesEx.
* Checks if a font matches everything we are trying to check against,
* and if so, adds it to a list. Both the data we are checking against
* and the list to which the fonts are added are passed in via the
* lparam argument, in the form of a font_callback_data struct. */
static int CALLBACK ALIGN_STACK
add_font_entity_to_list (ENUMLOGFONTEX *logical_font,
NEWTEXTMETRICEX *physical_font,
DWORD font_type, LPARAM lParam)
{
struct font_callback_data *match_data
= (struct font_callback_data *) lParam;
Lisp_Object backend = match_data->opentype_only ? Quniscribe : Qgdi;
Lisp_Object entity;
int is_unicode = physical_font->ntmFontSig.fsUsb[3]
|| physical_font->ntmFontSig.fsUsb[2]
|| physical_font->ntmFontSig.fsUsb[1]
|| physical_font->ntmFontSig.fsUsb[0] & 0x3fffffff;
/* Kludgey fix for Arial Unicode MS font that claims support for
scripts it doesn't actually cover. */
if (strncmp (logical_font->elfLogFont.lfFaceName,
"Arial Unicode MS", 16) == 0)
{
/* Reset bits 4 (Phonetic), 12 (Vai), 14 (Nko), 27 (Balinese). */
physical_font->ntmFontSig.fsUsb[0] &= 0xf7ffafef;
/* Reset bits 53 (Phags-pa) and 58 (Phoenician). */
physical_font->ntmFontSig.fsUsb[1] &= 0xfbdfffff;
/* Set bit 70 (Tibetan). */
physical_font->ntmFontSig.fsUsb[2] |= 0x00000040;
}
/* Skip non matching fonts. */
/* For uniscribe backend, consider only truetype or opentype fonts
that have some Unicode coverage. */
if (match_data->opentype_only
&& ((!(physical_font->ntmTm.ntmFlags & NTMFLAGS_OPENTYPE)
&& !(font_type & TRUETYPE_FONTTYPE))
|| !is_unicode))
return 1;
/* Ensure a match. */
if (!logfonts_match (&logical_font->elfLogFont, &match_data->pattern)
|| !(font_matches_spec (font_type, physical_font,
match_data->orig_font_spec, backend,
&logical_font->elfLogFont)
|| (!NILP (match_data->known_fonts)
&& memq_no_quit
(intern_font_name (logical_font->elfLogFont.lfFaceName),
match_data->known_fonts)))
|| !w32font_coverage_ok (&physical_font->ntmFontSig,
match_data->pattern.lfCharSet))
return 1;
/* Avoid substitutions involving raster fonts (eg Helv -> MS Sans Serif)
We limit this to raster fonts, because the test can catch some
genuine fonts (eg the full name of DejaVu Sans Mono Light is actually
DejaVu Sans Mono ExtraLight). Helvetica -> Arial substitution will
therefore get through this test. Since full names can be prefixed
by a foundry, we accept raster fonts if the font name is found
anywhere within the full name. */
if ((logical_font->elfLogFont.lfOutPrecision == OUT_STRING_PRECIS
&& !strstr ((char *)logical_font->elfFullName,
logical_font->elfLogFont.lfFaceName))
/* Check for well known substitutions that mess things up in the
presence of Type-1 fonts of the same name. */
|| (!check_face_name (&logical_font->elfLogFont,
(char *)logical_font->elfFullName)))
return 1;
/* Make a font entity for the font. */
entity = w32_enumfont_pattern_entity (match_data->frame, logical_font,
physical_font, font_type,
&match_data->pattern,
backend);
if (!NILP (entity))
{
Lisp_Object spec_charset = AREF (match_data->orig_font_spec,
FONT_REGISTRY_INDEX);
/* iso10646-1 fonts must contain Unicode mapping tables. */
if (EQ (spec_charset, Qiso10646_1))
{
if (!is_unicode)
return 1;
}
/* unicode-bmp fonts must contain characters from the BMP. */
else if (EQ (spec_charset, Qunicode_bmp))
{
if (!physical_font->ntmFontSig.fsUsb[3]
&& !(physical_font->ntmFontSig.fsUsb[2] & 0xFFFFFF9E)
&& !(physical_font->ntmFontSig.fsUsb[1] & 0xE81FFFFF)
&& !(physical_font->ntmFontSig.fsUsb[0] & 0x007F001F))
return 1;
}
/* unicode-sip fonts must contain characters in Unicode plane 2.
so look for bit 57 (surrogates) in the Unicode subranges, plus
the bits for CJK ranges that include those characters. */
else if (EQ (spec_charset, Qunicode_sip))
{
if (!(physical_font->ntmFontSig.fsUsb[1] & 0x02000000)
|| !(physical_font->ntmFontSig.fsUsb[1] & 0x28000000))
return 1;
}
/* This font matches. */
/* If registry was specified, ensure it is reported as the same. */
if (!NILP (spec_charset))
{
/* Avoid using non-Japanese fonts for Japanese, even if they
claim they are capable, due to known breakage in Vista
and Windows 7 fonts (bug#6029). */
if (logical_font->elfLogFont.lfCharSet == SHIFTJIS_CHARSET
&& !(physical_font->ntmFontSig.fsCsb[0] & CSB_JAPANESE))
return 1;
else
ASET (entity, FONT_REGISTRY_INDEX, spec_charset);
}
/* Otherwise if using the uniscribe backend, report ANSI and DEFAULT
fonts as Unicode and skip other charsets. */
else if (match_data->opentype_only)
{
if (logical_font->elfLogFont.lfCharSet == ANSI_CHARSET
|| logical_font->elfLogFont.lfCharSet == DEFAULT_CHARSET)
ASET (entity, FONT_REGISTRY_INDEX, Qiso10646_1);
else
return 1;
}
/* Add this font to the list. */
match_data->list = Fcons (entity, match_data->list);
}
return 1;
}
/* Callback function for EnumFontFamiliesEx.
* Terminates the search once we have a match. */
static int CALLBACK ALIGN_STACK
add_one_font_entity_to_list (ENUMLOGFONTEX *logical_font,
NEWTEXTMETRICEX *physical_font,
DWORD font_type, LPARAM lParam)
{
struct font_callback_data *match_data
= (struct font_callback_data *) lParam;
add_font_entity_to_list (logical_font, physical_font, font_type, lParam);
/* If we have a font in the list, terminate the search. */
return NILP (match_data->list);
}
/* Old function to convert from x to w32 charset, from w32fns.c. */
static LONG
x_to_w32_charset (char * lpcs)
{
Lisp_Object this_entry, w32_charset;
char *charset;
int len = strlen (lpcs);
/* Support "*-#nnn" format for unknown charsets. */
if (strncmp (lpcs, "*-#", 3) == 0)
return atoi (lpcs + 3);
/* All Windows fonts qualify as Unicode. */
if (!strncmp (lpcs, "iso10646", 8))
return DEFAULT_CHARSET;
/* Handle wildcards by ignoring them; eg. treat "big5*-*" as "big5". */
charset = alloca (len + 1);
strcpy (charset, lpcs);
lpcs = strchr (charset, '*');
if (lpcs)
*lpcs = '\0';
/* Look through w32-charset-info-alist for the character set.
Format of each entry is
(CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE)).
*/
this_entry = Fassoc (build_string (charset), Vw32_charset_info_alist, Qnil);
if (NILP (this_entry))
{
/* At startup, we want iso8859-1 fonts to come up properly. */
if (xstrcasecmp (charset, "iso8859-1") == 0)
return ANSI_CHARSET;
else
return DEFAULT_CHARSET;
}
w32_charset = Fcar (Fcdr (this_entry));
/* Translate Lisp symbol to number. */
if (EQ (w32_charset, Qw32_charset_ansi))
return ANSI_CHARSET;
if (EQ (w32_charset, Qw32_charset_symbol))
return SYMBOL_CHARSET;
if (EQ (w32_charset, Qw32_charset_shiftjis))
return SHIFTJIS_CHARSET;
if (EQ (w32_charset, Qw32_charset_hangeul))
return HANGEUL_CHARSET;
if (EQ (w32_charset, Qw32_charset_chinesebig5))
return CHINESEBIG5_CHARSET;
if (EQ (w32_charset, Qw32_charset_gb2312))
return GB2312_CHARSET;
if (EQ (w32_charset, Qw32_charset_oem))
return OEM_CHARSET;
if (EQ (w32_charset, Qw32_charset_johab))
return JOHAB_CHARSET;
if (EQ (w32_charset, Qw32_charset_easteurope))
return EASTEUROPE_CHARSET;
if (EQ (w32_charset, Qw32_charset_turkish))
return TURKISH_CHARSET;
if (EQ (w32_charset, Qw32_charset_baltic))
return BALTIC_CHARSET;
if (EQ (w32_charset, Qw32_charset_russian))
return RUSSIAN_CHARSET;
if (EQ (w32_charset, Qw32_charset_arabic))
return ARABIC_CHARSET;
if (EQ (w32_charset, Qw32_charset_greek))
return GREEK_CHARSET;
if (EQ (w32_charset, Qw32_charset_hebrew))
return HEBREW_CHARSET;
if (EQ (w32_charset, Qw32_charset_vietnamese))
return VIETNAMESE_CHARSET;
if (EQ (w32_charset, Qw32_charset_thai))
return THAI_CHARSET;
if (EQ (w32_charset, Qw32_charset_mac))
return MAC_CHARSET;
return DEFAULT_CHARSET;
}
/* Convert a Lisp font registry (symbol) to a windows charset. */
static LONG
registry_to_w32_charset (Lisp_Object charset)
{
if (EQ (charset, Qiso10646_1) || EQ (charset, Qunicode_bmp)
|| EQ (charset, Qunicode_sip))
return DEFAULT_CHARSET; /* UNICODE_CHARSET not defined in MingW32 */
else if (EQ (charset, Qiso8859_1))
return ANSI_CHARSET;
else if (SYMBOLP (charset))
return x_to_w32_charset (SSDATA (SYMBOL_NAME (charset)));
else
return DEFAULT_CHARSET;
}
/* Old function to convert from w32 to x charset, from w32fns.c. */
static char *
w32_to_x_charset (int fncharset, char *matching)
{
static char buf[32];
Lisp_Object charset_type;
int match_len = 0;
if (matching)
{
/* If fully specified, accept it as it is. Otherwise use a
substring match. */
char *wildcard = strchr (matching, '*');
if (wildcard)
*wildcard = '\0';
else if (strchr (matching, '-'))
return matching;
match_len = strlen (matching);
}
switch (fncharset)
{
case ANSI_CHARSET:
/* Handle startup case of w32-charset-info-alist not
being set up yet. */
if (NILP (Vw32_charset_info_alist))
return (char *)"iso8859-1";
charset_type = Qw32_charset_ansi;
break;
case DEFAULT_CHARSET:
charset_type = Qw32_charset_default;
break;
case SYMBOL_CHARSET:
charset_type = Qw32_charset_symbol;
break;
case SHIFTJIS_CHARSET:
charset_type = Qw32_charset_shiftjis;
break;
case HANGEUL_CHARSET:
charset_type = Qw32_charset_hangeul;
break;
case GB2312_CHARSET:
charset_type = Qw32_charset_gb2312;
break;
case CHINESEBIG5_CHARSET:
charset_type = Qw32_charset_chinesebig5;
break;
case OEM_CHARSET:
charset_type = Qw32_charset_oem;
break;
case EASTEUROPE_CHARSET:
charset_type = Qw32_charset_easteurope;
break;
case TURKISH_CHARSET:
charset_type = Qw32_charset_turkish;
break;
case BALTIC_CHARSET:
charset_type = Qw32_charset_baltic;
break;
case RUSSIAN_CHARSET:
charset_type = Qw32_charset_russian;
break;
case ARABIC_CHARSET:
charset_type = Qw32_charset_arabic;
break;
case GREEK_CHARSET:
charset_type = Qw32_charset_greek;
break;
case HEBREW_CHARSET:
charset_type = Qw32_charset_hebrew;
break;
case VIETNAMESE_CHARSET:
charset_type = Qw32_charset_vietnamese;
break;
case THAI_CHARSET:
charset_type = Qw32_charset_thai;
break;
case MAC_CHARSET:
charset_type = Qw32_charset_mac;
break;
case JOHAB_CHARSET:
charset_type = Qw32_charset_johab;
break;
default:
/* Encode numerical value of unknown charset. */
sprintf (buf, "*-#%d", fncharset);
return buf;
}
{
Lisp_Object rest;
char * best_match = NULL;
int matching_found = 0;
/* Look through w32-charset-info-alist for the character set.
Prefer ISO codepages, and prefer lower numbers in the ISO
range. Only return charsets for codepages which are installed.
Format of each entry is
(CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE)).
*/
for (rest = Vw32_charset_info_alist; CONSP (rest); rest = XCDR (rest))
{
char * x_charset;
Lisp_Object w32_charset;
Lisp_Object codepage;
Lisp_Object this_entry = XCAR (rest);
/* Skip invalid entries in alist. */
if (!CONSP (this_entry) || !STRINGP (XCAR (this_entry))
|| !CONSP (XCDR (this_entry))
|| !SYMBOLP (XCAR (XCDR (this_entry))))
continue;
x_charset = SSDATA (XCAR (this_entry));
w32_charset = XCAR (XCDR (this_entry));
codepage = XCDR (XCDR (this_entry));
/* Look for Same charset and a valid codepage (or non-int
which means ignore). */
if (EQ (w32_charset, charset_type)
&& (!FIXNUMP (codepage) || XFIXNUM (codepage) == CP_DEFAULT
|| IsValidCodePage (XFIXNUM (codepage))))
{
/* If we don't have a match already, then this is the
best. */
if (!best_match)
{
best_match = x_charset;
if (matching && !strnicmp (x_charset, matching, match_len))
matching_found = 1;
}
/* If we already found a match for MATCHING, then
only consider other matches. */
else if (matching_found
&& strnicmp (x_charset, matching, match_len))
continue;
/* If this matches what we want, and the best so far doesn't,
then this is better. */
else if (!matching_found && matching
&& !strnicmp (x_charset, matching, match_len))
{
best_match = x_charset;
matching_found = 1;
}
/* If this is fully specified, and the best so far isn't,
then this is better. */
else if ((!strchr (best_match, '-') && strchr (x_charset, '-'))
/* If this is an ISO codepage, and the best so far isn't,
then this is better, but only if it fully specifies the
encoding. */
|| (strnicmp (best_match, "iso", 3) != 0
&& strnicmp (x_charset, "iso", 3) == 0
&& strchr (x_charset, '-')))
best_match = x_charset;
/* If both are ISO8859 codepages, choose the one with the
lowest number in the encoding field. */
else if (strnicmp (best_match, "iso8859-", 8) == 0
&& strnicmp (x_charset, "iso8859-", 8) == 0)
{
int best_enc = atoi (best_match + 8);
int this_enc = atoi (x_charset + 8);
if (this_enc > 0 && this_enc < best_enc)
best_match = x_charset;
}
}
}
/* If no match, encode the numeric value. */
if (!best_match)
{
sprintf (buf, "*-#%d", fncharset);
return buf;
}
strncpy (buf, best_match, 31);
/* If the charset is not fully specified, put -0 on the end. */
if (!strchr (best_match, '-'))
{
int pos = strlen (best_match);
/* Charset specifiers shouldn't be very long. If it is a made
up one, truncating it should not do any harm since it isn't
recognized anyway. */
if (pos > 29)
pos = 29;
strcpy (buf + pos, "-0");
}
buf[31] = '\0';
return buf;
}
}
static Lisp_Object
w32_registry (LONG w32_charset, DWORD font_type)
{
char *charset;
/* If charset is defaulted, charset is Unicode or unknown, depending on
font type. */
if (w32_charset == DEFAULT_CHARSET)
return font_type == TRUETYPE_FONTTYPE ? Qiso10646_1 : Qunknown;
charset = w32_to_x_charset (w32_charset, NULL);
return font_intern_prop (charset, strlen (charset), 1);
}
static int
w32_decode_weight (int fnweight)
{
if (fnweight >= FW_HEAVY) return 210;
if (fnweight >= FW_EXTRABOLD) return 205;
if (fnweight >= FW_BOLD) return 200;
if (fnweight >= FW_SEMIBOLD) return 180;
if (fnweight >= FW_MEDIUM) return 100;
if (fnweight >= FW_NORMAL) return 80;
if (fnweight >= FW_LIGHT) return 50;
if (fnweight >= FW_EXTRALIGHT) return 40;
if (fnweight >= FW_THIN) return 20;
return 0;
}
static int
w32_encode_weight (int n)
{
if (n >= 210) return FW_HEAVY;
if (n >= 205) return FW_EXTRABOLD;
if (n >= 200) return FW_BOLD;
if (n >= 180) return FW_SEMIBOLD;
if (n >= 100) return FW_MEDIUM;
if (n >= 80) return FW_NORMAL;
if (n >= 50) return FW_LIGHT;
if (n >= 40) return FW_EXTRALIGHT;
if (n >= 20) return FW_THIN;
return 0;
}
/* Convert a Windows font weight into one of the weights supported
by fontconfig (see font.c:font_parse_fcname). */
static Lisp_Object
w32_to_fc_weight (int n)
{
if (n >= FW_HEAVY) return Qblack;
if (n >= FW_EXTRABOLD) return Qextra_bold;
if (n >= FW_BOLD) return Qbold;
if (n >= FW_SEMIBOLD) return Qsemi_bold;
if (n >= FW_MEDIUM) return Qmedium;
if (n >= FW_NORMAL) return Qnormal;
if (n >= FW_LIGHT) return Qlight;
if (n >= FW_EXTRALIGHT) return Qextra_light;
return Qthin;
}
/* Fill in all the available details of LOGFONT from FONT_SPEC. */
static void
fill_in_logfont (struct frame *f, LOGFONT *logfont, Lisp_Object font_spec)
{
Lisp_Object tmp, extra;
int dpi = FRAME_RES (f);
tmp = AREF (font_spec, FONT_DPI_INDEX);
if (FIXNUMP (tmp))
dpi = XFIXNUM (tmp);
else if (FLOATP (tmp))
dpi = (int) (XFLOAT_DATA (tmp) + 0.5);
/* Height */
tmp = AREF (font_spec, FONT_SIZE_INDEX);
if (FIXNUMP (tmp))
logfont->lfHeight = -1 * XFIXNUM (tmp);
else if (FLOATP (tmp))
logfont->lfHeight = (int) (-1.0 * dpi * XFLOAT_DATA (tmp) / 72.27 + 0.5);
/* Escapement */
/* Orientation */
/* Weight */
tmp = AREF (font_spec, FONT_WEIGHT_INDEX);
if (FIXNUMP (tmp))
logfont->lfWeight = w32_encode_weight (FONT_WEIGHT_NUMERIC (font_spec));
/* Italic */
tmp = AREF (font_spec, FONT_SLANT_INDEX);
if (FIXNUMP (tmp))
{
int slant = FONT_SLANT_NUMERIC (font_spec);
logfont->lfItalic = slant > 150 ? 1 : 0;
}
/* Underline */
/* Strikeout */
/* Charset */
tmp = AREF (font_spec, FONT_REGISTRY_INDEX);
if (! NILP (tmp))
logfont->lfCharSet = registry_to_w32_charset (tmp);
else
logfont->lfCharSet = DEFAULT_CHARSET;
/* Out Precision */
/* Clip Precision */
/* Quality */
logfont->lfQuality = DEFAULT_QUALITY;
/* Generic Family and Face Name */
logfont->lfPitchAndFamily = FF_DONTCARE | DEFAULT_PITCH;
tmp = AREF (font_spec, FONT_FAMILY_INDEX);
if (! NILP (tmp))
{
logfont->lfPitchAndFamily = w32_generic_family (tmp) | DEFAULT_PITCH;
if ((logfont->lfPitchAndFamily & 0xF0) != FF_DONTCARE)
; /* Font name was generic, don't fill in font name. */
/* Font families are interned, but allow for strings also in case of
user input. */
else if (SYMBOLP (tmp))
{
strncpy (logfont->lfFaceName,
SSDATA (ENCODE_SYSTEM (SYMBOL_NAME (tmp))), LF_FACESIZE);
logfont->lfFaceName[LF_FACESIZE-1] = '\0';
}
}
tmp = AREF (font_spec, FONT_ADSTYLE_INDEX);
if (!NILP (tmp))
{
/* Override generic family. */
BYTE family = w32_generic_family (tmp);
if (family != FF_DONTCARE)
logfont->lfPitchAndFamily = family | DEFAULT_PITCH;
}
/* Set pitch based on the spacing property. */
tmp = AREF (font_spec, FONT_SPACING_INDEX);
if (FIXNUMP (tmp))
{
int spacing = XFIXNUM (tmp);
if (spacing < FONT_SPACING_MONO)
logfont->lfPitchAndFamily
= (logfont->lfPitchAndFamily & 0xF0) | VARIABLE_PITCH;
else
logfont->lfPitchAndFamily
= (logfont->lfPitchAndFamily & 0xF0) | FIXED_PITCH;
}
/* Process EXTRA info. */
for (extra = AREF (font_spec, FONT_EXTRA_INDEX);
CONSP (extra); extra = XCDR (extra))
{
tmp = XCAR (extra);
if (CONSP (tmp))
{
Lisp_Object key, val;
key = XCAR (tmp), val = XCDR (tmp);
/* Only use QCscript if charset is not provided, or is Unicode
and a single script is specified. This is rather crude,
and is only used to narrow down the fonts returned where
there is a definite match. Some scripts, such as latin, han,
cjk-misc match multiple lfCharSet values, so we can't pre-filter
them. */
if (EQ (key, QCscript)
&& logfont->lfCharSet == DEFAULT_CHARSET
&& SYMBOLP (val))
{
if (EQ (val, Qgreek))
logfont->lfCharSet = GREEK_CHARSET;
else if (EQ (val, Qhangul))
logfont->lfCharSet = HANGUL_CHARSET;
else if (EQ (val, Qkana) || EQ (val, Qkanbun))
logfont->lfCharSet = SHIFTJIS_CHARSET;
else if (EQ (val, Qbopomofo))
logfont->lfCharSet = CHINESEBIG5_CHARSET;
/* GB 18030 supports tibetan, yi, mongolian,
fonts that support it should show up if we ask for
GB2312 fonts. */
else if (EQ (val, Qtibetan) || EQ (val, Qyi)
|| EQ (val, Qmongolian))
logfont->lfCharSet = GB2312_CHARSET;
else if (EQ (val, Qhebrew))
logfont->lfCharSet = HEBREW_CHARSET;
else if (EQ (val, Qarabic))
logfont->lfCharSet = ARABIC_CHARSET;
else if (EQ (val, Qthai))
logfont->lfCharSet = THAI_CHARSET;
}
else if (EQ (key, QCantialias) && SYMBOLP (val))
{
logfont->lfQuality = w32_antialias_type (val);
}
}
}
}
static void
list_all_matching_fonts (struct font_callback_data *match_data)
{
HDC dc;
Lisp_Object families = w32font_list_family (XFRAME (match_data->frame));
struct frame *f = XFRAME (match_data->frame);
/* Prevent quitting while EnumFontFamiliesEx runs and conses the
list it will return. That's because get_frame_dc acquires the
critical section, so we cannot quit before we release it in
release_frame_dc. */
Lisp_Object prev_quit = Vinhibit_quit;
Vinhibit_quit = Qt;
dc = get_frame_dc (f);
while (!NILP (families))
{
/* Only fonts from the current locale are given localized names
on Windows, so we can keep backwards compatibility with
Windows 9x/ME by using non-Unicode font enumeration without
sacrificing internationalization here. */
char *name;
Lisp_Object family = CAR (families);
families = CDR (families);
if (NILP (family))
continue;
else if (SYMBOLP (family))
name = SSDATA (ENCODE_SYSTEM (SYMBOL_NAME (family)));
else
continue;
strncpy (match_data->pattern.lfFaceName, name, LF_FACESIZE);
match_data->pattern.lfFaceName[LF_FACESIZE - 1] = '\0';
EnumFontFamiliesEx (dc, &match_data->pattern,
(FONTENUMPROC) add_font_entity_to_list,
(LPARAM) match_data, 0);
}
release_frame_dc (f, dc);
Vinhibit_quit = prev_quit;
}
static Lisp_Object
lispy_antialias_type (BYTE type)
{
Lisp_Object lispy;
switch (type)
{
case NONANTIALIASED_QUALITY:
lispy = Qnone;
break;
case ANTIALIASED_QUALITY:
lispy = Qstandard;
break;
case CLEARTYPE_QUALITY:
lispy = Qsubpixel;
break;
case CLEARTYPE_NATURAL_QUALITY:
lispy = Qnatural;
break;
default:
lispy = Qnil;
break;
}
return lispy;
}
/* Convert antialiasing symbols to lfQuality */
static BYTE
w32_antialias_type (Lisp_Object type)
{
if (EQ (type, Qnone))
return NONANTIALIASED_QUALITY;
else if (EQ (type, Qstandard))
return ANTIALIASED_QUALITY;
else if (EQ (type, Qsubpixel))
return CLEARTYPE_QUALITY;
else if (EQ (type, Qnatural))
return CLEARTYPE_NATURAL_QUALITY;
else
return DEFAULT_QUALITY;
}
/* Return a list of all the scripts that the font supports. */
static Lisp_Object
font_supported_scripts (FONTSIGNATURE * sig)
{
DWORD * subranges = sig->fsUsb;
Lisp_Object supported = Qnil;
/* Match a single subrange. SYM is set if bit N is set in subranges. */
#define SUBRANGE(n,sym) \
if (subranges[(n) / 32] & (1U << ((n) % 32))) \
supported = Fcons (sym, supported)
/* Match multiple subranges. SYM is set if any MASK bit is set in
subranges[0 - 3]. */
#define MASK_ANY(mask0,mask1,mask2,mask3,sym) \
if ((subranges[0] & (mask0)) || (subranges[1] & (mask1)) \
|| (subranges[2] & (mask2)) || (subranges[3] & (mask3))) \
supported = Fcons (sym, supported)
/* 0: ASCII (a.k.a. "Basic Latin"),
1: Latin-1 supplement, 2: Latin Extended A, 3: Latin Extended B,
29: Latin Extended Additional. */
/* Most fonts that support Latin will have good coverage of the
Extended blocks, so in practice marking them below is not really
needed, or useful: if a font claims support for, say, Latin
Extended-B, but does not contain glyphs for some of the
characters in the range, the user will have to augment her
fontset to display those few characters. But we mark these
subranges here anyway, for the marginal use cases where they
might make a difference. */
MASK_ANY (0x2000000F, 0, 0, 0, Qlatin);
SUBRANGE (4, Qphonetic);
/* 5: Spacing and tone modifiers, 6: Combining Diacritical Marks. */
/* 7: Greek and Coptic, 30: Greek Extended. */
MASK_ANY (0x40000080, 0, 0, 0, Qgreek);
SUBRANGE (8, Qcoptic);
SUBRANGE (9, Qcyrillic);
SUBRANGE (10, Qarmenian);
SUBRANGE (11, Qhebrew);
/* Bit 12 is rather useless if the user has Hebrew fonts installed,
because apparently at some point in the past bit 12 was "Hebrew
Extended", and many Hebrew fonts still have this bit set. The
only workaround is to customize fontsets to use fonts like Ebrima
or Quivira. */
SUBRANGE (12, Qvai);
SUBRANGE (13, Qarabic);
SUBRANGE (14, Qnko);
SUBRANGE (15, Qdevanagari);
SUBRANGE (16, Qbengali);
SUBRANGE (17, Qgurmukhi);
SUBRANGE (18, Qgujarati);
SUBRANGE (19, Qoriya); /* a.k.a. "Odia" */
SUBRANGE (20, Qtamil);
SUBRANGE (21, Qtelugu);
SUBRANGE (22, Qkannada);
SUBRANGE (23, Qmalayalam);
SUBRANGE (24, Qthai);
SUBRANGE (25, Qlao);
SUBRANGE (26, Qgeorgian);
SUBRANGE (27, Qbalinese);
/* 28: Hangul Jamo -- covered by the default fontset. */
/* 29: Latin Extended, 30: Greek Extended -- covered above. */
/* 31: Supplemental Punctuation -- most probably be masked by
Courier New, so fontset customization is needed. */
/* 31-47: Symbols (defined below). */
SUBRANGE (48, Qcjk_misc);
/* Match either 49: katakana or 50: hiragana for kana. */
MASK_ANY (0, 0x00060000, 0, 0, Qkana);
SUBRANGE (51, Qbopomofo);
/* 52: Compatibility Jamo */
SUBRANGE (53, Qphags_pa);
/* 54: Enclosed CJK letters and months, 55: CJK Compatibility. */
SUBRANGE (56, Qhangul);
/* 57: Surrogates. */
SUBRANGE (58, Qphoenician);
SUBRANGE (59, Qhan); /* There are others, but this is the main one. */
SUBRANGE (59, Qideographic_description); /* Windows lumps this in. */
SUBRANGE (59, Qkanbun); /* And this. */
/* These are covered well either by the default Courier New or by
CJK fonts that are set up specially in the default fontset. So
marking them here wouldn't be useful. */
/* 60: Private use, 61: CJK strokes and compatibility. */
/* 62: Alphabetic Presentation, 63: Arabic Presentation A. */
/* 64: Combining half marks, 65: Vertical and CJK compatibility. */
/* 66: Small forms, 67: Arabic Presentation B, 68: Half and Full width. */
/* 69: Specials. */
SUBRANGE (70, Qtibetan);
SUBRANGE (71, Qsyriac);
SUBRANGE (72, Qthaana);
SUBRANGE (73, Qsinhala);
SUBRANGE (74, Qburmese); /* a.k.a. "Myanmar" */
SUBRANGE (75, Qethiopic);
SUBRANGE (76, Qcherokee);
SUBRANGE (77, Qcanadian_aboriginal);
SUBRANGE (78, Qogham);
SUBRANGE (79, Qrunic);
SUBRANGE (80, Qkhmer);
SUBRANGE (81, Qmongolian);
SUBRANGE (82, Qbraille);
SUBRANGE (83, Qyi);
SUBRANGE (84, Qbuhid);
SUBRANGE (84, Qhanunoo);
SUBRANGE (84, Qtagalog);
SUBRANGE (84, Qtagbanwa);
SUBRANGE (85, Qold_italic);
SUBRANGE (86, Qgothic);
SUBRANGE (87, Qdeseret);
SUBRANGE (88, Qbyzantine_musical_symbol);
SUBRANGE (88, Qmusical_symbol); /* Windows doesn't distinguish these. */
SUBRANGE (89, Qmathematical_bold); /* See fontset.el:setup-default-fontset. */
SUBRANGE (89, Qmathematical_italic);
SUBRANGE (89, Qmathematical_bold_italic);
SUBRANGE (89, Qmathematical_script);
SUBRANGE (89, Qmathematical_bold_script);
SUBRANGE (89, Qmathematical_fraktur);
SUBRANGE (89, Qmathematical_double_struck);
SUBRANGE (89, Qmathematical_bold_fraktur);
SUBRANGE (89, Qmathematical_sans_serif);
SUBRANGE (89, Qmathematical_sans_serif_bold);
SUBRANGE (89, Qmathematical_sans_serif_italic);
SUBRANGE (89, Qmathematical_sans_serif_bold_italic);
SUBRANGE (89, Qmathematical_monospace);
/* 90: Private use, 91: Variation selectors, 92: Tags. */
SUBRANGE (93, Qlimbu);
SUBRANGE (94, Qtai_le);
SUBRANGE (95, Qtai_le);
SUBRANGE (96, Qbuginese);
SUBRANGE (97, Qglagolitic);
SUBRANGE (98, Qtifinagh);
/* 99: Yijing Hexagrams. */
SUBRANGE (99, Qhan);
SUBRANGE (100, Qsyloti_nagri);
SUBRANGE (101, Qlinear_b);
SUBRANGE (101, Qaegean_number);
SUBRANGE (102, Qancient_greek_number);
SUBRANGE (103, Qugaritic);
SUBRANGE (104, Qold_persian);
SUBRANGE (105, Qshavian);
SUBRANGE (106, Qosmanya);
SUBRANGE (107, Qcypriot);
SUBRANGE (108, Qkharoshthi);
SUBRANGE (109, Qtai_xuan_jing_symbol);
SUBRANGE (110, Qcuneiform);
SUBRANGE (111, Qcounting_rod_numeral);
SUBRANGE (112, Qsundanese);
SUBRANGE (113, Qlepcha);
SUBRANGE (114, Qol_chiki);
SUBRANGE (115, Qsaurashtra);
SUBRANGE (116, Qkayah_li);
SUBRANGE (117, Qrejang);
SUBRANGE (118, Qcham);
SUBRANGE (119, Qancient_symbol);
SUBRANGE (120, Qphaistos_disc);
SUBRANGE (121, Qlycian);
SUBRANGE (121, Qcarian);
SUBRANGE (121, Qlydian);
SUBRANGE (122, Qdomino_tile);
SUBRANGE (122, Qmahjong_tile);
/* 123-127: Reserved. */
/* There isn't really a main symbol range, so include symbol if any
relevant range is set. */
MASK_ANY (0x80000000, 0x0000FFFF, 0, 0, Qsymbol);
/* Missing:
Tai Viet
Old Permic
Palmyrene
Nabatean
Manichean
Hanifi Rohingya
Sogdian
Elymaic
Mahajani
Khojki
Khudawadi
Grantha
Newa
Tirhuta
Siddham
Modi
Takri
Dogra
Warang Citi
Nandinagari
Zanabazar Square
Soyombo
Pau Cin Hau
Bhaiksuki
Marchen
Masaram Gondi
Makasar
Egyptian
Mro
Bassa-Vah
Pahawh Hmong
Medefaidrin
Tangut
Tangut Components
Nushu
Duployan Shorthand
Ancient Greek Musical Notation
Nyiakeng Puachue Hmong
Wancho
Mende Kikakui
Adlam
Indic Siyaq Number
Ottoman Siyaq Number. */
#undef SUBRANGE
#undef MASK_ANY
return supported;
}
/* Generate a full name for a Windows font.
The full name is in fcname format, with weight, slant and antialiasing
specified if they are not "normal". */
static int
w32font_full_name (LOGFONT * font, Lisp_Object font_obj,
int pixel_size, char *name, int nbytes)
{
int len, height, outline;
char *p;
Lisp_Object antialiasing, weight = Qnil;
len = strlen (font->lfFaceName);
outline = EQ (AREF (font_obj, FONT_FOUNDRY_INDEX), Qoutline);
/* Represent size of scalable fonts by point size. But use pixelsize for
raster fonts to indicate that they are exactly that size. */
if (outline)
len += 11; /* -SIZE */
else
len += 21;
if (font->lfItalic)
len += 7; /* :italic */
if (font->lfWeight && font->lfWeight != FW_NORMAL)
{
weight = w32_to_fc_weight (font->lfWeight);
len += 1 + SBYTES (SYMBOL_NAME (weight)); /* :WEIGHT */
}
antialiasing = lispy_antialias_type (font->lfQuality);
if (! NILP (antialiasing))
len += 11 + SBYTES (SYMBOL_NAME (antialiasing)); /* :antialias=NAME */
/* Check that the buffer is big enough */
if (len > nbytes)
return -1;
p = name;
p += sprintf (p, "%s", font->lfFaceName);
height = font->lfHeight ? eabs (font->lfHeight) : pixel_size;
if (height > 0)
{
if (outline)
{
double pointsize = height * 72.0 / one_w32_display_info.resy;
/* Round to nearest half point. floor is used, since round is not
supported in MS library. */
pointsize = floor (pointsize * 2 + 0.5) / 2;
p += sprintf (p, "-%1.1f", pointsize);
}
else
p += sprintf (p, ":pixelsize=%d", height);
}
if (SYMBOLP (weight) && ! NILP (weight))
p += sprintf (p, ":%s", SDATA (SYMBOL_NAME (weight)));
if (font->lfItalic)
p += sprintf (p, ":italic");
if (SYMBOLP (antialiasing) && ! NILP (antialiasing))
p += sprintf (p, ":antialias=%s", SDATA (SYMBOL_NAME (antialiasing)));
return (p - name);
}
/* Convert a logfont and point size into a fontconfig style font name.
POINTSIZE is in tenths of points.
If SIZE indicates the size of buffer FCNAME, into which the font name
is written. If the buffer is not large enough to contain the name,
the function returns -1, otherwise it returns the number of bytes
written to FCNAME. */
static int
logfont_to_fcname (LOGFONT* font, int pointsize, char *fcname, int size)
{
int len, height;
char *p = fcname;
Lisp_Object weight = Qnil;
len = strlen (font->lfFaceName) + 2;
height = pointsize / 10;
while (height /= 10)
len++;
if (pointsize % 10)
len += 2;
if (font->lfItalic)
len += 7; /* :italic */
if (font->lfWeight && font->lfWeight != FW_NORMAL)
{
weight = w32_to_fc_weight (font->lfWeight);
len += SBYTES (SYMBOL_NAME (weight)) + 1;
}
if (len > size)
return -1;
p += sprintf (p, "%s-%d", font->lfFaceName, pointsize / 10);
if (pointsize % 10)
p += sprintf (p, ".%d", pointsize % 10);
if (SYMBOLP (weight) && !NILP (weight))
p += sprintf (p, ":%s", SDATA (SYMBOL_NAME (weight)));
if (font->lfItalic)
p += sprintf (p, ":italic");
return (p - fcname);
}
static void
compute_metrics (HDC dc, struct w32font_info *w32_font, unsigned int code,
struct w32_metric_cache *metrics)
{
GLYPHMETRICS gm;
MAT2 transform;
unsigned int options = GGO_METRICS;
INT width;
if (w32_font->glyph_idx)
options |= GGO_GLYPH_INDEX;
memset (&transform, 0, sizeof (transform));
transform.eM11.value = 1;
transform.eM22.value = 1;
if (get_glyph_outline_w (dc, code, options, &gm, 0, NULL, &transform)
!= GDI_ERROR)
{
metrics->lbearing = gm.gmptGlyphOrigin.x;
metrics->rbearing = gm.gmptGlyphOrigin.x + gm.gmBlackBoxX;
metrics->width = gm.gmCellIncX;
metrics->ascent = gm.gmptGlyphOrigin.y;
metrics->descent = gm.gmBlackBoxY - gm.gmptGlyphOrigin.y;
metrics->status = W32METRIC_SUCCESS;
}
else if (get_char_width_32_w (dc, code, code, &width) != 0)
{
metrics->lbearing = 0;
metrics->rbearing = width;
metrics->width = width;
metrics->ascent = w32_font->font.ascent;
metrics->descent = w32_font->font.descent;
metrics->status = W32METRIC_SUCCESS;
}
else
metrics->status = W32METRIC_FAIL;
}
DEFUN ("x-select-font", Fx_select_font, Sx_select_font, 0, 2, 0,
doc: /* Read a font name using a W32 font selection dialog.
Return fontconfig style font string corresponding to the selection.
If FRAME is omitted or nil, it defaults to the selected frame.
If EXCLUDE-PROPORTIONAL is non-nil, exclude proportional fonts
in the font selection dialog. */)
(Lisp_Object frame, Lisp_Object exclude_proportional)
{
struct frame *f = decode_window_system_frame (frame);
CHOOSEFONT cf;
LOGFONT lf;
TEXTMETRIC tm;
HDC hdc;
HANDLE oldobj;
char buf[100];
memset (&cf, 0, sizeof (cf));
memset (&lf, 0, sizeof (lf));
cf.lStructSize = sizeof (cf);
cf.hwndOwner = FRAME_W32_WINDOW (f);
cf.Flags = CF_FORCEFONTEXIST | CF_SCREENFONTS | CF_NOVERTFONTS;
/* If exclude_proportional is non-nil, limit the selection to
monospaced fonts. */
if (!NILP (exclude_proportional))
cf.Flags |= CF_FIXEDPITCHONLY;
cf.lpLogFont = &lf;
/* Initialize as much of the font details as we can from the current
default font. */
hdc = GetDC (FRAME_W32_WINDOW (f));
oldobj = SelectObject (hdc, FONT_HANDLE (FRAME_FONT (f)));
GetTextFace (hdc, LF_FACESIZE, lf.lfFaceName);
if (GetTextMetrics (hdc, &tm))
{
lf.lfHeight = tm.tmInternalLeading - tm.tmHeight;
lf.lfWeight = tm.tmWeight;
lf.lfItalic = tm.tmItalic;
lf.lfUnderline = tm.tmUnderlined;
lf.lfStrikeOut = tm.tmStruckOut;
lf.lfCharSet = tm.tmCharSet;
cf.Flags |= CF_INITTOLOGFONTSTRUCT;
}
SelectObject (hdc, oldobj);
ReleaseDC (FRAME_W32_WINDOW (f), hdc);
{
specpdl_ref count = SPECPDL_INDEX ();
Lisp_Object value = Qnil;
w32_dialog_in_progress (Qt);
specbind (Qinhibit_redisplay, Qt);
record_unwind_protect (w32_dialog_in_progress, Qnil);
if (ChooseFont (&cf)
&& logfont_to_fcname (&lf, cf.iPointSize, buf, 100) >= 0)
value = DECODE_SYSTEM (build_string (buf));
unbind_to (count, Qnil);
return value;
}
}
static const char *const w32font_booleans [] = {
NULL,
};
static const char *const w32font_non_booleans [] = {
":script",
":antialias",
":style",
NULL,
};
static void
w32font_filter_properties (Lisp_Object font, Lisp_Object alist)
{
font_filter_properties (font, alist, w32font_booleans, w32font_non_booleans);
}
struct font_driver w32font_driver =
{
LISPSYM_INITIALLY (Qgdi),
false, /* case insensitive */
w32font_get_cache,
w32font_list,
w32font_match,
w32font_list_family,
NULL, /* free_entity */
w32font_open,
w32font_close,
NULL, /* prepare_face */
NULL, /* done_face */
w32font_has_char,
w32font_encode_char,
w32font_text_extents,
w32font_draw,
NULL, /* get_bitmap */
NULL, /* free_bitmap */
NULL, /* anchor_point */
NULL, /* otf_capability */
NULL, /* otf_drive */
NULL, /* start_for_frame */
NULL, /* end_for_frame */
NULL, /* shape */
NULL, /* check */
NULL, /* get_variation_glyphs */
w32font_filter_properties,
NULL, /* cached_font_ok */
};
/* Initialize state that does not change between invocations. This is only
called when Emacs is dumped. */
static void syms_of_w32font_for_pdumper (void);
void
syms_of_w32font (void)
{
DEFSYM (Qgdi, "gdi");
DEFSYM (Quniscribe, "uniscribe");
DEFSYM (Qharfbuzz, "harfbuzz");
DEFSYM (QCformat, ":format");
/* Generic font families. */
DEFSYM (Qmonospace, "monospace");
DEFSYM (Qserif, "serif");
DEFSYM (Qsansserif, "sansserif");
DEFSYM (Qscript, "script");
DEFSYM (Qdecorative, "decorative");
/* Aliases. */
DEFSYM (Qsans_serif, "sans_serif");
DEFSYM (Qsans, "sans");
DEFSYM (Qmono, "mono");
/* Fake foundries. */
DEFSYM (Qraster, "raster");
DEFSYM (Qoutline, "outline");
DEFSYM (Qunknown, "unknown");
/* Antialiasing. */
DEFSYM (Qstandard, "standard");
DEFSYM (Qsubpixel, "subpixel");
DEFSYM (Qnatural, "natural");
/* Font formats. */
DEFSYM (Qtruetype, "truetype");
DEFSYM (Qtype1, "type1");
DEFSYM (Qw32bitmap, "w32bitmap");
DEFSYM (Qw32vector, "w32vector");
/* Languages */
DEFSYM (Qzh, "zh");
/* Scripts */
DEFSYM (Qlatin, "latin");
DEFSYM (Qgreek, "greek");
DEFSYM (Qcoptic, "coptic");
DEFSYM (Qcyrillic, "cyrillic");
DEFSYM (Qarmenian, "armenian");
DEFSYM (Qhebrew, "hebrew");
DEFSYM (Qvai, "vai");
DEFSYM (Qarabic, "arabic");
DEFSYM (Qsyriac, "syriac");
DEFSYM (Qnko, "nko");
DEFSYM (Qthaana, "thaana");
DEFSYM (Qdevanagari, "devanagari");
DEFSYM (Qbengali, "bengali");
DEFSYM (Qgurmukhi, "gurmukhi");
DEFSYM (Qgujarati, "gujarati");
DEFSYM (Qoriya, "oriya");
DEFSYM (Qtamil, "tamil");
DEFSYM (Qtelugu, "telugu");
DEFSYM (Qkannada, "kannada");
DEFSYM (Qmalayalam, "malayalam");
DEFSYM (Qsinhala, "sinhala");
DEFSYM (Qthai, "thai");
DEFSYM (Qlao, "lao");
DEFSYM (Qtibetan, "tibetan");
DEFSYM (Qburmese, "burmese");
DEFSYM (Qgeorgian, "georgian");
DEFSYM (Qhangul, "hangul");
DEFSYM (Qethiopic, "ethiopic");
DEFSYM (Qcherokee, "cherokee");
DEFSYM (Qcanadian_aboriginal, "canadian-aboriginal");
DEFSYM (Qogham, "ogham");
DEFSYM (Qrunic, "runic");
DEFSYM (Qkhmer, "khmer");
DEFSYM (Qmongolian, "mongolian");
DEFSYM (Qbraille, "braille");
DEFSYM (Qhan, "han");
DEFSYM (Qideographic_description, "ideographic-description");
DEFSYM (Qcjk_misc, "cjk-misc");
DEFSYM (Qkana, "kana");
DEFSYM (Qbopomofo, "bopomofo");
DEFSYM (Qkanbun, "kanbun");
DEFSYM (Qyi, "yi");
DEFSYM (Qbyzantine_musical_symbol, "byzantine-musical-symbol");
DEFSYM (Qmusical_symbol, "musical-symbol");
DEFSYM (Qmathematical_bold, "mathematical-bold");
DEFSYM (Qmathematical_italic, "mathematical-italic");
DEFSYM (Qmathematical_bold_italic, "mathematical-bold-italic");
DEFSYM (Qmathematical_script, "mathematical-script");
DEFSYM (Qmathematical_bold_script, "mathematical-bold-script");
DEFSYM (Qmathematical_fraktur, "mathematical-fraktur");
DEFSYM (Qmathematical_double_struck, "mathematical-double-struck");
DEFSYM (Qmathematical_bold_fraktur, "mathematical-bold-fraktur");
DEFSYM (Qmathematical_sans_serif, "mathematical-sans-serif");
DEFSYM (Qmathematical_sans_serif_bold, "mathematical-sans-serif-bold");
DEFSYM (Qmathematical_sans_serif_italic, "mathematical-sans-serif-italic");
DEFSYM (Qmathematical_sans_serif_bold_italic, "mathematical-sans-serif-bold-italic");
DEFSYM (Qmathematical_monospace, "mathematical-monospace");
DEFSYM (Qcham, "cham");
DEFSYM (Qphonetic, "phonetic");
DEFSYM (Qbalinese, "balinese");
DEFSYM (Qbuginese, "buginese");
DEFSYM (Qbuhid, "buhid");
DEFSYM (Qcuneiform, "cuneiform");
DEFSYM (Qcypriot, "cypriot");
DEFSYM (Qdeseret, "deseret");
DEFSYM (Qglagolitic, "glagolitic");
DEFSYM (Qgothic, "gothic");
DEFSYM (Qhanunoo, "hanunoo");
DEFSYM (Qkharoshthi, "kharoshthi");
DEFSYM (Qlimbu, "limbu");
DEFSYM (Qlinear_b, "linear-b");
DEFSYM (Qaegean_number, "aegean-number");
DEFSYM (Qold_italic, "old-italic");
DEFSYM (Qold_persian, "old-persian");
DEFSYM (Qosmanya, "osmanya");
DEFSYM (Qphags_pa, "phags-pa");
DEFSYM (Qphoenician, "phoenician");
DEFSYM (Qshavian, "shavian");
DEFSYM (Qsyloti_nagri, "syloti-nagri");
DEFSYM (Qtagalog, "tagalog");
DEFSYM (Qtagbanwa, "tagbanwa");
DEFSYM (Qtai_le, "tai-le");
DEFSYM (Qtifinagh, "tifinagh");
DEFSYM (Qugaritic, "ugaritic");
DEFSYM (Qlycian, "lycian");
DEFSYM (Qcarian, "carian");
DEFSYM (Qlydian, "lydian");
DEFSYM (Qdomino_tile, "domino-tile");
DEFSYM (Qmahjong_tile, "mahjong-tile");
DEFSYM (Qtai_xuan_jing_symbol, "tai-xuan-jing-symbol");
DEFSYM (Qcounting_rod_numeral, "counting-rod-numeral");
DEFSYM (Qancient_symbol, "ancient-symbol");
DEFSYM (Qphaistos_disc, "phaistos-disc");
DEFSYM (Qancient_greek_number, "ancient-greek-number");
DEFSYM (Qsundanese, "sundanese");
DEFSYM (Qlepcha, "lepcha");
DEFSYM (Qol_chiki, "ol-chiki");
DEFSYM (Qsaurashtra, "saurashtra");
DEFSYM (Qkayah_li, "kayah-li");
DEFSYM (Qrejang, "rejang");
/* W32 font encodings. */
DEFVAR_LISP ("w32-charset-info-alist",
Vw32_charset_info_alist,
doc: /* Alist linking Emacs character sets to Windows fonts and codepages.
Each entry should be of the form:
(CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE))
where CHARSET_NAME is a string used in font names to identify the charset,
WINDOWS_CHARSET is a symbol that can be one of:
w32-charset-ansi, w32-charset-default, w32-charset-symbol,
w32-charset-shiftjis, w32-charset-hangeul, w32-charset-gb2312,
w32-charset-chinesebig5, w32-charset-johab, w32-charset-hebrew,
w32-charset-arabic, w32-charset-greek, w32-charset-turkish,
w32-charset-vietnamese, w32-charset-thai, w32-charset-easteurope,
w32-charset-russian, w32-charset-mac, w32-charset-baltic,
or w32-charset-oem.
CODEPAGE should be an integer specifying the codepage that should be used
to display the character set, t to do no translation and output as Unicode,
or nil to do no translation and output as 8 bit (or multibyte on far-east
versions of Windows) characters. */);
Vw32_charset_info_alist = Qnil;
DEFSYM (Qw32_charset_ansi, "w32-charset-ansi");
DEFSYM (Qw32_charset_symbol, "w32-charset-symbol");
DEFSYM (Qw32_charset_default, "w32-charset-default");
DEFSYM (Qw32_charset_shiftjis, "w32-charset-shiftjis");
DEFSYM (Qw32_charset_hangeul, "w32-charset-hangeul");
DEFSYM (Qw32_charset_chinesebig5, "w32-charset-chinesebig5");
DEFSYM (Qw32_charset_gb2312, "w32-charset-gb2312");
DEFSYM (Qw32_charset_oem, "w32-charset-oem");
DEFSYM (Qw32_charset_johab, "w32-charset-johab");
DEFSYM (Qw32_charset_easteurope, "w32-charset-easteurope");
DEFSYM (Qw32_charset_turkish, "w32-charset-turkish");
DEFSYM (Qw32_charset_baltic, "w32-charset-baltic");
DEFSYM (Qw32_charset_russian, "w32-charset-russian");
DEFSYM (Qw32_charset_arabic, "w32-charset-arabic");
DEFSYM (Qw32_charset_greek, "w32-charset-greek");
DEFSYM (Qw32_charset_hebrew, "w32-charset-hebrew");
DEFSYM (Qw32_charset_vietnamese, "w32-charset-vietnamese");
DEFSYM (Qw32_charset_thai, "w32-charset-thai");
DEFSYM (Qw32_charset_mac, "w32-charset-mac");
DEFSYM (Qw32_non_USB_fonts, "w32-non-USB-fonts");
defsubr (&Sx_select_font);
pdumper_do_now_and_after_load (syms_of_w32font_for_pdumper);
}
static void
syms_of_w32font_for_pdumper (void)
{
register_font_driver (&w32font_driver, NULL);
}
void
globals_of_w32font (void)
{
#ifdef WINDOWSNT
g_b_init_get_outline_metrics_w = 0;
g_b_init_get_text_metrics_w = 0;
g_b_init_get_glyph_outline_w = 0;
g_b_init_get_char_width_32_w = 0;
#endif
}