diff options
| author | Kenichi Handa | 2010-10-29 09:50:13 +0900 |
|---|---|---|
| committer | Kenichi Handa | 2010-10-29 09:50:13 +0900 |
| commit | b2cca8569ad863c651dde1523ed841b280a96658 (patch) | |
| tree | 1fe09dc61ed7cb5c690f7446058216fdfbfbb6b9 /src | |
| parent | 8289f37b64d3734339f8c82a1e444113873d8d25 (diff) | |
| download | emacs-b2cca8569ad863c651dde1523ed841b280a96658.tar.gz emacs-b2cca8569ad863c651dde1523ed841b280a96658.zip | |
Implement various display methods for glyphless characters.
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 43 | ||||
| -rw-r--r-- | src/dispextern.h | 45 | ||||
| -rw-r--r-- | src/nsterm.m | 16 | ||||
| -rw-r--r-- | src/w32term.c | 95 | ||||
| -rw-r--r-- | src/xdisp.c | 443 | ||||
| -rw-r--r-- | src/xterm.c | 85 |
6 files changed, 702 insertions, 25 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index f3e2ea7854e..0928978ba28 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,3 +1,46 @@ | |||
| 1 | 2010-10-28 Kenichi Handa <handa@m17n.org> | ||
| 2 | |||
| 3 | Implement various display methods for glyphless characters. | ||
| 4 | |||
| 5 | * xdisp.c (Qglyphless_char, Vglyphless_char_display) | ||
| 6 | (Qglyphless_char_display, Qhexa_code, Qempty_box, Qthin_space) | ||
| 7 | (Qzero_width): New variables. | ||
| 8 | (THIN_SPACE_WIDTH): New macro. | ||
| 9 | (lookup_glyphless_char_display): New funciton. | ||
| 10 | (last_glyphless_glyph_frame, last_glyphless_glyph_face_id) | ||
| 11 | (last_glyphless_glyph_merged_face_id): New variables. | ||
| 12 | (get_next_display_element): Check glyphless characters. | ||
| 13 | (redisplay_internal): Initialize last_glyphless_glyph_frame and | ||
| 14 | last_glyphless_glyph_face_id. | ||
| 15 | (fill_glyphless_glyph_string): New function. | ||
| 16 | (BUILD_GLYPHLESS_GLYPH_STRING): New macro. | ||
| 17 | (BUILD_GLYPH_STRINGS): Handle the case GLYPHLESS_GLYPH. | ||
| 18 | (append_glyphless_glyph, produce_glyphless_glyph): New functions. | ||
| 19 | (x_produce_glyphs): If a suitable font is not found, produce a | ||
| 20 | glyphless glyph. Handle the case it->what == IT_GLYPHLESS. | ||
| 21 | (syms_of_xdisp): Intern and staticpro Qglyphless_char, | ||
| 22 | Qglyphless_char_display, Qhexa_code, Qempty_box, Qthin_space, and | ||
| 23 | Qzero_width. | ||
| 24 | (Vglyphless_char_display): Declare it as a Lisp variable. | ||
| 25 | |||
| 26 | * dispextern.h (enum glyph_type): Add GLYPHLESS_GLYPH. | ||
| 27 | (struct glyph): Change the size of the member "type" to 3. Add | ||
| 28 | glyphless to the union slice and u. | ||
| 29 | (enum display_element_type): Add IT_GLYPHLESS. | ||
| 30 | (enum glyphless_display_method): New enum. | ||
| 31 | (struct it): New member glyphless_method. | ||
| 32 | (Vglyphless_char_display): Extern it. | ||
| 33 | |||
| 34 | * xterm.c (x_draw_glyphless_glyph_string_foreground): New function. | ||
| 35 | (x_draw_glyph_string): Handle the case GLYPHLESS_GLYPH. | ||
| 36 | |||
| 37 | * w32term.c (x_draw_glyphless_glyph_string_foreground): New | ||
| 38 | function. | ||
| 39 | (x_draw_glyph_string): Handle the case GLYPHLESS_GLYPH. | ||
| 40 | |||
| 41 | * nsterm.m (ns_draw_glyph_string): Handle the case | ||
| 42 | GLYPHLESS_GLYPH (the detail is not yet implemented). | ||
| 43 | |||
| 1 | 2010-10-26 Juanma Barranquero <lekktu@gmail.com> | 44 | 2010-10-26 Juanma Barranquero <lekktu@gmail.com> |
| 2 | 45 | ||
| 3 | * eval.c (init_eval_once): Set max_lisp_eval_depth to 600; | 46 | * eval.c (init_eval_once): Set max_lisp_eval_depth to 600; |
diff --git a/src/dispextern.h b/src/dispextern.h index 20e074d2393..af09ec5d3de 100644 --- a/src/dispextern.h +++ b/src/dispextern.h | |||
| @@ -279,6 +279,9 @@ enum glyph_type | |||
| 279 | /* Glyph describes a static composition. */ | 279 | /* Glyph describes a static composition. */ |
| 280 | COMPOSITE_GLYPH, | 280 | COMPOSITE_GLYPH, |
| 281 | 281 | ||
| 282 | /* Glyph describes a glyphless character. */ | ||
| 283 | GLYPHLESS_GLYPH, | ||
| 284 | |||
| 282 | /* Glyph describes an image. */ | 285 | /* Glyph describes an image. */ |
| 283 | IMAGE_GLYPH, | 286 | IMAGE_GLYPH, |
| 284 | 287 | ||
| @@ -333,7 +336,7 @@ struct glyph | |||
| 333 | 336 | ||
| 334 | /* Which kind of glyph this is---character, image etc. Value | 337 | /* Which kind of glyph this is---character, image etc. Value |
| 335 | should be an enumerator of type enum glyph_type. */ | 338 | should be an enumerator of type enum glyph_type. */ |
| 336 | unsigned type : 2; | 339 | unsigned type : 3; |
| 337 | 340 | ||
| 338 | /* 1 means this glyph was produced from multibyte text. Zero | 341 | /* 1 means this glyph was produced from multibyte text. Zero |
| 339 | means it was produced from unibyte text, i.e. charsets aren't | 342 | means it was produced from unibyte text, i.e. charsets aren't |
| @@ -402,6 +405,11 @@ struct glyph | |||
| 402 | /* Start and end indices of glyphs of a graphme cluster of a | 405 | /* Start and end indices of glyphs of a graphme cluster of a |
| 403 | composition (type == COMPOSITE_GLYPH). */ | 406 | composition (type == COMPOSITE_GLYPH). */ |
| 404 | struct { int from, to; } cmp; | 407 | struct { int from, to; } cmp; |
| 408 | /* Pixel offsets for upper and lower part of the acronym. */ | ||
| 409 | struct { | ||
| 410 | short upper_xoff, upper_yoff; | ||
| 411 | short lower_xoff, lower_yoff; | ||
| 412 | } glyphless; | ||
| 405 | } slice; | 413 | } slice; |
| 406 | 414 | ||
| 407 | /* A union of sub-structures for different glyph types. */ | 415 | /* A union of sub-structures for different glyph types. */ |
| @@ -433,6 +441,19 @@ struct glyph | |||
| 433 | } | 441 | } |
| 434 | stretch; | 442 | stretch; |
| 435 | 443 | ||
| 444 | /* Sub-stretch for type == GLYPHLESS_GLYPH. */ | ||
| 445 | struct | ||
| 446 | { | ||
| 447 | /* Value is an enum of the type glyphless_display_method. */ | ||
| 448 | unsigned method : 2; | ||
| 449 | /* 1 iff this glyph is for a character of no font. */ | ||
| 450 | unsigned for_no_font : 1; | ||
| 451 | /* Length of acronym or hexadecimal code string (at most 8). */ | ||
| 452 | unsigned len : 4; | ||
| 453 | /* Character to display. Actually we need only 22 bits. */ | ||
| 454 | unsigned ch : 26; | ||
| 455 | } glyphless; | ||
| 456 | |||
| 436 | /* Used to compare all bit-fields above in one step. */ | 457 | /* Used to compare all bit-fields above in one step. */ |
| 437 | unsigned val; | 458 | unsigned val; |
| 438 | } u; | 459 | } u; |
| @@ -1918,6 +1939,9 @@ enum display_element_type | |||
| 1918 | /* A composition (static and automatic). */ | 1939 | /* A composition (static and automatic). */ |
| 1919 | IT_COMPOSITION, | 1940 | IT_COMPOSITION, |
| 1920 | 1941 | ||
| 1942 | /* A glyphless character (e.g. ZWNJ, LRE). */ | ||
| 1943 | IT_GLYPHLESS, | ||
| 1944 | |||
| 1921 | /* An image. */ | 1945 | /* An image. */ |
| 1922 | IT_IMAGE, | 1946 | IT_IMAGE, |
| 1923 | 1947 | ||
| @@ -1964,6 +1988,20 @@ enum line_wrap_method | |||
| 1964 | WINDOW_WRAP | 1988 | WINDOW_WRAP |
| 1965 | }; | 1989 | }; |
| 1966 | 1990 | ||
| 1991 | /* An enumerator for the method of displaying glyphless characters. */ | ||
| 1992 | |||
| 1993 | enum glyphless_display_method | ||
| 1994 | { | ||
| 1995 | /* Display a thin (1-pixel width) space. */ | ||
| 1996 | GLYPHLESS_DISPLAY_THIN_SPACE, | ||
| 1997 | /* Display an empty box of proper width. */ | ||
| 1998 | GLYPHLESS_DISPLAY_EMPTY_BOX, | ||
| 1999 | /* Display an acronym string in a box. */ | ||
| 2000 | GLYPHLESS_DISPLAY_ACRONYM, | ||
| 2001 | /* Display a hexadecimal character code in a box. */ | ||
| 2002 | GLYPHLESS_DISPLAY_HEXA_CODE | ||
| 2003 | }; | ||
| 2004 | |||
| 1967 | struct it_slice | 2005 | struct it_slice |
| 1968 | { | 2006 | { |
| 1969 | Lisp_Object x; | 2007 | Lisp_Object x; |
| @@ -2295,6 +2333,10 @@ struct it | |||
| 2295 | PRODUCE_GLYPHS, this should be set beforehand too. */ | 2333 | PRODUCE_GLYPHS, this should be set beforehand too. */ |
| 2296 | int char_to_display; | 2334 | int char_to_display; |
| 2297 | 2335 | ||
| 2336 | /* If what == IT_GLYPHLESS, the method to display such a | ||
| 2337 | character. */ | ||
| 2338 | enum glyphless_display_method glyphless_method; | ||
| 2339 | |||
| 2298 | /* If what == IT_IMAGE, the id of the image to display. */ | 2340 | /* If what == IT_IMAGE, the id of the image to display. */ |
| 2299 | int image_id; | 2341 | int image_id; |
| 2300 | 2342 | ||
| @@ -2976,6 +3018,7 @@ extern int last_tool_bar_item; | |||
| 2976 | extern Lisp_Object Vmouse_autoselect_window; | 3018 | extern Lisp_Object Vmouse_autoselect_window; |
| 2977 | extern int unibyte_display_via_language_environment; | 3019 | extern int unibyte_display_via_language_environment; |
| 2978 | extern EMACS_INT underline_minimum_offset; | 3020 | extern EMACS_INT underline_minimum_offset; |
| 3021 | extern Lisp_Object Vglyphless_char_display; | ||
| 2979 | 3022 | ||
| 2980 | extern void reseat_at_previous_visible_line_start (struct it *); | 3023 | extern void reseat_at_previous_visible_line_start (struct it *); |
| 2981 | 3024 | ||
diff --git a/src/nsterm.m b/src/nsterm.m index 247ef4dd40c..f11c477d192 100644 --- a/src/nsterm.m +++ b/src/nsterm.m | |||
| @@ -2983,6 +2983,22 @@ ns_draw_glyph_string (struct glyph_string *s) | |||
| 2983 | ns_unfocus (s->f); | 2983 | ns_unfocus (s->f); |
| 2984 | break; | 2984 | break; |
| 2985 | 2985 | ||
| 2986 | case GLYPHLESS_GLYPH: | ||
| 2987 | n = ns_get_glyph_string_clip_rect (s, r); | ||
| 2988 | ns_focus (s->f, r, n); | ||
| 2989 | |||
| 2990 | if (s->for_overlaps || (s->cmp_from > 0 | ||
| 2991 | && ! s->first_glyph->u.cmp.automatic)) | ||
| 2992 | s->background_filled_p = 1; | ||
| 2993 | else | ||
| 2994 | ns_maybe_dumpglyphs_background | ||
| 2995 | (s, s->first_glyph->type == COMPOSITE_GLYPH); | ||
| 2996 | /* ... */ | ||
| 2997 | /* Not yet implemented. */ | ||
| 2998 | /* ... */ | ||
| 2999 | ns_unfocus (s->f); | ||
| 3000 | break; | ||
| 3001 | |||
| 2986 | default: | 3002 | default: |
| 2987 | abort (); | 3003 | abort (); |
| 2988 | } | 3004 | } |
diff --git a/src/w32term.c b/src/w32term.c index 7690f13799f..49447d6eafc 100644 --- a/src/w32term.c +++ b/src/w32term.c | |||
| @@ -1394,6 +1394,92 @@ x_draw_composite_glyph_string_foreground (struct glyph_string *s) | |||
| 1394 | } | 1394 | } |
| 1395 | 1395 | ||
| 1396 | 1396 | ||
| 1397 | /* Draw the foreground of glyph string S for glyphless characters. */ | ||
| 1398 | |||
| 1399 | static void | ||
| 1400 | x_draw_glyphless_glyph_string_foreground (struct glyph_string *s) | ||
| 1401 | { | ||
| 1402 | struct glyph *glyph = s->first_glyph; | ||
| 1403 | XChar2b char2b[8]; | ||
| 1404 | int x, i, j; | ||
| 1405 | |||
| 1406 | /* If first glyph of S has a left box line, start drawing the text | ||
| 1407 | of S to the right of that box line. */ | ||
| 1408 | if (s->face->box != FACE_NO_BOX | ||
| 1409 | && s->first_glyph->left_box_line_p) | ||
| 1410 | x = s->x + eabs (s->face->box_line_width); | ||
| 1411 | else | ||
| 1412 | x = s->x; | ||
| 1413 | |||
| 1414 | SetTextColor (s->hdc, s->gc->foreground); | ||
| 1415 | SetBkColor (s->hdc, s->gc->background); | ||
| 1416 | SetTextAlign (s->hdc, TA_BASELINE | TA_LEFT); | ||
| 1417 | |||
| 1418 | s->char2b = char2b; | ||
| 1419 | |||
| 1420 | for (i = 0; i < s->nchars; i++, glyph++) | ||
| 1421 | { | ||
| 1422 | char buf[7], *str = NULL; | ||
| 1423 | int len = glyph->u.glyphless.len; | ||
| 1424 | |||
| 1425 | if (glyph->u.glyphless.method == GLYPHLESS_DISPLAY_ACRONYM) | ||
| 1426 | { | ||
| 1427 | if (len > 1 | ||
| 1428 | && CHAR_TABLE_P (Vglyphless_char_display) | ||
| 1429 | && (CHAR_TABLE_EXTRA_SLOTS (XCHAR_TABLE (Vglyphless_char_display)) | ||
| 1430 | >= 1)) | ||
| 1431 | { | ||
| 1432 | Lisp_Object acronym | ||
| 1433 | = (! glyph->u.glyphless.for_no_font | ||
| 1434 | ? CHAR_TABLE_REF (Vglyphless_char_display, | ||
| 1435 | glyph->u.glyphless.ch) | ||
| 1436 | : XCHAR_TABLE (Vglyphless_char_display)->extras[0]); | ||
| 1437 | if (STRINGP (acronym)) | ||
| 1438 | str = (char *) SDATA (acronym); | ||
| 1439 | } | ||
| 1440 | } | ||
| 1441 | else if (glyph->u.glyphless.method == GLYPHLESS_DISPLAY_HEXA_CODE) | ||
| 1442 | { | ||
| 1443 | sprintf ((char *) buf, "%0*X", | ||
| 1444 | glyph->u.glyphless.ch < 0x10000 ? 4 : 6, | ||
| 1445 | glyph->u.glyphless.ch); | ||
| 1446 | str = buf; | ||
| 1447 | } | ||
| 1448 | |||
| 1449 | if (str) | ||
| 1450 | { | ||
| 1451 | struct font *font = s->font; | ||
| 1452 | int upper_len = (len + 1) / 2; | ||
| 1453 | unsigned code; | ||
| 1454 | HFONT old_font; | ||
| 1455 | |||
| 1456 | old_font = SelectObject (s->hdc, FONT_HANDLE (font)); | ||
| 1457 | /* It is assured that all LEN characters in STR is ASCII. */ | ||
| 1458 | for (j = 0; j < len; j++) | ||
| 1459 | { | ||
| 1460 | code = font->driver->encode_char (font, str[j]); | ||
| 1461 | STORE_XCHAR2B (char2b + j, code >> 8, code & 0xFF); | ||
| 1462 | } | ||
| 1463 | font->driver->draw (s, 0, upper_len, | ||
| 1464 | x + glyph->slice.glyphless.upper_xoff, | ||
| 1465 | s->ybase + glyph->slice.glyphless.upper_yoff, | ||
| 1466 | 0); | ||
| 1467 | font->driver->draw (s, upper_len, len, | ||
| 1468 | x + glyph->slice.glyphless.lower_xoff, | ||
| 1469 | s->ybase + glyph->slice.glyphless.lower_yoff, | ||
| 1470 | 0); | ||
| 1471 | SelectObject (s->hdc, old_font); | ||
| 1472 | } | ||
| 1473 | if (glyph->u.glyphless.method != GLYPHLESS_DISPLAY_THIN_SPACE) | ||
| 1474 | w32_draw_rectangle (s->hdc, s->gc, | ||
| 1475 | x, s->ybase - glyph->ascent, | ||
| 1476 | glyph->pixel_width - 1, | ||
| 1477 | glyph->ascent + glyph->descent - 1); | ||
| 1478 | x += glyph->pixel_width; | ||
| 1479 | } | ||
| 1480 | } | ||
| 1481 | |||
| 1482 | |||
| 1397 | /* Brightness beyond which a color won't have its highlight brightness | 1483 | /* Brightness beyond which a color won't have its highlight brightness |
| 1398 | boosted. | 1484 | boosted. |
| 1399 | 1485 | ||
| @@ -2282,6 +2368,15 @@ x_draw_glyph_string (struct glyph_string *s) | |||
| 2282 | x_draw_composite_glyph_string_foreground (s); | 2368 | x_draw_composite_glyph_string_foreground (s); |
| 2283 | break; | 2369 | break; |
| 2284 | 2370 | ||
| 2371 | case GLYPHLESS_GLYPH: | ||
| 2372 | if (s->for_overlaps || (s->cmp_from > 0 | ||
| 2373 | && ! s->first_glyph->u.cmp.automatic)) | ||
| 2374 | s->background_filled_p = 1; | ||
| 2375 | else | ||
| 2376 | x_draw_glyph_string_background (s, 1); | ||
| 2377 | x_draw_glyphless_glyph_string_foreground (s); | ||
| 2378 | break; | ||
| 2379 | |||
| 2285 | default: | 2380 | default: |
| 2286 | abort (); | 2381 | abort (); |
| 2287 | } | 2382 | } |
diff --git a/src/xdisp.c b/src/xdisp.c index c9af2ba88ec..52938417aac 100644 --- a/src/xdisp.c +++ b/src/xdisp.c | |||
| @@ -932,6 +932,21 @@ struct atimer *hourglass_atimer; | |||
| 932 | /* Number of seconds to wait before displaying an hourglass cursor. */ | 932 | /* Number of seconds to wait before displaying an hourglass cursor. */ |
| 933 | Lisp_Object Vhourglass_delay; | 933 | Lisp_Object Vhourglass_delay; |
| 934 | 934 | ||
| 935 | /* Name of the face used to display glyphless characters. */ | ||
| 936 | Lisp_Object Qglyphless_char; | ||
| 937 | |||
| 938 | /* Char-table to control the display of glyphless characters. */ | ||
| 939 | Lisp_Object Vglyphless_char_display; | ||
| 940 | |||
| 941 | /* Symbol for the purpose of Vglyphless_char_display. */ | ||
| 942 | Lisp_Object Qglyphless_char_display; | ||
| 943 | |||
| 944 | /* Method symbols for Vglyphless_char_display. */ | ||
| 945 | static Lisp_Object Qhexa_code, Qempty_box, Qthin_space, Qzero_width; | ||
| 946 | |||
| 947 | /* Default pixel width of `thin-space' display method. */ | ||
| 948 | #define THIN_SPACE_WIDTH 1 | ||
| 949 | |||
| 935 | /* Default number of seconds to wait before displaying an hourglass | 950 | /* Default number of seconds to wait before displaying an hourglass |
| 936 | cursor. */ | 951 | cursor. */ |
| 937 | #define DEFAULT_HOURGLASS_DELAY 1 | 952 | #define DEFAULT_HOURGLASS_DELAY 1 |
| @@ -5732,6 +5747,57 @@ static int (* get_next_element[NUM_IT_METHODS]) (struct it *it) = | |||
| 5732 | (IT)->string))) | 5747 | (IT)->string))) |
| 5733 | 5748 | ||
| 5734 | 5749 | ||
| 5750 | /* Lookup the char-table Vglyphless_char_display for character C (-1 | ||
| 5751 | if we want information for no-font case), and return the display | ||
| 5752 | method symbol. By side-effect, update it->what and | ||
| 5753 | it->glyphless_method. This function is called from | ||
| 5754 | get_next_display_element for each character element, and from | ||
| 5755 | x_produce_glyphs when no suitable font was found. */ | ||
| 5756 | |||
| 5757 | static Lisp_Object | ||
| 5758 | lookup_glyphless_char_display (int c, struct it *it) | ||
| 5759 | { | ||
| 5760 | Lisp_Object glyphless_method = Qnil; | ||
| 5761 | |||
| 5762 | if (CHAR_TABLE_P (Vglyphless_char_display) | ||
| 5763 | && CHAR_TABLE_EXTRA_SLOTS (XCHAR_TABLE (Vglyphless_char_display)) >= 1) | ||
| 5764 | glyphless_method = (c >= 0 | ||
| 5765 | ? CHAR_TABLE_REF (Vglyphless_char_display, c) | ||
| 5766 | : XCHAR_TABLE (Vglyphless_char_display)->extras[0]); | ||
| 5767 | retry: | ||
| 5768 | if (NILP (glyphless_method)) | ||
| 5769 | { | ||
| 5770 | if (c >= 0) | ||
| 5771 | /* The default is to display the character by a proper font. */ | ||
| 5772 | return Qnil; | ||
| 5773 | /* The default for the no-font case is to display an empty box. */ | ||
| 5774 | glyphless_method = Qempty_box; | ||
| 5775 | } | ||
| 5776 | if (EQ (glyphless_method, Qzero_width)) | ||
| 5777 | { | ||
| 5778 | if (c >= 0) | ||
| 5779 | return glyphless_method; | ||
| 5780 | /* This method can't be used for the no-font case. */ | ||
| 5781 | glyphless_method = Qempty_box; | ||
| 5782 | } | ||
| 5783 | it->what = IT_GLYPHLESS; | ||
| 5784 | if (EQ (glyphless_method, Qthin_space)) | ||
| 5785 | it->glyphless_method = GLYPHLESS_DISPLAY_THIN_SPACE; | ||
| 5786 | else if (EQ (glyphless_method, Qempty_box)) | ||
| 5787 | it->glyphless_method = GLYPHLESS_DISPLAY_EMPTY_BOX; | ||
| 5788 | else if (EQ (glyphless_method, Qhexa_code)) | ||
| 5789 | it->glyphless_method = GLYPHLESS_DISPLAY_HEXA_CODE; | ||
| 5790 | else if (STRINGP (glyphless_method)) | ||
| 5791 | it->glyphless_method = GLYPHLESS_DISPLAY_ACRONYM; | ||
| 5792 | else | ||
| 5793 | { | ||
| 5794 | /* Invalid value. We use the default method. */ | ||
| 5795 | glyphless_method = Qnil; | ||
| 5796 | goto retry; | ||
| 5797 | } | ||
| 5798 | return glyphless_method; | ||
| 5799 | } | ||
| 5800 | |||
| 5735 | /* Load IT's display element fields with information about the next | 5801 | /* Load IT's display element fields with information about the next |
| 5736 | display element from the current position of IT. Value is zero if | 5802 | display element from the current position of IT. Value is zero if |
| 5737 | end of buffer (or C string) is reached. */ | 5803 | end of buffer (or C string) is reached. */ |
| @@ -5740,6 +5806,10 @@ static struct frame *last_escape_glyph_frame = NULL; | |||
| 5740 | static unsigned last_escape_glyph_face_id = (1 << FACE_ID_BITS); | 5806 | static unsigned last_escape_glyph_face_id = (1 << FACE_ID_BITS); |
| 5741 | static int last_escape_glyph_merged_face_id = 0; | 5807 | static int last_escape_glyph_merged_face_id = 0; |
| 5742 | 5808 | ||
| 5809 | static struct frame *last_glyphless_glyph_frame = NULL; | ||
| 5810 | static unsigned last_glyphless_glyph_face_id = (1 << FACE_ID_BITS); | ||
| 5811 | static int last_glyphless_glyph_merged_face_id = 0; | ||
| 5812 | |||
| 5743 | int | 5813 | int |
| 5744 | get_next_display_element (struct it *it) | 5814 | get_next_display_element (struct it *it) |
| 5745 | { | 5815 | { |
| @@ -5818,6 +5888,15 @@ get_next_display_element (struct it *it) | |||
| 5818 | goto get_next; | 5888 | goto get_next; |
| 5819 | } | 5889 | } |
| 5820 | 5890 | ||
| 5891 | if (! NILP (lookup_glyphless_char_display (c, it))) | ||
| 5892 | { | ||
| 5893 | if (it->what == IT_GLYPHLESS) | ||
| 5894 | goto done; | ||
| 5895 | /* Don't display this character. */ | ||
| 5896 | set_iterator_to_next (it, 0); | ||
| 5897 | goto get_next; | ||
| 5898 | } | ||
| 5899 | |||
| 5821 | if (! ASCII_CHAR_P (c) && ! NILP (Vnobreak_char_display)) | 5900 | if (! ASCII_CHAR_P (c) && ! NILP (Vnobreak_char_display)) |
| 5822 | nbsp_or_shy = (c == 0xA0 ? char_is_nbsp | 5901 | nbsp_or_shy = (c == 0xA0 ? char_is_nbsp |
| 5823 | : c == 0xAD ? char_is_soft_hyphen | 5902 | : c == 0xAD ? char_is_soft_hyphen |
| @@ -6032,6 +6111,7 @@ get_next_display_element (struct it *it) | |||
| 6032 | } | 6111 | } |
| 6033 | #endif | 6112 | #endif |
| 6034 | 6113 | ||
| 6114 | done: | ||
| 6035 | /* Is this character the last one of a run of characters with | 6115 | /* Is this character the last one of a run of characters with |
| 6036 | box? If yes, set IT->end_of_box_run_p to 1. */ | 6116 | box? If yes, set IT->end_of_box_run_p to 1. */ |
| 6037 | if (it->face_box_p | 6117 | if (it->face_box_p |
| @@ -11579,6 +11659,8 @@ redisplay_internal (int preserve_echo_area) | |||
| 11579 | reconsider_clip_changes (w, current_buffer); | 11659 | reconsider_clip_changes (w, current_buffer); |
| 11580 | last_escape_glyph_frame = NULL; | 11660 | last_escape_glyph_frame = NULL; |
| 11581 | last_escape_glyph_face_id = (1 << FACE_ID_BITS); | 11661 | last_escape_glyph_face_id = (1 << FACE_ID_BITS); |
| 11662 | last_glyphless_glyph_frame = NULL; | ||
| 11663 | last_glyphless_glyph_face_id = (1 << FACE_ID_BITS); | ||
| 11582 | 11664 | ||
| 11583 | /* If new fonts have been loaded that make a glyph matrix adjustment | 11665 | /* If new fonts have been loaded that make a glyph matrix adjustment |
| 11584 | necessary, do it. */ | 11666 | necessary, do it. */ |
| @@ -20657,6 +20739,42 @@ fill_gstring_glyph_string (struct glyph_string *s, int face_id, | |||
| 20657 | } | 20739 | } |
| 20658 | 20740 | ||
| 20659 | 20741 | ||
| 20742 | /* Fill glyph string S from a sequence glyphs for glyphless characters. | ||
| 20743 | See the comment of fill_glyph_string for arguments. | ||
| 20744 | Value is the index of the first glyph not in S. */ | ||
| 20745 | |||
| 20746 | |||
| 20747 | static int | ||
| 20748 | fill_glyphless_glyph_string (struct glyph_string *s, int face_id, | ||
| 20749 | int start, int end, int overlaps) | ||
| 20750 | { | ||
| 20751 | struct glyph *glyph, *last; | ||
| 20752 | int voffset; | ||
| 20753 | |||
| 20754 | xassert (s->first_glyph->type == GLYPHLESS_GLYPH); | ||
| 20755 | s->for_overlaps = overlaps; | ||
| 20756 | glyph = s->row->glyphs[s->area] + start; | ||
| 20757 | last = s->row->glyphs[s->area] + end; | ||
| 20758 | voffset = glyph->voffset; | ||
| 20759 | s->face = FACE_FROM_ID (s->f, face_id); | ||
| 20760 | s->font = s->face->font; | ||
| 20761 | s->nchars = 1; | ||
| 20762 | s->width = glyph->pixel_width; | ||
| 20763 | glyph++; | ||
| 20764 | while (glyph < last | ||
| 20765 | && glyph->type == GLYPHLESS_GLYPH | ||
| 20766 | && glyph->voffset == voffset | ||
| 20767 | && glyph->face_id == face_id) | ||
| 20768 | { | ||
| 20769 | s->nchars++; | ||
| 20770 | s->width += glyph->pixel_width; | ||
| 20771 | glyph++; | ||
| 20772 | } | ||
| 20773 | s->ybase += voffset; | ||
| 20774 | return glyph - s->row->glyphs[s->area]; | ||
| 20775 | } | ||
| 20776 | |||
| 20777 | |||
| 20660 | /* Fill glyph string S from a sequence of character glyphs. | 20778 | /* Fill glyph string S from a sequence of character glyphs. |
| 20661 | 20779 | ||
| 20662 | FACE_ID is the face id of the string. START is the index of the | 20780 | FACE_ID is the face id of the string. START is the index of the |
| @@ -21167,6 +21285,28 @@ compute_overhangs_and_x (struct glyph_string *s, int x, int backward_p) | |||
| 21167 | } while (0) | 21285 | } while (0) |
| 21168 | 21286 | ||
| 21169 | 21287 | ||
| 21288 | /* Add a glyph string for a sequence of glyphless character's glyphs | ||
| 21289 | to the list of strings between HEAD and TAIL. The meanings of | ||
| 21290 | arguments are the same as those of BUILD_CHAR_GLYPH_STRINGS. */ | ||
| 21291 | |||
| 21292 | #define BUILD_GLYPHLESS_GLYPH_STRING(START, END, HEAD, TAIL, HL, X, LAST_X) \ | ||
| 21293 | do \ | ||
| 21294 | { \ | ||
| 21295 | int face_id; \ | ||
| 21296 | XChar2b *char2b; \ | ||
| 21297 | \ | ||
| 21298 | face_id = (row)->glyphs[area][START].face_id; \ | ||
| 21299 | \ | ||
| 21300 | s = (struct glyph_string *) alloca (sizeof *s); \ | ||
| 21301 | INIT_GLYPH_STRING (s, NULL, w, row, area, START, HL); \ | ||
| 21302 | append_glyph_string (&HEAD, &TAIL, s); \ | ||
| 21303 | s->x = (X); \ | ||
| 21304 | START = fill_glyphless_glyph_string (s, face_id, START, END, \ | ||
| 21305 | overlaps); \ | ||
| 21306 | } \ | ||
| 21307 | while (0) | ||
| 21308 | |||
| 21309 | |||
| 21170 | /* Build a list of glyph strings between HEAD and TAIL for the glyphs | 21310 | /* Build a list of glyph strings between HEAD and TAIL for the glyphs |
| 21171 | of AREA of glyph row ROW on window W between indices START and END. | 21311 | of AREA of glyph row ROW on window W between indices START and END. |
| 21172 | HL overrides the face for drawing glyph strings, e.g. it is | 21312 | HL overrides the face for drawing glyph strings, e.g. it is |
| @@ -21190,7 +21330,7 @@ compute_overhangs_and_x (struct glyph_string *s, int x, int backward_p) | |||
| 21190 | BUILD_CHAR_GLYPH_STRINGS (START, END, HEAD, TAIL, \ | 21330 | BUILD_CHAR_GLYPH_STRINGS (START, END, HEAD, TAIL, \ |
| 21191 | HL, X, LAST_X); \ | 21331 | HL, X, LAST_X); \ |
| 21192 | break; \ | 21332 | break; \ |
| 21193 | \ | 21333 | \ |
| 21194 | case COMPOSITE_GLYPH: \ | 21334 | case COMPOSITE_GLYPH: \ |
| 21195 | if (first_glyph->u.cmp.automatic) \ | 21335 | if (first_glyph->u.cmp.automatic) \ |
| 21196 | BUILD_GSTRING_GLYPH_STRING (START, END, HEAD, TAIL, \ | 21336 | BUILD_GSTRING_GLYPH_STRING (START, END, HEAD, TAIL, \ |
| @@ -21199,21 +21339,26 @@ compute_overhangs_and_x (struct glyph_string *s, int x, int backward_p) | |||
| 21199 | BUILD_COMPOSITE_GLYPH_STRING (START, END, HEAD, TAIL, \ | 21339 | BUILD_COMPOSITE_GLYPH_STRING (START, END, HEAD, TAIL, \ |
| 21200 | HL, X, LAST_X); \ | 21340 | HL, X, LAST_X); \ |
| 21201 | break; \ | 21341 | break; \ |
| 21202 | \ | 21342 | \ |
| 21203 | case STRETCH_GLYPH: \ | 21343 | case STRETCH_GLYPH: \ |
| 21204 | BUILD_STRETCH_GLYPH_STRING (START, END, HEAD, TAIL, \ | 21344 | BUILD_STRETCH_GLYPH_STRING (START, END, HEAD, TAIL, \ |
| 21205 | HL, X, LAST_X); \ | 21345 | HL, X, LAST_X); \ |
| 21206 | break; \ | 21346 | break; \ |
| 21207 | \ | 21347 | \ |
| 21208 | case IMAGE_GLYPH: \ | 21348 | case IMAGE_GLYPH: \ |
| 21209 | BUILD_IMAGE_GLYPH_STRING (START, END, HEAD, TAIL, \ | 21349 | BUILD_IMAGE_GLYPH_STRING (START, END, HEAD, TAIL, \ |
| 21210 | HL, X, LAST_X); \ | 21350 | HL, X, LAST_X); \ |
| 21211 | break; \ | 21351 | break; \ |
| 21212 | \ | 21352 | \ |
| 21353 | case GLYPHLESS_GLYPH: \ | ||
| 21354 | BUILD_GLYPHLESS_GLYPH_STRING (START, END, HEAD, TAIL, \ | ||
| 21355 | HL, X, LAST_X); \ | ||
| 21356 | break; \ | ||
| 21357 | \ | ||
| 21213 | default: \ | 21358 | default: \ |
| 21214 | abort (); \ | 21359 | abort (); \ |
| 21215 | } \ | 21360 | } \ |
| 21216 | \ | 21361 | \ |
| 21217 | if (s) \ | 21362 | if (s) \ |
| 21218 | { \ | 21363 | { \ |
| 21219 | set_glyph_string_background_width (s, START, LAST_X); \ | 21364 | set_glyph_string_background_width (s, START, LAST_X); \ |
| @@ -22109,6 +22254,229 @@ calc_line_height_property (struct it *it, Lisp_Object val, struct font *font, | |||
| 22109 | } | 22254 | } |
| 22110 | 22255 | ||
| 22111 | 22256 | ||
| 22257 | /* Append a glyph for a glyphless character to IT->glyph_row. FACE_ID | ||
| 22258 | is a face ID to be used for the glyph. FOR_NO_FONT is nonzero if | ||
| 22259 | and only if this is for a character for which no font was found. | ||
| 22260 | |||
| 22261 | If the display method (it->glyphless_method) is | ||
| 22262 | GLYPHLESS_DISPLAY_ACRONYM or GLYPHLESS_DISPLAY_HEXA_CODE, LEN is a | ||
| 22263 | length of the acronym or the hexadecimal string, UPPER_XOFF and | ||
| 22264 | UPPER_YOFF are pixel offsets for the upper part of the string, | ||
| 22265 | LOWER_XOFF and LOWER_YOFF are for the lower part. | ||
| 22266 | |||
| 22267 | For the other display methods, LEN through LOWER_YOFF are zero. */ | ||
| 22268 | |||
| 22269 | static void | ||
| 22270 | append_glyphless_glyph (struct it *it, int face_id, int for_no_font, int len, | ||
| 22271 | short upper_xoff, short upper_yoff, | ||
| 22272 | short lower_xoff, short lower_yoff) | ||
| 22273 | { | ||
| 22274 | struct glyph *glyph; | ||
| 22275 | enum glyph_row_area area = it->area; | ||
| 22276 | |||
| 22277 | glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area]; | ||
| 22278 | if (glyph < it->glyph_row->glyphs[area + 1]) | ||
| 22279 | { | ||
| 22280 | /* If the glyph row is reversed, we need to prepend the glyph | ||
| 22281 | rather than append it. */ | ||
| 22282 | if (it->glyph_row->reversed_p && area == TEXT_AREA) | ||
| 22283 | { | ||
| 22284 | struct glyph *g; | ||
| 22285 | |||
| 22286 | /* Make room for the additional glyph. */ | ||
| 22287 | for (g = glyph - 1; g >= it->glyph_row->glyphs[area]; g--) | ||
| 22288 | g[1] = *g; | ||
| 22289 | glyph = it->glyph_row->glyphs[area]; | ||
| 22290 | } | ||
| 22291 | glyph->charpos = CHARPOS (it->position); | ||
| 22292 | glyph->object = it->object; | ||
| 22293 | glyph->pixel_width = it->pixel_width; | ||
| 22294 | glyph->ascent = it->ascent; | ||
| 22295 | glyph->descent = it->descent; | ||
| 22296 | glyph->voffset = it->voffset; | ||
| 22297 | glyph->type = GLYPHLESS_GLYPH; | ||
| 22298 | glyph->u.glyphless.method = it->glyphless_method; | ||
| 22299 | glyph->u.glyphless.for_no_font = for_no_font; | ||
| 22300 | glyph->u.glyphless.len = len; | ||
| 22301 | glyph->u.glyphless.ch = it->c; | ||
| 22302 | glyph->slice.glyphless.upper_xoff = upper_xoff; | ||
| 22303 | glyph->slice.glyphless.upper_yoff = upper_yoff; | ||
| 22304 | glyph->slice.glyphless.lower_xoff = lower_xoff; | ||
| 22305 | glyph->slice.glyphless.lower_yoff = lower_yoff; | ||
| 22306 | glyph->avoid_cursor_p = it->avoid_cursor_p; | ||
| 22307 | glyph->multibyte_p = it->multibyte_p; | ||
| 22308 | glyph->left_box_line_p = it->start_of_box_run_p; | ||
| 22309 | glyph->right_box_line_p = it->end_of_box_run_p; | ||
| 22310 | glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent | ||
| 22311 | || it->phys_descent > it->descent); | ||
| 22312 | glyph->padding_p = 0; | ||
| 22313 | glyph->glyph_not_available_p = 0; | ||
| 22314 | glyph->face_id = face_id; | ||
| 22315 | glyph->font_type = FONT_TYPE_UNKNOWN; | ||
| 22316 | if (it->bidi_p) | ||
| 22317 | { | ||
| 22318 | glyph->resolved_level = it->bidi_it.resolved_level; | ||
| 22319 | if ((it->bidi_it.type & 7) != it->bidi_it.type) | ||
| 22320 | abort (); | ||
| 22321 | glyph->bidi_type = it->bidi_it.type; | ||
| 22322 | } | ||
| 22323 | ++it->glyph_row->used[area]; | ||
| 22324 | } | ||
| 22325 | else | ||
| 22326 | IT_EXPAND_MATRIX_WIDTH (it, area); | ||
| 22327 | } | ||
| 22328 | |||
| 22329 | |||
| 22330 | /* Produce a glyph for a glyphless character for iterator IT. | ||
| 22331 | IT->glyphless_method specifies which method to use for displaying | ||
| 22332 | the glyph. See the description of enum glyphless_display_method in | ||
| 22333 | dispextern.h for the default of the display methods. | ||
| 22334 | |||
| 22335 | FOR_NO_FONT is nonzero if and only if this is for a character for | ||
| 22336 | which no font was found. ACRONYM, if non-nil, is an acronym string | ||
| 22337 | for the character. */ | ||
| 22338 | |||
| 22339 | static void | ||
| 22340 | produce_glyphless_glyph (struct it *it, int for_no_font, Lisp_Object acronym) | ||
| 22341 | { | ||
| 22342 | int face_id; | ||
| 22343 | struct face *face; | ||
| 22344 | struct font *font; | ||
| 22345 | int base_width, base_height, width, height; | ||
| 22346 | short upper_xoff, upper_yoff, lower_xoff, lower_yoff; | ||
| 22347 | int len; | ||
| 22348 | |||
| 22349 | /* Get the metrics of the base font. We always refer to the current | ||
| 22350 | ASCII face. */ | ||
| 22351 | face = FACE_FROM_ID (it->f, it->face_id)->ascii_face; | ||
| 22352 | font = face->font ? face->font : FRAME_FONT (it->f); | ||
| 22353 | it->ascent = FONT_BASE (font) + font->baseline_offset; | ||
| 22354 | it->descent = FONT_DESCENT (font) - font->baseline_offset; | ||
| 22355 | base_height = it->ascent + it->descent; | ||
| 22356 | base_width = font->average_width; | ||
| 22357 | |||
| 22358 | /* Get a face ID for the glyph by utilizing a cache (the same way as | ||
| 22359 | doen for `escape-glyph' in get_next_display_element). */ | ||
| 22360 | if (it->f == last_glyphless_glyph_frame | ||
| 22361 | && it->face_id == last_glyphless_glyph_face_id) | ||
| 22362 | { | ||
| 22363 | face_id = last_glyphless_glyph_merged_face_id; | ||
| 22364 | } | ||
| 22365 | else | ||
| 22366 | { | ||
| 22367 | /* Merge the `glyphless-char' face into the current face. */ | ||
| 22368 | face_id = merge_faces (it->f, Qglyphless_char, 0, it->face_id); | ||
| 22369 | last_glyphless_glyph_frame = it->f; | ||
| 22370 | last_glyphless_glyph_face_id = it->face_id; | ||
| 22371 | last_glyphless_glyph_merged_face_id = face_id; | ||
| 22372 | } | ||
| 22373 | |||
| 22374 | if (it->glyphless_method == GLYPHLESS_DISPLAY_THIN_SPACE) | ||
| 22375 | { | ||
| 22376 | it->pixel_width = THIN_SPACE_WIDTH; | ||
| 22377 | len = 0; | ||
| 22378 | upper_xoff = upper_yoff = lower_xoff = lower_yoff = 0; | ||
| 22379 | } | ||
| 22380 | else if (it->glyphless_method == GLYPHLESS_DISPLAY_EMPTY_BOX) | ||
| 22381 | { | ||
| 22382 | width = CHAR_WIDTH (it->c); | ||
| 22383 | if (width == 0) | ||
| 22384 | width = 1; | ||
| 22385 | else if (width > 4) | ||
| 22386 | width = 4; | ||
| 22387 | it->pixel_width = base_width * width; | ||
| 22388 | len = 0; | ||
| 22389 | upper_xoff = upper_yoff = lower_xoff = lower_yoff = 0; | ||
| 22390 | } | ||
| 22391 | else | ||
| 22392 | { | ||
| 22393 | char buf[7], *str; | ||
| 22394 | unsigned int code[6]; | ||
| 22395 | int upper_len; | ||
| 22396 | int ascent, descent; | ||
| 22397 | struct font_metrics metrics_upper, metrics_lower; | ||
| 22398 | |||
| 22399 | face = FACE_FROM_ID (it->f, face_id); | ||
| 22400 | font = face->font ? face->font : FRAME_FONT (it->f); | ||
| 22401 | PREPARE_FACE_FOR_DISPLAY (it->f, face); | ||
| 22402 | |||
| 22403 | if (it->glyphless_method == GLYPHLESS_DISPLAY_ACRONYM) | ||
| 22404 | { | ||
| 22405 | if (! STRINGP (acronym) && CHAR_TABLE_P (Vglyphless_char_display)) | ||
| 22406 | acronym = CHAR_TABLE_REF (Vglyphless_char_display, it->c); | ||
| 22407 | str = STRINGP (acronym) ? (char *) SDATA (acronym) : ""; | ||
| 22408 | } | ||
| 22409 | else | ||
| 22410 | { | ||
| 22411 | xassert (it->glyphless_method == GLYPHLESS_DISPLAY_HEXA_CODE); | ||
| 22412 | sprintf (buf, "%0*X", it->c < 0x10000 ? 4 : 6, it->c); | ||
| 22413 | str = buf; | ||
| 22414 | } | ||
| 22415 | for (len = 0; str[len] && ASCII_BYTE_P (str[len]); len++) | ||
| 22416 | code[len] = font->driver->encode_char (font, str[len]); | ||
| 22417 | upper_len = (len + 1) / 2; | ||
| 22418 | font->driver->text_extents (font, code, upper_len, | ||
| 22419 | &metrics_upper); | ||
| 22420 | font->driver->text_extents (font, code + upper_len, len - upper_len, | ||
| 22421 | &metrics_lower); | ||
| 22422 | |||
| 22423 | |||
| 22424 | |||
| 22425 | /* +4 is for vertical bars of a box plus 1-pixel spaces at both side. */ | ||
| 22426 | width = max (metrics_upper.width, metrics_lower.width) + 4; | ||
| 22427 | upper_xoff = upper_yoff = 2; /* the typical case */ | ||
| 22428 | if (base_width >= width) | ||
| 22429 | { | ||
| 22430 | /* Align the upper to the left, the lower to the right. */ | ||
| 22431 | it->pixel_width = base_width; | ||
| 22432 | lower_xoff = base_width - 2 - metrics_lower.width; | ||
| 22433 | } | ||
| 22434 | else | ||
| 22435 | { | ||
| 22436 | /* Center the shorter one. */ | ||
| 22437 | it->pixel_width = width; | ||
| 22438 | if (metrics_upper.width >= metrics_lower.width) | ||
| 22439 | lower_xoff = (width - metrics_lower.width) / 2; | ||
| 22440 | else | ||
| 22441 | upper_xoff = (width - metrics_upper.width) / 2; | ||
| 22442 | } | ||
| 22443 | |||
| 22444 | /* +5 is for horizontal bars of a box plus 1-pixel spaces at | ||
| 22445 | top, bottom, and between upper and lower strings. */ | ||
| 22446 | height = (metrics_upper.ascent + metrics_upper.descent | ||
| 22447 | + metrics_lower.ascent + metrics_lower.descent) + 5; | ||
| 22448 | /* Center vertically. | ||
| 22449 | H:base_height, D:base_descent | ||
| 22450 | h:height, ld:lower_descent, la:lower_ascent, ud:upper_descent | ||
| 22451 | |||
| 22452 | ascent = - (D - H/2 - h/2 + 1); "+ 1" for rounding up | ||
| 22453 | descent = D - H/2 + h/2; | ||
| 22454 | lower_yoff = descent - 2 - ld; | ||
| 22455 | upper_yoff = lower_yoff - la - 1 - ud; */ | ||
| 22456 | ascent = - (it->descent - (base_height + height + 1) / 2); | ||
| 22457 | descent = it->descent - (base_height - height) / 2; | ||
| 22458 | lower_yoff = descent - 2 - metrics_lower.descent; | ||
| 22459 | upper_yoff = (lower_yoff - metrics_lower.ascent - 1 | ||
| 22460 | - metrics_upper.descent); | ||
| 22461 | /* Don't make the height shorter than the base height. */ | ||
| 22462 | if (height > base_height) | ||
| 22463 | { | ||
| 22464 | it->ascent = ascent; | ||
| 22465 | it->descent = descent; | ||
| 22466 | } | ||
| 22467 | } | ||
| 22468 | |||
| 22469 | it->phys_ascent = it->ascent; | ||
| 22470 | it->phys_descent = it->descent; | ||
| 22471 | if (it->glyph_row) | ||
| 22472 | append_glyphless_glyph (it, face_id, for_no_font, len, | ||
| 22473 | upper_xoff, upper_yoff, | ||
| 22474 | lower_xoff, lower_yoff); | ||
| 22475 | it->nglyphs = 1; | ||
| 22476 | take_vertical_position_into_account (it); | ||
| 22477 | } | ||
| 22478 | |||
| 22479 | |||
| 22112 | /* RIF: | 22480 | /* RIF: |
| 22113 | Produce glyphs/get display metrics for the display element IT is | 22481 | Produce glyphs/get display metrics for the display element IT is |
| 22114 | loaded with. See the description of struct it in dispextern.h | 22482 | loaded with. See the description of struct it in dispextern.h |
| @@ -22126,29 +22494,25 @@ x_produce_glyphs (struct it *it) | |||
| 22126 | XChar2b char2b; | 22494 | XChar2b char2b; |
| 22127 | struct face *face = FACE_FROM_ID (it->f, it->face_id); | 22495 | struct face *face = FACE_FROM_ID (it->f, it->face_id); |
| 22128 | struct font *font = face->font; | 22496 | struct font *font = face->font; |
| 22129 | int font_not_found_p = font == NULL; | ||
| 22130 | struct font_metrics *pcm = NULL; | 22497 | struct font_metrics *pcm = NULL; |
| 22131 | int boff; /* baseline offset */ | 22498 | int boff; /* baseline offset */ |
| 22132 | 22499 | ||
| 22133 | if (font_not_found_p) | 22500 | if (font == NULL) |
| 22134 | { | ||
| 22135 | /* When no suitable font found, display an empty box based | ||
| 22136 | on the metrics of the font of the default face (or what | ||
| 22137 | remapped). */ | ||
| 22138 | struct face *no_font_face | ||
| 22139 | = FACE_FROM_ID (it->f, | ||
| 22140 | NILP (Vface_remapping_alist) ? DEFAULT_FACE_ID | ||
| 22141 | : lookup_basic_face (it->f, DEFAULT_FACE_ID)); | ||
| 22142 | font = no_font_face->font; | ||
| 22143 | boff = font->baseline_offset; | ||
| 22144 | } | ||
| 22145 | else | ||
| 22146 | { | 22501 | { |
| 22147 | boff = font->baseline_offset; | 22502 | /* When no suitable font is found, display this character by |
| 22148 | if (font->vertical_centering) | 22503 | the method specified in the first extra slot of |
| 22149 | boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff; | 22504 | Vglyphless_char_display. */ |
| 22505 | Lisp_Object acronym = lookup_glyphless_char_display (-1, it); | ||
| 22506 | |||
| 22507 | xassert (it->what == IT_GLYPHLESS); | ||
| 22508 | produce_glyphless_glyph (it, 1, STRINGP (acronym) ? acronym : Qnil); | ||
| 22509 | goto done; | ||
| 22150 | } | 22510 | } |
| 22151 | 22511 | ||
| 22512 | boff = font->baseline_offset; | ||
| 22513 | if (font->vertical_centering) | ||
| 22514 | boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff; | ||
| 22515 | |||
| 22152 | if (it->char_to_display != '\n' && it->char_to_display != '\t') | 22516 | if (it->char_to_display != '\n' && it->char_to_display != '\t') |
| 22153 | { | 22517 | { |
| 22154 | int stretched_p; | 22518 | int stretched_p; |
| @@ -22167,8 +22531,7 @@ x_produce_glyphs (struct it *it) | |||
| 22167 | it->descent = FONT_DESCENT (font) - boff; | 22531 | it->descent = FONT_DESCENT (font) - boff; |
| 22168 | } | 22532 | } |
| 22169 | 22533 | ||
| 22170 | if (! font_not_found_p | 22534 | if (get_char_glyph_code (it->char_to_display, font, &char2b)) |
| 22171 | && get_char_glyph_code (it->char_to_display, font, &char2b)) | ||
| 22172 | { | 22535 | { |
| 22173 | pcm = get_per_char_metric (it->f, font, &char2b); | 22536 | pcm = get_per_char_metric (it->f, font, &char2b); |
| 22174 | if (pcm->width == 0 | 22537 | if (pcm->width == 0 |
| @@ -22758,11 +23121,14 @@ x_produce_glyphs (struct it *it) | |||
| 22758 | if (it->glyph_row) | 23121 | if (it->glyph_row) |
| 22759 | append_composite_glyph (it); | 23122 | append_composite_glyph (it); |
| 22760 | } | 23123 | } |
| 23124 | else if (it->what == IT_GLYPHLESS) | ||
| 23125 | produce_glyphless_glyph (it, 0, Qnil); | ||
| 22761 | else if (it->what == IT_IMAGE) | 23126 | else if (it->what == IT_IMAGE) |
| 22762 | produce_image_glyph (it); | 23127 | produce_image_glyph (it); |
| 22763 | else if (it->what == IT_STRETCH) | 23128 | else if (it->what == IT_STRETCH) |
| 22764 | produce_stretch_glyph (it); | 23129 | produce_stretch_glyph (it); |
| 22765 | 23130 | ||
| 23131 | done: | ||
| 22766 | /* Accumulate dimensions. Note: can't assume that it->descent > 0 | 23132 | /* Accumulate dimensions. Note: can't assume that it->descent > 0 |
| 22767 | because this isn't true for images with `:ascent 100'. */ | 23133 | because this isn't true for images with `:ascent 100'. */ |
| 22768 | xassert (it->ascent >= 0 && it->descent >= 0); | 23134 | xassert (it->ascent >= 0 && it->descent >= 0); |
| @@ -26592,6 +26958,35 @@ cursor shapes. */); | |||
| 26592 | 26958 | ||
| 26593 | hourglass_atimer = NULL; | 26959 | hourglass_atimer = NULL; |
| 26594 | hourglass_shown_p = 0; | 26960 | hourglass_shown_p = 0; |
| 26961 | |||
| 26962 | DEFSYM (Qglyphless_char, "glyphless-char"); | ||
| 26963 | DEFSYM (Qhexa_code, "hexa-code"); | ||
| 26964 | DEFSYM (Qempty_box, "empty-box"); | ||
| 26965 | DEFSYM (Qthin_space, "thin-space"); | ||
| 26966 | DEFSYM (Qzero_width, "zero-width"); | ||
| 26967 | |||
| 26968 | DEFSYM (Qglyphless_char_display, "glyphless-char-display"); | ||
| 26969 | /* Intern this now in case it isn't already done. | ||
| 26970 | Setting this variable twice is harmless. | ||
| 26971 | But don't staticpro it here--that is done in alloc.c. */ | ||
| 26972 | Qchar_table_extra_slots = intern_c_string ("char-table-extra-slots"); | ||
| 26973 | Fput (Qglyphless_char_display, Qchar_table_extra_slots, make_number (1)); | ||
| 26974 | |||
| 26975 | DEFVAR_LISP ("glyphless-char-display", &Vglyphless_char_display, | ||
| 26976 | doc: /* Char-table to control displaying of glyphless characters. | ||
| 26977 | Each element, if non-nil, is an ASCII acronym string (displayed in a box) | ||
| 26978 | or one of these symbols: | ||
| 26979 | hexa-code: display with hexadecimal character code in a box | ||
| 26980 | empty-box: display with an empty box | ||
| 26981 | thin-space: display with 1-pixel width space | ||
| 26982 | zero-width: don't display | ||
| 26983 | |||
| 26984 | It has one extra slot to control the display of a character for which | ||
| 26985 | no font is found. The value of the slot is `hexa-code' or `empty-box'. | ||
| 26986 | The default is `empty-box'. */); | ||
| 26987 | Vglyphless_char_display = Fmake_char_table (Qglyphless_char_display, Qnil); | ||
| 26988 | Fset_char_table_extra_slot (Vglyphless_char_display, make_number (0), | ||
| 26989 | Qempty_box); | ||
| 26595 | } | 26990 | } |
| 26596 | 26991 | ||
| 26597 | 26992 | ||
diff --git a/src/xterm.c b/src/xterm.c index 401b3ecfa4e..83e9465daf3 100644 --- a/src/xterm.c +++ b/src/xterm.c | |||
| @@ -1330,6 +1330,83 @@ x_draw_composite_glyph_string_foreground (struct glyph_string *s) | |||
| 1330 | } | 1330 | } |
| 1331 | 1331 | ||
| 1332 | 1332 | ||
| 1333 | /* Draw the foreground of glyph string S for glyphless characters. */ | ||
| 1334 | |||
| 1335 | static void | ||
| 1336 | x_draw_glyphless_glyph_string_foreground (struct glyph_string *s) | ||
| 1337 | { | ||
| 1338 | struct glyph *glyph = s->first_glyph; | ||
| 1339 | XChar2b char2b[8]; | ||
| 1340 | int x, i, j; | ||
| 1341 | |||
| 1342 | /* If first glyph of S has a left box line, start drawing the text | ||
| 1343 | of S to the right of that box line. */ | ||
| 1344 | if (s->face && s->face->box != FACE_NO_BOX | ||
| 1345 | && s->first_glyph->left_box_line_p) | ||
| 1346 | x = s->x + eabs (s->face->box_line_width); | ||
| 1347 | else | ||
| 1348 | x = s->x; | ||
| 1349 | |||
| 1350 | s->char2b = char2b; | ||
| 1351 | |||
| 1352 | for (i = 0; i < s->nchars; i++, glyph++) | ||
| 1353 | { | ||
| 1354 | char buf[7], *str = NULL; | ||
| 1355 | int len = glyph->u.glyphless.len; | ||
| 1356 | |||
| 1357 | if (glyph->u.glyphless.method == GLYPHLESS_DISPLAY_ACRONYM) | ||
| 1358 | { | ||
| 1359 | if (len > 0 | ||
| 1360 | && CHAR_TABLE_P (Vglyphless_char_display) | ||
| 1361 | && (CHAR_TABLE_EXTRA_SLOTS (XCHAR_TABLE (Vglyphless_char_display)) | ||
| 1362 | >= 1)) | ||
| 1363 | { | ||
| 1364 | Lisp_Object acronym | ||
| 1365 | = (! glyph->u.glyphless.for_no_font | ||
| 1366 | ? CHAR_TABLE_REF (Vglyphless_char_display, | ||
| 1367 | glyph->u.glyphless.ch) | ||
| 1368 | : XCHAR_TABLE (Vglyphless_char_display)->extras[0]); | ||
| 1369 | if (STRINGP (acronym)) | ||
| 1370 | str = (char *) SDATA (acronym); | ||
| 1371 | } | ||
| 1372 | } | ||
| 1373 | else if (glyph->u.glyphless.method == GLYPHLESS_DISPLAY_HEXA_CODE) | ||
| 1374 | { | ||
| 1375 | sprintf ((char *) buf, "%0*X", | ||
| 1376 | glyph->u.glyphless.ch < 0x10000 ? 4 : 6, | ||
| 1377 | glyph->u.glyphless.ch); | ||
| 1378 | str = buf; | ||
| 1379 | } | ||
| 1380 | |||
| 1381 | if (str) | ||
| 1382 | { | ||
| 1383 | int upper_len = (len + 1) / 2; | ||
| 1384 | unsigned code; | ||
| 1385 | |||
| 1386 | /* It is assured that all LEN characters in STR is ASCII. */ | ||
| 1387 | for (j = 0; j < len; j++) | ||
| 1388 | { | ||
| 1389 | code = s->font->driver->encode_char (s->font, str[j]); | ||
| 1390 | STORE_XCHAR2B (char2b + j, code >> 8, code & 0xFF); | ||
| 1391 | } | ||
| 1392 | s->font->driver->draw (s, 0, upper_len, | ||
| 1393 | x + glyph->slice.glyphless.upper_xoff, | ||
| 1394 | s->ybase + glyph->slice.glyphless.upper_yoff, | ||
| 1395 | 0); | ||
| 1396 | s->font->driver->draw (s, upper_len, len, | ||
| 1397 | x + glyph->slice.glyphless.lower_xoff, | ||
| 1398 | s->ybase + glyph->slice.glyphless.lower_yoff, | ||
| 1399 | 0); | ||
| 1400 | } | ||
| 1401 | if (glyph->u.glyphless.method != GLYPHLESS_DISPLAY_THIN_SPACE) | ||
| 1402 | XDrawRectangle (s->display, s->window, s->gc, | ||
| 1403 | x, s->ybase - glyph->ascent, | ||
| 1404 | glyph->pixel_width - 1, | ||
| 1405 | glyph->ascent + glyph->descent - 1); | ||
| 1406 | x += glyph->pixel_width; | ||
| 1407 | } | ||
| 1408 | } | ||
| 1409 | |||
| 1333 | #ifdef USE_X_TOOLKIT | 1410 | #ifdef USE_X_TOOLKIT |
| 1334 | 1411 | ||
| 1335 | static struct frame *x_frame_of_widget (Widget); | 1412 | static struct frame *x_frame_of_widget (Widget); |
| @@ -2656,6 +2733,14 @@ x_draw_glyph_string (struct glyph_string *s) | |||
| 2656 | x_draw_composite_glyph_string_foreground (s); | 2733 | x_draw_composite_glyph_string_foreground (s); |
| 2657 | break; | 2734 | break; |
| 2658 | 2735 | ||
| 2736 | case GLYPHLESS_GLYPH: | ||
| 2737 | if (s->for_overlaps) | ||
| 2738 | s->background_filled_p = 1; | ||
| 2739 | else | ||
| 2740 | x_draw_glyph_string_background (s, 1); | ||
| 2741 | x_draw_glyphless_glyph_string_foreground (s); | ||
| 2742 | break; | ||
| 2743 | |||
| 2659 | default: | 2744 | default: |
| 2660 | abort (); | 2745 | abort (); |
| 2661 | } | 2746 | } |