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