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