diff options
| author | Ben Simms | 2025-01-05 20:03:53 +0100 |
|---|---|---|
| committer | Eli Zaretskii | 2025-03-04 14:31:35 +0200 |
| commit | 9cbbdcee132588a11dc03c3da371176aaa13927c (patch) | |
| tree | a6051b5234fe0bcb9256d8d7aef17ecc52abb002 /src | |
| parent | fe7a8c92be6269f8fc7933eb6c190178839d0f8a (diff) | |
| download | emacs-9cbbdcee132588a11dc03c3da371176aaa13927c.tar.gz emacs-9cbbdcee132588a11dc03c3da371176aaa13927c.zip | |
Support colored stipples on Cocoa NS (Bug#73384)
On Cocoa builds of NS Emacs, stipples are now rendered
using masked CGImages instead of patterned NSColors so that
stipples now render with color.
* src/nsimage.m ([EmacsImage stippleMask:]): Use a CGImageMask to
store the stipple mask when building for Cocoa.
* src/nsterm.m (ns_maybe_dumpglyphs_background): Perform a masked
fill to draw stipples when building for Cocoa.
(ns_draw_stretch_glyph_string): Perform a masked fill to draw
stipples when building for Cocoa.
Diffstat (limited to 'src')
| -rw-r--r-- | src/nsimage.m | 31 | ||||
| -rw-r--r-- | src/nsterm.h | 8 | ||||
| -rw-r--r-- | src/nsterm.m | 68 |
3 files changed, 106 insertions, 1 deletions
diff --git a/src/nsimage.m b/src/nsimage.m index e8c82269bce..8f1653d085a 100644 --- a/src/nsimage.m +++ b/src/nsimage.m | |||
| @@ -35,6 +35,9 @@ GNUstep port and post-20 update by Adrian Robert (arobert@cogsci.ucsd.edu) | |||
| 35 | #include "frame.h" | 35 | #include "frame.h" |
| 36 | #include "coding.h" | 36 | #include "coding.h" |
| 37 | 37 | ||
| 38 | #ifdef NS_IMPL_COCOA | ||
| 39 | #include <CoreGraphics/CoreGraphics.h> | ||
| 40 | #endif | ||
| 38 | 41 | ||
| 39 | #if defined (NS_IMPL_GNUSTEP) || MAC_OS_X_VERSION_MAX_ALLOWED < 1070 | 42 | #if defined (NS_IMPL_GNUSTEP) || MAC_OS_X_VERSION_MAX_ALLOWED < 1070 |
| 40 | # define COLORSPACE_NAME NSCalibratedRGBColorSpace | 43 | # define COLORSPACE_NAME NSCalibratedRGBColorSpace |
| @@ -289,7 +292,11 @@ ns_image_size_in_bytes (void *img) | |||
| 289 | 292 | ||
| 290 | - (void)dealloc | 293 | - (void)dealloc |
| 291 | { | 294 | { |
| 295 | #ifdef NS_IMPL_COCOA | ||
| 296 | CGImageRelease(stippleMask); | ||
| 297 | #else | ||
| 292 | [stippleMask release]; | 298 | [stippleMask release]; |
| 299 | #endif | ||
| 293 | [bmRep release]; | 300 | [bmRep release]; |
| 294 | [transform release]; | 301 | [transform release]; |
| 295 | [super dealloc]; | 302 | [super dealloc]; |
| @@ -300,7 +307,11 @@ ns_image_size_in_bytes (void *img) | |||
| 300 | { | 307 | { |
| 301 | EmacsImage *copy = [super copyWithZone:zone]; | 308 | EmacsImage *copy = [super copyWithZone:zone]; |
| 302 | 309 | ||
| 310 | #ifdef NS_IMPL_COCOA | ||
| 311 | copy->stippleMask = CGImageCreateCopy(stippleMask); | ||
| 312 | #else | ||
| 303 | copy->stippleMask = [stippleMask copyWithZone:zone]; | 313 | copy->stippleMask = [stippleMask copyWithZone:zone]; |
| 314 | #endif /* NS_IMPL_COCOA */ | ||
| 304 | copy->bmRep = [bmRep copyWithZone:zone]; | 315 | copy->bmRep = [bmRep copyWithZone:zone]; |
| 305 | copy->transform = [transform copyWithZone:zone]; | 316 | copy->transform = [transform copyWithZone:zone]; |
| 306 | 317 | ||
| @@ -509,6 +520,25 @@ ns_image_size_in_bytes (void *img) | |||
| 509 | } | 520 | } |
| 510 | } | 521 | } |
| 511 | 522 | ||
| 523 | #ifdef NS_IMPL_COCOA | ||
| 524 | /* Returns a cached CGImageMask of the stipple pattern */ | ||
| 525 | - (CGImageRef)stippleMask | ||
| 526 | { | ||
| 527 | if (stippleMask == nil) | ||
| 528 | { | ||
| 529 | CGDataProviderRef provider = CGDataProviderCreateWithData (NULL, [bmRep bitmapData], | ||
| 530 | [self sizeInBytes], NULL); | ||
| 531 | CGImageRef mask = CGImageMaskCreate([self size].width, | ||
| 532 | [self size].height, | ||
| 533 | 8, 8, [self size].width, | ||
| 534 | provider, NULL, 0); | ||
| 535 | |||
| 536 | CGDataProviderRelease(provider); | ||
| 537 | stippleMask = CGImageRetain(mask); | ||
| 538 | } | ||
| 539 | return stippleMask; | ||
| 540 | } | ||
| 541 | #else | ||
| 512 | /* Returns a pattern color, which is cached here. */ | 542 | /* Returns a pattern color, which is cached here. */ |
| 513 | - (NSColor *)stippleMask | 543 | - (NSColor *)stippleMask |
| 514 | { | 544 | { |
| @@ -516,6 +546,7 @@ ns_image_size_in_bytes (void *img) | |||
| 516 | stippleMask = [[NSColor colorWithPatternImage: self] retain]; | 546 | stippleMask = [[NSColor colorWithPatternImage: self] retain]; |
| 517 | return stippleMask; | 547 | return stippleMask; |
| 518 | } | 548 | } |
| 549 | #endif /* NS_IMPL_COCOA */ | ||
| 519 | 550 | ||
| 520 | /* Find the first NSBitmapImageRep which has multiple frames. */ | 551 | /* Find the first NSBitmapImageRep which has multiple frames. */ |
| 521 | - (NSBitmapImageRep *)getAnimatedBitmapImageRep | 552 | - (NSBitmapImageRep *)getAnimatedBitmapImageRep |
diff --git a/src/nsterm.h b/src/nsterm.h index d03908eb521..0009f1ab2bf 100644 --- a/src/nsterm.h +++ b/src/nsterm.h | |||
| @@ -671,7 +671,11 @@ enum ns_return_frame_mode | |||
| 671 | { | 671 | { |
| 672 | NSBitmapImageRep *bmRep; /* used for accessing pixel data */ | 672 | NSBitmapImageRep *bmRep; /* used for accessing pixel data */ |
| 673 | unsigned char *pixmapData[5]; /* shortcut to access pixel data */ | 673 | unsigned char *pixmapData[5]; /* shortcut to access pixel data */ |
| 674 | #ifdef NS_IMPL_COCOA | ||
| 675 | CGImageRef stippleMask; | ||
| 676 | #else | ||
| 674 | NSColor *stippleMask; | 677 | NSColor *stippleMask; |
| 678 | #endif /* NS_IMPL_COCOA */ | ||
| 675 | @public | 679 | @public |
| 676 | NSAffineTransform *transform; | 680 | NSAffineTransform *transform; |
| 677 | BOOL smoothing; | 681 | BOOL smoothing; |
| @@ -688,7 +692,11 @@ enum ns_return_frame_mode | |||
| 688 | green: (unsigned char)g blue: (unsigned char)b | 692 | green: (unsigned char)g blue: (unsigned char)b |
| 689 | alpha:(unsigned char)a; | 693 | alpha:(unsigned char)a; |
| 690 | - (void)setAlphaAtX: (int)x Y: (int)y to: (unsigned char)a; | 694 | - (void)setAlphaAtX: (int)x Y: (int)y to: (unsigned char)a; |
| 695 | #ifdef NS_IMPL_COCOA | ||
| 696 | - (CGImageRef)stippleMask; | ||
| 697 | #else | ||
| 691 | - (NSColor *)stippleMask; | 698 | - (NSColor *)stippleMask; |
| 699 | #endif /* NS_IMPL_COCOA */ | ||
| 692 | - (Lisp_Object)getMetadata; | 700 | - (Lisp_Object)getMetadata; |
| 693 | - (BOOL)setFrame: (unsigned int) index; | 701 | - (BOOL)setFrame: (unsigned int) index; |
| 694 | - (void)setTransform: (double[3][3]) m; | 702 | - (void)setTransform: (double[3][3]) m; |
diff --git a/src/nsterm.m b/src/nsterm.m index 12141dfac44..745addfc46c 100644 --- a/src/nsterm.m +++ b/src/nsterm.m | |||
| @@ -3817,8 +3817,41 @@ ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p) | |||
| 3817 | if (s->stippled_p) | 3817 | if (s->stippled_p) |
| 3818 | { | 3818 | { |
| 3819 | struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f); | 3819 | struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f); |
| 3820 | #ifdef NS_IMPL_COCOA | ||
| 3821 | /* On cocoa emacs the stipple is stored as a mask CGImage. | ||
| 3822 | First we want to clear the background with the bg colour */ | ||
| 3823 | [[NSColor colorWithUnsignedLong:face->background] set]; | ||
| 3824 | r = NSMakeRect (s->x, s->y + box_line_width, | ||
| 3825 | s->background_width, | ||
| 3826 | s->height - 2 * box_line_width); | ||
| 3827 | NSRectFill (r); | ||
| 3828 | s->background_filled_p = 1; | ||
| 3829 | CGImageRef mask = | ||
| 3830 | [dpyinfo->bitmaps[face->stipple - 1].img stippleMask]; | ||
| 3831 | |||
| 3832 | /* This part could possibly be improved, the author is | ||
| 3833 | unfamiliar with NS/CoreGraphics and isn't sure if it's | ||
| 3834 | possible to do this with NSImage */ | ||
| 3835 | NSGraphicsContext *ctx = [NSGraphicsContext currentContext]; | ||
| 3836 | [ctx saveGraphicsState]; | ||
| 3837 | /* Checkpoint the graphics state and then focus in on the area | ||
| 3838 | we're going to fill */ | ||
| 3839 | CGContextRef context = [ctx CGContext]; | ||
| 3840 | CGContextClipToRect (context, r); | ||
| 3841 | CGContextScaleCTM (context, 1, -1); | ||
| 3842 | |||
| 3843 | /* Stamp the foreground colour using the stipple mask */ | ||
| 3844 | [[NSColor colorWithUnsignedLong:face->foreground] set]; | ||
| 3845 | CGRect imageSize = CGRectMake (0, 0, CGImageGetWidth (mask), | ||
| 3846 | CGImageGetHeight (mask)); | ||
| 3847 | CGContextDrawTiledImage (context, imageSize, mask); | ||
| 3848 | |||
| 3849 | [[NSGraphicsContext currentContext] restoreGraphicsState]; | ||
| 3850 | #else | ||
| 3820 | [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set]; | 3851 | [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set]; |
| 3821 | goto fill; | 3852 | goto fill; |
| 3853 | #endif /* NS_IMPL_COCOA */ | ||
| 3854 | |||
| 3822 | } | 3855 | } |
| 3823 | else if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width | 3856 | else if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width |
| 3824 | /* When xdisp.c ignores FONT_HEIGHT, we cannot trust font | 3857 | /* When xdisp.c ignores FONT_HEIGHT, we cannot trust font |
| @@ -3841,7 +3874,9 @@ ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p) | |||
| 3841 | else | 3874 | else |
| 3842 | [FRAME_CURSOR_COLOR (s->f) set]; | 3875 | [FRAME_CURSOR_COLOR (s->f) set]; |
| 3843 | 3876 | ||
| 3877 | #ifndef NS_IMPL_COCOA | ||
| 3844 | fill: | 3878 | fill: |
| 3879 | #endif /* !NS_IMPL_COCOA */ | ||
| 3845 | r = NSMakeRect (s->x, s->y + box_line_width, | 3880 | r = NSMakeRect (s->x, s->y + box_line_width, |
| 3846 | s->background_width, | 3881 | s->background_width, |
| 3847 | s->height - 2 * box_line_width); | 3882 | s->height - 2 * box_line_width); |
| @@ -4166,7 +4201,38 @@ ns_draw_stretch_glyph_string (struct glyph_string *s) | |||
| 4166 | if (s->hl == DRAW_CURSOR) | 4201 | if (s->hl == DRAW_CURSOR) |
| 4167 | [FRAME_CURSOR_COLOR (s->f) set]; | 4202 | [FRAME_CURSOR_COLOR (s->f) set]; |
| 4168 | else if (s->stippled_p) | 4203 | else if (s->stippled_p) |
| 4169 | [[dpyinfo->bitmaps[s->face->stipple - 1].img stippleMask] set]; | 4204 | { |
| 4205 | #ifdef NS_IMPL_COCOA | ||
| 4206 | /* On cocoa emacs the stipple is stored as a mask CGImage. | ||
| 4207 | First we want to clear the background with the bg | ||
| 4208 | colour */ | ||
| 4209 | [[NSColor colorWithUnsignedLong:s->face->background] set]; | ||
| 4210 | NSRectFill (NSMakeRect (x, s->y, background_width, s->height)); | ||
| 4211 | |||
| 4212 | /* This part could possibly be improved, the author is | ||
| 4213 | unfamiliar with NS/CoreGraphics and isn't sure if it's | ||
| 4214 | possible to do this with NSImage */ | ||
| 4215 | CGImageRef mask = [dpyinfo->bitmaps[s->face->stipple - 1].img stippleMask]; | ||
| 4216 | CGRect bounds = CGRectMake (s->x, s->y, s->background_width, s->height); | ||
| 4217 | |||
| 4218 | /* Checkpoint the graphics state and then focus in on the | ||
| 4219 | area we're going to fill */ | ||
| 4220 | NSGraphicsContext *ctx = [NSGraphicsContext currentContext]; | ||
| 4221 | [ctx saveGraphicsState]; | ||
| 4222 | CGContextRef context = [ctx CGContext]; | ||
| 4223 | CGContextClipToRect(context, bounds); | ||
| 4224 | CGContextScaleCTM (context, 1, -1); | ||
| 4225 | |||
| 4226 | /* Stamp the foreground colour using the stipple mask */ | ||
| 4227 | [[NSColor colorWithUnsignedLong:s->face->foreground] set]; | ||
| 4228 | CGRect imageSize = CGRectMake (0, 0, CGImageGetWidth (mask), | ||
| 4229 | CGImageGetHeight (mask)); | ||
| 4230 | CGContextDrawTiledImage (context, imageSize, mask); | ||
| 4231 | [[NSGraphicsContext currentContext] restoreGraphicsState]; | ||
| 4232 | #else | ||
| 4233 | [[dpyinfo->bitmaps[s->face->stipple - 1].img stippleMask] set]; | ||
| 4234 | #endif /* NS_IMPL_COCOA */ | ||
| 4235 | } | ||
| 4170 | else | 4236 | else |
| 4171 | [[NSColor colorWithUnsignedLong: s->face->background] set]; | 4237 | [[NSColor colorWithUnsignedLong: s->face->background] set]; |
| 4172 | 4238 | ||