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