Chromium Code Reviews| Index: third_party/WebKit/Source/core/page/FocusController.cpp |
| diff --git a/third_party/WebKit/Source/core/page/FocusController.cpp b/third_party/WebKit/Source/core/page/FocusController.cpp |
| index 975f6c9970d044f1ec423ba6d6094fb37de9439d..e70cc80c991131d8a709b589a3f87fea87715fa1 100644 |
| --- a/third_party/WebKit/Source/core/page/FocusController.cpp |
| +++ b/third_party/WebKit/Source/core/page/FocusController.cpp |
| @@ -72,7 +72,8 @@ inline bool isShadowInsertionPointFocusScopeOwner(Element& element) |
| class FocusNavigationScope { |
| STACK_ALLOCATED(); |
| public: |
| - Node* rootNode() const; |
| + Element* firstElement() const; |
| + Element* lastElement() const; |
| Element* owner() const; |
| static FocusNavigationScope focusNavigationScopeOf(const Element&); |
| static FocusNavigationScope ownedByNonFocusableFocusScopeOwner(Element&); |
| @@ -82,6 +83,7 @@ public: |
| private: |
| explicit FocusNavigationScope(TreeScope*); |
| + ContainerNode& rootNode() const; |
| RawPtrWillBeMember<TreeScope> m_rootTreeScope; |
| }; |
| @@ -91,20 +93,33 @@ FocusNavigationScope::FocusNavigationScope(TreeScope* treeScope) |
| ASSERT(treeScope); |
| } |
| -Node* FocusNavigationScope::rootNode() const |
| +ContainerNode& FocusNavigationScope::rootNode() const |
| { |
| - return &m_rootTreeScope->rootNode(); |
| + return m_rootTreeScope->rootNode(); |
| +} |
| + |
| +Element* FocusNavigationScope::firstElement() const |
| +{ |
| + Node& root = m_rootTreeScope->rootNode(); |
|
kochi
2016/02/19 07:25:35
nit: |ContainerNode&| ?
hayato
2016/02/19 07:47:44
Done.
|
| + return root.isElementNode() ? &toElement(root) : ElementTraversal::next(root); |
| +} |
| + |
| +Element* FocusNavigationScope::lastElement() const |
| +{ |
| + if (Node* last = NodeTraversal::lastWithin(rootNode())) |
| + return last->isElementNode() ? toElement(last) : ElementTraversal::previous(*last); |
|
kochi
2016/02/19 07:25:35
Can |ElementTraversal::lastWithin(rootNode())| ret
hayato
2016/02/19 07:47:44
It can not. A node can have the non-element last c
hayato
2016/02/19 08:21:28
I'm wrong. Looks ElementTraversal::lastWithin does
|
| + return nullptr; |
| } |
| Element* FocusNavigationScope::owner() const |
| { |
| - Node* root = rootNode(); |
| - if (root->isShadowRoot()) { |
| - ShadowRoot* shadowRoot = toShadowRoot(root); |
| - return shadowRoot->isYoungest() ? shadowRoot->host() : shadowRoot->shadowInsertionPointOfYoungerShadowRoot(); |
| + Node& root = rootNode(); |
|
kochi
2016/02/19 07:25:35
nit: |ContainerNode&| ?
hayato
2016/02/19 07:47:44
Done.
|
| + if (root.isShadowRoot()) { |
| + ShadowRoot& shadowRoot = toShadowRoot(root); |
| + return shadowRoot.isYoungest() ? shadowRoot.host() : shadowRoot.shadowInsertionPointOfYoungerShadowRoot(); |
| } |
| // FIXME: Figure out the right thing for OOPI here. |
| - if (Frame* frame = root->document().frame()) |
| + if (Frame* frame = root.document().frame()) |
| return frame->deprecatedLocalOwner(); |
| return nullptr; |
| } |
| @@ -203,11 +218,8 @@ inline bool isShadowHostWithoutCustomFocusLogic(const Element& element) |
| } |
| #if ENABLE(ASSERT) |
| -inline bool isNonFocusableShadowHost(const Node& node) |
| +inline bool isNonFocusableShadowHost(const Element& element) |
| { |
| - if (!node.isElementNode()) |
| - return false; |
| - const Element& element = toElement(node); |
| return isShadowHostWithoutCustomFocusLogic(element) && !element.isFocusable(); |
| } |
| #endif |
| @@ -232,162 +244,154 @@ inline bool isShadowHostDelegatesFocus(const Element& element) |
| return element.authorShadowRoot() && element.authorShadowRoot()->delegatesFocus(); |
| } |
| -inline int adjustedTabIndex(Node& node) |
| +inline int adjustedTabIndex(Element& element) |
| { |
| - return node.isElementNode() && isNonFocusableFocusScopeOwner(toElement(node)) ? 0 : node.tabIndex(); |
| + return isNonFocusableFocusScopeOwner(element) ? 0 : element.tabIndex(); |
| } |
| -inline bool shouldVisit(Node& node) |
| +inline bool shouldVisit(Element& element) |
| { |
| - if (!node.isElementNode()) |
| - return false; |
| - Element& element = toElement(node); |
| return element.isKeyboardFocusable() || isNonFocusableFocusScopeOwner(element); |
| } |
| -Element* findElementWithExactTabIndex(Node* start, int tabIndex, WebFocusType type) |
| +Element* findElementWithExactTabIndex(Element* start, int tabIndex, WebFocusType type) |
| { |
| // Search is inclusive of start |
| - for (Node* node = start; node; node = type == WebFocusTypeForward ? ElementTraversal::next(*node) : ElementTraversal::previous(*node)) { |
| - if (shouldVisit(*node) && adjustedTabIndex(*node) == tabIndex) |
| - return toElement(node); |
| + for (Element* element = start; element; element = type == WebFocusTypeForward ? ElementTraversal::next(*element) : ElementTraversal::previous(*element)) { |
| + if (shouldVisit(*element) && adjustedTabIndex(*element) == tabIndex) |
| + return element; |
| } |
| return nullptr; |
| } |
| -Element* nextElementWithGreaterTabIndex(Node* start, int tabIndex) |
| +Element* nextElementWithGreaterTabIndex(Element* start, int tabIndex) |
| { |
| // Search is inclusive of start |
| int winningTabIndex = std::numeric_limits<short>::max() + 1; |
| - Node* winner = nullptr; |
| - for (Node& node : NodeTraversal::startsAt(start)) { |
| - int currentTabIndex = adjustedTabIndex(node); |
| - if (shouldVisit(node) && currentTabIndex > tabIndex && currentTabIndex < winningTabIndex) { |
| - winner = &node; |
| + Element* winner = nullptr; |
| + for (Element& element : ElementTraversal::startsAt(start)) { |
| + int currentTabIndex = adjustedTabIndex(element); |
| + if (shouldVisit(element) && currentTabIndex > tabIndex && currentTabIndex < winningTabIndex) { |
| + winner = &element; |
| winningTabIndex = currentTabIndex; |
| } |
| } |
| - ASSERT(!winner || winner->isElementNode()); |
| - return toElement(winner); |
| + return winner; |
| } |
| -Element* previousElementWithLowerTabIndex(Node* start, int tabIndex) |
| +Element* previousElementWithLowerTabIndex(Element* start, int tabIndex) |
| { |
| // Search is inclusive of start |
| int winningTabIndex = 0; |
| - Node* winner = nullptr; |
| - for (Node* node = start; node; node = ElementTraversal::previous(*node)) { |
| - int currentTabIndex = adjustedTabIndex(*node); |
| - if (shouldVisit(*node) && currentTabIndex < tabIndex && currentTabIndex > winningTabIndex) { |
| - winner = node; |
| + Element* winner = nullptr; |
| + for (Element* element = start; element; element = ElementTraversal::previous(*element)) { |
| + int currentTabIndex = adjustedTabIndex(*element); |
| + if (shouldVisit(*element) && currentTabIndex < tabIndex && currentTabIndex > winningTabIndex) { |
| + winner = element; |
| winningTabIndex = currentTabIndex; |
| } |
| } |
| - ASSERT(!winner || winner->isElementNode()); |
| - return toElement(winner); |
| + return winner; |
| } |
| -Element* nextFocusableElement(const FocusNavigationScope& scope, Node* start) |
| +Element* nextFocusableElement(const FocusNavigationScope& scope, Element* start) |
| { |
| if (start) { |
| int tabIndex = adjustedTabIndex(*start); |
| - // If a node is excluded from the normal tabbing cycle, the next focusable node is determined by tree order |
| + // If an element is excluded from the normal tabbing cycle, the next focusable element is determined by tree order |
| if (tabIndex < 0) { |
| - for (Node& node : NodeTraversal::startsAfter(*start)) { |
| - if (shouldVisit(node) && adjustedTabIndex(node) >= 0) |
| - return &toElement(node); |
| + for (Element& element : ElementTraversal::startsAfter(*start)) { |
| + if (shouldVisit(element) && adjustedTabIndex(element) >= 0) |
| + return &element; |
| } |
| } else { |
| - // First try to find a node with the same tabindex as start that comes after start in the scope. |
| + // First try to find an element with the same tabindex as start that comes after start in the scope. |
| if (Element* winner = findElementWithExactTabIndex(ElementTraversal::next(*start), tabIndex, WebFocusTypeForward)) |
| return winner; |
| } |
| if (!tabIndex) { |
| - // We've reached the last node in the document with a tabindex of 0. This is the end of the tabbing order. |
| + // We've reached the last element in the document with a tabindex of 0. This is the end of the tabbing order. |
| return nullptr; |
| } |
| } |
| - // Look for the first node in the scope that: |
| + // Look for the first element in the scope that: |
| // 1) has the lowest tabindex that is higher than start's tabindex (or 0, if start is null), and |
| // 2) comes first in the scope, if there's a tie. |
| - if (Element* winner = nextElementWithGreaterTabIndex(scope.rootNode(), start ? adjustedTabIndex(*start) : 0)) |
| + if (Element* winner = nextElementWithGreaterTabIndex(scope.firstElement(), start ? adjustedTabIndex(*start) : 0)) |
| return winner; |
| - // There are no nodes with a tabindex greater than start's tabindex, |
| - // so find the first node with a tabindex of 0. |
| - return findElementWithExactTabIndex(scope.rootNode(), 0, WebFocusTypeForward); |
| + // There are no elements with a tabindex greater than start's tabindex, |
| + // so find the first element with a tabindex of 0. |
| + return findElementWithExactTabIndex(scope.firstElement(), 0, WebFocusTypeForward); |
| } |
| -Element* previousFocusableElement(const FocusNavigationScope& scope, Node* start) |
| +Element* previousFocusableElement(const FocusNavigationScope& scope, Element* start) |
| { |
| - Node* last = nullptr; |
| - for (Node* node = scope.rootNode(); node; node = node->lastChild()) |
| - last = node; |
| - ASSERT(last); |
| - |
| - // First try to find the last node in the scope that comes before start and has the same tabindex as start. |
| - // If start is null, find the last node in the scope with a tabindex of 0. |
| - Node* startingNode; |
| - int startingTabIndex; |
| + Element* lastElement = scope.lastElement(); |
| + |
| + // First try to find the last element in the scope that comes before start and has the same tabindex as start. |
| + // If start is null, find the last element in the scope with a tabindex of 0. |
| + Element* startElement; |
| + int startTabIndex; |
| if (start) { |
| - startingNode = ElementTraversal::previous(*start); |
| - startingTabIndex = adjustedTabIndex(*start); |
| + startElement = ElementTraversal::previous(*start); |
| + startTabIndex = adjustedTabIndex(*start); |
| } else { |
| - startingNode = last; |
| - startingTabIndex = 0; |
| + startElement = lastElement; |
| + startTabIndex = 0; |
| } |
| - // However, if a node is excluded from the normal tabbing cycle, the previous focusable node is determined by tree order |
| - if (startingTabIndex < 0) { |
| - for (Node* node = startingNode; node; node = ElementTraversal::previous(*node)) { |
| - if (shouldVisit(*node) && adjustedTabIndex(*node) >= 0) |
| - return toElement(node); |
| + // However, if an element is excluded from the normal tabbing cycle, the previous focusable element is determined by tree order |
| + if (startTabIndex < 0) { |
| + for (Element* element = startElement; element; element = ElementTraversal::previous(*element)) { |
| + if (shouldVisit(*element) && adjustedTabIndex(*element) >= 0) |
| + return element; |
| } |
| } else { |
| - if (Element* winner = findElementWithExactTabIndex(startingNode, startingTabIndex, WebFocusTypeBackward)) |
| + if (Element* winner = findElementWithExactTabIndex(startElement, startTabIndex, WebFocusTypeBackward)) |
| return winner; |
| } |
| - // There are no nodes before start with the same tabindex as start, so look for a node that: |
| + // There are no elements before start with the same tabindex as start, so look for an element that: |
| // 1) has the highest non-zero tabindex (that is less than start's tabindex), and |
| // 2) comes last in the scope, if there's a tie. |
| - startingTabIndex = (start && startingTabIndex) ? startingTabIndex : std::numeric_limits<short>::max(); |
| - return previousElementWithLowerTabIndex(last, startingTabIndex); |
| + startTabIndex = (start && startTabIndex) ? startTabIndex : std::numeric_limits<short>::max(); |
| + return previousElementWithLowerTabIndex(lastElement, startTabIndex); |
| } |
| -// Searches through the given tree scope, starting from start node, for the next/previous |
| -// selectable element that comes after/before start node. |
| +// Searches through the given tree scope, starting from start element, for the next/previous |
| +// selectable element that comes after/before start element. |
| // The order followed is as specified in the HTML spec[1], which is elements with tab indexes |
| // first (from lowest to highest), and then elements without tab indexes (in document order). |
| // The search algorithm also conforms the Shadow DOM spec[2], which inserts sequence in a shadow |
| // tree into its host. |
| // |
| -// @param start The node from which to start searching. The node after this will be focused. |
| +// @param start The element from which to start searching. The element after this will be focused. |
| // May be null. |
| -// @return The focus element that comes after/before start node. |
| +// @return The focus element that comes after/before start element. |
| // |
| // [1] https://html.spec.whatwg.org/multipage/interaction.html#sequential-focus-navigation |
| // [2] https://w3c.github.io/webcomponents/spec/shadow/#focus-navigation |
| -inline Element* findFocusableElementInternal(WebFocusType type, const FocusNavigationScope& scope, Node* node) |
| +inline Element* findFocusableElementInternal(WebFocusType type, const FocusNavigationScope& scope, Element* element) |
| { |
| - Element* found = (type == WebFocusTypeForward) ? nextFocusableElement(scope, node) : previousFocusableElement(scope, node); |
| + Element* found = (type == WebFocusTypeForward) ? nextFocusableElement(scope, element) : previousFocusableElement(scope, element); |
| return found; |
| } |
| -Element* findFocusableElementRecursivelyForward(const FocusNavigationScope& scope, Node* start) |
| +Element* findFocusableElementRecursivelyForward(const FocusNavigationScope& scope, Element* start) |
| { |
| - // Starting node is exclusive. |
| + // Starting element is exclusive. |
| Element* found = findFocusableElementInternal(WebFocusTypeForward, scope, start); |
| while (found) { |
| if (isShadowHostDelegatesFocus(*found)) { |
| - // If tabindex is positive, find focusable node inside its shadow tree. |
| + // If tabindex is positive, find focusable element inside its shadow tree. |
| if (found->tabIndex() >= 0 && isShadowHostWithoutCustomFocusLogic(*found)) { |
| FocusNavigationScope innerScope = FocusNavigationScope::ownedByShadowHost(*found); |
| if (Element* foundInInnerFocusScope = findFocusableElementRecursivelyForward(innerScope, nullptr)) |
| return foundInInnerFocusScope; |
| } |
| - // Skip to the next node in the same scope. |
| + // Skip to the next element in the same scope. |
| found = findFocusableElementInternal(WebFocusTypeForward, scope, found); |
| continue; |
| } |
| @@ -406,9 +410,9 @@ Element* findFocusableElementRecursivelyForward(const FocusNavigationScope& scop |
| return nullptr; |
| } |
| -Element* findFocusableElementRecursivelyBackward(const FocusNavigationScope& scope, Node* start) |
| +Element* findFocusableElementRecursivelyBackward(const FocusNavigationScope& scope, Element* start) |
| { |
| - // Starting node is exclusive. |
| + // Starting element is exclusive. |
| Element* found = findFocusableElementInternal(WebFocusTypeBackward, scope, start); |
| while (found) { |
| // Now |found| is on a focusable shadow host. |
| @@ -434,7 +438,7 @@ Element* findFocusableElementRecursivelyBackward(const FocusNavigationScope& sco |
| } |
| // Now |found| is on a non focusable scope owner (either shadow host or <shadow>). |
| - // Find focusable node in descendant scope. If not found, find next focusable node within the |
| + // Find focusable element in descendant scope. If not found, find next focusable element within the |
| // current scope. |
| if (isNonFocusableFocusScopeOwner(*found)) { |
| FocusNavigationScope innerScope = FocusNavigationScope::ownedByNonFocusableFocusScopeOwner(*found); |
| @@ -451,7 +455,7 @@ Element* findFocusableElementRecursivelyBackward(const FocusNavigationScope& sco |
| return nullptr; |
| } |
| -Element* findFocusableElementRecursively(WebFocusType type, const FocusNavigationScope& scope, Node* start) |
| +Element* findFocusableElementRecursively(WebFocusType type, const FocusNavigationScope& scope, Element* start) |
| { |
| return (type == WebFocusTypeForward) ? |
| findFocusableElementRecursivelyForward(scope, start) : |
| @@ -477,19 +481,19 @@ Element* findFocusableElementDescendingDownIntoFrameDocument(WebFocusType type, |
| return element; |
| } |
| -Element* findFocusableElementAcrossFocusScopesForward(const FocusNavigationScope& scope, Node* currentNode) |
| +Element* findFocusableElementAcrossFocusScopesForward(const FocusNavigationScope& scope, Element* current) |
| { |
| - ASSERT(!currentNode || !isNonFocusableShadowHost(*currentNode)); |
| + ASSERT(!current || !isNonFocusableShadowHost(*current)); |
| Element* found; |
| - if (currentNode && currentNode->isElementNode() && isShadowHostWithoutCustomFocusLogic(*toElement(currentNode))) { |
| - FocusNavigationScope innerScope = FocusNavigationScope::ownedByShadowHost(*toElement(currentNode)); |
| + if (current && isShadowHostWithoutCustomFocusLogic(*current)) { |
| + FocusNavigationScope innerScope = FocusNavigationScope::ownedByShadowHost(*current); |
| Element* foundInInnerFocusScope = findFocusableElementRecursivelyForward(innerScope, nullptr); |
| - found = foundInInnerFocusScope ? foundInInnerFocusScope : findFocusableElementRecursivelyForward(scope, currentNode); |
| + found = foundInInnerFocusScope ? foundInInnerFocusScope : findFocusableElementRecursivelyForward(scope, current); |
| } else { |
| - found = findFocusableElementRecursivelyForward(scope, currentNode); |
| + found = findFocusableElementRecursivelyForward(scope, current); |
| } |
| - // If there's no focusable node to advance to, move up the focus scopes until we find one. |
| + // If there's no focusable element to advance to, move up the focus scopes until we find one. |
| FocusNavigationScope currentScope = scope; |
| while (!found) { |
| Element* owner = currentScope.owner(); |
| @@ -501,12 +505,12 @@ Element* findFocusableElementAcrossFocusScopesForward(const FocusNavigationScope |
| return findFocusableElementDescendingDownIntoFrameDocument(WebFocusTypeForward, found); |
| } |
| -Element* findFocusableElementAcrossFocusScopesBackward(const FocusNavigationScope& scope, Node* currentNode) |
| +Element* findFocusableElementAcrossFocusScopesBackward(const FocusNavigationScope& scope, Element* current) |
| { |
| - ASSERT(!currentNode || !isNonFocusableShadowHost(*currentNode)); |
| - Element* found = findFocusableElementRecursivelyBackward(scope, currentNode); |
| + ASSERT(!current || !isNonFocusableShadowHost(*current)); |
| + Element* found = findFocusableElementRecursivelyBackward(scope, current); |
| - // If there's no focusable node to advance to, move up the focus scopes until we find one. |
| + // If there's no focusable element to advance to, move up the focus scopes until we find one. |
| FocusNavigationScope currentScope = scope; |
| while (!found) { |
| Element* owner = currentScope.owner(); |
| @@ -522,11 +526,11 @@ Element* findFocusableElementAcrossFocusScopesBackward(const FocusNavigationScop |
| return findFocusableElementDescendingDownIntoFrameDocument(WebFocusTypeBackward, found); |
| } |
| -Element* findFocusableElementAcrossFocusScopes(WebFocusType type, const FocusNavigationScope& scope, Node* currentNode) |
| +Element* findFocusableElementAcrossFocusScopes(WebFocusType type, const FocusNavigationScope& scope, Element* current) |
| { |
| return (type == WebFocusTypeForward) ? |
| - findFocusableElementAcrossFocusScopesForward(scope, currentNode) : |
| - findFocusableElementAcrossFocusScopesBackward(scope, currentNode); |
| + findFocusableElementAcrossFocusScopesForward(scope, current) : |
| + findFocusableElementAcrossFocusScopesBackward(scope, current); |
| } |
| inline Element* adjustToElement(Node* node, WebFocusType type) |
| @@ -779,7 +783,7 @@ bool FocusController::advanceFocusInDocumentOrder(LocalFrame* frame, Element* st |
| ASSERT(element); |
| if (element == document->focusedElement()) { |
| - // Focus wrapped around to the same node. |
| + // Focus wrapped around to the same element. |
| return true; |
| } |
| @@ -803,13 +807,13 @@ bool FocusController::advanceFocusInDocumentOrder(LocalFrame* frame, Element* st |
| return true; |
| } |
| - // FIXME: It would be nice to just be able to call setFocusedElement(node) |
| + // FIXME: It would be nice to just be able to call setFocusedElement(element) |
| // here, but we can't do that because some elements (e.g. HTMLInputElement |
| // and HTMLTextAreaElement) do extra work in their focus() methods. |
| Document& newDocument = element->document(); |
| if (&newDocument != document) { |
| - // Focus is going away from this document, so clear the focused node. |
| + // Focus is going away from this document, so clear the focused element. |
| document->clearFocusedElement(); |
| } |
| @@ -914,7 +918,7 @@ bool FocusController::setFocusedElement(Element* element, PassRefPtrWillBeRawPtr |
| } |
| setFocusedFrame(newFocusedFrame); |
| - // Setting the focused node can result in losing our last reft to node when JS event handlers fire. |
| + // Setting the focused element can result in losing our last reft to element when JS event handlers fire. |
| RefPtrWillBeRawPtr<Element> protect = element; |
| ALLOW_UNUSED_LOCAL(protect); |
| if (newDocument) { |