blob: 66243c5cd151ce6fda46be9d1a2c3fd38a587524 [file] [log] [blame]
/*
* Copyright (C) 2011 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 "WebFullScreenManagerMac.h"
#if ENABLE(FULLSCREEN_API)
#import "Connection.h"
#import "LayerTreeContext.h"
#import "MessageID.h"
#import "WebFullScreenManagerProxyMessages.h"
#import "WebPage.h"
#import "WebProcess.h"
#import <QuartzCore/QuartzCore.h>
#import <WebCore/Frame.h>
#import <WebCore/FrameView.h>
#import <WebCore/GraphicsLayer.h>
#import <WebCore/Page.h>
#import <WebCore/Settings.h>
#import <WebKitSystemInterface.h>
using namespace WebCore;
typedef void (WebKit::WebFullScreenManager::*AnimationBeganFunction)();
typedef void (WebKit::WebFullScreenManager::*AnimationFinishedFunction)(bool);
#if defined(BUILDING_ON_LEOPARD)
@interface CATransaction(SnowLeopardConvenienceFunctions)
+ (void)setDisableActions:(BOOL)flag;
@end
@implementation CATransaction(SnowLeopardConvenienceFunctions)
+ (void)setDisableActions:(BOOL)flag
{
[self setValue:[NSNumber numberWithBool:flag] forKey:kCATransactionDisableActions];
}
@end
#endif
@interface WebFullScreenManagerAnimationListener : NSObject {
WebKit::WebFullScreenManager* _manager;
AnimationBeganFunction _began;
AnimationFinishedFunction _finished;
}
- (id)initWithManager:(WebKit::WebFullScreenManager*)manager began:(AnimationBeganFunction)began finished:(AnimationFinishedFunction)finished;
- (void)animationDidStart:(CAAnimation *)anim;
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag;
- (void)invalidate;
@end
@implementation WebFullScreenManagerAnimationListener
- (id)initWithManager:(WebKit::WebFullScreenManager*)manager began:(AnimationBeganFunction)began finished:(AnimationFinishedFunction)finished
{
self = [super init];
if (!self)
return nil;
_manager = manager;
_began = began;
_finished = finished;
return self;
}
- (void)animationDidStart:(CAAnimation *)anim
{
if (_manager && _began)
(_manager->*_began)();
}
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
{
if (_manager && _finished)
(_manager->*_finished)(flag);
}
- (void)invalidate
{
_manager = 0;
_began = 0;
_finished = 0;
}
@end
namespace WebKit {
PassRefPtr<WebFullScreenManager> WebFullScreenManager::create(WebPage* page)
{
return WebFullScreenManagerMac::create(page);
}
PassRefPtr<WebFullScreenManagerMac> WebFullScreenManagerMac::create(WebPage* page)
{
return adoptRef(new WebFullScreenManagerMac(page));
}
WebFullScreenManagerMac::WebFullScreenManagerMac(WebPage* page)
: WebFullScreenManager(page)
{
m_enterFullScreenListener.adoptNS([[WebFullScreenManagerAnimationListener alloc] initWithManager:this began:&WebFullScreenManagerMac::beganEnterFullScreenAnimation finished:&WebFullScreenManagerMac::finishedEnterFullScreenAnimation]);
m_exitFullScreenListener.adoptNS([[WebFullScreenManagerAnimationListener alloc] initWithManager:this began:&WebFullScreenManagerMac::beganExitFullScreenAnimation finished:&WebFullScreenManagerMac::finishedExitFullScreenAnimation]);
}
WebFullScreenManagerMac::~WebFullScreenManagerMac()
{
m_page->send(Messages::WebFullScreenManagerProxy::ExitAcceleratedCompositingMode());
[m_enterFullScreenListener.get() invalidate];
[m_exitFullScreenListener.get() invalidate];
}
void WebFullScreenManagerMac::setRootFullScreenLayer(WebCore::GraphicsLayer* layer)
{
if (m_fullScreenRootLayer == layer)
return;
m_fullScreenRootLayer = layer;
if (!m_fullScreenRootLayer) {
m_page->send(Messages::WebFullScreenManagerProxy::ExitAcceleratedCompositingMode());
if (m_rootLayer) {
m_rootLayer->removeAllChildren();
m_rootLayer = 0;
}
return;
}
if (!m_rootLayer) {
mach_port_t serverPort = WebProcess::shared().compositingRenderServerPort();
m_remoteLayerClient = WKCARemoteLayerClientMakeWithServerPort(serverPort);
m_rootLayer = GraphicsLayer::create(NULL);
#ifndef NDEBUG
m_rootLayer->setName("Full screen root layer");
#endif
m_rootLayer->setDrawsContent(false);
m_rootLayer->setSize(getFullScreenRect().size());
[m_rootLayer->platformLayer() setGeometryFlipped:YES];
WKCARemoteLayerClientSetLayer(m_remoteLayerClient.get(), m_rootLayer->platformLayer());
m_layerTreeContext.contextID = WKCARemoteLayerClientGetClientId(m_remoteLayerClient.get());
m_page->send(Messages::WebFullScreenManagerProxy::EnterAcceleratedCompositingMode(m_layerTreeContext));
}
m_rootLayer->removeAllChildren();
if (m_fullScreenRootLayer)
m_rootLayer->addChild(m_fullScreenRootLayer);
m_rootLayer->syncCompositingStateForThisLayerOnly();
m_page->corePage()->mainFrame()->view()->syncCompositingStateIncludingSubframes();
}
void WebFullScreenManagerMac::beginEnterFullScreenAnimation(float duration)
{
ASSERT(m_element);
ASSERT(m_fullScreenRootLayer);
IntRect destinationFrame = getFullScreenRect();
m_element->document()->setFullScreenRendererSize(destinationFrame.size());
m_rootLayer->syncCompositingStateForThisLayerOnly();
m_page->corePage()->mainFrame()->view()->syncCompositingStateIncludingSubframes();
// FIXME: Once we gain the ability to do native WebKit animations of generated
// content, this can change to use them. Meanwhile, we'll have to animate the
// CALayer directly:
CALayer* caLayer = m_fullScreenRootLayer->platformLayer();
// Create a transformation matrix that will transform the renderer layer such that
// the fullscreen element appears to move from its starting position and size to its
// final one.
CGPoint destinationPosition = [caLayer position];
CGPoint layerAnchor = [caLayer anchorPoint];
CGPoint initialPosition = CGPointMake(
m_initialFrame.x() + m_initialFrame.width() * layerAnchor.x,
m_initialFrame.y() + m_initialFrame.height() * layerAnchor.y);
CATransform3D shrinkTransform = CATransform3DMakeScale(
static_cast<CGFloat>(m_initialFrame.width()) / destinationFrame.width(),
static_cast<CGFloat>(m_initialFrame.height()) / destinationFrame.height(), 1);
CATransform3D shiftTransform = CATransform3DMakeTranslation(
initialPosition.x - destinationPosition.x,
// Drawing is flipped here, and so much be the translation transformation
destinationPosition.y - initialPosition.y, 0);
CATransform3D finalTransform = CATransform3DConcat(shrinkTransform, shiftTransform);
// Use a CABasicAnimation here for the zoom effect. We want to be notified that the animation has
// completed by way of the CAAnimation delegate.
CABasicAnimation* zoomAnimation = [CABasicAnimation animationWithKeyPath:@"transform"];
[zoomAnimation setFromValue:[NSValue valueWithCATransform3D:finalTransform]];
[zoomAnimation setToValue:[NSValue valueWithCATransform3D:CATransform3DIdentity]];
[zoomAnimation setDelegate:m_enterFullScreenListener.get()];
[zoomAnimation setDuration:duration];
[zoomAnimation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
[zoomAnimation setFillMode:kCAFillModeForwards];
// Disable implicit animations and set the layer's transformation matrix to its final state.
[CATransaction begin];
[CATransaction setDisableActions:YES];
[caLayer addAnimation:zoomAnimation forKey:@"zoom"];
[CATransaction commit];
}
void WebFullScreenManagerMac::beginExitFullScreenAnimation(float duration)
{
ASSERT(m_element);
ASSERT(m_fullScreenRootLayer);
IntRect destinationFrame = getFullScreenRect();
m_element->document()->setFullScreenRendererSize(destinationFrame.size());
m_rootLayer->syncCompositingStateForThisLayerOnly();
m_page->corePage()->mainFrame()->view()->syncCompositingStateIncludingSubframes();
// FIXME: Once we gain the ability to do native WebKit animations of generated
// content, this can change to use them. Meanwhile, we'll have to animate the
// CALayer directly:
CALayer* caLayer = m_fullScreenRootLayer->platformLayer();
// Create a transformation matrix that will transform the renderer layer such that
// the fullscreen element appears to move from its starting position and size to its
// final one.
CGPoint destinationPosition = [(CALayer*)[caLayer presentationLayer] position];
CGRect destinationBounds = NSRectToCGRect([[caLayer presentationLayer] bounds]);
CGPoint layerAnchor = [caLayer anchorPoint];
CGPoint initialPosition = CGPointMake(
m_initialFrame.x() + m_initialFrame.width() * layerAnchor.x,
m_initialFrame.y() + m_initialFrame.height() * layerAnchor.y);
CATransform3D shrinkTransform = CATransform3DMakeScale(
static_cast<CGFloat>(m_initialFrame.width()) / destinationBounds.size.width,
static_cast<CGFloat>(m_initialFrame.height()) / destinationBounds.size.height, 1);
CATransform3D shiftTransform = CATransform3DMakeTranslation(
initialPosition.x - destinationPosition.x,
// Drawing is flipped here, and so must be the translation transformation
destinationPosition.y - initialPosition.y, 0);
CATransform3D finalTransform = CATransform3DConcat(shrinkTransform, shiftTransform);
CATransform3D initialTransform = [(CALayer*)[caLayer presentationLayer] transform];
// Use a CABasicAnimation here for the zoom effect. We want to be notified that the animation has
// completed by way of the CAAnimation delegate.
CABasicAnimation* zoomAnimation = [CABasicAnimation animationWithKeyPath:@"transform"];
[zoomAnimation setFromValue:[NSValue valueWithCATransform3D:initialTransform]];
[zoomAnimation setToValue:[NSValue valueWithCATransform3D:finalTransform]];
[zoomAnimation setDelegate:m_exitFullScreenListener.get()];
[zoomAnimation setDuration:duration];
[zoomAnimation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
[zoomAnimation setFillMode:kCAFillModeForwards];
// Disable implicit animations and set the layer's transformation matrix to its final state.
[CATransaction begin];
[CATransaction setDisableActions:YES];
[caLayer addAnimation:zoomAnimation forKey:@"zoom"];
[caLayer setTransform:finalTransform];
[CATransaction commit];
}
} // namespace WebKit
#endif // ENABLE(FULLSCREEN_API)