/* * Copyright (C) 2010 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #import "config.h" #import "FindIndicatorWindow.h" #import "FindIndicator.h" #import "WKView.h" #import <WebCore/GraphicsContext.h> static const double bounceAnimationDuration = 0.12; static const double timeBeforeFadeStarts = bounceAnimationDuration + 0.2; static const double fadeOutAnimationDuration = 0.3; using namespace WebCore; @interface WebFindIndicatorView : NSView { RefPtr<WebKit::FindIndicator> _findIndicator; } - (id)_initWithFindIndicator:(PassRefPtr<WebKit::FindIndicator>)findIndicator; @end @implementation WebFindIndicatorView - (id)_initWithFindIndicator:(PassRefPtr<WebKit::FindIndicator>)findIndicator { if ((self = [super initWithFrame:NSZeroRect])) _findIndicator = findIndicator; return self; } - (void)drawRect:(NSRect)rect { GraphicsContext graphicsContext(static_cast<CGContextRef>([[NSGraphicsContext currentContext] graphicsPort])); _findIndicator->draw(graphicsContext, enclosingIntRect(rect)); } - (BOOL)isFlipped { return YES; } @end @interface WebFindIndicatorWindowAnimation : NSAnimation<NSAnimationDelegate> { WebKit::FindIndicatorWindow* _findIndicatorWindow; void (WebKit::FindIndicatorWindow::*_animationProgressCallback)(double progress); void (WebKit::FindIndicatorWindow::*_animationDidEndCallback)(); } - (id)_initWithFindIndicatorWindow:(WebKit::FindIndicatorWindow *)findIndicatorWindow animationDuration:(CFTimeInterval)duration animationProgressCallback:(void (WebKit::FindIndicatorWindow::*)(double progress))animationProgressCallback animationDidEndCallback:(void (WebKit::FindIndicatorWindow::*)())animationDidEndCallback; @end @implementation WebFindIndicatorWindowAnimation - (id)_initWithFindIndicatorWindow:(WebKit::FindIndicatorWindow *)findIndicatorWindow animationDuration:(CFTimeInterval)animationDuration animationProgressCallback:(void (WebKit::FindIndicatorWindow::*)(double progress))animationProgressCallback animationDidEndCallback:(void (WebKit::FindIndicatorWindow::*)())animationDidEndCallback { if ((self = [super initWithDuration:animationDuration animationCurve:NSAnimationEaseInOut])) { _findIndicatorWindow = findIndicatorWindow; _animationProgressCallback = animationProgressCallback; _animationDidEndCallback = animationDidEndCallback; [self setDelegate:self]; [self setAnimationBlockingMode:NSAnimationNonblocking]; } return self; } - (void)setCurrentProgress:(NSAnimationProgress)progress { (_findIndicatorWindow->*_animationProgressCallback)(progress); } - (void)animationDidEnd:(NSAnimation *)animation { ASSERT(animation == self); (_findIndicatorWindow->*_animationDidEndCallback)(); } @end namespace WebKit { PassOwnPtr<FindIndicatorWindow> FindIndicatorWindow::create(WKView *wkView) { return adoptPtr(new FindIndicatorWindow(wkView)); } FindIndicatorWindow::FindIndicatorWindow(WKView *wkView) : m_wkView(wkView) , m_bounceAnimationContext(0) , m_startFadeOutTimer(RunLoop::main(), this, &FindIndicatorWindow::startFadeOutTimerFired) { } FindIndicatorWindow::~FindIndicatorWindow() { closeWindow(); } void FindIndicatorWindow::setFindIndicator(PassRefPtr<FindIndicator> findIndicator, bool fadeOut) { if (m_findIndicator == findIndicator) return; m_findIndicator = findIndicator; // Get rid of the old window. closeWindow(); if (!m_findIndicator) return; NSRect contentRect = m_findIndicator->frameRect(); NSRect windowFrameRect = NSIntegralRect([m_wkView convertRect:contentRect toView:nil]); windowFrameRect.origin = [[m_wkView window] convertBaseToScreen:windowFrameRect.origin]; NSRect windowContentRect = [NSWindow contentRectForFrameRect:windowFrameRect styleMask:NSBorderlessWindowMask]; m_findIndicatorWindow.adoptNS([[NSWindow alloc] initWithContentRect:windowContentRect styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO]); [m_findIndicatorWindow.get() setBackgroundColor:[NSColor clearColor]]; [m_findIndicatorWindow.get() setOpaque:NO]; [m_findIndicatorWindow.get() setIgnoresMouseEvents:YES]; RetainPtr<WebFindIndicatorView> findIndicatorView(AdoptNS, [[WebFindIndicatorView alloc] _initWithFindIndicator:m_findIndicator]); [m_findIndicatorWindow.get() setContentView:findIndicatorView.get()]; [[m_wkView window] addChildWindow:m_findIndicatorWindow.get() ordered:NSWindowAbove]; [m_findIndicatorWindow.get() setReleasedWhenClosed:NO]; // Start the bounce animation. m_bounceAnimationContext = WKWindowBounceAnimationContextCreate(m_findIndicatorWindow.get()); m_bounceAnimation.adoptNS([[WebFindIndicatorWindowAnimation alloc] _initWithFindIndicatorWindow:this animationDuration:bounceAnimationDuration animationProgressCallback:&FindIndicatorWindow::bounceAnimationCallback animationDidEndCallback:&FindIndicatorWindow::bounceAnimationDidEnd]); [m_bounceAnimation.get() startAnimation]; if (fadeOut) m_startFadeOutTimer.startOneShot(timeBeforeFadeStarts); } void FindIndicatorWindow::closeWindow() { if (!m_findIndicatorWindow) return; m_startFadeOutTimer.stop(); if (m_fadeOutAnimation) { [m_fadeOutAnimation.get() stopAnimation]; m_fadeOutAnimation = nullptr; } if (m_bounceAnimation) { [m_bounceAnimation.get() stopAnimation]; m_bounceAnimation = nullptr; } if (m_bounceAnimationContext) WKWindowBounceAnimationContextDestroy(m_bounceAnimationContext); [[m_findIndicatorWindow.get() parentWindow] removeChildWindow:m_findIndicatorWindow.get()]; [m_findIndicatorWindow.get() close]; m_findIndicatorWindow = nullptr; } void FindIndicatorWindow::startFadeOutTimerFired() { ASSERT(!m_fadeOutAnimation); m_fadeOutAnimation.adoptNS([[WebFindIndicatorWindowAnimation alloc] _initWithFindIndicatorWindow:this animationDuration:fadeOutAnimationDuration animationProgressCallback:&FindIndicatorWindow::fadeOutAnimationCallback animationDidEndCallback:&FindIndicatorWindow::fadeOutAnimationDidEnd]); [m_fadeOutAnimation.get() startAnimation]; } void FindIndicatorWindow::fadeOutAnimationCallback(double progress) { ASSERT(m_fadeOutAnimation); [m_findIndicatorWindow.get() setAlphaValue:1.0 - progress]; } void FindIndicatorWindow::fadeOutAnimationDidEnd() { ASSERT(m_fadeOutAnimation); ASSERT(m_findIndicatorWindow); closeWindow(); } void FindIndicatorWindow::bounceAnimationCallback(double progress) { ASSERT(m_bounceAnimation); ASSERT(m_bounceAnimationContext); WKWindowBounceAnimationSetAnimationProgress(m_bounceAnimationContext, progress); } void FindIndicatorWindow::bounceAnimationDidEnd() { ASSERT(m_bounceAnimation); ASSERT(m_bounceAnimationContext); ASSERT(m_findIndicatorWindow); WKWindowBounceAnimationContextDestroy(m_bounceAnimationContext); m_bounceAnimationContext = 0; } } // namespace WebKit