diff options
-rw-r--r-- | src/composite.c | 6 | ||||
-rw-r--r-- | src/dispextern.h | 8 | ||||
-rw-r--r-- | src/font.c | 7 | ||||
-rw-r--r-- | src/nsterm.m | 9 | ||||
-rw-r--r-- | src/w32font.c | 25 | ||||
-rw-r--r-- | src/w32term.c | 12 | ||||
-rw-r--r-- | src/xdisp.c | 210 | ||||
-rw-r--r-- | src/xftfont.c | 22 | ||||
-rw-r--r-- | src/xterm.c | 10 |
9 files changed, 274 insertions, 35 deletions
diff --git a/src/composite.c b/src/composite.c index 1c9c62bf910..1c18165599d 100644 --- a/src/composite.c +++ b/src/composite.c @@ -732,9 +732,11 @@ composition_gstring_width (Lisp_Object gstring, ptrdiff_t from, ptrdiff_t to, if (FONT_OBJECT_P (font_object)) { struct font *font = XFONT_OBJECT (font_object); + int font_ascent, font_descent; - metrics->ascent = font->ascent; - metrics->descent = font->descent; + get_font_ascent_descent (font, &font_ascent, &font_descent); + metrics->ascent = font_ascent; + metrics->descent = font_descent; } else { diff --git a/src/dispextern.h b/src/dispextern.h index d9d4d2300fa..5202142313a 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -1526,6 +1526,12 @@ struct glyph_string + (FRAME_LINE_HEIGHT ((F)) > FONT_HEIGHT ((FONT)))) / 2 \ - (FONT_DESCENT (FRAME_FONT (F)) - FRAME_BASELINE_OFFSET (F))) +/* A heuristic test for fonts that claim they need a preposterously + large vertical space. The heuristics is in the factor of 3. We + ignore the ascent and descent values reported by such fonts, and + instead go by the values reported for individual glyphs. */ +#define FONT_TOO_HIGH(ft) ((ft)->ascent + (ft)->descent > 3*(ft)->pixel_size) + /*********************************************************************** Faces @@ -3240,6 +3246,8 @@ extern ptrdiff_t compute_display_string_end (ptrdiff_t, extern void produce_stretch_glyph (struct it *); extern int merge_glyphless_glyph_face (struct it *); +extern void get_font_ascent_descent (struct font *, int *, int *); + #ifdef HAVE_WINDOW_SYSTEM #ifdef GLYPH_DEBUG diff --git a/src/font.c b/src/font.c index 1405d437241..556f32bb432 100644 --- a/src/font.c +++ b/src/font.c @@ -2908,7 +2908,12 @@ font_open_entity (struct frame *f, Lisp_Object entity, int pixel_size) : font->average_width ? font->average_width : font->space_width ? font->space_width : 1); - height = (font->height ? font->height : 1); + + int font_ascent, font_descent; + get_font_ascent_descent (font, &font_ascent, &font_descent); + height = font_ascent + font_descent; + if (height <= 0) + height = 1; #ifdef HAVE_WINDOW_SYSTEM FRAME_DISPLAY_INFO (f)->n_fonts++; if (FRAME_DISPLAY_INFO (f)->n_fonts == 1) diff --git a/src/nsterm.m b/src/nsterm.m index 67a03898d13..2806f31155d 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -2928,6 +2928,11 @@ ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p) { int box_line_width = max (s->face->box_line_width, 0); if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width + /* When xdisp.c ignores FONT_HEIGHT, we cannot trust font + dimensions, since the actual glyphs might be much + smaller. So in that case we always clear the rectangle + with background color. */ + || FONT_TOO_HIGH (s->font) || s->font_not_found_p || s->extends_to_end_of_line_p || force_p) { struct face *face; @@ -7687,6 +7692,7 @@ x_new_font (struct frame *f, Lisp_Object font_object, int fontset) { struct font *font = XFONT_OBJECT (font_object); EmacsView *view = FRAME_NS_VIEW (f); + int font_ascent, font_descent; if (fontset < 0) fontset = fontset_from_font (font_object); @@ -7701,7 +7707,8 @@ x_new_font (struct frame *f, Lisp_Object font_object, int fontset) FRAME_BASELINE_OFFSET (f) = font->baseline_offset; FRAME_COLUMN_WIDTH (f) = font->average_width; - FRAME_LINE_HEIGHT (f) = font->height; + get_font_ascent_descent (font, &font_ascent, &font_descent); + FRAME_LINE_HEIGHT (f) = font_ascent + font_descent; /* Compute the scroll bar width in character columns. */ if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0) diff --git a/src/w32font.c b/src/w32font.c index 6306a8460e7..1c2f9665037 100644 --- a/src/w32font.c +++ b/src/w32font.c @@ -650,12 +650,31 @@ w32font_draw (struct glyph_string *s, int from, int to, HBRUSH brush; RECT rect; struct font *font = s->font; - + int ascent = font->ascent, descent = font->descent; + + /* Font's global ascent and descent values might be + preposterously large for some fonts. We fix here the case + when those fonts are used for display of glyphless + characters, because drawing background with font dimensions + in those cases makes the display illegible. There's only one + more call to the draw method with with_background set to + true, and that's in x_draw_glyph_string_foreground, when + drawing the cursor, where we have no such heuristics + available. FIXME. */ + if (s->first_glyph->type == GLYPHLESS_GLYPH + && (s->first_glyph->u.glyphless.method == GLYPHLESS_DISPLAY_HEX_CODE + || s->first_glyph->u.glyphless.method == GLYPHLESS_DISPLAY_ACRONYM)) + { + ascent = + s->first_glyph->slice.glyphless.lower_yoff + - s->first_glyph->slice.glyphless.upper_yoff; + descent = 0; + } brush = CreateSolidBrush (s->gc->background); rect.left = x; - rect.top = y - font->ascent; + rect.top = y - ascent; rect.right = x + s->width; - rect.bottom = y + font->descent; + rect.bottom = y + descent; FillRect (s->hdc, &rect, brush); DeleteObject (brush); } diff --git a/src/w32term.c b/src/w32term.c index 0bc2e980214..b7c6e13c8a8 100644 --- a/src/w32term.c +++ b/src/w32term.c @@ -1218,7 +1218,12 @@ x_draw_glyph_string_background (struct glyph_string *s, bool force_p) } else #endif - if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width + if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width + /* When xdisp.c ignores FONT_HEIGHT, we cannot trust + font dimensions, since the actual glyphs might be + much smaller. So in that case we always clear the + rectangle with background color. */ + || FONT_TOO_HIGH (s->font) || s->font_not_found_p || s->extends_to_end_of_line_p || force_p) @@ -5827,7 +5832,7 @@ Lisp_Object x_new_font (struct frame *f, Lisp_Object font_object, int fontset) { struct font *font = XFONT_OBJECT (font_object); - int unit; + int unit, font_ascent, font_descent; if (fontset < 0) fontset = fontset_from_font (font_object); @@ -5840,7 +5845,8 @@ x_new_font (struct frame *f, Lisp_Object font_object, int fontset) FRAME_FONT (f) = font; FRAME_BASELINE_OFFSET (f) = font->baseline_offset; FRAME_COLUMN_WIDTH (f) = unit = font->average_width; - FRAME_LINE_HEIGHT (f) = font->height; + get_font_ascent_descent (font, &font_ascent, &font_descent); + FRAME_LINE_HEIGHT (f) = font_ascent + font_descent; /* Compute number of scrollbar columns. */ unit = FRAME_COLUMN_WIDTH (f); diff --git a/src/xdisp.c b/src/xdisp.c index 05862d276ef..14385fa8421 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -833,6 +833,9 @@ static void x_draw_bottom_divider (struct window *w); static void notice_overwritten_cursor (struct window *, enum glyph_row_area, int, int, int, int); +static int normal_char_height (struct font *, int); +static void normal_char_ascent_descent (struct font *, int, int *, int *); + static void append_stretch_glyph (struct it *, Lisp_Object, int, int, int); @@ -1761,7 +1764,7 @@ estimate_mode_line_height (struct frame *f, enum face_id face_id) if (face) { if (face->font) - height = FONT_HEIGHT (face->font); + height = normal_char_height (face->font, -1); if (face->box_line_width > 0) height += 2 * face->box_line_width; } @@ -2150,7 +2153,7 @@ get_phys_cursor_geometry (struct window *w, struct glyph_row *row, struct glyph *glyph, int *xp, int *yp, int *heightp) { struct frame *f = XFRAME (WINDOW_FRAME (w)); - int x, y, wd, h, h0, y0; + int x, y, wd, h, h0, y0, ascent; /* Compute the width of the rectangle to draw. If on a stretch glyph, and `x-stretch-block-cursor' is nil, don't draw a @@ -2170,13 +2173,21 @@ get_phys_cursor_geometry (struct window *w, struct glyph_row *row, wd = min (FRAME_COLUMN_WIDTH (f), wd); w->phys_cursor_width = wd; - y = w->phys_cursor.y + row->ascent - glyph->ascent; + /* Don't let the hollow cursor glyph descend below the glyph row's + ascent value, lest the hollow cursor looks funny. */ + y = w->phys_cursor.y; + ascent = row->ascent; + if (row->ascent < glyph->ascent) + { + y =- glyph->ascent - row->ascent; + ascent = glyph->ascent; + } /* If y is below window bottom, ensure that we still see a cursor. */ h0 = min (FRAME_LINE_HEIGHT (f), row->visible_height); - h = max (h0, glyph->ascent + glyph->descent); - h0 = min (h0, glyph->ascent + glyph->descent); + h = max (h0, ascent + glyph->descent); + h0 = min (h0, ascent + glyph->descent); y0 = WINDOW_HEADER_LINE_HEIGHT (w); if (y < y0) @@ -4880,7 +4891,7 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object, { struct face *face = FACE_FROM_ID (it->f, it->face_id); it->voffset = - (XFLOATINT (value) - * (FONT_HEIGHT (face->font))); + * (normal_char_height (face->font, -1))); } #endif /* HAVE_WINDOW_SYSTEM */ } @@ -19157,6 +19168,7 @@ append_space_for_newline (struct it *it, bool default_face_p) struct text_pos saved_pos; Lisp_Object saved_object; struct face *face; + struct glyph *g; saved_object = it->object; saved_pos = it->position; @@ -19188,6 +19200,23 @@ append_space_for_newline (struct it *it, bool default_face_p) PRODUCE_GLYPHS (it); + /* Make sure this space glyph has the right ascent and + descent values, or else cursor at end of line will look + funny. */ + g = it->glyph_row->glyphs[TEXT_AREA] + n; + struct font *font = face->font ? face->font : FRAME_FONT (it->f); + if (n == 0 || it->glyph_row->height < font->pixel_size) + { + normal_char_ascent_descent (font, -1, &it->ascent, &it->descent); + it->max_ascent = it->ascent; + it->max_descent = it->descent; + /* Make sure compute_line_metrics recomputes the row height. */ + it->glyph_row->height = 0; + } + + g->ascent = it->max_ascent; + g->descent = it->max_descent; + it->override_ascent = -1; it->constrain_row_ascent_descent_p = false; it->current_x = saved_x; @@ -23900,9 +23929,13 @@ calc_pixel_width_or_height (double *res, struct it *it, Lisp_Object prop, #ifdef HAVE_WINDOW_SYSTEM if (EQ (prop, Qheight)) - return OK_PIXELS (font ? FONT_HEIGHT (font) : FRAME_LINE_HEIGHT (it->f)); + return OK_PIXELS (font + ? normal_char_height (font, -1) + : FRAME_LINE_HEIGHT (it->f)); if (EQ (prop, Qwidth)) - return OK_PIXELS (font ? FONT_WIDTH (font) : FRAME_COLUMN_WIDTH (it->f)); + return OK_PIXELS (font + ? FONT_WIDTH (font) + : FRAME_COLUMN_WIDTH (it->f)); #else if (EQ (prop, Qheight) || EQ (prop, Qwidth)) return OK_PIXELS (1); @@ -24032,6 +24065,17 @@ calc_pixel_width_or_height (double *res, struct it *it, Lisp_Object prop, return false; } +void +get_font_ascent_descent (struct font *font, int *ascent, int *descent) +{ +#ifdef HAVE_WINDOW_SYSTEM + normal_char_ascent_descent (font, -1, ascent, descent); +#else + *ascent = 1; + *descent = 0; +#endif +} + /*********************************************************************** Glyph Display @@ -24536,6 +24580,55 @@ get_per_char_metric (struct font *font, XChar2b *char2b) return &metrics; } +/* A subroutine that computes "normal" values of ASCENT and DESCENT + for FONT. Values are taken from font-global ones, except for fonts + that claim preposterously large values, but whose glyphs actually + have reasonable dimensions. C is the character to use for metrics + if the font-global values are too large; if C is negative, the + function selects a default character. */ +static void +normal_char_ascent_descent (struct font *font, int c, int *ascent, int *descent) +{ + *ascent = FONT_BASE (font); + *descent = FONT_DESCENT (font); + + if (FONT_TOO_HIGH (font)) + { + XChar2b char2b; + + /* Get metrics of C, defaulting to a reasonably sized ASCII + character. */ + if (get_char_glyph_code (c >= 0 ? c : '{', font, &char2b)) + { + struct font_metrics *pcm = get_per_char_metric (font, &char2b); + + if (!(pcm->width == 0 && pcm->rbearing == 0 && pcm->lbearing == 0)) + { + /* We add 1 pixel to character dimensions as heuristics + that produces nicer display, e.g. when the face has + the box attribute. */ + *ascent = pcm->ascent + 1; + *descent = pcm->descent + 1; + } + } + } +} + +/* A subroutine that computes a reasonable "normal character height" + for fonts that claim preposterously large vertical dimensions, but + whose glyphs are actually reasonably sized. C is the charcater + whose metrics to use for those fonts, or -1 for default + character. */ +static int +normal_char_height (struct font *font, int c) +{ + int ascent, descent; + + normal_char_ascent_descent (font, c, &ascent, &descent); + + return ascent + descent; +} + /* EXPORT for RIF: Set *LEFT and *RIGHT to the left and right overhang of GLYPH on frame F. Overhangs of glyphs other than type CHAR_GLYPH are @@ -25835,6 +25928,8 @@ produce_stretch_glyph (struct it *it) /* Compute height. */ if (FRAME_WINDOW_P (it->f)) { + int default_height = normal_char_height (font, ' '); + if ((prop = Fplist_get (plist, QCheight), !NILP (prop)) && calc_pixel_width_or_height (&tem, it, prop, font, false, 0)) { @@ -25843,9 +25938,9 @@ produce_stretch_glyph (struct it *it) } else if (prop = Fplist_get (plist, QCrelative_height), NUMVAL (prop) > 0) - height = FONT_HEIGHT (font) * NUMVAL (prop); + height = default_height * NUMVAL (prop); else - height = FONT_HEIGHT (font); + height = default_height; if (height <= 0 && (height < 0 || !zero_height_ok_p)) height = 1; @@ -26069,8 +26164,7 @@ calc_line_height_property (struct it *it, Lisp_Object val, struct font *font, boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff; } - ascent = FONT_BASE (font) + boff; - descent = FONT_DESCENT (font) - boff; + normal_char_ascent_descent (font, -1, &ascent, &descent); if (override) { @@ -26196,8 +26290,9 @@ produce_glyphless_glyph (struct it *it, bool for_no_font, Lisp_Object acronym) ASCII face. */ face = FACE_FROM_ID (it->f, it->face_id)->ascii_face; font = face->font ? face->font : FRAME_FONT (it->f); - it->ascent = FONT_BASE (font) + font->baseline_offset; - it->descent = FONT_DESCENT (font) - font->baseline_offset; + normal_char_ascent_descent (font, -1, &it->ascent, &it->descent); + it->ascent += font->baseline_offset; + it->descent -= font->baseline_offset; base_height = it->ascent + it->descent; base_width = font->average_width; @@ -26384,6 +26479,22 @@ x_produce_glyphs (struct it *it) it->phys_ascent = pcm->ascent + boff; it->phys_descent = pcm->descent - boff; it->pixel_width = pcm->width; + /* Don't use font-global values for ascent and descent + if they result in an exceedingly large line height. */ + if (it->override_ascent < 0) + { + if (FONT_TOO_HIGH (font)) + { + it->ascent = it->phys_ascent; + it->descent = it->phys_descent; + /* These limitations are enforced by an + assertion near the end of this function. */ + if (it->ascent < 0) + it->ascent = 0; + if (it->descent < 0) + it->descent = 0; + } + } } else { @@ -26511,8 +26622,18 @@ x_produce_glyphs (struct it *it) } else { - it->ascent = FONT_BASE (font) + boff; - it->descent = FONT_DESCENT (font) - boff; + if (FONT_TOO_HIGH (font)) + { + it->ascent = font->pixel_size + boff - 1; + it->descent = -boff + 1; + if (it->descent < 0) + it->descent = 0; + } + else + { + it->ascent = FONT_BASE (font) + boff; + it->descent = FONT_DESCENT (font) - boff; + } } if (EQ (height, Qt)) @@ -26583,8 +26704,38 @@ x_produce_glyphs (struct it *it) it->pixel_width = next_tab_x - x; it->nglyphs = 1; - it->ascent = it->phys_ascent = FONT_BASE (font) + boff; - it->descent = it->phys_descent = FONT_DESCENT (font) - boff; + if (FONT_TOO_HIGH (font)) + { + if (get_char_glyph_code (' ', font, &char2b)) + { + pcm = get_per_char_metric (font, &char2b); + if (pcm->width == 0 + && pcm->rbearing == 0 && pcm->lbearing == 0) + pcm = NULL; + } + + if (pcm) + { + it->ascent = pcm->ascent + boff; + it->descent = pcm->descent - boff; + } + else + { + it->ascent = font->pixel_size + boff - 1; + it->descent = -boff + 1; + } + if (it->ascent < 0) + it->ascent = 0; + if (it->descent < 0) + it->descent = 0; + } + else + { + it->ascent = FONT_BASE (font) + boff; + it->descent = FONT_DESCENT (font) - boff; + } + it->phys_ascent = it->ascent; + it->phys_descent = it->descent; if (it->glyph_row) { @@ -26598,6 +26749,22 @@ x_produce_glyphs (struct it *it) it->nglyphs = 1; } } + + if (FONT_TOO_HIGH (font)) + { + int font_ascent, font_descent; + + /* For very large fonts, where we ignore the declared font + dimensions, and go by per-character metrics instead, + don't let the row ascent and descent values (and the row + height computed from them) be smaller than the "normal" + character metrics. This avoids unpleasant effects + whereby lines on display would change their heigh + depending on which characters are shown. */ + normal_char_ascent_descent (font, -1, &font_ascent, &font_descent); + it->max_ascent = max (it->max_ascent, font_ascent); + it->max_descent = max (it->max_descent, font_descent); + } } else if (it->what == IT_COMPOSITION && it->cmp_it.ch < 0) { @@ -26664,9 +26831,10 @@ x_produce_glyphs (struct it *it) boff = font->baseline_offset; if (font->vertical_centering) boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff; - font_ascent = FONT_BASE (font) + boff; - font_descent = FONT_DESCENT (font) - boff; - font_height = FONT_HEIGHT (font); + normal_char_ascent_descent (font, -1, &font_ascent, &font_descent); + font_ascent += boff; + font_descent -= boff; + font_height = font_ascent + font_descent; cmp->font = font; diff --git a/src/xftfont.c b/src/xftfont.c index 0e8b876f1d3..a1846e8d461 100644 --- a/src/xftfont.c +++ b/src/xftfont.c @@ -617,8 +617,26 @@ xftfont_draw (struct glyph_string *s, int from, int to, int x, int y, XftDrawSetClip (xft_draw, NULL); if (with_background) - XftDrawRect (xft_draw, &bg, - x, y - s->font->ascent, s->width, s->font->height); + { + int height = FONT_HEIGHT (s->font), ascent = FONT_BASE (s->font); + + /* Font's global height and ascent values might be + preposterously large for some fonts. We fix here the case + when those fonts are used for display of glyphless + characters, because drawing background with font dimensions + in those cases makes the display illegible. There's only one + more call to the draw method with with_background set to + true, and that's in x_draw_glyph_string_foreground, when + drawing the cursor, where we have no such heuristics + available. FIXME. */ + if (s->first_glyph->type == GLYPHLESS_GLYPH + && (s->first_glyph->u.glyphless.method == GLYPHLESS_DISPLAY_HEX_CODE + || s->first_glyph->u.glyphless.method == GLYPHLESS_DISPLAY_ACRONYM)) + height = ascent = + s->first_glyph->slice.glyphless.lower_yoff + - s->first_glyph->slice.glyphless.upper_yoff; + XftDrawRect (xft_draw, &bg, x, y - ascent, s->width, height); + } code = alloca (sizeof (FT_UInt) * len); for (i = 0; i < len; i++) code[i] = ((XCHAR2B_BYTE1 (s->char2b + from + i) << 8) diff --git a/src/xterm.c b/src/xterm.c index 691ede58b43..4d7945059fe 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -1724,6 +1724,11 @@ x_draw_glyph_string_background (struct glyph_string *s, bool force_p) s->background_filled_p = true; } else if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width + /* When xdisp.c ignores FONT_HEIGHT, we cannot trust + font dimensions, since the actual glyphs might be + much smaller. So in that case we always clear the + rectangle with background color. */ + || FONT_TOO_HIGH (s->font) || s->font_not_found_p || s->extends_to_end_of_line_p || force_p) @@ -9405,7 +9410,7 @@ Lisp_Object x_new_font (struct frame *f, Lisp_Object font_object, int fontset) { struct font *font = XFONT_OBJECT (font_object); - int unit; + int unit, font_ascent, font_descent; if (fontset < 0) fontset = fontset_from_font (font_object); @@ -9418,7 +9423,8 @@ x_new_font (struct frame *f, Lisp_Object font_object, int fontset) FRAME_FONT (f) = font; FRAME_BASELINE_OFFSET (f) = font->baseline_offset; FRAME_COLUMN_WIDTH (f) = font->average_width; - FRAME_LINE_HEIGHT (f) = FONT_HEIGHT (font); + get_font_ascent_descent (font, &font_ascent, &font_descent); + FRAME_LINE_HEIGHT (f) = font_ascent + font_descent; #ifndef USE_X_TOOLKIT FRAME_MENU_BAR_HEIGHT (f) = FRAME_MENU_BAR_LINES (f) * FRAME_LINE_HEIGHT (f); |