From 720a56dcf3dc817f8bf54c12224ed2a2e8518bba Mon Sep 17 00:00:00 2001 From: Daniel Ferreira Date: Thu, 20 Jul 2017 12:20:33 +1000 Subject: [PATCH 1/3] opal/context: allow the client to supply a graphics port In Quartz, the "graphics port" bound to an NSGraphicsContext (subclassed by OpalContext) is a CGContext. We currently initialize one in OpalSurface if it does not exist, however we do not allow the client to initialize a graphics context with a custom graphics port, which should be allowed. This commit enables this feature. --- Headers/opal/OpalSurface.h | 2 +- Source/opal/OpalContext.m | 16 ++++++++++++++-- Source/opal/OpalSurface.m | 10 ++++++---- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/Headers/opal/OpalSurface.h b/Headers/opal/OpalSurface.h index 1e6e104..4e57425 100644 --- a/Headers/opal/OpalSurface.h +++ b/Headers/opal/OpalSurface.h @@ -35,7 +35,7 @@ CGContextRef _x11CGContext; } -- (id) initWithDevice: (void *)device; +- (id) initWithDevice: (void *)device context: (CGContextRef)ctx; - (void *)device; - (CGContextRef) CGContext; - (NSSize) size; diff --git a/Source/opal/OpalContext.m b/Source/opal/OpalContext.m index e77a03c..74983e2 100644 --- a/Source/opal/OpalContext.m +++ b/Source/opal/OpalContext.m @@ -167,8 +167,20 @@ : (int)y { OpalSurface *surface; - - surface = [[OpalSurface alloc] initWithDevice: device]; + + /* + * The "graphics port" associated to an OpalContext is necessarily a + * CGContextRef supplied by the client to back the OpalContext, instead + * of having us create the CGContextRef ourselves. + * + * Since -graphicsPort is overriden from NSGraphicsContext to compute the + * CGContextRef for an OpalSurface (which is not initialized yet), we + * get the _graphicsPort ivar directly to obtain the supplied CGContextRef + * on initialization, and use that to init our surface. + */ + CGContextRef suppliedContext = self->_graphicsPort; + surface = [[OpalSurface alloc] initWithDevice: device + context: suppliedContext]; [OGSTATE GSSetSurface: surface : x diff --git a/Source/opal/OpalSurface.m b/Source/opal/OpalSurface.m index c49d8d1..13df6df 100644 --- a/Source/opal/OpalSurface.m +++ b/Source/opal/OpalSurface.m @@ -70,7 +70,7 @@ static CGContextRef createCGBitmapContext(int pixelsWide, @implementation OpalSurface -- (void) createCGContexts +- (void) createCGContextsWithSuppliedBackingContext: (CGContextRef)ctx { // FIXME: this method and class presumes we are being passed // a window device. @@ -83,7 +83,7 @@ static CGContextRef createCGBitmapContext(int pixelsWide, Display * display = _gsWindowDevice->display; Window window = _gsWindowDevice->ident; - _x11CGContext = OPX11ContextCreate(display, window); + _x11CGContext = ctx ?: OPX11ContextCreate(display, window); #if 0 if (_gsWindowDevice->type == NSBackingStoreNonretained) @@ -114,7 +114,9 @@ static CGContextRef createCGBitmapContext(int pixelsWide, } -- (id) initWithDevice: (void *)device +// FIXME: *VERY* bad things will happen if a non-bitmap +// context is passed here. +- (id) initWithDevice: (void *)device context: (CGContextRef)ctx { self = [super init]; if (!self) @@ -124,7 +126,7 @@ static CGContextRef createCGBitmapContext(int pixelsWide, // a window device. _gsWindowDevice = (gswindow_device_t *) device; - [self createCGContexts]; + [self createCGContextsWithSuppliedBackingContext: ctx]; return self; } From 5f62df88d375f17604690eca55d294315bdab70f Mon Sep 17 00:00:00 2001 From: Daniel Ferreira Date: Thu, 20 Jul 2017 12:23:39 +1000 Subject: [PATCH 2/3] opal/bridge: implement bridge between GUI and Opal types Implement a bridge between NSColor and CGColorRef and a stub for a bridge between NSImage and CGImageRef. This improves compatibility with Quartz. --- Source/opal/GNUmakefile | 1 + Source/opal/OpalBridge.m | 116 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+) create mode 100644 Source/opal/OpalBridge.m diff --git a/Source/opal/GNUmakefile b/Source/opal/GNUmakefile index b919753..45decac 100644 --- a/Source/opal/GNUmakefile +++ b/Source/opal/GNUmakefile @@ -37,6 +37,7 @@ opal_OBJC_FILES = OpalSurface.m \ OpalFaceInfo.m \ OpalPSSurface.m \ OpalPDFSurface.m \ + OpalBridge.m \ ../fontconfig/FCFaceInfo.m \ ../fontconfig/FCFontEnumerator.m \ ../fontconfig/FCFontInfo.m \ diff --git a/Source/opal/OpalBridge.m b/Source/opal/OpalBridge.m new file mode 100644 index 0000000..d75d94d --- /dev/null +++ b/Source/opal/OpalBridge.m @@ -0,0 +1,116 @@ +/* + OpalBridge.m + + Copyright (C) 2017 Free Software Foundation, Inc. + + Author: Daniel Ferreira + Date: July 2017 + + This file is part of GNUstep. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; see the file COPYING.LIB. + If not, see or write to the + Free Software Foundation, 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#import +#import +#import +#import +#import +#import +#import + +@implementation NSColor (GSQuartz) +/* + * FIXME: + * NOTE 1: GNUstep-GUI does not allow an NSColor to be created with a custom + * NSColorSpace. If this were allowed, we'd have to: + * 1) implement a bridge for -[NSColorSpace CGColorSpace] + * 2) for each color, extract that color space and generate a CGColorRef. + * NOTE 2: GNUstep-GUI makes no distinction of device and generic color spaces. + * If this ever ceases to be the case, some adjustment might be necessary here. + */ +- (CGColorRef)CGColor +{ + NSString *name = [self colorSpaceName]; + + // FIXME: we should handle black color spaces here, which we currently + // ignore in the implementation. + CFStringRef cgColorSpaceName = NULL; + if ([name isEqualToString: NSCalibratedRGBColorSpace] + || [name isEqualToString: NSDeviceRGBColorSpace]) + cgColorSpaceName = kCGColorSpaceSRGB; + else if ([name isEqualToString: NSCalibratedBlackColorSpace] + || [name isEqualToString: NSCalibratedWhiteColorSpace] + || [name isEqualToString: NSDeviceBlackColorSpace] + || [name isEqualToString: NSDeviceWhiteColorSpace]) + cgColorSpaceName = kCGColorSpaceGenericGray; + else if ([name isEqualToString: NSDeviceCMYKColorSpace]) + cgColorSpaceName = kCGColorSpaceGenericCMYK; + else if ([name isEqualToString: NSNamedColorSpace]) + return [[self colorUsingColorSpaceName: NSDeviceRGBColorSpace] CGColor]; + + if (cgColorSpaceName == NULL) + return NULL; + + CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(cgColorSpaceName); + CGFloat values[10]; + [self getComponents: values]; + + CGColorRef color = CGColorCreate(colorSpace, values); + CFRelease(colorSpace); + + return (CGColorRef)[(id)color autorelease]; +} +@end + +@implementation NSImageRep (GSQuartz) +- (CGImageRef)CGImageForProposedRect: (NSRect *)proposedDestRect + context: (NSGraphicsContext *)referenceContext + hints: (NSDictionary *)hints +{ + /* + * FIXME Must implement this. + * A note for future implementors: + > Apparently each NSImageRep subclass implements this method, with the + > base implementation being[1], as I understand it (which may be wrong): + > i. create a new blank context with *proposedDestRect.size and set it + > as the current context. This context should theoretically be + > constructed with properties extracted from `referenceContext` and/or + > `hints`, although I suppose our first implementation can go without + > that. + > ii. call [self draw]; + > iii. adjust *proposedDestRect to round half-pixels + > iv. extract a CGImage from the bitmap context + > If NSImage.size == *proposedDestRect.size, we should just CGImageCreate + > directly from our representation data. + */ + + return NULL; +} +@end + +@implementation NSImage (GSQuartz) +- (CGImageRef)CGImageForProposedRect: (NSRect *)proposedDestRect + context: (NSGraphicsContext *)referenceContext + hints: (NSDictionary *)hints +{ + // FIXME: Must implement this. + // This should pick the best NSImageRep for this NSImage and call + // -[NSImageRep CGImageForProposedRect:...]. + return NULL; +} +@end From 16a5b54311957dfb874ce4b29077cff255d20978 Mon Sep 17 00:00:00 2001 From: Daniel Ferreira Date: Thu, 20 Jul 2017 12:27:10 +1000 Subject: [PATCH 3/3] Update ChangeLog --- ChangeLog | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/ChangeLog b/ChangeLog index 2f3546b..7357854 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,22 @@ +2017-07-17 Daniel Ferreira + + * Source/opal/GNUmakefile: add OpalBridge.m to project. + * Source/opal/OpalBridge.m: + Implement a bridge between NSColor and CGColorRef and a stub for a + bridge between NSImage and CGImageRef. This improves compatibility with + Quartz. + +2017-07-17 Daniel Ferreira + + * Headers/opal/OpalSurface.h + * Source/opal/OpalContext.m + * Source/opal/OpalSurface.m: + In Quartz, the "graphics port" bound to an NSGraphicsContext (subclassed + by OpalContext) is a CGContext. We currently initialize one in + OpalSurface if it does not exist, however we do not allow the client to + initialize a graphics context with a custom graphics port, which should + be allowed. We have enabled this feature. + 2017-04-16 Fred Kiefer * Source/gsc/GSGState.m