[iOS] Add a wrapper around the hosted AVPlayerLayer to intercept -setBounds:
authorjer.noble@apple.com <jer.noble@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 23 Apr 2015 23:43:04 +0000 (23:43 +0000)
committerjer.noble@apple.com <jer.noble@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 23 Apr 2015 23:43:04 +0000 (23:43 +0000)
https://bugs.webkit.org/show_bug.cgi?id=144129

Reviewed by Simon Fraser.

When passing the hosted AVPlayerLayer to the fullscreen controller, the new superlayer will
resize the hosted layer with a call to -setBounds:. But because this is a hosted layer, the
bonuds change has no effect. Instead, wrap the CALayerHost in another CALayer whose job it is
to intercept -setBounds: in the same way that WebAVVideoLayer did. In fact, we should just use
that wrapper class inside WebAVVideoLayer as well, to avoid duplicating code.

Drive-by Fix: Null-check m_videoElement in setVideoLayerFrame().

* platform/ios/WebVideoFullscreenInterfaceAVKit.h:
* platform/ios/WebVideoFullscreenInterfaceAVKit.mm:
(-[WebCALayerHostWrapper setVideoSublayer:]):
(-[WebCALayerHostWrapper videoSublayer]):
(-[WebCALayerHostWrapper setBounds:]): Moved from WebAVVideoLayer.
(-[WebCALayerHostWrapper resolveBounds]): Ditto.
(-[WebAVVideoLayer setBounds:]): Moved to WebCALayerHostWrapper.
(WebVideoFullscreenInterfaceAVKit::setupFullscreenInternal): Create the wrapper.
(WebVideoFullscreenInterfaceAVKit::cleanupFullscreenInternal): Clear the wrapper.
(-[WebAVVideoLayer resolveBounds]): Deleted. Moved to WebCALayerHostWrapper.
* platform/ios/WebVideoFullscreenModelVideoElement.mm:
(WebVideoFullscreenModelVideoElement::setVideoLayerFrame): Null-check m_videoElement.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@183229 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/platform/ios/WebVideoFullscreenInterfaceAVKit.h
Source/WebCore/platform/ios/WebVideoFullscreenInterfaceAVKit.mm
Source/WebCore/platform/ios/WebVideoFullscreenModelVideoElement.mm

index 63a71bb..9df52b2 100644 (file)
@@ -1,3 +1,31 @@
+2015-04-23  Jer Noble  <jer.noble@apple.com>
+
+        [iOS] Add a wrapper around the hosted AVPlayerLayer to intercept -setBounds:
+        https://bugs.webkit.org/show_bug.cgi?id=144129
+
+        Reviewed by Simon Fraser.
+
+        When passing the hosted AVPlayerLayer to the fullscreen controller, the new superlayer will
+        resize the hosted layer with a call to -setBounds:. But because this is a hosted layer, the
+        bonuds change has no effect. Instead, wrap the CALayerHost in another CALayer whose job it is
+        to intercept -setBounds: in the same way that WebAVVideoLayer did. In fact, we should just use
+        that wrapper class inside WebAVVideoLayer as well, to avoid duplicating code.
+
+        Drive-by Fix: Null-check m_videoElement in setVideoLayerFrame().
+
+        * platform/ios/WebVideoFullscreenInterfaceAVKit.h:
+        * platform/ios/WebVideoFullscreenInterfaceAVKit.mm:
+        (-[WebCALayerHostWrapper setVideoSublayer:]):
+        (-[WebCALayerHostWrapper videoSublayer]):
+        (-[WebCALayerHostWrapper setBounds:]): Moved from WebAVVideoLayer.
+        (-[WebCALayerHostWrapper resolveBounds]): Ditto.
+        (-[WebAVVideoLayer setBounds:]): Moved to WebCALayerHostWrapper.
+        (WebVideoFullscreenInterfaceAVKit::setupFullscreenInternal): Create the wrapper.
+        (WebVideoFullscreenInterfaceAVKit::cleanupFullscreenInternal): Clear the wrapper.
+        (-[WebAVVideoLayer resolveBounds]): Deleted. Moved to WebCALayerHostWrapper.
+        * platform/ios/WebVideoFullscreenModelVideoElement.mm:
+        (WebVideoFullscreenModelVideoElement::setVideoLayerFrame): Null-check m_videoElement.
+
 2015-04-23  Tim Horton  <timothy_horton@apple.com>
 
         Yellow highlight has gray background color when invoking Lookup on an address in a Google Maps drop down
