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