X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/c35f9821de5ec0cf127185890191ad0154600d0d..f5497e458ada626917620248ec1238dc44fa7fd1:/src/w32uniscribe.c diff --git a/src/w32uniscribe.c b/src/w32uniscribe.c index 366287e8de..1b5984fbea 100644 --- a/src/w32uniscribe.c +++ b/src/w32uniscribe.c @@ -34,6 +34,7 @@ along with GNU Emacs. If not, see . */ #include "dispextern.h" #include "character.h" #include "charset.h" +#include "composite.h" #include "fontset.h" #include "font.h" #include "w32font.h" @@ -120,10 +121,13 @@ uniscribe_open (f, font_entity, pixel_size) int pixel_size; { Lisp_Object font_object - = font_make_object (VECSIZE (struct uniscribe_font_info)); + = font_make_object (VECSIZE (struct uniscribe_font_info), + font_entity, pixel_size); struct uniscribe_font_info *uniscribe_font = (struct uniscribe_font_info *) XFONT_OBJECT (font_object); + ASET (font_object, FONT_TYPE_INDEX, Quniscribe); + if (!w32font_open_internal (f, font_entity, pixel_size, font_object)) { return Qnil; @@ -131,6 +135,10 @@ uniscribe_open (f, font_entity, pixel_size) /* 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.props[FONT_FORMAT_INDEX] = Qopentype; uniscribe_font->w32_font.font.driver = &uniscribe_font_driver; @@ -147,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); } @@ -203,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++) @@ -236,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. */ @@ -247,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; @@ -257,35 +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, FONT_HANDLE(font)); - 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; @@ -301,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; @@ -313,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) @@ -360,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 @@ -385,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; @@ -408,34 +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, FONT_HANDLE(font)); + 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; } /* @@ -496,8 +601,7 @@ add_opentype_font_name_to_list (logical_font, physical_font, font_type, && !(physical_font->ntmFontSig.fsUsb[0] & 0x3fffffff)) return 1; - family = font_intern_prop (logical_font->elfLogFont.lfFaceName, - strlen (logical_font->elfLogFont.lfFaceName), 1); + family = intern_font_name (logical_font->elfLogFont.lfFaceName); if (! memq_no_quit (family, *list)) *list = Fcons (family, *list); @@ -632,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. */