Subject: bug#73384: closed (Re: bug#73384: [PATCH] Draw coloured stipples on NS)

From: [email-masked] (GNU bug Tracking System)
Date: Tue, 04 Mar 2025 12:33:02 +0000

Your bug report

#73384: [PATCH] Draw coloured stipples on NS

which was filed against the emacs package, has been closed.

The explanation is attached below, along with your original report.
If you require more details, please reply to [email-masked].

-- 
73384: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=73384
GNU Bug Tracking System
Contact [email-masked] with problems

Subject: Re: bug#73384: [PATCH] Draw coloured stipples on NS
From: Eli Zaretskii <[email-masked]>
To: Ben Simms <[email-masked]>
Cc: [email-masked], [email-masked], [email-masked], [email-masked], [email-masked], [email-masked]
Date: Tue, 04 Mar 2025 14:32:21 +0200
List-Id: <debbugs-submit.debbugs.gnu.org>

Subject: [PATCH] Draw coloured stipples on NS
From: Ben Simms <[email-masked]>
To: [email-masked]
Date: Fri, 20 Sep 2024 09:57:21 +0200
List-Id: <debbugs-submit.debbugs.gnu.org>

Hello, I've been advised to submit my patch adding support for drawing
coloured stipples on NS Emacs here:

>From 87c143b1b77ae02a08b9e1bbe27da57859e28a8d Mon Sep 17 00:00:00 2001
From: Ben Simms <[email-masked]>
Date: Fri, 20 Sep 2024 09:50:47 +0200
Subject: [PATCH] Support drawing coloured stipples

This makes use of CoreGraphics, while this works fine on macos systems,
I'm unsure how to test this on a GNUStep or other supported NS
implementation.
---
 src/nsimage.m | 17 +++++++++++++---
 src/nsterm.h  |  4 ++--
 src/nsterm.m  | 56 +++++++++++++++++++++++++++++++++++++++++++++------
 3 files changed, 66 insertions(+), 11 deletions(-)

diff --git a/src/nsimage.m b/src/nsimage.m
index ee72d6e0ea..100af5c3e9 100644
--- a/src/nsimage.m
+++ b/src/nsimage.m
@@ -28,6 +28,7 @@ Updated by Christian Limpach ([email-masked])
 /* This should be the first include, as it may set up #defines affecting
    interpretation of even the system includes.  */
 #include <config.h>
+#include <CoreGraphics/CoreGraphics.h>

 #include "lisp.h"
 #include "dispextern.h"
@@ -510,10 +511,20 @@ - (void) setAlphaAtX: (int) x Y: (int) y to:
(unsigned char) a
 }

 /* Returns a pattern color, which is cached here.  */
-- (NSColor *)stippleMask
+- (CGImageRef)stippleMask
 {
-  if (stippleMask == nil)
-      stippleMask = [[NSColor colorWithPatternImage: self] retain];
+  if (stippleMask == nil) {
+    CGDataProviderRef provider = CGDataProviderCreateWithData (NULL,
[bmRep bitmapData],
+                                                             [self
sizeInBytes], NULL);
+    id mask = (id)CGImageMaskCreate(
+                                          [self size].width,
+                                          [self size].height,
+                                          8, 8, [self size].width,
+                                          provider, NULL, 0);
+
+    CGDataProviderRelease(provider);
+    stippleMask = (CGImageRef)[mask retain];
+  }
   return stippleMask;
 }

