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