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