Bug 86969

Summary: Match Firefox restrictions to window.blur and window.focus
Product: WebKit Reporter: jochen
Component: DOMAssignee: jochen
Status: RESOLVED FIXED    
Severity: Normal CC: abarth, adele, atwilson, dbates, dglazkov, eric, fishd, mario, mifenton, ojan, oliver, rakuco, svillar, thorton, tonikitoo, webkit.review.bot, zarvai
Priority: P2    
Version: 528+ (Nightly build)   
Hardware: Unspecified   
OS: Unspecified   
Bug Depends on: 87951, 88001, 87956, 90988    
Bug Blocks:    
Attachments:
Description Flags
Patch
none
Archive of layout-test-results from ec2-cr-linux-03
none
Patch
none
Archive of layout-test-results from ec2-cr-linux-02
none
Patch
none
Patch
none
Patch
none
Patch
none
patch for landing
none
patch for landing (rebased) none

Description jochen 2012-05-20 12:34:01 PDT
Firefox ignores window.blur from regular web pages: http://mxr.mozilla.org/mozilla-aurora/source/dom/base/nsGlobalWindow.cpp#5119 and only allows whoever opened a window to invoke window.focus on that window http://mxr.mozilla.org/mozilla-aurora/source/dom/base/nsGlobalWindow.cpp#5025

This is supposed to twart pop-unders. Given that Firefox does this, I think we should do the same.
Comment 1 jochen 2012-05-20 14:04:48 PDT
Created attachment 142917 [details]
Patch
Comment 2 WebKit Review Bot 2012-05-20 14:57:44 PDT
Comment on attachment 142917 [details]
Patch

Attachment 142917 [details] did not pass chromium-ews (chromium-xvfb):
Output: http://queues.webkit.org/results/12733443

New failing tests:
fast/dom/HTMLDocument/hasFocus.html
Comment 3 WebKit Review Bot 2012-05-20 14:57:49 PDT
Created attachment 142918 [details]
Archive of layout-test-results from ec2-cr-linux-03

The attached test failures were seen while running run-webkit-tests on the chromium-ews.
Bot: ec2-cr-linux-03  Port: <class 'webkitpy.common.config.ports.ChromiumXVFBPort'>  Platform: Linux-2.6.35-28-virtual-x86_64-with-Ubuntu-10.10-maverick
Comment 4 Adam Barth 2012-05-20 21:10:36 PDT
Comment on attachment 142917 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=142917&action=review

I wonder if all ports want this change.  Do you think we should have a WebCore::Setting to enable this new behavior?  It might be worth asking on webkit-dev to see if folks would like such a setting.

> Source/WebCore/ChangeLog:9
> +        Disallow window.blur altogether, and only allow window.focus to be
> +        invoked from the context that created this very window.

This patch doesn't seem to change blur at all...

> Source/WebCore/ChangeLog:11
> +        No new tests yet. I guess this will break some existing tests as well (OOPS!)

Looks like it only broke one test.

> Source/WebCore/page/Chrome.cpp:170
> +bool Chrome::canSetFocus() const
> +{
> +    return m_client->canSetFocus();
> +}

There's no need for this sort of do-nothing function.  The callers can just talk to the client directly.

> Source/WebCore/page/ChromeClient.h:94
> +        virtual bool canSetFocus() const { return false; }

