# HG changeset patch # User Gerd Moellmann # Date 933947999 0 # Node ID 710445260df6efb30a18b0dfa92a49e0296bca2b # Parent 6849f435f6e89ec0434e09a02665ac01c3390c6d (x_draw_phys_cursor_glyph): Redraw overlaps. (x_fix_overlapping_area): New. (x_redisplay_interface): Add x_fix_overlapping_area. (x_draw_glyphs): Add parameter overlaps_p. (struct glyph_string): Add member for_overlaps_p. (x_get_glyph_string_clip_rect): If glyph string draws foreground of overlapping rows, clip to window bottom. (x_fill_glyph_string): Add parameter overlaps_p. (x_fill_composite_glyph_string): Ditto. (BUILD_GLYPH_STRINGS): Ditto. (BUILD_CHAR_GLYPH_STRINGS): Ditto. (x_draw_glyph_string): Don't draw anything but the foreground if glyph string draws row overlaps. (x_append_glyph): Set glyph flag overlaps_vertically_p. (x_produce_image_glyph): Compute iterator's physical ascent and descent. (x_produce_stretch_glyph): Ditto. (x_produce_glyphs): Ditto. diff -r 6849f435f6e8 -r 710445260df6 src/xterm.c --- a/src/xterm.c Fri Aug 06 13:59:43 1999 +0000 +++ b/src/xterm.c Fri Aug 06 13:59:59 1999 +0000 @@ -1440,6 +1440,8 @@ 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]; } } @@ -1487,8 +1489,8 @@ PREPARE_FACE_FOR_DISPLAY (it->f, face); prepare_image_for_display (it->f, img); - it->ascent = IMAGE_ASCENT (img); - it->descent = img->height + 2 * img->margin - it->ascent; + 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; @@ -1691,8 +1693,8 @@ } it->pixel_width = width; - it->ascent = height * ascent; - it->descent = height - it->ascent; + it->ascent = it->phys_ascent = height * ascent; + it->descent = it->phys_descent = height - it->ascent; it->nglyphs = 1; if (face->box != FACE_NO_BOX) @@ -1758,10 +1760,12 @@ int stretched_p; it->nglyphs = 1; + + pcm = x_per_char_metric (font, &char2b); it->ascent = font->ascent; it->descent = font->descent; - - pcm = x_per_char_metric (font, &char2b); + 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 @@ -1820,8 +1824,8 @@ /* A newline has no width but we need the height of the line. */ it->pixel_width = 0; it->nglyphs = 0; - it->ascent = font->ascent; - it->descent = font->descent; + it->ascent = it->phys_ascent = font->ascent; + it->descent = it->phys_descent = font->descent; if (face->box != FACE_NO_BOX) { @@ -1840,8 +1844,8 @@ it->pixel_width = next_tab_x - x; it->nglyphs = 1; - it->ascent = font->ascent; - it->descent = font->descent; + it->ascent = it->phys_ascent = font->ascent; + it->descent = it->phys_descent = font->descent; if (it->glyph_row) { @@ -1879,6 +1883,8 @@ 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 { @@ -1894,6 +1900,8 @@ 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)) @@ -1932,8 +1940,11 @@ 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); } @@ -2065,6 +2076,11 @@ 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; @@ -2119,7 +2135,8 @@ 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)); +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 *, @@ -2127,7 +2144,7 @@ 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 *)); + 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 *, @@ -2159,9 +2176,10 @@ 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. */ @@ -2420,12 +2438,22 @@ r->y = WINDOW_DISPLAY_TOP_LINE_HEIGHT (s->w); else r->y = max (0, s->row->y); - r->y = WINDOW_TO_FRAME_PIXEL_Y (s->w, r->y); /* If drawing a toolbar window, draw it over the internal border at the top of the window. */ if (s->w == XWINDOW (s->f->toolbar_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_TOP_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); } @@ -2754,7 +2782,8 @@ Always use XDrawImageString when drawing the cursor so that there is no chance that characters under a box cursor are invisible. */ - if (s->background_filled_p && s->hl != DRAW_CURSOR) + 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) @@ -3675,7 +3704,7 @@ /* If S draws into the background of its successor, draw the background of the successor first so that S can draw into it. This makes S->next use XDrawString instead of XDrawImageString. */ - if (s->next && s->right_overhang) + if (s->next && s->right_overhang && !s->for_overlaps_p) { xassert (s->next->img == NULL); x_set_glyph_string_gc (s->next); @@ -3698,7 +3727,10 @@ break; case CHAR_GLYPH: - x_draw_glyph_string_background (s, 0); + if (s->for_overlaps_p) + s->background_filled_p = 1; + else + x_draw_glyph_string_background (s, 0); x_draw_glyph_string_foreground (s); break; @@ -3706,72 +3738,75 @@ abort (); } - /* Draw underline. */ - if (s->face->underline_p) - { - unsigned long dy, h; - - if (!XGetFontProperty (s->font, XA_UNDERLINE_THICKNESS, &h)) - h = 1; - if (!XGetFontProperty (s->font, XA_UNDERLINE_POSITION, &dy)) - dy = s->height - h; + if (!s->for_overlaps_p) + { + /* Draw underline. */ + if (s->face->underline_p) + { + unsigned long dy, h; + + if (!XGetFontProperty (s->font, XA_UNDERLINE_THICKNESS, &h)) + h = 1; + if (!XGetFontProperty (s->font, XA_UNDERLINE_POSITION, &dy)) + dy = s->height - h; - if (s->face->underline_defaulted_p) - XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy, - s->width, h); - else - { - XGCValues xgcv; - XGetGCValues (s->display, s->gc, GCForeground, &xgcv); - XSetForeground (s->display, s->gc, s->face->underline_color); - XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy, - s->width, h); - XSetForeground (s->display, s->gc, xgcv.foreground); - } - } - - /* Draw overline. */ - if (s->face->overline_p) - { - unsigned long dy = 0, h = 1; - - if (s->face->overline_color_defaulted_p) - XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy, - s->width, h); - else - { - XGCValues xgcv; - XGetGCValues (s->display, s->gc, GCForeground, &xgcv); - XSetForeground (s->display, s->gc, s->face->overline_color); - XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy, - s->width, h); - XSetForeground (s->display, s->gc, xgcv.foreground); - } - } - - /* Draw strike-through. */ - if (s->face->strike_through_p) - { - unsigned long h = 1; - unsigned long dy = (s->height - h) / 2; - - if (s->face->strike_through_color_defaulted_p) - XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy, - s->width, h); - else - { - XGCValues xgcv; - XGetGCValues (s->display, s->gc, GCForeground, &xgcv); - XSetForeground (s->display, s->gc, s->face->strike_through_color); - XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy, - s->width, h); - XSetForeground (s->display, s->gc, xgcv.foreground); - } - } - - /* Draw relief. */ - if (s->face->box != FACE_NO_BOX) - x_draw_glyph_string_box (s); + if (s->face->underline_defaulted_p) + XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy, + s->width, h); + else + { + XGCValues xgcv; + XGetGCValues (s->display, s->gc, GCForeground, &xgcv); + XSetForeground (s->display, s->gc, s->face->underline_color); + XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy, + s->width, h); + XSetForeground (s->display, s->gc, xgcv.foreground); + } + } + + /* Draw overline. */ + if (s->face->overline_p) + { + unsigned long dy = 0, h = 1; + + if (s->face->overline_color_defaulted_p) + XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy, + s->width, h); + else + { + XGCValues xgcv; + XGetGCValues (s->display, s->gc, GCForeground, &xgcv); + XSetForeground (s->display, s->gc, s->face->overline_color); + XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy, + s->width, h); + XSetForeground (s->display, s->gc, xgcv.foreground); + } + } + + /* Draw strike-through. */ + if (s->face->strike_through_p) + { + unsigned long h = 1; + unsigned long dy = (s->height - h) / 2; + + if (s->face->strike_through_color_defaulted_p) + XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy, + s->width, h); + else + { + XGCValues xgcv; + XGetGCValues (s->display, s->gc, GCForeground, &xgcv); + XSetForeground (s->display, s->gc, s->face->strike_through_color); + XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy, + s->width, h); + XSetForeground (s->display, s->gc, xgcv.foreground); + } + } + + /* Draw relief. */ + if (s->face->box != FACE_NO_BOX) + x_draw_glyph_string_box (s); + } /* Reset clipping. */ XSetClipMask (s->display, s->gc, None); @@ -3797,26 +3832,31 @@ static void x_fill_composite_glyph_string P_ ((struct glyph_string *, int, struct work **, - struct work **)); + struct work **, int)); /* Load glyph string S with information from the top of *STACK for a composite character. FACE_ID is the id of the face in which S is drawn. *NEW is a pointer to a struct work not on the stack, that can be used if this function needs to push a new structure on the - stack. If it uses it, *NEW is set to null. */ - -static void -x_fill_composite_glyph_string (s, face_id, stack, new) + stack. If it uses it, *NEW is set to null. OVERLAPS_P non-zero + means S should draw the foreground only, and use its lines physical + height for clipping. */ + +static void +x_fill_composite_glyph_string (s, face_id, stack, new, overlaps_p) struct glyph_string *s; int face_id; struct work **stack, **new; + int overlaps_p; { int i, c; struct work *work; xassert (s && *new && *stack); + s->for_overlaps_p = 1; + /* Pop the work stack. */ work = *stack; *stack = work->next; @@ -3885,14 +3925,17 @@ /* Load glyph string S with a sequence of non-composite characters. FACE_ID is the face id of the string. START is the index of the - first glyph to consider, END is the index of the last + 1. Value - is the index of the first glyph not in S. */ + first glyph to consider, END is the index of the last + 1. + OVERLAPS_P non-zero means S should draw the foreground only, and + use its lines physical height for clipping. + + Value is the index of the first glyph not in S. */ static int -x_fill_glyph_string (s, face_id, start, end) +x_fill_glyph_string (s, face_id, start, end, overlaps_p) struct glyph_string *s; int face_id; - int start, end; + int start, end, overlaps_p; { struct glyph *glyph, *last; int voffset; @@ -3902,6 +3945,7 @@ xassert (s->nchars == 0); xassert (start >= 0 && end > start); + s->for_overlaps_p = overlaps_p, glyph = s->row->glyphs[s->area] + start; last = s->row->glyphs[s->area] + end; voffset = glyph->voffset; @@ -3938,7 +3982,7 @@ /* Adjust base line for subscript/superscript text. */ s->ybase += voffset; - + xassert (s->face && s->face->gc); return glyph - s->row->glyphs[s->area]; } @@ -4102,7 +4146,7 @@ right-most x-position of the drawing area. */ #define BUILD_CHAR_GLYPH_STRINGS(W, ROW, AREA, START, END, HEAD, TAIL, HL, \ - X, LAST_X) \ + X, LAST_X, OVERLAPS_P) \ do \ { \ int c, charset, face_id; \ @@ -4152,7 +4196,7 @@ if (new == NULL) \ new = (struct work *) alloca (sizeof *new); \ x_fill_composite_glyph_string (s, face_id, &stack, \ - &new); \ + &new, OVERLAPS_P); \ } \ \ ++START; \ @@ -4166,7 +4210,8 @@ x_append_glyph_string (&HEAD, &TAIL, s); \ s->charset = charset; \ s->x = (X); \ - START = x_fill_glyph_string (s, face_id, START, END); \ + START = x_fill_glyph_string (s, face_id, START, END, \ + OVERLAPS_P); \ } \ } \ while (0) @@ -4183,7 +4228,7 @@ asynchronously). */ #define BUILD_GLYPH_STRINGS(W, ROW, AREA, START, END, HEAD, TAIL, HL, \ - X, LAST_X) \ + X, LAST_X, OVERLAPS_P) \ do \ { \ HEAD = TAIL = NULL; \ @@ -4194,7 +4239,8 @@ { \ case CHAR_GLYPH: \ BUILD_CHAR_GLYPH_STRINGS (W, ROW, AREA, START, END, HEAD, \ - TAIL, HL, X, LAST_X); \ + TAIL, HL, X, LAST_X, \ + OVERLAPS_P); \ break; \ \ case STRETCH_GLYPH: \ @@ -4235,10 +4281,14 @@ return in *REAL_END the real end position for display. This can be different from END in case overlapping glyphs must be displayed. + If OVERLAPS_P is non-zero, draw only the foreground of characters + and clip to the physical height of ROW. + Value is the x-position reached, relative to AREA of W. */ static int -x_draw_glyphs (w, x, row, area, start, end, hl, real_start, real_end) +x_draw_glyphs (w, x, row, area, start, end, hl, real_start, real_end, + overlaps_p) struct window *w; int x; struct glyph_row *row; @@ -4246,6 +4296,7 @@ int start, end; enum draw_glyphs_face hl; int *real_start, *real_end; + int overlaps_p; { struct glyph_string *head, *tail; struct glyph_string *s; @@ -4299,7 +4350,8 @@ BUILD_GLYPH_STRINGS will modify its start parameter. That's the reason we use a separate variable `i'. */ i = start; - BUILD_GLYPH_STRINGS (w, row, area, i, end, head, tail, hl, x, last_x); + BUILD_GLYPH_STRINGS (w, row, area, i, end, head, tail, hl, x, last_x, + overlaps_p); if (tail) x_reached = tail->x + tail->background_width; else @@ -4308,7 +4360,7 @@ /* If there are any glyphs with lbearing < 0 or rbearing > width in the row, redraw some glyphs in front or following the glyph strings built above. */ - if (row->contains_overlapping_glyphs_p) + if (!overlaps_p && row->contains_overlapping_glyphs_p) { int dummy_x = 0; struct glyph_string *h, *t; @@ -4327,7 +4379,8 @@ { j = i; BUILD_GLYPH_STRINGS (w, row, area, j, start, h, t, - DRAW_NORMAL_TEXT, dummy_x, last_x); + DRAW_NORMAL_TEXT, dummy_x, last_x, + overlaps_p); start = i; if (real_start) *real_start = start; @@ -4346,7 +4399,8 @@ if (i >= 0) { BUILD_GLYPH_STRINGS (w, row, area, i, start, h, t, - DRAW_NORMAL_TEXT, dummy_x, last_x); + DRAW_NORMAL_TEXT, dummy_x, last_x, + overlaps_p); for (s = h; s; s = s->next) s->background_filled_p = 1; if (real_start) @@ -4363,7 +4417,8 @@ if (i >= 0) { BUILD_GLYPH_STRINGS (w, row, area, end, i, h, t, - DRAW_NORMAL_TEXT, x, last_x); + DRAW_NORMAL_TEXT, x, last_x, + overlaps_p); x_compute_overhangs_and_x (h, tail->x + tail->width, 0); x_append_glyph_string_lists (&head, &tail, h, t); if (real_end) @@ -4379,7 +4434,8 @@ if (i >= 0) { BUILD_GLYPH_STRINGS (w, row, area, end, i, h, t, - DRAW_NORMAL_TEXT, x, last_x); + DRAW_NORMAL_TEXT, x, last_x, + overlaps_p); for (s = h; s; s = s->next) s->background_filled_p = 1; x_compute_overhangs_and_x (h, tail->x + tail->width, 0); @@ -4407,6 +4463,56 @@ } +/* Fix the display of area AREA of overlapping row ROW in window W. */ + +static void +x_fix_overlapping_area (w, row, area) + struct window *w; + struct glyph_row *row; + enum glyph_row_area area; +{ + int i, x; + + BLOCK_INPUT; + + if (area == LEFT_MARGIN_AREA) + x = 0; + else if (area == TEXT_AREA) + x = row->x + window_box_width (w, LEFT_MARGIN_AREA); + else + x = (window_box_width (w, LEFT_MARGIN_AREA) + + window_box_width (w, TEXT_AREA)); + + for (i = 0; i < row->used[area];) + { + if (row->glyphs[area][i].overlaps_vertically_p) + { + int start = i, start_x = x; + + do + { + x += row->glyphs[area][i].pixel_width; + ++i; + } + while (i < row->used[area] + && row->glyphs[area][i].overlaps_vertically_p); + + x_draw_glyphs (w, start_x, row, area, start, i, + (row->inverse_p + ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT), + NULL, NULL, 1); + } + else + { + x += row->glyphs[area][i].pixel_width; + ++i; + } + } + + UNBLOCK_INPUT; +} + + /* Output LEN glyphs starting at START at the nominal cursor position. Advance the nominal cursor over the text. The global variable updated_window contains the window being updated, updated_row is @@ -4431,7 +4537,7 @@ hpos, hpos + len, (updated_row->inverse_p ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT), - &real_start, &real_end); + &real_start, &real_end, 0); /* If we drew over the cursor, note that it is not visible any more. */ note_overwritten_text_cursor (updated_window, real_start, @@ -4490,7 +4596,7 @@ /* Write the glyphs. */ hpos = start - row->glyphs[updated_area]; x_draw_glyphs (w, output_cursor.x, row, updated_area, hpos, hpos + len, - DRAW_NORMAL_TEXT, &real_start, &real_end); + DRAW_NORMAL_TEXT, &real_start, &real_end, 0); note_overwritten_text_cursor (w, real_start, real_end - real_start); /* Advance the output cursor. */ @@ -5091,7 +5197,7 @@ first - row->glyphs[area], last - row->glyphs[area], row->inverse_p ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT, - NULL, NULL); + NULL, NULL, 0); } @@ -5109,7 +5215,7 @@ if (row->mode_line_p || w->pseudo_window_p) x_draw_glyphs (w, 0, row, TEXT_AREA, 0, row->used[TEXT_AREA], row->inverse_p ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT, - NULL, NULL); + NULL, NULL, 0); else { if (row->used[LEFT_MARGIN_AREA]) @@ -6583,7 +6689,7 @@ if (end_hpos > start_hpos) x_draw_glyphs (w, start_x, row, updated_area, - start_hpos, end_hpos, draw, NULL, NULL); + start_hpos, end_hpos, draw, NULL, NULL, 0); } /* If we turned the cursor off, turn it back on. */ @@ -9771,8 +9877,25 @@ happen in mini-buffer windows when switching between echo area glyphs and mini-buffer. */ if (w->phys_cursor.hpos < row->used[TEXT_AREA]) - x_draw_glyphs (w, w->phys_cursor.x, row, TEXT_AREA, - w->phys_cursor.hpos, w->phys_cursor.hpos + 1, hl, 0, 0); + { + x_draw_glyphs (w, w->phys_cursor.x, row, TEXT_AREA, + w->phys_cursor.hpos, w->phys_cursor.hpos + 1, + hl, 0, 0, 0); + + /* When we erase the cursor, and ROW is overlapped by other + rows, make sure that these overlapping parts of other rows + are redrawn. */ + if (hl == DRAW_NORMAL_TEXT && row->overlapped_p) + { + if (row > w->current_matrix->rows + && MATRIX_ROW_OVERLAPS_SUCC_P (row - 1)) + x_fix_overlapping_area (w, row - 1, TEXT_AREA); + + if (MATRIX_ROW_BOTTOM_Y (row) < window_text_bottom_y (w) + && MATRIX_ROW_OVERLAPS_PRED_P (row + 1)) + x_fix_overlapping_area (w, row + 1, TEXT_AREA); + } + } } @@ -12619,7 +12742,8 @@ x_update_window_end, XTcursor_to, x_flush, - x_get_glyph_overhangs + x_get_glyph_overhangs, + x_fix_overlapping_area }; void