diff --git a/src/nsterm.h b/src/nsterm.h
index 3a713f8e8c..7ec851966f 100644
--- a/src/nsterm.h
+++ b/src/nsterm.h
@@ -670,7 +670,7 @@ #define NSTRACE_UNSILENCE()
 {
   NSBitmapImageRep *bmRep; /* used for accessing pixel data */
   unsigned char *pixmapData[5]; /* shortcut to access pixel data */
-  NSColor *stippleMask;
+  CGImageRef stippleMask;
 @public
   NSAffineTransform *transform;
   BOOL smoothing;
@@ -687,7 +687,7 @@ #define NSTRACE_UNSILENCE()
                green: (unsigned char)g blue: (unsigned char)b
               alpha:(unsigned char)a;
 - (void)setAlphaAtX: (int)x Y: (int)y to: (unsigned char)a;
-- (NSColor *)stippleMask;
+- (CGImageRef)stippleMask;
 - (Lisp_Object)getMetadata;
 - (BOOL)setFrame: (unsigned int) index;
 - (void)setTransform: (double[3][3]) m;
diff --git a/src/nsterm.m b/src/nsterm.m
index 794630de1c..84084f12a4 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -3826,9 +3826,28 @@ Function modeled after x_draw_glyph_string_box ().

       if (s->stippled_p)
  {
+  [[NSColor colorWithUnsignedLong:face->background] set];
+  r = NSMakeRect (s->x, s->y + box_line_width,
+  s->background_width,
+  s->height - 2 * box_line_width);
+  NSRectFill (r);
+  s->background_filled_p = 1;
   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f);
-  [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
-  goto fill;
+  CGImageRef mask =
+    [dpyinfo->bitmaps[face->stipple - 1].img stippleMask];
+  CGRect bounds = CGRectMake (s->x, s->y + box_line_width,
+      s->background_width,
+      s->height - 2 * box_line_width);
+  NSGraphicsContext *ctx = [NSGraphicsContext currentContext];
+  [ctx saveGraphicsState];
+  CGContextRef context = [ctx CGContext];
+  CGContextClipToRect (context, bounds);
+  CGContextScaleCTM (context, 1, -1);
+  [[NSColor colorWithUnsignedLong:face->foreground] set];
+  CGRect imageSize = CGRectMake (0, 0, CGImageGetWidth (mask),
+ CGImageGetHeight (mask));
+  CGContextDrawTiledImage (context, imageSize, mask);
+  [[NSGraphicsContext currentContext] restoreGraphicsState];
  }
       else if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
        /* When xdisp.c ignores FONT_HEIGHT, we cannot trust font
@@ -3851,7 +3870,6 @@ Function modeled after x_draw_glyph_string_box ().
   else
     [FRAME_CURSOR_COLOR (s->f) set];

- fill:
   r = NSMakeRect (s->x, s->y + box_line_width,
   s->background_width,
   s->height - 2 * box_line_width);
@@ -4175,10 +4193,36 @@ Function modeled after x_draw_glyph_string_box ().
   dpyinfo = FRAME_DISPLAY_INFO (s->f);
   if (s->hl == DRAW_CURSOR)
     [FRAME_CURSOR_COLOR (s->f) set];
-  else if (s->stippled_p)
-    [[dpyinfo->bitmaps[s->face->stipple - 1].img stippleMask] set];
-  else
+  else if (s->stippled_p) {
+      [[NSColor colorWithUnsignedLong:s->face->background]
+ set];
+      NSRectFill (
+ NSMakeRect (x, s->y, background_width, s->height));
+      CGImageRef mask =
+ [dpyinfo->bitmaps[s->face->stipple - 1]
+    .img stippleMask];
+      CGRect bounds
+ = CGRectMake (s->x, s->y, s->background_width,
+      s->height);
+      NSGraphicsContext *ctx =
+ [NSGraphicsContext currentContext];
+      [ctx saveGraphicsState];
+      CGContextRef context = [ctx CGContext];
+      CGContextClipToRect(context, bounds);
+      CGContextScaleCTM (context, 1, -1);
+      [[NSColor colorWithUnsignedLong:s->face->foreground]
+ set];
+      CGRect imageSize
+ = CGRectMake (0, 0, CGImageGetWidth (mask),
+      CGImageGetHeight (mask));
+      CGContextDrawTiledImage (context, imageSize, mask);
+      [[NSGraphicsContext currentContext]
+ restoreGraphicsState];
+    }
+  else {
     [[NSColor colorWithUnsignedLong: s->face->background] set];
+    NSRectFill (NSMakeRect (x, s->y, background_width, s->height));
+  }

   NSRectFill (NSMakeRect (x, s->y, background_width, s->height));
  }
-- 
2.45.2