1from __future__ import with_statement
2
3from PyObjCTools.TestSupport import *
4from Quartz import *
5import Quartz
6import os
7import sys
8
9try:
10    long
11except NameError:
12    long = int
13
14if sys.version_info[0] != 2:
15    def buffer(value):
16        if isinstance(value, bytes):
17            return value
18        return value.encode('latin1')
19
20
21class TestCGContext (TestCase):
22    def testTypes(self):
23        self.assertIsCFType(CGContextRef)
24
25    def testConstants(self):
26        self.assertEqual(kCGLineJoinMiter, 0)
27        self.assertEqual(kCGLineJoinRound, 1)
28        self.assertEqual(kCGLineJoinBevel, 2)
29
30        self.assertEqual(kCGLineCapButt, 0)
31        self.assertEqual(kCGLineCapRound, 1)
32        self.assertEqual(kCGLineCapSquare, 2)
33
34        self.assertEqual(kCGPathFill, 0)
35        self.assertEqual(kCGPathEOFill, 1)
36        self.assertEqual(kCGPathStroke, 2)
37        self.assertEqual(kCGPathFillStroke, 3)
38        self.assertEqual(kCGPathEOFillStroke, 4)
39
40        self.assertEqual(kCGTextFill, 0)
41        self.assertEqual(kCGTextStroke, 1)
42        self.assertEqual(kCGTextFillStroke, 2)
43        self.assertEqual(kCGTextInvisible, 3)
44        self.assertEqual(kCGTextFillClip, 4)
45        self.assertEqual(kCGTextStrokeClip, 5)
46        self.assertEqual(kCGTextFillStrokeClip, 6)
47        self.assertEqual(kCGTextClip, 7)
48
49        self.assertEqual(kCGEncodingFontSpecific, 0)
50        self.assertEqual(kCGEncodingMacRoman, 1)
51
52        self.assertEqual(kCGInterpolationDefault, 0)
53        self.assertEqual(kCGInterpolationNone, 1)
54        self.assertEqual(kCGInterpolationLow, 2)
55        self.assertEqual(kCGInterpolationHigh, 3)
56
57        self.assertEqual(kCGBlendModeNormal, 0)
58        self.assertEqual(kCGBlendModeMultiply, 1)
59        self.assertEqual(kCGBlendModeScreen, 2)
60        self.assertEqual(kCGBlendModeOverlay, 3)
61        self.assertEqual(kCGBlendModeDarken, 4)
62        self.assertEqual(kCGBlendModeLighten, 5)
63        self.assertEqual(kCGBlendModeColorDodge, 6)
64        self.assertEqual(kCGBlendModeColorBurn, 7)
65        self.assertEqual(kCGBlendModeSoftLight, 8)
66        self.assertEqual(kCGBlendModeHardLight, 9)
67        self.assertEqual(kCGBlendModeDifference, 10)
68        self.assertEqual(kCGBlendModeExclusion, 11)
69        self.assertEqual(kCGBlendModeHue, 12)
70        self.assertEqual(kCGBlendModeSaturation, 13)
71        self.assertEqual(kCGBlendModeColor, 14)
72        self.assertEqual(kCGBlendModeLuminosity, 15)
73        self.assertEqual(kCGBlendModeClear, 16)
74        self.assertEqual(kCGBlendModeCopy, 17)
75        self.assertEqual(kCGBlendModeSourceIn, 18)
76        self.assertEqual(kCGBlendModeSourceOut, 19)
77        self.assertEqual(kCGBlendModeSourceAtop, 20)
78        self.assertEqual(kCGBlendModeDestinationOver, 21)
79        self.assertEqual(kCGBlendModeDestinationIn, 22)
80        self.assertEqual(kCGBlendModeDestinationOut, 23)
81        self.assertEqual(kCGBlendModeDestinationAtop, 24)
82        self.assertEqual(kCGBlendModeXOR, 25)
83        self.assertEqual(kCGBlendModePlusDarker, 26)
84        self.assertEqual(kCGBlendModePlusLighter, 27)
85
86    @min_os_level('10.5')
87    def testFunctions10_5(self):
88
89        url = CFURLCreateWithFileSystemPath(None,
90                "/tmp/pyobjc.test.pdf", kCFURLPOSIXPathStyle, False)
91        self.assertIsInstance(url, CFURLRef)
92        context = CGPDFContextCreateWithURL(url,
93                ((0, 0), (1000, 1000)), None)
94        self.assertIsInstance(context, CGContextRef)
95        CGContextBeginPage(context, objc.NULL)
96        try:
97            fn = '/System/Library/CoreServices/DefaultDesktop.jpg'
98            if not os.path.exists(fn):
99                fn = '/System/Library/Automator/Apply ColorSync Profile to Images.action/Contents/Resources/A-1075-normal.jpg'
100
101            with open(fn, 'rb') as fp:
102                data = fp.read()
103
104            provider = CGDataProviderCreateWithCFData(buffer(data))
105            image = CGImageCreateWithJPEGDataProvider(provider, None, True, kCGRenderingIntentDefault)
106            self.assertIsInstance(image, CGImageRef)
107
108            CGContextDrawTiledImage(context, ((0, 0), (10, 10)), image)
109
110            font =  CGFontCreateWithFontName("Helvetica")
111            self.assertIsInstance(font, CGFontRef)
112            CGContextSetFont(context, font)
113
114            CGContextBeginTransparencyLayerWithRect(context,
115                    ((10, 10), (500, 100)), None)
116            CGContextEndTransparencyLayer(context)
117
118            color = CGColorCreateGenericRGB(1.0, 0.5, 0.5, 1.0)
119            self.assertIsInstance(color, CGColorRef)
120            CGContextSetFillColorWithColor(context, color)
121            CGContextSetStrokeColorWithColor(context, color)
122
123            gradient = CGGradientCreateWithColorComponents(
124                CGColorSpaceCreateDeviceGray(),
125                (0.25, 0.8), (0.95, 0.99), 2)
126            self.assertIsInstance(gradient, CGGradientRef)
127
128            CGContextDrawRadialGradient(context, gradient, (10, 15),
129                    30, (50, 70), 99.5, kCGGradientDrawsAfterEndLocation)
130
131            def evaluate(info, input, output):
132                return input * 4
133
134            func = CGFunctionCreate(None, 1, (0, 1), 2, (0, 1, 0, 1), evaluate)
135            self.assertIsInstance(func, CGFunctionRef)
136            shading = CGShadingCreateAxial(
137                    CGColorSpaceCreateDeviceGray(),
138                    (0, 0), (30,90), func, False, False)
139            self.assertIsInstance(shading, CGShadingRef)
140
141            self.assertArgHasType(CGContextSetShouldSubpixelPositionFonts, 1, objc._C_BOOL)
142            self.assertArgHasType(CGContextSetAllowsFontSubpixelPositioning, 1, objc._C_BOOL)
143            self.assertArgHasType(CGContextSetShouldSubpixelQuantizeFonts, 1, objc._C_BOOL)
144
145            gradient = CGGradientCreateWithColorComponents(
146                    CGColorSpaceCreateDeviceGray(),
147                    (0.25, 0.8), (0.95, 0.99), 2)
148            self.assertIsInstance(gradient, CGGradientRef)
149
150            CGContextDrawLinearGradient(context, gradient, (0, 10), (50, 60),
151                    kCGGradientDrawsAfterEndLocation)
152
153        finally:
154            CGContextEndPage(context)
155            if hasattr(Quartz, 'CGPDFContextClose'): CGPDFContextClose(context)
156            if os.path.exists("/tmp/pyobjc.test.pdf"):
157                os.unlink("/tmp/pyobjc.test.pdf")
158
159
160
161    def testFunctions(self):
162        self.assertIsInstance(CGContextGetTypeID(), (int, long))
163
164        url = CFURLCreateWithFileSystemPath(None,
165                "/tmp/pyobjc.test.pdf", kCFURLPOSIXPathStyle, False)
166        self.assertIsInstance(url, CFURLRef)
167        context = CGPDFContextCreateWithURL(url,
168                ((0, 0), (1000, 1000)), None)
169        self.assertIsInstance(context, CGContextRef)
170        CGContextBeginPage(context, objc.NULL)
171
172        self.assertTrue(CGContextIsPathEmpty(context) is True)
173        try:
174            CGContextBeginPath(context)
175            CGContextAddEllipseInRect(context, ((0, 10), (50, 30)))
176            CGContextDrawPath(context, kCGPathStroke)
177
178            CGContextSaveGState(context)
179            CGContextRestoreGState(context)
180
181            CGContextScaleCTM(context, 5.5, 9.5)
182            CGContextTranslateCTM(context, 4.5, 3.5)
183            CGContextRotateCTM(context, 0.79)
184            CGContextConcatCTM(context, CGAffineTransformIdentity)
185
186            tf = CGContextGetCTM(context)
187            self.assertIsInstance(tf, CGAffineTransform)
188
189            CGContextSetLineWidth(context, 2.5)
190            CGContextSetLineCap(context, kCGLineCapRound)
191            CGContextSetLineJoin(context, kCGLineJoinMiter)
192            CGContextSetMiterLimit(context, 9.5)
193
194            CGContextSetLineDash(context, 0.5, [0.4, 0.2, 0.8, 0.1], 4)
195
196            self.assertRaises(ValueError, CGContextSetLineDash,
197                    context, 0.5, [0.4, 0.2, 0.8, 0.1], 8)
198
199            CGContextSetFlatness(context, 0.8)
200            CGContextSetAlpha(context, 0.5)
201            CGContextSetBlendMode(context, kCGBlendModeLighten)
202
203
204            CGContextMoveToPoint(context, 10.5, 50.8)
205            CGContextAddLineToPoint(context, 0.5, 0.7)
206            CGContextAddCurveToPoint(context, 7.5, 8.7, 9.10, 9.10, 99.5, 80.5)
207            CGContextAddQuadCurveToPoint(context, 50.5, 50.5, 75.9, 78.4)
208            CGContextClosePath(context)
209
210            CGContextAddRect(context, CGRect(CGPoint(10, 10), CGSize(50, 50)))
211            CGContextAddRects(context, [
212                ( (8, 8), (7, 7) ),
213                ( (90, 80), (6, 6) ),
214                ( (50, 80), (60, 6) ),
215            ], 3)
216            self.assertRaises(ValueError,
217                CGContextAddRects, context, [
218                    ( (8, 8), (7, 7) ),
219                    ( (90, 80), (6, 6) ),
220                    ( (50, 80), (60, 6) ),
221                ], 8)
222
223
224            CGContextAddLines(context, [ (0, 10), (50, 7), (50, 90), (90.5, 8)],
225                    4)
226            self.assertRaises(ValueError,
227                CGContextAddLines, context, [ (0, 10), (50, 7), (50, 90), (90.5, 8)],
228                    7)
229
230            CGContextAddEllipseInRect(context, ((0, 10), (50, 30)))
231
232            CGContextAddArc(context, 50, 50, 70.5, 0.5, 1.3, 0)
233
234            CGContextAddArcToPoint(context, 20, 30, 70, 20, 55)
235
236            path = CGPathCreateMutable()
237            CGPathAddEllipseInRect(path, None, ((10, 50), (33, 33)))
238            self.assertIsInstance(path, CGPathRef)
239            CGContextAddPath(context, path)
240
241            self.assertResultHasType(CGContextIsPathEmpty, objc._C_BOOL)
242            self.assertTrue(CGContextIsPathEmpty(context) is False)
243
244            pt = CGContextGetPathCurrentPoint(context)
245            self.assertIsInstance(pt, CGPoint)
246
247            box = CGContextGetPathBoundingBox(context)
248            self.assertIsInstance(box, CGRect)
249
250            self.assertResultHasType(CGContextPathContainsPoint, objc._C_BOOL)
251            self.assertIsInstance(CGContextPathContainsPoint(context, pt, kCGPathStroke), bool)
252
253            CGContextFillPath(context)
254            CGContextEOFillPath(context)
255            CGContextStrokePath(context)
256            CGContextFillRect(context, ((10, 10), (50, 30)))
257
258            CGContextFillRects(context, [
259                ((10, 10), (50, 30)),
260                ((90, 10), (50, 30)),
261                ((30, 50), (50, 30))], 3)
262            self.assertRaises(ValueError, CGContextFillRects, context, [
263                ((10, 10), (50, 30)),
264                ((90, 10), (50, 30)),
265                ((30, 50), (50, 30))], 6)
266
267            CGContextStrokeRect(context, ((10, 10), (50, 30)))
268            CGContextStrokeRectWithWidth(context, ((10, 10), (50, 30)), 8.0)
269            CGContextClearRect(context, ((10, 10), (50, 30)))
270
271            CGContextFillEllipseInRect(context, ((10, 10), (50, 30)))
272            CGContextStrokeEllipseInRect(context, ((10, 10), (50, 30)))
273
274            CGContextStrokeLineSegments(context,
275                    [ (0, 0), (10, 15), (15, 10) ], 3)
276            self.assertRaises(ValueError, CGContextStrokeLineSegments, context,
277                    [ (0, 0), (10, 15), (15, 10) ], 4)
278
279            CGContextAddRect(context, CGRect(CGPoint(10, 10), CGSize(50, 50)))
280            CGContextClip(context)
281
282            CGContextAddRect(context, CGRect(CGPoint(10, 10), CGSize(50, 50)))
283            CGContextEOClip(context)
284
285            box = CGContextGetClipBoundingBox(context)
286            self.assertIsInstance(box, CGRect)
287
288            CGContextClipToRect(context, ((0, 0), (40, 50)))
289            CGContextClipToRects(context,
290                    [ ((0, 0), (40, 50)), ((60, 50), (90, 100))], 2)
291            self.assertRaises(ValueError, CGContextClipToRects, context,
292                    [ ((0, 0), (40, 50)), ((60, 50), (90, 100))], 3)
293
294
295            CGContextSetFillColorSpace(context, CGColorSpaceCreateDeviceGray())
296            CGContextSetStrokeColorSpace(context, CGColorSpaceCreateDeviceGray())
297
298            CGContextSetFillColor(context, [0.5, 1.0])
299            CGContextSetStrokeColor(context, [0.5, 1.0])
300
301            CGContextSetPatternPhase(context, CGSize(10.0, 50.0))
302
303            CGContextSetGrayFillColor(context, 0.8, 1.0)
304            CGContextSetGrayStrokeColor(context, 0.8, 1.0)
305
306            CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 1.0)
307            CGContextSetRGBStrokeColor(context, 1.0, 1.0, 1.0, 1.0)
308
309            CGContextSetCMYKFillColor(context, 1.0, 1.0, 1.0, 0.5, 0.8)
310            CGContextSetCMYKStrokeColor(context, 1.0, 1.0, 1.0, 0.5, 0.8)
311
312            CGContextSetRenderingIntent(context, kCGRenderingIntentPerceptual)
313
314            v = CGContextGetInterpolationQuality(context)
315            self.assertIsInstance(v, (int, long))
316
317            CGContextSetInterpolationQuality(context, kCGInterpolationHigh)
318
319            color = CGColorCreate(CGColorSpaceCreateDeviceRGB(), (1,1,1,1))
320
321            CGContextSetShadowWithColor(context, (2, 3), 0.5, color)
322            CGContextSetShadow(context, (5, 6), 0.6)
323
324
325            CGContextSetCharacterSpacing(context, 0.1)
326            CGContextSetTextPosition(context, 10, 50)
327            p = CGContextGetTextPosition(context)
328            self.assertIsInstance(pt, CGPoint)
329
330            CGContextSetTextMatrix(context, CGAffineTransformIdentity)
331
332            tr = CGContextGetTextMatrix(context)
333            self.assertIsInstance(tr, CGAffineTransform)
334
335            CGContextSetTextDrawingMode(context, kCGTextStroke)
336
337
338            CGContextSetFontSize(context, 11.5)
339
340            CGContextSelectFont(context, b"Helvetica", 10.5, kCGEncodingMacRoman)
341
342            CGContextShowText(context, b"value", 5)
343            CGContextShowTextAtPoint(context, 50, 60, b"value", 5)
344
345
346            v = CGContextRetain(context)
347            self.assertTrue(v is context)
348            CGContextRelease(context)
349
350            CGContextFlush(context)
351            CGContextSynchronize(context)
352
353            self.assertArgHasType(CGContextSetShouldAntialias, 1, objc._C_BOOL)
354            CGContextSetShouldAntialias(context, True)
355
356            self.assertArgHasType(CGContextSetAllowsAntialiasing, 1, objc._C_BOOL)
357            CGContextSetAllowsAntialiasing(context, True)
358
359            self.assertArgHasType(CGContextSetShouldSmoothFonts, 1, objc._C_BOOL)
360            CGContextSetShouldSmoothFonts(context, True)
361
362
363            CGContextBeginTransparencyLayer(context, None)
364            CGContextEndTransparencyLayer(context)
365
366
367            tf = CGContextGetUserSpaceToDeviceSpaceTransform(context)
368            self.assertIsInstance(tf, CGAffineTransform)
369
370            pt = CGContextConvertPointToDeviceSpace(context, (10.5, 11.9))
371            self.assertIsInstance(pt, CGPoint)
372
373            pt = CGContextConvertPointToUserSpace(context, (10.5, 11.9))
374            self.assertIsInstance(pt, CGPoint)
375
376            sz = CGContextConvertSizeToDeviceSpace(context, (10.5, 11.9))
377            self.assertIsInstance(sz, CGSize)
378
379            sz = CGContextConvertSizeToUserSpace(context, (10.5, 11.9))
380            self.assertIsInstance(sz, CGSize)
381
382            box = CGContextConvertRectToDeviceSpace(context,
383                    ((10.5, 11.9), (55.6, 39.3)))
384            self.assertIsInstance(box, CGRect)
385            box = CGContextConvertRectToUserSpace(context,
386                    ((10.5, 11.9), (55.6, 39.3)))
387            self.assertIsInstance(box, CGRect)
388
389            myInfo = object()
390            def drawPattern(info, context):
391                pass
392
393            pattern = CGPatternCreate(myInfo, CGRectMake(0, 0, 10, 10), CGAffineTransformIdentity, 10.0, 10.0,
394                            kCGPatternTilingConstantSpacing, True, drawPattern)
395            self.assertIsInstance(pattern, CGPatternRef)
396
397            CGContextSetFillColorSpace(context, CGColorSpaceCreatePattern(None))
398            CGContextSetStrokeColorSpace(context, CGColorSpaceCreatePattern(None))
399            CGContextSetFillPattern(context, pattern, (1.0,1.0,1.0,1.0))
400            CGContextSetStrokePattern(context, pattern, (1.0,1.0,1.0,1.0))
401
402            fn = '/System/Library/CoreServices/DefaultDesktop.jpg'
403            if not os.path.exists(fn):
404                fn = '/System/Library/Automator/Apply ColorSync Profile to Images.action/Contents/Resources/A-1075-normal.jpg'
405
406            with open(fn, 'rb') as fp:
407                data = fp.read()
408            provider = CGDataProviderCreateWithCFData(buffer(data))
409            image = CGImageCreateWithJPEGDataProvider(provider, None, True, kCGRenderingIntentDefault)
410            self.assertIsInstance(image, CGImageRef)
411
412            CGContextDrawImage(context, ((0, 0), (70, 50)), image)
413
414            provider = CGDataProviderCreateWithCFData(buffer("1" * 4 * 20 * 10))
415            mask = CGImageMaskCreate(20, 10, 8, 32, 80, provider, None, True)
416            self.assertIsInstance(mask, CGImageRef)
417
418            CGContextClipToMask(context, CGRectMake(0, 0, 50, 90), mask)
419
420        finally:
421            CGContextEndPage(context)
422            if hasattr(Quartz, 'CGPDFContextClose'): CGPDFContextClose(context)
423            if os.path.exists("/tmp/pyobjc.test.pdf"):
424                os.unlink("/tmp/pyobjc.test.pdf")
425
426    def testGlyphFunctions(self):
427        self.assertArgHasType(CGContextShowGlyphsAtPositions, 1, b'n^S')
428        self.assertArgSizeInArg(CGContextShowGlyphsAtPositions, 1, 3)
429        self.assertArgHasType(CGContextShowGlyphsAtPositions, 2, b'n^' + CGPoint.__typestr__)
430        self.assertArgSizeInArg(CGContextShowGlyphsAtPositions, 2, 3)
431
432        self.assertArgHasType(CGContextShowGlyphs, 1, b'n^S')
433        self.assertArgSizeInArg(CGContextShowGlyphs, 1, 2)
434
435        self.assertArgHasType(CGContextShowGlyphsAtPoint, 1, objc._C_CGFloat)
436        self.assertArgHasType(CGContextShowGlyphsAtPoint, 2, objc._C_CGFloat)
437        self.assertArgHasType(CGContextShowGlyphsAtPoint, 3, b'n^S')
438        self.assertArgSizeInArg(CGContextShowGlyphsAtPoint, 3, 4)
439
440        self.assertArgHasType(CGContextShowGlyphsWithAdvances, 1, b'n^S')
441        self.assertArgSizeInArg(CGContextShowGlyphsWithAdvances, 1, 3)
442        self.assertArgHasType(CGContextShowGlyphsWithAdvances, 2, b'n^' + CGSize.__typestr__)
443        self.assertArgSizeInArg(CGContextShowGlyphsWithAdvances, 2, 3)
444
445        self.assertArgHasType(CGContextDrawPDFPage, 0, b'^{CGContext=}')
446        self.assertArgHasType(CGContextDrawPDFPage, 1, b'^{CGPDFPage=}')
447
448        self.assertArgHasType(CGContextDrawPDFDocument, 0, b'^{CGContext=}')
449        self.assertArgHasType(CGContextDrawPDFDocument, 1, CGRect.__typestr__)
450        self.assertArgHasType(CGContextDrawPDFDocument, 2, b'^{CGPDFDocument=}')
451        self.assertArgHasType(CGContextDrawPDFDocument, 3, objc._C_INT)
452
453
454    @min_os_level('10.5')
455    def testContextManager10_5(self):
456        url = CFURLCreateWithFileSystemPath(None,
457                "/tmp/pyobjc.test.pdf", kCFURLPOSIXPathStyle, False)
458        self.assertIsInstance(url, CFURLRef)
459        context = CGPDFContextCreateWithURL(url,
460                ((0, 0), (1000, 1000)), None)
461        self.assertIsInstance(context, CGContextRef)
462        try:
463            CGContextBeginPage(context, objc.NULL)
464
465            # XXX: This need actual tests, this at least tests that
466            # the contextmanagers can be used
467            with CGTransparencyLayer(context, None):
468                pass
469
470            with CGTransparencyLayer(context, None, ((10, 10), (200, 200))):
471                pass
472
473        finally:
474            CGContextEndPage(context)
475            if hasattr(Quartz, 'CGPDFContextClose'): CGPDFContextClose(context)
476            if os.path.exists("/tmp/pyobjc.test.pdf"):
477                os.unlink("/tmp/pyobjc.test.pdf")
478
479    def testContextManager(self):
480        """
481        Tests for some additional functionality
482        """
483        url = CFURLCreateWithFileSystemPath(None,
484                "/tmp/pyobjc.test.pdf", kCFURLPOSIXPathStyle, False)
485        self.assertIsInstance(url, CFURLRef)
486        context = CGPDFContextCreateWithURL(url,
487                ((0, 0), (1000, 1000)), None)
488        self.assertIsInstance(context, CGContextRef)
489        try:
490            CGContextBeginPage(context, objc.NULL)
491            transform = CGContextGetCTM(context)
492            newTransform = CGAffineTransformMake(1.5, 2.5, 3.5, 4.5, 5.5, 6.5)
493
494            with CGSavedGState(context):
495                CGContextConcatCTM(context, newTransform)
496                tf = CGContextGetCTM(context)
497                self.assertNotEqual(tf, transform)
498
499
500            tf = CGContextGetCTM(context)
501            self.assertEqual(tf, transform)
502
503
504
505
506            CGContextEndPage(context)
507            with CGContextPage(context):
508                pass
509
510            with CGContextPage(context, CGRectMake(0, 0, 500, 500)):
511                pass
512
513            CGContextBeginPage(context, None)
514
515
516
517        finally:
518            CGContextEndPage(context)
519            if hasattr(Quartz, 'CGPDFContextClose'): CGPDFContextClose(context)
520            if os.path.exists("/tmp/pyobjc.test.pdf"):
521                os.unlink("/tmp/pyobjc.test.pdf")
522
523if __name__ == "__main__":
524    main()
525