aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorKenichi Handa2010-10-29 09:50:13 +0900
committerKenichi Handa2010-10-29 09:50:13 +0900
commitb2cca8569ad863c651dde1523ed841b280a96658 (patch)
tree1fe09dc61ed7cb5c690f7446058216fdfbfbb6b9 /src
parent8289f37b64d3734339f8c82a1e444113873d8d25 (diff)
downloademacs-b2cca8569ad863c651dde1523ed841b280a96658.tar.gz
emacs-b2cca8569ad863c651dde1523ed841b280a96658.zip
Implement various display methods for glyphless characters.
Diffstat (limited to 'src')
-rw-r--r--src/ChangeLog43
-rw-r--r--src/dispextern.h45
-rw-r--r--src/nsterm.m16
-rw-r--r--src/w32term.c95
-rw-r--r--src/xdisp.c443
-rw-r--r--src/xterm.c85
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 @@
12010-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
12010-10-26 Juanma Barranquero <lekktu@gmail.com> 442010-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
1993enum 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
1967struct it_slice 2005struct 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;
2976extern Lisp_Object Vmouse_autoselect_window; 3018extern Lisp_Object Vmouse_autoselect_window;
2977extern int unibyte_display_via_language_environment; 3019extern int unibyte_display_via_language_environment;
2978extern EMACS_INT underline_minimum_offset; 3020extern EMACS_INT underline_minimum_offset;
3021extern Lisp_Object Vglyphless_char_display;
2979 3022
2980extern void reseat_at_previous_visible_line_start (struct it *); 3023extern 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
1399static void
1400x_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. */
933Lisp_Object Vhourglass_delay; 933Lisp_Object Vhourglass_delay;
934 934
935/* Name of the face used to display glyphless characters. */
936Lisp_Object Qglyphless_char;
937
938/* Char-table to control the display of glyphless characters. */
939Lisp_Object Vglyphless_char_display;
940
941/* Symbol for the purpose of Vglyphless_char_display. */
942Lisp_Object Qglyphless_char_display;
943
944/* Method symbols for Vglyphless_char_display. */
945static 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
5757static Lisp_Object
5758lookup_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;
5740static unsigned last_escape_glyph_face_id = (1 << FACE_ID_BITS); 5806static unsigned last_escape_glyph_face_id = (1 << FACE_ID_BITS);
5741static int last_escape_glyph_merged_face_id = 0; 5807static int last_escape_glyph_merged_face_id = 0;
5742 5808
5809static struct frame *last_glyphless_glyph_frame = NULL;
5810static unsigned last_glyphless_glyph_face_id = (1 << FACE_ID_BITS);
5811static int last_glyphless_glyph_merged_face_id = 0;
5812
5743int 5813int
5744get_next_display_element (struct it *it) 5814get_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
20747static int
20748fill_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
22269static void
22270append_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
22339static void
22340produce_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.
26977Each element, if non-nil, is an ASCII acronym string (displayed in a box)
26978or 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
26984It has one extra slot to control the display of a character for which
26985no font is found. The value of the slot is `hexa-code' or `empty-box'.
26986The 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
1335static void
1336x_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
1335static struct frame *x_frame_of_widget (Widget); 1412static 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 }