Changeset 18175 in webkit


Ignore:
Timestamp:
Dec 12, 2006 1:02:13 AM (17 years ago)
Author:
ggaren
Message:

LayoutTests:

Reviewed by Beth Dakin.


Added some focus-related tests.

  • editing/undo/undo-iframe-location-change-expected.txt: Updated to reflect the fact that we now unfocus nodes when they're removed from the document.
  • fast/events/keypress-removed-node-expected.txt: Added.
  • fast/events/keypress-removed-node.html: Added.
  • fast/forms/focus2-expected.txt: Added.
  • fast/forms/focus2.html: Added.

WebCore:

Reviewed by Beth Dakin.


Moved focus control to the page level. Fixed a minor bug where a node
would retain keyboard focus even when removed from the document.


We should probably move this, along with hover and active, into a separate
FocusController. But I'm too tired right now.

  • dom/Document.cpp: Migrated code to Page (WebCore::Document::removedLastRef): (WebCore::Document::detach): (WebCore::Document::setFocusedNode): (WebCore::Document::focusedNode):
  • dom/Document.h:
  • dom/Node.cpp: (WebCore::Node::detach): Clear ourselves from keyboard focus. This fixes the minor bug and was also necessary to prevent regressions caused by hanging on to a focused node after the document was replaced.
  • dom/Node.h: (WebCore::Node::inDetach):
  • page/Page.cpp: Migrated code from Document (WebCore::shouldAcquireEditingFocus): (WebCore::shouldRelinquishEditingFocus): (WebCore::clearSelectionIfNeeded): (WebCore::widgetForNode): (WebCore::Page::setFocusedNode):
  • page/Page.h: (WebCore::Page::focusedNode):
