diff --git a/AppKit/CPView.j b/AppKit/CPView.j index 33d1bac60..f0f598ab3 100644 --- a/AppKit/CPView.j +++ b/AppKit/CPView.j @@ -252,6 +252,8 @@ var CPViewHighDPIDrawingEnabled = YES; id _animator; CPDictionary _animationsDictionary; + BOOL _inhibitDOMUpdates @accessors(setter=_setInhibitDOMUpdates); + BOOL _forceUpdates @accessors(setter=_setForceUpdates); } /* @@ -404,6 +406,9 @@ var CPViewHighDPIDrawingEnabled = YES; [self _setupViewFlags]; [self _loadThemeAttributes]; + + _inhibitDOMUpdates = NO; + _forceUpdates = NO; } return self; @@ -1013,7 +1018,7 @@ var CPViewHighDPIDrawingEnabled = YES; */ - (void)setFrame:(CGRect)aFrame { - if (CGRectEqualToRect(_frame, aFrame)) + if (CGRectEqualToRect(_frame, aFrame) && !_forceUpdates) return; _inhibitFrameAndBoundsChangedNotifications = YES; @@ -1084,7 +1089,7 @@ var CPViewHighDPIDrawingEnabled = YES; { var origin = _frame.origin; - if (!aPoint || CGPointEqualToPoint(origin, aPoint)) + if (!aPoint || (CGPointEqualToPoint(origin, aPoint) && !_forceUpdates)) return; origin.x = aPoint.x; @@ -1097,9 +1102,12 @@ var CPViewHighDPIDrawingEnabled = YES; [[self superview] viewFrameChanged:[[CPNotification alloc] initWithName:CPViewFrameDidChangeNotification object:self userInfo:nil]]; #if PLATFORM(DOM) - var transform = _superview ? _superview._boundsTransform : NULL; + if (!_inhibitDOMUpdates) + { + var transform = _superview ? _superview._boundsTransform : NULL; - CPDOMDisplayServerSetStyleLeftTop(_DOMElement, transform, origin.x, origin.y); + CPDOMDisplayServerSetStyleLeftTop(_DOMElement, transform, origin.x, origin.y); + } #endif if (!_inhibitUpdateTrackingAreas && !_inhibitFrameAndBoundsChangedNotifications) @@ -1116,7 +1124,7 @@ var CPViewHighDPIDrawingEnabled = YES; { var size = _frame.size; - if (!aSize || CGSizeEqualToSize(size, aSize)) + if (!aSize || (CGSizeEqualToSize(size, aSize) && !_forceUpdates)) return; var oldSize = CGSizeMakeCopy(size); diff --git a/AppKit/CoreAnimation/CPAnimationContext.j b/AppKit/CoreAnimation/CPAnimationContext.j index e62b3002d..9d8b1c06f 100644 --- a/AppKit/CoreAnimation/CPAnimationContext.j +++ b/AppKit/CoreAnimation/CPAnimationContext.j @@ -152,24 +152,32 @@ CPLog.debug(_cmd + "context stack =" + _CPAnimationContextStack); duration = [animation duration] || [self duration]; - var needsFrameTimer = (aKeyPath == @"frame" || aKeyPath == @"frameSize") && - ([anObject hasCustomLayoutSubviews] || [anObject hasCustomDrawRect]) && - (objectId = [anObject UID]); + var needsPeriodicFrameUpdates = (((aKeyPath == @"frame" || aKeyPath == @"frameSize") && + ([anObject hasCustomLayoutSubviews] || [anObject hasCustomDrawRect])) || [[anObject animator] wantsPeriodicFrameUpdates]) && + (objectId = [anObject UID]); if (_completionHandlerAgent) _completionHandlerAgent.increment(); var completionFunction = function() { - if (needsFrameTimer) + if (needsPeriodicFrameUpdates) + { [self stopFrameUpdaterWithIdentifier:objectId]; + if ([anObject respondsToSelector:@selector(_setForceUpdates:)]) + [anObject _setForceUpdates:YES]; + } + if (animationCompletion) animationCompletion(); - if (needsFrameTimer || animationCompletion) + if (needsPeriodicFrameUpdates || animationCompletion) [[CPRunLoop currentRunLoop] performSelectors]; + if (needsPeriodicFrameUpdates && [anObject respondsToSelector:@selector(_setForceUpdates:)]) + [anObject _setForceUpdates:NO]; + if (_completionHandlerAgent) _completionHandlerAgent.decrement(); }; @@ -266,7 +274,7 @@ CPLog.debug(_cmd + "context stack =" + _CPAnimationContextStack); isFrameKeyPath = (keyPath == @"frame" || keyPath == @"frameSize"), customLayout = [aTargetView hasCustomLayoutSubviews], customDrawing = [aTargetView hasCustomDrawRect], - needsFrameTimer = isFrameKeyPath && (customLayout || customDrawing); + needsPeriodicFrameUpdates = ((isFrameKeyPath && (customLayout || customDrawing)) || [[aTargetView animator] wantsPeriodicFrameUpdates]); if (needsCSSAnimation) { @@ -305,7 +313,7 @@ CPLog.debug(_cmd + "context stack =" + _CPAnimationContextStack); }]; } - if (needsFrameTimer) + if (needsPeriodicFrameUpdates) { var timer = [self addFrameUpdaterWithIdentifier:[rootView UID] forView:aTargetView keyPath:keyPath duration:anAction.duration]; @@ -314,35 +322,36 @@ CPLog.debug(_cmd + "context stack =" + _CPAnimationContextStack); } var subviews = [aTargetView subviews], - count = [subviews count]; + count = [subviews count], + customLayout = [aTargetView hasCustomLayoutSubviews]; if (count && isFrameKeyPath) { var frameTimerId = [rootView UID], - lastIndex = count - 1; + lastIndex = count - 1; [subviews enumerateObjectsUsingBlock:function(aSubview, idx, stop) - { - var action = [self actionFromAction:anAction forAnimatedSubview:aSubview], + { + var action = [self actionFromAction:anAction forAnimatedSubview:aSubview], targetFrame = [action.values lastObject]; - if (CGRectEqualToRect([aSubview frame], targetFrame)) - return; + if (CGRectEqualToRect([aSubview frame], targetFrame)) + return; - if ([aSubview hasCustomDrawRect]) - { - action.completion = function() - { - [aSubview setFrame:targetFrame]; - CPLog.debug(aSubview + " setFrame: "); + if ([aSubview hasCustomDrawRect]) + { + action.completion = function() + { + [aSubview setFrame:targetFrame]; + CPLog.debug(aSubview + " setFrame: "); - if (idx == lastIndex) - [self stopFrameUpdaterWithIdentifier:frameTimerId]; - }; - } + if (idx == lastIndex) + [self stopFrameUpdaterWithIdentifier:frameTimerId]; + }; + } - [self getAnimations:cssAnimations getTimers:timers forView:aSubview usingAction:action rootView:rootView cssAnimate:!customLayout]; - }]; + [self getAnimations:cssAnimations getTimers:timers forView:aSubview usingAction:action rootView:rootView cssAnimate:!customLayout]; + }]; } } @@ -422,6 +431,7 @@ CPLog.debug(_cmd + "context stack =" + _CPAnimationContextStack); { var mask = [self autoresizingMask]; + if (mask == CPViewNotSizable) return _frame; @@ -674,31 +684,43 @@ FrameUpdater.prototype.addTarget = function(target, keyPath, duration) var createUpdateFrame = function(aView, aKeyPath) { - if (aKeyPath !== "frame" && aKeyPath !== "frameSize") + if (aKeyPath !== "frame" && aKeyPath !== "frameSize" && aKeyPath !== "frameOrigin") return nil; var style = getComputedStyle(aView._DOMElement), - getCSSPropertyValue = function(prop) { - return ROUND(parseFloat(style.getPropertyValue(prop))); - }; - - var updateFrame = function(timestamp) + getCSSPropertyValue = function(prop) { + return ROUND(parseFloat(style.getPropertyValue(prop))); + }, + initialOrigin = CGPointMakeCopy([aView frameOrigin]), + transformProperty = CPBrowserCSSProperty("transform"), + updateFrame = function(timestamp) { var width = getCSSPropertyValue("width"), height = getCSSPropertyValue("height"); - if (aKeyPath == "frame") - { - var left = getCSSPropertyValue("left"), - top = getCSSPropertyValue("top"), - frame = CGRectMake(left, top, width, height); - - [aView setFrame:frame]; - } - else if (aKeyPath == "frameSize") + if (aKeyPath === "frameSize") { [aView setFrameSize:CGSizeMake(width, height)]; } + else + { + [aView _setInhibitDOMUpdates:YES]; + + var matrix = style[transformProperty].split('(')[1].split(')')[0].split(','), + x = ROUND(initialOrigin.x + parseFloat(matrix[4])), + y = ROUND(initialOrigin.y + parseFloat(matrix[5])); + + if (aKeyPath === "frame") + { + [aView setFrame:CGRectMake(x, y, width, height)]; + } + else + { + [aView setFrameOrigin:CGPointMake(x, y)]; + } + + [aView _setInhibitDOMUpdates:NO]; + } [[CPRunLoop currentRunLoop] performSelectors]; }; diff --git a/AppKit/CoreAnimation/CPViewAnimator.j b/AppKit/CoreAnimation/CPViewAnimator.j index 61fd20b71..4d30e756d 100644 --- a/AppKit/CoreAnimation/CPViewAnimator.j +++ b/AppKit/CoreAnimation/CPViewAnimator.j @@ -1,9 +1,20 @@ @import "_CPObjectAnimator.j" @import "CPView.j" +@import "CPCompatibility.j" @implementation CPViewAnimator : _CPObjectAnimator { + BOOL _wantsPeriodicFrameUpdates @accessors(property=wantsPeriodicFrameUpdates); +} + +- (id)initWithTarget:(id)aTarget +{ + self = [super initWithTarget:aTarget]; + + _wantsPeriodicFrameUpdates = NO; + + return self; } - (void)removeFromSuperview @@ -76,16 +87,6 @@ @end -var transformOrigin = function(start, current) -{ - return "translate(" + (current.x - start.x) + "px," + (current.y - start.y) + "px)"; -}; - -var transformFrameToTranslate = function(start, current) -{ - return transformOrigin(start.origin, current.origin); -}; - var transformFrameToWidth = function(start, current) { return current.size.width + "px"; @@ -106,6 +107,25 @@ var transformSizeToHeight = function(start, current) return current.height + "px"; }; +var CSSStringFromCGAffineTransform = function(anAffineTransform) +{ + return "matrix(" + anAffineTransform.a + ", " + anAffineTransform.b + ", " + anAffineTransform.c + ", " + anAffineTransform.d + ", " + anAffineTransform.tx + (CPBrowserIsEngine(CPGeckoBrowserEngine) ? "px, " : ", ") + anAffineTransform.ty + (CPBrowserIsEngine(CPGeckoBrowserEngine) ? "px)" : ")"); +}; + +var frameOriginToCSSTransformMatrix = function(start, current) +{ + var affine = CGAffineTransformMakeTranslation(current.x - start.x, current.y - start.y); + + return CSSStringFromCGAffineTransform(affine); +}; + +var frameToCSSTranslationTransformMatrix = function(start, current) +{ + var affine = CGAffineTransformMakeTranslation(current.origin.x - start.origin.x, current.origin.y - start.origin.y); + + return CSSStringFromCGAffineTransform(affine); +}; + var DEFAULT_CSS_PROPERTIES = nil; @implementation CPView (CPAnimatablePropertyContainer) @@ -117,15 +137,15 @@ var DEFAULT_CSS_PROPERTIES = nil; var transformProperty = CPBrowserCSSProperty("transform"); DEFAULT_CSS_PROPERTIES = @{ - "backgroundColor" : [@{"property":"background", "value":function(sv, val){return [val cssString];}}], - "alphaValue" : [@{"property":"opacity"}], - "frame" : [@{"property":transformProperty, "value":transformFrameToTranslate}, - @{"property":"width", "value":transformFrameToWidth}, - @{"property":"height", "value":transformFrameToHeight}], - "frameOrigin" : [@{"property":transformProperty, "value":transformOrigin}], - "frameSize" : [@{"property":"width", "value":transformSizeToWidth}, - @{"property":"height", "value":transformSizeToHeight}] - }; + "backgroundColor" : [@{"property":"background", "value":function(sv, val){return [val cssString];}}], + "alphaValue" : [@{"property":"opacity"}], + "frame" : [@{"property":transformProperty, "value":frameToCSSTranslationTransformMatrix}, + @{"property":"width", "value":transformFrameToWidth}, + @{"property":"height", "value":transformFrameToHeight}], + "frameOrigin" : [@{"property":transformProperty, "value":frameOriginToCSSTransformMatrix}], + "frameSize" : [@{"property":"width", "value":transformSizeToWidth}, + @{"property":"height", "value":transformSizeToHeight}] + }; } return DEFAULT_CSS_PROPERTIES;