Commit b2cca856 authored by Kenichi Handa's avatar Kenichi Handa

Implement various display methods for glyphless characters.

parent 8289f37b
2010-10-28 Kenichi Handa <handa@m17n.org>
Implement various display methods for glyphless characters.
* international/characters.el (char-acronym-table): New variable.
(glyphless-char-control): New variable.
(update-glyphless-char-display): New funciton.
* faces.el (glyphless-char): New face.
2010-10-28 Glenn Morris <rgm@gnu.org>
* term/ns-win.el (global-map, menu-bar-final-items, menu-bar-help-menu):
......
......@@ -2482,6 +2482,12 @@ Note: Other faces cannot inherit from the cursor face."
(defface help-argument-name '((((supports :slant italic)) :inherit italic))
"Face to highlight argument names in *Help* buffers."
:group 'help)
(defface glyphless-char '((t :height 0.6))
"Face for displaying non-graphic characters (e.g. U+202A (LRE)).
It is used for characters of no fonts too."
:version "24.1"
:group 'basic-faces)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Manipulating font names.
......
......@@ -1233,6 +1233,131 @@ Setup char-width-table appropriate for non-CJK language environment."
(optimize-char-table (standard-category-table))
;; Display of glyphless characters.
(defvar char-acronym-table
(make-char-table 'char-acronym-table nil)
"Char table of acronyms for non-graphic characters.")
(let ((c0-acronyms '("NUL" "SOH" "STX" "ETX" "EOT" "ENQ" "ACK" "BEL"
"BS" nil nil "VT" "FF" "CR" "SO" "SI"
"DLE" "DC1" "DC2" "DC3" "DC4" "NAK" "SYN" "ETB"
"CAN" "EM" "SUB" "ESC" "FC" "GS" "RS" "US")))
(dotimes (i 32)
(aset char-acronym-table i (car c0-acronyms))
(setq c0-acronyms (cdr c0-acronyms))))
(let ((c1-acronyms '("XXX" "XXX" "BPH" "NBH" "IND" "NEL" "SSA" "ESA"
"HTS" "HTJ" "VTS" "PLD" "PLU" "R1" "SS2" "SS1"
"DCS" "PU1" "PU2" "STS" "CCH" "MW" "SPA" "EPA"
"SOS" "XXX" "SC1" "CSI" "ST" "OSC" "PM" "APC")))
(dotimes (i 32)
(aset char-acronym-table (+ #x0080 i) (car c1-acronyms))
(setq c1-acronyms (cdr c1-acronyms))))
(aset char-acronym-table #x17B4 "KIVAQ") ; KHMER VOWEL INHERENT AQ
(aset char-acronym-table #x17B5 "KIVAA") ; KHMER VOWEL INHERENT AA
(aset char-acronym-table #x200B "ZWSP") ; ZERO WIDTH SPACE
(aset char-acronym-table #x200C "ZWNJ") ; ZERO WIDTH NON-JOINER
(aset char-acronym-table #x200D "ZWJ") ; ZERO WIDTH JOINER
(aset char-acronym-table #x200E "LRM") ; LEFT-TO-RIGHT MARK
(aset char-acronym-table #x200F "RLM") ; RIGHT-TO-LEFT MARK
(aset char-acronym-table #x202A "LRE") ; LEFT-TO-RIGHT EMBEDDING
(aset char-acronym-table #x202B "RLE") ; RIGHT-TO-LEFT EMBEDDING
(aset char-acronym-table #x202C "PDF") ; POP DIRECTIONAL FORMATTING
(aset char-acronym-table #x202D "LRO") ; LEFT-TO-RIGHT OVERRIDE
(aset char-acronym-table #x202E "RLO") ; RIGHT-TO-LEFT OVERRIDE
(aset char-acronym-table #x2060 "WJ") ; WORD JOINER
(aset char-acronym-table #x206A "ISS") ; INHIBIT SYMMETRIC SWAPPING
(aset char-acronym-table #x206B "ASS") ; ACTIVATE SYMMETRIC SWAPPING
(aset char-acronym-table #x206C "IAFS") ; INHIBIT ARABIC FORM SHAPING
(aset char-acronym-table #x206D "AAFS") ; ACTIVATE ARABIC FORM SHAPING
(aset char-acronym-table #x206E "NADS") ; NATIONAL DIGIT SHAPES
(aset char-acronym-table #x206F "NODS") ; NOMINAL DIGIT SHAPES
(aset char-acronym-table #xFEFF "ZWNBSP") ; ZERO WIDTH NO-BREAK SPACE
(aset char-acronym-table #xFFF9 "IAA") ; INTERLINEAR ANNOTATION ANCHOR
(aset char-acronym-table #xFFFA "IAS") ; INTERLINEAR ANNOTATION SEPARATOR
(aset char-acronym-table #xFFFB "IAT") ; INTERLINEAR ANNOTATION TERMINATOR
(aset char-acronym-table #x1D173 "BEGBM") ; MUSICAL SYMBOL BEGIN BEAM
(aset char-acronym-table #x1D174 "ENDBM") ; MUSICAL SYMBOL END BEAM
(aset char-acronym-table #x1D175 "BEGTIE") ; MUSICAL SYMBOL BEGIN TIE
(aset char-acronym-table #x1D176 "END") ; MUSICAL SYMBOL END TIE
(aset char-acronym-table #x1D177 "BEGSLR") ; MUSICAL SYMBOL BEGIN SLUR
(aset char-acronym-table #x1D178 "ENDSLR") ; MUSICAL SYMBOL END SLUR
(aset char-acronym-table #x1D179 "BEGPHR") ; MUSICAL SYMBOL BEGIN PHRASE
(aset char-acronym-table #x1D17A "ENDPHR") ; MUSICAL SYMBOL END PHRASE
(aset char-acronym-table #xE0001 "|->TAG") ; LANGUAGE TAG
(aset char-acronym-table #xE0020 "SP TAG") ; TAG SPACE
(dotimes (i 94)
(aset char-acronym-table (+ #xE0021 i) (format " %c TAG" (+ 33 i))))
(aset char-acronym-table #xE007F "->|TAG") ; CANCEL TAG
;;; Control of displaying glyphless characters.
(defvar glyphless-char-control
'((format-control . thin-space)
(no-font . hexa-code))
"List of directives to control displaying of glyphless characters.
Each element has the form (TARGET . METHOD), where TARGET is a
symbol specifying the target character group to control, and
METHOD is a symbol specifying the method of displaying them.
TARGET must be one of these symbols:
`c0-control': U+0000..U+001F.
`c1-control': U+0080..U+009F.
`format-control': Characters of Unicode General Category `Cf'.
Ex: U+200C (ZWNJ), U+200E (LRM)), but don't include characters
that have graphic image such as U+00AD (SHY).
`no-font': characters for which no suitable font is found.
METHOD must be one of these symbols:
`zero-width': don't display.
`thin-space': display a thin space (1-pixel width).
`empty-box': display an empty box.
`acronym': display an acronum string in a box.
`hexa-code': display a hexadecimal character code in a box.
Just setting this variable does not take effect. Call the
function `update-glyphless-char-display' (which see) after
setting this variable.")
(defun update-glyphless-char-display ()
"Make the setting of `glyphless-char-control' take effect.
This function updates the char-table `glyphless-char-display'."
(dolist (elt glyphless-char-control)
(let ((target (car elt))
(method (cdr elt)))
(cond ((eq target 'c0-control)
(set-char-table-range glyphless-char-display '(#x00 . #x1F)
method))
((eq target 'c1-control)
(set-char-table-range glyphless-char-display '(#x80 . #x9F)
method))
((eq target 'format-control)
(map-char-table
#'(lambda (char category)
(if (eq category 'Cf)
(let ((this-method method)
from to)
(if (consp char)
(setq from (car char) to (cdr char))
(setq from char to char))
(while (<= from to)
(when (/= from #xAD)
(if (eq method 'acronym)
(setq this-method
(aref char-acronym-table from)))
(set-char-table-range glyphless-char-display
from this-method))
(setq from (1+ from))))))
unicode-category-table))
((eq target 'no-font)
(set-char-table-extra-slot glyphless-char-display 0 method))
(t
(error "Invalid target character group: %s" target))))))
(update-glyphless-char-display)
;;; Setting word boundary.
......
2010-10-28 Kenichi Handa <handa@m17n.org>
Implement various display methods for glyphless characters.
* xdisp.c (Qglyphless_char, Vglyphless_char_display)
(Qglyphless_char_display, Qhexa_code, Qempty_box, Qthin_space)
(Qzero_width): New variables.
(THIN_SPACE_WIDTH): New macro.
(lookup_glyphless_char_display): New funciton.
(last_glyphless_glyph_frame, last_glyphless_glyph_face_id)
(last_glyphless_glyph_merged_face_id): New variables.
(get_next_display_element): Check glyphless characters.
(redisplay_internal): Initialize last_glyphless_glyph_frame and
last_glyphless_glyph_face_id.
(fill_glyphless_glyph_string): New function.
(BUILD_GLYPHLESS_GLYPH_STRING): New macro.
(BUILD_GLYPH_STRINGS): Handle the case GLYPHLESS_GLYPH.
(append_glyphless_glyph, produce_glyphless_glyph): New functions.
(x_produce_glyphs): If a suitable font is not found, produce a
glyphless glyph. Handle the case it->what == IT_GLYPHLESS.
(syms_of_xdisp): Intern and staticpro Qglyphless_char,
Qglyphless_char_display, Qhexa_code, Qempty_box, Qthin_space, and
Qzero_width.
(Vglyphless_char_display): Declare it as a Lisp variable.
* dispextern.h (enum glyph_type): Add GLYPHLESS_GLYPH.
(struct glyph): Change the size of the member "type" to 3. Add
glyphless to the union slice and u.
(enum display_element_type): Add IT_GLYPHLESS.
(enum glyphless_display_method): New enum.
(struct it): New member glyphless_method.
(Vglyphless_char_display): Extern it.
* xterm.c (x_draw_glyphless_glyph_string_foreground): New function.
(x_draw_glyph_string): Handle the case GLYPHLESS_GLYPH.
* w32term.c (x_draw_glyphless_glyph_string_foreground): New
function.
(x_draw_glyph_string): Handle the case GLYPHLESS_GLYPH.
* nsterm.m (ns_draw_glyph_string): Handle the case
GLYPHLESS_GLYPH (the detail is not yet implemented).
2010-10-26 Juanma Barranquero <lekktu@gmail.com>
* eval.c (init_eval_once): Set max_lisp_eval_depth to 600;
......
......@@ -279,6 +279,9 @@ enum glyph_type
/* Glyph describes a static composition. */
COMPOSITE_GLYPH,
/* Glyph describes a glyphless character. */
GLYPHLESS_GLYPH,
/* Glyph describes an image. */
IMAGE_GLYPH,
......@@ -333,7 +336,7 @@ struct glyph
/* Which kind of glyph this is---character, image etc. Value
should be an enumerator of type enum glyph_type. */
unsigned type : 2;
unsigned type : 3;
/* 1 means this glyph was produced from multibyte text. Zero
means it was produced from unibyte text, i.e. charsets aren't
......@@ -402,6 +405,11 @@ struct glyph
/* Start and end indices of glyphs of a graphme cluster of a
composition (type == COMPOSITE_GLYPH). */
struct { int from, to; } cmp;
/* Pixel offsets for upper and lower part of the acronym. */
struct {
short upper_xoff, upper_yoff;
short lower_xoff, lower_yoff;
} glyphless;
} slice;
/* A union of sub-structures for different glyph types. */
......@@ -433,6 +441,19 @@ struct glyph
}
stretch;
/* Sub-stretch for type == GLYPHLESS_GLYPH. */
struct
{
/* Value is an enum of the type glyphless_display_method. */
unsigned method : 2;
/* 1 iff this glyph is for a character of no font. */
unsigned for_no_font : 1;
/* Length of acronym or hexadecimal code string (at most 8). */
unsigned len : 4;
/* Character to display. Actually we need only 22 bits. */
unsigned ch : 26;
} glyphless;
/* Used to compare all bit-fields above in one step. */
unsigned val;
} u;
......@@ -1918,6 +1939,9 @@ enum display_element_type
/* A composition (static and automatic). */
IT_COMPOSITION,
/* A glyphless character (e.g. ZWNJ, LRE). */
IT_GLYPHLESS,
/* An image. */
IT_IMAGE,
......@@ -1964,6 +1988,20 @@ enum line_wrap_method
WINDOW_WRAP
};
/* An enumerator for the method of displaying glyphless characters. */
enum glyphless_display_method
{
/* Display a thin (1-pixel width) space. */
GLYPHLESS_DISPLAY_THIN_SPACE,
/* Display an empty box of proper width. */
GLYPHLESS_DISPLAY_EMPTY_BOX,
/* Display an acronym string in a box. */
GLYPHLESS_DISPLAY_ACRONYM,
/* Display a hexadecimal character code in a box. */
GLYPHLESS_DISPLAY_HEXA_CODE
};
struct it_slice
{
Lisp_Object x;
......@@ -2295,6 +2333,10 @@ struct it
PRODUCE_GLYPHS, this should be set beforehand too. */
int char_to_display;
/* If what == IT_GLYPHLESS, the method to display such a
character. */
enum glyphless_display_method glyphless_method;
/* If what == IT_IMAGE, the id of the image to display. */
int image_id;
......@@ -2976,6 +3018,7 @@ extern int last_tool_bar_item;
extern Lisp_Object Vmouse_autoselect_window;
extern int unibyte_display_via_language_environment;
extern EMACS_INT underline_minimum_offset;
extern Lisp_Object Vglyphless_char_display;
extern void reseat_at_previous_visible_line_start (struct it *);
......
......@@ -2983,6 +2983,22 @@ overwriting cursor (usually when cursor on a tab) */
ns_unfocus (s->f);
break;
case GLYPHLESS_GLYPH:
n = ns_get_glyph_string_clip_rect (s, r);
ns_focus (s->f, r, n);
if (s->for_overlaps || (s->cmp_from > 0
&& ! s->first_glyph->u.cmp.automatic))
s->background_filled_p = 1;
else
ns_maybe_dumpglyphs_background
(s, s->first_glyph->type == COMPOSITE_GLYPH);
/* ... */
/* Not yet implemented. */
/* ... */
ns_unfocus (s->f);
break;
default:
abort ();
}
......
......@@ -1394,6 +1394,92 @@ x_draw_composite_glyph_string_foreground (struct glyph_string *s)
}
/* Draw the foreground of glyph string S for glyphless characters. */
static void
x_draw_glyphless_glyph_string_foreground (struct glyph_string *s)
{
struct glyph *glyph = s->first_glyph;
XChar2b char2b[8];
int x, i, j;
/* If first glyph of S has a left box line, start drawing the text
of S to the right of that box line. */
if (s->face->box != FACE_NO_BOX
&& s->first_glyph->left_box_line_p)
x = s->x + eabs (s->face->box_line_width);
else
x = s->x;
SetTextColor (s->hdc, s->gc->foreground);
SetBkColor (s->hdc, s->gc->background);
SetTextAlign (s->hdc, TA_BASELINE | TA_LEFT);
s->char2b = char2b;
for (i = 0; i < s->nchars; i++, glyph++)
{
char buf[7], *str = NULL;
int len = glyph->u.glyphless.len;
if (glyph->u.glyphless.method == GLYPHLESS_DISPLAY_ACRONYM)
{
if (len > 1
&& CHAR_TABLE_P (Vglyphless_char_display)
&& (CHAR_TABLE_EXTRA_SLOTS (XCHAR_TABLE (Vglyphless_char_display))
>= 1))
{
Lisp_Object acronym
= (! glyph->u.glyphless.for_no_font
? CHAR_TABLE_REF (Vglyphless_char_display,
glyph->u.glyphless.ch)
: XCHAR_TABLE (Vglyphless_char_display)->extras[0]);
if (STRINGP (acronym))
str = (char *) SDATA (acronym);
}
}
else if (glyph->u.glyphless.method == GLYPHLESS_DISPLAY_HEXA_CODE)
{
sprintf ((char *) buf, "%0*X",
glyph->u.glyphless.ch < 0x10000 ? 4 : 6,
glyph->u.glyphless.ch);
str = buf;
}
if (str)
{
struct font *font = s->font;
int upper_len = (len + 1) / 2;
unsigned code;
HFONT old_font;
old_font = SelectObject (s->hdc, FONT_HANDLE (font));
/* It is assured that all LEN characters in STR is ASCII. */
for (j = 0; j < len; j++)
{
code = font->driver->encode_char (font, str[j]);
STORE_XCHAR2B (char2b + j, code >> 8, code & 0xFF);
}
font->driver->draw (s, 0, upper_len,
x + glyph->slice.glyphless.upper_xoff,
s->ybase + glyph->slice.glyphless.upper_yoff,
0);
font->driver->draw (s, upper_len, len,
x + glyph->slice.glyphless.lower_xoff,
s->ybase + glyph->slice.glyphless.lower_yoff,
0);
SelectObject (s->hdc, old_font);
}
if (glyph->u.glyphless.method != GLYPHLESS_DISPLAY_THIN_SPACE)
w32_draw_rectangle (s->hdc, s->gc,
x, s->ybase - glyph->ascent,
glyph->pixel_width - 1,
glyph->ascent + glyph->descent - 1);
x += glyph->pixel_width;
}
}
/* Brightness beyond which a color won't have its highlight brightness
boosted.
......@@ -2282,6 +2368,15 @@ x_draw_glyph_string (struct glyph_string *s)
x_draw_composite_glyph_string_foreground (s);
break;
case GLYPHLESS_GLYPH:
if (s->for_overlaps || (s->cmp_from > 0
&& ! s->first_glyph->u.cmp.automatic))
s->background_filled_p = 1;
else
x_draw_glyph_string_background (s, 1);
x_draw_glyphless_glyph_string_foreground (s);
break;
default:
abort ();
}
......
......@@ -932,6 +932,21 @@ struct atimer *hourglass_atimer;
/* Number of seconds to wait before displaying an hourglass cursor. */
Lisp_Object Vhourglass_delay;
/* Name of the face used to display glyphless characters. */
Lisp_Object Qglyphless_char;
/* Char-table to control the display of glyphless characters. */
Lisp_Object Vglyphless_char_display;
/* Symbol for the purpose of Vglyphless_char_display. */
Lisp_Object Qglyphless_char_display;
/* Method symbols for Vglyphless_char_display. */
static Lisp_Object Qhexa_code, Qempty_box, Qthin_space, Qzero_width;
/* Default pixel width of `thin-space' display method. */
#define THIN_SPACE_WIDTH 1
/* Default number of seconds to wait before displaying an hourglass
cursor. */
#define DEFAULT_HOURGLASS_DELAY 1
......@@ -5732,6 +5747,57 @@ static int (* get_next_element[NUM_IT_METHODS]) (struct it *it) =
(IT)->string)))
/* Lookup the char-table Vglyphless_char_display for character C (-1
if we want information for no-font case), and return the display
method symbol. By side-effect, update it->what and
it->glyphless_method. This function is called from
get_next_display_element for each character element, and from
x_produce_glyphs when no suitable font was found. */
static Lisp_Object
lookup_glyphless_char_display (int c, struct it *it)
{
Lisp_Object glyphless_method = Qnil;
if (CHAR_TABLE_P (Vglyphless_char_display)
&& CHAR_TABLE_EXTRA_SLOTS (XCHAR_TABLE (Vglyphless_char_display)) >= 1)
glyphless_method = (c >= 0
? CHAR_TABLE_REF (Vglyphless_char_display, c)
: XCHAR_TABLE (Vglyphless_char_display)->extras[0]);
retry:
if (NILP (glyphless_method))
{
if (c >= 0)
/* The default is to display the character by a proper font. */
return Qnil;
/* The default for the no-font case is to display an empty box. */
glyphless_method = Qempty_box;
}
if (EQ (glyphless_method, Qzero_width))
{
if (c >= 0)
return glyphless_method;
/* This method can't be used for the no-font case. */
glyphless_method = Qempty_box;
}
it->what = IT_GLYPHLESS;
if (EQ (glyphless_method, Qthin_space))
it->glyphless_method = GLYPHLESS_DISPLAY_THIN_SPACE;
else if (EQ (glyphless_method, Qempty_box))
it->glyphless_method = GLYPHLESS_DISPLAY_EMPTY_BOX;
else if (EQ (glyphless_method, Qhexa_code))
it->glyphless_method = GLYPHLESS_DISPLAY_HEXA_CODE;
else if (STRINGP (glyphless_method))
it->glyphless_method = GLYPHLESS_DISPLAY_ACRONYM;
else
{
/* Invalid value. We use the default method. */
glyphless_method = Qnil;
goto retry;
}
return glyphless_method;
}
/* Load IT's display element fields with information about the next
display element from the current position of IT. Value is zero if
end of buffer (or C string) is reached. */
......@@ -5740,6 +5806,10 @@ static struct frame *last_escape_glyph_frame = NULL;
static unsigned last_escape_glyph_face_id = (1 << FACE_ID_BITS);
static int last_escape_glyph_merged_face_id = 0;
static struct frame *last_glyphless_glyph_frame = NULL;
static unsigned last_glyphless_glyph_face_id = (1 << FACE_ID_BITS);
static int last_glyphless_glyph_merged_face_id = 0;
int
get_next_display_element (struct it *it)
{
......@@ -5818,6 +5888,15 @@ get_next_display_element (struct it *it)
goto get_next;
}
if (! NILP (lookup_glyphless_char_display (c, it)))
{
if (it->what == IT_GLYPHLESS)
goto done;
/* Don't display this character. */
set_iterator_to_next (it, 0);
goto get_next;
}
if (! ASCII_CHAR_P (c) && ! NILP (Vnobreak_char_display))
nbsp_or_shy = (c == 0xA0 ? char_is_nbsp
: c == 0xAD ? char_is_soft_hyphen
......@@ -6032,6 +6111,7 @@ get_next_display_element (struct it *it)
}
#endif
done:
/* Is this character the last one of a run of characters with
box? If yes, set IT->end_of_box_run_p to 1. */
if (it->face_box_p
......@@ -11579,6 +11659,8 @@ redisplay_internal (int preserve_echo_area)
reconsider_clip_changes (w, current_buffer);
last_escape_glyph_frame = NULL;
last_escape_glyph_face_id = (1 << FACE_ID_BITS);
last_glyphless_glyph_frame = NULL;
last_glyphless_glyph_face_id = (1 << FACE_ID_BITS);
/* If new fonts have been loaded that make a glyph matrix adjustment
necessary, do it. */
......@@ -20657,6 +20739,42 @@ fill_gstring_glyph_string (struct glyph_string *s, int face_id,
}
/* Fill glyph string S from a sequence glyphs for glyphless characters.
See the comment of fill_glyph_string for arguments.
Value is the index of the first glyph not in S. */
static int
fill_glyphless_glyph_string (struct glyph_string *s, int face_id,
int start, int end, int overlaps)
{
struct glyph *glyph, *last;
int voffset;
xassert (s->first_glyph->type == GLYPHLESS_GLYPH);
s->for_overlaps = overlaps;
glyph = s->row->glyphs[s->area] + start;
last = s->row->glyphs[s->area] + end;
voffset = glyph->voffset;
s->face = FACE_FROM_ID (s->f, face_id);
s->font = s->face->font;
s->nchars = 1;
s->width = glyph->pixel_width;
glyph++;
while (glyph < last
&& glyph->type == GLYPHLESS_GLYPH
&& glyph->voffset == voffset
&& glyph->face_id == face_id)
{
s->nchars++;
s->width += glyph->pixel_width;
glyph++;
}
s->ybase += voffset;
return glyph - s->row->glyphs[s->area];
}
/* Fill glyph string S from a sequence of character glyphs.
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)
} while (0)
/* Add a glyph string for a sequence of glyphless character's glyphs
to the list of strings between HEAD and TAIL. The meanings of
arguments are the same as those of BUILD_CHAR_GLYPH_STRINGS. */
#define BUILD_GLYPHLESS_GLYPH_STRING(START, END, HEAD, TAIL, HL, X, LAST_X) \
do \
{ \
int face_id; \
XChar2b *char2b; \
\
face_id = (row)->glyphs[area][START].face_id; \
\
s = (struct glyph_string *) alloca (sizeof *s); \
INIT_GLYPH_STRING (s, NULL, w, row, area, START, HL); \
append_glyph_string (&HEAD, &TAIL, s); \
s->x = (X); \
START = fill_glyphless_glyph_string (s, face_id, START, END, \
overlaps); \
} \
while (0)
/* Build a list of glyph strings between HEAD and TAIL for the glyphs
of AREA of glyph row ROW on window W between indices START and END.
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)
BUILD_CHAR_GLYPH_STRINGS (START, END, HEAD, TAIL, \
HL, X, LAST_X); \
break; \
\
\
case COMPOSITE_GLYPH: \
if (first_glyph->u.cmp.automatic) \
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)
BUILD_COMPOSITE_GLYPH_STRING (START, END, HEAD, TAIL, \
HL, X, LAST_X); \
break; \
\
\
case STRETCH_GLYPH: \
BUILD_STRETCH_GLYPH_STRING (START, END, HEAD, TAIL, \
HL, X, LAST_X); \
break; \
\
\
case IMAGE_GLYPH: \
BUILD_IMAGE_GLYPH_STRING (START, END, HEAD, TAIL, \
HL, X, LAST_X); \
break; \
\
\
case GLYPHLESS_GLYPH: \
BUILD_GLYPHLESS_GLYPH_STRING (START, END, HEAD, TAIL, \
HL, X, LAST_X); \
break; \
\
default: \