static CounterNode* makeCounterNode(RenderObject* object, const AtomicString& identifier, bool alwaysCreateCounter) { ASSERT(object); // Real text nodes don't have their own style so they can't have counters. // We can't even look at their styles or we'll see extra resets and increments! if (object->isText()) return nullptr; RenderElement* element = toRenderElement(object); if (element->hasCounterNodeMap()) { if (CounterMap* nodeMap = counterMaps().get(element)) { if (CounterNode* node = nodeMap->get(identifier)) return node; } } bool isReset = false; int value = 0; if (!planCounter(element, identifier, isReset, value) && !alwaysCreateCounter) return nullptr; RefPtr<CounterNode> newParent = 0; RefPtr<CounterNode> newPreviousSibling = 0; RefPtr<CounterNode> newNode = CounterNode::create(element, isReset, value); if (findPlaceForCounter(element, identifier, isReset, newParent, newPreviousSibling)) newParent->insertAfter(newNode.get(), newPreviousSibling.get(), identifier); CounterMap* nodeMap; if (element->hasCounterNodeMap()) nodeMap = counterMaps().get(element); else { nodeMap = new CounterMap; counterMaps().set(element, adoptPtr(nodeMap)); element->setHasCounterNodeMap(true); } nodeMap->set(identifier, newNode); if (newNode->parent()) return newNode.get(); // Checking if some nodes that were previously counter tree root nodes // should become children of this node now. CounterMaps& maps = counterMaps(); Element* stayWithin = parentOrPseudoHostElement(element); bool skipDescendants; for (RenderElement* currentRenderer = nextInPreOrder(element, stayWithin); currentRenderer; currentRenderer = nextInPreOrder(currentRenderer, stayWithin, skipDescendants)) { skipDescendants = false; if (!currentRenderer->hasCounterNodeMap()) continue; CounterNode* currentCounter = maps.get(currentRenderer)->get(identifier); if (!currentCounter) continue; skipDescendants = true; if (currentCounter->parent()) continue; if (stayWithin == parentOrPseudoHostElement(currentRenderer) && currentCounter->hasResetType()) break; newNode->insertAfter(currentCounter, newNode->lastChild(), identifier); } return newNode.get(); }
static CounterNode* makeCounterNode(RenderObject* object, const AtomicString& identifier, bool alwaysCreateCounter) { ASSERT(object); if (object->m_hasCounterNodeMap) { if (CounterMap* nodeMap = counterMaps().get(object)) { if (CounterNode* node = nodeMap->get(identifier.impl()).get()) return node; } } bool isReset = false; int value = 0; if (!planCounter(object, identifier, isReset, value) && !alwaysCreateCounter) return 0; CounterNode* newParent = 0; CounterNode* newPreviousSibling = 0; RefPtr<CounterNode> newNode = CounterNode::create(object, isReset, value); if (findPlaceForCounter(object, identifier, isReset, newParent, newPreviousSibling)) newParent->insertAfter(newNode.get(), newPreviousSibling, identifier); CounterMap* nodeMap; if (object->m_hasCounterNodeMap) nodeMap = counterMaps().get(object); else { nodeMap = new CounterMap; counterMaps().set(object, nodeMap); object->m_hasCounterNodeMap = true; } nodeMap->set(identifier.impl(), newNode); if (newNode->parent()) return newNode.get(); // Checking if some nodes that were previously counter tree root nodes // should become children of this node now. CounterMaps& maps = counterMaps(); Element* stayWithin = parentElement(object); bool skipDescendants; for (RenderObject* currentRenderer = nextInPreOrder(object, stayWithin); currentRenderer; currentRenderer = nextInPreOrder(currentRenderer, stayWithin, skipDescendants)) { skipDescendants = false; if (!currentRenderer->m_hasCounterNodeMap) continue; CounterNode* currentCounter = maps.get(currentRenderer)->get(identifier.impl()).get(); if (!currentCounter) continue; skipDescendants = true; if (currentCounter->parent()) { ASSERT(newNode->firstChild()); continue; } if (stayWithin == parentElement(currentRenderer) && currentCounter->hasResetType()) break; newNode->insertAfter(currentCounter, newNode->lastChild(), identifier); } return newNode.get(); }
static void destroyCounterNodeWithoutMapRemoval(const AtomicString& identifier, CounterNode* node) { CounterNode* previous; for (RefPtr<CounterNode> child = node->lastDescendant(); child && child != node; child = previous) { previous = child->previousInPreOrder(); child->parent()->removeChild(child.get()); ASSERT(counterMaps().get(child->owner())->get(identifier) == child); counterMaps().get(child->owner())->remove(identifier); } if (CounterNode* parent = node->parent()) parent->removeChild(node); }
static CounterNode* makeCounterNode(RenderElement& renderer, const AtomicString& identifier, bool alwaysCreateCounter) { if (renderer.hasCounterNodeMap()) { if (CounterMap* nodeMap = counterMaps().get(&renderer)) { if (CounterNode* node = nodeMap->get(identifier)) return node; } } bool isReset = false; int value = 0; if (!planCounter(renderer, identifier, isReset, value) && !alwaysCreateCounter) return nullptr; RefPtr<CounterNode> newParent = 0; RefPtr<CounterNode> newPreviousSibling = 0; RefPtr<CounterNode> newNode = CounterNode::create(renderer, isReset, value); if (findPlaceForCounter(renderer, identifier, isReset, newParent, newPreviousSibling)) newParent->insertAfter(newNode.get(), newPreviousSibling.get(), identifier); CounterMap* nodeMap; if (renderer.hasCounterNodeMap()) nodeMap = counterMaps().get(&renderer); else { nodeMap = new CounterMap; counterMaps().set(&renderer, std::unique_ptr<CounterMap>(nodeMap)); renderer.setHasCounterNodeMap(true); } nodeMap->set(identifier, newNode); if (newNode->parent()) return newNode.get(); // Checking if some nodes that were previously counter tree root nodes // should become children of this node now. CounterMaps& maps = counterMaps(); Element* stayWithin = parentOrPseudoHostElement(renderer); bool skipDescendants; for (RenderElement* currentRenderer = nextInPreOrder(renderer, stayWithin); currentRenderer; currentRenderer = nextInPreOrder(*currentRenderer, stayWithin, skipDescendants)) { skipDescendants = false; if (!currentRenderer->hasCounterNodeMap()) continue; CounterNode* currentCounter = maps.get(currentRenderer)->get(identifier); if (!currentCounter) continue; skipDescendants = true; if (currentCounter->parent()) continue; if (stayWithin == parentOrPseudoHostElement(*currentRenderer) && currentCounter->hasResetType()) break; newNode->insertAfter(currentCounter, newNode->lastChild(), identifier); } return newNode.get(); }
static void updateCounters(RenderObject* renderer) { ASSERT(renderer->style()); const CounterDirectiveMap* directiveMap = renderer->style()->counterDirectives(); if (!directiveMap) return; CounterDirectiveMap::const_iterator end = directiveMap->end(); if (!renderer->hasCounterNodeMap()) { for (CounterDirectiveMap::const_iterator it = directiveMap->begin(); it != end; ++it) makeCounterNode(renderer, it->key, false); return; } CounterMap* counterMap = counterMaps().get(renderer); ASSERT(counterMap); for (CounterDirectiveMap::const_iterator it = directiveMap->begin(); it != end; ++it) { RefPtr<CounterNode> node = counterMap->get(it->key); if (!node) { makeCounterNode(renderer, it->key, false); continue; } RefPtr<CounterNode> newParent = 0; RefPtr<CounterNode> newPreviousSibling = 0; findPlaceForCounter(renderer, it->key, node->hasResetType(), newParent, newPreviousSibling); if (node != counterMap->get(it->key)) continue; CounterNode* parent = node->parent(); if (newParent == parent && newPreviousSibling == node->previousSibling()) continue; if (parent) parent->removeChild(node.get()); if (newParent) newParent->insertAfter(node.get(), newPreviousSibling.get(), it->key); } }
static void destroyCounterNodeChildren(AtomicStringImpl* identifier, CounterNode* node) { CounterNode* previous; for (CounterNode* child = lastDescendant(node); child && child != node; child = previous) { previous = previousInPreOrder(child); child->parent()->removeChild(child); ASSERT(counterMaps().get(child->renderer())->get(identifier) == child); counterMaps().get(child->renderer())->remove(identifier); if (!child->renderer()->documentBeingDestroyed()) { RenderObjectChildList* children = child->renderer()->virtualChildren(); if (children) children->invalidateCounters(child->renderer()); } delete child; } }
static void destroyCounterNodeWithoutMapRemoval(const AtomicString& identifier, CounterNode* node) { CounterNode* previous; for (RefPtr<CounterNode> child = node->lastDescendant(); child && child != node; child = previous) { previous = child->previousInPreOrder(); child->parent()->removeChild(child.get(), identifier); ASSERT(counterMaps().get(child->renderer())->get(identifier.impl()) == child); counterMaps().get(child->renderer())->remove(identifier.impl()); if (!child->renderer()->documentBeingDestroyed()) { RenderObjectChildList* children = child->renderer()->virtualChildren(); if (children) children->invalidateCounters(child->renderer(), identifier); } } RenderObject* renderer = node->renderer(); if (!renderer->documentBeingDestroyed()) { if (RenderObjectChildList* children = renderer->virtualChildren()) children->invalidateCounters(renderer, identifier); } if (CounterNode* parent = node->parent()) parent->removeChild(node, identifier); }
void RenderCounter::destroyCounterNodes(RenderObject* owner) { CounterMaps& maps = counterMaps(); CounterMaps::iterator mapsIterator = maps.find(owner); if (mapsIterator == maps.end()) return; CounterMap* map = mapsIterator->value.get(); CounterMap::const_iterator end = map->end(); for (CounterMap::const_iterator it = map->begin(); it != end; ++it) { destroyCounterNodeWithoutMapRemoval(it->key, it->value.get()); } maps.remove(mapsIterator); owner->setHasCounterNodeMap(false); }
static CounterNode* counter(RenderObject* object, const AtomicString& counterName, bool alwaysCreateCounter) { ASSERT(object); if (object->m_hasCounterNodeMap) if (CounterMap* nodeMap = counterMaps().get(object)) if (CounterNode* node = nodeMap->get(counterName.impl())) return node; bool isReset = false; int value = 0; if (!planCounter(object, counterName, isReset, value) && !alwaysCreateCounter) return 0; CounterNode* newParent = 0; CounterNode* newPreviousSibling = 0; CounterNode* newNode; if (findPlaceForCounter(object, counterName, isReset, newParent, newPreviousSibling)) { newNode = new CounterNode(object, isReset, value); newParent->insertAfter(newNode, newPreviousSibling); } else { // Make a reset node for counters that aren't inside an existing reset node. newNode = new CounterNode(object, true, value); } CounterMap* nodeMap; if (object->m_hasCounterNodeMap) nodeMap = counterMaps().get(object); else { nodeMap = new CounterMap; counterMaps().set(object, nodeMap); object->m_hasCounterNodeMap = true; } nodeMap->set(counterName.impl(), newNode); return newNode; }
void RenderCounter::destroyCounterNodes(RenderObject* owner) { CounterMaps& maps = counterMaps(); CounterMaps::iterator mapsIterator = maps.find(owner); if (mapsIterator == maps.end()) return; CounterMap* map = mapsIterator->second; CounterMap::const_iterator end = map->end(); for (CounterMap::const_iterator it = map->begin(); it != end; ++it) { AtomicString identifier(it->first.get()); destroyCounterNodeWithoutMapRemoval(identifier, it->second.get()); } maps.remove(mapsIterator); delete map; owner->setHasCounterNodeMap(false); }
void RenderCounter::destroyCounterNodes(RenderObject* object) { CounterMaps& maps = counterMaps(); CounterMap* map = maps.get(object); if (!map) return; maps.remove(object); CounterMap::const_iterator end = map->end(); for (CounterMap::const_iterator it = map->begin(); it != end; ++it) { CounterNode* node = it->second; destroyCounterNodeChildren(it->first.get(), node); if (CounterNode* parent = node->parent()) parent->removeChild(node); delete node; } delete map; }
void RenderCounter::destroyCounterNode(RenderObject* owner, const AtomicString& identifier) { CounterMap* map = counterMaps().get(owner); if (!map) return; CounterMap::iterator mapIterator = map->find(identifier); if (mapIterator == map->end()) return; destroyCounterNodeWithoutMapRemoval(identifier, mapIterator->value.get()); map->remove(mapIterator); // We do not delete "map" here even if empty because we expect to reuse // it soon. In order for a renderer to lose all its counters permanently, // a style change for the renderer involving removal of all counter // directives must occur, in which case, RenderCounter::destroyCounterNodes() // must be called. // The destruction of the Renderer (possibly caused by the removal of its // associated DOM node) is the other case that leads to the permanent // destruction of all counters attached to a Renderer. In this case // RenderCounter::destroyCounterNodes() must be and is now called, too. // RenderCounter::destroyCounterNodes() handles destruction of the counter // map associated with a renderer, so there is no risk in leaking the map. }