/* Font backend for the Microsoft W32 API.
- Copyright (C) 2007 Free Software Foundation, Inc.
+ Copyright (C) 2007, 2008 Free Software Foundation, Inc.
This file is part of GNU Emacs.
-GNU Emacs is free software; you can redistribute it and/or modify
+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 2, or (at your option)
-any later version.
+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
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with GNU Emacs; see the file COPYING. If not, write to
-the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-Boston, MA 02110-1301, USA. */
+along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
#include <config.h>
#include <windows.h>
+#include <math.h>
+#include <ctype.h>
#include "lisp.h"
#include "w32term.h"
#include "charset.h"
#include "fontset.h"
#include "font.h"
+#include "w32font.h"
/* Cleartype available on Windows XP, cleartype_natural from XP SP1.
The latter does not try to fit cleartype smoothed fonts into the
#define CLEARTYPE_NATURAL_QUALITY 6
#endif
-/* The actual structure for a w32 font, that can be cast to struct font. */
-struct w32font_info
-{
- struct font font;
- TEXTMETRIC metrics;
-};
-
extern struct font_driver w32font_driver;
Lisp_Object Qgdi;
-extern Lisp_Object QCfamily; /* reuse from xfaces.c */
-static Lisp_Object Qmonospace, Qsans_serif, Qserif, Qmono, Qsans, Qsans__serif;
-static Lisp_Object Qscript, Qdecorative, Qraster, Qoutline, Qunknown;
+Lisp_Object Quniscribe;
+static Lisp_Object QCformat;
+static Lisp_Object Qmonospace, Qsansserif, Qmono, Qsans, Qsans_serif;
+static Lisp_Object Qserif, Qscript, Qdecorative;
+static Lisp_Object Qraster, Qoutline, Qunknown;
/* antialiasing */
-extern Lisp_Object QCantialias; /* defined in font.c */
+extern Lisp_Object QCantialias, QCotf, QClang; /* defined in font.c */
extern Lisp_Object Qnone; /* reuse from w32fns.c */
static Lisp_Object Qstandard, Qsubpixel, Qnatural;
+/* languages */
+static Lisp_Object Qja, Qko, Qzh;
+
/* scripts */
static Lisp_Object Qlatin, Qgreek, Qcoptic, Qcyrillic, Qarmenian, Qhebrew;
static Lisp_Object Qarabic, Qsyriac, Qnko, Qthaana, Qdevanagari, Qbengali;
static Lisp_Object Qideographic_description, Qcjk_misc, Qkana, Qbopomofo;
static Lisp_Object Qkanbun, Qyi, Qbyzantine_musical_symbol;
static Lisp_Object Qmusical_symbol, Qmathematical;
+/* Not defined in characters.el, but referenced in fontset.el. */
+static Lisp_Object Qbalinese, Qbuginese, Qbuhid, Qcuneiform, Qcypriot;
+static Lisp_Object Qdeseret, Qglagolitic, Qgothic, Qhanunoo, Qkharoshthi;
+static Lisp_Object Qlimbu, Qlinear_b, Qold_italic, Qold_persian, Qosmanya;
+static Lisp_Object Qphags_pa, Qphoenician, Qshavian, Qsyloti_nagri;
+static Lisp_Object Qtagalog, Qtagbanwa, Qtai_le, Qtifinagh, Qugaritic;
+/* Only defined here, but useful for distinguishing IPA capable fonts. */
+static Lisp_Object Qphonetic;
/* Font spacing symbols - defined in font.c. */
extern Lisp_Object Qc, Qp, Qm;
-static void fill_in_logfont P_ ((FRAME_PTR f, LOGFONT *logfont,
- Lisp_Object font_spec));
+static void fill_in_logfont P_ ((FRAME_PTR, LOGFONT *, Lisp_Object));
-static BYTE w32_antialias_type P_ ((Lisp_Object type));
-static Lisp_Object lispy_antialias_type P_ ((BYTE type));
+static BYTE w32_antialias_type P_ ((Lisp_Object));
+static Lisp_Object lispy_antialias_type P_ ((BYTE));
-static Lisp_Object font_supported_scripts P_ ((FONTSIGNATURE * sig));
+static Lisp_Object font_supported_scripts P_ ((FONTSIGNATURE *));
+static int w32font_full_name P_ ((LOGFONT *, Lisp_Object, int, char *, int));
+static void compute_metrics P_ ((HDC, struct w32font_info *, unsigned int,
+ struct w32_metric_cache *));
+static void clear_cached_metrics P_ ((struct w32font_info *));
-/* From old font code in w32fns.c */
-char * w32_to_x_charset P_ ((int charset, char * matching));
-
-static Lisp_Object w32_registry P_ ((LONG w32_charset));
+static Lisp_Object w32_registry P_ ((LONG, DWORD));
/* EnumFontFamiliesEx callbacks. */
static int CALLBACK add_font_entity_to_list P_ ((ENUMLOGFONTEX *,
Lisp_Object frame;
/* The list to add matches to. */
Lisp_Object list;
+ /* Whether to match only opentype fonts. */
+ int 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 P_ ((struct font_callback_data *match_data));
+static void list_all_matching_fonts P_ ((struct font_callback_data *));
+/* From old font code in w32fns.c */
+char * w32_to_x_charset P_ ((int, char *));
-/* MingW headers only define this when _WIN32_WINNT >= 0x0500, but we
- target older versions. */
-#define GGI_MARK_NONEXISTING_GLYPHS 1
static int
memq_no_quit (elt, list)
/* 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. */
-static Lisp_Object
-w32font_get_cache (frame)
- Lisp_Object frame;
+Lisp_Object
+w32font_get_cache (f)
+ FRAME_PTR f;
{
- struct w32_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (XFRAME (frame));
+ struct w32_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
return (dpyinfo->name_list_element);
}
w32font_list (frame, font_spec)
Lisp_Object frame, font_spec;
{
- struct font_callback_data match_data;
- HDC dc;
- FRAME_PTR f = XFRAME (frame);
-
- match_data.orig_font_spec = font_spec;
- match_data.list = Qnil;
- match_data.frame = frame;
- bzero (&match_data.pattern, sizeof (LOGFONT));
- fill_in_logfont (f, &match_data.pattern, font_spec);
-
- 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
- {
- 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);
- }
-
- return NILP (match_data.list) ? null_vector : Fvconcat (1, &match_data.list);
+ return w32font_list_internal (frame, font_spec, 0);
}
/* w32 implementation of match for font backend.
w32font_match (frame, font_spec)
Lisp_Object frame, font_spec;
{
- struct font_callback_data match_data;
- HDC dc;
- FRAME_PTR f = XFRAME (frame);
-
- match_data.orig_font_spec = font_spec;
- match_data.frame = frame;
- match_data.list = Qnil;
- bzero (&match_data.pattern, sizeof (LOGFONT));
- fill_in_logfont (f, &match_data.pattern, font_spec);
-
- 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);
-
- return NILP (match_data.list) ? Qnil : XCAR (match_data.list);
+ return w32font_match_internal (frame, font_spec, 0);
}
-
/* w32 implementation of list_family for font backend.
List available families. The value is a list of family names
(symbols). */
FRAME_PTR f = XFRAME (frame);
bzero (&font_match_pattern, sizeof (font_match_pattern));
+ font_match_pattern.lfCharSet = DEFAULT_CHARSET;
dc = get_frame_dc (f);
/* 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 struct font *
+static Lisp_Object
w32font_open (f, font_entity, pixel_size)
FRAME_PTR f;
Lisp_Object font_entity;
int pixel_size;
{
- int len, size;
- LOGFONT logfont;
- HDC dc;
- HFONT hfont, old_font;
- Lisp_Object val, extra;
- /* For backwards compatibility. */
- W32FontStruct *compat_w32_font;
-
- struct w32font_info *w32_font = xmalloc (sizeof (struct w32font_info));
+ Lisp_Object font_object;
- struct font * font = (struct font *) w32_font;
- if (!font)
- return NULL;
+ font_object = font_make_object (VECSIZE (struct w32font_info));
- bzero (&logfont, sizeof (logfont));
- fill_in_logfont (f, &logfont, font_entity);
-
- size = XINT (AREF (font_entity, FONT_SIZE_INDEX));
- if (!size)
- size = pixel_size;
-
- logfont.lfHeight = -size;
- hfont = CreateFontIndirect (&logfont);
-
- if (hfont == NULL)
+ if (!w32font_open_internal (f, font_entity, pixel_size, font_object))
{
- xfree (w32_font);
- return NULL;
+ return Qnil;
}
- /* Get the metrics for this font. */
- dc = get_frame_dc (f);
- old_font = SelectObject (dc, hfont);
-
- GetTextMetrics (dc, &w32_font->metrics);
-
- SelectObject (dc, old_font);
- release_frame_dc (f, dc);
- /* W32FontStruct - we should get rid of this, and use the w32font_info
- struct for any W32 specific fields. font->font.font can then be hfont. */
- font->font.font = xmalloc (sizeof (W32FontStruct));
- compat_w32_font = (W32FontStruct *) font->font.font;
- bzero (compat_w32_font, sizeof (W32FontStruct));
- compat_w32_font->font_type = UNICODE_FONT;
- /* Duplicate the text metrics. */
- bcopy (&w32_font->metrics, &compat_w32_font->tm, sizeof (TEXTMETRIC));
- compat_w32_font->hfont = hfont;
-
- len = strlen (logfont.lfFaceName);
- font->font.name = (char *) xmalloc (len + 1);
- bcopy (logfont.lfFaceName, font->font.name, len);
- font->font.name[len] = '\0';
- font->font.full_name = font->font.name;
- font->font.charset = 0;
- font->font.codepage = 0;
- font->font.size = w32_font->metrics.tmMaxCharWidth;
- font->font.height = w32_font->metrics.tmHeight
- + w32_font->metrics.tmExternalLeading;
- font->font.space_width = font->font.average_width
- = w32_font->metrics.tmAveCharWidth;
-
- font->font.vertical_centering = 0;
- font->font.encoding_type = 0;
- font->font.baseline_offset = 0;
- font->font.relative_compose = 0;
- font->font.default_ascent = w32_font->metrics.tmAscent;
- font->font.font_encoder = NULL;
- font->entity = font_entity;
- font->pixel_size = size;
- font->driver = &w32font_driver;
- font->format = Qgdi;
- font->file_name = NULL;
- font->encoding_charset = -1;
- font->repertory_charset = -1;
- font->min_width = 0;
- font->ascent = w32_font->metrics.tmAscent;
- font->descent = w32_font->metrics.tmDescent;
- font->scalable = w32_font->metrics.tmPitchAndFamily & TMPF_VECTOR;
-
- return font;
+ return font_object;
}
/* w32 implementation of close for font_backend.
Close FONT on frame F. */
-static void
+void
w32font_close (f, font)
FRAME_PTR f;
struct font *font;
{
- if (font->font.font)
+ struct w32font_info *w32_font = (struct w32font_info *) font;
+
+ if (w32_font->compat_w32_font)
{
- W32FontStruct *old_w32_font = (W32FontStruct *)font->font.font;
+ W32FontStruct *old_w32_font = w32_font->compat_w32_font;
DeleteObject (old_w32_font->hfont);
xfree (old_w32_font);
- font->font.font = 0;
+ w32_font->compat_w32_font = 0;
}
-
- if (font->font.name)
- xfree (font->font.name);
- xfree (font);
}
/* w32 implementation of has_char for font backend.
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. */
-static int
+int
w32font_has_char (entity, c)
Lisp_Object entity;
int c;
script = CHAR_TABLE_REF (Vchar_script_table, c);
- return (memq_no_quit (script, supported_scripts)) ? 1 : 0;
+ return (memq_no_quit (script, supported_scripts)) ? -1 : 0;
}
/* w32 implementation of encode_char for font backend.
struct font *font;
int c;
{
- /* Avoid unneccesary conversion - all the Win32 APIs will take a unicode
- character. */
- return c;
+ struct frame *f;
+ HDC dc;
+ HFONT old_font;
+ DWORD retval;
+ GCP_RESULTSW result;
+ wchar_t in[2];
+ wchar_t out[2];
+ int len;
+ struct w32font_info *w32_font = (struct w32font_info *) font;
+
+ /* If glyph indexing is not working for this font, just return the
+ unicode code-point. */
+ if (!w32_font->glyph_idx)
+ return c;
+
+ if (c > 0xFFFF)
+ {
+ /* TODO: Encode as surrogate pair and lookup the glyph. */
+ return FONT_INVALID_CODE;
+ }
+ else
+ {
+ in[0] = (wchar_t) c;
+ len = 1;
+ }
+
+ bzero (&result, sizeof (result));
+ result.lStructSize = sizeof (result);
+ result.lpGlyphs = out;
+ result.nGlyphs = 2;
+
+ f = XFRAME (selected_frame);
+
+ dc = get_frame_dc (f);
+ old_font = SelectObject (dc, w32_font->compat_w32_font->hfont);
+
+ /* GetCharacterPlacement is used here rather than GetGlyphIndices because
+ it is supported on Windows NT 4 and 9x/ME. But it cannot reliably report
+ missing glyphs, see below for workaround. */
+ retval = GetCharacterPlacementW (dc, in, len, 0, &result, 0);
+
+ SelectObject (dc, old_font);
+ release_frame_dc (f, dc);
+
+ if (retval)
+ {
+ if (result.nGlyphs != 1 || !result.lpGlyphs[0]
+ /* GetCharacterPlacementW seems to return 3, which seems to be
+ the space glyph in most/all truetype fonts, instead of 0
+ for unsupported glyphs. */
+ || (result.lpGlyphs[0] == 3 && !iswspace (in[0])))
+ return FONT_INVALID_CODE;
+ return result.lpGlyphs[0];
+ }
+ else
+ {
+ int i;
+ /* Mark this font as not supporting glyph indices. This can happen
+ on Windows9x, and maybe with non-Truetype fonts on NT etc. */
+ w32_font->glyph_idx = 0;
+ /* Clear metrics cache. */
+ clear_cached_metrics (w32_font);
+
+ return c;
+ }
}
/* w32 implementation of text_extents for font backend.
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. */
-static int
+int
w32font_text_extents (font, code, nglyphs, metrics)
struct font *font;
unsigned *code;
struct font_metrics *metrics;
{
int i;
- HFONT old_font;
- /* FIXME: Be nice if we had a frame here, rather than getting the desktop's
- device context to measure against... */
- HDC dc = GetDC (NULL);
+ HFONT old_font = NULL;
+ HDC dc = NULL;
+ struct frame * f;
int total_width = 0;
- WORD *wcode = alloca(nglyphs * sizeof (WORD));
+ WORD *wcode = NULL;
SIZE size;
- old_font = SelectObject (dc, ((W32FontStruct *)(font->font.font))->hfont);
-
if (metrics)
{
- GLYPHMETRICS gm;
- MAT2 transform;
+ struct w32font_info *w32_font = (struct w32font_info *) font;
- /* Set transform to the identity matrix. */
- bzero (&transform, sizeof (transform));
- transform.eM11.value = 1;
- transform.eM22.value = 1;
- metrics->width = 0;
- metrics->ascent = 0;
- metrics->descent = 0;
+ bzero (metrics, sizeof (struct font_metrics));
+ metrics->ascent = font->ascent;
+ metrics->descent = font->descent;
for (i = 0; i < nglyphs; i++)
{
- if (GetGlyphOutlineW (dc, *(code + i), GGO_METRICS, &gm, 0,
- NULL, &transform) != GDI_ERROR)
- {
- int new_val = metrics->width + gm.gmBlackBoxX
- + gm.gmptGlyphOrigin.x;
-
- metrics->rbearing = max (metrics->rbearing, new_val);
- metrics->width += gm.gmCellIncX;
- new_val = -gm.gmptGlyphOrigin.y;
- metrics->ascent = max (metrics->ascent, new_val);
- new_val = gm.gmBlackBoxY + gm.gmptGlyphOrigin.y;
- metrics->descent = max (metrics->descent, new_val);
- }
- else
- {
- /* Rely on an estimate based on the overall font metrics. */
- break;
- }
- }
-
+ 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_cached_metric *));
+ else
+ w32_font->cached_metrics
+ = xrealloc (w32_font->cached_metrics,
+ (block + 1)
+ * sizeof (struct w32_cached_metric *));
+ bzero (w32_font->cached_metrics + w32_font->n_cache_blocks,
+ ((block + 1 - w32_font->n_cache_blocks)
+ * sizeof (struct w32_cached_metric *)));
+ w32_font->n_cache_blocks = block + 1;
+ }
+
+ if (!w32_font->cached_metrics[block])
+ {
+ w32_font->cached_metrics[block]
+ = xmalloc (CACHE_BLOCKSIZE * sizeof (struct font_metrics));
+ bzero (w32_font->cached_metrics[block],
+ CACHE_BLOCKSIZE * sizeof (struct font_metrics));
+ }
+
+ 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);
+
+ dc = get_frame_dc (f);
+ old_font = SelectObject (dc, FONT_COMPAT (font)->hfont);
+ }
+ compute_metrics (dc, w32_font, *(code + i), char_metric);
+ }
+
+ if (char_metric->status == W32METRIC_SUCCESS)
+ {
+ metrics->lbearing = min (metrics->lbearing,
+ metrics->width + char_metric->lbearing);
+ metrics->rbearing = max (metrics->rbearing,
+ metrics->width + char_metric->rbearing);
+ metrics->width += char_metric->width;
+ }
+ else
+ /* If we couldn't get metrics for a char,
+ use alternative method. */
+ break;
+ }
/* If we got through everything, return. */
if (i == nglyphs)
{
- /* Restore state and release DC. */
- SelectObject (dc, old_font);
- ReleaseDC (NULL, dc);
+ if (dc != NULL)
+ {
+ /* Restore state and release DC. */
+ SelectObject (dc, old_font);
+ release_frame_dc (f, dc);
+ }
return metrics->width;
}
}
- for (i = 0; i < nglyphs; i++)
+ /* For non-truetype fonts, GetGlyphOutlineW is not supported, so
+ fallback on other methods that will at least give some of the metric
+ information. */
+ if (!wcode) {
+ wcode = alloca (nglyphs * sizeof (WORD));
+ for (i = 0; i < nglyphs; i++)
+ {
+ if (code[i] < 0x10000)
+ wcode[i] = code[i];
+ else
+ {
+ /* TODO: Convert to surrogate, reallocating array if needed */
+ wcode[i] = 0xffff;
+ }
+ }
+ }
+ if (dc == NULL)
{
- if (code[i] < 0x10000)
- wcode[i] = code[i];
- else
- {
- /* TODO: Convert to surrogate, reallocating array if needed */
- wcode[i] = 0xffff;
- }
+ /* 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);
+
+ dc = get_frame_dc (f);
+ old_font = SelectObject (dc, FONT_COMPAT (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->font.height; rect.left = 0; rect.right = 1;
+ 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. */
if (metrics)
{
metrics->width = total_width;
- metrics->ascent = font->ascent;
- metrics->descent = font->descent;
metrics->lbearing = 0;
metrics->rbearing = total_width
+ ((struct w32font_info *) font)->metrics.tmOverhang;
/* Restore state and release DC. */
SelectObject (dc, old_font);
- ReleaseDC (NULL, dc);
+ release_frame_dc (f, dc);
return total_width;
}
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
is nonzero, fill the background in advance. It is assured that
- WITH_BACKGROUND is zero when (FROM > 0 || TO < S->nchars). */
-static int
+ WITH_BACKGROUND is zero 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 (s, from, to, x, y, with_background)
struct glyph_string *s;
int from, to, x, y, with_background;
{
- UINT options = 0;
+ UINT options;
HRGN orig_clip;
+ struct w32font_info *w32font = (struct w32font_info *) s->font;
+
+ options = w32font->glyph_idx;
/* Save clip region for later restoration. */
GetClipRgn(s->hdc, orig_clip);
{
HBRUSH brush;
RECT rect;
- struct font *font = (struct font *) s->face->font_info;
+ struct font *font = s->font;
brush = CreateSolidBrush (s->gc->background);
rect.left = x;
DeleteObject (brush);
}
- ExtTextOutW (s->hdc, x, y, options, NULL, s->char2b + from, to - from, NULL);
+ if (s->padding_p)
+ {
+ int len = to - from, i;
+
+ for (i = 0; i < len; i++)
+ ExtTextOutW (s->hdc, x + i, y, options, NULL,
+ s->char2b + from + i, 1, NULL);
+ }
+ else
+ ExtTextOutW (s->hdc, x, y, options, NULL, s->char2b + from, to - from, NULL);
/* Restore clip region. */
if (s->num_clips > 0)
int 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 (frame, font_spec, opentype_only)
+ Lisp_Object frame, font_spec;
+ int opentype_only;
+{
+ struct font_callback_data match_data;
+ HDC dc;
+ FRAME_PTR f = XFRAME (frame);
+
+ match_data.orig_font_spec = font_spec;
+ match_data.list = Qnil;
+ match_data.frame = frame;
+
+ bzero (&match_data.pattern, 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;
+
+ 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
+ {
+ 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);
+ }
+
+ return NILP (match_data.list) ? Qnil : 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 (frame, font_spec, opentype_only)
+ Lisp_Object frame, font_spec;
+ int opentype_only;
+{
+ struct font_callback_data match_data;
+ HDC dc;
+ FRAME_PTR f = XFRAME (frame);
+
+ match_data.orig_font_spec = font_spec;
+ match_data.frame = frame;
+ match_data.list = Qnil;
+
+ bzero (&match_data.pattern, 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;
+
+ 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);
+
+ return NILP (match_data.list) ? Qnil : XCAR (match_data.list);
+}
+
+int
+w32font_open_internal (f, font_entity, pixel_size, font_object)
+ FRAME_PTR f;
+ Lisp_Object font_entity;
+ int pixel_size;
+ Lisp_Object font_object;
+{
+ int len, size, i;
+ LOGFONT logfont;
+ HDC dc;
+ HFONT hfont, old_font;
+ Lisp_Object val, extra;
+ /* For backwards compatibility. */
+ W32FontStruct *compat_w32_font;
+ struct w32font_info *w32_font;
+ struct font * font;
+ OUTLINETEXTMETRIC* metrics = NULL;
+
+ w32_font = (struct w32font_info *) XFONT_OBJECT (font_object);
+ font = (struct font *) w32_font;
+
+ if (!font)
+ return 0;
+
+ /* Copy from font entity. */
+ for (i = 0; i < FONT_ENTITY_MAX; i++)
+ ASET (font_object, i, AREF (font_entity, i));
+ ASET (font_object, FONT_SIZE_INDEX, make_number (pixel_size));
+
+ bzero (&logfont, 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 = XINT (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 = GetOutlineTextMetrics (dc, 0, NULL);
+ if (len)
+ {
+ metrics = (OUTLINETEXTMETRIC *) alloca (len);
+ if (GetOutlineTextMetrics (dc, len, metrics))
+ bcopy (&metrics->otmTextMetrics, &w32_font->metrics,
+ sizeof (TEXTMETRIC));
+ else
+ metrics = NULL;
+
+ /* If it supports outline metrics, it should support Glyph Indices. */
+ w32_font->glyph_idx = ETO_GLYPH_INDEX;
+ }
+
+ if (!metrics)
+ {
+ GetTextMetrics (dc, &w32_font->metrics);
+ w32_font->glyph_idx = 0;
+ }
+
+ w32_font->cached_metrics = NULL;
+ w32_font->n_cache_blocks = 0;
+
+ SelectObject (dc, old_font);
+ release_frame_dc (f, dc);
+
+ /* W32FontStruct - we should get rid of this, and use the w32font_info
+ struct for any W32 specific fields. font->font.font can then be hfont. */
+ w32_font->compat_w32_font = xmalloc (sizeof (W32FontStruct));
+ compat_w32_font = w32_font->compat_w32_font;
+ bzero (compat_w32_font, sizeof (W32FontStruct));
+ compat_w32_font->font_type = UNICODE_FONT;
+ /* Duplicate the text metrics. */
+ bcopy (&w32_font->metrics, &compat_w32_font->tm, sizeof (TEXTMETRIC));
+ compat_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 = xmalloc (len);
+ while (name && w32font_full_name (&logfont, font_entity, pixel_size,
+ name, len) < 0)
+ {
+ char *new = xrealloc (name, len += 32);
+
+ if (! new)
+ xfree (name);
+ name = new;
+ }
+ if (name)
+ font->props[FONT_FULLNAME_INDEX]
+ = make_unibyte_string (name, strlen (name));
+ else
+ font->props[FONT_FULLNAME_INDEX] =
+ make_unibyte_string (logfont.lfFaceName, len);
+ }
+
+ font->max_width = w32_font->metrics.tmMaxCharWidth;
+ 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->encoding_type = 0;
+ font->baseline_offset = 0;
+ font->relative_compose = 0;
+ font->default_ascent = w32_font->metrics.tmAscent;
+ font->font_encoder = NULL;
+ font->pixel_size = size;
+ font->driver = &w32font_driver;
+ /* Use format cached during list, as the information we have access to
+ here is incomplete. */
+ extra = AREF (font_entity, FONT_EXTRA_INDEX);
+ if (CONSP (extra))
+ {
+ val = assq_no_quit (QCformat, extra);
+ if (CONSP (val))
+ font->props[FONT_FORMAT_INDEX] = XCDR (val);
+ else
+ font->props[FONT_FORMAT_INDEX] = Qunknown;
+ }
+ else
+ font->props[FONT_FORMAT_INDEX] = Qunknown;
+
+ font->props[FONT_FILE_INDEX] = Qnil;
+ 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;
+
+ if (metrics)
+ {
+ font->underline_thickness = metrics->otmsUnderscoreSize;
+ font->underline_position = -metrics->otmsUnderscorePosition;
+ }
+ else
+ {
+ font->underline_thickness = 0;
+ font->underline_position = -1;
+ }
+
+ /* max_descent is used for underlining in w32term.c. Hopefully this
+ is temporary, as we'll want to get rid of the old compatibility
+ stuff later. */
+ compat_w32_font->max_bounds.descent = font->descent;
+
+ /* 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);
+
+ 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
if (logical_font->elfLogFont.lfFaceName[0] == '@')
return 1;
- family = intern_downcase (logical_font->elfLogFont.lfFaceName,
- strlen (logical_font->elfLogFont.lfFaceName));
+ family = font_intern_prop (logical_font->elfLogFont.lfFaceName,
+ strlen (logical_font->elfLogFont.lfFaceName), 1);
if (! memq_no_quit (family, *list))
*list = Fcons (family, *list);
return 1;
}
+static int w32_decode_weight P_ ((int));
+static int w32_encode_weight P_ ((int));
+
/* Convert an enumerated Windows font to an Emacs font entity. */
static Lisp_Object
w32_enumfont_pattern_entity (frame, logical_font, physical_font,
- font_type, requested_font)
+ font_type, requested_font, backend)
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 = Fmake_vector (make_number (FONT_ENTITY_MAX), Qnil);
+ entity = font_make_entity ();
- ASET (entity, FONT_TYPE_INDEX, Qgdi);
- ASET (entity, FONT_FRAME_INDEX, frame);
- ASET (entity, FONT_REGISTRY_INDEX, w32_registry (lf->lfCharSet));
+ 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. Thes values make xflds compatible with Emacs 22. */
+ generic. These values make xlfds compatible with Emacs 22. */
if (lf->lfOutPrecision == OUT_STRING_PRECIS)
tem = Qraster;
else if (lf->lfOutPrecision == OUT_STROKE_PRECIS)
if (generic_type == FF_DECORATIVE)
tem = Qdecorative;
else if (generic_type == FF_MODERN)
- tem = Qmonospace;
+ 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_serif;
+ tem = Qsans;
else
tem = Qnil;
-
- if (! NILP (tem))
- font_put_extra (entity, QCfamily, tem);
+
+ ASET (entity, FONT_ADSTYLE_INDEX, tem);
if (physical_font->ntmTm.tmPitchAndFamily & 0x01)
- font_put_extra (entity, QCspacing, make_number (FONT_SPACING_PROPORTIONAL));
+ ASET (entity, FONT_SPACING_INDEX, make_number (FONT_SPACING_PROPORTIONAL));
else
- font_put_extra (entity, QCspacing, make_number (FONT_SPACING_MONO));
+ ASET (entity, FONT_SPACING_INDEX, make_number (FONT_SPACING_CHARCELL));
if (requested_font->lfQuality != DEFAULT_QUALITY)
{
lispy_antialias_type (requested_font->lfQuality));
}
ASET (entity, FONT_FAMILY_INDEX,
- intern_downcase (lf->lfFaceName, strlen (lf->lfFaceName)));
+ font_intern_prop (lf->lfFaceName, strlen (lf->lfFaceName), 1));
- ASET (entity, FONT_WEIGHT_INDEX, make_number (lf->lfWeight));
- ASET (entity, FONT_SLANT_INDEX, make_number (lf->lfItalic ? 200 : 100));
+ FONT_SET_STYLE (entity, FONT_WEIGHT_INDEX,
+ make_number (w32_decode_weight (lf->lfWeight)));
+ FONT_SET_STYLE (entity, FONT_SLANT_INDEX,
+ make_number (lf->lfItalic ? 200 : 100));
/* TODO: PANOSE struct has this info, but need to call GetOutlineTextMetrics
to get it. */
- ASET (entity, FONT_WIDTH_INDEX, make_number (100));
+ FONT_SET_STYLE (entity, FONT_WIDTH_INDEX, make_number (100));
if (font_type & RASTER_FONTTYPE)
ASET (entity, FONT_SIZE_INDEX, make_number (physical_font->ntmTm.tmHeight));
of getting this information easily. */
if (font_type & TRUETYPE_FONTTYPE)
{
- font_put_extra (entity, QCscript,
- font_supported_scripts (&physical_font->ntmFontSig));
+ 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 = intern ("opentype");
+ else if (font_type & TRUETYPE_FONTTYPE)
+ tem = intern ("truetype");
+ else if (full_type & NTM_PS_OPENTYPE)
+ tem = intern ("postscript");
+ else if (full_type & NTM_TYPE1)
+ tem = intern ("type1");
+ else if (font_type & RASTER_FONTTYPE)
+ tem = intern ("w32bitmap");
+ else
+ tem = intern ("w32vector");
+
+ font_put_extra (entity, QCformat, tem);
+
return entity;
}
/* Generic families. */
if (EQ (name, Qmonospace) || EQ (name, Qmono))
return FF_MODERN;
- else if (EQ (name, Qsans_serif) || EQ (name, Qsans__serif)
- || EQ (name, Qsans))
+ else if (EQ (name, Qsans) || EQ (name, Qsans_serif) || EQ (name, Qsansserif))
return FF_SWISS;
else if (EQ (name, Qserif))
return FF_ROMAN;
}
static int
-font_matches_spec (type, font, spec)
+font_matches_spec (type, font, spec, backend, logfont)
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". */
- val = AREF (spec, FONT_SLANT_INDEX);
- if (INTEGERP (val))
+ {
+ 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))
{
- int slant = XINT (val);
- if ((slant > 150 && !font->ntmTm.tmItalic)
- || (slant <= 150 && font->ntmTm.tmItalic))
+ 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 (INTEGERP (val))
+ {
+ int spacing = XINT (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))
if (CONSP (extra_entry))
{
Lisp_Object key = XCAR (extra_entry);
- val = XCDR (extra_entry);
- if (EQ (key, QCfamily))
- {
- /* Generic family. Most useful when there is no font name
- specified. eg, if a script does not exist in the default
- font, we could look for a font with the same generic family
- that does support the script. Full PANOSE support would
- be better, but we need to open the font to get that. */
- BYTE w32_family = w32_generic_family (val);
-
- /* Reject if FF_DONTCARE is returned, as it means the
- font spec is bad. */
- if (w32_family == FF_DONTCARE
- || w32_family != (font->ntmTm.tmPitchAndFamily & 0xF0))
- return 0;
- }
- else if (EQ (key, QCspacing))
- {
- int proportional;
- if (INTEGERP (val))
- {
- int spacing = XINT (val);
- proportional = (spacing < FONT_SPACING_MONO);
- }
- else if (EQ (val, Qp))
- proportional = 1;
- else if (EQ (val, Qc) || EQ (val, Qm))
- proportional = 0;
- else
- return 0; /* Bad font spec. */
- if ((proportional && !(font->ntmTm.tmPitchAndFamily & 0x01))
- || (!proportional && (font->ntmTm.tmPitchAndFamily & 0x01)))
- return 0;
- }
- else if (EQ (key, QCscript) && SYMBOLP (val))
+ 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
return 0;
}
else
- /* Other scripts unlikely to be handled. */
+ /* 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 language
+ 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->ntmTm.tmCharSet != SHIFTJIS_CHARSET)
+ return 0;
+ }
+ else if (EQ (val, Qko))
+ {
+ if (font->ntmTm.tmCharSet != HANGUL_CHARSET
+ && font->ntmTm.tmCharSet != JOHAB_CHARSET)
+ return 0;
+ }
+ else if (EQ (val, Qzh))
+ {
+ if (font->ntmTm.tmCharSet != GB2312_CHARSET
+ && font->ntmTm.tmCharSet != CHINESEBIG5_CHARSET)
+ return 0;
+ }
+ else
+ /* Any other language, we don't recognize it. 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 (coverage, charset)
+ 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;
+}
+
/* Callback function for EnumFontFamiliesEx.
* Checks if a font matches everything we are trying to check agaist,
* and if so, adds it to a list. Both the data we are checking against
{
struct font_callback_data *match_data
= (struct font_callback_data *) lParam;
-
- if (logfonts_match (&logical_font->elfLogFont, &match_data->pattern)
+ Lisp_Object backend = match_data->opentype_only ? Quniscribe : Qgdi;
+
+ if ((!match_data->opentype_only
+ || (((physical_font->ntmTm.ntmFlags & NTMFLAGS_OPENTYPE)
+ || (font_type & TRUETYPE_FONTTYPE))
+ /* For the uniscribe backend, only consider fonts that claim
+ to cover at least some part of Unicode. */
+ && (physical_font->ntmFontSig.fsUsb[3]
+ || physical_font->ntmFontSig.fsUsb[2]
+ || physical_font->ntmFontSig.fsUsb[1]
+ || (physical_font->ntmFontSig.fsUsb[0] & 0x3fffffff))))
+ && logfonts_match (&logical_font->elfLogFont, &match_data->pattern)
&& font_matches_spec (font_type, physical_font,
- match_data->orig_font_spec)
- /* Avoid Windows substitution so we can control substitution with
- alternate-fontname-alist. */
- && !strnicmp (&logical_font->elfFullName,
- &match_data->pattern.lfFaceName, LF_FACESIZE))
+ match_data->orig_font_spec, backend,
+ &logical_font->elfLogFont)
+ && w32font_coverage_ok (&physical_font->ntmFontSig,
+ match_data->pattern.lfCharSet)
+ /* 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. */
+ && (logical_font->elfLogFont.lfOutPrecision != OUT_STRING_PRECIS
+ || strstr (logical_font->elfFullName,
+ logical_font->elfLogFont.lfFaceName)))
{
Lisp_Object entity
= w32_enumfont_pattern_entity (match_data->frame, logical_font,
physical_font, font_type,
- &match_data->pattern);
+ &match_data->pattern,
+ backend);
if (!NILP (entity))
- match_data->list = Fcons (entity, match_data->list);
+ {
+ Lisp_Object spec_charset = AREF (match_data->orig_font_spec,
+ FONT_REGISTRY_INDEX);
+
+ /* If registry was specified as iso10646-1, only report
+ ANSI and DEFAULT charsets, as most unicode fonts will
+ contain one of those plus others. */
+ if ((EQ (spec_charset, Qiso10646_1)
+ || EQ (spec_charset, Qunicode_bmp)
+ || EQ (spec_charset, Qunicode_sip))
+ && logical_font->elfLogFont.lfCharSet != DEFAULT_CHARSET
+ && logical_font->elfLogFont.lfCharSet != ANSI_CHARSET)
+ return 1;
+ /* If registry was specified, but did not map to a windows
+ charset, only report fonts that have unknown charsets.
+ This will still report fonts that don't match, but at
+ least it eliminates known definite mismatches. */
+ else if (!NILP (spec_charset)
+ && !EQ (spec_charset, Qiso10646_1)
+ && !EQ (spec_charset, Qunicode_bmp)
+ && !EQ (spec_charset, Qunicode_sip)
+ && match_data->pattern.lfCharSet == DEFAULT_CHARSET
+ && logical_font->elfLogFont.lfCharSet != DEFAULT_CHARSET)
+ return 1;
+
+ /* If registry was specified, ensure it is reported as the same. */
+ if (!NILP (spec_charset))
+ ASET (entity, FONT_REGISTRY_INDEX, spec_charset);
+
+ match_data->list = Fcons (entity, match_data->list);
+
+ /* If no registry specified, duplicate iso8859-1 truetype fonts
+ as iso10646-1. */
+ if (NILP (spec_charset)
+ && font_type == TRUETYPE_FONTTYPE
+ && logical_font->elfLogFont.lfCharSet == ANSI_CHARSET)
+ {
+ Lisp_Object tem = Fcopy_font_spec (entity);
+ ASET (tem, FONT_REGISTRY_INDEX, Qiso10646_1);
+ match_data->list = Fcons (tem, match_data->list);
+ }
+ }
}
return 1;
}
return ANSI_CHARSET;
else if (SYMBOLP (charset))
return x_to_w32_charset (SDATA (SYMBOL_NAME (charset)));
- else if (STRINGP (charset))
- return x_to_w32_charset (SDATA (charset));
else
return DEFAULT_CHARSET;
}
static Lisp_Object
-w32_registry (w32_charset)
+w32_registry (w32_charset, font_type)
LONG w32_charset;
+ DWORD font_type;
{
- if (w32_charset == ANSI_CHARSET)
- return Qiso10646_1;
- else
- {
- char * charset = w32_to_x_charset (w32_charset, NULL);
- return intern_downcase (charset, strlen(charset));
- }
+ 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 (fnweight)
+ 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_NORMAL) return 100;
+ 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 (n)
+ 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_NORMAL;
+ if (n >= 50) return FW_LIGHT;
+ if (n >= 40) return FW_EXTRALIGHT;
+ if (n >= 20) return FW_THIN;
+ return 0;
}
/* Fill in all the available details of LOGFONT from FONT_SPEC. */
Lisp_Object tmp, extra;
int dpi = FRAME_W32_DISPLAY_INFO (f)->resy;
- extra = AREF (font_spec, FONT_EXTRA_INDEX);
- /* Allow user to override dpi settings. */
- if (CONSP (extra))
+ tmp = AREF (font_spec, FONT_DPI_INDEX);
+ if (INTEGERP (tmp))
{
- tmp = assq_no_quit (QCdpi, extra);
- if (CONSP (tmp) && INTEGERP (XCDR (tmp)))
- {
- dpi = XINT (XCDR (tmp));
- }
- else if (CONSP (tmp) && FLOATP (XCDR (tmp)))
- {
- dpi = (int) (XFLOAT_DATA (XCDR (tmp)) + 0.5);
- }
+ dpi = XINT (tmp);
+ }
+ else if (FLOATP (tmp))
+ {
+ dpi = (int) (XFLOAT_DATA (tmp) + 0.5);
}
/* Height */
/* Weight */
tmp = AREF (font_spec, FONT_WEIGHT_INDEX);
if (INTEGERP (tmp))
- logfont->lfWeight = XINT (tmp);
+ logfont->lfWeight = w32_encode_weight (FONT_WEIGHT_NUMERIC (font_spec));
/* Italic */
tmp = AREF (font_spec, FONT_SLANT_INDEX);
if (INTEGERP (tmp))
{
- int slant = XINT (tmp);
+ int slant = FONT_SLANT_NUMERIC (font_spec);
logfont->lfItalic = slant > 150 ? 1 : 0;
}
tmp = AREF (font_spec, FONT_REGISTRY_INDEX);
if (! NILP (tmp))
logfont->lfCharSet = registry_to_w32_charset (tmp);
+ else
+ logfont->lfCharSet = DEFAULT_CHARSET;
/* Out Precision */
user input. */
else if (SYMBOLP (tmp))
strncpy (logfont->lfFaceName, SDATA (SYMBOL_NAME (tmp)), LF_FACESIZE);
- else if (STRINGP (tmp))
- strncpy (logfont->lfFaceName, SDATA (tmp), LF_FACESIZE);
+ }
+
+ 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 (INTEGERP (tmp))
+ {
+ int spacing = XINT (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 ( ; CONSP (extra); extra = XCDR (extra))
+ 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);
- if (EQ (key, QCfamily))
- {
- /* Override generic family. */
- BYTE family = w32_generic_family (val);
- if (family != FF_DONTCARE)
- logfont->lfPitchAndFamily
- = logfont->lfPitchAndFamily & 0x0F | family;
- }
- else if (EQ (key, QCspacing))
- {
- /* Set pitch based on the spacing property. */
- if (INTEGERP (val))
- {
- int spacing = XINT (val);
- if (spacing < FONT_SPACING_MONO)
- logfont->lfPitchAndFamily
- = logfont->lfPitchAndFamily & 0xF0 | VARIABLE_PITCH;
- else
- logfont->lfPitchAndFamily
- = logfont->lfPitchAndFamily & 0xF0 | FIXED_PITCH;
- }
- else if (EQ (val, Qp))
- logfont->lfPitchAndFamily
- = logfont->lfPitchAndFamily & 0xF0 | VARIABLE_PITCH;
- else if (EQ (val, Qc) || EQ (val, Qm))
- logfont->lfPitchAndFamily
- = logfont->lfPitchAndFamily & 0xF0 | FIXED_PITCH;
- }
/* 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. */
- else if (EQ (key, QCscript)
+ if (EQ (key, QCscript)
&& logfont->lfCharSet == DEFAULT_CHARSET
&& SYMBOLP (val))
{
families = CDR (families);
if (NILP (family))
continue;
- else if (STRINGP (family))
- name = SDATA (family);
+ else if (SYMBOLP (family))
+ name = SDATA (SYMBOL_NAME (family));
else
- name = SDATA (SYMBOL_NAME (family));
+ continue;
strncpy (match_data->pattern.lfFaceName, name, LF_FACESIZE);
match_data->pattern.lfFaceName[LF_FACESIZE - 1] = '\0';
|| (subranges[2] & (mask2)) || (subranges[3] & (mask3))) \
supported = Fcons ((sym), supported)
- SUBRANGE (0, Qlatin); /* There are many others... */
-
+ SUBRANGE (0, Qlatin);
+ /* The following count as latin too, ASCII should be present in these fonts,
+ so don't need to mark them separately. */
+ /* 1: Latin-1 supplement, 2: Latin Extended A, 3: Latin Extended B. */
+ SUBRANGE (4, Qphonetic);
+ /* 5: Spacing and tone modifiers, 6: Combining Diacriticals. */
SUBRANGE (7, Qgreek);
SUBRANGE (8, Qcoptic);
SUBRANGE (9, Qcyrillic);
SUBRANGE (24, Qthai);
SUBRANGE (25, Qlao);
SUBRANGE (26, Qgeorgian);
-
+ SUBRANGE (27, Qbalinese);
+ /* 28: Hangul Jamo. */
+ /* 29: Latin Extended, 30: Greek Extended, 31: Punctuation. */
+ /* 32-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);
- SUBRANGE (54, Qkanbun); /* Is this right? */
+ /* 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, Qideographic_description); /* Windows lumps this in. */
+ SUBRANGE (59, Qkanbun); /* And this. */
+ /* 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 (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);
-
- /* Match either katakana or hiragana for kana. */
- MASK_ANY (0, 0x00060000, 0, 0, Qkana);
+ /* 90: Private use, 91: Variation selectors, 92: Tags. */
+ SUBRANGE (93, Qlimbu);
+ SUBRANGE (94, Qtai_le);
+ /* 95: New Tai Le */
+ SUBRANGE (90, Qbuginese);
+ SUBRANGE (97, Qglagolitic);
+ SUBRANGE (98, Qtifinagh);
+ /* 99: Yijing Hexagrams. */
+ SUBRANGE (100, Qsyloti_nagri);
+ SUBRANGE (101, Qlinear_b);
+ /* 102: Ancient Greek Numbers. */
+ SUBRANGE (103, Qugaritic);
+ SUBRANGE (104, Qold_persian);
+ SUBRANGE (105, Qshavian);
+ SUBRANGE (106, Qosmanya);
+ SUBRANGE (107, Qcypriot);
+ SUBRANGE (108, Qkharoshthi);
+ /* 109: Tai Xuan Jing. */
+ SUBRANGE (110, Qcuneiform);
+ /* 111: Counting Rods. */
/* There isn't really a main symbol range, so include symbol if any
relevant range is set. */
MASK_ANY (0x8000000, 0x0000FFFF, 0, 0, Qsymbol);
+ /* Missing: Tai Viet (U+AA80) and Cham (U+AA00) . */
#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 (font, font_obj, pixel_size, name, nbytes)
+ 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 = strlen (font->lfFaceName) + 21;
+
+ if (font->lfItalic)
+ len += 7; /* :italic */
+
+ if (font->lfWeight && font->lfWeight != FW_NORMAL)
+ {
+ weight = FONT_WEIGHT_SYMBOLIC (font_obj);
+ len += 8 + SBYTES (SYMBOL_NAME (weight)); /* :weight=NAME */
+ }
+
+ 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)
+ {
+ float 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 (font->lfItalic)
+ p += sprintf (p, ":italic");
+
+ if (SYMBOLP (weight) && ! NILP (weight))
+ p += sprintf (p, ":weight=%s", SDATA (SYMBOL_NAME (weight)));
+
+ if (SYMBOLP (antialiasing) && ! NILP (antialiasing))
+ p += sprintf (p, ":antialias=%s", SDATA (SYMBOL_NAME (antialiasing)));
+
+ return (p - name);
+}
+
+
+static void
+compute_metrics (dc, w32_font, code, 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;
+
+ if (w32_font->glyph_idx)
+ options |= GGO_GLYPH_INDEX;
+
+ bzero (&transform, sizeof (transform));
+ transform.eM11.value = 1;
+ transform.eM22.value = 1;
+
+ if (GetGlyphOutlineW (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->status = W32METRIC_SUCCESS;
+ }
+ else if (w32_font->glyph_idx)
+ {
+ /* Can't use glyph indexes after all.
+ Avoid it in future, and clear any metrics that were based on
+ glyph indexes. */
+ w32_font->glyph_idx = 0;
+ clear_cached_metrics (w32_font);
+ }
+ else
+ metrics->status = W32METRIC_FAIL;
+}
+
+static void
+clear_cached_metrics (w32_font)
+ struct w32font_info *w32_font;
+{
+ int i;
+ for (i = 0; i < w32_font->n_cache_blocks; i++)
+ {
+ if (w32_font->cached_metrics[i])
+ bzero (w32_font->cached_metrics[i],
+ CACHE_BLOCKSIZE * sizeof (struct font_metrics));
+ }
+}
struct font_driver w32font_driver =
{
0, /* Qgdi */
+ 0, /* case insensitive */
w32font_get_cache,
w32font_list,
w32font_match,
syms_of_w32font ()
{
DEFSYM (Qgdi, "gdi");
+ DEFSYM (Quniscribe, "uniscribe");
+ DEFSYM (QCformat, ":format");
/* Generic font families. */
DEFSYM (Qmonospace, "monospace");
DEFSYM (Qserif, "serif");
- DEFSYM (Qsans_serif, "sans-serif");
+ DEFSYM (Qsansserif, "sansserif");
DEFSYM (Qscript, "script");
DEFSYM (Qdecorative, "decorative");
/* Aliases. */
- DEFSYM (Qsans__serif, "sans_serif");
+ DEFSYM (Qsans_serif, "sans_serif");
DEFSYM (Qsans, "sans");
DEFSYM (Qmono, "mono");
DEFSYM (Qsubpixel, "subpixel");
DEFSYM (Qnatural, "natural");
+ /* Languages */
+ DEFSYM (Qja, "ja");
+ DEFSYM (Qko, "ko");
+ DEFSYM (Qzh, "zh");
+
/* Scripts */
DEFSYM (Qlatin, "latin");
DEFSYM (Qgreek, "greek");
DEFSYM (Qbyzantine_musical_symbol, "byzantine-musical-symbol");
DEFSYM (Qmusical_symbol, "musical-symbol");
DEFSYM (Qmathematical, "mathematical");
+ 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 (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");
w32font_driver.type = Qgdi;
register_font_driver (&w32font_driver, NULL);