Changeset 18175 in webkit
- Timestamp:
- Dec 12, 2006, 1:02:13 AM (18 years ago)
- Location:
- trunk
- Files:
-
- 4 added
- 8 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r18173 r18175 1 2006-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 1 15 2006-12-11 Alexey Proskuryakov <ap@webkit.org> 2 16 -
trunk/WebCore/ChangeLog
r18172 r18175 1 2006-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 1 32 2006-12-11 Alexey Proskuryakov <ap@webkit.org> 2 33 -
trunk/WebCore/dom/Document.cpp
r18171 r18175 73 73 #include "NodeFilter.h" 74 74 #include "NodeIterator.h" 75 #include "Page.h" 75 76 #include "PlatformKeyboardEvent.h" 76 77 #include "ProcessingInstruction.h" … … 318 319 // these extra pointers or we will create a reference cycle 319 320 m_docType = 0; 320 m_focusedNode = 0;321 321 m_hoverNode = 0; 322 322 m_activeNode = 0; … … 1028 1028 m_imageLoadEventDispatchSoonList.clear(); 1029 1029 m_imageLoadEventDispatchingList.clear(); 1030 1030 1031 1031 m_hoverNode = 0; 1032 m_focusedNode = 0;1033 1032 m_activeNode = 0; 1034 1033 … … 1967 1966 } 1968 1967 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 1993 1968 #if PLATFORM(MAC) 1994 1969 const Vector<DashboardRegionValue>& Document::dashboardRegions() const … … 2004 1979 #endif 2005 1980 2006 static Widget *widgetForNode(Node *focusedNode) 2007 { 2008 if (!focusedNode) 1981 bool 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 1994 Node* Document::focusedNode() const 1995 { 1996 Frame* frame = this->frame(); 1997 if (!frame) 2009 1998 return 0; 2010 RenderObject *renderer = focusedNode->renderer(); 2011 if (!renderer || !renderer->isWidget()) 1999 2000 Page* page = frame->page(); 2001 if (!page) 2012 2002 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(); 2138 2005 } 2139 2006 -
trunk/WebCore/dom/Document.h
r17958 r18175 403 403 void setSelectedStylesheetSet(const String&); 404 404 405 Node* focusedNode() const { return m_focusedNode.get(); }406 405 bool setFocusedNode(PassRefPtr<Node>); 407 void clearSelectionIfNeeded(Node*);406 Node* focusedNode() const; 408 407 409 408 Node* hoverNode() const { return m_hoverNode.get(); } … … 651 650 Color m_textColor; 652 651 653 RefPtr<Node> m_focusedNode;654 652 RefPtr<Node> m_hoverNode; 655 653 RefPtr<Node> m_activeNode; … … 781 779 782 780 JSEditor* jsEditor(); 783 784 781 JSEditor* m_jsEditor; 785 bool relinquishesEditingFocus(Node*);786 bool acceptsEditingFocus(Node*);787 782 788 783 mutable String m_domain; -
trunk/WebCore/dom/Node.cpp
r18171 r18175 717 717 718 718 Document* doc = document(); 719 if (m_focused) 720 doc->setFocusedNode(0); 719 721 if (m_hovered) 720 722 doc->hoveredNodeDetached(this); -
trunk/WebCore/dom/Node.h
r17908 r18175 211 211 bool active() const { return m_active; } 212 212 bool inActiveChain() const { return m_inActiveChain; } 213 bool inDetach() const { return m_inDetach; } 213 214 bool hovered() const { return m_hovered; } 214 215 bool focused() const { return m_focused; } -
trunk/WebCore/page/Page.cpp
r17945 r18175 22 22 #include "Page.h" 23 23 24 #include "AXObjectCache.h" 24 25 #include "Chrome.h" 25 26 #include "ChromeClient.h" 26 27 #include "ContextMenuClient.h" 27 28 #include "ContextMenuController.h" 29 #include "Document.h" 30 #include "Editor.h" 28 31 #include "EditorClient.h" 32 #include "Element.h" 33 #include "Event.h" 34 #include "EventNames.h" 29 35 #include "Frame.h" 30 36 #include "FrameLoader.h" 31 37 #include "FrameTree.h" 38 #include "FrameView.h" 39 #include "RenderWidget.h" 32 40 #include "SelectionController.h" 33 41 #include "StringHash.h" … … 43 51 static HashSet<Page*>* allPages; 44 52 static HashMap<String, HashSet<Page*>*>* frameNamespaces; 53 54 using namespace EventNames; 55 56 static 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 68 static 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 80 static 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 93 static 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 } 45 102 46 103 Page::Page(ChromeClient* chromeClient, ContextMenuClient* contextMenuClient, EditorClient* editorClient) … … 112 169 } 113 170 171 bool 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 273 SetFocusedNodeDone: 274 Document::updateDocumentsRendering(); 275 return !focusChangeBlocked; 276 } 277 114 278 const HashSet<Page*>* Page::frameNamespace() const 115 279 { … … 153 317 } 154 318 155 } 319 } // namespace WebCore -
trunk/WebCore/page/Page.h
r17910 r18175 40 40 class FrameNamespace; 41 41 class FloatRect; 42 class Node; 42 43 class SelectionController; 43 44 class Settings; … … 56 57 void setGroupName(const String&); 57 58 String groupName() const { return m_groupName; } 59 60 bool setFocusedNode(PassRefPtr<Node>); 61 Node* focusedNode() const { return m_focusedNode.get(); } 58 62 59 63 const HashSet<Page*>* frameNamespace() const; … … 87 91 EditorClient* m_editorClient; 88 92 RefPtr<Frame> m_mainFrame; 93 RefPtr<Node> m_focusedNode; 89 94 int m_frameCount; 90 95 String m_groupName;
Note:
See TracChangeset
for help on using the changeset viewer.