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

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: More proper fix 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
(...skipping 13 matching lines...) Expand all
24 // is directly assigned to a slot. 24 // is directly assigned to a slot.
25 Element* element = const_cast<Element*>(&current); 25 Element* element = const_cast<Element*>(&current);
26 for (; element; element = element->parentElement()) { 26 for (; element; element = element->parentElement()) {
27 if (element->assignedSlot()) 27 if (element->assignedSlot())
28 break; 28 break;
29 } 29 }
30 return element; 30 return element;
31 } 31 }
32 32
33 Element* SlotScopedTraversal::next(const Element& current) { 33 Element* SlotScopedTraversal::next(const Element& current) {
34 // current.assignedSlot returns a slot only when current is assigned 34 Element* next = nullptr;
35 // explicitly
36 // If current is assigned to a slot, return a descendant of current, which is
37 // in the assigned scope of the same slot as current.
38 HTMLSlotElement* slot = current.assignedSlot();
39 Element* nearestAncestorAssignedToSlot = 35 Element* nearestAncestorAssignedToSlot =
hayato 2016/10/24 06:43:26 Could we rename |nearestAncestorAssignedToSlot| to
kochi 2016/10/24 08:55:20 I agree the renaming, and adding "Inclusive" clari
40 SlotScopedTraversal::nearestAncestorAssignedToSlot(current); 36 SlotScopedTraversal::nearestAncestorAssignedToSlot(current);
41 if (slot) { 37 // Search within children of an element which is directly assigned to a slot.
hayato 2016/10/24 06:43:26 Could you remove |directly| from the comments in t
kochi 2016/10/24 08:55:20 Done.
42 if (Element* next = ElementTraversal::next(current, &current)) 38 if (current.assignedSlot()) {
43 return next; 39 next = ElementTraversal::next(current, &current);
44 } else { 40 } else {
45 // If current is in assigned scope, find an assigned ancestor. 41 // If current is in assigned scope, find an assigned ancestor.
46 DCHECK(nearestAncestorAssignedToSlot); 42 DCHECK(nearestAncestorAssignedToSlot);
47 if (Element* next = 43 if (current == nearestAncestorAssignedToSlot)
hayato 2016/10/24 06:43:26 When does it happen? It looks that current.assigne
kochi 2016/10/24 08:55:20 Good catch. Looks like an artifact while I was de
48 ElementTraversal::next(current, nearestAncestorAssignedToSlot)) 44 return nullptr;
49 return next; 45 next = ElementTraversal::next(current, nearestAncestorAssignedToSlot);
50 slot = nearestAncestorAssignedToSlot->assignedSlot();
51 DCHECK(slot);
52 } 46 }
47
48 // Exclude elements that is assigned to another slot scope.
49 while (next && next->assignedSlot())
50 next = ElementTraversal::nextSkippingChildren(*next, &current);
51
52 if (next) {
53 DCHECK(!next->assignedSlot());
54 return next;
55 }
56
57 // Seek to the next element assigned to the same slot.
58 HTMLSlotElement* slot = nearestAncestorAssignedToSlot->assignedSlot();
59 DCHECK(slot);
53 HeapVector<Member<Node>> assignedNodes = slot->assignedNodes(); 60 HeapVector<Member<Node>> assignedNodes = slot->assignedNodes();
54 size_t currentIndex = assignedNodes.find(*nearestAncestorAssignedToSlot); 61 size_t currentIndex = assignedNodes.find(*nearestAncestorAssignedToSlot);
55 DCHECK_NE(currentIndex, kNotFound); 62 DCHECK_NE(currentIndex, kNotFound);
56 for (++currentIndex; currentIndex < assignedNodes.size(); ++currentIndex) { 63 for (++currentIndex; currentIndex < assignedNodes.size(); ++currentIndex) {
57 if (assignedNodes[currentIndex]->isElementNode()) 64 if (assignedNodes[currentIndex]->isElementNode())
58 return toElement(assignedNodes[currentIndex]); 65 return toElement(assignedNodes[currentIndex]);
59 } 66 }
60 return nullptr; 67 return nullptr;
61 } 68 }
62 69
63 Element* SlotScopedTraversal::previous(const Element& current) { 70 Element* SlotScopedTraversal::previous(const Element& current) {
64 Element* nearestAncestorAssignedToSlot = 71 Element* nearestAncestorAssignedToSlot =
65 SlotScopedTraversal::nearestAncestorAssignedToSlot(current); 72 SlotScopedTraversal::nearestAncestorAssignedToSlot(current);
66 DCHECK(nearestAncestorAssignedToSlot); 73 DCHECK(nearestAncestorAssignedToSlot);
67 // NodeTraversal within nearestAncestorAssignedToSlot 74
68 if (Element* previous = 75 // Search within children of an element which is directly assigned to a slot.
69 ElementTraversal::previous(current, nearestAncestorAssignedToSlot)) 76 Element* previous =
70 return previous; 77 ElementTraversal::previous(current, nearestAncestorAssignedToSlot);
71 // If null, jump to previous assigned node's descendant 78
79 // TODO(kochi): repeatedly calling nearestAncestorAssignedToSlot() which
80 // is O(depth from directly slotted ancestor) and can be very slow.
81 while (previous) {
hayato 2016/10/24 06:43:26 Could you extract L81-L88 as a separate function?
kochi 2016/10/24 08:55:20 Separated as a function previousWithinSameSlotScop
82 Element* ancestor =
83 SlotScopedTraversal::nearestAncestorAssignedToSlot(*previous);
84 DCHECK(ancestor);
85 if (ancestor == nearestAncestorAssignedToSlot)
86 return previous;
87 previous = ancestor->parentElement();
88 }
89
90 // Seek to the previous element assigned to the same slot.
72 const HeapVector<Member<Node>> assignedNodes = 91 const HeapVector<Member<Node>> assignedNodes =
73 nearestAncestorAssignedToSlot->assignedSlot()->assignedNodes(); 92 nearestAncestorAssignedToSlot->assignedSlot()->assignedNodes();
74 size_t currentIndex = 93 size_t currentIndex =
75 assignedNodes.reverseFind(*nearestAncestorAssignedToSlot); 94 assignedNodes.reverseFind(*nearestAncestorAssignedToSlot);
76 DCHECK_NE(currentIndex, kNotFound); 95 DCHECK_NE(currentIndex, kNotFound);
77 for (; currentIndex > 0; --currentIndex) { 96 for (; currentIndex > 0; --currentIndex) {
78 const Member<Node> assignedPrevious = assignedNodes[currentIndex - 1]; 97 const Member<Node> assignedPrevious = assignedNodes[currentIndex - 1];
79 if (assignedPrevious->isElementNode()) { 98 if (!assignedPrevious->isElementNode())
80 if (Element* last = 99 continue;
81 ElementTraversal::lastWithin(*toElement(assignedPrevious))) 100
101 Element* last = ElementTraversal::lastWithin(*toElement(assignedPrevious));
102 if (!last)
103 return toElement(assignedPrevious);
104
105 while (last) {
106 Element* ancestor =
107 SlotScopedTraversal::nearestAncestorAssignedToSlot(*last);
108 DCHECK(ancestor);
109 if (ancestor == assignedPrevious)
82 return last; 110 return last;
83 return toElement(assignedPrevious); 111 last = ancestor->parentElement();
84 } 112 }
113 NOTREACHED();
85 } 114 }
86 return nullptr; 115 return nullptr;
87 } 116 }
88 117
89 bool SlotScopedTraversal::isSlotScoped(const Element& current) { 118 bool SlotScopedTraversal::isSlotScoped(const Element& current) {
90 return SlotScopedTraversal::nearestAncestorAssignedToSlot(current); 119 return SlotScopedTraversal::nearestAncestorAssignedToSlot(current);
91 } 120 }
92 121
93 } // namespace blink 122 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698