| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. | 2 * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. |
| 3 * Copyright (C) 2008 Nuanti Ltd. | 3 * Copyright (C) 2008 Nuanti Ltd. |
| 4 * | 4 * |
| 5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
| 6 * modification, are permitted provided that the following conditions | 6 * modification, are permitted provided that the following conditions |
| 7 * are met: | 7 * are met: |
| 8 * 1. Redistributions of source code must retain the above copyright | 8 * 1. Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * 2. Redistributions in binary form must reproduce the above copyright | 10 * 2. Redistributions in binary form must reproduce the above copyright |
| (...skipping 10 matching lines...) Expand all Loading... |
| 21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | 21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| 22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 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. | 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 25 */ | 25 */ |
| 26 | 26 |
| 27 #include "core/page/FocusController.h" | 27 #include "core/page/FocusController.h" |
| 28 | 28 |
| 29 #include "core/HTMLNames.h" | 29 #include "core/HTMLNames.h" |
| 30 #include "core/dom/AXObjectCache.h" | 30 #include "core/dom/AXObjectCache.h" |
| 31 #include "core/dom/ContainerNode.h" |
| 31 #include "core/dom/Document.h" | 32 #include "core/dom/Document.h" |
| 32 #include "core/dom/Element.h" | 33 #include "core/dom/Element.h" |
| 33 #include "core/dom/ElementTraversal.h" | 34 #include "core/dom/ElementTraversal.h" |
| 34 #include "core/dom/NodeTraversal.h" | |
| 35 #include "core/dom/Range.h" | 35 #include "core/dom/Range.h" |
| 36 #include "core/dom/shadow/ElementShadow.h" | 36 #include "core/dom/shadow/ElementShadow.h" |
| 37 #include "core/dom/shadow/ShadowRoot.h" | 37 #include "core/dom/shadow/ShadowRoot.h" |
| 38 #include "core/dom/shadow/SlotScopedTraversal.h" |
| 38 #include "core/editing/EditingUtilities.h" // For firstPositionInOrBeforeNode | 39 #include "core/editing/EditingUtilities.h" // For firstPositionInOrBeforeNode |
| 39 #include "core/editing/Editor.h" | 40 #include "core/editing/Editor.h" |
| 40 #include "core/editing/FrameSelection.h" | 41 #include "core/editing/FrameSelection.h" |
| 41 #include "core/events/Event.h" | 42 #include "core/events/Event.h" |
| 42 #include "core/frame/FrameClient.h" | 43 #include "core/frame/FrameClient.h" |
| 43 #include "core/frame/FrameView.h" | 44 #include "core/frame/FrameView.h" |
| 44 #include "core/frame/LocalDOMWindow.h" | 45 #include "core/frame/LocalDOMWindow.h" |
| 45 #include "core/frame/LocalFrame.h" | 46 #include "core/frame/LocalFrame.h" |
| 46 #include "core/frame/RemoteFrame.h" | 47 #include "core/frame/RemoteFrame.h" |
| 47 #include "core/frame/Settings.h" | 48 #include "core/frame/Settings.h" |
| 48 #include "core/html/HTMLAreaElement.h" | 49 #include "core/html/HTMLAreaElement.h" |
| 49 #include "core/html/HTMLImageElement.h" | 50 #include "core/html/HTMLImageElement.h" |
| 50 #include "core/html/HTMLPlugInElement.h" | 51 #include "core/html/HTMLPlugInElement.h" |
| 51 #include "core/html/HTMLShadowElement.h" | 52 #include "core/html/HTMLShadowElement.h" |
| 53 #include "core/html/HTMLSlotElement.h" |
| 52 #include "core/html/HTMLTextFormControlElement.h" | 54 #include "core/html/HTMLTextFormControlElement.h" |
| 53 #include "core/input/EventHandler.h" | 55 #include "core/input/EventHandler.h" |
| 54 #include "core/page/ChromeClient.h" | 56 #include "core/page/ChromeClient.h" |
| 55 #include "core/page/FrameTree.h" | 57 #include "core/page/FrameTree.h" |
| 56 #include "core/page/Page.h" | 58 #include "core/page/Page.h" |
| 57 #include "core/layout/HitTestResult.h" | 59 #include "core/layout/HitTestResult.h" |
| 58 #include "core/page/SpatialNavigation.h" | 60 #include "core/page/SpatialNavigation.h" |
| 59 #include <limits> | 61 #include <limits> |
| 60 | 62 |
| 61 namespace blink { | 63 namespace blink { |
| 62 | 64 |
| 63 using namespace HTMLNames; | 65 using namespace HTMLNames; |
| 64 | 66 |
| 65 namespace { | 67 namespace { |
| 66 | 68 |
| 67 inline bool isShadowInsertionPointFocusScopeOwner(Element& element) | 69 inline bool isShadowInsertionPointFocusScopeOwner(Element& element) |
| 68 { | 70 { |
| 69 return isActiveShadowInsertionPoint(element) && toHTMLShadowElement(element)
.olderShadowRoot(); | 71 return isActiveShadowInsertionPoint(element) && toHTMLShadowElement(element)
.olderShadowRoot(); |
| 70 } | 72 } |
| 71 | 73 |
| 72 class FocusNavigationScope { | 74 class ScopedFocusNavigation { |
| 73 STACK_ALLOCATED(); | 75 STACK_ALLOCATED(); |
| 74 public: | 76 public: |
| 75 Element* firstElement() const; | 77 Element* currentElement() const; |
| 76 Element* lastElement() const; | 78 void setCurrentElement(Element*); |
| 79 void moveToNext(); |
| 80 void moveToPrevious(); |
| 81 void moveToFirst(); |
| 82 void moveToLast(); |
| 77 Element* owner() const; | 83 Element* owner() const; |
| 78 static FocusNavigationScope focusNavigationScopeOf(const Element&); | 84 static ScopedFocusNavigation createScopedFocusNavigation(const Element& root
, const Element* current); |
| 79 static FocusNavigationScope ownedByNonFocusableFocusScopeOwner(Element&); | 85 static ScopedFocusNavigation ownedByNonFocusableFocusScopeOwner(Element&); |
| 80 static FocusNavigationScope ownedByShadowHost(const Element&); | 86 static ScopedFocusNavigation ownedByShadowHost(const Element&); |
| 81 static FocusNavigationScope ownedByShadowInsertionPoint(HTMLShadowElement&); | 87 static ScopedFocusNavigation ownedByShadowInsertionPoint(HTMLShadowElement&)
; |
| 82 static FocusNavigationScope ownedByIFrame(const HTMLFrameOwnerElement&); | 88 static ScopedFocusNavigation ownedByHTMLSlotElement(const HTMLSlotElement&); |
| 89 static ScopedFocusNavigation ownedByIFrame(const HTMLFrameOwnerElement&); |
| 83 | 90 |
| 84 private: | 91 private: |
| 85 explicit FocusNavigationScope(TreeScope*); | 92 ScopedFocusNavigation(TreeScope&, const Element*); |
| 86 ContainerNode& rootNode() const; | 93 ScopedFocusNavigation(HTMLSlotElement&, const Element*); |
| 87 RawPtrWillBeMember<TreeScope> m_rootTreeScope; | 94 RawPtrWillBeMember<ContainerNode> m_rootNode; |
| 95 RawPtrWillBeMember<HTMLSlotElement> m_rootSlot; |
| 96 RawPtrWillBeMember<Element> m_current; |
| 88 }; | 97 }; |
| 89 | 98 |
| 90 FocusNavigationScope::FocusNavigationScope(TreeScope* treeScope) | 99 ScopedFocusNavigation::ScopedFocusNavigation(TreeScope& treeScope, const Element
* current) |
| 91 : m_rootTreeScope(treeScope) | 100 : m_rootNode(treeScope.rootNode()) |
| 101 , m_rootSlot(nullptr) |
| 102 , m_current(const_cast<Element*>(current)) |
| 92 { | 103 { |
| 93 ASSERT(treeScope); | |
| 94 } | 104 } |
| 95 | 105 |
| 96 ContainerNode& FocusNavigationScope::rootNode() const | 106 ScopedFocusNavigation::ScopedFocusNavigation(HTMLSlotElement& slot, const Elemen
t* current) |
| 107 : m_rootNode(nullptr) |
| 108 , m_rootSlot(&slot) |
| 109 , m_current(const_cast<Element*>(current)) |
| 97 { | 110 { |
| 98 return m_rootTreeScope->rootNode(); | |
| 99 } | 111 } |
| 100 | 112 |
| 101 Element* FocusNavigationScope::firstElement() const | 113 Element* ScopedFocusNavigation::currentElement() const |
| 102 { | 114 { |
| 103 ContainerNode& root = rootNode(); | 115 return m_current; |
| 104 return root.isElementNode() ? &toElement(root) : ElementTraversal::next(root
); | |
| 105 } | 116 } |
| 106 | 117 |
| 107 Element* FocusNavigationScope::lastElement() const | 118 void ScopedFocusNavigation::setCurrentElement(Element* element) |
| 108 { | 119 { |
| 109 return ElementTraversal::lastWithin(rootNode()); | 120 m_current = element; |
| 110 } | 121 } |
| 111 | 122 |
| 112 Element* FocusNavigationScope::owner() const | 123 void ScopedFocusNavigation::moveToNext() |
| 113 { | 124 { |
| 114 ContainerNode& root = rootNode(); | 125 ASSERT(m_current); |
| 115 if (root.isShadowRoot()) { | 126 if (m_rootSlot) { |
| 116 ShadowRoot& shadowRoot = toShadowRoot(root); | 127 m_current = SlotScopedTraversal::next(*m_current); |
| 128 } else { |
| 129 m_current = ElementTraversal::next(*m_current); |
| 130 while (m_current && SlotScopedTraversal::isSlotScoped(*m_current)) |
| 131 m_current = ElementTraversal::next(*m_current); |
| 132 } |
| 133 } |
| 134 |
| 135 void ScopedFocusNavigation::moveToPrevious() |
| 136 { |
| 137 ASSERT(m_current); |
| 138 if (m_rootSlot) { |
| 139 m_current = SlotScopedTraversal::previous(*m_current); |
| 140 } else { |
| 141 m_current = ElementTraversal::previous(*m_current); |
| 142 while (m_current && SlotScopedTraversal::isSlotScoped(*m_current)) |
| 143 m_current = ElementTraversal::previous(*m_current); |
| 144 } |
| 145 } |
| 146 |
| 147 void ScopedFocusNavigation::moveToFirst() |
| 148 { |
| 149 if (m_rootSlot) { |
| 150 if (!m_rootSlot->getAssignedNodes().isEmpty()) { |
| 151 WillBeHeapVector<RefPtrWillBeMember<Node>> assignedNodes = m_rootSlo
t->getAssignedNodes(); |
| 152 for (auto assignedNode : assignedNodes) { |
| 153 if (assignedNode->isElementNode()) { |
| 154 m_current = toElement(assignedNode); |
| 155 break; |
| 156 } |
| 157 } |
| 158 } else { |
| 159 m_current = nullptr; |
| 160 } |
| 161 } else { |
| 162 Element* first = m_rootNode->isElementNode() ? &toElement(*m_rootNode) :
ElementTraversal::next(*m_rootNode); |
| 163 while (first && SlotScopedTraversal::isSlotScoped(*first)) |
| 164 first = ElementTraversal::next(*first, m_rootNode); |
| 165 m_current = first; |
| 166 } |
| 167 } |
| 168 |
| 169 void ScopedFocusNavigation::moveToLast() |
| 170 { |
| 171 if (m_rootSlot) { |
| 172 if (!m_rootSlot->getAssignedNodes().isEmpty()) { |
| 173 WillBeHeapVector<RefPtrWillBeMember<Node>> assignedNodes = m_rootSlo
t->getAssignedNodes(); |
| 174 for (auto assignedNode = assignedNodes.rbegin(); assignedNode != ass
ignedNodes.rend(); ++assignedNode) { |
| 175 if ((*assignedNode)->isElementNode()) { |
| 176 Element* lastWithin = ElementTraversal::lastWithin(*toElemen
t(*assignedNode)); |
| 177 if (lastWithin) |
| 178 m_current = lastWithin; |
| 179 else |
| 180 m_current = toElement(*assignedNode); |
| 181 break; |
| 182 } |
| 183 } |
| 184 } else { |
| 185 m_current = nullptr; |
| 186 } |
| 187 } else { |
| 188 Element* last = ElementTraversal::lastWithin(*m_rootNode); |
| 189 while (last && SlotScopedTraversal::isSlotScoped(*last)) |
| 190 last = ElementTraversal::previous(*last, m_rootNode); |
| 191 m_current = last; |
| 192 } |
| 193 } |
| 194 |
| 195 Element* ScopedFocusNavigation::owner() const |
| 196 { |
| 197 if (m_rootSlot) |
| 198 return m_rootSlot; |
| 199 if (m_rootNode->isShadowRoot()) { |
| 200 ShadowRoot& shadowRoot = toShadowRoot(*m_rootNode); |
| 117 return shadowRoot.isYoungest() ? shadowRoot.host() : shadowRoot.shadowIn
sertionPointOfYoungerShadowRoot(); | 201 return shadowRoot.isYoungest() ? shadowRoot.host() : shadowRoot.shadowIn
sertionPointOfYoungerShadowRoot(); |
| 118 } | 202 } |
| 119 // FIXME: Figure out the right thing for OOPI here. | 203 // FIXME: Figure out the right thing for OOPI here. |
| 120 if (Frame* frame = root.document().frame()) | 204 if (Frame* frame = m_rootNode->document().frame()) |
| 121 return frame->deprecatedLocalOwner(); | 205 return frame->deprecatedLocalOwner(); |
| 122 return nullptr; | 206 return nullptr; |
| 123 } | 207 } |
| 124 | 208 |
| 125 FocusNavigationScope FocusNavigationScope::focusNavigationScopeOf(const Element&
element) | 209 ScopedFocusNavigation ScopedFocusNavigation::createScopedFocusNavigation(const E
lement& root, const Element* current) |
| 126 { | 210 { |
| 127 return FocusNavigationScope(&element.treeScope()); | 211 if (SlotScopedTraversal::isSlotScoped(root)) |
| 212 return ScopedFocusNavigation(*SlotScopedTraversal::findScopeOwnerSlot(ro
ot), current); |
| 213 return ScopedFocusNavigation(*&root.treeScope(), current); |
| 128 } | 214 } |
| 129 | 215 |
| 130 FocusNavigationScope FocusNavigationScope::ownedByNonFocusableFocusScopeOwner(El
ement& element) | 216 ScopedFocusNavigation ScopedFocusNavigation::ownedByNonFocusableFocusScopeOwner(
Element& element) |
| 131 { | 217 { |
| 132 if (isShadowHost(element)) | 218 if (isShadowHost(element)) |
| 133 return FocusNavigationScope::ownedByShadowHost(element); | 219 return ScopedFocusNavigation::ownedByShadowHost(element); |
| 134 ASSERT(isShadowInsertionPointFocusScopeOwner(element)); | 220 if (isShadowInsertionPointFocusScopeOwner(element)) |
| 135 return FocusNavigationScope::ownedByShadowInsertionPoint(toHTMLShadowElement
(element)); | 221 return ScopedFocusNavigation::ownedByShadowInsertionPoint(toHTMLShadowEl
ement(element)); |
| 222 ASSERT(isHTMLSlotElement(element)); |
| 223 return ScopedFocusNavigation::ownedByHTMLSlotElement(toHTMLSlotElement(eleme
nt)); |
| 136 } | 224 } |
| 137 | 225 |
| 138 FocusNavigationScope FocusNavigationScope::ownedByShadowHost(const Element& elem
ent) | 226 ScopedFocusNavigation ScopedFocusNavigation::ownedByShadowHost(const Element& el
ement) |
| 139 { | 227 { |
| 140 ASSERT(isShadowHost(element)); | 228 ASSERT(isShadowHost(element)); |
| 141 return FocusNavigationScope(&element.shadow()->youngestShadowRoot()); | 229 return ScopedFocusNavigation(*&element.shadow()->youngestShadowRoot(), nullp
tr); |
| 142 } | 230 } |
| 143 | 231 |
| 144 FocusNavigationScope FocusNavigationScope::ownedByIFrame(const HTMLFrameOwnerEle
ment& frame) | 232 ScopedFocusNavigation ScopedFocusNavigation::ownedByIFrame(const HTMLFrameOwnerE
lement& frame) |
| 145 { | 233 { |
| 146 ASSERT(frame.contentFrame()); | 234 ASSERT(frame.contentFrame()); |
| 147 ASSERT(frame.contentFrame()->isLocalFrame()); | 235 ASSERT(frame.contentFrame()->isLocalFrame()); |
| 148 return FocusNavigationScope(toLocalFrame(frame.contentFrame())->document()); | 236 toLocalFrame(frame.contentFrame())->document()->updateDistribution(); |
| 237 return ScopedFocusNavigation(*toLocalFrame(frame.contentFrame())->document()
, nullptr); |
| 149 } | 238 } |
| 150 | 239 |
| 151 FocusNavigationScope FocusNavigationScope::ownedByShadowInsertionPoint(HTMLShado
wElement& shadowInsertionPoint) | 240 ScopedFocusNavigation ScopedFocusNavigation::ownedByShadowInsertionPoint(HTMLSha
dowElement& shadowInsertionPoint) |
| 152 { | 241 { |
| 153 ASSERT(isShadowInsertionPointFocusScopeOwner(shadowInsertionPoint)); | 242 ASSERT(isShadowInsertionPointFocusScopeOwner(shadowInsertionPoint)); |
| 154 return FocusNavigationScope(shadowInsertionPoint.olderShadowRoot()); | 243 return ScopedFocusNavigation(*shadowInsertionPoint.olderShadowRoot(), nullpt
r); |
| 244 } |
| 245 |
| 246 ScopedFocusNavigation ScopedFocusNavigation::ownedByHTMLSlotElement(const HTMLSl
otElement& element) |
| 247 { |
| 248 return ScopedFocusNavigation(const_cast<HTMLSlotElement&>(element), nullptr)
; |
| 155 } | 249 } |
| 156 | 250 |
| 157 inline void dispatchBlurEvent(const Document& document, Element& focusedElement) | 251 inline void dispatchBlurEvent(const Document& document, Element& focusedElement) |
| 158 { | 252 { |
| 159 focusedElement.dispatchBlurEvent(nullptr, WebFocusTypePage); | 253 focusedElement.dispatchBlurEvent(nullptr, WebFocusTypePage); |
| 160 if (focusedElement == document.focusedElement()) { | 254 if (focusedElement == document.focusedElement()) { |
| 161 focusedElement.dispatchFocusOutEvent(EventTypeNames::focusout, nullptr); | 255 focusedElement.dispatchFocusOutEvent(EventTypeNames::focusout, nullptr); |
| 162 if (focusedElement == document.focusedElement()) | 256 if (focusedElement == document.focusedElement()) |
| 163 focusedElement.dispatchFocusOutEvent(EventTypeNames::DOMFocusOut, nu
llptr); | 257 focusedElement.dispatchFocusOutEvent(EventTypeNames::DOMFocusOut, nu
llptr); |
| 164 } | 258 } |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 227 return isShadowHostWithoutCustomFocusLogic(element) && !element.isKeyboardFo
cusable(); | 321 return isShadowHostWithoutCustomFocusLogic(element) && !element.isKeyboardFo
cusable(); |
| 228 } | 322 } |
| 229 | 323 |
| 230 inline bool isKeyboardFocusableShadowHost(const Element& element) | 324 inline bool isKeyboardFocusableShadowHost(const Element& element) |
| 231 { | 325 { |
| 232 return isShadowHostWithoutCustomFocusLogic(element) && element.isKeyboardFoc
usable(); | 326 return isShadowHostWithoutCustomFocusLogic(element) && element.isKeyboardFoc
usable(); |
| 233 } | 327 } |
| 234 | 328 |
| 235 inline bool isNonFocusableFocusScopeOwner(Element& element) | 329 inline bool isNonFocusableFocusScopeOwner(Element& element) |
| 236 { | 330 { |
| 237 return isNonKeyboardFocusableShadowHost(element) || isShadowInsertionPointFo
cusScopeOwner(element); | 331 return isNonKeyboardFocusableShadowHost(element) || isShadowInsertionPointFo
cusScopeOwner(element) || isHTMLSlotElement(element); |
| 238 } | 332 } |
| 239 | 333 |
| 240 inline bool isShadowHostDelegatesFocus(const Element& element) | 334 inline bool isShadowHostDelegatesFocus(const Element& element) |
| 241 { | 335 { |
| 242 return element.authorShadowRoot() && element.authorShadowRoot()->delegatesFo
cus(); | 336 return element.authorShadowRoot() && element.authorShadowRoot()->delegatesFo
cus(); |
| 243 } | 337 } |
| 244 | 338 |
| 245 inline int adjustedTabIndex(Element& element) | 339 inline int adjustedTabIndex(Element& element) |
| 246 { | 340 { |
| 247 return isNonFocusableFocusScopeOwner(element) ? 0 : element.tabIndex(); | 341 return isNonFocusableFocusScopeOwner(element) ? 0 : element.tabIndex(); |
| 248 } | 342 } |
| 249 | 343 |
| 250 inline bool shouldVisit(Element& element) | 344 inline bool shouldVisit(Element& element) |
| 251 { | 345 { |
| 252 return element.isKeyboardFocusable() || isNonFocusableFocusScopeOwner(elemen
t); | 346 return element.isKeyboardFocusable() || isNonFocusableFocusScopeOwner(elemen
t); |
| 253 } | 347 } |
| 254 | 348 |
| 255 Element* findElementWithExactTabIndex(Element* start, int tabIndex, WebFocusType
type) | 349 Element* findElementWithExactTabIndex(ScopedFocusNavigation& scope, int tabIndex
, WebFocusType type) |
| 256 { | 350 { |
| 257 // Search is inclusive of start | 351 // Search is inclusive of start |
| 258 for (Element* element = start; element; element = type == WebFocusTypeForwar
d ? ElementTraversal::next(*element) : ElementTraversal::previous(*element)) { | 352 for (; scope.currentElement(); type == WebFocusTypeForward ? scope.moveToNex
t() : scope.moveToPrevious()) { |
| 259 if (shouldVisit(*element) && adjustedTabIndex(*element) == tabIndex) | 353 Element* current = scope.currentElement(); |
| 260 return element; | 354 if (shouldVisit(*current) && adjustedTabIndex(*current) == tabIndex) |
| 355 return current; |
| 261 } | 356 } |
| 262 return nullptr; | 357 return nullptr; |
| 263 } | 358 } |
| 264 | 359 |
| 265 Element* nextElementWithGreaterTabIndex(Element* start, int tabIndex) | 360 Element* nextElementWithGreaterTabIndex(ScopedFocusNavigation& scope, int tabInd
ex) |
| 266 { | 361 { |
| 267 // Search is inclusive of start | 362 // Search is inclusive of start |
| 268 int winningTabIndex = std::numeric_limits<short>::max() + 1; | 363 int winningTabIndex = std::numeric_limits<short>::max() + 1; |
| 269 Element* winner = nullptr; | 364 Element* winner = nullptr; |
| 270 for (Element& element : ElementTraversal::startsAt(start)) { | 365 for (; scope.currentElement(); scope.moveToNext()) { |
| 271 int currentTabIndex = adjustedTabIndex(element); | 366 Element* current = scope.currentElement(); |
| 272 if (shouldVisit(element) && currentTabIndex > tabIndex && currentTabInde
x < winningTabIndex) { | 367 int currentTabIndex = adjustedTabIndex(*current); |
| 273 winner = &element; | 368 if (shouldVisit(*current) && currentTabIndex > tabIndex && currentTabInd
ex < winningTabIndex) { |
| 369 winner = current; |
| 274 winningTabIndex = currentTabIndex; | 370 winningTabIndex = currentTabIndex; |
| 275 } | 371 } |
| 276 } | 372 } |
| 277 return winner; | 373 return winner; |
| 278 } | 374 } |
| 279 | 375 |
| 280 Element* previousElementWithLowerTabIndex(Element* start, int tabIndex) | 376 Element* previousElementWithLowerTabIndex(ScopedFocusNavigation& scope, int tabI
ndex) |
| 281 { | 377 { |
| 282 // Search is inclusive of start | 378 // Search is inclusive of start |
| 283 int winningTabIndex = 0; | 379 int winningTabIndex = 0; |
| 284 Element* winner = nullptr; | 380 Element* winner = nullptr; |
| 285 for (Element* element = start; element; element = ElementTraversal::previous
(*element)) { | 381 for (; scope.currentElement(); scope.moveToPrevious()) { |
| 286 int currentTabIndex = adjustedTabIndex(*element); | 382 Element* current = scope.currentElement(); |
| 287 if (shouldVisit(*element) && currentTabIndex < tabIndex && currentTabInd
ex > winningTabIndex) { | 383 int currentTabIndex = adjustedTabIndex(*current); |
| 288 winner = element; | 384 if (shouldVisit(*current) && currentTabIndex < tabIndex && currentTabInd
ex > winningTabIndex) { |
| 385 winner = current; |
| 289 winningTabIndex = currentTabIndex; | 386 winningTabIndex = currentTabIndex; |
| 290 } | 387 } |
| 291 } | 388 } |
| 292 return winner; | 389 return winner; |
| 293 } | 390 } |
| 294 | 391 |
| 295 Element* nextFocusableElement(const FocusNavigationScope& scope, Element* start) | 392 Element* nextFocusableElement(ScopedFocusNavigation& scope) |
| 296 { | 393 { |
| 297 if (start) { | 394 Element* current = scope.currentElement(); |
| 298 int tabIndex = adjustedTabIndex(*start); | 395 if (current) { |
| 396 int tabIndex = adjustedTabIndex(*current); |
| 299 // If an element is excluded from the normal tabbing cycle, the next foc
usable element is determined by tree order | 397 // If an element is excluded from the normal tabbing cycle, the next foc
usable element is determined by tree order |
| 300 if (tabIndex < 0) { | 398 if (tabIndex < 0) { |
| 301 for (Element& element : ElementTraversal::startsAfter(*start)) { | 399 for (scope.moveToNext(); scope.currentElement(); scope.moveToNext())
{ |
| 302 if (shouldVisit(element) && adjustedTabIndex(element) >= 0) | 400 current = scope.currentElement(); |
| 303 return &element; | 401 if (shouldVisit(*current) && adjustedTabIndex(*current) >= 0) |
| 402 return current; |
| 304 } | 403 } |
| 305 } else { | 404 } else { |
| 306 // First try to find an element with the same tabindex as start that
comes after start in the scope. | 405 // First try to find an element with the same tabindex as start that
comes after start in the scope. |
| 307 if (Element* winner = findElementWithExactTabIndex(ElementTraversal:
:next(*start), tabIndex, WebFocusTypeForward)) | 406 scope.moveToNext(); |
| 407 if (Element* winner = findElementWithExactTabIndex(scope, tabIndex,
WebFocusTypeForward)) |
| 308 return winner; | 408 return winner; |
| 309 } | 409 } |
| 310 if (!tabIndex) { | 410 if (!tabIndex) { |
| 311 // We've reached the last element in the document with a tabindex of
0. This is the end of the tabbing order. | 411 // We've reached the last element in the document with a tabindex of
0. This is the end of the tabbing order. |
| 312 return nullptr; | 412 return nullptr; |
| 313 } | 413 } |
| 314 } | 414 } |
| 315 | 415 |
| 316 // Look for the first element in the scope that: | 416 // Look for the first element in the scope that: |
| 317 // 1) has the lowest tabindex that is higher than start's tabindex (or 0, if
start is null), and | 417 // 1) has the lowest tabindex that is higher than start's tabindex (or 0, if
start is null), and |
| 318 // 2) comes first in the scope, if there's a tie. | 418 // 2) comes first in the scope, if there's a tie. |
| 319 if (Element* winner = nextElementWithGreaterTabIndex(scope.firstElement(), s
tart ? adjustedTabIndex(*start) : 0)) | 419 scope.moveToFirst(); |
| 420 if (Element* winner = nextElementWithGreaterTabIndex(scope, current ? adjust
edTabIndex(*current) : 0)) { |
| 320 return winner; | 421 return winner; |
| 422 } |
| 321 | 423 |
| 322 // There are no elements with a tabindex greater than start's tabindex, | 424 // There are no elements with a tabindex greater than start's tabindex, |
| 323 // so find the first element with a tabindex of 0. | 425 // so find the first element with a tabindex of 0. |
| 324 return findElementWithExactTabIndex(scope.firstElement(), 0, WebFocusTypeFor
ward); | 426 scope.moveToFirst(); |
| 427 return findElementWithExactTabIndex(scope, 0, WebFocusTypeForward); |
| 325 } | 428 } |
| 326 | 429 |
| 327 Element* previousFocusableElement(const FocusNavigationScope& scope, Element* st
art) | 430 Element* previousFocusableElement(ScopedFocusNavigation& scope) |
| 328 { | 431 { |
| 329 Element* lastElement = scope.lastElement(); | |
| 330 | |
| 331 // First try to find the last element in the scope that comes before start a
nd has the same tabindex as start. | 432 // First try to find the last element in the scope that comes before start a
nd has the same tabindex as start. |
| 332 // If start is null, find the last element in the scope with a tabindex of 0
. | 433 // If start is null, find the last element in the scope with a tabindex of 0
. |
| 333 Element* startElement; | 434 int tabIndex; |
| 334 int startTabIndex; | 435 Element* current = scope.currentElement(); |
| 335 if (start) { | 436 if (current) { |
| 336 startElement = ElementTraversal::previous(*start); | 437 scope.moveToPrevious(); |
| 337 startTabIndex = adjustedTabIndex(*start); | 438 tabIndex = adjustedTabIndex(*current); |
| 338 } else { | 439 } else { |
| 339 startElement = lastElement; | 440 scope.moveToLast(); |
| 340 startTabIndex = 0; | 441 tabIndex = 0; |
| 341 } | 442 } |
| 342 | 443 |
| 343 // However, if an element is excluded from the normal tabbing cycle, the pre
vious focusable element is determined by tree order | 444 // However, if an element is excluded from the normal tabbing cycle, the pre
vious focusable element is determined by tree order |
| 344 if (startTabIndex < 0) { | 445 if (tabIndex < 0) { |
| 345 for (Element* element = startElement; element; element = ElementTraversa
l::previous(*element)) { | 446 for (; scope.currentElement(); scope.moveToPrevious()) { |
| 346 if (shouldVisit(*element) && adjustedTabIndex(*element) >= 0) | 447 current = scope.currentElement(); |
| 347 return element; | 448 if (shouldVisit(*current) && adjustedTabIndex(*current) >= 0) |
| 449 return current; |
| 348 } | 450 } |
| 349 } else { | 451 } else { |
| 350 if (Element* winner = findElementWithExactTabIndex(startElement, startTa
bIndex, WebFocusTypeBackward)) | 452 if (Element* winner = findElementWithExactTabIndex(scope, tabIndex, WebF
ocusTypeBackward)) |
| 351 return winner; | 453 return winner; |
| 352 } | 454 } |
| 353 | 455 |
| 354 // There are no elements before start with the same tabindex as start, so lo
ok for an element that: | 456 // There are no elements before start with the same tabindex as start, so lo
ok for an element that: |
| 355 // 1) has the highest non-zero tabindex (that is less than start's tabindex)
, and | 457 // 1) has the highest non-zero tabindex (that is less than start's tabindex)
, and |
| 356 // 2) comes last in the scope, if there's a tie. | 458 // 2) comes last in the scope, if there's a tie. |
| 357 startTabIndex = (start && startTabIndex) ? startTabIndex : std::numeric_limi
ts<short>::max(); | 459 tabIndex = (current && tabIndex) ? tabIndex : std::numeric_limits<short>::ma
x(); |
| 358 return previousElementWithLowerTabIndex(lastElement, startTabIndex); | 460 scope.moveToLast(); |
| 461 return previousElementWithLowerTabIndex(scope, tabIndex); |
| 359 } | 462 } |
| 360 | 463 |
| 361 // Searches through the given tree scope, starting from start element, for the n
ext/previous | 464 // Searches through the given tree scope, starting from start element, for the n
ext/previous |
| 362 // selectable element that comes after/before start element. | 465 // selectable element that comes after/before start element. |
| 363 // The order followed is as specified in the HTML spec[1], which is elements wit
h tab indexes | 466 // The order followed is as specified in the HTML spec[1], which is elements wit
h tab indexes |
| 364 // first (from lowest to highest), and then elements without tab indexes (in doc
ument order). | 467 // first (from lowest to highest), and then elements without tab indexes (in doc
ument order). |
| 365 // The search algorithm also conforms the Shadow DOM spec[2], which inserts sequ
ence in a shadow | 468 // The search algorithm also conforms the Shadow DOM spec[2], which inserts sequ
ence in a shadow |
| 366 // tree into its host. | 469 // tree into its host. |
| 367 // | 470 // |
| 368 // @param start The element from which to start searching. The element after thi
s will be focused. | 471 // @param start The element from which to start searching. The element after thi
s will be focused. |
| 369 // May be null. | 472 // May be null. |
| 370 // @return The focus element that comes after/before start element. | 473 // @return The focus element that comes after/before start element. |
| 371 // | 474 // |
| 372 // [1] https://html.spec.whatwg.org/multipage/interaction.html#sequential-focus-
navigation | 475 // [1] https://html.spec.whatwg.org/multipage/interaction.html#sequential-focus-
navigation |
| 373 // [2] https://w3c.github.io/webcomponents/spec/shadow/#focus-navigation | 476 // [2] https://w3c.github.io/webcomponents/spec/shadow/#focus-navigation |
| 374 inline Element* findFocusableElementInternal(WebFocusType type, const FocusNavig
ationScope& scope, Element* element) | 477 inline Element* findFocusableElementInternal(WebFocusType type, ScopedFocusNavig
ation& scope) |
| 375 { | 478 { |
| 376 Element* found = (type == WebFocusTypeForward) ? nextFocusableElement(scope,
element) : previousFocusableElement(scope, element); | 479 Element* found = (type == WebFocusTypeForward) ? nextFocusableElement(scope)
: previousFocusableElement(scope); |
| 377 return found; | 480 return found; |
| 378 } | 481 } |
| 379 | 482 |
| 380 Element* findFocusableElementRecursivelyForward(const FocusNavigationScope& scop
e, Element* start) | 483 Element* findFocusableElementRecursivelyForward(ScopedFocusNavigation& scope) |
| 381 { | 484 { |
| 382 // Starting element is exclusive. | 485 // Starting element is exclusive. |
| 383 Element* found = findFocusableElementInternal(WebFocusTypeForward, scope, st
art); | 486 Element* found = findFocusableElementInternal(WebFocusTypeForward, scope); |
| 384 while (found) { | 487 while (found) { |
| 385 if (isShadowHostDelegatesFocus(*found)) { | 488 if (isShadowHostDelegatesFocus(*found)) { |
| 386 // If tabindex is positive, find focusable element inside its shadow
tree. | 489 // If tabindex is positive, find focusable element inside its shadow
tree. |
| 387 if (found->tabIndex() >= 0 && isShadowHostWithoutCustomFocusLogic(*f
ound)) { | 490 if (found->tabIndex() >= 0 && isShadowHostWithoutCustomFocusLogic(*f
ound)) { |
| 388 FocusNavigationScope innerScope = FocusNavigationScope::ownedByS
hadowHost(*found); | 491 ScopedFocusNavigation innerScope = ScopedFocusNavigation::ownedB
yShadowHost(*found); |
| 389 if (Element* foundInInnerFocusScope = findFocusableElementRecurs
ivelyForward(innerScope, nullptr)) | 492 if (Element* foundInInnerFocusScope = findFocusableElementRecurs
ivelyForward(innerScope)) |
| 390 return foundInInnerFocusScope; | 493 return foundInInnerFocusScope; |
| 391 } | 494 } |
| 392 // Skip to the next element in the same scope. | 495 // Skip to the next element in the same scope. |
| 393 found = findFocusableElementInternal(WebFocusTypeForward, scope, fou
nd); | 496 found = findFocusableElementInternal(WebFocusTypeForward, scope); |
| 394 continue; | 497 continue; |
| 395 } | 498 } |
| 396 if (!isNonFocusableFocusScopeOwner(*found)) | 499 if (!isNonFocusableFocusScopeOwner(*found)) |
| 397 return found; | 500 return found; |
| 398 | 501 |
| 399 // Now |found| is on a non focusable scope owner (either shadow host or
<shadow>) | 502 // Now |found| is on a non focusable scope owner (either shadow host or
<shadow> or slot) |
| 400 // Find inside the inward scope and return it if found. Otherwise contin
ue searching in the same | 503 // Find inside the inward scope and return it if found. Otherwise contin
ue searching in the same |
| 401 // scope. | 504 // scope. |
| 402 FocusNavigationScope innerScope = FocusNavigationScope::ownedByNonFocusa
bleFocusScopeOwner(*found); | 505 ScopedFocusNavigation innerScope = ScopedFocusNavigation::ownedByNonFocu
sableFocusScopeOwner(*found); |
| 403 if (Element* foundInInnerFocusScope = findFocusableElementRecursivelyFor
ward(innerScope, nullptr)) | 506 if (Element* foundInInnerFocusScope = findFocusableElementRecursivelyFor
ward(innerScope)) |
| 404 return foundInInnerFocusScope; | 507 return foundInInnerFocusScope; |
| 405 | 508 |
| 406 found = findFocusableElementInternal(WebFocusTypeForward, scope, found); | 509 scope.setCurrentElement(found); |
| 510 found = findFocusableElementInternal(WebFocusTypeForward, scope); |
| 407 } | 511 } |
| 408 return nullptr; | 512 return nullptr; |
| 409 } | 513 } |
| 410 | 514 |
| 411 Element* findFocusableElementRecursivelyBackward(const FocusNavigationScope& sco
pe, Element* start) | 515 Element* findFocusableElementRecursivelyBackward(ScopedFocusNavigation& scope) |
| 412 { | 516 { |
| 413 // Starting element is exclusive. | 517 // Starting element is exclusive. |
| 414 Element* found = findFocusableElementInternal(WebFocusTypeBackward, scope, s
tart); | 518 Element* found = findFocusableElementInternal(WebFocusTypeBackward, scope); |
| 519 |
| 415 while (found) { | 520 while (found) { |
| 416 // Now |found| is on a focusable shadow host. | 521 // Now |found| is on a focusable shadow host. |
| 417 // Find inside shadow backwards. If any focusable element is found, retu
rn it, otherwise return | 522 // Find inside shadow backwards. If any focusable element is found, retu
rn it, otherwise return |
| 418 // the host itself. | 523 // the host itself. |
| 419 if (isKeyboardFocusableShadowHost(*found)) { | 524 if (isKeyboardFocusableShadowHost(*found)) { |
| 420 FocusNavigationScope innerScope = FocusNavigationScope::ownedByShado
wHost(*found); | 525 ScopedFocusNavigation innerScope = ScopedFocusNavigation::ownedBySha
dowHost(*found); |
| 421 Element* foundInInnerFocusScope = findFocusableElementRecursivelyBac
kward(innerScope, nullptr); | 526 Element* foundInInnerFocusScope = findFocusableElementRecursivelyBac
kward(innerScope); |
| 422 if (foundInInnerFocusScope) | 527 if (foundInInnerFocusScope) |
| 423 return foundInInnerFocusScope; | 528 return foundInInnerFocusScope; |
| 424 if (isShadowHostDelegatesFocus(*found)) { | 529 if (isShadowHostDelegatesFocus(*found)) { |
| 425 found = findFocusableElementInternal(WebFocusTypeBackward, scope
, found); | 530 found = findFocusableElementInternal(WebFocusTypeBackward, scope
); |
| 426 continue; | 531 continue; |
| 427 } | 532 } |
| 428 return found; | 533 return found; |
| 429 } | 534 } |
| 430 | 535 |
| 431 // If delegatesFocus is true and tabindex is negative, skip the whole sh
adow tree under the | 536 // If delegatesFocus is true and tabindex is negative, skip the whole sh
adow tree under the |
| 432 // shadow host. | 537 // shadow host. |
| 433 if (isShadowHostDelegatesFocus(*found) && found->tabIndex() < 0) { | 538 if (isShadowHostDelegatesFocus(*found) && found->tabIndex() < 0) { |
| 434 found = findFocusableElementInternal(WebFocusTypeBackward, scope, fo
und); | 539 found = findFocusableElementInternal(WebFocusTypeBackward, scope); |
| 435 continue; | 540 continue; |
| 436 } | 541 } |
| 437 | 542 |
| 438 // Now |found| is on a non focusable scope owner (either shadow host or
<shadow>). | 543 // Now |found| is on a non focusable scope owner (either shadow host or
<shadow> or slot). |
| 439 // Find focusable element in descendant scope. If not found, find next f
ocusable element within the | 544 // Find focusable element in descendant scope. If not found, find next f
ocusable element within the |
| 440 // current scope. | 545 // current scope. |
| 441 if (isNonFocusableFocusScopeOwner(*found)) { | 546 if (isNonFocusableFocusScopeOwner(*found)) { |
| 442 FocusNavigationScope innerScope = FocusNavigationScope::ownedByNonFo
cusableFocusScopeOwner(*found); | 547 ScopedFocusNavigation innerScope = ScopedFocusNavigation::ownedByNon
FocusableFocusScopeOwner(*found); |
| 443 Element* foundInInnerFocusScope = findFocusableElementRecursivelyBac
kward(innerScope, nullptr); | 548 Element* foundInInnerFocusScope = findFocusableElementRecursivelyBac
kward(innerScope); |
| 549 |
| 444 if (foundInInnerFocusScope) | 550 if (foundInInnerFocusScope) |
| 445 return foundInInnerFocusScope; | 551 return foundInInnerFocusScope; |
| 446 found = findFocusableElementInternal(WebFocusTypeBackward, scope, fo
und); | 552 found = findFocusableElementInternal(WebFocusTypeBackward, scope); |
| 447 continue; | 553 continue; |
| 448 } | 554 } |
| 449 if (!isShadowHostDelegatesFocus(*found)) | 555 if (!isShadowHostDelegatesFocus(*found)) |
| 450 return found; | 556 return found; |
| 451 found = findFocusableElementInternal(WebFocusTypeBackward, scope, found)
; | 557 |
| 558 scope.setCurrentElement(found); |
| 559 found = findFocusableElementInternal(WebFocusTypeBackward, scope); |
| 452 } | 560 } |
| 453 return nullptr; | 561 return nullptr; |
| 454 } | 562 } |
| 455 | 563 |
| 456 Element* findFocusableElementRecursively(WebFocusType type, const FocusNavigatio
nScope& scope, Element* start) | 564 Element* findFocusableElementRecursively(WebFocusType type, ScopedFocusNavigatio
n& scope) |
| 457 { | 565 { |
| 458 return (type == WebFocusTypeForward) ? | 566 return (type == WebFocusTypeForward) ? |
| 459 findFocusableElementRecursivelyForward(scope, start) : | 567 findFocusableElementRecursivelyForward(scope) : |
| 460 findFocusableElementRecursivelyBackward(scope, start); | 568 findFocusableElementRecursivelyBackward(scope); |
| 461 } | 569 } |
| 462 | 570 |
| 463 Element* findFocusableElementDescendingDownIntoFrameDocument(WebFocusType type,
Element* element) | 571 Element* findFocusableElementDescendingDownIntoFrameDocument(WebFocusType type,
Element* element) |
| 464 { | 572 { |
| 465 // The element we found might be a HTMLFrameOwnerElement, so descend down th
e tree until we find either: | 573 // The element we found might be a HTMLFrameOwnerElement, so descend down th
e tree until we find either: |
| 466 // 1) a focusable element, or | 574 // 1) a focusable element, or |
| 467 // 2) the deepest-nested HTMLFrameOwnerElement. | 575 // 2) the deepest-nested HTMLFrameOwnerElement. |
| 468 while (element && element->isFrameOwnerElement()) { | 576 while (element && element->isFrameOwnerElement()) { |
| 469 HTMLFrameOwnerElement& owner = toHTMLFrameOwnerElement(*element); | 577 HTMLFrameOwnerElement& owner = toHTMLFrameOwnerElement(*element); |
| 470 if (!owner.contentFrame() || !owner.contentFrame()->isLocalFrame()) | 578 if (!owner.contentFrame() || !owner.contentFrame()->isLocalFrame()) |
| 471 break; | 579 break; |
| 472 toLocalFrame(owner.contentFrame())->document()->updateLayoutIgnorePendin
gStylesheets(); | 580 toLocalFrame(owner.contentFrame())->document()->updateLayoutIgnorePendin
gStylesheets(); |
| 473 Element* foundElement = findFocusableElementRecursively(type, FocusNavig
ationScope::ownedByIFrame(owner), nullptr); | 581 ScopedFocusNavigation scope = ScopedFocusNavigation::ownedByIFrame(owner
); |
| 582 Element* foundElement = findFocusableElementRecursively(type, scope); |
| 474 if (!foundElement) | 583 if (!foundElement) |
| 475 break; | 584 break; |
| 476 ASSERT(element != foundElement); | 585 ASSERT(element != foundElement); |
| 477 element = foundElement; | 586 element = foundElement; |
| 478 } | 587 } |
| 479 return element; | 588 return element; |
| 480 } | 589 } |
| 481 | 590 |
| 482 Element* findFocusableElementAcrossFocusScopesForward(const FocusNavigationScope
& scope, Element* current) | 591 Element* findFocusableElementAcrossFocusScopesForward(ScopedFocusNavigation& sco
pe) |
| 483 { | 592 { |
| 593 Element* current = scope.currentElement(); |
| 484 ASSERT(!current || !isNonFocusableShadowHost(*current)); | 594 ASSERT(!current || !isNonFocusableShadowHost(*current)); |
| 485 Element* found; | 595 Element* found; |
| 486 if (current && isShadowHostWithoutCustomFocusLogic(*current)) { | 596 if (current && isShadowHostWithoutCustomFocusLogic(*current)) { |
| 487 FocusNavigationScope innerScope = FocusNavigationScope::ownedByShadowHos
t(*current); | 597 ScopedFocusNavigation innerScope = ScopedFocusNavigation::ownedByShadowH
ost(*current); |
| 488 Element* foundInInnerFocusScope = findFocusableElementRecursivelyForward
(innerScope, nullptr); | 598 Element* foundInInnerFocusScope = findFocusableElementRecursivelyForward
(innerScope); |
| 489 found = foundInInnerFocusScope ? foundInInnerFocusScope : findFocusableE
lementRecursivelyForward(scope, current); | 599 found = foundInInnerFocusScope ? foundInInnerFocusScope : findFocusableE
lementRecursivelyForward(scope); |
| 490 } else { | 600 } else { |
| 491 found = findFocusableElementRecursivelyForward(scope, current); | 601 found = findFocusableElementRecursivelyForward(scope); |
| 492 } | 602 } |
| 493 | 603 |
| 494 // If there's no focusable element to advance to, move up the focus scopes u
ntil we find one. | 604 // If there's no focusable element to advance to, move up the focus scopes u
ntil we find one. |
| 495 FocusNavigationScope currentScope = scope; | 605 ScopedFocusNavigation currentScope = scope; |
| 496 while (!found) { | 606 while (!found) { |
| 497 Element* owner = currentScope.owner(); | 607 Element* owner = currentScope.owner(); |
| 498 if (!owner) | 608 if (!owner) |
| 499 break; | 609 break; |
| 500 currentScope = FocusNavigationScope::focusNavigationScopeOf(*owner); | 610 currentScope = ScopedFocusNavigation::createScopedFocusNavigation(*owner
, owner); |
| 501 found = findFocusableElementRecursivelyForward(currentScope, owner); | 611 found = findFocusableElementRecursivelyForward(currentScope); |
| 502 } | 612 } |
| 503 return findFocusableElementDescendingDownIntoFrameDocument(WebFocusTypeForwa
rd, found); | 613 return findFocusableElementDescendingDownIntoFrameDocument(WebFocusTypeForwa
rd, found); |
| 504 } | 614 } |
| 505 | 615 |
| 506 Element* findFocusableElementAcrossFocusScopesBackward(const FocusNavigationScop
e& scope, Element* current) | 616 Element* findFocusableElementAcrossFocusScopesBackward(ScopedFocusNavigation& sc
ope) |
| 507 { | 617 { |
| 508 ASSERT(!current || !isNonFocusableShadowHost(*current)); | 618 ASSERT(!scope.currentElement() || !isNonFocusableShadowHost(*scope.currentEl
ement())); |
| 509 Element* found = findFocusableElementRecursivelyBackward(scope, current); | 619 Element* found = findFocusableElementRecursivelyBackward(scope); |
| 510 | 620 |
| 511 // If there's no focusable element to advance to, move up the focus scopes u
ntil we find one. | 621 // If there's no focusable element to advance to, move up the focus scopes u
ntil we find one. |
| 512 FocusNavigationScope currentScope = scope; | 622 ScopedFocusNavigation currentScope = scope; |
| 513 while (!found) { | 623 while (!found) { |
| 514 Element* owner = currentScope.owner(); | 624 Element* owner = currentScope.owner(); |
| 515 if (!owner) | 625 if (!owner) |
| 516 break; | 626 break; |
| 517 currentScope = FocusNavigationScope::focusNavigationScopeOf(*owner); | 627 currentScope = ScopedFocusNavigation::createScopedFocusNavigation(*owner
, owner); |
| 518 if (isKeyboardFocusableShadowHost(*owner) && !isShadowHostDelegatesFocus
(*owner)) { | 628 if (isKeyboardFocusableShadowHost(*owner) && !isShadowHostDelegatesFocus
(*owner)) { |
| 519 found = owner; | 629 found = owner; |
| 520 break; | 630 break; |
| 521 } | 631 } |
| 522 found = findFocusableElementRecursivelyBackward(currentScope, owner); | 632 found = findFocusableElementRecursivelyBackward(currentScope); |
| 523 } | 633 } |
| 524 return findFocusableElementDescendingDownIntoFrameDocument(WebFocusTypeBackw
ard, found); | 634 return findFocusableElementDescendingDownIntoFrameDocument(WebFocusTypeBackw
ard, found); |
| 525 } | 635 } |
| 526 | 636 |
| 527 Element* findFocusableElementAcrossFocusScopes(WebFocusType type, const FocusNav
igationScope& scope, Element* current) | 637 Element* findFocusableElementAcrossFocusScopes(WebFocusType type, ScopedFocusNav
igation& scope) |
| 528 { | 638 { |
| 529 return (type == WebFocusTypeForward) ? | 639 return (type == WebFocusTypeForward) ? |
| 530 findFocusableElementAcrossFocusScopesForward(scope, current) : | 640 findFocusableElementAcrossFocusScopesForward(scope) : |
| 531 findFocusableElementAcrossFocusScopesBackward(scope, current); | 641 findFocusableElementAcrossFocusScopesBackward(scope); |
| 532 } | 642 } |
| 533 | 643 |
| 534 inline Element* adjustToElement(Node* node, WebFocusType type) | 644 inline Element* adjustToElement(Node* node, WebFocusType type) |
| 535 { | 645 { |
| 536 ASSERT(type == WebFocusTypeForward || type == WebFocusTypeBackward); | 646 ASSERT(type == WebFocusTypeForward || type == WebFocusTypeBackward); |
| 537 if (!node) | 647 if (!node) |
| 538 return nullptr; | 648 return nullptr; |
| 539 if (node->isElementNode()) | 649 if (node->isElementNode()) |
| 540 return toElement(node); | 650 return toElement(node); |
| 541 // The returned element is used as an *exclusive* start element. Thus, we sh
ould return the result of ElementTraversal::previous(*node), | 651 // The returned element is used as an *exclusive* start element. Thus, we sh
ould return the result of ElementTraversal::previous(*node), |
| 542 // instead of ElementTraversal::next(*node), if type == WebFocusTypeForward,
and vice-versa. | 652 // instead of ElementTraversal::next(*node), if type == WebFocusTypeForward,
and vice-versa. |
| 543 // The caller will call ElementTraversal::{next/previous} for the returned v
alue and get the {next|previous} element of the |node|. | 653 // The caller will call ElementTraversal::{next/previous} for the returned v
alue and get the {next|previous} element of the |node|. |
| 654 |
| 655 // TODO(yuzus) Use ScopedFocusNavigation traversal here. |
| 544 return (type == WebFocusTypeForward) ? ElementTraversal::previous(*node) : E
lementTraversal::next(*node); | 656 return (type == WebFocusTypeForward) ? ElementTraversal::previous(*node) : E
lementTraversal::next(*node); |
| 545 } | 657 } |
| 546 | 658 |
| 547 } // anonymous namespace | 659 } // anonymous namespace |
| 548 | 660 |
| 549 FocusController::FocusController(Page* page) | 661 FocusController::FocusController(Page* page) |
| 550 : m_page(page) | 662 : m_page(page) |
| 551 , m_isActive(false) | 663 , m_isActive(false) |
| 552 , m_isFocused(false) | 664 , m_isFocused(false) |
| 553 , m_isChangingFocusedFrame(false) | 665 , m_isChangingFocusedFrame(false) |
| (...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 736 } | 848 } |
| 737 | 849 |
| 738 return advanceFocusInDocumentOrder(to, start, type, false, sourceCapabilitie
s); | 850 return advanceFocusInDocumentOrder(to, start, type, false, sourceCapabilitie
s); |
| 739 } | 851 } |
| 740 | 852 |
| 741 bool FocusController::advanceFocusInDocumentOrder(LocalFrame* frame, Element* st
art, WebFocusType type, bool initialFocus, InputDeviceCapabilities* sourceCapabi
lities) | 853 bool FocusController::advanceFocusInDocumentOrder(LocalFrame* frame, Element* st
art, WebFocusType type, bool initialFocus, InputDeviceCapabilities* sourceCapabi
lities) |
| 742 { | 854 { |
| 743 ASSERT(frame); | 855 ASSERT(frame); |
| 744 Document* document = frame->document(); | 856 Document* document = frame->document(); |
| 745 ASSERT(document->documentElement()); | 857 ASSERT(document->documentElement()); |
| 858 document->updateDistribution(); |
| 746 | 859 |
| 747 Element* current = start; | 860 Element* current = start; |
| 748 if (!current && !initialFocus) | 861 if (!current && !initialFocus) |
| 749 current = document->sequentialFocusNavigationStartingPoint(type); | 862 current = document->sequentialFocusNavigationStartingPoint(type); |
| 750 | 863 |
| 751 // FIXME: Not quite correct when it comes to focus transitions leaving/enter
ing the WebView itself | 864 // FIXME: Not quite correct when it comes to focus transitions leaving/enter
ing the WebView itself |
| 752 bool caretBrowsing = frame->settings() && frame->settings()->caretBrowsingEn
abled(); | 865 bool caretBrowsing = frame->settings() && frame->settings()->caretBrowsingEn
abled(); |
| 753 | 866 |
| 754 if (caretBrowsing && !current) | 867 if (caretBrowsing && !current) |
| 755 current = adjustToElement(frame->selection().start().anchorNode(), type)
; | 868 current = adjustToElement(frame->selection().start().anchorNode(), type)
; |
| 756 | 869 |
| 757 document->updateLayoutIgnorePendingStylesheets(); | 870 document->updateLayoutIgnorePendingStylesheets(); |
| 758 | 871 ScopedFocusNavigation scope = ScopedFocusNavigation::createScopedFocusNaviga
tion(current ? *current : *document->documentElement(), current); |
| 759 RefPtrWillBeRawPtr<Element> element = findFocusableElementAcrossFocusScopes(
type, FocusNavigationScope::focusNavigationScopeOf(current ? *current : *documen
t->documentElement()), current); | 872 RefPtrWillBeRawPtr<Element> element = findFocusableElementAcrossFocusScopes(
type, scope); |
| 760 | 873 |
| 761 if (!element) { | 874 if (!element) { |
| 762 // If there's a RemoteFrame on the ancestor chain, we need to continue | 875 // If there's a RemoteFrame on the ancestor chain, we need to continue |
| 763 // searching for focusable elements there. | 876 // searching for focusable elements there. |
| 764 if (frame->localFrameRoot() != frame->tree().top()) { | 877 if (frame->localFrameRoot() != frame->tree().top()) { |
| 765 document->clearFocusedElement(); | 878 document->clearFocusedElement(); |
| 766 document->setSequentialFocusNavigationStartingPoint(nullptr); | 879 document->setSequentialFocusNavigationStartingPoint(nullptr); |
| 767 toRemoteFrame(frame->localFrameRoot()->tree().parent())->advanceFocu
s(type, frame->localFrameRoot()); | 880 toRemoteFrame(frame->localFrameRoot()->tree().parent())->advanceFocu
s(type, frame->localFrameRoot()); |
| 768 return true; | 881 return true; |
| 769 } | 882 } |
| 770 | 883 |
| 771 // We didn't find an element to focus, so we should try to pass focus to
Chrome. | 884 // We didn't find an element to focus, so we should try to pass focus to
Chrome. |
| 772 if (!initialFocus && m_page->chromeClient().canTakeFocus(type)) { | 885 if (!initialFocus && m_page->chromeClient().canTakeFocus(type)) { |
| 773 document->clearFocusedElement(); | 886 document->clearFocusedElement(); |
| 774 document->setSequentialFocusNavigationStartingPoint(nullptr); | 887 document->setSequentialFocusNavigationStartingPoint(nullptr); |
| 775 setFocusedFrame(nullptr); | 888 setFocusedFrame(nullptr); |
| 776 m_page->chromeClient().takeFocus(type); | 889 m_page->chromeClient().takeFocus(type); |
| 777 return true; | 890 return true; |
| 778 } | 891 } |
| 779 | 892 |
| 780 // Chrome doesn't want focus, so we should wrap focus. | 893 // Chrome doesn't want focus, so we should wrap focus. |
| 781 element = findFocusableElementRecursively(type, FocusNavigationScope::fo
cusNavigationScopeOf(*toLocalFrame(m_page->mainFrame())->document()->documentEle
ment()), nullptr); | 894 ScopedFocusNavigation scope = ScopedFocusNavigation::createScopedFocusNa
vigation(*toLocalFrame(m_page->mainFrame())->document()->documentElement(), null
ptr); |
| 895 element = findFocusableElementRecursively(type, scope); |
| 782 element = findFocusableElementDescendingDownIntoFrameDocument(type, elem
ent.get()); | 896 element = findFocusableElementDescendingDownIntoFrameDocument(type, elem
ent.get()); |
| 783 | 897 |
| 784 if (!element) | 898 if (!element) |
| 785 return false; | 899 return false; |
| 786 } | 900 } |
| 787 | 901 |
| 788 ASSERT(element); | 902 ASSERT(element); |
| 789 | 903 |
| 790 if (element == document->focusedElement()) { | 904 if (element == document->focusedElement()) { |
| 791 // Focus wrapped around to the same element. | 905 // Focus wrapped around to the same element. |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 831 } | 945 } |
| 832 | 946 |
| 833 element->focus(FocusParams(SelectionBehaviorOnFocus::Reset, type, sourceCapa
bilities)); | 947 element->focus(FocusParams(SelectionBehaviorOnFocus::Reset, type, sourceCapa
bilities)); |
| 834 return true; | 948 return true; |
| 835 } | 949 } |
| 836 | 950 |
| 837 Element* FocusController::findFocusableElement(WebFocusType type, Element& eleme
nt) | 951 Element* FocusController::findFocusableElement(WebFocusType type, Element& eleme
nt) |
| 838 { | 952 { |
| 839 // FIXME: No spacial navigation code yet. | 953 // FIXME: No spacial navigation code yet. |
| 840 ASSERT(type == WebFocusTypeForward || type == WebFocusTypeBackward); | 954 ASSERT(type == WebFocusTypeForward || type == WebFocusTypeBackward); |
| 841 return findFocusableElementAcrossFocusScopes(type, FocusNavigationScope::foc
usNavigationScopeOf(element), &element); | 955 ScopedFocusNavigation scope = ScopedFocusNavigation::createScopedFocusNaviga
tion(element, &element); |
| 956 return findFocusableElementAcrossFocusScopes(type, scope); |
| 842 } | 957 } |
| 843 | 958 |
| 844 Element* FocusController::findFocusableElementInShadowHost(const Element& shadow
Host) | 959 Element* FocusController::findFocusableElementInShadowHost(const Element& shadow
Host) |
| 845 { | 960 { |
| 846 ASSERT(shadowHost.authorShadowRoot()); | 961 ASSERT(shadowHost.authorShadowRoot()); |
| 847 return findFocusableElementAcrossFocusScopes(WebFocusTypeForward, FocusNavig
ationScope::ownedByShadowHost(shadowHost), nullptr); | 962 ScopedFocusNavigation scope = ScopedFocusNavigation::ownedByShadowHost(shado
wHost); |
| 963 return findFocusableElementAcrossFocusScopes(WebFocusTypeForward, scope); |
| 848 } | 964 } |
| 849 | 965 |
| 850 static bool relinquishesEditingFocus(const Element& element) | 966 static bool relinquishesEditingFocus(const Element& element) |
| 851 { | 967 { |
| 852 ASSERT(element.hasEditableStyle()); | 968 ASSERT(element.hasEditableStyle()); |
| 853 return element.document().frame() && element.rootEditableElement(); | 969 return element.document().frame() && element.rootEditableElement(); |
| 854 } | 970 } |
| 855 | 971 |
| 856 static void clearSelectionIfNeeded(LocalFrame* oldFocusedFrame, LocalFrame* newF
ocusedFrame, Element* newFocusedElement) | 972 static void clearSelectionIfNeeded(LocalFrame* oldFocusedFrame, LocalFrame* newF
ocusedFrame, Element* newFocusedElement) |
| 857 { | 973 { |
| (...skipping 282 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1140 return consumed; | 1256 return consumed; |
| 1141 } | 1257 } |
| 1142 | 1258 |
| 1143 DEFINE_TRACE(FocusController) | 1259 DEFINE_TRACE(FocusController) |
| 1144 { | 1260 { |
| 1145 visitor->trace(m_page); | 1261 visitor->trace(m_page); |
| 1146 visitor->trace(m_focusedFrame); | 1262 visitor->trace(m_focusedFrame); |
| 1147 } | 1263 } |
| 1148 | 1264 |
| 1149 } // namespace blink | 1265 } // namespace blink |
| OLD | NEW |