Reported by: Dave Abrahams <dave <at> boostpro.com>
Date: Tue, 14 Jun 2011 16:06:02 UTC
Severity: important
Found in version 23.3
Done: Chong Yidong <cyd <at> stupidchicken.com>
Bug is archived. No further changes may be made.
View this message in rfc822 format
From: Alp Aker <alptekin.aker <at> gmail.com> To: 8863 <at> debbugs.gnu.org Cc: Dave Abrahams <dave <at> boostpro.com>, Chong Yidong <cyd <at> stupidchicken.com> Subject: bug#8863: [PATCH] bug#8863: 23.3; Strikethrough won't display on MacOS Date: Tue, 26 Jul 2011 15:41:38 -0400
Dave Abrahams wrote: > Thanks for your work on it. Will you apply this to the 23.3 branch as > well as trunk? I'm not a committer, so that will be up to whoever decides to apply the patch. I should note the code below has only been tested on 24.0.50; I suspect it should work as it on 23.3, but haven't tried it. (About the anti-aliasing issue I mentioned before: Whether it's noticeable depends on factors like font metrics and the degree of contrast between background and foreground. I've done everything with exact pixel drawing, so it shouldn't be an issue.) A quick implementation note: This patch implements strike-through and overline face attributes on NS. It also implements underlining for stretch and image glyphs (the existing implementation does underlining only for char and composite char glyphs). It also adds support for the user options underline-minimum-offset, x-use-underline-position-properties, and x-underline-at-descent-line, which are currently ignored on NextStep. Sorry for the delay in posting this. This patch is large enough that I need a copyright assignment, which has taken a few weeks. The signed papers should have arrived as FSF today, so hopefully the way will soon be clear to incorporate this code. 2011-07-26 Alp Aker <alp.tekin.aker <at> gmail.com> Implement strike-through and overline face attributes on NextStep. Extend implemention of underlining to include stretch and image glyphs. Add support for user options underline-minimum-offset, x-use-underline-position-properties, and x-underline-at-descent-line. * nsfont.m (nsfont_open): Use underline position provided by font, instead of hard-coded value of 2. (nsfont_draw): Remove underlining code. 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. === modified file 'src/nsfont.m' --- src/nsfont.m 2011-04-16 03:14:08 +0000 +++ src/nsfont.m 2011-07-25 01:29:36 +0000 @@ -845,7 +845,7 @@ 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 @@ /*[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 @@ 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 @@ 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; } === modified file 'src/nsterm.h' --- src/nsterm.h 2011-07-08 10:04:23 +0000 +++ src/nsterm.h 2011-07-25 01:29:36 +0000 @@ -825,6 +825,13 @@ 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 === modified file 'src/nsterm.m' --- src/nsterm.m 2011-07-23 08:33:06 +0000 +++ src/nsterm.m 2011-07-25 06:33:54 +0000 @@ -263,8 +263,6 @@ 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 @@ 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 @@ char raised_p; NSRect br; struct face *face; + NSColor *tdCol; NSTRACE (ns_dumpglyphs_image); @@ -2882,10 +2982,7 @@ 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 @@ [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 @@ 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; i<n; i++) { if (!s->row->full_width_p) @@ -2998,30 +3131,37 @@ 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; + + x = r[i].origin.x; + width = s->w->phys_cursor_width; + r[i].size.width -= width; + r[i].origin.x += width; + + NSRectFill (r[i]); + + /* 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]); + } + + /* 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_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); - - [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set]; - - NSRectFill (r[0]); - NSRectFill (r[1]); ns_unfocus (s->f); s->background_filled_p = 1; } @@ -6556,23 +6696,17 @@ 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. */);
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.