]> git.eshelyaron.com Git - emacs.git/commitdiff
Use CGImage instead of NSBitmapImageRep (bug#32932)
authorAlan Third <alan@idiocy.org>
Sat, 1 Feb 2020 21:17:29 +0000 (21:17 +0000)
committerAlan Third <alan@idiocy.org>
Thu, 13 Feb 2020 18:26:20 +0000 (18:26 +0000)
* src/nsterm.m (ns_update_end):
(ns_clear_frame): Remove forced draws.
(ns_draw_fringe_bitmap):
(ns_dumpglyphs_image): No longer need to invert images as the context
is already flipped.
([EmacsView updateFrameSize:]):
([EmacsView initFrameFromEmacs:]): Use new function.
([EmacsView createDrawingBuffer]): Replaces createDrawingBufferWithRect:.
([EmacsView focusOnDrawingBuffer]): Set CGImage context.
([EmacsView windowDidChangeBackingProperties:]): Use new function.
([EmacsView copyRect:to:]): Copy using CGImages.
([EmacsView wantsUpdateLayer]):
([EmacsView updateLayer]): New Functions.
([EmacsView drawRect:]): We no longer do anything special here for
Cocoa.
([EmacsView windowDidChangeBackingProperties:]): Fix indentation and
add NSTRACE.

src/nsterm.h
src/nsterm.m

index 980ca534cfaa3e58224cbdc3fb26ac2145d072f9..7c6197f12880f707c9afa99d3790e9482cfb6a0c 100644 (file)
@@ -418,7 +418,7 @@ typedef id instancetype;
    NSWindow *nonfs_window;
    BOOL fs_is_native;
 #ifdef NS_IMPL_COCOA
-   NSBitmapImageRep *drawingBuffer;
+   CGContextRef drawingBuffer;
 #endif
 @public
    struct frame *emacsframe;
@@ -464,7 +464,7 @@ typedef id instancetype;
 - (void)focusOnDrawingBuffer;
 #endif
 - (void)copyRect:(NSRect)srcRect to:(NSRect)dstRect;
-- (void)createDrawingBufferWithRect:(NSRect)rect;
+- (void)createDrawingBuffer;
 
 /* Non-notification versions of NSView methods. Used for direct calls.  */
 - (void)windowWillEnterFullScreen;
index 9d427b9b38d7bb1205c22188c933fad8b8fe7cae..2cf6774a1f19ed79202fe925e3989e5e102f3465 100644 (file)
@@ -1141,7 +1141,6 @@ ns_update_end (struct frame *f)
 
 #ifdef NS_IMPL_COCOA
   [NSGraphicsContext setCurrentContext:nil];
-  [view display];
 #else
   block_input ();
 
@@ -2853,7 +2852,9 @@ ns_clear_frame (struct frame *f)
   ns_unfocus (f);
 
   /* as of 2006/11 or so this is now needed */
-  ns_redraw_scroll_bars (f);
+  /* FIXME: I don't see any reason for this and removing it makes no
+     difference here.  Do we need it for GNUstep?  */
+  //ns_redraw_scroll_bars (f);
   unblock_input ();
 }
 
@@ -3169,18 +3170,6 @@ ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
 
       NSTRACE_RECT ("fromRect", fromRect);
 
