diff --git a/ChangeLog b/ChangeLog index a401bcb..4f2b871 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-07-31 Fred Kiefer * Source/cairo/CairoGState.m (-DPSshow:): Get DPSshow: to work on 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/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 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; }