]> code.delx.au - gnu-emacs/blob - src/w32uniscribe.c
($(BLD)/w32uniscribe.$(O)): Depend on composite.h
[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 "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
343 if (NILP (lglyph))
344 {
345 lglyph = Fmake_vector (make_number (LGLYPH_SIZE), Qnil);
346 LGSTRING_SET_GLYPH (lgstring, lglyph_index, lglyph);
347 }
348 LGLYPH_SET_CODE (lglyph, glyphs[j]);
349
350 /* Detect clusters, for linking codes back to characters. */
351 if (attributes[j].fClusterStart)
352 {
353 while (from >= 0 && from < nchars_in_run
354 && clusters[from] < j)
355 from += rtl;
356 if (from < 0)
357 from = to = 0;
358 else if (from >= nchars_in_run)
359 from = to = nchars_in_run - 1;
360 else
361 {
362 int k;
363 to = rtl > 0 ? nchars_in_run - 1 : 0;
364 for (k = from + rtl; k >= 0 && k < nchars_in_run;
365 k += rtl)
366 {
367 if (clusters[k] > j)
368 {
369 to = k - 1;
370 break;
371 }
372 }
373 }
374 }
375
376 LGLYPH_SET_CHAR (lglyph, chars[items[i].iCharPos
377 + from]);
378 LGLYPH_SET_FROM (lglyph, items[i].iCharPos + from);
379 LGLYPH_SET_TO (lglyph, items[i].iCharPos + to);
380
381 /* Metrics. */
382 LGLYPH_SET_WIDTH (lglyph, advances[j]);
383 LGLYPH_SET_ASCENT (lglyph, font->ascent);
384 LGLYPH_SET_DESCENT (lglyph, font->descent);
385
386 result = ScriptGetGlyphABCWidth (context,
387 &(uniscribe_font->cache),
388 glyphs[j], &char_metric);
389 if (result == E_PENDING && !context)
390 {
391 /* Cache incomplete... */
392 f = XFRAME (selected_frame);
393 context = get_frame_dc (f);
394 old_font = SelectObject (context, FONT_HANDLE(font));
395 result = ScriptGetGlyphABCWidth (context,
396 &(uniscribe_font->cache),
397 glyphs[j], &char_metric);
398 }
399
400 if (SUCCEEDED (result))
401 {
402 LGLYPH_SET_LBEARING (lglyph, char_metric.abcA);
403 LGLYPH_SET_RBEARING (lglyph, (char_metric.abcA
404 + char_metric.abcB));
405 }
406 else
407 {
408 LGLYPH_SET_LBEARING (lglyph, 0);
409 LGLYPH_SET_RBEARING (lglyph, advances[j]);
410 }
411
412 if (offsets[j].du || offsets[j].dv)
413 {
414 Lisp_Object vec;
415 vec = Fmake_vector (make_number (3), Qnil);
416 ASET (vec, 0, make_number (offsets[j].du));
417 ASET (vec, 1, make_number (offsets[j].dv));
418 /* Based on what ftfont.c does... */
419 ASET (vec, 2, make_number (advances[j]));
420 LGLYPH_SET_ADJUSTMENT (lglyph, vec);
421 }
422 else
423 LGLYPH_SET_ADJUSTMENT (lglyph, Qnil);
424 }
425 }
426 }
427 done_glyphs += nglyphs;
428 }
429
430 xfree (items);
431
432 if (context)
433 {
434 SelectObject (context, old_font);
435 release_frame_dc (f, context);
436 }
437
438 if (NILP (lgstring))
439 return Qnil;
440 else
441 return make_number (done_glyphs);
442 }
443
444 /* Uniscribe implementation of encode_char for font backend.
445 Return a glyph code of FONT for characer C (Unicode code point).
446 If FONT doesn't have such a glyph, return FONT_INVALID_CODE. */
447 static unsigned
448 uniscribe_encode_char (font, c)
449 struct font *font;
450 int c;
451 {
452 HDC context = NULL;
453 struct frame *f = NULL;
454 HFONT old_font = NULL;
455 unsigned code = FONT_INVALID_CODE;
456 wchar_t ch[2];
457 int len;
458 SCRIPT_ITEM* items;
459 int nitems;
460 struct uniscribe_font_info *uniscribe_font
461 = (struct uniscribe_font_info *)font;
462
463 if (c < 0x10000)
464 {
465 ch[0] = (wchar_t) c;
466 len = 1;
467 }
468 else
469 {
470 DWORD surrogate = c - 0x10000;
471
472 /* High surrogate: U+D800 - U+DBFF. */
473 ch[0] = 0xD800 + ((surrogate >> 10) & 0x03FF);
474 /* Low surrogate: U+DC00 - U+DFFF. */
475 ch[1] = 0xDC00 + (surrogate & 0x03FF);
476 len = 2;
477 }
478
479 /* Non BMP characters must be handled by the uniscribe shaping
480 engine as GDI functions (except blindly displaying lines of
481 unicode text) and the promising looking ScriptGetCMap do not
482 convert surrogate pairs to glyph indexes correctly. */
483 {
484 items = (SCRIPT_ITEM *) alloca (sizeof (SCRIPT_ITEM) * 2 + 1);
485 if (SUCCEEDED (ScriptItemize (ch, len, 2, NULL, NULL, items, &nitems)))
486 {
487 HRESULT result;
488 /* Some Indic characters result in more than 1 glyph. */
489 WORD glyphs[1], clusters[1];
490 SCRIPT_VISATTR attrs[1];
491 int nglyphs;
492
493 result = ScriptShape (context, &(uniscribe_font->cache),
494 ch, len, 1, &(items[0].a),
495 glyphs, clusters, attrs, &nglyphs);
496
497 if (result == E_PENDING)
498 {
499 /* Use selected frame until API is updated to pass
500 the frame. */
501 f = XFRAME (selected_frame);
502 context = get_frame_dc (f);
503 old_font = SelectObject (context, FONT_HANDLE(font));
504 result = ScriptShape (context, &(uniscribe_font->cache),
505 ch, len, 2, &(items[0].a),
506 glyphs, clusters, attrs, &nglyphs);
507 }
508
509 if (SUCCEEDED (result) && nglyphs == 1)
510 {
511 code = glyphs[0];
512 }
513 else if (SUCCEEDED (result) || result == E_OUTOFMEMORY)
514 {
515 /* This character produces zero or more than one glyph
516 when shaped. But we still need the return from here
517 to be valid for the shaping engine to be invoked
518 later. */
519 result = ScriptGetCMap (context, &(uniscribe_font->cache),
520 ch, len, 0, glyphs);
521 if (SUCCEEDED (result))
522 return glyphs[0];
523 else
524 return 0; /* notdef - enough in some cases to get the script
525 engine working, but not others... */
526 }
527 }
528 }
529 if (context)
530 {
531 SelectObject (context, old_font);
532 release_frame_dc (f, context);
533 }
534
535 return code;
536 }
537
538 /*
539 Shared with w32font:
540 Lisp_Object uniscribe_get_cache (Lisp_Object frame);
541 void uniscribe_free_entity (Lisp_Object font_entity);
542 int uniscribe_has_char (Lisp_Object entity, int c);
543 int uniscribe_text_extents (struct font *font, unsigned *code,
544 int nglyphs, struct font_metrics *metrics);
545 int uniscribe_draw (struct glyph_string *s, int from, int to,
546 int x, int y, int with_background);
547
548 Unused:
549 int uniscribe_prepare_face (FRAME_PTR f, struct face *face);
550 void uniscribe_done_face (FRAME_PTR f, struct face *face);
551 int uniscribe_get_bitmap (struct font *font, unsigned code,
552 struct font_bitmap *bitmap, int bits_per_pixel);
553 void uniscribe_free_bitmap (struct font *font, struct font_bitmap *bitmap);
554 void * uniscribe_get_outline (struct font *font, unsigned code);
555 void uniscribe_free_outline (struct font *font, void *outline);
556 int uniscribe_anchor_point (struct font *font, unsigned code,
557 int index, int *x, int *y);
558 int uniscribe_start_for_frame (FRAME_PTR f);
559 int uniscribe_end_for_frame (FRAME_PTR f);
560
561 */
562
563 \f
564 /* Callback function for EnumFontFamiliesEx.
565 Adds the name of opentype fonts to a Lisp list (passed in as the
566 lParam arg). */
567 static int CALLBACK
568 add_opentype_font_name_to_list (logical_font, physical_font, font_type,
569 list_object)
570 ENUMLOGFONTEX *logical_font;
571 NEWTEXTMETRICEX *physical_font;
572 DWORD font_type;
573 LPARAM list_object;
574 {
575 Lisp_Object* list = (Lisp_Object *) list_object;
576 Lisp_Object family;
577
578 /* Skip vertical fonts (intended only for printing) */
579 if (logical_font->elfLogFont.lfFaceName[0] == '@')
580 return 1;
581
582 /* Skip non opentype fonts. Count old truetype fonts as opentype,
583 as some of them do contain GPOS and GSUB data that Uniscribe
584 can make use of. */
585 if (!(physical_font->ntmTm.ntmFlags & NTMFLAGS_OPENTYPE)
586 && font_type != TRUETYPE_FONTTYPE)
587 return 1;
588
589 /* Skip fonts that have no unicode coverage. */
590 if (!physical_font->ntmFontSig.fsUsb[3]
591 && !physical_font->ntmFontSig.fsUsb[2]
592 && !physical_font->ntmFontSig.fsUsb[1]
593 && !(physical_font->ntmFontSig.fsUsb[0] & 0x3fffffff))
594 return 1;
595
596 family = font_intern_prop (logical_font->elfLogFont.lfFaceName,
597 strlen (logical_font->elfLogFont.lfFaceName), 1);
598 if (! memq_no_quit (family, *list))
599 *list = Fcons (family, *list);
600
601 return 1;
602 }
603
604 \f
605 /* :otf property handling.
606 Since the necessary Uniscribe APIs for getting font tag information
607 are only available in Vista, we need to parse the font data directly
608 according to the OpenType Specification. */
609
610 /* Push into DWORD backwards to cope with endianness. */
611 #define OTF_TAG(STR) \
612 ((STR[3] << 24) | (STR[2] << 16) | (STR[1] << 8) | STR[0])
613
614 #define OTF_INT16_VAL(TABLE, OFFSET, PTR) \
615 do { \
616 BYTE temp, data[2]; \
617 if (GetFontData (context, TABLE, OFFSET, data, 2) != 2) \
618 goto font_table_error; \
619 temp = data[0], data[0] = data[1], data[1] = temp; \
620 memcpy (PTR, data, 2); \
621 } while (0)
622
623 /* Do not reverse the bytes, because we will compare with a OTF_TAG value
624 that has them reversed already. */
625 #define OTF_DWORDTAG_VAL(TABLE, OFFSET, PTR) \
626 do { \
627 if (GetFontData (context, TABLE, OFFSET, PTR, 4) != 4) \
628 goto font_table_error; \
629 } while (0)
630
631 #define OTF_TAG_VAL(TABLE, OFFSET, STR) \
632 do { \
633 if (GetFontData (context, TABLE, OFFSET, STR, 4) != 4) \
634 goto font_table_error; \
635 STR[4] = '\0'; \
636 } while (0)
637
638 static char* NOTHING = " ";
639
640 #define SNAME(VAL) SDATA (SYMBOL_NAME (VAL))
641
642 /* Check if font supports the otf script/language/features specified.
643 OTF_SPEC is in the format
644 (script lang [(gsub_feature ...)|nil] [(gpos_feature ...)]?) */
645 int uniscribe_check_otf (font, otf_spec)
646 LOGFONT *font;
647 Lisp_Object otf_spec;
648 {
649 Lisp_Object script, lang, rest;
650 Lisp_Object features[2];
651 DWORD feature_tables[2];
652 DWORD script_tag, default_script, lang_tag = 0;
653 struct frame * f;
654 HDC context;
655 HFONT check_font, old_font;
656 DWORD table;
657 int i, retval = 0;
658 struct gcpro gcpro1;
659
660 /* Check the spec is in the right format. */
661 if (!CONSP (otf_spec) || Flength (otf_spec) < 3)
662 return 0;
663
664 /* Break otf_spec into its components. */
665 script = XCAR (otf_spec);
666 rest = XCDR (otf_spec);
667
668 lang = XCAR (rest);
669 rest = XCDR (rest);
670
671 features[0] = XCAR (rest);
672 rest = XCDR (rest);
673 if (NILP (rest))
674 features[1] = Qnil;
675 else
676 features[1] = XCAR (rest);
677
678 /* Set up tags we will use in the search. */
679 feature_tables[0] = OTF_TAG ("GSUB");
680 feature_tables[1] = OTF_TAG ("GPOS");
681 default_script = OTF_TAG ("DFLT");
682 if (NILP (script))
683 script_tag = default_script;
684 else
685 script_tag = OTF_TAG (SNAME (script));
686 if (!NILP (lang))
687 lang_tag = OTF_TAG (SNAME (lang));
688
689 /* Set up graphics context so we can use the font. */
690 f = XFRAME (selected_frame);
691 context = get_frame_dc (f);
692 check_font = CreateFontIndirect (font);
693 old_font = SelectObject (context, check_font);
694
695 /* Everything else is contained within otf_spec so should get
696 marked along with it. */
697 GCPRO1 (otf_spec);
698
699 /* Scan GSUB and GPOS tables. */
700 for (i = 0; i < 2; i++)
701 {
702 int j, n_match_features;
703 unsigned short scriptlist_table, feature_table, n_scripts;
704 unsigned short script_table, langsys_table, n_langs;
705 unsigned short feature_index, n_features;
706 DWORD tbl = feature_tables[i];
707
708 /* Skip if no features requested from this table. */
709 if (NILP (features[i]))
710 continue;
711
712 /* If features is not a cons, this font spec is messed up. */
713 if (!CONSP (features[i]))
714 goto no_support;
715
716 /* Read GPOS/GSUB header. */
717 OTF_INT16_VAL (tbl, 4, &scriptlist_table);
718 OTF_INT16_VAL (tbl, 6, &feature_table);
719 OTF_INT16_VAL (tbl, scriptlist_table, &n_scripts);
720
721 /* Find the appropriate script table. */
722 script_table = 0;
723 for (j = 0; j < n_scripts; j++)
724 {
725 DWORD script_id;
726 OTF_DWORDTAG_VAL (tbl, scriptlist_table + 2 + j * 6, &script_id);
727 if (script_id == script_tag)
728 {
729 OTF_INT16_VAL (tbl, scriptlist_table + 6 + j * 6, &script_table);
730 break;
731 }
732 /* If there is a DFLT script defined in the font, use it
733 if the specified script is not found. */
734 else if (script_id == default_script)
735 OTF_INT16_VAL (tbl, scriptlist_table + 6 + j * 6, &script_table);
736 }
737 /* If no specific or default script table was found, then this font
738 does not support the script. */
739 if (!script_table)
740 goto no_support;
741
742 /* Offset is from beginning of scriptlist_table. */
743 script_table += scriptlist_table;
744
745 /* Get default langsys table. */
746 OTF_INT16_VAL (tbl, script_table, &langsys_table);
747
748 /* If lang was specified, see if font contains a specific entry. */
749 if (!NILP (lang))
750 {
751 OTF_INT16_VAL (tbl, script_table + 2, &n_langs);
752
753 for (j = 0; j < n_langs; j++)
754 {
755 DWORD lang_id;
756 OTF_DWORDTAG_VAL (tbl, script_table + 4 + j * 6, &lang_id);
757 if (lang_id == lang_tag)
758 {
759 OTF_INT16_VAL (tbl, script_table + 8 + j * 6, &langsys_table);
760 break;
761 }
762 }
763 }
764
765 if (!langsys_table)
766 goto no_support;
767
768 /* Offset is from beginning of script table. */
769 langsys_table += script_table;
770
771 /* Check the features. Features may contain nil according to
772 documentation in font_prop_validate_otf, so count them. */
773 n_match_features = 0;
774 for (rest = features[i]; CONSP (rest); rest = XCDR (rest))
775 {
776 Lisp_Object feature = XCAR (rest);
777 if (!NILP (feature))
778 n_match_features++;
779 }
780
781 /* If there are no features to check, skip checking. */
782 if (!n_match_features)
783 continue;
784
785 /* First check required feature (if any). */
786 OTF_INT16_VAL (tbl, langsys_table + 2, &feature_index);
787 if (feature_index != 0xFFFF)
788 {
789 char feature_id[5];
790 OTF_TAG_VAL (tbl, feature_table + 2 + feature_index * 6, feature_id);
791 OTF_TAG_VAL (tbl, feature_table + 2 + feature_index * 6, feature_id);
792 /* Assume no duplicates in the font table. This allows us to mark
793 the features off by simply decrementing a counter. */
794 if (!NILP (Fmemq (intern (feature_id), features[i])))
795 n_match_features--;
796 }
797 /* Now check all the other features. */
798 OTF_INT16_VAL (tbl, langsys_table + 4, &n_features);
799 for (j = 0; j < n_features; j++)
800 {
801 char feature_id[5];
802 OTF_INT16_VAL (tbl, langsys_table + 6 + j * 2, &feature_index);
803 OTF_TAG_VAL (tbl, feature_table + 2 + feature_index * 6, feature_id);
804 /* Assume no duplicates in the font table. This allows us to mark
805 the features off by simply decrementing a counter. */
806 if (!NILP (Fmemq (intern (feature_id), features[i])))
807 n_match_features--;
808 }
809
810 if (n_match_features > 0)
811 goto no_support;
812 }
813
814 retval = 1;
815
816 no_support:
817 font_table_error:
818 /* restore graphics context. */
819 SelectObject (context, old_font);
820 DeleteObject (check_font);
821 release_frame_dc (f, context);
822
823 return retval;
824 }
825
826 static Lisp_Object
827 otf_features (HDC context, char *table)
828 {
829 Lisp_Object script_list = Qnil;
830 unsigned short scriptlist_table, n_scripts, feature_table;
831 DWORD tbl = OTF_TAG (table);
832 int i, j, k;
833
834 /* Look for scripts in the table. */
835 OTF_INT16_VAL (tbl, 4, &scriptlist_table);
836 OTF_INT16_VAL (tbl, 6, &feature_table);
837 OTF_INT16_VAL (tbl, scriptlist_table, &n_scripts);
838
839 for (i = 0; i < n_scripts; i++)
840 {
841 char script[5], lang[5];
842 unsigned short script_table, lang_count, langsys_table, feature_count;
843 Lisp_Object script_tag, langsys_list, langsys_tag, feature_list;
844 unsigned short record_offset = scriptlist_table + 2 + i * 6;
845 OTF_TAG_VAL (tbl, record_offset, script);
846 OTF_INT16_VAL (tbl, record_offset + 4, &script_table);
847
848 /* Offset is from beginning of script table. */
849 script_table += scriptlist_table;
850
851 script_tag = intern (script);
852 langsys_list = Qnil;
853
854 /* Optional default lang. */
855 OTF_INT16_VAL (tbl, script_table, &langsys_table);
856 if (langsys_table)
857 {
858 /* Offset is from beginning of script table. */
859 langsys_table += script_table;
860
861 langsys_tag = Qnil;
862 feature_list = Qnil;
863 OTF_INT16_VAL (tbl, langsys_table + 4, &feature_count);
864 for (k = 0; k < feature_count; k++)
865 {
866 char feature[5];
867 unsigned short index;
868 OTF_INT16_VAL (tbl, langsys_table + 6 + k * 2, &index);
869 OTF_TAG_VAL (tbl, feature_table + 2 + index * 6, feature);
870 feature_list = Fcons (intern (feature), feature_list);
871 }
872 langsys_list = Fcons (Fcons (langsys_tag, feature_list),
873 langsys_list);
874 }
875
876 /* List of supported languages. */
877 OTF_INT16_VAL (tbl, script_table + 2, &lang_count);
878
879 for (j = 0; j < lang_count; j++)
880 {
881 record_offset = script_table + 4 + j * 6;
882 OTF_TAG_VAL (tbl, record_offset, lang);
883 OTF_INT16_VAL (tbl, record_offset + 4, &langsys_table);
884
885 /* Offset is from beginning of script table. */
886 langsys_table += script_table;
887
888 langsys_tag = intern (lang);
889 feature_list = Qnil;
890 OTF_INT16_VAL (tbl, langsys_table + 4, &feature_count);
891 for (k = 0; k < feature_count; k++)
892 {
893 char feature[5];
894 unsigned short index;
895 OTF_INT16_VAL (tbl, langsys_table + 6 + k * 2, &index);
896 OTF_TAG_VAL (tbl, feature_table + 2 + index * 6, feature);
897 feature_list = Fcons (intern (feature), feature_list);
898 }
899 langsys_list = Fcons (Fcons (langsys_tag, feature_list),
900 langsys_list);
901
902 }
903
904 script_list = Fcons (Fcons (script_tag, langsys_list), script_list);
905 }
906
907 return script_list;
908
909 font_table_error:
910 return Qnil;
911 }
912
913 #undef OTF_INT16_VAL
914 #undef OTF_TAG_VAL
915 #undef OTF_TAG
916
917 \f
918 struct font_driver uniscribe_font_driver =
919 {
920 0, /* Quniscribe */
921 0, /* case insensitive */
922 w32font_get_cache,
923 uniscribe_list,
924 uniscribe_match,
925 uniscribe_list_family,
926 NULL, /* free_entity */
927 uniscribe_open,
928 uniscribe_close,
929 NULL, /* prepare_face */
930 NULL, /* done_face */
931 w32font_has_char,
932 uniscribe_encode_char,
933 w32font_text_extents,
934 w32font_draw,
935 NULL, /* get_bitmap */
936 NULL, /* free_bitmap */
937 NULL, /* get_outline */
938 NULL, /* free_outline */
939 NULL, /* anchor_point */
940 uniscribe_otf_capability, /* Defined so (font-get FONTOBJ :otf) works. */
941 NULL, /* otf_drive - use shape instead. */
942 NULL, /* start_for_frame */
943 NULL, /* end_for_frame */
944 uniscribe_shape
945 };
946
947 /* Note that this should be called at every startup, not just when dumping,
948 as it needs to test for the existence of the Uniscribe library. */
949 void
950 syms_of_w32uniscribe ()
951 {
952 HMODULE uniscribe;
953
954 /* Don't init uniscribe when dumping */
955 if (!initialized)
956 return;
957
958 /* Don't register if uniscribe is not available. */
959 uniscribe = GetModuleHandle ("usp10");
960 if (!uniscribe)
961 return;
962
963 uniscribe_font_driver.type = Quniscribe;
964 uniscribe_available = 1;
965
966 register_font_driver (&uniscribe_font_driver, NULL);
967 }
968
969 /* arch-tag: 9530f0e1-7471-47dd-a780-94330af87ea0
970 (do not change this comment) */