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