| /* |
| * 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) |