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 30 static const CGFloat slowMotionFactor = 10.; 31 32 static NSTimeInterval WebWindowAnimationDurationFromDuration(NSTimeInterval duration) 33 { 34 return ([[NSApp currentEvent] modifierFlags] & NSShiftKeyMask) ? duration * slowMotionFactor : duration; 35 } 36 37 static 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 47 static 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