(clean mostlyclean): Delete leim-list.el~.
[bpt/emacs.git] / src / w32font.c
CommitLineData
f7a84cb4 1/* Font backend for the Microsoft W32 API.
7e14d905 2 Copyright (C) 2007, 2008 Free Software Foundation, Inc.
f7a84cb4
JR
3
4This file is part of GNU Emacs.
5
9ec0b715 6GNU Emacs is free software: you can redistribute it and/or modify
f7a84cb4 7it under the terms of the GNU General Public License as published by
9ec0b715
GM
8the Free Software Foundation, either version 3 of the License, or
9(at your option) any later version.
f7a84cb4
JR
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
9ec0b715 17along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
f7a84cb4
JR
18
19#include <config.h>
20#include <windows.h>
09fe06b7 21#include <math.h>
0500dcc9 22#include <ctype.h>
6fe9826d 23#include <commdlg.h>
f7a84cb4
JR
24
25#include "lisp.h"
26#include "w32term.h"
27#include "frame.h"
28#include "dispextern.h"
29#include "character.h"
30#include "charset.h"
31#include "fontset.h"
32#include "font.h"
46fd1ded 33#include "w32font.h"
f7a84cb4 34
91583281
JR
35/* Cleartype available on Windows XP, cleartype_natural from XP SP1.
36 The latter does not try to fit cleartype smoothed fonts into the
37 same bounding box as the non-antialiased version of the font.
38 */
39#ifndef CLEARTYPE_QUALITY
40#define CLEARTYPE_QUALITY 5
41#endif
42#ifndef CLEARTYPE_NATURAL_QUALITY
43#define CLEARTYPE_NATURAL_QUALITY 6
44#endif
45
f7a84cb4
JR
46extern struct font_driver w32font_driver;
47
91583281 48Lisp_Object Qgdi;
34fd2d28
JR
49Lisp_Object Quniscribe;
50static Lisp_Object QCformat;
9e1a2995
JR
51static Lisp_Object Qmonospace, Qsansserif, Qmono, Qsans, Qsans_serif;
52static Lisp_Object Qserif, Qscript, Qdecorative;
53static Lisp_Object Qraster, Qoutline, Qunknown;
d205d43b 54
91583281 55/* antialiasing */
5f18d119 56extern Lisp_Object QCantialias, QCotf, QClang; /* defined in font.c */
91583281
JR
57extern Lisp_Object Qnone; /* reuse from w32fns.c */
58static Lisp_Object Qstandard, Qsubpixel, Qnatural;
59
8f112d52
JR
60/* languages */
61static Lisp_Object Qja, Qko, Qzh;
62
d205d43b
JR
63/* scripts */
64static Lisp_Object Qlatin, Qgreek, Qcoptic, Qcyrillic, Qarmenian, Qhebrew;
65static Lisp_Object Qarabic, Qsyriac, Qnko, Qthaana, Qdevanagari, Qbengali;
66static Lisp_Object Qgurmukhi, Qgujarati, Qoriya, Qtamil, Qtelugu;
67static Lisp_Object Qkannada, Qmalayalam, Qsinhala, Qthai, Qlao;
68static Lisp_Object Qtibetan, Qmyanmar, Qgeorgian, Qhangul, Qethiopic;
69static Lisp_Object Qcherokee, Qcanadian_aboriginal, Qogham, Qrunic;
70static Lisp_Object Qkhmer, Qmongolian, Qsymbol, Qbraille, Qhan;
71static Lisp_Object Qideographic_description, Qcjk_misc, Qkana, Qbopomofo;
72static Lisp_Object Qkanbun, Qyi, Qbyzantine_musical_symbol;
73static Lisp_Object Qmusical_symbol, Qmathematical;
56df6710
JR
74/* Not defined in characters.el, but referenced in fontset.el. */
75static Lisp_Object Qbalinese, Qbuginese, Qbuhid, Qcuneiform, Qcypriot;
76static Lisp_Object Qdeseret, Qglagolitic, Qgothic, Qhanunoo, Qkharoshthi;
77static Lisp_Object Qlimbu, Qlinear_b, Qold_italic, Qold_persian, Qosmanya;
78static Lisp_Object Qphags_pa, Qphoenician, Qshavian, Qsyloti_nagri;
79static Lisp_Object Qtagalog, Qtagbanwa, Qtai_le, Qtifinagh, Qugaritic;
80/* Only defined here, but useful for distinguishing IPA capable fonts. */
81static Lisp_Object Qphonetic;
d205d43b
JR
82
83/* Font spacing symbols - defined in font.c. */
84extern Lisp_Object Qc, Qp, Qm;
f7a84cb4 85
8f112d52 86static void fill_in_logfont P_ ((FRAME_PTR, LOGFONT *, Lisp_Object));
f7a84cb4 87
8f112d52
JR
88static BYTE w32_antialias_type P_ ((Lisp_Object));
89static Lisp_Object lispy_antialias_type P_ ((BYTE));
91583281 90
8f112d52
JR
91static Lisp_Object font_supported_scripts P_ ((FONTSIGNATURE *));
92static int w32font_full_name P_ ((LOGFONT *, Lisp_Object, int, char *, int));
93static void compute_metrics P_ ((HDC, struct w32font_info *, unsigned int,
94 struct w32_metric_cache *));
95static void clear_cached_metrics P_ ((struct w32font_info *));
f7a84cb4 96
8f112d52 97static Lisp_Object w32_registry P_ ((LONG, DWORD));
f7a84cb4
JR
98
99/* EnumFontFamiliesEx callbacks. */
100static int CALLBACK add_font_entity_to_list P_ ((ENUMLOGFONTEX *,
101 NEWTEXTMETRICEX *,
102 DWORD, LPARAM));
103static int CALLBACK add_one_font_entity_to_list P_ ((ENUMLOGFONTEX *,
104 NEWTEXTMETRICEX *,
105 DWORD, LPARAM));
106static int CALLBACK add_font_name_to_list P_ ((ENUMLOGFONTEX *,
107 NEWTEXTMETRICEX *,
108 DWORD, LPARAM));
109
d205d43b
JR
110/* struct passed in as LPARAM arg to EnumFontFamiliesEx, for keeping track
111 of what we really want. */
112struct font_callback_data
113{
114 /* The logfont we are matching against. EnumFontFamiliesEx only matches
115 face name and charset, so we need to manually match everything else
116 in the callback function. */
117 LOGFONT pattern;
118 /* The original font spec or entity. */
119 Lisp_Object orig_font_spec;
120 /* The frame the font is being loaded on. */
121 Lisp_Object frame;
122 /* The list to add matches to. */
123 Lisp_Object list;
46fd1ded
JR
124 /* Whether to match only opentype fonts. */
125 int opentype_only;
d205d43b
JR
126};
127
128/* Handles the problem that EnumFontFamiliesEx will not return all
129 style variations if the font name is not specified. */
8f112d52 130static void list_all_matching_fonts P_ ((struct font_callback_data *));
d205d43b 131
34fd2d28 132/* From old font code in w32fns.c */
8f112d52 133char * w32_to_x_charset P_ ((int, char *));
d205d43b 134
f7a84cb4
JR
135
136static int
137memq_no_quit (elt, list)
138 Lisp_Object elt, list;
139{
140 while (CONSP (list) && ! EQ (XCAR (list), elt))
141 list = XCDR (list);
142 return (CONSP (list));
143}
144
145/* w32 implementation of get_cache for font backend.
146 Return a cache of font-entities on FRAME. The cache must be a
147 cons whose cdr part is the actual cache area. */
46fd1ded 148Lisp_Object
a4c71909
KH
149w32font_get_cache (f)
150 FRAME_PTR f;
f7a84cb4 151{
a4c71909 152 struct w32_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
f7a84cb4
JR
153
154 return (dpyinfo->name_list_element);
155}
156
157/* w32 implementation of list for font backend.
158 List fonts exactly matching with FONT_SPEC on FRAME. The value
159 is a vector of font-entities. This is the sole API that
160 allocates font-entities. */
20399669
JR
161static Lisp_Object
162w32font_list (frame, font_spec)
163 Lisp_Object frame, font_spec;
f7a84cb4 164{
07d9ba9b
JR
165 Lisp_Object fonts = w32font_list_internal (frame, font_spec, 0);
166 font_add_log ("w32font-list", font_spec, fonts);
167 return fonts;
f7a84cb4
JR
168}
169
170/* w32 implementation of match for font backend.
171 Return a font entity most closely matching with FONT_SPEC on
172 FRAME. The closeness is detemined by the font backend, thus
173 `face-font-selection-order' is ignored here. */
20399669
JR
174static Lisp_Object
175w32font_match (frame, font_spec)
176 Lisp_Object frame, font_spec;
f7a84cb4 177{
07d9ba9b
JR
178 Lisp_Object entity = w32font_match_internal (frame, font_spec, 0);
179 font_add_log ("w32font-match", font_spec, entity);
180 return entity;
f7a84cb4
JR
181}
182
f7a84cb4
JR
183/* w32 implementation of list_family for font backend.
184 List available families. The value is a list of family names
185 (symbols). */
20399669
JR
186static Lisp_Object
187w32font_list_family (frame)
188 Lisp_Object frame;
f7a84cb4
JR
189{
190 Lisp_Object list = Qnil;
191 LOGFONT font_match_pattern;
192 HDC dc;
193 FRAME_PTR f = XFRAME (frame);
194
195 bzero (&font_match_pattern, sizeof (font_match_pattern));
56df6710 196 font_match_pattern.lfCharSet = DEFAULT_CHARSET;
f7a84cb4
JR
197
198 dc = get_frame_dc (f);
199
200 EnumFontFamiliesEx (dc, &font_match_pattern,
201 (FONTENUMPROC) add_font_name_to_list,
202 (LPARAM) &list, 0);
203 release_frame_dc (f, dc);
204
205 return list;
206}
207
208/* w32 implementation of open for font backend.
209 Open a font specified by FONT_ENTITY on frame F.
210 If the font is scalable, open it with PIXEL_SIZE. */
5f18d119 211static Lisp_Object
20399669
JR
212w32font_open (f, font_entity, pixel_size)
213 FRAME_PTR f;
214 Lisp_Object font_entity;
215 int pixel_size;
f7a84cb4 216{
5f18d119 217 Lisp_Object font_object;
f7a84cb4 218
5f18d119 219 font_object = font_make_object (VECSIZE (struct w32font_info));
f7a84cb4 220
5f18d119 221 if (!w32font_open_internal (f, font_entity, pixel_size, font_object))
f7a84cb4 222 {
5f18d119 223 return Qnil;
f7a84cb4
JR
224 }
225
5f18d119 226 return font_object;
f7a84cb4
JR
227}
228
229/* w32 implementation of close for font_backend.
230 Close FONT on frame F. */
46fd1ded 231void
20399669
JR
232w32font_close (f, font)
233 FRAME_PTR f;
234 struct font *font;
f7a84cb4 235{
5f18d119
KH
236 struct w32font_info *w32_font = (struct w32font_info *) font;
237
238 if (w32_font->compat_w32_font)
f7a84cb4 239 {
5f18d119 240 W32FontStruct *old_w32_font = w32_font->compat_w32_font;
e9a15283 241 DeleteObject (old_w32_font->hfont);
f7a84cb4 242 xfree (old_w32_font);
5f18d119 243 w32_font->compat_w32_font = 0;
f7a84cb4 244 }
f7a84cb4
JR
245}
246
247/* w32 implementation of has_char for font backend.
248 Optional.
249 If FONT_ENTITY has a glyph for character C (Unicode code point),
250 return 1. If not, return 0. If a font must be opened to check
251 it, return -1. */
46fd1ded 252int
20399669
JR
253w32font_has_char (entity, c)
254 Lisp_Object entity;
255 int c;
f7a84cb4 256{
d205d43b 257 Lisp_Object supported_scripts, extra, script;
f7a84cb4
JR
258 DWORD mask;
259
01dbeb0b
JR
260 extra = AREF (entity, FONT_EXTRA_INDEX);
261 if (!CONSP (extra))
262 return -1;
263
d205d43b
JR
264 supported_scripts = assq_no_quit (QCscript, extra);
265 if (!CONSP (supported_scripts))
f7a84cb4
JR
266 return -1;
267
d205d43b 268 supported_scripts = XCDR (supported_scripts);
f7a84cb4 269
d205d43b 270 script = CHAR_TABLE_REF (Vchar_script_table, c);
f7a84cb4 271
34fd2d28 272 return (memq_no_quit (script, supported_scripts)) ? -1 : 0;
f7a84cb4
JR
273}
274
275/* w32 implementation of encode_char for font backend.
276 Return a glyph code of FONT for characer C (Unicode code point).
277 If FONT doesn't have such a glyph, return FONT_INVALID_CODE. */
34fd2d28 278static unsigned
20399669
JR
279w32font_encode_char (font, c)
280 struct font *font;
281 int c;
f7a84cb4 282{
34fd2d28
JR
283 struct frame *f;
284 HDC dc;
285 HFONT old_font;
286 DWORD retval;
287 GCP_RESULTSW result;
288 wchar_t in[2];
289 wchar_t out[2];
290 int len;
291 struct w32font_info *w32_font = (struct w32font_info *) font;
292
293 /* If glyph indexing is not working for this font, just return the
294 unicode code-point. */
295 if (!w32_font->glyph_idx)
296 return c;
297
298 if (c > 0xFFFF)
299 {
300 /* TODO: Encode as surrogate pair and lookup the glyph. */
301 return FONT_INVALID_CODE;
302 }
303 else
304 {
305 in[0] = (wchar_t) c;
306 len = 1;
307 }
308
309 bzero (&result, sizeof (result));
310 result.lStructSize = sizeof (result);
311 result.lpGlyphs = out;
312 result.nGlyphs = 2;
313
314 f = XFRAME (selected_frame);
315
316 dc = get_frame_dc (f);
5f18d119 317 old_font = SelectObject (dc, w32_font->compat_w32_font->hfont);
34fd2d28 318
f42adef6
JR
319 /* GetCharacterPlacement is used here rather than GetGlyphIndices because
320 it is supported on Windows NT 4 and 9x/ME. But it cannot reliably report
321 missing glyphs, see below for workaround. */
34fd2d28
JR
322 retval = GetCharacterPlacementW (dc, in, len, 0, &result, 0);
323
324 SelectObject (dc, old_font);
325 release_frame_dc (f, dc);
326
327 if (retval)
328 {
f42adef6
JR
329 if (result.nGlyphs != 1 || !result.lpGlyphs[0]
330 /* GetCharacterPlacementW seems to return 3, which seems to be
331 the space glyph in most/all truetype fonts, instead of 0
332 for unsupported glyphs. */
333 || (result.lpGlyphs[0] == 3 && !iswspace (in[0])))
34fd2d28
JR
334 return FONT_INVALID_CODE;
335 return result.lpGlyphs[0];
336 }
337 else
338 {
339 int i;
340 /* Mark this font as not supporting glyph indices. This can happen
341 on Windows9x, and maybe with non-Truetype fonts on NT etc. */
342 w32_font->glyph_idx = 0;
8f112d52
JR
343 /* Clear metrics cache. */
344 clear_cached_metrics (w32_font);
34fd2d28
JR
345
346 return c;
347 }
f7a84cb4
JR
348}
349
350/* w32 implementation of text_extents for font backend.
351 Perform the size computation of glyphs of FONT and fillin members
352 of METRICS. The glyphs are specified by their glyph codes in
78573c57 353 CODE (length NGLYPHS). Apparently metrics can be NULL, in this
f7a84cb4 354 case just return the overall width. */
46fd1ded 355int
20399669
JR
356w32font_text_extents (font, code, nglyphs, metrics)
357 struct font *font;
358 unsigned *code;
359 int nglyphs;
360 struct font_metrics *metrics;
f7a84cb4
JR
361{
362 int i;
2a36efcf
JR
363 HFONT old_font = NULL;
364 HDC dc = NULL;
46fd1ded 365 struct frame * f;
f7a84cb4 366 int total_width = 0;
8f112d52 367 WORD *wcode = NULL;
d205d43b 368 SIZE size;
f7a84cb4 369
f7a84cb4
JR
370 if (metrics)
371 {
34fd2d28 372 struct w32font_info *w32_font = (struct w32font_info *) font;
d205d43b 373
ba93d684 374 bzero (metrics, sizeof (struct font_metrics));
388c38f9
JR
375 metrics->ascent = font->ascent;
376 metrics->descent = font->descent;
f7a84cb4
JR
377
378 for (i = 0; i < nglyphs; i++)
379 {
8f112d52
JR
380 struct w32_metric_cache *char_metric;
381 int block = *(code + i) / CACHE_BLOCKSIZE;
382 int pos_in_block = *(code + i) % CACHE_BLOCKSIZE;
383
384 if (block >= w32_font->n_cache_blocks)
385 {
386 if (!w32_font->cached_metrics)
387 w32_font->cached_metrics
388 = xmalloc ((block + 1)
389 * sizeof (struct w32_cached_metric *));
390 else
391 w32_font->cached_metrics
392 = xrealloc (w32_font->cached_metrics,
393 (block + 1)
394 * sizeof (struct w32_cached_metric *));
395 bzero (w32_font->cached_metrics + w32_font->n_cache_blocks,
396 ((block + 1 - w32_font->n_cache_blocks)
397 * sizeof (struct w32_cached_metric *)));
398 w32_font->n_cache_blocks = block + 1;
399 }
400
401 if (!w32_font->cached_metrics[block])
402 {
403 w32_font->cached_metrics[block]
404 = xmalloc (CACHE_BLOCKSIZE * sizeof (struct font_metrics));
405 bzero (w32_font->cached_metrics[block],
406 CACHE_BLOCKSIZE * sizeof (struct font_metrics));
407 }
408
409 char_metric = w32_font->cached_metrics[block] + pos_in_block;
410
411 if (char_metric->status == W32METRIC_NO_ATTEMPT)
412 {
413 if (dc == NULL)
414 {
415 /* TODO: Frames can come and go, and their fonts
416 outlive them. So we can't cache the frame in the
417 font structure. Use selected_frame until the API
418 is updated to pass in a frame. */
419 f = XFRAME (selected_frame);
9c623c85 420
2a36efcf 421 dc = get_frame_dc (f);
5f18d119 422 old_font = SelectObject (dc, FONT_COMPAT (font)->hfont);
8f112d52
JR
423 }
424 compute_metrics (dc, w32_font, *(code + i), char_metric);
425 }
78573c57 426
8f112d52
JR
427 if (char_metric->status == W32METRIC_SUCCESS)
428 {
429 metrics->lbearing = min (metrics->lbearing,
430 metrics->width + char_metric->lbearing);
431 metrics->rbearing = max (metrics->rbearing,
432 metrics->width + char_metric->rbearing);
433 metrics->width += char_metric->width;
434 }
435 else
436 /* If we couldn't get metrics for a char,
437 use alternative method. */
438 break;
439 }
78573c57
JR
440 /* If we got through everything, return. */
441 if (i == nglyphs)
442 {
2a36efcf
JR
443 if (dc != NULL)
444 {
445 /* Restore state and release DC. */
446 SelectObject (dc, old_font);
447 release_frame_dc (f, dc);
448 }
78573c57
JR
449
450 return metrics->width;
451 }
f7a84cb4 452 }
78573c57 453
56df6710
JR
454 /* For non-truetype fonts, GetGlyphOutlineW is not supported, so
455 fallback on other methods that will at least give some of the metric
456 information. */
8f112d52
JR
457 if (!wcode) {
458 wcode = alloca (nglyphs * sizeof (WORD));
459 for (i = 0; i < nglyphs; i++)
460 {
461 if (code[i] < 0x10000)
462 wcode[i] = code[i];
463 else
464 {
465 /* TODO: Convert to surrogate, reallocating array if needed */
466 wcode[i] = 0xffff;
467 }
468 }
469 }
2a36efcf
JR
470 if (dc == NULL)
471 {
8f112d52
JR
472 /* TODO: Frames can come and go, and their fonts outlive
473 them. So we can't cache the frame in the font structure. Use
474 selected_frame until the API is updated to pass in a
475 frame. */
476 f = XFRAME (selected_frame);
477
2a36efcf 478 dc = get_frame_dc (f);
5f18d119 479 old_font = SelectObject (dc, FONT_COMPAT (font)->hfont);
2a36efcf
JR
480 }
481
d205d43b 482 if (GetTextExtentPoint32W (dc, wcode, nglyphs, &size))
f7a84cb4 483 {
d205d43b 484 total_width = size.cx;
f7a84cb4
JR
485 }
486
56df6710
JR
487 /* On 95/98/ME, only some unicode functions are available, so fallback
488 on doing a dummy draw to find the total width. */
d205d43b 489 if (!total_width)
f7a84cb4
JR
490 {
491 RECT rect;
5f18d119 492 rect.top = 0; rect.bottom = font->height; rect.left = 0; rect.right = 1;
f7a84cb4
JR
493 DrawTextW (dc, wcode, nglyphs, &rect,
494 DT_CALCRECT | DT_NOPREFIX | DT_SINGLELINE);
495 total_width = rect.right;
496 }
d205d43b 497
56df6710 498 /* Give our best estimate of the metrics, based on what we know. */
78573c57
JR
499 if (metrics)
500 {
501 metrics->width = total_width;
78573c57
JR
502 metrics->lbearing = 0;
503 metrics->rbearing = total_width
504 + ((struct w32font_info *) font)->metrics.tmOverhang;
505 }
506
f7a84cb4
JR
507 /* Restore state and release DC. */
508 SelectObject (dc, old_font);
46fd1ded 509 release_frame_dc (f, dc);
f7a84cb4
JR
510
511 return total_width;
512}
513
514/* w32 implementation of draw for font backend.
515 Optional.
516 Draw glyphs between FROM and TO of S->char2b at (X Y) pixel
517 position of frame F with S->FACE and S->GC. If WITH_BACKGROUND
518 is nonzero, fill the background in advance. It is assured that
a74ddbda
JR
519 WITH_BACKGROUND is zero when (FROM > 0 || TO < S->nchars).
520
521 TODO: Currently this assumes that the colors and fonts are already
522 set in the DC. This seems to be true now, but maybe only due to
523 the old font code setting it up. It may be safer to resolve faces
524 and fonts in here and set them explicitly
525*/
526
46fd1ded 527int
20399669
JR
528w32font_draw (s, from, to, x, y, with_background)
529 struct glyph_string *s;
530 int from, to, x, y, with_background;
f7a84cb4 531{
34fd2d28 532 UINT options;
5c2c9c79 533 HRGN orig_clip;
5f18d119 534 struct w32font_info *w32font = (struct w32font_info *) s->font;
34fd2d28
JR
535
536 options = w32font->glyph_idx;
5c2c9c79
JR
537
538 /* Save clip region for later restoration. */
539 GetClipRgn(s->hdc, orig_clip);
540
541 if (s->num_clips > 0)
542 {
543 HRGN new_clip = CreateRectRgnIndirect (s->clip);
544
545 if (s->num_clips > 1)
546 {
547 HRGN clip2 = CreateRectRgnIndirect (s->clip + 1);
548
549 CombineRgn (new_clip, new_clip, clip2, RGN_OR);
550 DeleteObject (clip2);
551 }
552
553 SelectClipRgn (s->hdc, new_clip);
554 DeleteObject (new_clip);
555 }
f7a84cb4 556
fb3b8017
JR
557 /* Using OPAQUE background mode can clear more background than expected
558 when Cleartype is used. Draw the background manually to avoid this. */
559 SetBkMode (s->hdc, TRANSPARENT);
f7a84cb4
JR
560 if (with_background)
561 {
1065a502
JR
562 HBRUSH brush;
563 RECT rect;
5f18d119 564 struct font *font = s->font;
1065a502
JR
565
566 brush = CreateSolidBrush (s->gc->background);
567 rect.left = x;
fb3b8017 568 rect.top = y - font->ascent;
1065a502 569 rect.right = x + s->width;
fb3b8017 570 rect.bottom = y + font->descent;
1065a502 571 FillRect (s->hdc, &rect, brush);
f2b25c0e 572 DeleteObject (brush);
f7a84cb4 573 }
040fe918 574
de63f07f
KH
575 if (s->padding_p)
576 {
577 int len = to - from, i;
578
579 for (i = 0; i < len; i++)
580 ExtTextOutW (s->hdc, x + i, y, options, NULL,
8501c48b 581 s->char2b + from + i, 1, NULL);
de63f07f
KH
582 }
583 else
584 ExtTextOutW (s->hdc, x, y, options, NULL, s->char2b + from, to - from, NULL);
5c2c9c79
JR
585
586 /* Restore clip region. */
587 if (s->num_clips > 0)
588 {
589 SelectClipRgn (s->hdc, orig_clip);
590 }
f7a84cb4
JR
591}
592
593/* w32 implementation of free_entity for font backend.
594 Optional (if FONT_EXTRA_INDEX is not Lisp_Save_Value).
595 Free FONT_EXTRA_INDEX field of FONT_ENTITY.
20399669
JR
596static void
597w32font_free_entity (Lisp_Object entity);
f7a84cb4
JR
598 */
599
600/* w32 implementation of prepare_face for font backend.
601 Optional (if FACE->extra is not used).
602 Prepare FACE for displaying characters by FONT on frame F by
603 storing some data in FACE->extra. If successful, return 0.
604 Otherwise, return -1.
20399669
JR
605static int
606w32font_prepare_face (FRAME_PTR f, struct face *face);
f7a84cb4
JR
607 */
608/* w32 implementation of done_face for font backend.
609 Optional.
610 Done FACE for displaying characters by FACE->font on frame F.
20399669
JR
611static void
612w32font_done_face (FRAME_PTR f, struct face *face); */
f7a84cb4
JR
613
614/* w32 implementation of get_bitmap for font backend.
615 Optional.
616 Store bitmap data for glyph-code CODE of FONT in BITMAP. It is
f2b25c0e 617 intended that this method is called from the other font-driver
f7a84cb4 618 for actual drawing.
20399669
JR
619static int
620w32font_get_bitmap (struct font *font, unsigned code,
621 struct font_bitmap *bitmap, int bits_per_pixel);
f7a84cb4
JR
622 */
623/* w32 implementation of free_bitmap for font backend.
624 Optional.
625 Free bitmap data in BITMAP.
20399669
JR
626static void
627w32font_free_bitmap (struct font *font, struct font_bitmap *bitmap);
f7a84cb4
JR
628 */
629/* w32 implementation of get_outline for font backend.
630 Optional.
631 Return an outline data for glyph-code CODE of FONT. The format
632 of the outline data depends on the font-driver.
20399669
JR
633static void *
634w32font_get_outline (struct font *font, unsigned code);
f7a84cb4
JR
635 */
636/* w32 implementation of free_outline for font backend.
637 Optional.
638 Free OUTLINE (that is obtained by the above method).
20399669
JR
639static void
640w32font_free_outline (struct font *font, void *outline);
f7a84cb4
JR
641 */
642/* w32 implementation of anchor_point for font backend.
643 Optional.
644 Get coordinates of the INDEXth anchor point of the glyph whose
645 code is CODE. Store the coordinates in *X and *Y. Return 0 if
646 the operations was successfull. Otherwise return -1.
20399669
JR
647static int
648w32font_anchor_point (struct font *font, unsigned code,
f7a84cb4
JR
649 int index, int *x, int *y);
650 */
651/* w32 implementation of otf_capability for font backend.
652 Optional.
653 Return a list describing which scripts/languages FONT
654 supports by which GSUB/GPOS features of OpenType tables.
20399669
JR
655static Lisp_Object
656w32font_otf_capability (struct font *font);
f7a84cb4
JR
657 */
658/* w32 implementation of otf_drive for font backend.
659 Optional.
660 Apply FONT's OTF-FEATURES to the glyph string.
661
662 FEATURES specifies which OTF features to apply in this format:
663 (SCRIPT LANGSYS GSUB-FEATURE GPOS-FEATURE)
664 See the documentation of `font-drive-otf' for the detail.
665
666 This method applies the specified features to the codes in the
667 elements of GSTRING-IN (between FROMth and TOth). The output
668 codes are stored in GSTRING-OUT at the IDXth element and the
669 following elements.
670
671 Return the number of output codes. If none of the features are
672 applicable to the input data, return 0. If GSTRING-OUT is too
673 short, return -1.
20399669
JR
674static int
675w32font_otf_drive (struct font *font, Lisp_Object features,
676 Lisp_Object gstring_in, int from, int to,
677 Lisp_Object gstring_out, int idx,
678 int alternate_subst);
f7a84cb4
JR
679 */
680
46fd1ded
JR
681/* Internal implementation of w32font_list.
682 Additional parameter opentype_only restricts the returned fonts to
683 opentype fonts, which can be used with the Uniscribe backend. */
684Lisp_Object
685w32font_list_internal (frame, font_spec, opentype_only)
686 Lisp_Object frame, font_spec;
687 int opentype_only;
688{
689 struct font_callback_data match_data;
690 HDC dc;
691 FRAME_PTR f = XFRAME (frame);
692
693 match_data.orig_font_spec = font_spec;
694 match_data.list = Qnil;
695 match_data.frame = frame;
696
697 bzero (&match_data.pattern, sizeof (LOGFONT));
698 fill_in_logfont (f, &match_data.pattern, font_spec);
699
700 match_data.opentype_only = opentype_only;
701 if (opentype_only)
702 match_data.pattern.lfOutPrecision = OUT_OUTLINE_PRECIS;
703
704 if (match_data.pattern.lfFaceName[0] == '\0')
705 {
706 /* EnumFontFamiliesEx does not take other fields into account if
707 font name is blank, so need to use two passes. */
708 list_all_matching_fonts (&match_data);
709 }
710 else
711 {
712 dc = get_frame_dc (f);
713
714 EnumFontFamiliesEx (dc, &match_data.pattern,
715 (FONTENUMPROC) add_font_entity_to_list,
716 (LPARAM) &match_data, 0);
717 release_frame_dc (f, dc);
718 }
719
5f18d119 720 return NILP (match_data.list) ? Qnil : match_data.list;
46fd1ded
JR
721}
722
723/* Internal implementation of w32font_match.
724 Additional parameter opentype_only restricts the returned fonts to
725 opentype fonts, which can be used with the Uniscribe backend. */
726Lisp_Object
727w32font_match_internal (frame, font_spec, opentype_only)
728 Lisp_Object frame, font_spec;
729 int opentype_only;
730{
731 struct font_callback_data match_data;
732 HDC dc;
733 FRAME_PTR f = XFRAME (frame);
734
735 match_data.orig_font_spec = font_spec;
736 match_data.frame = frame;
737 match_data.list = Qnil;
738
739 bzero (&match_data.pattern, sizeof (LOGFONT));
740 fill_in_logfont (f, &match_data.pattern, font_spec);
741
742 match_data.opentype_only = opentype_only;
743 if (opentype_only)
744 match_data.pattern.lfOutPrecision = OUT_OUTLINE_PRECIS;
745
746 dc = get_frame_dc (f);
747
748 EnumFontFamiliesEx (dc, &match_data.pattern,
749 (FONTENUMPROC) add_one_font_entity_to_list,
750 (LPARAM) &match_data, 0);
751 release_frame_dc (f, dc);
752
753 return NILP (match_data.list) ? Qnil : XCAR (match_data.list);
754}
755
f0121ad2 756int
5f18d119 757w32font_open_internal (f, font_entity, pixel_size, font_object)
f0121ad2
JR
758 FRAME_PTR f;
759 Lisp_Object font_entity;
760 int pixel_size;
5f18d119 761 Lisp_Object font_object;
f0121ad2 762{
5f18d119 763 int len, size, i;
f0121ad2
JR
764 LOGFONT logfont;
765 HDC dc;
766 HFONT hfont, old_font;
767 Lisp_Object val, extra;
768 /* For backwards compatibility. */
769 W32FontStruct *compat_w32_font;
5f18d119
KH
770 struct w32font_info *w32_font;
771 struct font * font;
772 OUTLINETEXTMETRIC* metrics = NULL;
773
774 w32_font = (struct w32font_info *) XFONT_OBJECT (font_object);
775 font = (struct font *) w32_font;
f0121ad2 776
f0121ad2
JR
777 if (!font)
778 return 0;
779
5f18d119
KH
780 /* Copy from font entity. */
781 for (i = 0; i < FONT_ENTITY_MAX; i++)
782 ASET (font_object, i, AREF (font_entity, i));
783 ASET (font_object, FONT_SIZE_INDEX, make_number (pixel_size));
784
f0121ad2
JR
785 bzero (&logfont, sizeof (logfont));
786 fill_in_logfont (f, &logfont, font_entity);
787
1519d52e
JR
788 /* Prefer truetype fonts, to avoid known problems with type1 fonts, and
789 limitations in bitmap fonts. */
790 val = AREF (font_entity, FONT_FOUNDRY_INDEX);
791 if (!EQ (val, Qraster))
792 logfont.lfOutPrecision = OUT_TT_PRECIS;
793
f0121ad2
JR
794 size = XINT (AREF (font_entity, FONT_SIZE_INDEX));
795 if (!size)
796 size = pixel_size;
797
798 logfont.lfHeight = -size;
799 hfont = CreateFontIndirect (&logfont);
800
801 if (hfont == NULL)
802 return 0;
803
f0121ad2
JR
804 /* Get the metrics for this font. */
805 dc = get_frame_dc (f);
806 old_font = SelectObject (dc, hfont);
807
5f18d119
KH
808 /* Try getting the outline metrics (only works for truetype fonts). */
809 len = GetOutlineTextMetrics (dc, 0, NULL);
810 if (len)
811 {
812 metrics = (OUTLINETEXTMETRIC *) alloca (len);
813 if (GetOutlineTextMetrics (dc, len, metrics))
814 bcopy (&metrics->otmTextMetrics, &w32_font->metrics,
815 sizeof (TEXTMETRIC));
816 else
817 metrics = NULL;
943f2093
JR
818
819 /* If it supports outline metrics, it should support Glyph Indices. */
820 w32_font->glyph_idx = ETO_GLYPH_INDEX;
5f18d119 821 }
f0121ad2 822
943f2093
JR
823 if (!metrics)
824 {
825 GetTextMetrics (dc, &w32_font->metrics);
826 w32_font->glyph_idx = 0;
827 }
7145be81 828
8f112d52
JR
829 w32_font->cached_metrics = NULL;
830 w32_font->n_cache_blocks = 0;
54efdcd1 831
f0121ad2
JR
832 SelectObject (dc, old_font);
833 release_frame_dc (f, dc);
34fd2d28 834
f0121ad2
JR
835 /* W32FontStruct - we should get rid of this, and use the w32font_info
836 struct for any W32 specific fields. font->font.font can then be hfont. */
5f18d119
KH
837 w32_font->compat_w32_font = xmalloc (sizeof (W32FontStruct));
838 compat_w32_font = w32_font->compat_w32_font;
f0121ad2
JR
839 bzero (compat_w32_font, sizeof (W32FontStruct));
840 compat_w32_font->font_type = UNICODE_FONT;
841 /* Duplicate the text metrics. */
842 bcopy (&w32_font->metrics, &compat_w32_font->tm, sizeof (TEXTMETRIC));
843 compat_w32_font->hfont = hfont;
844
5ace1ec1
JR
845 {
846 char *name;
847
848 /* We don't know how much space we need for the full name, so start with
849 96 bytes and go up in steps of 32. */
850 len = 96;
e3a77b22 851 name = xmalloc (len);
67997c79
JR
852 while (name && w32font_full_name (&logfont, font_entity, pixel_size,
853 name, len) < 0)
5ace1ec1 854 {
e3a77b22 855 char *new = xrealloc (name, len += 32);
5ace1ec1
JR
856
857 if (! new)
e3a77b22 858 xfree (name);
5ace1ec1
JR
859 name = new;
860 }
861 if (name)
5f18d119
KH
862 font->props[FONT_FULLNAME_INDEX]
863 = make_unibyte_string (name, strlen (name));
5ace1ec1 864 else
5f18d119
KH
865 font->props[FONT_FULLNAME_INDEX] =
866 make_unibyte_string (logfont.lfFaceName, len);
5ace1ec1 867 }
5f18d119
KH
868
869 font->max_width = w32_font->metrics.tmMaxCharWidth;
870 font->height = w32_font->metrics.tmHeight
f0121ad2 871 + w32_font->metrics.tmExternalLeading;
5f18d119
KH
872 font->space_width = font->average_width = w32_font->metrics.tmAveCharWidth;
873
874 font->vertical_centering = 0;
875 font->encoding_type = 0;
876 font->baseline_offset = 0;
877 font->relative_compose = 0;
878 font->default_ascent = w32_font->metrics.tmAscent;
879 font->font_encoder = NULL;
f0121ad2
JR
880 font->pixel_size = size;
881 font->driver = &w32font_driver;
34fd2d28
JR
882 /* Use format cached during list, as the information we have access to
883 here is incomplete. */
884 extra = AREF (font_entity, FONT_EXTRA_INDEX);
885 if (CONSP (extra))
886 {
887 val = assq_no_quit (QCformat, extra);
888 if (CONSP (val))
5f18d119 889 font->props[FONT_FORMAT_INDEX] = XCDR (val);
34fd2d28 890 else
5f18d119 891 font->props[FONT_FORMAT_INDEX] = Qunknown;
34fd2d28
JR
892 }
893 else
5f18d119 894 font->props[FONT_FORMAT_INDEX] = Qunknown;
34fd2d28 895
5f18d119 896 font->props[FONT_FILE_INDEX] = Qnil;
f0121ad2
JR
897 font->encoding_charset = -1;
898 font->repertory_charset = -1;
04b65d2b 899 /* TODO: do we really want the minimum width here, which could be negative? */
5f18d119 900 font->min_width = font->space_width;
f0121ad2
JR
901 font->ascent = w32_font->metrics.tmAscent;
902 font->descent = w32_font->metrics.tmDescent;
5f18d119
KH
903
904 if (metrics)
905 {
906 font->underline_thickness = metrics->otmsUnderscoreSize;
907 font->underline_position = -metrics->otmsUnderscorePosition;
908 }
909 else
910 {
911 font->underline_thickness = 0;
912 font->underline_position = -1;
913 }
f0121ad2 914
e157d7ba
JR
915 /* max_descent is used for underlining in w32term.c. Hopefully this
916 is temporary, as we'll want to get rid of the old compatibility
917 stuff later. */
918 compat_w32_font->max_bounds.descent = font->descent;
919
5f18d119
KH
920 /* For temporary compatibility with legacy code that expects the
921 name to be usable in x-list-fonts. Eventually we expect to change
922 x-list-fonts and other places that use fonts so that this can be
923 an fcname or similar. */
a30e1957 924 font->props[FONT_NAME_INDEX] = Ffont_xlfd_name (font_object, Qnil);
04b65d2b 925
f0121ad2
JR
926 return 1;
927}
928
f7a84cb4
JR
929/* Callback function for EnumFontFamiliesEx.
930 * Adds the name of a font to a Lisp list (passed in as the lParam arg). */
20399669
JR
931static int CALLBACK
932add_font_name_to_list (logical_font, physical_font, font_type, list_object)
933 ENUMLOGFONTEX *logical_font;
934 NEWTEXTMETRICEX *physical_font;
935 DWORD font_type;
936 LPARAM list_object;
f7a84cb4
JR
937{
938 Lisp_Object* list = (Lisp_Object *) list_object;
20a2b756
JR
939 Lisp_Object family;
940
941 /* Skip vertical fonts (intended only for printing) */
942 if (logical_font->elfLogFont.lfFaceName[0] == '@')
943 return 1;
944
5f18d119 945 family = font_intern_prop (logical_font->elfLogFont.lfFaceName,
4cb35b63 946 strlen (logical_font->elfLogFont.lfFaceName), 1);
f7a84cb4
JR
947 if (! memq_no_quit (family, *list))
948 *list = Fcons (family, *list);
949
950 return 1;
951}
952
5f18d119
KH
953static int w32_decode_weight P_ ((int));
954static int w32_encode_weight P_ ((int));
955
f7a84cb4 956/* Convert an enumerated Windows font to an Emacs font entity. */
20399669 957static Lisp_Object
91583281 958w32_enumfont_pattern_entity (frame, logical_font, physical_font,
34fd2d28 959 font_type, requested_font, backend)
d205d43b 960 Lisp_Object frame;
20399669
JR
961 ENUMLOGFONTEX *logical_font;
962 NEWTEXTMETRICEX *physical_font;
963 DWORD font_type;
91583281 964 LOGFONT *requested_font;
34fd2d28 965 Lisp_Object backend;
f7a84cb4
JR
966{
967 Lisp_Object entity, tem;
968 LOGFONT *lf = (LOGFONT*) logical_font;
969 BYTE generic_type;
56df6710 970 DWORD full_type = physical_font->ntmTm.ntmFlags;
f7a84cb4 971
5f18d119 972 entity = font_make_entity ();
f7a84cb4 973
34fd2d28 974 ASET (entity, FONT_TYPE_INDEX, backend);
c960bff8 975 ASET (entity, FONT_REGISTRY_INDEX, w32_registry (lf->lfCharSet, font_type));
f7a84cb4
JR
976 ASET (entity, FONT_OBJLIST_INDEX, Qnil);
977
978 /* Foundry is difficult to get in readable form on Windows.
d205d43b 979 But Emacs crashes if it is not set, so set it to something more
9c623c85 980 generic. These values make xlfds compatible with Emacs 22. */
d205d43b
JR
981 if (lf->lfOutPrecision == OUT_STRING_PRECIS)
982 tem = Qraster;
983 else if (lf->lfOutPrecision == OUT_STROKE_PRECIS)
984 tem = Qoutline;
985 else
986 tem = Qunknown;
987
988 ASET (entity, FONT_FOUNDRY_INDEX, tem);
989
990 /* Save the generic family in the extra info, as it is likely to be
991 useful to users looking for a close match. */
f7a84cb4
JR
992 generic_type = physical_font->ntmTm.tmPitchAndFamily & 0xF0;
993 if (generic_type == FF_DECORATIVE)
994 tem = Qdecorative;
995 else if (generic_type == FF_MODERN)
9e1a2995 996 tem = Qmono;
f7a84cb4 997 else if (generic_type == FF_ROMAN)
d205d43b 998 tem = Qserif;
f7a84cb4
JR
999 else if (generic_type == FF_SCRIPT)
1000 tem = Qscript;
1001 else if (generic_type == FF_SWISS)
9e1a2995 1002 tem = Qsans;
f7a84cb4 1003 else
5f18d119 1004 tem = Qnil;
9e1a2995
JR
1005
1006 ASET (entity, FONT_ADSTYLE_INDEX, tem);
f7a84cb4 1007
d205d43b 1008 if (physical_font->ntmTm.tmPitchAndFamily & 0x01)
5f18d119 1009 ASET (entity, FONT_SPACING_INDEX, make_number (FONT_SPACING_PROPORTIONAL));
d205d43b 1010 else
ed18e612 1011 ASET (entity, FONT_SPACING_INDEX, make_number (FONT_SPACING_CHARCELL));
f7a84cb4 1012
91583281
JR
1013 if (requested_font->lfQuality != DEFAULT_QUALITY)
1014 {
1015 font_put_extra (entity, QCantialias,
1016 lispy_antialias_type (requested_font->lfQuality));
1017 }
f7a84cb4 1018 ASET (entity, FONT_FAMILY_INDEX,
4cb35b63 1019 font_intern_prop (lf->lfFaceName, strlen (lf->lfFaceName), 1));
f7a84cb4 1020
5f18d119
KH
1021 FONT_SET_STYLE (entity, FONT_WEIGHT_INDEX,
1022 make_number (w32_decode_weight (lf->lfWeight)));
1023 FONT_SET_STYLE (entity, FONT_SLANT_INDEX,
1024 make_number (lf->lfItalic ? 200 : 100));
d205d43b
JR
1025 /* TODO: PANOSE struct has this info, but need to call GetOutlineTextMetrics
1026 to get it. */
5f18d119 1027 FONT_SET_STYLE (entity, FONT_WIDTH_INDEX, make_number (100));
f7a84cb4 1028
040fe918
JR
1029 if (font_type & RASTER_FONTTYPE)
1030 ASET (entity, FONT_SIZE_INDEX, make_number (physical_font->ntmTm.tmHeight));
1031 else
1032 ASET (entity, FONT_SIZE_INDEX, make_number (0));
f7a84cb4
JR
1033
1034 /* Cache unicode codepoints covered by this font, as there is no other way
1035 of getting this information easily. */
040fe918 1036 if (font_type & TRUETYPE_FONTTYPE)
f7a84cb4 1037 {
aee986fd
JR
1038 tem = font_supported_scripts (&physical_font->ntmFontSig);
1039 if (!NILP (tem))
1040 font_put_extra (entity, QCscript, tem);
f7a84cb4 1041 }
d205d43b 1042
34fd2d28
JR
1043 /* This information is not fully available when opening fonts, so
1044 save it here. Only Windows 2000 and later return information
1045 about opentype and type1 fonts, so need a fallback for detecting
1046 truetype so that this information is not any worse than we could
1047 have obtained later. */
56df6710
JR
1048 if (EQ (backend, Quniscribe) && (full_type & NTMFLAGS_OPENTYPE))
1049 tem = intern ("opentype");
1050 else if (font_type & TRUETYPE_FONTTYPE)
34fd2d28 1051 tem = intern ("truetype");
34fd2d28
JR
1052 else if (full_type & NTM_PS_OPENTYPE)
1053 tem = intern ("postscript");
56df6710
JR
1054 else if (full_type & NTM_TYPE1)
1055 tem = intern ("type1");
34fd2d28
JR
1056 else if (font_type & RASTER_FONTTYPE)
1057 tem = intern ("w32bitmap");
1058 else
1059 tem = intern ("w32vector");
1060
1061 font_put_extra (entity, QCformat, tem);
1062
f7a84cb4
JR
1063 return entity;
1064}
1065
d205d43b
JR
1066
1067/* Convert generic families to the family portion of lfPitchAndFamily. */
1068BYTE
1069w32_generic_family (Lisp_Object name)
1070{
1071 /* Generic families. */
1072 if (EQ (name, Qmonospace) || EQ (name, Qmono))
1073 return FF_MODERN;
9e1a2995 1074 else if (EQ (name, Qsans) || EQ (name, Qsans_serif) || EQ (name, Qsansserif))
d205d43b
JR
1075 return FF_SWISS;
1076 else if (EQ (name, Qserif))
1077 return FF_ROMAN;
1078 else if (EQ (name, Qdecorative))
1079 return FF_DECORATIVE;
1080 else if (EQ (name, Qscript))
1081 return FF_SCRIPT;
1082 else
1083 return FF_DONTCARE;
1084}
1085
1086static int
1087logfonts_match (font, pattern)
1088 LOGFONT *font, *pattern;
1089{
1090 /* Only check height for raster fonts. */
1091 if (pattern->lfHeight && font->lfOutPrecision == OUT_STRING_PRECIS
1092 && font->lfHeight != pattern->lfHeight)
1093 return 0;
1094
1095 /* Have some flexibility with weights. */
1096 if (pattern->lfWeight
1097 && ((font->lfWeight < (pattern->lfWeight - 150))
1098 || font->lfWeight > (pattern->lfWeight + 150)))
1099 return 0;
1100
1101 /* Charset and face should be OK. Italic has to be checked
1102 against the original spec, in case we don't have any preference. */
1103 return 1;
1104}
1105
1106static int
56df6710 1107font_matches_spec (type, font, spec, backend, logfont)
d205d43b
JR
1108 DWORD type;
1109 NEWTEXTMETRICEX *font;
1110 Lisp_Object spec;
56df6710
JR
1111 Lisp_Object backend;
1112 LOGFONT *logfont;
d205d43b
JR
1113{
1114 Lisp_Object extra, val;
1115
1116 /* Check italic. Can't check logfonts, since it is a boolean field,
1117 so there is no difference between "non-italic" and "don't care". */
5f18d119
KH
1118 {
1119 int slant = FONT_SLANT_NUMERIC (spec);
1120
1121 if (slant >= 0
1122 && ((slant > 150 && !font->ntmTm.tmItalic)
1123 || (slant <= 150 && font->ntmTm.tmItalic)))
1124 return 0;
1125 }
d205d43b 1126
4f2a2ee2
JR
1127 /* Check adstyle against generic family. */
1128 val = AREF (spec, FONT_ADSTYLE_INDEX);
1129 if (!NILP (val))
1130 {
1131 BYTE family = w32_generic_family (val);
1132 if (family != FF_DONTCARE
1133 && family != (font->ntmTm.tmPitchAndFamily & 0xF0))
1134 return 0;
1135 }
1136
5f18d119
KH
1137 /* Check spacing */
1138 val = AREF (spec, FONT_SPACING_INDEX);
1139 if (INTEGERP (val))
1140 {
1141 int spacing = XINT (val);
1142 int proportional = (spacing < FONT_SPACING_MONO);
1143
1144 if ((proportional && !(font->ntmTm.tmPitchAndFamily & 0x01))
1145 || (!proportional && (font->ntmTm.tmPitchAndFamily & 0x01)))
1146 return 0;
1147 }
1148
d205d43b
JR
1149 /* Check extra parameters. */
1150 for (extra = AREF (spec, FONT_EXTRA_INDEX);
1151 CONSP (extra); extra = XCDR (extra))
1152 {
1153 Lisp_Object extra_entry;
1154 extra_entry = XCAR (extra);
1155 if (CONSP (extra_entry))
1156 {
1157 Lisp_Object key = XCAR (extra_entry);
d205d43b 1158
5f18d119
KH
1159 val = XCDR (extra_entry);
1160 if (EQ (key, QCscript) && SYMBOLP (val))
d205d43b
JR
1161 {
1162 /* Only truetype fonts will have information about what
1163 scripts they support. This probably means the user
1164 will have to force Emacs to use raster, postscript
1165 or atm fonts for non-ASCII text. */
1166 if (type & TRUETYPE_FONTTYPE)
1167 {
1168 Lisp_Object support
1169 = font_supported_scripts (&font->ntmFontSig);
1170 if (! memq_no_quit (val, support))
1171 return 0;
1172 }
1173 else
1174 {
1175 /* Return specific matches, but play it safe. Fonts
1176 that cover more than their charset would suggest
1177 are likely to be truetype or opentype fonts,
1178 covered above. */
1179 if (EQ (val, Qlatin))
1180 {
1181 /* Although every charset but symbol, thai and
1182 arabic contains the basic ASCII set of latin
1183 characters, Emacs expects much more. */
1184 if (font->ntmTm.tmCharSet != ANSI_CHARSET)
1185 return 0;
1186 }
1187 else if (EQ (val, Qsymbol))
1188 {
1189 if (font->ntmTm.tmCharSet != SYMBOL_CHARSET)
1190 return 0;
1191 }
1192 else if (EQ (val, Qcyrillic))
1193 {
1194 if (font->ntmTm.tmCharSet != RUSSIAN_CHARSET)
1195 return 0;
1196 }
1197 else if (EQ (val, Qgreek))
1198 {
1199 if (font->ntmTm.tmCharSet != GREEK_CHARSET)
1200 return 0;
1201 }
1202 else if (EQ (val, Qarabic))
1203 {
1204 if (font->ntmTm.tmCharSet != ARABIC_CHARSET)
1205 return 0;
1206 }
1207 else if (EQ (val, Qhebrew))
1208 {
1209 if (font->ntmTm.tmCharSet != HEBREW_CHARSET)
1210 return 0;
1211 }
1212 else if (EQ (val, Qthai))
1213 {
1214 if (font->ntmTm.tmCharSet != THAI_CHARSET)
1215 return 0;
1216 }
1217 else if (EQ (val, Qkana))
1218 {
1219 if (font->ntmTm.tmCharSet != SHIFTJIS_CHARSET)
1220 return 0;
1221 }
1222 else if (EQ (val, Qbopomofo))
1223 {
1224 if (font->ntmTm.tmCharSet != CHINESEBIG5_CHARSET)
1225 return 0;
1226 }
1227 else if (EQ (val, Qhangul))
1228 {
1229 if (font->ntmTm.tmCharSet != HANGUL_CHARSET
1230 && font->ntmTm.tmCharSet != JOHAB_CHARSET)
1231 return 0;
1232 }
1233 else if (EQ (val, Qhan))
1234 {
1235 if (font->ntmTm.tmCharSet != CHINESEBIG5_CHARSET
1236 && font->ntmTm.tmCharSet != GB2312_CHARSET
1237 && font->ntmTm.tmCharSet != HANGUL_CHARSET
1238 && font->ntmTm.tmCharSet != JOHAB_CHARSET
1239 && font->ntmTm.tmCharSet != SHIFTJIS_CHARSET)
1240 return 0;
1241 }
1242 else
56df6710
JR
1243 /* Other scripts unlikely to be handled by non-truetype
1244 fonts. */
d205d43b
JR
1245 return 0;
1246 }
1247 }
5f18d119 1248 else if (EQ (key, QClang) && SYMBOLP (val))
8f112d52
JR
1249 {
1250 /* Just handle the CJK languages here, as the language
1251 parameter is used to select a font with appropriate
1252 glyphs in the cjk unified ideographs block. Other fonts
1253 support for a language can be solely determined by
1254 its character coverage. */
1255 if (EQ (val, Qja))
1256 {
1257 if (font->ntmTm.tmCharSet != SHIFTJIS_CHARSET)
1258 return 0;
1259 }
1260 else if (EQ (val, Qko))
1261 {
1262 if (font->ntmTm.tmCharSet != HANGUL_CHARSET
1263 && font->ntmTm.tmCharSet != JOHAB_CHARSET)
1264 return 0;
1265 }
1266 else if (EQ (val, Qzh))
1267 {
1268 if (font->ntmTm.tmCharSet != GB2312_CHARSET
1269 && font->ntmTm.tmCharSet != CHINESEBIG5_CHARSET)
1270 return 0;
1271 }
1272 else
1273 /* Any other language, we don't recognize it. Fontset
1274 spec should have a fallback, as some backends do
1275 not recognize language at all. */
1276 return 0;
1277 }
56df6710
JR
1278 else if (EQ (key, QCotf) && CONSP (val))
1279 {
1280 /* OTF features only supported by the uniscribe backend. */
1281 if (EQ (backend, Quniscribe))
1282 {
1283 if (!uniscribe_check_otf (logfont, val))
1284 return 0;
1285 }
1286 else
1287 return 0;
1288 }
d205d43b
JR
1289 }
1290 }
1291 return 1;
1292}
1293
c960bff8
JR
1294static int
1295w32font_coverage_ok (coverage, charset)
1296 FONTSIGNATURE * coverage;
1297 BYTE charset;
1298{
1299 DWORD subrange1 = coverage->fsUsb[1];
1300
1301#define SUBRANGE1_HAN_MASK 0x08000000
1302#define SUBRANGE1_HANGEUL_MASK 0x01000000
1303#define SUBRANGE1_JAPANESE_MASK (0x00060000 | SUBRANGE1_HAN_MASK)
1304
1305 if (charset == GB2312_CHARSET || charset == CHINESEBIG5_CHARSET)
1306 {
1307 return (subrange1 & SUBRANGE1_HAN_MASK) == SUBRANGE1_HAN_MASK;
1308 }
1309 else if (charset == SHIFTJIS_CHARSET)
1310 {
1311 return (subrange1 & SUBRANGE1_JAPANESE_MASK) == SUBRANGE1_JAPANESE_MASK;
1312 }
1313 else if (charset == HANGEUL_CHARSET)
1314 {
1315 return (subrange1 & SUBRANGE1_HANGEUL_MASK) == SUBRANGE1_HANGEUL_MASK;
1316 }
1317
1318 return 1;
1319}
1320
f7a84cb4 1321/* Callback function for EnumFontFamiliesEx.
d205d43b
JR
1322 * Checks if a font matches everything we are trying to check agaist,
1323 * and if so, adds it to a list. Both the data we are checking against
1324 * and the list to which the fonts are added are passed in via the
1325 * lparam argument, in the form of a font_callback_data struct. */
20399669 1326static int CALLBACK
d205d43b 1327add_font_entity_to_list (logical_font, physical_font, font_type, lParam)
20399669
JR
1328 ENUMLOGFONTEX *logical_font;
1329 NEWTEXTMETRICEX *physical_font;
1330 DWORD font_type;
d205d43b 1331 LPARAM lParam;
f7a84cb4 1332{
d205d43b
JR
1333 struct font_callback_data *match_data
1334 = (struct font_callback_data *) lParam;
56df6710 1335 Lisp_Object backend = match_data->opentype_only ? Quniscribe : Qgdi;
f7a84cb4 1336
46fd1ded 1337 if ((!match_data->opentype_only
ef8e283d
JR
1338 || (((physical_font->ntmTm.ntmFlags & NTMFLAGS_OPENTYPE)
1339 || (font_type & TRUETYPE_FONTTYPE))
1340 /* For the uniscribe backend, only consider fonts that claim
1341 to cover at least some part of Unicode. */
1342 && (physical_font->ntmFontSig.fsUsb[3]
1343 || physical_font->ntmFontSig.fsUsb[2]
1344 || physical_font->ntmFontSig.fsUsb[1]
1345 || (physical_font->ntmFontSig.fsUsb[0] & 0x3fffffff))))
46fd1ded 1346 && logfonts_match (&logical_font->elfLogFont, &match_data->pattern)
d205d43b 1347 && font_matches_spec (font_type, physical_font,
56df6710
JR
1348 match_data->orig_font_spec, backend,
1349 &logical_font->elfLogFont)
c960bff8
JR
1350 && w32font_coverage_ok (&physical_font->ntmFontSig,
1351 match_data->pattern.lfCharSet)
4f2a2ee2
JR
1352 /* Avoid substitutions involving raster fonts (eg Helv -> MS Sans Serif)
1353 We limit this to raster fonts, because the test can catch some
1354 genuine fonts (eg the full name of DejaVu Sans Mono Light is actually
1355 DejaVu Sans Mono ExtraLight). Helvetica -> Arial substitution will
1356 therefore get through this test. Since full names can be prefixed
1357 by a foundry, we accept raster fonts if the font name is found
1358 anywhere within the full name. */
1359 && (logical_font->elfLogFont.lfOutPrecision != OUT_STRING_PRECIS
1360 || strstr (logical_font->elfFullName,
1361 logical_font->elfLogFont.lfFaceName)))
d205d43b
JR
1362 {
1363 Lisp_Object entity
1364 = w32_enumfont_pattern_entity (match_data->frame, logical_font,
91583281 1365 physical_font, font_type,
34fd2d28 1366 &match_data->pattern,
56df6710 1367 backend);
d205d43b 1368 if (!NILP (entity))
aee986fd
JR
1369 {
1370 Lisp_Object spec_charset = AREF (match_data->orig_font_spec,
1371 FONT_REGISTRY_INDEX);
1372
1373 /* If registry was specified as iso10646-1, only report
1374 ANSI and DEFAULT charsets, as most unicode fonts will
1375 contain one of those plus others. */
f42adef6
JR
1376 if ((EQ (spec_charset, Qiso10646_1)
1377 || EQ (spec_charset, Qunicode_bmp)
1378 || EQ (spec_charset, Qunicode_sip))
aee986fd
JR
1379 && logical_font->elfLogFont.lfCharSet != DEFAULT_CHARSET
1380 && logical_font->elfLogFont.lfCharSet != ANSI_CHARSET)
1381 return 1;
1382 /* If registry was specified, but did not map to a windows
1383 charset, only report fonts that have unknown charsets.
1384 This will still report fonts that don't match, but at
1385 least it eliminates known definite mismatches. */
1386 else if (!NILP (spec_charset)
1387 && !EQ (spec_charset, Qiso10646_1)
f42adef6
JR
1388 && !EQ (spec_charset, Qunicode_bmp)
1389 && !EQ (spec_charset, Qunicode_sip)
aee986fd
JR
1390 && match_data->pattern.lfCharSet == DEFAULT_CHARSET
1391 && logical_font->elfLogFont.lfCharSet != DEFAULT_CHARSET)
1392 return 1;
1393
1394 /* If registry was specified, ensure it is reported as the same. */
1395 if (!NILP (spec_charset))
1396 ASET (entity, FONT_REGISTRY_INDEX, spec_charset);
1397
1398 match_data->list = Fcons (entity, match_data->list);
1399
1400 /* If no registry specified, duplicate iso8859-1 truetype fonts
1401 as iso10646-1. */
1402 if (NILP (spec_charset)
1403 && font_type == TRUETYPE_FONTTYPE
1404 && logical_font->elfLogFont.lfCharSet == ANSI_CHARSET)
1405 {
1406 Lisp_Object tem = Fcopy_font_spec (entity);
1407 ASET (tem, FONT_REGISTRY_INDEX, Qiso10646_1);
1408 match_data->list = Fcons (tem, match_data->list);
1409 }
1410 }
d205d43b 1411 }
f7a84cb4
JR
1412 return 1;
1413}
1414
1415/* Callback function for EnumFontFamiliesEx.
d205d43b 1416 * Terminates the search once we have a match. */
20399669 1417static int CALLBACK
d205d43b 1418add_one_font_entity_to_list (logical_font, physical_font, font_type, lParam)
20399669
JR
1419 ENUMLOGFONTEX *logical_font;
1420 NEWTEXTMETRICEX *physical_font;
1421 DWORD font_type;
d205d43b 1422 LPARAM lParam;
f7a84cb4 1423{
d205d43b
JR
1424 struct font_callback_data *match_data
1425 = (struct font_callback_data *) lParam;
1426 add_font_entity_to_list (logical_font, physical_font, font_type, lParam);
1427
1428 /* If we have a font in the list, terminate the search. */
1429 return !NILP (match_data->list);
f7a84cb4
JR
1430}
1431
1432/* Convert a Lisp font registry (symbol) to a windows charset. */
20399669
JR
1433static LONG
1434registry_to_w32_charset (charset)
1435 Lisp_Object charset;
f7a84cb4
JR
1436{
1437 if (EQ (charset, Qiso10646_1) || EQ (charset, Qunicode_bmp)
1438 || EQ (charset, Qunicode_sip))
1439 return DEFAULT_CHARSET; /* UNICODE_CHARSET not defined in MingW32 */
1440 else if (EQ (charset, Qiso8859_1))
1441 return ANSI_CHARSET;
040fe918
JR
1442 else if (SYMBOLP (charset))
1443 return x_to_w32_charset (SDATA (SYMBOL_NAME (charset)));
f7a84cb4
JR
1444 else
1445 return DEFAULT_CHARSET;
1446}
1447
20399669 1448static Lisp_Object
c960bff8 1449w32_registry (w32_charset, font_type)
20399669 1450 LONG w32_charset;
c960bff8 1451 DWORD font_type;
f7a84cb4 1452{
aee986fd
JR
1453 char *charset;
1454
1455 /* If charset is defaulted, charset is unicode or unknown, depending on
1456 font type. */
c960bff8 1457 if (w32_charset == DEFAULT_CHARSET)
aee986fd 1458 return font_type == TRUETYPE_FONTTYPE ? Qiso10646_1 : Qunknown;
c960bff8 1459
aee986fd 1460 charset = w32_to_x_charset (w32_charset, NULL);
4cb35b63 1461 return font_intern_prop (charset, strlen(charset), 1);
f7a84cb4
JR
1462}
1463
5f18d119
KH
1464static int
1465w32_decode_weight (fnweight)
1466 int fnweight;
1467{
1468 if (fnweight >= FW_HEAVY) return 210;
1469 if (fnweight >= FW_EXTRABOLD) return 205;
1470 if (fnweight >= FW_BOLD) return 200;
1471 if (fnweight >= FW_SEMIBOLD) return 180;
1472 if (fnweight >= FW_NORMAL) return 100;
1473 if (fnweight >= FW_LIGHT) return 50;
1474 if (fnweight >= FW_EXTRALIGHT) return 40;
1475 if (fnweight > FW_THIN) return 20;
1476 return 0;
1477}
1478
1479static int
1480w32_encode_weight (n)
1481 int n;
1482{
1483 if (n >= 210) return FW_HEAVY;
1484 if (n >= 205) return FW_EXTRABOLD;
1485 if (n >= 200) return FW_BOLD;
1486 if (n >= 180) return FW_SEMIBOLD;
1487 if (n >= 100) return FW_NORMAL;
1488 if (n >= 50) return FW_LIGHT;
1489 if (n >= 40) return FW_EXTRALIGHT;
1490 if (n >= 20) return FW_THIN;
1491 return 0;
1492}
1493
3ef8c1b4
JR
1494/* Convert a Windows font weight into one of the weights supported
1495 by fontconfig (see font.c:font_parse_fcname). */
1496static Lisp_Object
1497w32_to_fc_weight (n)
1498 int n;
1499{
1500 if (n >= FW_EXTRABOLD) return intern ("black");
1501 if (n >= FW_BOLD) return intern ("bold");
1502 if (n >= FW_SEMIBOLD) return intern ("demibold");
1503 if (n >= FW_NORMAL) return intern ("medium");
1504 return intern ("light");
1505}
1506
f7a84cb4 1507/* Fill in all the available details of LOGFONT from FONT_SPEC. */
20399669
JR
1508static void
1509fill_in_logfont (f, logfont, font_spec)
1510 FRAME_PTR f;
1511 LOGFONT *logfont;
1512 Lisp_Object font_spec;
f7a84cb4 1513{
d205d43b 1514 Lisp_Object tmp, extra;
f7a84cb4
JR
1515 int dpi = FRAME_W32_DISPLAY_INFO (f)->resy;
1516
5f18d119
KH
1517 tmp = AREF (font_spec, FONT_DPI_INDEX);
1518 if (INTEGERP (tmp))
d205d43b 1519 {
5f18d119
KH
1520 dpi = XINT (tmp);
1521 }
1522 else if (FLOATP (tmp))
1523 {
1524 dpi = (int) (XFLOAT_DATA (tmp) + 0.5);
d205d43b 1525 }
f7a84cb4
JR
1526
1527 /* Height */
1528 tmp = AREF (font_spec, FONT_SIZE_INDEX);
1529 if (INTEGERP (tmp))
040fe918 1530 logfont->lfHeight = -1 * XINT (tmp);
f7a84cb4 1531 else if (FLOATP (tmp))
d205d43b 1532 logfont->lfHeight = (int) (-1.0 * dpi * XFLOAT_DATA (tmp) / 72.27 + 0.5);
f7a84cb4
JR
1533
1534 /* Escapement */
1535
1536 /* Orientation */
1537
1538 /* Weight */
1539 tmp = AREF (font_spec, FONT_WEIGHT_INDEX);
1540 if (INTEGERP (tmp))
5f18d119 1541 logfont->lfWeight = w32_encode_weight (FONT_WEIGHT_NUMERIC (font_spec));
f7a84cb4
JR
1542
1543 /* Italic */
1544 tmp = AREF (font_spec, FONT_SLANT_INDEX);
1545 if (INTEGERP (tmp))
1546 {
5f18d119 1547 int slant = FONT_SLANT_NUMERIC (font_spec);
f7a84cb4
JR
1548 logfont->lfItalic = slant > 150 ? 1 : 0;
1549 }
1550
1551 /* Underline */
1552
1553 /* Strikeout */
1554
1555 /* Charset */
1556 tmp = AREF (font_spec, FONT_REGISTRY_INDEX);
1557 if (! NILP (tmp))
d205d43b 1558 logfont->lfCharSet = registry_to_w32_charset (tmp);
56df6710
JR
1559 else
1560 logfont->lfCharSet = DEFAULT_CHARSET;
f7a84cb4
JR
1561
1562 /* Out Precision */
91583281 1563
f7a84cb4 1564 /* Clip Precision */
91583281
JR
1565
1566 /* Quality */
040fe918
JR
1567 logfont->lfQuality = DEFAULT_QUALITY;
1568
d205d43b
JR
1569 /* Generic Family and Face Name */
1570 logfont->lfPitchAndFamily = FF_DONTCARE | DEFAULT_PITCH;
1571
f7a84cb4 1572 tmp = AREF (font_spec, FONT_FAMILY_INDEX);
d205d43b
JR
1573 if (! NILP (tmp))
1574 {
1575 logfont->lfPitchAndFamily = w32_generic_family (tmp) | DEFAULT_PITCH;
1576 if ((logfont->lfPitchAndFamily & 0xF0) != FF_DONTCARE)
1577 ; /* Font name was generic, don't fill in font name. */
1578 /* Font families are interned, but allow for strings also in case of
1579 user input. */
1580 else if (SYMBOLP (tmp))
1581 strncpy (logfont->lfFaceName, SDATA (SYMBOL_NAME (tmp)), LF_FACESIZE);
d205d43b 1582 }
f7a84cb4 1583
9e1a2995
JR
1584 tmp = AREF (font_spec, FONT_ADSTYLE_INDEX);
1585 if (!NILP (tmp))
1586 {
1587 /* Override generic family. */
1588 BYTE family = w32_generic_family (tmp);
1589 if (family != FF_DONTCARE)
1590 logfont->lfPitchAndFamily = family | DEFAULT_PITCH;
1591 }
1592
9c623c85 1593
5f18d119
KH
1594 /* Set pitch based on the spacing property. */
1595 tmp = AREF (font_spec, FONT_SPACING_INDEX);
1596 if (INTEGERP (tmp))
1597 {
1598 int spacing = XINT (tmp);
1599 if (spacing < FONT_SPACING_MONO)
1600 logfont->lfPitchAndFamily
1601 = logfont->lfPitchAndFamily & 0xF0 | VARIABLE_PITCH;
1602 else
1603 logfont->lfPitchAndFamily
1604 = logfont->lfPitchAndFamily & 0xF0 | FIXED_PITCH;
1605 }
1606
d205d43b 1607 /* Process EXTRA info. */
5f18d119
KH
1608 for (extra = AREF (font_spec, FONT_EXTRA_INDEX);
1609 CONSP (extra); extra = XCDR (extra))
d205d43b
JR
1610 {
1611 tmp = XCAR (extra);
1612 if (CONSP (tmp))
1613 {
1614 Lisp_Object key, val;
1615 key = XCAR (tmp), val = XCDR (tmp);
d205d43b
JR
1616 /* Only use QCscript if charset is not provided, or is unicode
1617 and a single script is specified. This is rather crude,
1618 and is only used to narrow down the fonts returned where
1619 there is a definite match. Some scripts, such as latin, han,
1620 cjk-misc match multiple lfCharSet values, so we can't pre-filter
1621 them. */
5f18d119 1622 if (EQ (key, QCscript)
d205d43b
JR
1623 && logfont->lfCharSet == DEFAULT_CHARSET
1624 && SYMBOLP (val))
1625 {
1626 if (EQ (val, Qgreek))
1627 logfont->lfCharSet = GREEK_CHARSET;
1628 else if (EQ (val, Qhangul))
1629 logfont->lfCharSet = HANGUL_CHARSET;
1630 else if (EQ (val, Qkana) || EQ (val, Qkanbun))
1631 logfont->lfCharSet = SHIFTJIS_CHARSET;
1632 else if (EQ (val, Qbopomofo))
1633 logfont->lfCharSet = CHINESEBIG5_CHARSET;
1634 /* GB 18030 supports tibetan, yi, mongolian,
1635 fonts that support it should show up if we ask for
1636 GB2312 fonts. */
1637 else if (EQ (val, Qtibetan) || EQ (val, Qyi)
1638 || EQ (val, Qmongolian))
1639 logfont->lfCharSet = GB2312_CHARSET;
1640 else if (EQ (val, Qhebrew))
1641 logfont->lfCharSet = HEBREW_CHARSET;
1642 else if (EQ (val, Qarabic))
1643 logfont->lfCharSet = ARABIC_CHARSET;
1644 else if (EQ (val, Qthai))
1645 logfont->lfCharSet = THAI_CHARSET;
1646 else if (EQ (val, Qsymbol))
1647 logfont->lfCharSet = SYMBOL_CHARSET;
1648 }
91583281
JR
1649 else if (EQ (key, QCantialias) && SYMBOLP (val))
1650 {
1651 logfont->lfQuality = w32_antialias_type (val);
1652 }
d205d43b
JR
1653 }
1654 }
f7a84cb4
JR
1655}
1656
20399669 1657static void
d205d43b
JR
1658list_all_matching_fonts (match_data)
1659 struct font_callback_data *match_data;
f7a84cb4
JR
1660{
1661 HDC dc;
d205d43b
JR
1662 Lisp_Object families = w32font_list_family (match_data->frame);
1663 struct frame *f = XFRAME (match_data->frame);
f7a84cb4
JR
1664
1665 dc = get_frame_dc (f);
1666
1667 while (!NILP (families))
1668 {
d205d43b
JR
1669 /* TODO: Use the Unicode versions of the W32 APIs, so we can
1670 handle non-ASCII font names. */
1671 char *name;
f7a84cb4
JR
1672 Lisp_Object family = CAR (families);
1673 families = CDR (families);
d205d43b
JR
1674 if (NILP (family))
1675 continue;
8f112d52 1676 else if (SYMBOLP (family))
9c623c85 1677 name = SDATA (SYMBOL_NAME (family));
8f112d52
JR
1678 else
1679 continue;
d205d43b
JR
1680
1681 strncpy (match_data->pattern.lfFaceName, name, LF_FACESIZE);
1682 match_data->pattern.lfFaceName[LF_FACESIZE - 1] = '\0';
1683
1684 EnumFontFamiliesEx (dc, &match_data->pattern,
1685 (FONTENUMPROC) add_font_entity_to_list,
1686 (LPARAM) match_data, 0);
f7a84cb4
JR
1687 }
1688
1689 release_frame_dc (f, dc);
1690}
1691
91583281
JR
1692static Lisp_Object
1693lispy_antialias_type (type)
1694 BYTE type;
1695{
1696 Lisp_Object lispy;
1697
1698 switch (type)
1699 {
1700 case NONANTIALIASED_QUALITY:
1701 lispy = Qnone;
1702 break;
1703 case ANTIALIASED_QUALITY:
1704 lispy = Qstandard;
1705 break;
1706 case CLEARTYPE_QUALITY:
1707 lispy = Qsubpixel;
1708 break;
1709 case CLEARTYPE_NATURAL_QUALITY:
1710 lispy = Qnatural;
1711 break;
1712 default:
1713 lispy = Qnil;
1714 break;
1715 }
1716 return lispy;
1717}
1718
1719/* Convert antialiasing symbols to lfQuality */
1720static BYTE
1721w32_antialias_type (type)
1722 Lisp_Object type;
1723{
1724 if (EQ (type, Qnone))
1725 return NONANTIALIASED_QUALITY;
1726 else if (EQ (type, Qstandard))
1727 return ANTIALIASED_QUALITY;
1728 else if (EQ (type, Qsubpixel))
1729 return CLEARTYPE_QUALITY;
1730 else if (EQ (type, Qnatural))
1731 return CLEARTYPE_NATURAL_QUALITY;
1732 else
1733 return DEFAULT_QUALITY;
1734}
1735
d205d43b
JR
1736/* Return a list of all the scripts that the font supports. */
1737static Lisp_Object
1738font_supported_scripts (FONTSIGNATURE * sig)
f7a84cb4 1739{
d205d43b
JR
1740 DWORD * subranges = sig->fsUsb;
1741 Lisp_Object supported = Qnil;
1742
1743 /* Match a single subrange. SYM is set if bit N is set in subranges. */
1744#define SUBRANGE(n,sym) \
1745 if (subranges[(n) / 32] & (1 << ((n) % 32))) \
1746 supported = Fcons ((sym), supported)
1747
1748 /* Match multiple subranges. SYM is set if any MASK bit is set in
1749 subranges[0 - 3]. */
1750#define MASK_ANY(mask0,mask1,mask2,mask3,sym) \
1751 if ((subranges[0] & (mask0)) || (subranges[1] & (mask1)) \
1752 || (subranges[2] & (mask2)) || (subranges[3] & (mask3))) \
1753 supported = Fcons ((sym), supported)
1754
56df6710
JR
1755 SUBRANGE (0, Qlatin);
1756 /* The following count as latin too, ASCII should be present in these fonts,
1757 so don't need to mark them separately. */
1758 /* 1: Latin-1 supplement, 2: Latin Extended A, 3: Latin Extended B. */
1759 SUBRANGE (4, Qphonetic);
1760 /* 5: Spacing and tone modifiers, 6: Combining Diacriticals. */
d205d43b
JR
1761 SUBRANGE (7, Qgreek);
1762 SUBRANGE (8, Qcoptic);
1763 SUBRANGE (9, Qcyrillic);
1764 SUBRANGE (10, Qarmenian);
1765 SUBRANGE (11, Qhebrew);
1766 SUBRANGE (13, Qarabic);
1767 SUBRANGE (14, Qnko);
1768 SUBRANGE (15, Qdevanagari);
1769 SUBRANGE (16, Qbengali);
1770 SUBRANGE (17, Qgurmukhi);
1771 SUBRANGE (18, Qgujarati);
1772 SUBRANGE (19, Qoriya);
1773 SUBRANGE (20, Qtamil);
1774 SUBRANGE (21, Qtelugu);
1775 SUBRANGE (22, Qkannada);
1776 SUBRANGE (23, Qmalayalam);
1777 SUBRANGE (24, Qthai);
1778 SUBRANGE (25, Qlao);
1779 SUBRANGE (26, Qgeorgian);
56df6710
JR
1780 SUBRANGE (27, Qbalinese);
1781 /* 28: Hangul Jamo. */
1782 /* 29: Latin Extended, 30: Greek Extended, 31: Punctuation. */
1783 /* 32-47: Symbols (defined below). */
d205d43b 1784 SUBRANGE (48, Qcjk_misc);
56df6710
JR
1785 /* Match either 49: katakana or 50: hiragana for kana. */
1786 MASK_ANY (0, 0x00060000, 0, 0, Qkana);
d205d43b 1787 SUBRANGE (51, Qbopomofo);
56df6710
JR
1788 /* 52: Compatibility Jamo */
1789 SUBRANGE (53, Qphags_pa);
1790 /* 54: Enclosed CJK letters and months, 55: CJK Compatibility. */
d205d43b 1791 SUBRANGE (56, Qhangul);
56df6710
JR
1792 /* 57: Surrogates. */
1793 SUBRANGE (58, Qphoenician);
d205d43b 1794 SUBRANGE (59, Qhan); /* There are others, but this is the main one. */
56df6710
JR
1795 SUBRANGE (59, Qideographic_description); /* Windows lumps this in. */
1796 SUBRANGE (59, Qkanbun); /* And this. */
1797 /* 60: Private use, 61: CJK strokes and compatibility. */
1798 /* 62: Alphabetic Presentation, 63: Arabic Presentation A. */
1799 /* 64: Combining half marks, 65: Vertical and CJK compatibility. */
1800 /* 66: Small forms, 67: Arabic Presentation B, 68: Half and Full width. */
1801 /* 69: Specials. */
d205d43b
JR
1802 SUBRANGE (70, Qtibetan);
1803 SUBRANGE (71, Qsyriac);
1804 SUBRANGE (72, Qthaana);
1805 SUBRANGE (73, Qsinhala);
1806 SUBRANGE (74, Qmyanmar);
1807 SUBRANGE (75, Qethiopic);
1808 SUBRANGE (76, Qcherokee);
1809 SUBRANGE (77, Qcanadian_aboriginal);
1810 SUBRANGE (78, Qogham);
1811 SUBRANGE (79, Qrunic);
1812 SUBRANGE (80, Qkhmer);
1813 SUBRANGE (81, Qmongolian);
1814 SUBRANGE (82, Qbraille);
1815 SUBRANGE (83, Qyi);
56df6710
JR
1816 SUBRANGE (84, Qbuhid);
1817 SUBRANGE (84, Qhanunoo);
1818 SUBRANGE (84, Qtagalog);
1819 SUBRANGE (84, Qtagbanwa);
1820 SUBRANGE (85, Qold_italic);
1821 SUBRANGE (86, Qgothic);
1822 SUBRANGE (87, Qdeseret);
d205d43b
JR
1823 SUBRANGE (88, Qbyzantine_musical_symbol);
1824 SUBRANGE (88, Qmusical_symbol); /* Windows doesn't distinguish these. */
d205d43b 1825 SUBRANGE (89, Qmathematical);
56df6710
JR
1826 /* 90: Private use, 91: Variation selectors, 92: Tags. */
1827 SUBRANGE (93, Qlimbu);
1828 SUBRANGE (94, Qtai_le);
1829 /* 95: New Tai Le */
1830 SUBRANGE (90, Qbuginese);
1831 SUBRANGE (97, Qglagolitic);
1832 SUBRANGE (98, Qtifinagh);
1833 /* 99: Yijing Hexagrams. */
1834 SUBRANGE (100, Qsyloti_nagri);
1835 SUBRANGE (101, Qlinear_b);
1836 /* 102: Ancient Greek Numbers. */
1837 SUBRANGE (103, Qugaritic);
1838 SUBRANGE (104, Qold_persian);
1839 SUBRANGE (105, Qshavian);
1840 SUBRANGE (106, Qosmanya);
1841 SUBRANGE (107, Qcypriot);
1842 SUBRANGE (108, Qkharoshthi);
1843 /* 109: Tai Xuan Jing. */
1844 SUBRANGE (110, Qcuneiform);
1845 /* 111: Counting Rods. */
d205d43b
JR
1846
1847 /* There isn't really a main symbol range, so include symbol if any
1848 relevant range is set. */
1849 MASK_ANY (0x8000000, 0x0000FFFF, 0, 0, Qsymbol);
1850
56df6710 1851 /* Missing: Tai Viet (U+AA80) and Cham (U+AA00) . */
d205d43b
JR
1852#undef SUBRANGE
1853#undef MASK_ANY
1854
1855 return supported;
f7a84cb4
JR
1856}
1857
67997c79
JR
1858/* Generate a full name for a Windows font.
1859 The full name is in fcname format, with weight, slant and antialiasing
1860 specified if they are not "normal". */
1861static int
1862w32font_full_name (font, font_obj, pixel_size, name, nbytes)
1863 LOGFONT * font;
1864 Lisp_Object font_obj;
1865 int pixel_size;
1866 char *name;
1867 int nbytes;
1868{
a823468b 1869 int len, height, outline;
67997c79
JR
1870 char *p;
1871 Lisp_Object antialiasing, weight = Qnil;
1872
a823468b
JR
1873 len = strlen (font->lfFaceName);
1874
1875 outline = EQ (AREF (font_obj, FONT_FOUNDRY_INDEX), Qoutline);
1876
1877 /* Represent size of scalable fonts by point size. But use pixelsize for
1878 raster fonts to indicate that they are exactly that size. */
1879 if (outline)
1880 len += 11; /* -SIZE */
1881 else
6fe9826d 1882 len += 21;
67997c79
JR
1883
1884 if (font->lfItalic)
1885 len += 7; /* :italic */
1886
1887 if (font->lfWeight && font->lfWeight != FW_NORMAL)
1888 {
3ef8c1b4
JR
1889 weight = w32_to_fc_weight (font->lfWeight);
1890 len += 1 + SBYTES (SYMBOL_NAME (weight)); /* :WEIGHT */
67997c79
JR
1891 }
1892
1893 antialiasing = lispy_antialias_type (font->lfQuality);
1894 if (! NILP (antialiasing))
1895 len += 11 + SBYTES (SYMBOL_NAME (antialiasing)); /* :antialias=NAME */
1896
1897 /* Check that the buffer is big enough */
1898 if (len > nbytes)
1899 return -1;
1900
1901 p = name;
1902 p += sprintf (p, "%s", font->lfFaceName);
1903
a823468b
JR
1904 height = font->lfHeight ? eabs (font->lfHeight) : pixel_size;
1905
1906 if (height > 0)
1907 {
1908 if (outline)
1909 {
1910 float pointsize = height * 72.0 / one_w32_display_info.resy;
7145be81
JR
1911 /* Round to nearest half point. floor is used, since round is not
1912 supported in MS library. */
1913 pointsize = floor (pointsize * 2 + 0.5) / 2;
a823468b
JR
1914 p += sprintf (p, "-%1.1f", pointsize);
1915 }
1916 else
1917 p += sprintf (p, ":pixelsize=%d", height);
1918 }
67997c79 1919
3ef8c1b4
JR
1920 if (SYMBOLP (weight) && ! NILP (weight))
1921 p += sprintf (p, ":%s", SDATA (SYMBOL_NAME (weight)));
1922
67997c79
JR
1923 if (font->lfItalic)
1924 p += sprintf (p, ":italic");
1925
67997c79
JR
1926 if (SYMBOLP (antialiasing) && ! NILP (antialiasing))
1927 p += sprintf (p, ":antialias=%s", SDATA (SYMBOL_NAME (antialiasing)));
1928
1929 return (p - name);
1930}
f7a84cb4 1931
6fe9826d
JR
1932/* Convert a logfont and point size into a fontconfig style font name.
1933 POINTSIZE is in tenths of points.
1934 If SIZE indicates the size of buffer FCNAME, into which the font name
1935 is written. If the buffer is not large enough to contain the name,
1936 the function returns -1, otherwise it returns the number of bytes
1937 written to FCNAME. */
1938static int logfont_to_fcname(font, pointsize, fcname, size)
1939 LOGFONT* font;
1940 int pointsize;
1941 char *fcname;
1942 int size;
1943{
1944 int len, height;
1945 char *p = fcname;
1946 Lisp_Object weight = Qnil;
1947
1948 len = strlen (font->lfFaceName) + 2;
1949 height = pointsize / 10;
1950 while (height /= 10)
1951 len++;
1952
1953 if (pointsize % 10)
1954 len += 2;
1955
1956 if (font->lfItalic)
1957 len += 7; /* :italic */
1958 if (font->lfWeight && font->lfWeight != FW_NORMAL)
1959 {
3ef8c1b4
JR
1960 weight = w32_to_fc_weight (font->lfWeight);
1961 len += SBYTES (SYMBOL_NAME (weight)) + 1;
6fe9826d
JR
1962 }
1963
1964 if (len > size)
1965 return -1;
1966
1967 p += sprintf (p, "%s-%d", font->lfFaceName, pointsize / 10);
1968 if (pointsize % 10)
1969 p += sprintf (p, ".%d", pointsize % 10);
1970
3ef8c1b4
JR
1971 if (SYMBOLP (weight) && !NILP (weight))
1972 p += sprintf (p, ":%s", SDATA (SYMBOL_NAME (weight)));
1973
6fe9826d
JR
1974 if (font->lfItalic)
1975 p += sprintf (p, ":italic");
1976
6fe9826d
JR
1977 return (p - fcname);
1978}
34fd2d28 1979
9c623c85
JB
1980static void
1981compute_metrics (dc, w32_font, code, metrics)
34fd2d28 1982 HDC dc;
54efdcd1 1983 struct w32font_info *w32_font;
8f112d52
JR
1984 unsigned int code;
1985 struct w32_metric_cache *metrics;
34fd2d28
JR
1986{
1987 GLYPHMETRICS gm;
1988 MAT2 transform;
8f112d52
JR
1989 unsigned int options = GGO_METRICS;
1990
1991 if (w32_font->glyph_idx)
1992 options |= GGO_GLYPH_INDEX;
34fd2d28
JR
1993
1994 bzero (&transform, sizeof (transform));
1995 transform.eM11.value = 1;
1996 transform.eM22.value = 1;
8f112d52
JR
1997
1998 if (GetGlyphOutlineW (dc, code, options, &gm, 0, NULL, &transform)
1999 != GDI_ERROR)
2000 {
2001 metrics->lbearing = gm.gmptGlyphOrigin.x;
2002 metrics->rbearing = gm.gmptGlyphOrigin.x + gm.gmBlackBoxX;
2003 metrics->width = gm.gmCellIncX;
2004 metrics->status = W32METRIC_SUCCESS;
2005 }
9c623c85 2006 else if (w32_font->glyph_idx)
34fd2d28 2007 {
9c623c85
JB
2008 /* Can't use glyph indexes after all.
2009 Avoid it in future, and clear any metrics that were based on
2010 glyph indexes. */
2011 w32_font->glyph_idx = 0;
2012 clear_cached_metrics (w32_font);
34fd2d28 2013 }
9c623c85
JB
2014 else
2015 metrics->status = W32METRIC_FAIL;
34fd2d28
JR
2016}
2017
8f112d52
JR
2018static void
2019clear_cached_metrics (w32_font)
2020 struct w32font_info *w32_font;
2021{
2022 int i;
2023 for (i = 0; i < w32_font->n_cache_blocks; i++)
5f18d119
KH
2024 {
2025 if (w32_font->cached_metrics[i])
2026 bzero (w32_font->cached_metrics[i],
2027 CACHE_BLOCKSIZE * sizeof (struct font_metrics));
2028 }
8f112d52
JR
2029}
2030
6fe9826d
JR
2031DEFUN ("x-select-font", Fx_select_font, Sx_select_font, 0, 2, 0,
2032 doc: /* Read a font name using a W32 font selection dialog.
2033Return fontconfig style font string corresponding to the selection.
2034
2035If FRAME is omitted or nil, it defaults to the selected frame.
2036If INCLUDE-PROPORTIONAL is non-nil, include proportional fonts
2037in the font selection dialog. */)
2038 (frame, include_proportional)
2039 Lisp_Object frame, include_proportional;
2040{
2041 FRAME_PTR f = check_x_frame (frame);
2042 CHOOSEFONT cf;
2043 LOGFONT lf;
2044 TEXTMETRIC tm;
2045 HDC hdc;
2046 HANDLE oldobj;
2047 char buf[100];
2048
2049 bzero (&cf, sizeof (cf));
2050 bzero (&lf, sizeof (lf));
2051
2052 cf.lStructSize = sizeof (cf);
2053 cf.hwndOwner = FRAME_W32_WINDOW (f);
2054 cf.Flags = CF_FORCEFONTEXIST | CF_SCREENFONTS | CF_NOVERTFONTS;
2055
2056 /* Unless include_proportional is non-nil, limit the selection to
2057 monospaced fonts. */
2058 if (NILP (include_proportional))
2059 cf.Flags |= CF_FIXEDPITCHONLY;
2060
2061 cf.lpLogFont = &lf;
2062
2063 /* Initialize as much of the font details as we can from the current
2064 default font. */
2065 hdc = GetDC (FRAME_W32_WINDOW (f));
2066 oldobj = SelectObject (hdc, FONT_COMPAT (FRAME_FONT (f))->hfont);
2067 GetTextFace (hdc, LF_FACESIZE, lf.lfFaceName);
2068 if (GetTextMetrics (hdc, &tm))
2069 {
2070 lf.lfHeight = tm.tmInternalLeading - tm.tmHeight;
2071 lf.lfWeight = tm.tmWeight;
2072 lf.lfItalic = tm.tmItalic;
2073 lf.lfUnderline = tm.tmUnderlined;
2074 lf.lfStrikeOut = tm.tmStruckOut;
2075 lf.lfCharSet = tm.tmCharSet;
2076 cf.Flags |= CF_INITTOLOGFONTSTRUCT;
2077 }
2078 SelectObject (hdc, oldobj);
2079 ReleaseDC (FRAME_W32_WINDOW (f), hdc);
2080
2081 if (!ChooseFont (&cf)
2082 || logfont_to_fcname (&lf, cf.iPointSize, buf, 100) < 0)
2083 return Qnil;
2084
2085 return build_string (buf);
2086}
2087
f7a84cb4
JR
2088struct font_driver w32font_driver =
2089 {
8eac0c84 2090 0, /* Qgdi */
5f18d119 2091 0, /* case insensitive */
f7a84cb4
JR
2092 w32font_get_cache,
2093 w32font_list,
2094 w32font_match,
2095 w32font_list_family,
2096 NULL, /* free_entity */
2097 w32font_open,
2098 w32font_close,
2099 NULL, /* prepare_face */
2100 NULL, /* done_face */
2101 w32font_has_char,
2102 w32font_encode_char,
2103 w32font_text_extents,
2104 w32font_draw,
2105 NULL, /* get_bitmap */
2106 NULL, /* free_bitmap */
2107 NULL, /* get_outline */
2108 NULL, /* free_outline */
2109 NULL, /* anchor_point */
2110 NULL, /* otf_capability */
5b0c3446
JR
2111 NULL, /* otf_drive */
2112 NULL, /* start_for_frame */
2113 NULL, /* end_for_frame */
2114 NULL /* shape */
f7a84cb4
JR
2115 };
2116
f7a84cb4
JR
2117
2118/* Initialize state that does not change between invocations. This is only
2119 called when Emacs is dumped. */
20399669
JR
2120void
2121syms_of_w32font ()
f7a84cb4 2122{
8eac0c84 2123 DEFSYM (Qgdi, "gdi");
34fd2d28
JR
2124 DEFSYM (Quniscribe, "uniscribe");
2125 DEFSYM (QCformat, ":format");
d205d43b
JR
2126
2127 /* Generic font families. */
2128 DEFSYM (Qmonospace, "monospace");
2129 DEFSYM (Qserif, "serif");
9e1a2995 2130 DEFSYM (Qsansserif, "sansserif");
f7a84cb4 2131 DEFSYM (Qscript, "script");
d205d43b
JR
2132 DEFSYM (Qdecorative, "decorative");
2133 /* Aliases. */
9e1a2995 2134 DEFSYM (Qsans_serif, "sans_serif");
d205d43b
JR
2135 DEFSYM (Qsans, "sans");
2136 DEFSYM (Qmono, "mono");
2137
2138 /* Fake foundries. */
2139 DEFSYM (Qraster, "raster");
2140 DEFSYM (Qoutline, "outline");
f7a84cb4 2141 DEFSYM (Qunknown, "unknown");
d205d43b 2142
91583281
JR
2143 /* Antialiasing. */
2144 DEFSYM (Qstandard, "standard");
2145 DEFSYM (Qsubpixel, "subpixel");
2146 DEFSYM (Qnatural, "natural");
d205d43b 2147
8f112d52
JR
2148 /* Languages */
2149 DEFSYM (Qja, "ja");
2150 DEFSYM (Qko, "ko");
2151 DEFSYM (Qzh, "zh");
2152
d205d43b
JR
2153 /* Scripts */
2154 DEFSYM (Qlatin, "latin");
2155 DEFSYM (Qgreek, "greek");
2156 DEFSYM (Qcoptic, "coptic");
2157 DEFSYM (Qcyrillic, "cyrillic");
2158 DEFSYM (Qarmenian, "armenian");
2159 DEFSYM (Qhebrew, "hebrew");
2160 DEFSYM (Qarabic, "arabic");
2161 DEFSYM (Qsyriac, "syriac");
2162 DEFSYM (Qnko, "nko");
2163 DEFSYM (Qthaana, "thaana");
2164 DEFSYM (Qdevanagari, "devanagari");
2165 DEFSYM (Qbengali, "bengali");
2166 DEFSYM (Qgurmukhi, "gurmukhi");
2167 DEFSYM (Qgujarati, "gujarati");
2168 DEFSYM (Qoriya, "oriya");
2169 DEFSYM (Qtamil, "tamil");
2170 DEFSYM (Qtelugu, "telugu");
2171 DEFSYM (Qkannada, "kannada");
2172 DEFSYM (Qmalayalam, "malayalam");
2173 DEFSYM (Qsinhala, "sinhala");
2174 DEFSYM (Qthai, "thai");
2175 DEFSYM (Qlao, "lao");
2176 DEFSYM (Qtibetan, "tibetan");
2177 DEFSYM (Qmyanmar, "myanmar");
2178 DEFSYM (Qgeorgian, "georgian");
2179 DEFSYM (Qhangul, "hangul");
2180 DEFSYM (Qethiopic, "ethiopic");
2181 DEFSYM (Qcherokee, "cherokee");
2182 DEFSYM (Qcanadian_aboriginal, "canadian-aboriginal");
2183 DEFSYM (Qogham, "ogham");
2184 DEFSYM (Qrunic, "runic");
2185 DEFSYM (Qkhmer, "khmer");
2186 DEFSYM (Qmongolian, "mongolian");
2187 DEFSYM (Qsymbol, "symbol");
2188 DEFSYM (Qbraille, "braille");
2189 DEFSYM (Qhan, "han");
2190 DEFSYM (Qideographic_description, "ideographic-description");
2191 DEFSYM (Qcjk_misc, "cjk-misc");
2192 DEFSYM (Qkana, "kana");
2193 DEFSYM (Qbopomofo, "bopomofo");
2194 DEFSYM (Qkanbun, "kanbun");
2195 DEFSYM (Qyi, "yi");
2196 DEFSYM (Qbyzantine_musical_symbol, "byzantine-musical-symbol");
2197 DEFSYM (Qmusical_symbol, "musical-symbol");
2198 DEFSYM (Qmathematical, "mathematical");
56df6710
JR
2199 DEFSYM (Qphonetic, "phonetic");
2200 DEFSYM (Qbalinese, "balinese");
2201 DEFSYM (Qbuginese, "buginese");
2202 DEFSYM (Qbuhid, "buhid");
2203 DEFSYM (Qcuneiform, "cuneiform");
2204 DEFSYM (Qcypriot, "cypriot");
2205 DEFSYM (Qdeseret, "deseret");
2206 DEFSYM (Qglagolitic, "glagolitic");
2207 DEFSYM (Qgothic, "gothic");
2208 DEFSYM (Qhanunoo, "hanunoo");
2209 DEFSYM (Qkharoshthi, "kharoshthi");
2210 DEFSYM (Qlimbu, "limbu");
2211 DEFSYM (Qlinear_b, "linear_b");
2212 DEFSYM (Qold_italic, "old_italic");
2213 DEFSYM (Qold_persian, "old_persian");
2214 DEFSYM (Qosmanya, "osmanya");
2215 DEFSYM (Qphags_pa, "phags-pa");
2216 DEFSYM (Qphoenician, "phoenician");
2217 DEFSYM (Qshavian, "shavian");
2218 DEFSYM (Qsyloti_nagri, "syloti_nagri");
2219 DEFSYM (Qtagalog, "tagalog");
2220 DEFSYM (Qtagbanwa, "tagbanwa");
2221 DEFSYM (Qtai_le, "tai_le");
2222 DEFSYM (Qtifinagh, "tifinagh");
2223 DEFSYM (Qugaritic, "ugaritic");
d205d43b 2224
6fe9826d
JR
2225 defsubr (&Sx_select_font);
2226
8eac0c84 2227 w32font_driver.type = Qgdi;
f7a84cb4
JR
2228 register_font_driver (&w32font_driver, NULL);
2229}
6d8c85b5
MB
2230
2231/* arch-tag: 65b8a3cd-46aa-4c0d-a1f3-99e75b9c07ee
2232 (do not change this comment) */