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 of the License, or
9 (at your option) any later version.
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. If not, see <http://www.gnu.org/licenses/>. */
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. */
27 #define _WIN32_WINNT 0x500
34 #include "dispextern.h"
35 #include "character.h"
41 struct uniscribe_font_info
43 struct w32font_info w32_font
;
47 int uniscribe_available
= 0;
49 /* Defined in w32font.c, since it is required there as well. */
50 extern Lisp_Object Quniscribe
;
51 extern Lisp_Object Qopentype
;
53 extern int initialized
;
55 extern struct font_driver uniscribe_font_driver
;
57 /* EnumFontFamiliesEx callback. */
58 static int CALLBACK add_opentype_font_name_to_list
P_ ((ENUMLOGFONTEX
*,
61 /* Used by uniscribe_otf_capability. */
62 static Lisp_Object
otf_features (HDC context
, char *table
);
65 memq_no_quit (elt
, list
)
66 Lisp_Object elt
, list
;
68 while (CONSP (list
) && ! EQ (XCAR (list
), elt
))
70 return (CONSP (list
));
74 /* Font backend interface implementation. */
76 uniscribe_list (frame
, font_spec
)
77 Lisp_Object frame
, font_spec
;
79 return w32font_list_internal (frame
, font_spec
, 1);
83 uniscribe_match (frame
, font_spec
)
84 Lisp_Object frame
, font_spec
;
86 return w32font_match_internal (frame
, font_spec
, 1);
90 uniscribe_list_family (frame
)
93 Lisp_Object list
= Qnil
;
94 LOGFONT font_match_pattern
;
96 FRAME_PTR f
= XFRAME (frame
);
98 bzero (&font_match_pattern
, sizeof (font_match_pattern
));
99 /* Limit enumerated fonts to outline fonts to save time. */
100 font_match_pattern
.lfOutPrecision
= OUT_OUTLINE_PRECIS
;
102 dc
= get_frame_dc (f
);
104 EnumFontFamiliesEx (dc
, &font_match_pattern
,
105 (FONTENUMPROC
) add_opentype_font_name_to_list
,
107 release_frame_dc (f
, dc
);
113 uniscribe_open (f
, font_entity
, pixel_size
)
115 Lisp_Object font_entity
;
118 Lisp_Object font_object
119 = font_make_object (VECSIZE (struct uniscribe_font_info
));
120 struct uniscribe_font_info
*uniscribe_font
121 = (struct uniscribe_font_info
*) XFONT_OBJECT (font_object
);
123 if (!w32font_open_internal (f
, font_entity
, pixel_size
, font_object
))
128 /* Initialize the cache for this font. */
129 uniscribe_font
->cache
= NULL
;
130 /* Mark the format as opentype */
131 uniscribe_font
->w32_font
.font
.props
[FONT_FORMAT_INDEX
] = Qopentype
;
132 uniscribe_font
->w32_font
.font
.driver
= &uniscribe_font_driver
;
138 uniscribe_close (f
, font
)
142 struct uniscribe_font_info
*uniscribe_font
143 = (struct uniscribe_font_info
*) font
;
145 if (uniscribe_font
->cache
)
146 ScriptFreeCache (&uniscribe_font
->cache
);
148 w32font_close (f
, font
);
151 /* Return a list describing which scripts/languages FONT supports by
152 which GSUB/GPOS features of OpenType tables. */
154 uniscribe_otf_capability (font
)
160 Lisp_Object capability
= Fcons (Qnil
, Qnil
);
161 Lisp_Object features
;
163 f
= XFRAME (selected_frame
);
164 context
= get_frame_dc (f
);
165 old_font
= SelectObject (context
, FONT_COMPAT (font
)->hfont
);
167 features
= otf_features (context
, "GSUB");
168 XSETCAR (capability
, features
);
169 features
= otf_features (context
, "GPOS");
170 XSETCDR (capability
, features
);
172 SelectObject (context
, old_font
);
173 release_frame_dc (f
, context
);
178 /* Uniscribe implementation of shape for font backend.
180 Shape text in LGSTRING. See the docstring of `font-make-gstring'
181 for the format of LGSTRING. If the (N+1)th element of LGSTRING
182 is nil, input of shaping is from the 1st to (N)th elements. In
183 each input glyph, FROM, TO, CHAR, and CODE are already set.
185 This function updates all fields of the input glyphs. If the
186 output glyphs (M) are more than the input glyphs (N), (N+1)th
187 through (M)th elements of LGSTRING are updated possibly by making
188 a new glyph object and storing it in LGSTRING. If (M) is greater
189 than the length of LGSTRING, nil should be return. In that case,
190 this function is called again with the larger LGSTRING. */
192 uniscribe_shape (lgstring
)
193 Lisp_Object lgstring
;
196 struct uniscribe_font_info
* uniscribe_font
;
198 int nitems
, max_items
, i
, max_glyphs
, done_glyphs
;
200 WORD
*glyphs
, *clusters
;
202 SCRIPT_CONTROL control
;
203 SCRIPT_VISATTR
*attributes
;
213 CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring
), font
);
214 uniscribe_font
= (struct uniscribe_font_info
*) font
;
216 /* Get the chars from lgstring in a form we can use with uniscribe. */
217 max_glyphs
= nchars
= LGSTRING_LENGTH (lgstring
);
219 chars
= (wchar_t *) alloca (nchars
* sizeof (wchar_t));
220 for (i
= 0; i
< nchars
; i
++)
222 /* lgstring can be bigger than the number of characters in it, in
223 the case where more glyphs are required to display those characters.
224 If that is the case, note the real number of characters. */
225 if (NILP (LGSTRING_GLYPH (lgstring
, i
)))
228 chars
[i
] = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring
, i
));
231 /* First we need to break up the glyph string into runs of glyphs that
232 can be treated together. First try a single run. */
234 items
= (SCRIPT_ITEM
*) xmalloc (sizeof (SCRIPT_ITEM
) * max_items
+ 1);
235 bzero (&control
, sizeof (control
));
237 while ((result
= ScriptItemize (chars
, nchars
, max_items
, &control
, NULL
,
238 items
, &nitems
)) == E_OUTOFMEMORY
)
240 /* If that wasn't enough, keep trying with one more run. */
242 items
= (SCRIPT_ITEM
*) xrealloc (items
,
243 sizeof (SCRIPT_ITEM
) * max_items
+ 1);
246 /* 0 = success in Microsoft's backwards world. */
253 /* TODO: When we get BIDI support, we need to call ScriptLayout here.
254 Requires that we know the surrounding context. */
256 f
= XFRAME (selected_frame
);
257 context
= get_frame_dc (f
);
258 old_font
= SelectObject (context
, FONT_COMPAT (font
)->hfont
);
260 glyphs
= alloca (max_glyphs
* sizeof (WORD
));
261 clusters
= alloca (nchars
* sizeof (WORD
));
262 attributes
= alloca (max_glyphs
* sizeof (SCRIPT_VISATTR
));
263 advances
= alloca (max_glyphs
* sizeof (int));
264 offsets
= alloca (max_glyphs
* sizeof (GOFFSET
));
265 bzero (&transform
, sizeof (transform
));
266 transform
.eM11
.value
= 1;
267 transform
.eM22
.value
= 1;
269 for (i
= 0; i
< nitems
; i
++)
271 int nglyphs
, nchars_in_run
, rtl
= items
[i
].a
.fRTL
? -1 : 1;
272 nchars_in_run
= items
[i
+1].iCharPos
- items
[i
].iCharPos
;
274 result
= ScriptShape (context
, &(uniscribe_font
->cache
),
275 chars
+ items
[i
].iCharPos
, nchars_in_run
,
276 max_glyphs
- done_glyphs
, &(items
[i
].a
),
277 glyphs
, clusters
, attributes
, &nglyphs
);
278 if (result
== E_OUTOFMEMORY
)
280 /* Need a bigger lgstring. */
284 else if (result
) /* Failure. */
286 /* Can't shape this run - return results so far if any. */
289 else if (items
[i
].a
.fNoGlyphIndex
)
291 /* Glyph indices not supported by this font (or OS), means we
292 can't really do any meaningful shaping. */
297 result
= ScriptPlace (context
, &(uniscribe_font
->cache
),
298 glyphs
, nglyphs
, attributes
, &(items
[i
].a
),
299 advances
, offsets
, &overall_metrics
);
300 if (result
== 0) /* Success. */
302 int j
, nclusters
, from
, to
;
304 from
= rtl
> 0 ? 0 : nchars_in_run
- 1;
307 for (j
= 0; j
< nglyphs
; j
++)
309 int lglyph_index
= j
+ done_glyphs
;
310 Lisp_Object lglyph
= LGSTRING_GLYPH (lgstring
, lglyph_index
);
315 lglyph
= Fmake_vector (make_number (LGLYPH_SIZE
), Qnil
);
316 LGSTRING_SET_GLYPH (lgstring
, lglyph_index
, lglyph
);
318 LGLYPH_SET_CODE (lglyph
, glyphs
[j
]);
320 /* Detect clusters, for linking codes back to characters. */
321 if (attributes
[j
].fClusterStart
)
323 while (from
>= 0 && from
< nchars_in_run
324 && clusters
[from
] < j
)
328 else if (from
>= nchars_in_run
)
329 from
= to
= nchars_in_run
- 1;
333 to
= rtl
> 0 ? nchars_in_run
- 1 : 0;
334 for (k
= from
+ rtl
; k
>= 0 && k
< nchars_in_run
;
346 LGLYPH_SET_CHAR (lglyph
, chars
[items
[i
].iCharPos
348 LGLYPH_SET_FROM (lglyph
, items
[i
].iCharPos
+ from
);
349 LGLYPH_SET_TO (lglyph
, items
[i
].iCharPos
+ to
);
352 LGLYPH_SET_WIDTH (lglyph
, advances
[j
]);
353 LGLYPH_SET_ASCENT (lglyph
, font
->ascent
);
354 LGLYPH_SET_DESCENT (lglyph
, font
->descent
);
356 result
= ScriptGetGlyphABCWidth (context
,
357 &(uniscribe_font
->cache
),
358 glyphs
[j
], &char_metric
);
360 if (result
== 0) /* Success. */
362 LGLYPH_SET_LBEARING (lglyph
, char_metric
.abcA
);
363 LGLYPH_SET_RBEARING (lglyph
, (char_metric
.abcA
364 + char_metric
.abcB
));
368 LGLYPH_SET_LBEARING (lglyph
, 0);
369 LGLYPH_SET_RBEARING (lglyph
, advances
[j
]);
372 if (offsets
[j
].du
|| offsets
[j
].dv
)
375 vec
= Fmake_vector (make_number (3), Qnil
);
376 ASET (vec
, 0, make_number (offsets
[j
].du
));
377 ASET (vec
, 1, make_number (offsets
[j
].dv
));
378 /* Based on what ftfont.c does... */
379 ASET (vec
, 2, make_number (advances
[j
]));
380 LGLYPH_SET_ADJUSTMENT (lglyph
, vec
);
383 LGLYPH_SET_ADJUSTMENT (lglyph
, Qnil
);
386 done_glyphs
+= nglyphs
;
390 SelectObject (context
, old_font
);
391 release_frame_dc (f
, context
);
396 return make_number (done_glyphs
);
399 /* Uniscribe implementation of encode_char for font backend.
400 Return a glyph code of FONT for characer C (Unicode code point).
401 If FONT doesn't have such a glyph, return FONT_INVALID_CODE. */
403 uniscribe_encode_char (font
, c
)
414 /* TODO: surrogates. */
416 return FONT_INVALID_CODE
;
418 chars
[0] = (wchar_t) c
;
420 /* Use selected frame until API is updated to pass the frame. */
421 f
= XFRAME (selected_frame
);
422 context
= get_frame_dc (f
);
423 old_font
= SelectObject (context
, FONT_COMPAT (font
)->hfont
);
425 retval
= GetGlyphIndicesW (context
, chars
, 1, indices
,
426 GGI_MARK_NONEXISTING_GLYPHS
);
428 SelectObject (context
, old_font
);
429 release_frame_dc (f
, context
);
432 return indices
[0] == 0xFFFF ? FONT_INVALID_CODE
: indices
[0];
434 return FONT_INVALID_CODE
;
439 Lisp_Object uniscribe_get_cache (Lisp_Object frame);
440 void uniscribe_free_entity (Lisp_Object font_entity);
441 int uniscribe_has_char (Lisp_Object entity, int c);
442 int uniscribe_text_extents (struct font *font, unsigned *code,
443 int nglyphs, struct font_metrics *metrics);
444 int uniscribe_draw (struct glyph_string *s, int from, int to,
445 int x, int y, int with_background);
448 int uniscribe_prepare_face (FRAME_PTR f, struct face *face);
449 void uniscribe_done_face (FRAME_PTR f, struct face *face);
450 int uniscribe_get_bitmap (struct font *font, unsigned code,
451 struct font_bitmap *bitmap, int bits_per_pixel);
452 void uniscribe_free_bitmap (struct font *font, struct font_bitmap *bitmap);
453 void * uniscribe_get_outline (struct font *font, unsigned code);
454 void uniscribe_free_outline (struct font *font, void *outline);
455 int uniscribe_anchor_point (struct font *font, unsigned code,
456 int index, int *x, int *y);
457 int uniscribe_start_for_frame (FRAME_PTR f);
458 int uniscribe_end_for_frame (FRAME_PTR f);
463 /* Callback function for EnumFontFamiliesEx.
464 Adds the name of opentype fonts to a Lisp list (passed in as the
467 add_opentype_font_name_to_list (logical_font
, physical_font
, font_type
,
469 ENUMLOGFONTEX
*logical_font
;
470 NEWTEXTMETRICEX
*physical_font
;
474 Lisp_Object
* list
= (Lisp_Object
*) list_object
;
477 /* Skip vertical fonts (intended only for printing) */
478 if (logical_font
->elfLogFont
.lfFaceName
[0] == '@')
481 /* Skip non opentype fonts. Count old truetype fonts as opentype,
482 as some of them do contain GPOS and GSUB data that Uniscribe
484 if (!(physical_font
->ntmTm
.ntmFlags
& NTMFLAGS_OPENTYPE
)
485 && font_type
!= TRUETYPE_FONTTYPE
)
488 /* Skip fonts that have no unicode coverage. */
489 if (!physical_font
->ntmFontSig
.fsUsb
[3]
490 && !physical_font
->ntmFontSig
.fsUsb
[2]
491 && !physical_font
->ntmFontSig
.fsUsb
[1]
492 && !(physical_font
->ntmFontSig
.fsUsb
[0] & 0x3fffffff))
495 family
= font_intern_prop (logical_font
->elfLogFont
.lfFaceName
,
496 strlen (logical_font
->elfLogFont
.lfFaceName
), 1);
497 if (! memq_no_quit (family
, *list
))
498 *list
= Fcons (family
, *list
);
504 /* :otf property handling.
505 Since the necessary Uniscribe APIs for getting font tag information
506 are only available in Vista, we need to parse the font data directly
507 according to the OpenType Specification. */
509 /* Push into DWORD backwards to cope with endianness. */
510 #define OTF_TAG(STR) \
511 ((STR[3] << 24) | (STR[2] << 16) | (STR[1] << 8) | STR[0])
513 #define OTF_INT16_VAL(TABLE, OFFSET, PTR) \
515 BYTE temp, data[2]; \
516 if (GetFontData (context, TABLE, OFFSET, data, 2) != 2) \
517 goto font_table_error; \
518 temp = data[0], data[0] = data[1], data[1] = temp; \
519 memcpy (PTR, data, 2); \
522 /* Do not reverse the bytes, because we will compare with a OTF_TAG value
523 that has them reversed already. */
524 #define OTF_DWORDTAG_VAL(TABLE, OFFSET, PTR) \
526 if (GetFontData (context, TABLE, OFFSET, PTR, 4) != 4) \
527 goto font_table_error; \
530 #define OTF_TAG_VAL(TABLE, OFFSET, STR) \
532 if (GetFontData (context, TABLE, OFFSET, STR, 4) != 4) \
533 goto font_table_error; \
537 static char* NOTHING
= " ";
539 #define SNAME(VAL) SDATA (SYMBOL_NAME (VAL))
541 /* Check if font supports the otf script/language/features specified.
542 OTF_SPEC is in the format
543 (script lang [(gsub_feature ...)|nil] [(gpos_feature ...)]?) */
544 int uniscribe_check_otf (font
, otf_spec
)
546 Lisp_Object otf_spec
;
548 Lisp_Object script
, lang
, rest
;
549 Lisp_Object features
[2];
550 DWORD feature_tables
[2];
551 DWORD script_tag
, default_script
, lang_tag
= 0;
554 HFONT check_font
, old_font
;
559 /* Check the spec is in the right format. */
560 if (!CONSP (otf_spec
) || Flength (otf_spec
) < 3)
563 /* Break otf_spec into its components. */
564 script
= XCAR (otf_spec
);
565 rest
= XCDR (otf_spec
);
570 features
[0] = XCAR (rest
);
575 features
[1] = XCAR (rest
);
577 /* Set up tags we will use in the search. */
578 feature_tables
[0] = OTF_TAG ("GSUB");
579 feature_tables
[1] = OTF_TAG ("GPOS");
580 default_script
= OTF_TAG ("DFLT");
582 script_tag
= default_script
;
584 script_tag
= OTF_TAG (SNAME (script
));
586 lang_tag
= OTF_TAG (SNAME (lang
));
588 /* Set up graphics context so we can use the font. */
589 f
= XFRAME (selected_frame
);
590 context
= get_frame_dc (f
);
591 check_font
= CreateFontIndirect (font
);
592 old_font
= SelectObject (context
, check_font
);
594 /* Everything else is contained within otf_spec so should get
595 marked along with it. */
598 /* Scan GSUB and GPOS tables. */
599 for (i
= 0; i
< 2; i
++)
601 int j
, n_match_features
;
602 unsigned short scriptlist_table
, feature_table
, n_scripts
;
603 unsigned short script_table
, langsys_table
, n_langs
;
604 unsigned short feature_index
, n_features
;
605 DWORD tbl
= feature_tables
[i
];
607 /* Skip if no features requested from this table. */
608 if (NILP (features
[i
]))
611 /* If features is not a cons, this font spec is messed up. */
612 if (!CONSP (features
[i
]))
615 /* Read GPOS/GSUB header. */
616 OTF_INT16_VAL (tbl
, 4, &scriptlist_table
);
617 OTF_INT16_VAL (tbl
, 6, &feature_table
);
618 OTF_INT16_VAL (tbl
, scriptlist_table
, &n_scripts
);
620 /* Find the appropriate script table. */
622 for (j
= 0; j
< n_scripts
; j
++)
625 OTF_DWORDTAG_VAL (tbl
, scriptlist_table
+ 2 + j
* 6, &script_id
);
626 if (script_id
== script_tag
)
628 OTF_INT16_VAL (tbl
, scriptlist_table
+ 6 + j
* 6, &script_table
);
631 /* If there is a DFLT script defined in the font, use it
632 if the specified script is not found. */
633 else if (script_id
== default_script
)
634 OTF_INT16_VAL (tbl
, scriptlist_table
+ 6 + j
* 6, &script_table
);
636 /* If no specific or default script table was found, then this font
637 does not support the script. */
641 /* Offset is from beginning of scriptlist_table. */
642 script_table
+= scriptlist_table
;
644 /* Get default langsys table. */
645 OTF_INT16_VAL (tbl
, script_table
, &langsys_table
);
647 /* If lang was specified, see if font contains a specific entry. */
650 OTF_INT16_VAL (tbl
, script_table
+ 2, &n_langs
);
652 for (j
= 0; j
< n_langs
; j
++)
655 OTF_DWORDTAG_VAL (tbl
, script_table
+ 4 + j
* 6, &lang_id
);
656 if (lang_id
== lang_tag
)
658 OTF_INT16_VAL (tbl
, script_table
+ 8 + j
* 6, &langsys_table
);
667 /* Offset is from beginning of script table. */
668 langsys_table
+= script_table
;
670 /* Check the features. Features may contain nil according to
671 documentation in font_prop_validate_otf, so count them. */
672 n_match_features
= 0;
673 for (rest
= features
[i
]; CONSP (rest
); rest
= XCDR (rest
))
675 Lisp_Object feature
= XCAR (rest
);
680 /* If there are no features to check, skip checking. */
681 if (!n_match_features
)
684 /* First check required feature (if any). */
685 OTF_INT16_VAL (tbl
, langsys_table
+ 2, &feature_index
);
686 if (feature_index
!= 0xFFFF)
689 OTF_TAG_VAL (tbl
, feature_table
+ 2 + feature_index
* 6, feature_id
);
690 OTF_TAG_VAL (tbl
, feature_table
+ 2 + feature_index
* 6, feature_id
);
691 /* Assume no duplicates in the font table. This allows us to mark
692 the features off by simply decrementing a counter. */
693 if (!NILP (Fmemq (intern (feature_id
), features
[i
])))
696 /* Now check all the other features. */
697 OTF_INT16_VAL (tbl
, langsys_table
+ 4, &n_features
);
698 for (j
= 0; j
< n_features
; j
++)
701 OTF_INT16_VAL (tbl
, langsys_table
+ 6 + j
* 2, &feature_index
);
702 OTF_TAG_VAL (tbl
, feature_table
+ 2 + feature_index
* 6, feature_id
);
703 /* Assume no duplicates in the font table. This allows us to mark
704 the features off by simply decrementing a counter. */
705 if (!NILP (Fmemq (intern (feature_id
), features
[i
])))
709 if (n_match_features
> 0)
717 /* restore graphics context. */
718 SelectObject (context
, old_font
);
719 DeleteObject (check_font
);
720 release_frame_dc (f
, context
);
726 otf_features (HDC context
, char *table
)
728 Lisp_Object script_list
= Qnil
;
729 unsigned short scriptlist_table
, n_scripts
, feature_table
;
730 DWORD tbl
= OTF_TAG (table
);
733 /* Look for scripts in the table. */
734 OTF_INT16_VAL (tbl
, 4, &scriptlist_table
);
735 OTF_INT16_VAL (tbl
, 6, &feature_table
);
736 OTF_INT16_VAL (tbl
, scriptlist_table
, &n_scripts
);
738 for (i
= 0; i
< n_scripts
; i
++)
740 char script
[5], lang
[5];
741 unsigned short script_table
, lang_count
, langsys_table
, feature_count
;
742 Lisp_Object script_tag
, langsys_list
, langsys_tag
, feature_list
;
743 unsigned short record_offset
= scriptlist_table
+ 2 + i
* 6;
744 OTF_TAG_VAL (tbl
, record_offset
, script
);
745 OTF_INT16_VAL (tbl
, record_offset
+ 4, &script_table
);
747 /* Offset is from beginning of script table. */
748 script_table
+= scriptlist_table
;
750 script_tag
= intern (script
);
753 /* Optional default lang. */
754 OTF_INT16_VAL (tbl
, script_table
, &langsys_table
);
757 /* Offset is from beginning of script table. */
758 langsys_table
+= script_table
;
762 OTF_INT16_VAL (tbl
, langsys_table
+ 4, &feature_count
);
763 for (k
= 0; k
< feature_count
; k
++)
766 unsigned short index
;
767 OTF_INT16_VAL (tbl
, langsys_table
+ 6 + k
* 2, &index
);
768 OTF_TAG_VAL (tbl
, feature_table
+ 2 + index
* 6, feature
);
769 feature_list
= Fcons (intern (feature
), feature_list
);
771 langsys_list
= Fcons (Fcons (langsys_tag
, feature_list
),
775 /* List of supported languages. */
776 OTF_INT16_VAL (tbl
, script_table
+ 2, &lang_count
);
778 for (j
= 0; j
< lang_count
; j
++)
780 record_offset
= script_table
+ 4 + j
* 6;
781 OTF_TAG_VAL (tbl
, record_offset
, lang
);
782 OTF_INT16_VAL (tbl
, record_offset
+ 4, &langsys_table
);
784 /* Offset is from beginning of script table. */
785 langsys_table
+= script_table
;
787 langsys_tag
= intern (lang
);
789 OTF_INT16_VAL (tbl
, langsys_table
+ 4, &feature_count
);
790 for (k
= 0; k
< feature_count
; k
++)
793 unsigned short index
;
794 OTF_INT16_VAL (tbl
, langsys_table
+ 6 + k
* 2, &index
);
795 OTF_TAG_VAL (tbl
, feature_table
+ 2 + index
* 6, feature
);
796 feature_list
= Fcons (intern (feature
), feature_list
);
798 langsys_list
= Fcons (Fcons (langsys_tag
, feature_list
),
803 script_list
= Fcons (Fcons (script_tag
, langsys_list
), script_list
);
817 struct font_driver uniscribe_font_driver
=
820 0, /* case insensitive */
824 uniscribe_list_family
,
825 NULL
, /* free_entity */
828 NULL
, /* prepare_face */
829 NULL
, /* done_face */
831 uniscribe_encode_char
,
832 w32font_text_extents
,
834 NULL
, /* get_bitmap */
835 NULL
, /* free_bitmap */
836 NULL
, /* get_outline */
837 NULL
, /* free_outline */
838 NULL
, /* anchor_point */
839 uniscribe_otf_capability
, /* Defined so (font-get FONTOBJ :otf) works. */
840 NULL
, /* otf_drive - use shape instead. */
841 NULL
, /* start_for_frame */
842 NULL
, /* end_for_frame */
846 /* Note that this should be called at every startup, not just when dumping,
847 as it needs to test for the existence of the Uniscribe library. */
849 syms_of_w32uniscribe ()
853 /* Don't init uniscribe when dumping */
857 /* Don't register if uniscribe is not available. */
858 uniscribe
= GetModuleHandle ("usp10");
862 uniscribe_font_driver
.type
= Quniscribe
;
863 uniscribe_available
= 1;
865 register_font_driver (&uniscribe_font_driver
, NULL
);
868 /* arch-tag: 9530f0e1-7471-47dd-a780-94330af87ea0
869 (do not change this comment) */