6eadb2150e4defadbf17f5e84f3450d132e125fe
[WebKit-https.git] / Source / WebKit / mac / WebView / WebWindowAnimation.m
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