1/*
2 * Copyright (C) 2006, 2007, 2013 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Nuanti Ltd.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
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.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE 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 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.
25 */
26
27#include "config.h"
28#include "FocusController.h"
29
30#include "AXObjectCache.h"
31#include "Chrome.h"
32#include "Document.h"
33#include "Editing.h"
34#include "Editor.h"
35#include "EditorClient.h"
36#include "Element.h"
37#include "ElementTraversal.h"
38#include "Event.h"
39#include "EventHandler.h"
40#include "EventNames.h"
41#include "Frame.h"
42#include "FrameSelection.h"
43#include "FrameTree.h"
44#include "FrameView.h"
45#include "HTMLAreaElement.h"
46#include "HTMLImageElement.h"
47#include "HTMLInputElement.h"
48#include "HTMLNames.h"
49#include "HTMLPlugInElement.h"
50#include "HTMLSlotElement.h"
51#include "HTMLTextAreaElement.h"
52#include "HitTestResult.h"
53#include "KeyboardEvent.h"
54#include "Page.h"
55#include "Range.h"
56#include "RenderWidget.h"
57#include "ScrollAnimator.h"
58#include "Settings.h"
59#include "ShadowRoot.h"
60#include "SpatialNavigation.h"
61#include "Widget.h"
62#include <limits>
63#include <wtf/Ref.h>
64
65namespace WebCore {
66
67using namespace HTMLNames;
68
69static inline bool hasCustomFocusLogic(const Element& element)
70{
71 return is<HTMLElement>(element) && downcast<HTMLElement>(element).hasCustomFocusLogic();
72}
73
74static inline bool isFocusScopeOwner(const Element& element)
75{
76 if (element.shadowRoot() && !hasCustomFocusLogic(element))
77 return true;
78 if (is<HTMLSlotElement>(element)) {
79 ShadowRoot* root = element.containingShadowRoot();
80 if (root && root->host() && !hasCustomFocusLogic(*root->host()))
81 return true;
82 }
83 return false;
84}
85
86class FocusNavigationScope {
87public:
88 Element* owner() const;
89 WEBCORE_EXPORT static FocusNavigationScope scopeOf(Node&);
90 static FocusNavigationScope scopeOwnedByScopeOwner(Element&);
91 static FocusNavigationScope scopeOwnedByIFrame(HTMLFrameOwnerElement&);
92
93 Node* firstNodeInScope() const;
94 Node* lastNodeInScope() const;
95 Node* nextInScope(const Node*) const;
96 Node* previousInScope(const Node*) const;
97 Node* lastChildInScope(const Node&) const;
98
99private:
100 enum class SlotKind : uint8_t { Assigned, Fallback };
101
102 Node* firstChildInScope(const Node&) const;
103
104 Node* parentInScope(const Node&) const;
105
106 Node* nextSiblingInScope(const Node&) const;
107 Node* previousSiblingInScope(const Node&) const;
108
109 explicit FocusNavigationScope(TreeScope&);
110 explicit FocusNavigationScope(HTMLSlotElement&, SlotKind);
111
112 RefPtr<ContainerNode> m_treeScopeRootNode;
113 RefPtr<HTMLSlotElement> m_slotElement;
114 SlotKind m_slotKind { SlotKind::Assigned };
115};
116
117// FIXME: Focus navigation should work with shadow trees that have slots.
118Node* FocusNavigationScope::firstChildInScope(const Node& node) const
119{
120 if (is<Element>(node) && isFocusScopeOwner(downcast<Element>(node)))
121 return nullptr;
122 return node.firstChild();
123}
124
125Node* FocusNavigationScope::lastChildInScope(const Node& node) const
126{
127 if (is<Element>(node) && isFocusScopeOwner(downcast<Element>(node)))
128 return nullptr;
129 return node.lastChild();
130}
131
132Node* FocusNavigationScope::parentInScope(const Node& node) const
133{
134 if (m_treeScopeRootNode == &node)
135 return nullptr;
136
137 if (UNLIKELY(m_slotElement)) {
138 if (m_slotKind == SlotKind::Assigned) {
139 if (m_slotElement == node.assignedSlot())
140 return nullptr;
141 } else {
142 ASSERT(m_slotKind == SlotKind::Fallback);
143 auto* parentNode = node.parentNode();
144 if (parentNode == m_slotElement)
145 return nullptr;
146 }
147 }
148
149 return node.parentNode();
150}
151
152Node* FocusNavigationScope::nextSiblingInScope(const Node& node) const
153{
154 if (UNLIKELY(m_slotElement && m_slotElement == node.assignedSlot())) {
155 for (Node* current = node.nextSibling(); current; current = current->nextSibling()) {
156 if (current->assignedSlot() == m_slotElement)
157 return current;
158 }
159 return nullptr;
160 }
161 return node.nextSibling();
162}
163
164Node* FocusNavigationScope::previousSiblingInScope(const Node& node) const
165{
166 if (UNLIKELY(m_slotElement && m_slotElement == node.assignedSlot())) {
167 for (Node* current = node.previousSibling(); current; current = current->previousSibling()) {
168 if (current->assignedSlot() == m_slotElement)
169 return current;
170 }
171 return nullptr;
172 }
173 return node.previousSibling();
174}
175
176Node* FocusNavigationScope::firstNodeInScope() const
177{
178 if (UNLIKELY(m_slotElement)) {
179 auto* assigneNodes = m_slotElement->assignedNodes();
180 if (m_slotKind == SlotKind::Assigned) {
181 ASSERT(assigneNodes);
182 return assigneNodes->first();
183 }
184 ASSERT(m_slotKind == SlotKind::Fallback);
185 return m_slotElement->firstChild();
186 }
187 ASSERT(m_treeScopeRootNode);
188 return m_treeScopeRootNode.get();
189}
190
191Node* FocusNavigationScope::lastNodeInScope() const
192{
193 if (UNLIKELY(m_slotElement)) {
194 auto* assigneNodes = m_slotElement->assignedNodes();
195 if (m_slotKind == SlotKind::Assigned) {
196 ASSERT(assigneNodes);
197 return assigneNodes->last();
198 }
199 ASSERT(m_slotKind == SlotKind::Fallback);
200 return m_slotElement->lastChild();
201 }
202 ASSERT(m_treeScopeRootNode);
203 return m_treeScopeRootNode.get();
204}
205
206Node* FocusNavigationScope::nextInScope(const Node* node) const
207{
208 ASSERT(node);
209 if (Node* next = firstChildInScope(*node))
210 return next;
211 if (Node* next = nextSiblingInScope(*node))
212 return next;
213 const Node* current = node;
214 while (current && !nextSiblingInScope(*current))
215 current = parentInScope(*current);
216 return current ? nextSiblingInScope(*current) : nullptr;
217}
218
219Node* FocusNavigationScope::previousInScope(const Node* node) const
220{
221 ASSERT(node);
222 if (Node* current = previousSiblingInScope(*node)) {
223 while (Node* child = lastChildInScope(*current))
224 current = child;
225 return current;
226 }
227 return parentInScope(*node);
228}
229
230FocusNavigationScope::FocusNavigationScope(TreeScope& treeScope)
231 : m_treeScopeRootNode(&treeScope.rootNode())
232{
233}
234
235FocusNavigationScope::FocusNavigationScope(HTMLSlotElement& slotElement, SlotKind slotKind)
236 : m_slotElement(&slotElement)
237 , m_slotKind(slotKind)
238{
239}
240
241Element* FocusNavigationScope::owner() const
242{
243 if (m_slotElement)
244 return m_slotElement.get();
245
246 ASSERT(m_treeScopeRootNode);
247 if (is<ShadowRoot>(*m_treeScopeRootNode))
248 return downcast<ShadowRoot>(*m_treeScopeRootNode).host();
249 if (Frame* frame = m_treeScopeRootNode->document().frame())
250 return frame->ownerElement();
251 return nullptr;
252}
253
254FocusNavigationScope FocusNavigationScope::scopeOf(Node& startingNode)
255{
256 ASSERT(startingNode.isInTreeScope());
257 RefPtr<Node> root;
258 RefPtr<Node> parentNode;
259 for (RefPtr<Node> currentNode = &startingNode; currentNode; currentNode = parentNode) {
260 root = currentNode;
261 if (HTMLSlotElement* slot = currentNode->assignedSlot()) {
262 if (isFocusScopeOwner(*slot))
263 return FocusNavigationScope(*slot, SlotKind::Assigned);
264 }
265 if (is<ShadowRoot>(currentNode))
266 return FocusNavigationScope(downcast<ShadowRoot>(*currentNode));
267 parentNode = currentNode->parentNode();
268 // The scope of a fallback content of a HTMLSlotElement is the slot element
269 // but the scope of a HTMLSlotElement is its parent scope.
270 if (parentNode && is<HTMLSlotElement>(parentNode) && !downcast<HTMLSlotElement>(*parentNode).assignedNodes())
271 return FocusNavigationScope(downcast<HTMLSlotElement>(*parentNode), SlotKind::Fallback);
272 }
273 ASSERT(root);
274 return FocusNavigationScope(root->treeScope());
275}
276
277FocusNavigationScope FocusNavigationScope::scopeOwnedByScopeOwner(Element& element)
278{
279 ASSERT(element.shadowRoot() || is<HTMLSlotElement>(element));
280 if (is<HTMLSlotElement>(element)) {
281 auto& slot = downcast<HTMLSlotElement>(element);
282 return FocusNavigationScope(slot, slot.assignedNodes() ? SlotKind::Assigned : SlotKind::Fallback);
283 }
284 return FocusNavigationScope(*element.shadowRoot());
285}
286
287FocusNavigationScope FocusNavigationScope::scopeOwnedByIFrame(HTMLFrameOwnerElement& frame)
288{
289 ASSERT(frame.contentFrame());
290 ASSERT(frame.contentFrame()->document());
291 return FocusNavigationScope(*frame.contentFrame()->document());
292}
293
294static inline void dispatchEventsOnWindowAndFocusedElement(Document* document, bool focused)
295{
296 // If we have a focused node we should dispatch blur on it before we blur the window.
297 // If we have a focused node we should dispatch focus on it after we focus the window.
298 // https://bugs.webkit.org/show_bug.cgi?id=27105
299
300 // Do not fire events while modal dialogs are up. See https://bugs.webkit.org/show_bug.cgi?id=33962
301 if (Page* page = document->page()) {
302 if (page->defersLoading())
303 return;
304 }
305
306 if (!focused && document->focusedElement())
307 document->focusedElement()->dispatchBlurEvent(nullptr);
308 document->dispatchWindowEvent(Event::create(focused ? eventNames().focusEvent : eventNames().blurEvent, Event::CanBubble::No, Event::IsCancelable::No));
309 if (focused && document->focusedElement())
310 document->focusedElement()->dispatchFocusEvent(nullptr, FocusDirectionNone);
311}
312
313static inline bool isFocusableElementOrScopeOwner(Element& element, KeyboardEvent* event)
314{
315 return element.isKeyboardFocusable(event) || isFocusScopeOwner(element);
316}
317
318static inline bool isNonFocusableScopeOwner(Element& element, KeyboardEvent* event)
319{
320 return !element.isKeyboardFocusable(event) && isFocusScopeOwner(element);
321}
322
323static inline bool isFocusableScopeOwner(Element& element, KeyboardEvent* event)
324{
325 return element.isKeyboardFocusable(event) && isFocusScopeOwner(element);
326}
327
328static inline int shadowAdjustedTabIndex(Element& element, KeyboardEvent* event)
329{
330 if (isNonFocusableScopeOwner(element, event)) {
331 if (!element.tabIndexSetExplicitly())
332 return 0; // Treat a shadow host without tabindex if it has tabindex=0 even though HTMLElement::tabIndex returns -1 on such an element.
333 }
334 return element.tabIndex();
335}
336
337FocusController::FocusController(Page& page, OptionSet<ActivityState::Flag> activityState)
338 : m_page(page)
339 , m_isChangingFocusedFrame(false)
340 , m_activityState(activityState)
341 , m_focusRepaintTimer(*this, &FocusController::focusRepaintTimerFired)
342{
343}
344
345void FocusController::setFocusedFrame(Frame* frame)
346{
347 ASSERT(!frame || frame->page() == &m_page);
348 if (m_focusedFrame == frame || m_isChangingFocusedFrame)
349 return;
350
351 m_isChangingFocusedFrame = true;
352
353 RefPtr<Frame> oldFrame = m_focusedFrame;
354 RefPtr<Frame> newFrame = frame;
355
356 m_focusedFrame = newFrame;
357
358 // Now that the frame is updated, fire events and update the selection focused states of both frames.
359 if (oldFrame && oldFrame->view()) {
360 oldFrame->selection().setFocused(false);
361 oldFrame->document()->dispatchWindowEvent(Event::create(eventNames().blurEvent, Event::CanBubble::No, Event::IsCancelable::No));
362 }
363
364 if (newFrame && newFrame->view() && isFocused()) {
365 newFrame->selection().setFocused(true);
366 newFrame->document()->dispatchWindowEvent(Event::create(eventNames().focusEvent, Event::CanBubble::No, Event::IsCancelable::No));
367 }
368
369 m_page.chrome().focusedFrameChanged(newFrame.get());
370
371 m_isChangingFocusedFrame = false;
372}
373
374Frame& FocusController::focusedOrMainFrame() const
375{
376 if (Frame* frame = focusedFrame())
377 return *frame;
378 return m_page.mainFrame();
379}
380
381void FocusController::setFocused(bool focused)
382{
383 m_page.setActivityState(focused ? m_activityState | ActivityState::IsFocused : m_activityState - ActivityState::IsFocused);
384}
385
386void FocusController::setFocusedInternal(bool focused)
387{
388 if (!isFocused())
389 focusedOrMainFrame().eventHandler().stopAutoscrollTimer();
390
391 if (!m_focusedFrame)
392 setFocusedFrame(&m_page.mainFrame());
393
394 if (m_focusedFrame->view()) {
395 m_focusedFrame->selection().setFocused(focused);
396 dispatchEventsOnWindowAndFocusedElement(m_focusedFrame->document(), focused);
397 }
398}
399
400Element* FocusController::findFocusableElementDescendingIntoSubframes(FocusDirection direction, Element* element, KeyboardEvent* event)
401{
402 // The node we found might be a HTMLFrameOwnerElement, so descend down the tree until we find either:
403 // 1) a focusable node, or
404 // 2) the deepest-nested HTMLFrameOwnerElement.
405 while (is<HTMLFrameOwnerElement>(element)) {
406 HTMLFrameOwnerElement& owner = downcast<HTMLFrameOwnerElement>(*element);
407 if (!owner.contentFrame() || !owner.contentFrame()->document())
408 break;
409 owner.contentFrame()->document()->updateLayoutIgnorePendingStylesheets();
410 Element* foundElement = findFocusableElementWithinScope(direction, FocusNavigationScope::scopeOwnedByIFrame(owner), nullptr, event);
411 if (!foundElement)
412 break;
413 ASSERT(element != foundElement);
414 element = foundElement;
415 }
416 return element;
417}
418
419bool FocusController::setInitialFocus(FocusDirection direction, KeyboardEvent* providedEvent)
420{
421 bool didAdvanceFocus = advanceFocus(direction, providedEvent, true);
422
423 // If focus is being set initially, accessibility needs to be informed that system focus has moved
424 // into the web area again, even if focus did not change within WebCore. PostNotification is called instead
425 // of handleFocusedUIElementChanged, because this will send the notification even if the element is the same.
426 if (auto* cache = focusedOrMainFrame().document()->existingAXObjectCache())
427 cache->postNotification(focusedOrMainFrame().document(), AXObjectCache::AXFocusedUIElementChanged);
428
429 return didAdvanceFocus;
430}
431
432bool FocusController::advanceFocus(FocusDirection direction, KeyboardEvent* event, bool initialFocus)
433{
434 switch (direction) {
435 case FocusDirectionForward:
436 case FocusDirectionBackward:
437 return advanceFocusInDocumentOrder(direction, event, initialFocus);
438 case FocusDirectionLeft:
439 case FocusDirectionRight:
440 case FocusDirectionUp:
441 case FocusDirectionDown:
442 return advanceFocusDirectionally(direction, event);
443 default:
444 ASSERT_NOT_REACHED();
445 }
446
447 return false;
448}
449
450bool FocusController::advanceFocusInDocumentOrder(FocusDirection direction, KeyboardEvent* event, bool initialFocus)
451{
452 Frame& frame = focusedOrMainFrame();
453 Document* document = frame.document();
454
455 Node* currentNode = document->focusNavigationStartingNode(direction);
456 // FIXME: Not quite correct when it comes to focus transitions leaving/entering the WebView itself
457 bool caretBrowsing = frame.settings().caretBrowsingEnabled();
458
459 if (caretBrowsing && !currentNode)
460 currentNode = frame.selection().selection().start().deprecatedNode();
461
462 document->updateLayoutIgnorePendingStylesheets();
463
464 RefPtr<Element> element = findFocusableElementAcrossFocusScope(direction, FocusNavigationScope::scopeOf(currentNode ? *currentNode : *document), currentNode, event);
465
466 if (!element) {
467 // We didn't find a node to focus, so we should try to pass focus to Chrome.
468 if (!initialFocus && m_page.chrome().canTakeFocus(direction) && !m_page.isControlledByAutomation()) {
469 document->setFocusedElement(nullptr);
470 setFocusedFrame(nullptr);
471 m_page.chrome().takeFocus(direction);
472 return true;
473 }
474
475 // Chrome doesn't want focus, so we should wrap focus.
476 element = findFocusableElementAcrossFocusScope(direction, FocusNavigationScope::scopeOf(*m_page.mainFrame().document()), nullptr, event);
477
478 if (!element)
479 return false;
480 }
481
482 ASSERT(element);
483
484 if (element == document->focusedElement()) {
485 // Focus wrapped around to the same element.
486 return true;
487 }
488
489 if (is<HTMLFrameOwnerElement>(*element) && (!is<HTMLPlugInElement>(*element) || !element->isKeyboardFocusable(event))) {
490 // We focus frames rather than frame owners.
491 // FIXME: We should not focus frames that have no scrollbars, as focusing them isn't useful to the user.
492 HTMLFrameOwnerElement& owner = downcast<HTMLFrameOwnerElement>(*element);
493 if (!owner.contentFrame())
494 return false;
495
496 document->setFocusedElement(nullptr);
497 setFocusedFrame(owner.contentFrame());
498 return true;
499 }
500
501 // FIXME: It would be nice to just be able to call setFocusedElement(node) here, but we can't do
502 // that because some elements (e.g. HTMLInputElement and HTMLTextAreaElement) do extra work in
503 // their focus() methods.
504
505 Document& newDocument = element->document();
506
507 if (&newDocument != document) {
508 // Focus is going away from this document, so clear the focused node.
509 document->setFocusedElement(nullptr);
510 }
511
512 setFocusedFrame(newDocument.frame());
513
514 if (caretBrowsing) {
515 Position position = firstPositionInOrBeforeNode(element.get());
516 VisibleSelection newSelection(position, position, DOWNSTREAM);
517 if (frame.selection().shouldChangeSelection(newSelection)) {
518 AXTextStateChangeIntent intent(AXTextStateChangeTypeSelectionMove, AXTextSelection { AXTextSelectionDirectionDiscontiguous, AXTextSelectionGranularityUnknown, true });
519 frame.selection().setSelection(newSelection, FrameSelection::defaultSetSelectionOptions(UserTriggered), intent);
520 }
521 }
522
523 element->focus(false, direction);
524 return true;
525}
526
527Element* FocusController::findFocusableElementAcrossFocusScope(FocusDirection direction, const FocusNavigationScope& scope, Node* currentNode, KeyboardEvent* event)
528{
529 ASSERT(!is<Element>(currentNode) || !isNonFocusableScopeOwner(downcast<Element>(*currentNode), event));
530
531 if (currentNode && direction == FocusDirectionForward && is<Element>(currentNode) && isFocusableScopeOwner(downcast<Element>(*currentNode), event)) {
532 if (Element* candidateInInnerScope = findFocusableElementWithinScope(direction, FocusNavigationScope::scopeOwnedByScopeOwner(downcast<Element>(*currentNode)), 0, event))
533 return candidateInInnerScope;
534 }
535
536 if (Element* candidateInCurrentScope = findFocusableElementWithinScope(direction, scope, currentNode, event))
537 return candidateInCurrentScope;
538
539 // If there's no focusable node to advance to, move up the focus scopes until we find one.
540 Element* owner = scope.owner();
541 while (owner) {
542 if (direction == FocusDirectionBackward && isFocusableScopeOwner(*owner, event))
543 return findFocusableElementDescendingIntoSubframes(direction, owner, event);
544
545 auto outerScope = FocusNavigationScope::scopeOf(*owner);
546 if (Element* candidateInOuterScope = findFocusableElementWithinScope(direction, outerScope, owner, event))
547 return candidateInOuterScope;
548 owner = outerScope.owner();
549 }
550 return nullptr;
551}
552
553Element* FocusController::findFocusableElementWithinScope(FocusDirection direction, const FocusNavigationScope& scope, Node* start, KeyboardEvent* event)
554{
555 // Starting node is exclusive.
556 Element* candidate = direction == FocusDirectionForward
557 ? nextFocusableElementWithinScope(scope, start, event)
558 : previousFocusableElementWithinScope(scope, start, event);
559 return findFocusableElementDescendingIntoSubframes(direction, candidate, event);
560}
561
562Element* FocusController::nextFocusableElementWithinScope(const FocusNavigationScope& scope, Node* start, KeyboardEvent* event)
563{
564 Element* found = nextFocusableElementOrScopeOwner(scope, start, event);
565 if (!found)
566 return nullptr;
567 if (isNonFocusableScopeOwner(*found, event)) {
568 if (Element* foundInInnerFocusScope = nextFocusableElementWithinScope(FocusNavigationScope::scopeOwnedByScopeOwner(*found), 0, event))
569 return foundInInnerFocusScope;
570 return nextFocusableElementWithinScope(scope, found, event);
571 }
572 return found;
573}
574
575Element* FocusController::previousFocusableElementWithinScope(const FocusNavigationScope& scope, Node* start, KeyboardEvent* event)
576{
577 Element* found = previousFocusableElementOrScopeOwner(scope, start, event);
578 if (!found)
579 return nullptr;
580 if (isFocusableScopeOwner(*found, event)) {
581 // Search an inner focusable element in the shadow tree from the end.
582 if (Element* foundInInnerFocusScope = previousFocusableElementWithinScope(FocusNavigationScope::scopeOwnedByScopeOwner(*found), 0, event))
583 return foundInInnerFocusScope;
584 return found;
585 }
586 if (isNonFocusableScopeOwner(*found, event)) {
587 if (Element* foundInInnerFocusScope = previousFocusableElementWithinScope(FocusNavigationScope::scopeOwnedByScopeOwner(*found), 0, event))
588 return foundInInnerFocusScope;
589 return previousFocusableElementWithinScope(scope, found, event);
590 }
591 return found;
592}
593
594Element* FocusController::findFocusableElementOrScopeOwner(FocusDirection direction, const FocusNavigationScope& scope, Node* node, KeyboardEvent* event)
595{
596 return (direction == FocusDirectionForward)
597 ? nextFocusableElementOrScopeOwner(scope, node, event)
598 : previousFocusableElementOrScopeOwner(scope, node, event);
599}
600
601Element* FocusController::findElementWithExactTabIndex(const FocusNavigationScope& scope, Node* start, int tabIndex, KeyboardEvent* event, FocusDirection direction)
602{
603 // Search is inclusive of start
604 for (Node* node = start; node; node = direction == FocusDirectionForward ? scope.nextInScope(node) : scope.previousInScope(node)) {
605 if (!is<Element>(*node))
606 continue;
607 Element& element = downcast<Element>(*node);
608 if (isFocusableElementOrScopeOwner(element, event) && shadowAdjustedTabIndex(element, event) == tabIndex)
609 return &element;
610 }
611 return nullptr;
612}
613
614static Element* nextElementWithGreaterTabIndex(const FocusNavigationScope& scope, int tabIndex, KeyboardEvent* event)
615{
616 // Search is inclusive of start
617 int winningTabIndex = std::numeric_limits<int>::max();
618 Element* winner = nullptr;
619 for (Node* node = scope.firstNodeInScope(); node; node = scope.nextInScope(node)) {
620 if (!is<Element>(*node))
621 continue;
622 Element& candidate = downcast<Element>(*node);
623 int candidateTabIndex = candidate.tabIndex();
624 if (isFocusableElementOrScopeOwner(candidate, event) && candidateTabIndex > tabIndex && (!winner || candidateTabIndex < winningTabIndex)) {
625 winner = &candidate;
626 winningTabIndex = candidateTabIndex;
627 }
628 }
629
630 return winner;
631}
632
633static Element* previousElementWithLowerTabIndex(const FocusNavigationScope& scope, Node* start, int tabIndex, KeyboardEvent* event)
634{
635 // Search is inclusive of start
636 int winningTabIndex = 0;
637 Element* winner = nullptr;
638 for (Node* node = start; node; node = scope.previousInScope(node)) {
639 if (!is<Element>(*node))
640 continue;
641 Element& element = downcast<Element>(*node);
642 int currentTabIndex = shadowAdjustedTabIndex(element, event);
643 if (isFocusableElementOrScopeOwner(element, event) && currentTabIndex < tabIndex && currentTabIndex > winningTabIndex) {
644 winner = &element;
645 winningTabIndex = currentTabIndex;
646 }
647 }
648 return winner;
649}
650
651Element* FocusController::nextFocusableElement(Node& start)
652{
653 // FIXME: This can return a non-focusable shadow host.
654 // FIXME: This can't give the correct answer that takes modifier keys into account since it doesn't pass an event.
655 return nextFocusableElementOrScopeOwner(FocusNavigationScope::scopeOf(start), &start, nullptr);
656}
657
658Element* FocusController::previousFocusableElement(Node& start)
659{
660 // FIXME: This can return a non-focusable shadow host.
661 // FIXME: This can't give the correct answer that takes modifier keys into account since it doesn't pass an event.
662 return previousFocusableElementOrScopeOwner(FocusNavigationScope::scopeOf(start), &start, nullptr);
663}
664
665Element* FocusController::nextFocusableElementOrScopeOwner(const FocusNavigationScope& scope, Node* start, KeyboardEvent* event)
666{
667 int startTabIndex = 0;
668 if (start && is<Element>(*start))
669 startTabIndex = shadowAdjustedTabIndex(downcast<Element>(*start), event);
670
671 if (start) {
672 // If a node is excluded from the normal tabbing cycle, the next focusable node is determined by tree order
673 if (startTabIndex < 0) {
674 for (Node* node = scope.nextInScope(start); node; node = scope.nextInScope(node)) {
675 if (!is<Element>(*node))
676 continue;
677 Element& element = downcast<Element>(*node);
678 if (isFocusableElementOrScopeOwner(element, event) && shadowAdjustedTabIndex(element, event) >= 0)
679 return &element;
680 }
681 }
682
683 // First try to find a node with the same tabindex as start that comes after start in the scope.
684 if (Element* winner = findElementWithExactTabIndex(scope, scope.nextInScope(start), startTabIndex, event, FocusDirectionForward))
685 return winner;
686
687 if (!startTabIndex)
688 return nullptr; // We've reached the last node in the document with a tabindex of 0. This is the end of the tabbing order.
689 }
690
691 // Look for the first Element in the scope that:
692 // 1) has the lowest tabindex that is higher than start's tabindex (or 0, if start is null), and
693 // 2) comes first in the scope, if there's a tie.
694 if (Element* winner = nextElementWithGreaterTabIndex(scope, startTabIndex, event))
695 return winner;
696
697 // There are no nodes with a tabindex greater than start's tabindex,
698 // so find the first node with a tabindex of 0.
699 return findElementWithExactTabIndex(scope, scope.firstNodeInScope(), 0, event, FocusDirectionForward);
700}
701
702Element* FocusController::previousFocusableElementOrScopeOwner(const FocusNavigationScope& scope, Node* start, KeyboardEvent* event)
703{
704 Node* last = nullptr;
705 for (Node* node = scope.lastNodeInScope(); node; node = scope.lastChildInScope(*node))
706 last = node;
707 ASSERT(last);
708
709 // First try to find the last node in the scope that comes before start and has the same tabindex as start.
710 // If start is null, find the last node in the scope with a tabindex of 0.
711 Node* startingNode;
712 int startingTabIndex = 0;
713 if (start) {
714 startingNode = scope.previousInScope(start);
715 if (is<Element>(*start))
716 startingTabIndex = shadowAdjustedTabIndex(downcast<Element>(*start), event);
717 } else
718 startingNode = last;
719
720 // However, if a node is excluded from the normal tabbing cycle, the previous focusable node is determined by tree order
721 if (startingTabIndex < 0) {
722 for (Node* node = startingNode; node; node = scope.previousInScope(node)) {
723 if (!is<Element>(*node))
724 continue;
725 Element& element = downcast<Element>(*node);
726 if (isFocusableElementOrScopeOwner(element, event) && shadowAdjustedTabIndex(element, event) >= 0)
727 return &element;
728 }
729 }
730
731 if (Element* winner = findElementWithExactTabIndex(scope, startingNode, startingTabIndex, event, FocusDirectionBackward))
732 return winner;
733
734 // There are no nodes before start with the same tabindex as start, so look for a node that:
735 // 1) has the highest non-zero tabindex (that is less than start's tabindex), and
736 // 2) comes last in the scope, if there's a tie.
737 startingTabIndex = (start && startingTabIndex) ? startingTabIndex : std::numeric_limits<int>::max();
738 return previousElementWithLowerTabIndex(scope, last, startingTabIndex, event);
739}
740
741static bool relinquishesEditingFocus(Node *node)
742{
743 ASSERT(node);
744 ASSERT(node->hasEditableStyle());
745
746 Node* root = node->rootEditableElement();
747 Frame* frame = node->document().frame();
748 if (!frame || !root)
749 return false;
750
751 return frame->editor().shouldEndEditing(rangeOfContents(*root).ptr());
752}
753
754static void clearSelectionIfNeeded(Frame* oldFocusedFrame, Frame* newFocusedFrame, Node* newFocusedNode)
755{
756 if (!oldFocusedFrame || !newFocusedFrame)
757 return;
758
759 if (oldFocusedFrame->document() != newFocusedFrame->document())
760 return;
761
762 const VisibleSelection& selection = oldFocusedFrame->selection().selection();
763 if (selection.isNone())
764 return;
765
766 bool caretBrowsing = oldFocusedFrame->settings().caretBrowsingEnabled();
767 if (caretBrowsing)
768 return;
769
770 if (newFocusedNode) {
771 Node* selectionStartNode = selection.start().deprecatedNode();
772 if (newFocusedNode->contains(selectionStartNode) || selectionStartNode->shadowHost() == newFocusedNode)
773 return;
774 }
775
776 if (Node* mousePressNode = newFocusedFrame->eventHandler().mousePressNode()) {
777 if (!mousePressNode->canStartSelection()) {
778 // Don't clear the selection for contentEditable elements, but do clear it for input and textarea. See bug 38696.
779 auto* root = selection.rootEditableElement();
780 if (!root)
781 return;
782 auto* host = root->shadowHost();
783 // FIXME: Seems likely we can just do the check on "host" here instead of "rootOrHost".
784 auto* rootOrHost = host ? host : root;
785 if (!is<HTMLInputElement>(*rootOrHost) && !is<HTMLTextAreaElement>(*rootOrHost))
786 return;
787 }
788 }
789
790 oldFocusedFrame->selection().clear();
791}
792
793static bool shouldClearSelectionWhenChangingFocusedElement(const Page& page, RefPtr<Element> oldFocusedElement, RefPtr<Element> newFocusedElement)
794{
795#if ENABLE(DATA_INTERACTION)
796 if (newFocusedElement || !oldFocusedElement)
797 return true;
798
799 // FIXME: These additional checks should not be necessary. We should consider generally keeping the selection whenever the
800 // focused element is blurred, with no new element taking focus.
801 if (!oldFocusedElement->isRootEditableElement() && !is<HTMLInputElement>(oldFocusedElement) && !is<HTMLTextAreaElement>(oldFocusedElement))
802 return true;
803
804 for (auto ancestor = page.mainFrame().eventHandler().draggedElement(); ancestor; ancestor = ancestor->parentOrShadowHostElement()) {
805 if (ancestor == oldFocusedElement)
806 return false;
807 }
808#else
809 UNUSED_PARAM(page);
810 UNUSED_PARAM(oldFocusedElement);
811 UNUSED_PARAM(newFocusedElement);
812#endif
813 return true;
814}
815
816bool FocusController::setFocusedElement(Element* element, Frame& newFocusedFrame, FocusDirection direction)
817{
818 Ref<Frame> protectedNewFocusedFrame = newFocusedFrame;
819 RefPtr<Frame> oldFocusedFrame = focusedFrame();
820 RefPtr<Document> oldDocument = oldFocusedFrame ? oldFocusedFrame->document() : nullptr;
821
822 Element* oldFocusedElement = oldDocument ? oldDocument->focusedElement() : nullptr;
823 if (oldFocusedElement == element)
824 return true;
825
826 // FIXME: Might want to disable this check for caretBrowsing
827 if (oldFocusedElement && oldFocusedElement->isRootEditableElement() && !relinquishesEditingFocus(oldFocusedElement))
828 return false;
829
830 m_page.editorClient().willSetInputMethodState();
831
832 if (shouldClearSelectionWhenChangingFocusedElement(m_page, oldFocusedElement, element))
833 clearSelectionIfNeeded(oldFocusedFrame.get(), &newFocusedFrame, element);
834
835 if (!element) {
836 if (oldDocument)
837 oldDocument->setFocusedElement(nullptr);
838 m_page.editorClient().setInputMethodState(false);
839 return true;
840 }
841
842 Ref<Document> newDocument(element->document());
843
844 if (newDocument->focusedElement() == element) {
845 m_page.editorClient().setInputMethodState(element->shouldUseInputMethod());
846 return true;
847 }
848
849 if (oldDocument && oldDocument != newDocument.ptr())
850 oldDocument->setFocusedElement(nullptr);
851
852 if (!newFocusedFrame.page()) {
853 setFocusedFrame(nullptr);
854 return false;
855 }
856 setFocusedFrame(&newFocusedFrame);
857
858 Ref<Element> protect(*element);
859
860 bool successfullyFocused = newDocument->setFocusedElement(element, direction);
861 if (!successfullyFocused)
862 return false;
863
864 if (newDocument->focusedElement() == element)
865 m_page.editorClient().setInputMethodState(element->shouldUseInputMethod());
866
867 m_focusSetTime = MonotonicTime::now();
868 m_focusRepaintTimer.stop();
869
870 return true;
871}
872
873void FocusController::setActivityState(OptionSet<ActivityState::Flag> activityState)
874{
875 auto changed = m_activityState ^ activityState;
876 m_activityState = activityState;
877
878 if (changed & ActivityState::IsFocused)
879 setFocusedInternal(activityState.contains(ActivityState::IsFocused));
880 if (changed & ActivityState::WindowIsActive) {
881 setActiveInternal(activityState.contains(ActivityState::WindowIsActive));
882 if (changed & ActivityState::IsVisible)
883 setIsVisibleAndActiveInternal(activityState.contains(ActivityState::WindowIsActive));
884 }
885}
886
887void FocusController::setActive(bool active)
888{
889 m_page.setActivityState(active ? m_activityState | ActivityState::WindowIsActive : m_activityState - ActivityState::WindowIsActive);
890}
891
892void FocusController::setActiveInternal(bool active)
893{
894 if (FrameView* view = m_page.mainFrame().view()) {
895 if (!view->platformWidget()) {
896 view->updateLayoutAndStyleIfNeededRecursive();
897 view->updateControlTints();
898 }
899 }
900
901 focusedOrMainFrame().selection().pageActivationChanged();
902
903 if (m_focusedFrame && isFocused())
904 dispatchEventsOnWindowAndFocusedElement(m_focusedFrame->document(), active);
905}
906
907static void contentAreaDidShowOrHide(ScrollableArea* scrollableArea, bool didShow)
908{
909 if (didShow)
910 scrollableArea->contentAreaDidShow();
911 else
912 scrollableArea->contentAreaDidHide();
913}
914
915void FocusController::setIsVisibleAndActiveInternal(bool contentIsVisible)
916{
917 FrameView* view = m_page.mainFrame().view();
918 if (!view)
919 return;
920
921 contentAreaDidShowOrHide(view, contentIsVisible);
922
923 for (Frame* frame = &m_page.mainFrame(); frame; frame = frame->tree().traverseNext()) {
924 FrameView* frameView = frame->view();
925 if (!frameView)
926 continue;
927
928 const HashSet<ScrollableArea*>* scrollableAreas = frameView->scrollableAreas();
929 if (!scrollableAreas)
930 continue;
931
932 for (auto& scrollableArea : *scrollableAreas) {
933 ASSERT(scrollableArea->scrollbarsCanBeActive() || m_page.shouldSuppressScrollbarAnimations());
934
935 contentAreaDidShowOrHide(scrollableArea, contentIsVisible);
936 }
937 }
938}
939
940static void updateFocusCandidateIfNeeded(FocusDirection direction, const FocusCandidate& current, FocusCandidate& candidate, FocusCandidate& closest)
941{
942 ASSERT(candidate.visibleNode->isElementNode());
943 ASSERT(candidate.visibleNode->renderer());
944
945 // Ignore iframes that don't have a src attribute
946 if (frameOwnerElement(candidate) && (!frameOwnerElement(candidate)->contentFrame() || candidate.rect.isEmpty()))
947 return;
948
949 // Ignore off screen child nodes of containers that do not scroll (overflow:hidden)
950 if (candidate.isOffscreen && !canBeScrolledIntoView(direction, candidate))
951 return;
952
953 distanceDataForNode(direction, current, candidate);
954 if (candidate.distance == maxDistance())
955 return;
956
957 if (candidate.isOffscreenAfterScrolling && candidate.alignment < Full)
958 return;
959
960 if (closest.isNull()) {
961 closest = candidate;
962 return;
963 }
964
965 LayoutRect intersectionRect = intersection(candidate.rect, closest.rect);
966 if (!intersectionRect.isEmpty() && !areElementsOnSameLine(closest, candidate)) {
967 // If 2 nodes are intersecting, do hit test to find which node in on top.
968 LayoutUnit x = intersectionRect.x() + intersectionRect.width() / 2;
969 LayoutUnit y = intersectionRect.y() + intersectionRect.height() / 2;
970 HitTestResult result = candidate.visibleNode->document().page()->mainFrame().eventHandler().hitTestResultAtPoint(IntPoint(x, y), HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::IgnoreClipping | HitTestRequest::DisallowUserAgentShadowContent);
971 if (candidate.visibleNode->contains(result.innerNode())) {
972 closest = candidate;
973 return;
974 }
975 if (closest.visibleNode->contains(result.innerNode()))
976 return;
977 }
978
979 if (candidate.alignment == closest.alignment) {
980 if (candidate.distance < closest.distance)
981 closest = candidate;
982 return;
983 }
984
985 if (candidate.alignment > closest.alignment)
986 closest = candidate;
987}
988
989void FocusController::findFocusCandidateInContainer(Node& container, const LayoutRect& startingRect, FocusDirection direction, KeyboardEvent* event, FocusCandidate& closest)
990{
991 Node* focusedNode = (focusedFrame() && focusedFrame()->document()) ? focusedFrame()->document()->focusedElement() : 0;
992
993 Element* element = ElementTraversal::firstWithin(container);
994 FocusCandidate current;
995 current.rect = startingRect;
996 current.focusableNode = focusedNode;
997 current.visibleNode = focusedNode;
998
999 unsigned candidateCount = 0;
1000 for (; element; element = (element->isFrameOwnerElement() || canScrollInDirection(element, direction))
1001 ? ElementTraversal::nextSkippingChildren(*element, &container)
1002 : ElementTraversal::next(*element, &container)) {
1003 if (element == focusedNode)
1004 continue;
1005
1006 if (!element->isKeyboardFocusable(event) && !element->isFrameOwnerElement() && !canScrollInDirection(element, direction))
1007 continue;
1008
1009 FocusCandidate candidate = FocusCandidate(element, direction);
1010 if (candidate.isNull())
1011 continue;
1012
1013 if (!isValidCandidate(direction, current, candidate))
1014 continue;
1015
1016 candidateCount++;
1017 candidate.enclosingScrollableBox = &container;
1018 updateFocusCandidateIfNeeded(direction, current, candidate, closest);
1019 }
1020
1021 // The variable 'candidateCount' keeps track of the number of nodes traversed in a given container.
1022 // If we have more than one container in a page then the total number of nodes traversed is equal to the sum of nodes traversed in each container.
1023 if (focusedFrame() && focusedFrame()->document()) {
1024 candidateCount += focusedFrame()->document()->page()->lastSpatialNavigationCandidateCount();
1025 focusedFrame()->document()->page()->setLastSpatialNavigationCandidateCount(candidateCount);
1026 }
1027}
1028
1029bool FocusController::advanceFocusDirectionallyInContainer(Node* container, const LayoutRect& startingRect, FocusDirection direction, KeyboardEvent* event)
1030{
1031 if (!container)
1032 return false;
1033
1034 LayoutRect newStartingRect = startingRect;
1035
1036 if (startingRect.isEmpty())
1037 newStartingRect = virtualRectForDirection(direction, nodeRectInAbsoluteCoordinates(container));
1038
1039 // Find the closest node within current container in the direction of the navigation.
1040 FocusCandidate focusCandidate;
1041 findFocusCandidateInContainer(*container, newStartingRect, direction, event, focusCandidate);
1042
1043 if (focusCandidate.isNull()) {
1044 // Nothing to focus, scroll if possible.
1045 // NOTE: If no scrolling is performed (i.e. scrollInDirection returns false), the
1046 // spatial navigation algorithm will skip this container.
1047 return scrollInDirection(container, direction);
1048 }
1049
1050 if (HTMLFrameOwnerElement* frameElement = frameOwnerElement(focusCandidate)) {
1051 // If we have an iframe without the src attribute, it will not have a contentFrame().
1052 // We ASSERT here to make sure that
1053 // updateFocusCandidateIfNeeded() will never consider such an iframe as a candidate.
1054 ASSERT(frameElement->contentFrame());
1055
1056 if (focusCandidate.isOffscreenAfterScrolling) {
1057 scrollInDirection(&focusCandidate.visibleNode->document(), direction);
1058 return true;
1059 }
1060 // Navigate into a new frame.
1061 LayoutRect rect;
1062 Element* focusedElement = focusedOrMainFrame().document()->focusedElement();
1063 if (focusedElement && !hasOffscreenRect(focusedElement))
1064 rect = nodeRectInAbsoluteCoordinates(focusedElement, true /* ignore border */);
1065 frameElement->contentFrame()->document()->updateLayoutIgnorePendingStylesheets();
1066 if (!advanceFocusDirectionallyInContainer(frameElement->contentFrame()->document(), rect, direction, event)) {
1067 // The new frame had nothing interesting, need to find another candidate.
1068 return advanceFocusDirectionallyInContainer(container, nodeRectInAbsoluteCoordinates(focusCandidate.visibleNode, true), direction, event);
1069 }
1070 return true;
1071 }
1072
1073 if (canScrollInDirection(focusCandidate.visibleNode, direction)) {
1074 if (focusCandidate.isOffscreenAfterScrolling) {
1075 scrollInDirection(focusCandidate.visibleNode, direction);
1076 return true;
1077 }
1078 // Navigate into a new scrollable container.
1079 LayoutRect startingRect;
1080 Element* focusedElement = focusedOrMainFrame().document()->focusedElement();
1081 if (focusedElement && !hasOffscreenRect(focusedElement))
1082 startingRect = nodeRectInAbsoluteCoordinates(focusedElement, true);
1083 return advanceFocusDirectionallyInContainer(focusCandidate.visibleNode, startingRect, direction, event);
1084 }
1085 if (focusCandidate.isOffscreenAfterScrolling) {
1086 Node* container = focusCandidate.enclosingScrollableBox;
1087 scrollInDirection(container, direction);
1088 return true;
1089 }
1090
1091 // We found a new focus node, navigate to it.
1092 Element* element = downcast<Element>(focusCandidate.focusableNode);
1093 ASSERT(element);
1094
1095 element->focus(false, direction);
1096 return true;
1097}
1098
1099bool FocusController::advanceFocusDirectionally(FocusDirection direction, KeyboardEvent* event)
1100{
1101 Document* focusedDocument = focusedOrMainFrame().document();
1102 if (!focusedDocument)
1103 return false;
1104
1105 focusedDocument->updateLayoutIgnorePendingStylesheets();
1106
1107 // Figure out the starting rect.
1108 Node* container = focusedDocument;
1109 LayoutRect startingRect;
1110 if (auto* focusedElement = focusedDocument->focusedElement()) {
1111 if (!hasOffscreenRect(focusedElement)) {
1112 container = scrollableEnclosingBoxOrParentFrameForNodeInDirection(direction, focusedElement);
1113 startingRect = nodeRectInAbsoluteCoordinates(focusedElement, true /* ignore border */);
1114 } else if (is<HTMLAreaElement>(*focusedElement)) {
1115 HTMLAreaElement& area = downcast<HTMLAreaElement>(*focusedElement);
1116 container = scrollableEnclosingBoxOrParentFrameForNodeInDirection(direction, area.imageElement());
1117 startingRect = virtualRectForAreaElementAndDirection(&area, direction);
1118 }
1119 }
1120
1121 if (focusedFrame() && focusedFrame()->document())
1122 focusedDocument->page()->setLastSpatialNavigationCandidateCount(0);
1123
1124 bool consumed = false;
1125 do {
1126 consumed = advanceFocusDirectionallyInContainer(container, startingRect, direction, event);
1127 focusedDocument->updateLayoutIgnorePendingStylesheets();
1128 startingRect = nodeRectInAbsoluteCoordinates(container, true /* ignore border */);
1129 container = scrollableEnclosingBoxOrParentFrameForNodeInDirection(direction, container);
1130 } while (!consumed && container);
1131
1132 return consumed;
1133}
1134
1135void FocusController::setFocusedElementNeedsRepaint()
1136{
1137 m_focusRepaintTimer.startOneShot(33_ms);
1138}
1139
1140void FocusController::focusRepaintTimerFired()
1141{
1142 Document* focusedDocument = focusedOrMainFrame().document();
1143 if (!focusedDocument)
1144 return;
1145
1146 Element* focusedElement = focusedDocument->focusedElement();
1147 if (!focusedElement)
1148 return;
1149
1150 if (focusedElement->renderer())
1151 focusedElement->renderer()->repaint();
1152}
1153
1154Seconds FocusController::timeSinceFocusWasSet() const
1155{
1156 return MonotonicTime::now() - m_focusSetTime;
1157}
1158
1159} // namespace WebCore
1160