1/* 2 * Copyright (C) 2009 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#import "WebWindowAnimation.h" 27#import "WebKitSystemInterface.h" 28#import <wtf/Assertions.h> 29 30static const CGFloat slowMotionFactor = 10.; 31 32static NSTimeInterval WebWindowAnimationDurationFromDuration(NSTimeInterval duration) 33{ 34 return ([[NSApp currentEvent] modifierFlags] & NSShiftKeyMask) ? duration * slowMotionFactor : duration; 35} 36 37static NSRect scaledRect(NSRect _initialFrame, NSRect _finalFrame, double factor) 38{ 39 NSRect currentRect = _initialFrame; 40 currentRect.origin.x += (NSMinX(_finalFrame) - NSMinX(_initialFrame)) * factor; 41 currentRect.origin.y += (NSMinY(_finalFrame) - NSMinY(_initialFrame)) * factor; 42 currentRect.size.width += (NSWidth(_finalFrame) - NSWidth(_initialFrame)) * factor; 43 currentRect.size.height += (NSHeight(_finalFrame) - NSHeight(_initialFrame)) * factor; 44 return currentRect; 45} 46 47static CGFloat squaredDistance(NSPoint point1, NSPoint point2) 48{ 49 CGFloat deltaX = point1.x - point2.x; 50 CGFloat deltaY = point1.y - point2.y; 51 return deltaX * deltaX + deltaY * deltaY; 52} 53 54@implementation WebWindowScaleAnimation 55 56- (id)init 57{ 58 self = [super init]; 59 if (!self) 60 return nil; 61#ifndef BUILDING_ON_TIGER 62 [self setAnimationBlockingMode:NSAnimationNonblockingThreaded]; 63#endif 64 [self setFrameRate:60.]; 65 return self; 66} 67 68- (id)initWithHintedDuration:(NSTimeInterval)duration window:(NSWindow *)window initalFrame:(NSRect)initialFrame finalFrame:(NSRect)finalFrame 69{ 70 self = [self init]; 71 if (!self) 72 return nil; 73 _hintedDuration = duration; 74 _window = window; 75 _initialFrame = initialFrame; 76 _finalFrame = finalFrame; 77 _realFrame = [window frame]; 78 return self; 79} 80 81- (void) dealloc 82{ 83 [_subAnimation release]; 84 [super dealloc]; 85} 86 87- (void)setDuration:(NSTimeInterval)duration 88{ 89 [super setDuration:WebWindowAnimationDurationFromDuration(duration)]; 90} 91 92- (void)setWindow:(NSWindow *)window 93{ 94 _window = window; 95} 96 97- (float)currentValue 98{ 99 return 0.5 - 0.5 * cos(M_PI * (1 - [self currentProgress])); 100} 101 102- (NSRect)currentFrame 103{ 104 return scaledRect(_finalFrame, _initialFrame, [self currentValue]); 105} 106 107- (void)setCurrentProgress:(NSAnimationProgress)progress 108{ 109 if (!_window) 110 return; 111 112 [super setCurrentProgress:progress]; 113 114 NSRect currentRect = [self currentFrame]; 115#ifndef BUILDING_ON_TIGER 116 WKWindowSetScaledFrame(_window, currentRect, _realFrame); 117#else 118 [_window setFrame:currentRect display:YES]; 119#endif 120 [_subAnimation setCurrentProgress:progress]; 121} 122 123- (void)setSubAnimation:(NSAnimation *)animation 124{ 125 id oldAnimation = _subAnimation; 126 _subAnimation = [animation retain]; 127 [oldAnimation release]; 128} 129 130- (NSTimeInterval)additionalDurationNeededToReachFinalFrame 131{ 132 static const CGFloat maxAdditionalDuration = 1.0; 133 static const CGFloat speedFactor = 0.0001; 134 135 CGFloat maxDist = squaredDistance(_initialFrame.origin, _finalFrame.origin); 136 CGFloat dist; 137 138 dist = squaredDistance(NSMakePoint(NSMaxX(_initialFrame), NSMinY(_initialFrame)), NSMakePoint(NSMaxX(_finalFrame), NSMinY(_finalFrame))); 139 if (dist > maxDist) 140 maxDist = dist; 141 142 dist = squaredDistance(NSMakePoint(NSMaxX(_initialFrame), NSMaxY(_initialFrame)), NSMakePoint(NSMaxX(_finalFrame), NSMaxY(_finalFrame))); 143 if (dist > maxDist) 144 maxDist = dist; 145 146 dist = squaredDistance(NSMakePoint(NSMinX(_initialFrame), NSMinY(_initialFrame)), NSMakePoint(NSMinX(_finalFrame), NSMinY(_finalFrame))); 147 if (dist > maxDist) 148 maxDist = dist; 149 150 return MIN(sqrt(maxDist) * speedFactor, maxAdditionalDuration); 151} 152 153- (void)startAnimation 154{ 155 // Compute extra time 156 if (_hintedDuration) 157 [self setDuration:_hintedDuration + [self additionalDurationNeededToReachFinalFrame]]; 158 [super startAnimation]; 159} 160 161- (void)stopAnimation 162{ 163 _window = nil; 164 [super stopAnimation]; 165 [_subAnimation stopAnimation]; 166} 167 168@end 169 170@implementation WebWindowFadeAnimation 171 172- (id)init 173{ 174 self = [super init]; 175 if (!self) 176 return nil; 177#ifndef BUILDING_ON_TIGER 178 [self setAnimationBlockingMode:NSAnimationNonblockingThreaded]; 179#endif 180 [self setFrameRate:60]; 181 [self setAnimationCurve:NSAnimationEaseInOut]; 182 return self; 183} 184 185- (id)initWithDuration:(NSTimeInterval)duration window:(NSWindow *)window initialAlpha:(CGFloat)initialAlpha finalAlpha:(CGFloat)finalAlpha 186{ 187 self = [self init]; 188 if (!self) 189 return nil; 190 _window = window; 191 _initialAlpha = initialAlpha; 192 _finalAlpha = finalAlpha; 193 return self; 194} 195 196- (void)setDuration:(NSTimeInterval)duration 197{ 198 [super setDuration:WebWindowAnimationDurationFromDuration(duration)]; 199} 200 201- (CGFloat)currentAlpha 202{ 203 return MAX(0.0, MIN(1.0, _initialAlpha + [self currentValue] * (_finalAlpha - _initialAlpha))); 204} 205 206- (void)setCurrentProgress:(NSAnimationProgress)progress 207{ 208 if (_isStopped) 209 return; 210 211 ASSERT(_window); 212 [super setCurrentProgress:progress]; 213 214#ifndef BUILDING_ON_TIGER 215 WKWindowSetAlpha(_window, [self currentAlpha]); 216#else 217 [_window setAlphaValue:[self currentAlpha]]; 218#endif 219} 220 221- (void)setWindow:(NSWindow*)window 222{ 223 _window = window; 224} 225 226- (void)stopAnimation 227{ 228 // This is relevant when we are a sub animation of a scale animation. 229 // In this case we are hosted in the animated thread of the parent 230 // and even after [super stopAnimation], the parent might call 231 // setCurrrentProgress. 232 _isStopped = YES; 233 234 [super stopAnimation]; 235} 236 237@end 238 239