blob: 250da8774a565f15e8ad893af101fe10a491980a [file] [log] [blame]
bdakin5d6edd42006-10-02 23:15:31 +00001/*
bdakin5d6edd42006-10-02 23:15:31 +00002 * Copyright (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com)
darinb5a0e3d2007-01-10 00:08:18 +00003 * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
bdakin5d6edd42006-10-02 23:15:31 +00004 *
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
ddkilzerc8eccec2007-09-26 02:29:57 +000017 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
bdakin5d6edd42006-10-02 23:15:31 +000019 *
20 */
21
22#include "config.h"
23#include "CounterNode.h"
24
eric@webkit.orgae29b2f2010-01-16 02:14:25 +000025#include "RenderCounter.h"
darin@apple.com8cdf7122013-09-30 02:40:50 +000026#include "RenderElement.h"
hausmann@webkit.org3de6b942008-02-25 13:16:40 +000027#include <stdio.h>
bdakin5d6edd42006-10-02 23:15:31 +000028
29namespace WebCore {
30
antti@apple.com9735e7d2014-08-18 22:16:47 +000031CounterNode::CounterNode(RenderElement& owner, bool hasResetType, int value)
eric@webkit.orgd8ca5e12009-12-21 20:11:47 +000032 : m_hasResetType(hasResetType)
darinec375482007-01-06 01:36:24 +000033 , m_value(value)
34 , m_countInParent(0)
antti@apple.com9735e7d2014-08-18 22:16:47 +000035 , m_owner(owner)
eric@webkit.org02482712009-11-13 20:21:44 +000036{
37}
38
carol.szabo@nokia.comd7917f72011-03-24 02:25:06 +000039CounterNode::~CounterNode()
40{
cdn@chromium.orgc9e05062011-08-08 20:39:23 +000041 // Ideally this would be an assert and this would never be reached. In reality this happens a lot
42 // so we need to handle these cases. The node is still connected to the tree so we need to detach it.
43 if (m_parent || m_previousSibling || m_nextSibling || m_firstChild || m_lastChild) {
zalan@apple.coma057f4e2016-10-15 14:24:33 +000044 CounterNode* oldParent = nullptr;
45 CounterNode* oldPreviousSibling = nullptr;
cdn@chromium.orgc9e05062011-08-08 20:39:23 +000046 // Instead of calling removeChild() we do this safely as the tree is likely broken if we get here.
47 if (m_parent) {
48 if (m_parent->m_firstChild == this)
49 m_parent->m_firstChild = m_nextSibling;
50 if (m_parent->m_lastChild == this)
51 m_parent->m_lastChild = m_previousSibling;
52 oldParent = m_parent;
zalan@apple.coma057f4e2016-10-15 14:24:33 +000053 m_parent = nullptr;
cdn@chromium.orgc9e05062011-08-08 20:39:23 +000054 }
55 if (m_previousSibling) {
56 if (m_previousSibling->m_nextSibling == this)
57 m_previousSibling->m_nextSibling = m_nextSibling;
58 oldPreviousSibling = m_previousSibling;
zalan@apple.coma057f4e2016-10-15 14:24:33 +000059 m_previousSibling = nullptr;
cdn@chromium.orgc9e05062011-08-08 20:39:23 +000060 }
61 if (m_nextSibling) {
62 if (m_nextSibling->m_previousSibling == this)
63 m_nextSibling->m_previousSibling = oldPreviousSibling;
zalan@apple.coma057f4e2016-10-15 14:24:33 +000064 m_nextSibling = nullptr;
cdn@chromium.orgc9e05062011-08-08 20:39:23 +000065 }
66 if (m_firstChild) {
67 // The node's children are reparented to the old parent.
68 for (CounterNode* child = m_firstChild; child; ) {
69 CounterNode* nextChild = child->m_nextSibling;
zalan@apple.coma057f4e2016-10-15 14:24:33 +000070 CounterNode* nextSibling = nullptr;
cdn@chromium.orgc9e05062011-08-08 20:39:23 +000071 child->m_parent = oldParent;
72 if (oldPreviousSibling) {
73 nextSibling = oldPreviousSibling->m_nextSibling;
74 child->m_previousSibling = oldPreviousSibling;
75 oldPreviousSibling->m_nextSibling = child;
76 child->m_nextSibling = nextSibling;
77 nextSibling->m_previousSibling = child;
78 oldPreviousSibling = child;
79 }
80 child = nextChild;
81 }
82 }
83 }
carol.szabo@nokia.comd7917f72011-03-24 02:25:06 +000084 resetRenderers();
85}
86
akling@apple.comad2beb52014-12-25 07:50:20 +000087Ref<CounterNode> CounterNode::create(RenderElement& owner, bool hasResetType, int value)
jschuh@chromium.orge94df972010-09-30 20:31:45 +000088{
akling@apple.comad2beb52014-12-25 07:50:20 +000089 return adoptRef(*new CounterNode(owner, hasResetType, value));
jschuh@chromium.orge94df972010-09-30 20:31:45 +000090}
91
eric@webkit.org02482712009-11-13 20:21:44 +000092CounterNode* CounterNode::nextInPreOrderAfterChildren(const CounterNode* stayWithin) const
93{
94 if (this == stayWithin)
zalan@apple.coma057f4e2016-10-15 14:24:33 +000095 return nullptr;
eric@webkit.org02482712009-11-13 20:21:44 +000096
eric@webkit.orgd9edbba2010-01-14 03:30:36 +000097 const CounterNode* current = this;
98 CounterNode* next;
99 while (!(next = current->m_nextSibling)) {
100 current = current->m_parent;
101 if (!current || current == stayWithin)
zalan@apple.coma057f4e2016-10-15 14:24:33 +0000102 return nullptr;
eric@webkit.org02482712009-11-13 20:21:44 +0000103 }
eric@webkit.orgd9edbba2010-01-14 03:30:36 +0000104 return next;
eric@webkit.org02482712009-11-13 20:21:44 +0000105}
106
107CounterNode* CounterNode::nextInPreOrder(const CounterNode* stayWithin) const
108{
109 if (CounterNode* next = m_firstChild)
110 return next;
111
112 return nextInPreOrderAfterChildren(stayWithin);
113}
114
115CounterNode* CounterNode::lastDescendant() const
116{
117 CounterNode* last = m_lastChild;
118 if (!last)
zalan@apple.coma057f4e2016-10-15 14:24:33 +0000119 return nullptr;
eric@webkit.org02482712009-11-13 20:21:44 +0000120
121 while (CounterNode* lastChild = last->m_lastChild)
122 last = lastChild;
123
124 return last;
125}
126
127CounterNode* CounterNode::previousInPreOrder() const
128{
129 CounterNode* previous = m_previousSibling;
130 if (!previous)
131 return m_parent;
132
133 while (CounterNode* lastChild = previous->m_lastChild)
134 previous = lastChild;
135
136 return previous;
bdakin5d6edd42006-10-02 23:15:31 +0000137}
138
darinec375482007-01-06 01:36:24 +0000139int CounterNode::computeCountInParent() const
bdakin5d6edd42006-10-02 23:15:31 +0000140{
eric@webkit.orgd8ca5e12009-12-21 20:11:47 +0000141 int increment = actsAsReset() ? 0 : m_value;
darinec375482007-01-06 01:36:24 +0000142 if (m_previousSibling)
143 return m_previousSibling->m_countInParent + increment;
144 ASSERT(m_parent->m_firstChild == this);
145 return m_parent->m_value + increment;
bdakin5d6edd42006-10-02 23:15:31 +0000146}
147
zalan@apple.coma057f4e2016-10-15 14:24:33 +0000148void CounterNode::addRenderer(RenderCounter& renderer)
bdakin5d6edd42006-10-02 23:15:31 +0000149{
zalan@apple.coma057f4e2016-10-15 14:24:33 +0000150 ASSERT(!renderer.m_counterNode);
151 ASSERT(!renderer.m_nextForSameCounter);
152 renderer.m_nextForSameCounter = m_rootRenderer;
153 m_rootRenderer = &renderer;
154 renderer.m_counterNode = this;
eric@webkit.org02482712009-11-13 20:21:44 +0000155}
156
zalan@apple.coma057f4e2016-10-15 14:24:33 +0000157void CounterNode::removeRenderer(RenderCounter& renderer)
eric@webkit.org02482712009-11-13 20:21:44 +0000158{
zalan@apple.coma057f4e2016-10-15 14:24:33 +0000159 ASSERT(renderer.m_counterNode && renderer.m_counterNode == this);
160 RenderCounter* previous = nullptr;
161 for (auto* current = m_rootRenderer; current; previous = current, current = current->m_nextForSameCounter) {
162 if (current != &renderer)
163 continue;
164
165 if (previous)
166 previous->m_nextForSameCounter = renderer.m_nextForSameCounter;
167 else
168 m_rootRenderer = renderer.m_nextForSameCounter;
169 renderer.m_nextForSameCounter = nullptr;
170 renderer.m_counterNode = nullptr;
carol.szabo@nokia.com7cf0a552011-03-23 00:04:58 +0000171 return;
172 }
carol.szabo@nokia.com7cf0a552011-03-23 00:04:58 +0000173 ASSERT_NOT_REACHED();
174}
175
176void CounterNode::resetRenderers()
177{
zalan@apple.coma057f4e2016-10-15 14:24:33 +0000178 if (!m_rootRenderer)
179 return;
simon.fraser@apple.comb59c6902017-03-17 00:20:45 +0000180 bool skipLayoutAndPerfWidthsRecalc = m_rootRenderer->renderTreeBeingDestroyed();
zalan@apple.coma057f4e2016-10-15 14:24:33 +0000181 auto* current = m_rootRenderer;
182 while (current) {
183 if (!skipLayoutAndPerfWidthsRecalc)
184 current->setNeedsLayoutAndPrefWidthsRecalc();
185 auto* next = current->m_nextForSameCounter;
186 current->m_nextForSameCounter = nullptr;
187 current->m_counterNode = nullptr;
188 current = next;
189 }
190 m_rootRenderer = nullptr;
carol.szabo@nokia.com7cf0a552011-03-23 00:04:58 +0000191}
192
193void CounterNode::resetThisAndDescendantsRenderers()
194{
195 CounterNode* node = this;
eric@webkit.org02482712009-11-13 20:21:44 +0000196 do {
carol.szabo@nokia.com7cf0a552011-03-23 00:04:58 +0000197 node->resetRenderers();
eric@webkit.org02482712009-11-13 20:21:44 +0000198 node = node->nextInPreOrder(this);
199 } while (node);
200}
201
carol.szabo@nokia.com7cf0a552011-03-23 00:04:58 +0000202void CounterNode::recount()
eric@webkit.org02482712009-11-13 20:21:44 +0000203{
204 for (CounterNode* node = this; node; node = node->m_nextSibling) {
205 int oldCount = node->m_countInParent;
206 int newCount = node->computeCountInParent();
darinec375482007-01-06 01:36:24 +0000207 if (oldCount == newCount)
208 break;
eric@webkit.org02482712009-11-13 20:21:44 +0000209 node->m_countInParent = newCount;
carol.szabo@nokia.com7cf0a552011-03-23 00:04:58 +0000210 node->resetThisAndDescendantsRenderers();
bdakin5d6edd42006-10-02 23:15:31 +0000211 }
212}
213
darin@apple.com0ce67df2019-06-17 01:48:13 +0000214void CounterNode::insertAfter(CounterNode& newChild, CounterNode* beforeChild, const AtomString& identifier)
bdakin5d6edd42006-10-02 23:15:31 +0000215{
zalan@apple.com84066f82016-11-15 20:12:26 +0000216 ASSERT(!newChild.m_parent);
217 ASSERT(!newChild.m_previousSibling);
218 ASSERT(!newChild.m_nextSibling);
219 // If the beforeChild is not our child we can not complete the request. This hardens against bugs in RenderCounter.
cdn@chromium.org009d1ab2011-09-13 22:49:15 +0000220 // When renderers are reparented it may request that we insert counter nodes improperly.
zalan@apple.com84066f82016-11-15 20:12:26 +0000221 if (beforeChild && beforeChild->m_parent != this)
cdn@chromium.org009d1ab2011-09-13 22:49:15 +0000222 return;
darinec375482007-01-06 01:36:24 +0000223
zalan@apple.com84066f82016-11-15 20:12:26 +0000224 if (newChild.m_hasResetType) {
225 while (m_lastChild != beforeChild)
carol.szabo@nokia.com7cf0a552011-03-23 00:04:58 +0000226 RenderCounter::destroyCounterNode(m_lastChild->owner(), identifier);
eric@webkit.orgae29b2f2010-01-16 02:14:25 +0000227 }
228
darinec375482007-01-06 01:36:24 +0000229 CounterNode* next;
230
zalan@apple.com84066f82016-11-15 20:12:26 +0000231 if (beforeChild) {
232 next = beforeChild->m_nextSibling;
233 beforeChild->m_nextSibling = &newChild;
darinec375482007-01-06 01:36:24 +0000234 } else {
235 next = m_firstChild;
zalan@apple.com84066f82016-11-15 20:12:26 +0000236 m_firstChild = &newChild;
darinec375482007-01-06 01:36:24 +0000237 }
238
zalan@apple.com84066f82016-11-15 20:12:26 +0000239 newChild.m_parent = this;
240 newChild.m_previousSibling = beforeChild;
darinec375482007-01-06 01:36:24 +0000241
cdn@chromium.org32296c32012-06-20 05:36:27 +0000242 if (next) {
zalan@apple.com84066f82016-11-15 20:12:26 +0000243 ASSERT(next->m_previousSibling == beforeChild);
244 next->m_previousSibling = &newChild;
245 newChild.m_nextSibling = next;
cdn@chromium.org32296c32012-06-20 05:36:27 +0000246 } else {
zalan@apple.com84066f82016-11-15 20:12:26 +0000247 ASSERT(m_lastChild == beforeChild);
248 m_lastChild = &newChild;
cdn@chromium.org32296c32012-06-20 05:36:27 +0000249 }
eric@webkit.orgae29b2f2010-01-16 02:14:25 +0000250
zalan@apple.com84066f82016-11-15 20:12:26 +0000251 if (!newChild.m_firstChild || newChild.m_hasResetType) {
252 newChild.m_countInParent = newChild.computeCountInParent();
253 newChild.resetThisAndDescendantsRenderers();
eric@webkit.orgae29b2f2010-01-16 02:14:25 +0000254 if (next)
carol.szabo@nokia.com7cf0a552011-03-23 00:04:58 +0000255 next->recount();
eric@webkit.orgae29b2f2010-01-16 02:14:25 +0000256 return;
257 }
258
259 // The code below handles the case when a formerly root increment counter is loosing its root position
260 // and therefore its children become next siblings.
zalan@apple.com84066f82016-11-15 20:12:26 +0000261 CounterNode* last = newChild.m_lastChild;
262 CounterNode* first = newChild.m_firstChild;
eric@webkit.orgae29b2f2010-01-16 02:14:25 +0000263
cdn@chromium.org009d1ab2011-09-13 22:49:15 +0000264 if (first) {
265 ASSERT(last);
zalan@apple.com84066f82016-11-15 20:12:26 +0000266 newChild.m_nextSibling = first;
267 if (m_lastChild == &newChild)
cdn@chromium.org009d1ab2011-09-13 22:49:15 +0000268 m_lastChild = last;
269
zalan@apple.com84066f82016-11-15 20:12:26 +0000270 first->m_previousSibling = &newChild;
cdn@chromium.org009d1ab2011-09-13 22:49:15 +0000271
272 // The case when the original next sibling of the inserted node becomes a child of
273 // one of the former children of the inserted node is not handled as it is believed
274 // to be impossible since:
275 // 1. if the increment counter node lost it's root position as a result of another
276 // counter node being created, it will be inserted as the last child so next is null.
277 // 2. if the increment counter node lost it's root position as a result of a renderer being
278 // inserted into the document's render tree, all its former children counters are attached
279 // to children of the inserted renderer and hence cannot be in scope for counter nodes
280 // attached to renderers that were already in the document's render tree.
281 last->m_nextSibling = next;
282 if (next) {
zalan@apple.com84066f82016-11-15 20:12:26 +0000283 ASSERT(next->m_previousSibling == &newChild);
cdn@chromium.org009d1ab2011-09-13 22:49:15 +0000284 next->m_previousSibling = last;
285 } else
286 m_lastChild = last;
287 for (next = first; ; next = next->m_nextSibling) {
288 next->m_parent = this;
289 if (last == next)
290 break;
291 }
eric@webkit.orgae29b2f2010-01-16 02:14:25 +0000292 }
zalan@apple.com84066f82016-11-15 20:12:26 +0000293 newChild.m_firstChild = nullptr;
294 newChild.m_lastChild = nullptr;
295 newChild.m_countInParent = newChild.computeCountInParent();
296 newChild.resetRenderers();
carol.szabo@nokia.com7cf0a552011-03-23 00:04:58 +0000297 first->recount();
bdakin5d6edd42006-10-02 23:15:31 +0000298}
299
zalan@apple.com84066f82016-11-15 20:12:26 +0000300void CounterNode::removeChild(CounterNode& oldChild)
bdakin5d6edd42006-10-02 23:15:31 +0000301{
zalan@apple.com84066f82016-11-15 20:12:26 +0000302 ASSERT(!oldChild.m_firstChild);
303 ASSERT(!oldChild.m_lastChild);
darinec375482007-01-06 01:36:24 +0000304
zalan@apple.com84066f82016-11-15 20:12:26 +0000305 CounterNode* next = oldChild.m_nextSibling;
306 CounterNode* previous = oldChild.m_previousSibling;
darinec375482007-01-06 01:36:24 +0000307
zalan@apple.com84066f82016-11-15 20:12:26 +0000308 oldChild.m_nextSibling = nullptr;
309 oldChild.m_previousSibling = nullptr;
310 oldChild.m_parent = nullptr;
darinec375482007-01-06 01:36:24 +0000311
eric@webkit.org02482712009-11-13 20:21:44 +0000312 if (previous)
313 previous->m_nextSibling = next;
bdakin5d6edd42006-10-02 23:15:31 +0000314 else {
zalan@apple.com84066f82016-11-15 20:12:26 +0000315 ASSERT(m_firstChild == &oldChild);
darinec375482007-01-06 01:36:24 +0000316 m_firstChild = next;
bdakin5d6edd42006-10-02 23:15:31 +0000317 }
eric@webkit.org02482712009-11-13 20:21:44 +0000318
darinec375482007-01-06 01:36:24 +0000319 if (next)
eric@webkit.org02482712009-11-13 20:21:44 +0000320 next->m_previousSibling = previous;
darinec375482007-01-06 01:36:24 +0000321 else {
zalan@apple.com84066f82016-11-15 20:12:26 +0000322 ASSERT(m_lastChild == &oldChild);
eric@webkit.org02482712009-11-13 20:21:44 +0000323 m_lastChild = previous;
bdakin5d6edd42006-10-02 23:15:31 +0000324 }
eric@webkit.org02482712009-11-13 20:21:44 +0000325
darinec375482007-01-06 01:36:24 +0000326 if (next)
carol.szabo@nokia.com7cf0a552011-03-23 00:04:58 +0000327 next->recount();
bdakin5d6edd42006-10-02 23:15:31 +0000328}
329
simon.fraser@apple.comc9f96132015-03-06 18:20:40 +0000330#if ENABLE(TREE_DEBUGGING)
darinec375482007-01-06 01:36:24 +0000331
darinec375482007-01-06 01:36:24 +0000332static void showTreeAndMark(const CounterNode* node)
bdakin5d6edd42006-10-02 23:15:31 +0000333{
darinec375482007-01-06 01:36:24 +0000334 const CounterNode* root = node;
335 while (root->parent())
336 root = root->parent();
337
eric@webkit.orgcb918422009-11-13 20:55:51 +0000338 for (const CounterNode* current = root; current; current = current->nextInPreOrder()) {
zalan@apple.com29eeb9d2017-06-28 16:45:14 +0000339 fprintf(stderr, "%c", (current == node) ? '*' : ' ');
eric@webkit.orga0062952009-11-09 19:43:17 +0000340 for (const CounterNode* parent = current; parent && parent != root; parent = parent->parent())
zalan@apple.com29eeb9d2017-06-28 16:45:14 +0000341 fprintf(stderr, " ");
342 fprintf(stderr, "%p %s: %d %d P:%p PS:%p NS:%p R:%p\n",
eric@webkit.orgd8ca5e12009-12-21 20:11:47 +0000343 current, current->actsAsReset() ? "reset____" : "increment", current->value(),
eric@webkit.orga0062952009-11-09 19:43:17 +0000344 current->countInParent(), current->parent(), current->previousSibling(),
antti@apple.com9735e7d2014-08-18 22:16:47 +0000345 current->nextSibling(), &current->owner());
darinec375482007-01-06 01:36:24 +0000346 }
carol.szabo@nokia.com7cf0a552011-03-23 00:04:58 +0000347 fflush(stderr);
bdakin5d6edd42006-10-02 23:15:31 +0000348}
349
darinec375482007-01-06 01:36:24 +0000350#endif
351
weinig1497a7e2006-10-26 20:23:55 +0000352} // namespace WebCore
darinec375482007-01-06 01:36:24 +0000353
simon.fraser@apple.comc9f96132015-03-06 18:20:40 +0000354#if ENABLE(TREE_DEBUGGING)
darinec375482007-01-06 01:36:24 +0000355
carol.szabo@nokia.com02635bf2011-02-05 00:28:57 +0000356void showCounterTree(const WebCore::CounterNode* counter)
darinec375482007-01-06 01:36:24 +0000357{
358 if (counter)
359 showTreeAndMark(counter);
360}
361
362#endif