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