/* * Copyright (C) 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #import "WebWindowAnimation.h" #import "WebKitSystemInterface.h" #import static const CGFloat slowMotionFactor = 10.; static NSTimeInterval WebWindowAnimationDurationFromDuration(NSTimeInterval duration) { return ([[NSApp currentEvent] modifierFlags] & NSShiftKeyMask) ? duration * slowMotionFactor : duration; } static NSRect scaledRect(NSRect _initialFrame, NSRect _finalFrame, double factor) { NSRect currentRect = _initialFrame; currentRect.origin.x += (NSMinX(_finalFrame) - NSMinX(_initialFrame)) * factor; currentRect.origin.y += (NSMinY(_finalFrame) - NSMinY(_initialFrame)) * factor; currentRect.size.width += (NSWidth(_finalFrame) - NSWidth(_initialFrame)) * factor; currentRect.size.height += (NSHeight(_finalFrame) - NSHeight(_initialFrame)) * factor; return currentRect; } static CGFloat squaredDistance(NSPoint point1, NSPoint point2) { CGFloat deltaX = point1.x - point2.x; CGFloat deltaY = point1.y - point2.y; return deltaX * deltaX + deltaY * deltaY; } @implementation WebWindowScaleAnimation - (id)init { self = [super init]; if (!self) return nil; #ifndef BUILDING_ON_TIGER [self setAnimationBlockingMode:NSAnimationNonblockingThreaded]; #endif [self setFrameRate:60.]; return self; } - (id)initWithHintedDuration:(NSTimeInterval)duration window:(NSWindow *)window initalFrame:(NSRect)initialFrame finalFrame:(NSRect)finalFrame { self = [self init]; if (!self) return nil; _hintedDuration = duration; _window = window; _initialFrame = initialFrame; _finalFrame = finalFrame; _realFrame = [window frame]; return self; } - (void) dealloc { [_subAnimation release]; [super dealloc]; } - (void)setDuration:(NSTimeInterval)duration { [super setDuration:WebWindowAnimationDurationFromDuration(duration)]; } - (void)setWindow:(NSWindow *)window { _window = window; } - (float)currentValue { return 0.5 - 0.5 * cos(M_PI * (1 - [self currentProgress])); } - (NSRect)currentFrame { return scaledRect(_finalFrame, _initialFrame, [self currentValue]); } - (void)setCurrentProgress:(NSAnimationProgress)progress { if (!_window) return; [super setCurrentProgress:progress]; NSRect currentRect = [self currentFrame]; #ifndef BUILDING_ON_TIGER WKWindowSetScaledFrame(_window, currentRect, _realFrame); #else [_window setFrame:currentRect display:YES]; #endif [_subAnimation setCurrentProgress:progress]; } - (void)setSubAnimation:(NSAnimation *)animation { id oldAnimation = _subAnimation; _subAnimation = [animation retain]; [oldAnimation release]; } - (NSTimeInterval)additionalDurationNeededToReachFinalFrame { static const CGFloat maxAdditionalDuration = 1.0; static const CGFloat speedFactor = 0.0001; CGFloat maxDist = squaredDistance(_initialFrame.origin, _finalFrame.origin); CGFloat dist; dist = squaredDistance(NSMakePoint(NSMaxX(_initialFrame), NSMinY(_initialFrame)), NSMakePoint(NSMaxX(_finalFrame), NSMinY(_finalFrame))); if (dist > maxDist) maxDist = dist; dist = squaredDistance(NSMakePoint(NSMaxX(_initialFrame), NSMaxY(_initialFrame)), NSMakePoint(NSMaxX(_finalFrame), NSMaxY(_finalFrame))); if (dist > maxDist) maxDist = dist; dist = squaredDistance(NSMakePoint(NSMinX(_initialFrame), NSMinY(_initialFrame)), NSMakePoint(NSMinX(_finalFrame), NSMinY(_finalFrame))); if (dist > maxDist) maxDist = dist; return MIN(sqrt(maxDist) * speedFactor, maxAdditionalDuration); } - (void)startAnimation { // Compute extra time if (_hintedDuration) [self setDuration:_hintedDuration + [self additionalDurationNeededToReachFinalFrame]]; [super startAnimation]; } - (void)stopAnimation { _window = nil; [super stopAnimation]; [_subAnimation stopAnimation]; } @end @implementation WebWindowFadeAnimation - (id)init { self = [super init]; if (!self) return nil; #ifndef BUILDING_ON_TIGER [self setAnimationBlockingMode:NSAnimationNonblockingThreaded]; #endif [self setFrameRate:60]; [self setAnimationCurve:NSAnimationEaseInOut]; return self; } - (id)initWithDuration:(NSTimeInterval)duration window:(NSWindow *)window initialAlpha:(CGFloat)initialAlpha finalAlpha:(CGFloat)finalAlpha { self = [self init]; if (!self) return nil; _window = window; _initialAlpha = initialAlpha; _finalAlpha = finalAlpha; return self; } - (void)setDuration:(NSTimeInterval)duration { [super setDuration:WebWindowAnimationDurationFromDuration(duration)]; } - (CGFloat)currentAlpha { return MAX(0.0, MIN(1.0, _initialAlpha + [self currentValue] * (_finalAlpha - _initialAlpha))); } - (void)setCurrentProgress:(NSAnimationProgress)progress { if (_isStopped) return; ASSERT(_window); [super setCurrentProgress:progress]; #ifndef BUILDING_ON_TIGER WKWindowSetAlpha(_window, [self currentAlpha]); #else [_window setAlphaValue:[self currentAlpha]]; #endif } - (void)setWindow:(NSWindow*)window { _window = window; } - (void)stopAnimation { // This is relevant when we are a sub animation of a scale animation. // In this case we are hosted in the animated thread of the parent // and even after [super stopAnimation], the parent might call // setCurrrentProgress. _isStopped = YES; [super stopAnimation]; } @end