Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(668)

Side by Side Diff: third_party/WebKit/Source/core/dom/shadow/SlotScopedTraversal.cpp

Issue 2432293002: Fix focus navigation for nested slot case (Closed)
Patch Set: Fix bugs, add unit tests Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "core/dom/shadow/SlotScopedTraversal.h" 5 #include "core/dom/shadow/SlotScopedTraversal.h"
6 6
7 #include "core/dom/Element.h" 7 #include "core/dom/Element.h"
8 #include "core/dom/ElementTraversal.h" 8 #include "core/dom/ElementTraversal.h"
9 #include "core/html/HTMLSlotElement.h" 9 #include "core/html/HTMLSlotElement.h"
10 10
11 namespace blink { 11 namespace blink {
12 12
13 HTMLSlotElement* SlotScopedTraversal::findScopeOwnerSlot( 13 namespace {
14 const Element& current) { 14 Element* nextSkippingShadowHost(const Element& start, const Element& scope) {
hayato 2016/10/31 05:27:12 This name is confusing because it is inconsistent
kochi 2016/10/31 07:30:25 All renamed to *SkippingChildrenOfShadowHost().
15 if (Element* nearestAncestorAssignedToSlot = 15 DCHECK(scope.assignedSlot());
16 SlotScopedTraversal::nearestAncestorAssignedToSlot(current)) 16 const Element* current = &start;
hayato 2016/10/31 05:27:12 It does not need to declare |current| here. It is
kochi 2016/10/31 07:30:25 Done.
17 return nearestAncestorAssignedToSlot->assignedSlot(); 17 if (!current->authorShadowRoot()) {
18 if (Element* first = ElementTraversal::firstChild(*current))
19 return first;
20 }
21
22 while (current != scope) {
23 if (Element* nextSibling = ElementTraversal::nextSibling(*current))
24 return nextSibling;
25 current = current->parentElement();
26 }
18 return nullptr; 27 return nullptr;
19 } 28 }
20 29
21 Element* SlotScopedTraversal::nearestAncestorAssignedToSlot( 30 Element* lastWithinOrSelfSkippingShadowHost(const Element& scope) {
31 Element* current = const_cast<Element*>(&scope);
32 while (!current->authorShadowRoot()) {
hayato 2016/10/31 05:27:12 You can rewrite this with for loop.
kochi 2016/10/31 07:30:25 I'm not sure rewriting with for loop improves read
hayato 2016/10/31 08:12:00 I see. Thanks. It is okay to leave this as is beca
33 Element* lastChild = ElementTraversal::lastChild(*current);
34 if (!lastChild)
35 break;
36 current = lastChild;
37 }
38 return current;
39 }
40
41 Element* previousSkippingShadowHost(const Element& start,
42 const Element& scope) {
43 DCHECK(scope.assignedSlot());
44 DCHECK_NE(start, &scope);
45 if (Element* previousSibling = ElementTraversal::previousSibling(start))
46 return lastWithinOrSelfSkippingShadowHost(*previousSibling);
47 return start.parentElement();
48 }
49 } // namespace
50
51 HTMLSlotElement* SlotScopedTraversal::findScopeOwnerSlot(
22 const Element& current) { 52 const Element& current) {
23 // nearestAncestorAssignedToSlot returns an ancestor element of current which 53 if (Element* nearestInclusiveAncestorAssignedToSlot =
24 // is directly assigned to a slot. 54 SlotScopedTraversal::nearestInclusiveAncestorAssignedToSlot(current))
55 return nearestInclusiveAncestorAssignedToSlot->assignedSlot();
56 return nullptr;
57 }
58
59 Element* SlotScopedTraversal::nearestInclusiveAncestorAssignedToSlot(
60 const Element& current) {
25 Element* element = const_cast<Element*>(&current); 61 Element* element = const_cast<Element*>(&current);
26 for (; element; element = element->parentElement()) { 62 for (; element; element = element->parentElement()) {
27 if (element->assignedSlot()) 63 if (element->assignedSlot())
28 break; 64 break;
29 } 65 }
30 return element; 66 return element;
31 } 67 }
32 68
33 Element* SlotScopedTraversal::next(const Element& current) { 69 Element* SlotScopedTraversal::next(const Element& current) {
34 // current.assignedSlot returns a slot only when current is assigned 70 Element* nearestInclusiveAncestorAssignedToSlot =
35 // explicitly 71 SlotScopedTraversal::nearestInclusiveAncestorAssignedToSlot(current);
36 // If current is assigned to a slot, return a descendant of current, which is 72 DCHECK(nearestInclusiveAncestorAssignedToSlot);
37 // in the assigned scope of the same slot as current. 73 // Search within children of an element which is assigned to a slot.
38 HTMLSlotElement* slot = current.assignedSlot(); 74 if (Element* next = nextSkippingShadowHost(
39 Element* nearestAncestorAssignedToSlot = 75 current, *nearestInclusiveAncestorAssignedToSlot))
40 SlotScopedTraversal::nearestAncestorAssignedToSlot(current); 76 return next;
41 if (slot) { 77
42 if (Element* next = ElementTraversal::next(current, &current)) 78 // Seek to the next element assigned to the same slot.
43 return next; 79 HTMLSlotElement* slot =
44 } else { 80 nearestInclusiveAncestorAssignedToSlot->assignedSlot();
45 // If current is in assigned scope, find an assigned ancestor. 81 DCHECK(slot);
46 DCHECK(nearestAncestorAssignedToSlot);
47 if (Element* next =
48 ElementTraversal::next(current, nearestAncestorAssignedToSlot))
49 return next;
50 slot = nearestAncestorAssignedToSlot->assignedSlot();
51 DCHECK(slot);
52 }
53 HeapVector<Member<Node>> assignedNodes = slot->assignedNodes(); 82 HeapVector<Member<Node>> assignedNodes = slot->assignedNodes();
54 size_t currentIndex = assignedNodes.find(*nearestAncestorAssignedToSlot); 83 size_t currentIndex =
84 assignedNodes.find(*nearestInclusiveAncestorAssignedToSlot);
55 DCHECK_NE(currentIndex, kNotFound); 85 DCHECK_NE(currentIndex, kNotFound);
56 for (++currentIndex; currentIndex < assignedNodes.size(); ++currentIndex) { 86 for (++currentIndex; currentIndex < assignedNodes.size(); ++currentIndex) {
57 if (assignedNodes[currentIndex]->isElementNode()) 87 if (assignedNodes[currentIndex]->isElementNode())
58 return toElement(assignedNodes[currentIndex]); 88 return toElement(assignedNodes[currentIndex]);
59 } 89 }
60 return nullptr; 90 return nullptr;
61 } 91 }
62 92
63 Element* SlotScopedTraversal::previous(const Element& current) { 93 Element* SlotScopedTraversal::previous(const Element& current) {
64 Element* nearestAncestorAssignedToSlot = 94 Element* nearestInclusiveAncestorAssignedToSlot =
65 SlotScopedTraversal::nearestAncestorAssignedToSlot(current); 95 SlotScopedTraversal::nearestInclusiveAncestorAssignedToSlot(current);
66 DCHECK(nearestAncestorAssignedToSlot); 96 DCHECK(nearestInclusiveAncestorAssignedToSlot);
67 // NodeTraversal within nearestAncestorAssignedToSlot 97
68 if (Element* previous = 98 if (current != nearestInclusiveAncestorAssignedToSlot) {
69 ElementTraversal::previous(current, nearestAncestorAssignedToSlot)) 99 // Search within children of an element which is assigned to a slot.
100 Element* previous = previousSkippingShadowHost(
101 current, *nearestInclusiveAncestorAssignedToSlot);
102 DCHECK(previous);
70 return previous; 103 return previous;
71 // If null, jump to previous assigned node's descendant 104 }
105
106 // Seek to the previous element assigned to the same slot.
72 const HeapVector<Member<Node>> assignedNodes = 107 const HeapVector<Member<Node>> assignedNodes =
73 nearestAncestorAssignedToSlot->assignedSlot()->assignedNodes(); 108 nearestInclusiveAncestorAssignedToSlot->assignedSlot()->assignedNodes();
74 size_t currentIndex = 109 size_t currentIndex =
75 assignedNodes.reverseFind(*nearestAncestorAssignedToSlot); 110 assignedNodes.reverseFind(*nearestInclusiveAncestorAssignedToSlot);
76 DCHECK_NE(currentIndex, kNotFound); 111 DCHECK_NE(currentIndex, kNotFound);
77 for (; currentIndex > 0; --currentIndex) { 112 for (; currentIndex > 0; --currentIndex) {
78 const Member<Node> assignedPrevious = assignedNodes[currentIndex - 1]; 113 const Member<Node> assignedNode = assignedNodes[currentIndex - 1];
79 if (assignedPrevious->isElementNode()) { 114 if (!assignedNode->isElementNode())
80 if (Element* last = 115 continue;
81 ElementTraversal::lastWithin(*toElement(assignedPrevious))) 116 return lastWithinOrSelfSkippingShadowHost(*toElement(assignedNode));
82 return last; 117 }
83 return toElement(assignedPrevious); 118 return nullptr;
84 } 119 }
120
121 Element* SlotScopedTraversal::firstAssignedToSlot(HTMLSlotElement& slot) {
122 HeapVector<Member<Node>> assignedNodes = slot.assignedNodes();
hayato 2016/10/31 05:27:13 Use a reference. Unless that, vector is copied, I'
kochi 2016/10/31 07:30:25 Done.
123 for (auto assignedNode : assignedNodes) {
124 if (assignedNode->isElementNode())
125 return toElement(assignedNode);
126 }
127 return nullptr;
128 }
129
130 Element* SlotScopedTraversal::lastAssignedToSlot(HTMLSlotElement& slot) {
131 HeapVector<Member<Node>> assignedNodes = slot.assignedNodes();
132 for (auto assignedNode = assignedNodes.rbegin();
133 assignedNode != assignedNodes.rend(); ++assignedNode) {
134 if (!(*assignedNode)->isElementNode())
135 continue;
136 return lastWithinOrSelfSkippingShadowHost(*toElement(*assignedNode));
hayato 2016/10/31 05:27:13 Hmm. This function name is confusing because it re
85 } 137 }
86 return nullptr; 138 return nullptr;
87 } 139 }
88 140
89 bool SlotScopedTraversal::isSlotScoped(const Element& current) { 141 bool SlotScopedTraversal::isSlotScoped(const Element& current) {
90 return SlotScopedTraversal::nearestAncestorAssignedToSlot(current); 142 return SlotScopedTraversal::nearestInclusiveAncestorAssignedToSlot(current);
91 } 143 }
92 144
93 } // namespace blink 145 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698