Location:
trunk
Files:
4 added
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r18173 r18175  
     12006-12-12  Geoffrey Garen  <ggaren@apple.com>
     2
     3        Reviewed by Beth Dakin.
     4       
     5        Added some focus-related tests.
     6
     7        * editing/undo/undo-iframe-location-change-expected.txt: Updated to reflect
     8        the fact that we now unfocus nodes when they're removed from the document.
     9
     10        * fast/events/keypress-removed-node-expected.txt: Added.
     11        * fast/events/keypress-removed-node.html: Added.
     12        * fast/forms/focus2-expected.txt: Added.
     13        * fast/forms/focus2.html: Added.
     14
    1152006-12-11  Alexey Proskuryakov  <ap@webkit.org>
    216
  • trunk/WebCore/ChangeLog

    r18172 r18175  
     12006-12-12  Geoffrey Garen  <ggaren@apple.com>
     2
     3        Reviewed by Beth Dakin.
     4       
     5        Moved focus control to the page level. Fixed a minor bug where a node
     6        would retain keyboard focus even when removed from the document.
     7       
     8        We should probably move this, along with hover and active, into a separate
     9        FocusController. But I'm too tired right now.
     10
     11        * dom/Document.cpp: Migrated code to Page
     12        (WebCore::Document::removedLastRef):
     13        (WebCore::Document::detach):
     14        (WebCore::Document::setFocusedNode):
     15        (WebCore::Document::focusedNode):
     16        * dom/Document.h:
     17        * dom/Node.cpp:
     18        (WebCore::Node::detach): Clear ourselves from keyboard focus. This fixes
     19        the minor bug and was also necessary to prevent regressions caused by hanging
     20        on to a focused node after the document was replaced.
     21        * dom/Node.h:
     22        (WebCore::Node::inDetach):
     23        * page/Page.cpp: Migrated code from Document
     24        (WebCore::shouldAcquireEditingFocus):
     25        (WebCore::shouldRelinquishEditingFocus):
     26        (WebCore::clearSelectionIfNeeded):
     27        (WebCore::widgetForNode):
     28        (WebCore::Page::setFocusedNode):
     29        * page/Page.h:
     30        (WebCore::Page::focusedNode):
     31
    1322006-12-11  Alexey Proskuryakov  <ap@webkit.org>
    233
  • trunk/WebCore/dom/Document.cpp

    r18171 r18175  
    7373#include "NodeFilter.h"
    7474#include "NodeIterator.h"
     75#include "Page.h"
    7576#include "PlatformKeyboardEvent.h"
    7677#include "ProcessingInstruction.h"
     
    318319        // these extra pointers or we will create a reference cycle
    319320        m_docType = 0;
    320         m_focusedNode = 0;
    321321        m_hoverNode = 0;
    322322        m_activeNode = 0;
     
    10281028    m_imageLoadEventDispatchSoonList.clear();
    10291029    m_imageLoadEventDispatchingList.clear();
    1030    
     1030
    10311031    m_hoverNode = 0;
    1032     m_focusedNode = 0;
    10331032    m_activeNode = 0;
    10341033
     
    19671966}
    19681967
    1969 bool Document::relinquishesEditingFocus(Node *node)
    1970 {
    1971     assert(node);
    1972     assert(node->isContentEditable());
    1973 
    1974     Node *root = node->rootEditableElement();
    1975     if (!frame() || !root)
    1976         return false;
    1977 
    1978     return frame()->editor()->shouldEndEditing(rangeOfContents(root).get());
    1979 }
    1980 
    1981 bool Document::acceptsEditingFocus(Node *node)
    1982 {
    1983     assert(node);
    1984     assert(node->isContentEditable());
    1985 
    1986     Node *root = node->rootEditableElement();
    1987     if (!frame() || !root)
    1988         return false;
    1989 
    1990     return frame()->editor()->shouldBeginEditing(rangeOfContents(root).get());
    1991 }
    1992 
    19931968#if PLATFORM(MAC)
    19941969const Vector<DashboardRegionValue>& Document::dashboardRegions() const
     
    20041979#endif
    20051980
    2006 static Widget *widgetForNode(Node *focusedNode)
    2007 {
    2008     if (!focusedNode)
     1981bool Document::setFocusedNode(PassRefPtr<Node> node)
     1982{
     1983    Frame* frame = this->frame();
     1984    if (!frame)
     1985        return false;
     1986   
     1987    Page* page = frame->page();
     1988    if (!page)
     1989        return false;
     1990   
     1991    return page->setFocusedNode(node);
     1992}
     1993
     1994Node* Document::focusedNode() const
     1995{
     1996    Frame* frame = this->frame();
     1997    if (!frame)
    20091998        return 0;
    2010     RenderObject *renderer = focusedNode->renderer();
    2011     if (!renderer || !renderer->isWidget())
     1999   
     2000    Page* page = frame->page();
     2001    if (!page)
    20122002        return 0;
    2013     return static_cast<RenderWidget*>(renderer)->widget();
    2014 }
    2015 
    2016 bool Document::setFocusedNode(PassRefPtr<Node> newFocusedNode)
    2017 {   
    2018     // Make sure newFocusedNode is actually in this document
    2019     if (newFocusedNode && (newFocusedNode->document() != this))
    2020         return true;
    2021 
    2022     if (m_focusedNode == newFocusedNode)
    2023         return true;
    2024 
    2025     if (m_focusedNode && m_focusedNode.get() == m_focusedNode->rootEditableElement() && !relinquishesEditingFocus(m_focusedNode.get()))
    2026         return false;
    2027        
    2028     bool focusChangeBlocked = false;
    2029     RefPtr<Node> oldFocusedNode = m_focusedNode;
    2030     m_focusedNode = 0;
    2031     clearSelectionIfNeeded(newFocusedNode.get());
    2032 
    2033     // Remove focus from the existing focus node (if any)
    2034     if (oldFocusedNode && !oldFocusedNode->m_inDetach) {
    2035         if (oldFocusedNode->active())
    2036             oldFocusedNode->setActive(false);
    2037 
    2038         oldFocusedNode->setFocus(false);
    2039                
    2040         // Dispatch a change event for text fields or textareas that have been edited
    2041         RenderObject *r = static_cast<RenderObject*>(oldFocusedNode.get()->renderer());
    2042         if (r && (r->isTextArea() || r->isTextField()) && r->isEdited()) {
    2043             EventTargetNodeCast(oldFocusedNode.get())->dispatchHTMLEvent(changeEvent, true, false);
    2044             if ((r = static_cast<RenderObject*>(oldFocusedNode.get()->renderer())))
    2045                 r->setEdited(false);
    2046         }
    2047 
    2048         // Dispatch the blur event and let the node do any other blur related activities (important for text fields)
    2049         EventTargetNodeCast(oldFocusedNode.get())->dispatchBlurEvent();
    2050 
    2051         if (m_focusedNode) {
    2052             // handler shifted focus
    2053             focusChangeBlocked = true;
    2054             newFocusedNode = 0;
    2055         }
    2056         clearSelectionIfNeeded(newFocusedNode.get());
    2057         EventTargetNodeCast(oldFocusedNode.get())->dispatchUIEvent(DOMFocusOutEvent);
    2058         if (m_focusedNode) {
    2059             // handler shifted focus
    2060             focusChangeBlocked = true;
    2061             newFocusedNode = 0;
    2062         }
    2063         clearSelectionIfNeeded(newFocusedNode.get());
    2064         if ((oldFocusedNode.get() == this) && oldFocusedNode->hasOneRef())
    2065             return true;
    2066            
    2067         if (oldFocusedNode.get() == oldFocusedNode->rootEditableElement())
    2068             frame()->editor()->didEndEditing();
    2069     }
    2070 
    2071     if (newFocusedNode) {
    2072         if (newFocusedNode == newFocusedNode->rootEditableElement() && !acceptsEditingFocus(newFocusedNode.get())) {
    2073             // delegate blocks focus change
    2074             focusChangeBlocked = true;
    2075             goto SetFocusedNodeDone;
    2076         }
    2077         // Set focus on the new node
    2078         m_focusedNode = newFocusedNode.get();
    2079 
    2080         // Dispatch the focus event and let the node do any other focus related activities (important for text fields)
    2081         EventTargetNodeCast(m_focusedNode.get())->dispatchFocusEvent();
    2082 
    2083         if (m_focusedNode != newFocusedNode) {
    2084             // handler shifted focus
    2085             focusChangeBlocked = true;
    2086             goto SetFocusedNodeDone;
    2087         }
    2088         EventTargetNodeCast(m_focusedNode.get())->dispatchUIEvent(DOMFocusInEvent);
    2089         if (m_focusedNode != newFocusedNode) {
    2090             // handler shifted focus
    2091             focusChangeBlocked = true;
    2092             goto SetFocusedNodeDone;
    2093         }
    2094         m_focusedNode->setFocus();
    2095        
    2096         if (m_focusedNode.get() == m_focusedNode->rootEditableElement())
    2097             frame()->editor()->didBeginEditing();
    2098        
    2099         // eww, I suck. set the qt focus correctly
    2100         // ### find a better place in the code for this
    2101         if (view()) {
    2102             Widget *focusWidget = widgetForNode(m_focusedNode.get());
    2103             if (focusWidget) {
    2104                 // Make sure a widget has the right size before giving it focus.
    2105                 // Otherwise, we are testing edge cases of the Widget code.
    2106                 // Specifically, in WebCore this does not work well for text fields.
    2107                 updateLayout();
    2108                 // Re-get the widget in case updating the layout changed things.
    2109                 focusWidget = widgetForNode(m_focusedNode.get());
    2110             }
    2111             if (focusWidget)
    2112                 focusWidget->setFocus();
    2113             else
    2114                 view()->setFocus();
    2115         }
    2116    }
    2117 
    2118 #if PLATFORM(MAC)
    2119     if (!focusChangeBlocked && m_focusedNode && AXObjectCache::accessibilityEnabled())
    2120         axObjectCache()->handleFocusedUIElementChanged();
    2121 #endif
    2122 
    2123 SetFocusedNodeDone:
    2124     updateRendering();
    2125     return !focusChangeBlocked;
    2126 }
    2127 
    2128 void Document::clearSelectionIfNeeded(Node *newFocusedNode)
    2129 {
    2130     if (!frame())
    2131         return;
    2132 
    2133     // Clear the selection when changing the focus node to null or to a node that is not
    2134     // contained by the current selection.
    2135     Node *startContainer = frame()->selectionController()->start().node();
    2136     if (!newFocusedNode || (startContainer && startContainer != newFocusedNode && !(startContainer->isDescendantOf(newFocusedNode)) && startContainer->shadowAncestorNode() != newFocusedNode))
    2137         frame()->selectionController()->clear();
     2003   
     2004    return page->focusedNode();
    21382005}
    21392006
  • trunk/WebCore/dom/Document.h

    r17958 r18175  
    403403    void setSelectedStylesheetSet(const String&);
    404404
    405     Node* focusedNode() const { return m_focusedNode.get(); }
    406405    bool setFocusedNode(PassRefPtr<Node>);
    407     void clearSelectionIfNeeded(Node*);
     406    Node* focusedNode() const;
    408407
    409408    Node* hoverNode() const { return m_hoverNode.get(); }
     
    651650    Color m_textColor;
    652651
    653     RefPtr<Node> m_focusedNode;
    654652    RefPtr<Node> m_hoverNode;
    655653    RefPtr<Node> m_activeNode;
     
    781779
    782780    JSEditor* jsEditor();
    783 
    784781    JSEditor* m_jsEditor;
    785     bool relinquishesEditingFocus(Node*);
    786     bool acceptsEditingFocus(Node*);
    787782
    788783    mutable String m_domain;
  • trunk/WebCore/dom/Node.cpp

    r18171 r18175  
    717717
    718718    Document* doc = document();
     719    if (m_focused)
     720        doc->setFocusedNode(0);
    719721    if (m_hovered)
    720722        doc->hoveredNodeDetached(this);
  • trunk/WebCore/dom/Node.h

    r17908 r18175  
    211211    bool active() const { return m_active; }
    212212    bool inActiveChain() const { return m_inActiveChain; }
     213    bool inDetach() const { return m_inDetach; }
    213214    bool hovered() const { return m_hovered; }
    214215    bool focused() const { return m_focused; }
  • trunk/WebCore/page/Page.cpp

    r17945 r18175  
    2222#include "Page.h"
    2323
     24#include "AXObjectCache.h"
    2425#include "Chrome.h"
    2526#include "ChromeClient.h"
    2627#include "ContextMenuClient.h"
    2728#include "ContextMenuController.h"
     29#include "Document.h"
     30#include "Editor.h"
    2831#include "EditorClient.h"
     32#include "Element.h"
     33#include "Event.h"
     34#include "EventNames.h"
    2935#include "Frame.h"
    3036#include "FrameLoader.h"
    3137#include "FrameTree.h"
     38#include "FrameView.h"
     39#include "RenderWidget.h"
    3240#include "SelectionController.h"
    3341#include "StringHash.h"
     
    4351static HashSet<Page*>* allPages;
    4452static HashMap<String, HashSet<Page*>*>* frameNamespaces;
     53
     54using namespace EventNames;
     55
     56static bool shouldAcquireEditingFocus(Node* node)
     57{
     58    ASSERT(node);
     59    ASSERT(node->isContentEditable());
     60
     61    Node* root = node->rootEditableElement();
     62    if (!root || !root->document()->frame())
     63        return false;
     64
     65    return root->document()->frame()->editor()->shouldBeginEditing(rangeOfContents(root).get());
     66}
     67
     68static bool shouldRelinquishEditingFocus(Node* node)
     69{
     70    ASSERT(node);
     71    ASSERT(node->isContentEditable());
     72
     73    Node* root = node->rootEditableElement();
     74    if (!root || !root->document()->frame())
     75        return false;
     76
     77    return root->document()->frame()->editor()->shouldEndEditing(rangeOfContents(root).get());
     78}
     79
     80static void clearSelectionIfNeeded(Node* oldFocusedNode, Node* newFocusedNode)
     81{
     82    Frame* frame = oldFocusedNode ? oldFocusedNode->document()->frame() : 0;
     83    if (!frame)
     84        return;
     85
     86    // Clear the selection when changing the focus node to null or to a node that is not
     87    // contained by the current selection.
     88    Node *startContainer = frame->selectionController()->start().node();
     89    if (!newFocusedNode || (startContainer && startContainer != newFocusedNode && !(startContainer->isDescendantOf(newFocusedNode)) && startContainer->shadowAncestorNode() != newFocusedNode))
     90        frame->selectionController()->clear();
     91}
     92
     93static Widget* widgetForNode(Node* node)
     94{
     95    if (!node)
     96        return 0;
     97    RenderObject* renderer = node->renderer();
     98    if (!renderer || !renderer->isWidget())
     99        return 0;
     100    return static_cast<RenderWidget*>(renderer)->widget();
     101}
    45102
    46103Page::Page(ChromeClient* chromeClient, ContextMenuClient* contextMenuClient, EditorClient* editorClient)
     
    112169}
    113170
     171bool Page::setFocusedNode(PassRefPtr<Node> newFocusedNode)
     172{   
     173    if (m_focusedNode == newFocusedNode)
     174        return true;
     175
     176    if (m_focusedNode && m_focusedNode == m_focusedNode->rootEditableElement() && !shouldRelinquishEditingFocus(m_focusedNode.get()))
     177        return false;
     178
     179    bool focusChangeBlocked = false;
     180    RefPtr<Node> oldFocusedNode = m_focusedNode;
     181    m_focusedNode = 0;
     182    clearSelectionIfNeeded(oldFocusedNode.get(), newFocusedNode.get());
     183
     184    // Remove focus from the existing focus node (if any)
     185    if (oldFocusedNode && !oldFocusedNode->inDetach()) {
     186        if (oldFocusedNode->active())
     187            oldFocusedNode->setActive(false);
     188
     189        oldFocusedNode->setFocus(false);
     190               
     191        // Dispatch a change event for text fields or textareas that have been edited
     192        RenderObject *r = static_cast<RenderObject*>(oldFocusedNode->renderer());
     193        if (r && (r->isTextArea() || r->isTextField()) && r->isEdited()) {
     194            EventTargetNodeCast(oldFocusedNode.get())->dispatchHTMLEvent(changeEvent, true, false);
     195            if ((r = static_cast<RenderObject*>(oldFocusedNode.get()->renderer())))
     196                r->setEdited(false);
     197        }
     198
     199        // Dispatch the blur event and let the node do any other blur related activities (important for text fields)
     200        EventTargetNodeCast(oldFocusedNode.get())->dispatchBlurEvent();
     201
     202        if (m_focusedNode) {
     203            // handler shifted focus
     204            focusChangeBlocked = true;
     205            newFocusedNode = 0;
     206        }
     207        clearSelectionIfNeeded(oldFocusedNode.get(), newFocusedNode.get());
     208        EventTargetNodeCast(oldFocusedNode.get())->dispatchUIEvent(DOMFocusOutEvent);
     209        if (m_focusedNode) {
     210            // handler shifted focus
     211            focusChangeBlocked = true;
     212            newFocusedNode = 0;
     213        }
     214        clearSelectionIfNeeded(oldFocusedNode.get(), newFocusedNode.get());
     215        if ((oldFocusedNode == oldFocusedNode->document()) && oldFocusedNode->hasOneRef())
     216            return true;
     217
     218        if (oldFocusedNode == oldFocusedNode->rootEditableElement())
     219            oldFocusedNode->document()->frame()->editor()->didEndEditing();
     220    }
     221
     222    if (newFocusedNode) {
     223        if (newFocusedNode == newFocusedNode->rootEditableElement() && !shouldAcquireEditingFocus(newFocusedNode.get())) {
     224            // delegate blocks focus change
     225            focusChangeBlocked = true;
     226            goto SetFocusedNodeDone;
     227        }
     228        // Set focus on the new node
     229        m_focusedNode = newFocusedNode.get();
     230
     231        // Dispatch the focus event and let the node do any other focus related activities (important for text fields)
     232        EventTargetNodeCast(m_focusedNode.get())->dispatchFocusEvent();
     233
     234        if (m_focusedNode != newFocusedNode) {
     235            // handler shifted focus
     236            focusChangeBlocked = true;
     237            goto SetFocusedNodeDone;
     238        }
     239        EventTargetNodeCast(m_focusedNode.get())->dispatchUIEvent(DOMFocusInEvent);
     240        if (m_focusedNode != newFocusedNode) {
     241            // handler shifted focus
     242            focusChangeBlocked = true;
     243            goto SetFocusedNodeDone;
     244        }
     245        m_focusedNode->setFocus();
     246       
     247        if (m_focusedNode.get() == m_focusedNode->rootEditableElement())
     248            m_focusedNode->document()->frame()->editor()->didBeginEditing();
     249       
     250        // This only matters for searchfield
     251        if (m_focusedNode->document()->view()) {
     252            Widget* focusWidget = widgetForNode(m_focusedNode.get());
     253            if (focusWidget) {
     254                // Make sure a widget has the right size before giving it focus.
     255                // Otherwise, we are testing edge cases of the Widget code.
     256                // Specifically, in WebCore this does not work well for text fields.
     257                m_focusedNode->document()->updateLayout();
     258                // Re-get the widget in case updating the layout changed things.
     259                focusWidget = widgetForNode(m_focusedNode.get());
     260            }
     261            if (focusWidget)
     262                focusWidget->setFocus();
     263            else
     264                m_focusedNode->document()->view()->setFocus();
     265        }
     266   }
     267
     268#if PLATFORM(MAC)
     269    if (!focusChangeBlocked && m_focusedNode && AXObjectCache::accessibilityEnabled())
     270        m_focusedNode->document()->axObjectCache()->handleFocusedUIElementChanged();
     271#endif
     272
     273SetFocusedNodeDone:
     274    Document::updateDocumentsRendering();
     275    return !focusChangeBlocked;
     276}
     277
    114278const HashSet<Page*>* Page::frameNamespace() const
    115279{
     
    153317}
    154318
    155 }
     319} // namespace WebCore
  • trunk/WebCore/page/Page.h

    r17910 r18175  
    4040    class FrameNamespace;
    4141    class FloatRect;
     42    class Node;
    4243    class SelectionController;
    4344    class Settings;
     
    5657        void setGroupName(const String&);
    5758        String groupName() const { return m_groupName; }
     59
     60        bool setFocusedNode(PassRefPtr<Node>);
     61        Node* focusedNode() const { return m_focusedNode.get(); }
    5862
    5963        const HashSet<Page*>* frameNamespace() const;
     
    8791        EditorClient* m_editorClient;
    8892        RefPtr<Frame> m_mainFrame;
     93        RefPtr<Node> m_focusedNode;
    8994        int m_frameCount;
    9095        String m_groupName;
Note: See TracChangeset for help on using the changeset viewer.