Merge branch 'master' of git://github.com/cappuccino/cappuccino

This commit is contained in:
Valerii Hiora
2011-12-07 09:58:36 +02:00
7 changed files with 162 additions and 77 deletions
+15 -8
View File
@@ -480,7 +480,9 @@ function CPColorWithImages()
parts[3] ? parseFloat(parts[3], 10) : 1.0
];
_cssString = aString;
// We can't reuse aString as _cssString because the browser might not support the `rgba` syntax, and aString might
// use it (issue #1413.)
[self _initCSSStringFromComponents];
return self;
}
@@ -494,18 +496,23 @@ function CPColorWithImages()
{
_components = components;
var hasAlpha = CPFeatureIsCompatible(CPCSSRGBAFeature) && _components[3] != 1.0;
_cssString = (hasAlpha ? "rgba(" : "rgb(") +
parseInt(_components[0] * 255.0) + ", " +
parseInt(_components[1] * 255.0) + ", " +
parseInt(_components[2] * 255.0) +
(hasAlpha ? (", " + _components[3]) : "") + ")";
[self _initCSSStringFromComponents];
}
return self;
}
- (void)_initCSSStringFromComponents
{
var hasAlpha = CPFeatureIsCompatible(CPCSSRGBAFeature) && _components[3] != 1.0;
_cssString = (hasAlpha ? "rgba(" : "rgb(") +
parseInt(_components[0] * 255.0) + ", " +
parseInt(_components[1] * 255.0) + ", " +
parseInt(_components[2] * 255.0) +
(hasAlpha ? (", " + _components[3]) : "") + ")";
}
/* @ignore */
- (id)_initWithPatternImage:(CPImage)anImage
{
+2 -6
View File
@@ -768,10 +768,6 @@ NOT YET IMPLEMENTED
*/
- (void)setSelectionHighlightStyle:(unsigned)aSelectionHighlightStyle
{
//early return for IE.
if (aSelectionHighlightStyle == CPTableViewSelectionHighlightStyleSourceList && !CPFeatureIsCompatible(CPHTMLCanvasFeature))
return;
_selectionHighlightStyle = aSelectionHighlightStyle;
[self setNeedsDisplay:YES];
@@ -3690,7 +3686,7 @@ Your delegate can implement this method to avoid subclassing the tableview to ad
if (!count)
return;
var drawGradient = (_selectionHighlightStyle === CPTableViewSelectionHighlightStyleSourceList && [_selectedRowIndexes count] >= 1),
var drawGradient = (CPFeatureIsCompatible(CPHTMLCanvasFeature) && _selectionHighlightStyle === CPTableViewSelectionHighlightStyleSourceList && [_selectedRowIndexes count] >= 1),
deltaHeight = 0.5 * (_gridStyleMask & CPTableViewSolidHorizontalGridLineMask);
CGContextBeginPath(context);
@@ -3817,7 +3813,7 @@ Your delegate can implement this method to avoid subclassing the tableview to ad
*/
- (void)_drawGroupRowsForRects:(CPArray)rects
{
if (_selectionHighlightStyle === CPTableViewSelectionHighlightStyleSourceList || !rects.length)
if ((CPFeatureIsCompatible(CPHTMLCanvasFeature) && _selectionHighlightStyle === CPTableViewSelectionHighlightStyleSourceList) || !rects.length)
return;
var context = [[CPGraphicsContext currentContext] graphicsPort],
+4 -1
View File
@@ -390,7 +390,10 @@ var _CPimageAndTextViewFrameSizeChangedFlag = 1 << 0,
var textStyle = hasDOMTextElement ? _DOMTextElement.style : nil;
// Create or destroy the DOM Text Shadow element as necessary.
var needsDOMTextShadowElement = hasDOMTextElement && !!_textShadowColor,
// If _textShadowColor's alphaComponent is 0, don't bother drawing anything (issue #1412).
// This improves performance as we get rid of an invisible element, and makes IE <9.0 capable
// of correctly 'rendering' shadows with [CPColor clearColor].
var needsDOMTextShadowElement = hasDOMTextElement && [_textShadowColor alphaComponent] > 0.0,
hasDOMTextShadowElement = !!_DOMTextShadowElement;
if (needsDOMTextShadowElement !== hasDOMTextShadowElement)
+27 -44
View File
@@ -85,7 +85,6 @@ var CPNotificationDefaultCenter = nil;
if (aNotificationName == nil)
registry = _unnamedRegistry;
else if (!(registry = [_namedRegistries objectForKey:aNotificationName]))
{
registry = [[_CPNotificationRegistry alloc] init];
@@ -181,7 +180,6 @@ var _CPNotificationCenterPostNotification = function(/* CPNotificationCenter */
@implementation _CPNotificationRegistry : CPObject
{
CPDictionary _objectObservers;
BOOL _observerRemovalCount;
}
- (id)init
@@ -190,7 +188,6 @@ var _CPNotificationCenterPostNotification = function(/* CPNotificationCenter */
if (self)
{
_observerRemovalCount = 0;
_objectObservers = [CPDictionary dictionary];
}
@@ -209,12 +206,12 @@ var _CPNotificationCenterPostNotification = function(/* CPNotificationCenter */
if (!observers)
{
observers = [];
observers = [CPMutableSet set];
[_objectObservers setObject:observers forKey:[anObject UID]];
}
// Add this observer.
observers.push(anObserver);
[observers addObject:anObserver];
}
- (void)removeObserver:(id)anObserver object:(id)anObject
@@ -231,16 +228,14 @@ var _CPNotificationCenterPostNotification = function(/* CPNotificationCenter */
while (key = [keys nextObject])
{
var observers = [_objectObservers objectForKey:key],
count = observers ? observers.length : 0;
observer = nil,
observersEnumerator = [observers objectEnumerator];
while (count--)
if ([observers[count] observer] == anObserver)
{
++_observerRemovalCount;
observers.splice(count, 1);
}
while ((observer = [observersEnumerator nextObject]) !== nil)
if ([observer observer] == anObserver)
[observers removeObject:observer];
if (!observers || observers.length == 0)
if (![observers count])
removedKeys.push(key);
}
}
@@ -248,16 +243,14 @@ var _CPNotificationCenterPostNotification = function(/* CPNotificationCenter */
{
var key = [anObject UID],
observers = [_objectObservers objectForKey:key],
count = observers ? observers.length : 0;
observer = nil,
observersEnumerator = [observers objectEnumerator];
while (count--)
if ([observers[count] observer] == anObserver)
{
++_observerRemovalCount;
observers.splice(count, 1)
}
while ((observer = [observersEnumerator nextObject]) !== nil)
if ([observer observer] == anObserver)
[observers removeObject:observer];
if (!observers || observers.length == 0)
if (![observers count])
removedKeys.push(key);
}
@@ -273,26 +266,20 @@ var _CPNotificationCenterPostNotification = function(/* CPNotificationCenter */
// during the posting of this notification, nor observers that get added. The
// best way to do this is to make a copy of the current observers (this avoids
// new observers from being notified) and double checking every observer against
// the current array (this avoids removed observers from receiving notifications).
// However, this is a very expensive operation (O(N) => O(N^2)), so to avoid it,
// we keep track of whether observers are added or removed, and only do our
// rigorous testing in those cases.
var observerRemovalCount = _observerRemovalCount,
object = [aNotification object],
observers = nil;
// the current set (this avoids removed observers from receiving notifications).
var object = [aNotification object],
currentObservers = nil;
if (object != nil && (currentObservers = [_objectObservers objectForKey:[object UID]]))
{
var observers = [currentObservers copy],
count = observers.length;
observer = nil,
observersEnumerator = [observers objectEnumerator];
while (count--)
while ((observer = [observersEnumerator nextObject]) !== nil)
{
var observer = observers[count];
// if there wasn't removal of an observer during this posting, or there
// was but we are still in the observer list...
if ((observerRemovalCount === _observerRemovalCount) || [currentObservers indexOfObjectIdenticalTo:observer] !== CPNotFound)
// CPSet containsObject is N(1) so this is a fast check.
if ([currentObservers containsObject:observer])
[observer postNotification:aNotification];
}
}
@@ -303,17 +290,13 @@ var _CPNotificationCenterPostNotification = function(/* CPNotificationCenter */
if (!currentObservers)
return;
var observerRemovalCount = _observerRemovalCount,
observers = [currentObservers copy],
count = observers.length;
var observers = [currentObservers copy],
observersEnumerator = [observers objectEnumerator];
while (count--)
while ((observer = [observersEnumerator nextObject]) !== nil)
{
var observer = observers[count];
// if there wasn't removal of an observer during this posting, or there
// was but we are still in the observer list...
if ((observerRemovalCount === _observerRemovalCount) || [currentObservers indexOfObjectIdenticalTo:observer] !== CPNotFound)
// CPSet containsObject is N(1) so this is a fast check.
if ([currentObservers containsObject:observer])
[observer postNotification:aNotification];
}
}
+16 -16
View File
@@ -35,7 +35,7 @@ CFDictionary.prototype.copy = function()
{
// Immutable, so no need to actually copy.
return this;
}
};
CFDictionary.prototype.mutableCopy = function()
{
@@ -58,12 +58,12 @@ CFDictionary.prototype.mutableCopy = function()
}
return newDictionary;
}
};
CFDictionary.prototype.containsKey = function(/*String*/ aKey)
{
return hasOwnProperty.apply(this._buckets, [aKey]);
}
};
DISPLAY_NAME(CFDictionary.prototype.containsKey);
@@ -79,21 +79,21 @@ CFDictionary.prototype.containsValue = function(/*id*/ anObject)
return YES;
return NO;
}
};
DISPLAY_NAME(CFDictionary.prototype.containsValue);
CFDictionary.prototype.count = function()
{
return this._count;
}
};
DISPLAY_NAME(CFDictionary.prototype.count);
CFDictionary.prototype.countOfKey = function(/*String*/ aKey)
{
return this.containsKey(aKey) ? 1 : 0;
}
};
DISPLAY_NAME(CFDictionary.prototype.countOfKey);
@@ -110,14 +110,14 @@ CFDictionary.prototype.countOfValue = function(/*id*/ anObject)
++countOfValue;
return countOfValue;
}
};
DISPLAY_NAME(CFDictionary.prototype.countOfValue);
CFDictionary.prototype.keys = function()
{
return this._keys.slice();
}
};
DISPLAY_NAME(CFDictionary.prototype.keys);
@@ -129,7 +129,7 @@ CFDictionary.prototype.valueForKey = function(/*String*/ aKey)
return nil;
return buckets[aKey];
}
};
DISPLAY_NAME(CFDictionary.prototype.valueForKey);
@@ -148,7 +148,7 @@ CFDictionary.prototype.toString = function()
}
return string + "}";
}
};
DISPLAY_NAME(CFDictionary.prototype.toString);
@@ -162,7 +162,7 @@ CFMutableDictionary.prototype = new CFDictionary();
CFMutableDictionary.prototype.copy = function()
{
return this.mutableCopy();
}
};
CFMutableDictionary.prototype.addValueForKey = function(/*String*/ aKey, /*Object*/ aValue)
{
@@ -173,7 +173,7 @@ CFMutableDictionary.prototype.addValueForKey = function(/*String*/ aKey, /*Objec
this._keys.push(aKey);
this._buckets[aKey] = aValue;
}
};
DISPLAY_NAME(CFMutableDictionary.prototype.addValueForKey);
@@ -204,7 +204,7 @@ CFMutableDictionary.prototype.removeValueForKey = function(/*String*/ aKey)
this._keys.splice(indexOfKey, 1);
delete this._buckets[aKey];
}
};
DISPLAY_NAME(CFMutableDictionary.prototype.removeValueForKey);
@@ -213,7 +213,7 @@ CFMutableDictionary.prototype.removeAllValues = function()
this._count = 0;
this._keys = [];
this._buckets = { };
}
};
DISPLAY_NAME(CFMutableDictionary.prototype.removeAllValues);
@@ -223,7 +223,7 @@ CFMutableDictionary.prototype.replaceValueForKey = function(/*String*/ aKey, /*O
return;
this._buckets[aKey] = aValue;
}
};
DISPLAY_NAME(CFMutableDictionary.prototype.replaceValueForKey);
@@ -237,6 +237,6 @@ CFMutableDictionary.prototype.setValueForKey = function(/*String*/ aKey, /*Objec
else
this.addValueForKey(aKey, aValue);
}
};
DISPLAY_NAME(CFMutableDictionary.prototype.setValueForKey);
+81 -2
View File
@@ -1,14 +1,77 @@
@import <Foundation/CPNotificationCenter.j>
var TestNotification = @"TestNotification";
@implementation CPNotificationCenterTest : OJTestCase
{
int notificationCount;
}
/*!
Test various filter parameters.
*/
- (void)testNotify
{
var center = [CPNotificationCenter defaultCenter];
notificationCount = 0;
[center addObserver:self selector:@selector(countNotification:) name:TestNotification object:2];
[center addObserver:self selector:@selector(countNotification:) name:TestNotification object:25];
[center postNotificationName:TestNotification object:self];
[self assert:0 equals:notificationCount message:@"observer should only be notified for object '2'"];
[center postNotificationName:TestNotification object:2];
[self assert:1 equals:notificationCount message:@"observer should be notified for object '2'"];
[center addObserver:self selector:@selector(countNotification:) name:TestNotification object:nil];
[center postNotificationName:TestNotification object:2];
[self assert:3 equals:notificationCount message:@"observer should be notified for object '2' and for any object"];
[center removeObserver:self name:TestNotification object:2];
[center postNotificationName:TestNotification object:2];
[self assert:4 equals:notificationCount message:@"observer should be notified only for any object"];
// At this point we have TestNofication:nil observer and a TestNotification:25 observer.
[center addObserver:self selector:@selector(countNotification:) name:nil object:2];
[center postNotificationName:TestNotification object:2];
[self assert:6 equals:notificationCount message:@"observer should be notified for TestNofication and for object '2' (TestNotification)"];
[center postNotificationName:@"RandomNotification" object:2];
[self assert:7 equals:notificationCount message:@"observer should be notified for object '2' (RandomNotification)"];
[center removeObserver:self name:TestNotification object:nil];
[center postNotificationName:TestNotification object:nil];
[center postNotificationName:TestNotification object:2];
[center postNotificationName:TestNotification object:25];
[self assert:8 equals:notificationCount message:@"observer should be notified only for object '2'"];
[center removeObserver:self];
[center postNotificationName:TestNotification object:nil];
[center postNotificationName:TestNotification object:2];
[center postNotificationName:TestNotification object:25];
[self assert:8 equals:notificationCount message:@"observer should not be notified"];
}
- (void)testAddObserversDuringNotification
{
var center = [CPNotificationCenter defaultCenter];
notificationCount = 0;
[center addObserver:self selector:@selector(addObserversNotification:) name:TestNotification object:nil];
[center postNotificationName:TestNotification object:self];
[self assert:1 equals:notificationCount message:@"the new observers in addObserversNotification: should not be notified"];
[center postNotificationName:TestNotification object:self];
[self assert:5 equals:notificationCount message:@"the new observers from the first addObserversNotification should now be active"];
}
- (void)testRemoveObserversDuringNotification
{
var center = [CPNotificationCenter defaultCenter],
TestNotification = @"TestNotification";
var center = [CPNotificationCenter defaultCenter];
notificationCount = 0;
@@ -29,4 +92,20 @@
[center removeObserver:self];
}
- (void)addObserversNotification:(CPNotification)aNotification
{
notificationCount += 1;
var center = [CPNotificationCenter defaultCenter];
// These should not be notified.
[center addObserver:self selector:@selector(countNotification:) name:TestNotification object:nil];
[center addObserver:self selector:@selector(countNotification:) name:TestNotification object:nil];
[center addObserver:self selector:@selector(countNotification:) name:TestNotification object:nil];
}
- (void)countNotification:(CPNotification)aNotification
{
notificationCount += 1;
}
@end
+17
View File
@@ -35,6 +35,23 @@
[contentView addSubview:textField];
var shadowLabel = [CPTextField labelWithTitle:@"This text should have a shadow."],
championOfLightLabel = [CPTextField labelWithTitle:@"This text should have no shadow."];
[shadowLabel setTextColor:[CPColor blackColor]];
[shadowLabel setTextShadowOffset:CGSizeMake(0, 1)];
[shadowLabel setTextShadowColor:[CPColor colorWithCSSString:@"rgba(0, 0, 0, 0.5)"]];
[championOfLightLabel setTextColor:[CPColor blackColor]];
[championOfLightLabel setTextShadowOffset:CGSizeMake(0, 1)];
[championOfLightLabel setTextShadowColor:[CPColor clearColor]];
[shadowLabel setFrame:CGRectMake(15, CGRectGetMaxY([textField frame]) + 10, 300, 18)];
[championOfLightLabel setFrame:CGRectMake(15, CGRectGetMaxY([shadowLabel frame]) + 2, 300, 18)];
[contentView addSubview:shadowLabel];
[contentView addSubview:championOfLightLabel];
[theWindow orderFront:self];
aWindow = [[CPWindow alloc] initWithContentRect:CGRectMake(150, 300, 400, 150) styleMask:CPTitledWindowMask | CPClosableWindowMask | CPDocModalWindowMask];