1 /* Font backend for the Microsoft W32 Uniscribe API.
2 Copyright (C) 2008 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
6 GNU Emacs is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 Boston, MA 02110-1301, USA. */
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. */
29 #define _WIN32_WINNT 0x500
36 #include "dispextern.h"
37 #include "character.h"
43 struct uniscribe_font_info
45 struct w32font_info w32_font
;
49 int uniscribe_available
= 0;
51 /* Defined in w32font.c, since it is required there as well. */
52 extern Lisp_Object Quniscribe
;
53 extern Lisp_Object Qopentype
;
55 extern int initialized
;
57 extern struct font_driver uniscribe_font_driver
;
59 /* EnumFontFamiliesEx callback. */
60 static int CALLBACK add_opentype_font_name_to_list
P_ ((ENUMLOGFONTEX
*,
63 /* Used by uniscribe_otf_capability. */
64 static Lisp_Object
otf_features (HDC context
, char *table
);
67 memq_no_quit (elt
, list
)
68 Lisp_Object elt
, list
;
70 while (CONSP (list
) && ! EQ (XCAR (list
), elt
))
72 return (CONSP (list
));
76 /* Font backend interface implementation. */
78 uniscribe_list (frame
, font_spec
)
79 Lisp_Object frame
, font_spec
;
81 return w32font_list_internal (frame
, font_spec
, 1);
85 uniscribe_match (frame
, font_spec
)
86 Lisp_Object frame
, font_spec
;
88 return w32font_match_internal (frame
, font_spec
, 1);
92 uniscribe_list_family (frame
)
95 Lisp_Object list
= Qnil
;
96 LOGFONT font_match_pattern
;
98 FRAME_PTR f
= XFRAME (frame
);
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
;
104 dc
= get_frame_dc (f
);
106 EnumFontFamiliesEx (dc
, &font_match_pattern
,
107 (FONTENUMPROC
) add_opentype_font_name_to_list
,
109 release_frame_dc (f
, dc
);
115 uniscribe_open (f
, font_entity
, pixel_size
)
117 Lisp_Object font_entity
;
120 Lisp_Object font_object
121 = font_make_object (VECSIZE (struct uniscribe_font_info
));
122 struct uniscribe_font_info
*uniscribe_font
123 = (struct uniscribe_font_info
*) XFONT_OBJECT (font_object
);
125 if (!w32font_open_internal (f
, font_entity
, pixel_size
, font_object
))
130 /* Initialize the cache for this font. */
131 uniscribe_font
->cache
= NULL
;
132 /* Mark the format as opentype */
133 uniscribe_font
->w32_font
.font
.props
[FONT_FORMAT_INDEX
] = Qopentype
;
134 uniscribe_font
->w32_font
.font
.driver
= &uniscribe_font_driver
;
140 uniscribe_close (f
, font
)
144 struct uniscribe_font_info
*uniscribe_font
145 = (struct uniscribe_font_info
*) font
;
147 if (uniscribe_font
->cache
)
148 ScriptFreeCache (&uniscribe_font
->cache
);
150 w32font_close (f
, font
);
153 /* Return a list describing which scripts/languages FONT supports by
154 which GSUB/GPOS features of OpenType tables. */
156 uniscribe_otf_capability (font
)
162 Lisp_Object capability
= Fcons (Qnil
, Qnil
);
163 Lisp_Object features
;
165 f
= XFRAME (selected_frame
);
166 context
= get_frame_dc (f
);
167 old_font
= SelectObject (context
, FONT_COMPAT (font
)->hfont
);
169 features
= otf_features (context
, "GSUB");
170 XSETCAR (capability
, features
);
171 features
= otf_features (context
, "GPOS");
172 XSETCDR (capability
, features
);
174 SelectObject (context
, old_font
);
175 release_frame_dc (f
, context
);
180 /* Uniscribe implementation of shape for font backend.
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.
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. */
194 uniscribe_shape (lgstring
)
195 Lisp_Object lgstring
;
198 struct uniscribe_font_info
* uniscribe_font
;
200 int nitems
, max_items
, i
, max_glyphs
, done_glyphs
;
202 WORD
*glyphs
, *clusters
;
204 SCRIPT_CONTROL control
;
205 SCRIPT_VISATTR
*attributes
;
215 CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring
), font
);
216 uniscribe_font
= (struct uniscribe_font_info
*) font
;
218 /* Get the chars from lgstring in a form we can use with uniscribe. */
219 max_glyphs
= nchars
= LGSTRING_LENGTH (lgstring
);
221 chars
= (wchar_t *) alloca (nchars
* sizeof (wchar_t));
222 for (i
= 0; i
< nchars
; i
++)
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
)))
230 chars
[i
] = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring
, i
));
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. */
236 items
= (SCRIPT_ITEM
*) xmalloc (sizeof (SCRIPT_ITEM
) * max_items
+ 1);
237 bzero (&control
, sizeof (control
));
239 while ((result
= ScriptItemize (chars
, nchars
, max_items
, &control
, NULL
,
240 items
, &nitems
)) == E_OUTOFMEMORY
)
242 /* If that wasn't enough, keep trying with one more run. */
244 items
= (SCRIPT_ITEM
*) xrealloc (items
,
245 sizeof (SCRIPT_ITEM
) * max_items
+ 1);
248 /* 0 = success in Microsoft's backwards world. */
255 /* TODO: When we get BIDI support, we need to call ScriptLayout here.
256 Requires that we know the surrounding context. */
258 f
= XFRAME (selected_frame
);
259 context
= get_frame_dc (f
);
260 old_font
= SelectObject (context
, FONT_COMPAT (font
)->hfont
);
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;
271 for (i
= 0; i
< nitems
; i
++)
273 int nglyphs
, nchars_in_run
, rtl
= items
[i
].a
.fRTL
? -1 : 1;
274 nchars_in_run
= items
[i
+1].iCharPos
- items
[i
].iCharPos
;
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
)
282 /* Need a bigger lgstring. */
286 else if (result
) /* Failure. */
288 /* Can't shape this run - return results so far if any. */
291 else if (items
[i
].a
.fNoGlyphIndex
)
293 /* Glyph indices not supported by this font (or OS), means we
294 can't really do any meaningful shaping. */
299 result
= ScriptPlace (context
, &(uniscribe_font
->cache
),
300 glyphs
, nglyphs
, attributes
, &(items
[i
].a
),
301 advances
, offsets
, &overall_metrics
);
302 if (result
== 0) /* Success. */
304 int j
, nclusters
, from
, to
;
306 from
= rtl
> 0 ? 0 : nchars_in_run
- 1;
309 for (j
= 0; j
< nglyphs
; j
++)
311 int lglyph_index
= j
+ done_glyphs
;
312 Lisp_Object lglyph
= LGSTRING_GLYPH (lgstring
, lglyph_index
);
317 lglyph
= Fmake_vector (make_number (LGLYPH_SIZE
), Qnil
);
318 LGSTRING_SET_GLYPH (lgstring
, lglyph_index
, lglyph
);
320 LGLYPH_SET_CODE (lglyph
, glyphs
[j
]);
322 /* Detect clusters, for linking codes back to characters. */
323 if (attributes
[j
].fClusterStart
)
325 while (from
>= 0 && from
< nchars_in_run
326 && clusters
[from
] < j
)
330 else if (from
>= nchars_in_run
)
331 from
= to
= nchars_in_run
- 1;
335 to
= rtl
> 0 ? nchars_in_run
- 1 : 0;
336 for (k
= from
+ rtl
; k
>= 0 && k
< nchars_in_run
;
348 LGLYPH_SET_CHAR (lglyph
, chars
[items
[i
].iCharPos
350 LGLYPH_SET_FROM (lglyph
, items
[i
].iCharPos
+ from
);
351 LGLYPH_SET_TO (lglyph
, items
[i
].iCharPos
+ to
);
354 LGLYPH_SET_WIDTH (lglyph
, advances
[j
]);
355 LGLYPH_SET_ASCENT (lglyph
, font
->ascent
);
356 LGLYPH_SET_DESCENT (lglyph
, font
->descent
);
358 result
= ScriptGetGlyphABCWidth (context
,
359 &(uniscribe_font
->cache
),
360 glyphs
[j
], &char_metric
);
362 if (result
== 0) /* Success. */
364 LGLYPH_SET_LBEARING (lglyph
, char_metric
.abcA
);
365 LGLYPH_SET_RBEARING (lglyph
, (char_metric
.abcA
366 + char_metric
.abcB
));
370 LGLYPH_SET_LBEARING (lglyph
, 0);
371 LGLYPH_SET_RBEARING (lglyph
, advances
[j
]);
374 if (offsets
[j
].du
|| offsets
[j
].dv
)
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
);
385 LGLYPH_SET_ADJUSTMENT (lglyph
, Qnil
);
388 done_glyphs
+= nglyphs
;
392 SelectObject (context
, old_font
);
393 release_frame_dc (f
, context
);
398 return make_number (done_glyphs
);
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. */
405 uniscribe_encode_char (font
, c
)
416 /* TODO: surrogates. */
418 return FONT_INVALID_CODE
;
420 chars
[0] = (wchar_t) c
;
422 /* Use selected frame until API is updated to pass the frame. */
423 f
= XFRAME (selected_frame
);
424 context
= get_frame_dc (f
);
425 old_font
= SelectObject (context
, FONT_COMPAT (font
)->hfont
);
427 retval
= GetGlyphIndicesW (context
, chars
, 1, indices
,
428 GGI_MARK_NONEXISTING_GLYPHS
);
430 SelectObject (context
, old_font
);
431 release_frame_dc (f
, context
);
434 return indices
[0] == 0xFFFF ? FONT_INVALID_CODE
: indices
[0];
436 return FONT_INVALID_CODE
;
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);
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);
465 /* Callback function for EnumFontFamiliesEx.
466 Adds the name of opentype fonts to a Lisp list (passed in as the
469 add_opentype_font_name_to_list (logical_font
, physical_font
, font_type
,
471 ENUMLOGFONTEX
*logical_font
;
472 NEWTEXTMETRICEX
*physical_font
;
476 Lisp_Object
* list
= (Lisp_Object
*) list_object
;
479 /* Skip vertical fonts (intended only for printing) */
480 if (logical_font
->elfLogFont
.lfFaceName
[0] == '@')
483 /* Skip non opentype fonts. Count old truetype fonts as opentype,
484 as some of them do contain GPOS and GSUB data that Uniscribe
486 if (!(physical_font
->ntmTm
.ntmFlags
& NTMFLAGS_OPENTYPE
)
487 && font_type
!= TRUETYPE_FONTTYPE
)
490 family
= font_intern_prop (logical_font
->elfLogFont
.lfFaceName
,
491 strlen (logical_font
->elfLogFont
.lfFaceName
));
492 if (! memq_no_quit (family
, *list
))
493 *list
= Fcons (family
, *list
);
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. */
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])
508 #define OTF_INT16_VAL(TABLE, OFFSET, PTR) \
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); \
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) \
521 if (GetFontData (context, TABLE, OFFSET, PTR, 4) != 4) \
522 goto font_table_error; \
525 #define OTF_TAG_VAL(TABLE, OFFSET, STR) \
527 if (GetFontData (context, TABLE, OFFSET, STR, 4) != 4) \
528 goto font_table_error; \
532 static char* NOTHING
= " ";
534 #define SNAME(VAL) SDATA (SYMBOL_NAME (VAL))
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 ...)]?) */
539 int uniscribe_check_otf (font
, otf_spec
)
541 Lisp_Object otf_spec
;
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;
549 HFONT check_font
, old_font
;
554 /* Check the spec is in the right format. */
555 if (!CONSP (otf_spec
) || Flength (otf_spec
) < 3)
558 /* Break otf_spec into its components. */
559 script
= XCAR (otf_spec
);
560 rest
= XCDR (otf_spec
);
565 features
[0] = XCAR (rest
);
570 features
[1] = XCAR (rest
);
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");
577 script_tag
= default_script
;
579 script_tag
= OTF_TAG (SNAME (script
));
581 lang_tag
= OTF_TAG (SNAME (lang
));
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
);
589 /* Everything else is contained within otf_spec so should get
590 marked along with it. */
593 /* Scan GSUB and GPOS tables. */
594 for (i
= 0; i
< 2; i
++)
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
];
602 /* Skip if no features requested from this table. */
603 if (NILP (features
[i
]))
606 /* If features is not a cons, this font spec is messed up. */
607 if (!CONSP (features
[i
]))
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
);
615 /* Find the appropriate script table. */
617 for (j
= 0; j
< n_scripts
; j
++)
620 OTF_DWORDTAG_VAL (tbl
, scriptlist_table
+ 2 + j
* 6, &script_id
);
621 if (script_id
== script_tag
)
623 OTF_INT16_VAL (tbl
, scriptlist_table
+ 6 + j
* 6, &script_table
);
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
);
631 /* If no specific or default script table was found, then this font
632 does not support the script. */
636 /* Offset is from beginning of scriptlist_table. */
637 script_table
+= scriptlist_table
;
639 /* Get default langsys table. */
640 OTF_INT16_VAL (tbl
, script_table
, &langsys_table
);
642 /* If lang was specified, see if font contains a specific entry. */
645 OTF_INT16_VAL (tbl
, script_table
+ 2, &n_langs
);
647 for (j
= 0; j
< n_langs
; j
++)
650 OTF_DWORDTAG_VAL (tbl
, script_table
+ 4 + j
* 6, &lang_id
);
651 if (lang_id
== lang_tag
)
653 OTF_INT16_VAL (tbl
, script_table
+ 8 + j
* 6, &langsys_table
);
662 /* Offset is from beginning of script table. */
663 langsys_table
+= script_table
;
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;
668 for (rest
= features
[i
]; CONSP (rest
); rest
= XCDR (rest
))
670 Lisp_Object feature
= XCAR (rest
);
675 /* If there are no features to check, skip checking. */
676 if (!n_match_features
)
679 /* First check required feature (if any). */
680 OTF_INT16_VAL (tbl
, langsys_table
+ 2, &feature_index
);
681 if (feature_index
!= 0xFFFF)
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
])))
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
++)
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
])))
704 if (n_match_features
> 0)
712 /* restore graphics context. */
713 SelectObject (context
, old_font
);
714 DeleteObject (check_font
);
715 release_frame_dc (f
, context
);
721 otf_features (HDC context
, char *table
)
723 Lisp_Object script_list
= Qnil
;
724 unsigned short scriptlist_table
, n_scripts
, feature_table
;
725 DWORD tbl
= OTF_TAG (table
);
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
);
733 for (i
= 0; i
< n_scripts
; i
++)
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
);
742 /* Offset is from beginning of script table. */
743 script_table
+= scriptlist_table
;
745 script_tag
= intern (script
);
748 /* Optional default lang. */
749 OTF_INT16_VAL (tbl
, script_table
, &langsys_table
);
752 /* Offset is from beginning of script table. */
753 langsys_table
+= script_table
;
757 OTF_INT16_VAL (tbl
, langsys_table
+ 4, &feature_count
);
758 for (k
= 0; k
< feature_count
; k
++)
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
);
766 langsys_list
= Fcons (Fcons (langsys_tag
, feature_list
),
770 /* List of supported languages. */
771 OTF_INT16_VAL (tbl
, script_table
+ 2, &lang_count
);
773 for (j
= 0; j
< lang_count
; j
++)
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
);
779 /* Offset is from beginning of script table. */
780 langsys_table
+= script_table
;
782 langsys_tag
= intern (lang
);
784 OTF_INT16_VAL (tbl
, langsys_table
+ 4, &feature_count
);
785 for (k
= 0; k
< feature_count
; k
++)
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
);
793 langsys_list
= Fcons (Fcons (langsys_tag
, feature_list
),
798 script_list
= Fcons (Fcons (script_tag
, langsys_list
), script_list
);
812 struct font_driver uniscribe_font_driver
=
815 0, /* case insensitive */
819 uniscribe_list_family
,
820 NULL
, /* free_entity */
823 NULL
, /* prepare_face */
824 NULL
, /* done_face */
826 uniscribe_encode_char
,
827 w32font_text_extents
,
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 */
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. */
844 syms_of_w32uniscribe ()
848 /* Don't init uniscribe when dumping */
852 /* Don't register if uniscribe is not available. */
853 uniscribe
= GetModuleHandle ("usp10");
857 uniscribe_font_driver
.type
= Quniscribe
;
858 uniscribe_available
= 1;
860 register_font_driver (&uniscribe_font_driver
, NULL
);
863 /* arch-tag: 9530f0e1-7471-47dd-a780-94330af87ea0
864 (do not change this comment) */