Hiding a focused element should unfocus it and fire a blur event
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 22 Sep 2013 23:19:14 +0000 (23:19 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 22 Sep 2013 23:19:14 +0000 (23:19 +0000)
https://bugs.webkit.org/show_bug.cgi?id=29241

Patch by Arunprasad Rajkumar <ararunprasad@gmail.com> on 2013-09-22
Reviewed by Darin Adler.

Source/WebCore:

Test: fast/dom/HTMLDocument/active-element-gets-unfocusable.html

We check whether the current focus element is really focusable after
the style recalculation and layout change. If it is not focusable then schedule a
timer to reset it asynchronously.

* dom/Document.cpp:
(WebCore::Document::Document):
(WebCore::Document::recalcStyle): Check isFocusable() on the focus element after
style recalculation.
(WebCore::Document::updateLayout): Check isFocusable() on the focus element after
layout.
(WebCore::Document::resetHiddenFocusElementSoon):
(WebCore::Document::resetHiddenFocusElementTimer):
* dom/Document.h:

LayoutTests:

* fast/dom/HTMLDocument/active-element-gets-unfocusable-expected.txt: Added.
* fast/dom/HTMLDocument/active-element-gets-unfocusable.html: Added.

LayoutTest reused from https://chromium.googlesource.com/chromium/blink/+/c58f636fd18fc27944c42e27d6a92a36867c57e1
with little modification.

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

LayoutTests/ChangeLog
LayoutTests/fast/dom/HTMLDocument/active-element-gets-unfocusable-expected.txt [new file with mode: 0644]
LayoutTests/fast/dom/HTMLDocument/active-element-gets-unfocusable.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/dom/Document.cpp
Source/WebCore/dom/Document.h

index 037cda78a017d2a82512f4806ebe866bb0824cd2..1ef16d8f83005a3e0401da1d18760af8e069a757 100644 (file)
@@ -1,3 +1,16 @@
+2013-09-22  Arunprasad Rajkumar  <ararunprasad@gmail.com>
+
+        Hiding a focused element should unfocus it and fire a blur event
+        https://bugs.webkit.org/show_bug.cgi?id=29241
+
+        Reviewed by Darin Adler.
+
+        * fast/dom/HTMLDocument/active-element-gets-unfocusable-expected.txt: Added.
+        * fast/dom/HTMLDocument/active-element-gets-unfocusable.html: Added.
+
+        LayoutTest reused from https://chromium.googlesource.com/chromium/blink/+/c58f636fd18fc27944c42e27d6a92a36867c57e1
+        with little modification.
+
 2013-09-22  Darin Adler  <darin@apple.com>
 
         Fix accessibility-node-memory-management.html to use normal style for
diff --git a/LayoutTests/fast/dom/HTMLDocument/active-element-gets-unfocusable-expected.txt b/LayoutTests/fast/dom/HTMLDocument/active-element-gets-unfocusable-expected.txt
new file mode 100644 (file)
index 0000000..4e180bf
--- /dev/null
@@ -0,0 +1,19 @@
+Making a focused element invisible should make it blur.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+===> Setting display:none
+Event: blur
+PASS document.activeElement is document.body
+PASS The focusTarget element lost focus.
+
+===> Setting visibility:hidden
+Event: blur
+PASS document.activeElement is document.body
+PASS The focusTarget element lost focus.
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/dom/HTMLDocument/active-element-gets-unfocusable.html b/LayoutTests/fast/dom/HTMLDocument/active-element-gets-unfocusable.html
new file mode 100644 (file)
index 0000000..8c14df0
--- /dev/null
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<body>
+<script src="../../../resources/js-test-pre.js"></script>
+
+<div id="f1">
+  <div tabindex="1" id="div1"></div>
+</div>
+
+<script type="text/javascript">
+description('Making a focused element invisible should make it blur.');
+jsTestIsAsync = true;
+var focusTarget = document.getElementById('div1');
+var testStage = 0;
+var testTimeout = 0;
+
+document.body.onload = function() {
+    focusTarget.focus();
+
+    shouldBe('document.activeElement', 'focusTarget', true);
+    debug('===> Setting display:none');
+    setTimeout("f1.style.display = 'none'",0);
+
+    testTimeout = setTimeout(function() {
+        testFailed('Timeout: Didn\'t loose focus.');
+        finishJSTest();
+    }, 1000);
+};
+
+focusTarget.addEventListener('blur', function() {
+    debug('Event: blur');
+    shouldBe('document.activeElement', 'document.body');
+    testPassed('The focusTarget element lost focus.');
+
+    debug('');
+    if (testStage++ == 0) {
+        f1.style.display = 'block';
+        focusTarget.focus();
+        shouldBe('document.activeElement', 'focusTarget', true);
+        debug('===> Setting visibility:hidden');
+        setTimeout("f1.style.visibility = 'hidden'",0);
+    } else {
+        clearTimeout(testTimeout);
+        finishJSTest();
+    }
+}, false);
+
+</script>
+<script src="../../../resources/js-test-post.js"></script>
+</body>
index 5aca7e5e0106deff0fc1e4111cc5aa97b54d1f1d..ddd0871de3334888e4404c15ed7bbbf0b245afc0 100644 (file)
@@ -1,3 +1,26 @@
+2013-09-22  Arunprasad Rajkumar  <ararunprasad@gmail.com>
+
+        Hiding a focused element should unfocus it and fire a blur event
+        https://bugs.webkit.org/show_bug.cgi?id=29241
+
+        Reviewed by Darin Adler.
+
+        Test: fast/dom/HTMLDocument/active-element-gets-unfocusable.html
+
+        We check whether the current focus element is really focusable after
+        the style recalculation and layout change. If it is not focusable then schedule a
+        timer to reset it asynchronously.
+
+        * dom/Document.cpp:
+        (WebCore::Document::Document):
+        (WebCore::Document::recalcStyle): Check isFocusable() on the focus element after
+        style recalculation.
+        (WebCore::Document::updateLayout): Check isFocusable() on the focus element after
+        layout.
+        (WebCore::Document::resetHiddenFocusElementSoon):
+        (WebCore::Document::resetHiddenFocusElementTimer):
+        * dom/Document.h:
+
 2013-09-22  Sam Weinig  <sam@webkit.org>
 
         CTTE: StaticNodeLists often contain only Elements, we shouldn't store them as Vector<RefPtr<Node>> in those cases
index 6467b29de64a0addee00dfa8807567e6748bfa52..7ad76e152fda86f7285e802dc7980e314179809f 100644 (file)
@@ -440,6 +440,7 @@ Document::Document(Frame* frame, const KURL& url, unsigned documentClasses)
     , m_titleSetExplicitly(false)
     , m_markers(adoptPtr(new DocumentMarkerController))
     , m_updateFocusAppearanceTimer(this, &Document::updateFocusAppearanceTimerFired)
+    , m_resetHiddenFocusElementTimer(this, &Document::resetHiddenFocusElementTimer)
     , m_cssTarget(0)
     , m_processingLoadEvent(false)
     , m_loadEventFinished(false)
@@ -1828,6 +1829,9 @@ void Document::recalcStyle(Style::Change change)
     // to check if any other elements ended up under the mouse pointer due to re-layout.
     if (m_hoveredElement && !m_hoveredElement->renderer())
         frameView.frame().eventHandler().dispatchFakeMouseMoveEventSoon();
+
+    // Style change may reset the focus, e.g. display: none, visibility: hidden.
+    resetHiddenFocusElementSoon();
 }
 
 void Document::updateStyleIfNeeded()
