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