| 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 00331f92853074ae97f543955673ddafec30f748..4617e58fbc64fcb03ecdc1167f5bc3041d6d51b2 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,31 @@ 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
|
| +{
|
| + ContainerNode& root = rootNode();
|
| + return root.isElementNode() ? &toElement(root) : ElementTraversal::next(root);
|
| +}
|
| +
|
| +Element* FocusNavigationScope::lastElement() const
|
| +{
|
| + return ElementTraversal::lastWithin(rootNode());
|
| }
|
|
|
| Element* FocusNavigationScope::owner() const
|
| {
|
| - Node* root = rootNode();
|
| - if (root->isShadowRoot()) {
|
| - ShadowRoot* shadowRoot = toShadowRoot(root);
|
| - return shadowRoot->isYoungest() ? shadowRoot->host() : shadowRoot->shadowInsertionPointOfYoungerShadowRoot();
|
| + ContainerNode& root = rootNode();
|
| + 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 +216,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 +242,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 +408,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 +436,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 +453,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 +479,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 +503,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 +524,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)
|
| @@ -781,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;
|
| }
|
|
|
| @@ -805,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();
|
| }
|
|
|
| @@ -916,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) {
|
|
|