@@ -1866,6 +1870,9 @@ void Document::updateLayout()
     // Only do a layout if changes have occurred that make it necessary.      
     if (frameView && renderView() && (frameView->layoutPending() || renderView()->needsLayout()))
         frameView->layout();
+
+    // Active focus element's isFocusable() state may change after Layout. e.g. width: 0px or height: 0px.
+    resetHiddenFocusElementSoon();
 }
 
 // FIXME: This is a bad idea and needs to be removed eventually.
@@ -4690,6 +4697,12 @@ void Document::cancelFocusAppearanceUpdate()
     m_updateFocusAppearanceTimer.stop();
 }
 
+void Document::resetHiddenFocusElementSoon()
+{
+    if (!m_resetHiddenFocusElementTimer.isActive() && m_focusedElement)
+        m_resetHiddenFocusElementTimer.startOneShot(0);
+}
+
 void Document::updateFocusAppearanceTimerFired(Timer<Document>*)
 {
     Element* element = focusedElement();
@@ -4701,6 +4714,15 @@ void Document::updateFocusAppearanceTimerFired(Timer<Document>*)
         element->updateFocusAppearance(m_updateFocusAppearanceRestoresSelection);
 }
 
+void Document::resetHiddenFocusElementTimer(Timer<Document>*)
+{
+    if (view() && view()->needsLayout())
+        return;
+
+    if (m_focusedElement && !m_focusedElement->isFocusable())
+        setFocusedElement(0);
+}
+
 void Document::attachRange(Range* range)
 {
     ASSERT(!m_ranges.contains(range));
index 868704aec952b3c9f233d60a4b56f6176d1b627e..239f13b2af85b4ddce71883bf750180376962382 100644 (file)
@@ -919,7 +919,9 @@ public:
 
     void updateFocusAppearanceSoon(bool restorePreviousSelection);
     void cancelFocusAppearanceUpdate();
-        
+
+    void resetHiddenFocusElementSoon();
+
     // Extension for manipulating canvas drawing contexts for use in CSS
     CanvasRenderingContext* getCSSCanvasContext(const String& type, const String& name, int width, int height);
     HTMLCanvasElement* getCSSCanvasElement(const String& name);
@@ -1226,6 +1228,8 @@ private:
     void updateFocusAppearanceTimerFired(Timer<Document>*);
     void updateBaseURL();
 
+    void resetHiddenFocusElementTimer(Timer<Document>*);
+
     void buildAccessKeyMap(TreeScope* root);
 
     void createStyleResolver();
@@ -1377,6 +1381,7 @@ private:
     const OwnPtr<DocumentMarkerController> m_markers;
     
     Timer<Document> m_updateFocusAppearanceTimer;
+    Timer<Document> m_resetHiddenFocusElementTimer;
 
     Element* m_cssTarget;