1 /*
2 * This file is part of the HTML rendering engine for KDE.
3 *
4 * Copyright (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com)
5 * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public License
18 * along with this library; see the file COPYING.LIB. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21 *
22 */
23
24 #include "config.h"
25 #include "CounterNode.h"
26
27 #include "RenderObject.h"
28 #include <stdio.h>
29
30 // FIXME: There's currently no strategy for getting the counter tree updated when new
31 // elements with counter-reset and counter-increment styles are added to the render tree.
32 // Also, the code can't handle changes where an existing node needs to change into a
33 // "reset" node, or from a "reset" node back to not a "reset" node. As of this writing,
34 // at least some of these problems manifest as failures in the t1204-increment and
35 // t1204-reset tests in the CSS 2.1 test suite.
36
37 namespace WebCore {
38
CounterNode(RenderObject * o,bool isReset,int value)39 CounterNode::CounterNode(RenderObject* o, bool isReset, int value)
40 : m_isReset(isReset)
41 , m_value(value)
42 , m_countInParent(0)
43 , m_renderer(o)
44 , m_parent(0)
45 , m_previousSibling(0)
46 , m_nextSibling(0)
47 , m_firstChild(0)
48 , m_lastChild(0)
49 {
50 }
51
computeCountInParent() const52 int CounterNode::computeCountInParent() const
53 {
54 int increment = m_isReset ? 0 : m_value;
55 if (m_previousSibling)
56 return m_previousSibling->m_countInParent + increment;
57 ASSERT(m_parent->m_firstChild == this);
58 return m_parent->m_value + increment;
59 }
60
recount()61 void CounterNode::recount()
62 {
63 for (CounterNode* c = this; c; c = c->m_nextSibling) {
64 int oldCount = c->m_countInParent;
65 int newCount = c->computeCountInParent();
66 c->m_countInParent = newCount;
67 if (oldCount == newCount)
68 break;
69 if (c->m_renderer->isCounter())
70 c->m_renderer->setNeedsLayoutAndPrefWidthsRecalc();
71 }
72 }
73
insertAfter(CounterNode * newChild,CounterNode * refChild)74 void CounterNode::insertAfter(CounterNode* newChild, CounterNode* refChild)
75 {
76 ASSERT(newChild);
77 ASSERT(!newChild->m_parent);
78 ASSERT(!newChild->m_previousSibling);
79 ASSERT(!newChild->m_nextSibling);
80 ASSERT(!refChild || refChild->m_parent == this);
81
82 CounterNode* next;
83
84 if (refChild) {
85 next = refChild->m_nextSibling;
86 refChild->m_nextSibling = newChild;
87 } else {
88 next = m_firstChild;
89 m_firstChild = newChild;
90 }
91
92 if (next) {
93 ASSERT(next->m_previousSibling == refChild);
94 next->m_previousSibling = newChild;
95 } else {
96 ASSERT(m_lastChild == refChild);
97 m_lastChild = newChild;
98 }
99
100 newChild->m_parent = this;
101 newChild->m_previousSibling = refChild;
102 newChild->m_nextSibling = next;
103
104 newChild->m_countInParent = newChild->computeCountInParent();
105 if (next)
106 next->recount();
107 }
108
removeChild(CounterNode * oldChild)109 void CounterNode::removeChild(CounterNode* oldChild)
110 {
111 ASSERT(oldChild);
112 ASSERT(!oldChild->m_firstChild);
113 ASSERT(!oldChild->m_lastChild);
114
115 CounterNode* next = oldChild->m_nextSibling;
116 CounterNode* prev = oldChild->m_previousSibling;
117
118 oldChild->m_nextSibling = 0;
119 oldChild->m_previousSibling = 0;
120 oldChild->m_parent = 0;
121
122 if (prev)
123 prev->m_nextSibling = next;
124 else {
125 ASSERT(m_firstChild == oldChild);
126 m_firstChild = next;
127 }
128
129 if (next)
130 next->m_previousSibling = prev;
131 else {
132 ASSERT(m_lastChild == oldChild);
133 m_lastChild = prev;
134 }
135
136 if (next)
137 next->recount();
138 }
139
140 #ifndef NDEBUG
141
nextInPreOrderAfterChildren(const CounterNode * node)142 static const CounterNode* nextInPreOrderAfterChildren(const CounterNode* node)
143 {
144 CounterNode* next = node->nextSibling();
145 if (!next) {
146 next = node->parent();
147 while (next && !next->nextSibling())
148 next = next->parent();
149 if (next)
150 next = next->nextSibling();
151 }
152 return next;
153 }
154
nextInPreOrder(const CounterNode * node)155 static const CounterNode* nextInPreOrder(const CounterNode* node)
156 {
157 if (CounterNode* child = node->firstChild())
158 return child;
159 return nextInPreOrderAfterChildren(node);
160 }
161
showTreeAndMark(const CounterNode * node)162 static void showTreeAndMark(const CounterNode* node)
163 {
164 const CounterNode* root = node;
165 while (root->parent())
166 root = root->parent();
167
168 for (const CounterNode* c = root; c; c = nextInPreOrder(c)) {
169 if (c == node)
170 fprintf(stderr, "*");
171 for (const CounterNode* d = c; d && d != root; d = d->parent())
172 fprintf(stderr, "\t");
173 if (c->isReset())
174 fprintf(stderr, "reset: %d\n", c->value());
175 else
176 fprintf(stderr, "increment: %d\n", c->value());
177 }
178 }
179
180 #endif
181
182 } // namespace WebCore
183
184 #ifndef NDEBUG
185
showTree(const WebCore::CounterNode * counter)186 void showTree(const WebCore::CounterNode* counter)
187 {
188 if (counter)
189 showTreeAndMark(counter);
190 }
191
192 #endif
193