]> code.delx.au - gnu-emacs/blob - src/w32uniscribe.c
Nuke arch-tags.
[gnu-emacs] / src / w32uniscribe.c
1 /* Font backend for the Microsoft W32 Uniscribe API.
2 Copyright (C) 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
3
4 This file is part of GNU Emacs.
5
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.
10
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.
15
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/>. */
18
19
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>
30 #include <setjmp.h>
31
32 #include "lisp.h"
33 #include "w32term.h"
34 #include "frame.h"
35 #include "dispextern.h"
36 #include "character.h"
37 #include "charset.h"
38 #include "composite.h"
39 #include "fontset.h"
40 #include "font.h"
41 #include "w32font.h"
42
43 struct uniscribe_font_info
44 {
45 struct w32font_info w32_font;
46 SCRIPT_CACHE cache;
47 };
48
49 int uniscribe_available = 0;
50
51 /* Defined in w32font.c, since it is required there as well. */
52 extern Lisp_Object Quniscribe;
53 extern Lisp_Object Qopentype;
54
55 extern int initialized;
56
57 extern struct font_driver uniscribe_font_driver;
58
59 /* EnumFontFamiliesEx callback. */
60 static int CALLBACK add_opentype_font_name_to_list (ENUMLOGFONTEX *,
61 NEWTEXTMETRICEX *,
62 DWORD, LPARAM);
63 /* Used by uniscribe_otf_capability. */
64 static Lisp_Object otf_features (HDC context, char *table);
65
66 static int
67 memq_no_quit (Lisp_Object elt, Lisp_Object list)
68 {
69 while (CONSP (list) && ! EQ (XCAR (list), elt))
70 list = XCDR (list);
71 return (CONSP (list));
72 }
73
74 \f
75 /* Font backend interface implementation. */
76 static Lisp_Object
77 uniscribe_list (Lisp_Object frame, Lisp_Object font_spec)
78 {
79 Lisp_Object fonts = w32font_list_internal (frame, font_spec, 1);
80 FONT_ADD_LOG ("uniscribe-list", font_spec, fonts);
81 return fonts;
82 }
83
84 static Lisp_Object
85 uniscribe_match (Lisp_Object frame, Lisp_Object font_spec)
86 {
87 Lisp_Object entity = w32font_match_internal (frame, font_spec, 1);
88 FONT_ADD_LOG ("uniscribe-match", font_spec, entity);
89 return entity;
90 }
91
92 static Lisp_Object
93 uniscribe_list_family (Lisp_Object frame)
94 {
95 Lisp_Object list = Qnil;
96 LOGFONT font_match_pattern;
97 HDC dc;
98 FRAME_PTR f = XFRAME (frame);
99
100 memset (&font_match_pattern, 0, sizeof (font_match_pattern));
101 /* Limit enumerated fonts to outline fonts to save time. */
102 font_match_pattern.lfOutPrecision = OUT_OUTLINE_PRECIS;
103
104 dc = get_frame_dc (f);
105
106 EnumFontFamiliesEx (dc, &font_match_pattern,
107 (FONTENUMPROC) add_opentype_font_name_to_list,
108 (LPARAM) &list, 0);
109 release_frame_dc (f, dc);
110
111 return list;
112 }
113
114 static Lisp_Object
115 uniscribe_open (FRAME_PTR f, Lisp_Object font_entity, int pixel_size)
116 {
117 Lisp_Object font_object
118 = font_make_object (VECSIZE (struct uniscribe_font_info),
119 font_entity, pixel_size);
120 struct uniscribe_font_info *uniscribe_font
121 = (struct uniscribe_font_info *) XFONT_OBJECT (font_object);
122
123 ASET (font_object, FONT_TYPE_INDEX, Quniscribe);
124
125 if (!w32font_open_internal (f, font_entity, pixel_size, font_object))
126 {
127 return Qnil;
128 }
129
130 /* Initialize the cache for this font. */
131 uniscribe_font->cache = NULL;
132
133 /* Uniscribe backend uses glyph indices. */
134 uniscribe_font->w32_font.glyph_idx = ETO_GLYPH_INDEX;
135
136 /* Mark the format as opentype */
137 uniscribe_font->w32_font.font.props[FONT_FORMAT_INDEX] = Qopentype;
138 uniscribe_font->w32_font.font.driver = &uniscribe_font_driver;
139
140 return font_object;
141 }
142
143 static void
144 uniscribe_close (FRAME_PTR f, struct font *font)
145 {
146 struct uniscribe_font_info *uniscribe_font
147 = (struct uniscribe_font_info *) font;
148
149 if (uniscribe_font->cache)
150 ScriptFreeCache (&(uniscribe_font->cache));
151
152 w32font_close (f, font);
153 }
154
155 /* Return a list describing which scripts/languages FONT supports by
156 which GSUB/GPOS features of OpenType tables. */
157 static Lisp_Object
158 uniscribe_otf_capability (struct font *font)
159 {
160 HDC context;
161 HFONT old_font;
162 struct frame *f;
163 Lisp_Object capability = Fcons (Qnil, Qnil);
164 Lisp_Object features;
165
166 f = XFRAME (selected_frame);
167 context = get_frame_dc (f);
168 old_font = SelectObject (context, FONT_HANDLE (font));
169
170 features = otf_features (context, "GSUB");
171 XSETCAR (capability, features);
172 features = otf_features (context, "GPOS");
173 XSETCDR (capability, features);
174
175 SelectObject (context, old_font);
176 release_frame_dc (f, context);
177
178 return capability;
179 }
180
181 /* Uniscribe implementation of shape for font backend.
182
183 Shape text in LGSTRING. See the docstring of
184 `composition-get-gstring' for the format of LGSTRING. If the
185 (N+1)th element of LGSTRING is nil, input of shaping is from the
186 1st to (N)th elements. In each input glyph, FROM, TO, CHAR, and
187 CODE are already set.
188
189 This function updates all fields of the input glyphs. If the
190 output glyphs (M) are more than the input glyphs (N), (N+1)th
191 through (M)th elements of LGSTRING are updated possibly by making
192 a new glyph object and storing it in LGSTRING. If (M) is greater
193 than the length of LGSTRING, nil should be returned. In that case,
194 this function is called again with a larger LGSTRING. */
195 static Lisp_Object
196 uniscribe_shape (Lisp_Object lgstring)
197 {
198 struct font * font;
199 struct uniscribe_font_info * uniscribe_font;
200 EMACS_UINT nchars;
201 int nitems, max_items, i, max_glyphs, done_glyphs;
202 wchar_t *chars;
203 WORD *glyphs, *clusters;
204 SCRIPT_ITEM *items;
205 SCRIPT_VISATTR *attributes;
206 int *advances;
207 GOFFSET *offsets;
208 ABC overall_metrics;
209 HRESULT result;
210 struct frame * f = NULL;
211 HDC context = NULL;
212 HFONT old_font = NULL;
213
214 CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring), font);
215 uniscribe_font = (struct uniscribe_font_info *) font;
216
217 /* Get the chars from lgstring in a form we can use with uniscribe. */
218 max_glyphs = nchars = LGSTRING_GLYPH_LEN (lgstring);
219 done_glyphs = 0;
220 chars = (wchar_t *) alloca (nchars * sizeof (wchar_t));
221 /* FIXME: This loop assumes that characters in the input LGSTRING
222 are all inside the BMP. Need to encode characters beyond the BMP
223 as UTF-16. */
224 for (i = 0; i < nchars; i++)
225 {
226 /* lgstring can be bigger than the number of characters in it, in
227 the case where more glyphs are required to display those characters.
228 If that is the case, note the real number of characters. */
229 if (NILP (LGSTRING_GLYPH (lgstring, i)))
230 nchars = i;
231 else
232 chars[i] = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, i));
233 }
234
235 /* First we need to break up the glyph string into runs of glyphs that
236 can be treated together. First try a single run. */
237 max_items = 2;
238 items = (SCRIPT_ITEM *) xmalloc (sizeof (SCRIPT_ITEM) * max_items + 1);
239
240 while ((result = ScriptItemize (chars, nchars, max_items, NULL, NULL,
241 items, &nitems)) == E_OUTOFMEMORY)
242 {
243 /* If that wasn't enough, keep trying with one more run. */
244 max_items++;
245 items = (SCRIPT_ITEM *) xrealloc (items,
246 sizeof (SCRIPT_ITEM) * max_items + 1);
247 }
248
249 if (FAILED (result))
250 {
251 xfree (items);
252 return Qnil;
253 }
254
255 glyphs = alloca (max_glyphs * sizeof (WORD));
256 clusters = alloca (nchars * sizeof (WORD));
257 attributes = alloca (max_glyphs * sizeof (SCRIPT_VISATTR));
258 advances = alloca (max_glyphs * sizeof (int));
259 offsets = alloca (max_glyphs * sizeof (GOFFSET));
260
261 for (i = 0; i < nitems; i++)
262 {
263 int nglyphs, nchars_in_run;
264 nchars_in_run = items[i+1].iCharPos - items[i].iCharPos;
265 /* Force ScriptShape to generate glyphs in the same order as
266 they are in the input LGSTRING, which is in the logical
267 order. */
268 items[i].a.fLogicalOrder = 1;
269
270 /* Context may be NULL here, in which case the cache should be
271 used without needing to select the font. */
272 result = ScriptShape (context, &(uniscribe_font->cache),
273 chars + items[i].iCharPos, nchars_in_run,
274 max_glyphs - done_glyphs, &(items[i].a),
275 glyphs, clusters, attributes, &nglyphs);
276
277 if (result == E_PENDING && !context)
278 {
279 /* This assumes the selected frame is on the same display as the
280 one we are drawing. It would be better for the frame to be
281 passed in. */
282 f = XFRAME (selected_frame);
283 context = get_frame_dc (f);
284 old_font = SelectObject (context, FONT_HANDLE (font));
285
286 result = ScriptShape (context, &(uniscribe_font->cache),
287 chars + items[i].iCharPos, nchars_in_run,
288 max_glyphs - done_glyphs, &(items[i].a),
289 glyphs, clusters, attributes, &nglyphs);
290 }
291
292 if (result == E_OUTOFMEMORY)
293 {
294 /* Need a bigger lgstring. */
295 lgstring = Qnil;
296 break;
297 }
298 else if (FAILED (result))
299 {
300 /* Can't shape this run - return results so far if any. */
301 break;
302 }
303 else if (items[i].a.fNoGlyphIndex)
304 {
305 /* Glyph indices not supported by this font (or OS), means we
306 can't really do any meaningful shaping. */
307 break;
308 }
309 else
310 {
311 result = ScriptPlace (context, &(uniscribe_font->cache),
312 glyphs, nglyphs, attributes, &(items[i].a),
313 advances, offsets, &overall_metrics);
314 if (result == E_PENDING && !context)
315 {
316 /* Cache not complete... */
317 f = XFRAME (selected_frame);
318 context = get_frame_dc (f);
319 old_font = SelectObject (context, FONT_HANDLE (font));
320
321 result = ScriptPlace (context, &(uniscribe_font->cache),
322 glyphs, nglyphs, attributes, &(items[i].a),
323 advances, offsets, &overall_metrics);
324 }
325 if (SUCCEEDED (result))
326 {
327 int j, nclusters, from, to;
328
329 from = 0;
330 to = from;
331
332 for (j = 0; j < nglyphs; j++)
333 {
334 int lglyph_index = j + done_glyphs;
335 Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, lglyph_index);
336 ABC char_metric;
337 unsigned gl;
338
339 if (NILP (lglyph))
340 {
341 lglyph = Fmake_vector (make_number (LGLYPH_SIZE), Qnil);
342 LGSTRING_SET_GLYPH (lgstring, lglyph_index, lglyph);
343 }
344 /* Copy to a 32-bit data type to shut up the
345 compiler warning in LGLYPH_SET_CODE about
346 comparison being always false. */
347 gl = glyphs[j];
348 LGLYPH_SET_CODE (lglyph, gl);
349
350 /* Detect clusters, for linking codes back to
351 characters. */
352 if (attributes[j].fClusterStart)
353 {
354 while (from < nchars_in_run && clusters[from] < j)
355 from++;
356 if (from >= nchars_in_run)
357 from = to = nchars_in_run - 1;
358 else
359 {
360 int k;
361 to = nchars_in_run - 1;
362 for (k = from + 1; k < nchars_in_run; k++)
363 {
364 if (clusters[k] > j)
365 {
366 to = k - 1;
367 break;
368 }
369 }
370 }
371 }
372
373 LGLYPH_SET_CHAR (lglyph, chars[items[i].iCharPos
374 + from]);
375 LGLYPH_SET_FROM (lglyph, items[i].iCharPos + from);
376 LGLYPH_SET_TO (lglyph, items[i].iCharPos + to);
377
378 /* Metrics. */
379 LGLYPH_SET_WIDTH (lglyph, advances[j]);
380 LGLYPH_SET_ASCENT (lglyph, font->ascent);
381 LGLYPH_SET_DESCENT (lglyph, font->descent);
382
383 result = ScriptGetGlyphABCWidth (context,
384 &(uniscribe_font->cache),
385 glyphs[j], &char_metric);
386 if (result == E_PENDING && !context)
387 {
388 /* Cache incomplete... */
389 f = XFRAME (selected_frame);
390 context = get_frame_dc (f);
391 old_font = SelectObject (context, FONT_HANDLE (font));
392 result = ScriptGetGlyphABCWidth (context,
393 &(uniscribe_font->cache),
394 glyphs[j], &char_metric);
395 }
396
397 if (SUCCEEDED (result))
398 {
399 LGLYPH_SET_LBEARING (lglyph, char_metric.abcA);
400 LGLYPH_SET_RBEARING (lglyph, (char_metric.abcA
401 + char_metric.abcB));
402 }
403 else
404 {
405 LGLYPH_SET_LBEARING (lglyph, 0);
406 LGLYPH_SET_RBEARING (lglyph, advances[j]);
407 }
408
409 if (offsets[j].du || offsets[j].dv)
410 {
411 Lisp_Object vec;
412 vec = Fmake_vector (make_number (3), Qnil);
413 ASET (vec, 0, make_number (offsets[j].du));
414 ASET (vec, 1, make_number (offsets[j].dv));
415 /* Based on what ftfont.c does... */
416 ASET (vec, 2, make_number (advances[j]));
417 LGLYPH_SET_ADJUSTMENT (lglyph, vec);
418 }
419 else
420 LGLYPH_SET_ADJUSTMENT (lglyph, Qnil);
421 }
422 }
423 }
424 done_glyphs += nglyphs;
425 }
426
427 xfree (items);
428
429 if (context)
430 {
431 SelectObject (context, old_font);
432 release_frame_dc (f, context);
433 }
434
435 if (NILP (lgstring))
436 return Qnil;
437 else
438 return make_number (done_glyphs);
439 }
440
441 /* Uniscribe implementation of encode_char for font backend.
442 Return a glyph code of FONT for character C (Unicode code point).
443 If FONT doesn't have such a glyph, return FONT_INVALID_CODE. */
444 static unsigned
445 uniscribe_encode_char (struct font *font, int c)
446 {
447 HDC context = NULL;
448 struct frame *f = NULL;
449 HFONT old_font = NULL;
450 unsigned code = FONT_INVALID_CODE;
451 wchar_t ch[2];
452 int len;
453 SCRIPT_ITEM* items;
454 int nitems;
455 struct uniscribe_font_info *uniscribe_font
456 = (struct uniscribe_font_info *)font;
457
458 if (c < 0x10000)
459 {
460 ch[0] = (wchar_t) c;
461 len = 1;
462 }
463 else
464 {
465 DWORD surrogate = c - 0x10000;
466
467 /* High surrogate: U+D800 - U+DBFF. */
468 ch[0] = 0xD800 + ((surrogate >> 10) & 0x03FF);
469 /* Low surrogate: U+DC00 - U+DFFF. */
470 ch[1] = 0xDC00 + (surrogate & 0x03FF);
471 len = 2;
472 }
473
474 /* Non BMP characters must be handled by the uniscribe shaping
475 engine as GDI functions (except blindly displaying lines of
476 unicode text) and the promising looking ScriptGetCMap do not
477 convert surrogate pairs to glyph indexes correctly. */
478 {
479 items = (SCRIPT_ITEM *) alloca (sizeof (SCRIPT_ITEM) * 2 + 1);
480 if (SUCCEEDED (ScriptItemize (ch, len, 2, NULL, NULL, items, &nitems)))
481 {
482 HRESULT result;
483 /* Surrogates seem to need 2 here, even though only one glyph is
484 returned. Indic characters can also produce 2 or more glyphs for
485 a single code point, but they need to use uniscribe_shape
486 above for correct display. */
487 WORD glyphs[2], clusters[2];
488 SCRIPT_VISATTR attrs[2];
489 int nglyphs;
490
491 /* Force ScriptShape to generate glyphs in the logical
492 order. */
493 items[0].a.fLogicalOrder = 1;
494
495 result = ScriptShape (context, &(uniscribe_font->cache),
496 ch, len, 2, &(items[0].a),
497 glyphs, clusters, attrs, &nglyphs);
498
499 if (result == E_PENDING)
500 {
501 /* Use selected frame until API is updated to pass
502 the frame. */
503 f = XFRAME (selected_frame);
504 context = get_frame_dc (f);
505 old_font = SelectObject (context, FONT_HANDLE (font));
506 result = ScriptShape (context, &(uniscribe_font->cache),
507 ch, len, 2, &(items[0].a),
508 glyphs, clusters, attrs, &nglyphs);
509 }
510
511 if (SUCCEEDED (result) && nglyphs == 1)
512 {
513 /* Some fonts return .notdef glyphs instead of failing.
514 (Truetype spec reserves glyph code 0 for .notdef) */
515 if (glyphs[0])
516 code = glyphs[0];
517 }
518 else if (SUCCEEDED (result) || result == E_OUTOFMEMORY)
519 {
520 /* This character produces zero or more than one glyph
521 when shaped. But we still need the return from here
522 to be valid for the shaping engine to be invoked
523 later. */
524 result = ScriptGetCMap (context, &(uniscribe_font->cache),
525 ch, len, 0, glyphs);
526 if (SUCCEEDED (result) && glyphs[0])
527 code = glyphs[0];
528 }
529 }
530 }
531 if (context)
532 {
533 SelectObject (context, old_font);
534 release_frame_dc (f, context);
535 }
536
537 return code;
538 }
539
540 /*
541 Shared with w32font:
542 Lisp_Object uniscribe_get_cache (Lisp_Object frame);
543 void uniscribe_free_entity (Lisp_Object font_entity);
544 int uniscribe_has_char (Lisp_Object entity, int c);
545 int uniscribe_text_extents (struct font *font, unsigned *code,
546 int nglyphs, struct font_metrics *metrics);
547 int uniscribe_draw (struct glyph_string *s, int from, int to,
548 int x, int y, int with_background);
549
550 Unused:
551 int uniscribe_prepare_face (FRAME_PTR f, struct face *face);
552 void uniscribe_done_face (FRAME_PTR f, struct face *face);
553 int uniscribe_get_bitmap (struct font *font, unsigned code,
554 struct font_bitmap *bitmap, int bits_per_pixel);
555 void uniscribe_free_bitmap (struct font *font, struct font_bitmap *bitmap);
556 void * uniscribe_get_outline (struct font *font, unsigned code);
557 void uniscribe_free_outline (struct font *font, void *outline);
558 int uniscribe_anchor_point (struct font *font, unsigned code,
559 int index, int *x, int *y);
560 int uniscribe_start_for_frame (FRAME_PTR f);
561 int uniscribe_end_for_frame (FRAME_PTR f);
562
563 */
564
565 \f
566 /* Callback function for EnumFontFamiliesEx.
567 Adds the name of opentype fonts to a Lisp list (passed in as the
568 lParam arg). */
569 static int CALLBACK
570 add_opentype_font_name_to_list (ENUMLOGFONTEX *logical_font,
571 NEWTEXTMETRICEX *physical_font,
572 DWORD font_type, LPARAM list_object)
573 {
574 Lisp_Object* list = (Lisp_Object *) list_object;
575 Lisp_Object family;
576
577 /* Skip vertical fonts (intended only for printing) */
578 if (logical_font->elfLogFont.lfFaceName[0] == '@')
579 return 1;
580
581 /* Skip non opentype fonts. Count old truetype fonts as opentype,
582 as some of them do contain GPOS and GSUB data that Uniscribe
583 can make use of. */
584 if (!(physical_font->ntmTm.ntmFlags & NTMFLAGS_OPENTYPE)
585 && font_type != TRUETYPE_FONTTYPE)
586 return 1;
587
588 /* Skip fonts that have no unicode coverage. */
589 if (!physical_font->ntmFontSig.fsUsb[3]
590 && !physical_font->ntmFontSig.fsUsb[2]
591 && !physical_font->ntmFontSig.fsUsb[1]
592 && !(physical_font->ntmFontSig.fsUsb[0] & 0x3fffffff))
593 return 1;
594
595 family = intern_font_name (logical_font->elfLogFont.lfFaceName);
596 if (! memq_no_quit (family, *list))
597 *list = Fcons (family, *list);
598
599 return 1;
600 }
601
602 \f
603 /* :otf property handling.
604 Since the necessary Uniscribe APIs for getting font tag information
605 are only available in Vista, we need to parse the font data directly
606 according to the OpenType Specification. */
607
608 /* Push into DWORD backwards to cope with endianness. */
609 #define OTF_TAG(STR) \
610 ((STR[3] << 24) | (STR[2] << 16) | (STR[1] << 8) | STR[0])
611
612 #define OTF_INT16_VAL(TABLE, OFFSET, PTR) \
613 do { \
614 BYTE temp, data[2]; \
615 if (GetFontData (context, TABLE, OFFSET, data, 2) != 2) \
616 goto font_table_error; \
617 temp = data[0], data[0] = data[1], data[1] = temp; \
618 memcpy (PTR, data, 2); \
619 } while (0)
620
621 /* Do not reverse the bytes, because we will compare with a OTF_TAG value
622 that has them reversed already. */
623 #define OTF_DWORDTAG_VAL(TABLE, OFFSET, PTR) \
624 do { \
625 if (GetFontData (context, TABLE, OFFSET, PTR, 4) != 4) \
626 goto font_table_error; \
627 } while (0)
628
629 #define OTF_TAG_VAL(TABLE, OFFSET, STR) \
630 do { \
631 if (GetFontData (context, TABLE, OFFSET, STR, 4) != 4) \
632 goto font_table_error; \
633 STR[4] = '\0'; \
634 } while (0)
635
636 static char* NOTHING = " ";
637
638 #define SNAME(VAL) SDATA (SYMBOL_NAME (VAL))
639
640 /* Check if font supports the otf script/language/features specified.
641 OTF_SPEC is in the format
642 (script lang [(gsub_feature ...)|nil] [(gpos_feature ...)]?) */
643 int
644 uniscribe_check_otf (LOGFONT *font, Lisp_Object otf_spec)
645 {
646 Lisp_Object script, lang, rest;
647 Lisp_Object features[2];
648 DWORD feature_tables[2];
649 DWORD script_tag, default_script, lang_tag = 0;
650 struct frame * f;
651 HDC context;
652 HFONT check_font, old_font;
653 DWORD table;
654 int i, retval = 0;
655 struct gcpro gcpro1;
656
657 /* Check the spec is in the right format. */
658 if (!CONSP (otf_spec) || XINT (Flength (otf_spec)) < 3)
659 return 0;
660
661 /* Break otf_spec into its components. */
662 script = XCAR (otf_spec);
663 rest = XCDR (otf_spec);
664
665 lang = XCAR (rest);
666 rest = XCDR (rest);
667
668 features[0] = XCAR (rest);
669 rest = XCDR (rest);
670 if (NILP (rest))
671 features[1] = Qnil;
672 else
673 features[1] = XCAR (rest);
674
675 /* Set up tags we will use in the search. */
676 feature_tables[0] = OTF_TAG ("GSUB");
677 feature_tables[1] = OTF_TAG ("GPOS");
678 default_script = OTF_TAG ("DFLT");
679 if (NILP (script))
680 script_tag = default_script;
681 else
682 script_tag = OTF_TAG (SNAME (script));
683 if (!NILP (lang))
684 lang_tag = OTF_TAG (SNAME (lang));
685
686 /* Set up graphics context so we can use the font. */
687 f = XFRAME (selected_frame);
688 context = get_frame_dc (f);
689 check_font = CreateFontIndirect (font);
690 old_font = SelectObject (context, check_font);
691
692 /* Everything else is contained within otf_spec so should get
693 marked along with it. */
694 GCPRO1 (otf_spec);
695
696 /* Scan GSUB and GPOS tables. */
697 for (i = 0; i < 2; i++)
698 {
699 int j, n_match_features;
700 unsigned short scriptlist_table, feature_table, n_scripts;
701 unsigned short script_table, langsys_table, n_langs;
702 unsigned short feature_index, n_features;
703 DWORD tbl = feature_tables[i];
704
705 /* Skip if no features requested from this table. */
706 if (NILP (features[i]))
707 continue;
708
709 /* If features is not a cons, this font spec is messed up. */
710 if (!CONSP (features[i]))
711 goto no_support;
712
713 /* Read GPOS/GSUB header. */
714 OTF_INT16_VAL (tbl, 4, &scriptlist_table);
715 OTF_INT16_VAL (tbl, 6, &feature_table);
716 OTF_INT16_VAL (tbl, scriptlist_table, &n_scripts);
717
718 /* Find the appropriate script table. */
719 script_table = 0;
720 for (j = 0; j < n_scripts; j++)
721 {
722 DWORD script_id;
723 OTF_DWORDTAG_VAL (tbl, scriptlist_table + 2 + j * 6, &script_id);
724 if (script_id == script_tag)
725 {
726 OTF_INT16_VAL (tbl, scriptlist_table + 6 + j * 6, &script_table);
727 break;
728 }
729 #if 0 /* Causes false positives. */
730 /* If there is a DFLT script defined in the font, use it
731 if the specified script is not found. */
732 else if (script_id == default_script)
733 OTF_INT16_VAL (tbl, scriptlist_table + 6 + j * 6, &script_table);
734 #endif
735 }
736 /* If no specific or default script table was found, then this font
737 does not support the script. */
738 if (!script_table)
739 goto no_support;
740
741 /* Offset is from beginning of scriptlist_table. */
742 script_table += scriptlist_table;
743
744 /* Get default langsys table. */
745 OTF_INT16_VAL (tbl, script_table, &langsys_table);
746
747 /* If lang was specified, see if font contains a specific entry. */
748 if (!NILP (lang))
749 {
750 OTF_INT16_VAL (tbl, script_table + 2, &n_langs);
751
752 for (j = 0; j < n_langs; j++)
753 {
754 DWORD lang_id;
755 OTF_DWORDTAG_VAL (tbl, script_table + 4 + j * 6, &lang_id);
756 if (lang_id == lang_tag)
757 {
758 OTF_INT16_VAL (tbl, script_table + 8 + j * 6, &langsys_table);
759 break;
760 }
761 }
762 }
763
764 if (!langsys_table)
765 goto no_support;
766
767 /* Offset is from beginning of script table. */
768 langsys_table += script_table;
769
770 /* Check the features. Features may contain nil according to
771 documentation in font_prop_validate_otf, so count them. */
772 n_match_features = 0;
773 for (rest = features[i]; CONSP (rest); rest = XCDR (rest))
774 {
775 Lisp_Object feature = XCAR (rest);
776 if (!NILP (feature))
777 n_match_features++;
778 }
779
780 /* If there are no features to check, skip checking. */
781 if (!n_match_features)
782 continue;
783
784 /* First check required feature (if any). */
785 OTF_INT16_VAL (tbl, langsys_table + 2, &feature_index);
786 if (feature_index != 0xFFFF)
787 {
788 char feature_id[5];
789 OTF_TAG_VAL (tbl, feature_table + 2 + feature_index * 6, feature_id);
790 OTF_TAG_VAL (tbl, feature_table + 2 + feature_index * 6, feature_id);
791 /* Assume no duplicates in the font table. This allows us to mark
792 the features off by simply decrementing a counter. */
793 if (!NILP (Fmemq (intern (feature_id), features[i])))
794 n_match_features--;
795 }
796 /* Now check all the other features. */
797 OTF_INT16_VAL (tbl, langsys_table + 4, &n_features);
798 for (j = 0; j < n_features; j++)
799 {
800 char feature_id[5];
801 OTF_INT16_VAL (tbl, langsys_table + 6 + j * 2, &feature_index);
802 OTF_TAG_VAL (tbl, feature_table + 2 + feature_index * 6, feature_id);
803 /* Assume no duplicates in the font table. This allows us to mark
804 the features off by simply decrementing a counter. */
805 if (!NILP (Fmemq (intern (feature_id), features[i])))
806 n_match_features--;
807 }
808
809 if (n_match_features > 0)
810 goto no_support;
811 }
812
813 retval = 1;
814
815 no_support:
816 font_table_error:
817 /* restore graphics context. */
818 SelectObject (context, old_font);
819 DeleteObject (check_font);
820 release_frame_dc (f, context);
821
822 return retval;
823 }
824
825 static Lisp_Object
826 otf_features (HDC context, char *table)
827 {
828 Lisp_Object script_list = Qnil;
829 unsigned short scriptlist_table, n_scripts, feature_table;
830 DWORD tbl = OTF_TAG (table);
831 int i, j, k;
832
833 /* Look for scripts in the table. */
834 OTF_INT16_VAL (tbl, 4, &scriptlist_table);
835 OTF_INT16_VAL (tbl, 6, &feature_table);
836 OTF_INT16_VAL (tbl, scriptlist_table, &n_scripts);
837
838 for (i = 0; i < n_scripts; i++)
839 {
840 char script[5], lang[5];
841 unsigned short script_table, lang_count, langsys_table, feature_count;
842 Lisp_Object script_tag, langsys_list, langsys_tag, feature_list;
843 unsigned short record_offset = scriptlist_table + 2 + i * 6;
844 OTF_TAG_VAL (tbl, record_offset, script);
845 OTF_INT16_VAL (tbl, record_offset + 4, &script_table);
846
847 /* Offset is from beginning of script table. */
848 script_table += scriptlist_table;
849
850 script_tag = intern (script);
851 langsys_list = Qnil;
852
853 /* Optional default lang. */
854 OTF_INT16_VAL (tbl, script_table, &langsys_table);
855 if (langsys_table)
856 {
857 /* Offset is from beginning of script table. */
858 langsys_table += script_table;
859
860 langsys_tag = Qnil;
861 feature_list = Qnil;
862 OTF_INT16_VAL (tbl, langsys_table + 4, &feature_count);
863 for (k = 0; k < feature_count; k++)
864 {
865 char feature[5];
866 unsigned short index;
867 OTF_INT16_VAL (tbl, langsys_table + 6 + k * 2, &index);
868 OTF_TAG_VAL (tbl, feature_table + 2 + index * 6, feature);
869 feature_list = Fcons (intern (feature), feature_list);
870 }
871 langsys_list = Fcons (Fcons (langsys_tag, feature_list),
872 langsys_list);
873 }
874
875 /* List of supported languages. */
876 OTF_INT16_VAL (tbl, script_table + 2, &lang_count);
877
878 for (j = 0; j < lang_count; j++)
879 {
880 record_offset = script_table + 4 + j * 6;
881 OTF_TAG_VAL (tbl, record_offset, lang);
882 OTF_INT16_VAL (tbl, record_offset + 4, &langsys_table);
883
884 /* Offset is from beginning of script table. */
885 langsys_table += script_table;
886
887 langsys_tag = intern (lang);
888 feature_list = Qnil;
889 OTF_INT16_VAL (tbl, langsys_table + 4, &feature_count);
890 for (k = 0; k < feature_count; k++)
891 {
892 char feature[5];
893 unsigned short index;
894 OTF_INT16_VAL (tbl, langsys_table + 6 + k * 2, &index);
895 OTF_TAG_VAL (tbl, feature_table + 2 + index * 6, feature);
896 feature_list = Fcons (intern (feature), feature_list);
897 }
898 langsys_list = Fcons (Fcons (langsys_tag, feature_list),
899 langsys_list);
900
901 }
902
903 script_list = Fcons (Fcons (script_tag, langsys_list), script_list);
904 }
905
906 return script_list;
907
908 font_table_error:
909 return Qnil;
910 }
911
912 #undef OTF_INT16_VAL
913 #undef OTF_TAG_VAL
914 #undef OTF_TAG
915
916 \f
917 struct font_driver uniscribe_font_driver =
918 {
919 0, /* Quniscribe */
920 0, /* case insensitive */
921 w32font_get_cache,
922 uniscribe_list,
923 uniscribe_match,
924 uniscribe_list_family,
925 NULL, /* free_entity */
926 uniscribe_open,
927 uniscribe_close,
928 NULL, /* prepare_face */
929 NULL, /* done_face */
930 w32font_has_char,
931 uniscribe_encode_char,
932 w32font_text_extents,
933 w32font_draw,
934 NULL, /* get_bitmap */
935 NULL, /* free_bitmap */
936 NULL, /* get_outline */
937 NULL, /* free_outline */
938 NULL, /* anchor_point */
939 uniscribe_otf_capability, /* Defined so (font-get FONTOBJ :otf) works. */
940 NULL, /* otf_drive - use shape instead. */
941 NULL, /* start_for_frame */
942 NULL, /* end_for_frame */
943 uniscribe_shape
944 };
945
946 /* Note that this should be called at every startup, not just when dumping,
947 as it needs to test for the existence of the Uniscribe library. */
948 void
949 syms_of_w32uniscribe (void)
950 {
951 HMODULE uniscribe;
952
953 /* Don't init uniscribe when dumping */
954 if (!initialized)
955 return;
956
957 /* Don't register if uniscribe is not available. */
958 uniscribe = GetModuleHandle ("usp10");
959 if (!uniscribe)
960 return;
961
962 uniscribe_font_driver.type = Quniscribe;
963 uniscribe_available = 1;
964
965 register_font_driver (&uniscribe_font_driver, NULL);
966 }
967