1 /* 2 * Copyright (C) 2005 Allan Sandfeld Jensen (kde (at) carewolf.com) 3 * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Library General Public 7 * License as published by the Free Software Foundation; either 8 * version 2 of the License, or (at your option) any later version. 9 * 10 * This library is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * Library General Public License for more details. 14 * 15 * You should have received a copy of the GNU Library General Public License 16 * along with this library; see the file COPYING.LIB. If not, write to 17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 18 * Boston, MA 02110-1301, USA. 19 * 20 */ 21 22 #include "config.h" 23 #include "CounterNode.h" 24 25 #include "RenderCounter.h" 26 #include "RenderObject.h" 27 #include <stdio.h> 28 29 namespace WebCore { 30 31 CounterNode::CounterNode(RenderObject* o, bool hasResetType, int value) 32 : m_hasResetType(hasResetType) 33 , m_value(value) 34 , m_countInParent(0) 35 , m_renderer(o) 36 , m_parent(0) 37 , m_previousSibling(0) 38 , m_nextSibling(0) 39 , m_firstChild(0) 40 , m_lastChild(0) 41 { 42 } 43 44 CounterNode* CounterNode::nextInPreOrderAfterChildren(const CounterNode* stayWithin) const 45 { 46 if (this == stayWithin) 47 return 0; 48 49 const CounterNode* current = this; 50 CounterNode* next; 51 while (!(next = current->m_nextSibling)) { 52 current = current->m_parent; 53 if (!current || current == stayWithin) 54 return 0; 55 } 56 return next; 57 } 58 59 CounterNode* CounterNode::nextInPreOrder(const CounterNode* stayWithin) const 60 { 61 if (CounterNode* next = m_firstChild) 62 return next; 63 64 return nextInPreOrderAfterChildren(stayWithin); 65 } 66 67 CounterNode* CounterNode::lastDescendant() const 68 { 69 CounterNode* last = m_lastChild; 70 if (!last) 71 return 0; 72 73 while (CounterNode* lastChild = last->m_lastChild) 74 last = lastChild; 75 76 return last; 77 } 78 79 CounterNode* CounterNode::previousInPreOrder() const 80 { 81 CounterNode* previous = m_previousSibling; 82 if (!previous) 83 return m_parent; 84 85 while (CounterNode* lastChild = previous->m_lastChild) 86 previous = lastChild; 87 88 return previous; 89 } 90 91 int CounterNode::computeCountInParent() const 92 { 93 int increment = actsAsReset() ? 0 : m_value; 94 if (m_previousSibling) 95 return m_previousSibling->m_countInParent + increment; 96 ASSERT(m_parent->m_firstChild == this); 97 return m_parent->m_value + increment; 98 } 99 100 void CounterNode::resetRenderer(const AtomicString& identifier) const 101 { 102 if (!m_renderer || m_renderer->documentBeingDestroyed()) 103 return; 104 if (RenderObjectChildList* children = m_renderer->virtualChildren()) 105 children->invalidateCounters(m_renderer, identifier); 106 } 107 108 void CounterNode::resetRenderers(const AtomicString& identifier) const 109 { 110 const CounterNode* node = this; 111 do { 112 node->resetRenderer(identifier); 113 node = node->nextInPreOrder(this); 114 } while (node); 115 } 116 117 void CounterNode::recount(const AtomicString& identifier) 118 { 119 for (CounterNode* node = this; node; node = node->m_nextSibling) { 120 int oldCount = node->m_countInParent; 121 int newCount = node->computeCountInParent(); 122 if (oldCount == newCount) 123 break; 124 node->m_countInParent = newCount; 125 node->resetRenderers(identifier); 126 } 127 } 128 129 void CounterNode::insertAfter(CounterNode* newChild, CounterNode* refChild, const AtomicString& identifier) 130 { 131 ASSERT(newChild); 132 ASSERT(!newChild->m_parent); 133 ASSERT(!newChild->m_previousSibling); 134 ASSERT(!newChild->m_nextSibling); 135 ASSERT(!refChild || refChild->m_parent == this); 136 137 if (newChild->m_hasResetType) { 138 while (m_lastChild != refChild) 139 RenderCounter::destroyCounterNode(m_lastChild->renderer(), identifier); 140 } 141 142 CounterNode* next; 143 144 if (refChild) { 145 next = refChild->m_nextSibling; 146 refChild->m_nextSibling = newChild; 147 } else { 148 next = m_firstChild; 149 m_firstChild = newChild; 150 } 151 152 newChild->m_parent = this; 153 newChild->m_previousSibling = refChild; 154 155 if (!newChild->m_firstChild || newChild->m_hasResetType) { 156 newChild->m_nextSibling = next; 157 if (next) { 158 ASSERT(next->m_previousSibling == refChild); 159 next->m_previousSibling = newChild; 160 } else { 161 ASSERT(m_lastChild == refChild); 162 m_lastChild = newChild; 163 } 164 165 newChild->m_countInParent = newChild->computeCountInParent(); 166 newChild->resetRenderers(identifier); 167 if (next) 168 next->recount(identifier); 169 return; 170 } 171 172 // The code below handles the case when a formerly root increment counter is loosing its root position 173 // and therefore its children become next siblings. 174 CounterNode* last = newChild->m_lastChild; 175 CounterNode* first = newChild->m_firstChild; 176 177 newChild->m_nextSibling = first; 178 first->m_previousSibling = newChild; 179 // The case when the original next sibling of the inserted node becomes a child of 180 // one of the former children of the inserted node is not handled as it is believed 181 // to be impossible since: 182 // 1. if the increment counter node lost it's root position as a result of another 183 // counter node being created, it will be inserted as the last child so next is null. 184 // 2. if the increment counter node lost it's root position as a result of a renderer being 185 // inserted into the document's render tree, all its former children counters are attached 186 // to children of the inserted renderer and hence cannot be in scope for counter nodes 187 // attached to renderers that were already in the document's render tree. 188 last->m_nextSibling = next; 189 if (next) 190 next->m_previousSibling = last; 191 else 192 m_lastChild = last; 193 for (next = first; ; next = next->m_nextSibling) { 194 next->m_parent = this; 195 if (last == next) 196 break; 197 } 198 newChild->m_firstChild = 0; 199 newChild->m_lastChild = 0; 200 newChild->m_countInParent = newChild->computeCountInParent(); 201 newChild->resetRenderer(identifier); 202 first->recount(identifier); 203 } 204 205 void CounterNode::removeChild(CounterNode* oldChild, const AtomicString& identifier) 206 { 207 ASSERT(oldChild); 208 ASSERT(!oldChild->m_firstChild); 209 ASSERT(!oldChild->m_lastChild); 210 211 CounterNode* next = oldChild->m_nextSibling; 212 CounterNode* previous = oldChild->m_previousSibling; 213 214 oldChild->m_nextSibling = 0; 215 oldChild->m_previousSibling = 0; 216 oldChild->m_parent = 0; 217 218 if (previous) 219 previous->m_nextSibling = next; 220 else { 221 ASSERT(m_firstChild == oldChild); 222 m_firstChild = next; 223 } 224 225 if (next) 226 next->m_previousSibling = previous; 227 else { 228 ASSERT(m_lastChild == oldChild); 229 m_lastChild = previous; 230 } 231 232 if (next) 233 next->recount(identifier); 234 } 235 236 #ifndef NDEBUG 237 238 static void showTreeAndMark(const CounterNode* node) 239 { 240 const CounterNode* root = node; 241 while (root->parent()) 242 root = root->parent(); 243 244 for (const CounterNode* current = root; current; current = current->nextInPreOrder()) { 245 fwrite((current == node) ? "*" : " ", 1, 1, stderr); 246 for (const CounterNode* parent = current; parent && parent != root; parent = parent->parent()) 247 fwrite(" ", 1, 2, stderr); 248 fprintf(stderr, "%p %s: %d %d P:%p PS:%p NS:%p R:%p\n", 249 current, current->actsAsReset() ? "reset____" : "increment", current->value(), 250 current->countInParent(), current->parent(), current->previousSibling(), 251 current->nextSibling(), current->renderer()); 252 } 253 } 254 255 #endif 256 257 } // namespace WebCore 258 259 #ifndef NDEBUG 260 261 void showTree(const WebCore::CounterNode* counter) 262 { 263 if (counter) 264 showTreeAndMark(counter); 265 } 266 267 #endif 268