(ucs-names): New internal variable.
[bpt/emacs.git] / src / w32uniscribe.c
CommitLineData
e14dc92d
JR
1/* Font backend for the Microsoft W32 Uniscribe API.
2 Copyright (C) 2008 Free Software Foundation, Inc.
3
4This file is part of GNU Emacs.
5
9ec0b715 6GNU Emacs is free software: you can redistribute it and/or modify
e14dc92d 7it under the terms of the GNU General Public License as published by
9ec0b715
GM
8the Free Software Foundation, either version 3 of the License, or
9(at your option) any later version.
e14dc92d
JR
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
9ec0b715 17along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
e14dc92d 18
e14dc92d
JR
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
41struct uniscribe_font_info
42{
43 struct w32font_info w32_font;
44 SCRIPT_CACHE cache;
45};
46
47int uniscribe_available = 0;
48
49/* Defined in w32font.c, since it is required there as well. */
50extern Lisp_Object Quniscribe;
51extern Lisp_Object Qopentype;
52
53extern int initialized;
54
55extern struct font_driver uniscribe_font_driver;
56
57/* EnumFontFamiliesEx callback. */
58static int CALLBACK add_opentype_font_name_to_list P_ ((ENUMLOGFONTEX *,
59 NEWTEXTMETRICEX *,
60 DWORD, LPARAM));
61/* Used by uniscribe_otf_capability. */
62static Lisp_Object otf_features (HDC context, char *table);
63
64static int
65memq_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. */
75static Lisp_Object
76uniscribe_list (frame, font_spec)
77 Lisp_Object frame, font_spec;
78{
07d9ba9b
JR
79 Lisp_Object fonts = w32font_list_internal (frame, font_spec, 1);
80 font_add_log ("uniscribe-list", font_spec, fonts);
81 return fonts;
e14dc92d
JR
82}
83
84static Lisp_Object
85uniscribe_match (frame, font_spec)
86 Lisp_Object frame, font_spec;
87{
07d9ba9b
JR
88 Lisp_Object entity = w32font_match_internal (frame, font_spec, 1);
89 font_add_log ("uniscribe-match", font_spec, entity);
90 return entity;
e14dc92d
JR
91}
92
93static Lisp_Object
94uniscribe_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
fd302b02 116static Lisp_Object
e14dc92d
JR
117uniscribe_open (f, font_entity, pixel_size)
118 FRAME_PTR f;
119 Lisp_Object font_entity;
120 int pixel_size;
121{
fd302b02 122 Lisp_Object font_object
e83ceb8b
KH
123 = font_make_object (VECSIZE (struct uniscribe_font_info),
124 font_entity, pixel_size);
e14dc92d 125 struct uniscribe_font_info *uniscribe_font
fd302b02 126 = (struct uniscribe_font_info *) XFONT_OBJECT (font_object);
e14dc92d 127
4b135503
JR
128 ASET (font_object, FONT_TYPE_INDEX, Quniscribe);
129
fd302b02 130 if (!w32font_open_internal (f, font_entity, pixel_size, font_object))
e14dc92d 131 {
fd302b02 132 return Qnil;
e14dc92d
JR
133 }
134
135 /* Initialize the cache for this font. */
136 uniscribe_font->cache = NULL;
11856d4d 137
e14dc92d 138 /* Mark the format as opentype */
fd302b02 139 uniscribe_font->w32_font.font.props[FONT_FORMAT_INDEX] = Qopentype;
e14dc92d
JR
140 uniscribe_font->w32_font.font.driver = &uniscribe_font_driver;
141
fd302b02 142 return font_object;
e14dc92d
JR
143}
144
145static void
146uniscribe_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)
11856d4d 154 ScriptFreeCache (&(uniscribe_font->cache));
e14dc92d
JR
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. */
161static Lisp_Object
162uniscribe_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);
c35f9821 173 old_font = SelectObject (context, FONT_HANDLE(font));
e14dc92d
JR
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. */
199static Lisp_Object
200uniscribe_shape (lgstring)
201 Lisp_Object lgstring;
202{
203 struct font * font;
204 struct uniscribe_font_info * uniscribe_font;
205 EMACS_UINT nchars;
0ce24b2d 206 int nitems, max_items, i, max_glyphs, done_glyphs;
e14dc92d
JR
207 wchar_t *chars;
208 WORD *glyphs, *clusters;
209 SCRIPT_ITEM *items;
e14dc92d
JR
210 SCRIPT_VISATTR *attributes;
211 int *advances;
212 GOFFSET *offsets;
213 ABC overall_metrics;
e14dc92d
JR
214 HDC context;
215 HFONT old_font;
216 HRESULT result;
217 struct frame * f;
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);
0ce24b2d 224 done_glyphs = 0;
e14dc92d
JR
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;
0ce24b2d 240 items = (SCRIPT_ITEM *) xmalloc (sizeof (SCRIPT_ITEM) * max_items + 1);
e14dc92d 241
11856d4d 242 while ((result = ScriptItemize (chars, nchars, max_items, NULL, NULL,
e14dc92d
JR
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,
0ce24b2d 248 sizeof (SCRIPT_ITEM) * max_items + 1);
e14dc92d
JR
249 }
250
11856d4d 251 if (!SUCCEEDED (result))
e14dc92d
JR
252 {
253 xfree (items);
254 return Qnil;
255 }
256
0ce24b2d
JR
257 /* TODO: When we get BIDI support, we need to call ScriptLayout here.
258 Requires that we know the surrounding context. */
259
e14dc92d
JR
260 f = XFRAME (selected_frame);
261 context = get_frame_dc (f);
c35f9821 262 old_font = SelectObject (context, FONT_HANDLE(font));
e14dc92d
JR
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));
e14dc92d
JR
269
270 for (i = 0; i < nitems; i++)
271 {
0ce24b2d 272 int nglyphs, nchars_in_run, rtl = items[i].a.fRTL ? -1 : 1;
e14dc92d
JR
273 nchars_in_run = items[i+1].iCharPos - items[i].iCharPos;
274
275 result = ScriptShape (context, &(uniscribe_font->cache),
276 chars + items[i].iCharPos, nchars_in_run,
277 max_glyphs - done_glyphs, &(items[i].a),
278 glyphs, clusters, attributes, &nglyphs);
279 if (result == E_OUTOFMEMORY)
280 {
281 /* Need a bigger lgstring. */
282 lgstring = Qnil;
283 break;
284 }
0ce24b2d 285 else if (result) /* Failure. */
e14dc92d
JR
286 {
287 /* Can't shape this run - return results so far if any. */
288 break;
289 }
0ce24b2d
JR
290 else if (items[i].a.fNoGlyphIndex)
291 {
292 /* Glyph indices not supported by this font (or OS), means we
293 can't really do any meaningful shaping. */
294 break;
295 }
e14dc92d
JR
296 else
297 {
298 result = ScriptPlace (context, &(uniscribe_font->cache),
299 glyphs, nglyphs, attributes, &(items[i].a),
300 advances, offsets, &overall_metrics);
11856d4d 301 if (SUCCEEDED (result))
e14dc92d 302 {
b7655e0c
JR
303 int j, nclusters, from, to;
304
305 from = rtl > 0 ? 0 : nchars_in_run - 1;
306 to = from;
e14dc92d
JR
307
308 for (j = 0; j < nglyphs; j++)
309 {
310 int lglyph_index = j + done_glyphs;
311 Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, lglyph_index);
0ce24b2d 312 ABC char_metric;
e14dc92d
JR
313
314 if (NILP (lglyph))
315 {
316 lglyph = Fmake_vector (make_number (LGLYPH_SIZE), Qnil);
317 LGSTRING_SET_GLYPH (lgstring, lglyph_index, lglyph);
318 }
319 LGLYPH_SET_CODE (lglyph, glyphs[j]);
0ce24b2d
JR
320
321 /* Detect clusters, for linking codes back to characters. */
322 if (attributes[j].fClusterStart)
e14dc92d 323 {
b7655e0c
JR
324 while (from >= 0 && from < nchars_in_run
325 && clusters[from] < j)
326 from += rtl;
327 if (from < 0)
328 from = to = 0;
329 else if (from >= nchars_in_run)
330 from = to = nchars_in_run - 1;
0ce24b2d
JR
331 else
332 {
333 int k;
b7655e0c
JR
334 to = rtl > 0 ? nchars_in_run - 1 : 0;
335 for (k = from + rtl; k >= 0 && k < nchars_in_run;
0ce24b2d
JR
336 k += rtl)
337 {
338 if (clusters[k] > j)
339 {
b7655e0c 340 to = k - 1;
0ce24b2d
JR
341 break;
342 }
343 }
344 }
e14dc92d 345 }
e14dc92d 346
b7655e0c
JR
347 LGLYPH_SET_CHAR (lglyph, chars[items[i].iCharPos
348 + from]);
349 LGLYPH_SET_FROM (lglyph, items[i].iCharPos + from);
350 LGLYPH_SET_TO (lglyph, items[i].iCharPos + to);
e14dc92d 351
0ce24b2d
JR
352 /* Metrics. */
353 LGLYPH_SET_WIDTH (lglyph, advances[j]);
354 LGLYPH_SET_ASCENT (lglyph, font->ascent);
355 LGLYPH_SET_DESCENT (lglyph, font->descent);
356
357 result = ScriptGetGlyphABCWidth (context,
358 &(uniscribe_font->cache),
359 glyphs[j], &char_metric);
e14dc92d 360
11856d4d 361 if (SUCCEEDED (result))
0ce24b2d
JR
362 {
363 LGLYPH_SET_LBEARING (lglyph, char_metric.abcA);
364 LGLYPH_SET_RBEARING (lglyph, (char_metric.abcA
365 + char_metric.abcB));
366 }
367 else
e14dc92d 368 {
0ce24b2d
JR
369 LGLYPH_SET_LBEARING (lglyph, 0);
370 LGLYPH_SET_RBEARING (lglyph, advances[j]);
e14dc92d 371 }
0ce24b2d
JR
372
373 if (offsets[j].du || offsets[j].dv)
e14dc92d 374 {
0ce24b2d
JR
375 Lisp_Object vec;
376 vec = Fmake_vector (make_number (3), Qnil);
377 ASET (vec, 0, make_number (offsets[j].du));
378 ASET (vec, 1, make_number (offsets[j].dv));
379 /* Based on what ftfont.c does... */
380 ASET (vec, 2, make_number (advances[j]));
381 LGLYPH_SET_ADJUSTMENT (lglyph, vec);
e14dc92d 382 }
0ce24b2d
JR
383 else
384 LGLYPH_SET_ADJUSTMENT (lglyph, Qnil);
385 } }
e14dc92d
JR
386 }
387 done_glyphs += nglyphs;
e14dc92d
JR
388 }
389
390 xfree (items);
391 SelectObject (context, old_font);
392 release_frame_dc (f, context);
393
394 if (NILP (lgstring))
395 return Qnil;
396 else
0ce24b2d 397 return make_number (done_glyphs);
e14dc92d
JR
398}
399
400/* Uniscribe implementation of encode_char for font backend.
401 Return a glyph code of FONT for characer C (Unicode code point).
402 If FONT doesn't have such a glyph, return FONT_INVALID_CODE. */
403static unsigned
404uniscribe_encode_char (font, c)
405 struct font *font;
406 int c;
407{
e14dc92d
JR
408 HDC context;
409 struct frame *f;
410 HFONT old_font;
11856d4d
JR
411 unsigned code = FONT_INVALID_CODE;
412
413 /* Use selected frame until API is updated to pass the frame. */
414 f = XFRAME (selected_frame);
415 context = get_frame_dc (f);
416 old_font = SelectObject (context, FONT_HANDLE(font));
e14dc92d 417
11856d4d
JR
418 /* There are a number of ways to get glyph indices for BMP characters.
419 The GetGlyphIndices GDI function seems to work best for detecting
420 non-existing glyphs. */
421 if (c < 0x10000)
422 {
423 wchar_t ch = (wchar_t) c;
424 WORD index;
425 DWORD retval = GetGlyphIndicesW (context, &ch, 1, &index,
426 GGI_MARK_NONEXISTING_GLYPHS);
427 if (retval == 1 && index != 0xFFFF)
428 code = index;
429 }
430
431 /* Non BMP characters must be handled by the uniscribe shaping
432 engine as GDI functions (except blindly displaying lines of
433 unicode text) and the promising looking ScriptGetCMap do not
434 convert surrogate pairs to glyph indexes correctly. */
435 else
f31cf550 436 {
11856d4d
JR
437 wchar_t ch[2];
438 SCRIPT_ITEM* items;
439 int nitems;
440 struct uniscribe_font_info *uniscribe_font
441 = (struct uniscribe_font_info *)font;
f31cf550 442 DWORD surrogate = c - 0x10000;
e14dc92d 443
f31cf550 444 /* High surrogate: U+D800 - U+DBFF. */
11856d4d 445 ch[0] = 0xD800 + ((surrogate >> 10) & 0x03FF);
f31cf550 446 /* Low surrogate: U+DC00 - U+DFFF. */
11856d4d
JR
447 ch[1] = 0xDC00 + (surrogate & 0x03FF);
448
449 items = (SCRIPT_ITEM *) alloca (sizeof (SCRIPT_ITEM) * 2 + 1);
450 if (SUCCEEDED (ScriptItemize (ch, 2, 2, NULL, NULL, items, &nitems)))
451 {
452 WORD glyphs[2], clusters[2];
453 SCRIPT_VISATTR attrs[2];
454 int nglyphs;
455
456 if (SUCCEEDED (ScriptShape (context, &(uniscribe_font->cache),
457 ch, 2, 2, &(items[0].a),
458 glyphs, clusters, attrs, &nglyphs))
459 && nglyphs == 1)
460 {
461 code = glyphs[0];
462 }
463 }
f31cf550 464 }
e14dc92d
JR
465
466 SelectObject (context, old_font);
467 release_frame_dc (f, context);
468
11856d4d 469 return code;
e14dc92d
JR
470}
471
472/*
473 Shared with w32font:
474 Lisp_Object uniscribe_get_cache (Lisp_Object frame);
475 void uniscribe_free_entity (Lisp_Object font_entity);
476 int uniscribe_has_char (Lisp_Object entity, int c);
477 int uniscribe_text_extents (struct font *font, unsigned *code,
478 int nglyphs, struct font_metrics *metrics);
479 int uniscribe_draw (struct glyph_string *s, int from, int to,
480 int x, int y, int with_background);
481
482 Unused:
483 int uniscribe_prepare_face (FRAME_PTR f, struct face *face);
484 void uniscribe_done_face (FRAME_PTR f, struct face *face);
485 int uniscribe_get_bitmap (struct font *font, unsigned code,
486 struct font_bitmap *bitmap, int bits_per_pixel);
487 void uniscribe_free_bitmap (struct font *font, struct font_bitmap *bitmap);
488 void * uniscribe_get_outline (struct font *font, unsigned code);
489 void uniscribe_free_outline (struct font *font, void *outline);
490 int uniscribe_anchor_point (struct font *font, unsigned code,
491 int index, int *x, int *y);
492 int uniscribe_start_for_frame (FRAME_PTR f);
493 int uniscribe_end_for_frame (FRAME_PTR f);
494
495*/
496
497\f
498/* Callback function for EnumFontFamiliesEx.
499 Adds the name of opentype fonts to a Lisp list (passed in as the
500 lParam arg). */
501static int CALLBACK
502add_opentype_font_name_to_list (logical_font, physical_font, font_type,
503 list_object)
504 ENUMLOGFONTEX *logical_font;
505 NEWTEXTMETRICEX *physical_font;
506 DWORD font_type;
507 LPARAM list_object;
508{
509 Lisp_Object* list = (Lisp_Object *) list_object;
510 Lisp_Object family;
511
512 /* Skip vertical fonts (intended only for printing) */
513 if (logical_font->elfLogFont.lfFaceName[0] == '@')
514 return 1;
515
516 /* Skip non opentype fonts. Count old truetype fonts as opentype,
517 as some of them do contain GPOS and GSUB data that Uniscribe
518 can make use of. */
519 if (!(physical_font->ntmTm.ntmFlags & NTMFLAGS_OPENTYPE)
520 && font_type != TRUETYPE_FONTTYPE)
521 return 1;
522
351ccb76
JR
523 /* Skip fonts that have no unicode coverage. */
524 if (!physical_font->ntmFontSig.fsUsb[3]
525 && !physical_font->ntmFontSig.fsUsb[2]
526 && !physical_font->ntmFontSig.fsUsb[1]
527 && !(physical_font->ntmFontSig.fsUsb[0] & 0x3fffffff))
528 return 1;
529
fd302b02 530 family = font_intern_prop (logical_font->elfLogFont.lfFaceName,
9ede7109 531 strlen (logical_font->elfLogFont.lfFaceName), 1);
e14dc92d
JR
532 if (! memq_no_quit (family, *list))
533 *list = Fcons (family, *list);
534
535 return 1;
536}
537
538\f
539/* :otf property handling.
540 Since the necessary Uniscribe APIs for getting font tag information
541 are only available in Vista, we need to parse the font data directly
542 according to the OpenType Specification. */
543
544/* Push into DWORD backwards to cope with endianness. */
545#define OTF_TAG(STR) \
546 ((STR[3] << 24) | (STR[2] << 16) | (STR[1] << 8) | STR[0])
547
548#define OTF_INT16_VAL(TABLE, OFFSET, PTR) \
549 do { \
550 BYTE temp, data[2]; \
551 if (GetFontData (context, TABLE, OFFSET, data, 2) != 2) \
552 goto font_table_error; \
553 temp = data[0], data[0] = data[1], data[1] = temp; \
554 memcpy (PTR, data, 2); \
555 } while (0)
556
557/* Do not reverse the bytes, because we will compare with a OTF_TAG value
558 that has them reversed already. */
559#define OTF_DWORDTAG_VAL(TABLE, OFFSET, PTR) \
560 do { \
561 if (GetFontData (context, TABLE, OFFSET, PTR, 4) != 4) \
562 goto font_table_error; \
563 } while (0)
564
565#define OTF_TAG_VAL(TABLE, OFFSET, STR) \
566 do { \
567 if (GetFontData (context, TABLE, OFFSET, STR, 4) != 4) \
568 goto font_table_error; \
569 STR[4] = '\0'; \
570 } while (0)
571
572static char* NOTHING = " ";
573
3bf8d230 574#define SNAME(VAL) SDATA (SYMBOL_NAME (VAL))
e14dc92d
JR
575
576/* Check if font supports the otf script/language/features specified.
577 OTF_SPEC is in the format
578 (script lang [(gsub_feature ...)|nil] [(gpos_feature ...)]?) */
579int uniscribe_check_otf (font, otf_spec)
580 LOGFONT *font;
581 Lisp_Object otf_spec;
582{
583 Lisp_Object script, lang, rest;
584 Lisp_Object features[2];
585 DWORD feature_tables[2];
586 DWORD script_tag, default_script, lang_tag = 0;
587 struct frame * f;
588 HDC context;
589 HFONT check_font, old_font;
590 DWORD table;
591 int i, retval = 0;
e38ac6e2 592 struct gcpro gcpro1;
e14dc92d 593
6b8aa22a 594 /* Check the spec is in the right format. */
3187540e 595 if (!CONSP (otf_spec) || Flength (otf_spec) < 3)
6b8aa22a
JR
596 return 0;
597
e14dc92d
JR
598 /* Break otf_spec into its components. */
599 script = XCAR (otf_spec);
600 rest = XCDR (otf_spec);
601
602 lang = XCAR (rest);
603 rest = XCDR (rest);
604
605 features[0] = XCAR (rest);
606 rest = XCDR (rest);
607 if (NILP (rest))
608 features[1] = Qnil;
609 else
610 features[1] = XCAR (rest);
611
612 /* Set up tags we will use in the search. */
613 feature_tables[0] = OTF_TAG ("GSUB");
614 feature_tables[1] = OTF_TAG ("GPOS");
615 default_script = OTF_TAG ("DFLT");
616 if (NILP (script))
617 script_tag = default_script;
618 else
619 script_tag = OTF_TAG (SNAME (script));
620 if (!NILP (lang))
621 lang_tag = OTF_TAG (SNAME (lang));
622
623 /* Set up graphics context so we can use the font. */
624 f = XFRAME (selected_frame);
625 context = get_frame_dc (f);
626 check_font = CreateFontIndirect (font);
627 old_font = SelectObject (context, check_font);
628
e38ac6e2
JR
629 /* Everything else is contained within otf_spec so should get
630 marked along with it. */
631 GCPRO1 (otf_spec);
632
e14dc92d
JR
633 /* Scan GSUB and GPOS tables. */
634 for (i = 0; i < 2; i++)
635 {
636 int j, n_match_features;
637 unsigned short scriptlist_table, feature_table, n_scripts;
638 unsigned short script_table, langsys_table, n_langs;
639 unsigned short feature_index, n_features;
640 DWORD tbl = feature_tables[i];
e14dc92d
JR
641
642 /* Skip if no features requested from this table. */
643 if (NILP (features[i]))
644 continue;
645
6b8aa22a
JR
646 /* If features is not a cons, this font spec is messed up. */
647 if (!CONSP (features[i]))
648 goto no_support;
649
e14dc92d
JR
650 /* Read GPOS/GSUB header. */
651 OTF_INT16_VAL (tbl, 4, &scriptlist_table);
652 OTF_INT16_VAL (tbl, 6, &feature_table);
653 OTF_INT16_VAL (tbl, scriptlist_table, &n_scripts);
654
655 /* Find the appropriate script table. */
656 script_table = 0;
657 for (j = 0; j < n_scripts; j++)
658 {
659 DWORD script_id;
660 OTF_DWORDTAG_VAL (tbl, scriptlist_table + 2 + j * 6, &script_id);
661 if (script_id == script_tag)
662 {
663 OTF_INT16_VAL (tbl, scriptlist_table + 6 + j * 6, &script_table);
664 break;
665 }
666 /* If there is a DFLT script defined in the font, use it
667 if the specified script is not found. */
668 else if (script_id == default_script)
669 OTF_INT16_VAL (tbl, scriptlist_table + 6 + j * 6, &script_table);
670 }
671 /* If no specific or default script table was found, then this font
672 does not support the script. */
673 if (!script_table)
674 goto no_support;
675
676 /* Offset is from beginning of scriptlist_table. */
677 script_table += scriptlist_table;
678
679 /* Get default langsys table. */
680 OTF_INT16_VAL (tbl, script_table, &langsys_table);
681
682 /* If lang was specified, see if font contains a specific entry. */
683 if (!NILP (lang))
684 {
685 OTF_INT16_VAL (tbl, script_table + 2, &n_langs);
686
687 for (j = 0; j < n_langs; j++)
688 {
689 DWORD lang_id;
690 OTF_DWORDTAG_VAL (tbl, script_table + 4 + j * 6, &lang_id);
691 if (lang_id == lang_tag)
692 {
693 OTF_INT16_VAL (tbl, script_table + 8 + j * 6, &langsys_table);
694 break;
695 }
696 }
697 }
698
699 if (!langsys_table)
700 goto no_support;
701
702 /* Offset is from beginning of script table. */
703 langsys_table += script_table;
704
705 /* Check the features. Features may contain nil according to
706 documentation in font_prop_validate_otf, so count them. */
707 n_match_features = 0;
d0bfec76 708 for (rest = features[i]; CONSP (rest); rest = XCDR (rest))
e14dc92d 709 {
d0bfec76 710 Lisp_Object feature = XCAR (rest);
e14dc92d
JR
711 if (!NILP (feature))
712 n_match_features++;
713 }
714
715 /* If there are no features to check, skip checking. */
716 if (!n_match_features)
717 continue;
718
719 /* First check required feature (if any). */
720 OTF_INT16_VAL (tbl, langsys_table + 2, &feature_index);
721 if (feature_index != 0xFFFF)
722 {
723 char feature_id[5];
724 OTF_TAG_VAL (tbl, feature_table + 2 + feature_index * 6, feature_id);
725 OTF_TAG_VAL (tbl, feature_table + 2 + feature_index * 6, feature_id);
726 /* Assume no duplicates in the font table. This allows us to mark
727 the features off by simply decrementing a counter. */
728 if (!NILP (Fmemq (intern (feature_id), features[i])))
729 n_match_features--;
730 }
731 /* Now check all the other features. */
732 OTF_INT16_VAL (tbl, langsys_table + 4, &n_features);
733 for (j = 0; j < n_features; j++)
734 {
735 char feature_id[5];
736 OTF_INT16_VAL (tbl, langsys_table + 6 + j * 2, &feature_index);
737 OTF_TAG_VAL (tbl, feature_table + 2 + feature_index * 6, feature_id);
738 /* Assume no duplicates in the font table. This allows us to mark
739 the features off by simply decrementing a counter. */
740 if (!NILP (Fmemq (intern (feature_id), features[i])))
741 n_match_features--;
742 }
743
744 if (n_match_features > 0)
745 goto no_support;
746 }
747
748 retval = 1;
749
750 no_support:
751 font_table_error:
752 /* restore graphics context. */
753 SelectObject (context, old_font);
754 DeleteObject (check_font);
755 release_frame_dc (f, context);
756
757 return retval;
758}
759
760static Lisp_Object
761otf_features (HDC context, char *table)
762{
763 Lisp_Object script_list = Qnil;
764 unsigned short scriptlist_table, n_scripts, feature_table;
765 DWORD tbl = OTF_TAG (table);
766 int i, j, k;
767
768 /* Look for scripts in the table. */
769 OTF_INT16_VAL (tbl, 4, &scriptlist_table);
770 OTF_INT16_VAL (tbl, 6, &feature_table);
771 OTF_INT16_VAL (tbl, scriptlist_table, &n_scripts);
772
773 for (i = 0; i < n_scripts; i++)
774 {
775 char script[5], lang[5];
776 unsigned short script_table, lang_count, langsys_table, feature_count;
777 Lisp_Object script_tag, langsys_list, langsys_tag, feature_list;
778 unsigned short record_offset = scriptlist_table + 2 + i * 6;
779 OTF_TAG_VAL (tbl, record_offset, script);
780 OTF_INT16_VAL (tbl, record_offset + 4, &script_table);
781
782 /* Offset is from beginning of script table. */
783 script_table += scriptlist_table;
784
785 script_tag = intern (script);
786 langsys_list = Qnil;
787
788 /* Optional default lang. */
789 OTF_INT16_VAL (tbl, script_table, &langsys_table);
790 if (langsys_table)
791 {
792 /* Offset is from beginning of script table. */
793 langsys_table += script_table;
794
795 langsys_tag = Qnil;
796 feature_list = Qnil;
797 OTF_INT16_VAL (tbl, langsys_table + 4, &feature_count);
798 for (k = 0; k < feature_count; k++)
799 {
800 char feature[5];
801 unsigned short index;
802 OTF_INT16_VAL (tbl, langsys_table + 6 + k * 2, &index);
803 OTF_TAG_VAL (tbl, feature_table + 2 + index * 6, feature);
804 feature_list = Fcons (intern (feature), feature_list);
805 }
806 langsys_list = Fcons (Fcons (langsys_tag, feature_list),
807 langsys_list);
808 }
809
810 /* List of supported languages. */
811 OTF_INT16_VAL (tbl, script_table + 2, &lang_count);
812
813 for (j = 0; j < lang_count; j++)
814 {
815 record_offset = script_table + 4 + j * 6;
816 OTF_TAG_VAL (tbl, record_offset, lang);
817 OTF_INT16_VAL (tbl, record_offset + 4, &langsys_table);
818
819 /* Offset is from beginning of script table. */
820 langsys_table += script_table;
821
822 langsys_tag = intern (lang);
823 feature_list = Qnil;
824 OTF_INT16_VAL (tbl, langsys_table + 4, &feature_count);
825 for (k = 0; k < feature_count; k++)
826 {
827 char feature[5];
828 unsigned short index;
829 OTF_INT16_VAL (tbl, langsys_table + 6 + k * 2, &index);
830 OTF_TAG_VAL (tbl, feature_table + 2 + index * 6, feature);
831 feature_list = Fcons (intern (feature), feature_list);
832 }
833 langsys_list = Fcons (Fcons (langsys_tag, feature_list),
834 langsys_list);
835
836 }
837
838 script_list = Fcons (Fcons (script_tag, langsys_list), script_list);
839 }
840
841 return script_list;
842
843font_table_error:
844 return Qnil;
845}
846
847#undef OTF_INT16_VAL
848#undef OTF_TAG_VAL
849#undef OTF_TAG
850
851\f
852struct font_driver uniscribe_font_driver =
853 {
854 0, /* Quniscribe */
fd302b02 855 0, /* case insensitive */
e14dc92d
JR
856 w32font_get_cache,
857 uniscribe_list,
858 uniscribe_match,
859 uniscribe_list_family,
860 NULL, /* free_entity */
861 uniscribe_open,
862 uniscribe_close,
863 NULL, /* prepare_face */
864 NULL, /* done_face */
865 w32font_has_char,
866 uniscribe_encode_char,
867 w32font_text_extents,
868 w32font_draw,
869 NULL, /* get_bitmap */
870 NULL, /* free_bitmap */
871 NULL, /* get_outline */
872 NULL, /* free_outline */
873 NULL, /* anchor_point */
874 uniscribe_otf_capability, /* Defined so (font-get FONTOBJ :otf) works. */
875 NULL, /* otf_drive - use shape instead. */
876 NULL, /* start_for_frame */
877 NULL, /* end_for_frame */
878 uniscribe_shape
879 };
880
881/* Note that this should be called at every startup, not just when dumping,
882 as it needs to test for the existence of the Uniscribe library. */
883void
884syms_of_w32uniscribe ()
885{
886 HMODULE uniscribe;
887
888 /* Don't init uniscribe when dumping */
889 if (!initialized)
890 return;
891
892 /* Don't register if uniscribe is not available. */
893 uniscribe = GetModuleHandle ("usp10");
894 if (!uniscribe)
895 return;
896
897 uniscribe_font_driver.type = Quniscribe;
898 uniscribe_available = 1;
899
900 register_font_driver (&uniscribe_font_driver, NULL);
901}
902
80d0c8d9
MB
903/* arch-tag: 9530f0e1-7471-47dd-a780-94330af87ea0
904 (do not change this comment) */