index b04bd10..f206784 100644 (file)
@@ -44,6 +44,7 @@ OBJC_CLASS UIWindow;
 OBJC_CLASS UIView;
 OBJC_CLASS CALayer;
 OBJC_CLASS WebAVVideoLayer;
+OBJC_CLASS WebCALayerHostWrapper;
 
 namespace WTF {
 class String;
@@ -128,6 +129,7 @@ protected:
     RetainPtr<AVPlayerViewController> m_playerViewController;
     RetainPtr<CALayer> m_videoLayer;
     RetainPtr<WebAVVideoLayer> m_videoLayerContainer;
+    RetainPtr<WebCALayerHostWrapper> m_layerHostWrapper;
     WebVideoFullscreenModel* m_videoFullscreenModel { nullptr };
     WebVideoFullscreenChangeObserver* m_fullscreenChangeObserver { nullptr };
 
index 1ae8fb9..2a92dd7 100644 (file)
@@ -566,6 +566,74 @@ static const char* boolString(bool val)
 @implementation WebAVMediaSelectionOption
 @end
 
+
+@interface WebCALayerHostWrapper : CALayer
+@property (assign) WebVideoFullscreenModel* model;
+@end
+
+@implementation WebCALayerHostWrapper {
+    RetainPtr<CALayer> _videoSublayer;
+}
+
+- (void)setVideoSublayer:(CALayer*)videoSublayer
+{
+    _videoSublayer = videoSublayer;
+    [self addSublayer:videoSublayer];
+}
+
+- (CALayer*)videoSublayer
+{
+    return _videoSublayer.get();
+}
+
+- (void)setBounds:(CGRect)bounds
+{
+    if (CGRectEqualToRect(bounds, self.bounds))
+        return;
+
+    [super setBounds:bounds];
+
+    [_videoSublayer setPosition:CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds))];
+
+    if (!self.model)
+        return;
+
+    FloatRect videoFrame = self.model->videoLayerFrame();
+    FloatRect targetFrame;
+    switch (self.model->videoLayerGravity()) {
+    case WebCore::WebVideoFullscreenModel::VideoGravityResize:
+        targetFrame = bounds;
+        break;
+    case WebCore::WebVideoFullscreenModel::VideoGravityResizeAspect:
+        targetFrame = largestRectWithAspectRatioInsideRect(videoFrame.size().aspectRatio(), bounds);
+        break;
+    case WebCore::WebVideoFullscreenModel::VideoGravityResizeAspectFill:
+        targetFrame = smallestRectWithAspectRatioAroundRect(videoFrame.size().aspectRatio(), bounds);
+        break;
+    }
+    CATransform3D transform = CATransform3DMakeScale(targetFrame.width() / videoFrame.width(), targetFrame.height() / videoFrame.height(), 1);
+    [_videoSublayer setSublayerTransform:transform];
+
+    [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(resolveBounds) object:nil];
+    [self performSelector:@selector(resolveBounds) withObject:nil afterDelay:[CATransaction animationDuration] + 0.1];
+}
+
+- (void)resolveBounds
+{
+    [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(resolveBounds) object:nil];
+    if (!self.model)
+        return;
+
+    [CATransaction begin];
+    [CATransaction setAnimationDuration:0];
+
+    [_videoSublayer setSublayerTransform:CATransform3DIdentity];
+    self.model->setVideoLayerFrame([self bounds]);
+    
+    [CATransaction commit];
+}
+@end
+
 @interface WebAVVideoLayer : CALayer <AVVideoLayer>
 +(WebAVVideoLayer *)videoLayer;
 @property (nonatomic) AVVideoLayerGravity videoLayerGravity;
