Add window occlusion criteria to determine page visibility on Mac
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 29 Jan 2013 05:11:09 +0000 (05:11 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 29 Jan 2013 05:11:09 +0000 (05:11 +0000)
https://bugs.webkit.org/show_bug.cgi?id=107494

Patch by Kiran Muppala <cmuppala@apple.com> on 2013-01-28
Reviewed by Simon Fraser.

Source/WebKit2:

* UIProcess/API/mac/PageClientImpl.mm:
(WebKit::PageClientImpl::isViewVisible): Add window occlusion check.
* UIProcess/API/mac/WKView.mm:
(-[WKView dealloc]): Remove self from the all views vector.
(-[WKView addWindowObserversForWindow:]): Register observer for
NSWindowWillOrderOffScreenNotification.
(-[WKView removeWindowObservers]): Unregister observer for
NSWindowWillOrderOffScreenNotification.
(-[WKView viewWillMoveToWindow:]): Disable occlusion notifications.
(-[WKView viewDidMoveToWindow]): Enable occlusion notifications.
(-[WKView _windowWillOrderOffScreen:]): Disable occlusion notifications.
(-[WKView _windowDidOrderOnScreen:]): Enable occlusion notifications.
This notification ensures that occlusion notifications are registered
correctly even if the NSWindow object is assigned a window number after
the viewDidMoveToWindow notification has been received.  This occurs
for instance during application launch.
(-[WKView _setIsWindowOccluded:]):
(-[WKView _enableWindowOcclusionNotifications]):
(-[WKView _disableWindowOcclusionNotifications]):
(windowBecameVisible):
(windowBecameOccluded):
(+[WKView _registerWindowOcclusionNotificationHandlers]):
(+[WKView _unregisterWindowOcclusionNotificationHandlers]):
(+[WKView _allViews]):
(-[WKView _isWindowOccluded]):
(-[WKView initWithFrame:contextRef:pageGroupRef:relatedToPage:]): Add
self to the all views vector.
* UIProcess/API/mac/WKViewInternal.h:

WebKitLibraries:

Add enum constants to specify window occlusion notification type to
notification registration/unregistration methods.  Add typedef for
window ID data passed to the window occlusion notification handler.
Add method to enable occlusion notifications for a particular window.

* WebKitSystemInterface.h: Add
WKOcclusionNotificationTypeWindowBecameVisible,
WKOcclusionNotificationTypeWindowBecameOccluded,
WKWindowID,
WKEnableWindowOcclusionNotifications().

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

Source/WebKit2/ChangeLog
Source/WebKit2/UIProcess/API/mac/PageClientImpl.mm
Source/WebKit2/UIProcess/API/mac/WKView.mm
Source/WebKit2/UIProcess/API/mac/WKViewInternal.h
WebKitLibraries/ChangeLog
WebKitLibraries/WebKitSystemInterface.h

index 34c91b7..0e22fd6 100644 (file)
@@ -1,3 +1,39 @@
+2013-01-28  Kiran Muppala  <cmuppala@apple.com>
+
+        Add window occlusion criteria to determine page visibility on Mac
+        https://bugs.webkit.org/show_bug.cgi?id=107494
+
+        Reviewed by Simon Fraser.
+
+        * UIProcess/API/mac/PageClientImpl.mm:
+        (WebKit::PageClientImpl::isViewVisible): Add window occlusion check.
+        * UIProcess/API/mac/WKView.mm:
+        (-[WKView dealloc]): Remove self from the all views vector.
+        (-[WKView addWindowObserversForWindow:]): Register observer for
+        NSWindowWillOrderOffScreenNotification.
+        (-[WKView removeWindowObservers]): Unregister observer for
+        NSWindowWillOrderOffScreenNotification.
+        (-[WKView viewWillMoveToWindow:]): Disable occlusion notifications.
+        (-[WKView viewDidMoveToWindow]): Enable occlusion notifications.
+        (-[WKView _windowWillOrderOffScreen:]): Disable occlusion notifications.
+        (-[WKView _windowDidOrderOnScreen:]): Enable occlusion notifications.
+        This notification ensures that occlusion notifications are registered
+        correctly even if the NSWindow object is assigned a window number after
+        the viewDidMoveToWindow notification has been received.  This occurs
+        for instance during application launch.
+        (-[WKView _setIsWindowOccluded:]):
+        (-[WKView _enableWindowOcclusionNotifications]):
+        (-[WKView _disableWindowOcclusionNotifications]):
+        (windowBecameVisible):
+        (windowBecameOccluded):
+        (+[WKView _registerWindowOcclusionNotificationHandlers]):
+        (+[WKView _unregisterWindowOcclusionNotificationHandlers]):
+        (+[WKView _allViews]):
+        (-[WKView _isWindowOccluded]):
+        (-[WKView initWithFrame:contextRef:pageGroupRef:relatedToPage:]): Add
+        self to the all views vector.
+        * UIProcess/API/mac/WKViewInternal.h:
+
 2013-01-28  Huang Dongsung  <luxtella@company100.net>
 
         [TexMap] Enable debug borders and repaint counter via Settings.
index 5670319..2a627a0 100644 (file)
@@ -200,6 +200,9 @@ bool PageClientImpl::isViewVisible()
     if ([m_wkView isHiddenOrHasHiddenAncestor])
         return false;
 
+    if ([m_wkView _isWindowOccluded])
+        return false;
+
     return true;
 }
 
