diff --git a/AppKit/CoreGraphics/CGColor.j b/AppKit/CoreGraphics/CGColor.j index 321d091b6..7b8ee6088 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]); } /*! @@ -149,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/CGColorSpaceTest.j b/Tests/AppKit/CGColorSpaceTest.j new file mode 100644 index 000000000..3df8b4c3f --- /dev/null +++ b/Tests/AppKit/CGColorSpaceTest.j @@ -0,0 +1,168 @@ +@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 +{ + 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]; + } +} + +- (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 diff --git a/Tests/AppKit/CGColorTest.j b/Tests/AppKit/CGColorTest.j new file mode 100644 index 000000000..97416ef87 --- /dev/null +++ b/Tests/AppKit/CGColorTest.j @@ -0,0 +1,217 @@ +@import + +@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(), + 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"]; +} + +- (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 +{ + [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 +