Is the plan to override this function at some point?  I'm not sure I understand the role it plays in this patch.
Comment 5 Adam Barth 2012-05-20 21:13:01 PDT
Eric suggests that another way to deal with popunders is to close the "popup" if we detect that it has become a popunder.
Comment 6 jochen 2012-05-20 22:54:28 PDT
(In reply to comment #4)
> (From update of attachment 142917 [details])
> View in context: https://bugs.webkit.org/attachment.cgi?id=142917&action=review
> 
> I wonder if all ports want this change.  Do you think we should have a WebCore::Setting to enable this new behavior?  It might be worth asking on webkit-dev to see if folks would like such a setting.
> 

I asked here: http://lists.macosforge.org/pipermail/webkit-dev/2012-April/020172.html and but I can ask more explicitly again

> > Source/WebCore/ChangeLog:9
> > +        Disallow window.blur altogether, and only allow window.focus to be
> > +        invoked from the context that created this very window.
> 
> This patch doesn't seem to change blur at all...

Since canSetFocus() defaults to false, unfocus is never invoked.

> 
> > Source/WebCore/ChangeLog:11
> > +        No new tests yet. I guess this will break some existing tests as well (OOPS!)
> 
> Looks like it only broke one test.

Test coverage seems overrated :-/

> 
> > Source/WebCore/page/Chrome.cpp:170
> > +bool Chrome::canSetFocus() const
> > +{
> > +    return m_client->canSetFocus();
> > +}
> 
> There's no need for this sort of do-nothing function.  The callers can just talk to the client directly.
> 
> > Source/WebCore/page/ChromeClient.h:94
> > +        virtual bool canSetFocus() const { return false; }
> 
> Is the plan to override this function at some point?  I'm not sure I understand the role it plays in this patch.

The idea was that one might want to override this function for e.g. app extents in chromium, or if you embed a webview somewhere that expects this to work "the old way"
Comment 7 Adam Barth 2012-05-20 23:22:58 PDT
> The idea was that one might want to override this function for e.g. app extents in chromium, or if you embed a webview somewhere that expects this to work "the old way"

I would leave the function out until we actually want to do that.
Comment 8 Adam Barth 2012-05-20 23:23:23 PDT
Comment on attachment 142917 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=142917&action=review

> Source/WebCore/page/DOMWindow.cpp:942
> -    page->chrome()->unfocus();
> +    if (page->chrome()->canSetFocus())
> +        page->chrome()->unfocus();

I see.  I missed this part of the change.
Comment 9 jochen 2012-05-20 23:54:34 PDT
(In reply to comment #5)
> Eric suggests that another way to deal with popunders is to close the "popup" if we detect that it has become a popunder.

I'd rather match Firefox here than to fragment the possible UA behavior further
Comment 10 jochen 2012-05-21 02:15:28 PDT
Created attachment 142972 [details]
Patch
Comment 11 WebKit Review Bot 2012-05-21 05:46:17 PDT
Comment on attachment 142972 [details]
Patch

Attachment 142972 [details] did not pass chromium-ews (chromium-xvfb):
Output: http://queues.webkit.org/results/12730609

New failing tests:
fast/events/change-frame-focus.html
Comment 12 WebKit Review Bot 2012-05-21 05:46:22 PDT
Created attachment 143012 [details]
Archive of layout-test-results from ec2-cr-linux-02

The attached test failures were seen while running run-webkit-tests on the chromium-ews.
Bot: ec2-cr-linux-02  Port: <class 'webkitpy.common.config.ports.ChromiumXVFBPort'>  Platform: Linux-2.6.35-28-virtual-x86_64-with-Ubuntu-10.10-maverick
Comment 13 jochen 2012-05-21 08:25:47 PDT
Created attachment 143038 [details]
Patch
Comment 14 Adam Barth 2012-05-21 09:23:17 PDT
Comment on attachment 143038 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=143038&action=review

This looks fine, but please wait a bit before landing this patch in case folks on webkit-dev have comments.

> LayoutTests/fast/dom/HTMLDocument/hasFocus.html:32
> -                checkFocus(false, false);
> +                checkFocus(true, false);

I'd add a comment about how window.blur() doesn't do anything anymore because of popupunders.  Otherwise, someone reading this test might think this is pretty odd.

> LayoutTests/fast/dom/Window/mozilla-focus-blur.html:19
> +    var log = document.getElementById('log');
> +    var escaped = message.replace(/</g, '&lt;');
> +    if (isOk)
> +        log.innerHTML += 'PASS: ' + escaped + '<br>';
> +    else
> +        log.innerHTML += 'FAIL: ' + escaped + '<br>';

Why not just use document.createTextNode and appendChild() ?

> LayoutTests/fast/dom/Window/mozilla-focus-blur.html:22
> +function focusShouldNotChange(aAction, nextTest) {

Is there a better name we can use than aAction?  That looks like a name Mozilla would use.

> LayoutTests/fast/dom/Window/mozilla-focus-blur.html:77
> +    focusShouldNotChange2('data:text/html,\<script>opener.focus();opener.postMessage("", "*");\<\/script>', test4);

\<    <-- The \ isn't needed.
Comment 15 Andrew Wilson 2012-05-21 12:12:07 PDT
Comment on attachment 143038 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=143038&action=review

> Source/WebCore/page/DOMWindow.cpp:915
> +        if (activeDocument && opener() && activeDocument->domWindow() == opener())

So, I don't think the if (activeDocument) is needed in this clause (since this is already wrapped in if(context).

Also, I'm concerned that this change will prevent gmail chat notifications from focusing the gmail window. Currently, the code does this:

notification.onclick = function() {
  // Called in the context of the parent window.
  // User clicked the notification, so bring the gmail window to the front.
  window.focus();
}

This change basically breaks notifications because notifications mostly want to be able to focus the parent window when they are clicked on.
Comment 16 jochen 2012-05-21 12:17:55 PDT
(In reply to comment #15)
> (From update of attachment 143038 [details])
> View in context: https://bugs.webkit.org/attachment.cgi?id=143038&action=review
> 
> > Source/WebCore/page/DOMWindow.cpp:915
> > +        if (activeDocument && opener() && activeDocument->domWindow() == opener())
> 
> So, I don't think the if (activeDocument) is needed in this clause (since this is already wrapped in if(context).

True. I copied this from DOMWindow::close, where this also seems to be superfluous.

> 
> Also, I'm concerned that this change will prevent gmail chat notifications from focusing the gmail window. Currently, the code does this:
> 
> notification.onclick = function() {
>   // Called in the context of the parent window.
>   // User clicked the notification, so bring the gmail window to the front.
>   window.focus();
> }
> 
> This change basically breaks notifications because notifications mostly want to be able to focus the parent window when they are clicked on.

We could introduce some ScopedAllowFocus class as Darin suggested earlier to enable this use case.
Comment 17 Andrew Wilson 2012-05-21 12:22:46 PDT
Interesting idea, although adding ScopedAllowFocus would still allow apps to display popunders in their notification onclick handlers. But that's probably not a huge use case.

In any case, I would encourage you not to land this change until we add some kind of accommodation for the notifications onclick API.
Comment 18 jochen 2012-05-27 03:25:44 PDT
Created attachment 144221 [details]
Patch
Comment 19 jochen 2012-05-27 03:35:39 PDT
Created attachment 144222 [details]
Patch
Comment 20 jochen 2012-05-27 03:38:21 PDT
I believe I addressed all comments

I added a new setting (windowFocusRestricted) that defaults to true. It's also accessible via window.internals.settings for tests.

I also added a class WindowFocusAllowedIndicator to temporarily allow window.focus() and use it for notifications (also added a test for it)
Comment 21 Gyuyoung Kim 2012-05-27 04:29:43 PDT
Comment on attachment 144222 [details]
Patch

Attachment 144222 [details] did not pass efl-ews (efl):
Output: http://queues.webkit.org/results/12794929
Comment 22 jochen 2012-05-27 04:42:41 PDT
Created attachment 144224 [details]
Patch
Comment 23 Adam Barth 2012-05-28 15:16:22 PDT
Comment on attachment 144224 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=144224&action=review

> Source/WebCore/GNUmakefile.list.am:3081
> +        Source/WebCore/page/WindowFocusAllowedIndicator.cpp \
> +        Source/WebCore/page/WindowFocusAllowedIndicator.h \

Bad indent.

> Source/WebCore/notifications/Notification.cpp:226
> +    // During clicks on notifications, the page is allowed to focus itself.

This comment is redundant with the code below.

> Source/WebCore/page/DOMWindow.cpp:913
> +    Settings* settings = m_frame->settings();
> +    bool allowFocus = WindowFocusAllowedIndicator::windowFocusAllowed() || (settings && !settings->windowFocusRestricted());

Note: settings will always be non-null here because page is non-null.

> Source/WebCore/page/DOMWindow.cpp:917
> +        // Only allow our opener to focus us.

This comment is redundant with the code below.

> Source/WebCore/page/WindowFocusAllowedIndicator.h:35
> +// Lifts restrictions on window.focus() and window.blur() as imposed by WebCore
> +// during its lifetime.

window.blur doesn't seem to interact with WindowFocusAllowedIndicator.  I'd probably just remove this comment because it's likely to get out of date.  The real purpose of this class is easy to determine by grepping the codebase.

> Source/WebKit/chromium/src/WebNotification.cpp:144
>      // Make sure clicks on notifications are treated as user gestures.
>      UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
> +    // During clicks on notifications, the page is allowed to focus itself.
> +    WindowFocusAllowedIndicator windowFocusAllowed;
>      dispatchEvent(eventNames().clickEvent);

I would remove both of these comments.  They're just noise.
Comment 24 jochen 2012-05-30 01:25:25 PDT
Created attachment 144750 [details]
patch for landing
Comment 25 jochen 2012-05-30 02:25:27 PDT
Created attachment 144763 [details]
patch for landing (rebased)
Comment 26 WebKit Review Bot 2012-05-30 06:28:32 PDT
Comment on attachment 144763 [details]
patch for landing (rebased)

Clearing flags on attachment: 144763

Committed r118916: <http://trac.webkit.org/changeset/118916>
Comment 27 WebKit Review Bot 2012-05-30 06:28:39 PDT
All reviewed patches have been landed.  Closing bug.
Comment 28 Sergio Villar Senin 2012-05-30 08:45:14 PDT
(In reply to comment #27)
> All reviewed patches have been landed.  Closing bug.

fast/dom/Window/mozilla-focus-blur.html has been consistently failing in both Mac and Gtk+ ports since it landed
Comment 29 Sergio Villar Senin 2012-05-30 08:46:03 PDT
(In reply to comment #28)
> (In reply to comment #27)
> > All reviewed patches have been landed.  Closing bug.
> 
> fast/dom/Window/mozilla-focus-blur.html has been consistently failing in both Mac and Gtk+ ports since it landed

Also Qt
Comment 30 jochen 2012-05-30 08:59:26 PDT
Looking
Comment 31 Tim Horton 2012-05-30 12:34:56 PDT
(In reply to comment #30)
> Looking

I landed failing mac results in http://trac.webkit.org/changeset/118953 to help the bots out, please revert when you fix.
Comment 32 Zoltan Arvai 2012-05-31 02:02:03 PDT
(In reply to comment #30)
> Looking

Skipped on Qt after r118916:
fast/dom/Window/mozilla-focus-blur.html
fast/notifications/notifications-click-event-focus.html
Please unskip these tests when its fixed.
Comment 33 Mario Sanchez Prada 2012-05-31 03:42:55 PDT
Skipped for GTK too, and added a new bug to keep track of this:

https://bugs.webkit.org/show_bug.cgi?id=87951
Comment 34 jochen 2012-05-31 05:33:57 PDT
I modified DRT for mac so that it displays the window on screen (instead of off-screen). It seems that DRT and WKTR both don't support changing the focus between different windows (i.e. a simple test window.open('about:blank).focus() won't focus the newly created window (even without this CL).

This is a bit unfortunate, as it makes testing this change hardly possible on those platforms :-/