index 81a31ee..c1a04e9 100644 (file)
@@ -93,6 +93,9 @@
 #import "WKBrowsingContextGroupInternal.h"
 #import "WKProcessGroupInternal.h"
 
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
+static BOOL windowOcclusionNotificationsAreRegistered = NO;
+#endif
 
 @interface NSApplication (WKNSApplicationDetails)
 - (void)speakString:(NSString *)string;
@@ -135,6 +138,14 @@ struct WKViewInterpretKeyEventsParameters {
 - (void)_setDrawingAreaSize:(NSSize)size;
 - (void)_setPluginComplexTextInputState:(PluginComplexTextInputState)pluginComplexTextInputState;
 - (BOOL)_shouldUseTiledDrawingArea;
+- (void)_setIsWindowOccluded:(BOOL)isWindowOccluded;
+- (void)_enableWindowOcclusionNotifications;
+- (void)_disableWindowOcclusionNotifications;
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
++ (BOOL)_registerWindowOcclusionNotificationHandlers;
++ (BOOL)_unregisterWindowOcclusionNotificationHandlers;
+#endif
++ (Vector<WKView *>&)_allViews;
 @end
 
 @interface WKViewData : NSObject {
@@ -211,6 +222,7 @@ struct WKViewInterpretKeyEventsParameters {
 
     NSSize _intrinsicContentSize;
     BOOL _expandsToFitContentViaAutoLayout;
+    BOOL _isWindowOccluded;
 }
 
 @end
@@ -261,6 +273,9 @@ struct WKViewInterpretKeyEventsParameters {
     [_data release];
     _data = nil;
 
+    Vector<WKView *>& allViews = [WKView _allViews];
+    allViews.remove(allViews.find(self));
+
     WebContext::statistics().wkViewCount--;
 
     [super dealloc];
@@ -1817,6 +1832,8 @@ static NSString * const backingPropertyOldScaleFactorKey = @"NSBackingPropertyOl
                                                      name:NSWindowDidMoveNotification object:window];
         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowDidResize:) 
                                                      name:NSWindowDidResizeNotification object:window];
+        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowWillOrderOffScreen:)
+                                                     name:@"NSWindowWillOrderOffScreenNotification" object:window];
         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowDidOrderOffScreen:) 
                                                      name:@"NSWindowDidOrderOffScreenNotification" object:window];
         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowDidOrderOnScreen:) 
@@ -1840,6 +1857,7 @@ static NSString * const backingPropertyOldScaleFactorKey = @"NSBackingPropertyOl
     [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowDidDeminiaturizeNotification object:window];
     [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowDidMoveNotification object:window];
     [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowDidResizeNotification object:window];
+    [[NSNotificationCenter defaultCenter] removeObserver:self name:@"NSWindowWillOrderOffScreenNotification" object:window];
     [[NSNotificationCenter defaultCenter] removeObserver:self name:@"NSWindowDidOrderOffScreenNotification" object:window];
     [[NSNotificationCenter defaultCenter] removeObserver:self name:@"_NSWindowDidBecomeVisible" object:window];
     [[NSNotificationCenter defaultCenter] removeObserver:self name:windowDidChangeBackingPropertiesNotification object:window];
@@ -1865,10 +1883,13 @@ static NSString * const backingPropertyOldScaleFactorKey = @"NSBackingPropertyOl
     
     [self removeWindowObservers];
     [self addWindowObserversForWindow:window];
