OLD | NEW |
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 Loading... |
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 |
OLD | NEW |