+ if (pcm == NULL || pcm->width == 0)
+ {
+ /* Character not contained in the font. FONT->default_char
+ gives the character that will be printed. FONT->default_char
+ is a 16-bit character code with byte1 in the most significant
+ byte and byte2 in the least significant byte. */
+ XChar2b default_char;
+ default_char.byte1 = (font->default_char >> BITS_PER_CHAR) & 0xff;
+ default_char.byte2 = font->default_char & 0xff;
+
+ /* Avoid an endless recursion if FONT->default_char itself
+ hasn't per char metrics. handa@etl.go.jp reports that some
+ fonts have this problem. */
+ if (default_char.byte1 != char2b->byte1
+ || default_char.byte2 != char2b->byte2)
+ pcm = x_per_char_metric (font, &default_char);
+ else
+ pcm = &font->max_bounds;
+ }
+
+ return pcm;
+}
+
+
+/* Encode CHAR2B using encoding information from FONT_INFO. CHAR2B is
+ the two-byte form of C. Encoding is returned in *CHAR2B. */
+
+static INLINE void
+x_encode_char (c, char2b, font_info)
+ int c;
+ XChar2b *char2b;
+ struct font_info *font_info;
+{
+ int charset = CHAR_CHARSET (c);
+ XFontStruct *font = font_info->font;
+
+ /* FONT_INFO may define a scheme by which to encode byte1 and byte2.
+ This may be either a program in a special encoder language or a
+ fixed encoding. */
+ if (font_info->font_encoder)
+ {
+ /* It's a program. */
+ struct ccl_program *ccl = font_info->font_encoder;
+
+ if (CHARSET_DIMENSION (charset) == 1)
+ {
+ ccl->reg[0] = charset;
+ ccl->reg[1] = char2b->byte2;
+ }
+ else
+ {
+ ccl->reg[0] = charset;
+ ccl->reg[1] = char2b->byte1;
+ ccl->reg[2] = char2b->byte2;
+ }
+
+ ccl_driver (ccl, NULL, NULL, 0, 0, NULL);
+
+ /* We assume that MSBs are appropriately set/reset by CCL
+ program. */
+ if (font->max_byte1 == 0) /* 1-byte font */
+ char2b->byte2 = ccl->reg[1];
+ else
+ char2b->byte1 = ccl->reg[1], char2b->byte2 = ccl->reg[2];
+ }
+ else if (font_info->encoding[charset])
+ {
+ /* Fixed encoding scheme. See fontset.h for the meaning of the
+ encoding numbers. */
+ int enc = font_info->encoding[charset];
+
+ if ((enc == 1 || enc == 2)
+ && CHARSET_DIMENSION (charset) == 2)
+ char2b->byte1 |= 0x80;
+
+ if (enc == 1 || enc == 3)
+ char2b->byte2 |= 0x80;
+ }
+}
+
+
+/* Get face and two-byte form of character C in face FACE_ID on frame
+ F. The encoding of C is returned in *CHAR2B. MULTIBYTE_P non-zero
+ means we want to display multibyte text. Value is a pointer to a
+ realized face that is ready for display. */
+
+static INLINE struct face *
+x_get_char_face_and_encoding (f, c, face_id, char2b, multibyte_p)
+ struct frame *f;
+ int c, face_id;
+ XChar2b *char2b;
+ int multibyte_p;
+{
+ struct face *face = FACE_FROM_ID (f, face_id);
+
+ if (!multibyte_p)
+ {
+ /* Unibyte case. We don't have to encode, but we have to make
+ sure to use a face suitable for unibyte. */
+ char2b->byte1 = 0;
+ char2b->byte2 = c;
+
+ if (!FACE_SUITABLE_FOR_CHARSET_P (face, -1))
+ {
+ face_id = FACE_FOR_CHARSET (f, face_id, -1);
+ face = FACE_FROM_ID (f, face_id);
+ }
+ }
+ else if (c < 128 && face_id < BASIC_FACE_ID_SENTINEL)
+ {
+ /* Case of ASCII in a face known to fit ASCII. */
+ char2b->byte1 = 0;
+ char2b->byte2 = c;
+ }
+ else
+ {
+ int c1, c2, charset;
+
+ /* Split characters into bytes. If c2 is -1 afterwards, C is
+ really a one-byte character so that byte1 is zero. */
+ SPLIT_CHAR (c, charset, c1, c2);
+ if (c2 > 0)
+ char2b->byte1 = c1, char2b->byte2 = c2;
+ else
+ char2b->byte1 = 0, char2b->byte2 = c1;
+
+ /* Get the face for displaying C. If `face' is not suitable for
+ charset, get the one that fits. (This can happen for the
+ translations of composite characters where the glyph
+ specifies a face for ASCII, but translations have a different
+ charset.) */
+ if (!FACE_SUITABLE_FOR_CHARSET_P (face, charset))
+ {
+ face_id = FACE_FOR_CHARSET (f, face_id, charset);
+ face = FACE_FROM_ID (f, face_id);
+ }
+
+ /* Maybe encode the character in *CHAR2B. */
+ if (charset != CHARSET_ASCII)
+ {
+ struct font_info *font_info
+ = FONT_INFO_FROM_ID (f, face->font_info_id);
+ if (font_info)
+ {
+ x_encode_char (c, char2b, font_info);
+ if (charset == charset_latin_iso8859_1)
+ {
+ xassert (((XFontStruct *) font_info->font)->max_char_or_byte2
+ >= 0x80);
+ char2b->byte2 |= 0x80;
+ }
+ }
+ }
+ }
+
+ /* Make sure X resources of the face are allocated. */
+ xassert (face != NULL);
+ PREPARE_FACE_FOR_DISPLAY (f, face);
+
+ return face;
+}
+
+
+/* Get face and two-byte form of character glyph GLYPH on frame F.
+ The encoding of GLYPH->u.ch.code is returned in *CHAR2B. Value is
+ a pointer to a realized face that is ready for display. */
+
+static INLINE struct face *
+x_get_glyph_face_and_encoding (f, glyph, char2b)
+ struct frame *f;
+ struct glyph *glyph;
+ XChar2b *char2b;
+{
+ struct face *face;
+
+ xassert (glyph->type == CHAR_GLYPH);
+ face = FACE_FROM_ID (f, glyph->u.ch.face_id);
+
+ if (!glyph->multibyte_p)
+ {
+ /* Unibyte case. We don't have to encode, but we have to make
+ sure to use a face suitable for unibyte. */
+ char2b->byte1 = 0;
+ char2b->byte2 = glyph->u.ch.code;
+ }
+ else if (glyph->u.ch.code < 128
+ && glyph->u.ch.face_id < BASIC_FACE_ID_SENTINEL)
+ {
+ /* Case of ASCII in a face known to fit ASCII. */
+ char2b->byte1 = 0;
+ char2b->byte2 = glyph->u.ch.code;
+ }
+ else
+ {
+ int c1, c2, charset;
+
+ /* Split characters into bytes. If c2 is -1 afterwards, C is
+ really a one-byte character so that byte1 is zero. */
+ SPLIT_CHAR (glyph->u.ch.code, charset, c1, c2);
+ if (c2 > 0)
+ char2b->byte1 = c1, char2b->byte2 = c2;
+ else
+ char2b->byte1 = 0, char2b->byte2 = c1;
+
+ /* Maybe encode the character in *CHAR2B. */
+ if (charset != CHARSET_ASCII)
+ {
+ struct font_info *font_info
+ = FONT_INFO_FROM_ID (f, face->font_info_id);
+ if (font_info)
+ {
+ x_encode_char (glyph->u.ch.code, char2b, font_info);
+ if (charset == charset_latin_iso8859_1)
+ char2b->byte2 |= 0x80;
+ }
+ }
+ }
+
+ /* Make sure X resources of the face are allocated. */
+ xassert (face != NULL);
+ PREPARE_FACE_FOR_DISPLAY (f, face);
+ return face;
+}
+
+
+/* Store one glyph for IT->char_to_display in IT->glyph_row.
+ Called from x_produce_glyphs when IT->glyph_row is non-null. */
+
+static INLINE void
+x_append_glyph (it)
+ struct it *it;
+{
+ struct glyph *glyph;
+ enum glyph_row_area area = it->area;
+
+ xassert (it->glyph_row);
+ xassert (it->char_to_display != '\n' && it->char_to_display != '\t');
+
+ glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
+ if (glyph < it->glyph_row->glyphs[area + 1])
+ {
+ /* Play it safe. If sub-structures of the glyph are not all the
+ same size, it otherwise be that some bits stay set. This
+ would prevent a comparison with GLYPH_EQUAL_P. */
+ glyph->u.val = 0;
+
+ glyph->type = CHAR_GLYPH;
+ glyph->pixel_width = it->pixel_width;
+ glyph->u.ch.code = it->char_to_display;
+ glyph->u.ch.face_id = it->face_id;
+ glyph->charpos = CHARPOS (it->position);
+ glyph->object = it->object;
+ glyph->left_box_line_p = it->start_of_box_run_p;
+ glyph->right_box_line_p = it->end_of_box_run_p;
+ glyph->voffset = it->voffset;
+ glyph->multibyte_p = it->multibyte_p;
+ glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent
+ || it->phys_descent > it->descent);
+ ++it->glyph_row->used[area];
+ }
+}
+
+
+/* Change IT->ascent and IT->height according to the setting of
+ IT->voffset. */
+
+static INLINE void
+take_vertical_position_into_account (it)
+ struct it *it;
+{
+ if (it->voffset)
+ {
+ if (it->voffset < 0)
+ /* Increase the ascent so that we can display the text higher
+ in the line. */
+ it->ascent += abs (it->voffset);
+ else
+ /* Increase the descent so that we can display the text lower
+ in the line. */
+ it->descent += it->voffset;
+ }
+}
+
+
+/* Produce glyphs/get display metrics for the image IT is loaded with.
+ See the description of struct display_iterator in dispextern.h for
+ an overview of struct display_iterator. */
+
+static void
+x_produce_image_glyph (it)
+ struct it *it;
+{
+ struct image *img;
+ struct face *face;
+
+ xassert (it->what == IT_IMAGE);
+
+ face = FACE_FROM_ID (it->f, it->face_id);
+ img = IMAGE_FROM_ID (it->f, it->image_id);
+ xassert (img);
+
+ /* Make sure X resources of the face and image are loaded. */
+ PREPARE_FACE_FOR_DISPLAY (it->f, face);
+ prepare_image_for_display (it->f, img);
+
+ it->ascent = it->phys_ascent = IMAGE_ASCENT (img);
+ it->descent = it->phys_descent = img->height + 2 * img->margin - it->ascent;
+ it->pixel_width = img->width + 2 * img->margin;
+
+ it->nglyphs = 1;
+
+ if (face->box != FACE_NO_BOX)
+ {
+ it->ascent += face->box_line_width;
+ it->descent += face->box_line_width;
+
+ if (it->start_of_box_run_p)
+ it->pixel_width += face->box_line_width;
+ if (it->end_of_box_run_p)
+ it->pixel_width += face->box_line_width;
+ }
+
+ take_vertical_position_into_account (it);
+
+ if (it->glyph_row)
+ {
+ struct glyph *glyph;
+ enum glyph_row_area area = it->area;
+
+ glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
+ if (glyph < it->glyph_row->glyphs[area + 1])
+ {
+ glyph->type = IMAGE_GLYPH;
+ glyph->u.img.id = img->id;
+ glyph->u.img.face_id = it->face_id;
+ glyph->pixel_width = it->pixel_width;
+ glyph->charpos = CHARPOS (it->position);
+ glyph->object = it->object;
+ glyph->left_box_line_p = it->start_of_box_run_p;
+ glyph->right_box_line_p = it->end_of_box_run_p;
+ glyph->voffset = it->voffset;
+ glyph->multibyte_p = it->multibyte_p;
+ ++it->glyph_row->used[area];
+ }
+ }
+}
+
+
+/* Append a stretch glyph to IT->glyph_row. OBJECT is the source
+ of the glyph, WIDTH and HEIGHT are the width and height of the
+ stretch. ASCENT is the percentage/100 of HEIGHT to use for the
+ ascent of the glyph (0 <= ASCENT <= 1). */
+
+static void
+x_append_stretch_glyph (it, object, width, height, ascent)
+ struct it *it;
+ Lisp_Object object;
+ int width, height;
+ double ascent;
+{
+ struct glyph *glyph;
+ enum glyph_row_area area = it->area;
+
+ xassert (ascent >= 0 && ascent <= 1);
+
+ glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
+ if (glyph < it->glyph_row->glyphs[area + 1])
+ {
+ glyph->type = STRETCH_GLYPH;
+ glyph->u.stretch.ascent = height * ascent;
+ glyph->u.stretch.height = height;
+ glyph->u.stretch.face_id = it->face_id;
+ glyph->pixel_width = width;
+ glyph->charpos = CHARPOS (it->position);
+ glyph->object = object;
+ glyph->left_box_line_p = it->start_of_box_run_p;
+ glyph->right_box_line_p = it->end_of_box_run_p;
+ glyph->voffset = it->voffset;
+ glyph->multibyte_p = it->multibyte_p;
+ ++it->glyph_row->used[area];
+ }
+}
+
+
+/* Produce a stretch glyph for iterator IT. IT->object is the value
+ of the glyph property displayed. The value must be a list
+ `(space KEYWORD VALUE ...)' with the following KEYWORD/VALUE pairs
+ being recognized:
+
+ 1. `:width WIDTH' specifies that the space should be WIDTH *
+ canonical char width wide. WIDTH may be an integer or floating
+ point number.
+
+ 2. `:relative-width FACTOR' specifies that the width of the stretch
+ should be computed from the width of the first character having the
+ `glyph' property, and should be FACTOR times that width.
+
+ 3. `:align-to HPOS' specifies that the space should be wide enough
+ to reach HPOS, a value in canonical character units.
+
+ Exactly one of the above pairs must be present.
+
+ 4. `:height HEIGHT' specifies that the height of the stretch produced
+ should be HEIGHT, measured in canonical character units.
+
+ 5. `:relative-height FACTOR' specifies that the height of the the
+ stretch should be FACTOR times the height of the characters having
+ the glyph property.
+
+ Either none or exactly one of 4 or 5 must be present.
+
+ 6. `:ascent ASCENT' specifies that ASCENT percent of the height
+ of the stretch should be used for the ascent of the stretch.
+ ASCENT must be in the range 0 <= ASCENT <= 100. */
+
+#define NUMVAL(X) \
+ ((INTEGERP (X) || FLOATP (X)) \
+ ? XFLOATINT (X) \
+ : - 1)
+
+
+static void
+x_produce_stretch_glyph (it)
+ struct it *it;
+{
+ /* (space :width WIDTH :height HEIGHT. */
+ extern Lisp_Object QCwidth, QCheight, QCascent, Qspace;
+ extern Lisp_Object QCrelative_width, QCrelative_height;
+ extern Lisp_Object QCalign_to;
+ Lisp_Object prop, plist;
+ double width = 0, height = 0, ascent = 0;
+ struct face *face = FACE_FROM_ID (it->f, it->face_id);
+ XFontStruct *font = face->font ? face->font : FRAME_FONT (it->f);
+
+ PREPARE_FACE_FOR_DISPLAY (it->f, face);
+
+ /* List should start with `space'. */
+ xassert (CONSP (it->object) && EQ (XCAR (it->object), Qspace));
+ plist = XCDR (it->object);
+
+ /* Compute the width of the stretch. */
+ if (prop = Fplist_get (plist, QCwidth),
+ NUMVAL (prop) > 0)
+ /* Absolute width `:width WIDTH' specified and valid. */
+ width = NUMVAL (prop) * CANON_X_UNIT (it->f);
+ else if (prop = Fplist_get (plist, QCrelative_width),
+ NUMVAL (prop) > 0)
+ {
+ /* Relative width `:relative-width FACTOR' specified and valid.
+ Compute the width of the characters having the `glyph'
+ property. */
+ struct it it2;
+ unsigned char *p = BYTE_POS_ADDR (IT_BYTEPOS (*it));
+
+ it2 = *it;
+ if (it->multibyte_p)
+ {
+ int maxlen = ((IT_BYTEPOS (*it) >= GPT ? ZV : GPT)
+ - IT_BYTEPOS (*it));
+ it2.c = STRING_CHAR_AND_LENGTH (p, maxlen, it2.len);
+ }
+ else
+ it2.c = *p, it2.len = 1;
+
+ it2.glyph_row = NULL;
+ it2.what = IT_CHARACTER;
+ x_produce_glyphs (&it2);
+ width = NUMVAL (prop) * it2.pixel_width;
+ }
+ else if (prop = Fplist_get (plist, QCalign_to),
+ NUMVAL (prop) > 0)
+ width = NUMVAL (prop) * CANON_X_UNIT (it->f) - it->current_x;
+ else
+ /* Nothing specified -> width defaults to canonical char width. */
+ width = CANON_X_UNIT (it->f);
+
+ /* Compute height. */
+ if (prop = Fplist_get (plist, QCheight),
+ NUMVAL (prop) > 0)
+ height = NUMVAL (prop) * CANON_Y_UNIT (it->f);
+ else if (prop = Fplist_get (plist, QCrelative_height),
+ NUMVAL (prop) > 0)
+ height = FONT_HEIGHT (font) * NUMVAL (prop);
+ else
+ height = FONT_HEIGHT (font);
+
+ /* Compute percentage of height used for ascent. If
+ `:ascent ASCENT' is present and valid, use that. Otherwise,
+ derive the ascent from the font in use. */
+ if (prop = Fplist_get (plist, QCascent),
+ NUMVAL (prop) > 0 && NUMVAL (prop) <= 100)
+ ascent = NUMVAL (prop) / 100.0;
+ else
+ ascent = (double) font->ascent / FONT_HEIGHT (font);
+
+ if (width <= 0)
+ width = 1;
+ if (height <= 0)
+ height = 1;
+
+ if (it->glyph_row)
+ {
+ Lisp_Object object = it->stack[it->sp - 1].string;
+ if (!STRINGP (object))
+ object = it->w->buffer;
+ x_append_stretch_glyph (it, object, width, height, ascent);
+ }
+
+ it->pixel_width = width;
+ it->ascent = it->phys_ascent = height * ascent;
+ it->descent = it->phys_descent = height - it->ascent;
+ it->nglyphs = 1;
+
+ if (face->box != FACE_NO_BOX)
+ {
+ it->ascent += face->box_line_width;
+ it->descent += face->box_line_width;
+
+ if (it->start_of_box_run_p)
+ it->pixel_width += face->box_line_width;
+ if (it->end_of_box_run_p)
+ it->pixel_width += face->box_line_width;
+ }
+
+ take_vertical_position_into_account (it);
+}
+
+
+/* Produce glyphs/get display metrics for the display element IT is
+ loaded with. See the description of struct display_iterator in
+ dispextern.h for an overview of struct display_iterator. */
+
+static void
+x_produce_glyphs (it)
+ struct it *it;
+{
+ if (it->what == IT_CHARACTER)
+ {
+ XChar2b char2b;
+ XFontStruct *font;
+ struct face *face;
+ XCharStruct *pcm;
+ int font_not_found_p;
+
+ /* Maybe translate single-byte characters to multibyte. */
+ it->char_to_display = it->c;
+ if (unibyte_display_via_language_environment
+ && SINGLE_BYTE_CHAR_P (it->c)
+ && (it->c >= 0240
+ || (it->c >= 0200
+ && !NILP (Vnonascii_translation_table))))
+ {
+ it->char_to_display = unibyte_char_to_multibyte (it->c);
+ it->charset = CHAR_CHARSET (it->char_to_display);
+ }
+
+ /* Get face and font to use. Encode IT->char_to_display. */
+ face = x_get_char_face_and_encoding (it->f, it->char_to_display,
+ it->face_id, &char2b,
+ it->multibyte_p);
+ font = face->font;
+
+ /* When no suitable font found, use the default font. */
+ font_not_found_p = font == NULL;
+ if (font_not_found_p)
+ font = FRAME_FONT (it->f);
+
+ if (it->char_to_display >= ' '
+ && (!it->multibyte_p || it->char_to_display < 128))
+ {
+ /* Either unibyte or ASCII. */
+ int stretched_p;
+
+ it->nglyphs = 1;
+
+ pcm = x_per_char_metric (font, &char2b);
+ it->ascent = font->ascent;
+ it->descent = font->descent;
+ it->phys_ascent = pcm->ascent;
+ it->phys_descent = pcm->descent;
+ it->pixel_width = pcm->width;
+
+ /* If this is a space inside a region of text with
+ `space-width' property, change its width. */
+ stretched_p = it->char_to_display == ' ' && !NILP (it->space_width);
+ if (stretched_p)
+ it->pixel_width *= XFLOATINT (it->space_width);
+
+ /* If face has a box, add the box thickness to the character
+ height. If character has a box line to the left and/or
+ right, add the box line width to the character's width. */
+ if (face->box != FACE_NO_BOX)
+ {
+ int thick = face->box_line_width;
+
+ it->ascent += thick;
+ it->descent += thick;
+
+ if (it->start_of_box_run_p)
+ it->pixel_width += thick;
+ if (it->end_of_box_run_p)
+ it->pixel_width += thick;
+ }
+
+ /* If face has an overline, add the height of the overline
+ (1 pixel) and a 1 pixel margin to the character height. */
+ if (face->overline_p)
+ it->ascent += 2;
+
+ take_vertical_position_into_account (it);
+
+ /* If we have to actually produce glyphs, do it. */
+ if (it->glyph_row)
+ {
+ if (stretched_p)
+ {
+ /* Translate a space with a `space-width' property
+ into a stretch glyph. */
+ double ascent = (double) font->ascent / FONT_HEIGHT (font);
+ x_append_stretch_glyph (it, it->object, it->pixel_width,
+ it->ascent + it->descent, ascent);
+ }
+ else
+ x_append_glyph (it);
+
+ /* If characters with lbearing or rbearing are displayed
+ in this line, record that fact in a flag of the
+ glyph row. This is used to optimize X output code. */
+ if (pcm->lbearing < 0
+ || pcm->rbearing > pcm->width)
+ it->glyph_row->contains_overlapping_glyphs_p = 1;
+ }
+ }
+ else if (it->char_to_display == '\n')
+ {
+ /* A newline has no width but we need the height of the line. */
+ it->pixel_width = 0;
+ it->nglyphs = 0;
+ it->ascent = it->phys_ascent = font->ascent;
+ it->descent = it->phys_descent = font->descent;
+
+ if (face->box != FACE_NO_BOX)
+ {
+ int thick = face->box_line_width;
+ it->ascent += thick;
+ it->descent += thick;
+ }
+ }
+ else if (it->char_to_display == '\t')
+ {
+ int tab_width = it->tab_width * CANON_X_UNIT (it->f);
+ int x = (it->current_x
+ - it->prompt_width
+ + it->continuation_lines_width);
+ int next_tab_x = ((1 + x + tab_width - 1) / tab_width) * tab_width;
+
+ it->pixel_width = next_tab_x - x;
+ it->nglyphs = 1;
+ it->ascent = it->phys_ascent = font->ascent;
+ it->descent = it->phys_descent = font->descent;
+
+ if (it->glyph_row)
+ {
+ double ascent = (double) it->ascent / (it->ascent + it->descent);
+ x_append_stretch_glyph (it, it->object, it->pixel_width,
+ it->ascent + it->descent, ascent);
+ }
+ }
+ else
+ {
+ /* A multi-byte character. Assume that the display width of the
+ character is the width of the character multiplied by the
+ width of the font. There has to be better support for
+ variable sizes in cmpchar_info to do anything better than
+ that.
+
+ Note: composite characters are represented as one glyph in
+ the glyph matrix. There are no padding glyphs. */
+ if (it->charset == CHARSET_COMPOSITION)
+ {
+ struct cmpchar_info *cmpcharp;
+ int idx;
+
+ idx = COMPOSITE_CHAR_ID (it->char_to_display);
+ cmpcharp = cmpchar_table[idx];
+ it->pixel_width = font->max_bounds.width * cmpcharp->width;
+
+ /* There are no padding glyphs, so there is only one glyph
+ to produce for the composite char. Important is that
+ pixel_width, ascent and descent are the values of what is
+ drawn by draw_glyphs. */
+ it->nglyphs = 1;
+
+ /* These settings may not be correct. We must have more
+ information in cmpcharp to do the correct setting. */
+ it->ascent = font->ascent;
+ it->descent = font->descent;
+ it->phys_ascent = font->max_bounds.ascent;
+ it->phys_descent = font->max_bounds.descent;
+ }
+ else
+ {
+ /* If we found a font, this font should give us the right
+ metrics. If we didn't find a font, use the frame's
+ default font and calculate the width of the character
+ from the charset width; this is what old redisplay code
+ did. */
+ pcm = x_per_char_metric (font, &char2b);
+ it->pixel_width = pcm->width;
+ if (font_not_found_p)
+ it->pixel_width *= CHARSET_WIDTH (it->charset);
+ it->nglyphs = 1;
+ it->ascent = font->ascent;
+ it->descent = font->descent;
+ it->phys_ascent = pcm->ascent;
+ it->phys_descent = pcm->descent;
+ if (it->glyph_row
+ && (pcm->lbearing < 0
+ || pcm->rbearing > pcm->width))
+ it->glyph_row->contains_overlapping_glyphs_p = 1;
+ }
+
+ if (face->box != FACE_NO_BOX)
+ {
+ int thick = face->box_line_width;
+ it->ascent += thick;
+ it->descent += thick;
+
+ if (it->start_of_box_run_p)
+ it->pixel_width += thick;
+ if (it->end_of_box_run_p)
+ it->pixel_width += thick;
+ }
+
+ /* If face has an overline, add the height of the overline
+ (1 pixel) and a 1 pixel margin to the character height. */
+ if (face->overline_p)
+ it->ascent += 2;
+
+ take_vertical_position_into_account (it);
+
+ if (it->glyph_row)
+ x_append_glyph (it);
+ }
+ }
+ else if (it->what == IT_IMAGE)
+ x_produce_image_glyph (it);
+ else if (it->what == IT_STRETCH)
+ x_produce_stretch_glyph (it);
+
+ /* Accumulate dimensions. */
+ xassert (it->ascent >= 0 && it->descent > 0);
+ if (it->area == TEXT_AREA)
+ it->current_x += it->pixel_width;
+
+ it->max_ascent = max (it->max_ascent, it->ascent);
+ it->max_descent = max (it->max_descent, it->descent);
+ it->max_phys_ascent = max (it->max_phys_ascent, it->phys_ascent);
+ it->max_phys_descent = max (it->max_phys_descent, it->phys_descent);
+}
+
+
+/* Estimate the pixel height of the mode or top line on frame F.
+ FACE_ID specifies what line's height to estimate. */
+
+int
+x_estimate_mode_line_height (f, face_id)
+ struct frame *f;
+ enum face_id face_id;
+{
+ int height = 1;
+
+ /* This function is called so early when Emacs starts that the face
+ cache and mode line face are not yet initialized. */
+ if (FRAME_FACE_CACHE (f))
+ {
+ struct face *face = FACE_FROM_ID (f, face_id);
+ if (face)
+ height = FONT_HEIGHT (face->font) + 2 * face->box_line_width;
+ }
+
+ return height;
+}
+
+\f
+/***********************************************************************
+ Glyph display
+ ***********************************************************************/
+
+/* A sequence of glyphs to be drawn in the same face.
+
+ This data structure is not really completely X specific, so it
+ could possibly, at least partially, be useful for other systems. It
+ is currently not part of the external redisplay interface because
+ it's not clear what other systems will need. */
+
+struct glyph_string
+{
+ /* X-origin of the string. */
+ int x;
+
+ /* Y-origin and y-position of the base line of this string. */
+ int y, ybase;
+
+ /* The width of the string, not including a face extension. */
+ int width;
+
+ /* The width of the string, including a face extension. */
+ int background_width;
+
+ /* The height of this string. This is the height of the line this
+ string is drawn in, and can be different from the height of the
+ font the string is drawn in. */
+ int height;
+
+ /* Number of pixels this string overwrites in front of its x-origin.
+ This number is zero if the string has an lbearing >= 0; it is
+ -lbearing, if the string has an lbearing < 0. */
+ int left_overhang;
+
+ /* Number of pixels this string overwrites past its right-most
+ nominal x-position, i.e. x + width. Zero if the string's
+ rbearing is <= its nominal width, rbearing - width otherwise. */
+ int right_overhang;
+
+ /* The frame on which the glyph string is drawn. */
+ struct frame *f;
+
+ /* The window on which the glyph string is drawn. */
+ struct window *w;
+
+ /* X display and window for convenience. */
+ Display *display;
+ Window window;
+
+ /* The glyph row for which this string was built. It determines the
+ y-origin and height of the string. */
+ struct glyph_row *row;
+
+ /* The area within row. */
+ enum glyph_row_area area;
+
+ /* Characters to be drawn, and number of characters. */
+ XChar2b *char2b;
+ int nchars;
+
+ /* Character set of this glyph string. */
+ int charset;
+
+ /* A face-override for drawing cursors, mouse face and similar. */
+ enum draw_glyphs_face hl;
+
+ /* Face in which this string is to be drawn. */
+ struct face *face;
+
+ /* Font in which this string is to be drawn. */
+ XFontStruct *font;
+
+ /* Font info for this string. */
+ struct font_info *font_info;
+
+ /* Non-null means this string describes (part of) a composite
+ character. All characters from char2b are drawn at the same
+ x-origin in that case. */
+ struct cmpchar_info *cmpcharp;
+
+ /* Index of this glyph string's first character in the glyph
+ definition of cmpcharp. If this is zero, this glyph string
+ describes the first character of a composite character. */
+ int gidx;
+
+ /* 1 means this glyph strings face has to be drawn to the right end
+ of the window's drawing area. */
+ unsigned extends_to_end_of_line_p : 1;
+
+ /* 1 means the background of this string has been drawn. */
+ unsigned background_filled_p : 1;
+
+ /* 1 means glyph string must be drawn with 16-bit functions. */
+ unsigned two_byte_p : 1;
+
+ /* 1 means that the original font determined for drawing this glyph
+ string could not be loaded. The member `font' has been set to
+ the frame's default font in this case. */
+ unsigned font_not_found_p : 1;
+
+ /* 1 means that the face in which this glyph string is drawn has a
+ stipple pattern. */
+ unsigned stippled_p : 1;
+
+ /* 1 means only the foreground of this glyph string must be drawn,
+ and we should use the physical height of the line this glyph
+ string appears in as clip rect. */
+ unsigned for_overlaps_p : 1;
+
+ /* The GC to use for drawing this glyph string. */
+ GC gc;
+
+ /* A pointer to the first glyph in the string. This glyph
+ corresponds to char2b[0]. Needed to draw rectangles if
+ font_not_found_p is 1. */
+ struct glyph *first_glyph;
+
+ /* Image, if any. */
+ struct image *img;
+
+ struct glyph_string *next, *prev;
+};
+
+
+#if 0
+
+static void
+x_dump_glyph_string (s)
+ struct glyph_string *s;
+{
+ fprintf (stderr, "glyph string\n");
+ fprintf (stderr, " x, y, w, h = %d, %d, %d, %d\n",
+ s->x, s->y, s->width, s->height);
+ fprintf (stderr, " ybase = %d\n", s->ybase);
+ fprintf (stderr, " hl = %d\n", s->hl);
+ fprintf (stderr, " left overhang = %d, right = %d\n",
+ s->left_overhang, s->right_overhang);
+ fprintf (stderr, " nchars = %d\n", s->nchars);
+ fprintf (stderr, " extends to end of line = %d\n",
+ s->extends_to_end_of_line_p);
+ fprintf (stderr, " font height = %d\n", FONT_HEIGHT (s->font));
+ fprintf (stderr, " bg width = %d\n", s->background_width);
+}
+
+#endif /* GLYPH_DEBUG */
+
+
+
+static void x_append_glyph_string_lists P_ ((struct glyph_string **,
+ struct glyph_string **,
+ struct glyph_string *,
+ struct glyph_string *));
+static void x_prepend_glyph_string_lists P_ ((struct glyph_string **,
+ struct glyph_string **,
+ struct glyph_string *,
+ struct glyph_string *));
+static void x_append_glyph_string P_ ((struct glyph_string **,
+ struct glyph_string **,
+ struct glyph_string *));
+static int x_left_overwritten P_ ((struct glyph_string *));
+static int x_left_overwriting P_ ((struct glyph_string *));
+static int x_right_overwritten P_ ((struct glyph_string *));
+static int x_right_overwriting P_ ((struct glyph_string *));
+static int x_fill_glyph_string P_ ((struct glyph_string *, int, int, int,
+ int));
+static void x_init_glyph_string P_ ((struct glyph_string *,
+ XChar2b *, struct window *,
+ struct glyph_row *,
+ enum glyph_row_area, int,
+ enum draw_glyphs_face));
+static int x_draw_glyphs P_ ((struct window *, int , struct glyph_row *,
+ enum glyph_row_area, int, int,
+ enum draw_glyphs_face, int *, int *, int));
+static void x_set_glyph_string_clipping P_ ((struct glyph_string *));
+static void x_set_glyph_string_gc P_ ((struct glyph_string *));
+static void x_draw_glyph_string_background P_ ((struct glyph_string *,
+ int));
+static void x_draw_glyph_string_foreground P_ ((struct glyph_string *));
+static void x_draw_glyph_string_box P_ ((struct glyph_string *));
+static void x_draw_glyph_string P_ ((struct glyph_string *));
+static void x_compute_glyph_string_overhangs P_ ((struct glyph_string *));
+static void x_set_cursor_gc P_ ((struct glyph_string *));
+static void x_set_mode_line_face_gc P_ ((struct glyph_string *));
+static void x_set_mouse_face_gc P_ ((struct glyph_string *));
+static void x_get_glyph_overhangs P_ ((struct glyph *, struct frame *,
+ int *, int *));
+static void x_compute_overhangs_and_x P_ ((struct glyph_string *, int, int));
+static int x_alloc_lighter_color P_ ((struct frame *, Display *, Colormap,
+ unsigned long *, double, int));
+static void x_setup_relief_color P_ ((struct frame *, struct relief *,
+ double, int, unsigned long));
+static void x_setup_relief_colors P_ ((struct glyph_string *));
+static void x_draw_image_glyph_string P_ ((struct glyph_string *));
+static void x_draw_image_relief P_ ((struct glyph_string *));
+static void x_draw_image_foreground P_ ((struct glyph_string *));
+static void x_draw_image_foreground_1 P_ ((struct glyph_string *, Pixmap));
+static void x_fill_image_glyph_string P_ ((struct glyph_string *));
+static void x_clear_glyph_string_rect P_ ((struct glyph_string *, int,
+ int, int, int));
+static void x_draw_relief_rect P_ ((struct frame *, int, int, int, int,
+ int, int, int, int, XRectangle *));
+static void x_draw_box_rect P_ ((struct glyph_string *, int, int, int, int,
+ int, int, int, XRectangle *));
+static void x_fix_overlapping_area P_ ((struct window *, struct glyph_row *,
+ enum glyph_row_area));
+
+
+/* Append the list of glyph strings with head H and tail T to the list
+ with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the result. */
+
+static INLINE void
+x_append_glyph_string_lists (head, tail, h, t)
+ struct glyph_string **head, **tail;
+ struct glyph_string *h, *t;
+{
+ if (h)
+ {
+ if (*head)
+ (*tail)->next = h;
+ else
+ *head = h;
+ h->prev = *tail;
+ *tail = t;
+ }
+}
+
+
+/* Prepend the list of glyph strings with head H and tail T to the
+ list with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the
+ result. */
+
+static INLINE void
+x_prepend_glyph_string_lists (head, tail, h, t)
+ struct glyph_string **head, **tail;
+ struct glyph_string *h, *t;
+{
+ if (h)
+ {
+ if (*head)
+ (*head)->prev = t;
+ else
+ *tail = t;
+ t->next = *head;
+ *head = h;
+ }
+}
+
+
+/* Append glyph string S to the list with head *HEAD and tail *TAIL.
+ Set *HEAD and *TAIL to the resulting list. */
+
+static INLINE void
+x_append_glyph_string (head, tail, s)
+ struct glyph_string **head, **tail;
+ struct glyph_string *s;
+{
+ s->next = s->prev = NULL;
+ x_append_glyph_string_lists (head, tail, s, s);
+}
+
+
+/* Set S->gc to a suitable GC for drawing glyph string S in cursor
+ face. */
+
+static void
+x_set_cursor_gc (s)
+ struct glyph_string *s;
+{
+ if (s->font == FRAME_FONT (s->f)
+ && s->face->background == FRAME_BACKGROUND_PIXEL (s->f)
+ && s->face->foreground == FRAME_FOREGROUND_PIXEL (s->f)
+ && !s->cmpcharp)
+ s->gc = s->f->output_data.x->cursor_gc;
+ else
+ {
+ /* Cursor on non-default face: must merge. */
+ XGCValues xgcv;
+ unsigned long mask;
+
+ xgcv.background = s->f->output_data.x->cursor_pixel;
+ xgcv.foreground = s->face->background;
+
+ /* If the glyph would be invisible, try a different foreground. */
+ if (xgcv.foreground == xgcv.background)
+ xgcv.foreground = s->face->foreground;
+ if (xgcv.foreground == xgcv.background)
+ xgcv.foreground = s->f->output_data.x->cursor_foreground_pixel;
+ if (xgcv.foreground == xgcv.background)
+ xgcv.foreground = s->face->foreground;
+
+ /* Make sure the cursor is distinct from text in this face. */
+ if (xgcv.background == s->face->background
+ && xgcv.foreground == s->face->foreground)
+ {
+ xgcv.background = s->face->foreground;
+ xgcv.foreground = s->face->background;
+ }
+
+ IF_DEBUG (x_check_font (s->f, s->font));
+ xgcv.font = s->font->fid;
+ xgcv.graphics_exposures = False;
+ mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
+
+ if (FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc)
+ XChangeGC (s->display, FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc,
+ mask, &xgcv);
+ else
+ FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc
+ = XCreateGC (s->display, s->window, mask, &xgcv);
+
+ s->gc = FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc;
+ }
+}
+
+
+/* Set up S->gc of glyph string S for drawing text in mouse face. */
+
+static void
+x_set_mouse_face_gc (s)
+ struct glyph_string *s;
+{
+ int face_id;
+
+ /* What face has to be used for the mouse face? */
+ face_id = FRAME_X_DISPLAY_INFO (s->f)->mouse_face_face_id;
+ face_id = FACE_FOR_CHARSET (s->f, face_id, s->charset);
+ s->face = FACE_FROM_ID (s->f, face_id);
+ PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
+
+ /* If font in this face is same as S->font, use it. */
+ if (s->font == s->face->font)
+ s->gc = s->face->gc;
+ else
+ {
+ /* Otherwise construct scratch_cursor_gc with values from FACE
+ but font FONT. */
+ XGCValues xgcv;
+ unsigned long mask;
+
+ xgcv.background = s->face->background;
+ xgcv.foreground = s->face->foreground;
+ IF_DEBUG (x_check_font (s->f, s->font));
+ xgcv.font = s->font->fid;
+ xgcv.graphics_exposures = False;
+ mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
+
+ if (FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc)
+ XChangeGC (s->display, FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc,
+ mask, &xgcv);
+ else
+ FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc
+ = XCreateGC (s->display, s->window, mask, &xgcv);
+
+ s->gc = FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc;
+ }
+
+ xassert (s->gc != 0);
+}
+
+
+/* Set S->gc of glyph string S to a GC suitable for drawing a mode line.
+ Faces to use in the mode line have already been computed when the
+ matrix was built, so there isn't much to do, here. */
+
+static INLINE void
+x_set_mode_line_face_gc (s)
+ struct glyph_string *s;
+{
+ s->gc = s->face->gc;
+ xassert (s->gc != 0);
+}
+
+
+/* Set S->gc of glyph string S for drawing that glyph string. Set
+ S->stippled_p to a non-zero value if the face of S has a stipple
+ pattern. */
+
+static INLINE void
+x_set_glyph_string_gc (s)
+ struct glyph_string *s;
+{
+ if (s->hl == DRAW_NORMAL_TEXT)
+ {
+ s->gc = s->face->gc;
+ s->stippled_p = s->face->stipple != 0;
+ }
+ else if (s->hl == DRAW_INVERSE_VIDEO)
+ {
+ x_set_mode_line_face_gc (s);
+ s->stippled_p = s->face->stipple != 0;
+ }
+ else if (s->hl == DRAW_CURSOR)
+ {
+ x_set_cursor_gc (s);
+ s->stippled_p = 0;
+ }
+ else if (s->hl == DRAW_MOUSE_FACE)
+ {
+ x_set_mouse_face_gc (s);
+ s->stippled_p = s->face->stipple != 0;
+ }
+ else if (s->hl == DRAW_IMAGE_RAISED
+ || s->hl == DRAW_IMAGE_SUNKEN)
+ {
+ s->gc = s->face->gc;
+ s->stippled_p = s->face->stipple != 0;
+ }
+ else
+ {
+ s->gc = s->face->gc;
+ s->stippled_p = s->face->stipple != 0;
+ }
+
+ /* GC must have been set. */
+ xassert (s->gc != 0);
+}
+
+
+/* Return in *R the clipping rectangle for glyph string S. */
+
+static void
+x_get_glyph_string_clip_rect (s, r)
+ struct glyph_string *s;
+ XRectangle *r;
+{
+ if (s->row->full_width_p)
+ {
+ /* Draw full-width. X coordinates are relative to S->w->left. */
+ int canon_x = CANON_X_UNIT (s->f);
+
+ r->x = WINDOW_LEFT_MARGIN (s->w) * canon_x;
+ r->width = XFASTINT (s->w->width) * canon_x;
+
+ if (FRAME_HAS_VERTICAL_SCROLL_BARS (s->f))
+ {
+ int width = FRAME_SCROLL_BAR_WIDTH (s->f) * canon_x;
+ if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (s->f))
+ r->x -= width;
+ }
+
+ r->x += FRAME_INTERNAL_BORDER_WIDTH (s->f);
+
+ /* Unless displaying a mode or menu bar line, which are always
+ fully visible, clip to the visible part of the row. */
+ if (s->w->pseudo_window_p)
+ r->height = s->row->visible_height;
+ else
+ r->height = s->height;
+ }
+ else
+ {
+ /* This is a text line that may be partially visible. */
+ r->x = WINDOW_AREA_TO_FRAME_PIXEL_X (s->w, s->area, 0);
+ r->width = window_box_width (s->w, s->area);
+ r->height = s->row->visible_height;
+ }
+
+ /* Don't use S->y for clipping because it doesn't take partially
+ visible lines into account. For example, it can be negative for
+ partially visible lines at the top of a window. */
+ if (!s->row->full_width_p
+ && MATRIX_ROW_PARTIALLY_VISIBLE_AT_TOP_P (s->w, s->row))
+ r->y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (s->w);
+ else
+ r->y = max (0, s->row->y);
+
+ /* If drawing a tool-bar window, draw it over the internal border
+ at the top of the window. */
+ if (s->w == XWINDOW (s->f->tool_bar_window))
+ r->y -= s->f->output_data.x->internal_border_width;
+
+ /* If S draws overlapping rows, it's sufficient to use the top and
+ bottom of the window for clipping because this glyph string
+ intentionally draws over other lines. */
+ if (s->for_overlaps_p)
+ {
+ r->y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (s->w);
+ r->height = window_text_bottom_y (s->w) - r->y;
+ }
+
+ r->y = WINDOW_TO_FRAME_PIXEL_Y (s->w, r->y);
+}
+
+
+/* Set clipping for output of glyph string S. S may be part of a mode
+ line or menu if we don't have X toolkit support. */
+
+static INLINE void
+x_set_glyph_string_clipping (s)
+ struct glyph_string *s;
+{
+ XRectangle r;
+ x_get_glyph_string_clip_rect (s, &r);
+ XSetClipRectangles (s->display, s->gc, 0, 0, &r, 1, Unsorted);
+}
+
+
+/* Compute left and right overhang of glyph string S. If S is a glyph
+ string for a composite character, assume overhangs don't exist. */
+
+static INLINE void
+x_compute_glyph_string_overhangs (s)
+ struct glyph_string *s;
+{
+ if (s->cmpcharp == NULL
+ && s->first_glyph->type == CHAR_GLYPH)
+ {
+ XCharStruct cs;
+ int direction, font_ascent, font_descent;
+ XTextExtents16 (s->font, s->char2b, s->nchars, &direction,
+ &font_ascent, &font_descent, &cs);
+ s->right_overhang = cs.rbearing > cs.width ? cs.rbearing - cs.width : 0;
+ s->left_overhang = cs.lbearing < 0 ? -cs.lbearing : 0;
+ }
+}
+
+
+/* Compute overhangs and x-positions for glyph string S and its
+ predecessors, or successors. X is the starting x-position for S.
+ BACKWARD_P non-zero means process predecessors. */
+
+static void
+x_compute_overhangs_and_x (s, x, backward_p)
+ struct glyph_string *s;
+ int x;
+ int backward_p;
+{
+ if (backward_p)
+ {
+ while (s)
+ {
+ x_compute_glyph_string_overhangs (s);
+ x -= s->width;
+ s->x = x;
+ s = s->prev;
+ }
+ }
+ else
+ {
+ while (s)
+ {
+ x_compute_glyph_string_overhangs (s);
+ s->x = x;
+ x += s->width;
+ s = s->next;
+ }
+ }
+}
+
+
+/* Set *LEFT and *RIGHT to the left and right overhang of GLYPH on
+ frame F. Overhangs of glyphs other than type CHAR_GLYPH or of
+ character glyphs for composite characters are assumed to be zero. */
+
+static void
+x_get_glyph_overhangs (glyph, f, left, right)
+ struct glyph *glyph;
+ struct frame *f;
+ int *left, *right;
+{
+ int c;
+
+ *left = *right = 0;
+
+ if (glyph->type == CHAR_GLYPH
+ && (c = glyph->u.ch.code,
+ CHAR_CHARSET (c) != CHARSET_COMPOSITION))
+ {
+ XFontStruct *font;
+ struct face *face;
+ struct font_info *font_info;
+ XChar2b char2b;
+
+ face = x_get_glyph_face_and_encoding (f, glyph, &char2b);
+ font = face->font;
+ font_info = FONT_INFO_FROM_ID (f, face->font_info_id);
+ if (font)
+ {
+ XCharStruct *pcm = x_per_char_metric (font, &char2b);
+
+ if (pcm->rbearing > pcm->width)
+ *right = pcm->rbearing - pcm->width;
+ if (pcm->lbearing < 0)
+ *left = -pcm->lbearing;
+ }
+ }
+}
+
+
+/* Return the index of the first glyph preceding glyph string S that
+ is overwritten by S because of S's left overhang. Value is -1
+ if no glyphs are overwritten. */
+
+static int
+x_left_overwritten (s)
+ struct glyph_string *s;
+{
+ int k;
+
+ if (s->left_overhang)
+ {
+ int x = 0, i;
+ struct glyph *glyphs = s->row->glyphs[s->area];
+ int first = s->first_glyph - glyphs;
+
+ for (i = first - 1; i >= 0 && x > -s->left_overhang; --i)
+ x -= glyphs[i].pixel_width;
+
+ k = i + 1;
+ }
+ else
+ k = -1;
+
+ return k;
+}
+
+
+/* Return the index of the first glyph preceding glyph string S that
+ is overwriting S because of its right overhang. Value is -1 if no
+ glyph in front of S overwrites S. */
+
+static int
+x_left_overwriting (s)
+ struct glyph_string *s;
+{
+ int i, k, x;
+ struct glyph *glyphs = s->row->glyphs[s->area];
+ int first = s->first_glyph - glyphs;
+
+ k = -1;
+ x = 0;
+ for (i = first - 1; i >= 0; --i)
+ {
+ int left, right;
+ x_get_glyph_overhangs (glyphs + i, s->f, &left, &right);
+ if (x + right > 0)
+ k = i;
+ x -= glyphs[i].pixel_width;
+ }
+
+ return k;
+}
+
+
+/* Return the index of the last glyph following glyph string S that is
+ not overwritten by S because of S's right overhang. Value is -1 if
+ no such glyph is found. */
+
+static int
+x_right_overwritten (s)
+ struct glyph_string *s;
+{
+ int k = -1;
+
+ if (s->right_overhang)
+ {
+ int x = 0, i;
+ struct glyph *glyphs = s->row->glyphs[s->area];
+ int first = (s->first_glyph - glyphs) + (s->cmpcharp ? 1 : s->nchars);
+ int end = s->row->used[s->area];
+
+ for (i = first; i < end && s->right_overhang > x; ++i)
+ x += glyphs[i].pixel_width;
+
+ k = i;
+ }
+
+ return k;
+}
+
+
+/* Return the index of the last glyph following glyph string S that
+ overwrites S because of its left overhang. Value is negative
+ if no such glyph is found. */
+
+static int
+x_right_overwriting (s)
+ struct glyph_string *s;
+{
+ int i, k, x;
+ int end = s->row->used[s->area];
+ struct glyph *glyphs = s->row->glyphs[s->area];
+ int first = (s->first_glyph - glyphs) + (s->cmpcharp ? 1 : s->nchars);
+
+ k = -1;
+ x = 0;
+ for (i = first; i < end; ++i)
+ {
+ int left, right;
+ x_get_glyph_overhangs (glyphs + i, s->f, &left, &right);
+ if (x - left < 0)
+ k = i;
+ x += glyphs[i].pixel_width;
+ }
+
+ return k;
+}
+
+
+/* Fill rectangle X, Y, W, H with background color of glyph string S. */
+
+static INLINE void
+x_clear_glyph_string_rect (s, x, y, w, h)
+ struct glyph_string *s;
+ int x, y, w, h;
+{
+ XGCValues xgcv;
+ XGetGCValues (s->display, s->gc, GCForeground | GCBackground, &xgcv);
+ XSetForeground (s->display, s->gc, xgcv.background);
+ XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
+ XSetForeground (s->display, s->gc, xgcv.foreground);
+}
+
+
+/* Draw the background of glyph_string S. If S->background_filled_p
+ is non-zero don't draw it. FORCE_P non-zero means draw the
+ background even if it wouldn't be drawn normally. This is used
+ when a string preceding S draws into the background of S. */
+
+static void
+x_draw_glyph_string_background (s, force_p)
+ struct glyph_string *s;
+ int force_p;
+{
+ /* Nothing to do if background has already been drawn or if it
+ shouldn't be drawn in the first place. */
+ if (!s->background_filled_p)
+ {
+ if (s->cmpcharp
+ && s->gidx > 0
+ && !s->font_not_found_p
+ && !s->extends_to_end_of_line_p)
+ {
+ /* Don't draw background for glyphs of a composite
+ characters, except for the first one. */
+ s->background_filled_p = 1;
+ }
+ else if (s->stippled_p)
+ {
+ /* Fill background with a stipple pattern. */
+ XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
+ XFillRectangle (s->display, s->window, s->gc, s->x,
+ s->y + s->face->box_line_width,
+ s->background_width,
+ s->height - 2 * s->face->box_line_width);
+ XSetFillStyle (s->display, s->gc, FillSolid);
+ s->background_filled_p = 1;
+ }
+ else if (FONT_HEIGHT (s->font) < s->height - 2 * s->face->box_line_width
+ || s->font_not_found_p
+ || s->extends_to_end_of_line_p
+ || s->cmpcharp
+ || force_p)
+ {
+ x_clear_glyph_string_rect (s, s->x, s->y + s->face->box_line_width,
+ s->background_width,
+ s->height - 2 * s->face->box_line_width);
+ s->background_filled_p = 1;
+ }
+ }
+}
+
+
+/* Draw the foreground of glyph string S. */
+
+static void
+x_draw_glyph_string_foreground (s)
+ struct glyph_string *s;
+{
+ int i, x;
+
+ /* 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 + s->face->box_line_width;
+ else
+ x = s->x;
+
+ if (s->cmpcharp == NULL)
+ {
+ /* Not a composite character. Draw characters of S as
+ rectangles if S's font could not be loaded. */
+ if (s->font_not_found_p)
+ {
+ for (i = 0; i < s->nchars; ++i)
+ {
+ struct glyph *g = s->first_glyph + i;
+ XDrawRectangle (s->display, s->window,
+ s->gc, x, s->y, g->pixel_width - 1,
+ s->height - 1);
+ x += g->pixel_width;
+ }
+ }
+ else
+ {
+ char *char1b = (char *) s->char2b;
+
+ /* If we can use 8-bit functions, condense S->char2b. */
+ if (!s->two_byte_p)
+ for (i = 0; i < s->nchars; ++i)
+ char1b[i] = s->char2b[i].byte2;
+
+ /* Draw text with XDrawString if background has already been
+ filled. Otherwise, use XDrawImageString. (Note that
+ XDrawImageString is usually faster than XDrawString.)
+ Always use XDrawImageString when drawing the cursor so
+ that there is no chance that characters under a box
+ cursor are invisible. */
+ if (s->for_overlaps_p
+ || (s->background_filled_p && s->hl != DRAW_CURSOR))
+ {
+ /* Draw characters with 16-bit or 8-bit functions. */
+ if (s->two_byte_p)
+ XDrawString16 (s->display, s->window, s->gc, x, s->ybase,
+ s->char2b, s->nchars);
+ else
+ XDrawString (s->display, s->window, s->gc, x, s->ybase,
+ char1b, s->nchars);
+ }
+ else
+ {
+ if (s->two_byte_p)
+ XDrawImageString16 (s->display, s->window, s->gc,
+ x, s->ybase, s->char2b, s->nchars);
+ else
+ XDrawImageString (s->display, s->window, s->gc,
+ x, s->ybase, char1b, s->nchars);
+ }
+ }
+ }
+ else
+ {
+ /* S is a glyph string for a composite character. S->gidx is the
+ index of the first character drawn in the vector
+ S->cmpcharp->glyph. S->gidx == 0 means we are drawing the
+ very first component character of a composite char. */
+
+ /* Draw a single rectangle for the composite character if S's
+ font could not be loaded. */
+ if (s->font_not_found_p && s->gidx == 0)
+ XDrawRectangle (s->display, s->window, s->gc, x, s->y,
+ s->width - 1, s->height - 1);
+ else
+ {
+ XCharStruct *pcm;
+ int relative_compose, default_ascent, i;
+ int highest = 0, lowest = 0;
+
+ /* The value of font_info my be null if we couldn't find it
+ in x_get_char_face_and_encoding. */
+ if (s->cmpcharp->cmp_rule == NULL && s->font_info)
+ {
+ relative_compose = s->font_info->relative_compose;
+ default_ascent = s->font_info->default_ascent;
+ }
+ else
+ relative_compose = default_ascent = 0;
+
+ if ((s->cmpcharp->cmp_rule || relative_compose)
+ && s->gidx == 0)
+ {
+ /* This is the first character. Initialize variables.
+ Highest is the highest position of glyphs ever
+ written, lowest the lowest position. */
+ int x_offset = 0;
+ int first_ch = s->first_glyph->u.ch.code;
+
+ if (default_ascent
+ && CHAR_TABLE_P (Vuse_default_ascent)
+ && !NILP (Faref (Vuse_default_ascent, first_ch)))
+ {
+ highest = default_ascent;
+ lowest = 0;
+ }
+ else
+ {
+ pcm = PER_CHAR_METRIC (s->font, s->char2b);
+ highest = pcm->ascent + 1;
+ lowest = - pcm->descent;
+ }
+
+ if (s->cmpcharp->cmp_rule)
+ x_offset = (s->cmpcharp->col_offset[0]
+ * FONT_WIDTH (s->f->output_data.x->font));
+
+ /* Draw the first character at the normal position. */
+ XDrawString16 (s->display, s->window, s->gc,
+ x + x_offset,
+ s->ybase, s->char2b, 1);
+ i = 1;
+ ++s->gidx;
+ }
+ else
+ i = 0;
+
+ for (; i < s->nchars; i++, ++s->gidx)
+ {
+ int x_offset = 0, y_offset = 0;
+
+ if (relative_compose)
+ {
+ pcm = PER_CHAR_METRIC (s->font, s->char2b + i);
+ if (NILP (Vignore_relative_composition)
+ || NILP (Faref (Vignore_relative_composition,
+ make_number (s->cmpcharp->glyph[s->gidx]))))
+ {
+ if (- pcm->descent >= relative_compose)
+ {
+ /* Draw above the current glyphs. */
+ y_offset = highest + pcm->descent;
+ highest += pcm->ascent + pcm->descent;
+ }
+ else if (pcm->ascent <= 0)
+ {
+ /* Draw beneath the current glyphs. */
+ y_offset = lowest - pcm->ascent;
+ lowest -= pcm->ascent + pcm->descent;
+ }
+ }
+ else
+ {
+ /* Draw the glyph at normal position. If
+ it sticks out of HIGHEST or LOWEST,
+ update them appropriately. */
+ if (pcm->ascent > highest)
+ highest = pcm->ascent;
+ else if (- pcm->descent < lowest)
+ lowest = - pcm->descent;
+ }
+ }
+ else if (s->cmpcharp->cmp_rule)
+ {
+ int gref = (s->cmpcharp->cmp_rule[s->gidx] - 0xA0) / 9;
+ int nref = (s->cmpcharp->cmp_rule[s->gidx] - 0xA0) % 9;
+ int bottom, top;
+
+ /* Re-encode GREF and NREF so that they specify
+ only Y-axis information:
+ 0:top, 1:base, 2:bottom, 3:center */
+ gref = gref / 3 + (gref == 4) * 2;
+ nref = nref / 3 + (nref == 4) * 2;
+
+ pcm = PER_CHAR_METRIC (s->font, s->char2b + i);
+ bottom = ((gref == 0 ? highest : gref == 1 ? 0
+ : gref == 2 ? lowest
+ : (highest + lowest) / 2)
+ - (nref == 0 ? pcm->ascent + pcm->descent
+ : nref == 1 ? pcm->descent : nref == 2 ? 0
+ : (pcm->ascent + pcm->descent) / 2));
+ top = bottom + (pcm->ascent + pcm->descent);
+ if (top > highest)
+ highest = top;
+ if (bottom < lowest)
+ lowest = bottom;
+ y_offset = bottom + pcm->descent;
+ x_offset = (s->cmpcharp->col_offset[s->gidx]
+ * FONT_WIDTH (FRAME_FONT (s->f)));
+ }
+
+ XDrawString16 (s->display, s->window, s->gc,
+ x + x_offset, s->ybase - y_offset,
+ s->char2b + i, 1);
+ }
+ }
+ }
+}
+
+
+#ifdef USE_X_TOOLKIT
+
+/* Allocate the color COLOR->pixel on the screen and display of
+ widget WIDGET in colormap CMAP. If an exact match cannot be
+ allocated, try the nearest color available. Value is non-zero
+ if successful. This is called from lwlib. */
+
+int
+x_alloc_nearest_color_for_widget (widget, cmap, color)
+ Widget widget;
+ Colormap cmap;
+ XColor *color;
+{
+ struct frame *f;
+ struct x_display_info *dpyinfo;
+ Lisp_Object tail;
+
+ dpyinfo = x_display_info_for_display (XtDisplay (widget));
+
+ /* Find the top-level shell of the widget. Note that this function
+ can be called when the widget is not yet realized, so XtWindow
+ (widget) == 0. That's the reason we can't simply use
+ x_any_window_to_frame. */
+ while (!XtIsTopLevelShell (widget))
+ widget = XtParent (widget);
+
+ /* Look for a frame with that top-level widget. Allocate the color
+ on that frame to get the right gamma correction value. */
+ for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
+ if (GC_FRAMEP (XCAR (tail))
+ && (f = XFRAME (XCAR (tail)),
+ (f->output_data.nothing != 1
+ && FRAME_X_DISPLAY_INFO (f) == dpyinfo))
+ && f->output_data.x->widget == widget)
+ return x_alloc_nearest_color (f, cmap, color);
+
+ abort ();
+}
+
+#endif /* USE_X_TOOLKIT */
+
+
+/* Allocate the color COLOR->pixel on SCREEN of DISPLAY, colormap
+ CMAP. If an exact match can't be allocated, try the nearest color
+ available. Value is non-zero if successful. Set *COLOR to the
+ color allocated. */
+
+int
+x_alloc_nearest_color (f, cmap, color)
+ struct frame *f;
+ Colormap cmap;
+ XColor *color;
+{
+ Display *display = FRAME_X_DISPLAY (f);
+ Screen *screen = FRAME_X_SCREEN (f);
+ int rc;
+
+ gamma_correct (f, color);
+ rc = XAllocColor (display, cmap, color);
+ if (rc == 0)
+ {
+ /* If we got to this point, the colormap is full, so we're going
+ to try to get the next closest color. The algorithm used is
+ a least-squares matching, which is what X uses for closest
+ color matching with StaticColor visuals. */
+ int nearest, i;
+ unsigned long nearest_delta = ~0;
+ int ncells = XDisplayCells (display, XScreenNumberOfScreen (screen));
+ XColor *cells = (XColor *) alloca (ncells * sizeof *cells);
+
+ for (i = 0; i < ncells; ++i)
+ cells[i].pixel = i;
+ XQueryColors (display, cmap, cells, ncells);
+
+ for (nearest = i = 0; i < ncells; ++i)
+ {
+ long dred = (color->red >> 8) - (cells[i].red >> 8);
+ long dgreen = (color->green >> 8) - (cells[i].green >> 8);
+ long dblue = (color->blue >> 8) - (cells[i].blue >> 8);
+ unsigned long delta = dred * dred + dgreen * dgreen + dblue * dblue;
+
+ if (delta < nearest_delta)
+ {
+ nearest = i;
+ nearest_delta = delta;
+ }
+ }
+
+ color->red = cells[nearest].red;
+ color->green = cells[nearest].green;
+ color->blue = cells[nearest].blue;
+ rc = XAllocColor (display, cmap, color);
+ }
+
+ return rc;
+}
+
+
+/* Allocate a color which is lighter or darker than *PIXEL by FACTOR
+ or DELTA. Try a color with RGB values multiplied by FACTOR first.
+ If this produces the same color as PIXEL, try a color where all RGB
+ values have DELTA added. Return the allocated color in *PIXEL.
+ DISPLAY is the X display, CMAP is the colormap to operate on.
+ Value is non-zero if successful. */
+
+static int
+x_alloc_lighter_color (f, display, cmap, pixel, factor, delta)
+ struct frame *f;
+ Display *display;
+ Colormap cmap;
+ unsigned long *pixel;
+ double factor;
+ int delta;
+{
+ XColor color, new;
+ int success_p;
+
+ /* Get RGB color values. */
+ color.pixel = *pixel;
+ XQueryColor (display, cmap, &color);
+
+ /* Change RGB values by specified FACTOR. Avoid overflow! */
+ xassert (factor >= 0);
+ new.red = min (0xffff, factor * color.red);
+ new.green = min (0xffff, factor * color.green);
+ new.blue = min (0xffff, factor * color.blue);
+
+ /* Try to allocate the color. */
+ success_p = x_alloc_nearest_color (f, cmap, &new);
+ if (success_p)
+ {
+ if (new.pixel == *pixel)
+ {
+ /* If we end up with the same color as before, try adding
+ delta to the RGB values. */
+ int class = FRAME_X_DISPLAY_INFO (f)->visual->class;
+
+ /* If display has an immutable color map, freeing colors is
+ not necessary and some servers don't allow it. So don't
+ do it. */
+ if (class != StaticColor
+ && class != StaticGray
+ && class != TrueColor)
+ XFreeColors (display, cmap, &new.pixel, 1, 0);
+
+ new.red = min (0xffff, delta + color.red);
+ new.green = min (0xffff, delta + color.green);
+ new.blue = min (0xffff, delta + color.blue);
+ success_p = x_alloc_nearest_color (f, cmap, &new);
+ }
+ else
+ success_p = 1;
+ *pixel = new.pixel;
+ }
+
+ return success_p;
+}
+
+
+/* Set up the foreground color for drawing relief lines of glyph
+ string S. RELIEF is a pointer to a struct relief containing the GC
+ with which lines will be drawn. Use a color that is FACTOR or
+ DELTA lighter or darker than the relief's background which is found
+ in S->f->output_data.x->relief_background. If such a color cannot
+ be allocated, use DEFAULT_PIXEL, instead. */
+
+static void
+x_setup_relief_color (f, relief, factor, delta, default_pixel)
+ struct frame *f;
+ struct relief *relief;
+ double factor;
+ int delta;
+ unsigned long default_pixel;
+{
+ XGCValues xgcv;
+ struct x_output *di = f->output_data.x;
+ unsigned long mask = GCForeground | GCLineWidth | GCGraphicsExposures;
+ unsigned long pixel;
+ unsigned long background = di->relief_background;
+ Colormap cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
+ struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+ Display *dpy = FRAME_X_DISPLAY (f);
+
+ xgcv.graphics_exposures = False;
+ xgcv.line_width = 1;
+
+ /* Free previously allocated color. The color cell will be reused
+ when it has been freed as many times as it was allocated, so this
+ doesn't affect faces using the same colors. */
+ if (relief->gc
+ && relief->allocated_p)
+ {
+ /* If display has an immutable color map, freeing colors is not
+ necessary and some servers don't allow it. So don't do it. */
+ int class = dpyinfo->visual->class;
+ if (class != StaticColor
+ && class != StaticGray
+ && class != TrueColor)
+ XFreeColors (dpy, cmap, &relief->pixel, 1, 0);
+ relief->allocated_p = 0;
+ }
+
+ /* Allocate new color. */
+ xgcv.foreground = default_pixel;
+ pixel = background;
+ if (dpyinfo->n_planes != 1
+ && x_alloc_lighter_color (f, dpy, cmap, &pixel, factor, delta))
+ {
+ relief->allocated_p = 1;
+ xgcv.foreground = relief->pixel = pixel;
+ }
+
+ if (relief->gc == 0)
+ {
+ xgcv.stipple = dpyinfo->gray;
+ mask |= GCStipple;
+ relief->gc = XCreateGC (dpy, FRAME_X_WINDOW (f), mask, &xgcv);
+ }
+ else
+ XChangeGC (dpy, relief->gc, mask, &xgcv);
+}
+
+
+/* Set up colors for the relief lines around glyph string S. */
+
+static void
+x_setup_relief_colors (s)
+ struct glyph_string *s;
+{
+ struct x_output *di = s->f->output_data.x;
+ unsigned long color;
+
+ if (s->face->use_box_color_for_shadows_p)
+ color = s->face->box_color;
+ else
+ {
+ XGCValues xgcv;
+
+ /* Get the background color of the face. */
+ XGetGCValues (s->display, s->gc, GCBackground, &xgcv);
+ color = xgcv.background;
+ }
+
+ if (di->white_relief.gc == 0
+ || color != di->relief_background)
+ {
+ di->relief_background = color;
+ x_setup_relief_color (s->f, &di->white_relief, 1.2, 0x8000,
+ WHITE_PIX_DEFAULT (s->f));
+ x_setup_relief_color (s->f, &di->black_relief, 0.6, 0x4000,
+ BLACK_PIX_DEFAULT (s->f));
+ }
+}
+
+
+/* Draw a relief on frame F inside the rectangle given by LEFT_X,
+ TOP_Y, RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the relief
+ to draw, it must be >= 0. RAISED_P non-zero means draw a raised
+ relief. LEFT_P non-zero means draw a relief on the left side of
+ the rectangle. RIGHT_P non-zero means draw a relief on the right
+ side of the rectangle. CLIP_RECT is the clipping rectangle to use
+ when drawing. */
+
+static void
+x_draw_relief_rect (f, left_x, top_y, right_x, bottom_y, width,
+ raised_p, left_p, right_p, clip_rect)
+ struct frame *f;
+ int left_x, top_y, right_x, bottom_y, left_p, right_p, raised_p;
+ XRectangle *clip_rect;
+{
+ int i;
+ GC gc;
+
+ if (raised_p)
+ gc = f->output_data.x->white_relief.gc;
+ else
+ gc = f->output_data.x->black_relief.gc;
+ XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, clip_rect, 1, Unsorted);
+
+ /* Top. */
+ for (i = 0; i < width; ++i)
+ XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
+ left_x + i * left_p, top_y + i,
+ right_x + 1 - i * right_p, top_y + i);
+
+ /* Left. */
+ if (left_p)
+ for (i = 0; i < width; ++i)
+ XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
+ left_x + i, top_y + i, left_x + i, bottom_y - i);
+
+ XSetClipMask (FRAME_X_DISPLAY (f), gc, None);
+ if (raised_p)
+ gc = f->output_data.x->black_relief.gc;
+ else
+ gc = f->output_data.x->white_relief.gc;
+ XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, clip_rect, 1, Unsorted);
+
+ /* Bottom. */
+ for (i = 0; i < width; ++i)
+ XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
+ left_x + i * left_p, bottom_y - i,
+ right_x + 1 - i * right_p, bottom_y - i);
+
+ /* Right. */
+ if (right_p)
+ for (i = 0; i < width; ++i)
+ XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
+ right_x - i, top_y + i + 1, right_x - i, bottom_y - i);
+
+ XSetClipMask (FRAME_X_DISPLAY (f), gc, None);
+}
+
+
+/* Draw a box on frame F inside the rectangle given by LEFT_X, TOP_Y,
+ RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the lines to
+ draw, it must be >= 0. LEFT_P non-zero means draw a line on the
+ left side of the rectangle. RIGHT_P non-zero means draw a line
+ on the right side of the rectangle. CLIP_RECT is the clipping
+ rectangle to use when drawing. */
+
+static void
+x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
+ left_p, right_p, clip_rect)
+ struct glyph_string *s;
+ int left_x, top_y, right_x, bottom_y, left_p, right_p;
+ XRectangle *clip_rect;
+{
+ XGCValues xgcv;
+
+ XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
+ XSetForeground (s->display, s->gc, s->face->box_color);
+ XSetClipRectangles (s->display, s->gc, 0, 0, clip_rect, 1, Unsorted);
+
+ /* Top. */
+ XFillRectangle (s->display, s->window, s->gc,
+ left_x, top_y, right_x - left_x, width);
+
+ /* Left. */
+ if (left_p)
+ XFillRectangle (s->display, s->window, s->gc,
+ left_x, top_y, width, bottom_y - top_y);
+
+ /* Bottom. */
+ XFillRectangle (s->display, s->window, s->gc,
+ left_x, bottom_y - width, right_x - left_x, width);
+
+ /* Right. */
+ if (right_p)
+ XFillRectangle (s->display, s->window, s->gc,
+ right_x - width, top_y, width, bottom_y - top_y);
+
+ XSetForeground (s->display, s->gc, xgcv.foreground);
+ XSetClipMask (s->display, s->gc, None);
+}
+
+
+/* Draw a box around glyph string S. */
+
+static void
+x_draw_glyph_string_box (s)
+ struct glyph_string *s;
+{
+ int width, left_x, right_x, top_y, bottom_y, last_x, raised_p;
+ int left_p, right_p;
+ struct glyph *last_glyph;
+ XRectangle clip_rect;
+
+ last_x = window_box_right (s->w, s->area);
+ if (s->row->full_width_p
+ && !s->w->pseudo_window_p)
+ {
+ last_x += FRAME_X_RIGHT_FLAGS_AREA_WIDTH (s->f);
+ if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (s->f))
+ last_x += FRAME_SCROLL_BAR_WIDTH (s->f) * CANON_X_UNIT (s->f);
+ }
+
+ /* The glyph that may have a right box line. */
+ last_glyph = (s->cmpcharp || s->img
+ ? s->first_glyph
+ : s->first_glyph + s->nchars - 1);
+
+ width = s->face->box_line_width;
+ raised_p = s->face->box == FACE_RAISED_BOX;
+ left_x = s->x;
+ right_x = ((s->row->full_width_p
+ ? last_x - 1
+ : min (last_x, s->x + s->background_width) - 1));
+ top_y = s->y;
+ bottom_y = top_y + s->height - 1;
+
+ left_p = (s->first_glyph->left_box_line_p
+ || (s->hl == DRAW_MOUSE_FACE
+ && (s->prev == NULL
+ || s->prev->hl != s->hl)));
+ right_p = (last_glyph->right_box_line_p
+ || (s->hl == DRAW_MOUSE_FACE
+ && (s->next == NULL
+ || s->next->hl != s->hl)));
+
+ x_get_glyph_string_clip_rect (s, &clip_rect);
+
+ if (s->face->box == FACE_SIMPLE_BOX)
+ x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
+ left_p, right_p, &clip_rect);
+ else
+ {
+ x_setup_relief_colors (s);
+ x_draw_relief_rect (s->f, left_x, top_y, right_x, bottom_y,
+ width, raised_p, left_p, right_p, &clip_rect);
+ }
+}
+
+
+/* Draw foreground of image glyph string S. */
+
+static void
+x_draw_image_foreground (s)
+ struct glyph_string *s;
+{
+ int x;
+ int y = s->ybase - IMAGE_ASCENT (s->img);
+
+ /* If first glyph of S has a left box line, start drawing it to the
+ right of that line. */
+ if (s->face->box != FACE_NO_BOX
+ && s->first_glyph->left_box_line_p)
+ x = s->x + s->face->box_line_width;
+ else
+ x = s->x;
+
+ /* If there is a margin around the image, adjust x- and y-position
+ by that margin. */
+ if (s->img->margin)
+ {
+ x += s->img->margin;
+ y += s->img->margin;
+ }
+
+ if (s->img->pixmap)
+ {
+ if (s->img->mask)
+ {
+ /* We can't set both a clip mask and use XSetClipRectangles
+ because the latter also sets a clip mask. We also can't
+ trust on the shape extension to be available
+ (XShapeCombineRegion). So, compute the rectangle to draw
+ manually. */
+ unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
+ | GCFunction);
+ XGCValues xgcv;
+ XRectangle clip_rect, image_rect, r;
+
+ xgcv.clip_mask = s->img->mask;
+ xgcv.clip_x_origin = x;
+ xgcv.clip_y_origin = y;
+ xgcv.function = GXcopy;
+ XChangeGC (s->display, s->gc, mask, &xgcv);
+
+ x_get_glyph_string_clip_rect (s, &clip_rect);
+ image_rect.x = x;
+ image_rect.y = y;
+ image_rect.width = s->img->width;
+ image_rect.height = s->img->height;
+ if (x_intersect_rectangles (&clip_rect, &image_rect, &r))
+ XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
+ r.x - x, r.y - y, r.width, r.height, r.x, r.y);
+ }
+ else
+ {
+ XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
+ 0, 0, s->img->width, s->img->height, x, y);
+
+ /* When the image has a mask, we can expect that at
+ least part of a mouse highlight or a block cursor will
+ be visible. If the image doesn't have a mask, make
+ a block cursor visible by drawing a rectangle around
+ the image. I believe it's looking better if we do
+ nothing here for mouse-face. */
+ if (s->hl == DRAW_CURSOR)
+ XDrawRectangle (s->display, s->window, s->gc, x, y,
+ s->img->width - 1, s->img->height - 1);
+ }
+ }
+ else
+ /* Draw a rectangle if image could not be loaded. */
+ XDrawRectangle (s->display, s->window, s->gc, x, y,
+ s->img->width - 1, s->img->height - 1);
+}
+
+
+/* Draw a relief around the image glyph string S. */
+
+static void
+x_draw_image_relief (s)
+ struct glyph_string *s;
+{
+ int x0, y0, x1, y1, thick, raised_p;
+ XRectangle r;
+ int x;
+ int y = s->ybase - IMAGE_ASCENT (s->img);
+
+ /* If first glyph of S has a left box line, start drawing it to the
+ right of that line. */
+ if (s->face->box != FACE_NO_BOX
+ && s->first_glyph->left_box_line_p)
+ x = s->x + s->face->box_line_width;
+ else
+ x = s->x;
+
+ /* If there is a margin around the image, adjust x- and y-position
+ by that margin. */
+ if (s->img->margin)
+ {
+ x += s->img->margin;
+ y += s->img->margin;
+ }
+
+ if (s->hl == DRAW_IMAGE_SUNKEN
+ || s->hl == DRAW_IMAGE_RAISED)
+ {
+ thick = tool_bar_button_relief > 0 ? tool_bar_button_relief : 3;
+ raised_p = s->hl == DRAW_IMAGE_RAISED;
+ }
+ else
+ {
+ thick = abs (s->img->relief);
+ raised_p = s->img->relief > 0;
+ }
+
+ x0 = x - thick;
+ y0 = y - thick;
+ x1 = x + s->img->width + thick - 1;
+ y1 = y + s->img->height + thick - 1;
+
+ x_setup_relief_colors (s);
+ x_get_glyph_string_clip_rect (s, &r);
+ x_draw_relief_rect (s->f, x0, y0, x1, y1, thick, raised_p, 1, 1, &r);
+}
+
+
+/* Draw the foreground of image glyph string S to PIXMAP. */
+
+static void
+x_draw_image_foreground_1 (s, pixmap)
+ struct glyph_string *s;
+ Pixmap pixmap;
+{
+ int x;
+ int y = s->ybase - s->y - IMAGE_ASCENT (s->img);
+
+ /* If first glyph of S has a left box line, start drawing it to the
+ right of that line. */
+ if (s->face->box != FACE_NO_BOX
+ && s->first_glyph->left_box_line_p)
+ x = s->face->box_line_width;
+ else
+ x = 0;
+
+ /* If there is a margin around the image, adjust x- and y-position
+ by that margin. */
+ if (s->img->margin)
+ {
+ x += s->img->margin;
+ y += s->img->margin;
+ }
+
+ if (s->img->pixmap)
+ {
+ if (s->img->mask)
+ {
+ /* We can't set both a clip mask and use XSetClipRectangles
+ because the latter also sets a clip mask. We also can't
+ trust on the shape extension to be available
+ (XShapeCombineRegion). So, compute the rectangle to draw
+ manually. */
+ unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
+ | GCFunction);
+ XGCValues xgcv;
+
+ xgcv.clip_mask = s->img->mask;
+ xgcv.clip_x_origin = x;
+ xgcv.clip_y_origin = y;
+ xgcv.function = GXcopy;
+ XChangeGC (s->display, s->gc, mask, &xgcv);
+
+ XCopyArea (s->display, s->img->pixmap, pixmap, s->gc,
+ 0, 0, s->img->width, s->img->height, x, y);
+ XSetClipMask (s->display, s->gc, None);
+ }
+ else
+ {
+ XCopyArea (s->display, s->img->pixmap, pixmap, s->gc,
+ 0, 0, s->img->width, s->img->height, x, y);
+
+ /* When the image has a mask, we can expect that at
+ least part of a mouse highlight or a block cursor will
+ be visible. If the image doesn't have a mask, make
+ a block cursor visible by drawing a rectangle around
+ the image. I believe it's looking better if we do
+ nothing here for mouse-face. */
+ if (s->hl == DRAW_CURSOR)
+ XDrawRectangle (s->display, pixmap, s->gc, x, y,
+ s->img->width - 1, s->img->height - 1);
+ }
+ }
+ else
+ /* Draw a rectangle if image could not be loaded. */
+ XDrawRectangle (s->display, pixmap, s->gc, x, y,
+ s->img->width - 1, s->img->height - 1);
+}
+
+
+/* Draw part of the background of glyph string S. X, Y, W, and H
+ give the rectangle to draw. */
+
+static void
+x_draw_glyph_string_bg_rect (s, x, y, w, h)
+ struct glyph_string *s;
+ int x, y, w, h;
+{
+ if (s->stippled_p)
+ {
+ /* Fill background with a stipple pattern. */
+ XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
+ XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
+ XSetFillStyle (s->display, s->gc, FillSolid);
+ }
+ else
+ x_clear_glyph_string_rect (s, x, y, w, h);
+}
+
+
+/* Draw image glyph string S.
+
+ s->y
+ s->x +-------------------------
+ | s->face->box
+ |
+ | +-------------------------
+ | | s->img->margin
+ | |
+ | | +-------------------
+ | | | the image
+
+ */
+
+static void
+x_draw_image_glyph_string (s)
+ struct glyph_string *s;
+{
+ int x, y;
+ int box_line_width = s->face->box_line_width;
+ int margin = s->img->margin;
+ int height;
+ Pixmap pixmap = None;
+
+ height = s->height - 2 * box_line_width;
+
+ /* Fill background with face under the image. Do it only if row is
+ taller than image or if image has a clip mask to reduce
+ flickering. */
+ s->stippled_p = s->face->stipple != 0;
+ if (height > s->img->height
+ || margin
+ || s->img->mask
+ || s->img->pixmap == 0
+ || s->width != s->background_width)
+ {
+ if (box_line_width && s->first_glyph->left_box_line_p)
+ x = s->x + box_line_width;
+ else
+ x = s->x;
+
+ y = s->y + box_line_width;
+
+ if (s->img->mask)
+ {
+ /* Create a pixmap as large as the glyph string Fill it with
+ the background color. Copy the image to it, using its
+ mask. Copy the temporary pixmap to the display. */
+ Screen *screen = FRAME_X_SCREEN (s->f);
+ int depth = DefaultDepthOfScreen (screen);
+
+ /* Create a pixmap as large as the glyph string. */
+ pixmap = XCreatePixmap (s->display, s->window,
+ s->background_width,
+ s->height, depth);
+
+ /* Don't clip in the following because we're working on the
+ pixmap. */
+ XSetClipMask (s->display, s->gc, None);
+
+ /* Fill the pixmap with the background color/stipple. */
+ if (s->stippled_p)
+ {
+ /* Fill background with a stipple pattern. */
+ XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
+ XFillRectangle (s->display, pixmap, s->gc,
+ 0, 0, s->background_width, s->height);
+ XSetFillStyle (s->display, s->gc, FillSolid);
+ }
+ else
+ {
+ XGCValues xgcv;
+ XGetGCValues (s->display, s->gc, GCForeground | GCBackground,
+ &xgcv);
+ XSetForeground (s->display, s->gc, xgcv.background);
+ XFillRectangle (s->display, pixmap, s->gc,
+ 0, 0, s->background_width, s->height);
+ XSetForeground (s->display, s->gc, xgcv.foreground);
+ }
+ }
+ else
+ /* Implementation idea: Is it possible to construct a mask?
+ We could look at the color at the margins of the image, and
+ say that this color is probably the background color of the
+ image. */
+ x_draw_glyph_string_bg_rect (s, x, y, s->background_width, height);
+
+ s->background_filled_p = 1;
+ }
+
+ /* Draw the foreground. */
+ if (pixmap != None)
+ {
+ x_draw_image_foreground_1 (s, pixmap);
+ x_set_glyph_string_clipping (s);
+ XCopyArea (s->display, pixmap, s->window, s->gc,
+ 0, 0, s->background_width, s->height, s->x, s->y);
+ XFreePixmap (s->display, pixmap);
+ }
+ else
+ x_draw_image_foreground (s);
+
+ /* If we must draw a relief around the image, do it. */
+ if (s->img->relief
+ || s->hl == DRAW_IMAGE_RAISED
+ || s->hl == DRAW_IMAGE_SUNKEN)
+ x_draw_image_relief (s);
+}
+
+
+/* Draw stretch glyph string S. */
+
+static void
+x_draw_stretch_glyph_string (s)
+ struct glyph_string *s;
+{
+ xassert (s->first_glyph->type == STRETCH_GLYPH);
+ s->stippled_p = s->face->stipple != 0;
+
+ if (s->hl == DRAW_CURSOR
+ && !x_stretch_cursor_p)
+ {
+ /* If `x-stretch-block-cursor' is nil, don't draw a block cursor
+ as wide as the stretch glyph. */
+ int width = min (CANON_X_UNIT (s->f), s->background_width);