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