+    [self _disableWindowOcclusionNotifications];
 }
 
 - (void)viewDidMoveToWindow
 {
+    [self _enableWindowOcclusionNotifications];
+
     // We want to make sure to update the active state while hidden, so if the view is about to become visible, we
     // update the active state first and then make it visible. If the view is about to be hidden, we hide it first and then
     // update the active state.
@@ -1962,6 +1983,11 @@ static NSString * const backingPropertyOldScaleFactorKey = @"NSBackingPropertyOl
     [self _updateWindowAndViewFrames];
 }
 
+- (void)_windowWillOrderOffScreen:(NSNotification *)notification
+{
+    [self _disableWindowOcclusionNotifications];
+}
+
 - (void)_windowDidOrderOffScreen:(NSNotification *)notification
 {
     [self _updateWindowVisibility];
@@ -1975,6 +2001,7 @@ static NSString * const backingPropertyOldScaleFactorKey = @"NSBackingPropertyOl
 - (void)_windowDidOrderOnScreen:(NSNotification *)notification
 {
     [self _updateWindowVisibility];
+    [self _enableWindowOcclusionNotifications];
 
     // We want to make sure to update the active state while hidden, so since the view is about to become visible,
     // we update the active state first and then make it visible.
@@ -2208,6 +2235,126 @@ static void drawPageBackground(CGContextRef context, WebPageProxy* page, const I
 }
 #endif
 
+- (void)_setIsWindowOccluded:(BOOL)isWindowOccluded
+{
+    if (_data->_isWindowOccluded == isWindowOccluded)
+        return;
+    
+    _data->_isWindowOccluded = isWindowOccluded;
+    _data->_page->viewStateDidChange(WebPageProxy::ViewIsVisible);
+}
+
+- (void)_enableWindowOcclusionNotifications
+{
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
+    NSWindow *window = [self window];
+    if (!window)
+        return;
+
+    NSInteger windowID = [window windowNumber];
+    if (windowID <= 0)
+        return;
+
+    if (![WKView _registerWindowOcclusionNotificationHandlers])
+        return;
+
+    bool isWindowOccluded = false;
+    if (!WKEnableWindowOcclusionNotifications(windowID, &isWindowOccluded)) {
+        WTFLogAlways("Enabling window occlusion notifications for window %ld failed.\n", windowID);
+        return;
+    }
+
+    if (isWindowOccluded)
+        [self _setIsWindowOccluded:YES];
+#endif
+}
+
+- (void)_disableWindowOcclusionNotifications
+{
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
+    [self _setIsWindowOccluded:NO];
+
+    // Occlusion notifications for a given window might also be used else where in the
+    // application, hence unregister notification handlers instead.
+    Vector<WKView *>& allViews = [WKView _allViews];
+    if ((allViews.size() == 1) && (allViews[0] == self))
+        [WKView _unregisterWindowOcclusionNotificationHandlers];
+#endif
+}
+
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
+
+static void windowBecameVisible(uint32_t, void* data, uint32_t dataLength, void*, uint32_t)
+{
+    ASSERT(dataLength == sizeof(WKWindowID));
+    NSInteger windowID = *(WKWindowID *)data;
+
+    Vector<WKView *>& allViews = [WKView _allViews];
+    for (size_t i = 0, size = allViews.size(); i < size; ++i) {
+        WKView *view = allViews[i];
+        if ([[view window] windowNumber] == windowID)
+            [view _setIsWindowOccluded:NO];
+    }
+}
+
+static void windowBecameOccluded(uint32_t, void* data, uint32_t dataLength, void*, uint32_t)
+{
+    ASSERT(dataLength == sizeof(WKWindowID));
+    NSInteger windowID = *(WKWindowID *)data;
+
+    Vector<WKView *>& allViews = [WKView _allViews];
+    for (size_t i = 0, size = allViews.size(); i < size; ++i) {
+        WKView *view = allViews[i];
+        if ([[view window] windowNumber] == windowID)
+            [view _setIsWindowOccluded:YES];
+    }
+}
+
++ (BOOL)_registerWindowOcclusionNotificationHandlers
+{
+    if (windowOcclusionNotificationsAreRegistered)
+        return YES;
+
+    if (!WKRegisterOcclusionNotificationHandler(WKOcclusionNotificationTypeWindowBecameVisible, windowBecameVisible)) {
+        WTFLogAlways("Registeration of \"Window Became Visible\" notification handler failed.\n");
+        return NO;
+    }
+    
+    if (!WKRegisterOcclusionNotificationHandler(WKOcclusionNotificationTypeWindowBecameOccluded, windowBecameOccluded)) {
+        WTFLogAlways("Registeration of \"Window Became Occluded\" notification handler failed.\n");
+        return NO;
+    }
+
+    windowOcclusionNotificationsAreRegistered = YES;
+    return YES;
+}
+
++ (BOOL)_unregisterWindowOcclusionNotificationHandlers
+{
+    if (!windowOcclusionNotificationsAreRegistered)
+        return YES;
+
+    if (!WKUnregisterOcclusionNotificationHandler(WKOcclusionNotificationTypeWindowBecameOccluded, windowBecameOccluded)) {
+        WTFLogAlways("Unregisteration of \"Window Became Occluded\" notification handler failed.\n");
+        return NO;
+    }
+
+    if (!WKUnregisterOcclusionNotificationHandler(WKOcclusionNotificationTypeWindowBecameVisible, windowBecameVisible)) {
+        WTFLogAlways("Unregisteration of \"Window Became Visible\" notification handler failed.\n");
+        return NO;
+    }
+
+    windowOcclusionNotificationsAreRegistered = NO;
+    return YES;
+}
+#endif
+
++ (Vector<WKView *>&)_allViews
+{
+    DEFINE_STATIC_LOCAL(Vector<WKView *>, vector, ());
+    return vector;
+}
+
 @end
 
 @implementation WKView (Internal)
@@ -2905,6 +3052,11 @@ static NSString *pathWithUniqueFilenameForPath(NSString *path)
     return _data->_page->suppressVisibilityUpdates();
 }
 
+- (BOOL)_isWindowOccluded
+{
+    return _data->_isWindowOccluded;
+}
+
 @end
 
 @implementation WKView (Private)
@@ -2971,6 +3123,8 @@ static NSString *pathWithUniqueFilenameForPath(NSString *path)
         self.layerContentsPlacement = NSViewLayerContentsPlacementTopLeft;
     }
 