@@ -632,43 +700,7 @@ static const char* boolString(bool val)
     [super setBounds:bounds];
 
     [_videoSublayer setPosition:CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds))];
-
-    if (![_avPlayerController delegate] || !_avPlayerViewController)
-        return;
-
-    FloatRect videoFrame = [_avPlayerController delegate]->videoLayerFrame();
-    FloatRect targetFrame;
-    switch ([_avPlayerController delegate]->videoLayerGravity()) {
-    case WebCore::WebVideoFullscreenModel::VideoGravityResize:
-        targetFrame = bounds;
-        break;
-    case WebCore::WebVideoFullscreenModel::VideoGravityResizeAspect:
-        targetFrame = largestRectWithAspectRatioInsideRect(videoFrame.size().aspectRatio(), bounds);
-        break;
-    case WebCore::WebVideoFullscreenModel::VideoGravityResizeAspectFill:
-        targetFrame = smallestRectWithAspectRatioAroundRect(videoFrame.size().aspectRatio(), bounds);
-        break;
-    }
-    CATransform3D transform = CATransform3DMakeScale(targetFrame.width() / videoFrame.width(), targetFrame.height() / videoFrame.height(), 1);
-    [_videoSublayer setSublayerTransform:transform];
-
-    [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(resolveBounds) object:nil];
-    [self performSelector:@selector(resolveBounds) withObject:nil afterDelay:[CATransaction animationDuration] + 0.1];
-}
-
-- (void)resolveBounds
-{
-    [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(resolveBounds) object:nil];
-    if (!_avPlayerController || ![_avPlayerController delegate])
-        return;
-
-    [CATransaction begin];
-    [CATransaction setAnimationDuration:0];
-
-    [_videoSublayer setSublayerTransform:CATransform3DIdentity];
-    [_avPlayerController delegate]->setVideoLayerFrame([self bounds]);
-
-    [CATransaction commit];
+    [_videoSublayer setBounds:bounds];
 }
 
 - (void)setVideoLayerGravity:(AVVideoLayerGravity)videoLayerGravity
@@ -932,9 +964,13 @@ void WebVideoFullscreenInterfaceAVKit::setupFullscreenInternal(PlatformLayer& vi
 
     [m_videoLayer removeFromSuperlayer];
 
+    m_layerHostWrapper = adoptNS([[WebCALayerHostWrapper alloc] init]);
+    [m_layerHostWrapper setModel:m_videoFullscreenModel];
+    [m_layerHostWrapper setVideoSublayer:m_videoLayer.get()];
+
     m_videoLayerContainer = [WebAVVideoLayer videoLayer];
     [m_videoLayerContainer setHidden:[m_playerController isExternalPlaybackActive]];
-    [m_videoLayerContainer setVideoSublayer:m_videoLayer.get()];
+    [m_videoLayerContainer setVideoSublayer:m_layerHostWrapper.get()];
 
     CGSize videoSize = [m_playerController contentDimensions];
     CGRect videoRect = CGRectMake(0, 0, videoSize.width, videoSize.height);
@@ -1122,7 +1158,8 @@ void WebVideoFullscreenInterfaceAVKit::cleanupFullscreenInternal()
     [m_videoLayerContainer removeFromSuperlayer];
     [m_videoLayerContainer setPlayerViewController:nil];
     [[m_viewController view] removeFromSuperview];
-    
+
+    m_layerHostWrapper = nil;
     m_videoLayer = nil;
     m_videoLayerContainer = nil;
     m_playerViewController = nil;
index 11ed663..35b5137 100644 (file)
@@ -304,7 +304,8 @@ void WebVideoFullscreenModelVideoElement::setVideoLayerFrame(FloatRect rect)
 {
     m_videoFrame = rect;
     [m_videoFullscreenLayer setBounds:CGRect(rect)];
-    m_videoElement->setVideoFullscreenFrame(rect);
+    if (m_videoElement)
+        m_videoElement->setVideoFullscreenFrame(rect);
 }
 
 FloatRect WebVideoFullscreenModelVideoElement::videoLayerFrame() const