-      /* Because we're drawing into an offscreen buffer which isn't
-         flipped, the images come out upside down.  To work around it
-         we need to do some fancy transforms.  */
-      {
-        NSAffineTransform *transform = [NSAffineTransform transform];
-        [transform translateXBy:0 yBy:NSMaxY(imageRect)];
-        [transform scaleXBy:1 yBy:-1];
-        [transform concat];
-
-        imageRect.origin.y = 0;
-      }
-
       [img drawInRect: imageRect
              fromRect: fromRect
             operation: NSCompositingOperationSourceOver
@@ -3938,11 +3927,6 @@ ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
 
       NSAffineTransform *doTransform = [NSAffineTransform transform];
 
-      /* We have to flip the image around the X axis as the offscreen
-         bitmap we're drawing to is flipped.  */
-      [doTransform scaleXBy:1 yBy:-1];
-      [doTransform translateXBy:0 yBy:-[img size].height];
-
       /* ImageMagick images don't have transforms.  */
       if (img->transform)
         [doTransform appendTransform:img->transform];
@@ -7104,7 +7088,7 @@ not_in_argv (NSString *arg)
          from non-native fullscreen, in other circumstances it appears
          to be a noop.  (bug#28872) */
       wr = NSMakeRect (0, 0, neww, newh);
-      [self createDrawingBufferWithRect:wr];
+      [self createDrawingBuffer];
       [view setFrame: wr];
 
       // To do: consider using [NSNotificationCenter postNotificationName:].
@@ -7444,7 +7428,7 @@ not_in_argv (NSString *arg)
   maximizing_resize = NO;
 #endif
 
-  [self createDrawingBufferWithRect:r];
+  [self createDrawingBuffer];
 
   win = [[EmacsWindow alloc]
             initWithContentRect: r
@@ -8229,52 +8213,65 @@ not_in_argv (NSString *arg)
 }
 
 
-- (void)createDrawingBufferWithRect:(NSRect)rect
-  /* Create and store a new NSBitmapImageRep for Emacs to draw
-     into.
+#ifdef NS_IMPL_COCOA
+- (void)createDrawingBuffer
+  /* Create and store a new CGGraphicsContext for Emacs to draw into.
 
-     Drawing to an offscreen bitmap doesn't work in GNUstep as there's
-     a bug in graphicsContextWithBitmapImageRep
-     (https://savannah.gnu.org/bugs/?38405).  So under GNUstep we
-     retain the old method of drawing direct to the EmacsView.  */
+     We can't do this in GNUstep as there's no equivalent, so under
+     GNUstep we retain the old method of drawing direct to the
+     EmacsView.  */
 {
-#ifdef NS_IMPL_COCOA
+  NSTRACE ("EmacsView createDrawingBuffer]");
+
+  NSGraphicsContext *screen;
+  CGColorSpaceRef colorSpace = [[[self window] colorSpace] CGColorSpace];
+  CGFloat scale = [[self window] backingScaleFactor];
+  NSRect frame = [self frame];
+
   if (drawingBuffer != nil)
-    [drawingBuffer release];
+    CGContextRelease (drawingBuffer);
 
-  drawingBuffer = [[self bitmapImageRepForCachingDisplayInRect:rect] retain];
-#endif
+  drawingBuffer = CGBitmapContextCreate (nil, NSWidth (frame) * scale, NSHeight (frame) * scale,
+                                         8, 0, colorSpace,
+                                         kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host);
+
+  /* This fixes the scale to match the backing scale factor, and flips the image.  */
+  CGContextTranslateCTM(drawingBuffer, 0, NSHeight (frame) * scale);
+  CGContextScaleCTM(drawingBuffer, scale, -scale);
 }
 
 
-#ifdef NS_IMPL_COCOA
 - (void)focusOnDrawingBuffer
 {
-  /* Creating the graphics context each time is very slow, but it
-     doesn't seem possible to cache and reuse it.  */
-  [NSGraphicsContext
-    setCurrentContext:
-      [NSGraphicsContext graphicsContextWithBitmapImageRep:drawingBuffer]];
+  NSTRACE ("EmacsView focusOnDrawingBuffer]");
+
+  NSGraphicsContext *buf =
+    [NSGraphicsContext
+        graphicsContextWithCGContext:drawingBuffer flipped:YES];
+
+  [NSGraphicsContext setCurrentContext:buf];
 }
 
 
 - (void)windowDidChangeBackingProperties:(NSNotification *)notification
   /* Update the drawing buffer when the backing scale factor changes.  */
 {
-   CGFloat old = [[[notification userInfo]
+  NSTRACE ("EmacsView windowDidChangeBackingProperties:]");
+
+  CGFloat old = [[[notification userInfo]
                     objectForKey:@"NSBackingPropertyOldScaleFactorKey"]
-                   doubleValue];
-   CGFloat new = [[self window] backingScaleFactor];
+                  doubleValue];
+  CGFloat new = [[self window] backingScaleFactor];
 
-   if (old != new)
-     {
-       NSRect frame = [self frame];
-       [self createDrawingBufferWithRect:frame];
-       ns_clear_frame (emacsframe);
-       expose_frame (emacsframe, 0, 0, NSWidth (frame), NSHeight (frame));
-     }
+  if (old != new)
+    {
+      NSRect frame = [self frame];
+      [self createDrawingBuffer];
+      ns_clear_frame (emacsframe);
+      expose_frame (emacsframe, 0, 0, NSWidth (frame), NSHeight (frame));
+    }
 }
-#endif
+#endif /* NS_IMPL_COCOA */
 
 
 - (void)copyRect:(NSRect)srcRect to:(NSRect)dstRect
@@ -8284,13 +8281,31 @@ not_in_argv (NSString *arg)
   NSTRACE_RECT ("Destination", dstRect);
 
 #ifdef NS_IMPL_COCOA
-  [drawingBuffer drawInRect:dstRect
-                   fromRect:srcRect
-                  operation:NSCompositingOperationCopy
-                   fraction:1.0
-             respectFlipped:NO
-                      hints:nil];
+  CGImageRef copy;
+  NSRect frame = [self frame];
+  NSAffineTransform *setOrigin = [NSAffineTransform transform];
+
+  [[NSGraphicsContext currentContext] saveGraphicsState];
+
+  /* Set the clipping before messing with the buffer's
+     orientation.  */
+  NSRectClip (dstRect);
+
+  /* Unflip the buffer as the copied image will be unflipped, and
+     offset the top left so when we draw back into the buffer the
+     correct part of the image is drawn.  */
+  CGContextScaleCTM(drawingBuffer, 1, -1);
+  CGContextTranslateCTM(drawingBuffer, 0, -NSHeight (frame)
+                        - (NSMinY (dstRect) - NSMinY (srcRect)));
+
+  /* Take a copy of the buffer and then draw it back to the buffer,
+     limited by the clipping rectangle.  */
+  copy = CGBitmapContextCreateImage (drawingBuffer);
+  CGContextDrawImage (drawingBuffer, frame, copy);
+
+  CGImageRelease (copy);
 
+  [[NSGraphicsContext currentContext] restoreGraphicsState];
   [self setNeedsDisplayInRect:dstRect];
 #else
   hide_bell();              // Ensure the bell image isn't scrolled.
@@ -8304,6 +8319,24 @@ not_in_argv (NSString *arg)
 }
 
 
+#ifdef NS_IMPL_COCOA
+- (BOOL)wantsUpdateLayer
+{
+    return YES;
+}
+
+
+- (void)updateLayer
+{
+  NSTRACE ("EmacsView updateLayer]");
+
+  CGImageRef contentsImage = CGBitmapContextCreateImage(drawingBuffer);
+  [[self layer] setContents:(id)contentsImage];
+  CGImageRelease(contentsImage);
+}
+#endif
+
+
 - (void)drawRect: (NSRect)rect
 {
   NSTRACE ("[EmacsView drawRect:" NSTRACE_FMT_RECT "]",
@@ -8312,14 +8345,6 @@ not_in_argv (NSString *arg)
   if (!emacsframe || !emacsframe->output_data.ns)
     return;
 
-#ifdef NS_IMPL_COCOA
-  [drawingBuffer drawInRect:rect
-                   fromRect:rect
-                  operation:NSCompositingOperationSourceOver
-                   fraction:1
-             respectFlipped:NO
-                      hints:nil];
-#else
   int x = NSMinX (rect), y = NSMinY (rect);
   int width = NSWidth (rect), height = NSHeight (rect);
 
@@ -8327,7 +8352,6 @@ not_in_argv (NSString *arg)
   block_input ();
   expose_frame (emacsframe, x, y, width, height);
   unblock_input ();
-#endif
 }