• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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