mirror of
https://github.com/gnustep/libs-back.git
synced 2025-02-23 03:41:04 +00:00
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:
parent
ff80e49fb1
commit
595cc19471
6 changed files with 500 additions and 67 deletions
66
ChangeLog
66
ChangeLog
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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__);
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue