Merge branch 'master' into fontinfo-path-fix

This commit is contained in:
cncolder
2011-04-28 10:28:04 +08:00
30 changed files with 1646 additions and 257 deletions
+23 -3
View File
@@ -589,9 +589,7 @@
_mouseDownEvent = anEvent;
var location = [self convertPoint:[anEvent locationInWindow] fromView:nil],
row = FLOOR(location.y / (_itemSize.height + _verticalMargin)),
column = FLOOR(location.x / (_itemSize.width + _horizontalMargin)),
index = row * _numberOfColumns + column;
index = [self _indexAtPoint:location];
if (index >= 0 && index < _items.length)
{
@@ -727,6 +725,28 @@
return _delegate;
}
/*!
@ignore
*/
- (CPMenu)menuForEvent:(CPEvent)theEvent
{
if (![[self delegate] respondsToSelector:@selector(collectionView:menuForItemAtIndex:)])
return [super menuForEvent:theEvent];
var location = [self convertPoint:[theEvent locationInWindow] fromView:nil],
index = [self _indexAtPoint:location];
return [_delegate collectionView:self menuForItemAtIndex:index];
}
- (int)_indexAtPoint:(CGPoint)thePoint
{
var row = FLOOR(thePoint.y / (_itemSize.height + _verticalMargin)),
column = FLOOR(thePoint.x / (_itemSize.width + _horizontalMargin));
return row * _numberOfColumns + column;
}
- (CPCollectionViewItem)itemAtIndex:(unsigned)anIndex
{
return [_items objectAtIndex:anIndex];
+13 -9
View File
@@ -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];
}
}
}
+26 -2
View File
@@ -536,7 +536,6 @@ var _CPMenuBarVisible = NO,
*/
- (void)submenuAction:(id)aSender
{
}
/*!
@@ -584,11 +583,34 @@ var _CPMenuBarVisible = NO,
}
/*!
Not implemented.
Enables or disables the receivers menu items.
If the target does not implement the menu item's action method the item is disabled.
If the target responsds to selector validateMenuItem: or validateUserInterfaceItem: (in that order) the return value is used.
*/
- (void)update
{
if (![self autoenablesItems])
return;
var items = [self itemArray];
for (var i = 0; i < [items count]; i++)
{
var item = [items objectAtIndex:i];
if ([item hasSubmenu])
continue;
var validator = [CPApp targetForAction:[item action] to:[item target] from:item];
if (!validator || ![validator respondsToSelector:[item action]])
[item _setEnabled:NO];
else if ([validator respondsToSelector:@selector(validateMenuItem:)])
[item _setEnabled:[validator validateMenuItem:item]];
else if ([validator respondsToSelector:@selector(validateUserInterfaceItem:)])
[item _setEnabled:[validator validateUserInterfaceItem:item]];
}
[[_menuWindow _menuView] tile];
}
// Managing the Title
@@ -1100,6 +1122,8 @@ var CPMenuTitleKey = @"CPMenuTitleKey",
_showsStateColumn = ![aCoder containsValueForKey:CPMenuShowsStateColumnKey] || [aCoder decodeBoolForKey:CPMenuShowsStateColumnKey];
_autoenablesItems = YES;
[self setMinimumWidth:0];
}
+8 -2
View File
@@ -243,9 +243,15 @@ var STICKY_TIME_INTERVAL = 500,
// Close the current menu item because we are going to select a new one after a short delay
[self showMenu:nil fromMenu:activeMenu atPoint:CGPointMakeZero()];
_showTimerID = setTimeout(function() {
if (![activeMenuContainer isMenuBar])
{
_showTimerID = setTimeout(function() {
[self showMenu:[activeItem submenu] fromMenu:[activeItem menu] atPoint:newMenuOrigin];
}, 250);
}
else
[self showMenu:[activeItem submenu] fromMenu:[activeItem menu] atPoint:newMenuOrigin];
}, 250);
}
}
+6
View File
@@ -208,8 +208,14 @@ var STICKY_TIME_INTERVAL = 500,
return [_menuView menu];
}
- (_CPMenuView)_menuView
{
return _menuView;
}
- (void)orderFront:(id)aSender
{
[[self menu] update];
[self setFrame:_unconstrainedFrame];
[super orderFront:aSender];
+14 -2
View File
@@ -133,10 +133,17 @@
if ([_menu autoenablesItems])
return;
_isEnabled = isEnabled;
[self _setEnabled:isEnabled];
}
- (void)_setEnabled:(BOOL)isEnabled
{
if (_isEnabled === isEnabled)
return;
_isEnabled = !!isEnabled;
[_menuItemView setDirty];
[_menu itemChanged:self];
}
@@ -851,6 +858,11 @@ CPControlKeyMask
return ![self submenu] && [self menu] === [CPApp mainMenu];
}
- (CPString)description
{
return [super description] + @" target: " + [self target] + @" action: " + CPStringFromSelector([self action]);
}
@end
var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey",
+44 -26
View File
@@ -739,41 +739,59 @@ var CPSplitViewHorizontalImage = nil,
Sets the delegate of the receiver.
Possible delegate methods to implement are listed below.
<pre>
- (void)splitViewDidResizeSubviews:(CPSplitView)aSplitView;
Notifies the delegate when the subviews have resized.
Notifies the delegate when the subviews have resized.
@code
- (void)splitViewDidResizeSubviews:(CPNotification)aNotification;
@endcode
- (void)splitViewWillResizeSubviews:(CPSplitView)aSplitView;
Notifies the delegate when the subviews will be resized.
Notifies the delegate when the subviews will be resized.
@code
- (void)splitViewWillResizeSubviews:(CPNotification)aNotification;
@endcode
- (CGRect)splitView:(CPSplitView)aSplitView effectiveRect:(CGRect)aRect forDrawnRect:(CGRect)aDrawnRect ofDividerAtIndex:(int)aDividerIndex;
Lets the delegate specify a different rect for which the user can drag the splitView divider.
Lets the delegate specify a different rect for which the user can drag the splitView divider.
@code
- (CGRect)splitView:(CPSplitView)aSplitView effectiveRect:(CGRect)aRect forDrawnRect:(CGRect)aDrawnRect ofDividerAtIndex:(int)aDividerIndex;
@endcode
- (CGRect)splitView:(CPSplitView)aSplitView additionalEffectiveRectOfDividerAtIndex:(int)indexOfDivider;
Lets the delegate specify an additional rect for which the user can drag the splitview divider.
Lets the delegate specify an additional rect for which the user can drag the splitview divider.
@code
- (CGRect)splitView:(CPSplitView)aSplitView additionalEffectiveRectOfDividerAtIndex:(int)indexOfDivider;
@endcode
- (BOOL)splitView:(CPSplitView)aSplitView canCollapseSubview:(CPView)aSubview;
Notifies the delegate that the splitview is about to be collapsed. This usually happens when the user
Double clicks on the divider. Return YES if the subview can be collapsed, otherwise NO.
Notifies the delegate that the splitview is about to be collapsed. This usually happens when the user
Double clicks on the divider. Return YES if the subview can be collapsed, otherwise NO.
@code
- (BOOL)splitView:(CPSplitView)aSplitView canCollapseSubview:(CPView)aSubview;
@endcode
- (BOOL)splitView:(CPSplitView)aSplitView shouldCollapseSubview:(CPView)aSubview forDoubleClickOnDividerAtIndex:(int)indexOfDivider;
Notifies the delegate that the subview at indexOfDivider is about to be collapsed. This usually happens when the user
Double clicks on the divider. Return YES if the subview should be collapsed, otherwise NO.
Notifies the delegate that the subview at indexOfDivider is about to be collapsed. This usually happens when the user
Double clicks on the divider. Return YES if the subview should be collapsed, otherwise NO.
@code
- (BOOL)splitView:(CPSplitView)aSplitView shouldCollapseSubview:(CPView)aSubview forDoubleClickOnDividerAtIndex:(int)indexOfDivider;
@endcode
- (float)splitView:(CPSplitView)aSpiltView constrainSplitPosition:(float)proposedPosition ofSubviewAt:(int)subviewIndex;
Allows the delegate to constrain the subview beings resized. This method is called continuously as the user resizes the divider.
For example if the subview needs to have a width which is a multiple of a certain number you could return that multiple with this method.
Allows the delegate to constrain the subview beings resized. This method is called continuously as the user resizes the divider.
For example if the subview needs to have a width which is a multiple of a certain number you could return that multiple with this method.
@code
- (float)splitView:(CPSplitView)aSpiltView constrainSplitPosition:(float)proposedPosition ofSubviewAt:(int)subviewIndex;
@endcode
- (float)splitView:(CPSplitView)aSplitView constrainMinCoordinate:(float)proposedMin ofSubviewAt:(int)subviewIndex;
Allows the delegate to constrain the minimum position of a subview.
Allows the delegate to constrain the minimum position of a subview.
@code
- (float)splitView:(CPSplitView)aSplitView constrainMinCoordinate:(float)proposedMin ofSubviewAt:(int)subviewIndex;
@endcode
- (float)splitView:(CPSplitView)aSplitView constrainMaxCoordinate:(float)proposedMax ofSubviewAt:(int)subviewIndex;
Allows the delegate to constrain the maximum position of a subview.
Allows the delegate to constrain the maximum position of a subview.
@code
- (float)splitView:(CPSplitView)aSplitView constrainMaxCoordinate:(float)proposedMax ofSubviewAt:(int)subviewIndex;
@endcode
- (void)splitView:(CPSplitView)aSplitView resizeSubviewsWithOldSize:(CGSize)oldSize;
Allows the splitview to specify a custom resizing behavior. This is called when the splitview is resized.
The sum of the views and the sum of the dividers should be equal to the size of the splitview.
</pre>
Allows the splitview to specify a custom resizing behavior. This is called when the splitview is resized.
The sum of the views and the sum of the dividers should be equal to the size of the splitview.
@code
- (void)splitView:(CPSplitView)aSplitView resizeSubviewsWithOldSize:(CGSize)oldSize;
@endcode
@param delegate - The delegate of the splitview.
*/
+17 -13
View File
@@ -193,24 +193,24 @@ var SHADOW_MARGIN_LEFT = 20.0,
_CPWindowShadowColor = nil;
var CPWindowSaveImage = nil,
CPWindowSavingImage = nil;
CPWindowSavingImage = nil,
var CPWindowResizeTime = 0.2;
CPWindowResizeTime = 0.2;
/*
Keys for which action messages will be sent by default when unhandled, e.g. complete:.
*/
var CPWindowActionMessageKeys = [
CPLeftArrowFunctionKey,
CPRightArrowFunctionKey,
CPUpArrowFunctionKey,
CPDownArrowFunctionKey,
CPPageUpFunctionKey,
CPPageDownFunctionKey,
CPHomeFunctionKey,
CPEndFunctionKey,
CPEscapeFunctionKey
];
CPLeftArrowFunctionKey,
CPRightArrowFunctionKey,
CPUpArrowFunctionKey,
CPDownArrowFunctionKey,
CPPageUpFunctionKey,
CPPageDownFunctionKey,
CPHomeFunctionKey,
CPEndFunctionKey,
CPEscapeFunctionKey
];
/*!
@ingroup appkit
@@ -2377,7 +2377,9 @@ CPTexturedBackgroundWindowMask
// an event going of the responder chain is passed to the input system as a last resort.
// However, the only methods I could get Cocoa to call automatically are
// moveUp: moveDown: moveLeft: moveRight: pageUp: pageDown: and complete:
[self _processKeyboardUIKey:anEvent];
// Unhandled events just travel further up the responder chain _past_ the window.
if (![self _processKeyboardUIKey:anEvent])
[super keyDown:anEvent];
}
/*
@@ -2412,6 +2414,8 @@ CPTexturedBackgroundWindowMask
// The difference is that doCommandBySelector: will also send the action to the window and application delegates.
[[self firstResponder] doCommandBySelector:@selector(complete:)];
}
return NO;
}
- (void)_dirtyKeyViewLoop
-4
View File
@@ -47,12 +47,8 @@
// If the destination doesn't respond to this selector, warn but don't die.
if (_destination && ![_destination respondsToSelector:selector])
{
CPLog.warn(@"Could not connect the action " + selector + @" to target of class " + [_destination className]);
return;
}
// Not being able to set the action is a fatal error.
if ([_source respondsToSelector:@selector(setAction:)])
objj_msgSend(_source, @selector(setAction:), selector);
+14 -11
View File
@@ -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);
}
/*!
+2 -2
View File
@@ -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) };
}
/*!
@@ -606,7 +606,7 @@ function CGContextStrokeLineSegments(aContext, points, count)
{
var i = 0;
if (arguments["count"] == NULL)
if (count === NULL)
var count = points.length;
CGContextBeginPath(aContext);
+3 -3
View File
@@ -144,7 +144,7 @@ function CGContextAddRects(aContext, rects, count)
{
var i = 0;
if (arguments["count"] == NULL)
if (count === NULL)
var count = rects.length;
for (; i < count; ++i)
@@ -194,7 +194,7 @@ function CGContextFillRects(aContext, rects, count)
{
var i = 0;
if (arguments["count"] == NULL)
if (count === NULL)
var count = rects.length;
for (; i < count; ++i)
@@ -225,7 +225,7 @@ function CGContextClipToRect(aContext, aRect)
function CGContextClipToRects(aContext, rects, count)
{
if (arguments["count"] == NULL)
if (count === NULL)
var count = rects.length;
_CGContextBeginPathCanvas(aContext);
+9 -4
View File
@@ -29,10 +29,15 @@ kCGGradientDrawsAfterEndLocation = 1 << 1;
function CGGradientCreateWithColorComponents(aColorSpace, components, locations, count)
{
if (arguments["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 (arguments["count"] == NULL)
if ( count === undefined || count === NULL)
var count = locations.length;
var colors = [];
@@ -58,4 +63,4 @@ function CGGradientRelease()
function CGGradientRetain(aGradient)
{
return aGradient;
}
}
+2 -2
View File
@@ -141,7 +141,7 @@ function CGPathAddLines(aPath, aTransform, points, count)
{
var i = 1;
if (arguments["count"] == NULL)
if (count === NULL)
var count = points.length;
if (!aPath || count < 2)
@@ -224,7 +224,7 @@ function CGPathAddRects(aPath, aTransform, rects, count)
{
var i = 0;
if (arguments["count"] == NULL)
if (count === NULL)
var count = rects.length;
for (; i < count; ++i)
+1 -1
View File
@@ -332,7 +332,7 @@
[self replaceObjectAtIndex:otherIndex withObject:temporary];
}
- (CPArray)sortUsingDescriptors:(CPArray)descriptors
- (void)sortUsingDescriptors:(CPArray)descriptors
{
[self sortUsingFunction:compareObjectsUsingDescriptors context:descriptors];
}
+8
View File
@@ -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;
+69 -66
View File
@@ -441,71 +441,48 @@ var _CPKeyedUnarchiverDecodeObjectAtIndex = function(self, anIndex)
var object = self._objects[anIndex];
if (object)
{
if (object === self._objects[0])
return nil;
else
return object;
var object,
plistObject = self._plistObjects[anIndex],
plistObjectClass = plistObject.isa;
if (plistObjectClass === CPDictionaryClass || plistObjectClass === CPMutableDictionaryClass)
// Don't return immediately here. The _CPKeyedArchiverValueClass unwrapper code
// hasn't executed yet.
}
else
{
var plistClass = self._plistObjects[plistObject.valueForKey(_CPKeyedArchiverClassKey).valueForKey(_CPKeyedArchiverUIDKey)],
className = plistClass.valueForKey(_CPKeyedArchiverClassNameKey),
classes = plistClass.valueForKey(_CPKeyedArchiverClassesKey),
theClass = [self classForClassName:className];
var plistObject = self._plistObjects[anIndex],
plistObjectClass = plistObject.isa;
if (!theClass)
theClass = CPClassFromString(className);
if (!theClass && (self._delegateSelectors & CPKeyedUnarchiverDelegate_unarchiver_cannotDecodeObjectOfClassName_originalClasses_))
theClass = [_delegate unarchiver:self cannotDecodeObjectOfClassName:className originalClasses:classes];
if (!theClass)
[CPException raise:CPInvalidUnarchiveOperationException reason:@"-[CPKeyedUnarchiver decodeObjectForKey:]: cannot decode object of class (" + className + @")"];
var savedPlistObject = self._plistObject;
self._plistObject = plistObject;
// Should we only call this on _CPCibClassSwapper? (currently the only class that makes use of this).
object = [theClass allocWithCoder:self];
// It is important to do this before calling initWithCoder so that decoding can be self referential (something = self).
self._objects[anIndex] = object;
var processedObject = [object initWithCoder:self];
self._plistObject = savedPlistObject;
if (processedObject !== object)
if (plistObjectClass === CPDictionaryClass || plistObjectClass === CPMutableDictionaryClass)
{
if (self._delegateSelectors & _CPKeyedUnarchiverWillReplaceObjectWithObjectSelector)
[self._delegate unarchiver:self willReplaceObject:object withObject:processedObject];
var plistClass = self._plistObjects[plistObject.valueForKey(_CPKeyedArchiverClassKey).valueForKey(_CPKeyedArchiverUIDKey)],
className = plistClass.valueForKey(_CPKeyedArchiverClassNameKey),
classes = plistClass.valueForKey(_CPKeyedArchiverClassesKey),
theClass = [self classForClassName:className];
object = processedObject;
self._objects[anIndex] = processedObject;
}
if (!theClass)
theClass = CPClassFromString(className);
processedObject = [object awakeAfterUsingCoder:self];
if (!theClass && (self._delegateSelectors & CPKeyedUnarchiverDelegate_unarchiver_cannotDecodeObjectOfClassName_originalClasses_))
theClass = [_delegate unarchiver:self cannotDecodeObjectOfClassName:className originalClasses:classes];
if (processedObject !== object)
{
if (self._delegateSelectors & _CPKeyedUnarchiverWillReplaceObjectWithObjectSelector)
[self._delegate unarchiver:self willReplaceObject:object withObject:processedObject];
if (!theClass)
[CPException raise:CPInvalidUnarchiveOperationException reason:@"-[CPKeyedUnarchiver decodeObjectForKey:]: cannot decode object of class (" + className + @")"];
object = processedObject;
self._objects[anIndex] = processedObject;
}
var savedPlistObject = self._plistObject;
if (self._delegate)
{
if (self._delegateSelectors & _CPKeyedUnarchiverDidDecodeObjectSelector)
processedObject = [self._delegate unarchiver:self didDecodeObject:object];
self._plistObject = plistObject;
if (processedObject && processedObject != object)
// Should we only call this on _CPCibClassSwapper? (currently the only class that makes use of this).
object = [theClass allocWithCoder:self];
// It is important to do this before calling initWithCoder so that decoding can be self referential (something = self).
self._objects[anIndex] = object;
var processedObject = [object initWithCoder:self];
self._plistObject = savedPlistObject;
if (processedObject !== object)
{
if (self._delegateSelectors & _CPKeyedUnarchiverWillReplaceObjectWithObjectSelector)
[self._delegate unarchiver:self willReplaceObject:object withObject:processedObject];
@@ -513,22 +490,48 @@ var _CPKeyedUnarchiverDecodeObjectAtIndex = function(self, anIndex)
object = processedObject;
self._objects[anIndex] = processedObject;
}
}
}
else
{
self._objects[anIndex] = object = plistObject;
if ([object class] === CPStringClass)
{
if (object === _CPKeyedArchiverNullString)
processedObject = [object awakeAfterUsingCoder:self];
if (processedObject !== object)
{
self._objects[anIndex] = self._objects[0];
if (self._delegateSelectors & _CPKeyedUnarchiverWillReplaceObjectWithObjectSelector)
[self._delegate unarchiver:self willReplaceObject:object withObject:processedObject];
return nil;
object = processedObject;
self._objects[anIndex] = processedObject;
}
if (self._delegate)
{
if (self._delegateSelectors & _CPKeyedUnarchiverDidDecodeObjectSelector)
processedObject = [self._delegate unarchiver:self didDecodeObject:object];
if (processedObject && processedObject != object)
{
if (self._delegateSelectors & _CPKeyedUnarchiverWillReplaceObjectWithObjectSelector)
[self._delegate unarchiver:self willReplaceObject:object withObject:processedObject];
object = processedObject;
self._objects[anIndex] = processedObject;
}
}
}
else
{
self._objects[anIndex] = object = plistObject;
if ([object class] === CPStringClass)
{
if (object === _CPKeyedArchiverNullString)
{
self._objects[anIndex] = self._objects[0];
return nil;
}
else
self._objects[anIndex] = object = plistObject;
}
else
self._objects[anIndex] = object = plistObject;
}
}
+1 -1
View File
@@ -227,7 +227,7 @@ CPURLCustomIconKey = @"CPURLCustomIconKey";
return self.setResourcePropertyForKey(aKey, anObject);
}
- (CPString)staticResourceData
- (CPData)staticResourceData
{
return self.staticResourceData();
}
+511
View File
@@ -0,0 +1,511 @@
@import <AppKit/CGAffineTransform.j>
@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
+168
View File
@@ -0,0 +1,168 @@
@import <AppKit/CGColorSpace.j>
@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
+217
View File
@@ -0,0 +1,217 @@
@import <AppKit/CGColor.j>
@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
+78
View File
@@ -0,0 +1,78 @@
@import <AppKit/CGContext.j>
@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
+100
View File
@@ -0,0 +1,100 @@
@import <AppKit/CGGradient.j>
@implementation CGGradientTest : OJTestCase
/*
Using default values for location and count.
*/
- (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 ];
var tmp = CGGradientCreateWithColorComponents(CGColorSpaceCreateDeviceRGB(),
components);
[self assert:2 equals:tmp.colors.length];
[self assert:2 equals:tmp.locations.length];
[self assert:0 equals:tmp.locations[0]];
[self assert:1.0 equals:tmp.locations[1]];
[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];
}
/*
Using location and components to specify two color stops that aren't
evenly spread out.
*/
- (void)testCreateWithColorComponentsUsingTwoColorStops
{
var components = [ 0.2,0.2,0.4,0.4,
0.6,0.6,0.8,0.8 ];
var locations = [0.3,0.6];
var tmp = CGGradientCreateWithColorComponents(CGColorSpaceCreateDeviceRGB(),
components,locations);
[self assert:2 equals:tmp.colors.length];
[self assert:2 equals:tmp.locations.length];
[self assert:0.3 equals:tmp.locations[0]];
[self assert:0.6 equals:tmp.locations[1]];
[self assert:components.slice(4,8) equals:tmp.colors[1].components];
[self assert:components.slice(0,4) equals:tmp.colors[0].components];
}
/*
Define three color components and ensure that the Gradient defined contains 3 color stops.
*/
- (void)testCanHaveMoreThanTwoColorStops
{
var components = [ 1,2,3,4, 5,6,7,8, 9,10,11,12 ];
var locations = [1,2,3];
var tmp = CGGradientCreateWithColorComponents(CGColorSpaceCreateDeviceRGB(),
components, locations, 3);
[self assert:3 equals:tmp.colors.length];
[self assert:3 equals:tmp.locations.length];
[self assert:1 equals:tmp.locations[0]];
[self assert:2 equals:tmp.locations[1]];
[self assert:3 equals:tmp.locations[2]];
}
@end
+44
View File
@@ -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
-106
View File
@@ -1,106 +0,0 @@
@import <Foundation/CPKeyValueObserving.j>
@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
@@ -0,0 +1,86 @@
var CPMenuValidatedUserInterfaceItemTestValidatedItems = [];
@implementation CPMenuValidatedUserInterfaceItemTest : OJTestCase
{
CPMenu _menu @accessors(property=menu);
MenuTarget _menuTarget @accessors(property=menuTarget);
}
- (void)setUp
{
_menuTarget = [[MenuTarget alloc] init];
[[CPApplication sharedApplication] setDelegate:_menuTarget];
_menu = [[CPMenu alloc] init];
[_menu addItem:[[CPMenuItem alloc] initWithTitle:@"implemented" action:@selector(implementedAction:) keyEquivalent:nil]];
[_menu addItem:[[CPMenuItem alloc] initWithTitle:@"disabled" action:@selector(disabledAction:) keyEquivalent:nil]];
[_menu addItem:[[CPMenuItem alloc] initWithTitle:@"unimplemented" action:@selector(unimplementedAction:) keyEquivalent:nil]];
var parentItem = [[CPMenuItem alloc] initWithTitle:@"parent" action:nil keyEquivalent:nil];
[_menu addItem:parentItem];
[parentItem setSubmenu:[[CPMenu alloc] init]];
[[parentItem submenu] addItem:[[CPMenuItem alloc] initWithTitle:@"Submenu 1" action:nil keyEquivalent:nil]];
CPMenuValidatedUserInterfaceItemTestValidatedItems = [];
// Update is what performs the autoenabling so we need to call it manually.
// It's normally called automatically just before a menu becomes visible.
[_menu update];
}
- (void)testAutoenable
{
[self assertTrue:[[[self menu] itemWithTitle:@"implemented"] isEnabled] message:@"The implemented action should be enabled"];
[self assertFalse:[[[self menu] itemWithTitle:@"disabled"] isEnabled] message:@"The disbabled action should be disabled"];
[self assertFalse:[[[self menu] itemWithTitle:@"unimplemented"] isEnabled] message:@"The unimplemented action should be disabled"];
}
- (void)testThatParentMenusAreNotValidated
{
var parentItem = [[self menu] itemWithTitle:@"parent"];
[self assertTrue:[parentItem isEnabled] message:@"Parent items should never be disabled"];
[self assertFalse:[[[self menuTarget] validatedItems] containsObject:parent] message:@"Parent items should never be validated"];
}
@end
@implementation MenuTarget : CPObject
{
CPArray _validatedItems @accessors(property=validatedItems, readonly);
}
- (id)init
{
if (self = [super init])
{
_validatedItems = [];
}
return self;
}
- (BOOL)validateMenuItem:(CPMenuItem)theMenuItem
{
[_validatedItems addObject:theMenuItem];
if ([theMenuItem action] === @selector(disabledAction:))
return NO;
return YES;
}
- (@action)implementedAction:(id)theSender
{
}
- (@action)disabledAction:(id)theSender
{
}
@end
+41
View File
@@ -0,0 +1,41 @@
@import <AppKit/CPTextField.j>
[CPApplication sharedApplication]
@implementation CPTextFieldTest : OJTestCase
{
}
/*!
Detect regressions with JS object theme attribute encoding in subclasses.
This test is not actually CPTextField specific at all. This just happens
to be the first place the keyed archiving bug was discovered, and there is
an additional, more specific, test in CPKeyedArchiverTest.
*/
- (void)testArchiveThemeAttributes
{
var view = [[CPTextFieldSubclass alloc] initWithFrame:CGRectMakeZero()],
decoded = [CPKeyedUnarchiver unarchiveObjectWithData:[CPKeyedArchiver archivedDataWithRootObject:view]];
[self assert:[view valueForThemeAttribute:@"content-inset"].top equals:2 message:@"content-inset should initialise correctly"];
[self assert:[view valueForThemeAttribute:@"content-inset"].top equals:[decoded valueForThemeAttribute:@"content-inset"].top message:@"content-inset should unarchive correctly"];
}
@end
@implementation CPTextFieldSubclass : CPTextField
{
}
- (id)initWithFrame:aFrame
{
if (self = [super initWithFrame:aFrame])
{
[self setValue:CGInsetMake(2.0, 2.0, 2.0, 2.0) forThemeAttribute:"content-inset"];
}
return self;
}
@end
@@ -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
+44
View File
@@ -0,0 +1,44 @@
@import <Foundation/CPKeyedArchiver.j>
@import <Foundation/CPKeyedUnarchiver.j>
@implementation CPKeyedArchiverTest : OJTestCase
{
}
- (void)testJavaScriptObject
{
var original = [Archivable new];
[original setAJsObject:{ 'top': 5 }];
var decoded = [CPKeyedUnarchiver unarchiveObjectWithData:[CPKeyedArchiver archivedDataWithRootObject:original]]
[self assert:5 equals:[decoded aJsObject].top message:"JS object encoded and decoded right"];
}
@end
@implementation Archivable : CPObject
{
JSObject aJsObject @accessors;
}
- (id)initWithCoder:(CPCoder)aCoder
{
if (self = [super init])
{
// Note we decode this twice to expose a bug where the cached decoded
// values did not properly unwrap JS objects.
aJsObject = [aCoder decodeObjectForKey:@"aJsObject"];
aJsObject = [aCoder decodeObjectForKey:@"aJsObject"];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[aCoder encodeObject:aJsObject forKey:@"aJsObject"];
}
@end
+2
View File
@@ -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)