+    [WKView _allViews].append(self);
+
     WebContext::statistics().wkViewCount++;
 
     return self;
index 23500ac..33f7bd7 100644 (file)
@@ -101,4 +101,6 @@ namespace WebKit {
 - (void)_setSuppressVisibilityUpdates:(BOOL)suppressVisibilityUpdates;
 - (BOOL)_suppressVisibilityUpdates;
 
+- (BOOL)_isWindowOccluded;
+
 @end
index 03c1d5d..072e382 100644 (file)
@@ -1,3 +1,21 @@
+2013-01-28  Kiran Muppala  <cmuppala@apple.com>
+
+        Add window occlusion criteria to determine page visibility on Mac
+        https://bugs.webkit.org/show_bug.cgi?id=107494
+
+        Reviewed by Simon Fraser.
+
+        Add enum constants to specify window occlusion notification type to
+        notification registration/unregistration methods.  Add typedef for
+        window ID data passed to the window occlusion notification handler.
+        Add method to enable occlusion notifications for a particular window.
+
+        * WebKitSystemInterface.h: Add
+        WKOcclusionNotificationTypeWindowBecameVisible,
+        WKOcclusionNotificationTypeWindowBecameOccluded,
+        WKWindowID,
+        WKEnableWindowOcclusionNotifications().
+
 2013-01-25  Andy Estes  <aestes@apple.com>
 
         Update WKSI header and libraries after r140875.
index 0f71dda..3b2fd2b 100644 (file)
@@ -522,13 +522,18 @@ CFStringRef WKCaptionAppearanceGetSettingsChangedNotification(void);
 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
 typedef enum {
     WKOcclusionNotificationTypeApplicationBecameVisible,
-    WKOcclusionNotificationTypeApplicationBecameOccluded
+    WKOcclusionNotificationTypeApplicationBecameOccluded,
+    WKOcclusionNotificationTypeWindowBecameVisible,
+    WKOcclusionNotificationTypeWindowBecameOccluded
 } WKOcclusionNotificationType;
 
-typedef void (*WKOcclusionNotificationHandler)(uint32_t, void*, uint32_t, void*, uint32_t);
+typedef uint32_t WKWindowID;
+
+typedef void (*WKOcclusionNotificationHandler)(uint32_t, void* data, uint32_t dataLength, void*, uint32_t);
 
 bool WKRegisterOcclusionNotificationHandler(WKOcclusionNotificationType, WKOcclusionNotificationHandler);
 bool WKUnregisterOcclusionNotificationHandler(WKOcclusionNotificationType, WKOcclusionNotificationHandler);
+bool WKEnableWindowOcclusionNotifications(NSInteger windowID, bool *outCurrentOcclusionState);
 
 enum {
     WKProcessAssertionTypeVisible = (1UL << 10)