Fixes for doublebuffering. (Nearly?) correct implementation of -compositeGState: and -drawGState:. Temporarily fixed image drawing issues by lying about drawing to screen.

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/back/trunk@37142 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Ivan Vučica 2013-09-23 18:04:06 +00:00
parent ff80e49fb1
commit 595cc19471
6 changed files with 500 additions and 67 deletions

View file

@ -1,3 +1,69 @@
2013-09-23 Ivan Vucica <ivan@vucica.net>
* Source/opal/OpalContext.m:
Once again pretending we're not drawing on screen. This is a temporary
fix for -DPSimage:.
-DPSgsave is now passed on to current gstate before GSContext is given
chance to replace it.
Changes relating to rename of OpalSurface and OpalGState methods
-cgContext to -CGContext.
* Source/opal/OpalGState.m:
Apparently mostly functional -compositeGState:. Includes disabled
modification of code from CairoGState.
Apparently functional -drawGState.
-DPSsetlinecap: stub (need to match linecap constants.)
-DPSsetmiterlimit:.
Extended -copyWithZone: to assign a 'default' OpalGStateRef to the
newly copied gstate in case we currently have no context. This is
done by creating a context and copying whatever's in that context
onto the new OpalGState.
Improved -DPSinitgraphics by setting the device offset that was
set here and calling CGContextSaveGState() as many times as it
was supposed to be called while CGContext did not exist. Noted
that we should, instead of recreating contexts, just reset the
internal GState of Opal.
Added -GSSetCTM:.
-flushGraphics no longer 'flushes' rect 0,0,1024,1024. Now it instead
queries surface for its size.
In case surface exists but not the CGContext, -DPSgsave creates it.
Otherwise, it records that gsave should be run upon context
creation.
Added -DPSsetlinewidth:.
Changes relating to rename of OpalSurface and OpalGState methods
-cgContext to -CGContext.
* Source/opal/OpalSurface.m:
Added reminder of how we should handle recreation of CGContexts.
Disabled non-doublebuffered windows. (We always need a backing
CGBitmapContext so we can implement -compositeGState: and -drawGState:.
Added accessors -x11CGContext and -backingCGContext.
Fixed bug where sometimes we'd get incorrect expose values and would
try to incorrectly copy the backing image, stretching the resulting
on-screen image.
Added -size accessor.
* Headers/opal/OpalGState.h:
Some accessors. _CGContextSaveGStatesOnContextCreation ivar.
* Headers/opal/OpalSurface.h:
New and renamed accessors.
2013-09-19 Ivan Vucica <ivan@vucica.net>
* Source/opal/OpalContext.m:

View file

@ -57,6 +57,15 @@
have a different cairo_t with the same surface.
**/
OPGStateRef _opGState;
/**
Sometimes, -DPSgsave may get called before context has
been created.
We need a counter for how many times CGContextSaveGState()
needs to be called in first -DPSinitgraphics that gets called.
**/
int _CGContextSaveGStatesOnContextCreation;
}
- (void) DPSinitclip;
@ -84,10 +93,13 @@
- (void) GSSetSurface: (OpalSurface *)opalSurface
: (int)x
: (int)y;
- (void) DPSgsave;
- (void) DPSgrestore;
@end
@interface OpalGState (Accessors)
- (CGContextRef) cgContext;
- (CGContextRef) CGContext;
- (OPGStateRef) OPGState;
- (void) setOPGState: (OPGStateRef) opGState;
@end

View file

@ -37,8 +37,12 @@
- (id) initWithDevice: (void *)device;
- (struct _gswindow_device_t *) device;
- (CGContextRef) cgContext;
- (CGContextRef) CGContext;
- (void) createCGContexts;
- (NSSize) size;
- (CGContextRef) backingCGContext;
- (CGContextRef) x11CGContext;
@end
@interface OpalSurface (DebugExtensions)

View file

