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. */
21 #ifdef USE_FONT_BACKEND
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. */
30 #define _WIN32_WINNT 0x500
37 #include "dispextern.h"
38 #include "character.h"
44 struct uniscribe_font_info
46 struct w32font_info w32_font
;
50 int uniscribe_available
= 0;
52 /* Defined in w32font.c, since it is required there as well. */
53 extern Lisp_Object Quniscribe
;
54 extern Lisp_Object Qopentype
;
56 extern int initialized
;
58 extern struct font_driver uniscribe_font_driver
;
60 /* EnumFontFamiliesEx callback. */
61 static int CALLBACK add_opentype_font_name_to_list
P_ ((ENUMLOGFONTEX
*,
64 /* Used by uniscribe_otf_capability. */
65 static Lisp_Object
otf_features (HDC context
, char *table
);
68 memq_no_quit (elt
, list
)
69 Lisp_Object elt
, list
;
71 while (CONSP (list
) && ! EQ (XCAR (list
), elt
))
73 return (CONSP (list
));
77 /* Font backend interface implementation. */
79 uniscribe_list (frame
, font_spec
)
80 Lisp_Object frame
, font_spec
;
82 return w32font_list_internal (frame
, font_spec
, 1);
86 uniscribe_match (frame
, font_spec
)
87 Lisp_Object frame
, font_spec
;
89 return w32font_match_internal (frame
, font_spec
, 1);
93 uniscribe_list_family (frame
)
96 Lisp_Object list
= Qnil
;
97 LOGFONT font_match_pattern
;
99 FRAME_PTR f
= XFRAME (frame
);
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
;
105 dc
= get_frame_dc (f
);
107 EnumFontFamiliesEx (dc
, &font_match_pattern
,
108 (FONTENUMPROC
) add_opentype_font_name_to_list
,
110 release_frame_dc (f
, dc
);
116 uniscribe_open (f
, font_entity
, pixel_size
)
118 Lisp_Object font_entity
;
121 struct uniscribe_font_info
*uniscribe_font
122 = xmalloc (sizeof (struct uniscribe_font_info
));
124 if (uniscribe_font
== NULL
)
127 if (!w32font_open_internal (f
, font_entity
, pixel_size
,
128 (struct w32font_info
*) uniscribe_font
))
130 xfree (uniscribe_font
);
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
;
140 return (struct font
*) uniscribe_font
;
144 uniscribe_close (f
, font
)
148 struct uniscribe_font_info
*uniscribe_font
149 = (struct uniscribe_font_info
*) font
;
151 if (uniscribe_font
->cache
)
152 ScriptFreeCache (&uniscribe_font
->cache
);
154 w32font_close (f
, font
);
157 /* Return a list describing which scripts/languages FONT supports by
158 which GSUB/GPOS features of OpenType tables. */
160 uniscribe_otf_capability (font
)
166 Lisp_Object capability
= Fcons (Qnil
, Qnil
);
167 Lisp_Object features
;
169 f
= XFRAME (selected_frame
);
170 context
= get_frame_dc (f
);
171 old_font
= SelectObject (context
,
172 ((W32FontStruct
*) (font
->font
.font
))->hfont
);
174 features
= otf_features (context
, "GSUB");
175 XSETCAR (capability
, features
);
176 features
= otf_features (context
, "GPOS");
177 XSETCDR (capability
, features
);
179 SelectObject (context
, old_font
);
180 release_frame_dc (f
, context
);
185 /* Uniscribe implementation of shape for font backend.
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.
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. */
199 uniscribe_shape (lgstring
)
200 Lisp_Object lgstring
;
203 struct uniscribe_font_info
* uniscribe_font
;
205 int nitems
, max_items
, i
, max_glyphs
, done_glyphs
, done_chars
;
207 WORD
*glyphs
, *clusters
;
209 SCRIPT_CONTROL control
;
210 SCRIPT_VISATTR
*attributes
;
220 CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring
), font
);
221 uniscribe_font
= (struct uniscribe_font_info
*) font
;
223 /* Get the chars from lgstring in a form we can use with uniscribe. */
224 max_glyphs
= nchars
= LGSTRING_LENGTH (lgstring
);
225 done_glyphs
= done_chars
= 0;
226 chars
= (wchar_t *) alloca (nchars
* sizeof (wchar_t));
227 for (i
= 0; i
< nchars
; i
++)
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
)))
235 chars
[i
] = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring
, i
));
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. */
241 items
= (SCRIPT_ITEM
*) xmalloc (sizeof (SCRIPT_ITEM
) * max_items
);
242 bzero (&control
, sizeof (control
));
244 while ((result
= ScriptItemize (chars
, nchars
, max_items
, &control
, NULL
,
245 items
, &nitems
)) == E_OUTOFMEMORY
)
247 /* If that wasn't enough, keep trying with one more run. */
249 items
= (SCRIPT_ITEM
*) xrealloc (items
,
250 sizeof (SCRIPT_ITEM
) * max_items
);
253 /* 0 = success in Microsoft's backwards world. */
260 f
= XFRAME (selected_frame
);
261 context
= get_frame_dc (f
);
262 old_font
= SelectObject (context
,
263 ((W32FontStruct
*) (font
->font
.font
))->hfont
);
265 glyphs
= alloca (max_glyphs
* sizeof (WORD
));
266 clusters
= alloca (nchars
* sizeof (WORD
));
267 attributes
= alloca (max_glyphs
* sizeof (SCRIPT_VISATTR
));
268 advances
= alloca (max_glyphs
* sizeof (int));
269 offsets
= alloca (max_glyphs
* sizeof (GOFFSET
));
270 bzero (&transform
, sizeof (transform
));
271 transform
.eM11
.value
= 1;
272 transform
.eM22
.value
= 1;
274 for (i
= 0; i
< nitems
; i
++)
276 int nglyphs
, nchars_in_run
;
277 nchars_in_run
= items
[i
+1].iCharPos
- items
[i
].iCharPos
;
279 result
= ScriptShape (context
, &(uniscribe_font
->cache
),
280 chars
+ items
[i
].iCharPos
, nchars_in_run
,
281 max_glyphs
- done_glyphs
, &(items
[i
].a
),
282 glyphs
, clusters
, attributes
, &nglyphs
);
283 if (result
== E_OUTOFMEMORY
)
285 /* Need a bigger lgstring. */
291 /* Can't shape this run - return results so far if any. */
296 result
= ScriptPlace (context
, &(uniscribe_font
->cache
),
297 glyphs
, nglyphs
, attributes
, &(items
[i
].a
),
298 advances
, offsets
, &overall_metrics
);
303 for (j
= 0; j
< nglyphs
; j
++)
305 int lglyph_index
= j
+ done_glyphs
;
306 Lisp_Object lglyph
= LGSTRING_GLYPH (lgstring
, lglyph_index
);
307 GLYPHMETRICS metrics
;
311 lglyph
= Fmake_vector (make_number (LGLYPH_SIZE
), Qnil
);
312 LGSTRING_SET_GLYPH (lgstring
, lglyph_index
, lglyph
);
314 LGLYPH_SET_CODE (lglyph
, glyphs
[j
]);
315 LGLYPH_SET_WIDTH (lglyph
, advances
[j
]);
316 if (offsets
[j
].du
|| offsets
[j
].dv
)
319 /* Convert from logical inches. */
320 int dpi
= FRAME_W32_DISPLAY_INFO (f
)->resy
;
321 int dx
= (int)(offsets
[j
].du
* dpi
/ 72.27 + 0.5);
322 int dy
= (int)(offsets
[j
].dv
* dpi
/ 72.27 + 0.5);
323 vec
= Fmake_vector (make_number (3), Qnil
);
324 ASET (vec
, 0, make_number (dx
));
325 ASET (vec
, 1, make_number (dy
));
326 /* Based on what ftfont.c does... */
327 ASET (vec
, 2, make_number (advances
[j
]));
328 LGLYPH_SET_ADJUSTMENT (lglyph
, vec
);
331 LGLYPH_SET_ADJUSTMENT (lglyph
, Qnil
);
333 if (GetGlyphOutlineW (context
, glyphs
[j
],
334 GGO_METRICS
| GGO_GLYPH_INDEX
,
335 &metrics
, 0, NULL
, &transform
)
338 LGLYPH_SET_LBEARING (lglyph
, metrics
.gmptGlyphOrigin
.x
);
339 LGLYPH_SET_RBEARING (lglyph
,
341 + metrics
.gmptGlyphOrigin
.x
);
342 LGLYPH_SET_ASCENT (lglyph
, metrics
.gmBlackBoxY
);
343 LGLYPH_SET_DESCENT (lglyph
,
345 - metrics
.gmptGlyphOrigin
.y
346 - metrics
.gmBlackBoxY
));
350 /* Defaults based on what we know from elsewhere. */
351 LGLYPH_SET_LBEARING (lglyph
, 0);
352 LGLYPH_SET_RBEARING (lglyph
, advances
[j
]);
353 LGLYPH_SET_ASCENT (lglyph
, font
->ascent
);
354 LGLYPH_SET_DESCENT (lglyph
, font
->descent
);
358 /* Set character codes as indicated in clusters. */
359 for (j
= 0; j
< nchars_in_run
- 1; j
++)
362 wchar_t this_char
= *(chars
+ items
[i
].iCharPos
+ j
);
372 for (k
= start
; k
< end
; k
++)
374 Lisp_Object lglyph
= LGSTRING_GLYPH (lgstring
,
376 LGLYPH_SET_CHAR (lglyph
, this_char
);
379 /* Last one until end (or beginning) of string. */
382 wchar_t last_char
= *(chars
+ items
[i
].iCharPos
383 + nchars_in_run
- 1);
384 start
= clusters
[nchars_in_run
- 1];
386 if (start
< clusters
[nchars_in_run
- 2])
391 for (k
= start
; k
< end
; k
++)
393 Lisp_Object lglyph
= LGSTRING_GLYPH (lgstring
,
395 LGLYPH_SET_CHAR (lglyph
, last_char
);
400 done_glyphs
+= nglyphs
;
401 done_chars
+= nchars_in_run
;
405 SelectObject (context
, old_font
);
406 release_frame_dc (f
, context
);
411 return make_number (done_chars
);
414 /* Uniscribe implementation of encode_char for font backend.
415 Return a glyph code of FONT for characer C (Unicode code point).
416 If FONT doesn't have such a glyph, return FONT_INVALID_CODE. */
418 uniscribe_encode_char (font
, c
)
429 /* TODO: surrogates. */
431 return FONT_INVALID_CODE
;
433 chars
[0] = (wchar_t) c
;
435 /* Use selected frame until API is updated to pass the frame. */
436 f
= XFRAME (selected_frame
);
437 context
= get_frame_dc (f
);
438 old_font
= SelectObject (context
,
439 ((W32FontStruct
*)(font
->font
.font
))->hfont
);
441 retval
= GetGlyphIndicesW (context
, chars
, 1, indices
,
442 GGI_MARK_NONEXISTING_GLYPHS
);
444 SelectObject (context
, old_font
);
445 release_frame_dc (f
, context
);
448 return indices
[0] == 0xFFFF ? FONT_INVALID_CODE
: indices
[0];
450 return FONT_INVALID_CODE
;
455 Lisp_Object uniscribe_get_cache (Lisp_Object frame);
456 void uniscribe_free_entity (Lisp_Object font_entity);
457 int uniscribe_has_char (Lisp_Object entity, int c);
458 int uniscribe_text_extents (struct font *font, unsigned *code,
459 int nglyphs, struct font_metrics *metrics);
460 int uniscribe_draw (struct glyph_string *s, int from, int to,
461 int x, int y, int with_background);
464 int uniscribe_prepare_face (FRAME_PTR f, struct face *face);
465 void uniscribe_done_face (FRAME_PTR f, struct face *face);
466 int uniscribe_get_bitmap (struct font *font, unsigned code,
467 struct font_bitmap *bitmap, int bits_per_pixel);
468 void uniscribe_free_bitmap (struct font *font, struct font_bitmap *bitmap);
469 void * uniscribe_get_outline (struct font *font, unsigned code);
470 void uniscribe_free_outline (struct font *font, void *outline);
471 int uniscribe_anchor_point (struct font *font, unsigned code,
472 int index, int *x, int *y);
473 int uniscribe_start_for_frame (FRAME_PTR f);
474 int uniscribe_end_for_frame (FRAME_PTR f);
479 /* Callback function for EnumFontFamiliesEx.
480 Adds the name of opentype fonts to a Lisp list (passed in as the
483 add_opentype_font_name_to_list (logical_font
, physical_font
, font_type
,
485 ENUMLOGFONTEX
*logical_font
;
486 NEWTEXTMETRICEX
*physical_font
;
490 Lisp_Object
* list
= (Lisp_Object
*) list_object
;
493 /* Skip vertical fonts (intended only for printing) */
494 if (logical_font
->elfLogFont
.lfFaceName
[0] == '@')
497 /* Skip non opentype fonts. Count old truetype fonts as opentype,
498 as some of them do contain GPOS and GSUB data that Uniscribe
500 if (!(physical_font
->ntmTm
.ntmFlags
& NTMFLAGS_OPENTYPE
)
501 && font_type
!= TRUETYPE_FONTTYPE
)
504 family
= intern_downcase (logical_font
->elfLogFont
.lfFaceName
,
505 strlen (logical_font
->elfLogFont
.lfFaceName
));
506 if (! memq_no_quit (family
, *list
))
507 *list
= Fcons (family
, *list
);
513 /* :otf property handling.
514 Since the necessary Uniscribe APIs for getting font tag information
515 are only available in Vista, we need to parse the font data directly
516 according to the OpenType Specification. */
518 /* Push into DWORD backwards to cope with endianness. */
519 #define OTF_TAG(STR) \
520 ((STR[3] << 24) | (STR[2] << 16) | (STR[1] << 8) | STR[0])
522 #define OTF_INT16_VAL(TABLE, OFFSET, PTR) \
524 BYTE temp, data[2]; \
525 if (GetFontData (context, TABLE, OFFSET, data, 2) != 2) \
526 goto font_table_error; \
527 temp = data[0], data[0] = data[1], data[1] = temp; \
528 memcpy (PTR, data, 2); \
531 /* Do not reverse the bytes, because we will compare with a OTF_TAG value
532 that has them reversed already. */
533 #define OTF_DWORDTAG_VAL(TABLE, OFFSET, PTR) \
535 if (GetFontData (context, TABLE, OFFSET, PTR, 4) != 4) \
536 goto font_table_error; \
539 #define OTF_TAG_VAL(TABLE, OFFSET, STR) \
541 if (GetFontData (context, TABLE, OFFSET, STR, 4) != 4) \
542 goto font_table_error; \
546 static char* NOTHING
= " ";
548 #define SNAME(VAL) SDATA (STRINGP (VAL) ? VAL : SYMBOL_NAME (VAL))
550 /* Check if font supports the otf script/language/features specified.
551 OTF_SPEC is in the format
552 (script lang [(gsub_feature ...)|nil] [(gpos_feature ...)]?) */
553 int uniscribe_check_otf (font
, otf_spec
)
555 Lisp_Object otf_spec
;
557 Lisp_Object script
, lang
, rest
;
558 Lisp_Object features
[2];
559 DWORD feature_tables
[2];
560 DWORD script_tag
, default_script
, lang_tag
= 0;
563 HFONT check_font
, old_font
;
567 /* Check the spec is in the right format. */
568 if (!CONSP (otf_spec
) || Flength (val
) < 3)
571 /* Break otf_spec into its components. */
572 script
= XCAR (otf_spec
);
573 rest
= XCDR (otf_spec
);
578 features
[0] = XCAR (rest
);
583 features
[1] = XCAR (rest
);
585 /* Set up tags we will use in the search. */
586 feature_tables
[0] = OTF_TAG ("GSUB");
587 feature_tables
[1] = OTF_TAG ("GPOS");
588 default_script
= OTF_TAG ("DFLT");
590 script_tag
= default_script
;
592 script_tag
= OTF_TAG (SNAME (script
));
594 lang_tag
= OTF_TAG (SNAME (lang
));
596 /* Set up graphics context so we can use the font. */
597 f
= XFRAME (selected_frame
);
598 context
= get_frame_dc (f
);
599 check_font
= CreateFontIndirect (font
);
600 old_font
= SelectObject (context
, check_font
);
602 /* Scan GSUB and GPOS tables. */
603 for (i
= 0; i
< 2; i
++)
605 int j
, n_match_features
;
606 unsigned short scriptlist_table
, feature_table
, n_scripts
;
607 unsigned short script_table
, langsys_table
, n_langs
;
608 unsigned short feature_index
, n_features
;
609 DWORD tbl
= feature_tables
[i
];
612 /* Skip if no features requested from this table. */
613 if (NILP (features
[i
]))
616 /* If features is not a cons, this font spec is messed up. */
617 if (!CONSP (features
[i
]))
620 /* Read GPOS/GSUB header. */
621 OTF_INT16_VAL (tbl
, 4, &scriptlist_table
);
622 OTF_INT16_VAL (tbl
, 6, &feature_table
);
623 OTF_INT16_VAL (tbl
, scriptlist_table
, &n_scripts
);
625 /* Find the appropriate script table. */
627 for (j
= 0; j
< n_scripts
; j
++)
630 OTF_DWORDTAG_VAL (tbl
, scriptlist_table
+ 2 + j
* 6, &script_id
);
631 if (script_id
== script_tag
)
633 OTF_INT16_VAL (tbl
, scriptlist_table
+ 6 + j
* 6, &script_table
);
636 /* If there is a DFLT script defined in the font, use it
637 if the specified script is not found. */
638 else if (script_id
== default_script
)
639 OTF_INT16_VAL (tbl
, scriptlist_table
+ 6 + j
* 6, &script_table
);
641 /* If no specific or default script table was found, then this font
642 does not support the script. */
646 /* Offset is from beginning of scriptlist_table. */
647 script_table
+= scriptlist_table
;
649 /* Get default langsys table. */
650 OTF_INT16_VAL (tbl
, script_table
, &langsys_table
);
652 /* If lang was specified, see if font contains a specific entry. */
655 OTF_INT16_VAL (tbl
, script_table
+ 2, &n_langs
);
657 for (j
= 0; j
< n_langs
; j
++)
660 OTF_DWORDTAG_VAL (tbl
, script_table
+ 4 + j
* 6, &lang_id
);
661 if (lang_id
== lang_tag
)
663 OTF_INT16_VAL (tbl
, script_table
+ 8 + j
* 6, &langsys_table
);
672 /* Offset is from beginning of script table. */
673 langsys_table
+= script_table
;
675 /* Check the features. Features may contain nil according to
676 documentation in font_prop_validate_otf, so count them. */
677 n_match_features
= 0;
679 for (feature
= XCAR (rest
); CONSP (rest
); feature
= XCAR (rest
))
686 /* If there are no features to check, skip checking. */
687 if (!n_match_features
)
690 /* First check required feature (if any). */
691 OTF_INT16_VAL (tbl
, langsys_table
+ 2, &feature_index
);
692 if (feature_index
!= 0xFFFF)
695 OTF_TAG_VAL (tbl
, feature_table
+ 2 + feature_index
* 6, feature_id
);
696 OTF_TAG_VAL (tbl
, feature_table
+ 2 + feature_index
* 6, feature_id
);
697 /* Assume no duplicates in the font table. This allows us to mark
698 the features off by simply decrementing a counter. */
699 if (!NILP (Fmemq (intern (feature_id
), features
[i
])))
702 /* Now check all the other features. */
703 OTF_INT16_VAL (tbl
, langsys_table
+ 4, &n_features
);
704 for (j
= 0; j
< n_features
; j
++)
707 OTF_INT16_VAL (tbl
, langsys_table
+ 6 + j
* 2, &feature_index
);
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
])))
715 if (n_match_features
> 0)
723 /* restore graphics context. */
724 SelectObject (context
, old_font
);
725 DeleteObject (check_font
);
726 release_frame_dc (f
, context
);
732 otf_features (HDC context
, char *table
)
734 Lisp_Object script_list
= Qnil
;
735 unsigned short scriptlist_table
, n_scripts
, feature_table
;
736 DWORD tbl
= OTF_TAG (table
);
739 /* Look for scripts in the table. */
740 OTF_INT16_VAL (tbl
, 4, &scriptlist_table
);
741 OTF_INT16_VAL (tbl
, 6, &feature_table
);
742 OTF_INT16_VAL (tbl
, scriptlist_table
, &n_scripts
);
744 for (i
= 0; i
< n_scripts
; i
++)
746 char script
[5], lang
[5];
747 unsigned short script_table
, lang_count
, langsys_table
, feature_count
;
748 Lisp_Object script_tag
, langsys_list
, langsys_tag
, feature_list
;
749 unsigned short record_offset
= scriptlist_table
+ 2 + i
* 6;
750 OTF_TAG_VAL (tbl
, record_offset
, script
);
751 OTF_INT16_VAL (tbl
, record_offset
+ 4, &script_table
);
753 /* Offset is from beginning of script table. */
754 script_table
+= scriptlist_table
;
756 script_tag
= intern (script
);
759 /* Optional default lang. */
760 OTF_INT16_VAL (tbl
, script_table
, &langsys_table
);
763 /* Offset is from beginning of script table. */
764 langsys_table
+= script_table
;
768 OTF_INT16_VAL (tbl
, langsys_table
+ 4, &feature_count
);
769 for (k
= 0; k
< feature_count
; k
++)
772 unsigned short index
;
773 OTF_INT16_VAL (tbl
, langsys_table
+ 6 + k
* 2, &index
);
774 OTF_TAG_VAL (tbl
, feature_table
+ 2 + index
* 6, feature
);
775 feature_list
= Fcons (intern (feature
), feature_list
);
777 langsys_list
= Fcons (Fcons (langsys_tag
, feature_list
),
781 /* List of supported languages. */
782 OTF_INT16_VAL (tbl
, script_table
+ 2, &lang_count
);
784 for (j
= 0; j
< lang_count
; j
++)
786 record_offset
= script_table
+ 4 + j
* 6;
787 OTF_TAG_VAL (tbl
, record_offset
, lang
);
788 OTF_INT16_VAL (tbl
, record_offset
+ 4, &langsys_table
);
790 /* Offset is from beginning of script table. */
791 langsys_table
+= script_table
;
793 langsys_tag
= intern (lang
);
795 OTF_INT16_VAL (tbl
, langsys_table
+ 4, &feature_count
);
796 for (k
= 0; k
< feature_count
; k
++)
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
);
804 langsys_list
= Fcons (Fcons (langsys_tag
, feature_list
),
809 script_list
= Fcons (Fcons (script_tag
, langsys_list
), script_list
);
823 struct font_driver uniscribe_font_driver
=
829 uniscribe_list_family
,
830 NULL
, /* free_entity */
833 NULL
, /* prepare_face */
834 NULL
, /* done_face */
836 uniscribe_encode_char
,
837 w32font_text_extents
,
839 NULL
, /* get_bitmap */
840 NULL
, /* free_bitmap */
841 NULL
, /* get_outline */
842 NULL
, /* free_outline */
843 NULL
, /* anchor_point */
844 uniscribe_otf_capability
, /* Defined so (font-get FONTOBJ :otf) works. */
845 NULL
, /* otf_drive - use shape instead. */
846 NULL
, /* start_for_frame */
847 NULL
, /* end_for_frame */
851 /* Note that this should be called at every startup, not just when dumping,
852 as it needs to test for the existence of the Uniscribe library. */
854 syms_of_w32uniscribe ()
858 /* Don't init uniscribe when dumping */
862 /* Don't register if uniscribe is not available. */
863 uniscribe
= GetModuleHandle ("usp10");
867 uniscribe_font_driver
.type
= Quniscribe
;
868 uniscribe_available
= 1;
870 register_font_driver (&uniscribe_font_driver
, NULL
);
873 #endif /* USE_FONT_BACKEND */