Chromium Code Reviews| Index: third_party/WebKit/Source/core/layout/LayoutCounter.cpp |
| diff --git a/third_party/WebKit/Source/core/layout/LayoutCounter.cpp b/third_party/WebKit/Source/core/layout/LayoutCounter.cpp |
| index 14a2c72c93c37bddc8ff09c57047d028387e4308..03c0ec115a33683f713ef8896d7621489b303c9c 100644 |
| --- a/third_party/WebKit/Source/core/layout/LayoutCounter.cpp |
| +++ b/third_party/WebKit/Source/core/layout/LayoutCounter.cpp |
| @@ -43,7 +43,7 @@ using namespace HTMLNames; |
| typedef HashMap<AtomicString, RefPtr<CounterNode>> CounterMap; |
| typedef HashMap<const LayoutObject*, OwnPtr<CounterMap>> CounterMaps; |
| -static CounterNode* makeCounterNode(LayoutObject&, const AtomicString& identifier, bool alwaysCreateCounter); |
| +static CounterNode* makeCounterNodeIfNeeded(LayoutObject&, const AtomicString& identifier, bool alwaysCreateCounter); |
| // See class definition as to why we have this map. |
| static CounterMaps& counterMaps() |
| @@ -52,21 +52,43 @@ static CounterMaps& counterMaps() |
| return staticCounterMaps; |
| } |
| +Element* ancestorStyleContainmentObject(const Element& element) |
| +{ |
| + for (Element* ancestor = element.parentElement(); ancestor; ancestor = ancestor->parentElement()) { |
|
esprehn
2016/02/10 02:00:01
I think you want to use LayoutTreeTraversal::paren
|
| + if (ancestor->layoutObject() && ancestor->layoutObject()->style()->containsStyle()) |
| + return ancestor; |
| + } |
| + return nullptr; |
| +} |
| + |
| // This function processes the layoutObject tree in the order of the DOM tree |
| -// including pseudo elements as defined in CSS 2.1. |
| -static LayoutObject* previousInPreOrder(const LayoutObject& object) |
| +// including pseudo elements as defined in CSS 2.1. This method will always return |
| +// either a previous object within the same contain: style scope or nullptr. |
| +static LayoutObject* previousInPreOrderRespectingContainment(const LayoutObject& object) |
| { |
| Element* self = toElement(object.node()); |
| ASSERT(self); |
| Element* previous = ElementTraversal::previousIncludingPseudo(*self); |
| - while (previous && !previous->layoutObject()) |
| - previous = ElementTraversal::previousIncludingPseudo(*previous); |
| - return previous ? previous->layoutObject() : 0; |
| + Element* styleContainAncestor = ancestorStyleContainmentObject(*self); |
| + |
| + while (1) { |
| + while (previous && !previous->layoutObject()) |
| + previous = ElementTraversal::previousIncludingPseudo(*previous); |
| + if (!previous) |
| + return nullptr; |
| + Element* previousStyleContainAncestor = ancestorStyleContainmentObject(*previous); |
| + if (previousStyleContainAncestor == styleContainAncestor) |
| + return previous->layoutObject(); |
| + if (!previousStyleContainAncestor) |
| + return nullptr; |
| + previous = previousStyleContainAncestor; |
| + } |
| } |
| // This function processes the layoutObject tree in the order of the DOM tree |
| -// including pseudo elements as defined in CSS 2.1. |
| -static LayoutObject* previousSiblingOrParent(const LayoutObject& object) |
| +// including pseudo elements as defined in CSS 2.1. This method avoids crossing |
| +// contain: style boundaries. |
| +static LayoutObject* previousSiblingOrParentRespectingContainment(const LayoutObject& object) |
| { |
| Element* self = toElement(object.node()); |
| ASSERT(self); |
| @@ -76,7 +98,7 @@ static LayoutObject* previousSiblingOrParent(const LayoutObject& object) |
| if (previous) |
| return previous->layoutObject(); |
| previous = self->parentElement(); |
| - return previous ? previous->layoutObject() : 0; |
| + return previous && previous->layoutObject() && !(previous->layoutObject()->style()->contain() & ContainsStyle) ? previous->layoutObject() : nullptr; |
| } |
| static inline Element* parentElement(LayoutObject& object) |
| @@ -98,7 +120,7 @@ static LayoutObject* nextInPreOrder(const LayoutObject& object, const Element* s |
| Element* next = skipDescendants ? ElementTraversal::nextIncludingPseudoSkippingChildren(*self, stayWithin) : ElementTraversal::nextIncludingPseudo(*self, stayWithin); |
| while (next && !next->layoutObject()) |
| next = skipDescendants ? ElementTraversal::nextIncludingPseudoSkippingChildren(*next, stayWithin) : ElementTraversal::nextIncludingPseudo(*next, stayWithin); |
| - return next ? next->layoutObject() : 0; |
| + return next ? next->layoutObject() : nullptr; |
| } |
| static bool planCounter(LayoutObject& object, const AtomicString& identifier, bool& isReset, int& value) |
| @@ -182,16 +204,16 @@ static bool findPlaceForCounter(LayoutObject& counterOwner, const AtomicString& |
| { |
| // We cannot stop searching for counters with the same identifier before we also |
| // check this layoutObject, because it may affect the positioning in the tree of our counter. |
| - LayoutObject* searchEndLayoutObject = previousSiblingOrParent(counterOwner); |
| + LayoutObject* searchEndLayoutObject = previousSiblingOrParentRespectingContainment(counterOwner); |
| // We check layoutObjects in preOrder from the layoutObject that our counter is attached to |
| // towards the beginning of the document for counters with the same identifier as the one |
| // we are trying to find a place for. This is the next layoutObject to be checked. |
| - LayoutObject* currentLayoutObject = previousInPreOrder(counterOwner); |
| + LayoutObject* currentLayoutObject = previousInPreOrderRespectingContainment(counterOwner); |
| previousSibling = nullptr; |
| RefPtr<CounterNode> previousSiblingProtector = nullptr; |
| while (currentLayoutObject) { |
| - CounterNode* currentCounter = makeCounterNode(*currentLayoutObject, identifier, false); |
| + CounterNode* currentCounter = makeCounterNodeIfNeeded(*currentLayoutObject, identifier, false); |
| if (searchEndLayoutObject == currentLayoutObject) { |
| // We may be at the end of our search. |
| if (currentCounter) { |
| @@ -204,7 +226,7 @@ static bool findPlaceForCounter(LayoutObject& counterOwner, const AtomicString& |
| // hence we are the next sibling of that counter if that reset is not a root or |
| // we are a root node if that reset is a root. |
| parent = currentCounter->parent(); |
| - previousSibling = parent ? currentCounter : 0; |
| + previousSibling = parent ? currentCounter : nullptr; |
| return parent; |
| } |
| // We are not a reset node or the previous reset must be on an ancestor of our owner layoutObject |
| @@ -257,7 +279,7 @@ static bool findPlaceForCounter(LayoutObject& counterOwner, const AtomicString& |
| // good counter, or we are a reset node and the counter on the previous sibling |
| // of our owner layoutObject was not a reset counter. |
| // Set a new goal for the end of the search. |
| - searchEndLayoutObject = previousSiblingOrParent(*currentLayoutObject); |
| + searchEndLayoutObject = previousSiblingOrParentRespectingContainment(*currentLayoutObject); |
| } else { |
| // We are searching descendants of a previous sibling of the layoutObject that the |
| // counter being placed is attached to. |
| @@ -277,7 +299,7 @@ static bool findPlaceForCounter(LayoutObject& counterOwner, const AtomicString& |
| } else { |
| previousSiblingProtector = currentCounter; |
| } |
| - currentLayoutObject = previousSiblingOrParent(*currentLayoutObject); |
| + currentLayoutObject = previousSiblingOrParentRespectingContainment(*currentLayoutObject); |
| continue; |
| } |
| } |
| @@ -286,14 +308,14 @@ static bool findPlaceForCounter(LayoutObject& counterOwner, const AtomicString& |
| // performance improvement would create more code duplication than is worthwhile in my opinion and may further |
| // impede the readability of this already complex algorithm. |
| if (previousSiblingProtector) |
| - currentLayoutObject = previousSiblingOrParent(*currentLayoutObject); |
| + currentLayoutObject = previousSiblingOrParentRespectingContainment(*currentLayoutObject); |
| else |
| - currentLayoutObject = previousInPreOrder(*currentLayoutObject); |
| + currentLayoutObject = previousInPreOrderRespectingContainment(*currentLayoutObject); |
| } |
| return false; |
| } |
| -static CounterNode* makeCounterNode(LayoutObject& object, const AtomicString& identifier, bool alwaysCreateCounter) |
| +static CounterNode* makeCounterNodeIfNeeded(LayoutObject& object, const AtomicString& identifier, bool alwaysCreateCounter) |
| { |
| if (object.hasCounterNodeMap()) { |
| if (CounterMap* nodeMap = counterMaps().get(&object)) { |
| @@ -383,7 +405,7 @@ PassRefPtr<StringImpl> LayoutCounter::originalText() const |
| break; |
| beforeAfterContainer = beforeAfterContainer->parent(); |
| } |
| - makeCounterNode(*beforeAfterContainer, m_counter.identifier(), true)->addLayoutObject(const_cast<LayoutCounter*>(this)); |
| + makeCounterNodeIfNeeded(*beforeAfterContainer, m_counter.identifier(), true)->addLayoutObject(const_cast<LayoutCounter*>(this)); |
| ASSERT(m_counterNode); |
| } |
| CounterNode* child = m_counterNode; |
| @@ -496,7 +518,7 @@ static void updateCounters(LayoutObject& layoutObject) |
| CounterDirectiveMap::const_iterator end = directiveMap->end(); |
| if (!layoutObject.hasCounterNodeMap()) { |
| for (CounterDirectiveMap::const_iterator it = directiveMap->begin(); it != end; ++it) |
| - makeCounterNode(layoutObject, it->key, false); |
| + makeCounterNodeIfNeeded(layoutObject, it->key, false); |
| return; |
| } |
| CounterMap* counterMap = counterMaps().get(&layoutObject); |
| @@ -504,7 +526,7 @@ static void updateCounters(LayoutObject& layoutObject) |
| for (CounterDirectiveMap::const_iterator it = directiveMap->begin(); it != end; ++it) { |
| RefPtr<CounterNode> node = counterMap->get(it->key); |
| if (!node) { |
| - makeCounterNode(layoutObject, it->key, false); |
| + makeCounterNodeIfNeeded(layoutObject, it->key, false); |
| continue; |
| } |
| RefPtr<CounterNode> newParent = nullptr; |
| @@ -560,7 +582,7 @@ void LayoutCounter::layoutObjectStyleChanged(LayoutObject& layoutObject, const C |
| // We must create this node here, because the changed node may be a node with no display such as |
| // as those created by the increment or reset directives and the re-layout that will happen will |
| // not catch the change if the node had no children. |
| - makeCounterNode(layoutObject, it->key, false); |
| + makeCounterNodeIfNeeded(layoutObject, it->key, false); |
| } |
| // Destroying old counters that do not exist in the new counterDirective map. |
| for (CounterDirectiveMap::const_iterator it = oldCounterDirectives->begin(); it !=oldMapEnd; ++it) { |
| @@ -579,7 +601,7 @@ void LayoutCounter::layoutObjectStyleChanged(LayoutObject& layoutObject, const C |
| // We must create this node here, because the added node may be a node with no display such as |
| // as those created by the increment or reset directives and the re-layout that will happen will |
| // not catch the change if the node had no children. |
| - makeCounterNode(layoutObject, it->key, false); |
| + makeCounterNodeIfNeeded(layoutObject, it->key, false); |
| } |
| } |
| } |