4
Copyright (C) 2013 Free Software Foundation, Inc.
6
Author: Ivan Vucica <ivan@vucica.net>
9
This file is part of GNUstep.
11
This library is free software; you can redistribute it and/or
12
modify it under the terms of the GNU Lesser General Public
13
License as published by the Free Software Foundation; either
14
version 2 of the License, or (at your option) any later version.
16
This library is distributed in the hope that it will be useful,
17
but WITHOUT ANY WARRANTY; without even the implied warranty of
18
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19
Lesser General Public License for more details.
21
You should have received a copy of the GNU Lesser General Public
22
License along with this library; see the file COPYING.LIB.
23
If not, see <http://www.gnu.org/licenses/> or write to the
24
Free Software Foundation, 51 Franklin Street, Fifth Floor,
25
Boston, MA 02110-1301, USA.
28
#import <CoreGraphics/CoreGraphics.h>
29
#import <AppKit/NSGraphics.h> // NS*ColorSpace
30
#import <AppKit/NSAffineTransform.h>
31
#import <AppKit/NSBezierPath.h>
32
#import "opal/OpalGState.h"
33
#import "opal/OpalSurface.h"
34
#import "opal/OpalFontInfo.h"
36
#define CGCTX [self CGContext]
38
static inline NSString * _CGRectRepr(CGRect rect)
40
return [NSString stringWithFormat: @"(%g,%g,%g,%g)",
41
rect.origin.x, rect.origin.y,
42
rect.size.width, rect.size.height];
45
static inline CGRect _CGRectFromNSRect(NSRect nsrect)
47
return CGRectMake(nsrect.origin.x, nsrect.origin.y,
48
nsrect.size.width, nsrect.size.height);
51
static inline NSPoint _NSPointFromCGPoint(CGPoint cgpoint)
53
return NSMakePoint(cgpoint.x, cgpoint.y);
56
@implementation OpalGState
58
- (id)copyWithZone: (NSZone *)zone
60
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
61
OpalGState * theCopy = (OpalGState *) [super copyWithZone: zone];
62
CGContextRef cgctx = CGCTX;
64
[_opalSurface retain];
67
theCopy->_opGState = OPContextCopyGState(cgctx);
71
// FIXME: perhaps Opal could provide an API for getting the default
73
CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
74
CGContextRef ctx = CGBitmapContextCreate(NULL, 1, 1, 8, 32, colorSpace, kCGImageAlphaPremultipliedFirst);
75
CGColorSpaceRelease(colorSpace);
76
theCopy->_opGState = OPContextCopyGState(ctx);
77
CGContextRelease(ctx);
78
NSDebugLLog(@"OpalGState", @"Included default gstate %p", theCopy->_opGState);
84
- (void) setOffset: (NSPoint)theOffset
86
NSDebugLLog(@"OpalGState", @"%p (%@): %s - %g %g", self, [self class], __PRETTY_FUNCTION__, theOffset.x, theOffset.y);
87
CGContextRef cgctx = CGCTX;
91
OPContextSetCairoDeviceOffset(cgctx, -theOffset.x,
92
theOffset.y - [_opalSurface size].height);
94
[super setOffset: theOffset];
99
@implementation OpalGState (Ops)
101
- (void) DPSsetalpha: (CGFloat)a
103
NSDebugLLog(@"OpalGState", @"%p (%@): %s - alpha %g", self, [self class], __PRETTY_FUNCTION__, a);
104
CGContextRef cgctx = CGCTX;
108
CGContextSetAlpha(cgctx, a);
110
[super DPSsetalpha: a];
113
- (void) DPSsetgray: (CGFloat)gray
115
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
116
CGContextRef cgctx = CGCTX;
118
const CGFloat alpha = 1.0; // TODO: is this correct?
121
CGContextSetGrayFillColor(cgctx, gray, alpha);
123
[super DPSsetgray: gray];
126
- (void) DPSsetrgbcolor: (CGFloat)r : (CGFloat)g : (CGFloat)b
128
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
129
CGContextRef cgctx = CGCTX;
131
const CGFloat alpha = 1.0; // TODO: is this correct?
134
CGContextSetRGBStrokeColor(cgctx, r, g, b, alpha);
135
CGContextSetRGBFillColor(CGCTX, r, g, b, alpha);
137
[super DPSsetrgbcolor: r : g : b];
141
- (void) DPSshow: (const char *)s
143
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
144
CGContextRef cgctx = CGCTX;
148
CGContextSaveGState(cgctx);
149
CGContextSetRGBFillColor(cgctx, 0, 1, 0, 1);
150
CGContextFillRect(cgctx, CGRectMake(0, 0, strlen(s) * 12, 12));
151
CGContextRestoreGState(cgctx);
155
- (void) GSShowText: (const char *)s : (size_t) length
157
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
158
CGContextRef cgctx = CGCTX;
162
CGContextSaveGState(cgctx);
163
CGContextSetRGBFillColor(cgctx, 0, 1, 0, 1);
164
CGContextFillRect(cgctx, CGRectMake(0, 0, length * 12, 12));
165
CGContextRestoreGState(cgctx);
170
- (void) GSSetFont: (GSFontInfo *)fontref
172
const CGFloat * matrix;
173
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
174
[super GSSetFont: fontref];
176
CGContextRef cgctx = CGCTX;
180
CGFontRef opalFont = (CGFontRef)[((OpalFontInfo *)fontref)->_faceInfo fontFace];
181
CGContextSetFont(cgctx, opalFont);
182
CGContextSetFontSize(cgctx, 1);
183
matrix = [fontref matrix];
184
CGAffineTransform cgAT = CGAffineTransformMake(matrix[0], matrix[1],
185
matrix[2], matrix[3],
186
matrix[4], matrix[5]);
187
CGContextSetTextMatrix(cgctx, cgAT);
191
- (void) GSShowGlyphsWithAdvances: (const NSGlyph *)glyphs : (const NSSize *)advances : (size_t) length
194
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
196
CGContextRef cgctx = CGCTX;
200
// NSGlyph = unsigned int, CGGlyph = unsigned short
201
CGGlyph cgglyphs[length];
203
for (i = 0; i < length; i++)
205
cgglyphs[i] = glyphs[i];
208
CGPoint pt = CGContextGetPathCurrentPoint(cgctx);
209
// FIXME: why * 0.66?
210
pt.y += [self->font defaultLineHeightForFont] * 0.66;
211
CGContextSetTextPosition(cgctx, pt.x, pt.y);
212
CGContextShowGlyphsWithAdvances(cgctx, cgglyphs, (const CGSize *)advances,
217
- (NSPoint) currentPoint
219
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
220
CGContextRef cgctx = CGCTX;
224
CGPoint pt = CGContextGetPathCurrentPoint(cgctx);
225
return _NSPointFromCGPoint(pt);
233
- (void) DPSsetdash: (const CGFloat*)pat
235
: (CGFloat)dashOffset
237
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
239
if (!pat && size != 0)
241
NSLog(@"%s: null 'pat' passed with size %d. Fixing by setting size to 0.", pat, (int)size);
243
// TODO: looking at opal, it does not seem to have a tolerance for
244
// pat=NULL although CGContextSetLineDash() explicitly specifies that
245
// as a possible argument
247
CGContextRef cgctx = CGCTX;
251
CGContextSetLineDash(cgctx, dashOffset, pat, size);
255
- (void) DPSsetlinecap: (int)linecap
257
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
259
CGContextRef cgctx = CGCTX;
263
// TODO: ensure match of linecap constants between Opal and DPS
264
CGContextSetLineCap(cgctx, linecap);
268
- (void) DPSsetlinejoin: (int)linejoin
270
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
271
CGContextRef cgctx = CGCTX;
275
CGContextSetLineJoin(cgctx, linejoin);
279
- (void) DPSsetlinewidth: (CGFloat) width
281
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
282
CGContextRef cgctx = CGCTX;
286
CGContextSetLineWidth(cgctx, width);
290
- (void) DPSsetmiterlimit: (CGFloat)miterlimit
292
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
293
CGContextRef cgctx = CGCTX;
297
CGContextSetMiterLimit(cgctx, miterlimit);
301
- (void) DPSsetstrokeadjust: (int) b
303
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
305
// TODO: Opal doesn't implement this private API of Core Graphics
308
/* Matrix operations */
309
- (void)DPSconcat: (const CGFloat *)m
311
NSDebugLLog(@"OpalGState", @"%p (%@): %s - %g %g %g %g %g %g", self,
312
[self class], __PRETTY_FUNCTION__,
313
m[0], m[1], m[2], m[3], m[4], m[5]);
314
CGContextRef cgctx = CGCTX;
318
CGContextConcatCTM(cgctx,
319
CGAffineTransformMake(m[0], m[1], m[2],
322
[super DPSconcat: m];
325
- (void)DPSinitmatrix
327
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
328
CGContextRef cgctx = CGCTX;
332
OPContextSetIdentityCTM(cgctx);
334
[super DPSinitmatrix];
337
- (void)DPSrotate: (CGFloat)angle
339
CGContextRef cgctx = CGCTX;
343
CGContextRotateCTM(cgctx, angle);
345
[super DPSrotate: angle];
348
- (void)DPSscale: (CGFloat)x
351
NSDebugLLog(@"OpalGState", @"%p (%@): %s - %g %g", self, [self class], __PRETTY_FUNCTION__, x, y);
352
CGContextRef cgctx = CGCTX;
356
CGContextScaleCTM(cgctx, x, y);
358
[super DPSscale: x : y];
361
- (void)DPStranslate: (CGFloat)x
364
NSDebugLLog(@"OpalGState", @"%p (%@): %s - x %g y %g", self, [self class], __PRETTY_FUNCTION__, x, y);
365
CGContextRef cgctx = CGCTX;
369
CGContextTranslateCTM(cgctx, x, y);
371
[super DPStranslate: x: y];
374
- (NSAffineTransform *) GSCurrentCTM
376
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
378
return [super GSCurrentCTM];
381
CGAffineTransform cgCTM = CGContextGetCTM(CGCTX);
382
NSAffineTransform * affineTransform = [NSAffineTransform transform];
384
// This depends on CGAffineTransform and NSAffineTransformStruct having
385
// the same in-memory layout.
386
// Here's an elementary check if that is true.
387
// We should probably check this in -back's "configure" script.
388
assert(sizeof(CGAffineTransform) == sizeof(NSAffineTransformStruct));
390
NSAffineTransformStruct nsCTM = *(NSAffineTransformStruct *)&cgCTM;
391
[affineTransform setTransformStruct: nsCTM];
393
return affineTransform;
397
- (void) GSSetCTM: (NSAffineTransform *)newCTM
399
CGContextRef cgctx = CGCTX;
403
// This depends on CGAffineTransform and NSAffineTransformStruct having
404
// the same in-memory layout.
405
// Here's an elementary check if that is true.
406
// We should probably check this in -back's "configure" script.
407
assert(sizeof(CGAffineTransform) == sizeof(NSAffineTransformStruct));
408
NSAffineTransformStruct nsAT = [newCTM transformStruct];
409
CGAffineTransform cgAT = *(CGAffineTransform *)&nsAT;
411
OPContextSetIdentityCTM(cgctx);
412
CGContextConcatCTM(cgctx, cgAT);
415
[super GSSetCTM: newCTM];
418
- (void) GSConcatCTM: (NSAffineTransform *)newCTM
420
CGContextRef cgctx = CGCTX;
424
assert(sizeof(CGAffineTransform) == sizeof(NSAffineTransformStruct));
425
NSAffineTransformStruct nsAT = [newCTM transformStruct];
426
CGAffineTransform cgAT = *(CGAffineTransform *)&nsAT;
428
CGContextConcatCTM(cgctx, cgAT);
431
[super GSConcatCTM: newCTM];
435
// MARK: Path operations
438
- (void) DPSarc: (CGFloat)x : (CGFloat)y : (CGFloat)r : (CGFloat)angle1 : (CGFloat)angle2
440
CGContextRef cgctx = CGCTX;
444
CGContextAddArc(cgctx, x, y, r, angle1, angle2, YES);
446
[super DPSarc: x : y : r : angle1 : angle2];
449
- (void) DPSarcn: (CGFloat)x : (CGFloat)y : (CGFloat)r : (CGFloat)angle1 : (CGFloat)angle2
451
CGContextRef cgctx = CGCTX;
455
CGContextAddArc(cgctx, x, y, r, angle1, angle2, NO);
457
[super DPSarcn: x : y : r : angle1 : angle2];
460
- (void)DPSarct: (CGFloat)x1 : (CGFloat)y1 : (CGFloat)x2 : (CGFloat)y2 : (CGFloat)r
462
CGContextRef cgctx = CGCTX;
466
CGContextAddArcToPoint(cgctx, x1, y1, x1, y2, r);
468
[super DPSarct: x1 : y1 : x2 : y2 : r];
473
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
474
CGContextRef cgctx = CGCTX;
478
CGContextClip(cgctx);
485
CGContextRef cgctx = CGCTX;
489
CGContextClosePath(cgctx);
491
[super DPSclosepath];
494
- (void)DPScurveto: (CGFloat)x1 : (CGFloat)y1 : (CGFloat)x2 : (CGFloat)y2
495
: (CGFloat)x3 : (CGFloat)y3
497
CGContextRef cgctx = CGCTX;
501
CGContextAddCurveToPoint(cgctx, x1, y1, x2, y2, x3, y3);
503
[super DPScurveto: x1 : y1 : x2 : y2 : x3 : y3];
508
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
509
CGContextRef cgctx = CGCTX;
513
CGContextEOClip(cgctx);
520
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
521
CGContextRef cgctx = CGCTX;
525
CGContextEOFillPath(cgctx);
532
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
533
CGContextRef cgctx = CGCTX;
537
CGContextFillPath(cgctx);
544
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
545
CGContextRef cgctx = CGCTX;
549
OPContextResetClip(cgctx);
553
- (void) DPSlineto: (CGFloat) x
556
NSDebugLLog(@"OpalGState", @"%p (%@): %s - %g %g", self, [self class], __PRETTY_FUNCTION__, x, y);
557
CGContextRef cgctx = CGCTX;
561
CGContextAddLineToPoint(cgctx, x, y);
563
[super DPSlineto: x : y];
566
- (void) DPSmoveto: (CGFloat) x
569
NSDebugLLog(@"OpalGState", @"%p (%@): %s - %g %g", self, [self class], __PRETTY_FUNCTION__, x, y);
570
CGContextRef cgctx = CGCTX;
574
CGContextMoveToPoint(cgctx, x, y);
576
[super DPSmoveto: x : y];
581
CGContextRef cgctx = CGCTX;
585
CGContextBeginPath(cgctx);
590
- (void)DPSrcurveto: (CGFloat)x1 : (CGFloat)y1 : (CGFloat)x2 : (CGFloat)y2
591
: (CGFloat)x3 : (CGFloat)y3
593
CGContextRef cgctx = CGCTX;
599
[self DPScurrentpoint: &x : &y];
606
CGContextAddCurveToPoint(cgctx, x1, y1, x2, y2, x3, y3);
608
[super DPSrcurveto: x1 : y1 : x2 : y2 : x3 : y3];
611
- (void) DPSrectclip: (CGFloat)x : (CGFloat)y : (CGFloat)w : (CGFloat)h
613
NSDebugLLog(@"OpalGState", @"%p (%@): %s - %g %g %g %g", self, [self class], __PRETTY_FUNCTION__, x, y, w, h);
614
CGContextRef cgctx = CGCTX;
618
CGContextClipToRect(cgctx, CGRectMake(x, y, w, h));
622
- (void) DPSrectfill: (CGFloat)x : (CGFloat)y : (CGFloat)w : (CGFloat)h
624
NSDebugLLog(@"OpalGState", @"%p (%@): %s - rect %g %g %g %g", self, [self class], __PRETTY_FUNCTION__, x, y, w, h);
625
CGContextRef cgctx = CGCTX;
629
CGContextFillRect(cgctx, CGRectMake(x, y, w, h));
633
- (void) DPSrectstroke: (CGFloat)x : (CGFloat)y : (CGFloat)w : (CGFloat)h
635
CGContextRef cgctx = CGCTX;
639
CGContextStrokeRect(cgctx, CGRectMake(x, y, w, h));
643
- (void) DPSrlineto: (CGFloat) x
646
NSDebugLLog(@"OpalGState", @"%p (%@): %s - %g %g", self, [self class], __PRETTY_FUNCTION__, x, y);
647
CGContextRef cgctx = CGCTX;
653
[self DPScurrentpoint: &x2 : &y2];
656
CGContextAddLineToPoint(cgctx, x, y);
658
[super DPSrlineto: x : y];
661
- (void) DPSrmoveto: (CGFloat) x
664
NSDebugLLog(@"OpalGState", @"%p (%@): %s - %g %g", self, [self class], __PRETTY_FUNCTION__, x, y);
665
CGContextRef cgctx = CGCTX;
671
[self DPScurrentpoint: &x2 : &y2];
674
CGContextMoveToPoint(cgctx, x2, y2);
676
[super DPSrmoveto: x : y];
681
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
682
CGContextRef cgctx = CGCTX;
686
CGContextStrokePath(cgctx);
691
- (void) GSSendBezierPath: (NSBezierPath *)newpath
693
NSInteger count = [newpath elementCount];
695
SEL elmsel = @selector(elementAtIndex:associatedPoints:);
696
NSBezierPathElement (*elmidx)(id, SEL, NSInteger, NSPoint*) =
697
(NSBezierPathElement (*)(id, SEL, NSInteger, NSPoint*))[newpath methodForSelector: elmsel];
699
[super GSSendBezierPath: newpath];
700
CGContextRef cgctx = CGCTX;
704
CGContextBeginPath(cgctx);
705
for (i = 0; i < count; i++)
707
NSBezierPathElement type;
710
type = (NSBezierPathElement)(*elmidx)(newpath, elmsel, i, points);
713
case NSMoveToBezierPathElement:
714
CGContextMoveToPoint(cgctx, points[0].x, points[0].y);
716
case NSLineToBezierPathElement:
717
CGContextAddLineToPoint(cgctx, points[0].x, points[0].y);
719
case NSCurveToBezierPathElement:
720
CGContextAddCurveToPoint(cgctx, points[0].x, points[0].y,
721
points[1].x, points[1].y,
722
points[2].x, points[2].y);
724
case NSClosePathBezierPathElement:
725
CGContextClosePath(cgctx);
734
- (NSDictionary *) GSReadRect: (NSRect)r
736
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
740
- (void) DPSimage: (NSAffineTransform *)matrix
741
: (NSInteger)pixelsWide
742
: (NSInteger)pixelsHigh
743
: (NSInteger)bitsPerSample // is this used correctly ?
744
: (NSInteger)samplesPerPixel // < unused
745
: (NSInteger)bitsPerPixel
746
: (NSInteger)bytesPerRow
747
: (BOOL)isPlanar // < unused
749
: (NSString *)colorSpaceName
750
: (const unsigned char *const[5])data
752
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
753
NSDebugLLog(@"OpalGState", @" %s - %@ - cgctx %@", __PRETTY_FUNCTION__, _opalSurface, [self CGContext]);
754
NSDebugLLog(@"OpalGState", @"Bits per component : bitspersample = %d", bitsPerSample);
755
NSDebugLLog(@"OpalGState", @"Bits per pixel : bitsperpixel = %d", bitsPerPixel);
756
NSDebugLLog(@"OpalGState", @" : samplesperpixel = %d", samplesPerPixel);
757
NSDebugLLog(@"OpalGState", @"tf: %@ x %@", matrix, [self GSCurrentCTM]);
760
// We may want to normalize colorspace names between Opal and -gui,
761
// to avoid this conversion?
762
if ([colorSpaceName isEqualToString: NSCalibratedRGBColorSpace])
763
colorSpaceName = kCGColorSpaceGenericRGB; // SRGB?
764
else if ([colorSpaceName isEqualToString: NSDeviceRGBColorSpace])
765
colorSpaceName = kCGColorSpaceGenericRGB;
766
else if ([colorSpaceName isEqualToString: NSCalibratedWhiteColorSpace])
767
colorSpaceName = kCGColorSpaceGenericGray;
768
else if ([colorSpaceName isEqualToString: NSDeviceWhiteColorSpace])
769
colorSpaceName = kCGColorSpaceGenericGray;
772
NSLog(@"Opal backend: Unhandled colorspace: %@", colorSpaceName);
776
CGContextRef cgctx = CGCTX;
780
// This depends on CGAffineTransform and NSAffineTransformStruct having
781
// the same in-memory layout.
782
// Here's an elementary check if that is true.
783
// We should probably check this in -back's "configure" script.
784
assert(sizeof(CGAffineTransform) == sizeof(NSAffineTransformStruct));
785
NSAffineTransformStruct nsAT = [matrix transformStruct];
786
CGAffineTransform cgAT = *(CGAffineTransform *)&nsAT;
788
CGContextSaveGState(cgctx);
789
CGContextConcatCTM(cgctx, cgAT);
791
CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(colorSpaceName);
792
NSData *nsData = [NSData dataWithBytesNoCopy: (void*)*data
793
length: pixelsHigh * bytesPerRow
795
CGDataProviderRef dataProvider = CGDataProviderCreateWithCFData(nsData);
796
CGImageRef img = CGImageCreate(pixelsWide, pixelsHigh, bitsPerSample,
797
bitsPerPixel, bytesPerRow, colorSpace,
798
hasAlpha ? kCGImageAlphaPremultipliedLast : 0 /* correct? */,
800
NULL, /* const CGFloat decode[] is what? */
801
false, /* shouldInterpolate? */
802
kCGRenderingIntentDefault );
805
CGContextDrawImage(cgctx, CGRectMake(0, 0, pixelsWide, pixelsHigh), img);
809
CGDataProviderRelease(dataProvider);
810
CGColorSpaceRelease(colorSpace);
811
CGContextRestoreGState(cgctx);
815
- (void) compositeGState: (OpalGState *)source
816
fromRect: (NSRect)srcRect
817
toPoint: (NSPoint)destPoint
818
op: (NSCompositingOperation)op
819
fraction: (CGFloat)delta
820
destCGContext: (CGContextRef) destCGContext
822
// NOTE: This method seems to need to paint to X11 context, too.
824
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]);
826
NSSize ssize = [source->_opalSurface size];
827
srcRect = [source rectInMatrixSpace: srcRect];
828
destPoint = [self pointInMatrixSpace: destPoint];
830
srcRect.origin.y = ssize.height-srcRect.origin.y-srcRect.size.height;
832
CGRect srcCGRect = _CGRectFromNSRect(srcRect);
833
CGRect destCGRect = CGRectMake(destPoint.x, destPoint.y,
834
srcRect.size.width, srcRect.size.height);
835
NSDebugLLog(@"OpalGState", @"Source cgctx: %p, self: %p - from %@ to %@ with ctm %@", [source CGContext], self, _CGRectRepr(srcCGRect), _CGRectRepr(destCGRect), [self GSCurrentCTM]);
836
// FIXME: this presumes that the backing CGContext of 'source' is
837
// an OpalSurface with a backing CGBitmapContext
838
CGImageRef backingImage = CGBitmapContextCreateImage([source CGContext]);
839
CGImageRef subImage = CGImageCreateWithImageInRect(backingImage, srcCGRect);
841
CGContextSaveGState(destCGContext);
842
OPContextSetIdentityCTM(destCGContext);
843
OPContextSetCairoDeviceOffset(destCGContext, 0, 0);
845
// TODO: this ignores op
846
// TODO: this ignores delta
847
CGContextDrawImage(destCGContext, destCGRect, subImage);
849
OPContextSetCairoDeviceOffset(CGCTX, -offset.x,
850
offset.y - [_opalSurface size].height);
852
CGContextRestoreGState(destCGContext);
854
CGImageRelease(subImage);
855
CGImageRelease(backingImage);
858
- (void) compositeGState: (OpalGState *)source
859
fromRect: (NSRect)srcRect
860
toPoint: (NSPoint)destPoint
861
op: (NSCompositingOperation)op
862
fraction: (CGFloat)delta
864
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
865
CGContextRef destContexts[2] = { [_opalSurface backingCGContext], [_opalSurface x11CGContext] };
867
/* x11 context needs to have correct ctm applied */
868
CGContextSaveGState([_opalSurface x11CGContext]);
869
OPContextSetIdentityCTM([_opalSurface x11CGContext]);
870
CGContextConcatCTM([_opalSurface x11CGContext], CGContextGetCTM([_opalSurface backingCGContext]));
873
for (i = 0; i < 1; i++) // not drawing into x11cgctx after all.
875
CGContextRef ctx = destContexts[i];
877
[self compositeGState: source
885
/* restore x11 context's previous state */
886
CGContextRestoreGState([_opalSurface x11CGContext]);
889
/** Unlike -compositeGState, -drawGSstate fully respects the AppKit CTM but
890
doesn't support to use the receiver cairo target as the source. */
891
/* This method is required if -[OpalContext supportsDrawGState] returns YES */
892
- (void) drawGState: (OpalGState *)source
893
fromRect: (NSRect)srcRect
894
toPoint: (NSPoint)destPoint
895
op: (NSCompositingOperation)op
896
fraction: (CGFloat)delta
897
destCGContext: (CGContextRef)destCGContext
899
// TODO: CairoGState has a lot more complex implementation.
900
// For now, we'll just call compositeGState and live
901
// with the fact that CTM is not respected.
903
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
905
CGRect srcCGRect = CGRectMake(srcRect.origin.x, srcRect.origin.y,
906
srcRect.size.width, srcRect.size.height);
907
CGRect destCGRect = CGRectMake(destPoint.x, destPoint.y,
908
srcRect.size.width, srcRect.size.height);
909
CGImageRef backingImage = CGBitmapContextCreateImage([source CGContext]);
910
CGImageRef subImage = CGImageCreateWithImageInRect(backingImage, srcCGRect);
911
// TODO: this ignores op
912
// TODO: this ignores delta
913
CGContextDrawImage(destCGContext, destCGRect, subImage);
914
CGImageRelease(subImage);
915
CGImageRelease(backingImage);
918
- (void) drawGState: (OpalGState *)source
919
fromRect: (NSRect)srcRect
920
toPoint: (NSPoint)destPoint
921
op: (NSCompositingOperation)op
922
fraction: (CGFloat)delta
924
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
925
CGContextRef destContexts[2] = { [_opalSurface backingCGContext], [_opalSurface x11CGContext] };
928
for (i = 0; i < 1; i++)
930
CGContextRef ctx = destContexts[i];
932
[self drawGState: source
941
- (void) compositerect: (NSRect)aRect
942
op: (NSCompositingOperation)op
944
NSDebugLLog(@"OpalGState", @"%p (%@): %s - %@", self, [self class], __PRETTY_FUNCTION__, NSStringFromRect(aRect));
945
CGContextRef cgctx = CGCTX;
949
CGContextSaveGState(cgctx);
950
OPContextSetIdentityCTM(cgctx);
951
// FIXME: Set operator
952
CGContextFillRect(cgctx,
953
CGRectMake(aRect.origin.x,
954
[_opalSurface size].height - aRect.origin.y,
955
aRect.size.width, aRect.size.height));
956
CGContextRestoreGState(cgctx);
962
// MARK: Initialization methods
965
@implementation OpalGState (InitializationMethods)
967
- (void) DPSinitgraphics
969
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
971
[super DPSinitgraphics];
972
[self DPSinitmatrix];
976
- GState approximates a cairo context: a drawing state.
977
- Surface approximates a cairo surface: a place to draw things.
979
- CGContext seems to be a mix of these two: surface + state.
981
Should we unite these two somehow? Can we unite these two somehow?
982
Possibly not. We still need to support bitmap contexts, pdf contexts
983
etc which contain both state and contents.
985
So, we will still need surfaces (containing CGContexts, hence including
986
state) and GState as a wrapper around whatever context happens to be
991
Makes the specified surface active in the current graphics state,
992
ready for use. Also, sets the device offset to specified coordinates.
994
- (void) GSSetSurface: (OpalSurface *)opalSurface
998
NSDebugLLog(@"OpalGState", @"%p (%@): %s - %@ %d %d", self, [self class], __PRETTY_FUNCTION__, opalSurface, x, y);
1000
ASSIGN(_opalSurface, opalSurface);
1001
[self setOffset: NSMakePoint(x, y)];
1002
[self DPSinitgraphics];
1005
- (void) GSCurrentSurface: (OpalSurface **)surface
1009
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
1017
*surface = _opalSurface;
1026
@implementation OpalGState (Accessors)
1028
- (CGContextRef) CGContext
1032
NSDebugMLLog(@"OpalGState", @"No OpalSurface");
1037
CGContextRef context = [_opalSurface CGContext];
1041
NSDebugMLLog(@"OpalGState", @"No OpalSurface CGContext");
1048
- (OPGStateRef) OPGState
1053
- (void) setOPGState: (OPGStateRef)opGState
1055
ASSIGN(_opGState, opGState);
1060
// MARK: Non-required methods
1062
@implementation OpalGState (NonrequiredMethods)
1066
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
1069
CGContextSaveGState(CGCTX);
1073
- (void) DPSgrestore
1075
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
1078
CGContextRestoreGState(CGCTX);
1084
@implementation OpalGState (PatternColor)
1088
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
1089
CGRect * r = calloc(sizeof(CGRect), 1);
1090
*r = CGContextGetClipBoundingBox(CGCTX);
1094
- (void) restoreClip: (void *)savedClip
1096
NSDebugLLog(@"OpalGState", @"%p (%@): %s", self, [self class], __PRETTY_FUNCTION__);
1097
OPContextResetClip(CGCTX);
1098
CGContextClipToRect(CGCTX, *(CGRect *)savedClip);