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