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