• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
33static const double bounceAnimationDuration = 0.12;
34static const double timeBeforeFadeStarts = bounceAnimationDuration + 0.2;
35static const double fadeOutAnimationDuration = 0.3;
36
37using 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
113namespace WebKit {
114
115PassOwnPtr<FindIndicatorWindow> FindIndicatorWindow::create(WKView *wkView)
116{
117    return adoptPtr(new FindIndicatorWindow(wkView));
118}
119
120FindIndicatorWindow::FindIndicatorWindow(WKView *wkView)
121    : m_wkView(wkView)
122    , m_bounceAnimationContext(0)
123    , m_startFadeOutTimer(RunLoop::main(), this, &FindIndicatorWindow::startFadeOutTimerFired)
124{
125}
126
127FindIndicatorWindow::~FindIndicatorWindow()
128{
129    closeWindow();
130}
131
132void 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
178void 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
203void 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
214void FindIndicatorWindow::fadeOutAnimationCallback(double progress)
215{
216    ASSERT(m_fadeOutAnimation);
217
218    [m_findIndicatorWindow.get() setAlphaValue:1.0 - progress];
219}
220
221void FindIndicatorWindow::fadeOutAnimationDidEnd()
222{
223    ASSERT(m_fadeOutAnimation);
224    ASSERT(m_findIndicatorWindow);
225
226    closeWindow();
227}
228
229void FindIndicatorWindow::bounceAnimationCallback(double progress)
230{
231    ASSERT(m_bounceAnimation);
232    ASSERT(m_bounceAnimationContext);
233
234    WKWindowBounceAnimationSetAnimationProgress(m_bounceAnimationContext, progress);
235}
236
237void 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
248