Home | History | Annotate | Download | only in mac
      1 /*
      2  * Copyright (C) 2011 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 #import "config.h"
     26 #import "WebFullScreenManagerMac.h"
     27 
     28 #if ENABLE(FULLSCREEN_API)
     29 
     30 #import "Connection.h"
     31 #import "LayerTreeContext.h"
     32 #import "MessageID.h"
     33 #import "WebFullScreenManagerProxyMessages.h"
     34 #import "WebPage.h"
     35 #import "WebProcess.h"
     36 #import <QuartzCore/QuartzCore.h>
     37 #import <WebCore/Frame.h>
     38 #import <WebCore/FrameView.h>
     39 #import <WebCore/GraphicsLayer.h>
     40 #import <WebCore/Page.h>
     41 #import <WebCore/Settings.h>
     42 #import <WebKitSystemInterface.h>
     43 
     44 using namespace WebCore;
     45 
     46 typedef void (WebKit::WebFullScreenManager::*AnimationBeganFunction)();
     47 typedef void (WebKit::WebFullScreenManager::*AnimationFinishedFunction)(bool);
     48 
     49 #if defined(BUILDING_ON_LEOPARD)
     50 @interface CATransaction(SnowLeopardConvenienceFunctions)
     51 + (void)setDisableActions:(BOOL)flag;
     52 @end
     53 
     54 @implementation CATransaction(SnowLeopardConvenienceFunctions)
     55 + (void)setDisableActions:(BOOL)flag
     56 {
     57     [self setValue:[NSNumber numberWithBool:flag] forKey:kCATransactionDisableActions];
     58 }
     59 @end
     60 #endif
     61 
     62 @interface WebFullScreenManagerAnimationListener : NSObject {
     63     WebKit::WebFullScreenManager* _manager;
     64     AnimationBeganFunction _began;
     65     AnimationFinishedFunction _finished;
     66 }
     67 - (id)initWithManager:(WebKit::WebFullScreenManager*)manager began:(AnimationBeganFunction)began finished:(AnimationFinishedFunction)finished;
     68 - (void)animationDidStart:(CAAnimation *)anim;
     69 - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag;
     70 - (void)invalidate;
     71 @end
     72 
     73 @implementation WebFullScreenManagerAnimationListener
     74 - (id)initWithManager:(WebKit::WebFullScreenManager*)manager began:(AnimationBeganFunction)began finished:(AnimationFinishedFunction)finished
     75 {
     76     self = [super init];
     77     if (!self)
     78         return nil;
     79 
     80     _manager = manager;
     81     _began = began;
     82     _finished = finished;
     83     return self;
     84 }
     85 
     86 - (void)animationDidStart:(CAAnimation *)anim
     87 {
     88     if (_manager && _began)
     89         (_manager->*_began)();
     90 }
     91 
     92 - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
     93 {
     94     if (_manager && _finished)
     95         (_manager->*_finished)(flag);
     96 }
     97 
     98 - (void)invalidate
     99 {
    100     _manager = 0;
    101     _began = 0;
    102     _finished = 0;
    103 }
    104 @end
    105 
    106 namespace WebKit {
    107 
    108 PassRefPtr<WebFullScreenManager> WebFullScreenManager::create(WebPage* page)
    109 {
    110     return WebFullScreenManagerMac::create(page);
    111 }
    112 
    113 PassRefPtr<WebFullScreenManagerMac> WebFullScreenManagerMac::create(WebPage* page)
    114 {
    115     return adoptRef(new WebFullScreenManagerMac(page));
    116 }
    117 
    118 WebFullScreenManagerMac::WebFullScreenManagerMac(WebPage* page)
    119     : WebFullScreenManager(page)
    120 {
    121     m_enterFullScreenListener.adoptNS([[WebFullScreenManagerAnimationListener alloc] initWithManager:this began:&WebFullScreenManagerMac::beganEnterFullScreenAnimation finished:&WebFullScreenManagerMac::finishedEnterFullScreenAnimation]);
    122     m_exitFullScreenListener.adoptNS([[WebFullScreenManagerAnimationListener alloc] initWithManager:this began:&WebFullScreenManagerMac::beganExitFullScreenAnimation finished:&WebFullScreenManagerMac::finishedExitFullScreenAnimation]);
    123 }
    124 
    125 WebFullScreenManagerMac::~WebFullScreenManagerMac()
    126 {
    127     m_page->send(Messages::WebFullScreenManagerProxy::ExitAcceleratedCompositingMode());
    128     [m_enterFullScreenListener.get() invalidate];
    129     [m_exitFullScreenListener.get() invalidate];
    130 }
    131 
    132 void WebFullScreenManagerMac::setRootFullScreenLayer(WebCore::GraphicsLayer* layer)
    133 {
    134     if (m_fullScreenRootLayer == layer)
    135         return;
    136     m_fullScreenRootLayer = layer;
    137 
    138     if (!m_fullScreenRootLayer) {
    139         m_page->send(Messages::WebFullScreenManagerProxy::ExitAcceleratedCompositingMode());
    140         if (m_rootLayer) {
    141             m_rootLayer->removeAllChildren();
    142             m_rootLayer = 0;
    143         }
    144         return;
    145     }
    146 
    147     if (!m_rootLayer) {
    148         mach_port_t serverPort = WebProcess::shared().compositingRenderServerPort();
    149         m_remoteLayerClient = WKCARemoteLayerClientMakeWithServerPort(serverPort);
    150 
    151         m_rootLayer = GraphicsLayer::create(NULL);
    152 #ifndef NDEBUG
    153         m_rootLayer->setName("Full screen root layer");
    154 #endif
    155         m_rootLayer->setDrawsContent(false);
    156         m_rootLayer->setSize(getFullScreenRect().size());
    157 
    158         [m_rootLayer->platformLayer() setGeometryFlipped:YES];
    159         WKCARemoteLayerClientSetLayer(m_remoteLayerClient.get(), m_rootLayer->platformLayer());
    160         m_layerTreeContext.contextID = WKCARemoteLayerClientGetClientId(m_remoteLayerClient.get());
    161         m_page->send(Messages::WebFullScreenManagerProxy::EnterAcceleratedCompositingMode(m_layerTreeContext));
    162     }
    163 
    164     m_rootLayer->removeAllChildren();
    165 
    166     if (m_fullScreenRootLayer)
    167         m_rootLayer->addChild(m_fullScreenRootLayer);
    168 
    169     m_rootLayer->syncCompositingStateForThisLayerOnly();
    170     m_page->corePage()->mainFrame()->view()->syncCompositingStateIncludingSubframes();
    171 }
    172 
    173 void WebFullScreenManagerMac::beginEnterFullScreenAnimation(float duration)
    174 {
    175     ASSERT(m_element);
    176     ASSERT(m_fullScreenRootLayer);
    177 
    178     IntRect destinationFrame = getFullScreenRect();
    179     m_element->document()->setFullScreenRendererSize(destinationFrame.size());
    180     m_rootLayer->syncCompositingStateForThisLayerOnly();
    181     m_page->corePage()->mainFrame()->view()->syncCompositingStateIncludingSubframes();
    182 
    183     // FIXME: Once we gain the ability to do native WebKit animations of generated
    184     // content, this can change to use them.  Meanwhile, we'll have to animate the
    185     // CALayer directly:
    186     CALayer* caLayer = m_fullScreenRootLayer->platformLayer();
    187 
    188     // Create a transformation matrix that will transform the renderer layer such that
    189     // the fullscreen element appears to move from its starting position and size to its
    190     // final one.
    191     CGPoint destinationPosition = [caLayer position];
    192     CGPoint layerAnchor = [caLayer anchorPoint];
    193     CGPoint initialPosition = CGPointMake(
    194         m_initialFrame.x() + m_initialFrame.width() * layerAnchor.x,
    195         m_initialFrame.y() + m_initialFrame.height() * layerAnchor.y);
    196     CATransform3D shrinkTransform = CATransform3DMakeScale(
    197         static_cast<CGFloat>(m_initialFrame.width()) / destinationFrame.width(),
    198         static_cast<CGFloat>(m_initialFrame.height()) / destinationFrame.height(), 1);
    199     CATransform3D shiftTransform = CATransform3DMakeTranslation(
    200         initialPosition.x - destinationPosition.x,
    201         // Drawing is flipped here, and so much be the translation transformation
    202         destinationPosition.y - initialPosition.y, 0);
    203     CATransform3D finalTransform = CATransform3DConcat(shrinkTransform, shiftTransform);
    204 
    205     // Use a CABasicAnimation here for the zoom effect. We want to be notified that the animation has
    206     // completed by way of the CAAnimation delegate.
    207     CABasicAnimation* zoomAnimation = [CABasicAnimation animationWithKeyPath:@"transform"];
    208     [zoomAnimation setFromValue:[NSValue valueWithCATransform3D:finalTransform]];
    209     [zoomAnimation setToValue:[NSValue valueWithCATransform3D:CATransform3DIdentity]];
    210     [zoomAnimation setDelegate:m_enterFullScreenListener.get()];
    211     [zoomAnimation setDuration:duration];
    212     [zoomAnimation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
    213     [zoomAnimation setFillMode:kCAFillModeForwards];
    214 
    215     // Disable implicit animations and set the layer's transformation matrix to its final state.
    216     [CATransaction begin];
    217     [CATransaction setDisableActions:YES];
    218     [caLayer addAnimation:zoomAnimation forKey:@"zoom"];
    219     [CATransaction commit];
    220 }
    221 
    222 void WebFullScreenManagerMac::beginExitFullScreenAnimation(float duration)
    223 {
    224     ASSERT(m_element);
    225     ASSERT(m_fullScreenRootLayer);
    226 
    227     IntRect destinationFrame = getFullScreenRect();
    228     m_element->document()->setFullScreenRendererSize(destinationFrame.size());
    229     m_rootLayer->syncCompositingStateForThisLayerOnly();
    230     m_page->corePage()->mainFrame()->view()->syncCompositingStateIncludingSubframes();
    231 
    232     // FIXME: Once we gain the ability to do native WebKit animations of generated
    233     // content, this can change to use them.  Meanwhile, we'll have to animate the
    234     // CALayer directly:
    235     CALayer* caLayer = m_fullScreenRootLayer->platformLayer();
    236 
    237     // Create a transformation matrix that will transform the renderer layer such that
    238     // the fullscreen element appears to move from its starting position and size to its
    239     // final one.
    240     CGPoint destinationPosition = [(CALayer*)[caLayer presentationLayer] position];
    241     CGRect destinationBounds = NSRectToCGRect([[caLayer presentationLayer] bounds]);
    242     CGPoint layerAnchor = [caLayer anchorPoint];
    243     CGPoint initialPosition = CGPointMake(
    244         m_initialFrame.x() + m_initialFrame.width() * layerAnchor.x,
    245         m_initialFrame.y() + m_initialFrame.height() * layerAnchor.y);
    246     CATransform3D shrinkTransform = CATransform3DMakeScale(
    247         static_cast<CGFloat>(m_initialFrame.width()) / destinationBounds.size.width,
    248         static_cast<CGFloat>(m_initialFrame.height()) / destinationBounds.size.height, 1);
    249     CATransform3D shiftTransform = CATransform3DMakeTranslation(
    250         initialPosition.x - destinationPosition.x,
    251         // Drawing is flipped here, and so must be the translation transformation
    252         destinationPosition.y - initialPosition.y, 0);
    253     CATransform3D finalTransform = CATransform3DConcat(shrinkTransform, shiftTransform);
    254 
    255     CATransform3D initialTransform = [(CALayer*)[caLayer presentationLayer] transform];
    256 
    257     // Use a CABasicAnimation here for the zoom effect. We want to be notified that the animation has
    258     // completed by way of the CAAnimation delegate.
    259     CABasicAnimation* zoomAnimation = [CABasicAnimation animationWithKeyPath:@"transform"];
    260     [zoomAnimation setFromValue:[NSValue valueWithCATransform3D:initialTransform]];
    261     [zoomAnimation setToValue:[NSValue valueWithCATransform3D:finalTransform]];
    262     [zoomAnimation setDelegate:m_exitFullScreenListener.get()];
    263     [zoomAnimation setDuration:duration];
    264     [zoomAnimation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
    265     [zoomAnimation setFillMode:kCAFillModeForwards];
    266 
    267     // Disable implicit animations and set the layer's transformation matrix to its final state.
    268     [CATransaction begin];
    269     [CATransaction setDisableActions:YES];
    270     [caLayer addAnimation:zoomAnimation forKey:@"zoom"];
    271     [caLayer setTransform:finalTransform];
    272     [CATransaction commit];
    273 }
    274 
    275 } // namespace WebKit
    276 
    277 #endif // ENABLE(FULLSCREEN_API)
    278