initial import
[vuplus_webkit] / Source / WebKit2 / UIProcess / API / mac / FindIndicatorWindow.mm
1 /*
2  * Copyright (C) 2010 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 INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #import "config.h"
27 #import "FindIndicatorWindow.h"
28
29 #import "FindIndicator.h"
30 #import "WKView.h"
31 #import <WebCore/GraphicsContext.h>
32
33 static const double bounceAnimationDuration = 0.12;
34 static const double timeBeforeFadeStarts = bounceAnimationDuration + 0.2;
35 static const double fadeOutAnimationDuration = 0.3;
36
37 using namespace WebCore;
38
39 @interface WebFindIndicatorView : NSView {
40     RefPtr<WebKit::FindIndicator> _findIndicator;
41 }
42
43 - (id)_initWithFindIndicator:(PassRefPtr<WebKit::FindIndicator>)findIndicator;
44 @end
45
46 @implementation WebFindIndicatorView
47
48 - (id)_initWithFindIndicator:(PassRefPtr<WebKit::FindIndicator>)findIndicator
49 {
50     if ((self = [super initWithFrame:NSZeroRect]))
51         _findIndicator = findIndicator;
52
53     return self;
54 }
55
56 - (void)drawRect:(NSRect)rect
57 {
58     GraphicsContext graphicsContext(static_cast<CGContextRef>([[NSGraphicsContext currentContext] graphicsPort]));
59
60     _findIndicator->draw(graphicsContext, enclosingIntRect(rect));
61 }
62
63 - (BOOL)isFlipped
64 {
65     return YES;
66 }
67
68 @end
69
70 @interface WebFindIndicatorWindowAnimation : NSAnimation<NSAnimationDelegate> {
71     WebKit::FindIndicatorWindow* _findIndicatorWindow;
72     void (WebKit::FindIndicatorWindow::*_animationProgressCallback)(double progress);
73     void (WebKit::FindIndicatorWindow::*_animationDidEndCallback)();
74 }
75
76 - (id)_initWithFindIndicatorWindow:(WebKit::FindIndicatorWindow *)findIndicatorWindow 
77                  animationDuration:(CFTimeInterval)duration
78          animationProgressCallback:(void (WebKit::FindIndicatorWindow::*)(double progress))animationProgressCallback
79            animationDidEndCallback:(void (WebKit::FindIndicatorWindow::*)())animationDidEndCallback;
80 @end
81
82 @implementation WebFindIndicatorWindowAnimation
83
84 - (id)_initWithFindIndicatorWindow:(WebKit::FindIndicatorWindow *)findIndicatorWindow 
85                  animationDuration:(CFTimeInterval)animationDuration
86          animationProgressCallback:(void (WebKit::FindIndicatorWindow::*)(double progress))animationProgressCallback
87            animationDidEndCallback:(void (WebKit::FindIndicatorWindow::*)())animationDidEndCallback
88 {
89     if ((self = [super initWithDuration:animationDuration animationCurve:NSAnimationEaseInOut])) {
90         _findIndicatorWindow = findIndicatorWindow;
91         _animationProgressCallback = animationProgressCallback;
92         _animationDidEndCallback = animationDidEndCallback;
93         [self setDelegate:self];
94         [self setAnimationBlockingMode:NSAnimationNonblocking];
95     }
96     return self;
97 }
98
99 - (void)setCurrentProgress:(NSAnimationProgress)progress
100 {
101     (_findIndicatorWindow->*_animationProgressCallback)(progress);
102 }
103
104 - (void)animationDidEnd:(NSAnimation *)animation
105 {
106     ASSERT(animation == self);
107
108     (_findIndicatorWindow->*_animationDidEndCallback)();
109 }
110
111 @end
112
113 namespace WebKit {
114
115 PassOwnPtr<FindIndicatorWindow> FindIndicatorWindow::create(WKView *wkView)
116 {
117     return adoptPtr(new FindIndicatorWindow(wkView));
118 }
119
120 FindIndicatorWindow::FindIndicatorWindow(WKView *wkView)
121     : m_wkView(wkView)
122     , m_bounceAnimationContext(0)
123     , m_startFadeOutTimer(RunLoop::main(), this, &FindIndicatorWindow::startFadeOutTimerFired)
124 {
125 }
126
127 FindIndicatorWindow::~FindIndicatorWindow()
128 {
129     closeWindow();
130 }
131
132 void FindIndicatorWindow::setFindIndicator(PassRefPtr<FindIndicator> findIndicator, bool fadeOut)
133 {
134     if (m_findIndicator == findIndicator)
135         return;
136
137     m_findIndicator = findIndicator;
138
139     // Get rid of the old window.
140     closeWindow();
141
142     if (!m_findIndicator)
143         return;
144
145     NSRect contentRect = m_findIndicator->frameRect();
146     NSRect windowFrameRect = NSIntegralRect([m_wkView convertRect:contentRect toView:nil]);
147     windowFrameRect.origin = [[m_wkView window] convertBaseToScreen:windowFrameRect.origin];
148
149     NSRect windowContentRect = [NSWindow contentRectForFrameRect:windowFrameRect styleMask:NSBorderlessWindowMask];
150     
151     m_findIndicatorWindow.adoptNS([[NSWindow alloc] initWithContentRect:windowContentRect 
152                                                               styleMask:NSBorderlessWindowMask 
153                                                                 backing:NSBackingStoreBuffered
154                                                                   defer:NO]);
155
156     [m_findIndicatorWindow.get() setBackgroundColor:[NSColor clearColor]];
157     [m_findIndicatorWindow.get() setOpaque:NO];
158     [m_findIndicatorWindow.get() setIgnoresMouseEvents:YES];
159
160     RetainPtr<WebFindIndicatorView> findIndicatorView(AdoptNS, [[WebFindIndicatorView alloc] _initWithFindIndicator:m_findIndicator]);
161     [m_findIndicatorWindow.get() setContentView:findIndicatorView.get()];
162
163     [[m_wkView window] addChildWindow:m_findIndicatorWindow.get() ordered:NSWindowAbove];
164     [m_findIndicatorWindow.get() setReleasedWhenClosed:NO];
165
166     // Start the bounce animation.
167     m_bounceAnimationContext = WKWindowBounceAnimationContextCreate(m_findIndicatorWindow.get());
168     m_bounceAnimation.adoptNS([[WebFindIndicatorWindowAnimation alloc] _initWithFindIndicatorWindow:this
169                                                                                   animationDuration:bounceAnimationDuration
170                                                                           animationProgressCallback:&FindIndicatorWindow::bounceAnimationCallback
171                                                                             animationDidEndCallback:&FindIndicatorWindow::bounceAnimationDidEnd]);
172     [m_bounceAnimation.get() startAnimation];
173
174     if (fadeOut)
175         m_startFadeOutTimer.startOneShot(timeBeforeFadeStarts);
176 }
177
178 void FindIndicatorWindow::closeWindow()
179 {
180     if (!m_findIndicatorWindow)
181         return;
182
183     m_startFadeOutTimer.stop();
184
185     if (m_fadeOutAnimation) {
186         [m_fadeOutAnimation.get() stopAnimation];
187         m_fadeOutAnimation = nullptr;
188     }
189
190     if (m_bounceAnimation) {
191         [m_bounceAnimation.get() stopAnimation];
192         m_bounceAnimation = nullptr;
193     }
194
195     if (m_bounceAnimationContext)
196         WKWindowBounceAnimationContextDestroy(m_bounceAnimationContext);
197     
198     [[m_findIndicatorWindow.get() parentWindow] removeChildWindow:m_findIndicatorWindow.get()];
199     [m_findIndicatorWindow.get() close];
200     m_findIndicatorWindow = nullptr;
201 }
202
203 void FindIndicatorWindow::startFadeOutTimerFired()
204 {
205     ASSERT(!m_fadeOutAnimation);
206     
207     m_fadeOutAnimation.adoptNS([[WebFindIndicatorWindowAnimation alloc] _initWithFindIndicatorWindow:this
208                                                                                    animationDuration:fadeOutAnimationDuration
209                                                                            animationProgressCallback:&FindIndicatorWindow::fadeOutAnimationCallback
210                                                                              animationDidEndCallback:&FindIndicatorWindow::fadeOutAnimationDidEnd]);
211     [m_fadeOutAnimation.get() startAnimation];
212 }
213                         
214 void FindIndicatorWindow::fadeOutAnimationCallback(double progress)
215 {
216     ASSERT(m_fadeOutAnimation);
217
218     [m_findIndicatorWindow.get() setAlphaValue:1.0 - progress];
219 }
220
221 void FindIndicatorWindow::fadeOutAnimationDidEnd()
222 {
223     ASSERT(m_fadeOutAnimation);
224     ASSERT(m_findIndicatorWindow);
225
226     closeWindow();
227 }
228
229 void FindIndicatorWindow::bounceAnimationCallback(double progress)
230 {
231     ASSERT(m_bounceAnimation);
232     ASSERT(m_bounceAnimationContext);
233
234     WKWindowBounceAnimationSetAnimationProgress(m_bounceAnimationContext, progress);
235 }
236
237 void FindIndicatorWindow::bounceAnimationDidEnd()
238 {
239     ASSERT(m_bounceAnimation);
240     ASSERT(m_bounceAnimationContext);
241     ASSERT(m_findIndicatorWindow);
242
243     WKWindowBounceAnimationContextDestroy(m_bounceAnimationContext);
244     m_bounceAnimationContext = 0;
245 }
246
247 } // namespace WebKit