Home | History | Annotate | Download | only in mac
      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