Use binary-io module, O_BINARY, and "b" flag.
[emacs.git] / src / w32uniscribe.c
blobd06586f973ab5a9b653fa7a3b0b3c4804b5cf86b
1 /* Font backend for the Microsoft W32 Uniscribe API.
2 Copyright (C) 2008-2014 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 since
22 Windows 2000, though most users of older systems will have it
23 since it installs with Internet Explorer 5.0 and other software.
24 We only enable the feature if it is available, so there is no chance
25 of calling non-existent functions. */
26 #undef _WIN32_WINNT
27 #define _WIN32_WINNT 0x500
28 #include <windows.h>
29 #include <usp10.h>
31 #include "lisp.h"
32 #include "w32term.h"
33 #include "frame.h"
34 #include "dispextern.h"
35 #include "character.h"
36 #include "charset.h"
37 #include "composite.h"
38 #include "fontset.h"
39 #include "font.h"
40 #include "w32font.h"
42 struct uniscribe_font_info
44 struct w32font_info w32_font;
45 SCRIPT_CACHE cache;
48 int uniscribe_available = 0;
50 /* Defined in w32font.c, since it is required there as well. */
51 extern Lisp_Object Quniscribe;
52 extern Lisp_Object Qopentype;
54 /* EnumFontFamiliesEx callback. */
55 static int CALLBACK add_opentype_font_name_to_list (ENUMLOGFONTEX *,
56 NEWTEXTMETRICEX *,
57 DWORD, LPARAM);
58 /* Used by uniscribe_otf_capability. */
59 static Lisp_Object otf_features (HDC context, char *table);
61 static int
62 memq_no_quit (Lisp_Object elt, Lisp_Object list)
64 while (CONSP (list) && ! EQ (XCAR (list), elt))
65 list = XCDR (list);
66 return (CONSP (list));
70 /* Font backend interface implementation. */
71 static Lisp_Object
72 uniscribe_list (struct frame *f, Lisp_Object font_spec)
74 Lisp_Object fonts = w32font_list_internal (f, font_spec, 1);
75 FONT_ADD_LOG ("uniscribe-list", font_spec, fonts);
76 return fonts;
79 static Lisp_Object
80 uniscribe_match (struct frame *f, Lisp_Object font_spec)
82 Lisp_Object entity = w32font_match_internal (f, font_spec, 1);
83 FONT_ADD_LOG ("uniscribe-match", font_spec, entity);
84 return entity;
87 static Lisp_Object
88 uniscribe_list_family (struct frame *f)
90 Lisp_Object list = Qnil;
91 LOGFONT font_match_pattern;
92 HDC dc;
94 memset (&font_match_pattern, 0, sizeof (font_match_pattern));
95 /* Limit enumerated fonts to outline fonts to save time. */
96 font_match_pattern.lfOutPrecision = OUT_OUTLINE_PRECIS;
98 dc = get_frame_dc (f);
100 EnumFontFamiliesEx (dc, &font_match_pattern,
101 (FONTENUMPROC) add_opentype_font_name_to_list,
102 (LPARAM) &list, 0);
103 release_frame_dc (f, dc);
105 return list;
108 static Lisp_Object
109 uniscribe_open (struct frame *f, Lisp_Object font_entity, int pixel_size)
111 Lisp_Object font_object
112 = font_make_object (VECSIZE (struct uniscribe_font_info),
113 font_entity, pixel_size);
114 struct uniscribe_font_info *uniscribe_font
115 = (struct uniscribe_font_info *) XFONT_OBJECT (font_object);
117 ASET (font_object, FONT_TYPE_INDEX, Quniscribe);
119 if (!w32font_open_internal (f, font_entity, pixel_size, font_object))
121 return Qnil;
124 /* Initialize the cache for this font. */
125 uniscribe_font->cache = NULL;
127 /* Uniscribe backend uses glyph indices. */
128 uniscribe_font->w32_font.glyph_idx = ETO_GLYPH_INDEX;
130 uniscribe_font->w32_font.font.driver = &uniscribe_font_driver;
132 return font_object;
135 static void
136 uniscribe_close (struct font *font)
138 struct uniscribe_font_info *uniscribe_font
139 = (struct uniscribe_font_info *) font;
141 if (uniscribe_font->cache)
142 ScriptFreeCache (&(uniscribe_font->cache));
144 w32font_close (font);
147 /* Return a list describing which scripts/languages FONT supports by
148 which GSUB/GPOS features of OpenType tables. */
149 static Lisp_Object
150 uniscribe_otf_capability (struct font *font)
152 HDC context;
153 HFONT old_font;
154 struct frame *f;
155 Lisp_Object capability = Fcons (Qnil, Qnil);
156 Lisp_Object features;
158 f = XFRAME (selected_frame);
159 context = get_frame_dc (f);
160 old_font = SelectObject (context, FONT_HANDLE (font));
162 features = otf_features (context, "GSUB");
163 XSETCAR (capability, features);
164 features = otf_features (context, "GPOS");
165 XSETCDR (capability, features);
167 SelectObject (context, old_font);
168 release_frame_dc (f, context);
170 return capability;
173 /* Uniscribe implementation of shape for font backend.
175 Shape text in LGSTRING. See the docstring of
176 `composition-get-gstring' for the format of LGSTRING. If the
177 (N+1)th element of LGSTRING is nil, input of shaping is from the
178 1st to (N)th elements. In each input glyph, FROM, TO, CHAR, and
179 CODE are already set.
181 This function updates all fields of the input glyphs. If the
182 output glyphs (M) are more than the input glyphs (N), (N+1)th
183 through (M)th elements of LGSTRING are updated possibly by making
184 a new glyph object and storing it in LGSTRING. If (M) is greater
185 than the length of LGSTRING, nil should be returned. In that case,
186 this function is called again with a larger LGSTRING. */
187 static Lisp_Object
188 uniscribe_shape (Lisp_Object lgstring)
190 struct font * font;
191 struct uniscribe_font_info * uniscribe_font;
192 EMACS_UINT nchars;
193 int nitems, max_items, i, max_glyphs, done_glyphs;
194 wchar_t *chars;
195 WORD *glyphs, *clusters;
196 SCRIPT_ITEM *items;
197 SCRIPT_VISATTR *attributes;
198 int *advances;
199 GOFFSET *offsets;
200 ABC overall_metrics;
201 HRESULT result;
202 struct frame * f = NULL;
203 HDC context = NULL;
204 HFONT old_font = NULL;
206 CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring), font);
207 uniscribe_font = (struct uniscribe_font_info *) font;
209 /* Get the chars from lgstring in a form we can use with uniscribe. */
210 max_glyphs = nchars = LGSTRING_GLYPH_LEN (lgstring);
211 done_glyphs = 0;
212 chars = (wchar_t *) alloca (nchars * sizeof (wchar_t));
213 /* FIXME: This loop assumes that characters in the input LGSTRING
214 are all inside the BMP. Need to encode characters beyond the BMP
215 as UTF-16. */
216 for (i = 0; i < nchars; i++)
218 /* lgstring can be bigger than the number of characters in it, in
219 the case where more glyphs are required to display those characters.
220 If that is the case, note the real number of characters. */
221 if (NILP (LGSTRING_GLYPH (lgstring, i)))
222 nchars = i;
223 else
224 chars[i] = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, i));
227 /* First we need to break up the glyph string into runs of glyphs that
228 can be treated together. First try a single run. */
229 max_items = 2;
230 items = xmalloc (sizeof (SCRIPT_ITEM) * max_items + 1);
232 while ((result = ScriptItemize (chars, nchars, max_items, NULL, NULL,
233 items, &nitems)) == E_OUTOFMEMORY)
235 /* If that wasn't enough, keep trying with one more run. */
236 max_items++;
237 items = (SCRIPT_ITEM *) xrealloc (items,
238 sizeof (SCRIPT_ITEM) * max_items + 1);
241 if (FAILED (result))
243 xfree (items);
244 return Qnil;
247 glyphs = alloca (max_glyphs * sizeof (WORD));
248 clusters = alloca (nchars * sizeof (WORD));
249 attributes = alloca (max_glyphs * sizeof (SCRIPT_VISATTR));
250 advances = alloca (max_glyphs * sizeof (int));
251 offsets = alloca (max_glyphs * sizeof (GOFFSET));
253 for (i = 0; i < nitems; i++)
255 int nglyphs, nchars_in_run;
256 nchars_in_run = items[i+1].iCharPos - items[i].iCharPos;
257 /* Force ScriptShape to generate glyphs in the same order as
258 they are in the input LGSTRING, which is in the logical
259 order. */
260 items[i].a.fLogicalOrder = 1;
262 /* Context may be NULL here, in which case the cache should be
263 used without needing to select the font. */
264 result = ScriptShape (context, &(uniscribe_font->cache),
265 chars + items[i].iCharPos, nchars_in_run,
266 max_glyphs - done_glyphs, &(items[i].a),
267 glyphs, clusters, attributes, &nglyphs);
269 if (result == E_PENDING && !context)
271 /* This assumes the selected frame is on the same display as the
272 one we are drawing. It would be better for the frame to be
273 passed in. */
274 f = XFRAME (selected_frame);
275 context = get_frame_dc (f);
276 old_font = SelectObject (context, FONT_HANDLE (font));
278 result = ScriptShape (context, &(uniscribe_font->cache),
279 chars + items[i].iCharPos, nchars_in_run,
280 max_glyphs - done_glyphs, &(items[i].a),
281 glyphs, clusters, attributes, &nglyphs);
284 if (result == E_OUTOFMEMORY)
286 /* Need a bigger lgstring. */
287 lgstring = Qnil;
288 break;
290 else if (FAILED (result))
292 /* Can't shape this run - return results so far if any. */
293 break;
295 else if (items[i].a.fNoGlyphIndex)
297 /* Glyph indices not supported by this font (or OS), means we
298 can't really do any meaningful shaping. */
299 break;
301 else
303 result = ScriptPlace (context, &(uniscribe_font->cache),
304 glyphs, nglyphs, attributes, &(items[i].a),
305 advances, offsets, &overall_metrics);
306 if (result == E_PENDING && !context)
308 /* Cache not complete... */
309 f = XFRAME (selected_frame);
310 context = get_frame_dc (f);
311 old_font = SelectObject (context, FONT_HANDLE (font));
313 result = ScriptPlace (context, &(uniscribe_font->cache),
314 glyphs, nglyphs, attributes, &(items[i].a),
315 advances, offsets, &overall_metrics);
317 if (SUCCEEDED (result))
319 int j, from, to, adj_offset = 0;
321 from = 0;
322 to = from;
324 for (j = 0; j < nglyphs; j++)
326 int lglyph_index = j + done_glyphs;
327 Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, lglyph_index);
328 ABC char_metric;
329 unsigned gl;
331 if (NILP (lglyph))
333 lglyph = LGLYPH_NEW ();
334 LGSTRING_SET_GLYPH (lgstring, lglyph_index, lglyph);
336 /* Copy to a 32-bit data type to shut up the
337 compiler warning in LGLYPH_SET_CODE about
338 comparison being always false. */
339 gl = glyphs[j];
340 LGLYPH_SET_CODE (lglyph, gl);
342 /* Detect clusters, for linking codes back to
343 characters. */
344 if (attributes[j].fClusterStart)
346 while (from < nchars_in_run && clusters[from] < j)
347 from++;
348 if (from >= nchars_in_run)
349 from = to = nchars_in_run - 1;
350 else
352 int k;
353 to = nchars_in_run - 1;
354 for (k = from + 1; k < nchars_in_run; k++)
356 if (clusters[k] > j)
358 to = k - 1;
359 break;
364 /* For RTL text, the Uniscribe shaper prepares
365 the values in ADVANCES array for layout in
366 reverse order, whereby "advance width" is
367 applied to move the pen in reverse direction
368 and _before_ drawing the glyph. Since we
369 draw glyphs in their normal left-to-right
370 order, we need to adjust the coordinates of
371 each non-base glyph in a grapheme cluster via
372 X-OFF component of the gstring's ADJUSTMENT
373 sub-vector. This loop computes, for each
374 grapheme cluster, the initial value of the
375 adjustment for the base character, which is
376 then updated for each successive glyph in the
377 grapheme cluster. */
378 if (items[i].a.fRTL)
380 int j1 = j;
382 adj_offset = 0;
383 while (j1 < nglyphs && !attributes[j1].fClusterStart)
385 adj_offset += advances[j1];
386 j1++;
391 LGLYPH_SET_CHAR (lglyph, chars[items[i].iCharPos
392 + from]);
393 LGLYPH_SET_FROM (lglyph, items[i].iCharPos + from);
394 LGLYPH_SET_TO (lglyph, items[i].iCharPos + to);
396 /* Metrics. */
397 LGLYPH_SET_WIDTH (lglyph, advances[j]);
398 LGLYPH_SET_ASCENT (lglyph, font->ascent);
399 LGLYPH_SET_DESCENT (lglyph, font->descent);
401 result = ScriptGetGlyphABCWidth (context,
402 &(uniscribe_font->cache),
403 glyphs[j], &char_metric);
404 if (result == E_PENDING && !context)
406 /* Cache incomplete... */
407 f = XFRAME (selected_frame);
408 context = get_frame_dc (f);
409 old_font = SelectObject (context, FONT_HANDLE (font));
410 result = ScriptGetGlyphABCWidth (context,
411 &(uniscribe_font->cache),
412 glyphs[j], &char_metric);
415 if (SUCCEEDED (result))
417 int lbearing = char_metric.abcA;
418 int rbearing = char_metric.abcA + char_metric.abcB;
420 LGLYPH_SET_LBEARING (lglyph, lbearing);
421 LGLYPH_SET_RBEARING (lglyph, rbearing);
423 else
425 LGLYPH_SET_LBEARING (lglyph, 0);
426 LGLYPH_SET_RBEARING (lglyph, advances[j]);
429 if (offsets[j].du || offsets[j].dv
430 /* For non-base glyphs of RTL grapheme clusters,
431 adjust the X offset even if both DU and DV
432 are zero. */
433 || (!attributes[j].fClusterStart && items[i].a.fRTL))
435 Lisp_Object vec = make_uninit_vector (3);
437 if (items[i].a.fRTL)
439 /* Empirically, it looks like Uniscribe
440 interprets DU in reverse direction for
441 RTL clusters. E.g., if we don't reverse
442 the direction, the Hebrew point HOLAM is
443 drawn above the right edge of the base
444 consonant, instead of above the left edge. */
445 ASET (vec, 0, make_number (-offsets[j].du
446 + adj_offset));
447 /* Update the adjustment value for the width
448 advance of the glyph we just emitted. */
449 adj_offset -= 2 * advances[j];
451 else
452 ASET (vec, 0, make_number (offsets[j].du + adj_offset));
453 /* In the font definition coordinate system, the
454 Y coordinate points up, while in our screen
455 coordinates Y grows downwards. So we need to
456 reverse the sign of Y-OFFSET here. */
457 ASET (vec, 1, make_number (-offsets[j].dv));
458 /* Based on what ftfont.c does... */
459 ASET (vec, 2, make_number (advances[j]));
460 LGLYPH_SET_ADJUSTMENT (lglyph, vec);
462 else
464 LGLYPH_SET_ADJUSTMENT (lglyph, Qnil);
465 /* Update the adjustment value to compensate for
466 the width of the base character. */
467 if (items[i].a.fRTL)
468 adj_offset -= advances[j];
473 done_glyphs += nglyphs;
476 xfree (items);
478 if (context)
480 SelectObject (context, old_font);
481 release_frame_dc (f, context);
484 if (NILP (lgstring))
485 return Qnil;
486 else
487 return make_number (done_glyphs);
490 /* Uniscribe implementation of encode_char for font backend.
491 Return a glyph code of FONT for character C (Unicode code point).
492 If FONT doesn't have such a glyph, return FONT_INVALID_CODE. */
493 static unsigned
494 uniscribe_encode_char (struct font *font, int c)
496 HDC context = NULL;
497 struct frame *f = NULL;
498 HFONT old_font = NULL;
499 unsigned code = FONT_INVALID_CODE;
500 wchar_t ch[2];
501 int len;
502 SCRIPT_ITEM* items;
503 int nitems;
504 struct uniscribe_font_info *uniscribe_font
505 = (struct uniscribe_font_info *)font;
507 if (c < 0x10000)
509 ch[0] = (wchar_t) c;
510 len = 1;
512 else
514 DWORD surrogate = c - 0x10000;
516 /* High surrogate: U+D800 - U+DBFF. */
517 ch[0] = 0xD800 + ((surrogate >> 10) & 0x03FF);
518 /* Low surrogate: U+DC00 - U+DFFF. */
519 ch[1] = 0xDC00 + (surrogate & 0x03FF);
520 len = 2;
523 /* Non BMP characters must be handled by the uniscribe shaping
524 engine as GDI functions (except blindly displaying lines of
525 Unicode text) and the promising looking ScriptGetCMap do not
526 convert surrogate pairs to glyph indexes correctly. */
528 items = (SCRIPT_ITEM *) alloca (sizeof (SCRIPT_ITEM) * 2 + 1);
529 if (SUCCEEDED (ScriptItemize (ch, len, 2, NULL, NULL, items, &nitems)))
531 HRESULT result;
532 /* Surrogates seem to need 2 here, even though only one glyph is
533 returned. Indic characters can also produce 2 or more glyphs for
534 a single code point, but they need to use uniscribe_shape
535 above for correct display. */
536 WORD glyphs[2], clusters[2];
537 SCRIPT_VISATTR attrs[2];
538 int nglyphs;
540 /* Force ScriptShape to generate glyphs in the logical
541 order. */
542 items[0].a.fLogicalOrder = 1;
544 result = ScriptShape (context, &(uniscribe_font->cache),
545 ch, len, 2, &(items[0].a),
546 glyphs, clusters, attrs, &nglyphs);
548 if (result == E_PENDING)
550 /* Use selected frame until API is updated to pass
551 the frame. */
552 f = XFRAME (selected_frame);
553 context = get_frame_dc (f);
554 old_font = SelectObject (context, FONT_HANDLE (font));
555 result = ScriptShape (context, &(uniscribe_font->cache),
556 ch, len, 2, &(items[0].a),
557 glyphs, clusters, attrs, &nglyphs);
560 if (SUCCEEDED (result) && nglyphs == 1)
562 /* Some fonts return .notdef glyphs instead of failing.
563 (TrueType spec reserves glyph code 0 for .notdef) */
564 if (glyphs[0])
565 code = glyphs[0];
567 else if (SUCCEEDED (result) || result == E_OUTOFMEMORY)
569 /* This character produces zero or more than one glyph
570 when shaped. But we still need the return from here
571 to be valid for the shaping engine to be invoked
572 later. */
573 result = ScriptGetCMap (context, &(uniscribe_font->cache),
574 ch, len, 0, glyphs);
575 if (SUCCEEDED (result) && glyphs[0])
576 code = glyphs[0];
580 if (context)
582 SelectObject (context, old_font);
583 release_frame_dc (f, context);
586 return code;
590 Shared with w32font:
591 Lisp_Object uniscribe_get_cache (Lisp_Object frame);
592 void uniscribe_free_entity (Lisp_Object font_entity);
593 int uniscribe_has_char (Lisp_Object entity, int c);
594 int uniscribe_text_extents (struct font *font, unsigned *code,
595 int nglyphs, struct font_metrics *metrics);
596 int uniscribe_draw (struct glyph_string *s, int from, int to,
597 int x, int y, int with_background);
599 Unused:
600 int uniscribe_prepare_face (struct frame *f, struct face *face);
601 void uniscribe_done_face (struct frame *f, struct face *face);
602 int uniscribe_get_bitmap (struct font *font, unsigned code,
603 struct font_bitmap *bitmap, int bits_per_pixel);
604 void uniscribe_free_bitmap (struct font *font, struct font_bitmap *bitmap);
605 int uniscribe_anchor_point (struct font *font, unsigned code,
606 int index, int *x, int *y);
607 int uniscribe_start_for_frame (struct frame *f);
608 int uniscribe_end_for_frame (struct frame *f);
613 /* Callback function for EnumFontFamiliesEx.
614 Adds the name of opentype fonts to a Lisp list (passed in as the
615 lParam arg). */
616 static int CALLBACK
617 add_opentype_font_name_to_list (ENUMLOGFONTEX *logical_font,
618 NEWTEXTMETRICEX *physical_font,
619 DWORD font_type, LPARAM list_object)
621 Lisp_Object* list = (Lisp_Object *) list_object;
622 Lisp_Object family;
624 /* Skip vertical fonts (intended only for printing) */
625 if (logical_font->elfLogFont.lfFaceName[0] == '@')
626 return 1;
628 /* Skip non opentype fonts. Count old truetype fonts as opentype,
629 as some of them do contain GPOS and GSUB data that Uniscribe
630 can make use of. */
631 if (!(physical_font->ntmTm.ntmFlags & NTMFLAGS_OPENTYPE)
632 && font_type != TRUETYPE_FONTTYPE)
633 return 1;
635 /* Skip fonts that have no Unicode coverage. */
636 if (!physical_font->ntmFontSig.fsUsb[3]
637 && !physical_font->ntmFontSig.fsUsb[2]
638 && !physical_font->ntmFontSig.fsUsb[1]
639 && !(physical_font->ntmFontSig.fsUsb[0] & 0x3fffffff))
640 return 1;
642 family = intern_font_name (logical_font->elfLogFont.lfFaceName);
643 if (! memq_no_quit (family, *list))
644 *list = Fcons (family, *list);
646 return 1;
650 /* :otf property handling.
651 Since the necessary Uniscribe APIs for getting font tag information
652 are only available in Vista, we need to parse the font data directly
653 according to the OpenType Specification. */
655 /* Push into DWORD backwards to cope with endianness. */
656 #define OTF_TAG(STR) \
657 ((STR[3] << 24) | (STR[2] << 16) | (STR[1] << 8) | STR[0])
659 #define OTF_INT16_VAL(TABLE, OFFSET, PTR) \
660 do { \
661 BYTE temp, data[2]; \
662 if (GetFontData (context, TABLE, OFFSET, data, 2) != 2) \
663 goto font_table_error; \
664 temp = data[0], data[0] = data[1], data[1] = temp; \
665 memcpy (PTR, data, 2); \
666 } while (0)
668 /* Do not reverse the bytes, because we will compare with a OTF_TAG value
669 that has them reversed already. */
670 #define OTF_DWORDTAG_VAL(TABLE, OFFSET, PTR) \
671 do { \
672 if (GetFontData (context, TABLE, OFFSET, PTR, 4) != 4) \
673 goto font_table_error; \
674 } while (0)
676 #define OTF_TAG_VAL(TABLE, OFFSET, STR) \
677 do { \
678 if (GetFontData (context, TABLE, OFFSET, STR, 4) != 4) \
679 goto font_table_error; \
680 STR[4] = '\0'; \
681 } while (0)
683 #define SNAME(VAL) SDATA (SYMBOL_NAME (VAL))
685 /* Check if font supports the otf script/language/features specified.
686 OTF_SPEC is in the format
687 (script lang [(gsub_feature ...)|nil] [(gpos_feature ...)]?) */
689 uniscribe_check_otf (LOGFONT *font, Lisp_Object otf_spec)
691 Lisp_Object script, lang, rest;
692 Lisp_Object features[2];
693 DWORD feature_tables[2];
694 DWORD script_tag, default_script, lang_tag = 0;
695 struct frame * f;
696 HDC context;
697 HFONT check_font, old_font;
698 int i, retval = 0;
699 struct gcpro gcpro1;
701 /* Check the spec is in the right format. */
702 if (!CONSP (otf_spec) || XINT (Flength (otf_spec)) < 3)
703 return 0;
705 /* Break otf_spec into its components. */
706 script = XCAR (otf_spec);
707 rest = XCDR (otf_spec);
709 lang = XCAR (rest);
710 rest = XCDR (rest);
712 features[0] = XCAR (rest);
713 rest = XCDR (rest);
714 if (NILP (rest))
715 features[1] = Qnil;
716 else
717 features[1] = XCAR (rest);
719 /* Set up tags we will use in the search. */
720 feature_tables[0] = OTF_TAG ("GSUB");
721 feature_tables[1] = OTF_TAG ("GPOS");
722 default_script = OTF_TAG ("DFLT");
723 if (NILP (script))
724 script_tag = default_script;
725 else
726 script_tag = OTF_TAG (SNAME (script));
727 if (!NILP (lang))
728 lang_tag = OTF_TAG (SNAME (lang));
730 /* Set up graphics context so we can use the font. */
731 f = XFRAME (selected_frame);
732 context = get_frame_dc (f);
733 check_font = CreateFontIndirect (font);
734 old_font = SelectObject (context, check_font);
736 /* Everything else is contained within otf_spec so should get
737 marked along with it. */
738 GCPRO1 (otf_spec);
740 /* Scan GSUB and GPOS tables. */
741 for (i = 0; i < 2; i++)
743 int j, n_match_features;
744 unsigned short scriptlist_table, feature_table, n_scripts;
745 unsigned short script_table, langsys_table, n_langs;
746 unsigned short feature_index, n_features;
747 DWORD tbl = feature_tables[i];
749 /* Skip if no features requested from this table. */
750 if (NILP (features[i]))
751 continue;
753 /* If features is not a cons, this font spec is messed up. */
754 if (!CONSP (features[i]))
755 goto no_support;
757 /* Read GPOS/GSUB header. */
758 OTF_INT16_VAL (tbl, 4, &scriptlist_table);
759 OTF_INT16_VAL (tbl, 6, &feature_table);
760 OTF_INT16_VAL (tbl, scriptlist_table, &n_scripts);
762 /* Find the appropriate script table. */
763 script_table = 0;
764 for (j = 0; j < n_scripts; j++)
766 DWORD script_id;
767 OTF_DWORDTAG_VAL (tbl, scriptlist_table + 2 + j * 6, &script_id);
768 if (script_id == script_tag)
770 OTF_INT16_VAL (tbl, scriptlist_table + 6 + j * 6, &script_table);
771 break;
773 #if 0 /* Causes false positives. */
774 /* If there is a DFLT script defined in the font, use it
775 if the specified script is not found. */
776 else if (script_id == default_script)
777 OTF_INT16_VAL (tbl, scriptlist_table + 6 + j * 6, &script_table);
778 #endif
780 /* If no specific or default script table was found, then this font
781 does not support the script. */
782 if (!script_table)
783 goto no_support;
785 /* Offset is from beginning of scriptlist_table. */
786 script_table += scriptlist_table;
788 /* Get default langsys table. */
789 OTF_INT16_VAL (tbl, script_table, &langsys_table);
791 /* If lang was specified, see if font contains a specific entry. */
792 if (!NILP (lang))
794 OTF_INT16_VAL (tbl, script_table + 2, &n_langs);
796 for (j = 0; j < n_langs; j++)
798 DWORD lang_id;
799 OTF_DWORDTAG_VAL (tbl, script_table + 4 + j * 6, &lang_id);
800 if (lang_id == lang_tag)
802 OTF_INT16_VAL (tbl, script_table + 8 + j * 6, &langsys_table);
803 break;
808 if (!langsys_table)
809 goto no_support;
811 /* Offset is from beginning of script table. */
812 langsys_table += script_table;
814 /* Check the features. Features may contain nil according to
815 documentation in font_prop_validate_otf, so count them. */
816 n_match_features = 0;
817 for (rest = features[i]; CONSP (rest); rest = XCDR (rest))
819 Lisp_Object feature = XCAR (rest);
820 if (!NILP (feature))
821 n_match_features++;
824 /* If there are no features to check, skip checking. */
825 if (!n_match_features)
826 continue;
828 /* First check required feature (if any). */
829 OTF_INT16_VAL (tbl, langsys_table + 2, &feature_index);
830 if (feature_index != 0xFFFF)
832 char feature_id[5];
833 OTF_TAG_VAL (tbl, feature_table + 2 + feature_index * 6, feature_id);
834 OTF_TAG_VAL (tbl, feature_table + 2 + feature_index * 6, feature_id);
835 /* Assume no duplicates in the font table. This allows us to mark
836 the features off by simply decrementing a counter. */
837 if (!NILP (Fmemq (intern (feature_id), features[i])))
838 n_match_features--;
840 /* Now check all the other features. */
841 OTF_INT16_VAL (tbl, langsys_table + 4, &n_features);
842 for (j = 0; j < n_features; j++)
844 char feature_id[5];
845 OTF_INT16_VAL (tbl, langsys_table + 6 + j * 2, &feature_index);
846 OTF_TAG_VAL (tbl, feature_table + 2 + feature_index * 6, feature_id);
847 /* Assume no duplicates in the font table. This allows us to mark
848 the features off by simply decrementing a counter. */
849 if (!NILP (Fmemq (intern (feature_id), features[i])))
850 n_match_features--;
853 if (n_match_features > 0)
854 goto no_support;
857 retval = 1;
859 no_support:
860 font_table_error:
861 /* restore graphics context. */
862 SelectObject (context, old_font);
863 DeleteObject (check_font);
864 release_frame_dc (f, context);
866 return retval;
869 static Lisp_Object
870 otf_features (HDC context, char *table)
872 Lisp_Object script_list = Qnil;
873 unsigned short scriptlist_table, n_scripts, feature_table;
874 DWORD tbl = OTF_TAG (table);
875 int i, j, k;
877 /* Look for scripts in the table. */
878 OTF_INT16_VAL (tbl, 4, &scriptlist_table);
879 OTF_INT16_VAL (tbl, 6, &feature_table);
880 OTF_INT16_VAL (tbl, scriptlist_table, &n_scripts);
882 for (i = 0; i < n_scripts; i++)
884 char script[5], lang[5];
885 unsigned short script_table, lang_count, langsys_table, feature_count;
886 Lisp_Object script_tag, langsys_list, langsys_tag, feature_list;
887 unsigned short record_offset = scriptlist_table + 2 + i * 6;
888 OTF_TAG_VAL (tbl, record_offset, script);
889 OTF_INT16_VAL (tbl, record_offset + 4, &script_table);
891 /* Offset is from beginning of script table. */
892 script_table += scriptlist_table;
894 script_tag = intern (script);
895 langsys_list = Qnil;
897 /* Optional default lang. */
898 OTF_INT16_VAL (tbl, script_table, &langsys_table);
899 if (langsys_table)
901 /* Offset is from beginning of script table. */
902 langsys_table += script_table;
904 langsys_tag = Qnil;
905 feature_list = Qnil;
906 OTF_INT16_VAL (tbl, langsys_table + 4, &feature_count);
907 for (k = 0; k < feature_count; k++)
909 char feature[5];
910 unsigned short index;
911 OTF_INT16_VAL (tbl, langsys_table + 6 + k * 2, &index);
912 OTF_TAG_VAL (tbl, feature_table + 2 + index * 6, feature);
913 feature_list = Fcons (intern (feature), feature_list);
915 langsys_list = Fcons (Fcons (langsys_tag, feature_list),
916 langsys_list);
919 /* List of supported languages. */
920 OTF_INT16_VAL (tbl, script_table + 2, &lang_count);
922 for (j = 0; j < lang_count; j++)
924 record_offset = script_table + 4 + j * 6;
925 OTF_TAG_VAL (tbl, record_offset, lang);
926 OTF_INT16_VAL (tbl, record_offset + 4, &langsys_table);
928 /* Offset is from beginning of script table. */
929 langsys_table += script_table;
931 langsys_tag = intern (lang);
932 feature_list = Qnil;
933 OTF_INT16_VAL (tbl, langsys_table + 4, &feature_count);
934 for (k = 0; k < feature_count; k++)
936 char feature[5];
937 unsigned short index;
938 OTF_INT16_VAL (tbl, langsys_table + 6 + k * 2, &index);
939 OTF_TAG_VAL (tbl, feature_table + 2 + index * 6, feature);
940 feature_list = Fcons (intern (feature), feature_list);
942 langsys_list = Fcons (Fcons (langsys_tag, feature_list),
943 langsys_list);
947 script_list = Fcons (Fcons (script_tag, langsys_list), script_list);
950 return script_list;
952 font_table_error:
953 return Qnil;
956 #undef OTF_INT16_VAL
957 #undef OTF_TAG_VAL
958 #undef OTF_TAG
961 struct font_driver uniscribe_font_driver =
963 LISP_INITIALLY_ZERO, /* Quniscribe */
964 0, /* case insensitive */
965 w32font_get_cache,
966 uniscribe_list,
967 uniscribe_match,
968 uniscribe_list_family,
969 NULL, /* free_entity */
970 uniscribe_open,
971 uniscribe_close,
972 NULL, /* prepare_face */
973 NULL, /* done_face */
974 w32font_has_char,
975 uniscribe_encode_char,
976 w32font_text_extents,
977 w32font_draw,
978 NULL, /* get_bitmap */
979 NULL, /* free_bitmap */
980 NULL, /* anchor_point */
981 uniscribe_otf_capability, /* Defined so (font-get FONTOBJ :otf) works. */
982 NULL, /* otf_drive - use shape instead. */
983 NULL, /* start_for_frame */
984 NULL, /* end_for_frame */
985 uniscribe_shape,
986 NULL, /* check */
987 NULL, /* get_variation_glyphs */
988 NULL, /* filter_properties */
989 NULL, /* cached_font_ok */
992 /* Note that this should be called at every startup, not just when dumping,
993 as it needs to test for the existence of the Uniscribe library. */
994 void
995 syms_of_w32uniscribe (void)
997 HMODULE uniscribe;
999 /* Don't init uniscribe when dumping */
1000 if (!initialized)
1001 return;
1003 /* Don't register if uniscribe is not available. */
1004 uniscribe = GetModuleHandle ("usp10");
1005 if (!uniscribe)
1006 return;
1008 uniscribe_font_driver.type = Quniscribe;
1009 uniscribe_available = 1;
1011 register_font_driver (&uniscribe_font_driver, NULL);