1 /* 2 * Copyright (C) 2006, 2007 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 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. 25 */ 26 27 #include "config.h" 28 #include "core/page/FocusController.h" 29 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/LocalDOMWindow.h" 44 #include "core/frame/FrameView.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" 60 #include <limits> 61 62 namespace WebCore { 63 64 using namespace HTMLNames; 65 66 static inline bool isShadowInsertionPointFocusScopeOwner(Node& node) 67 { 68 return isActiveShadowInsertionPoint(node) && toHTMLShadowElement(node).olderShadowRoot(); 69 } 70 71 // FIXME: Some of Node* return values and Node* arguments should be Element*. 72 73 FocusNavigationScope::FocusNavigationScope(TreeScope* treeScope) 74 : m_rootTreeScope(treeScope) 75 { 76 ASSERT(treeScope); 77 } 78 79 Node* FocusNavigationScope::rootNode() const 80 { 81 return &m_rootTreeScope->rootNode(); 82 } 83 84 Element* FocusNavigationScope::owner() const 85 { 86 Node* root = rootNode(); 87 if (root->isShadowRoot()) { 88 ShadowRoot* shadowRoot = toShadowRoot(root); 89 return shadowRoot->isYoungest() ? shadowRoot->host() : shadowRoot->shadowInsertionPointOfYoungerShadowRoot(); 90 } 91 // FIXME: Figure out the right thing for OOPI here. 92 if (Frame* frame = root->document().frame()) 93 return frame->deprecatedLocalOwner(); 94 return 0; 95 } 96 97 FocusNavigationScope FocusNavigationScope::focusNavigationScopeOf(Node* node) 98 { 99 ASSERT(node); 100 Node* root = node; 101 for (Node* n = node; n; n = n->parentNode()) 102 root = n; 103 // The result is not always a ShadowRoot nor a DocumentNode since 104 // a starting node is in an orphaned tree in composed shadow tree. 105 return FocusNavigationScope(&root->treeScope()); 106 } 107 108 FocusNavigationScope FocusNavigationScope::ownedByNonFocusableFocusScopeOwner(Node* node) 109 { 110 ASSERT(node); 111 if (isShadowHost(node)) 112 return FocusNavigationScope::ownedByShadowHost(node); 113 ASSERT(isShadowInsertionPointFocusScopeOwner(*node)); 114 return FocusNavigationScope::ownedByShadowInsertionPoint(toHTMLShadowElement(node)); 115 } 116 117 FocusNavigationScope FocusNavigationScope::ownedByShadowHost(Node* node) 118 { 119 ASSERT(isShadowHost(node)); 120 return FocusNavigationScope(toElement(node)->shadow()->youngestShadowRoot()); 121 } 122 123 FocusNavigationScope FocusNavigationScope::ownedByIFrame(HTMLFrameOwnerElement* frame) 124 { 125 ASSERT(frame && frame->contentFrame() && frame->contentFrame()->isLocalFrame()); 126 return FocusNavigationScope(toLocalFrame(frame->contentFrame())->document()); 127 } 128 129 FocusNavigationScope FocusNavigationScope::ownedByShadowInsertionPoint(HTMLShadowElement* shadowInsertionPoint) 130 { 131 ASSERT(isShadowInsertionPointFocusScopeOwner(*shadowInsertionPoint)); 132 return FocusNavigationScope(shadowInsertionPoint->olderShadowRoot()); 133 } 134 135 static inline void dispatchEventsOnWindowAndFocusedNode(Document* document, bool focused) 136 { 137 // If we have a focused node we should dispatch blur on it before we blur the window. 138 // If we have a focused node we should dispatch focus on it after we focus the window. 139 // https://bugs.webkit.org/show_bug.cgi?id=27105 140 141 // Do not fire events while modal dialogs are up. See https://bugs.webkit.org/show_bug.cgi?id=33962 142 if (Page* page = document->page()) { 143 if (page->defersLoading()) 144 return; 145 } 146 147 if (!focused && document->focusedElement()) { 148 RefPtrWillBeRawPtr<Element> focusedElement(document->focusedElement()); 149 focusedElement->setFocus(false); 150 focusedElement->dispatchBlurEvent(0); 151 if (focusedElement == document->focusedElement()) { 152 focusedElement->dispatchFocusOutEvent(EventTypeNames::focusout, 0); 153 if (focusedElement == document->focusedElement()) 154 focusedElement->dispatchFocusOutEvent(EventTypeNames::DOMFocusOut, 0); 155 } 156 } 157 158 if (LocalDOMWindow* window = document->domWindow()) 159 window->dispatchEvent(Event::create(focused ? EventTypeNames::focus : EventTypeNames::blur)); 160 if (focused && document->focusedElement()) { 161 RefPtrWillBeRawPtr<Element> focusedElement(document->focusedElement()); 162 focusedElement->setFocus(true); 163 focusedElement->dispatchFocusEvent(0, FocusTypePage); 164 if (focusedElement == document->focusedElement()) { 165 document->focusedElement()->dispatchFocusInEvent(EventTypeNames::focusin, 0); 166 if (focusedElement == document->focusedElement()) 167 document->focusedElement()->dispatchFocusInEvent(EventTypeNames::DOMFocusIn, 0); 168 } 169 } 170 } 171 172 static inline bool hasCustomFocusLogic(Element* element) 173 { 174 return element->isHTMLElement() && toHTMLElement(element)->hasCustomFocusLogic(); 175 } 176 177 #if ASSERT_ENABLED 178 static inline bool isNonFocusableShadowHost(Node* node) 179 { 180 ASSERT(node); 181 if (!node->isElementNode()) 182 return false; 183 Element* element = toElement(node); 184 return !element->isFocusable() && isShadowHost(element) && !hasCustomFocusLogic(element); 185 } 186 #endif 187 188 static inline bool isNonKeyboardFocusableShadowHost(Node* node) 189 { 190 ASSERT(node); 191 if (!node->isElementNode()) 192 return false; 193 Element* element = toElement(node); 194 return !element->isKeyboardFocusable() && isShadowHost(element) && !hasCustomFocusLogic(element); 195 } 196 197 static inline bool isKeyboardFocusableShadowHost(Node* node) 198 { 199 ASSERT(node); 200 if (!node->isElementNode()) 201 return false; 202 Element* element = toElement(node); 203 return element->isKeyboardFocusable() && isShadowHost(element) && !hasCustomFocusLogic(element); 204 } 205 206 static inline bool isNonFocusableFocusScopeOwner(Node* node) 207 { 208 ASSERT(node); 209 return isNonKeyboardFocusableShadowHost(node) || isShadowInsertionPointFocusScopeOwner(*node); 210 } 211 212 static inline int adjustedTabIndex(Node* node) 213 { 214 ASSERT(node); 215 return isNonFocusableFocusScopeOwner(node) ? 0 : node->tabIndex(); 216 } 217 218 static inline bool shouldVisit(Node* node) 219 { 220 ASSERT(node); 221 return (node->isElementNode() && toElement(node)->isKeyboardFocusable()) || isNonFocusableFocusScopeOwner(node); 222 } 223 224 FocusController::FocusController(Page* page) 225 : m_page(page) 226 , m_isActive(false) 227 , m_isFocused(false) 228 , m_isChangingFocusedFrame(false) 229 { 230 } 231 232 PassOwnPtr<FocusController> FocusController::create(Page* page) 233 { 234 return adoptPtr(new FocusController(page)); 235 } 236 237 void FocusController::setFocusedFrame(PassRefPtr<Frame> frame) 238 { 239 ASSERT(!frame || frame->page() == m_page); 240 if (m_focusedFrame == frame || m_isChangingFocusedFrame) 241 return; 242 243 m_isChangingFocusedFrame = true; 244 245 RefPtr<LocalFrame> oldFrame = (m_focusedFrame && m_focusedFrame->isLocalFrame()) ? toLocalFrame(m_focusedFrame.get()) : 0; 246 RefPtr<LocalFrame> newFrame = (frame && frame->isLocalFrame()) ? toLocalFrame(frame.get()) : 0; 247 248 m_focusedFrame = frame.get(); 249 250 // Now that the frame is updated, fire events and update the selection focused states of both frames. 251 if (oldFrame && oldFrame->view()) { 252 oldFrame->selection().setFocused(false); 253 oldFrame->domWindow()->dispatchEvent(Event::create(EventTypeNames::blur)); 254 } 255 256 if (newFrame && newFrame->view() && isFocused()) { 257 newFrame->selection().setFocused(true); 258 newFrame->domWindow()->dispatchEvent(Event::create(EventTypeNames::focus)); 259 } 260 261 m_isChangingFocusedFrame = false; 262 263 m_page->chrome().client().focusedFrameChanged(newFrame.get()); 264 } 265 266 void FocusController::focusDocumentView(PassRefPtr<Frame> frame) 267 { 268 ASSERT(!frame || frame->page() == m_page); 269 if (m_focusedFrame == frame) 270 return; 271 272 RefPtr<LocalFrame> focusedFrame = (m_focusedFrame && m_focusedFrame->isLocalFrame()) ? toLocalFrame(m_focusedFrame.get()) : 0; 273 if (focusedFrame && focusedFrame->view()) { 274 RefPtrWillBeRawPtr<Document> document = focusedFrame->document(); 275 Element* focusedElement = document ? document->focusedElement() : 0; 276 if (focusedElement) { 277 focusedElement->dispatchBlurEvent(0); 278 if (focusedElement == document->focusedElement()) { 279 focusedElement->dispatchFocusOutEvent(EventTypeNames::focusout, 0); 280 if (focusedElement == document->focusedElement()) 281 focusedElement->dispatchFocusOutEvent(EventTypeNames::DOMFocusOut, 0); 282 } 283 } 284 } 285 286 RefPtr<LocalFrame> newFocusedFrame = (frame && frame->isLocalFrame()) ? toLocalFrame(frame.get()) : 0; 287 if (newFocusedFrame && newFocusedFrame->view()) { 288 RefPtrWillBeRawPtr<Document> document = newFocusedFrame->document(); 289 Element* focusedElement = document ? document->focusedElement() : 0; 290 if (focusedElement) { 291 focusedElement->dispatchFocusEvent(0, FocusTypePage); 292 if (focusedElement == document->focusedElement()) { 293 document->focusedElement()->dispatchFocusInEvent(EventTypeNames::focusin, 0); 294 if (focusedElement == document->focusedElement()) 295 document->focusedElement()->dispatchFocusInEvent(EventTypeNames::DOMFocusIn, 0); 296 } 297 } 298 } 299 300 setFocusedFrame(frame); 301 } 302 303 Frame* FocusController::focusedOrMainFrame() const 304 { 305 if (Frame* frame = focusedFrame()) 306 return frame; 307 return m_page->mainFrame(); 308 } 309 310 void FocusController::setFocused(bool focused) 311 { 312 if (isFocused() == focused) 313 return; 314 315 m_isFocused = focused; 316 317 if (!m_isFocused && focusedOrMainFrame()->isLocalFrame()) 318 toLocalFrame(focusedOrMainFrame())->eventHandler().stopAutoscroll(); 319 320 if (!m_focusedFrame) 321 setFocusedFrame(m_page->mainFrame()); 322 323 // setFocusedFrame above might reject to update m_focusedFrame, or 324 // m_focusedFrame might be changed by blur/focus event handlers. 325 if (m_focusedFrame && m_focusedFrame->isLocalFrame() && toLocalFrame(m_focusedFrame.get())->view()) { 326 toLocalFrame(m_focusedFrame.get())->selection().setFocused(focused); 327 dispatchEventsOnWindowAndFocusedNode(toLocalFrame(m_focusedFrame.get())->document(), focused); 328 } 329 } 330 331 Node* FocusController::findFocusableNodeDecendingDownIntoFrameDocument(FocusType type, Node* node) 332 { 333 // The node we found might be a HTMLFrameOwnerElement, so descend down the tree until we find either: 334 // 1) a focusable node, or 335 // 2) the deepest-nested HTMLFrameOwnerElement. 336 while (node && node->isFrameOwnerElement()) { 337 HTMLFrameOwnerElement* owner = toHTMLFrameOwnerElement(node); 338 if (!owner->contentFrame() || !owner->contentFrame()->isLocalFrame()) 339 break; 340 Node* foundNode = findFocusableNode(type, FocusNavigationScope::ownedByIFrame(owner), 0); 341 if (!foundNode) 342 break; 343 ASSERT(node != foundNode); 344 node = foundNode; 345 } 346 return node; 347 } 348 349 bool FocusController::setInitialFocus(FocusType type) 350 { 351 bool didAdvanceFocus = advanceFocus(type, true); 352 353 // If focus is being set initially, accessibility needs to be informed that system focus has moved 354 // into the web area again, even if focus did not change within WebCore. PostNotification is called instead 355 // of handleFocusedUIElementChanged, because this will send the notification even if the element is the same. 356 if (focusedOrMainFrame()->isLocalFrame()) { 357 Document* document = toLocalFrame(focusedOrMainFrame())->document(); 358 if (AXObjectCache* cache = document->existingAXObjectCache()) 359 cache->postNotification(document, AXObjectCache::AXFocusedUIElementChanged, true); 360 } 361 362 return didAdvanceFocus; 363 } 364 365 bool FocusController::advanceFocus(FocusType type, bool initialFocus) 366 { 367 switch (type) { 368 case FocusTypeForward: 369 case FocusTypeBackward: 370 return advanceFocusInDocumentOrder(type, initialFocus); 371 case FocusTypeLeft: 372 case FocusTypeRight: 373 case FocusTypeUp: 374 case FocusTypeDown: 375 return advanceFocusDirectionally(type); 376 default: 377 ASSERT_NOT_REACHED(); 378 } 379 380 return false; 381 } 382 383 bool FocusController::advanceFocusInDocumentOrder(FocusType type, bool initialFocus) 384 { 385 // FIXME: Focus advancement won't work with externally rendered frames until after 386 // inter-frame focus control is moved out of Blink. 387 if (!focusedOrMainFrame()->isLocalFrame()) 388 return false; 389 LocalFrame* frame = toLocalFrame(focusedOrMainFrame()); 390 ASSERT(frame); 391 Document* document = frame->document(); 392 393 Node* currentNode = document->focusedElement(); 394 // FIXME: Not quite correct when it comes to focus transitions leaving/entering the WebView itself 395 bool caretBrowsing = frame->settings() && frame->settings()->caretBrowsingEnabled(); 396 397 if (caretBrowsing && !currentNode) 398 currentNode = frame->selection().start().deprecatedNode(); 399 400 document->updateLayoutIgnorePendingStylesheets(); 401 402 RefPtrWillBeRawPtr<Node> node = findFocusableNodeAcrossFocusScope(type, FocusNavigationScope::focusNavigationScopeOf(currentNode ? currentNode : document), currentNode); 403 404 if (!node) { 405 // We didn't find a node to focus, so we should try to pass focus to Chrome. 406 if (!initialFocus && m_page->chrome().canTakeFocus(type)) { 407 document->setFocusedElement(nullptr); 408 setFocusedFrame(nullptr); 409 m_page->chrome().takeFocus(type); 410 return true; 411 } 412 413 // Chrome doesn't want focus, so we should wrap focus. 414 if (!m_page->mainFrame()->isLocalFrame()) 415 return false; 416 node = findFocusableNodeRecursively(type, FocusNavigationScope::focusNavigationScopeOf(m_page->deprecatedLocalMainFrame()->document()), 0); 417 node = findFocusableNodeDecendingDownIntoFrameDocument(type, node.get()); 418 419 if (!node) 420 return false; 421 } 422 423 ASSERT(node); 424 425 if (node == document->focusedElement()) 426 // Focus wrapped around to the same node. 427 return true; 428 429 if (!node->isElementNode()) 430 // FIXME: May need a way to focus a document here. 431 return false; 432 433 Element* element = toElement(node); 434 if (element->isFrameOwnerElement() && (!isHTMLPlugInElement(*element) || !element->isKeyboardFocusable())) { 435 // We focus frames rather than frame owners. 436 // FIXME: We should not focus frames that have no scrollbars, as focusing them isn't useful to the user. 437 HTMLFrameOwnerElement* owner = toHTMLFrameOwnerElement(element); 438 if (!owner->contentFrame()) 439 return false; 440 441 document->setFocusedElement(nullptr); 442 setFocusedFrame(owner->contentFrame()); 443 return true; 444 } 445 446 // FIXME: It would be nice to just be able to call setFocusedElement(node) 447 // here, but we can't do that because some elements (e.g. HTMLInputElement 448 // and HTMLTextAreaElement) do extra work in their focus() methods. 449 Document& newDocument = element->document(); 450 451 if (&newDocument != document) { 452 // Focus is going away from this document, so clear the focused node. 453 document->setFocusedElement(nullptr); 454 } 455 456 setFocusedFrame(newDocument.frame()); 457 458 if (caretBrowsing) { 459 Position position = firstPositionInOrBeforeNode(element); 460 VisibleSelection newSelection(position, position, DOWNSTREAM); 461 frame->selection().setSelection(newSelection); 462 } 463 464 element->focus(false, type); 465 return true; 466 } 467 468 Node* FocusController::findFocusableNodeAcrossFocusScope(FocusType type, FocusNavigationScope scope, Node* currentNode) 469 { 470 ASSERT(!currentNode || !isNonFocusableShadowHost(currentNode)); 471 Node* found; 472 if (currentNode && type == FocusTypeForward && isKeyboardFocusableShadowHost(currentNode)) { 473 Node* foundInInnerFocusScope = findFocusableNodeRecursively(type, FocusNavigationScope::ownedByShadowHost(currentNode), 0); 474 found = foundInInnerFocusScope ? foundInInnerFocusScope : findFocusableNodeRecursively(type, scope, currentNode); 475 } else { 476 found = findFocusableNodeRecursively(type, scope, currentNode); 477 } 478 479 // If there's no focusable node to advance to, move up the focus scopes until we find one. 480 while (!found) { 481 Node* owner = scope.owner(); 482 if (!owner) 483 break; 484 scope = FocusNavigationScope::focusNavigationScopeOf(owner); 485 if (type == FocusTypeBackward && isKeyboardFocusableShadowHost(owner)) { 486 found = owner; 487 break; 488 } 489 found = findFocusableNodeRecursively(type, scope, owner); 490 } 491 found = findFocusableNodeDecendingDownIntoFrameDocument(type, found); 492 return found; 493 } 494 495 Node* FocusController::findFocusableNodeRecursively(FocusType type, FocusNavigationScope scope, Node* start) 496 { 497 // Starting node is exclusive. 498 Node* found = findFocusableNode(type, scope, start); 499 if (!found) 500 return 0; 501 if (type == FocusTypeForward) { 502 if (!isNonFocusableFocusScopeOwner(found)) 503 return found; 504 Node* foundInInnerFocusScope = findFocusableNodeRecursively(type, FocusNavigationScope::ownedByNonFocusableFocusScopeOwner(found), 0); 505 return foundInInnerFocusScope ? foundInInnerFocusScope : findFocusableNodeRecursively(type, scope, found); 506 } 507 ASSERT(type == FocusTypeBackward); 508 if (isKeyboardFocusableShadowHost(found)) { 509 Node* foundInInnerFocusScope = findFocusableNodeRecursively(type, FocusNavigationScope::ownedByShadowHost(found), 0); 510 return foundInInnerFocusScope ? foundInInnerFocusScope : found; 511 } 512 if (isNonFocusableFocusScopeOwner(found)) { 513 Node* foundInInnerFocusScope = findFocusableNodeRecursively(type, FocusNavigationScope::ownedByNonFocusableFocusScopeOwner(found), 0); 514 return foundInInnerFocusScope ? foundInInnerFocusScope :findFocusableNodeRecursively(type, scope, found); 515 } 516 return found; 517 } 518 519 Node* FocusController::findFocusableNode(FocusType type, FocusNavigationScope scope, Node* node) 520 { 521 return type == FocusTypeForward ? nextFocusableNode(scope, node) : previousFocusableNode(scope, node); 522 } 523 524 Node* FocusController::findNodeWithExactTabIndex(Node* start, int tabIndex, FocusType type) 525 { 526 // Search is inclusive of start 527 for (Node* node = start; node; node = type == FocusTypeForward ? NodeTraversal::next(*node) : NodeTraversal::previous(*node)) { 528 if (shouldVisit(node) && adjustedTabIndex(node) == tabIndex) 529 return node; 530 } 531 return 0; 532 } 533 534 static Node* nextNodeWithGreaterTabIndex(Node* start, int tabIndex) 535 { 536 // Search is inclusive of start 537 int winningTabIndex = std::numeric_limits<short>::max() + 1; 538 Node* winner = 0; 539 for (Node* node = start; node; node = NodeTraversal::next(*node)) { 540 if (shouldVisit(node) && node->tabIndex() > tabIndex && node->tabIndex() < winningTabIndex) { 541 winner = node; 542 winningTabIndex = node->tabIndex(); 543 } 544 } 545 546 return winner; 547 } 548 549 static Node* previousNodeWithLowerTabIndex(Node* start, int tabIndex) 550 { 551 // Search is inclusive of start 552 int winningTabIndex = 0; 553 Node* winner = 0; 554 for (Node* node = start; node; node = NodeTraversal::previous(*node)) { 555 int currentTabIndex = adjustedTabIndex(node); 556 if ((shouldVisit(node) || isNonKeyboardFocusableShadowHost(node)) && currentTabIndex < tabIndex && currentTabIndex > winningTabIndex) { 557 winner = node; 558 winningTabIndex = currentTabIndex; 559 } 560 } 561 return winner; 562 } 563 564 Node* FocusController::nextFocusableNode(FocusNavigationScope scope, Node* start) 565 { 566 if (start) { 567 int tabIndex = adjustedTabIndex(start); 568 // If a node is excluded from the normal tabbing cycle, the next focusable node is determined by tree order 569 if (tabIndex < 0) { 570 for (Node* node = NodeTraversal::next(*start); node; node = NodeTraversal::next(*node)) { 571 if (shouldVisit(node) && adjustedTabIndex(node) >= 0) 572 return node; 573 } 574 } 575 576 // First try to find a node with the same tabindex as start that comes after start in the scope. 577 if (Node* winner = findNodeWithExactTabIndex(NodeTraversal::next(*start), tabIndex, FocusTypeForward)) 578 return winner; 579 580 if (!tabIndex) 581 // We've reached the last node in the document with a tabindex of 0. This is the end of the tabbing order. 582 return 0; 583 } 584 585 // Look for the first node in the scope that: 586 // 1) has the lowest tabindex that is higher than start's tabindex (or 0, if start is null), and 587 // 2) comes first in the scope, if there's a tie. 588 if (Node* winner = nextNodeWithGreaterTabIndex(scope.rootNode(), start ? adjustedTabIndex(start) : 0)) 589 return winner; 590 591 // There are no nodes with a tabindex greater than start's tabindex, 592 // so find the first node with a tabindex of 0. 593 return findNodeWithExactTabIndex(scope.rootNode(), 0, FocusTypeForward); 594 } 595 596 Node* FocusController::previousFocusableNode(FocusNavigationScope scope, Node* start) 597 { 598 Node* last = 0; 599 for (Node* node = scope.rootNode(); node; node = node->lastChild()) 600 last = node; 601 ASSERT(last); 602 603 // First try to find the last node in the scope that comes before start and has the same tabindex as start. 604 // If start is null, find the last node in the scope with a tabindex of 0. 605 Node* startingNode; 606 int startingTabIndex; 607 if (start) { 608 startingNode = NodeTraversal::previous(*start); 609 startingTabIndex = adjustedTabIndex(start); 610 } else { 611 startingNode = last; 612 startingTabIndex = 0; 613 } 614 615 // However, if a node is excluded from the normal tabbing cycle, the previous focusable node is determined by tree order 616 if (startingTabIndex < 0) { 617 for (Node* node = startingNode; node; node = NodeTraversal::previous(*node)) { 618 if (shouldVisit(node) && adjustedTabIndex(node) >= 0) 619 return node; 620 } 621 } 622 623 if (Node* winner = findNodeWithExactTabIndex(startingNode, startingTabIndex, FocusTypeBackward)) 624 return winner; 625 626 // There are no nodes before start with the same tabindex as start, so look for a node that: 627 // 1) has the highest non-zero tabindex (that is less than start's tabindex), and 628 // 2) comes last in the scope, if there's a tie. 629 startingTabIndex = (start && startingTabIndex) ? startingTabIndex : std::numeric_limits<short>::max(); 630 return previousNodeWithLowerTabIndex(last, startingTabIndex); 631 } 632 633 static bool relinquishesEditingFocus(Node *node) 634 { 635 ASSERT(node); 636 ASSERT(node->rendererIsEditable()); 637 return node->document().frame() && node->rootEditableElement(); 638 } 639 640 static void clearSelectionIfNeeded(LocalFrame* oldFocusedFrame, LocalFrame* newFocusedFrame, Node* newFocusedNode) 641 { 642 if (!oldFocusedFrame || !newFocusedFrame) 643 return; 644 645 if (oldFocusedFrame->document() != newFocusedFrame->document()) 646 return; 647 648 FrameSelection& selection = oldFocusedFrame->selection(); 649 if (selection.isNone()) 650 return; 651 652 bool caretBrowsing = oldFocusedFrame->settings()->caretBrowsingEnabled(); 653 if (caretBrowsing) 654 return; 655 656 Node* selectionStartNode = selection.selection().start().deprecatedNode(); 657 if (selectionStartNode == newFocusedNode || selectionStartNode->isDescendantOf(newFocusedNode) || selectionStartNode->deprecatedShadowAncestorNode() == newFocusedNode) 658 return; 659 660 if (Node* mousePressNode = newFocusedFrame->eventHandler().mousePressNode()) { 661 if (mousePressNode->renderer() && !mousePressNode->canStartSelection()) { 662 // Don't clear the selection for contentEditable elements, but do 663 // clear it for input and textarea. See bug 38696. 664 if (!enclosingTextFormControl(selection.start())) 665 return; 666 } 667 } 668 669 selection.clear(); 670 } 671 672 bool FocusController::setFocusedElement(Element* element, PassRefPtr<Frame> newFocusedFrame, FocusType type) 673 { 674 RefPtr<LocalFrame> oldFocusedFrame = toLocalFrame(focusedFrame()); 675 RefPtrWillBeRawPtr<Document> oldDocument = oldFocusedFrame ? oldFocusedFrame->document() : 0; 676 677 Element* oldFocusedElement = oldDocument ? oldDocument->focusedElement() : 0; 678 if (element && oldFocusedElement == element) 679 return true; 680 681 // FIXME: Might want to disable this check for caretBrowsing 682 if (oldFocusedElement && oldFocusedElement->isRootEditableElement() && !relinquishesEditingFocus(oldFocusedElement)) 683 return false; 684 685 m_page->chrome().client().willSetInputMethodState(); 686 687 RefPtrWillBeRawPtr<Document> newDocument = nullptr; 688 if (element) 689 newDocument = &element->document(); 690 else if (newFocusedFrame && newFocusedFrame->isLocalFrame()) 691 newDocument = toLocalFrame(newFocusedFrame.get())->document(); 692 693 if (newDocument && oldDocument == newDocument && newDocument->focusedElement() == element) 694 return true; 695 696 clearSelectionIfNeeded(oldFocusedFrame.get(), toLocalFrame(newFocusedFrame.get()), element); 697 698 if (oldDocument && oldDocument != newDocument) 699 oldDocument->setFocusedElement(nullptr); 700 701 if (newFocusedFrame && !newFocusedFrame->page()) { 702 setFocusedFrame(nullptr); 703 return false; 704 } 705 setFocusedFrame(newFocusedFrame); 706 707 // Setting the focused node can result in losing our last reft to node when JS event handlers fire. 708 RefPtrWillBeRawPtr<Element> protect ALLOW_UNUSED = element; 709 if (newDocument) { 710 bool successfullyFocused = newDocument->setFocusedElement(element, type); 711 if (!successfullyFocused) 712 return false; 713 } 714 715 return true; 716 } 717 718 void FocusController::setActive(bool active) 719 { 720 if (m_isActive == active) 721 return; 722 723 m_isActive = active; 724 725 if (m_page->mainFrame()->isLocalFrame()) { 726 if (FrameView* view = m_page->deprecatedLocalMainFrame()->view()) 727 view->updateControlTints(); 728 } 729 730 toLocalFrame(focusedOrMainFrame())->selection().pageActivationChanged(); 731 } 732 733 static void updateFocusCandidateIfNeeded(FocusType type, const FocusCandidate& current, FocusCandidate& candidate, FocusCandidate& closest) 734 { 735 ASSERT(candidate.visibleNode->isElementNode()); 736 ASSERT(candidate.visibleNode->renderer()); 737 738 // Ignore iframes that don't have a src attribute 739 if (frameOwnerElement(candidate) && (!frameOwnerElement(candidate)->contentFrame() || candidate.rect.isEmpty())) 740 return; 741 742 // Ignore off screen child nodes of containers that do not scroll (overflow:hidden) 743 if (candidate.isOffscreen && !canBeScrolledIntoView(type, candidate)) 744 return; 745 746 distanceDataForNode(type, current, candidate); 747 if (candidate.distance == maxDistance()) 748 return; 749 750 if (candidate.isOffscreenAfterScrolling && candidate.alignment < Full) 751 return; 752 753 if (closest.isNull()) { 754 closest = candidate; 755 return; 756 } 757 758 LayoutRect intersectionRect = intersection(candidate.rect, closest.rect); 759 if (!intersectionRect.isEmpty() && !areElementsOnSameLine(closest, candidate) 760 && intersectionRect == candidate.rect) { 761 // If 2 nodes are intersecting, do hit test to find which node in on top. 762 LayoutUnit x = intersectionRect.x() + intersectionRect.width() / 2; 763 LayoutUnit y = intersectionRect.y() + intersectionRect.height() / 2; 764 if (!candidate.visibleNode->document().page()->mainFrame()->isLocalFrame()) 765 return; 766 HitTestResult result = candidate.visibleNode->document().page()->deprecatedLocalMainFrame()->eventHandler().hitTestResultAtPoint(IntPoint(x, y), HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::IgnoreClipping | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent); 767 if (candidate.visibleNode->contains(result.innerNode())) { 768 closest = candidate; 769 return; 770 } 771 if (closest.visibleNode->contains(result.innerNode())) 772 return; 773 } 774 775 if (candidate.alignment == closest.alignment) { 776 if (candidate.distance < closest.distance) 777 closest = candidate; 778 return; 779 } 780 781 if (candidate.alignment > closest.alignment) 782 closest = candidate; 783 } 784 785 void FocusController::findFocusCandidateInContainer(Node& container, const LayoutRect& startingRect, FocusType type, FocusCandidate& closest) 786 { 787 Element* focusedElement = (focusedFrame() && toLocalFrame(focusedFrame())->document()) ? toLocalFrame(focusedFrame())->document()->focusedElement() : 0; 788 789 Element* element = ElementTraversal::firstWithin(container); 790 FocusCandidate current; 791 current.rect = startingRect; 792 current.focusableNode = focusedElement; 793 current.visibleNode = focusedElement; 794 795 for (; element; element = (element->isFrameOwnerElement() || canScrollInDirection(element, type)) 796 ? ElementTraversal::nextSkippingChildren(*element, &container) 797 : ElementTraversal::next(*element, &container)) { 798 if (element == focusedElement) 799 continue; 800 801 if (!element->isKeyboardFocusable() && !element->isFrameOwnerElement() && !canScrollInDirection(element, type)) 802 continue; 803 804 FocusCandidate candidate = FocusCandidate(element, type); 805 if (candidate.isNull()) 806 continue; 807 808 candidate.enclosingScrollableBox = &container; 809 updateFocusCandidateIfNeeded(type, current, candidate, closest); 810 } 811 } 812 813 bool FocusController::advanceFocusDirectionallyInContainer(Node* container, const LayoutRect& startingRect, FocusType type) 814 { 815 if (!container) 816 return false; 817 818 LayoutRect newStartingRect = startingRect; 819 820 if (startingRect.isEmpty()) 821 newStartingRect = virtualRectForDirection(type, nodeRectInAbsoluteCoordinates(container)); 822 823 // Find the closest node within current container in the direction of the navigation. 824 FocusCandidate focusCandidate; 825 findFocusCandidateInContainer(*container, newStartingRect, type, focusCandidate); 826 827 if (focusCandidate.isNull()) { 828 // Nothing to focus, scroll if possible. 829 // NOTE: If no scrolling is performed (i.e. scrollInDirection returns false), the 830 // spatial navigation algorithm will skip this container. 831 return scrollInDirection(container, type); 832 } 833 834 HTMLFrameOwnerElement* frameElement = frameOwnerElement(focusCandidate); 835 // If we have an iframe without the src attribute, it will not have a contentFrame(). 836 // We ASSERT here to make sure that 837 // updateFocusCandidateIfNeeded() will never consider such an iframe as a candidate. 838 ASSERT(!frameElement || frameElement->contentFrame()); 839 if (frameElement && frameElement->contentFrame()->isLocalFrame()) { 840 if (focusCandidate.isOffscreenAfterScrolling) { 841 scrollInDirection(&focusCandidate.visibleNode->document(), type); 842 return true; 843 } 844 // Navigate into a new frame. 845 LayoutRect rect; 846 Element* focusedElement = toLocalFrame(focusedOrMainFrame())->document()->focusedElement(); 847 if (focusedElement && !hasOffscreenRect(focusedElement)) 848 rect = nodeRectInAbsoluteCoordinates(focusedElement, true /* ignore border */); 849 toLocalFrame(frameElement->contentFrame())->document()->updateLayoutIgnorePendingStylesheets(); 850 if (!advanceFocusDirectionallyInContainer(toLocalFrame(frameElement->contentFrame())->document(), rect, type)) { 851 // The new frame had nothing interesting, need to find another candidate. 852 return advanceFocusDirectionallyInContainer(container, nodeRectInAbsoluteCoordinates(focusCandidate.visibleNode, true), type); 853 } 854 return true; 855 } 856 857 if (canScrollInDirection(focusCandidate.visibleNode, type)) { 858 if (focusCandidate.isOffscreenAfterScrolling) { 859 scrollInDirection(focusCandidate.visibleNode, type); 860 return true; 861 } 862 // Navigate into a new scrollable container. 863 LayoutRect startingRect; 864 Element* focusedElement = toLocalFrame(focusedOrMainFrame())->document()->focusedElement(); 865 if (focusedElement && !hasOffscreenRect(focusedElement)) 866 startingRect = nodeRectInAbsoluteCoordinates(focusedElement, true); 867 return advanceFocusDirectionallyInContainer(focusCandidate.visibleNode, startingRect, type); 868 } 869 if (focusCandidate.isOffscreenAfterScrolling) { 870 Node* container = focusCandidate.enclosingScrollableBox; 871 scrollInDirection(container, type); 872 return true; 873 } 874 875 // We found a new focus node, navigate to it. 876 Element* element = toElement(focusCandidate.focusableNode); 877 ASSERT(element); 878 879 element->focus(false, type); 880 return true; 881 } 882 883 bool FocusController::advanceFocusDirectionally(FocusType type) 884 { 885 // FIXME: Directional focus changes don't yet work with RemoteFrames. 886 if (!focusedOrMainFrame()->isLocalFrame()) 887 return false; 888 LocalFrame* curFrame = toLocalFrame(focusedOrMainFrame()); 889 ASSERT(curFrame); 890 891 Document* focusedDocument = curFrame->document(); 892 if (!focusedDocument) 893 return false; 894 895 Element* focusedElement = focusedDocument->focusedElement(); 896 Node* container = focusedDocument; 897 898 if (container->isDocumentNode()) 899 toDocument(container)->updateLayoutIgnorePendingStylesheets(); 900 901 // Figure out the starting rect. 902 LayoutRect startingRect; 903 if (focusedElement) { 904 if (!hasOffscreenRect(focusedElement)) { 905 container = scrollableEnclosingBoxOrParentFrameForNodeInDirection(type, focusedElement); 906 startingRect = nodeRectInAbsoluteCoordinates(focusedElement, true /* ignore border */); 907 } else if (isHTMLAreaElement(*focusedElement)) { 908 HTMLAreaElement& area = toHTMLAreaElement(*focusedElement); 909 container = scrollableEnclosingBoxOrParentFrameForNodeInDirection(type, area.imageElement()); 910 startingRect = virtualRectForAreaElementAndDirection(area, type); 911 } 912 } 913 914 bool consumed = false; 915 do { 916 consumed = advanceFocusDirectionallyInContainer(container, startingRect, type); 917 startingRect = nodeRectInAbsoluteCoordinates(container, true /* ignore border */); 918 container = scrollableEnclosingBoxOrParentFrameForNodeInDirection(type, container); 919 if (container && container->isDocumentNode()) 920 toDocument(container)->updateLayoutIgnorePendingStylesheets(); 921 } while (!consumed && container); 922 923 return consumed; 924 } 925 926 } // namespace WebCore 927