X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/657d08d30a63536174fe9ec60b7f2cb8de541eb5..017a270078be5ae39301e3205afad80d23facbbc:/src/w32font.c diff --git a/src/w32font.c b/src/w32font.c index f47b7a46b1..833b7cdfb2 100644 --- a/src/w32font.c +++ b/src/w32font.c @@ -1,5 +1,5 @@ -/* Font backend for the Microsoft W32 API. - Copyright (C) 2007-2011 Free Software Foundation, Inc. +/* Font backend for the Microsoft Windows API. + Copyright (C) 2007-2012 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -21,7 +21,6 @@ along with GNU Emacs. If not, see . */ #include #include #include -#include #include "lisp.h" #include "w32term.h" @@ -62,7 +61,6 @@ static Lisp_Object Qserif, Qscript, Qdecorative; static Lisp_Object Qraster, Qoutline, Qunknown; /* antialiasing */ -extern Lisp_Object Qnone; /* reuse from w32fns.c */ static Lisp_Object Qstandard, Qsubpixel, Qnatural; /* languages */ @@ -75,7 +73,7 @@ static Lisp_Object Qgurmukhi, Qgujarati, Qoriya, Qtamil, Qtelugu; static Lisp_Object Qkannada, Qmalayalam, Qsinhala, Qthai, Qlao; static Lisp_Object Qtibetan, Qmyanmar, Qgeorgian, Qhangul, Qethiopic; static Lisp_Object Qcherokee, Qcanadian_aboriginal, Qogham, Qrunic; -static Lisp_Object Qkhmer, Qmongolian, Qsymbol, Qbraille, Qhan; +static Lisp_Object Qkhmer, Qmongolian, Qbraille, Qhan; static Lisp_Object Qideographic_description, Qcjk_misc, Qkana, Qbopomofo; static Lisp_Object Qkanbun, Qyi, Qbyzantine_musical_symbol; static Lisp_Object Qmusical_symbol, Qmathematical, Qcham, Qphonetic; @@ -145,6 +143,135 @@ struct font_callback_data style variations if the font name is not specified. */ static void list_all_matching_fonts (struct font_callback_data *); +static BOOL g_b_init_is_w9x; +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_glyph_outline_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); + +/* 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) +{ + static BOOL is_9x = 0; + OSVERSIONINFO os_ver; + HMODULE ret; + if (g_b_init_is_w9x == 0) + { + g_b_init_is_w9x = 1; + ZeroMemory (&os_ver, sizeof (OSVERSIONINFO)); + os_ver.dwOSVersionInfoSize = sizeof (OSVERSIONINFO); + if (GetVersionEx (&os_ver)) + is_9x = (os_ver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS); + } + if (is_9x) + { + ret = LoadLibrary ("Unicows.dll"); + if (!ret) + { + int button; + + button = MessageBox (NULL, + "Emacs cannot load the UNICOWS.DLL library.\n" + "This library is essential for using Emacs\n" + "on this system. You need to install it.\n\n" + "However, you can still use Emacs by invoking\n" + "it with the '-nw' command-line option.\n\n" + "Emacs will exit when you click OK.", + "Emacs cannot load UNICOWS.DLL", + MB_ICONERROR | MB_TASKMODAL + | MB_SETFOREGROUND | MB_OK); + switch (button) + { + case IDOK: + default: + exit (1); + } + } + } + else + ret = LoadLibrary ("Gdi32.dll"); + return ret; +} + +/* 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) + GetProcAddress (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) + GetProcAddress (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) + GetProcAddress (hm_unicows, "GetGlyphOutlineW"); + } + eassert (s_pfn_Get_Glyph_OutlineW != NULL); + return s_pfn_Get_Glyph_OutlineW (hdc, uChar, uFormat, lpgm, cbBuffer, + lpvBuffer, lpmat2); +} static int memq_no_quit (Lisp_Object elt, Lisp_Object list) @@ -157,20 +284,12 @@ memq_no_quit (Lisp_Object elt, Lisp_Object list) Lisp_Object intern_font_name (char * string) { - Lisp_Object obarray, tem, str; - int len; - - str = DECODE_SYSTEM (build_string (string)); - len = SCHARS (str); - - /* The following code is copied from the function intern (in lread.c). */ - obarray = Vobarray; - if (!VECTORP (obarray) || ASIZE (obarray) == 0) - obarray = check_obarray (obarray); - tem = oblookup (obarray, SDATA (str), len, len); - if (SYMBOLP (tem)) - return tem; - return Fintern (str, obarray); + Lisp_Object str = DECODE_SYSTEM (build_string (string)); + int len = SCHARS (str); + Lisp_Object obarray = check_obarray (Vobarray); + Lisp_Object tem = oblookup (obarray, SDATA (str), len, len); + /* This code is similar to intern function from lread.c. */ + return SYMBOLP (tem) ? tem : Fintern (str, obarray); } /* w32 implementation of get_cache for font backend. @@ -198,7 +317,7 @@ w32font_list (Lisp_Object frame, Lisp_Object font_spec) /* w32 implementation of match for font backend. Return a font entity most closely matching with FONT_SPEC on - FRAME. The closeness is detemined by the font backend, thus + FRAME. The closeness is determined by the font backend, thus `face-font-selection-order' is ignored here. */ static Lisp_Object w32font_match (Lisp_Object frame, Lisp_Object font_spec) @@ -330,7 +449,7 @@ w32font_has_char (Lisp_Object entity, int c) 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 + 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. */ @@ -397,9 +516,7 @@ w32font_text_extents (struct font *font, unsigned *code, if (!w32_font->cached_metrics[block]) { w32_font->cached_metrics[block] - = xmalloc (CACHE_BLOCKSIZE * sizeof (struct w32_metric_cache)); - memset (w32_font->cached_metrics[block], 0, - CACHE_BLOCKSIZE * sizeof (struct w32_metric_cache)); + = xzalloc (CACHE_BLOCKSIZE * sizeof (struct w32_metric_cache)); } char_metric = w32_font->cached_metrics[block] + pos_in_block; @@ -488,7 +605,7 @@ w32font_text_extents (struct font *font, unsigned *code, total_width = size.cx; } - /* On 95/98/ME, only some unicode functions are available, so fallback + /* 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) { @@ -517,9 +634,9 @@ w32font_text_extents (struct font *font, unsigned *code, /* 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 - is nonzero, fill the background in advance. It is assured that - WITH_BACKGROUND is zero when (FROM > 0 || TO < S->nchars). + 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 @@ -529,7 +646,7 @@ w32font_text_extents (struct font *font, unsigned *code, int w32font_draw (struct glyph_string *s, int from, int to, - int x, int y, int with_background) + int x, int y, bool with_background) { UINT options; HRGN orig_clip = NULL; @@ -654,7 +771,7 @@ w32font_free_outline (struct font *font, void *outline); 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 successfull. Otherwise return -1. + the operations was successful. Otherwise return -1. static int w32font_anchor_point (struct font *font, unsigned code, int index, int *x, int *y); @@ -686,7 +803,7 @@ 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, - int alternate_subst); + bool alternate_subst); */ /* Internal implementation of w32font_list. @@ -816,11 +933,11 @@ w32font_open_internal (FRAME_PTR f, Lisp_Object font_entity, old_font = SelectObject (dc, hfont); /* Try getting the outline metrics (only works for truetype fonts). */ - len = GetOutlineTextMetricsW (dc, 0, NULL); + len = get_outline_metrics_w (dc, 0, NULL); if (len) { metrics = (OUTLINETEXTMETRICW *) alloca (len); - if (GetOutlineTextMetricsW (dc, len, metrics)) + if (get_outline_metrics_w (dc, len, metrics)) memcpy (&w32_font->metrics, &metrics->otmTextMetrics, sizeof (TEXTMETRICW)); else @@ -828,7 +945,7 @@ w32font_open_internal (FRAME_PTR f, Lisp_Object font_entity, } if (!metrics) - GetTextMetricsW (dc, &w32_font->metrics); + get_text_metrics_w (dc, &w32_font->metrics); w32_font->cached_metrics = NULL; w32_font->n_cache_blocks = 0; @@ -869,7 +986,6 @@ w32font_open_internal (FRAME_PTR f, Lisp_Object font_entity, 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; @@ -1021,7 +1137,7 @@ w32_enumfont_pattern_entity (Lisp_Object frame, else ASET (entity, FONT_SIZE_INDEX, make_number (0)); - /* Cache unicode codepoints covered by this font, as there is no other way + /* Cache Unicode codepoints covered by this font, as there is no other way of getting this information easily. */ if (font_type & TRUETYPE_FONTTYPE) { @@ -1152,14 +1268,23 @@ font_matches_spec (DWORD type, NEWTEXTMETRICEX *font, { /* 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. */ + 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 { @@ -1263,7 +1388,7 @@ font_matches_spec (DWORD type, NEWTEXTMETRICEX *font, 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 W32 API does not expose. Fontset + 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; @@ -1323,7 +1448,7 @@ check_face_name (LOGFONT *font, char *full_name) /* 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 + with Arial's characteristics, since that attempt to use TrueType works some places, but not others. */ if (!xstrcasecmp (font->lfFaceName, "helvetica")) { @@ -1351,7 +1476,7 @@ check_face_name (LOGFONT *font, char *full_name) /* Callback function for EnumFontFamiliesEx. - * Checks if a font matches everything we are trying to check agaist, + * 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. */ @@ -1373,9 +1498,9 @@ add_font_entity_to_list (ENUMLOGFONTEX *logical_font, /* Skip non matching fonts. */ /* For uniscribe backend, consider only truetype or opentype fonts - that have some unicode coverage. */ + that have some Unicode coverage. */ if (match_data->opentype_only - && ((!physical_font->ntmTm.ntmFlags & NTMFLAGS_OPENTYPE + && ((!(physical_font->ntmTm.ntmFlags & NTMFLAGS_OPENTYPE) && !(font_type & TRUETYPE_FONTTYPE)) || !is_unicode)) return 1; @@ -1416,7 +1541,7 @@ add_font_entity_to_list (ENUMLOGFONTEX *logical_font, Lisp_Object spec_charset = AREF (match_data->orig_font_spec, FONT_REGISTRY_INDEX); - /* iso10646-1 fonts must contain unicode mapping tables. */ + /* iso10646-1 fonts must contain Unicode mapping tables. */ if (EQ (spec_charset, Qiso10646_1)) { if (!is_unicode) @@ -1431,13 +1556,13 @@ add_font_entity_to_list (ENUMLOGFONTEX *logical_font, && !(physical_font->ntmFontSig.fsUsb[0] & 0x007F001F)) return 1; } - /* unicode-sip fonts must contain characters in unicode plane 2. + /* 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) + if (!(physical_font->ntmFontSig.fsUsb[1] & 0x02000000) + || !(physical_font->ntmFontSig.fsUsb[1] & 0x28000000)) return 1; } @@ -1445,10 +1570,18 @@ add_font_entity_to_list (ENUMLOGFONTEX *logical_font, /* If registry was specified, ensure it is reported as the same. */ if (!NILP (spec_charset)) - ASET (entity, FONT_REGISTRY_INDEX, 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. */ + fonts as Unicode and skip other charsets. */ else if (match_data->opentype_only) { if (logical_font->elfLogFont.lfCharSet == ANSI_CHARSET @@ -1491,7 +1624,7 @@ x_to_w32_charset (char * lpcs) if (strncmp (lpcs, "*-#", 3) == 0) return atoi (lpcs + 3); - /* All Windows fonts qualify as unicode. */ + /* All Windows fonts qualify as Unicode. */ if (!strncmp (lpcs, "iso10646", 8)) return DEFAULT_CHARSET; @@ -1776,7 +1909,7 @@ w32_registry (LONG w32_charset, DWORD font_type) { char *charset; - /* If charset is defaulted, charset is unicode or unknown, depending on + /* 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; @@ -1896,8 +2029,11 @@ fill_in_logfont (FRAME_PTR f, LOGFONT *logfont, Lisp_Object font_spec) /* Font families are interned, but allow for strings also in case of user input. */ else if (SYMBOLP (tmp)) - strncpy (logfont->lfFaceName, - SDATA (ENCODE_SYSTEM (SYMBOL_NAME (tmp))), LF_FACESIZE); + { + strncpy (logfont->lfFaceName, + SDATA (ENCODE_SYSTEM (SYMBOL_NAME (tmp))), LF_FACESIZE); + logfont->lfFaceName[LF_FACESIZE-1] = '\0'; + } } tmp = AREF (font_spec, FONT_ADSTYLE_INDEX); @@ -1931,7 +2067,7 @@ fill_in_logfont (FRAME_PTR f, LOGFONT *logfont, Lisp_Object font_spec) { Lisp_Object key, val; key = XCAR (tmp), val = XCDR (tmp); - /* Only use QCscript if charset is not provided, or is unicode + /* 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, @@ -2072,7 +2208,7 @@ font_supported_scripts (FONTSIGNATURE * sig) 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. */ + /* 5: Spacing and tone modifiers, 6: Combining Diacritical Marks. */ SUBRANGE (7, Qgreek); SUBRANGE (8, Qcoptic); SUBRANGE (9, Qcyrillic); @@ -2162,7 +2298,7 @@ font_supported_scripts (FONTSIGNATURE * sig) /* 115: Saurashtra, 116: Kayah Li, 117: Rejang. */ SUBRANGE (118, Qcham); /* 119: Ancient symbols, 120: Phaistos Disc. */ - /* 121: Carian, Lycian, Lydian, 122: Dominos, Mah Jong tiles. */ + /* 121: Carian, Lycian, Lydian, 122: Dominoes, Mahjong tiles. */ /* 123-127: Reserved. */ /* There isn't really a main symbol range, so include symbol if any @@ -2306,7 +2442,7 @@ compute_metrics (HDC dc, struct w32font_info *w32_font, unsigned int code, transform.eM11.value = 1; transform.eM22.value = 1; - if (GetGlyphOutlineW (dc, code, options, &gm, 0, NULL, &transform) + if (get_glyph_outline_w (dc, code, options, &gm, 0, NULL, &transform) != GDI_ERROR) { metrics->lbearing = gm.gmptGlyphOrigin.x; @@ -2492,7 +2628,6 @@ syms_of_w32font (void) DEFSYM (Qrunic, "runic"); DEFSYM (Qkhmer, "khmer"); DEFSYM (Qmongolian, "mongolian"); - DEFSYM (Qsymbol, "symbol"); DEFSYM (Qbraille, "braille"); DEFSYM (Qhan, "han"); DEFSYM (Qideographic_description, "ideographic-description"); @@ -2581,3 +2716,12 @@ versions of Windows) characters. */); w32font_driver.type = Qgdi; register_font_driver (&w32font_driver, NULL); } + +void +globals_of_w32font (void) +{ + g_b_init_is_w9x = 0; + g_b_init_get_outline_metrics_w = 0; + g_b_init_get_text_metrics_w = 0; + g_b_init_get_glyph_outline_w = 0; +}