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