/* 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
it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
any later version.
GNU Emacs is distributed in the hope that it will be useful,
#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;
+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 */
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 *match));
/* MingW headers only define this when _WIN32_WINNT >= 0x0500, but we
target older versions. */
+#ifndef GGI_MARK_NONEXISTING_GLYPHS
#define GGI_MARK_NONEXISTING_GLYPHS 1
+#endif
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). */
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));
- struct font * font = (struct font *) w32_font;
- if (!font)
+ if (w32_font == NULL)
return NULL;
- 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, w32_font))
{
xfree (w32_font);
return NULL;
}
- /* 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 (struct font *) w32_font;
}
/* 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;
font->font.font = 0;
}
+ if (font->font.full_name && font->font.full_name != font->font.name)
+ xfree (font->font.full_name);
+
if (font->font.name)
xfree (font->font.name);
+
xfree (font);
}
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;
/* w32 implementation of encode_char for font backend.
Return a glyph code of FONT for characer C (Unicode code point).
If FONT doesn't have such a glyph, return FONT_INVALID_CODE. */
-static unsigned
+unsigned
w32font_encode_char (font, c)
struct font *font;
int c;
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;
{
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);
+ HDC dc;
+ struct frame * f;
int total_width = 0;
WORD *wcode = alloca(nglyphs * sizeof (WORD));
SIZE size;
+#if 0
+ /* Frames can come and go, and their fonts outlive them. This is
+ particularly troublesome with tooltip frames, and causes crashes. */
+ f = ((struct w32font_info *)font)->owning_frame;
+#else
+ f = XFRAME (selected_frame);
+#endif
+
+ dc = get_frame_dc (f);
old_font = SelectObject (dc, ((W32FontStruct *)(font->font.font))->hfont);
if (metrics)
{
/* Restore state and release DC. */
SelectObject (dc, old_font);
- ReleaseDC (NULL, dc);
+ release_frame_dc (f, dc);
return metrics->width;
}
/* 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;
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)
{
- SetBkColor (s->hdc, s->gc->background);
- SetBkMode (s->hdc, OPAQUE);
-#if 0
HBRUSH brush;
RECT rect;
+ struct font *font = (struct font *) s->face->font_info;
brush = CreateSolidBrush (s->gc->background);
rect.left = x;
- rect.top = y - ((struct font *) (s->font_info->font))->ascent;
+ rect.top = y - font->ascent;
rect.right = x + s->width;
- rect.bottom = y + ((struct font *) (s->font_info->font))->descent;
+ rect.bottom = y + font->descent;
FillRect (s->hdc, &rect, brush);
DeleteObject (brush);
-#endif
}
- else
- SetBkMode (s->hdc, TRANSPARENT);
ExtTextOutW (s->hdc, x, y, options, NULL, s->char2b + from, to - from, NULL);
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) ? null_vector : Fvconcat (1, &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, w32_font)
+ FRAME_PTR f;
+ Lisp_Object font_entity;
+ int pixel_size;
+ struct w32font_info *w32_font;
+{
+ int len, size;
+ LOGFONT logfont;
+ HDC dc;
+ HFONT hfont, old_font;
+ Lisp_Object val, extra;
+ /* For backwards compatibility. */
+ W32FontStruct *compat_w32_font;
+
+ struct font * font = (struct font *) w32_font;
+ if (!font)
+ return 0;
+
+ 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)
+ return 0;
+
+ w32_font->owning_frame = f;
+
+ /* 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';
+
+ {
+ 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 = malloc (len);
+ while (name && font_unparse_fcname (font_entity, pixel_size, name, len) < 0)
+ {
+ char *new = realloc (name, len += 32);
+
+ if (! new)
+ free (name);
+ name = new;
+ }
+ if (name)
+ font->font.full_name = name;
+ else
+ 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 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 (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);
+ tem = null_string;
+
+ ASET (entity, FONT_ADSTYLE_INDEX, tem);
if (physical_font->ntmTm.tmPitchAndFamily & 0x01)
font_put_extra (entity, QCspacing, make_number (FONT_SPACING_PROPORTIONAL));
/* 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;
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 extra parameters. */
for (extra = AREF (spec, FONT_EXTRA_INDEX);
CONSP (extra); extra = XCDR (extra))
{
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))
+ if (EQ (key, QCspacing))
{
int proportional;
if (INTEGERP (val))
struct font_callback_data *match_data
= (struct font_callback_data *) lParam;
- if (logfonts_match (&logical_font->elfLogFont, &match_data->pattern)
+ if ((!match_data->opentype_only
+ || (physical_font->ntmTm.ntmFlags & NTMFLAGS_OPENTYPE))
+ && 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))
+ /* 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,
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;
+ }
+
/* Process EXTRA info. */
for ( ; CONSP (extra); extra = XCDR (extra))
{
{
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))
+ if (EQ (key, QCspacing))
{
/* Set pitch based on the spacing property. */
if (INTEGERP (val))
NULL, /* free_outline */
NULL, /* anchor_point */
NULL, /* otf_capability */
- NULL /* otf_drive */
+ NULL, /* otf_drive */
+ NULL, /* start_for_frame */
+ NULL, /* end_for_frame */
+ NULL /* shape */
};
/* 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");