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 248