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