From 4843aac304884a75581bcc27454cb9fc4353f036 Mon Sep 17 00:00:00 2001 From: Alp Aker Date: Thu, 28 Jul 2011 14:26:29 -0400 Subject: [PATCH] Implement strike-through and overline on NextStep (Bug#8863). * src/nsfont.m (nsfont_open): Use underline position provided by font, instead of hard-coded value of 2. (nsfont_draw): Call ns_draw_text_decoration instead. * src/nsterm.h: Add declaration for ns_draw_text_decoration. * src/nsterm.m (ns_draw_text_decoration): New function for drawing underline, overline, and strike-through. (ns_dumpglyphs_image, ns_dumpglyphs_stretch): Add call to ns_draw_text_decoration. Change treatment of cursor drawing to accomodate underlining, etc. --- src/ChangeLog | 16 +++++ src/nsfont.m | 39 ++-------- src/nsterm.h | 7 ++ src/nsterm.m | 196 ++++++++++++++++++++++++++++++++++++++++++-------- 4 files changed, 195 insertions(+), 63 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index e821b75f4c8..24b36e7ff61 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,19 @@ +2011-07-26 Alp Aker + + Implement strike-through and overline on NextStep (Bug#8863). + + * nsfont.m (nsfont_open): Use underline position provided by font, + instead of hard-coded value of 2. + (nsfont_draw): Call ns_draw_text_decoration instead. + + * nsterm.h: Add declaration for ns_draw_text_decoration. + + * nsterm.m (ns_draw_text_decoration): New function for drawing + underline, overline, and strike-through. + (ns_dumpglyphs_image, ns_dumpglyphs_stretch): Add call to + ns_draw_text_decoration. Change treatment of cursor drawing to + accomodate underlining, etc. + 2011-07-28 Eli Zaretskii * buffer.c (init_buffer_once): Set bidi-display-reordering to t by diff --git a/src/nsfont.m b/src/nsfont.m index 76c70aadf9f..3720e9a4615 100644 --- a/src/nsfont.m +++ b/src/nsfont.m @@ -845,7 +845,7 @@ nsfont_open (FRAME_PTR f, Lisp_Object font_entity, int pixel_size) expand = 0.0; hshrink = 1.0; - font_info->underpos = 2; /*[sfont underlinePosition] is often clipped out */ + font_info->underpos = [sfont underlinePosition]; font_info->underwidth = [sfont underlineThickness]; font_info->size = font->pixel_size; font_info->voffset = lrint (hshrink * [sfont ascender] + expand * hd / 2); @@ -1196,20 +1196,7 @@ nsfont_draw (struct glyph_string *s, int from, int to, int x, int y, /*[context GSSetTextDrawingMode: GSTextFill]; /// not implemented yet */ } - /* do underline */ - if (face->underline_p) - { - if (face->underline_color != 0) - [ns_lookup_indexed_color (face->underline_color, s->f) set]; - else - [col set]; - DPSmoveto (context, r.origin.x, r.origin.y + font->underpos); - DPSlineto (context, r.origin.x+r.size.width, r.origin.y+font->underpos); - if (face->underline_color != 0) - [col set]; - } - else - [col set]; + [col set]; /* draw with DPSxshow () */ DPSmoveto (context, r.origin.x, r.origin.y); @@ -1255,23 +1242,7 @@ nsfont_draw (struct glyph_string *s, int from, int to, int x, int y, CGContextSetTextDrawingMode (gcontext, kCGTextFill); } - if (face->underline_p) - { - if (face->underline_color != 0) - [ns_lookup_indexed_color (face->underline_color, s->f) set]; - else - [col set]; - CGContextBeginPath (gcontext); - CGContextMoveToPoint (gcontext, - r.origin.x, r.origin.y + font->underpos); - CGContextAddLineToPoint (gcontext, r.origin.x + r.size.width, - r.origin.y + font->underpos); - CGContextStrokePath (gcontext); - if (face->underline_color != 0) - [col set]; - } - else - [col set]; + [col set]; CGContextSetTextPosition (gcontext, r.origin.x, r.origin.y); CGContextShowGlyphsWithAdvances (gcontext, s->char2b + s->cmp_from, @@ -1287,6 +1258,10 @@ nsfont_draw (struct glyph_string *s, int from, int to, int x, int y, CGContextRestoreGState (gcontext); } #endif /* NS_IMPL_COCOA */ + + /* Draw underline, overline, strike-through. */ + ns_draw_text_decoration (s, face, col, r.size.width, r.origin.x); + return to-from; } diff --git a/src/nsterm.h b/src/nsterm.h index f419391a11e..227429ed515 100644 --- a/src/nsterm.h +++ b/src/nsterm.h @@ -825,6 +825,13 @@ extern unsigned long ns_get_rgb_color (struct frame *f, float r, float g, float b, float a); extern NSPoint last_mouse_motion_position; +/* From nsterm.m, needed in nsfont.m. */ +#ifdef __OBJC__ +extern void +ns_draw_text_decoration (struct glyph_string *s, struct face *face, + NSColor *defaultCol, CGFloat width, CGFloat x); +#endif + #ifdef NS_IMPL_GNUSTEP extern char gnustep_base_version[]; /* version tracking */ #endif diff --git a/src/nsterm.m b/src/nsterm.m index e45dc1a902d..e9e7dcc0804 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -263,8 +263,6 @@ static void ns_condemn_scroll_bars (struct frame *f); static void ns_judge_scroll_bars (struct frame *f); void x_set_frame_alpha (struct frame *f); -/* FIXME: figure out what to do with underline_minimum_offset. */ - /* ========================================================================== @@ -2597,6 +2595,107 @@ ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr) return n; } +void +ns_draw_text_decoration (struct glyph_string *s, struct face *face, + NSColor *defaultCol, CGFloat width, CGFloat x) +/* -------------------------------------------------------------------------- + Draw underline, overline, and strike-through on glyph string s. + -------------------------------------------------------------------------- */ +{ + if (s->for_overlaps) + return; + + /* Do underline. */ + if (face->underline_p) + { + NSRect r; + unsigned long thickness, position; + + /* If the prev was underlined, match its appearance. */ + if (s->prev && s->prev->face->underline_p + && s->prev->underline_thickness > 0) + { + thickness = s->prev->underline_thickness; + position = s->prev->underline_position; + } + else + { + struct font *font; + unsigned long descent; + + font=s->font; + descent = s->y + s->height - s->ybase; + + /* Use underline thickness of font, defaulting to 1. */ + thickness = (font && font->underline_thickness > 0) + ? font->underline_thickness : 1; + + /* Determine the offset of underlining from the baseline. */ + if (x_underline_at_descent_line) + position = descent - thickness; + else if (x_use_underline_position_properties + && font && font->underline_position >= 0) + position = font->underline_position; + else if (font) + position = lround (font->descent / 2); + else + position = underline_minimum_offset; + + position = max (position, underline_minimum_offset); + + /* Ensure underlining is not cropped. */ + if (descent <= position) + { + position = descent - 1; + thickness = 1; + } + else if (descent < position + thickness) + thickness = 1; + } + + s->underline_thickness = thickness; + s->underline_position = position; + + r = NSMakeRect (x, s->ybase + position, width, thickness); + + if (face->underline_defaulted_p) + [defaultCol set]; + else + [ns_lookup_indexed_color (face->underline_color, s->f) set]; + NSRectFill (r); + } + + /* Do overline. We follow other terms in using a thickness of 1 + and ignoring overline_margin. */ + if (face->overline_p) + { + NSRect r; + r = NSMakeRect (x, s->y, width, 1); + + if (face->overline_color_defaulted_p) + [defaultCol set]; + else + [ns_lookup_indexed_color (face->overline_color, s->f) set]; + NSRectFill (r); + } + + /* Do strike-through. We follow other terms for thickness and + vertical position.*/ + if (face->strike_through_p) + { + NSRect r; + unsigned long dy; + + dy = lrint ((s->height - 1) / 2); + r = NSMakeRect (x, s->y + dy, width, 1); + + if (face->strike_through_color_defaulted_p) + [defaultCol set]; + else + [ns_lookup_indexed_color (face->strike_through_color, s->f) set]; + NSRectFill (r); + } +} static void ns_draw_box (NSRect r, float thickness, NSColor *col, char left_p, char right_p) @@ -2854,6 +2953,7 @@ ns_dumpglyphs_image (struct glyph_string *s, NSRect r) char raised_p; NSRect br; struct face *face; + NSColor *tdCol; NSTRACE (ns_dumpglyphs_image); @@ -2882,10 +2982,7 @@ ns_dumpglyphs_image (struct glyph_string *s, NSRect r) else face = FACE_FROM_ID (s->f, s->first_glyph->face_id); - if (s->hl == DRAW_CURSOR) - [FRAME_CURSOR_COLOR (s->f) set]; - else - [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set]; + [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set]; if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width) @@ -2923,6 +3020,27 @@ ns_dumpglyphs_image (struct glyph_string *s, NSRect r) [img compositeToPoint: NSMakePoint (x, y + s->slice.height) operation: NSCompositeSourceOver]; + if (s->hl == DRAW_CURSOR) + { + [FRAME_CURSOR_COLOR (s->f) set]; + if (s->w->phys_cursor_type == FILLED_BOX_CURSOR) + tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f); + else + /* Currently on NS img->mask is always 0. Since + get_window_cursor_type specifies a hollow box cursor when on + a non-masked image we never reach this clause. But we put it + in in antipication of better support for image masks on + NS. */ + tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f); + } + else + { + tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f); + } + + /* Draw underline, overline, strike-through. */ + ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x); + /* Draw relief, if requested */ if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN) { @@ -2967,12 +3085,27 @@ ns_dumpglyphs_stretch (struct glyph_string *s) NSRect r[2]; int n, i; struct face *face; + NSColor *fgCol, *bgCol; if (!s->background_filled_p) { n = ns_get_glyph_string_clip_rect (s, r); *r = NSMakeRect (s->x, s->y, s->background_width, s->height); + ns_focus (s->f, r, n); + + if (s->hl == DRAW_MOUSE_FACE) + { + face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id); + if (!face) + face = FACE_FROM_ID (s->f, MOUSE_FACE_ID); + } + else + face = FACE_FROM_ID (s->f, s->first_glyph->face_id); + + bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f); + fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f); + for (i=0; irow->full_width_p) @@ -2998,30 +3131,37 @@ ns_dumpglyphs_stretch (struct glyph_string *s) FRAME_PIXEL_WIDTH (s->f)); } + [bgCol set]; + /* NOTE: under NS this is NOT used to draw cursors, but we must avoid overwriting cursor (usually when cursor on a tab) */ if (s->hl == DRAW_CURSOR) { - r[i].origin.x += s->width; - r[i].size.width -= s->width; - } - } + CGFloat x, width; - ns_focus (s->f, r, n); + x = r[i].origin.x; + width = s->w->phys_cursor_width; + r[i].size.width -= width; + r[i].origin.x += width; - if (s->hl == DRAW_MOUSE_FACE) - { - face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id); - if (!face) - face = FACE_FROM_ID (s->f, MOUSE_FACE_ID); - } - else - face = FACE_FROM_ID (s->f, s->first_glyph->face_id); + NSRectFill (r[i]); - [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set]; + /* Draw overlining, etc. on the cursor. */ + if (s->w->phys_cursor_type == FILLED_BOX_CURSOR) + ns_draw_text_decoration (s, face, bgCol, width, x); + else + ns_draw_text_decoration (s, face, fgCol, width, x); + } + else + { + NSRectFill (r[i]); + } - NSRectFill (r[0]); - NSRectFill (r[1]); + /* Draw overlining, etc. on the stretch glyph (or the part + of the stretch glyph after the cursor). */ + ns_draw_text_decoration (s, face, fgCol, r[i].size.width, + r[i].origin.x); + } ns_unfocus (s->f); s->background_filled_p = 1; } @@ -6556,23 +6696,17 @@ Only works on OSX 10.6 or later. */); Vx_toolkit_scroll_bars = Qnil; #endif - /* these are unsupported but we need the declarations to avoid whining - messages from cus-start.el */ DEFVAR_BOOL ("x-use-underline-position-properties", x_use_underline_position_properties, - doc: /* NOT SUPPORTED UNDER NS. -*Non-nil means make use of UNDERLINE_POSITION font properties. + doc: /*Non-nil means make use of UNDERLINE_POSITION font properties. A value of nil means ignore them. If you encounter fonts with bogus UNDERLINE_POSITION font properties, for example 7x13 on XFree prior -to 4.1, set this to nil. - -NOTE: Not supported on Mac yet. */); +to 4.1, set this to nil. */); x_use_underline_position_properties = 0; DEFVAR_BOOL ("x-underline-at-descent-line", x_underline_at_descent_line, - doc: /* NOT SUPPORTED UNDER NS. -*Non-nil means to draw the underline at the same place as the descent line. + doc: /* Non-nil means to draw the underline at the same place as the descent line. A value of nil means to draw the underline according to the value of the variable `x-use-underline-position-properties', which is usually at the baseline level. The default value is nil. */); -- 2.39.2