Add separator.pbm tool-bar image
[emacs.git] / src / w32uniscribe.c
blob8b3bf60b4b6cde03aa3c45e23113ad009e2d858b
1 /* Font backend for the Microsoft W32 Uniscribe API.
2 Copyright (C) 2008-2015 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
6 GNU Emacs is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
20 #include <config.h>
21 /* Override API version - Uniscribe is only available as standard
22 since Windows 2000, though most users of older systems will have it
23 since it installs with Internet Explorer 5.0 and other software.
24 Also, MinGW64 w32api headers by default define OPENTYPE_TAG typedef
25 only if _WIN32_WINNT >= 0x0600. We only use the affected APIs if
26 they are available, so there is no chance of calling non-existent
27 functions. */
28 #undef _WIN32_WINNT
29 #define _WIN32_WINNT 0x0600
30 #include <windows.h>
31 #include <usp10.h>
33 #include "lisp.h"
34 #include "w32term.h"
35 #include "frame.h"
36 #include "dispextern.h"
37 #include "character.h"
38 #include "charset.h"
39 #include "composite.h"
40 #include "fontset.h"
41 #include "font.h"
42 #include "w32font.h"
44 struct uniscribe_font_info
46 struct w32font_info w32_font;
47 SCRIPT_CACHE cache;
50 int uniscribe_available = 0;
52 /* EnumFontFamiliesEx callback. */
53 static int CALLBACK ALIGN_STACK add_opentype_font_name_to_list (ENUMLOGFONTEX *,
54 NEWTEXTMETRICEX *,
55 DWORD, LPARAM);
56 /* Used by uniscribe_otf_capability. */
57 static Lisp_Object otf_features (HDC context, char *table);
59 static int
60 memq_no_quit (Lisp_Object elt, Lisp_Object list)
62 while (CONSP (list) && ! EQ (XCAR (list), elt))
63 list = XCDR (list);
64 return (CONSP (list));
68 /* Font backend interface implementation. */
69 static Lisp_Object
70 uniscribe_list (struct frame *f, Lisp_Object font_spec)
72 Lisp_Object fonts = w32font_list_internal (f, font_spec, true);
73 FONT_ADD_LOG ("uniscribe-list", font_spec, fonts);
74 return fonts;
77 static Lisp_Object
78 uniscribe_match (struct frame *f, Lisp_Object font_spec)
80 Lisp_Object entity = w32font_match_internal (f, font_spec, true);
81 FONT_ADD_LOG ("uniscribe-match", font_spec, entity);
82 return entity;
85 static Lisp_Object
86 uniscribe_list_family (struct frame *f)
88 Lisp_Object list = Qnil;
89 LOGFONT font_match_pattern;
90 HDC dc;
92 memset (&font_match_pattern, 0, sizeof (font_match_pattern));
93 /* Limit enumerated fonts to outline fonts to save time. */
94 font_match_pattern.lfOutPrecision = OUT_OUTLINE_PRECIS;
96 dc = get_frame_dc (f);
98 EnumFontFamiliesEx (dc, &font_match_pattern,
99 (FONTENUMPROC) add_opentype_font_name_to_list,
100 (LPARAM) &list, 0);
101 release_frame_dc (f, dc);
103 return list;
106 static Lisp_Object
107 uniscribe_open (struct frame *f, Lisp_Object font_entity, int pixel_size)
109 Lisp_Object font_object
110 = font_make_object (VECSIZE (struct uniscribe_font_info),
111 font_entity, pixel_size);
112 struct uniscribe_font_info *uniscribe_font
113 = (struct uniscribe_font_info *) XFONT_OBJECT (font_object);
115 ASET (font_object, FONT_TYPE_INDEX, Quniscribe);
117 if (!w32font_open_internal (f, font_entity, pixel_size, font_object))
119 return Qnil;
122 /* Initialize the cache for this font. */
123 uniscribe_font->cache = NULL;
125 /* Uniscribe backend uses glyph indices. */
126 uniscribe_font->w32_font.glyph_idx = ETO_GLYPH_INDEX;
128 uniscribe_font->w32_font.font.driver = &uniscribe_font_driver;
130 return font_object;
133 static void
134 uniscribe_close (struct font *font)
136 struct uniscribe_font_info *uniscribe_font
137 = (struct uniscribe_font_info *) font;
139 if (uniscribe_font->cache)
140 ScriptFreeCache (&(uniscribe_font->cache));
142 w32font_close (font);
145 /* Return a list describing which scripts/languages FONT supports by
146 which GSUB/GPOS features of OpenType tables.
148 Implementation note: otf_features called by this function uses
149 GetFontData to access the font tables directly, instead of using
150 ScriptGetFontScriptTags etc. APIs even if those are available. The
151 reason is that font-get, which uses the result of this function,
152 expects a cons cell (GSUB . GPOS) where the features are reported
153 separately for these 2 OTF tables, while the Uniscribe APIs report
154 the features as a single list. There doesn't seem to be a reason
155 for returning the features in 2 separate parts, except for
156 compatibility with libotf; the features are disjoint (each can
157 appear only in one of the 2 slots), and no client of this data
158 discerns between the two slots: the few that request this data all
159 look in both slots. If use of the Uniscribe APIs ever becomes
160 necessary here, and the 2 separate slots are still required, it
161 should be possible to split the feature list the APIs return into 2
162 because each sub-list is alphabetically sorted, so the place where
163 the sorting order breaks is where the GSUB features end and GPOS
164 features begin. But for now, this is not necessary, so we leave
165 the original code in place. */
166 static Lisp_Object
167 uniscribe_otf_capability (struct font *font)
169 HDC context;
170 HFONT old_font;
171 struct frame *f;
172 Lisp_Object capability = Fcons (Qnil, Qnil);
173 Lisp_Object features;
175 f = XFRAME (selected_frame);
176 context = get_frame_dc (f);
177 old_font = SelectObject (context, FONT_HANDLE (font));
179 features = otf_features (context, "GSUB");
180 XSETCAR (capability, features);
181 features = otf_features (context, "GPOS");
182 XSETCDR (capability, features);
184 SelectObject (context, old_font);
185 release_frame_dc (f, context);
187 return capability;
190 /* Uniscribe implementation of shape for font backend.
192 Shape text in LGSTRING. See the docstring of
193 `composition-get-gstring' for the format of LGSTRING. If the
194 (N+1)th element of LGSTRING is nil, input of shaping is from the
195 1st to (N)th elements. In each input glyph, FROM, TO, CHAR, and
196 CODE are already set.
198 This function updates all fields of the input glyphs. If the
199 output glyphs (M) are more than the input glyphs (N), (N+1)th
200 through (M)th elements of LGSTRING are updated possibly by making
201 a new glyph object and storing it in LGSTRING. If (M) is greater
202 than the length of LGSTRING, nil should be returned. In that case,
203 this function is called again with a larger LGSTRING. */
204 static Lisp_Object
205 uniscribe_shape (Lisp_Object lgstring)
207 struct font *font = CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring));
208 struct uniscribe_font_info *uniscribe_font
209 = (struct uniscribe_font_info *) font;
210 EMACS_UINT nchars;
211 int nitems, max_items, i, max_glyphs, done_glyphs;
212 wchar_t *chars;
213 WORD *glyphs, *clusters;
214 SCRIPT_ITEM *items;
215 SCRIPT_VISATTR *attributes;
216 int *advances;
217 GOFFSET *offsets;
218 ABC overall_metrics;
219 HRESULT result;
220 struct frame * f = NULL;
221 HDC context = NULL;
222 HFONT old_font = NULL;
224 /* Get the chars from lgstring in a form we can use with uniscribe. */
225 max_glyphs = nchars = LGSTRING_GLYPH_LEN (lgstring);
226 done_glyphs = 0;
227 chars = (wchar_t *) alloca (nchars * sizeof (wchar_t));
228 /* FIXME: This loop assumes that characters in the input LGSTRING
229 are all inside the BMP. Need to encode characters beyond the BMP
230 as UTF-16. */
231 for (i = 0; i < nchars; i++)
233 /* lgstring can be bigger than the number of characters in it, in
234 the case where more glyphs are required to display those characters.
235 If that is the case, note the real number of characters. */
236 if (NILP (LGSTRING_GLYPH (lgstring, i)))
237 nchars = i;
238 else
239 chars[i] = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, i));
242 /* First we need to break up the glyph string into runs of glyphs that
243 can be treated together. First try a single run. */
244 max_items = 2;
245 items = xmalloc (sizeof (SCRIPT_ITEM) * max_items + 1);
247 while ((result = ScriptItemize (chars, nchars, max_items, NULL, NULL,
248 items, &nitems)) == E_OUTOFMEMORY)
250 /* If that wasn't enough, keep trying with one more run. */
251 max_items++;
252 items = (SCRIPT_ITEM *) xrealloc (items,
253 sizeof (SCRIPT_ITEM) * max_items + 1);
256 if (FAILED (result))
258 xfree (items);
259 return Qnil;
262 glyphs = alloca (max_glyphs * sizeof (WORD));
263 clusters = alloca (nchars * sizeof (WORD));
264 attributes = alloca (max_glyphs * sizeof (SCRIPT_VISATTR));
265 advances = alloca (max_glyphs * sizeof (int));
266 offsets = alloca (max_glyphs * sizeof (GOFFSET));
268 for (i = 0; i < nitems; i++)
270 int nglyphs, nchars_in_run;
271 nchars_in_run = items[i+1].iCharPos - items[i].iCharPos;
272 /* Force ScriptShape to generate glyphs in the same order as
273 they are in the input LGSTRING, which is in the logical
274 order. */
275 items[i].a.fLogicalOrder = 1;
277 /* Context may be NULL here, in which case the cache should be
278 used without needing to select the font. */
279 result = ScriptShape (context, &(uniscribe_font->cache),
280 chars + items[i].iCharPos, nchars_in_run,
281 max_glyphs - done_glyphs, &(items[i].a),
282 glyphs, clusters, attributes, &nglyphs);
284 if (result == E_PENDING && !context)
286 /* This assumes the selected frame is on the same display as the
287 one we are drawing. It would be better for the frame to be
288 passed in. */
289 f = XFRAME (selected_frame);
290 context = get_frame_dc (f);
291 old_font = SelectObject (context, FONT_HANDLE (font));
293 result = ScriptShape (context, &(uniscribe_font->cache),
294 chars + items[i].iCharPos, nchars_in_run,
295 max_glyphs - done_glyphs, &(items[i].a),
296 glyphs, clusters, attributes, &nglyphs);
299 if (result == E_OUTOFMEMORY)
301 /* Need a bigger lgstring. */
302 lgstring = Qnil;
303 break;
305 else if (FAILED (result))
307 /* Can't shape this run - return results so far if any. */
308 break;
310 else if (items[i].a.fNoGlyphIndex)
312 /* Glyph indices not supported by this font (or OS), means we
313 can't really do any meaningful shaping. */
314 break;
316 else
318 result = ScriptPlace (context, &(uniscribe_font->cache),
319 glyphs, nglyphs, attributes, &(items[i].a),
320 advances, offsets, &overall_metrics);
321 if (result == E_PENDING && !context)
323 /* Cache not complete... */
324 f = XFRAME (selected_frame);
325 context = get_frame_dc (f);
326 old_font = SelectObject (context, FONT_HANDLE (font));
328 result = ScriptPlace (context, &(uniscribe_font->cache),
329 glyphs, nglyphs, attributes, &(items[i].a),
330 advances, offsets, &overall_metrics);
332 if (SUCCEEDED (result))
334 int j, from, to, adj_offset = 0;
336 from = 0;
337 to = from;
339 for (j = 0; j < nglyphs; j++)
341 int lglyph_index = j + done_glyphs;
342 Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, lglyph_index);
343 ABC char_metric;
344 unsigned gl;
346 if (NILP (lglyph))
348 lglyph = LGLYPH_NEW ();
349 LGSTRING_SET_GLYPH (lgstring, lglyph_index, lglyph);
351 /* Copy to a 32-bit data type to shut up the
352 compiler warning in LGLYPH_SET_CODE about
353 comparison being always false. */
354 gl = glyphs[j];
355 LGLYPH_SET_CODE (lglyph, gl);
357 /* Detect clusters, for linking codes back to
358 characters. */
359 if (attributes[j].fClusterStart)
361 while (from < nchars_in_run && clusters[from] < j)
362 from++;
363 if (from >= nchars_in_run)
364 from = to = nchars_in_run - 1;
365 else
367 int k;
368 to = nchars_in_run - 1;
369 for (k = from + 1; k < nchars_in_run; k++)
371 if (clusters[k] > j)
373 to = k - 1;
374 break;
379 /* For RTL text, the Uniscribe shaper prepares
380 the values in ADVANCES array for layout in
381 reverse order, whereby "advance width" is
382 applied to move the pen in reverse direction
383 and _before_ drawing the glyph. Since we
384 draw glyphs in their normal left-to-right
385 order, we need to adjust the coordinates of
386 each non-base glyph in a grapheme cluster via
387 X-OFF component of the gstring's ADJUSTMENT
388 sub-vector. This loop computes, for each
389 grapheme cluster, the initial value of the
390 adjustment for the base character, which is
391 then updated for each successive glyph in the
392 grapheme cluster. */
393 if (items[i].a.fRTL)
395 int j1 = j;
397 adj_offset = 0;
398 while (j1 < nglyphs && !attributes[j1].fClusterStart)
400 adj_offset += advances[j1];
401 j1++;
406 LGLYPH_SET_CHAR (lglyph, chars[items[i].iCharPos
407 + from]);
408 LGLYPH_SET_FROM (lglyph, items[i].iCharPos + from);
409 LGLYPH_SET_TO (lglyph, items[i].iCharPos + to);
411 /* Metrics. */
412 LGLYPH_SET_WIDTH (lglyph, advances[j]);
413 LGLYPH_SET_ASCENT (lglyph, font->ascent);
414 LGLYPH_SET_DESCENT (lglyph, font->descent);
416 result = ScriptGetGlyphABCWidth (context,
417 &(uniscribe_font->cache),
418 glyphs[j], &char_metric);
419 if (result == E_PENDING && !context)
421 /* Cache incomplete... */
422 f = XFRAME (selected_frame);
423 context = get_frame_dc (f);
424 old_font = SelectObject (context, FONT_HANDLE (font));
425 result = ScriptGetGlyphABCWidth (context,
426 &(uniscribe_font->cache),
427 glyphs[j], &char_metric);
430 if (SUCCEEDED (result))
432 int lbearing = char_metric.abcA;
433 int rbearing = char_metric.abcA + char_metric.abcB;
435 LGLYPH_SET_LBEARING (lglyph, lbearing);
436 LGLYPH_SET_RBEARING (lglyph, rbearing);
438 else
440 LGLYPH_SET_LBEARING (lglyph, 0);
441 LGLYPH_SET_RBEARING (lglyph, advances[j]);
444 if (offsets[j].du || offsets[j].dv
445 /* For non-base glyphs of RTL grapheme clusters,
446 adjust the X offset even if both DU and DV
447 are zero. */
448 || (!attributes[j].fClusterStart && items[i].a.fRTL))
450 Lisp_Object vec = make_uninit_vector (3);
452 if (items[i].a.fRTL)
454 /* Empirically, it looks like Uniscribe
455 interprets DU in reverse direction for
456 RTL clusters. E.g., if we don't reverse
457 the direction, the Hebrew point HOLAM is
458 drawn above the right edge of the base
459 consonant, instead of above the left edge. */
460 ASET (vec, 0, make_number (-offsets[j].du
461 + adj_offset));
462 /* Update the adjustment value for the width
463 advance of the glyph we just emitted. */
464 adj_offset -= 2 * advances[j];
466 else
467 ASET (vec, 0, make_number (offsets[j].du + adj_offset));
468 /* In the font definition coordinate system, the
469 Y coordinate points up, while in our screen
470 coordinates Y grows downwards. So we need to
471 reverse the sign of Y-OFFSET here. */
472 ASET (vec, 1, make_number (-offsets[j].dv));
473 /* Based on what ftfont.c does... */
474 ASET (vec, 2, make_number (advances[j]));
475 LGLYPH_SET_ADJUSTMENT (lglyph, vec);
477 else
479 LGLYPH_SET_ADJUSTMENT (lglyph, Qnil);
480 /* Update the adjustment value to compensate for
481 the width of the base character. */
482 if (items[i].a.fRTL)
483 adj_offset -= advances[j];
488 done_glyphs += nglyphs;
491 xfree (items);
493 if (context)
495 SelectObject (context, old_font);
496 release_frame_dc (f, context);
499 if (NILP (lgstring))
500 return Qnil;
501 else
502 return make_number (done_glyphs);
505 /* Uniscribe implementation of encode_char for font backend.
506 Return a glyph code of FONT for character C (Unicode code point).
507 If FONT doesn't have such a glyph, return FONT_INVALID_CODE. */
508 static unsigned
509 uniscribe_encode_char (struct font *font, int c)
511 HDC context = NULL;
512 struct frame *f = NULL;
513 HFONT old_font = NULL;
514 unsigned code = FONT_INVALID_CODE;
515 wchar_t ch[2];
516 int len;
517 SCRIPT_ITEM* items;
518 int nitems;
519 struct uniscribe_font_info *uniscribe_font
520 = (struct uniscribe_font_info *)font;
522 if (c < 0x10000)
524 ch[0] = (wchar_t) c;
525 len = 1;
527 else
529 DWORD surrogate = c - 0x10000;
531 /* High surrogate: U+D800 - U+DBFF. */
532 ch[0] = 0xD800 + ((surrogate >> 10) & 0x03FF);
533 /* Low surrogate: U+DC00 - U+DFFF. */
534 ch[1] = 0xDC00 + (surrogate & 0x03FF);
535 len = 2;
538 /* Non BMP characters must be handled by the uniscribe shaping
539 engine as GDI functions (except blindly displaying lines of
540 Unicode text) and the promising looking ScriptGetCMap do not
541 convert surrogate pairs to glyph indexes correctly. */
543 items = (SCRIPT_ITEM *) alloca (sizeof (SCRIPT_ITEM) * 2 + 1);
544 if (SUCCEEDED (ScriptItemize (ch, len, 2, NULL, NULL, items, &nitems)))
546 HRESULT result;
547 /* Surrogates seem to need 2 here, even though only one glyph is
548 returned. Indic characters can also produce 2 or more glyphs for
549 a single code point, but they need to use uniscribe_shape
550 above for correct display. */
551 WORD glyphs[2], clusters[2];
552 SCRIPT_VISATTR attrs[2];
553 int nglyphs;
555 /* Force ScriptShape to generate glyphs in the logical
556 order. */
557 items[0].a.fLogicalOrder = 1;
559 result = ScriptShape (context, &(uniscribe_font->cache),
560 ch, len, 2, &(items[0].a),
561 glyphs, clusters, attrs, &nglyphs);
563 if (result == E_PENDING)
565 /* Use selected frame until API is updated to pass
566 the frame. */
567 f = XFRAME (selected_frame);
568 context = get_frame_dc (f);
569 old_font = SelectObject (context, FONT_HANDLE (font));
570 result = ScriptShape (context, &(uniscribe_font->cache),
571 ch, len, 2, &(items[0].a),
572 glyphs, clusters, attrs, &nglyphs);
575 if (SUCCEEDED (result) && nglyphs == 1)
577 /* Some fonts return .notdef glyphs instead of failing.
578 (TrueType spec reserves glyph code 0 for .notdef) */
579 if (glyphs[0])
580 code = glyphs[0];
582 else if (SUCCEEDED (result) || result == E_OUTOFMEMORY)
584 /* This character produces zero or more than one glyph
585 when shaped. But we still need the return from here
586 to be valid for the shaping engine to be invoked
587 later. */
588 result = ScriptGetCMap (context, &(uniscribe_font->cache),
589 ch, len, 0, glyphs);
590 if (SUCCEEDED (result) && glyphs[0])
591 code = glyphs[0];
595 if (context)
597 SelectObject (context, old_font);
598 release_frame_dc (f, context);
601 return code;
605 Shared with w32font:
606 Lisp_Object uniscribe_get_cache (Lisp_Object frame);
607 void uniscribe_free_entity (Lisp_Object font_entity);
608 int uniscribe_has_char (Lisp_Object entity, int c);
609 void uniscribe_text_extents (struct font *font, unsigned *code,
610 int nglyphs, struct font_metrics *metrics);
611 int uniscribe_draw (struct glyph_string *s, int from, int to,
612 int x, int y, int with_background);
614 Unused:
615 int uniscribe_prepare_face (struct frame *f, struct face *face);
616 void uniscribe_done_face (struct frame *f, struct face *face);
617 int uniscribe_get_bitmap (struct font *font, unsigned code,
618 struct font_bitmap *bitmap, int bits_per_pixel);
619 void uniscribe_free_bitmap (struct font *font, struct font_bitmap *bitmap);
620 int uniscribe_anchor_point (struct font *font, unsigned code,
621 int index, int *x, int *y);
622 int uniscribe_start_for_frame (struct frame *f);
623 int uniscribe_end_for_frame (struct frame *f);
628 /* Callback function for EnumFontFamiliesEx.
629 Adds the name of opentype fonts to a Lisp list (passed in as the
630 lParam arg). */
631 static int CALLBACK ALIGN_STACK
632 add_opentype_font_name_to_list (ENUMLOGFONTEX *logical_font,
633 NEWTEXTMETRICEX *physical_font,
634 DWORD font_type, LPARAM list_object)
636 Lisp_Object* list = (Lisp_Object *) list_object;
637 Lisp_Object family;
639 /* Skip vertical fonts (intended only for printing) */
640 if (logical_font->elfLogFont.lfFaceName[0] == '@')
641 return 1;
643 /* Skip non opentype fonts. Count old truetype fonts as opentype,
644 as some of them do contain GPOS and GSUB data that Uniscribe
645 can make use of. */
646 if (!(physical_font->ntmTm.ntmFlags & NTMFLAGS_OPENTYPE)
647 && font_type != TRUETYPE_FONTTYPE)
648 return 1;
650 /* Skip fonts that have no Unicode coverage. */
651 if (!physical_font->ntmFontSig.fsUsb[3]
652 && !physical_font->ntmFontSig.fsUsb[2]
653 && !physical_font->ntmFontSig.fsUsb[1]
654 && !(physical_font->ntmFontSig.fsUsb[0] & 0x3fffffff))
655 return 1;
657 family = intern_font_name (logical_font->elfLogFont.lfFaceName);
658 if (! memq_no_quit (family, *list))
659 *list = Fcons (family, *list);
661 return 1;
665 /* :otf property handling.
666 Since the necessary Uniscribe APIs for getting font tag information
667 are only available in Vista, we may need to parse the font data directly
668 according to the OpenType Specification. */
670 /* Push into DWORD backwards to cope with endianness. */
671 #define OTF_TAG(STR) \
672 ((STR[3] << 24) | (STR[2] << 16) | (STR[1] << 8) | STR[0])
674 #define OTF_INT16_VAL(TABLE, OFFSET, PTR) \
675 do { \
676 BYTE temp, data[2]; \
677 if (GetFontData (context, TABLE, OFFSET, data, 2) != 2) \
678 goto font_table_error; \
679 temp = data[0], data[0] = data[1], data[1] = temp; \
680 memcpy (PTR, data, 2); \
681 } while (0)
683 /* Do not reverse the bytes, because we will compare with a OTF_TAG value
684 that has them reversed already. */
685 #define OTF_DWORDTAG_VAL(TABLE, OFFSET, PTR) \
686 do { \
687 if (GetFontData (context, TABLE, OFFSET, PTR, 4) != 4) \
688 goto font_table_error; \
689 } while (0)
691 #define OTF_TAG_VAL(TABLE, OFFSET, STR) \
692 do { \
693 if (GetFontData (context, TABLE, OFFSET, STR, 4) != 4) \
694 goto font_table_error; \
695 STR[4] = '\0'; \
696 } while (0)
698 #define SNAME(VAL) SSDATA (SYMBOL_NAME (VAL))
700 /* Uniscribe APIs available only since Windows Vista. */
701 typedef HRESULT (WINAPI *ScriptGetFontScriptTags_Proc)
702 (HDC, SCRIPT_CACHE *, SCRIPT_ANALYSIS *, int, OPENTYPE_TAG *, int *);
704 typedef HRESULT (WINAPI *ScriptGetFontLanguageTags_Proc)
705 (HDC, SCRIPT_CACHE *, SCRIPT_ANALYSIS *, OPENTYPE_TAG, int, OPENTYPE_TAG *, int *);
707 typedef HRESULT (WINAPI *ScriptGetFontFeatureTags_Proc)
708 (HDC, SCRIPT_CACHE *, SCRIPT_ANALYSIS *, OPENTYPE_TAG, OPENTYPE_TAG, int, OPENTYPE_TAG *, int *);
710 ScriptGetFontScriptTags_Proc script_get_font_scripts_fn;
711 ScriptGetFontLanguageTags_Proc script_get_font_languages_fn;
712 ScriptGetFontFeatureTags_Proc script_get_font_features_fn;
714 static bool uniscribe_new_apis;
716 /* Verify that all the required features in FEATURES, each of whose
717 elements is a list or nil, can be found among the N feature tags in
718 FTAGS. Return 'true' if the required features are supported,
719 'false' if not. Each list in FEATURES can include an element of
720 nil, which means all the elements after it must not be in FTAGS. */
721 static bool
722 uniscribe_check_features (Lisp_Object features[2], OPENTYPE_TAG *ftags, int n)
724 int j;
726 for (j = 0; j < 2; j++)
728 bool negative = false;
729 Lisp_Object rest;
731 for (rest = features[j]; CONSP (rest); rest = XCDR (rest))
733 Lisp_Object feature = XCAR (rest);
735 /* The font must NOT have any of the features after nil.
736 See the doc string of 'font-spec', under ':otf'. */
737 if (NILP (feature))
738 negative = true;
739 else
741 OPENTYPE_TAG feature_tag = OTF_TAG (SNAME (feature));
742 int i;
744 for (i = 0; i < n; i++)
746 if (ftags[i] == feature_tag)
748 /* Test fails if we find a feature that the font
749 must NOT have. */
750 if (negative)
751 return false;
752 break;
756 /* Test fails if we do NOT find a feature that the font
757 should have. */
758 if (i >= n && !negative)
759 return false;
764 return true;
767 /* Check if font supports the required OTF script/language/features
768 using the Unsicribe APIs available since Windows Vista. We prefer
769 these APIs as a kind of future-proofing Emacs: they seem to
770 retrieve script tags that the old code (and also libotf) doesn't
771 seem to be able to get, e.g., some fonts that claim support for
772 "dev2" script don't show "deva", but the new APIs do report it. */
773 static int
774 uniscribe_check_otf_1 (HDC context, Lisp_Object script, Lisp_Object lang,
775 Lisp_Object features[2], int *retval)
777 SCRIPT_CACHE cache = NULL;
778 OPENTYPE_TAG tags[32], script_tag, lang_tag;
779 int max_tags = ARRAYELTS (tags);
780 int ntags, i, ret = 0;
781 HRESULT rslt;
782 Lisp_Object rest;
784 *retval = 0;
786 rslt = script_get_font_scripts_fn (context, &cache, NULL, max_tags,
787 tags, &ntags);
788 if (FAILED (rslt))
790 DebPrint (("ScriptGetFontScriptTags failed with 0x%x\n", rslt));
791 ret = -1;
792 goto no_support;
794 if (NILP (script))
795 script_tag = OTF_TAG ("DFLT");
796 else
797 script_tag = OTF_TAG (SNAME (script));
798 for (i = 0; i < ntags; i++)
799 if (tags[i] == script_tag)
800 break;
802 if (i >= ntags)
803 goto no_support;
805 if (NILP (lang))
806 lang_tag = OTF_TAG ("dflt");
807 else
809 rslt = script_get_font_languages_fn (context, &cache, NULL, script_tag,
810 max_tags, tags, &ntags);
811 if (FAILED (rslt))
813 DebPrint (("ScriptGetFontLanguageTags failed with 0x%x\n", rslt));
814 ret = -1;
815 goto no_support;
817 if (ntags == 0)
818 lang_tag = OTF_TAG ("dflt");
819 else
821 lang_tag = OTF_TAG (SNAME (lang));
822 for (i = 0; i < ntags; i++)
823 if (tags[i] == lang_tag)
824 break;
826 if (i >= ntags)
827 goto no_support;
831 if (!NILP (features[0]))
833 /* Are the 2 feature lists valid? */
834 if (!CONSP (features[0])
835 || (!NILP (features[1]) && !CONSP (features[1])))
836 goto no_support;
837 rslt = script_get_font_features_fn (context, &cache, NULL,
838 script_tag, lang_tag,
839 max_tags, tags, &ntags);
840 if (FAILED (rslt))
842 DebPrint (("ScriptGetFontFeatureTags failed with 0x%x\n", rslt));
843 ret = -1;
844 goto no_support;
847 /* ScriptGetFontFeatureTags doesn't let us query features
848 separately for GSUB and GPOS, so we check them all together.
849 It doesn't really matter, since the features in GSUB and GPOS
850 are disjoint, i.e. no feature can appear in both tables. */
851 if (!uniscribe_check_features (features, tags, ntags))
852 goto no_support;
855 ret = 1;
856 *retval = 1;
858 no_support:
859 if (cache)
860 ScriptFreeCache (&cache);
861 return ret;
864 /* Check if font supports the otf script/language/features specified.
865 OTF_SPEC is in the format
866 (script lang [(gsub_feature ...)|nil] [(gpos_feature ...)]?) */
868 uniscribe_check_otf (LOGFONT *font, Lisp_Object otf_spec)
870 Lisp_Object script, lang, rest;
871 Lisp_Object features[2];
872 DWORD feature_tables[2];
873 DWORD script_tag, default_script, lang_tag = 0;
874 struct frame * f;
875 HDC context;
876 HFONT check_font, old_font;
877 int i, retval = 0;
879 /* Check the spec is in the right format. */
880 if (!CONSP (otf_spec) || XINT (Flength (otf_spec)) < 3)
881 return 0;
883 /* Break otf_spec into its components. */
884 script = XCAR (otf_spec);
885 rest = XCDR (otf_spec);
887 lang = XCAR (rest);
888 rest = XCDR (rest);
890 features[0] = XCAR (rest);
891 rest = XCDR (rest);
892 if (NILP (rest))
893 features[1] = Qnil;
894 else
895 features[1] = XCAR (rest);
897 /* Set up graphics context so we can use the font. */
898 f = XFRAME (selected_frame);
899 context = get_frame_dc (f);
900 check_font = CreateFontIndirect (font);
901 old_font = SelectObject (context, check_font);
903 /* If we are on Vista or later, use the new APIs. */
904 if (uniscribe_new_apis
905 && !w32_disable_new_uniscribe_apis
906 && uniscribe_check_otf_1 (context, script, lang, features, &retval) != -1)
907 goto done;
909 /* Set up tags we will use in the search. */
910 feature_tables[0] = OTF_TAG ("GSUB");
911 feature_tables[1] = OTF_TAG ("GPOS");
912 default_script = OTF_TAG ("DFLT");
913 if (NILP (script))
914 script_tag = default_script;
915 else
916 script_tag = OTF_TAG (SNAME (script));
917 if (!NILP (lang))
918 lang_tag = OTF_TAG (SNAME (lang));
920 /* Scan GSUB and GPOS tables. */
921 for (i = 0; i < 2; i++)
923 int j, n_match_features;
924 unsigned short scriptlist_table, feature_table, n_scripts;
925 unsigned short script_table, langsys_table, n_langs;
926 unsigned short feature_index, n_features;
927 DWORD tbl = feature_tables[i];
928 DWORD feature_id, *ftags;
929 Lisp_Object farray[2];
931 /* Skip if no features requested from this table. */
932 if (NILP (features[i]))
933 continue;
935 /* If features is not a cons, this font spec is messed up. */
936 if (!CONSP (features[i]))
937 goto no_support;
939 /* Read GPOS/GSUB header. */
940 OTF_INT16_VAL (tbl, 4, &scriptlist_table);
941 OTF_INT16_VAL (tbl, 6, &feature_table);
942 OTF_INT16_VAL (tbl, scriptlist_table, &n_scripts);
944 /* Find the appropriate script table. */
945 script_table = 0;
946 for (j = 0; j < n_scripts; j++)
948 DWORD script_id;
949 OTF_DWORDTAG_VAL (tbl, scriptlist_table + 2 + j * 6, &script_id);
950 if (script_id == script_tag)
952 OTF_INT16_VAL (tbl, scriptlist_table + 6 + j * 6, &script_table);
953 break;
955 #if 0 /* Causes false positives. */
956 /* If there is a DFLT script defined in the font, use it
957 if the specified script is not found. */
958 else if (script_id == default_script)
959 OTF_INT16_VAL (tbl, scriptlist_table + 6 + j * 6, &script_table);
960 #endif
962 /* If no specific or default script table was found, then this font
963 does not support the script. */
964 if (!script_table)
965 goto no_support;
967 /* Offset is from beginning of scriptlist_table. */
968 script_table += scriptlist_table;
970 /* Get default langsys table. */
971 OTF_INT16_VAL (tbl, script_table, &langsys_table);
973 /* If lang was specified, see if font contains a specific entry. */
974 if (!NILP (lang))
976 OTF_INT16_VAL (tbl, script_table + 2, &n_langs);
978 for (j = 0; j < n_langs; j++)
980 DWORD lang_id;
981 OTF_DWORDTAG_VAL (tbl, script_table + 4 + j * 6, &lang_id);
982 if (lang_id == lang_tag)
984 OTF_INT16_VAL (tbl, script_table + 8 + j * 6, &langsys_table);
985 break;
990 if (!langsys_table)
991 goto no_support;
993 /* Offset is from beginning of script table. */
994 langsys_table += script_table;
996 /* If there are no features to check, skip checking. */
997 if (NILP (features[i]))
998 continue;
999 if (!CONSP (features[i]))
1000 goto no_support;
1002 n_match_features = 0;
1004 /* First get required feature (if any). */
1005 OTF_INT16_VAL (tbl, langsys_table + 2, &feature_index);
1006 if (feature_index != 0xFFFF)
1007 n_match_features = 1;
1008 OTF_INT16_VAL (tbl, langsys_table + 4, &n_features);
1009 n_match_features += n_features;
1010 USE_SAFE_ALLOCA;
1011 SAFE_NALLOCA (ftags, 1, n_match_features);
1012 int k = 0;
1013 if (feature_index != 0xFFFF)
1015 OTF_DWORDTAG_VAL (tbl, feature_table + 2 + feature_index * 6,
1016 &feature_id);
1017 ftags[k++] = feature_id;
1019 /* Now get all the other features. */
1020 for (j = 0; j < n_features; j++)
1022 OTF_INT16_VAL (tbl, langsys_table + 6 + j * 2, &feature_index);
1023 OTF_DWORDTAG_VAL (tbl, feature_table + 2 + feature_index * 6,
1024 &feature_id);
1025 ftags[k++] = feature_id;
1028 /* Check the features for this table. */
1029 farray[0] = features[i];
1030 farray[1] = Qnil;
1031 if (!uniscribe_check_features (farray, ftags, n_match_features))
1032 goto no_support;
1033 SAFE_FREE ();
1036 retval = 1;
1038 done:
1039 no_support:
1040 font_table_error:
1041 /* restore graphics context. */
1042 SelectObject (context, old_font);
1043 DeleteObject (check_font);
1044 release_frame_dc (f, context);
1046 return retval;
1049 static Lisp_Object
1050 otf_features (HDC context, char *table)
1052 Lisp_Object script_list = Qnil;
1053 unsigned short scriptlist_table, n_scripts, feature_table;
1054 DWORD tbl = OTF_TAG (table);
1055 int i, j, k;
1057 /* Look for scripts in the table. */
1058 OTF_INT16_VAL (tbl, 4, &scriptlist_table);
1059 OTF_INT16_VAL (tbl, 6, &feature_table);
1060 OTF_INT16_VAL (tbl, scriptlist_table, &n_scripts);
1062 for (i = n_scripts - 1; i >= 0; i--)
1064 char script[5], lang[5];
1065 unsigned short script_table, lang_count, langsys_table, feature_count;
1066 Lisp_Object script_tag, langsys_list, langsys_tag, feature_list;
1067 unsigned short record_offset = scriptlist_table + 2 + i * 6;
1068 OTF_TAG_VAL (tbl, record_offset, script);
1069 OTF_INT16_VAL (tbl, record_offset + 4, &script_table);
1071 /* Offset is from beginning of script table. */
1072 script_table += scriptlist_table;
1074 script_tag = intern (script);
1075 langsys_list = Qnil;
1077 /* Optional default lang. */
1078 OTF_INT16_VAL (tbl, script_table, &langsys_table);
1079 if (langsys_table)
1081 /* Offset is from beginning of script table. */
1082 langsys_table += script_table;
1084 langsys_tag = Qnil;
1085 feature_list = Qnil;
1086 OTF_INT16_VAL (tbl, langsys_table + 4, &feature_count);
1087 for (k = feature_count - 1; k >= 0; k--)
1089 char feature[5];
1090 unsigned short index;
1091 OTF_INT16_VAL (tbl, langsys_table + 6 + k * 2, &index);
1092 OTF_TAG_VAL (tbl, feature_table + 2 + index * 6, feature);
1093 feature_list = Fcons (intern (feature), feature_list);
1095 langsys_list = Fcons (Fcons (langsys_tag, feature_list),
1096 langsys_list);
1099 /* List of supported languages. */
1100 OTF_INT16_VAL (tbl, script_table + 2, &lang_count);
1102 for (j = lang_count - 1; j >= 0; j--)
1104 record_offset = script_table + 4 + j * 6;
1105 OTF_TAG_VAL (tbl, record_offset, lang);
1106 OTF_INT16_VAL (tbl, record_offset + 4, &langsys_table);
1108 /* Offset is from beginning of script table. */
1109 langsys_table += script_table;
1111 langsys_tag = intern (lang);
1112 feature_list = Qnil;
1113 OTF_INT16_VAL (tbl, langsys_table + 4, &feature_count);
1114 for (k = feature_count - 1; k >= 0; k--)
1116 char feature[5];
1117 unsigned short index;
1118 OTF_INT16_VAL (tbl, langsys_table + 6 + k * 2, &index);
1119 OTF_TAG_VAL (tbl, feature_table + 2 + index * 6, feature);
1120 feature_list = Fcons (intern (feature), feature_list);
1122 langsys_list = Fcons (Fcons (langsys_tag, feature_list),
1123 langsys_list);
1127 script_list = Fcons (Fcons (script_tag, langsys_list), script_list);
1130 return script_list;
1132 font_table_error:
1133 return Qnil;
1136 #undef OTF_INT16_VAL
1137 #undef OTF_TAG_VAL
1138 #undef OTF_TAG
1141 struct font_driver uniscribe_font_driver =
1143 LISP_INITIALLY_ZERO, /* Quniscribe */
1144 0, /* case insensitive */
1145 w32font_get_cache,
1146 uniscribe_list,
1147 uniscribe_match,
1148 uniscribe_list_family,
1149 NULL, /* free_entity */
1150 uniscribe_open,
1151 uniscribe_close,
1152 NULL, /* prepare_face */
1153 NULL, /* done_face */
1154 w32font_has_char,
1155 uniscribe_encode_char,
1156 w32font_text_extents,
1157 w32font_draw,
1158 NULL, /* get_bitmap */
1159 NULL, /* free_bitmap */
1160 NULL, /* anchor_point */
1161 uniscribe_otf_capability, /* Defined so (font-get FONTOBJ :otf) works. */
1162 NULL, /* otf_drive - use shape instead. */
1163 NULL, /* start_for_frame */
1164 NULL, /* end_for_frame */
1165 uniscribe_shape,
1166 NULL, /* check */
1167 NULL, /* get_variation_glyphs */
1168 NULL, /* filter_properties */
1169 NULL, /* cached_font_ok */
1172 /* Note that this should be called at every startup, not just when dumping,
1173 as it needs to test for the existence of the Uniscribe library. */
1174 void
1175 syms_of_w32uniscribe (void)
1177 HMODULE uniscribe;
1179 /* Don't init uniscribe when dumping */
1180 if (!initialized)
1181 return;
1183 /* Don't register if uniscribe is not available. */
1184 uniscribe = GetModuleHandle ("usp10");
1185 if (!uniscribe)
1186 return;
1188 uniscribe_font_driver.type = Quniscribe;
1189 uniscribe_available = 1;
1191 register_font_driver (&uniscribe_font_driver, NULL);
1193 script_get_font_scripts_fn = (ScriptGetFontScriptTags_Proc)
1194 GetProcAddress (uniscribe, "ScriptGetFontScriptTags");
1195 script_get_font_languages_fn = (ScriptGetFontLanguageTags_Proc)
1196 GetProcAddress (uniscribe, "ScriptGetFontLanguageTags");
1197 script_get_font_features_fn = (ScriptGetFontFeatureTags_Proc)
1198 GetProcAddress (uniscribe, "ScriptGetFontFeatureTags");
1199 if (script_get_font_scripts_fn
1200 && script_get_font_languages_fn
1201 && script_get_font_features_fn)
1202 uniscribe_new_apis = true;
1203 else
1204 uniscribe_new_apis = false;