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