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 "config.h" 27 28#import "WebWindowAnimation.h" 29 30#import "FloatConversion.h" 31#import "WebCoreSystemInterface.h" 32#import <wtf/Assertions.h> 33#import <wtf/MathExtras.h> 34 35using namespace WebCore; 36 37static const CGFloat slowMotionFactor = 10; 38 39static NSTimeInterval WebWindowAnimationDurationFromDuration(NSTimeInterval duration) 40{ 41 return ([[NSApp currentEvent] modifierFlags] & NSShiftKeyMask) ? duration * slowMotionFactor : duration; 42} 43 44static NSRect scaledRect(NSRect _initialFrame, NSRect _finalFrame, CGFloat factor) 45{ 46 NSRect currentRect = _initialFrame; 47 currentRect.origin.x += (NSMinX(_finalFrame) - NSMinX(_initialFrame)) * factor; 48 currentRect.origin.y += (NSMinY(_finalFrame) - NSMinY(_initialFrame)) * factor; 49 currentRect.size.width += (NSWidth(_finalFrame) - NSWidth(_initialFrame)) * factor; 50 currentRect.size.height += (NSHeight(_finalFrame) - NSHeight(_initialFrame)) * factor; 51 return currentRect; 52} 53 54static CGFloat squaredDistance(NSPoint point1, NSPoint point2) 55{ 56 CGFloat deltaX = point1.x - point2.x; 57 CGFloat deltaY = point1.y - point2.y; 58 return deltaX * deltaX + deltaY * deltaY; 59} 60 61@implementation WebWindowScaleAnimation 62 63- (id)init 64{ 65 self = [super init]; 66 if (!self) 67 return nil; 68 [self setAnimationBlockingMode:NSAnimationNonblockingThreaded]; 69 [self setFrameRate:60]; 70 return self; 71} 72 73- (id)initWithHintedDuration:(NSTimeInterval)duration window:(NSWindow *)window initalFrame:(NSRect)initialFrame finalFrame:(NSRect)finalFrame 74{ 75 self = [self init]; 76 if (!self) 77 return nil; 78 _hintedDuration = duration; 79 _window = window; 80 _initialFrame = initialFrame; 81 _finalFrame = finalFrame; 82 _realFrame = [window frame]; 83 return self; 84} 85 86- (void) dealloc 87{ 88 [_subAnimation release]; 89 [super dealloc]; 90} 91 92- (void)setDuration:(NSTimeInterval)duration 93{ 94 [super setDuration:WebWindowAnimationDurationFromDuration(duration)]; 95} 96 97- (void)setWindow:(NSWindow *)window 98{ 99 _window = window; 100} 101 102- (float)currentValue 103{ 104 return narrowPrecisionToFloat(0.5 - 0.5 * cos(piDouble * (1 - [self currentProgress]))); 105} 106 107- (NSRect)currentFrame 108{ 109 return scaledRect(_finalFrame, _initialFrame, [self currentValue]); 110} 111 112- (void)setCurrentProgress:(NSAnimationProgress)progress 113{ 114 if (!_window) 115 return; 116 117 [super setCurrentProgress:progress]; 118 119 NSRect currentRect = [self currentFrame]; 120 wkWindowSetScaledFrame(_window, currentRect, _realFrame); 121 [_subAnimation setCurrentProgress:progress]; 122} 123 124- (void)setSubAnimation:(NSAnimation *)animation 125{ 126 id oldAnimation = _subAnimation; 127 _subAnimation = [animation retain]; 128 [oldAnimation release]; 129} 130 131- (NSTimeInterval)additionalDurationNeededToReachFinalFrame 132{ 133 static const CGFloat maxAdditionalDuration = 1; 134 static const CGFloat speedFactor = 0.0001f; 135 136 CGFloat maxDist = squaredDistance(_initialFrame.origin, _finalFrame.origin); 137 CGFloat dist; 138 139 dist = squaredDistance(NSMakePoint(NSMaxX(_initialFrame), NSMinY(_initialFrame)), NSMakePoint(NSMaxX(_finalFrame), NSMinY(_finalFrame))); 140 if (dist > maxDist) 141 maxDist = dist; 142 143 dist = squaredDistance(NSMakePoint(NSMaxX(_initialFrame), NSMaxY(_initialFrame)), NSMakePoint(NSMaxX(_finalFrame), NSMaxY(_finalFrame))); 144 if (dist > maxDist) 145 maxDist = dist; 146 147 dist = squaredDistance(NSMakePoint(NSMinX(_initialFrame), NSMinY(_initialFrame)), NSMakePoint(NSMinX(_finalFrame), NSMinY(_finalFrame))); 148 if (dist > maxDist) 149 maxDist = dist; 150 151 return MIN(sqrt(maxDist) * speedFactor, maxAdditionalDuration); 152} 153 154- (void)startAnimation 155{ 156 // Compute extra time 157 if (_hintedDuration) 158 [self setDuration:_hintedDuration + [self additionalDurationNeededToReachFinalFrame]]; 159 [super startAnimation]; 160} 161 162- (void)stopAnimation 163{ 164 _window = nil; 165 [super stopAnimation]; 166 [_subAnimation stopAnimation]; 167} 168 169@end 170 171@implementation WebWindowFadeAnimation 172 173- (id)init 174{ 175 self = [super init]; 176 if (!self) 177 return nil; 178 [self setAnimationBlockingMode:NSAnimationNonblockingThreaded]; 179 [self setFrameRate:60]; 180 [self setAnimationCurve:NSAnimationEaseInOut]; 181 return self; 182} 183 184- (id)initWithDuration:(NSTimeInterval)duration window:(NSWindow *)window initialAlpha:(CGFloat)initialAlpha finalAlpha:(CGFloat)finalAlpha 185{ 186 self = [self init]; 187 if (!self) 188 return nil; 189 _window = window; 190 _initialAlpha = initialAlpha; 191 _finalAlpha = finalAlpha; 192 [self setDuration:duration]; 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, MIN(1, _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 wkWindowSetAlpha(_window, [self currentAlpha]); 215} 216 217- (void)setWindow:(NSWindow*)window 218{ 219 _window = window; 220} 221 222- (void)stopAnimation 223{ 224 // This is relevant when we are a sub animation of a scale animation. 225 // In this case we are hosted in the animated thread of the parent 226 // and even after [super stopAnimation], the parent might call 227 // setCurrrentProgress. 228 _isStopped = YES; 229 230 [super stopAnimation]; 231} 232 233@end 234 235