String RenderCounter::originalText() const { if (!m_counterNode) { RenderElement* beforeAfterContainer = parent(); while (true) { if (!beforeAfterContainer) return String(); if (!beforeAfterContainer->isAnonymous() && !beforeAfterContainer->isPseudoElement()) return String(); // RenderCounters are restricted to before and after pseudo elements PseudoId containerStyle = beforeAfterContainer->style().styleType(); if ((containerStyle == BEFORE) || (containerStyle == AFTER)) break; beforeAfterContainer = beforeAfterContainer->parent(); } makeCounterNode(*beforeAfterContainer, m_counter.identifier(), true)->addRenderer(const_cast<RenderCounter*>(this)); ASSERT(m_counterNode); } CounterNode* child = m_counterNode; int value = child->actsAsReset() ? child->value() : child->countInParent(); String text = listMarkerText(m_counter.listStyle(), value); if (!m_counter.separator().isNull()) { if (!child->actsAsReset()) child = child->parent(); while (CounterNode* parent = child->parent()) { text = listMarkerText(m_counter.listStyle(), child->countInParent()) + m_counter.separator() + text; child = parent; } } return text; }
PassRefPtr<StringImpl> RenderCounter::originalText() const { if (!parent()) return 0; if (!m_counterNode) m_counterNode = counter(parent(), m_counter.identifier(), true); CounterNode* child = m_counterNode; int value = child->isReset() ? child->value() : child->countInParent(); String text = listMarkerText(m_counter.listStyle(), value); if (!m_counter.separator().isNull()) { if (!child->isReset()) child = child->parent(); while (CounterNode* parent = child->parent()) { text = listMarkerText(m_counter.listStyle(), child->countInParent()) + m_counter.separator() + text; child = parent; } } return text.impl(); }
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->m_hasCounterNodeMap) { for (CounterDirectiveMap::const_iterator it = directiveMap->begin(); it != end; ++it) makeCounterNode(renderer, AtomicString(it->first.get()), false); return; } CounterMap* counterMap = counterMaps().get(renderer); ASSERT(counterMap); for (CounterDirectiveMap::const_iterator it = directiveMap->begin(); it != end; ++it) { CounterNode* node = counterMap->get(it->first.get()); if (!node) { makeCounterNode(renderer, AtomicString(it->first.get()), false); continue; } CounterNode* newParent = 0; CounterNode* newPreviousSibling; findPlaceForCounter(renderer, AtomicString(it->first.get()), node->hasResetType(), newParent, newPreviousSibling); CounterNode* parent = node->parent(); if (newParent == parent && newPreviousSibling == node->previousSibling()) continue; if (parent) parent->removeChild(node, it->first.get()); if (newParent) newParent->insertAfter(node, newPreviousSibling, it->first.get()); } }
void RenderCounter::generateContent() { bool counters; counters = !m_counter->separator().isNull(); if(!m_counterNode) m_counterNode = getCounter(m_counter->identifier().string(), true, counters); int value = m_counterNode->count(); if(m_counterNode->isReset()) value = m_counterNode->value(); int total = value; if(m_counterNode->parent()) total = m_counterNode->parent()->total(); m_item = toListStyleType(value, total, (EListStyleType)m_counter->listStyle()); if(counters) { CounterNode *counter = m_counterNode->parent(); // we deliberately do not render the root counter-node while(counter->parent() && !(counter->isReset() && counter->parent()->isRoot())) { value = counter->count(); total = counter->parent()->total(); m_item = toListStyleType(value, total, (EListStyleType)m_counter->listStyle()) + m_counter->separator().string() + m_item; counter = counter->parent(); }; } }
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; }
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; }
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 bool findPlaceForCounter(RenderObject* object, const AtomicString& counterName, bool isReset, CounterNode*& parent, CounterNode*& previousSibling) { // Find the appropriate previous sibling for insertion into the parent node // by searching in render tree order for a child of the counter. parent = 0; previousSibling = 0; RenderObject* resetCandidate = isReset ? object->parent() : previousSiblingOrParent(object); RenderObject* prevCounterCandidate = object; CounterNode* candidateCounter = 0; // When a reset counter is chosen as candidateCounter, we'll // decide the new node should be a child of the reset node or a // sibling or the reset node. This flag controls it. bool createChildForReset = true; while ((prevCounterCandidate = prevCounterCandidate->previousInPreOrder())) { CounterNode* c = counter(prevCounterCandidate, counterName, false); if (prevCounterCandidate == resetCandidate) { if (!candidateCounter) { candidateCounter = c; createChildForReset = true; } if (candidateCounter) { if (createChildForReset && candidateCounter->isReset()) { parent = candidateCounter; previousSibling = 0; } else { parent = candidateCounter->parent(); previousSibling = candidateCounter; } return true; } resetCandidate = previousSiblingOrParent(resetCandidate); } else if (c) { if (c->isReset()) { if (c->parent()) { // The new node may be the next sibling of this reset node. createChildForReset = false; candidateCounter = c; } else { createChildForReset = true; candidateCounter = 0; } } else if (!candidateCounter) { createChildForReset = true; candidateCounter = c; } } } return false; }
static void destroyCounterNodeWithoutMapRemoval(const AtomicString& identifier, CounterNode* node) { CounterNode* previous; for (CounterNode* child = node->lastDescendant(); child && child != node; child = previous) { previous = child->previousInPreOrder(); child->parent()->removeChild(child, 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); } delete child; } 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); delete node; }
static bool findPlaceForCounter(RenderObject* counterOwner, const AtomicString& identifier, bool isReset, RefPtr<CounterNode>& parent, RefPtr<CounterNode>& previousSibling) { // We cannot stop searching for counters with the same identifier before we also // check this renderer, because it may affect the positioning in the tree of our counter. RenderObject* searchEndRenderer = previousSiblingOrParent(counterOwner); // We check renderers in preOrder from the renderer that our counter is attached to // towards the begining of the document for counters with the same identifier as the one // we are trying to find a place for. This is the next renderer to be checked. RenderObject* currentRenderer = previousInPreOrder(counterOwner); previousSibling = 0; RefPtr<CounterNode> previousSiblingProtector = 0; while (currentRenderer) { CounterNode* currentCounter = makeCounterNode(currentRenderer, identifier, false); if (searchEndRenderer == currentRenderer) { // We may be at the end of our search. if (currentCounter) { // We have a suitable counter on the EndSearchRenderer. if (previousSiblingProtector) { // But we already found another counter that we come after. if (currentCounter->actsAsReset()) { // We found a reset counter that is on a renderer that is a sibling of ours or a parent. if (isReset && areRenderersElementsSiblings(currentRenderer, counterOwner)) { // We are also a reset counter and the previous reset was on a sibling renderer // 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; return parent; } // We are not a reset node or the previous reset must be on an ancestor of our owner renderer // hence we must be a child of that reset counter. parent = currentCounter; // In some cases renders can be reparented (ex. nodes inside a table but not in a column or row). // In these cases the identified previousSibling will be invalid as its parent is different from // our identified parent. if (previousSiblingProtector->parent() != currentCounter) previousSiblingProtector = 0; previousSibling = previousSiblingProtector.get(); return true; } // CurrentCounter, the counter at the EndSearchRenderer, is not reset. if (!isReset || !areRenderersElementsSiblings(currentRenderer, counterOwner)) { // If the node we are placing is not reset or we have found a counter that is attached // to an ancestor of the placed counter's owner renderer we know we are a sibling of that node. if (currentCounter->parent() != previousSiblingProtector->parent()) return false; parent = currentCounter->parent(); previousSibling = previousSiblingProtector.get(); return true; } } else { // We are at the potential end of the search, but we had no previous sibling candidate // In this case we follow pretty much the same logic as above but no ASSERTs about // previousSibling, and when we are a sibling of the end counter we must set previousSibling // to currentCounter. if (currentCounter->actsAsReset()) { if (isReset && areRenderersElementsSiblings(currentRenderer, counterOwner)) { parent = currentCounter->parent(); previousSibling = currentCounter; return parent; } parent = currentCounter; previousSibling = previousSiblingProtector.get(); return true; } if (!isReset || !areRenderersElementsSiblings(currentRenderer, counterOwner)) { parent = currentCounter->parent(); previousSibling = currentCounter; return true; } previousSiblingProtector = currentCounter; } } // We come here if the previous sibling or parent of our owner renderer had no // good counter, or we are a reset node and the counter on the previous sibling // of our owner renderer was not a reset counter. // Set a new goal for the end of the search. searchEndRenderer = previousSiblingOrParent(currentRenderer); } else { // We are searching descendants of a previous sibling of the renderer that the // counter being placed is attached to. if (currentCounter) { // We found a suitable counter. if (previousSiblingProtector) { // Since we had a suitable previous counter before, we should only consider this one as our // previousSibling if it is a reset counter and hence the current previousSibling is its child. if (currentCounter->actsAsReset()) { previousSiblingProtector = currentCounter; // We are no longer interested in previous siblings of the currentRenderer or their children // as counters they may have attached cannot be the previous sibling of the counter we are placing. currentRenderer = parentElement(currentRenderer)->renderer(); continue; } } else previousSiblingProtector = currentCounter; currentRenderer = previousSiblingOrParent(currentRenderer); continue; } } // This function is designed so that the same test is not done twice in an iteration, except for this one // which may be done twice in some cases. Rearranging the decision points though, to accommodate this // performance improvement would create more code duplication than is worthwhile in my oppinion and may further // impede the readability of this already complex algorithm. if (previousSiblingProtector) currentRenderer = previousSiblingOrParent(currentRenderer); else currentRenderer = previousInPreOrder(currentRenderer); } return false; }
void CounterNode::insertAfter(CounterNode* newChild, CounterNode* refChild, const AtomicString& identifier) { ASSERT(newChild); ASSERT(!newChild->m_parent); ASSERT(!newChild->m_previousSibling); ASSERT(!newChild->m_nextSibling); // If the refChild is not our child we can not complete the request. This hardens against bugs in RenderCounter. // When renderers are reparented it may request that we insert counter nodes improperly. if (refChild && refChild->m_parent != this) return; if (newChild->m_hasResetType) { while (m_lastChild != refChild) RenderCounter::destroyCounterNode(m_lastChild->owner(), identifier); } CounterNode* next; if (refChild) { next = refChild->m_nextSibling; refChild->m_nextSibling = newChild; } else { next = m_firstChild; m_firstChild = newChild; } newChild->m_parent = this; newChild->m_previousSibling = refChild; if (next) { ASSERT(next->m_previousSibling == refChild); next->m_previousSibling = newChild; newChild->m_nextSibling = next; } else { ASSERT(m_lastChild == refChild); m_lastChild = newChild; } if (!newChild->m_firstChild || newChild->m_hasResetType) { newChild->m_countInParent = newChild->computeCountInParent(); newChild->resetThisAndDescendantsRenderers(); if (next) next->recount(); return; } // The code below handles the case when a formerly root increment counter is loosing its root position // and therefore its children become next siblings. CounterNode* last = newChild->m_lastChild; CounterNode* first = newChild->m_firstChild; if (first) { ASSERT(last); newChild->m_nextSibling = first; if (m_lastChild == newChild) m_lastChild = last; first->m_previousSibling = newChild; // The case when the original next sibling of the inserted node becomes a child of // one of the former children of the inserted node is not handled as it is believed // to be impossible since: // 1. if the increment counter node lost it's root position as a result of another // counter node being created, it will be inserted as the last child so next is null. // 2. if the increment counter node lost it's root position as a result of a renderer being // inserted into the document's render tree, all its former children counters are attached // to children of the inserted renderer and hence cannot be in scope for counter nodes // attached to renderers that were already in the document's render tree. last->m_nextSibling = next; if (next) { ASSERT(next->m_previousSibling == newChild); next->m_previousSibling = last; } else m_lastChild = last; for (next = first; ; next = next->m_nextSibling) { next->m_parent = this; if (last == next) break; } } newChild->m_firstChild = 0; newChild->m_lastChild = 0; newChild->m_countInParent = newChild->computeCountInParent(); newChild->resetRenderers(); first->recount(); }
void CounterReset::removeChild(CounterNode *oldChild) { Q_ASSERT(oldChild); CounterNode *next = oldChild->m_next; CounterNode *prev = oldChild->m_previous; if(oldChild->firstChild()) { CounterNode *first = oldChild->firstChild(); CounterNode *last = oldChild->lastChild(); if(prev) { prev->m_next = first; first->m_previous = prev; } else { assert(m_first == oldChild); m_first = first; } if(next) { next->m_previous = last; last->m_next = next; } else { assert(m_last == oldChild); m_last = last; } next = first; while(next) { next->m_parent = this; if(next == last) break; next = next->m_next; } first->recount(true); } else { if(prev) prev->m_next = next; else { assert(m_first == oldChild); m_first = next; } if(next) next->m_previous = prev; else { assert(m_last == oldChild); m_last = prev; } if(next) next->recount(); } oldChild->m_next = 0; oldChild->m_previous = 0; oldChild->m_parent = 0; }