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