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; } }
void RenderQuote::attachQuote() { ASSERT(view()); ASSERT(!m_attached); ASSERT(!m_next && !m_previous); ASSERT(isRooted()); if (!view()->renderQuoteHead()) { view()->setRenderQuoteHead(this); m_attached = true; return; } for (RenderObject* predecessor = previousInPreOrder(); predecessor; predecessor = predecessor->previousInPreOrder()) { // Skip unattached predecessors to avoid having stale m_previous pointers // if the previous node is never attached and is then destroyed. if (!predecessor->isQuote() || !toRenderQuote(predecessor)->isAttached()) continue; m_previous = toRenderQuote(predecessor); m_next = m_previous->m_next; m_previous->m_next = this; if (m_next) m_next->m_previous = this; break; } if (!m_previous) { m_next = view()->renderQuoteHead(); view()->setRenderQuoteHead(this); if (m_next) m_next->m_previous = this; } m_attached = true; for (RenderQuote* quote = this; quote; quote = quote->m_next) quote->updateDepth(); ASSERT(!m_next || m_next->m_attached); ASSERT(!m_next || m_next->m_previous == this); ASSERT(!m_previous || m_previous->m_attached); ASSERT(!m_previous || m_previous->m_next == this); }
void RenderQuote::attachQuote() { ASSERT(!m_isAttached); ASSERT(!m_next); ASSERT(!m_previous); ASSERT(isRooted()); // Optimize case where this is the first quote in a RenderView by not searching for predecessors in that case. if (view().renderQuoteHead()) { for (RenderObject* predecessor = previousInPreOrder(); predecessor; predecessor = predecessor->previousInPreOrder()) { // Skip unattached predecessors to avoid having stale m_previous pointers // if the previous node is never attached and is then destroyed. if (!is<RenderQuote>(*predecessor) || !downcast<RenderQuote>(*predecessor).m_isAttached) continue; m_previous = downcast<RenderQuote>(predecessor); m_next = m_previous->m_next; m_previous->m_next = this; if (m_next) m_next->m_previous = this; break; } } if (!m_previous) { m_next = view().renderQuoteHead(); view().setRenderQuoteHead(this); if (m_next) m_next->m_previous = this; } m_isAttached = true; for (RenderQuote* quote = this; quote; quote = quote->m_next) quote->updateDepth(); ASSERT(!m_next || m_next->m_isAttached); ASSERT(!m_next || m_next->m_previous == this); ASSERT(!m_previous || m_previous->m_isAttached); ASSERT(!m_previous || m_previous->m_next == this); }
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; }