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