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 44using namespace WebCore; 45 46typedef void (WebKit::WebFullScreenManager::*AnimationBeganFunction)(); 47typedef 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 106namespace WebKit { 107 108PassRefPtr<WebFullScreenManager> WebFullScreenManager::create(WebPage* page) 109{ 110 return WebFullScreenManagerMac::create(page); 111} 112 113PassRefPtr<WebFullScreenManagerMac> WebFullScreenManagerMac::create(WebPage* page) 114{ 115 return adoptRef(new WebFullScreenManagerMac(page)); 116} 117 118WebFullScreenManagerMac::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 125WebFullScreenManagerMac::~WebFullScreenManagerMac() 126{ 127 m_page->send(Messages::WebFullScreenManagerProxy::ExitAcceleratedCompositingMode()); 128 [m_enterFullScreenListener.get() invalidate]; 129 [m_exitFullScreenListener.get() invalidate]; 130} 131 132void 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 173void 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 222void 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