aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Third2019-02-10 10:59:29 +0000
committerAlan Third2019-12-30 11:22:17 +0000
commit53f3d1f9f41e291f50977bbcff1d43416972208e (patch)
tree302db920b0cc9f5bab9b18e55e6daffab9cb13e3
parentf01286675ad7ff520138ca2a42a9bf3a45740b54 (diff)
downloademacs-scratch/ns/draw-to-bitmap.tar.gz
emacs-scratch/ns/draw-to-bitmap.zip
Draw to offscreen buffer on macOSscratch/ns/draw-to-bitmap
* src/nsfns.m (x_set_background_color): Clear the frame after changing the background color, not before. * src/nsterm.h (drawingBuffer): New variable. ([EmacsView focusOnDrawingBuffer]): ([EmacsView copyRect:to:]): ([EmacsView createDrawingBufferWithRect:]): New methods. * src/nsterm.m (ns_update_begin): (ns_update_end): (ns_focus): (ns_unfocus): Handle drawing to offscreen buffer. (ns_clip_to_row): Use ns_row_rect. (ns_copy_bits): Remove unused function. (ns_scroll_run): (ns_shift_glyphs_for_insert): Use new scrolling method. (ns_draw_fringe_bitmap): (ns_dumpglyphs_image): When drawing to the offscreen buffer, flip images so they appear the right way up. (ns_dumpglyphs_stretch): Remove unnecessary code. (ns_draw_window_cursor): Don't disable screen updates. ([EmacsView updateFrameSize:]): Update the size of the offscreen buffer. ([EmacsView initFrameFromEmacs:]): Create offscreen buffer. ([EmacsView windowDidChangeBackingProperties:]): ([EmacsView createDrawingBufferWithRect:]): ([EmacsView focusOnDrawingBuffer]): ([EmacsView copyRect]): New methods. ([EmacsView viewWillDraw]): Remove method as it no longer does anything useful. ([EmacsView drawRect:]): Handle drawing from offscreen buffer.
-rw-r--r--src/nsfns.m11
-rw-r--r--src/nsterm.h11
-rw-r--r--src/nsterm.m478
3 files changed, 248 insertions, 252 deletions
diff --git a/src/nsfns.m b/src/nsfns.m
index 3e835a71d03..4ae73de6754 100644
--- a/src/nsfns.m
+++ b/src/nsfns.m
@@ -287,12 +287,6 @@ ns_set_background_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
287 error ("Unknown color"); 287 error ("Unknown color");
288 } 288 }
289 289
290 /* Clear the frame; in some instances the NS-internal GC appears not
291 to update, or it does update and cannot clear old text
292 properly. */
293 if (FRAME_VISIBLE_P (f))
294 ns_clear_frame (f);
295
296 [col retain]; 290 [col retain];
297 [f->output_data.ns->background_color release]; 291 [f->output_data.ns->background_color release];
298 f->output_data.ns->background_color = col; 292 f->output_data.ns->background_color = col;
@@ -324,7 +318,10 @@ ns_set_background_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
324 } 318 }
325 319
326 if (FRAME_VISIBLE_P (f)) 320 if (FRAME_VISIBLE_P (f))
327 SET_FRAME_GARBAGED (f); 321 {
322 SET_FRAME_GARBAGED (f);
323 ns_clear_frame (f);
324 }
328 } 325 }
329 unblock_input (); 326 unblock_input ();
330} 327}
diff --git a/src/nsterm.h b/src/nsterm.h
index 3803009afa6..e9394e184fd 100644
--- a/src/nsterm.h
+++ b/src/nsterm.h
@@ -417,6 +417,9 @@ typedef id instancetype;
417 int maximized_width, maximized_height; 417 int maximized_width, maximized_height;
418 NSWindow *nonfs_window; 418 NSWindow *nonfs_window;
419 BOOL fs_is_native; 419 BOOL fs_is_native;
420#ifdef NS_IMPL_COCOA
421 NSBitmapImageRep *drawingBuffer;
422#endif
420@public 423@public
421 struct frame *emacsframe; 424 struct frame *emacsframe;
422 int rows, cols; 425 int rows, cols;
@@ -457,7 +460,13 @@ typedef id instancetype;
457#endif 460#endif
458- (int)fullscreenState; 461- (int)fullscreenState;
459 462
460/* Non-notification versions of NSView methods. Used for direct calls. */ 463#ifdef NS_IMPL_COCOA
464- (void)focusOnDrawingBuffer;
465#endif
466- (void)copyRect:(NSRect)srcRect to:(NSRect)dstRect;
467- (void)createDrawingBufferWithRect:(NSRect)rect;
468
469/* Non-notification versions of NSView methods. Used for direct calls. */
461- (void)windowWillEnterFullScreen; 470- (void)windowWillEnterFullScreen;
462- (void)windowDidEnterFullScreen; 471- (void)windowDidEnterFullScreen;
463- (void)windowWillExitFullScreen; 472- (void)windowWillExitFullScreen;
diff --git a/src/nsterm.m b/src/nsterm.m
index 2d76a260d8d..e643707394b 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -290,9 +290,6 @@ long context_menu_value = 0;
290static struct frame *ns_updating_frame; 290static struct frame *ns_updating_frame;
291static NSView *focus_view = NULL; 291static NSView *focus_view = NULL;
292static int ns_window_num = 0; 292static int ns_window_num = 0;
293#ifdef NS_IMPL_GNUSTEP
294static NSRect uRect; // TODO: This is dead, remove it?
295#endif
296static BOOL gsaved = NO; 293static BOOL gsaved = NO;
297static BOOL ns_fake_keydown = NO; 294static BOOL ns_fake_keydown = NO;
298#ifdef NS_IMPL_COCOA 295#ifdef NS_IMPL_COCOA
@@ -1120,33 +1117,10 @@ ns_update_begin (struct frame *f)
1120#endif 1117#endif
1121 1118
1122 ns_updating_frame = f; 1119 ns_updating_frame = f;
1123 [view lockFocus];
1124
1125 /* drawRect may have been called for say the minibuffer, and then clip path
1126 is for the minibuffer. But the display engine may draw more because
1127 we have set the frame as garbaged. So reset clip path to the whole
1128 view. */
1129#ifdef NS_IMPL_COCOA 1120#ifdef NS_IMPL_COCOA
1130 { 1121 [view focusOnDrawingBuffer];
1131 NSBezierPath *bp; 1122#else
1132 NSRect r = [view frame]; 1123 [view lockFocus];
1133 NSRect cr = [[view window] frame];
1134 /* If a large frame size is set, r may be larger than the window frame
1135 before constrained. In that case don't change the clip path, as we
1136 will clear in to the tool bar and title bar. */
1137 if (r.size.height
1138 + FRAME_NS_TITLEBAR_HEIGHT (f)
1139 + FRAME_TOOLBAR_HEIGHT (f) <= cr.size.height)
1140 {
1141 bp = [[NSBezierPath bezierPathWithRect: r] retain];
1142 [bp setClip];
1143 [bp release];
1144 }
1145 }
1146#endif
1147
1148#ifdef NS_IMPL_GNUSTEP
1149 uRect = NSMakeRect (0, 0, 0, 0);
1150#endif 1124#endif
1151} 1125}
1152 1126
@@ -1165,12 +1139,17 @@ ns_update_end (struct frame *f)
1165/* if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */ 1139/* if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
1166 MOUSE_HL_INFO (f)->mouse_face_defer = 0; 1140 MOUSE_HL_INFO (f)->mouse_face_defer = 0;
1167 1141
1142#ifdef NS_IMPL_COCOA
1143 [NSGraphicsContext setCurrentContext:nil];
1144 [view display];
1145#else
1168 block_input (); 1146 block_input ();
1169 1147
1170 [view unlockFocus]; 1148 [view unlockFocus];
1171 [[view window] flushWindow]; 1149 [[view window] flushWindow];
1172 1150
1173 unblock_input (); 1151 unblock_input ();
1152#endif
1174 ns_updating_frame = NULL; 1153 ns_updating_frame = NULL;
1175} 1154}
1176 1155
@@ -1185,6 +1164,8 @@ ns_focus (struct frame *f, NSRect *r, int n)
1185 the entire window. 1164 the entire window.
1186 -------------------------------------------------------------------------- */ 1165 -------------------------------------------------------------------------- */
1187{ 1166{
1167 EmacsView *view = FRAME_NS_VIEW (f);
1168
1188 NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_focus"); 1169 NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_focus");
1189 if (r != NULL) 1170 if (r != NULL)
1190 { 1171 {
@@ -1192,27 +1173,34 @@ ns_focus (struct frame *f, NSRect *r, int n)
1192 } 1173 }
1193 1174
1194 if (f != ns_updating_frame) 1175 if (f != ns_updating_frame)
1176#ifdef NS_IMPL_COCOA
1177 [view focusOnDrawingBuffer];
1178#else
1195 { 1179 {
1196 NSView *view = FRAME_NS_VIEW (f);
1197 if (view != focus_view) 1180 if (view != focus_view)
1198 { 1181 {
1199 if (focus_view != NULL) 1182 if (focus_view != NULL)
1200 { 1183 {
1201 [focus_view unlockFocus]; 1184 [focus_view unlockFocus];
1202 [[focus_view window] flushWindow]; 1185 [[focus_view window] flushWindow];
1203/*debug_lock--; */
1204 } 1186 }
1205 1187
1206 if (view) 1188 if (view)
1207 [view lockFocus]; 1189 [view lockFocus];
1208 focus_view = view; 1190 focus_view = view;
1209/*if (view) debug_lock++; */
1210 } 1191 }
1211 } 1192 }
1193#endif
1212 1194
1213 /* clipping */ 1195 /* clipping */
1214 if (r) 1196 if (r)
1215 { 1197 {
1198#ifdef NS_IMPL_COCOA
1199 int i;
1200 for (i = 0 ; i < n ; i++)
1201 [view setNeedsDisplayInRect:r[i]];
1202#endif
1203
1216 [[NSGraphicsContext currentContext] saveGraphicsState]; 1204 [[NSGraphicsContext currentContext] saveGraphicsState];
1217 if (n == 2) 1205 if (n == 2)
1218 NSRectClipList (r, 2); 1206 NSRectClipList (r, 2);
@@ -1237,6 +1225,7 @@ ns_unfocus (struct frame *f)
1237 gsaved = NO; 1225 gsaved = NO;
1238 } 1226 }
1239 1227
1228#ifdef NS_IMPL_GNUSTEP
1240 if (f != ns_updating_frame) 1229 if (f != ns_updating_frame)
1241 { 1230 {
1242 if (focus_view != NULL) 1231 if (focus_view != NULL)
@@ -1244,9 +1233,9 @@ ns_unfocus (struct frame *f)
1244 [focus_view unlockFocus]; 1233 [focus_view unlockFocus];
1245 [[focus_view window] flushWindow]; 1234 [[focus_view window] flushWindow];
1246 focus_view = NULL; 1235 focus_view = NULL;
1247/*debug_lock--; */
1248 } 1236 }
1249 } 1237 }
1238#endif
1250} 1239}
1251 1240
1252 1241
@@ -1258,16 +1247,7 @@ ns_clip_to_row (struct window *w, struct glyph_row *row,
1258 -------------------------------------------------------------------------- */ 1247 -------------------------------------------------------------------------- */
1259{ 1248{
1260 struct frame *f = XFRAME (WINDOW_FRAME (w)); 1249 struct frame *f = XFRAME (WINDOW_FRAME (w));
1261 NSRect clip_rect; 1250 NSRect clip_rect = ns_row_rect (w, row, area);
1262 int window_x, window_y, window_width;
1263
1264 window_box (w, area, &window_x, &window_y, &window_width, 0);
1265
1266 clip_rect.origin.x = window_x;
1267 clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
1268 clip_rect.origin.y = max (clip_rect.origin.y, window_y);
1269 clip_rect.size.width = window_width;
1270 clip_rect.size.height = row->visible_height;
1271 1251
1272 ns_focus (f, &clip_rect, 1); 1252 ns_focus (f, &clip_rect, 1);
1273} 1253}
@@ -2911,22 +2891,6 @@ ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
2911 return; 2891 return;
2912} 2892}
2913 2893
2914static void
2915ns_copy_bits (struct frame *f, NSRect src, NSRect dest)
2916{
2917 NSTRACE ("ns_copy_bits");
2918
2919 if (FRAME_NS_VIEW (f))
2920 {
2921 hide_bell(); // Ensure the bell image isn't scrolled.
2922
2923 ns_focus (f, &dest, 1);
2924 [FRAME_NS_VIEW (f) scrollRect: src
2925 by: NSMakeSize (dest.origin.x - src.origin.x,
2926 dest.origin.y - src.origin.y)];
2927 ns_unfocus (f);
2928 }
2929}
2930 2894
2931static void 2895static void
2932ns_scroll_run (struct window *w, struct run *run) 2896ns_scroll_run (struct window *w, struct run *run)
@@ -2979,8 +2943,12 @@ ns_scroll_run (struct window *w, struct run *run)
2979 { 2943 {
2980 NSRect srcRect = NSMakeRect (x, from_y, width, height); 2944 NSRect srcRect = NSMakeRect (x, from_y, width, height);
2981 NSRect dstRect = NSMakeRect (x, to_y, width, height); 2945 NSRect dstRect = NSMakeRect (x, to_y, width, height);
2946 EmacsView *view = FRAME_NS_VIEW (f);
2982 2947
2983 ns_copy_bits (f, srcRect , dstRect); 2948 [view copyRect:srcRect to:dstRect];
2949#ifdef NS_IMPL_COCOA
2950 [view setNeedsDisplayInRect:srcRect];
2951#endif
2984 } 2952 }
2985 2953
2986 unblock_input (); 2954 unblock_input ();
@@ -3034,20 +3002,12 @@ ns_shift_glyphs_for_insert (struct frame *f,
3034 External (RIF): copy an area horizontally, don't worry about clearing src 3002 External (RIF): copy an area horizontally, don't worry about clearing src
3035 -------------------------------------------------------------------------- */ 3003 -------------------------------------------------------------------------- */
3036{ 3004{
3037 //NSRect srcRect = NSMakeRect (x, y, width, height); 3005 NSRect srcRect = NSMakeRect (x, y, width, height);
3038 NSRect dstRect = NSMakeRect (x+shift_by, y, width, height); 3006 NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
3039 3007
3040 NSTRACE ("ns_shift_glyphs_for_insert"); 3008 NSTRACE ("ns_shift_glyphs_for_insert");
3041 3009
3042 /* This doesn't work now as we copy the "bits" before we've had a 3010 [FRAME_NS_VIEW (f) copyRect:srcRect to:dstRect];
3043 chance to actually draw any changes to the screen. This means in
3044 certain circumstances we end up with copies of the cursor all
3045 over the place. Just mark the area dirty so it is redrawn later.
3046
3047 FIXME: Work out how to do this properly. */
3048 // ns_copy_bits (f, srcRect, dstRect);
3049
3050 [FRAME_NS_VIEW (f) setNeedsDisplayInRect:dstRect];
3051} 3011}
3052 3012
3053 3013
@@ -3167,20 +3127,18 @@ ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
3167 3127
3168 /* The visible portion of imageRect will always be contained within 3128 /* The visible portion of imageRect will always be contained within
3169 clearRect. */ 3129 clearRect. */
3170 if (ns_clip_to_rect (f, &clearRect, 1)) 3130 ns_focus (f, &clearRect, 1);
3131 if (! NSIsEmptyRect (clearRect))
3171 { 3132 {
3172 if (! NSIsEmptyRect (clearRect)) 3133 NSTRACE_RECT ("clearRect", clearRect);
3173 {
3174 NSTRACE_RECT ("clearRect", clearRect);
3175 3134
3176 [ns_lookup_indexed_color(face->background, f) set]; 3135 [ns_lookup_indexed_color(face->background, f) set];
3177 NSRectFill (clearRect); 3136 NSRectFill (clearRect);
3178 }
3179 } 3137 }
3180 3138
3181 if (p->which) 3139 if (p->which)
3182 { 3140 {
3183 EmacsImage *img = bimgs[p->which - 1]; 3141 EmacsImage *img = bimgs[p->which - 1];
3184 3142
3185 if (!img) 3143 if (!img)
3186 { 3144 {
@@ -3213,20 +3171,30 @@ ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
3213 [img setXBMColor: bm_color]; 3171 [img setXBMColor: bm_color];
3214 } 3172 }
3215 3173
3216 // Note: For periodic images, the full image height is "h + hd". 3174 // Note: For periodic images, the full image height is "h + hd".
3217 // By using the height h, a suitable part of the image is used. 3175 // By using the height h, a suitable part of the image is used.
3218 NSRect fromRect = NSMakeRect(0, 0, p->wd, p->h); 3176 NSRect fromRect = NSMakeRect(0, 0, p->wd, p->h);
3219 3177
3220 NSTRACE_RECT ("fromRect", fromRect); 3178 NSTRACE_RECT ("fromRect", fromRect);
3221 3179
3222 [img drawInRect: imageRect 3180 /* Because we're drawing into an offscreen buffer which isn't
3223 fromRect: fromRect 3181 flipped, the images come out upside down. To work around it
3224 operation: NSCompositingOperationSourceOver 3182 we need to do some fancy transforms. */
3225 fraction: 1.0 3183 {
3226 respectFlipped: YES 3184 NSAffineTransform *transform = [NSAffineTransform transform];
3227 hints: nil]; 3185 [transform translateXBy:0 yBy:NSMaxY(imageRect)];
3228 } 3186 [transform scaleXBy:1 yBy:-1];
3229 ns_reset_clipping (f); 3187 [transform concat];
3188
3189 imageRect.origin.y = 0;
3190 }
3191
3192 [img drawInRect: imageRect
3193 fromRect: fromRect
3194 operation: NSCompositingOperationSourceOver
3195 fraction: 1.0
3196 respectFlipped: YES
3197 hints: nil];
3230 } 3198 }
3231 ns_unfocus (f); 3199 ns_unfocus (f);
3232} 3200}
@@ -3323,54 +3291,42 @@ ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
3323 else 3291 else
3324 [FRAME_CURSOR_COLOR (f) set]; 3292 [FRAME_CURSOR_COLOR (f) set];
3325 3293
3326#ifdef NS_IMPL_COCOA 3294 ns_focus (f, &r, 1);
3327 /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
3328 atomic. Cleaner ways of doing this should be investigated.
3329 One way would be to set a global variable DRAWING_CURSOR
3330 when making the call to draw_phys..(), don't focus in that
3331 case, then move the ns_unfocus() here after that call. */
3332 NSDisableScreenUpdates ();
3333#endif
3334
3335 switch (cursor_type)
3336 {
3337 case DEFAULT_CURSOR:
3338 case NO_CURSOR:
3339 break;
3340 case FILLED_BOX_CURSOR:
3341 NSRectFill (r);
3342 break;
3343 case HOLLOW_BOX_CURSOR:
3344 NSRectFill (r);
3345 [hollow_color set];
3346 NSRectFill (NSInsetRect (r, 1, 1));
3347 [FRAME_CURSOR_COLOR (f) set];
3348 break;
3349 case HBAR_CURSOR:
3350 NSRectFill (r);
3351 break;
3352 case BAR_CURSOR:
3353 s = r;
3354 /* If the character under cursor is R2L, draw the bar cursor
3355 on the right of its glyph, rather than on the left. */
3356 cursor_glyph = get_phys_cursor_glyph (w);
3357 if ((cursor_glyph->resolved_level & 1) != 0)
3358 s.origin.x += cursor_glyph->pixel_width - s.size.width;
3359
3360 NSRectFill (s);
3361 break;
3362 }
3363 ns_unfocus (f);
3364 3295
3365 /* Draw the character under the cursor. Other terms only draw 3296 switch (cursor_type)
3366 the character on top of box cursors, so do the same here. */ 3297 {
3367 if (cursor_type == FILLED_BOX_CURSOR || cursor_type == HOLLOW_BOX_CURSOR) 3298 case DEFAULT_CURSOR:
3368 draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR); 3299 case NO_CURSOR:
3300 break;
3301 case FILLED_BOX_CURSOR:
3302 NSRectFill (r);
3303 break;
3304 case HOLLOW_BOX_CURSOR:
3305 NSRectFill (r);
3306 [hollow_color set];
3307 NSRectFill (NSInsetRect (r, 1, 1));
3308 [FRAME_CURSOR_COLOR (f) set];
3309 break;
3310 case HBAR_CURSOR:
3311 NSRectFill (r);
3312 break;
3313 case BAR_CURSOR:
3314 s = r;
3315 /* If the character under cursor is R2L, draw the bar cursor
3316 on the right of its glyph, rather than on the left. */
3317 cursor_glyph = get_phys_cursor_glyph (w);
3318 if ((cursor_glyph->resolved_level & 1) != 0)
3319 s.origin.x += cursor_glyph->pixel_width - s.size.width;
3369 3320
3370#ifdef NS_IMPL_COCOA 3321 NSRectFill (s);
3371 NSEnableScreenUpdates (); 3322 break;
3372#endif 3323 }
3324 ns_unfocus (f);
3373 3325
3326 /* Draw the character under the cursor. Other terms only draw
3327 the character on top of box cursors, so do the same here. */
3328 if (cursor_type == FILLED_BOX_CURSOR || cursor_type == HOLLOW_BOX_CURSOR)
3329 draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
3374} 3330}
3375 3331
3376 3332
@@ -3455,6 +3411,7 @@ ns_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1)
3455 ns_unfocus (f); 3411 ns_unfocus (f);
3456} 3412}
3457 3413
3414
3458static void 3415static void
3459ns_show_hourglass (struct frame *f) 3416ns_show_hourglass (struct frame *f)
3460{ 3417{
@@ -3978,15 +3935,27 @@ ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
3978 3935
3979 [[NSGraphicsContext currentContext] saveGraphicsState]; 3936 [[NSGraphicsContext currentContext] saveGraphicsState];
3980 3937
3981 /* Because of the transforms it's far too difficult to work out 3938 /* Because of the transforms it's difficult to work out what
3982 what portion of the original, untransformed, image will be 3939 portion of the original, untransformed, image will be drawn,
3983 drawn, so the clipping area will ensure we draw only the 3940 so the clipping area will ensure we draw only the correct
3984 correct bit. */ 3941 bit. */
3985 NSRectClip (dr); 3942 NSRectClip (dr);
3986 3943
3987 [setOrigin translateXBy:x - s->slice.x yBy:y - s->slice.y]; 3944 [setOrigin translateXBy:x - s->slice.x yBy:y - s->slice.y];
3988 [setOrigin concat]; 3945 [setOrigin concat];
3989 [img->transform concat]; 3946
3947 NSAffineTransform *doTransform = [NSAffineTransform transform];
3948
3949 /* We have to flip the image around the X axis as the offscreen
3950 bitmap we're drawing to is flipped. */
3951 [doTransform scaleXBy:1 yBy:-1];
3952 [doTransform translateXBy:0 yBy:-[img size].height];
3953
3954 /* ImageMagick images don't have transforms. */
3955 if (img->transform)
3956 [doTransform appendTransform:img->transform];
3957
3958 [doTransform concat];
3990 3959
3991 [img drawInRect:ir fromRect:ir 3960 [img drawInRect:ir fromRect:ir
3992 operation:NSCompositingOperationSourceOver 3961 operation:NSCompositingOperationSourceOver
@@ -4059,6 +4028,7 @@ static void
4059ns_dumpglyphs_stretch (struct glyph_string *s) 4028ns_dumpglyphs_stretch (struct glyph_string *s)
4060{ 4029{
4061 NSRect r[2]; 4030 NSRect r[2];
4031 NSRect glyphRect;
4062 int n, i; 4032 int n, i;
4063 struct face *face; 4033 struct face *face;
4064 NSColor *fgCol, *bgCol; 4034 NSColor *fgCol, *bgCol;
@@ -4066,106 +4036,56 @@ ns_dumpglyphs_stretch (struct glyph_string *s)
4066 if (!s->background_filled_p) 4036 if (!s->background_filled_p)
4067 { 4037 {
4068 n = ns_get_glyph_string_clip_rect (s, r); 4038 n = ns_get_glyph_string_clip_rect (s, r);
4069
4070 ns_focus (s->f, r, n); 4039 ns_focus (s->f, r, n);
4071 4040
4072 if (s->hl == DRAW_MOUSE_FACE) 4041 if (s->hl == DRAW_MOUSE_FACE)
4073 { 4042 {
4074 face = FACE_FROM_ID_OR_NULL (s->f, 4043 face = FACE_FROM_ID_OR_NULL (s->f,
4075 MOUSE_HL_INFO (s->f)->mouse_face_face_id); 4044 MOUSE_HL_INFO (s->f)->mouse_face_face_id);
4076 if (!face) 4045 if (!face)
4077 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID); 4046 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
4078 } 4047 }
4079 else 4048 else
4080 face = FACE_FROM_ID (s->f, s->first_glyph->face_id); 4049 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
4081 4050
4082 bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f); 4051 bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
4083 fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f); 4052 fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
4084 4053
4085 for (i = 0; i < n; ++i) 4054 glyphRect = NSMakeRect (s->x, s->y, s->background_width, s->height);
4086 {
4087 /* FIXME: Why are we reusing the clipping rectangles? The
4088 other terms don't appear to do anything like this. */
4089 *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
4090
4091 if (s->hl == DRAW_MOUSE_FACE)
4092 {
4093 int overrun, leftoverrun;
4094
4095 /* truncate to avoid overwriting fringe and/or scrollbar */
4096 overrun = max (0, (s->x + s->background_width)
4097 - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
4098 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
4099 r[i].size.width -= overrun;
4100
4101 for (i = 0; i < n; ++i)
4102 {
4103 if (!s->row->full_width_p)
4104 {
4105 int overrun, leftoverrun;
4106
4107 /* truncate to avoid overwriting fringe and/or scrollbar */
4108 overrun = max (0, (s->x + s->background_width)
4109 - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
4110 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
4111 r[i].size.width -= overrun;
4112
4113 /* truncate to avoid overwriting to left of the window box */
4114 leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
4115 + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
4116
4117 if (leftoverrun > 0)
4118 {
4119 r[i].origin.x += leftoverrun;
4120 r[i].size.width -= leftoverrun;
4121 }
4122 }
4123
4124 if (leftoverrun > 0)
4125 {
4126 r[i].origin.x += leftoverrun;
4127 r[i].size.width -= leftoverrun;
4128 }
4129
4130 /* XXX: Try to work between problem where a stretch glyph on
4131 a partially-visible bottom row will clear part of the
4132 modeline, and another where list-buffers headers and similar
4133 rows erroneously have visible_height set to 0. Not sure
4134 where this is coming from as other terms seem not to show. */
4135 r[i].size.height = min (s->height, s->row->visible_height);
4136 }
4137 4055
4138 [bgCol set]; 4056 [bgCol set];
4139 4057
4140 /* NOTE: under NS this is NOT used to draw cursors, but we must avoid 4058 /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
4141 overwriting cursor (usually when cursor on a tab) */ 4059 overwriting cursor (usually when cursor on a tab) */
4142 if (s->hl == DRAW_CURSOR) 4060 if (s->hl == DRAW_CURSOR)
4143 { 4061 {
4144 CGFloat x, width; 4062 CGFloat x, width;
4145 4063
4146 x = r[i].origin.x; 4064 /* FIXME: This looks like it will only work for left to
4147 width = s->w->phys_cursor_width; 4065 right languages. */
4148 r[i].size.width -= width; 4066 x = NSMinX (glyphRect);
4149 r[i].origin.x += width; 4067 width = s->w->phys_cursor_width;
4068 glyphRect.size.width -= width;
4069 glyphRect.origin.x += width;
4150 4070
4151 NSRectFill (r[i]); 4071 NSRectFill (glyphRect);
4152 4072
4153 /* Draw overlining, etc. on the cursor. */ 4073 /* Draw overlining, etc. on the cursor. */
4154 if (s->w->phys_cursor_type == FILLED_BOX_CURSOR) 4074 if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
4155 ns_draw_text_decoration (s, face, bgCol, width, x); 4075 ns_draw_text_decoration (s, face, bgCol, width, x);
4156 else
4157 ns_draw_text_decoration (s, face, fgCol, width, x);
4158 }
4159 else 4076 else
4160 { 4077 ns_draw_text_decoration (s, face, fgCol, width, x);
4161 NSRectFill (r[i]);
4162 }
4163
4164 /* Draw overlining, etc. on the stretch glyph (or the part
4165 of the stretch glyph after the cursor). */
4166 ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
4167 r[i].origin.x);
4168 } 4078 }
4079 else
4080 {
4081 NSRectFill (glyphRect);
4082 }
4083
4084 /* Draw overlining, etc. on the stretch glyph (or the part
4085 of the stretch glyph after the cursor). */
4086 ns_draw_text_decoration (s, face, fgCol, NSWidth (glyphRect),
4087 NSMinX (glyphRect));
4088
4169 ns_unfocus (s->f); 4089 ns_unfocus (s->f);
4170 s->background_filled_p = 1; 4090 s->background_filled_p = 1;
4171 } 4091 }
@@ -7192,6 +7112,7 @@ not_in_argv (NSString *arg)
7192 from non-native fullscreen, in other circumstances it appears 7112 from non-native fullscreen, in other circumstances it appears
7193 to be a noop. (bug#28872) */ 7113 to be a noop. (bug#28872) */
7194 wr = NSMakeRect (0, 0, neww, newh); 7114 wr = NSMakeRect (0, 0, neww, newh);
7115 [self createDrawingBufferWithRect:wr];
7195 [view setFrame: wr]; 7116 [view setFrame: wr];
7196 7117
7197 // To do: consider using [NSNotificationCenter postNotificationName:]. 7118 // To do: consider using [NSNotificationCenter postNotificationName:].
@@ -7531,6 +7452,8 @@ not_in_argv (NSString *arg)
7531 maximizing_resize = NO; 7452 maximizing_resize = NO;
7532#endif 7453#endif
7533 7454
7455 [self createDrawingBufferWithRect:r];
7456
7534 win = [[EmacsWindow alloc] 7457 win = [[EmacsWindow alloc]
7535 initWithContentRect: r 7458 initWithContentRect: r
7536 styleMask: (FRAME_UNDECORATED (f) 7459 styleMask: (FRAME_UNDECORATED (f)
@@ -8322,38 +8245,105 @@ not_in_argv (NSString *arg)
8322} 8245}
8323 8246
8324 8247
8325- (void)viewWillDraw 8248- (void)createDrawingBufferWithRect:(NSRect)rect
8249 /* Create and store a new NSBitmapImageRep for Emacs to draw
8250 into.
8251
8252 Drawing to an offscreen bitmap doesn't work in GNUstep as there's
8253 a bug in graphicsContextWithBitmapImageRep
8254 (https://savannah.gnu.org/bugs/?38405). So under GNUstep we
8255 retain the old method of drawing direct to the EmacsView. */
8326{ 8256{
8327 /* If the frame has been garbaged there's no point in redrawing 8257#ifdef NS_IMPL_COCOA
8328 anything. */ 8258 if (drawingBuffer != nil)
8329 if (FRAME_GARBAGED_P (emacsframe)) 8259 [drawingBuffer release];
8330 [self setNeedsDisplay:NO]; 8260
8261 drawingBuffer = [[self bitmapImageRepForCachingDisplayInRect:rect] retain];
8262#endif
8331} 8263}
8332 8264
8333- (void)drawRect: (NSRect)rect 8265
8266#ifdef NS_IMPL_COCOA
8267- (void)focusOnDrawingBuffer
8334{ 8268{
8335 int x = NSMinX (rect), y = NSMinY (rect); 8269 /* Creating the graphics context each time is very slow, but it
8336 int width = NSWidth (rect), height = NSHeight (rect); 8270 doesn't seem possible to cache and reuse it. */
8271 [NSGraphicsContext
8272 setCurrentContext:
8273 [NSGraphicsContext graphicsContextWithBitmapImageRep:drawingBuffer]];
8274}
8275
8276
8277- (void)windowDidChangeBackingProperties:(NSNotification *)notification
8278 /* Update the drawing buffer when the backing scale factor changes. */
8279{
8280 CGFloat old = [[[notification userInfo]
8281 objectForKey:@"NSBackingPropertyOldScaleFactorKey"]
8282 doubleValue];
8283 CGFloat new = [[self window] backingScaleFactor];
8284
8285 if (old != new)
8286 {
8287 NSRect frame = [self frame];
8288 [self createDrawingBufferWithRect:frame];
8289 ns_clear_frame (emacsframe);
8290 expose_frame (emacsframe, 0, 0, NSWidth (frame), NSHeight (frame));
8291 }
8292}
8293#endif
8294
8337 8295
8296- (void)copyRect:(NSRect)srcRect to:(NSRect)dstRect
8297{
8298 NSTRACE ("[EmacsView copyRect:To:]");
8299 NSTRACE_RECT ("Source", srcRect);
8300 NSTRACE_RECT ("Destination", dstRect);
8301
8302#ifdef NS_IMPL_COCOA
8303 [drawingBuffer drawInRect:dstRect
8304 fromRect:srcRect
8305 operation:NSCompositingOperationCopy
8306 fraction:1.0
8307 respectFlipped:NO
8308 hints:nil];
8309
8310 [self setNeedsDisplayInRect:dstRect];
8311#else
8312 hide_bell(); // Ensure the bell image isn't scrolled.
8313
8314 ns_focus (emacsframe, &dstRect, 1);
8315 [self scrollRect: srcRect
8316 by: NSMakeSize (dstRect.origin.x - srcRect.origin.x,
8317 dstRect.origin.y - srcRect.origin.y)];
8318 ns_unfocus (emacsframe);
8319#endif
8320}
8321
8322
8323- (void)drawRect: (NSRect)rect
8324{
8338 NSTRACE ("[EmacsView drawRect:" NSTRACE_FMT_RECT "]", 8325 NSTRACE ("[EmacsView drawRect:" NSTRACE_FMT_RECT "]",
8339 NSTRACE_ARG_RECT(rect)); 8326 NSTRACE_ARG_RECT(rect));
8340 8327
8341 if (!emacsframe || !emacsframe->output_data.ns) 8328 if (!emacsframe || !emacsframe->output_data.ns)
8342 return; 8329 return;
8343 8330
8331#ifdef NS_IMPL_COCOA
8332 [drawingBuffer drawInRect:rect
8333 fromRect:rect
8334 operation:NSCompositingOperationSourceOver
8335 fraction:1
8336 respectFlipped:NO
8337 hints:nil];
8338#else
8339 int x = NSMinX (rect), y = NSMinY (rect);
8340 int width = NSWidth (rect), height = NSHeight (rect);
8341
8344 ns_clear_frame_area (emacsframe, x, y, width, height); 8342 ns_clear_frame_area (emacsframe, x, y, width, height);
8345 block_input (); 8343 block_input ();
8346 expose_frame (emacsframe, x, y, width, height); 8344 expose_frame (emacsframe, x, y, width, height);
8347 unblock_input (); 8345 unblock_input ();
8348 8346#endif
8349 /*
8350 drawRect: may be called (at least in Mac OS X 10.5) for invisible
8351 views as well for some reason. Thus, do not infer visibility
8352 here.
8353
8354 emacsframe->async_visible = 1;
8355 emacsframe->async_iconified = 0;
8356 */
8357} 8347}
8358 8348
8359 8349