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