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 df65ba7a8410a5cf58d5eca15f233de3dd7edd54..9fe5df2b50c93a921f6484660055703f7a5dd253 100644 |
| --- a/third_party/WebKit/Source/core/page/FocusController.cpp |
| +++ b/third_party/WebKit/Source/core/page/FocusController.cpp |
| @@ -88,6 +88,9 @@ public: |
| static ScopedFocusNavigation ownedByShadowInsertionPoint(HTMLShadowElement&); |
| static ScopedFocusNavigation ownedByHTMLSlotElement(const HTMLSlotElement&); |
| static ScopedFocusNavigation ownedByIFrame(const HTMLFrameOwnerElement&); |
| + static HTMLSlotElement* findFallbackScopeOwnerSlot(const Element&); |
| + static bool isSlotFallbackScoped(const Element&); |
| + static bool isSlotFallbackScopedForThisSlot(const HTMLSlotElement&, const Element&); |
| private: |
| ScopedFocusNavigation(TreeScope&, const Element*); |
| @@ -95,6 +98,7 @@ private: |
| RawPtrWillBeMember<ContainerNode> m_rootNode; |
| RawPtrWillBeMember<HTMLSlotElement> m_rootSlot; |
| RawPtrWillBeMember<Element> m_current; |
| + bool m_slotFallbackTraversal; |
| }; |
| ScopedFocusNavigation::ScopedFocusNavigation(TreeScope& treeScope, const Element* current) |
| @@ -108,6 +112,7 @@ ScopedFocusNavigation::ScopedFocusNavigation(HTMLSlotElement& slot, const Elemen |
| : m_rootNode(nullptr) |
| , m_rootSlot(&slot) |
| , m_current(const_cast<Element*>(current)) |
| + , m_slotFallbackTraversal(slot.getAssignedNodes().isEmpty()) |
| { |
| } |
| @@ -125,10 +130,16 @@ void ScopedFocusNavigation::moveToNext() |
| { |
| ASSERT(m_current); |
| if (m_rootSlot) { |
| - m_current = SlotScopedTraversal::next(*m_current); |
| + if (m_slotFallbackTraversal) { |
| + m_current = ElementTraversal::next(*m_current, m_rootSlot); |
| + while (m_current && !ScopedFocusNavigation::isSlotFallbackScopedForThisSlot(*m_rootSlot, *m_current)) |
| + m_current = ElementTraversal::next(*m_current, m_rootSlot); |
| + } else { |
| + m_current = SlotScopedTraversal::next(*m_current); |
| + } |
| } else { |
| m_current = ElementTraversal::next(*m_current); |
| - while (m_current && SlotScopedTraversal::isSlotScoped(*m_current)) |
| + while (m_current && (SlotScopedTraversal::isSlotScoped(*m_current) || ScopedFocusNavigation::isSlotFallbackScoped(*m_current))) |
| m_current = ElementTraversal::next(*m_current); |
| } |
| } |
| @@ -137,10 +148,18 @@ void ScopedFocusNavigation::moveToPrevious() |
| { |
| ASSERT(m_current); |
| if (m_rootSlot) { |
| - m_current = SlotScopedTraversal::previous(*m_current); |
| + if (m_slotFallbackTraversal) { |
| + m_current = ElementTraversal::previous(*m_current, m_rootSlot); |
| + if (m_current == m_rootSlot) |
| + m_current = nullptr; |
| + while (m_current && !ScopedFocusNavigation::isSlotFallbackScopedForThisSlot(*m_rootSlot, *m_current)) |
| + m_current = ElementTraversal::previous(*m_current); |
| + } else { |
| + m_current = SlotScopedTraversal::previous(*m_current); |
| + } |
| } else { |
| m_current = ElementTraversal::previous(*m_current); |
| - while (m_current && SlotScopedTraversal::isSlotScoped(*m_current)) |
| + while (m_current && (SlotScopedTraversal::isSlotScoped(*m_current) || ScopedFocusNavigation::isSlotFallbackScoped(*m_current))) |
| m_current = ElementTraversal::previous(*m_current); |
| } |
| } |
| @@ -148,7 +167,7 @@ void ScopedFocusNavigation::moveToPrevious() |
| void ScopedFocusNavigation::moveToFirst() |
| { |
| if (m_rootSlot) { |
| - if (!m_rootSlot->getAssignedNodes().isEmpty()) { |
| + if (!m_slotFallbackTraversal) { |
| WillBeHeapVector<RefPtrWillBeMember<Node>> assignedNodes = m_rootSlot->getAssignedNodes(); |
| for (auto assignedNode : assignedNodes) { |
| if (assignedNode->isElementNode()) { |
| @@ -157,20 +176,24 @@ void ScopedFocusNavigation::moveToFirst() |
| } |
| } |
| } else { |
| - m_current = nullptr; |
| + Element* first = ElementTraversal::firstChild(*m_rootSlot); |
| + while (first && !ScopedFocusNavigation::isSlotFallbackScopedForThisSlot(*m_rootSlot, *first)) |
| + first = ElementTraversal::next(*first, m_rootSlot); |
| + m_current = first; |
| } |
| } else { |
| Element* first = m_rootNode->isElementNode() ? &toElement(*m_rootNode) : ElementTraversal::next(*m_rootNode); |
| - while (first && SlotScopedTraversal::isSlotScoped(*first)) |
| + while (first && (SlotScopedTraversal::isSlotScoped(*first) || ScopedFocusNavigation::isSlotFallbackScoped(*first))) |
| first = ElementTraversal::next(*first, m_rootNode); |
| m_current = first; |
| } |
| + |
| } |
| void ScopedFocusNavigation::moveToLast() |
| { |
| if (m_rootSlot) { |
| - if (!m_rootSlot->getAssignedNodes().isEmpty()) { |
| + if (!m_slotFallbackTraversal) { |
| WillBeHeapVector<RefPtrWillBeMember<Node>> assignedNodes = m_rootSlot->getAssignedNodes(); |
| for (auto assignedNode = assignedNodes.rbegin(); assignedNode != assignedNodes.rend(); ++assignedNode) { |
| if ((*assignedNode)->isElementNode()) { |
| @@ -179,11 +202,14 @@ void ScopedFocusNavigation::moveToLast() |
| } |
| } |
| } else { |
| - m_current = nullptr; |
| + Element* last = ElementTraversal::lastWithin(*m_rootSlot); |
| + while (last && !ScopedFocusNavigation::isSlotFallbackScopedForThisSlot(*m_rootSlot, *last)) |
| + last = ElementTraversal::previous(*last, m_rootSlot); |
| + m_current = last; |
| } |
| } else { |
| Element* last = ElementTraversal::lastWithin(*m_rootNode); |
| - while (last && SlotScopedTraversal::isSlotScoped(*last)) |
| + while (last && (SlotScopedTraversal::isSlotScoped(*last) || ScopedFocusNavigation::isSlotFallbackScoped(*last))) |
| last = ElementTraversal::previous(*last, m_rootNode); |
| m_current = last; |
| } |
| @@ -193,6 +219,7 @@ Element* ScopedFocusNavigation::owner() const |
| { |
| if (m_rootSlot) |
| return m_rootSlot; |
| + ASSERT(m_rootNode); |
| if (m_rootNode->isShadowRoot()) { |
| ShadowRoot& shadowRoot = toShadowRoot(*m_rootNode); |
| return shadowRoot.isYoungest() ? shadowRoot.host() : shadowRoot.shadowInsertionPointOfYoungerShadowRoot(); |
| @@ -205,8 +232,10 @@ Element* ScopedFocusNavigation::owner() const |
| ScopedFocusNavigation ScopedFocusNavigation::createFor(const Element& current) |
| { |
| - if (SlotScopedTraversal::isSlotScoped(current)) |
| - return ScopedFocusNavigation(*SlotScopedTraversal::findScopeOwnerSlot(current), ¤t); |
| + if (HTMLSlotElement* slot = SlotScopedTraversal::findScopeOwnerSlot(current)) |
| + return ScopedFocusNavigation(*slot, ¤t); |
| + if (HTMLSlotElement* slot = ScopedFocusNavigation::findFallbackScopeOwnerSlot(current)) |
| + return ScopedFocusNavigation(*slot, ¤t); |
| return ScopedFocusNavigation(current.treeScope(), ¤t); |
| } |
| @@ -250,6 +279,33 @@ ScopedFocusNavigation ScopedFocusNavigation::ownedByHTMLSlotElement(const HTMLSl |
| return ScopedFocusNavigation(const_cast<HTMLSlotElement&>(element), nullptr); |
| } |
| +HTMLSlotElement* ScopedFocusNavigation::findFallbackScopeOwnerSlot(const Element& element) |
| +{ |
| + Element* parent = const_cast<Element*>(element.parentElement()); |
| + while (parent) { |
| + if (isHTMLSlotElement(parent)) |
| + return toHTMLSlotElement(parent)->getAssignedNodes().isEmpty() ? toHTMLSlotElement(parent) : nullptr; |
| + parent = parent->parentElement(); |
| + } |
| + return nullptr; |
| +} |
| + |
| +bool ScopedFocusNavigation::isSlotFallbackScoped(const Element& element) |
| +{ |
| + return ScopedFocusNavigation::findFallbackScopeOwnerSlot(element); |
| +} |
| + |
| +bool ScopedFocusNavigation::isSlotFallbackScopedForThisSlot(const HTMLSlotElement& slot, const Element& current) |
| +{ |
| + Element* parent = const_cast<Element*>(current.parentElement()); |
|
hayato
2016/04/01 05:45:34
No need to const_cast here, I think.
yuzuchan
2016/04/01 06:26:29
Done.
|
| + while (parent) { |
| + if (isHTMLSlotElement(parent) && toHTMLSlotElement(parent)->getAssignedNodes().isEmpty()) |
| + return !SlotScopedTraversal::isSlotScoped(current) && toHTMLSlotElement(parent) == slot; |
| + parent = parent->parentElement(); |
| + } |
| + return false; |
| +} |
| + |
| inline void dispatchBlurEvent(const Document& document, Element& focusedElement) |
| { |
| focusedElement.dispatchBlurEvent(nullptr, WebFocusTypePage); |