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 font_entity
, pixel_size
);
125 struct uniscribe_font_info
*uniscribe_font
126 = (struct uniscribe_font_info
*) XFONT_OBJECT (font_object
);
128 ASET (font_object
, FONT_TYPE_INDEX
, Quniscribe
);
130 if (!w32font_open_internal (f
, font_entity
, pixel_size
, font_object
))
135 /* Initialize the cache for this font. */
136 uniscribe_font
->cache
= NULL
;
138 /* Uniscribe backend uses glyph indices. */
139 uniscribe_font
->w32_font
.glyph_idx
= ETO_GLYPH_INDEX
;
141 /* Mark the format as opentype */
142 uniscribe_font
->w32_font
.font
.props
[FONT_FORMAT_INDEX
] = Qopentype
;
143 uniscribe_font
->w32_font
.font
.driver
= &uniscribe_font_driver
;
149 uniscribe_close (f
, font
)
153 struct uniscribe_font_info
*uniscribe_font
154 = (struct uniscribe_font_info
*) font
;
156 if (uniscribe_font
->cache
)
157 ScriptFreeCache (&(uniscribe_font
->cache
));
159 w32font_close (f
, font
);
162 /* Return a list describing which scripts/languages FONT supports by
163 which GSUB/GPOS features of OpenType tables. */
165 uniscribe_otf_capability (font
)
171 Lisp_Object capability
= Fcons (Qnil
, Qnil
);
172 Lisp_Object features
;
174 f
= XFRAME (selected_frame
);
175 context
= get_frame_dc (f
);
176 old_font
= SelectObject (context
, FONT_HANDLE(font
));
178 features
= otf_features (context
, "GSUB");
179 XSETCAR (capability
, features
);
180 features
= otf_features (context
, "GPOS");
181 XSETCDR (capability
, features
);
183 SelectObject (context
, old_font
);
184 release_frame_dc (f
, context
);
189 /* Uniscribe implementation of shape for font backend.
191 Shape text in LGSTRING. See the docstring of `font-make-gstring'
192 for the format of LGSTRING. If the (N+1)th element of LGSTRING
193 is nil, input of shaping is from the 1st to (N)th elements. In
194 each input glyph, FROM, TO, CHAR, and CODE are already set.
196 This function updates all fields of the input glyphs. If the
197 output glyphs (M) are more than the input glyphs (N), (N+1)th
198 through (M)th elements of LGSTRING are updated possibly by making
199 a new glyph object and storing it in LGSTRING. If (M) is greater
200 than the length of LGSTRING, nil should be return. In that case,
201 this function is called again with the larger LGSTRING. */
203 uniscribe_shape (lgstring
)
204 Lisp_Object lgstring
;
207 struct uniscribe_font_info
* uniscribe_font
;
209 int nitems
, max_items
, i
, max_glyphs
, done_glyphs
;
211 WORD
*glyphs
, *clusters
;
213 SCRIPT_VISATTR
*attributes
;
218 struct frame
* f
= NULL
;
220 HFONT old_font
= NULL
;
222 CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring
), font
);
223 uniscribe_font
= (struct uniscribe_font_info
*) font
;
225 /* Get the chars from lgstring in a form we can use with uniscribe. */
226 max_glyphs
= nchars
= LGSTRING_LENGTH (lgstring
);
228 chars
= (wchar_t *) alloca (nchars
* sizeof (wchar_t));
229 for (i
= 0; i
< nchars
; i
++)
231 /* lgstring can be bigger than the number of characters in it, in
232 the case where more glyphs are required to display those characters.
233 If that is the case, note the real number of characters. */
234 if (NILP (LGSTRING_GLYPH (lgstring
, i
)))
237 chars
[i
] = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring
, i
));
240 /* First we need to break up the glyph string into runs of glyphs that
241 can be treated together. First try a single run. */
243 items
= (SCRIPT_ITEM
*) xmalloc (sizeof (SCRIPT_ITEM
) * max_items
+ 1);
245 while ((result
= ScriptItemize (chars
, nchars
, max_items
, NULL
, NULL
,
246 items
, &nitems
)) == E_OUTOFMEMORY
)
248 /* If that wasn't enough, keep trying with one more run. */
250 items
= (SCRIPT_ITEM
*) xrealloc (items
,
251 sizeof (SCRIPT_ITEM
) * max_items
+ 1);
260 /* TODO: When we get BIDI support, we need to call ScriptLayout here.
261 Requires that we know the surrounding context. */
263 glyphs
= alloca (max_glyphs
* sizeof (WORD
));
264 clusters
= alloca (nchars
* sizeof (WORD
));
265 attributes
= alloca (max_glyphs
* sizeof (SCRIPT_VISATTR
));
266 advances
= alloca (max_glyphs
* sizeof (int));
267 offsets
= alloca (max_glyphs
* sizeof (GOFFSET
));
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 /* Context may be NULL here, in which case the cache should be
275 used without needing to select the font. */
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
);
281 if (result
== E_PENDING
&& !context
)
283 /* This assumes the selected frame is on the same display as the
284 one we are drawing. It would be better for the frame to be
286 f
= XFRAME (selected_frame
);
287 context
= get_frame_dc (f
);
288 old_font
= SelectObject (context
, FONT_HANDLE(font
));
290 result
= ScriptShape (context
, &(uniscribe_font
->cache
),
291 chars
+ items
[i
].iCharPos
, nchars_in_run
,
292 max_glyphs
- done_glyphs
, &(items
[i
].a
),
293 glyphs
, clusters
, attributes
, &nglyphs
);
296 if (result
== E_OUTOFMEMORY
)
298 /* Need a bigger lgstring. */
302 else if (FAILED (result
))
304 /* Can't shape this run - return results so far if any. */
307 else if (items
[i
].a
.fNoGlyphIndex
)
309 /* Glyph indices not supported by this font (or OS), means we
310 can't really do any meaningful shaping. */
315 result
= ScriptPlace (context
, &(uniscribe_font
->cache
),
316 glyphs
, nglyphs
, attributes
, &(items
[i
].a
),
317 advances
, offsets
, &overall_metrics
);
318 if (result
== E_PENDING
&& !context
)
320 /* Cache not complete... */
321 f
= XFRAME (selected_frame
);
322 context
= get_frame_dc (f
);
323 old_font
= SelectObject (context
, FONT_HANDLE(font
));
325 result
= ScriptPlace (context
, &(uniscribe_font
->cache
),
326 glyphs
, nglyphs
, attributes
, &(items
[i
].a
),
327 advances
, offsets
, &overall_metrics
);
329 if (SUCCEEDED (result
))
331 int j
, nclusters
, from
, to
;
333 from
= rtl
> 0 ? 0 : nchars_in_run
- 1;
336 for (j
= 0; j
< nglyphs
; j
++)
338 int lglyph_index
= j
+ done_glyphs
;
339 Lisp_Object lglyph
= LGSTRING_GLYPH (lgstring
, lglyph_index
);
344 lglyph
= Fmake_vector (make_number (LGLYPH_SIZE
), Qnil
);
345 LGSTRING_SET_GLYPH (lgstring
, lglyph_index
, lglyph
);
347 LGLYPH_SET_CODE (lglyph
, glyphs
[j
]);
349 /* Detect clusters, for linking codes back to characters. */
350 if (attributes
[j
].fClusterStart
)
352 while (from
>= 0 && from
< nchars_in_run
353 && clusters
[from
] < j
)
357 else if (from
>= nchars_in_run
)
358 from
= to
= nchars_in_run
- 1;
362 to
= rtl
> 0 ? nchars_in_run
- 1 : 0;
363 for (k
= from
+ rtl
; k
>= 0 && k
< nchars_in_run
;
375 LGLYPH_SET_CHAR (lglyph
, chars
[items
[i
].iCharPos
377 LGLYPH_SET_FROM (lglyph
, items
[i
].iCharPos
+ from
);
378 LGLYPH_SET_TO (lglyph
, items
[i
].iCharPos
+ to
);
381 LGLYPH_SET_WIDTH (lglyph
, advances
[j
]);
382 LGLYPH_SET_ASCENT (lglyph
, font
->ascent
);
383 LGLYPH_SET_DESCENT (lglyph
, font
->descent
);
385 result
= ScriptGetGlyphABCWidth (context
,
386 &(uniscribe_font
->cache
),
387 glyphs
[j
], &char_metric
);
388 if (result
== E_PENDING
&& !context
)
390 /* Cache incomplete... */
391 f
= XFRAME (selected_frame
);
392 context
= get_frame_dc (f
);
393 old_font
= SelectObject (context
, FONT_HANDLE(font
));
394 result
= ScriptGetGlyphABCWidth (context
,
395 &(uniscribe_font
->cache
),
396 glyphs
[j
], &char_metric
);
399 if (SUCCEEDED (result
))
401 LGLYPH_SET_LBEARING (lglyph
, char_metric
.abcA
);
402 LGLYPH_SET_RBEARING (lglyph
, (char_metric
.abcA
403 + char_metric
.abcB
));
407 LGLYPH_SET_LBEARING (lglyph
, 0);
408 LGLYPH_SET_RBEARING (lglyph
, advances
[j
]);
411 if (offsets
[j
].du
|| offsets
[j
].dv
)
414 vec
= Fmake_vector (make_number (3), Qnil
);
415 ASET (vec
, 0, make_number (offsets
[j
].du
));
416 ASET (vec
, 1, make_number (offsets
[j
].dv
));
417 /* Based on what ftfont.c does... */
418 ASET (vec
, 2, make_number (advances
[j
]));
419 LGLYPH_SET_ADJUSTMENT (lglyph
, vec
);
422 LGLYPH_SET_ADJUSTMENT (lglyph
, Qnil
);
426 done_glyphs
+= nglyphs
;
433 SelectObject (context
, old_font
);
434 release_frame_dc (f
, context
);
440 return make_number (done_glyphs
);
443 /* Uniscribe implementation of encode_char for font backend.
444 Return a glyph code of FONT for characer C (Unicode code point).
445 If FONT doesn't have such a glyph, return FONT_INVALID_CODE. */
447 uniscribe_encode_char (font
, c
)
452 struct frame
*f
= NULL
;
453 HFONT old_font
= NULL
;
454 unsigned code
= FONT_INVALID_CODE
;
459 struct uniscribe_font_info
*uniscribe_font
460 = (struct uniscribe_font_info
*)font
;
469 DWORD surrogate
= c
- 0x10000;
471 /* High surrogate: U+D800 - U+DBFF. */
472 ch
[0] = 0xD800 + ((surrogate
>> 10) & 0x03FF);
473 /* Low surrogate: U+DC00 - U+DFFF. */
474 ch
[1] = 0xDC00 + (surrogate
& 0x03FF);
478 /* Non BMP characters must be handled by the uniscribe shaping
479 engine as GDI functions (except blindly displaying lines of
480 unicode text) and the promising looking ScriptGetCMap do not
481 convert surrogate pairs to glyph indexes correctly. */
483 items
= (SCRIPT_ITEM
*) alloca (sizeof (SCRIPT_ITEM
) * 2 + 1);
484 if (SUCCEEDED (ScriptItemize (ch
, len
, 2, NULL
, NULL
, items
, &nitems
)))
487 /* Some Indic characters result in more than 1 glyph. */
488 WORD glyphs
[1], clusters
[1];
489 SCRIPT_VISATTR attrs
[1];
492 result
= ScriptShape (context
, &(uniscribe_font
->cache
),
493 ch
, len
, 1, &(items
[0].a
),
494 glyphs
, clusters
, attrs
, &nglyphs
);
496 if (result
== E_PENDING
)
498 /* Use selected frame until API is updated to pass
500 f
= XFRAME (selected_frame
);
501 context
= get_frame_dc (f
);
502 old_font
= SelectObject (context
, FONT_HANDLE(font
));
503 result
= ScriptShape (context
, &(uniscribe_font
->cache
),
504 ch
, len
, 2, &(items
[0].a
),
505 glyphs
, clusters
, attrs
, &nglyphs
);
508 if (SUCCEEDED (result
) && nglyphs
== 1)
512 else if (SUCCEEDED (result
) || result
== E_OUTOFMEMORY
)
514 /* This character produces zero or more than one glyph
515 when shaped. But we still need the return from here
516 to be valid for the shaping engine to be invoked
518 result
= ScriptGetCMap (context
, &(uniscribe_font
->cache
),
520 if (SUCCEEDED (result
))
523 return 0; /* notdef - enough in some cases to get the script
524 engine working, but not others... */
530 SelectObject (context
, old_font
);
531 release_frame_dc (f
, context
);
539 Lisp_Object uniscribe_get_cache (Lisp_Object frame);
540 void uniscribe_free_entity (Lisp_Object font_entity);
541 int uniscribe_has_char (Lisp_Object entity, int c);
542 int uniscribe_text_extents (struct font *font, unsigned *code,
543 int nglyphs, struct font_metrics *metrics);
544 int uniscribe_draw (struct glyph_string *s, int from, int to,
545 int x, int y, int with_background);
548 int uniscribe_prepare_face (FRAME_PTR f, struct face *face);
549 void uniscribe_done_face (FRAME_PTR f, struct face *face);
550 int uniscribe_get_bitmap (struct font *font, unsigned code,
551 struct font_bitmap *bitmap, int bits_per_pixel);
552 void uniscribe_free_bitmap (struct font *font, struct font_bitmap *bitmap);
553 void * uniscribe_get_outline (struct font *font, unsigned code);
554 void uniscribe_free_outline (struct font *font, void *outline);
555 int uniscribe_anchor_point (struct font *font, unsigned code,
556 int index, int *x, int *y);
557 int uniscribe_start_for_frame (FRAME_PTR f);
558 int uniscribe_end_for_frame (FRAME_PTR f);
563 /* Callback function for EnumFontFamiliesEx.
564 Adds the name of opentype fonts to a Lisp list (passed in as the
567 add_opentype_font_name_to_list (logical_font
, physical_font
, font_type
,
569 ENUMLOGFONTEX
*logical_font
;
570 NEWTEXTMETRICEX
*physical_font
;
574 Lisp_Object
* list
= (Lisp_Object
*) list_object
;
577 /* Skip vertical fonts (intended only for printing) */
578 if (logical_font
->elfLogFont
.lfFaceName
[0] == '@')
581 /* Skip non opentype fonts. Count old truetype fonts as opentype,
582 as some of them do contain GPOS and GSUB data that Uniscribe
584 if (!(physical_font
->ntmTm
.ntmFlags
& NTMFLAGS_OPENTYPE
)
585 && font_type
!= TRUETYPE_FONTTYPE
)
588 /* Skip fonts that have no unicode coverage. */
589 if (!physical_font
->ntmFontSig
.fsUsb
[3]
590 && !physical_font
->ntmFontSig
.fsUsb
[2]
591 && !physical_font
->ntmFontSig
.fsUsb
[1]
592 && !(physical_font
->ntmFontSig
.fsUsb
[0] & 0x3fffffff))
595 family
= font_intern_prop (logical_font
->elfLogFont
.lfFaceName
,
596 strlen (logical_font
->elfLogFont
.lfFaceName
), 1);
597 if (! memq_no_quit (family
, *list
))
598 *list
= Fcons (family
, *list
);
604 /* :otf property handling.
605 Since the necessary Uniscribe APIs for getting font tag information
606 are only available in Vista, we need to parse the font data directly
607 according to the OpenType Specification. */
609 /* Push into DWORD backwards to cope with endianness. */
610 #define OTF_TAG(STR) \
611 ((STR[3] << 24) | (STR[2] << 16) | (STR[1] << 8) | STR[0])
613 #define OTF_INT16_VAL(TABLE, OFFSET, PTR) \
615 BYTE temp, data[2]; \
616 if (GetFontData (context, TABLE, OFFSET, data, 2) != 2) \
617 goto font_table_error; \
618 temp = data[0], data[0] = data[1], data[1] = temp; \
619 memcpy (PTR, data, 2); \
622 /* Do not reverse the bytes, because we will compare with a OTF_TAG value
623 that has them reversed already. */
624 #define OTF_DWORDTAG_VAL(TABLE, OFFSET, PTR) \
626 if (GetFontData (context, TABLE, OFFSET, PTR, 4) != 4) \
627 goto font_table_error; \
630 #define OTF_TAG_VAL(TABLE, OFFSET, STR) \
632 if (GetFontData (context, TABLE, OFFSET, STR, 4) != 4) \
633 goto font_table_error; \
637 static char* NOTHING
= " ";
639 #define SNAME(VAL) SDATA (SYMBOL_NAME (VAL))
641 /* Check if font supports the otf script/language/features specified.
642 OTF_SPEC is in the format
643 (script lang [(gsub_feature ...)|nil] [(gpos_feature ...)]?) */
644 int uniscribe_check_otf (font
, otf_spec
)
646 Lisp_Object otf_spec
;
648 Lisp_Object script
, lang
, rest
;
649 Lisp_Object features
[2];
650 DWORD feature_tables
[2];
651 DWORD script_tag
, default_script
, lang_tag
= 0;
654 HFONT check_font
, old_font
;
659 /* Check the spec is in the right format. */
660 if (!CONSP (otf_spec
) || Flength (otf_spec
) < 3)
663 /* Break otf_spec into its components. */
664 script
= XCAR (otf_spec
);
665 rest
= XCDR (otf_spec
);
670 features
[0] = XCAR (rest
);
675 features
[1] = XCAR (rest
);
677 /* Set up tags we will use in the search. */
678 feature_tables
[0] = OTF_TAG ("GSUB");
679 feature_tables
[1] = OTF_TAG ("GPOS");
680 default_script
= OTF_TAG ("DFLT");
682 script_tag
= default_script
;
684 script_tag
= OTF_TAG (SNAME (script
));
686 lang_tag
= OTF_TAG (SNAME (lang
));
688 /* Set up graphics context so we can use the font. */
689 f
= XFRAME (selected_frame
);
690 context
= get_frame_dc (f
);
691 check_font
= CreateFontIndirect (font
);
692 old_font
= SelectObject (context
, check_font
);
694 /* Everything else is contained within otf_spec so should get
695 marked along with it. */
698 /* Scan GSUB and GPOS tables. */
699 for (i
= 0; i
< 2; i
++)
701 int j
, n_match_features
;
702 unsigned short scriptlist_table
, feature_table
, n_scripts
;
703 unsigned short script_table
, langsys_table
, n_langs
;
704 unsigned short feature_index
, n_features
;
705 DWORD tbl
= feature_tables
[i
];
707 /* Skip if no features requested from this table. */
708 if (NILP (features
[i
]))
711 /* If features is not a cons, this font spec is messed up. */
712 if (!CONSP (features
[i
]))
715 /* Read GPOS/GSUB header. */
716 OTF_INT16_VAL (tbl
, 4, &scriptlist_table
);
717 OTF_INT16_VAL (tbl
, 6, &feature_table
);
718 OTF_INT16_VAL (tbl
, scriptlist_table
, &n_scripts
);
720 /* Find the appropriate script table. */
722 for (j
= 0; j
< n_scripts
; j
++)
725 OTF_DWORDTAG_VAL (tbl
, scriptlist_table
+ 2 + j
* 6, &script_id
);
726 if (script_id
== script_tag
)
728 OTF_INT16_VAL (tbl
, scriptlist_table
+ 6 + j
* 6, &script_table
);
731 /* If there is a DFLT script defined in the font, use it
732 if the specified script is not found. */
733 else if (script_id
== default_script
)
734 OTF_INT16_VAL (tbl
, scriptlist_table
+ 6 + j
* 6, &script_table
);
736 /* If no specific or default script table was found, then this font
737 does not support the script. */
741 /* Offset is from beginning of scriptlist_table. */
742 script_table
+= scriptlist_table
;
744 /* Get default langsys table. */
745 OTF_INT16_VAL (tbl
, script_table
, &langsys_table
);
747 /* If lang was specified, see if font contains a specific entry. */
750 OTF_INT16_VAL (tbl
, script_table
+ 2, &n_langs
);
752 for (j
= 0; j
< n_langs
; j
++)
755 OTF_DWORDTAG_VAL (tbl
, script_table
+ 4 + j
* 6, &lang_id
);
756 if (lang_id
== lang_tag
)
758 OTF_INT16_VAL (tbl
, script_table
+ 8 + j
* 6, &langsys_table
);
767 /* Offset is from beginning of script table. */
768 langsys_table
+= script_table
;
770 /* Check the features. Features may contain nil according to
771 documentation in font_prop_validate_otf, so count them. */
772 n_match_features
= 0;
773 for (rest
= features
[i
]; CONSP (rest
); rest
= XCDR (rest
))
775 Lisp_Object feature
= XCAR (rest
);
780 /* If there are no features to check, skip checking. */
781 if (!n_match_features
)
784 /* First check required feature (if any). */
785 OTF_INT16_VAL (tbl
, langsys_table
+ 2, &feature_index
);
786 if (feature_index
!= 0xFFFF)
789 OTF_TAG_VAL (tbl
, feature_table
+ 2 + feature_index
* 6, feature_id
);
790 OTF_TAG_VAL (tbl
, feature_table
+ 2 + feature_index
* 6, feature_id
);
791 /* Assume no duplicates in the font table. This allows us to mark
792 the features off by simply decrementing a counter. */
793 if (!NILP (Fmemq (intern (feature_id
), features
[i
])))
796 /* Now check all the other features. */
797 OTF_INT16_VAL (tbl
, langsys_table
+ 4, &n_features
);
798 for (j
= 0; j
< n_features
; j
++)
801 OTF_INT16_VAL (tbl
, langsys_table
+ 6 + j
* 2, &feature_index
);
802 OTF_TAG_VAL (tbl
, feature_table
+ 2 + feature_index
* 6, feature_id
);
803 /* Assume no duplicates in the font table. This allows us to mark
804 the features off by simply decrementing a counter. */
805 if (!NILP (Fmemq (intern (feature_id
), features
[i
])))
809 if (n_match_features
> 0)
817 /* restore graphics context. */
818 SelectObject (context
, old_font
);
819 DeleteObject (check_font
);
820 release_frame_dc (f
, context
);
826 otf_features (HDC context
, char *table
)
828 Lisp_Object script_list
= Qnil
;
829 unsigned short scriptlist_table
, n_scripts
, feature_table
;
830 DWORD tbl
= OTF_TAG (table
);
833 /* Look for scripts in the table. */
834 OTF_INT16_VAL (tbl
, 4, &scriptlist_table
);
835 OTF_INT16_VAL (tbl
, 6, &feature_table
);
836 OTF_INT16_VAL (tbl
, scriptlist_table
, &n_scripts
);
838 for (i
= 0; i
< n_scripts
; i
++)
840 char script
[5], lang
[5];
841 unsigned short script_table
, lang_count
, langsys_table
, feature_count
;
842 Lisp_Object script_tag
, langsys_list
, langsys_tag
, feature_list
;
843 unsigned short record_offset
= scriptlist_table
+ 2 + i
* 6;
844 OTF_TAG_VAL (tbl
, record_offset
, script
);
845 OTF_INT16_VAL (tbl
, record_offset
+ 4, &script_table
);
847 /* Offset is from beginning of script table. */
848 script_table
+= scriptlist_table
;
850 script_tag
= intern (script
);
853 /* Optional default lang. */
854 OTF_INT16_VAL (tbl
, script_table
, &langsys_table
);
857 /* Offset is from beginning of script table. */
858 langsys_table
+= script_table
;
862 OTF_INT16_VAL (tbl
, langsys_table
+ 4, &feature_count
);
863 for (k
= 0; k
< feature_count
; k
++)
866 unsigned short index
;
867 OTF_INT16_VAL (tbl
, langsys_table
+ 6 + k
* 2, &index
);
868 OTF_TAG_VAL (tbl
, feature_table
+ 2 + index
* 6, feature
);
869 feature_list
= Fcons (intern (feature
), feature_list
);
871 langsys_list
= Fcons (Fcons (langsys_tag
, feature_list
),
875 /* List of supported languages. */
876 OTF_INT16_VAL (tbl
, script_table
+ 2, &lang_count
);
878 for (j
= 0; j
< lang_count
; j
++)
880 record_offset
= script_table
+ 4 + j
* 6;
881 OTF_TAG_VAL (tbl
, record_offset
, lang
);
882 OTF_INT16_VAL (tbl
, record_offset
+ 4, &langsys_table
);
884 /* Offset is from beginning of script table. */
885 langsys_table
+= script_table
;
887 langsys_tag
= intern (lang
);
889 OTF_INT16_VAL (tbl
, langsys_table
+ 4, &feature_count
);
890 for (k
= 0; k
< feature_count
; k
++)
893 unsigned short index
;
894 OTF_INT16_VAL (tbl
, langsys_table
+ 6 + k
* 2, &index
);
895 OTF_TAG_VAL (tbl
, feature_table
+ 2 + index
* 6, feature
);
896 feature_list
= Fcons (intern (feature
), feature_list
);
898 langsys_list
= Fcons (Fcons (langsys_tag
, feature_list
),
903 script_list
= Fcons (Fcons (script_tag
, langsys_list
), script_list
);
917 struct font_driver uniscribe_font_driver
=
920 0, /* case insensitive */
924 uniscribe_list_family
,
925 NULL
, /* free_entity */
928 NULL
, /* prepare_face */
929 NULL
, /* done_face */
931 uniscribe_encode_char
,
932 w32font_text_extents
,
934 NULL
, /* get_bitmap */
935 NULL
, /* free_bitmap */
936 NULL
, /* get_outline */
937 NULL
, /* free_outline */
938 NULL
, /* anchor_point */
939 uniscribe_otf_capability
, /* Defined so (font-get FONTOBJ :otf) works. */
940 NULL
, /* otf_drive - use shape instead. */
941 NULL
, /* start_for_frame */
942 NULL
, /* end_for_frame */
946 /* Note that this should be called at every startup, not just when dumping,
947 as it needs to test for the existence of the Uniscribe library. */
949 syms_of_w32uniscribe ()
953 /* Don't init uniscribe when dumping */
957 /* Don't register if uniscribe is not available. */
958 uniscribe
= GetModuleHandle ("usp10");
962 uniscribe_font_driver
.type
= Quniscribe
;
963 uniscribe_available
= 1;
965 register_font_driver (&uniscribe_font_driver
, NULL
);
968 /* arch-tag: 9530f0e1-7471-47dd-a780-94330af87ea0
969 (do not change this comment) */