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