2013-06-25 17:13:37 +00:00
|
|
|
/*
|
|
|
|
OpalGState.m
|
|
|
|
|
|
|
|
Copyright (C) 2013 Free Software Foundation, Inc.
|
|
|
|
|
|
|
|
Author: Ivan Vucica <ivan@vucica.net>
|
|
|
|
Date: June 2013
|
|
|
|
|
|
|
|
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 <http://www.gnu.org/licenses/> or write to the
|
|
|
|
Free Software Foundation, 51 Franklin Street, Fifth Floor,
|
|
|
|
Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
|
2013-07-11 20:44:32 +00:00
|
|
|
#import <CoreGraphics/CoreGraphics.h>
|
|
|
|
#import <X11/Xlib.h>
|
2013-08-01 22:28:57 +00:00
|
|
|
#import <AppKit/NSGraphics.h> // NS*ColorSpace
|
2013-06-25 17:13:37 +00:00
|
|
|
#import "opal/OpalGState.h"
|
2013-07-11 20:44:32 +00:00
|
|
|
#import "opal/OpalSurface.h"
|
|
|
|
#import "x11/XGServerWindow.h"
|
2013-06-25 17:13:37 +00:00
|
|
|
|
2013-07-15 15:24:04 +00:00
|
|
|
#define CGCTX [self cgContext]
|
|
|
|
|
2013-07-23 23:18:48 +00:00
|
|
|
|
2013-06-25 17:13:37 +00:00
|
|
|
@implementation OpalGState
|
|
|
|
|
2013-07-11 20:44:32 +00:00
|
|
|
// MARK: Minimum required methods
|
|
|
|
// MARK: -
|
|
|
|
|
2013-06-25 17:13:37 +00:00
|
|
|
- (void) DPSinitclip
|
|
|
|
{
|
2013-07-23 23:18:48 +00:00
|
|
|
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
|
2013-07-15 15:24:04 +00:00
|
|
|
|
|
|
|
OPContextResetClip(CGCTX);
|
2013-06-25 17:13:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) DPSclip
|
|
|
|
{
|
2013-07-23 23:18:48 +00:00
|
|
|
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
|
2013-07-15 15:24:04 +00:00
|
|
|
|
|
|
|
CGContextClip(CGCTX);
|
2013-06-25 17:13:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) DPSfill
|
|
|
|
{
|
2013-07-23 23:18:48 +00:00
|
|
|
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
|
2013-07-15 15:24:04 +00:00
|
|
|
|
2013-07-25 14:49:44 +00:00
|
|
|
CGContextFillPath(CGCTX);
|
2013-06-25 17:13:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) DPSimage: (NSAffineTransform *)matrix
|
|
|
|
: (NSInteger)pixelsWide
|
|
|
|
: (NSInteger)pixelsHigh
|
2013-08-01 22:28:57 +00:00
|
|
|
: (NSInteger)bitsPerSample // is this used correctly ?
|
|
|
|
: (NSInteger)samplesPerPixel // < unused
|
2013-06-25 17:13:37 +00:00
|
|
|
: (NSInteger)bitsPerPixel
|
|
|
|
: (NSInteger)bytesPerRow
|
2013-08-01 22:28:57 +00:00
|
|
|
: (BOOL)isPlanar // < unused
|
|
|
|
: (BOOL)hasAlpha // < unused
|
2013-06-25 17:13:37 +00:00
|
|
|
: (NSString *)colorSpaceName
|
|
|
|
: (const unsigned char *const[5])data
|
|
|
|
{
|
2013-07-23 23:18:48 +00:00
|
|
|
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
|
|
|
|
|
|
|
|
// This depends on CGAffineTransform and NSAffineTransformStruct having
|
|
|
|
// the same in-memory layout.
|
|
|
|
// Here's an elementary check if that is true.
|
|
|
|
// We should probably check this in -back's "configure" script.
|
|
|
|
assert(sizeof(CGAffineTransform) == sizeof(NSAffineTransformStruct));
|
|
|
|
NSAffineTransformStruct nsAT = [matrix transformStruct];
|
|
|
|
CGAffineTransform cgAT = *(CGAffineTransform *)&nsAT;
|
|
|
|
|
2013-07-21 11:58:05 +00:00
|
|
|
CGContextSaveGState(CGCTX);
|
2013-08-01 22:28:57 +00:00
|
|
|
// CGContextSetRGBFillColor(CGCTX, 1, 0, 0, 1);
|
2013-07-23 23:18:48 +00:00
|
|
|
CGContextConcatCTM(CGCTX, cgAT);
|
2013-08-01 22:28:57 +00:00
|
|
|
// CGContextFillRect(CGCTX, CGRectMake(0, 0, pixelsWide, pixelsHigh));
|
|
|
|
|
|
|
|
// TODO:
|
|
|
|
// We may want to normalize colorspace names between Opal and -gui,
|
|
|
|
// to avoid this conversion?
|
|
|
|
NSLog(@"Colorspace %@", colorSpaceName);
|
|
|
|
if ([colorSpaceName isEqualToString:NSCalibratedRGBColorSpace])
|
|
|
|
colorSpaceName = kCGColorSpaceGenericRGB; // SRGB?
|
|
|
|
else if ([colorSpaceName isEqualToString:NSDeviceRGBColorSpace])
|
|
|
|
colorSpaceName = kCGColorSpaceGenericRGB;
|
|
|
|
|
|
|
|
// TODO: bitsPerComponent (in variable bitsPerSample) is not
|
|
|
|
// liked combined with bitsBerPixel
|
|
|
|
else if ([colorSpaceName isEqualToString:NSCalibratedWhiteColorSpace])
|
|
|
|
colorSpaceName = kCGColorSpaceGenericGray;
|
|
|
|
else if ([colorSpaceName isEqualToString:NSDeviceWhiteColorSpace])
|
|
|
|
colorSpaceName = kCGColorSpaceGenericGray;
|
|
|
|
|
|
|
|
else
|
|
|
|
{
|
|
|
|
NSLog(@"Opal backend: Unhandled colorspace: %@", colorSpaceName);
|
|
|
|
CGContextRestoreGState(CGCTX);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bitsPerPixel != 32)
|
|
|
|
{
|
|
|
|
NSLog(@"Bits per pixel: %d - the only verified combination is 32", bitsPerPixel);
|
|
|
|
CGContextRestoreGState(CGCTX);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
//CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(colorSpaceName);
|
|
|
|
CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
|
|
|
|
#if 0
|
|
|
|
NSData * nsData = [NSData dataWithBytesNoCopy: *data
|
|
|
|
length: pixelsHigh * bytesPerRow];
|
|
|
|
#else
|
|
|
|
#warning Using suboptimal '-dataWithBytes:length:' because NoCopy variant breaks down
|
|
|
|
NSData * nsData = [NSData dataWithBytes: *data
|
|
|
|
length: pixelsHigh * bytesPerRow];
|
|
|
|
#endif
|
|
|
|
|
|
|
|
CGDataProviderRef dataProvider = CGDataProviderCreateWithCFData(nsData);
|
|
|
|
NSLog(@"Bits per component : bitspersample = %d", bitsPerSample);
|
|
|
|
NSLog(@"Bits per pixel : bitsperpixel = %d", bitsPerPixel);
|
|
|
|
NSLog(@" : samplesperpixel = %d", samplesPerPixel);
|
|
|
|
CGImageRef img = CGImageCreate(pixelsWide, pixelsHigh, bitsPerSample,
|
|
|
|
bitsPerPixel, bytesPerRow, colorSpace,
|
|
|
|
hasAlpha ? kCGImageAlphaPremultipliedLast : 0 /* correct? */,
|
|
|
|
dataProvider,
|
|
|
|
NULL /* const CGFloat decode[] is what? */,
|
|
|
|
false, /* shouldInterpolate? */
|
|
|
|
kCGRenderingIntentDefault );
|
|
|
|
CGContextDrawImage(CGCTX, CGRectMake(0, 0, pixelsWide, pixelsHigh), img);
|
|
|
|
CGDataProviderRelease(dataProvider);
|
|
|
|
CGImageRelease(img);
|
2013-07-21 11:58:05 +00:00
|
|
|
CGContextRestoreGState(CGCTX);
|
2013-06-25 17:13:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) compositeGState: (OpalGState *)source
|
|
|
|
fromRect: (NSRect)srcRect
|
|
|
|
toPoint: (NSPoint)destPoint
|
|
|
|
op: (NSCompositingOperation)op
|
|
|
|
fraction: (CGFloat)delta
|
|
|
|
{
|
2013-07-23 23:18:48 +00:00
|
|
|
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
|
2013-07-21 11:58:05 +00:00
|
|
|
#if 1
|
|
|
|
CGContextSaveGState(CGCTX);
|
|
|
|
CGContextSetRGBFillColor(CGCTX, 1, 1, 0, 1);
|
|
|
|
CGContextFillRect(CGCTX, CGRectMake(destPoint.x, destPoint.y, srcRect.size.width, srcRect.size.height));
|
|
|
|
CGContextRestoreGState(CGCTX);
|
|
|
|
#else
|
|
|
|
CGRect srcCGRect = CGRectMake(srcRect.origin.x, srcRect.origin.y,
|
|
|
|
srcRect.size.width, srcRect.size.height);
|
|
|
|
|
|
|
|
// FIXME: this presumes that the backing cgContext of 'source' is
|
|
|
|
// an OpalSurface with a backing CGBitmapContext
|
|
|
|
CGImageRef backingImage = CGBitmapContextCreateImage([source cgContext]);
|
|
|
|
CGContextMoveToPoint(CGCTX, destPoint.x, destPoint.y);
|
|
|
|
// TODO: this ignores op
|
|
|
|
// TODO: this ignores delta
|
|
|
|
CGContextDrawImage(CGCTX, srcCGRect, backingImage);
|
|
|
|
CGImageRelease(backingImage);
|
|
|
|
#endif
|
2013-06-25 17:13:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void) compositerect: (NSRect)aRect
|
|
|
|
op: (NSCompositingOperation)op
|
|
|
|
{
|
2013-07-23 23:18:48 +00:00
|
|
|
NSDebugLLog(@"OpalGState", @"%p (%@): %s - %@", self, [self class], __PRETTY_FUNCTION__, NSStringFromRect(aRect));
|
2013-07-15 15:24:04 +00:00
|
|
|
|
|
|
|
CGContextSaveGState(CGCTX);
|
2013-07-21 11:58:05 +00:00
|
|
|
[self DPSinitmatrix];
|
|
|
|
CGContextFillRect(CGCTX, CGRectMake(aRect.origin.x, [_opalSurface device]->buffer_height - aRect.origin.y,
|
2013-07-15 15:24:04 +00:00
|
|
|
aRect.size.width, aRect.size.height));
|
|
|
|
CGContextRestoreGState(CGCTX);
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) DPSsetdash: (const CGFloat*)pat
|
|
|
|
: (NSInteger)size
|
|
|
|
: (CGFloat)offset
|
|
|
|
{
|
2013-07-23 23:18:48 +00:00
|
|
|
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
|
2013-06-25 17:13:37 +00:00
|
|
|
|
2013-07-15 15:24:04 +00:00
|
|
|
// TODO: stub
|
|
|
|
}
|
|
|
|
- (void) DPSstroke
|
|
|
|
{
|
2013-07-23 23:18:48 +00:00
|
|
|
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
|
2013-07-15 15:24:04 +00:00
|
|
|
|
|
|
|
CGContextStrokePath(CGCTX);
|
2013-07-11 20:44:32 +00:00
|
|
|
}
|
|
|
|
|
2013-08-01 22:28:57 +00:00
|
|
|
- (void) DPSsetlinejoin: (int)linejoin
|
|
|
|
{
|
|
|
|
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
|
|
|
|
|
|
|
|
// TODO: stub
|
|
|
|
}
|
|
|
|
- (void) DPSsetlinecap: (int)linecap
|
|
|
|
{
|
|
|
|
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
|
|
|
|
|
|
|
|
// TODO: stub
|
|
|
|
}
|
|
|
|
- (void) DPSsetmiterlimit: (CGFloat)miterlimit
|
|
|
|
{
|
|
|
|
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
|
|
|
|
|
|
|
|
// TODO: stub
|
|
|
|
}
|
2013-07-11 20:44:32 +00:00
|
|
|
@end
|
|
|
|
|
|
|
|
// MARK: Initialization methods
|
|
|
|
// MARK: -
|
|
|
|
|
|
|
|
@implementation OpalGState (InitializationMethods)
|
|
|
|
|
|
|
|
/* SOME NOTES:
|
|
|
|
- GState approximates a cairo context: a drawing state.
|
|
|
|
- Surface approximates a cairo surface: a place to draw things.
|
|
|
|
|
|
|
|
- CGContext seems to be a mix of these two: surface + state.
|
|
|
|
|
|
|
|
Should we unite these two somehow? Can we unite these two somehow?
|
|
|
|
Possibly not. We still need to support bitmap contexts, pdf contexts
|
|
|
|
etc which contain both state and contents.
|
|
|
|
|
|
|
|
So, we will still need surfaces (containing CGContexts, hence including
|
|
|
|
state) and GState as a wrapper around whatever context happens to be
|
|
|
|
the current one.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
Makes the specified surface active in the current graphics state,
|
2013-07-21 11:58:05 +00:00
|
|
|
ready for use. Also, sets the device offset to specified coordinates.
|
2013-07-11 20:44:32 +00:00
|
|
|
**/
|
|
|
|
- (void) GSSetSurface: (OpalSurface *)opalSurface
|
|
|
|
: (int)x
|
|
|
|
: (int)y
|
|
|
|
{
|
2013-07-23 23:18:48 +00:00
|
|
|
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
|
2013-07-11 20:44:32 +00:00
|
|
|
|
2013-07-21 11:58:05 +00:00
|
|
|
if(_opalSurface != opalSurface)
|
|
|
|
{
|
|
|
|
id old = _opalSurface;
|
|
|
|
_opalSurface = [opalSurface retain];
|
|
|
|
[old release];
|
|
|
|
}
|
|
|
|
|
|
|
|
[self setOffset: NSMakePoint(x, y)];
|
|
|
|
[self DPSinitgraphics];
|
2013-07-11 20:44:32 +00:00
|
|
|
}
|
2013-07-15 15:24:04 +00:00
|
|
|
- (id) GSCurrentSurface: (OpalSurface **)surface
|
|
|
|
: (int *)x
|
|
|
|
: (int *)y
|
|
|
|
{
|
2013-07-23 23:18:48 +00:00
|
|
|
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
|
2013-07-11 20:44:32 +00:00
|
|
|
|
2013-07-15 15:24:04 +00:00
|
|
|
return _opalSurface;
|
|
|
|
}
|
2013-07-11 20:44:32 +00:00
|
|
|
/**
|
|
|
|
Sets up a new CG*Context() for drawing content.
|
|
|
|
**/
|
|
|
|
- (void) DPSinitgraphics
|
|
|
|
{
|
2013-07-23 23:18:48 +00:00
|
|
|
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
|
2013-07-11 20:44:32 +00:00
|
|
|
|
|
|
|
[super DPSinitgraphics];
|
|
|
|
|
2013-07-21 11:58:05 +00:00
|
|
|
[_opalSurface createCGContexts];
|
2013-07-25 14:49:44 +00:00
|
|
|
/*
|
|
|
|
if ([_opalSurface device])
|
|
|
|
{
|
|
|
|
CGContextTranslateCTM(CGCTX, 0, [_opalSurface device]->buffer_height);
|
|
|
|
CGContextScaleCTM(CGCTX, 1, -1);
|
|
|
|
}
|
|
|
|
*/
|
2013-07-11 20:44:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
2013-07-15 15:24:04 +00:00
|
|
|
// MARK: Accessors
|
2013-07-11 20:44:32 +00:00
|
|
|
// MARK: -
|
|
|
|
|
2013-07-15 15:24:04 +00:00
|
|
|
@implementation OpalGState (Accessors)
|
2013-07-11 20:44:32 +00:00
|
|
|
|
2013-07-15 15:24:04 +00:00
|
|
|
- (CGContextRef) cgContext
|
|
|
|
{
|
2013-07-23 23:18:48 +00:00
|
|
|
if (!_opalSurface)
|
|
|
|
NSDebugMLLog(@"OpalGState", @"No OpalSurface");
|
|
|
|
else if (![_opalSurface cgContext])
|
|
|
|
NSDebugMLLog(@"OpalGState", @"No OpalSurface CGContext");
|
2013-07-15 15:24:04 +00:00
|
|
|
return [_opalSurface cgContext];
|
|
|
|
}
|
2013-07-11 20:44:32 +00:00
|
|
|
|
2013-07-15 15:24:04 +00:00
|
|
|
@end
|
|
|
|
|
|
|
|
// MARK: Non-required methods
|
|
|
|
// MARK: -
|
|
|
|
static CGFloat theAlpha = 1.; // TODO: removeme
|
|
|
|
@implementation OpalGState (NonrequiredMethods)
|
|
|
|
|
|
|
|
- (void) DPSsetrgbcolor: (CGFloat)r : (CGFloat)g : (CGFloat)b
|
2013-07-11 20:44:32 +00:00
|
|
|
{
|
2013-07-23 23:18:48 +00:00
|
|
|
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
|
2013-07-15 15:24:04 +00:00
|
|
|
|
|
|
|
const CGFloat alpha = 1; // TODO: is this correct?
|
2013-07-21 11:58:05 +00:00
|
|
|
if(!CGCTX)
|
|
|
|
return;
|
2013-07-25 14:49:44 +00:00
|
|
|
CGContextSetRGBStrokeColor(CGCTX, r, g, b, alpha);
|
2013-07-15 15:24:04 +00:00
|
|
|
CGContextSetRGBFillColor(CGCTX, r, g, b, alpha);
|
2013-07-11 20:44:32 +00:00
|
|
|
}
|
2013-07-15 15:24:04 +00:00
|
|
|
- (void) DPSrectfill: (CGFloat)x : (CGFloat)y : (CGFloat)w : (CGFloat)h
|
2013-07-11 20:44:32 +00:00
|
|
|
{
|
2013-07-23 23:18:48 +00:00
|
|
|
NSDebugLLog(@"OpalGState", @"%p (%@): %s - rect %g %g %g %g", self, [self class], __PRETTY_FUNCTION__, x, y, w, h);
|
2013-07-21 11:58:05 +00:00
|
|
|
|
2013-07-15 15:24:04 +00:00
|
|
|
CGContextFillRect(CGCTX, CGRectMake(x, y, w, h));
|
2013-07-11 20:44:32 +00:00
|
|
|
}
|
2013-07-15 15:24:04 +00:00
|
|
|
- (void) DPSrectclip: (CGFloat)x : (CGFloat)y : (CGFloat)w : (CGFloat)h
|
2013-07-11 20:44:32 +00:00
|
|
|
{
|
2013-07-23 23:18:48 +00:00
|
|
|
NSDebugLLog(@"OpalGState", @"%p (%@): %s - %g %g %g %g", self, [self class], __PRETTY_FUNCTION__, x, y, w, h);
|
2013-07-15 15:24:04 +00:00
|
|
|
|
2013-07-21 11:58:05 +00:00
|
|
|
[self DPSinitclip];
|
2013-07-15 15:24:04 +00:00
|
|
|
CGContextClipToRect(CGCTX, CGRectMake(x, y, w, h));
|
2013-07-11 20:44:32 +00:00
|
|
|
}
|
2013-07-15 15:24:04 +00:00
|
|
|
- (void) DPSsetgray: (CGFloat)gray
|
2013-07-11 20:44:32 +00:00
|
|
|
{
|
2013-07-23 23:18:48 +00:00
|
|
|
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
|
2013-07-15 15:24:04 +00:00
|
|
|
|
|
|
|
const CGFloat alpha = 1; // TODO: is this correct?
|
|
|
|
CGContextSetGrayFillColor(CGCTX, gray, alpha);
|
2013-07-11 20:44:32 +00:00
|
|
|
}
|
|
|
|
- (void) DPSsetalpha: (CGFloat)a
|
2013-07-15 15:24:04 +00:00
|
|
|
{
|
2013-07-23 23:18:48 +00:00
|
|
|
NSDebugLLog(@"OpalGState", @"%p (%@): %s - alpha %g", self, [self class], __PRETTY_FUNCTION__, a);
|
2013-07-15 15:24:04 +00:00
|
|
|
|
|
|
|
CGContextSetAlpha(CGCTX, a);
|
|
|
|
theAlpha = a;
|
|
|
|
}
|
|
|
|
- (void)DPSinitmatrix
|
2013-07-11 20:44:32 +00:00
|
|
|
{
|
2013-07-23 23:18:48 +00:00
|
|
|
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
|
2013-07-15 15:24:04 +00:00
|
|
|
|
|
|
|
OPContextSetIdentityCTM(CGCTX);
|
2013-07-21 11:58:05 +00:00
|
|
|
#if 0
|
|
|
|
// Flipping the coordinate system is NOT required
|
|
|
|
CGContextTranslateCTM(CGCTX, 0, [_opalSurface device]->buffer_height);
|
|
|
|
CGContextScaleCTM(CGCTX, 1, -1);
|
|
|
|
#endif
|
|
|
|
[super DPSinitmatrix];
|
2013-07-11 20:44:32 +00:00
|
|
|
}
|
2013-07-15 15:24:04 +00:00
|
|
|
- (void)DPSconcat: (const CGFloat *)m
|
2013-07-11 20:44:32 +00:00
|
|
|
{
|
2013-07-23 23:18:48 +00:00
|
|
|
NSDebugLLog(@"OpalGState", @"%p (%@): %s - %g %g %g %g %g %g", self, [self class], __PRETTY_FUNCTION__, m[0], m[1], m[2], m[3], m[4], m[5]);
|
2013-07-15 15:24:04 +00:00
|
|
|
|
|
|
|
CGContextConcatCTM(CGCTX, CGAffineTransformMake(
|
|
|
|
m[0], m[1], m[2],
|
|
|
|
m[3], m[4], m[5]));
|
2013-07-21 11:58:05 +00:00
|
|
|
[super DPSconcat:m];
|
2013-07-11 20:44:32 +00:00
|
|
|
}
|
2013-07-15 15:24:04 +00:00
|
|
|
- (void)DPSscale: (CGFloat)x
|
|
|
|
: (CGFloat)y
|
2013-07-11 20:44:32 +00:00
|
|
|
{
|
2013-07-23 23:18:48 +00:00
|
|
|
NSDebugLLog(@"OpalGState", @"%p (%@): %s - %g %g", self, [self class], __PRETTY_FUNCTION__, x, y);
|
2013-07-15 15:24:04 +00:00
|
|
|
|
|
|
|
CGContextScaleCTM(CGCTX, x, y);
|
2013-07-11 20:44:32 +00:00
|
|
|
}
|
2013-07-15 15:24:04 +00:00
|
|
|
- (void)DPStranslate: (CGFloat)x
|
|
|
|
: (CGFloat)y
|
2013-07-11 20:44:32 +00:00
|
|
|
{
|
2013-07-23 23:18:48 +00:00
|
|
|
NSDebugLLog(@"OpalGState", @"%p (%@): %s - x %g y %g", self, [self class], __PRETTY_FUNCTION__, x, y);
|
2013-07-15 15:24:04 +00:00
|
|
|
|
|
|
|
CGContextTranslateCTM(CGCTX, x, y);
|
2013-07-21 11:58:05 +00:00
|
|
|
[super DPStranslate:x:y];
|
2013-07-11 20:44:32 +00:00
|
|
|
}
|
2013-07-15 15:24:04 +00:00
|
|
|
- (void) DPSmoveto: (CGFloat) x
|
|
|
|
: (CGFloat) y
|
2013-07-11 20:44:32 +00:00
|
|
|
{
|
2013-07-23 23:18:48 +00:00
|
|
|
NSDebugLLog(@"OpalGState", @"%p (%@): %s - %g %g", self, [self class], __PRETTY_FUNCTION__, x, y);
|
2013-07-15 15:24:04 +00:00
|
|
|
|
|
|
|
CGContextMoveToPoint(CGCTX, x, y);
|
2013-07-11 20:44:32 +00:00
|
|
|
}
|
2013-07-15 15:24:04 +00:00
|
|
|
- (void) DPSlineto: (CGFloat) x
|
|
|
|
: (CGFloat) y
|
2013-07-11 20:44:32 +00:00
|
|
|
{
|
2013-07-23 23:18:48 +00:00
|
|
|
NSDebugLLog(@"OpalGState", @"%p (%@): %s - %g %g", self, [self class], __PRETTY_FUNCTION__, x, y);
|
2013-07-15 15:24:04 +00:00
|
|
|
|
|
|
|
CGContextAddLineToPoint(CGCTX, x, y);
|
2013-07-11 20:44:32 +00:00
|
|
|
}
|
2013-07-21 11:58:05 +00:00
|
|
|
- (void) setOffset: (NSPoint)theOffset
|
|
|
|
{
|
2013-07-23 23:18:48 +00:00
|
|
|
NSDebugLLog(@"OpalGState", @"%p (%@): %s - %g %g", self, [self class], __PRETTY_FUNCTION__, theOffset.x, theOffset.y);
|
2013-07-15 15:24:04 +00:00
|
|
|
|
2013-07-21 11:58:05 +00:00
|
|
|
#if 1
|
|
|
|
if (CGCTX != nil)
|
|
|
|
{
|
|
|
|
#if 1
|
|
|
|
OPContextSetCairoDeviceOffset(CGCTX, -theOffset.x,
|
|
|
|
theOffset.y - [_opalSurface device]->buffer_height);
|
|
|
|
#else
|
|
|
|
OPContextSetCairoDeviceOffset(CGCTX, theOffset.x,
|
|
|
|
theOffset.y);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
// This is a BAD hack using transform matrix.
|
|
|
|
// It'll break horribly when Opal state is saved and restored.
|
|
|
|
static NSPoint OFFSET = { 0, 0 };
|
|
|
|
//CGContextTranslateCTM(CGCTX, -(-OFFSET.x),
|
|
|
|
// -(OFFSET.y - [_opalSurface device]->buffer_height));
|
|
|
|
CGContextTranslateCTM(CGCTX, -theOffset.x,
|
|
|
|
theOffset.y - [_opalSurface device]->buffer_height);
|
|
|
|
|
|
|
|
OFFSET = theOffset;
|
|
|
|
#endif
|
|
|
|
[super setOffset: theOffset];
|
|
|
|
}
|
2013-07-11 20:44:32 +00:00
|
|
|
/*
|
2013-07-15 15:24:04 +00:00
|
|
|
- (void) setColor: (device_color_t *)color state: (color_state_t)cState
|
2013-07-11 20:44:32 +00:00
|
|
|
{
|
2013-07-23 23:18:48 +00:00
|
|
|
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
|
2013-07-15 15:24:04 +00:00
|
|
|
|
|
|
|
[super setColor: color
|
|
|
|
state: cState];
|
|
|
|
|
|
|
|
switch (color->space)
|
|
|
|
{
|
|
|
|
case rgb_colorspace:
|
|
|
|
if (cState & COLOR_STROKE)
|
|
|
|
CGContextSetRGBStrokeColor(CGCTX, color->field[0],
|
|
|
|
color->field[1], color->field[2], color->field[3]);
|
|
|
|
if (cState & COLOR_FILL)
|
|
|
|
CGContextSetRGBFillColor(CGCTX, color->field[0],
|
|
|
|
color->field[1], color->field[2], color->field[3]);
|
|
|
|
break;
|
|
|
|
}
|
2013-07-11 20:44:32 +00:00
|
|
|
}
|
|
|
|
*/
|
2013-07-23 23:18:48 +00:00
|
|
|
- (NSAffineTransform *) GSCurrentCTM
|
|
|
|
{
|
|
|
|
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
|
|
|
|
|
|
|
|
CGAffineTransform cgCTM = CGContextGetCTM(CGCTX);
|
|
|
|
NSAffineTransform * affineTransform = [NSAffineTransform transform];
|
|
|
|
|
|
|
|
// This depends on CGAffineTransform and NSAffineTransformStruct having
|
|
|
|
// the same in-memory layout.
|
|
|
|
// Here's an elementary check if that is true.
|
|
|
|
// We should probably check this in -back's "configure" script.
|
|
|
|
assert(sizeof(CGAffineTransform) == sizeof(NSAffineTransformStruct));
|
|
|
|
|
|
|
|
NSAffineTransformStruct nsCTM = *(NSAffineTransformStruct *)&cgCTM;
|
|
|
|
[affineTransform setTransformStruct: nsCTM];
|
|
|
|
|
|
|
|
return affineTransform;
|
|
|
|
}
|
|
|
|
- (void) flushGraphics
|
|
|
|
{
|
|
|
|
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
|
|
|
|
CGContextFlush(CGCTX);
|
|
|
|
[_opalSurface handleExpose:CGRectMake(0, 0, 1024, 1024)];
|
|
|
|
}
|
2013-07-25 14:49:44 +00:00
|
|
|
- (void) DPSgsave
|
|
|
|
{
|
|
|
|
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
|
|
|
|
#warning Opal bug: nil ctx should 'only' print a warning instead of crashing
|
|
|
|
if (CGCTX)
|
|
|
|
CGContextSaveGState(CGCTX);
|
|
|
|
}
|
|
|
|
- (void) DPSgrestore
|
|
|
|
{
|
|
|
|
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
|
|
|
|
#warning Opal bug: nil ctx should 'only' print a warning instead of crashing
|
|
|
|
if (CGCTX)
|
|
|
|
CGContextRestoreGState(CGCTX);
|
|
|
|
}
|
|
|
|
- (void *) saveClip
|
|
|
|
{
|
|
|
|
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
|
|
|
|
CGRect * r = calloc(sizeof(CGRect), 1);
|
|
|
|
*r = CGContextGetClipBoundingBox(CGCTX);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
- (void) restoreClip: (void *)savedClip
|
|
|
|
{
|
|
|
|
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
|
|
|
|
OPContextResetClip(CGCTX);
|
|
|
|
CGContextClipToRect(CGCTX, *(CGRect *)savedClip);
|
|
|
|
free(savedClip);
|
|
|
|
}
|
|
|
|
- (void) DPSeoclip
|
|
|
|
{
|
|
|
|
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
|
|
|
|
|
|
|
|
CGContextEOClip(CGCTX);
|
|
|
|
}
|
|
|
|
- (void) DPSeofill
|
|
|
|
{
|
|
|
|
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
|
|
|
|
|
|
|
|
CGContextEOFillPath(CGCTX);
|
|
|
|
}
|
|
|
|
- (void) DPSshow: (const char *)s
|
2013-07-23 23:18:48 +00:00
|
|
|
{
|
|
|
|
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
|
2013-07-25 14:49:44 +00:00
|
|
|
|
2013-07-23 23:18:48 +00:00
|
|
|
CGContextSaveGState(CGCTX);
|
2013-07-25 14:49:44 +00:00
|
|
|
CGContextSetRGBFillColor(CGCTX, 0, 1, 0, 1);
|
|
|
|
CGContextFillRect(CGCTX, CGRectMake(0, 0, 12, strlen(s) * 12));
|
|
|
|
CGContextRestoreGState(CGCTX);
|
2013-07-23 23:18:48 +00:00
|
|
|
}
|
2013-07-25 14:49:44 +00:00
|
|
|
- (void) GSShowText: (const char *)s : (size_t) length
|
2013-07-23 23:18:48 +00:00
|
|
|
{
|
|
|
|
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
|
2013-07-25 14:49:44 +00:00
|
|
|
/*
|
|
|
|
const char * s2 = calloc(s, length+1);
|
|
|
|
strcpy(s2, s);
|
|
|
|
*/
|
|
|
|
CGContextSaveGState(CGCTX);
|
|
|
|
CGContextSetRGBFillColor(CGCTX, 0, 1, 0, 1);
|
|
|
|
CGContextFillRect(CGCTX, CGRectMake(0, 0, 12, length * 12));
|
2013-07-23 23:18:48 +00:00
|
|
|
CGContextRestoreGState(CGCTX);
|
2013-07-25 14:49:44 +00:00
|
|
|
// free(s2);
|
|
|
|
}
|
|
|
|
- (void) GSShowGlyphsWithAdvances: (const NSGlyph *)glyphs : (const NSSize *)advances : (size_t) length
|
|
|
|
{
|
|
|
|
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
|
|
|
|
CGContextSaveGState(CGCTX);
|
|
|
|
CGContextSetRGBFillColor(CGCTX, 0, 1, 0, 1);
|
|
|
|
CGContextFillRect(CGCTX, CGRectMake(0, 0, 12, length * 12));
|
|
|
|
CGContextRestoreGState(CGCTX);
|
|
|
|
|
|
|
|
}
|
|
|
|
#if 0
|
|
|
|
- (void) DPSrlineto: (CGFloat) x
|
|
|
|
: (CGFloat) y
|
|
|
|
{
|
|
|
|
NSDebugLLog(@"OpalGState", @"%p (%@): %s - %g %g", self, [self class], __PRETTY_FUNCTION__, x, y);
|
|
|
|
|
|
|
|
CGContextAddRelativeLine(CGCTX, x, y);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
#warning -DPSrlineto:: not implemented directly
|
|
|
|
#endif
|
|
|
|
- (void) DPScurrentpoint: (CGFloat *)x
|
|
|
|
: (CGFloat *)y
|
|
|
|
{
|
|
|
|
NSDebugLLog(@"OpalGState", @"%p (%@): %s - %g %g", self, [self class], __PRETTY_FUNCTION__, x, y);
|
|
|
|
|
|
|
|
CGPoint currentPoint = CGContextGetPathCurrentPoint(CGCTX);
|
|
|
|
*x = currentPoint.x;
|
|
|
|
*y = currentPoint.y;
|
2013-07-23 23:18:48 +00:00
|
|
|
}
|
2013-07-15 15:24:04 +00:00
|
|
|
@end
|
|
|
|
|
|
|
|
// MARK: Non-required unimplemented methods
|
|
|
|
// MARK: -
|
|
|
|
|
|
|
|
@implementation OpalGState (NonrequiredUnimplementedMethods)
|
|
|
|
|
|
|
|
/*
|
|
|
|
Methods that follow have not been implemented.
|
|
|
|
They are here to prevent GSGState implementations from
|
|
|
|
executing.
|
|
|
|
|
|
|
|
Sole criteria for picking them is looking at what methods
|
|
|
|
are called by a dummy AppKit application with a single
|
|
|
|
empty NSWindow.
|
|
|
|
*/
|
|
|
|
|
|
|
|
- (void) DPSsetlinewidth: (CGFloat) width
|
2013-07-11 20:44:32 +00:00
|
|
|
{
|
2013-07-23 23:18:48 +00:00
|
|
|
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
|
2013-06-25 17:13:37 +00:00
|
|
|
}
|
2013-07-25 14:49:44 +00:00
|
|
|
- (void) DPSsetgstate: (NSInteger) gst
|
|
|
|
{
|
|
|
|
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
|
|
|
|
abort();
|
|
|
|
}
|
2013-07-15 15:24:04 +00:00
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation OpalGState (Unused)
|
|
|
|
|
|
|
|
- (void) _setPath
|
|
|
|
{
|
|
|
|
#if 0
|
|
|
|
NSInteger count = [path elementCount];
|
|
|
|
NSInteger i;
|
|
|
|
SEL elmsel = @selector(elementAtIndex:associatedPoints:);
|
|
|
|
NSBezierPathElement (*elmidx)(id, SEL, NSInteger, NSPoint*) =
|
|
|
|
(NSBezierPathElement (*)(id, SEL, NSInteger, NSPoint*))[path methodForSelector: elmsel];
|
|
|
|
|
|
|
|
// reset current cairo path
|
|
|
|
cairo_new_path(_ct);
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
{
|
|
|
|
NSBezierPathElement type;
|
|
|
|
NSPoint points[3];
|
|
|
|
|
|
|
|
type = (NSBezierPathElement)(*elmidx)(path, elmsel, i, points);
|
|
|
|
switch(type)
|
|
|
|
{
|
|
|
|
case NSMoveToBezierPathElement:
|
|
|
|
cairo_move_to(_ct, points[0].x, points[0].y);
|
|
|
|
break;
|
|
|
|
case NSLineToBezierPathElement:
|
|
|
|
cairo_line_to(_ct, points[0].x, points[0].y);
|
|
|
|
break;
|
|
|
|
case NSCurveToBezierPathElement:
|
|
|
|
cairo_curve_to(_ct, points[0].x, points[0].y,
|
|
|
|
points[1].x, points[1].y,
|
|
|
|
points[2].x, points[2].y);
|
|
|
|
break;
|
|
|
|
case NSClosePathBezierPathElement:
|
|
|
|
cairo_close_path(_ct);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2013-06-25 17:13:37 +00:00
|
|
|
|
|
|
|
@end
|