2 * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Nuanti Ltd.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #include "core/page/FocusController.h"
30 #include "core/HTMLNames.h"
31 #include "core/accessibility/AXObjectCache.h"
32 #include "core/dom/Document.h"
33 #include "core/dom/Element.h"
34 #include "core/dom/ElementTraversal.h"
35 #include "core/dom/NodeTraversal.h"
36 #include "core/dom/Range.h"
37 #include "core/dom/shadow/ElementShadow.h"
38 #include "core/dom/shadow/ShadowRoot.h"
39 #include "core/editing/Editor.h"
40 #include "core/editing/FrameSelection.h"
41 #include "core/editing/htmlediting.h" // For firstPositionInOrBeforeNode
42 #include "core/events/Event.h"
43 #include "core/frame/FrameView.h"
44 #include "core/frame/LocalDOMWindow.h"
45 #include "core/frame/LocalFrame.h"
46 #include "core/html/HTMLAreaElement.h"
47 #include "core/html/HTMLImageElement.h"
48 #include "core/html/HTMLPlugInElement.h"
49 #include "core/html/HTMLShadowElement.h"
50 #include "core/html/HTMLTextFormControlElement.h"
51 #include "core/page/Chrome.h"
52 #include "core/page/ChromeClient.h"
53 #include "core/page/EventHandler.h"
54 #include "core/page/FrameTree.h"
55 #include "core/page/Page.h"
56 #include "core/frame/Settings.h"
57 #include "core/page/SpatialNavigation.h"
58 #include "core/rendering/HitTestResult.h"
59 #include "core/rendering/RenderLayer.h"
64 using namespace HTMLNames;
66 static inline bool isShadowInsertionPointFocusScopeOwner(Node& node)
68 return isActiveShadowInsertionPoint(node) && toHTMLShadowElement(node).olderShadowRoot();
71 // FIXME: Some of Node* return values and Node* arguments should be Element*.
73 FocusNavigationScope::FocusNavigationScope(TreeScope* treeScope)
74 : m_rootTreeScope(treeScope)
79 Node* FocusNavigationScope::rootNode() const
81 return &m_rootTreeScope->rootNode();
84 Element* FocusNavigationScope::owner() const
86 Node* root = rootNode();
87 if (root->isShadowRoot()) {
88 ShadowRoot* shadowRoot = toShadowRoot(root);
89 return shadowRoot->isYoungest() ? shadowRoot->host() : shadowRoot->shadowInsertionPointOfYoungerShadowRoot();
91 // FIXME: Figure out the right thing for OOPI here.
92 if (Frame* frame = root->document().frame())
93 return frame->deprecatedLocalOwner();
97 FocusNavigationScope FocusNavigationScope::focusNavigationScopeOf(Node& node)
100 for (Node* n = &node; n; n = n->parentNode())
102 // The result is not always a ShadowRoot nor a DocumentNode since
103 // a starting node is in an orphaned tree in composed shadow tree.
104 return FocusNavigationScope(&root->treeScope());
107 FocusNavigationScope FocusNavigationScope::ownedByNonFocusableFocusScopeOwner(Node& node)
109 if (isShadowHost(node))
110 return FocusNavigationScope::ownedByShadowHost(node);
111 ASSERT(isShadowInsertionPointFocusScopeOwner(node));
112 return FocusNavigationScope::ownedByShadowInsertionPoint(toHTMLShadowElement(node));
115 FocusNavigationScope FocusNavigationScope::ownedByShadowHost(Node& node)
117 ASSERT(isShadowHost(node));
118 return FocusNavigationScope(toElement(node).shadow()->youngestShadowRoot());
121 FocusNavigationScope FocusNavigationScope::ownedByIFrame(HTMLFrameOwnerElement& frame)
123 ASSERT(frame.contentFrame());
124 ASSERT(frame.contentFrame()->isLocalFrame());
125 return FocusNavigationScope(toLocalFrame(frame.contentFrame())->document());
128 FocusNavigationScope FocusNavigationScope::ownedByShadowInsertionPoint(HTMLShadowElement& shadowInsertionPoint)
130 ASSERT(isShadowInsertionPointFocusScopeOwner(shadowInsertionPoint));
131 return FocusNavigationScope(shadowInsertionPoint.olderShadowRoot());
134 static inline void dispatchEventsOnWindowAndFocusedNode(Document* document, bool focused)
136 // If we have a focused node we should dispatch blur on it before we blur the window.
137 // If we have a focused node we should dispatch focus on it after we focus the window.
138 // https://bugs.webkit.org/show_bug.cgi?id=27105
140 // Do not fire events while modal dialogs are up. See https://bugs.webkit.org/show_bug.cgi?id=33962
141 if (Page* page = document->page()) {
142 if (page->defersLoading())
146 if (!focused && document->focusedElement()) {
147 RefPtrWillBeRawPtr<Element> focusedElement(document->focusedElement());
148 focusedElement->setFocus(false);
149 focusedElement->dispatchBlurEvent(nullptr);
150 if (focusedElement == document->focusedElement()) {
151 focusedElement->dispatchFocusOutEvent(EventTypeNames::focusout, nullptr);
152 if (focusedElement == document->focusedElement())
153 focusedElement->dispatchFocusOutEvent(EventTypeNames::DOMFocusOut, nullptr);
157 if (LocalDOMWindow* window = document->domWindow())
158 window->dispatchEvent(Event::create(focused ? EventTypeNames::focus : EventTypeNames::blur));
159 if (focused && document->focusedElement()) {
160 RefPtrWillBeRawPtr<Element> focusedElement(document->focusedElement());
161 focusedElement->setFocus(true);
162 focusedElement->dispatchFocusEvent(0, FocusTypePage);
163 if (focusedElement == document->focusedElement()) {
164 document->focusedElement()->dispatchFocusInEvent(EventTypeNames::focusin, nullptr, FocusTypePage);
165 if (focusedElement == document->focusedElement())
166 document->focusedElement()->dispatchFocusInEvent(EventTypeNames::DOMFocusIn, nullptr, FocusTypePage);
171 static inline bool hasCustomFocusLogic(const Element& element)
173 return element.isHTMLElement() && toHTMLElement(element).hasCustomFocusLogic();
177 static inline bool isNonFocusableShadowHost(const Node& node)
179 if (!node.isElementNode())
181 const Element& element = toElement(node);
182 return !element.isFocusable() && isShadowHost(element) && !hasCustomFocusLogic(element);
186 static inline bool isNonKeyboardFocusableShadowHost(const Node& node)
188 if (!node.isElementNode())
190 const Element& element = toElement(node);
191 return !element.isKeyboardFocusable() && isShadowHost(element) && !hasCustomFocusLogic(element);
194 static inline bool isKeyboardFocusableShadowHost(const Node& node)
196 if (!node.isElementNode())
198 const Element& element = toElement(node);
199 return element.isKeyboardFocusable() && isShadowHost(element) && !hasCustomFocusLogic(element);
202 static inline bool isNonFocusableFocusScopeOwner(Node& node)
204 return isNonKeyboardFocusableShadowHost(node) || isShadowInsertionPointFocusScopeOwner(node);
207 static inline int adjustedTabIndex(Node& node)
209 return isNonFocusableFocusScopeOwner(node) ? 0 : node.tabIndex();
212 static inline bool shouldVisit(Node& node)
214 return (node.isElementNode() && toElement(node).isKeyboardFocusable()) || isNonFocusableFocusScopeOwner(node);
217 FocusController::FocusController(Page* page)
221 , m_isChangingFocusedFrame(false)
225 PassOwnPtrWillBeRawPtr<FocusController> FocusController::create(Page* page)
227 return adoptPtrWillBeNoop(new FocusController(page));
230 void FocusController::setFocusedFrame(PassRefPtrWillBeRawPtr<Frame> frame)
232 ASSERT(!frame || frame->page() == m_page);
233 if (m_focusedFrame == frame || m_isChangingFocusedFrame)
236 m_isChangingFocusedFrame = true;
238 RefPtrWillBeRawPtr<LocalFrame> oldFrame = (m_focusedFrame && m_focusedFrame->isLocalFrame()) ? toLocalFrame(m_focusedFrame.get()) : nullptr;
240 RefPtrWillBeRawPtr<LocalFrame> newFrame = (frame && frame->isLocalFrame()) ? toLocalFrame(frame.get()) : nullptr;
242 m_focusedFrame = frame.get();
244 // Now that the frame is updated, fire events and update the selection focused states of both frames.
245 if (oldFrame && oldFrame->view()) {
246 oldFrame->selection().setFocused(false);
247 oldFrame->domWindow()->dispatchEvent(Event::create(EventTypeNames::blur));
250 if (newFrame && newFrame->view() && isFocused()) {
251 newFrame->selection().setFocused(true);
252 newFrame->domWindow()->dispatchEvent(Event::create(EventTypeNames::focus));
255 m_isChangingFocusedFrame = false;
257 m_page->chrome().client().focusedFrameChanged(newFrame.get());
260 void FocusController::focusDocumentView(PassRefPtrWillBeRawPtr<Frame> frame)
262 ASSERT(!frame || frame->page() == m_page);
263 if (m_focusedFrame == frame)
266 RefPtrWillBeRawPtr<LocalFrame> focusedFrame = (m_focusedFrame && m_focusedFrame->isLocalFrame()) ? toLocalFrame(m_focusedFrame.get()) : nullptr;
267 if (focusedFrame && focusedFrame->view()) {
268 RefPtrWillBeRawPtr<Document> document = focusedFrame->document();
269 Element* focusedElement = document ? document->focusedElement() : nullptr;
270 if (focusedElement) {
271 focusedElement->dispatchBlurEvent(nullptr);
272 if (focusedElement == document->focusedElement()) {
273 focusedElement->dispatchFocusOutEvent(EventTypeNames::focusout, nullptr);
274 if (focusedElement == document->focusedElement())
275 focusedElement->dispatchFocusOutEvent(EventTypeNames::DOMFocusOut, nullptr);
280 RefPtrWillBeRawPtr<LocalFrame> newFocusedFrame = (frame && frame->isLocalFrame()) ? toLocalFrame(frame.get()) : nullptr;
281 if (newFocusedFrame && newFocusedFrame->view()) {
282 RefPtrWillBeRawPtr<Document> document = newFocusedFrame->document();
283 Element* focusedElement = document ? document->focusedElement() : nullptr;
284 if (focusedElement) {
285 focusedElement->dispatchFocusEvent(0, FocusTypePage);
286 if (focusedElement == document->focusedElement()) {
287 document->focusedElement()->dispatchFocusInEvent(EventTypeNames::focusin, nullptr, FocusTypePage);
288 if (focusedElement == document->focusedElement())
289 document->focusedElement()->dispatchFocusInEvent(EventTypeNames::DOMFocusIn, nullptr, FocusTypePage);
294 setFocusedFrame(frame);
297 Frame* FocusController::focusedOrMainFrame() const
299 if (Frame* frame = focusedFrame())
302 // FIXME: This is a temporary hack to ensure that we return a LocalFrame, even when the mainFrame is remote.
303 // FocusController needs to be refactored to deal with RemoteFrames cross-process focus transfers.
304 for (Frame* frame = m_page->mainFrame()->tree().top(); frame; frame = frame->tree().traverseNext()) {
305 if (frame->isLocalRoot())
309 return m_page->mainFrame();
312 void FocusController::setFocused(bool focused)
314 if (isFocused() == focused)
317 m_isFocused = focused;
319 if (!m_isFocused && focusedOrMainFrame()->isLocalFrame())
320 toLocalFrame(focusedOrMainFrame())->eventHandler().stopAutoscroll();
323 setFocusedFrame(m_page->mainFrame());
325 // setFocusedFrame above might reject to update m_focusedFrame, or
326 // m_focusedFrame might be changed by blur/focus event handlers.
327 if (m_focusedFrame && m_focusedFrame->isLocalFrame() && toLocalFrame(m_focusedFrame.get())->view()) {
328 toLocalFrame(m_focusedFrame.get())->selection().setFocused(focused);
329 dispatchEventsOnWindowAndFocusedNode(toLocalFrame(m_focusedFrame.get())->document(), focused);
333 Node* FocusController::findFocusableNodeDecendingDownIntoFrameDocument(FocusType type, Node* node)
335 // The node we found might be a HTMLFrameOwnerElement, so descend down the tree until we find either:
336 // 1) a focusable node, or
337 // 2) the deepest-nested HTMLFrameOwnerElement.
338 while (node && node->isFrameOwnerElement()) {
339 HTMLFrameOwnerElement& owner = toHTMLFrameOwnerElement(*node);
340 if (!owner.contentFrame() || !owner.contentFrame()->isLocalFrame())
342 Node* foundNode = findFocusableNode(type, FocusNavigationScope::ownedByIFrame(owner), nullptr);
345 ASSERT(node != foundNode);
351 bool FocusController::setInitialFocus(FocusType type)
353 bool didAdvanceFocus = advanceFocus(type, true);
355 // If focus is being set initially, accessibility needs to be informed that system focus has moved
356 // into the web area again, even if focus did not change within WebCore. PostNotification is called instead
357 // of handleFocusedUIElementChanged, because this will send the notification even if the element is the same.
358 if (focusedOrMainFrame()->isLocalFrame()) {
359 Document* document = toLocalFrame(focusedOrMainFrame())->document();
360 if (AXObjectCache* cache = document->existingAXObjectCache())
361 cache->handleInitialFocus();
364 return didAdvanceFocus;
367 bool FocusController::advanceFocus(FocusType type, bool initialFocus)
370 case FocusTypeForward:
371 case FocusTypeBackward:
372 return advanceFocusInDocumentOrder(type, initialFocus);
377 return advanceFocusDirectionally(type);
379 ASSERT_NOT_REACHED();
385 bool FocusController::advanceFocusInDocumentOrder(FocusType type, bool initialFocus)
387 // FIXME: Focus advancement won't work with externally rendered frames until after
388 // inter-frame focus control is moved out of Blink.
389 if (!focusedOrMainFrame()->isLocalFrame())
391 LocalFrame* frame = toLocalFrame(focusedOrMainFrame());
393 Document* document = frame->document();
395 Node* currentNode = document->focusedElement();
396 // FIXME: Not quite correct when it comes to focus transitions leaving/entering the WebView itself
397 bool caretBrowsing = frame->settings() && frame->settings()->caretBrowsingEnabled();
399 if (caretBrowsing && !currentNode)
400 currentNode = frame->selection().start().deprecatedNode();
402 document->updateLayoutIgnorePendingStylesheets();
404 RefPtrWillBeRawPtr<Node> node = findFocusableNodeAcrossFocusScope(type, FocusNavigationScope::focusNavigationScopeOf(currentNode ? *currentNode : *document), currentNode);
407 // We didn't find a node to focus, so we should try to pass focus to Chrome.
408 if (!initialFocus && m_page->chrome().canTakeFocus(type)) {
409 document->setFocusedElement(nullptr);
410 setFocusedFrame(nullptr);
411 m_page->chrome().takeFocus(type);
415 // Chrome doesn't want focus, so we should wrap focus.
416 if (!m_page->mainFrame()->isLocalFrame())
418 node = findFocusableNodeRecursively(type, FocusNavigationScope::focusNavigationScopeOf(*m_page->deprecatedLocalMainFrame()->document()), nullptr);
419 node = findFocusableNodeDecendingDownIntoFrameDocument(type, node.get());
427 if (node == document->focusedElement())
428 // Focus wrapped around to the same node.
431 if (!node->isElementNode())
432 // FIXME: May need a way to focus a document here.
435 Element* element = toElement(node);
436 if (element->isFrameOwnerElement() && (!isHTMLPlugInElement(*element) || !element->isKeyboardFocusable())) {
437 // We focus frames rather than frame owners.
438 // FIXME: We should not focus frames that have no scrollbars, as focusing them isn't useful to the user.
439 HTMLFrameOwnerElement* owner = toHTMLFrameOwnerElement(element);
440 if (!owner->contentFrame())
443 document->setFocusedElement(nullptr);
444 setFocusedFrame(owner->contentFrame());
448 // FIXME: It would be nice to just be able to call setFocusedElement(node)
449 // here, but we can't do that because some elements (e.g. HTMLInputElement
450 // and HTMLTextAreaElement) do extra work in their focus() methods.
451 Document& newDocument = element->document();
453 if (&newDocument != document) {
454 // Focus is going away from this document, so clear the focused node.
455 document->setFocusedElement(nullptr);
458 setFocusedFrame(newDocument.frame());
461 Position position = firstPositionInOrBeforeNode(element);
462 VisibleSelection newSelection(position, position, DOWNSTREAM);
463 frame->selection().setSelection(newSelection);
466 element->focus(false, type);
470 Node* FocusController::findFocusableNodeAcrossFocusScope(FocusType type, FocusNavigationScope scope, Node* currentNode)
472 ASSERT(!currentNode || !isNonFocusableShadowHost(*currentNode));
474 if (currentNode && type == FocusTypeForward && isKeyboardFocusableShadowHost(*currentNode)) {
475 Node* foundInInnerFocusScope = findFocusableNodeRecursively(type, FocusNavigationScope::ownedByShadowHost(*currentNode), nullptr);
476 found = foundInInnerFocusScope ? foundInInnerFocusScope : findFocusableNodeRecursively(type, scope, currentNode);
478 found = findFocusableNodeRecursively(type, scope, currentNode);
481 // If there's no focusable node to advance to, move up the focus scopes until we find one.
483 Node* owner = scope.owner();
486 scope = FocusNavigationScope::focusNavigationScopeOf(*owner);
487 if (type == FocusTypeBackward && isKeyboardFocusableShadowHost(*owner)) {
491 found = findFocusableNodeRecursively(type, scope, owner);
493 found = findFocusableNodeDecendingDownIntoFrameDocument(type, found);
497 Node* FocusController::findFocusableNodeRecursively(FocusType type, FocusNavigationScope scope, Node* start)
499 // Starting node is exclusive.
500 Node* foundOrNull = findFocusableNode(type, scope, start);
503 Node& found = *foundOrNull;
504 if (type == FocusTypeForward) {
505 if (!isNonFocusableFocusScopeOwner(found))
507 Node* foundInInnerFocusScope = findFocusableNodeRecursively(type, FocusNavigationScope::ownedByNonFocusableFocusScopeOwner(found), nullptr);
508 return foundInInnerFocusScope ? foundInInnerFocusScope : findFocusableNodeRecursively(type, scope, &found);
510 ASSERT(type == FocusTypeBackward);
511 if (isKeyboardFocusableShadowHost(found)) {
512 Node* foundInInnerFocusScope = findFocusableNodeRecursively(type, FocusNavigationScope::ownedByShadowHost(found), nullptr);
513 return foundInInnerFocusScope ? foundInInnerFocusScope : &found;
515 if (isNonFocusableFocusScopeOwner(found)) {
516 Node* foundInInnerFocusScope = findFocusableNodeRecursively(type, FocusNavigationScope::ownedByNonFocusableFocusScopeOwner(found), nullptr);
517 return foundInInnerFocusScope ? foundInInnerFocusScope :findFocusableNodeRecursively(type, scope, &found);
522 Node* FocusController::findFocusableNode(FocusType type, FocusNavigationScope scope, Node* node)
524 return type == FocusTypeForward ? nextFocusableNode(scope, node) : previousFocusableNode(scope, node);
527 Node* FocusController::findNodeWithExactTabIndex(Node* start, int tabIndex, FocusType type)
529 // Search is inclusive of start
530 for (Node* node = start; node; node = type == FocusTypeForward ? NodeTraversal::next(*node) : NodeTraversal::previous(*node)) {
531 if (shouldVisit(*node) && adjustedTabIndex(*node) == tabIndex)
537 static Node* nextNodeWithGreaterTabIndex(Node* start, int tabIndex)
539 // Search is inclusive of start
540 int winningTabIndex = std::numeric_limits<short>::max() + 1;
541 Node* winner = nullptr;
542 for (Node& node : NodeTraversal::startsAt(start)) {
543 int currentTabIndex = adjustedTabIndex(node);
544 if (shouldVisit(node) && currentTabIndex > tabIndex && currentTabIndex < winningTabIndex) {
546 winningTabIndex = currentTabIndex;
553 static Node* previousNodeWithLowerTabIndex(Node* start, int tabIndex)
555 // Search is inclusive of start
556 int winningTabIndex = 0;
557 Node* winner = nullptr;
558 for (Node* node = start; node; node = NodeTraversal::previous(*node)) {
559 int currentTabIndex = adjustedTabIndex(*node);
560 if (shouldVisit(*node) && currentTabIndex < tabIndex && currentTabIndex > winningTabIndex) {
562 winningTabIndex = currentTabIndex;
568 Node* FocusController::nextFocusableNode(FocusNavigationScope scope, Node* start)
571 int tabIndex = adjustedTabIndex(*start);
572 // If a node is excluded from the normal tabbing cycle, the next focusable node is determined by tree order
574 for (Node& node : NodeTraversal::startsAfter(*start)) {
575 if (shouldVisit(node) && adjustedTabIndex(node) >= 0)
579 // First try to find a node with the same tabindex as start that comes after start in the scope.
580 if (Node* winner = findNodeWithExactTabIndex(NodeTraversal::next(*start), tabIndex, FocusTypeForward))
584 // We've reached the last node in the document with a tabindex of 0. This is the end of the tabbing order.
589 // Look for the first node in the scope that:
590 // 1) has the lowest tabindex that is higher than start's tabindex (or 0, if start is null), and
591 // 2) comes first in the scope, if there's a tie.
592 if (Node* winner = nextNodeWithGreaterTabIndex(scope.rootNode(), start ? adjustedTabIndex(*start) : 0))
595 // There are no nodes with a tabindex greater than start's tabindex,
596 // so find the first node with a tabindex of 0.
597 return findNodeWithExactTabIndex(scope.rootNode(), 0, FocusTypeForward);
600 Node* FocusController::previousFocusableNode(FocusNavigationScope scope, Node* start)
602 Node* last = nullptr;
603 for (Node* node = scope.rootNode(); node; node = node->lastChild())
607 // First try to find the last node in the scope that comes before start and has the same tabindex as start.
608 // If start is null, find the last node in the scope with a tabindex of 0.
610 int startingTabIndex;
612 startingNode = NodeTraversal::previous(*start);
613 startingTabIndex = adjustedTabIndex(*start);
616 startingTabIndex = 0;
619 // However, if a node is excluded from the normal tabbing cycle, the previous focusable node is determined by tree order
620 if (startingTabIndex < 0) {
621 for (Node* node = startingNode; node; node = NodeTraversal::previous(*node)) {
622 if (shouldVisit(*node) && adjustedTabIndex(*node) >= 0)
626 if (Node* winner = findNodeWithExactTabIndex(startingNode, startingTabIndex, FocusTypeBackward))
630 // There are no nodes before start with the same tabindex as start, so look for a node that:
631 // 1) has the highest non-zero tabindex (that is less than start's tabindex), and
632 // 2) comes last in the scope, if there's a tie.
633 startingTabIndex = (start && startingTabIndex) ? startingTabIndex : std::numeric_limits<short>::max();
634 return previousNodeWithLowerTabIndex(last, startingTabIndex);
637 static bool relinquishesEditingFocus(const Element& element)
639 ASSERT(element.hasEditableStyle());
640 return element.document().frame() && element.rootEditableElement();
643 static void clearSelectionIfNeeded(LocalFrame* oldFocusedFrame, LocalFrame* newFocusedFrame, Node* newFocusedNode)
645 if (!oldFocusedFrame || !newFocusedFrame)
648 if (oldFocusedFrame->document() != newFocusedFrame->document())
651 FrameSelection& selection = oldFocusedFrame->selection();
652 if (selection.isNone())
655 bool caretBrowsing = oldFocusedFrame->settings()->caretBrowsingEnabled();
659 Node* selectionStartNode = selection.selection().start().deprecatedNode();
660 if (selectionStartNode == newFocusedNode || selectionStartNode->isDescendantOf(newFocusedNode))
663 if (!enclosingTextFormControl(selectionStartNode))
666 if (selectionStartNode->isInShadowTree() && selectionStartNode->shadowHost() == newFocusedNode)
672 bool FocusController::setFocusedElement(Element* element, PassRefPtrWillBeRawPtr<Frame> newFocusedFrame, FocusType type)
674 RefPtrWillBeRawPtr<LocalFrame> oldFocusedFrame = toLocalFrame(focusedFrame());
675 RefPtrWillBeRawPtr<Document> oldDocument = oldFocusedFrame ? oldFocusedFrame->document() : nullptr;
677 Element* oldFocusedElement = oldDocument ? oldDocument->focusedElement() : nullptr;
678 if (element && oldFocusedElement == element)
681 // FIXME: Might want to disable this check for caretBrowsing
682 if (oldFocusedElement && oldFocusedElement->isRootEditableElement() && !relinquishesEditingFocus(*oldFocusedElement))
685 m_page->chrome().client().willSetInputMethodState();
687 RefPtrWillBeRawPtr<Document> newDocument = nullptr;
689 newDocument = &element->document();
690 else if (newFocusedFrame && newFocusedFrame->isLocalFrame())
691 newDocument = toLocalFrame(newFocusedFrame.get())->document();
693 if (newDocument && oldDocument == newDocument && newDocument->focusedElement() == element)
696 clearSelectionIfNeeded(oldFocusedFrame.get(), toLocalFrame(newFocusedFrame.get()), element);
698 if (oldDocument && oldDocument != newDocument)
699 oldDocument->setFocusedElement(nullptr);
701 if (newFocusedFrame && !newFocusedFrame->page()) {
702 setFocusedFrame(nullptr);
705 setFocusedFrame(newFocusedFrame);
707 // Setting the focused node can result in losing our last reft to node when JS event handlers fire.
708 RefPtrWillBeRawPtr<Element> protect = element;
709 ALLOW_UNUSED_LOCAL(protect);
711 bool successfullyFocused = newDocument->setFocusedElement(element, type);
712 if (!successfullyFocused)
719 void FocusController::setActive(bool active)
721 if (m_isActive == active)
726 Frame* frame = focusedOrMainFrame();
727 if (frame->isLocalFrame())
728 toLocalFrame(frame)->selection().pageActivationChanged();
731 static void updateFocusCandidateIfNeeded(FocusType type, const FocusCandidate& current, FocusCandidate& candidate, FocusCandidate& closest)
733 ASSERT(candidate.visibleNode->isElementNode());
734 ASSERT(candidate.visibleNode->renderer());
736 // Ignore iframes that don't have a src attribute
737 if (frameOwnerElement(candidate) && (!frameOwnerElement(candidate)->contentFrame() || candidate.rect.isEmpty()))
740 // Ignore off screen child nodes of containers that do not scroll (overflow:hidden)
741 if (candidate.isOffscreen && !canBeScrolledIntoView(type, candidate))
744 distanceDataForNode(type, current, candidate);
745 if (candidate.distance == maxDistance())
748 if (candidate.isOffscreenAfterScrolling && candidate.alignment < Full)
751 if (closest.isNull()) {
756 LayoutRect intersectionRect = intersection(candidate.rect, closest.rect);
757 if (!intersectionRect.isEmpty() && !areElementsOnSameLine(closest, candidate)
758 && intersectionRect == candidate.rect) {
759 // If 2 nodes are intersecting, do hit test to find which node in on top.
760 LayoutUnit x = intersectionRect.x() + intersectionRect.width() / 2;
761 LayoutUnit y = intersectionRect.y() + intersectionRect.height() / 2;
762 if (!candidate.visibleNode->document().page()->mainFrame()->isLocalFrame())
764 HitTestResult result = candidate.visibleNode->document().page()->deprecatedLocalMainFrame()->eventHandler().hitTestResultAtPoint(IntPoint(x, y), HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::IgnoreClipping);
765 if (candidate.visibleNode->contains(result.innerNode())) {
769 if (closest.visibleNode->contains(result.innerNode()))
773 if (candidate.alignment == closest.alignment) {
774 if (candidate.distance < closest.distance)
779 if (candidate.alignment > closest.alignment)
783 void FocusController::findFocusCandidateInContainer(Node& container, const LayoutRect& startingRect, FocusType type, FocusCandidate& closest)
785 Element* focusedElement = (focusedFrame() && toLocalFrame(focusedFrame())->document()) ? toLocalFrame(focusedFrame())->document()->focusedElement() : nullptr;
787 Element* element = ElementTraversal::firstWithin(container);
788 FocusCandidate current;
789 current.rect = startingRect;
790 current.focusableNode = focusedElement;
791 current.visibleNode = focusedElement;
793 for (; element; element = (element->isFrameOwnerElement() || canScrollInDirection(element, type))
794 ? ElementTraversal::nextSkippingChildren(*element, &container)
795 : ElementTraversal::next(*element, &container)) {
796 if (element == focusedElement)
799 if (!element->isKeyboardFocusable() && !element->isFrameOwnerElement() && !canScrollInDirection(element, type))
802 FocusCandidate candidate = FocusCandidate(element, type);
803 if (candidate.isNull())
806 candidate.enclosingScrollableBox = &container;
807 updateFocusCandidateIfNeeded(type, current, candidate, closest);
811 bool FocusController::advanceFocusDirectionallyInContainer(Node* container, const LayoutRect& startingRect, FocusType type)
816 LayoutRect newStartingRect = startingRect;
818 if (startingRect.isEmpty())
819 newStartingRect = virtualRectForDirection(type, nodeRectInAbsoluteCoordinates(container));
821 // Find the closest node within current container in the direction of the navigation.
822 FocusCandidate focusCandidate;
823 findFocusCandidateInContainer(*container, newStartingRect, type, focusCandidate);
825 if (focusCandidate.isNull()) {
826 // Nothing to focus, scroll if possible.
827 // NOTE: If no scrolling is performed (i.e. scrollInDirection returns false), the
828 // spatial navigation algorithm will skip this container.
829 return scrollInDirection(container, type);
832 HTMLFrameOwnerElement* frameElement = frameOwnerElement(focusCandidate);
833 // If we have an iframe without the src attribute, it will not have a contentFrame().
834 // We ASSERT here to make sure that
835 // updateFocusCandidateIfNeeded() will never consider such an iframe as a candidate.
836 ASSERT(!frameElement || frameElement->contentFrame());
837 if (frameElement && frameElement->contentFrame()->isLocalFrame()) {
838 if (focusCandidate.isOffscreenAfterScrolling) {
839 scrollInDirection(&focusCandidate.visibleNode->document(), type);
842 // Navigate into a new frame.
844 Element* focusedElement = toLocalFrame(focusedOrMainFrame())->document()->focusedElement();
845 if (focusedElement && !hasOffscreenRect(focusedElement))
846 rect = nodeRectInAbsoluteCoordinates(focusedElement, true /* ignore border */);
847 toLocalFrame(frameElement->contentFrame())->document()->updateLayoutIgnorePendingStylesheets();
848 if (!advanceFocusDirectionallyInContainer(toLocalFrame(frameElement->contentFrame())->document(), rect, type)) {
849 // The new frame had nothing interesting, need to find another candidate.
850 return advanceFocusDirectionallyInContainer(container, nodeRectInAbsoluteCoordinates(focusCandidate.visibleNode, true), type);
855 if (canScrollInDirection(focusCandidate.visibleNode, type)) {
856 if (focusCandidate.isOffscreenAfterScrolling) {
857 scrollInDirection(focusCandidate.visibleNode, type);
860 // Navigate into a new scrollable container.
861 LayoutRect startingRect;
862 Element* focusedElement = toLocalFrame(focusedOrMainFrame())->document()->focusedElement();
863 if (focusedElement && !hasOffscreenRect(focusedElement))
864 startingRect = nodeRectInAbsoluteCoordinates(focusedElement, true);
865 return advanceFocusDirectionallyInContainer(focusCandidate.visibleNode, startingRect, type);
867 if (focusCandidate.isOffscreenAfterScrolling) {
868 Node* container = focusCandidate.enclosingScrollableBox;
869 scrollInDirection(container, type);
873 // We found a new focus node, navigate to it.
874 Element* element = toElement(focusCandidate.focusableNode);
877 element->focus(false, type);
881 bool FocusController::advanceFocusDirectionally(FocusType type)
883 // FIXME: Directional focus changes don't yet work with RemoteFrames.
884 if (!focusedOrMainFrame()->isLocalFrame())
886 LocalFrame* curFrame = toLocalFrame(focusedOrMainFrame());
889 Document* focusedDocument = curFrame->document();
890 if (!focusedDocument)
893 Element* focusedElement = focusedDocument->focusedElement();
894 Node* container = focusedDocument;
896 if (container->isDocumentNode())
897 toDocument(container)->updateLayoutIgnorePendingStylesheets();
899 // Figure out the starting rect.
900 LayoutRect startingRect;
901 if (focusedElement) {
902 if (!hasOffscreenRect(focusedElement)) {
903 container = scrollableEnclosingBoxOrParentFrameForNodeInDirection(type, focusedElement);
904 startingRect = nodeRectInAbsoluteCoordinates(focusedElement, true /* ignore border */);
905 } else if (isHTMLAreaElement(*focusedElement)) {
906 HTMLAreaElement& area = toHTMLAreaElement(*focusedElement);
907 container = scrollableEnclosingBoxOrParentFrameForNodeInDirection(type, area.imageElement());
908 startingRect = virtualRectForAreaElementAndDirection(area, type);
912 bool consumed = false;
914 consumed = advanceFocusDirectionallyInContainer(container, startingRect, type);
915 startingRect = nodeRectInAbsoluteCoordinates(container, true /* ignore border */);
916 container = scrollableEnclosingBoxOrParentFrameForNodeInDirection(type, container);
917 if (container && container->isDocumentNode())
918 toDocument(container)->updateLayoutIgnorePendingStylesheets();
919 } while (!consumed && container);
924 void FocusController::trace(Visitor* visitor)
926 visitor->trace(m_page);
927 visitor->trace(m_focusedFrame);