@ -65,6 +65,9 @@
- (BOOL) isDrawingToScreen
{
#warning isDrawingToScreen returning NO to fix DPSimage
return NO;
// NOTE: This was returning NO because it was not looking at the
// return value of GSCurrentSurface. Now it returns YES, which
// seems to have broken image drawing (yellow rectangles are drawn instead)
@ -75,8 +78,8 @@
- (void) DPSgsave
{
[super DPSgsave];
[OGSTATE DPSgsave];
[super DPSgsave];
}
- (void) DPSgrestore
{
@ -90,7 +93,7 @@
- (void) DPSsetgstate: (int)gstateID
{
OPGStateRef previousGState = OPContextCopyGState([OGSTATE cgContext]);
OPGStateRef previousGState = OPContextCopyGState([OGSTATE CGContext]);
[OGSTATE setOPGState: previousGState];
[previousGState release]; // FIXME
@ -99,17 +102,15 @@
OPGStateRef newGState = [OGSTATE OPGState];
if (newGState)
{
OPContextSetGState([OGSTATE cgContext], newGState);
OPContextSetGState([OGSTATE CGContext], newGState);
[OGSTATE setOPGState: nil];
}
}
/*
// FIXME: we should add this as soon as we implement -drawGState:...
- (BOOL) supportsDrawGState
{
return YES;
}
*/
/**
This handles 'expose' event notifications that arrive from
@ -127,7 +128,7 @@
{
OpalSurface * surface;
[OGSTATE GSCurrentSurface: &surface : NULL : NULL];
return [surface cgContext];
return [surface CGContext];
}
#if BUILD_SERVER == SERVER_x11

View file

@ -33,8 +33,19 @@
#import "opal/OpalFontInfo.h"
#import "x11/XGServerWindow.h"
#define CGCTX [self cgContext]
#define CGCTX [self CGContext]
static inline NSString * _CGRectRepr(CGRect rect)
{
return [NSString stringWithFormat: @"(%g,%g,%g,%g)",
rect.origin.x, rect.origin.y,
rect.size.width, rect.size.height];
}
static inline CGRect _CGRectFromNSRect(NSRect nsrect)
{
return CGRectMake(nsrect.origin.x, nsrect.origin.y,
nsrect.size.width, nsrect.size.height);
}
@implementation OpalGState
@ -75,7 +86,7 @@
: (const unsigned char *const[5])data
{
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
NSDebugLLog(@"OpalGState", @" %s - %@ - cgctx %@", __PRETTY_FUNCTION__, _opalSurface, [self CGContext]);
// This depends on CGAffineTransform and NSAffineTransformStruct having
// the same in-memory layout.
// Here's an elementary check if that is true.
@ -84,10 +95,18 @@
NSAffineTransformStruct nsAT = [matrix transformStruct];
CGAffineTransform cgAT = *(CGAffineTransform *)&nsAT;
NSDebugLLog(@"OpalGState", @"tf: %@ x %@", matrix, [self GSCurrentCTM]);
CGContextSaveGState(CGCTX);
// CGContextSetRGBFillColor(CGCTX, 1, 0, 0, 1);
//OPContextSetIdentityCTM(CGCTX);
CGContextConcatCTM(CGCTX, cgAT);
// CGContextFillRect(CGCTX, CGRectMake(0, 0, pixelsWide, pixelsHigh));
//OPContextSetCairoDeviceOffset(CGCTX, 0, 0);
//CGContextMoveToPoint(CGCTX, 0, 0);
#if 0
CGContextSetRGBFillColor(CGCTX, 1, 0, 0, 1);
CGContextFillRect(CGCTX, CGRectMake(-512, -512, 1024, 1024 /*pixelsWide, pixelsHigh*/ ));
#endif
// CGContextRestoreGState(CGCTX);
// return;
// TODO:
// We may want to normalize colorspace names between Opal and -gui,
@ -141,6 +160,8 @@ NSLog(@" : samplesperpixel = %d", samplesPerPixel);
false, /* shouldInterpolate? */
kCGRenderingIntentDefault );
CGContextDrawImage(CGCTX, CGRectMake(0, 0, pixelsWide, pixelsHigh), img);
//[_opalSurface _saveImage: img withPrefix:@"/tmp/opalback-dpsimage-" size: NSZeroSize];
CGDataProviderRelease(dataProvider);
CGImageRelease(img);
CGContextRestoreGState(CGCTX);
@ -153,22 +174,257 @@ NSLog(@" : samplesperpixel = %d", samplesPerPixel);
fraction: (CGFloat)delta
{
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
#if 0
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);
CGContextRef destContexts[2] = { [_opalSurface backingCGContext], [_opalSurface x11CGContext] };
// FIXME: this presumes that the backing cgContext of 'source' is
/* x11 context needs to have correct ctm applied */
CGContextSaveGState([_opalSurface x11CGContext]);
OPContextSetIdentityCTM([_opalSurface x11CGContext]);
CGContextConcatCTM([_opalSurface x11CGContext], CGContextGetCTM([_opalSurface backingCGContext]));
for (int i = 0; i < 1; i++) // not drawing into x11cgctx after all.
{
CGContextRef ctx = destContexts[i];
[self compositeGState: source
fromRect: srcRect
toPoint: destPoint
op: op
fraction: delta
destCGContext: ctx];
}
/* restore x11 context's previous state */
CGContextRestoreGState([_opalSurface x11CGContext]);
}
- (void) drawGState: (OpalGState *)source
fromRect: (NSRect)srcRect
toPoint: (NSPoint)destPoint
op: (NSCompositingOperation)op
fraction: (CGFloat)delta
{
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
CGContextRef destContexts[2] = { [_opalSurface backingCGContext], [_opalSurface x11CGContext] };
for (int i = 0; i < 2; i++)
{
CGContextRef ctx = destContexts[i];
[self drawGState: source
fromRect: srcRect
toPoint: destPoint
op: op
fraction: delta
destCGContext: ctx];
}
}
- (void) compositeGState: (OpalGState *)source
fromRect: (NSRect)srcRect
toPoint: (NSPoint)destPoint
op: (NSCompositingOperation)op
fraction: (CGFloat)delta
destCGContext: (CGContextRef) destCGContext
{
// NOTE: This method seems to need to paint to X11 context, too.
NSDebugLLog(@"OpalGState", @"%p (%@): %s - from %@ of gstate %p (cgctx %p) to %@ of %p (cgctx %p)", self, [self class], __PRETTY_FUNCTION__, NSStringFromRect(srcRect), source, [source CGContext], NSStringFromPoint(destPoint), self, [self CGContext]);
#if 0
CGContextSaveGState(destCGContext);
CGContextSetRGBFillColor(destCGContext, 1, 1, 0, 1);
CGContextFillRect(destCGContext, CGRectMake(destPoint.x, destPoint.y, srcRect.size.width, srcRect.size.height));
CGContextRestoreGState(destCGContext);
#else
#if 1
NSSize ssize = [source->_opalSurface size];
srcRect = [[source GSCurrentCTM] rectInMatrixSpace: srcRect];
destPoint = [[self GSCurrentCTM] pointInMatrixSpace: destPoint];
srcRect.origin.y = ssize.height-srcRect.origin.y-srcRect.size.height;
CGRect srcCGRect = _CGRectFromNSRect(srcRect);
CGRect destCGRect = CGRectMake(destPoint.x, destPoint.y,
srcRect.size.width, srcRect.size.height);
NSLog(@"Source cgctx: %p, self: %p - from %@ to %@ with ctm %@", [source CGContext], self, _CGRectRepr(srcCGRect), _CGRectRepr(destCGRect), [self GSCurrentCTM]);
// 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);
CGImageRef backingImage = CGBitmapContextCreateImage([source CGContext]);
CGImageRef subImage = CGImageCreateWithImageInRect(backingImage, srcCGRect);
CGContextSaveGState(destCGContext);
OPContextSetIdentityCTM(destCGContext);
OPContextSetCairoDeviceOffset(destCGContext, 0, 0);
// TODO: this ignores op
// TODO: this ignores delta
CGContextDrawImage(CGCTX, srcCGRect, backingImage);
CGContextDrawImage(destCGContext, destCGRect, subImage);
OPContextSetCairoDeviceOffset(CGCTX, -offset.x,
offset.y - [_opalSurface device]->buffer_height);
CGContextRestoreGState(destCGContext);
CGImageRelease(subImage);
CGImageRelease(backingImage);
#else
CGImageRef src;
NSSize ssize = NSZeroSize;
BOOL copyOnSelf;
/* The source rect in the source base coordinate space.
This rect is the minimum bounding rect of srcRect. */
NSRect srcRectInBase = NSZeroRect;
/* The destination point in the target base coordinate space */
NSPoint destPointInBase = NSZeroPoint;
/* The origin of srcRectInBase */
double minx, miny;
/* The composited content size */
double width, height;
/* The adjusted destination point in the target base coordinate space */
double x, y;
/* Alternative source rect origin in the source current CTM */
NSPoint srcRectAltOrigin;
/* Alternative source rect origin in the source base coordinate space */
NSPoint srcRectAltOriginInBase;
/* The source rect origin in the source base coordinate space */
NSPoint srcRectOriginInBase;
BOOL originFlippedBetweenBaseAndSource = NO;
/* The delta between the origins of srcRect and srcRectInBase */
double dx, dy;
if (![source CGContext] || !destCGContext)
return;
src = CGBitmapContextCreateImage([source CGContext]);
copyOnSelf = ([source CGContext] == destCGContext);
srcRectAltOrigin = NSMakePoint(srcRect.origin.x, srcRect.origin.y + srcRect.size.height);
srcRectAltOriginInBase = [[source GSCurrentCTM] transformPoint: srcRectAltOrigin];
srcRectOriginInBase = [[source GSCurrentCTM] transformPoint: srcRect.origin];
CGContextSaveGState(destCGContext);
/* When the target and source are the same surface, we use the group tricks */
/* // ?
if (copyOnSelf) cairo_push_group(_ct);
cairo_new_path(_ct);
_set_op(_ct, op);
*/
/* Scales and/or rotates the local destination point with the current AppKit CTM */
destPointInBase = [ctm transformPoint: destPoint];
/* Scales and/or rotates the source rect and retrieves the minimum bounding
rectangle that encloses it and makes it our source area */
[[source GSCurrentCTM] boundingRectFor: srcRect result: &srcRectInBase];
/* Find whether the source rect origin in the base is the same than in the
source current CTM.
We need to know the origin in the base to compute how much the source
bounding rect origin is shifted relatively to the closest source rect corner.
We use this delta (dx, dy) to correctly composite from a rotated source. */
originFlippedBetweenBaseAndSource =
((srcRect.origin.y < srcRectAltOrigin.y && srcRectOriginInBase.y > srcRectAltOriginInBase.y)
|| (srcRect.origin.y > srcRectAltOrigin.y && srcRectOriginInBase.y < srcRectAltOriginInBase.y));
if (originFlippedBetweenBaseAndSource)
{
srcRectOriginInBase = srcRectAltOriginInBase;
}
dx = srcRectOriginInBase.x - srcRectInBase.origin.x;
dy = srcRectOriginInBase.y - srcRectInBase.origin.y;
if (source->_opalSurface != nil)
{
ssize = [source->_opalSurface size];
}
/*
// ?
if (cairo_version() >= CAIRO_VERSION_ENCODE(1, 8, 0))
{
// For cairo > 1.8 we seem to need this adjustment
srcRectInBase.origin.y -= 2 * (source->offset.y - ssize.height);
}
*/
x = destPointInBase.x;
y = destPointInBase.y;
minx = NSMinX(srcRectInBase);
miny = NSMinY(srcRectInBase);
width = NSWidth(srcRectInBase);
height = NSHeight(srcRectInBase);
/* Comment from cairo backend:
-----8<---- */
/* We respect the AppKit CTM effect on the origin 'aPoint' (see
-[ctm transformPoint:]), but we ignore the scaling and rotation effect on
the composited content and size. Which means we never rotate or scale the
content we composite.
We use a pattern as a trick to simulate a target CTM change, this way we
don't touch the source CTM even when both source and target are identical
(e.g. scrolling case).
We must use a pattern matrix that matches the AppKit base CTM set up in
-DPSinitgraphics to ensure no transform is applied to the source content,
translation adjustements related to destination point and source rect put
aside. */
/* -----8<----
We don't have patterns with their own matrices at our disposal, so the
relevant code is NOT here. Instead we directly use srcRectInBase
*/
NSLog(@"dy: %d", (int)dy);
CGRect srcCGRect = CGRectMake(srcRect.origin.x, srcRect.origin.y, srcRect.size.width, srcRect.size.height);
srcCGRect = CGRectMake(minx, miny, width, height);
CGImageRef srcSubImage = CGImageCreateWithImageInRect(src, srcCGRect);
//OPContextSetIdentityCTM(destCGContext);
//CGContextScaleCTM(destCGContext, 1, -1);
//CGContextTranslateCTM(destCGContext, -(minx - x + dx), miny - y + dy - ssize.height);
//OPContextResetClip(destCGContext);
//CGContextAddRect(destCGContext, CGRectMake(x, y, width, height));
//CGContextClip(destCGContext);
// TODO: this ignores op
// TODO: this ignores delta
// (delta == opacity, in cairo backend)
CGRect destCGRect = CGRectMake(x, y, width, height);
CGContextDrawImage(destCGContext, destCGRect, srcSubImage);
CGContextSetRGBFillColor(destCGContext, 0.6, 1.0, 0.2, 0.2);
CGContextFillRect(destCGContext, destCGRect);
// NSLog(@" --> compsoiting subimage %@", srcSubImage);
//[source->_opalSurface _saveImage: srcSubImage withPrefix:[NSString stringWithFormat: @"/tmp/opalback-compositing-subimage-%p-", [source CGContext]] size: srcCGRect.size ];
//[source->_opalSurface _saveImage: src withPrefix:[NSString stringWithFormat: @"/tmp/opalback-compositing-image-%p-", [source CGContext]] size: NSZeroSize ];
CGImageRelease(src);
CGContextRestoreGState(destCGContext);
#endif
#endif
}
/** Unlike -compositeGState, -drawGSstate fully respects the AppKit CTM but
doesn't support to use the receiver cairo target as the source. */
/* This method is required if -[OpalContext supportsDrawGState] returns YES */
- (void) drawGState: (OpalGState *)source
fromRect: (NSRect)srcRect
toPoint: (NSPoint)destPoint
op: (NSCompositingOperation)op
fraction: (CGFloat)delta
destCGContext: (CGContextRef)destCGContext
{
// TODO: CairoGState has a lot more complex implementation.
// For now, we'll just call compositeGState and live
// with the fact that CTM is not respected.
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
#if 0
[self compositeGState: source fromRect: srcRect toPoint: destPoint op: op fraction: delta destCGContext: destCGContext];
#else
CGRect srcCGRect = CGRectMake(srcRect.origin.x, srcRect.origin.y,
srcRect.size.width, srcRect.size.height);
CGRect destCGRect = CGRectMake(destPoint.x, destPoint.y,
srcRect.size.width, srcRect.size.height);
CGImageRef backingImage = CGBitmapContextCreateImage([source CGContext]);
CGImageRef subImage = CGImageCreateWithImageInRect(backingImage, srcCGRect);
// TODO: this ignores op
// TODO: this ignores delta
CGContextDrawImage(destCGContext, destCGRect, subImage);
CGImageRelease(subImage);
CGImageRelease(backingImage);
#endif
}
@ -204,19 +460,20 @@ NSLog(@" : samplesperpixel = %d", samplesPerPixel);
{
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
// TODO: stub
CGContextSetLineJoin(CGCTX, linejoin);
}
- (void) DPSsetlinecap: (int)linecap
{
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
// TODO: stub
// TODO: ensure match of linecap constants between Opal and DPS
CGContextSetLineCap(CGCTX, linecap);
}
- (void) DPSsetmiterlimit: (CGFloat)miterlimit
{
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
// TODO: stub
CGContextSetMiterLimit(CGCTX, miterlimit);
}
@end
@ -227,10 +484,25 @@ NSLog(@" : samplesperpixel = %d", samplesPerPixel);
- (id)copyWithZone: (NSZone *)zone
{
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
OpalGState * theCopy = (OpalGState *) [super copyWithZone: zone];
[_opalSurface retain];
theCopy->_opGState = OPContextCopyGState(CGCTX);
if (CGCTX)
{
theCopy->_opGState = OPContextCopyGState(CGCTX);
}
else
{
// FIXME: perhaps Opal could provide an API for getting the default
// gstate?
CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
CGContextRef ctx = CGBitmapContextCreate(NULL, 1, 1, 8, 32, colorSpace, kCGImageAlphaPremultipliedFirst);
CGColorSpaceRelease(colorSpace);
theCopy->_opGState = OPContextCopyGState(ctx);
CGContextRelease(ctx);
NSLog(@"Included default gstate %p", theCopy->_opGState);
}
return theCopy;
}
@ -258,7 +530,7 @@ NSLog(@" : samplesperpixel = %d", samplesPerPixel);
: (int)x
: (int)y
{
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
NSDebugLLog(@"OpalGState", @"%p (%@): %s - %@ %d %d", self, [self class], __PRETTY_FUNCTION__, opalSurface, x, y);
if(_opalSurface != opalSurface)
{
@ -287,7 +559,29 @@ NSLog(@" : samplesperpixel = %d", samplesPerPixel);
[super DPSinitgraphics];
if (!_opalSurface)
{
NSLog(@"%s: called before GSSetSurface:::", __PRETTY_FUNCTION__);
return;
}
// TODO: instead of recreating contexts, we should only reset
// the gstate portion of the contexts. Add OPContextResetGState() which
// recreates _ct and resets _ctadditions. See DPSinitgraphics in
// CairoGState.
[_opalSurface createCGContexts];
OPContextSetCairoDeviceOffset(CGCTX, -offset.x,
offset.y - [_opalSurface device]->buffer_height);
while (_CGContextSaveGStatesOnContextCreation > 0)
{
NSLog(@"%d more times", _CGContextSaveGStatesOnContextCreation);
CGContextSaveGState(CGCTX);
_CGContextSaveGStatesOnContextCreation--;
}
/*
if ([_opalSurface device])
{
@ -304,13 +598,13 @@ NSLog(@" : samplesperpixel = %d", samplesPerPixel);
@implementation OpalGState (Accessors)
- (CGContextRef) cgContext
- (CGContextRef) CGContext
{
if (!_opalSurface)
NSDebugMLLog(@"OpalGState", @"No OpalSurface");
else if (![_opalSurface cgContext])
else if (![_opalSurface CGContext])
NSDebugMLLog(@"OpalGState", @"No OpalSurface CGContext");
return [_opalSurface cgContext];
return [_opalSurface CGContext];
}
- (OPGStateRef) OPGState
@ -473,7 +767,9 @@ static CGFloat theAlpha = 1.; // TODO: removeme
- (NSAffineTransform *) GSCurrentCTM
{
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
return ctm;
CGAffineTransform cgCTM = CGContextGetCTM(CGCTX);
NSAffineTransform * affineTransform = [NSAffineTransform transform];
@ -488,25 +784,54 @@ static CGFloat theAlpha = 1.; // TODO: removeme
return affineTransform;
}
- (void) GSSetCTM: (NSAffineTransform *)newCTM
{
// 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 = [newCTM transformStruct];
CGAffineTransform cgAT = *(CGAffineTransform *)&nsAT;
OPContextSetIdentityCTM(CGCTX);
CGContextConcatCTM(CGCTX, cgAT);
[super GSSetCTM: newCTM];
}
- (void) flushGraphics
{
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
CGContextFlush(CGCTX);
[_opalSurface handleExpose:CGRectMake(0, 0, 1024, 1024)]; // FIXME
[_opalSurface handleExpose: [_opalSurface size]];
}
- (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);
if (!CGCTX)
{
if (_opalSurface)
{
[_opalSurface createCGContexts];
}
else
{
NSLog(@"%s: called before CGContext was created; possible -gui bug?", __PRETTY_FUNCTION__);
_CGContextSaveGStatesOnContextCreation++;
}
}
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);
if (!CGCTX)
{
NSLog(@"%s: called before CGContext was created; possible -gui bug?", __PRETTY_FUNCTION__);
_CGContextSaveGStatesOnContextCreation--;
}
CGContextRestoreGState(CGCTX);
}
- (void *) saveClip
{
@ -626,6 +951,13 @@ static CGFloat theAlpha = 1.; // TODO: removeme
*y = currentPoint.y;
NSDebugLLog(@"OpalGState", @" %p (%@): %s (returning: %f %f)", self, [self class], __PRETTY_FUNCTION__, *x, *y);
}
- (void) DPSsetlinewidth: (CGFloat) width
{
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
CGContextSetLineWidth(CGCTX, width);
}
@end
// MARK: Non-required unimplemented methods
@ -643,10 +975,6 @@ static CGFloat theAlpha = 1.; // TODO: removeme
empty NSWindow.
*/
- (void) DPSsetlinewidth: (CGFloat) width
{
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
}
- (void) DPSsetgstate: (NSInteger) gst
{
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);

View file

@ -114,18 +114,29 @@ static CGContextRef createCGBitmapContext (int pixelsWide,
// FIXME: this method and class presumes we are being passed
// a window device.
// FIXME: this method does not destroy existing contexts if
// needed, nor transfer Opal GState.
if (_x11CGContext || _backingCGContext)
{
NSLog(@"FIXME: Replacement of OpalSurface %p's CGContexts (x11=%p,backing=%p) without transfer of gstate", self, _x11CGContext, _backingCGContext);
}
Display * display = _gsWindowDevice->display;
Window window = _gsWindowDevice->ident;
_x11CGContext = OPX11ContextCreate(display, window);
#if 0
if (_gsWindowDevice->type == NSBackingStoreNonretained)
{
// Don't double-buffer:
// use the window surface as the drawing destination.
}
else
#else
#warning All windows have to be doublebuffered
#endif
{
// Do double-buffer:
// Create a similar surface to the window which supports alpha
@ -143,9 +154,15 @@ static CGContextRef createCGBitmapContext (int pixelsWide,
#warning NOTE! Doublebuffering disabled.
#endif
}
#if 0
CGContextSaveGState(_backingCGContext);
CGContextSetRGBFillColor(_backingCGContext, (rand() % 255) / 255., (rand() % 255) / 255., (rand() % 255) / 255., 1);
CGContextFillRect(_backingCGContext, CGRectMake(-512, -512, 1024, 1024 /*pixelsWide, pixelsHigh*/ ));
CGContextRestoreGState(_backingCGContext);
#endif
NSDebugLLog(@"OpalSurface", @"Created CGContexts: X11=%p, backing=%p", _x11CGContext, _backingCGContext);
}
- (gswindow_device_t *) device
@ -153,10 +170,19 @@ static CGContextRef createCGBitmapContext (int pixelsWide,
return _gsWindowDevice;
}
- (CGContextRef) cgContext
- (CGContextRef) CGContext
{
return _backingCGContext ? _backingCGContext : _x11CGContext;
}
- (CGContextRef) backingCGContext
{
return _backingCGContext;
}
- (CGContextRef) x11CGContext
{
return _x11CGContext;
}
- (void) handleExposeRect: (NSRect)rect
{
@ -169,12 +195,13 @@ static CGContextRef createCGBitmapContext (int pixelsWide,
#if 1
CGRect cgRect = CGRectMake(rect.origin.x, rect.origin.y,
rect.size.width, rect.size.height);
NSDebugLLog(@"OpalSurface", @"Exposing %@", NSStringFromRect(*(NSRect *)&cgRect));
cgRect = CGRectIntegral(cgRect);
cgRect = CGRectIntersection(cgRect, CGRectMake(0, 0, CGImageGetWidth(backingImage), CGImageGetHeight(backingImage)));
CGRect subimageCGRect = cgRect;
//subimageCGRect.origin.y = CGImageGetHeight(backingImage) - cgRect.origin.y - cgRect.size.height;
// TODO: opal might be able to provide a variant of DrawImage that does
// not require creating a subimage
CGImageRef subImage = CGImageCreateWithImageInRect(backingImage, subimageCGRect);
CGContextSaveGState(_x11CGContext);
@ -182,7 +209,8 @@ static CGContextRef createCGBitmapContext (int pixelsWide,
OPContextSetIdentityCTM(_x11CGContext);
cgRect.origin.y = [self device]->buffer_height - cgRect.origin.y - cgRect.size.height;
NSDebugLLog(@"OpalSurface", @"Painting from %@ to %@", NSStringFromRect(*(NSRect *)&subimageCGRect), NSStringFromRect(*(NSRect *)&cgRect));
NSDebugLLog(@"OpalSurface", @" ... actually from %@ to %@", NSStringFromRect(*(NSRect *)&subimageCGRect), NSStringFromRect(*(NSRect *)&cgRect));
CGContextDrawImage(_x11CGContext, cgRect, subImage);
@ -200,8 +228,11 @@ static CGContextRef createCGBitmapContext (int pixelsWide,
CGContextDrawImage(_x11CGContext, CGRectMake(0, 0, [self device]->buffer_width, [self device]->buffer_height), backingImage);
#endif
#if 0
[self _saveImage: backingImage withPrefix:@"/tmp/opalback-backing-" size: CGSizeZero];
[self _saveImage: subImage withPrefix:@"/tmp/opalback-subimage-" size: subimageCGRect.size ];
#endif
CGImageRelease(backingImage);
CGImageRelease(subImage);
@ -212,7 +243,7 @@ static CGContextRef createCGBitmapContext (int pixelsWide,
- (void) _saveImage: (CGImageRef) img withPrefix: (NSString *) prefix size: (CGSize) size
{
#if 0
#if 1
#warning Saving debug images
#if 1
@ -247,19 +278,10 @@ static CGContextRef createCGBitmapContext (int pixelsWide,
return YES;
}
- (void) dummyDraw
- (NSSize) size
{
NSDebugLLog(@"OpalSurface", @"performing dummy draw");
CGContextSaveGState([self cgContext]);
CGRect r = CGRectMake(0, 0, 1024, 1024);
CGContextSetRGBFillColor([self cgContext], 1, 0, 0, 1);
CGContextFillRect([self cgContext], r);
CGContextRestoreGState([self cgContext]);
return NSMakeSize(_gsWindowDevice->buffer_width,
_gsWindowDevice->buffer_height);
}
@end