X-Git-Url: http://git.hcoop.net/bpt/emacs.git/blobdiff_plain/341dd15a7bd9d0b4adff846e94289b3e1877eed1..e3021fe7dbe7a4bbbe9b4c9433c0f01f64cdcef3:/src/w32uniscribe.c diff --git a/src/w32uniscribe.c b/src/w32uniscribe.c index 6682def4f1..1b5984fbea 100644 --- a/src/w32uniscribe.c +++ b/src/w32uniscribe.c @@ -3,10 +3,10 @@ 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 3, 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 @@ -14,11 +14,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with GNU Emacs; 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 . */ -#ifdef USE_FONT_BACKEND #include /* Override API version - Uniscribe is only available as standard since @@ -37,6 +34,7 @@ Boston, MA 02110-1301, USA. */ #include "dispextern.h" #include "character.h" #include "charset.h" +#include "composite.h" #include "fontset.h" #include "font.h" #include "w32font.h" @@ -79,14 +77,18 @@ static Lisp_Object uniscribe_list (frame, font_spec) Lisp_Object frame, font_spec; { - return w32font_list_internal (frame, font_spec, 1); + Lisp_Object fonts = w32font_list_internal (frame, font_spec, 1); + font_add_log ("uniscribe-list", font_spec, fonts); + return fonts; } static Lisp_Object uniscribe_match (frame, font_spec) Lisp_Object frame, font_spec; { - return w32font_match_internal (frame, font_spec, 1); + Lisp_Object entity = w32font_match_internal (frame, font_spec, 1); + font_add_log ("uniscribe-match", font_spec, entity); + return entity; } static Lisp_Object @@ -112,32 +114,36 @@ uniscribe_list_family (frame) return list; } -static struct font * +static Lisp_Object uniscribe_open (f, font_entity, pixel_size) FRAME_PTR f; Lisp_Object font_entity; int pixel_size; { + Lisp_Object font_object + = font_make_object (VECSIZE (struct uniscribe_font_info), + font_entity, pixel_size); struct uniscribe_font_info *uniscribe_font - = xmalloc (sizeof (struct uniscribe_font_info)); + = (struct uniscribe_font_info *) XFONT_OBJECT (font_object); - if (uniscribe_font == NULL) - return NULL; + ASET (font_object, FONT_TYPE_INDEX, Quniscribe); - if (!w32font_open_internal (f, font_entity, pixel_size, - (struct w32font_info *) uniscribe_font)) + if (!w32font_open_internal (f, font_entity, pixel_size, font_object)) { - xfree (uniscribe_font); - return NULL; + return Qnil; } /* Initialize the cache for this font. */ uniscribe_font->cache = NULL; + + /* Uniscribe backend uses glyph indices. */ + uniscribe_font->w32_font.glyph_idx = ETO_GLYPH_INDEX; + /* Mark the format as opentype */ - uniscribe_font->w32_font.font.format = Qopentype; + uniscribe_font->w32_font.font.props[FONT_FORMAT_INDEX] = Qopentype; uniscribe_font->w32_font.font.driver = &uniscribe_font_driver; - return (struct font *) uniscribe_font; + return font_object; } static void @@ -149,7 +155,7 @@ uniscribe_close (f, font) = (struct uniscribe_font_info *) font; if (uniscribe_font->cache) - ScriptFreeCache (&uniscribe_font->cache); + ScriptFreeCache (&(uniscribe_font->cache)); w32font_close (f, font); } @@ -168,8 +174,7 @@ uniscribe_otf_capability (font) f = XFRAME (selected_frame); context = get_frame_dc (f); - old_font = SelectObject (context, - ((W32FontStruct *) (font->font.font))->hfont); + old_font = SelectObject (context, FONT_HANDLE(font)); features = otf_features (context, "GSUB"); XSETCAR (capability, features); @@ -206,22 +211,20 @@ uniscribe_shape (lgstring) wchar_t *chars; WORD *glyphs, *clusters; SCRIPT_ITEM *items; - SCRIPT_CONTROL control; SCRIPT_VISATTR *attributes; int *advances; GOFFSET *offsets; ABC overall_metrics; - MAT2 transform; - HDC context; - HFONT old_font; HRESULT result; - struct frame * f; + struct frame * f = NULL; + HDC context = NULL; + HFONT old_font = NULL; CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring), font); uniscribe_font = (struct uniscribe_font_info *) font; /* Get the chars from lgstring in a form we can use with uniscribe. */ - max_glyphs = nchars = LGSTRING_LENGTH (lgstring); + max_glyphs = nchars = LGSTRING_GLYPH_LEN (lgstring); done_glyphs = 0; chars = (wchar_t *) alloca (nchars * sizeof (wchar_t)); for (i = 0; i < nchars; i++) @@ -239,9 +242,8 @@ uniscribe_shape (lgstring) can be treated together. First try a single run. */ max_items = 2; items = (SCRIPT_ITEM *) xmalloc (sizeof (SCRIPT_ITEM) * max_items + 1); - bzero (&control, sizeof (control)); - while ((result = ScriptItemize (chars, nchars, max_items, &control, NULL, + while ((result = ScriptItemize (chars, nchars, max_items, NULL, NULL, items, &nitems)) == E_OUTOFMEMORY) { /* If that wasn't enough, keep trying with one more run. */ @@ -250,8 +252,7 @@ uniscribe_shape (lgstring) sizeof (SCRIPT_ITEM) * max_items + 1); } - /* 0 = success in Microsoft's backwards world. */ - if (result) + if (FAILED (result)) { xfree (items); return Qnil; @@ -260,36 +261,46 @@ uniscribe_shape (lgstring) /* TODO: When we get BIDI support, we need to call ScriptLayout here. Requires that we know the surrounding context. */ - f = XFRAME (selected_frame); - context = get_frame_dc (f); - old_font = SelectObject (context, - ((W32FontStruct *) (font->font.font))->hfont); - glyphs = alloca (max_glyphs * sizeof (WORD)); clusters = alloca (nchars * sizeof (WORD)); attributes = alloca (max_glyphs * sizeof (SCRIPT_VISATTR)); advances = alloca (max_glyphs * sizeof (int)); offsets = alloca (max_glyphs * sizeof (GOFFSET)); - bzero (&transform, sizeof (transform)); - transform.eM11.value = 1; - transform.eM22.value = 1; for (i = 0; i < nitems; i++) { int nglyphs, nchars_in_run, rtl = items[i].a.fRTL ? -1 : 1; nchars_in_run = items[i+1].iCharPos - items[i].iCharPos; + /* Context may be NULL here, in which case the cache should be + used without needing to select the font. */ result = ScriptShape (context, &(uniscribe_font->cache), chars + items[i].iCharPos, nchars_in_run, max_glyphs - done_glyphs, &(items[i].a), glyphs, clusters, attributes, &nglyphs); + + if (result == E_PENDING && !context) + { + /* This assumes the selected frame is on the same display as the + one we are drawing. It would be better for the frame to be + passed in. */ + f = XFRAME (selected_frame); + context = get_frame_dc (f); + old_font = SelectObject (context, FONT_HANDLE(font)); + + result = ScriptShape (context, &(uniscribe_font->cache), + chars + items[i].iCharPos, nchars_in_run, + max_glyphs - done_glyphs, &(items[i].a), + glyphs, clusters, attributes, &nglyphs); + } + if (result == E_OUTOFMEMORY) { /* Need a bigger lgstring. */ lgstring = Qnil; break; } - else if (result) /* Failure. */ + else if (FAILED (result)) { /* Can't shape this run - return results so far if any. */ break; @@ -305,7 +316,18 @@ uniscribe_shape (lgstring) result = ScriptPlace (context, &(uniscribe_font->cache), glyphs, nglyphs, attributes, &(items[i].a), advances, offsets, &overall_metrics); - if (result == 0) /* Success. */ + if (result == E_PENDING && !context) + { + /* Cache not complete... */ + f = XFRAME (selected_frame); + context = get_frame_dc (f); + old_font = SelectObject (context, FONT_HANDLE(font)); + + result = ScriptPlace (context, &(uniscribe_font->cache), + glyphs, nglyphs, attributes, &(items[i].a), + advances, offsets, &overall_metrics); + } + if (SUCCEEDED (result)) { int j, nclusters, from, to; @@ -317,13 +339,18 @@ uniscribe_shape (lgstring) int lglyph_index = j + done_glyphs; Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, lglyph_index); ABC char_metric; + unsigned gl; if (NILP (lglyph)) { lglyph = Fmake_vector (make_number (LGLYPH_SIZE), Qnil); LGSTRING_SET_GLYPH (lgstring, lglyph_index, lglyph); } - LGLYPH_SET_CODE (lglyph, glyphs[j]); + /* Copy to a 32-bit data type to shut up the + compiler warning in LGLYPH_SET_CODE about + comparison being always false. */ + gl = glyphs[j]; + LGLYPH_SET_CODE (lglyph, gl); /* Detect clusters, for linking codes back to characters. */ if (attributes[j].fClusterStart) @@ -364,8 +391,18 @@ uniscribe_shape (lgstring) result = ScriptGetGlyphABCWidth (context, &(uniscribe_font->cache), glyphs[j], &char_metric); + if (result == E_PENDING && !context) + { + /* Cache incomplete... */ + f = XFRAME (selected_frame); + context = get_frame_dc (f); + old_font = SelectObject (context, FONT_HANDLE(font)); + result = ScriptGetGlyphABCWidth (context, + &(uniscribe_font->cache), + glyphs[j], &char_metric); + } - if (result == 0) /* Success. */ + if (SUCCEEDED (result)) { LGLYPH_SET_LBEARING (lglyph, char_metric.abcA); LGLYPH_SET_RBEARING (lglyph, (char_metric.abcA @@ -389,14 +426,19 @@ uniscribe_shape (lgstring) } else LGLYPH_SET_ADJUSTMENT (lglyph, Qnil); - } } + } + } } done_glyphs += nglyphs; } xfree (items); - SelectObject (context, old_font); - release_frame_dc (f, context); + + if (context) + { + SelectObject (context, old_font); + release_frame_dc (f, context); + } if (NILP (lgstring)) return Qnil; @@ -412,35 +454,93 @@ uniscribe_encode_char (font, c) struct font *font; int c; { - wchar_t chars[1]; - WORD indices[1]; - HDC context; - struct frame *f; - HFONT old_font; - DWORD retval; - - /* TODO: surrogates. */ - if (c > 0xFFFF) - return FONT_INVALID_CODE; - - chars[0] = (wchar_t) c; + HDC context = NULL; + struct frame *f = NULL; + HFONT old_font = NULL; + unsigned code = FONT_INVALID_CODE; + wchar_t ch[2]; + int len; + SCRIPT_ITEM* items; + int nitems; + struct uniscribe_font_info *uniscribe_font + = (struct uniscribe_font_info *)font; - /* Use selected frame until API is updated to pass the frame. */ - f = XFRAME (selected_frame); - context = get_frame_dc (f); - old_font = SelectObject (context, - ((W32FontStruct *)(font->font.font))->hfont); + if (c < 0x10000) + { + ch[0] = (wchar_t) c; + len = 1; + } + else + { + DWORD surrogate = c - 0x10000; - retval = GetGlyphIndicesW (context, chars, 1, indices, - GGI_MARK_NONEXISTING_GLYPHS); + /* High surrogate: U+D800 - U+DBFF. */ + ch[0] = 0xD800 + ((surrogate >> 10) & 0x03FF); + /* Low surrogate: U+DC00 - U+DFFF. */ + ch[1] = 0xDC00 + (surrogate & 0x03FF); + len = 2; + } - SelectObject (context, old_font); - release_frame_dc (f, context); + /* Non BMP characters must be handled by the uniscribe shaping + engine as GDI functions (except blindly displaying lines of + unicode text) and the promising looking ScriptGetCMap do not + convert surrogate pairs to glyph indexes correctly. */ + { + items = (SCRIPT_ITEM *) alloca (sizeof (SCRIPT_ITEM) * 2 + 1); + if (SUCCEEDED (ScriptItemize (ch, len, 2, NULL, NULL, items, &nitems))) + { + HRESULT result; + /* Surrogates seem to need 2 here, even though only one glyph is + returned. Indic characters can also produce 2 or more glyphs for + a single code point, but they need to use uniscribe_shape + above for correct display. */ + WORD glyphs[2], clusters[2]; + SCRIPT_VISATTR attrs[2]; + int nglyphs; + + result = ScriptShape (context, &(uniscribe_font->cache), + ch, len, 2, &(items[0].a), + glyphs, clusters, attrs, &nglyphs); + + if (result == E_PENDING) + { + /* Use selected frame until API is updated to pass + the frame. */ + f = XFRAME (selected_frame); + context = get_frame_dc (f); + old_font = SelectObject (context, FONT_HANDLE(font)); + result = ScriptShape (context, &(uniscribe_font->cache), + ch, len, 2, &(items[0].a), + glyphs, clusters, attrs, &nglyphs); + } + + if (SUCCEEDED (result) && nglyphs == 1) + { + /* Some fonts return .notdef glyphs instead of failing. + (Truetype spec reserves glyph code 0 for .notdef) */ + if (glyphs[0]) + code = glyphs[0]; + } + else if (SUCCEEDED (result) || result == E_OUTOFMEMORY) + { + /* This character produces zero or more than one glyph + when shaped. But we still need the return from here + to be valid for the shaping engine to be invoked + later. */ + result = ScriptGetCMap (context, &(uniscribe_font->cache), + ch, len, 0, glyphs); + if (SUCCEEDED (result) && glyphs[0]) + code = glyphs[0]; + } + } + } + if (context) + { + SelectObject (context, old_font); + release_frame_dc (f, context); + } - if (retval == 1) - return indices[0] == 0xFFFF ? FONT_INVALID_CODE : indices[0]; - else - return FONT_INVALID_CODE; + return code; } /* @@ -494,8 +594,14 @@ add_opentype_font_name_to_list (logical_font, physical_font, font_type, && font_type != TRUETYPE_FONTTYPE) return 1; - family = intern_downcase (logical_font->elfLogFont.lfFaceName, - strlen (logical_font->elfLogFont.lfFaceName)); + /* Skip fonts that have no unicode coverage. */ + if (!physical_font->ntmFontSig.fsUsb[3] + && !physical_font->ntmFontSig.fsUsb[2] + && !physical_font->ntmFontSig.fsUsb[1] + && !(physical_font->ntmFontSig.fsUsb[0] & 0x3fffffff)) + return 1; + + family = intern_font_name (logical_font->elfLogFont.lfFaceName); if (! memq_no_quit (family, *list)) *list = Fcons (family, *list); @@ -630,10 +736,12 @@ int uniscribe_check_otf (font, otf_spec) OTF_INT16_VAL (tbl, scriptlist_table + 6 + j * 6, &script_table); break; } +#if 0 /* Causes false positives. */ /* If there is a DFLT script defined in the font, use it if the specified script is not found. */ else if (script_id == default_script) OTF_INT16_VAL (tbl, scriptlist_table + 6 + j * 6, &script_table); +#endif } /* If no specific or default script table was found, then this font does not support the script. */ @@ -819,6 +927,7 @@ font_table_error: struct font_driver uniscribe_font_driver = { 0, /* Quniscribe */ + 0, /* case insensitive */ w32font_get_cache, uniscribe_list, uniscribe_match, @@ -866,7 +975,5 @@ syms_of_w32uniscribe () register_font_driver (&uniscribe_font_driver, NULL); } -#endif /* USE_FONT_BACKEND */ - /* arch-tag: 9530f0e1-7471-47dd-a780-94330af87ea0 (do not change this comment) */