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 Lisp_Object fonts
= w32font_list_internal (frame
, font_spec
, 1);
80 font_add_log ("uniscribe-list", font_spec
, fonts
);
85 uniscribe_match (frame
, font_spec
)
86 Lisp_Object frame
, font_spec
;
88 Lisp_Object entity
= w32font_match_internal (frame
, font_spec
, 1);
89 font_add_log ("uniscribe-match", font_spec
, entity
);
94 uniscribe_list_family (frame
)
97 Lisp_Object list
= Qnil
;
98 LOGFONT font_match_pattern
;
100 FRAME_PTR f
= XFRAME (frame
);
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
;
106 dc
= get_frame_dc (f
);
108 EnumFontFamiliesEx (dc
, &font_match_pattern
,
109 (FONTENUMPROC
) add_opentype_font_name_to_list
,
111 release_frame_dc (f
, dc
);
117 uniscribe_open (f
, font_entity
, pixel_size
)
119 Lisp_Object font_entity
;
122 Lisp_Object font_object
123 = font_make_object (VECSIZE (struct uniscribe_font_info
));
124 struct uniscribe_font_info
*uniscribe_font
125 = (struct uniscribe_font_info
*) XFONT_OBJECT (font_object
);
127 if (!w32font_open_internal (f
, font_entity
, pixel_size
, font_object
))
132 /* Initialize the cache for this font. */
133 uniscribe_font
->cache
= NULL
;
134 /* Mark the format as opentype */
135 uniscribe_font
->w32_font
.font
.props
[FONT_FORMAT_INDEX
] = Qopentype
;
136 uniscribe_font
->w32_font
.font
.driver
= &uniscribe_font_driver
;
142 uniscribe_close (f
, font
)
146 struct uniscribe_font_info
*uniscribe_font
147 = (struct uniscribe_font_info
*) font
;
149 if (uniscribe_font
->cache
)
150 ScriptFreeCache (&uniscribe_font
->cache
);
152 w32font_close (f
, font
);
155 /* Return a list describing which scripts/languages FONT supports by
156 which GSUB/GPOS features of OpenType tables. */
158 uniscribe_otf_capability (font
)
164 Lisp_Object capability
= Fcons (Qnil
, Qnil
);
165 Lisp_Object features
;
167 f
= XFRAME (selected_frame
);
168 context
= get_frame_dc (f
);
169 old_font
= SelectObject (context
, FONT_COMPAT (font
)->hfont
);
171 features
= otf_features (context
, "GSUB");
172 XSETCAR (capability
, features
);
173 features
= otf_features (context
, "GPOS");
174 XSETCDR (capability
, features
);
176 SelectObject (context
, old_font
);
177 release_frame_dc (f
, context
);
182 /* Uniscribe implementation of shape for font backend.
184 Shape text in LGSTRING. See the docstring of `font-make-gstring'
185 for the format of LGSTRING. If the (N+1)th element of LGSTRING
186 is nil, input of shaping is from the 1st to (N)th elements. In
187 each input glyph, FROM, TO, CHAR, and CODE are already set.
189 This function updates all fields of the input glyphs. If the
190 output glyphs (M) are more than the input glyphs (N), (N+1)th
191 through (M)th elements of LGSTRING are updated possibly by making
192 a new glyph object and storing it in LGSTRING. If (M) is greater
193 than the length of LGSTRING, nil should be return. In that case,
194 this function is called again with the larger LGSTRING. */
196 uniscribe_shape (lgstring
)
197 Lisp_Object lgstring
;
200 struct uniscribe_font_info
* uniscribe_font
;
202 int nitems
, max_items
, i
, max_glyphs
, done_glyphs
;
204 WORD
*glyphs
, *clusters
;
206 SCRIPT_CONTROL control
;
207 SCRIPT_VISATTR
*attributes
;
217 CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring
), font
);
218 uniscribe_font
= (struct uniscribe_font_info
*) font
;
220 /* Get the chars from lgstring in a form we can use with uniscribe. */
221 max_glyphs
= nchars
= LGSTRING_LENGTH (lgstring
);
223 chars
= (wchar_t *) alloca (nchars
* sizeof (wchar_t));
224 for (i
= 0; i
< nchars
; i
++)
226 /* lgstring can be bigger than the number of characters in it, in
227 the case where more glyphs are required to display those characters.
228 If that is the case, note the real number of characters. */
229 if (NILP (LGSTRING_GLYPH (lgstring
, i
)))
232 chars
[i
] = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring
, i
));
235 /* First we need to break up the glyph string into runs of glyphs that
236 can be treated together. First try a single run. */
238 items
= (SCRIPT_ITEM
*) xmalloc (sizeof (SCRIPT_ITEM
) * max_items
+ 1);
239 bzero (&control
, sizeof (control
));
241 while ((result
= ScriptItemize (chars
, nchars
, max_items
, &control
, NULL
,
242 items
, &nitems
)) == E_OUTOFMEMORY
)
244 /* If that wasn't enough, keep trying with one more run. */
246 items
= (SCRIPT_ITEM
*) xrealloc (items
,
247 sizeof (SCRIPT_ITEM
) * max_items
+ 1);
250 /* 0 = success in Microsoft's backwards world. */
257 /* TODO: When we get BIDI support, we need to call ScriptLayout here.
258 Requires that we know the surrounding context. */
260 f
= XFRAME (selected_frame
);
261 context
= get_frame_dc (f
);
262 old_font
= SelectObject (context
, FONT_COMPAT (font
)->hfont
);
264 glyphs
= alloca (max_glyphs
* sizeof (WORD
));
265 clusters
= alloca (nchars
* sizeof (WORD
));
266 attributes
= alloca (max_glyphs
* sizeof (SCRIPT_VISATTR
));
267 advances
= alloca (max_glyphs
* sizeof (int));
268 offsets
= alloca (max_glyphs
* sizeof (GOFFSET
));
269 bzero (&transform
, sizeof (transform
));
270 transform
.eM11
.value
= 1;
271 transform
.eM22
.value
= 1;
273 for (i
= 0; i
< nitems
; i
++)
275 int nglyphs
, nchars_in_run
, rtl
= items
[i
].a
.fRTL
? -1 : 1;
276 nchars_in_run
= items
[i
+1].iCharPos
- items
[i
].iCharPos
;
278 result
= ScriptShape (context
, &(uniscribe_font
->cache
),
279 chars
+ items
[i
].iCharPos
, nchars_in_run
,
280 max_glyphs
- done_glyphs
, &(items
[i
].a
),
281 glyphs
, clusters
, attributes
, &nglyphs
);
282 if (result
== E_OUTOFMEMORY
)
284 /* Need a bigger lgstring. */
288 else if (result
) /* Failure. */
290 /* Can't shape this run - return results so far if any. */
293 else if (items
[i
].a
.fNoGlyphIndex
)
295 /* Glyph indices not supported by this font (or OS), means we
296 can't really do any meaningful shaping. */
301 result
= ScriptPlace (context
, &(uniscribe_font
->cache
),
302 glyphs
, nglyphs
, attributes
, &(items
[i
].a
),
303 advances
, offsets
, &overall_metrics
);
304 if (result
== 0) /* Success. */
306 int j
, nclusters
, from
, to
;
308 from
= rtl
> 0 ? 0 : nchars_in_run
- 1;
311 for (j
= 0; j
< nglyphs
; j
++)
313 int lglyph_index
= j
+ done_glyphs
;
314 Lisp_Object lglyph
= LGSTRING_GLYPH (lgstring
, lglyph_index
);
319 lglyph
= Fmake_vector (make_number (LGLYPH_SIZE
), Qnil
);
320 LGSTRING_SET_GLYPH (lgstring
, lglyph_index
, lglyph
);
322 LGLYPH_SET_CODE (lglyph
, glyphs
[j
]);
324 /* Detect clusters, for linking codes back to characters. */
325 if (attributes
[j
].fClusterStart
)
327 while (from
>= 0 && from
< nchars_in_run
328 && clusters
[from
] < j
)
332 else if (from
>= nchars_in_run
)
333 from
= to
= nchars_in_run
- 1;
337 to
= rtl
> 0 ? nchars_in_run
- 1 : 0;
338 for (k
= from
+ rtl
; k
>= 0 && k
< nchars_in_run
;
350 LGLYPH_SET_CHAR (lglyph
, chars
[items
[i
].iCharPos
352 LGLYPH_SET_FROM (lglyph
, items
[i
].iCharPos
+ from
);
353 LGLYPH_SET_TO (lglyph
, items
[i
].iCharPos
+ to
);
356 LGLYPH_SET_WIDTH (lglyph
, advances
[j
]);
357 LGLYPH_SET_ASCENT (lglyph
, font
->ascent
);
358 LGLYPH_SET_DESCENT (lglyph
, font
->descent
);
360 result
= ScriptGetGlyphABCWidth (context
,
361 &(uniscribe_font
->cache
),
362 glyphs
[j
], &char_metric
);
364 if (result
== 0) /* Success. */
366 LGLYPH_SET_LBEARING (lglyph
, char_metric
.abcA
);
367 LGLYPH_SET_RBEARING (lglyph
, (char_metric
.abcA
368 + char_metric
.abcB
));
372 LGLYPH_SET_LBEARING (lglyph
, 0);
373 LGLYPH_SET_RBEARING (lglyph
, advances
[j
]);
376 if (offsets
[j
].du
|| offsets
[j
].dv
)
379 vec
= Fmake_vector (make_number (3), Qnil
);
380 ASET (vec
, 0, make_number (offsets
[j
].du
));
381 ASET (vec
, 1, make_number (offsets
[j
].dv
));
382 /* Based on what ftfont.c does... */
383 ASET (vec
, 2, make_number (advances
[j
]));
384 LGLYPH_SET_ADJUSTMENT (lglyph
, vec
);
387 LGLYPH_SET_ADJUSTMENT (lglyph
, Qnil
);
390 done_glyphs
+= nglyphs
;
394 SelectObject (context
, old_font
);
395 release_frame_dc (f
, context
);
400 return make_number (done_glyphs
);
403 /* Uniscribe implementation of encode_char for font backend.
404 Return a glyph code of FONT for characer C (Unicode code point).
405 If FONT doesn't have such a glyph, return FONT_INVALID_CODE. */
407 uniscribe_encode_char (font
, c
)
418 /* TODO: surrogates. */
420 return FONT_INVALID_CODE
;
422 chars
[0] = (wchar_t) c
;
424 /* Use selected frame until API is updated to pass the frame. */
425 f
= XFRAME (selected_frame
);
426 context
= get_frame_dc (f
);
427 old_font
= SelectObject (context
, FONT_COMPAT (font
)->hfont
);
429 retval
= GetGlyphIndicesW (context
, chars
, 1, indices
,
430 GGI_MARK_NONEXISTING_GLYPHS
);
432 SelectObject (context
, old_font
);
433 release_frame_dc (f
, context
);
436 return indices
[0] == 0xFFFF ? FONT_INVALID_CODE
: indices
[0];
438 return FONT_INVALID_CODE
;
443 Lisp_Object uniscribe_get_cache (Lisp_Object frame);
444 void uniscribe_free_entity (Lisp_Object font_entity);
445 int uniscribe_has_char (Lisp_Object entity, int c);
446 int uniscribe_text_extents (struct font *font, unsigned *code,
447 int nglyphs, struct font_metrics *metrics);
448 int uniscribe_draw (struct glyph_string *s, int from, int to,
449 int x, int y, int with_background);
452 int uniscribe_prepare_face (FRAME_PTR f, struct face *face);
453 void uniscribe_done_face (FRAME_PTR f, struct face *face);
454 int uniscribe_get_bitmap (struct font *font, unsigned code,
455 struct font_bitmap *bitmap, int bits_per_pixel);
456 void uniscribe_free_bitmap (struct font *font, struct font_bitmap *bitmap);
457 void * uniscribe_get_outline (struct font *font, unsigned code);
458 void uniscribe_free_outline (struct font *font, void *outline);
459 int uniscribe_anchor_point (struct font *font, unsigned code,
460 int index, int *x, int *y);
461 int uniscribe_start_for_frame (FRAME_PTR f);
462 int uniscribe_end_for_frame (FRAME_PTR f);
467 /* Callback function for EnumFontFamiliesEx.
468 Adds the name of opentype fonts to a Lisp list (passed in as the
471 add_opentype_font_name_to_list (logical_font
, physical_font
, font_type
,
473 ENUMLOGFONTEX
*logical_font
;
474 NEWTEXTMETRICEX
*physical_font
;
478 Lisp_Object
* list
= (Lisp_Object
*) list_object
;
481 /* Skip vertical fonts (intended only for printing) */
482 if (logical_font
->elfLogFont
.lfFaceName
[0] == '@')
485 /* Skip non opentype fonts. Count old truetype fonts as opentype,
486 as some of them do contain GPOS and GSUB data that Uniscribe
488 if (!(physical_font
->ntmTm
.ntmFlags
& NTMFLAGS_OPENTYPE
)
489 && font_type
!= TRUETYPE_FONTTYPE
)
492 /* Skip fonts that have no unicode coverage. */
493 if (!physical_font
->ntmFontSig
.fsUsb
[3]
494 && !physical_font
->ntmFontSig
.fsUsb
[2]
495 && !physical_font
->ntmFontSig
.fsUsb
[1]
496 && !(physical_font
->ntmFontSig
.fsUsb
[0] & 0x3fffffff))
499 family
= font_intern_prop (logical_font
->elfLogFont
.lfFaceName
,
500 strlen (logical_font
->elfLogFont
.lfFaceName
), 1);
501 if (! memq_no_quit (family
, *list
))
502 *list
= Fcons (family
, *list
);
508 /* :otf property handling.
509 Since the necessary Uniscribe APIs for getting font tag information
510 are only available in Vista, we need to parse the font data directly
511 according to the OpenType Specification. */
513 /* Push into DWORD backwards to cope with endianness. */
514 #define OTF_TAG(STR) \
515 ((STR[3] << 24) | (STR[2] << 16) | (STR[1] << 8) | STR[0])
517 #define OTF_INT16_VAL(TABLE, OFFSET, PTR) \
519 BYTE temp, data[2]; \
520 if (GetFontData (context, TABLE, OFFSET, data, 2) != 2) \
521 goto font_table_error; \
522 temp = data[0], data[0] = data[1], data[1] = temp; \
523 memcpy (PTR, data, 2); \
526 /* Do not reverse the bytes, because we will compare with a OTF_TAG value
527 that has them reversed already. */
528 #define OTF_DWORDTAG_VAL(TABLE, OFFSET, PTR) \
530 if (GetFontData (context, TABLE, OFFSET, PTR, 4) != 4) \
531 goto font_table_error; \
534 #define OTF_TAG_VAL(TABLE, OFFSET, STR) \
536 if (GetFontData (context, TABLE, OFFSET, STR, 4) != 4) \
537 goto font_table_error; \
541 static char* NOTHING
= " ";
543 #define SNAME(VAL) SDATA (SYMBOL_NAME (VAL))
545 /* Check if font supports the otf script/language/features specified.
546 OTF_SPEC is in the format
547 (script lang [(gsub_feature ...)|nil] [(gpos_feature ...)]?) */
548 int uniscribe_check_otf (font
, otf_spec
)
550 Lisp_Object otf_spec
;
552 Lisp_Object script
, lang
, rest
;
553 Lisp_Object features
[2];
554 DWORD feature_tables
[2];
555 DWORD script_tag
, default_script
, lang_tag
= 0;
558 HFONT check_font
, old_font
;
563 /* Check the spec is in the right format. */
564 if (!CONSP (otf_spec
) || Flength (otf_spec
) < 3)
567 /* Break otf_spec into its components. */
568 script
= XCAR (otf_spec
);
569 rest
= XCDR (otf_spec
);
574 features
[0] = XCAR (rest
);
579 features
[1] = XCAR (rest
);
581 /* Set up tags we will use in the search. */
582 feature_tables
[0] = OTF_TAG ("GSUB");
583 feature_tables
[1] = OTF_TAG ("GPOS");
584 default_script
= OTF_TAG ("DFLT");
586 script_tag
= default_script
;
588 script_tag
= OTF_TAG (SNAME (script
));
590 lang_tag
= OTF_TAG (SNAME (lang
));
592 /* Set up graphics context so we can use the font. */
593 f
= XFRAME (selected_frame
);
594 context
= get_frame_dc (f
);
595 check_font
= CreateFontIndirect (font
);
596 old_font
= SelectObject (context
, check_font
);
598 /* Everything else is contained within otf_spec so should get
599 marked along with it. */
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
];
611 /* Skip if no features requested from this table. */
612 if (NILP (features
[i
]))
615 /* If features is not a cons, this font spec is messed up. */
616 if (!CONSP (features
[i
]))
619 /* Read GPOS/GSUB header. */
620 OTF_INT16_VAL (tbl
, 4, &scriptlist_table
);
621 OTF_INT16_VAL (tbl
, 6, &feature_table
);
622 OTF_INT16_VAL (tbl
, scriptlist_table
, &n_scripts
);
624 /* Find the appropriate script table. */
626 for (j
= 0; j
< n_scripts
; j
++)
629 OTF_DWORDTAG_VAL (tbl
, scriptlist_table
+ 2 + j
* 6, &script_id
);
630 if (script_id
== script_tag
)
632 OTF_INT16_VAL (tbl
, scriptlist_table
+ 6 + j
* 6, &script_table
);
635 /* If there is a DFLT script defined in the font, use it
636 if the specified script is not found. */
637 else if (script_id
== default_script
)
638 OTF_INT16_VAL (tbl
, scriptlist_table
+ 6 + j
* 6, &script_table
);
640 /* If no specific or default script table was found, then this font
641 does not support the script. */
645 /* Offset is from beginning of scriptlist_table. */
646 script_table
+= scriptlist_table
;
648 /* Get default langsys table. */
649 OTF_INT16_VAL (tbl
, script_table
, &langsys_table
);
651 /* If lang was specified, see if font contains a specific entry. */
654 OTF_INT16_VAL (tbl
, script_table
+ 2, &n_langs
);
656 for (j
= 0; j
< n_langs
; j
++)
659 OTF_DWORDTAG_VAL (tbl
, script_table
+ 4 + j
* 6, &lang_id
);
660 if (lang_id
== lang_tag
)
662 OTF_INT16_VAL (tbl
, script_table
+ 8 + j
* 6, &langsys_table
);
671 /* Offset is from beginning of script table. */
672 langsys_table
+= script_table
;
674 /* Check the features. Features may contain nil according to
675 documentation in font_prop_validate_otf, so count them. */
676 n_match_features
= 0;
677 for (rest
= features
[i
]; CONSP (rest
); rest
= XCDR (rest
))
679 Lisp_Object feature
= XCAR (rest
);
684 /* If there are no features to check, skip checking. */
685 if (!n_match_features
)
688 /* First check required feature (if any). */
689 OTF_INT16_VAL (tbl
, langsys_table
+ 2, &feature_index
);
690 if (feature_index
!= 0xFFFF)
693 OTF_TAG_VAL (tbl
, feature_table
+ 2 + feature_index
* 6, feature_id
);
694 OTF_TAG_VAL (tbl
, feature_table
+ 2 + feature_index
* 6, feature_id
);
695 /* Assume no duplicates in the font table. This allows us to mark
696 the features off by simply decrementing a counter. */
697 if (!NILP (Fmemq (intern (feature_id
), features
[i
])))
700 /* Now check all the other features. */
701 OTF_INT16_VAL (tbl
, langsys_table
+ 4, &n_features
);
702 for (j
= 0; j
< n_features
; j
++)
705 OTF_INT16_VAL (tbl
, langsys_table
+ 6 + j
* 2, &feature_index
);
706 OTF_TAG_VAL (tbl
, feature_table
+ 2 + feature_index
* 6, feature_id
);
707 /* Assume no duplicates in the font table. This allows us to mark
708 the features off by simply decrementing a counter. */
709 if (!NILP (Fmemq (intern (feature_id
), features
[i
])))
713 if (n_match_features
> 0)
721 /* restore graphics context. */
722 SelectObject (context
, old_font
);
723 DeleteObject (check_font
);
724 release_frame_dc (f
, context
);
730 otf_features (HDC context
, char *table
)
732 Lisp_Object script_list
= Qnil
;
733 unsigned short scriptlist_table
, n_scripts
, feature_table
;
734 DWORD tbl
= OTF_TAG (table
);
737 /* Look for scripts in the table. */
738 OTF_INT16_VAL (tbl
, 4, &scriptlist_table
);
739 OTF_INT16_VAL (tbl
, 6, &feature_table
);
740 OTF_INT16_VAL (tbl
, scriptlist_table
, &n_scripts
);
742 for (i
= 0; i
< n_scripts
; i
++)
744 char script
[5], lang
[5];
745 unsigned short script_table
, lang_count
, langsys_table
, feature_count
;
746 Lisp_Object script_tag
, langsys_list
, langsys_tag
, feature_list
;
747 unsigned short record_offset
= scriptlist_table
+ 2 + i
* 6;
748 OTF_TAG_VAL (tbl
, record_offset
, script
);
749 OTF_INT16_VAL (tbl
, record_offset
+ 4, &script_table
);
751 /* Offset is from beginning of script table. */
752 script_table
+= scriptlist_table
;
754 script_tag
= intern (script
);
757 /* Optional default lang. */
758 OTF_INT16_VAL (tbl
, script_table
, &langsys_table
);
761 /* Offset is from beginning of script table. */
762 langsys_table
+= script_table
;
766 OTF_INT16_VAL (tbl
, langsys_table
+ 4, &feature_count
);
767 for (k
= 0; k
< feature_count
; k
++)
770 unsigned short index
;
771 OTF_INT16_VAL (tbl
, langsys_table
+ 6 + k
* 2, &index
);
772 OTF_TAG_VAL (tbl
, feature_table
+ 2 + index
* 6, feature
);
773 feature_list
= Fcons (intern (feature
), feature_list
);
775 langsys_list
= Fcons (Fcons (langsys_tag
, feature_list
),
779 /* List of supported languages. */
780 OTF_INT16_VAL (tbl
, script_table
+ 2, &lang_count
);
782 for (j
= 0; j
< lang_count
; j
++)
784 record_offset
= script_table
+ 4 + j
* 6;
785 OTF_TAG_VAL (tbl
, record_offset
, lang
);
786 OTF_INT16_VAL (tbl
, record_offset
+ 4, &langsys_table
);
788 /* Offset is from beginning of script table. */
789 langsys_table
+= script_table
;
791 langsys_tag
= intern (lang
);
793 OTF_INT16_VAL (tbl
, langsys_table
+ 4, &feature_count
);
794 for (k
= 0; k
< feature_count
; k
++)
797 unsigned short index
;
798 OTF_INT16_VAL (tbl
, langsys_table
+ 6 + k
* 2, &index
);
799 OTF_TAG_VAL (tbl
, feature_table
+ 2 + index
* 6, feature
);
800 feature_list
= Fcons (intern (feature
), feature_list
);
802 langsys_list
= Fcons (Fcons (langsys_tag
, feature_list
),
807 script_list
= Fcons (Fcons (script_tag
, langsys_list
), script_list
);
821 struct font_driver uniscribe_font_driver
=
824 0, /* case insensitive */
828 uniscribe_list_family
,
829 NULL
, /* free_entity */
832 NULL
, /* prepare_face */
833 NULL
, /* done_face */
835 uniscribe_encode_char
,
836 w32font_text_extents
,
838 NULL
, /* get_bitmap */
839 NULL
, /* free_bitmap */
840 NULL
, /* get_outline */
841 NULL
, /* free_outline */
842 NULL
, /* anchor_point */
843 uniscribe_otf_capability
, /* Defined so (font-get FONTOBJ :otf) works. */
844 NULL
, /* otf_drive - use shape instead. */
845 NULL
, /* start_for_frame */
846 NULL
, /* end_for_frame */
850 /* Note that this should be called at every startup, not just when dumping,
851 as it needs to test for the existence of the Uniscribe library. */
853 syms_of_w32uniscribe ()
857 /* Don't init uniscribe when dumping */
861 /* Don't register if uniscribe is not available. */
862 uniscribe
= GetModuleHandle ("usp10");
866 uniscribe_font_driver
.type
= Quniscribe
;
867 uniscribe_available
= 1;
869 register_font_driver (&uniscribe_font_driver
, NULL
);
872 /* arch-tag: 9530f0e1-7471-47dd-a780-94330af87ea0
873 (do not change this comment) */