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