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

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

Issue 2450093005: Support display: contents for elements, first-line and first-letter pseudos. (Closed)
Patch Set: Allow text as child of the LayoutView, since it can happen with display: contents Created 4 years 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 /* 1 /*
2 * Copyright (C) 2012 Google Inc. All rights reserved. 2 * Copyright (C) 2012 Google Inc. All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are 5 * modification, are permitted provided that the following conditions are
6 * met: 6 * met:
7 * 7 *
8 * * Redistributions of source code must retain the above copyright 8 * * 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 * * Neither the name of Google Inc. nor the names of its 10 * * Neither the name of Google Inc. nor the names of its
(...skipping 12 matching lines...) Expand all
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/dom/LayoutTreeBuilderTraversal.h" 27 #include "core/dom/LayoutTreeBuilderTraversal.h"
28 28
29 #include "core/HTMLNames.h" 29 #include "core/HTMLNames.h"
30 #include "core/dom/PseudoElement.h" 30 #include "core/dom/PseudoElement.h"
31 #include "core/dom/shadow/FlatTreeTraversal.h" 31 #include "core/dom/shadow/FlatTreeTraversal.h"
32 #include "core/layout/LayoutObject.h" 32 #include "core/layout/LayoutObject.h"
33 #include "core/layout/LayoutView.h"
33 34
34 namespace blink { 35 namespace blink {
35 36
36 namespace LayoutTreeBuilderTraversal { 37 inline static bool hasDisplayContentsStyle(const Node& node) {
38 return node.isElementNode() && toElement(node).hasDisplayContentsStyle();
39 }
37 40
38 static bool isLayoutObjectReparented(const LayoutObject* layoutObject) { 41 static bool isLayoutObjectReparented(const LayoutObject* layoutObject) {
39 if (!layoutObject->node()->isElementNode()) 42 if (!layoutObject->node()->isElementNode())
40 return false; 43 return false;
41 if (toElement(layoutObject->node())->isInTopLayer()) 44 return toElement(layoutObject->node())->isInTopLayer();
42 return true;
43 return false;
44 } 45 }
45 46
46 void ParentDetails::didTraverseInsertionPoint( 47 void LayoutTreeBuilderTraversal::ParentDetails::didTraverseInsertionPoint(
47 const InsertionPoint* insertionPoint) { 48 const InsertionPoint* insertionPoint) {
48 if (!m_insertionPoint) { 49 if (!m_insertionPoint) {
49 m_insertionPoint = insertionPoint; 50 m_insertionPoint = insertionPoint;
50 } 51 }
51 } 52 }
52 53
53 inline static void assertPseudoElementParent( 54 inline static void assertPseudoElementParent(
54 const PseudoElement& pseudoElement) { 55 const PseudoElement& pseudoElement) {
55 DCHECK(pseudoElement.parentNode()); 56 DCHECK(pseudoElement.parentNode());
56 DCHECK(pseudoElement.parentNode()->canParticipateInFlatTree()); 57 DCHECK(pseudoElement.parentNode()->canParticipateInFlatTree());
57 } 58 }
58 59
59 ContainerNode* parent(const Node& node, ParentDetails* details) { 60 ContainerNode* LayoutTreeBuilderTraversal::parent(const Node& node,
61 ParentDetails* details) {
60 // TODO(hayato): Uncomment this once we can be sure 62 // TODO(hayato): Uncomment this once we can be sure
61 // LayoutTreeBuilderTraversal::parent() is used only for a node which is 63 // LayoutTreeBuilderTraversal::parent() is used only for a node which is
62 // connected. 64 // connected.
63 // DCHECK(node.isConnected()); 65 // DCHECK(node.isConnected());
64 if (node.isPseudoElement()) { 66 if (node.isPseudoElement()) {
65 assertPseudoElementParent(toPseudoElement(node)); 67 assertPseudoElementParent(toPseudoElement(node));
66 return node.parentNode(); 68 return node.parentNode();
67 } 69 }
68 return FlatTreeTraversal::parent(node, details); 70 return FlatTreeTraversal::parent(node, details);
69 } 71 }
70 72
71 Node* nextSibling(const Node& node) { 73 ContainerNode* LayoutTreeBuilderTraversal::layoutParent(
74 const Node& node,
75 ParentDetails* details) {
76 ContainerNode* parent = LayoutTreeBuilderTraversal::parent(node, details);
77
78 while (parent && hasDisplayContentsStyle(*parent))
79 parent = LayoutTreeBuilderTraversal::parent(*parent, details);
80
81 return parent;
82 }
83
84 LayoutObject* LayoutTreeBuilderTraversal::parentLayoutObject(const Node& node) {
85 ContainerNode* parent = LayoutTreeBuilderTraversal::layoutParent(node);
86 return parent ? parent->layoutObject()
87 : node.isConnected() ? node.document().layoutView() : nullptr;
88 }
89
90 Node* LayoutTreeBuilderTraversal::nextSibling(const Node& node) {
72 if (node.isBeforePseudoElement()) { 91 if (node.isBeforePseudoElement()) {
73 assertPseudoElementParent(toPseudoElement(node)); 92 assertPseudoElementParent(toPseudoElement(node));
74 if (Node* next = FlatTreeTraversal::firstChild(*node.parentNode())) 93 if (Node* next = FlatTreeTraversal::firstChild(*node.parentNode()))
75 return next; 94 return next;
76 } else { 95 } else {
77 if (node.isAfterPseudoElement()) 96 if (node.isAfterPseudoElement())
78 return nullptr; 97 return nullptr;
79 if (Node* next = FlatTreeTraversal::nextSibling(node)) 98 if (Node* next = FlatTreeTraversal::nextSibling(node))
80 return next; 99 return next;
81 } 100 }
82 101
83 Node* parent = FlatTreeTraversal::parent(node); 102 Node* parent = FlatTreeTraversal::parent(node);
84 if (parent && parent->isElementNode()) 103 if (parent && parent->isElementNode())
85 return toElement(parent)->pseudoElement(PseudoIdAfter); 104 return toElement(parent)->pseudoElement(PseudoIdAfter);
86 105
87 return nullptr; 106 return nullptr;
88 } 107 }
89 108
90 Node* previousSibling(const Node& node) { 109 Node* LayoutTreeBuilderTraversal::previousSibling(const Node& node) {
91 if (node.isAfterPseudoElement()) { 110 if (node.isAfterPseudoElement()) {
92 assertPseudoElementParent(toPseudoElement(node)); 111 assertPseudoElementParent(toPseudoElement(node));
93 if (Node* previous = FlatTreeTraversal::lastChild(*node.parentNode())) 112 if (Node* previous = FlatTreeTraversal::lastChild(*node.parentNode()))
94 return previous; 113 return previous;
95 } else { 114 } else {
96 if (node.isBeforePseudoElement()) 115 if (node.isBeforePseudoElement())
97 return nullptr; 116 return nullptr;
98 if (Node* previous = FlatTreeTraversal::previousSibling(node)) 117 if (Node* previous = FlatTreeTraversal::previousSibling(node))
99 return previous; 118 return previous;
100 } 119 }
101 120
102 Node* parent = FlatTreeTraversal::parent(node); 121 Node* parent = FlatTreeTraversal::parent(node);
103 if (parent && parent->isElementNode()) 122 if (parent && parent->isElementNode())
104 return toElement(parent)->pseudoElement(PseudoIdBefore); 123 return toElement(parent)->pseudoElement(PseudoIdBefore);
105 124
106 return nullptr; 125 return nullptr;
107 } 126 }
108 127
109 static Node* lastChild(const Node& node) { 128 static Node* lastChild(const Node& node) {
110 return FlatTreeTraversal::lastChild(node); 129 return FlatTreeTraversal::lastChild(node);
111 } 130 }
112 131
113 static Node* pseudoAwarePreviousSibling(const Node& node) { 132 static Node* pseudoAwarePreviousSibling(const Node& node) {
114 Node* previousNode = previousSibling(node); 133 Node* previousNode = LayoutTreeBuilderTraversal::previousSibling(node);
115 Node* parentNode = parent(node); 134 Node* parentNode = LayoutTreeBuilderTraversal::parent(node);
116 135
117 if (parentNode && parentNode->isElementNode() && !previousNode) { 136 if (parentNode && parentNode->isElementNode() && !previousNode) {
118 if (node.isAfterPseudoElement()) { 137 if (node.isAfterPseudoElement()) {
119 if (Node* child = lastChild(*parentNode)) 138 if (Node* child = lastChild(*parentNode))
120 return child; 139 return child;
121 } 140 }
122 if (!node.isBeforePseudoElement()) 141 if (!node.isBeforePseudoElement())
123 return toElement(parentNode)->pseudoElement(PseudoIdBefore); 142 return toElement(parentNode)->pseudoElement(PseudoIdBefore);
124 } 143 }
125 return previousNode; 144 return previousNode;
126 } 145 }
127 146
128 static Node* pseudoAwareLastChild(const Node& node) { 147 static Node* pseudoAwareLastChild(const Node& node) {
129 if (node.isElementNode()) { 148 if (node.isElementNode()) {
130 const Element& currentElement = toElement(node); 149 const Element& currentElement = toElement(node);
131 Node* last = currentElement.pseudoElement(PseudoIdAfter); 150 Node* last = currentElement.pseudoElement(PseudoIdAfter);
132 if (last) 151 if (last)
133 return last; 152 return last;
134 153
135 last = lastChild(currentElement); 154 last = lastChild(currentElement);
136 if (!last) 155 if (!last)
137 last = currentElement.pseudoElement(PseudoIdBefore); 156 last = currentElement.pseudoElement(PseudoIdBefore);
138 return last; 157 return last;
139 } 158 }
140 159
141 return lastChild(node); 160 return lastChild(node);
142 } 161 }
143 162
144 Node* previous(const Node& node, const Node* stayWithin) { 163 Node* LayoutTreeBuilderTraversal::previous(const Node& node,
164 const Node* stayWithin) {
145 if (node == stayWithin) 165 if (node == stayWithin)
146 return 0; 166 return 0;
147 167
148 if (Node* previousNode = pseudoAwarePreviousSibling(node)) { 168 if (Node* previousNode = pseudoAwarePreviousSibling(node)) {
149 while (Node* previousLastChild = pseudoAwareLastChild(*previousNode)) 169 while (Node* previousLastChild = pseudoAwareLastChild(*previousNode))
150 previousNode = previousLastChild; 170 previousNode = previousLastChild;
151 return previousNode; 171 return previousNode;
152 } 172 }
153 return parent(node); 173 return parent(node);
154 } 174 }
155 175
156 Node* firstChild(const Node& node) { 176 Node* LayoutTreeBuilderTraversal::firstChild(const Node& node) {
157 return FlatTreeTraversal::firstChild(node); 177 return FlatTreeTraversal::firstChild(node);
158 } 178 }
159 179
160 static Node* pseudoAwareNextSibling(const Node& node) { 180 static Node* pseudoAwareNextSibling(const Node& node) {
161 Node* parentNode = parent(node); 181 Node* parentNode = LayoutTreeBuilderTraversal::parent(node);
162 Node* nextNode = nextSibling(node); 182 Node* nextNode = LayoutTreeBuilderTraversal::nextSibling(node);
163 183
164 if (parentNode && parentNode->isElementNode() && !nextNode) { 184 if (parentNode && parentNode->isElementNode() && !nextNode) {
165 if (node.isBeforePseudoElement()) { 185 if (node.isBeforePseudoElement()) {
166 if (Node* child = firstChild(*parentNode)) 186 if (Node* child = LayoutTreeBuilderTraversal::firstChild(*parentNode))
167 return child; 187 return child;
168 } 188 }
169 if (!node.isAfterPseudoElement()) 189 if (!node.isAfterPseudoElement())
170 return toElement(parentNode)->pseudoElement(PseudoIdAfter); 190 return toElement(parentNode)->pseudoElement(PseudoIdAfter);
171 } 191 }
172 return nextNode; 192 return nextNode;
173 } 193 }
174 194
175 static Node* pseudoAwareFirstChild(const Node& node) { 195 static Node* pseudoAwareFirstChild(const Node& node) {
176 if (node.isElementNode()) { 196 if (node.isElementNode()) {
177 const Element& currentElement = toElement(node); 197 const Element& currentElement = toElement(node);
178 Node* first = currentElement.pseudoElement(PseudoIdBefore); 198 Node* first = currentElement.pseudoElement(PseudoIdBefore);
179 if (first) 199 if (first)
180 return first; 200 return first;
181 first = firstChild(currentElement); 201 first = LayoutTreeBuilderTraversal::firstChild(currentElement);
182 if (!first) 202 if (!first)
183 first = currentElement.pseudoElement(PseudoIdAfter); 203 first = currentElement.pseudoElement(PseudoIdAfter);
184 return first; 204 return first;
185 } 205 }
186 206
187 return firstChild(node); 207 return LayoutTreeBuilderTraversal::firstChild(node);
188 } 208 }
189 209
190 static Node* nextAncestorSibling(const Node& node, const Node* stayWithin) { 210 static Node* nextAncestorSibling(const Node& node, const Node* stayWithin) {
191 DCHECK(!pseudoAwareNextSibling(node)); 211 DCHECK(!pseudoAwareNextSibling(node));
192 DCHECK_NE(node, stayWithin); 212 DCHECK_NE(node, stayWithin);
193 for (Node* parentNode = parent(node); parentNode; 213 for (Node* parentNode = LayoutTreeBuilderTraversal::parent(node); parentNode;
194 parentNode = parent(*parentNode)) { 214 parentNode = LayoutTreeBuilderTraversal::parent(*parentNode)) {
195 if (parentNode == stayWithin) 215 if (parentNode == stayWithin)
196 return 0; 216 return 0;
197 if (Node* nextNode = pseudoAwareNextSibling(*parentNode)) 217 if (Node* nextNode = pseudoAwareNextSibling(*parentNode))
198 return nextNode; 218 return nextNode;
199 } 219 }
200 return 0; 220 return 0;
201 } 221 }
202 222
203 Node* nextSkippingChildren(const Node& node, const Node* stayWithin) { 223 Node* LayoutTreeBuilderTraversal::nextSkippingChildren(const Node& node,
224 const Node* stayWithin) {
204 if (node == stayWithin) 225 if (node == stayWithin)
205 return 0; 226 return 0;
206 if (Node* nextNode = pseudoAwareNextSibling(node)) 227 if (Node* nextNode = pseudoAwareNextSibling(node))
207 return nextNode; 228 return nextNode;
208 return nextAncestorSibling(node, stayWithin); 229 return nextAncestorSibling(node, stayWithin);
209 } 230 }
210 231
211 Node* next(const Node& node, const Node* stayWithin) { 232 Node* LayoutTreeBuilderTraversal::next(const Node& node,
233 const Node* stayWithin) {
212 if (Node* child = pseudoAwareFirstChild(node)) 234 if (Node* child = pseudoAwareFirstChild(node))
213 return child; 235 return child;
214 return nextSkippingChildren(node, stayWithin); 236 return nextSkippingChildren(node, stayWithin);
215 } 237 }
216 238
217 LayoutObject* nextSiblingLayoutObject(const Node& node, int32_t limit) { 239 static LayoutObject* nextSiblingLayoutObjectInternal(Node* node,
218 DCHECK(limit == kTraverseAllSiblings || limit >= 0) << limit; 240 int32_t& limit) {
219 for (Node* sibling = LayoutTreeBuilderTraversal::nextSibling(node); 241 for (Node* sibling = node; sibling && limit-- != 0;
220 sibling && limit-- != 0;
221 sibling = LayoutTreeBuilderTraversal::nextSibling(*sibling)) { 242 sibling = LayoutTreeBuilderTraversal::nextSibling(*sibling)) {
222 LayoutObject* layoutObject = sibling->layoutObject(); 243 LayoutObject* layoutObject = sibling->layoutObject();
244
245 #if DCHECK_IS_ON()
246 if (hasDisplayContentsStyle(*sibling))
247 DCHECK(!layoutObject);
248 #endif
249
250 if (!layoutObject && hasDisplayContentsStyle(*sibling)) {
251 layoutObject = nextSiblingLayoutObjectInternal(
252 pseudoAwareFirstChild(*sibling), limit);
253 if (layoutObject)
254 return layoutObject;
255 if (!limit)
256 return nullptr;
257 }
258
223 if (layoutObject && !isLayoutObjectReparented(layoutObject)) 259 if (layoutObject && !isLayoutObjectReparented(layoutObject))
224 return layoutObject; 260 return layoutObject;
225 } 261 }
226 return 0; 262
263 return nullptr;
227 } 264 }
228 265
229 LayoutObject* previousSiblingLayoutObject(const Node& node, int32_t limit) { 266 LayoutObject* LayoutTreeBuilderTraversal::nextSiblingLayoutObject(
267 const Node& node,
268 int32_t limit) {
230 DCHECK(limit == kTraverseAllSiblings || limit >= 0) << limit; 269 DCHECK(limit == kTraverseAllSiblings || limit >= 0) << limit;
231 for (Node* sibling = LayoutTreeBuilderTraversal::previousSibling(node); 270 if (LayoutObject* sibling =
232 sibling && limit-- != 0; 271 nextSiblingLayoutObjectInternal(nextSibling(node), limit))
272 return sibling;
273
274 Node* parent = LayoutTreeBuilderTraversal::parent(node);
275 while (limit && parent && hasDisplayContentsStyle(*parent)) {
276 if (LayoutObject* sibling =
277 nextSiblingLayoutObjectInternal(nextSibling(*parent), limit))
278 return sibling;
279 parent = LayoutTreeBuilderTraversal::parent(*parent);
280 }
281
282 return nullptr;
283 }
284
285 static LayoutObject* previousSiblingLayoutObjectInternal(Node* node,
286 int32_t& limit) {
287 for (Node* sibling = node; sibling && limit-- != 0;
233 sibling = LayoutTreeBuilderTraversal::previousSibling(*sibling)) { 288 sibling = LayoutTreeBuilderTraversal::previousSibling(*sibling)) {
234 LayoutObject* layoutObject = sibling->layoutObject(); 289 LayoutObject* layoutObject = sibling->layoutObject();
290
291 #if DCHECK_IS_ON()
292 if (hasDisplayContentsStyle(*sibling))
293 DCHECK(!layoutObject);
294 #endif
295
296 if (!layoutObject && hasDisplayContentsStyle(*sibling)) {
297 layoutObject = previousSiblingLayoutObjectInternal(
298 pseudoAwareLastChild(*sibling), limit);
299 if (layoutObject)
300 return layoutObject;
301 if (!limit)
302 return nullptr;
303 }
304
235 if (layoutObject && !isLayoutObjectReparented(layoutObject)) 305 if (layoutObject && !isLayoutObjectReparented(layoutObject))
236 return layoutObject; 306 return layoutObject;
237 } 307 }
238 return 0; 308
309 return nullptr;
239 } 310 }
240 311
241 LayoutObject* nextInTopLayer(const Element& element) { 312 LayoutObject* LayoutTreeBuilderTraversal::previousSiblingLayoutObject(
313 const Node& node,
314 int32_t limit) {
315 DCHECK(limit == kTraverseAllSiblings || limit >= 0) << limit;
316 if (LayoutObject* sibling =
317 previousSiblingLayoutObjectInternal(previousSibling(node), limit))
318 return sibling;
319
320 Node* parent = LayoutTreeBuilderTraversal::parent(node);
321 while (limit && parent && hasDisplayContentsStyle(*parent)) {
322 if (LayoutObject* sibling = previousSiblingLayoutObjectInternal(
323 previousSibling(*parent), limit))
324 return sibling;
325 parent = LayoutTreeBuilderTraversal::parent(*parent);
326 }
327
328 return nullptr;
329 }
330
331 LayoutObject* LayoutTreeBuilderTraversal::nextInTopLayer(
332 const Element& element) {
242 if (!element.isInTopLayer()) 333 if (!element.isInTopLayer())
243 return 0; 334 return 0;
244 const HeapVector<Member<Element>>& topLayerElements = 335 const HeapVector<Member<Element>>& topLayerElements =
245 element.document().topLayerElements(); 336 element.document().topLayerElements();
246 size_t position = topLayerElements.find(&element); 337 size_t position = topLayerElements.find(&element);
247 DCHECK_NE(position, kNotFound); 338 DCHECK_NE(position, kNotFound);
248 for (size_t i = position + 1; i < topLayerElements.size(); ++i) { 339 for (size_t i = position + 1; i < topLayerElements.size(); ++i) {
249 if (LayoutObject* layoutObject = topLayerElements[i]->layoutObject()) 340 if (LayoutObject* layoutObject = topLayerElements[i]->layoutObject())
250 return layoutObject; 341 return layoutObject;
251 } 342 }
252 return 0; 343 return 0;
253 } 344 }
254 345
255 } // namespace LayoutTreeBuilderTraversal
256
257 } // namespace blink 346 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698