From 5315095182ff979c1642d00c8eb97f5c30003f90 Mon Sep 17 00:00:00 2001 From: Randall Luecke Date: Fri, 22 Apr 2011 12:53:49 -0400 Subject: [PATCH 01/13] When dragging horizontally we need to update the location of the header view too --- AppKit/CPDragServer.j | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/AppKit/CPDragServer.j b/AppKit/CPDragServer.j index 9d3344b09..bc67ee490 100644 --- a/AppKit/CPDragServer.j +++ b/AppKit/CPDragServer.j @@ -270,10 +270,10 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0, { if ([scrollView hasVerticalScroller]) { - if (eventLocation.y < CGRectGetMinY(insetBounds)) - deltaY = CGRectGetMinY(insetBounds) - eventLocation.y; - else if (eventLocation.y > CGRectGetMaxY(insetBounds)) - deltaY = CGRectGetMaxY(insetBounds) - eventLocation.y; + if (eventLocation.y < _CGRectGetMinY(insetBounds)) + deltaY = _CGRectGetMinY(insetBounds) - eventLocation.y; + else if (eventLocation.y > _CGRectGetMaxY(insetBounds)) + deltaY = _CGRectGetMaxY(insetBounds) - eventLocation.y; if (deltaY < -insetBounds.size.height) deltaY = -insetBounds.size.height; if (deltaY > insetBounds.size.height) @@ -282,17 +282,21 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0, if ([scrollView hasHorizontalScroller]) { - if (eventLocation.x < CGRectGetMinX(insetBounds)) - deltaX = CGRectGetMinX(insetBounds) - eventLocation.x; - else if (eventLocation.x > CGRectGetMaxX(insetBounds)) - deltaX = CGRectGetMaxX(insetBounds) - eventLocation.x; + if (eventLocation.x < _CGRectGetMinX(insetBounds)) + deltaX = _CGRectGetMinX(insetBounds) - eventLocation.x; + else if (eventLocation.x > _CGRectGetMaxX(insetBounds)) + deltaX = _CGRectGetMaxX(insetBounds) - eventLocation.x; if (deltaX < -insetBounds.size.width) deltaX = -insetBounds.size.width; if (deltaX > insetBounds.size.width) deltaX = insetBounds.size.width; } - [contentView scrollToPoint:CGPointMake(bounds.origin.x - deltaX, bounds.origin.y - deltaY)]; + var scrollPoint = _CGPointMake(bounds.origin.x - deltaX, bounds.origin.y - deltaY); + + [contentView scrollToPoint:scrollPoint]; + [[scrollView _headerView] scrollPoint:scrollPoint]; + } } } From 7ee414d0b89ae9c3f12c5fd8faac066f0285254d Mon Sep 17 00:00:00 2001 From: Gerrit Riessen Date: Fri, 22 Apr 2011 19:06:41 +0200 Subject: [PATCH 02/13] remove an assumption of two colors in the gradient creation stuff --- AppKit/CoreGraphics/CGGradient.j | 11 ++++++++--- Tests/AppKit/CGGradientTest.j | 34 ++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/AppKit/CoreGraphics/CGGradient.j b/AppKit/CoreGraphics/CGGradient.j index e8396aa3d..24d0c3573 100644 --- a/AppKit/CoreGraphics/CGGradient.j +++ b/AppKit/CoreGraphics/CGGradient.j @@ -29,10 +29,15 @@ kCGGradientDrawsAfterEndLocation = 1 << 1; function CGGradientCreateWithColorComponents(aColorSpace, components, locations, count) { - if (locations === NULL) - var locations = [0.0, 1.0]; + if ( locations === undefined || locations === NULL ) + { + var num_of_colors = components.length / 4, + locations = []; + for ( var idx = 0; idx < num_of_colors; idx++ ) + locations.push( idx / (num_of_colors - 1) ); + } - if (count === NULL) + if ( count === undefined || count === NULL) var count = locations.length; var colors = []; diff --git a/Tests/AppKit/CGGradientTest.j b/Tests/AppKit/CGGradientTest.j index 187dd713d..0f89d0c60 100644 --- a/Tests/AppKit/CGGradientTest.j +++ b/Tests/AppKit/CGGradientTest.j @@ -7,6 +7,22 @@ */ - (void)testCreateWithColorComponentsDefault { + + // Test one color and no location + var components = [ 0.2,0.2,0.4,0.4 ]; + + var tmp = CGGradientCreateWithColorComponents(CGColorSpaceCreateDeviceRGB(), + components); + [self assert:1 equals:tmp.colors.length]; + [self assert:1 equals:tmp.locations.length]; + + // TODO: This should not be supported since there is no gradient if only one color + // TODO: NaN not really helpful... + [self assert:NaN equals:tmp.locations[0]]; + + [self assert:components.slice(0,4) equals:tmp.colors[0].components]; + + // Test two colors and no location var components = [ 0.2,0.2,0.4,0.4, 0.6,0.6,0.8,0.8 ]; @@ -20,6 +36,24 @@ [self assert:components.slice(4,8) equals:tmp.colors[1].components]; [self assert:components.slice(0,4) equals:tmp.colors[0].components]; + + // Test three colors and no location + var components = [ 0.2,0.2,0.4,0.4, + 0.6,0.6,0.8,0.8, + 0.6,0.6,0.8,0.8 ]; + + var tmp = CGGradientCreateWithColorComponents(CGColorSpaceCreateDeviceRGB(), + components); + [self assert:3 equals:tmp.colors.length]; + [self assert:3 equals:tmp.locations.length]; + + [self assert:0 equals:tmp.locations[0]]; + [self assert:0.5 equals:tmp.locations[1]]; + [self assert:1.0 equals:tmp.locations[2]]; + + [self assert:components.slice(8,12) equals:tmp.colors[2].components]; + [self assert:components.slice(4,8) equals:tmp.colors[1].components]; + [self assert:components.slice(0,4) equals:tmp.colors[0].components]; } /* From 4ce8dcef12393948d317a7310bf43b300b4cfcbf Mon Sep 17 00:00:00 2001 From: Gerrit Riessen Date: Sat, 23 Apr 2011 15:25:11 +0200 Subject: [PATCH 03/13] testing cgcolorspace --- Tests/AppKit/CGColorSpaceTest.j | 138 ++++++++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 Tests/AppKit/CGColorSpaceTest.j diff --git a/Tests/AppKit/CGColorSpaceTest.j b/Tests/AppKit/CGColorSpaceTest.j new file mode 100644 index 000000000..2b17da8a6 --- /dev/null +++ b/Tests/AppKit/CGColorSpaceTest.j @@ -0,0 +1,138 @@ +@import + +@implementation CGColorSpaceTest : OJTestCase + +- (void)testColorSpaceCreateWithName +{ + var testdata = { + "CGColorSpaceGenericGray" : { + model: kCGColorSpaceModelMonochrome, + count: 1, + base: NULL + }, + "CGColorSpaceGenericRGB" : { + model: kCGColorSpaceModelRGB, + count: 3, + base: NULL + }, + "CGColorSpaceGenericCMYK" : { + model: kCGColorSpaceModelCMYK, + count: 4, + base: NULL + }, + "CGColorSpaceGenericRGBLinear" : { + model: kCGColorSpaceModelRGB, + count: 3, + base: NULL + }, + "CGColorSpaceGenericRGBHDR" : { + model: kCGColorSpaceModelRGB, + count: 3, + base: NULL + }, + "CGColorSpaceAdobeRGB1998" : { + model: kCGColorSpaceModelRGB, + count: 3, + base: NULL + }, + "CGColorSpaceSRGB" : { + model: kCGColorSpaceModelRGB, + count: 3, + base: NULL + }, + } + + for ( var key in testdata ) { + var clrsp = CGColorSpaceCreateWithName(key), + expdata = testdata[key]; + [self assert:expdata.model equals:clrsp.model message:"model for "+key]; + [self assert:expdata.count equals:clrsp.count message:"count for "+key]; + [self assert:expdata.base equals:clrsp.base message:"base for "+key]; + } + + [self assert:NULL + equals:CGColorSpaceCreateWithName("doesnotexist") + message:"should be missing"]; +} + + +- (void)testColorSpaceStandardizeComponents +{ + // the following models are all not supported. + + var testcases = { + "notsupported1" : { + testdata : { + model: kCGColorSpaceModelIndexed, + count: 5 + }, + expected: [5,4,3,2,1,NaN] // alpha value normalisation adds value at index 5 + }, + "notsupported2" : { + testdata : { + model: kCGColorSpaceModelLab, + count: 5 + }, + expected: [5,4,3,2,1,NaN] + }, + "notsupported3" : { + testdata : { + model: kCGColorSpaceModelPattern, + count: 4 + }, + expected: [5,4,3,2,1] + }, + "base override with count value" : { + testdata : { + model: kCGColorSpaceModelPattern, + base: { model: kCGColorSpaceModelMonochrome }, + count: 4 + }, + expected: [1,1,1,1,1], + }, + "base override no count value" : { + testdata : { + model: kCGColorSpaceModelPattern, + base: { model: kCGColorSpaceModelMonochrome, count: 4 }, + count: 0 + }, + expected: [1,4,3,2,1], // alpha value is assumed to be at index 0 + }, + "monochrome color space model" : { + testdata : { + model: kCGColorSpaceModelMonochrome, + count: 2 + }, + expected: [1,1,1,2,1], + }, + "rgb color space model" : { + testdata : { + model: kCGColorSpaceModelRGB, + count: 2 + }, + expected: [1,1,1,2,1], + }, + "cmyk color space model" : { + testdata : { + model: kCGColorSpaceModelCMYK, + count: 2 + }, + expected: [1,1,1,2,1], + }, + "devicen color space model" : { + testdata : { + model: kCGColorSpaceModelDeviceN, + count: 2 + }, + expected: [1,1,1,2,1], + }, + } + + for ( var key in testcases ) { + var components = [5,4,3,2,1]; + CGColorSpaceStandardizeComponents( testcases[key].testdata, components); + [self assert:testcases[key].expected equals:components message:"Failed for "+key]; + } +} + +@end From 6e6011c5ead1b89576f06504222b7009f1a793a6 Mon Sep 17 00:00:00 2001 From: Gerrit Riessen Date: Sat, 23 Apr 2011 15:50:32 +0200 Subject: [PATCH 04/13] testing rgb colorspace --- Tests/AppKit/CGColorSpaceTest.j | 36 ++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/Tests/AppKit/CGColorSpaceTest.j b/Tests/AppKit/CGColorSpaceTest.j index 2b17da8a6..3df8b4c3f 100644 --- a/Tests/AppKit/CGColorSpaceTest.j +++ b/Tests/AppKit/CGColorSpaceTest.j @@ -55,11 +55,8 @@ message:"should be missing"]; } - - (void)testColorSpaceStandardizeComponents { - // the following models are all not supported. - var testcases = { "notsupported1" : { testdata : { @@ -135,4 +132,37 @@ } } +- (void)testRgbStandardize +{ + var clrspc = CGColorSpaceCreateDeviceRGB(), + testcases = { + "negative values" : { + components: [-5,-4,-3,-2,-1,-1,-1,-1], + expected: [0,0,0,0,-1,-1,-1,-1], + }, + // TODO: this happens because first the alpha value is normalised, + // TODO: so the components array does not have length 0, rather 4. + "missing values become undefined" : { + components: [], + expected: [undefined,undefined,undefined,1], + }, + "values standarized if between 0 and 1" : { + components: [0.3, 0.4, 0.5, 0.6], + expected: [ROUND(0.3*255)/255, ROUND(0.4*255)/255, + ROUND(0.5*255)/255, ROUND(0.6*255)/255], + }, + "values 0 or 1 if zero or one" : { + components: [0, 1, 0, 1], + expected: [0,1,0,1], + } + }; + + for ( var key in testcases ) { + CGColorSpaceStandardizeComponents( clrspc, testcases[key].components); + [self assert:testcases[key].expected + equals:testcases[key].components + message:"Failed for "+key]; + } +} + @end From 63e63ce7a10a7ba9e11f08fd0320d60667d07de7 Mon Sep 17 00:00:00 2001 From: Gerrit Riessen Date: Sat, 23 Apr 2011 17:22:02 +0200 Subject: [PATCH 05/13] fix the color creation when using shortcut functions --- AppKit/CoreGraphics/CGColor.j | 7 ++-- Tests/AppKit/CGColorTest.j | 67 +++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 3 deletions(-) create mode 100644 Tests/AppKit/CGColorTest.j diff --git a/AppKit/CoreGraphics/CGColor.j b/AppKit/CoreGraphics/CGColor.j index 321d091b6..9f141c80c 100644 --- a/AppKit/CoreGraphics/CGColor.j +++ b/AppKit/CoreGraphics/CGColor.j @@ -108,7 +108,7 @@ function CGColorCreateCopy(aColor) */ function CGColorCreateGenericGray(gray, alpha) { - return CGColorCreate(0, [gray, alpha]); + return CGColorCreate(CGColorSpaceCreateDeviceRGB(), [gray,gray,gray, alpha]); } /*! @@ -122,7 +122,7 @@ function CGColorCreateGenericGray(gray, alpha) */ function CGColorCreateGenericRGB(red, green, blue, alpha) { - return CGColorCreate(0, [red, green, blue, alpha]); + return CGColorCreate(CGColorSpaceCreateDeviceRGB(), [red, green, blue, alpha]); } /*! @@ -137,7 +137,8 @@ function CGColorCreateGenericRGB(red, green, blue, alpha) */ function CGColorCreateGenericCMYK(cyan, magenta, yellow, black, alpha) { - return CGColorCreate(0, [cyan, magenta, yellow, black, alpha]); + return CGColorCreate(CGColorSpaceCreateDeviceCMYK(), + [cyan, magenta, yellow, black, alpha]); } /*! diff --git a/Tests/AppKit/CGColorTest.j b/Tests/AppKit/CGColorTest.j new file mode 100644 index 000000000..bb4bf2be6 --- /dev/null +++ b/Tests/AppKit/CGColorTest.j @@ -0,0 +1,67 @@ +@import + +@implementation CGColorTest : OJTestCase + +- (void)testColorCreate +{ + var colorspace = CGColorSpaceCreateDeviceRGB(), + components = [2,3,4,5], + clruid = CFHashCode(colorspace) + components.join(""); + + // Can't access the colormap cache, but it would be nice to + // [self assert:NULL equals:_CGColorMap[clruid]]; + + var clr = CGColorCreate( colorspace, components ); + [self assert:colorspace equals:clr.colorspace message:"colorspace failed"]; + [self assert:[1,1,1,1] equals:clr.components message:"components failed"]; + [self assert:NULL equals:clr.pattern message:"pattern failed"]; + + // Can't access the colormap cache, but it would be nice to + // [self assert:clr equals:_CGColorMap[clruid]]; +} + +- (void)testColorCopy +{ + // it returns it's argument, a little artifical but will fail if something + // changes with the function. + [self assert:"banana" equals:CGColorCreateCopy( "banana" )]; + + var colorspace = CGColorSpaceCreateDeviceRGB(), + components = [2,3,4,5], + clr = CGColorCreate( colorspace, components ); + [self assert:clr equals:CGColorCreateCopy(clr)]; +} + +- (void)testColorCreateGenericGray +{ + var clr = CGColorCreateGenericGray(0.3, 0.5); + [self assert:CGColorSpaceCreateDeviceRGB() + equals:clr.colorspace message:"colorspace failed"]; + [self assert:[ROUND(0.3*255)/255,ROUND(0.3*255)/255,ROUND(0.3*255)/255,0.5] + equals:clr.components message:"components failed"]; + [self assert:NULL equals:clr.pattern message:"pattern failed"]; +} + +- (void)testColorCreateGenericRGB +{ + var clr = CGColorCreateGenericRGB(0.4,0.3,0.2,0.1); + [self assert:CGColorSpaceCreateDeviceRGB() + equals:clr.colorspace message:"colorspace failed"]; + [self assert:[ROUND(0.4*255)/255,ROUND(0.3*255)/255,ROUND(0.2*255)/255,0.1] + equals:clr.components message:"components failed"]; + [self assert:NULL equals:clr.pattern message:"pattern failed"]; +} + +- (void)testColorCreateGenericCMYK +{ + var clr = CGColorCreateGenericCMYK(0.2, 0.3, 0.4, 0.5, 0.6) + [self assert:CGColorSpaceCreateDeviceCMYK() + equals:clr.colorspace message:"colorspace failed"]; + [self assert:[ROUND(0.2*255)/255,ROUND(0.3*255)/255,ROUND(0.4*255)/255, + ROUND(0.5*255)/255, 0.6] + equals:clr.components message:"components failed"]; + [self assert:NULL equals:clr.pattern message:"pattern failed"]; +} + +@end + From e248433ec0b7e2d62dff77d9f9f4f81ed405358a Mon Sep 17 00:00:00 2001 From: Gerrit Riessen Date: Sat, 23 Apr 2011 20:50:42 +0200 Subject: [PATCH 06/13] fixed an issue where setting the alpha after creating the color causes all colors referencing that color in the cache to have their alpha value changed --- AppKit/CoreGraphics/CGColor.j | 18 +++-- Tests/AppKit/CGColorTest.j | 141 ++++++++++++++++++++++++++++++++++ 2 files changed, 151 insertions(+), 8 deletions(-) diff --git a/AppKit/CoreGraphics/CGColor.j b/AppKit/CoreGraphics/CGColor.j index 9f141c80c..7b8ee6088 100644 --- a/AppKit/CoreGraphics/CGColor.j +++ b/AppKit/CoreGraphics/CGColor.j @@ -150,19 +150,21 @@ function CGColorCreateGenericCMYK(cyan, magenta, yellow, black, alpha) */ function CGColorCreateCopyWithAlpha(aColor, anAlpha) { - var components = aColor.components; + if ( !aColor ) return aColor; // Avoid error null pointer in next line - if (!aColor || anAlpha == components[components.length - 1]) + var components = aColor.components.slice(); + + if (anAlpha == components[components.length - 1]) return aColor; + // set new alpha value now so that a potentially a new cache entry is made and + // not that an existing cache entry is mutated. + components[components.length - 1] = anAlpha; + if (aColor.pattern) - var copy = CGColorCreateWithPattern(aColor.colorspace, aColor.pattern, components); + return CGColorCreateWithPattern(aColor.colorspace, aColor.pattern, components); else - var copy = CGColorCreate(aColor.colorspace, components); - - copy.components[components.length - 1] = anAlpha; - - return copy; + return CGColorCreate(aColor.colorspace, components); } /*! diff --git a/Tests/AppKit/CGColorTest.j b/Tests/AppKit/CGColorTest.j index bb4bf2be6..f437b1d46 100644 --- a/Tests/AppKit/CGColorTest.j +++ b/Tests/AppKit/CGColorTest.j @@ -2,6 +2,33 @@ @implementation CGColorTest : OJTestCase +- (void)testColorCreateReturnNullIfNull +{ + [self assert:NULL equals:CGColorCreate( NULL, [1,2,3] ) message:"colorspace null failed"]; + [self assert:NULL + equals:CGColorCreate( CGColorSpaceCreateDeviceRGB(), NULL ) + message:"components null failed"]; +} + +- (void)testColorCreateEnsureComponentsAreCopied +{ + var colorspace = CGColorSpaceCreateDeviceRGB(), + components = [2,3,4,5], + clr = CGColorCreate(colorspace, components); + + components[0] = components[1] = components[2] = components[3] = 0; + [self assert:[1,1,1,1] equals:clr.components]; + [self assert:[0,0,0,0] equals:components]; +} + +- (void)testColorCreateCachesColorsAlphaChangeIsPropagated +{ + var clr = CGColorCreate(CGColorSpaceCreateDeviceRGB(), [0.4, 0.3, 0.2, 0.2]), + newclr = CGColorCreate(CGColorSpaceCreateDeviceRGB(), [0.4, 0.3, 0.2, 0.2]); + newclr.components[newclr.components.length - 1] = 0.6; + [self assert:0.6 equals:clr.components[clr.components.length-1]]; +} + - (void)testColorCreate { var colorspace = CGColorSpaceCreateDeviceRGB(), @@ -63,5 +90,119 @@ [self assert:NULL equals:clr.pattern message:"pattern failed"]; } +- (void)testColorCreateWithPattern +{ + var clrspc = CGColorSpaceCreateDeviceRGB(), + pattern = "a new pattern", + components = [0.2, 0.4, 0.6, 0.8], + clr = CGColorCreateWithPattern(clrspc, pattern, components); + + [self assert:clrspc equals:clr.colorspace]; + [self assert:pattern equals:clr.pattern]; + [self assert:components equals:clr.components]; + + // ensure that there was a copy made of the components + components[0] = components[1] = components[2] = components[3] = 0.0; + [self assert:[0.2, 0.4, 0.6, 0.8] equals:clr.components]; + + // ensure that null is returned + [self assert:NULL equals:CGColorCreateWithPattern(NULL, "a new pattern", [])]; + [self assert:NULL equals:CGColorCreateWithPattern(CGColorSpaceCreateDeviceRGB(), + NULL, [])]; + [self assert:NULL equals:CGColorCreateWithPattern(CGColorSpaceCreateDeviceRGB(), + "a new pattern", NULL)]; + [self assert:NULL equals:CGColorCreateWithPattern(NULL, NULL, NULL)]; +} + +- (void)testColorGetAlpha +{ + var clr = CGColorCreateGenericCMYK(0.2, 0.3, 0.4, 0.5, 0.6); + [self assert:0.6 equals:CGColorGetAlpha(clr)]; +} + +- (void)testColorGetColorSpace +{ + var clr = CGColorCreateGenericCMYK(0.2, 0.3, 0.4, 0.5, 0.6); + [self assert:CGColorSpaceCreateDeviceCMYK() + equals:CGColorGetColorSpace(clr)]; +} + +- (void)testColorGetComponents +{ + var clr = CGColorCreateGenericCMYK(0.2, 0.3, 0.4, 0.5, 0.6); + [self assert:[ROUND(0.2*255)/255, ROUND(0.3*255)/255, ROUND(0.4*255)/255, + ROUND(0.5*255)/255, ROUND(0.6*255)/255] + equals:CGColorGetComponents(clr)]; +} + +- (void)testColorGetNumberOfComponents +{ + var clr = CGColorCreateGenericCMYK(0.2, 0.3, 0.4, 0.5, 0.6); + [self assert:5 equals:CGColorGetNumberOfComponents(clr)]; +} + +- (void)testColorGetPattern +{ + var clr = CGColorCreateWithPattern(CGColorSpaceCreateDeviceRGB(), "a new pattern", + [1,1,1,1]); + [self assert:"a new pattern" equals:CGColorGetPattern(clr)]; +} + +- (void)testColorCreateCopyWithAlphaWithPattern +{ + var clr = CGColorCreateWithPattern(CGColorSpaceCreateDeviceRGB(), "a new pattern", + [1,1,1,1]); + [self assert:1 equals:CGColorGetAlpha(clr) message:"initial alpha"]; + + var newclr = CGColorCreateCopyWithAlpha(clr, 0.6); + [self assert:0.6 equals:CGColorGetAlpha(newclr) message:"new color alpha value"]; + [self assert:1 equals:CGColorGetAlpha(clr) message:"alpha after copy"]; + + [self assert:clr.colorspace equals:newclr.colorspace message:"newclr colorspace failed"]; + [self assert:clr.pattern equals:newclr.pattern message:"newclr pattern failed"]; +} + +- (void)testColorCreateCopyWithAlphaWithComponents +{ + var clr = CGColorCreateGenericRGB(0.4, 0.3, 0.2, 0.3); + [self assert:0.3 equals:CGColorGetAlpha(clr) message:"initial alpha"]; + + var newclr = CGColorCreateCopyWithAlpha(clr, 0.6); + [self assert:0.6 equals:CGColorGetAlpha(newclr) message:"new color alpha value"]; + [self assert:0.3 equals:CGColorGetAlpha(clr) message:"alpha after copy"]; + + [self assert:CGColorSpaceCreateDeviceRGB() + equals:newclr.colorspace message:"newclr colorspace failed"]; + [self assert:[ROUND(0.4*255)/255,ROUND(0.3*255)/255,ROUND(0.2*255)/255,0.6] + equals:newclr.components message:"newclr components failed"]; + [self assert:NULL equals:newclr.pattern message:"newclr pattern failed"]; + + [self assert:CGColorSpaceCreateDeviceRGB() + equals:clr.colorspace message:"orig clr colorspace failed"]; + [self assert:[ROUND(0.4*255)/255,ROUND(0.3*255)/255,ROUND(0.2*255)/255,0.3] + equals:clr.components message:"orig clr components failed"]; + [self assert:NULL equals:clr.pattern message:"orig clr pattern failed"]; +} + +- (void)testColorCreateCopyWithAlphaWithComponentsNullColor +{ + [self assert:NULL + equals:CGColorCreateCopyWithAlpha(NULL,0.5) + message:"null color failed"]; + + var clr = CGColorCreateGenericRGB(0.4,0.3,0.2,0.1), + newclr = CGColorCreateCopyWithAlpha(clr, 0.1); + [self assert:clr equals:newclr]; +} + +- (void)testColorEqualToColor +{ + var clr1 = CGColorCreateGenericRGB(0.4, 0.3, 0.2, 0.3); + [self assert:true equals:CGColorEqualToColor(NULL,NULL)]; + [self assert:false equals:CGColorEqualToColor(NULL,clr1)]; + [self assert:true equals:CGColorEqualToColor(clr1,clr1)]; + [self assert:false equals:CGColorEqualToColor(clr1,NULL)]; +} + @end From c537541825fe82c85e6d2f0ea8b793bbdd31a792 Mon Sep 17 00:00:00 2001 From: Gerrit Riessen Date: Sat, 23 Apr 2011 20:56:23 +0200 Subject: [PATCH 07/13] added test for color equal to color --- Tests/AppKit/CGColorTest.j | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Tests/AppKit/CGColorTest.j b/Tests/AppKit/CGColorTest.j index f437b1d46..97416ef87 100644 --- a/Tests/AppKit/CGColorTest.j +++ b/Tests/AppKit/CGColorTest.j @@ -197,11 +197,20 @@ - (void)testColorEqualToColor { - var clr1 = CGColorCreateGenericRGB(0.4, 0.3, 0.2, 0.3); [self assert:true equals:CGColorEqualToColor(NULL,NULL)]; + + var clr1 = CGColorCreateGenericRGB(0.4, 0.3, 0.2, 0.3); [self assert:false equals:CGColorEqualToColor(NULL,clr1)]; [self assert:true equals:CGColorEqualToColor(clr1,clr1)]; [self assert:false equals:CGColorEqualToColor(clr1,NULL)]; + + var clr2 = CGColorCreateGenericRGB(0.4, 0.3, 0.2, 0.3); + [self assert:true equals:CGColorEqualToColor(clr1,clr2)]; + [self assert:true equals:CGColorEqualToColor(clr2,clr1)]; + + clr2 = CGColorCreateGenericCMYK(0.2, 0.3, 0.4, 0.5, 0.6); + [self assert:false equals:CGColorEqualToColor(clr1,clr2)]; + [self assert:false equals:CGColorEqualToColor(clr2,clr1)]; } @end From d147e9cbaa75090d017864b5aef68e490c9b65f5 Mon Sep 17 00:00:00 2001 From: Gerrit Riessen Date: Sun, 24 Apr 2011 12:41:06 +0200 Subject: [PATCH 08/13] unit test for CGAffineTransform --- Tests/AppKit/CGAffineTransformTest.j | 511 +++++++++++++++++++++++++++ Tests/AppKit/CGTestCase.j | 44 +++ 2 files changed, 555 insertions(+) create mode 100644 Tests/AppKit/CGAffineTransformTest.j create mode 100644 Tests/AppKit/CGTestCase.j diff --git a/Tests/AppKit/CGAffineTransformTest.j b/Tests/AppKit/CGAffineTransformTest.j new file mode 100644 index 000000000..f1d47a034 --- /dev/null +++ b/Tests/AppKit/CGAffineTransformTest.j @@ -0,0 +1,511 @@ +@import +@import "CGTestCase.j" + +@implementation CGAffineTransformTest : CGTestCase + +- (void)testAffineTransformMake +{ + [self compareTransform:CGAffineTransformMake(1, 2, 3, 4, 3.2, 5.4) + with:{ a: 1, b: 2, c:3, d:4, tx:3.2, ty:5.4 } + message:"transform make"]; +} + +- (void)testCGAffineTransformMakeIdentity +{ + [self compareTransform:CGAffineTransformMakeIdentity() + with:{ a: 1, b: 0, c:0, d:1, tx:0, ty:0 } + message:"transform make identity"]; +} + +- (void)testAffineTransformMakeCopy +{ + var transform = CGAffineTransformMake(1, 2, 3, 4, 3.2, 5.4), + t2 = CGAffineTransformMakeCopy(transform); + + transform.a = transform.b = transform.c = transform.d = + transform.tx = transform.ty = 0; + + [self compareTransform:t2 + with:CGAffineTransformMake( 1,2,3,4,3.2,5.4 ) + message:"copy correctly made"]; + + [self compareTransform:transform + with:CGAffineTransformMake( 0, 0, 0, 0, 0, 0 ) + message:"original transform was changed"] ; +} + +- (void)testAffineTransformCreateCopy +{ + // FIXME: CGAffineTransformCreateCopy seems to be working but code has a Fixme? + var transform = CGAffineTransformMake(1, 2, 3, 4, 3.2, 5.4), + t2 = CGAffineTransformCreateCopy(transform); + + transform.a = transform.b = transform.c = transform.d = + transform.tx = transform.ty = 0; + + [self compareTransform:t2 + with:CGAffineTransformMake( 1,2,3,4,3.2,5.4 ) + message:"copy correctly made"]; + + [self compareTransform:transform + with:CGAffineTransformMake( 0, 0, 0, 0, 0, 0 ) + message:"original transform was changed"] ; +} + +- (void)testAffineTransformMakeScale +{ + [self compareTransform:CGAffineTransformMakeScale(3,4) + with:CGAffineTransformMake(3, 0, 0, 4, 0, 0) + message:"make scale"]; +} + +- (void)testAffineTransformMakeTranslation +{ + [self compareTransform:CGAffineTransformMakeTranslation(3,4) + with:CGAffineTransformMake(1,0,0,1,3,4) + message:"make translation"]; +} + +- (void)testAffineTransformTranslate +{ + var transform = CGAffineTransformMakeTranslation(3,4); + + [self compareTransform:CGAffineTransformTranslate(transform,-3,-4) + with:CGAffineTransformMakeIdentity() + message:"translate to identity"]; + + [self compareTransform:CGAffineTransformTranslate(transform,0,0) + with:transform + message:"zero translate"]; +} + +- (void)testAffineTransformScale +{ + var transform = CGAffineTransformMakeScale(3,4); + + [self compareTransform:CGAffineTransformScale( transform, 1/3, 1/4) + with:CGAffineTransformMakeIdentity() + message:"scale to identity"]; + + transform = CGAffineTransformMake(2, -2, -3, 3, 3.2, 5.4); + [self compareTransform:CGAffineTransformScale(transform, 1, 1) + with:transform + message:"scale by 1"]; + + [self compareTransform:CGAffineTransformScale(transform, 2, 5) + with:CGAffineTransformMake(4,-4,-15,15, 3.2,5.4) + message:"random scale to somewhere"]; +} + +- (void)testAffineTransformConcat +{ + var testcases = { + "identity concat" : { + testdata: CGAffineTransformConcat( CGAffineTransformMakeIdentity(), + CGAffineTransformMakeIdentity() ), + expdata: CGAffineTransformMakeIdentity() + }, + + "translation" : { + testdata: CGAffineTransformConcat( CGAffineTransformMakeTranslation(3,4), + CGAffineTransformMakeTranslation(-3,-4) ), + expdata: CGAffineTransformMakeIdentity() + }, + + "translation (reversed)" : { + testdata: CGAffineTransformConcat( CGAffineTransformMakeTranslation(-3,-4), + CGAffineTransformMakeTranslation(3,4) ), + expdata: CGAffineTransformMakeIdentity() + }, + + "scale" : { + testdata: CGAffineTransformConcat(CGAffineTransformMakeScale(3,4), + CGAffineTransformMakeScale(1/3,1/4)), + expdata: CGAffineTransformMakeIdentity() + }, + + "scale (reversed)" : { + testdata: CGAffineTransformConcat(CGAffineTransformMakeScale(1/3,1/4), + CGAffineTransformMakeScale(3,4)), + expdata: CGAffineTransformMakeIdentity() + }, + + "rotation" : { + testdata: CGAffineTransformConcat(CGAffineTransformMakeRotation(Math.PI), + CGAffineTransformMakeRotation(-Math.PI)), + expdata: CGAffineTransformMakeIdentity() + }, + }; + + for ( var key in testcases ) + [self compareTransform:testcases[key].testdata with:testcases[key].expdata message:key]; +} + +- (void)testPointApplyAffineTransform +{ + var testcases = { + "translate to zero" : { + testdata: CGPointApplyAffineTransform( CGPointMake( 3, 4 ), + CGAffineTransformMakeTranslation(-3,-4)), + expdata: CGPointMakeZero() + }, + + "scale to 1,1" : { + testdata: CGPointApplyAffineTransform( CGPointMake( 3, 4 ), + CGAffineTransformMakeScale(1/3,1/4) ), + expdata: CGPointMake(1,1) + }, + + "scale and translate to zero" : { + testdata: CGPointApplyAffineTransform( CGPointMake( 3, 4 ), + CGAffineTransformConcat( + CGAffineTransformMakeScale(1/3,1/4), + CGAffineTransformMakeTranslation(-1,-1))), + expdata: CGPointMakeZero() + + }, + }; + + for ( var key in testcases ) + [self comparePoint:testcases[key].testdata with:testcases[key].expdata message:key]; +} + +- (void)testSizeApplyAffineTransform +{ + var testcases = { + "translation on size should do nothing" : { + testdata: CGSizeApplyAffineTransform( CGSizeMake(3, 12), + CGAffineTransformMakeTranslation(-3,-4)), + expdata: CGSizeMake(3, 12) + }, + + "scale to 1,1" : { + testdata: CGSizeApplyAffineTransform( CGSizeMake( 3, 4 ), + CGAffineTransformMakeScale(1/3,1/4) ), + expdata: CGSizeMake(1, 1) + }, + + "scale and translate combined" : { + testdata: CGSizeApplyAffineTransform( CGSizeMake( 3, 4 ), + CGAffineTransformConcat( + CGAffineTransformMakeScale(1/3,1/4), + CGAffineTransformMakeTranslation(-1,-1))), + expdata: CGSizeMake(1, 1) + + }, + }; + + for ( var key in testcases ) + [self compareSize:testcases[key].testdata with:testcases[key].expdata message:key]; +} + +- (void)testAffineTransformIsIdentityPositive +{ + var testcases = { + "identity is identity" : { + testdata: CGAffineTransformMakeIdentity() + }, + + "zero rotation is identity" : { + testdata: CGAffineTransformMakeRotation(0), + }, + + "zero translation is identity" : { + testdata: CGAffineTransformMakeTranslation(0,0) + }, + + "one scale is identity" : { + testdata: CGAffineTransformMakeScale(1,1) + }, + + "identity concat'ed" : { + testdata: CGAffineTransformConcat( CGAffineTransformMakeIdentity(), + CGAffineTransformMakeIdentity() ), + }, + + "translation" : { + testdata: CGAffineTransformConcat( CGAffineTransformMakeTranslation(3,4), + CGAffineTransformMakeTranslation(-3,-4) ), + }, + + "scale" : { + testdata: CGAffineTransformConcat(CGAffineTransformMakeScale(3,4), + CGAffineTransformMakeScale(1/3,1/4)), + }, + + "rotation" : { + testdata: CGAffineTransformConcat(CGAffineTransformMakeRotation(-Math.PI), + CGAffineTransformMakeRotation(Math.PI)), + }, + + }; + + for ( var key in testcases ) + [self assert:YES + equals:CGAffineTransformIsIdentity(testcases[key].testdata) + message:key]; +} + +- (void)testAffineTransformIsIdentityNegative +{ + var testcases = { + "some random transform" : { + testdata: CGAffineTransformMake(1,1,1,1,1,1) + }, + + "non-zero translation is not identity" : { + testdata: CGAffineTransformMakeTranslation(1,1) + }, + + "non-one scale is not identity" : { + testdata: CGAffineTransformMakeScale(2,2) + }, + + "rotation" : { + testdata: CGAffineTransformMakeRotation(Math.PI), + }, + + // TODO a two-pi rotation is actually identity + "2PI rotation is NOT identity?" : { + testdata: CGAffineTransformMakeRotation(Math.PI * 2), + }, + + }; + + for ( var key in testcases ) + [self assert:NO + equals:CGAffineTransformIsIdentity(testcases[key].testdata) + message:key]; +} + +- (void)testAffineTransformEqualToTransform +{ + var testcases = { + "identity" : { + lhs: CGAffineTransformMakeIdentity(), + rhs: CGAffineTransformMakeIdentity(), + expdata: YES + }, + + "translate" : { + lhs: CGAffineTransformMakeTranslation(1,1), + rhs: CGAffineTransformMakeTranslation(1,1), + expdata: YES + }, + + "scale" : { + lhs: CGAffineTransformMakeScale(1,1), + rhs: CGAffineTransformMakeScale(1,1), + expdata: YES + }, + + "rotation" : { + lhs: CGAffineTransformMakeRotation(Math.PI), + rhs: CGAffineTransformMakeRotation(Math.PI), + expdata: YES + }, + + "translate and scale" : { + lhs: CGAffineTransformMakeScale(1,1), + rhs: CGAffineTransformMakeTranslation(1,1), + expdata: NO + }, + }; + + for ( var key in testcases ) + [self assert:testcases[key].expdata + equals:CGAffineTransformEqualToTransform(testcases[key].lhs, testcases[key].rhs) + message:key]; +} + +- (void)testStringCreateWithCGAffineTransform +{ + // FIXME?: should there be a leading space on these strings + var testcases = { + "identity" : { + testdata: CGAffineTransformMakeIdentity(), + expdata: " [[ 1, 0, 0 ], [ 0, 1, 0 ], [ 0, 0, 1]]" + }, + + "scale" : { + testdata: CGAffineTransformMakeScale(3,4), + expdata: " [[ 3, 0, 0 ], [ 0, 4, 0 ], [ 0, 0, 1]]" + }, + + "translation" : { + testdata: CGAffineTransformMakeTranslation(3,4), + expdata: " [[ 1, 0, 0 ], [ 0, 1, 0 ], [ 3, 4, 1]]" + }, + + "scale and translation" : { + testdata: CGAffineTransformTranslate(CGAffineTransformMakeScale(3,4),5,6), + expdata: " [[ 3, 0, 0 ], [ 0, 4, 0 ], [ 15, 24, 1]]" + }, + }; + + for ( var key in testcases ) + [self assert:testcases[key].expdata + equals:CGStringCreateWithCGAffineTransform(testcases[key].testdata) + message:key]; +} + +- (void)testStringFromCGAffineTransform +{ + var testcases = { + "identity" : { + testdata: CGAffineTransformMakeIdentity(), + expdata: "{1, 0, 0, 1, 0, 0}" + }, + + "scale" : { + testdata: CGAffineTransformMakeScale(3,4), + expdata: "{3, 0, 0, 4, 0, 0}" + }, + + "translation" : { + testdata: CGAffineTransformMakeTranslation(3,4), + expdata: "{1, 0, 0, 1, 3, 4}" + }, + + "rotation - zero" : { + testdata: CGAffineTransformMakeRotation(0), + expdata: "{1, 0, 0, 1, 0, 0}" + }, + + "rotation - pi" : { + testdata: CGAffineTransformMakeRotation(Math.PI), + expdata: "{-1, 1.2246467991473532e-16, -1.2246467991473532e-16, -1, 0, 0}" + }, + + "rotation - 2pi" : { + testdata: CGAffineTransformMakeRotation(2 * Math.PI), + expdata: "{1, -2.4492935982947064e-16, 2.4492935982947064e-16, 1, 0, 0}" + }, + + "rotation - 3pi" : { + testdata: CGAffineTransformMakeRotation(3 * Math.PI), + expdata: "{-1, 3.6739403974420594e-16, -3.6739403974420594e-16, -1, 0, 0}" + }, + + "scale and translation and rotate" : { + testdata: CGAffineTransformRotate(CGAffineTransformTranslate(CGAffineTransformMakeScale(3,4),5,6),Math.PI), + expdata: "{-3, 4.898587196589413e-16, -3.6739403974420594e-16, -4, 15, 24}" + }, + }; + + for ( var key in testcases ) + [self assert:testcases[key].expdata + equals:CPStringFromCGAffineTransform(testcases[key].testdata) + message:key]; +} + +- (void)testAffineTransformRotate +{ + var ang = Math.PI + 0.5 * Math.PI, + transform = CGAffineTransformMake( 1,2,3,4, 5,6 ), + cos = COS(ang), + sin = SIN(ang); + + var testcases = { + "affine transform rotate failed" : { + testdata: CGAffineTransformRotate(transform, ang), + expdata: CGAffineTransformMake( transform.a * cos + transform.c * sin, + transform.b * cos + transform.d * sin, + transform.c * cos - transform.a * sin, + transform.d * cos - transform.b * sin, + transform.tx,transform.ty ) + }, + + "rotation negation" : { + testdata: CGAffineTransformRotate(CGAffineTransformRotate(CGAffineTransformMakeScale(3,4),Math.PI),-Math.PI), + expdata: CGAffineTransformMakeScale(3,4) + } + }; + + for ( var key in testcases ) + [self compareTransform:testcases[key].testdata with:testcases[key].expdata message:key]; +} + +- (void)testAffineTransformInvert +{ + var transform = CGAffineTransformRotate(CGAffineTransformTranslate(CGAffineTransformMakeScale(3,4),5,6),Math.PI), + determinant = 1 / (transform.a * transform.d - transform.b * transform.c), + invertedtransform = CGAffineTransformMake(determinant * transform.d, + -determinant * transform.b, + -determinant * transform.c, + determinant * transform.a, + determinant * (transform.c * transform.ty - + transform.d * transform.tx), + determinant * (transform.b * transform.tx - + transform.a * transform.ty)); + + var testcases = { + "test invert algorithm" : { + testdata: transform, + expdata: invertedtransform + }, + + "identity should be it self on inversion" : { + testdata: CGAffineTransformMakeIdentity(), + expdata: CGAffineTransformMakeIdentity() + }, + + "rotation" : { + testdata: CGAffineTransformMakeRotation(-Math.PI), + expdata: CGAffineTransformMakeRotation(Math.PI), + }, + + "translation" : { + testdata: CGAffineTransformMakeTranslation(4,5), + expdata: CGAffineTransformMakeTranslation(-4,-5) + }, + + "scale" : { + testdata: CGAffineTransformMakeScale(3,4), + expdata: CGAffineTransformMakeScale(1/3,1/4) + }, + }; + + for ( var key in testcases ) + [self compareTransform:CGAffineTransformInvert(testcases[key].testdata) + with:testcases[key].expdata + message:key]; +} + +- (void)testRectApplyAffineTransform +{ + var rect = CGRectMake( 3,4,5,6 ); + + var testcases = { + "identity does nothing" : { + testdata: CGRectApplyAffineTransform(rect, CGAffineTransformMakeIdentity() ), + expdata: rect + }, + + "rotation 90 degrees" : { + testdata: CGRectApplyAffineTransform(rect, CGAffineTransformMakeRotation(Math.PI/2)), + expdata: CGRectMake( -10,3.0000000000000004,6,5 ) + }, + + "translation" : { + testdata: CGRectApplyAffineTransform(rect, CGAffineTransformMakeTranslation(3,4)), + expdata: CGRectMake( 6,8,5,6 ) + }, + + "scale" : { + testdata: CGRectApplyAffineTransform(rect, CGAffineTransformMakeScale(1,4)), + expdata: CGRectMake( 3,16,5,24 ) + }, + + "rotate, translate and scale" : { + testdata: CGRectApplyAffineTransform(rect, CGAffineTransformRotate(CGAffineTransformTranslate(CGAffineTransformMakeScale(3,4),5,6),Math.PI)), + expdata: CGRectMake( -9.000000000000004, -16, + 15.000000000000002, 24.000000000000004 ) + }, + }; + + for ( var key in testcases ) + [self compareRect:testcases[key].testdata with:testcases[key].expdata message:key]; +} + +@end diff --git a/Tests/AppKit/CGTestCase.j b/Tests/AppKit/CGTestCase.j new file mode 100644 index 000000000..e00bb1e11 --- /dev/null +++ b/Tests/AppKit/CGTestCase.j @@ -0,0 +1,44 @@ +/* + Used for comparing geometry forms. Otherwise each unit test would repeat these + comparisons. +*/ +@implementation CGTestCase : OJTestCase + +- (void)compareRect:(CGRect)aRect + with:(id)anotherRect + message:(CPString)aMsg +{ + aMsg += " (via cmp. rect)"; + [self comparePoint:aRect.origin with:anotherRect.origin message:aMsg]; + [self compareSize:aRect.size with:anotherRect.size message:aMsg]; +} + +- (void)compareSize:(CGSize)aSize + with:(id)anotherSize + message:(CPString)aMsg +{ + [self assert:anotherSize.width equals:aSize.width message:aMsg + ": Failed for width"]; + [self assert:anotherSize.height equals:aSize.height message:aMsg + ": Failed for height"]; +} + +- (void)comparePoint:(CGPoint)aPoint + with:(id)anotherPoint + message:(CPString)aMsg +{ + [self assert:anotherPoint.x equals:aPoint.x message:aMsg + ": Failed for x"]; + [self assert:anotherPoint.y equals:aPoint.y message:aMsg + ": Failed for y"]; +} + +- (void)compareTransform:(CGAffineTransform)aTransform + with:(id)aDataSet + message:(CPString)aMsg +{ + [self assert:aDataSet.a equals:aTransform.a message:aMsg + ": Failed for a"]; + [self assert:aDataSet.b equals:aTransform.b message:aMsg + ": Failed for b"]; + [self assert:aDataSet.c equals:aTransform.c message:aMsg + ": Failed for c"]; + [self assert:aDataSet.d equals:aTransform.d message:aMsg + ": Failed for d"]; + [self assert:aDataSet.tx equals:aTransform.tx message:aMsg + ": Failed for tx"]; + [self assert:aDataSet.ty equals:aTransform.ty message:aMsg + ": Failed for ty"]; +} + +@end From 6a4d8a24be35668eb7c7f415ad0c4d93548e7c3c Mon Sep 17 00:00:00 2001 From: Gerrit Riessen Date: Mon, 25 Apr 2011 13:34:52 +0200 Subject: [PATCH 09/13] unit test for CGContext --- Tests/AppKit/CGContextTest.j | 78 ++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 Tests/AppKit/CGContextTest.j diff --git a/Tests/AppKit/CGContextTest.j b/Tests/AppKit/CGContextTest.j new file mode 100644 index 000000000..0ed6242e6 --- /dev/null +++ b/Tests/AppKit/CGContextTest.j @@ -0,0 +1,78 @@ +@import +@import "CGTestCase.j" + +@implementation CGContextTest : CGTestCase + +- (void)testEnsureTestingCanvas +{ + /* + Ensure that we have no canvas nor vml support. + */ + [self assert:YES equals:!CPFeatureIsCompatible(CPHTMLCanvasFeature)]; + [self assert:YES equals:!CPFeatureIsCompatible(CPVMLFeature)]; +} + +- (void)testGStateCreate +{ + var gstate = CGGStateCreate(), + testdata = { alpha: 1.0, + strokeStyle: "#000", + fillStyle: "#ccc", + lineWidth: 1.0, + lineJoin: kCGLineJoinMiter, + lineCap: kCGLineCapButt, + miterLimit: 10.0, + globalAlpha: 1.0, + blendMode: kCGBlendModeNormal, + shadowBlur: 0.0, + shadowColor: NULL }; + + for ( var key in testdata ) + [self assert:testdata[key] equals:gstate[key] message:"Failed for " + key]; + + [self compareSize:CGSizeMakeZero() + with:gstate.shadowOffset + message:"Failed for shadowOffset"]; + + [self compareTransform:CGAffineTransformMakeIdentity() + with:gstate.CTM + message:"Failed for CTM"]; +} + +- (void)testGStateCreateCopy +{ + var gstate = CGGStateCreate(), + gstatecopy = CGGStateCreateCopy(gstate), + testdata = { alpha: 1.0, + strokeStyle: "#000", + fillStyle: "#ccc", + lineWidth: 1.0, + lineJoin: kCGLineJoinMiter, + lineCap: kCGLineCapButt, + miterLimit: 10.0, + globalAlpha: 1.0, + blendMode: kCGBlendModeNormal, + shadowBlur: 0.0, + shadowColor: NULL }; + + for ( var key in testdata ) + [self assert:testdata[key] equals:gstatecopy[key] message:"Failed for " + key]; + + // ensure that the size is copied + var sizecopy = CGSizeMakeCopy( gstate.shadowOffset ); + gstate.shadowOffset.width += 1000; + gstate.shadowOffset.height += 2000; + [self compareSize:sizecopy with:gstatecopy.shadowOffset message:"Failed for shadowOffset"]; + + // ensure that the transform is copied + var transformcopy = CGAffineTransformMakeCopy( gstate.CTM ); + gstate.CTM.a += 1000; + gstate.CTM.b += 1000; + gstate.CTM.c += 1000; + gstate.CTM.d += 1000; + gstate.CTM.tx += 1000; + gstate.CTM.ty += 1000; + [self compareTransform:transformcopy with:gstatecopy.CTM message:"Failed with CTM"]; +} + +@end From 6c12442870f7eb0e551c841a9ab9db88274148f4 Mon Sep 17 00:00:00 2001 From: Gerrit Riessen Date: Mon, 25 Apr 2011 14:10:49 +0200 Subject: [PATCH 10/13] Fixed copy the shadowOffset, similar to the copying of the affine transform --- AppKit/CoreGraphics/CGContext.j | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AppKit/CoreGraphics/CGContext.j b/AppKit/CoreGraphics/CGContext.j index 88de992c1..a67d7b200 100644 --- a/AppKit/CoreGraphics/CGContext.j +++ b/AppKit/CoreGraphics/CGContext.j @@ -129,7 +129,7 @@ function CGGStateCreateCopy(aGState) return { alpha:aGState.alpha, strokeStyle:aGState.strokeStyle, fillStyle:aGState.fillStyle, lineWidth:aGState.lineWidth, lineJoin:aGState.lineJoin, lineCap:aGState.lineCap, miterLimit:aGState.miterLimit, globalAlpha:aGState.globalAlpha, blendMode:aGState.blendMode, - shadowOffset:aGState.shadowOffset, shadowBlur:aGState.shadowBlur, shadowColor:aGState.shadowColor, CTM:_CGAffineTransformMakeCopy(aGState.CTM) }; + shadowOffset:_CGSizeMakeCopy(aGState.shadowOffset), shadowBlur:aGState.shadowBlur, shadowColor:aGState.shadowColor, CTM:_CGAffineTransformMakeCopy(aGState.CTM) }; } /*! From 1b3792a1cc436ca9e19376d5f468ffd09febd22f Mon Sep 17 00:00:00 2001 From: Randall Luecke Date: Mon, 25 Apr 2011 17:13:43 -0400 Subject: [PATCH 11/13] Exclude build directory in xcodecapp. --- Tools/xcodecapp/XCResourceMonitor.j | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Tools/xcodecapp/XCResourceMonitor.j b/Tools/xcodecapp/XCResourceMonitor.j index d0fb64191..b6241090f 100644 --- a/Tools/xcodecapp/XCResourceMonitor.j +++ b/Tools/xcodecapp/XCResourceMonitor.j @@ -40,6 +40,8 @@ var FILE = require("file"), paths.exclude(FILE.join(FILE.dirname(aPath), "**", "*")); }); + paths.exclude(FILE.join("Build", "**", "*")); + var mtimesForFilePaths = [CPMutableDictionary new]; paths.forEach(function(aPath) From cde179786cfe3647fbde646b3a5a2c26d9a5ef09 Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Tue, 26 Apr 2011 11:16:36 +0200 Subject: [PATCH 12/13] fail more gracefully when attempting to remove the same observer twice Before this commit we would fail gracefully for single keys. For key paths an application would crash because we would try to get the forwarder property of an undefined object. This commit makes sure we don't attempt any removal and logs a warning (just like Cocoa) about the attempt to remove an unregistered observer. --- Foundation/CPKeyValueObserving.j | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Foundation/CPKeyValueObserving.j b/Foundation/CPKeyValueObserving.j index fbac24c09..ee72d91fc 100644 --- a/Foundation/CPKeyValueObserving.j +++ b/Foundation/CPKeyValueObserving.j @@ -678,6 +678,14 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew | CPKeyValueObservingOpti { var observers = _observersForKey[aPath]; + if (!observers) + { + CPLog.warn(@"Cannot remove an observer %@ for the key path \"%@\" from %@ because it is not registered as an observer.", + _targetObject, aPath, anObserver); + + return; + } + if (aPath.indexOf('.') != CPNotFound) { var forwarder = [observers objectForKey:[anObserver UID]].forwarder; From afb2352a7cb83c2875c808d66de8529f38b8eac7 Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Tue, 26 Apr 2011 11:20:47 +0200 Subject: [PATCH 13/13] consolidate both CPKeyValueObservingTests into one --- Tests/AppKit/CPKeyValueObservingTest.j | 106 --------------------- Tests/Foundation/CPKeyValueObservingTest.j | 95 ++++++++++++++++++ 2 files changed, 95 insertions(+), 106 deletions(-) delete mode 100644 Tests/AppKit/CPKeyValueObservingTest.j diff --git a/Tests/AppKit/CPKeyValueObservingTest.j b/Tests/AppKit/CPKeyValueObservingTest.j deleted file mode 100644 index 67e3cd07b..000000000 --- a/Tests/AppKit/CPKeyValueObservingTest.j +++ /dev/null @@ -1,106 +0,0 @@ -@import - -@implementation CPKeyValueObservingTest : OJTestCase -{ - CPString _lastKeyPath; - id _lastObject; - CPDictionary _lastChange; - id _lastContext; -} - -- (void)setup -{ - _lastKeyPath = _lastObject = _lastChange = _lastContext = nil; -} - -- (void)testInitialObserving -{ - var tester = [ObservingTester testerWithCheese:@"CHEESE!"]; - [tester addObserver:self forKeyPath:@"cheese" options:CPKeyValueObservingOptionNew | CPKeyValueObservingOptionInitial context:nil]; - - [self assert:@"cheese" equals:_lastKeyPath]; - [self assert:tester equals:_lastObject]; - [self assert:[CPDictionary dictionaryWithObject:@"CHEESE!" forKey:CPKeyValueChangeNewKey] equals:_lastChange]; - [self assert:nil equals:_lastContext]; -} - -- (void)observeValueForKeyPath:(CPString)aKeyPath - ofObject:(id)anObject - change:(CPDictionary)aChange - context:(id)aContext -{ - _lastKeyPath = aKeyPath; - _lastObject = anObject; - _lastChange = aChange; - _lastContext = aContext; -} - -- (void)testSendNotificationsForDependantKeyPaths -{ - var observingTester = [ObservingTester testerWithCheese:@"cheese"], - dependantKeyPathTester = [DependantKeyPathsTester testerWithObservingTester:observingTester]; - - [dependantKeyPathTester addObserver:self forKeyPath:@"observedCheese" options:CPKeyValueObservingOptionNew context:nil]; - [observingTester setCheese:@"changed cheese"]; - - [self assert:@"observedCheese" equals:_lastKeyPath] - [self assert:dependantKeyPathTester equals:_lastObject]; -} - -@end - -@implementation ObservingTester : CPObject -{ - id cheese; -} - -+ (id)testerWithCheese:(id)aCheese -{ - var tester = [[self alloc] init]; - [tester setCheese:aCheese]; - return tester; -} - -- (void)setCheese:(id)aCheese -{ - cheese = aCheese; -} - -- (id)cheese -{ - return cheese; -} - -@end - -@implementation DependantKeyPathsTester: CPObject -{ - ObservingTester _observingTester @accessors(property=observingTester); -} - -+ (CPSet)keyPathsForValuesAffectingObservedCheese -{ - return [CPSet setWithObjects:@"observingTester.cheese"]; -} - -+ (id)testerWithObservingTester:(ObservingTester)theObservingTester -{ - return [[self alloc] initWithObservingTester:theObservingTester]; -} - -- (id)initWithObservingTester:(ObservingTester)theObservingTester -{ - if (self = [super init]) - { - _observingTester = theObservingTester; - } - - return self; -} - -- (CPString)observedCheese -{ - return [[self observingTester] cheese]; -} - -@end diff --git a/Tests/Foundation/CPKeyValueObservingTest.j b/Tests/Foundation/CPKeyValueObservingTest.j index 5d43fc8da..2d409618f 100644 --- a/Tests/Foundation/CPKeyValueObservingTest.j +++ b/Tests/Foundation/CPKeyValueObservingTest.j @@ -22,6 +22,45 @@ return [theClass new]; } +- (void)setup +{ + _lastKeyPath = _lastObject = _lastChange = _lastContext = nil; +} + +- (void)testInitialObserving +{ + var tester = [ObservingTester testerWithCheese:@"CHEESE!"]; + [tester addObserver:self forKeyPath:@"cheese" options:CPKeyValueObservingOptionNew | CPKeyValueObservingOptionInitial context:nil]; + + [self assert:@"cheese" equals:_lastKeyPath]; + [self assert:tester equals:_lastObject]; + [self assert:[CPDictionary dictionaryWithObject:@"CHEESE!" forKey:CPKeyValueChangeNewKey] equals:_lastChange]; + [self assert:nil equals:_lastContext]; +} + +- (void)observeValueForKeyPath:(CPString)aKeyPath + ofObject:(id)anObject + change:(CPDictionary)aChange + context:(id)aContext +{ + _lastKeyPath = aKeyPath; + _lastObject = anObject; + _lastChange = aChange; + _lastContext = aContext; +} + +- (void)testSendNotificationsForDependantKeyPaths +{ + var observingTester = [ObservingTester testerWithCheese:@"cheese"], + dependantKeyPathTester = [DependantKeyPathsTester testerWithObservingTester:observingTester]; + + [dependantKeyPathTester addObserver:self forKeyPath:@"observedCheese" options:CPKeyValueObservingOptionNew context:nil]; + [observingTester setCheese:@"changed cheese"]; + + [self assert:@"observedCheese" equals:_lastKeyPath] + [self assert:dependantKeyPathTester equals:_lastObject]; +} + - (void)testOnlyInsertObject_AtKeyIndex_Implemented { var insertSelector = @selector(insertObject:inObjectsAtIndex:), @@ -155,3 +194,59 @@ } @end + +@implementation ObservingTester : CPObject +{ + id cheese; +} + ++ (id)testerWithCheese:(id)aCheese +{ + var tester = [[self alloc] init]; + [tester setCheese:aCheese]; + return tester; +} + +- (void)setCheese:(id)aCheese +{ + cheese = aCheese; +} + +- (id)cheese +{ + return cheese; +} + +@end + +@implementation DependantKeyPathsTester: CPObject +{ + ObservingTester _observingTester @accessors(property=observingTester); +} + ++ (CPSet)keyPathsForValuesAffectingObservedCheese +{ + return [CPSet setWithObjects:@"observingTester.cheese"]; +} + ++ (id)testerWithObservingTester:(ObservingTester)theObservingTester +{ + return [[self alloc] initWithObservingTester:theObservingTester]; +} + +- (id)initWithObservingTester:(ObservingTester)theObservingTester +{ + if (self = [super init]) + { + _observingTester = theObservingTester; + } + + return self; +} + +- (CPString)observedCheese +{ + return [[self observingTester] cheese]; +} + +@end