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