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