OLD | NEW |
1 /** | 1 /** |
2 * Copyright (C) 2004 Allan Sandfeld Jensen (kde@carewolf.com) | 2 * Copyright (C) 2004 Allan Sandfeld Jensen (kde@carewolf.com) |
3 * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. | 3 * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. |
4 * | 4 * |
5 * This library is free software; you can redistribute it and/or | 5 * This library is free software; you can redistribute it and/or |
6 * modify it under the terms of the GNU Library General Public | 6 * modify it under the terms of the GNU Library General Public |
7 * License as published by the Free Software Foundation; either | 7 * License as published by the Free Software Foundation; either |
8 * version 2 of the License, or (at your option) any later version. | 8 * version 2 of the License, or (at your option) any later version. |
9 * | 9 * |
10 * This library is distributed in the hope that it will be useful, | 10 * This library is distributed in the hope that it will be useful, |
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 * Library General Public License for more details. | 13 * Library General Public License for more details. |
14 * | 14 * |
15 * You should have received a copy of the GNU Library General Public License | 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 | 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, | 17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
18 * Boston, MA 02110-1301, USA. | 18 * Boston, MA 02110-1301, USA. |
19 * | 19 * |
20 */ | 20 */ |
21 | 21 |
22 #include "config.h" | 22 #include "config.h" |
23 #include "RenderCounter.h" | 23 #include "RenderCounter.h" |
24 | 24 |
25 #include "CounterNode.h" | 25 #include "CounterNode.h" |
26 #include "Document.h" | 26 #include "Document.h" |
| 27 #include "Element.h" |
27 #include "HTMLNames.h" | 28 #include "HTMLNames.h" |
28 #include "HTMLOListElement.h" | 29 #include "HTMLOListElement.h" |
29 #include "RenderListItem.h" | 30 #include "RenderListItem.h" |
30 #include "RenderListMarker.h" | 31 #include "RenderListMarker.h" |
31 #include "RenderStyle.h" | 32 #include "RenderStyle.h" |
32 #include <wtf/StdLibExtras.h> | 33 #include <wtf/StdLibExtras.h> |
33 | 34 |
34 namespace WebCore { | 35 namespace WebCore { |
35 | 36 |
36 using namespace HTMLNames; | 37 using namespace HTMLNames; |
37 | 38 |
38 typedef HashMap<RefPtr<AtomicStringImpl>, RefPtr<CounterNode> > CounterMap; | 39 typedef HashMap<RefPtr<AtomicStringImpl>, RefPtr<CounterNode> > CounterMap; |
39 typedef HashMap<const RenderObject*, CounterMap*> CounterMaps; | 40 typedef HashMap<const RenderObject*, CounterMap*> CounterMaps; |
40 | 41 |
41 static CounterNode* makeCounterNode(RenderObject*, const AtomicString& identifie
r, bool alwaysCreateCounter); | 42 static CounterNode* makeCounterNode(RenderObject*, const AtomicString& identifie
r, bool alwaysCreateCounter); |
42 | 43 |
43 static CounterMaps& counterMaps() | 44 static CounterMaps& counterMaps() |
44 { | 45 { |
45 DEFINE_STATIC_LOCAL(CounterMaps, staticCounterMaps, ()); | 46 DEFINE_STATIC_LOCAL(CounterMaps, staticCounterMaps, ()); |
46 return staticCounterMaps; | 47 return staticCounterMaps; |
47 } | 48 } |
48 | 49 |
49 static inline RenderObject* previousSiblingOrParent(RenderObject* object) | 50 // This function processes the renderer tree in the order of the DOM tree |
| 51 // including pseudo elements as defined in CSS 2.1. |
| 52 // Anonymous renderers are skipped except for those representing pseudo elements
. |
| 53 static RenderObject* previousInPreOrder(const RenderObject* object) |
50 { | 54 { |
51 if (RenderObject* sibling = object->previousSibling()) | 55 Element* parent; |
52 return sibling; | 56 Element* sibling; |
53 return object->parent(); | 57 switch (object->style()->styleType()) { |
| 58 case NOPSEUDO: |
| 59 ASSERT(!object->isAnonymous()); |
| 60 parent = toElement(object->node()); |
| 61 sibling = parent->previousElementSibling(); |
| 62 parent = parent->parentElement(); |
| 63 break; |
| 64 case BEFORE: |
| 65 return object->generatingNode()->renderer(); // It is always the generat
ing node's renderer |
| 66 case AFTER: |
| 67 parent = toElement(object->generatingNode()); |
| 68 sibling = parent->lastElementChild(); |
| 69 break; |
| 70 default: |
| 71 ASSERT_NOT_REACHED(); |
| 72 return 0; |
| 73 } |
| 74 while (sibling) { |
| 75 if (RenderObject* renderer = sibling->renderer()) { |
| 76 if (RenderObject* after = renderer->afterPseudoElementRenderer()) |
| 77 return after; |
| 78 parent = sibling; |
| 79 sibling = sibling->lastElementChild(); |
| 80 if (!sibling) { |
| 81 if (RenderObject* before = renderer->beforePseudoElementRenderer
()) |
| 82 return before; |
| 83 return renderer; |
| 84 } |
| 85 } else |
| 86 sibling = sibling->previousElementSibling(); |
| 87 } |
| 88 if (!parent) |
| 89 return 0; |
| 90 RenderObject* renderer = parent->renderer(); // Should never be null |
| 91 if (RenderObject* before = renderer->beforePseudoElementRenderer()) |
| 92 return before; |
| 93 return renderer; |
| 94 } |
| 95 |
| 96 // This function processes the renderer tree in the order of the DOM tree |
| 97 // including pseudo elements as defined in CSS 2.1. |
| 98 // Anonymous renderers are skipped except for those representing pseudo elements
. |
| 99 static RenderObject* previousSiblingOrParent(const RenderObject* object) |
| 100 { |
| 101 Element* parent; |
| 102 Element* sibling; |
| 103 switch (object->style()->styleType()) { |
| 104 case NOPSEUDO: |
| 105 ASSERT(!object->isAnonymous()); |
| 106 parent = toElement(object->node()); |
| 107 sibling = parent->previousElementSibling(); |
| 108 parent = parent->parentElement(); |
| 109 break; |
| 110 case BEFORE: |
| 111 return object->generatingNode()->renderer(); // It is always the generat
ing node's renderer |
| 112 case AFTER: |
| 113 parent = toElement(object->generatingNode()); |
| 114 sibling = parent->lastElementChild(); |
| 115 break; |
| 116 default: |
| 117 ASSERT_NOT_REACHED(); |
| 118 return 0; |
| 119 } |
| 120 while (sibling) { |
| 121 if (RenderObject* renderer = sibling->renderer()) // This skips invisibl
e nodes |
| 122 return renderer; |
| 123 sibling = sibling->previousElementSibling(); |
| 124 } |
| 125 if (parent) { |
| 126 RenderObject* renderer = parent->renderer(); |
| 127 if (RenderObject* before = renderer->virtualChildren()->beforePseudoElem
entRenderer(renderer)) |
| 128 return before; |
| 129 return renderer; |
| 130 } |
| 131 return 0; |
| 132 } |
| 133 |
| 134 static Element* parentElement(RenderObject* object) |
| 135 { |
| 136 switch (object->style()->styleType()) { |
| 137 case NOPSEUDO: |
| 138 ASSERT(!object->isAnonymous()); |
| 139 return toElement(object->node())->parentElement(); |
| 140 case BEFORE: |
| 141 case AFTER: |
| 142 return toElement(object->generatingNode()); |
| 143 default: |
| 144 ASSERT_NOT_REACHED(); |
| 145 return 0; |
| 146 } |
| 147 } |
| 148 |
| 149 static inline bool areRenderersElementsSiblings(RenderObject* first, RenderObjec
t* second) |
| 150 { |
| 151 return parentElement(first) == parentElement(second); |
| 152 } |
| 153 |
| 154 // This function processes the renderer tree in the order of the DOM tree |
| 155 // including pseudo elements as defined in CSS 2.1. |
| 156 // Anonymous renderers are skipped except for those representing pseudo elements
. |
| 157 static RenderObject* nextInPreOrder(const RenderObject* object, const Element* s
tayWithin, bool skipDescendants = false) |
| 158 { |
| 159 Element* self; |
| 160 Element* child; |
| 161 RenderObject* result; |
| 162 self = toElement(object->generatingNode()); |
| 163 if (skipDescendants) |
| 164 goto nextsibling; |
| 165 switch (object->style()->styleType()) { |
| 166 case NOPSEUDO: |
| 167 ASSERT(!object->isAnonymous()); |
| 168 result = object->beforePseudoElementRenderer(); |
| 169 if (result) |
| 170 return result; |
| 171 break; |
| 172 case BEFORE: |
| 173 break; |
| 174 case AFTER: |
| 175 goto nextsibling; |
| 176 default: |
| 177 ASSERT_NOT_REACHED(); |
| 178 return 0; |
| 179 } |
| 180 child = self->firstElementChild(); |
| 181 while (true) { |
| 182 while (child) { |
| 183 result = child->renderer(); |
| 184 if (result) |
| 185 return result; |
| 186 child = child->nextElementSibling(); |
| 187 } |
| 188 result = self->renderer()->afterPseudoElementRenderer(); |
| 189 if (result) |
| 190 return result; |
| 191 nextsibling: |
| 192 if (self == stayWithin) |
| 193 return 0; |
| 194 child = self->nextElementSibling(); |
| 195 self = self->parentElement(); |
| 196 if (!self) { |
| 197 ASSERT(!child); // We can only reach this if we are searching beyond
the root element |
| 198 return 0; // which cannot have siblings |
| 199 } |
| 200 } |
54 } | 201 } |
55 | 202 |
56 static bool planCounter(RenderObject* object, const AtomicString& identifier, bo
ol& isReset, int& value) | 203 static bool planCounter(RenderObject* object, const AtomicString& identifier, bo
ol& isReset, int& value) |
57 { | 204 { |
58 ASSERT(object); | 205 ASSERT(object); |
59 | 206 |
60 // Real text nodes don't have their own style so they can't have counters. | 207 // Real text nodes don't have their own style so they can't have counters. |
61 // We can't even look at their styles or we'll see extra resets and incremen
ts! | 208 // We can't even look at their styles or we'll see extra resets and incremen
ts! |
62 if (object->isText() && !object->isBR()) | 209 if (object->isText() && !object->isBR()) |
63 return false; | 210 return false; |
64 | 211 Node* generatingNode = object->generatingNode(); |
| 212 // We must have a generating node or else we cannot have a counter. |
| 213 if (!generatingNode) |
| 214 return false; |
65 RenderStyle* style = object->style(); | 215 RenderStyle* style = object->style(); |
66 ASSERT(style); | 216 ASSERT(style); |
67 | 217 |
| 218 switch (style->styleType()) { |
| 219 case NOPSEUDO: |
| 220 // Sometimes nodes have more then one renderer. Only the first one gets
the counter |
| 221 // LayoutTests/http/tests/css/counter-crash.html |
| 222 if (generatingNode->renderer() != object) |
| 223 return false; |
| 224 break; |
| 225 case BEFORE: |
| 226 case AFTER: |
| 227 break; |
| 228 default: |
| 229 return false; // Counters are forbidden from all other pseudo elements. |
| 230 } |
| 231 |
68 if (const CounterDirectiveMap* directivesMap = style->counterDirectives()) { | 232 if (const CounterDirectiveMap* directivesMap = style->counterDirectives()) { |
69 CounterDirectives directives = directivesMap->get(identifier.impl()); | 233 CounterDirectives directives = directivesMap->get(identifier.impl()); |
70 if (directives.m_reset) { | 234 if (directives.m_reset) { |
71 value = directives.m_resetValue; | 235 value = directives.m_resetValue; |
72 if (directives.m_increment) | 236 if (directives.m_increment) |
73 value += directives.m_incrementValue; | 237 value += directives.m_incrementValue; |
74 isReset = true; | 238 isReset = true; |
75 return true; | 239 return true; |
76 } | 240 } |
77 if (directives.m_increment) { | 241 if (directives.m_increment) { |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
126 // - Non-reset CounterNodes cannot have descendants. | 290 // - Non-reset CounterNodes cannot have descendants. |
127 | 291 |
128 static bool findPlaceForCounter(RenderObject* counterOwner, const AtomicString&
identifier, bool isReset, CounterNode*& parent, CounterNode*& previousSibling) | 292 static bool findPlaceForCounter(RenderObject* counterOwner, const AtomicString&
identifier, bool isReset, CounterNode*& parent, CounterNode*& previousSibling) |
129 { | 293 { |
130 // We cannot stop searching for counters with the same identifier before we
also | 294 // We cannot stop searching for counters with the same identifier before we
also |
131 // check this renderer, because it may affect the positioning in the tree of
our counter. | 295 // check this renderer, because it may affect the positioning in the tree of
our counter. |
132 RenderObject* searchEndRenderer = previousSiblingOrParent(counterOwner); | 296 RenderObject* searchEndRenderer = previousSiblingOrParent(counterOwner); |
133 // We check renderers in preOrder from the renderer that our counter is atta
ched to | 297 // We check renderers in preOrder from the renderer that our counter is atta
ched to |
134 // towards the begining of the document for counters with the same identifie
r as the one | 298 // towards the begining of the document for counters with the same identifie
r as the one |
135 // we are trying to find a place for. This is the next renderer to be checke
d. | 299 // we are trying to find a place for. This is the next renderer to be checke
d. |
136 RenderObject* currentRenderer = counterOwner->previousInPreOrder(); | 300 RenderObject* currentRenderer = previousInPreOrder(counterOwner); |
137 previousSibling = 0; | 301 previousSibling = 0; |
138 while (currentRenderer) { | 302 while (currentRenderer) { |
139 CounterNode* currentCounter = makeCounterNode(currentRenderer, identifie
r, false); | 303 CounterNode* currentCounter = makeCounterNode(currentRenderer, identifie
r, false); |
140 if (searchEndRenderer == currentRenderer) { | 304 if (searchEndRenderer == currentRenderer) { |
141 // We may be at the end of our search. | 305 // We may be at the end of our search. |
142 if (currentCounter) { | 306 if (currentCounter) { |
143 // We have a suitable counter on the EndSearchRenderer. | 307 // We have a suitable counter on the EndSearchRenderer. |
144 if (previousSibling) { // But we already found another counter t
hat we come after. | 308 if (previousSibling) { // But we already found another counter t
hat we come after. |
145 if (currentCounter->actsAsReset()) { | 309 if (currentCounter->actsAsReset()) { |
146 // We found a reset counter that is on a renderer that i
s a sibling of ours or a parent. | 310 // We found a reset counter that is on a renderer that i
s a sibling of ours or a parent. |
147 if (isReset && currentRenderer->parent() == counterOwner
->parent()) { | 311 if (isReset && areRenderersElementsSiblings(currentRende
rer, counterOwner)) { |
148 // We are also a reset counter and the previous rese
t was on a sibling renderer | 312 // We are also a reset counter and the previous rese
t was on a sibling renderer |
149 // hence we are the next sibling of that counter if
that reset is not a root or | 313 // hence we are the next sibling of that counter if
that reset is not a root or |
150 // we are a root node if that reset is a root. | 314 // we are a root node if that reset is a root. |
151 parent = currentCounter->parent(); | 315 parent = currentCounter->parent(); |
152 previousSibling = parent ? currentCounter : 0; | 316 previousSibling = parent ? currentCounter : 0; |
153 return parent; | 317 return parent; |
154 } | 318 } |
155 // We are not a reset node or the previous reset must be
on an ancestor of our renderer | 319 // We are not a reset node or the previous reset must be
on an ancestor of our renderer |
156 // hence we must be a child of that reset counter. | 320 // hence we must be a child of that reset counter. |
157 parent = currentCounter; | 321 parent = currentCounter; |
158 ASSERT(previousSibling->parent() == currentCounter); | 322 ASSERT(previousSibling->parent() == currentCounter); |
159 return true; | 323 return true; |
160 } | 324 } |
161 // CurrentCounter, the counter at the EndSearchRenderer, is
not reset. | 325 // CurrentCounter, the counter at the EndSearchRenderer, is
not reset. |
162 if (!isReset || currentRenderer->parent() != counterOwner->p
arent()) { | 326 if (!isReset || !areRenderersElementsSiblings(currentRendere
r, counterOwner)) { |
163 // If the node we are placing is not reset or we have fo
und a counter that is attached | 327 // If the node we are placing is not reset or we have fo
und a counter that is attached |
164 // to an ancestor of the placed counter's renderer we kn
ow we are a sibling of that node. | 328 // to an ancestor of the placed counter's renderer we kn
ow we are a sibling of that node. |
165 ASSERT(currentCounter->parent() == previousSibling->pare
nt()); | 329 ASSERT(currentCounter->parent() == previousSibling->pare
nt()); |
166 parent = currentCounter->parent(); | 330 parent = currentCounter->parent(); |
167 return true; | 331 return true; |
168 } | 332 } |
169 } else { | 333 } else { |
170 // We are at the potential end of the search, but we had no
previous sibling candidate | 334 // We are at the potential end of the search, but we had no
previous sibling candidate |
171 // In this case we follow pretty much the same logic as abov
e but no ASSERTs about | 335 // In this case we follow pretty much the same logic as abov
e but no ASSERTs about |
172 // previousSibling, and when we are a sibling of the end cou
nter we must set previousSibling | 336 // previousSibling, and when we are a sibling of the end cou
nter we must set previousSibling |
173 // to currentCounter. | 337 // to currentCounter. |
174 if (currentCounter->actsAsReset()) { | 338 if (currentCounter->actsAsReset()) { |
175 if (isReset && currentRenderer->parent() == counterOwner
->parent()) { | 339 if (isReset && areRenderersElementsSiblings(currentRende
rer, counterOwner)) { |
176 parent = currentCounter->parent(); | 340 parent = currentCounter->parent(); |
177 previousSibling = currentCounter; | 341 previousSibling = currentCounter; |
178 return parent; | 342 return parent; |
179 } | 343 } |
180 parent = currentCounter; | 344 parent = currentCounter; |
181 return true; | 345 return true; |
182 } | 346 } |
183 if (!isReset || currentRenderer->parent() != counterOwner->p
arent()) { | 347 if (!isReset || !areRenderersElementsSiblings(currentRendere
r, counterOwner)) { |
184 parent = currentCounter->parent(); | 348 parent = currentCounter->parent(); |
185 previousSibling = currentCounter; | 349 previousSibling = currentCounter; |
186 return true; | 350 return true; |
187 } | 351 } |
188 previousSibling = currentCounter; | 352 previousSibling = currentCounter; |
189 } | 353 } |
190 } | 354 } |
191 // We come here if the previous sibling or parent of our renderer ha
d no | 355 // We come here if the previous sibling or parent of our renderer ha
d no |
192 // good counter, or we are a reset node and the counter on the previ
ous sibling | 356 // good counter, or we are a reset node and the counter on the previ
ous sibling |
193 // of our renderer was not a reset counter. | 357 // of our renderer was not a reset counter. |
194 // Set a new goal for the end of the search. | 358 // Set a new goal for the end of the search. |
195 searchEndRenderer = previousSiblingOrParent(currentRenderer); | 359 searchEndRenderer = previousSiblingOrParent(currentRenderer); |
196 } else { | 360 } else { |
197 // We are searching descendants of a previous sibling of the rendere
r that the | 361 // We are searching descendants of a previous sibling of the rendere
r that the |
198 // counter being placed is attached to. | 362 // counter being placed is attached to. |
199 if (currentCounter) { | 363 if (currentCounter) { |
200 // We found a suitable counter. | 364 // We found a suitable counter. |
201 if (previousSibling) { | 365 if (previousSibling) { |
202 // Since we had a suitable previous counter before, we shoul
d only consider this one as our | 366 // Since we had a suitable previous counter before, we shoul
d only consider this one as our |
203 // previousSibling if it is a reset counter and hence the cu
rrent previousSibling is its child. | 367 // previousSibling if it is a reset counter and hence the cu
rrent previousSibling is its child. |
204 if (currentCounter->actsAsReset()) { | 368 if (currentCounter->actsAsReset()) { |
205 previousSibling = currentCounter; | 369 previousSibling = currentCounter; |
206 // We are no longer interested in previous siblings of t
he currentRenderer or their children | 370 // We are no longer interested in previous siblings of t
he currentRenderer or their children |
207 // as counters they may have attached cannot be the prev
ious sibling of the counter we are placing. | 371 // as counters they may have attached cannot be the prev
ious sibling of the counter we are placing. |
208 currentRenderer = currentRenderer->parent(); | 372 currentRenderer = parentElement(currentRenderer)->render
er(); |
209 continue; | 373 continue; |
210 } | 374 } |
211 } else | 375 } else |
212 previousSibling = currentCounter; | 376 previousSibling = currentCounter; |
213 currentRenderer = previousSiblingOrParent(currentRenderer); | 377 currentRenderer = previousSiblingOrParent(currentRenderer); |
214 continue; | 378 continue; |
215 } | 379 } |
216 } | 380 } |
217 // This function is designed so that the same test is not done twice in
an iteration, except for this one | 381 // This function is designed so that the same test is not done twice in
an iteration, except for this one |
218 // which may be done twice in some cases. Rearranging the decision point
s though, to accommodate this | 382 // which may be done twice in some cases. Rearranging the decision point
s though, to accommodate this |
(...skipping 30 matching lines...) Expand all Loading... |
249 newParent->insertAfter(newNode.get(), newPreviousSibling, identifier); | 413 newParent->insertAfter(newNode.get(), newPreviousSibling, identifier); |
250 CounterMap* nodeMap; | 414 CounterMap* nodeMap; |
251 if (object->m_hasCounterNodeMap) | 415 if (object->m_hasCounterNodeMap) |
252 nodeMap = counterMaps().get(object); | 416 nodeMap = counterMaps().get(object); |
253 else { | 417 else { |
254 nodeMap = new CounterMap; | 418 nodeMap = new CounterMap; |
255 counterMaps().set(object, nodeMap); | 419 counterMaps().set(object, nodeMap); |
256 object->m_hasCounterNodeMap = true; | 420 object->m_hasCounterNodeMap = true; |
257 } | 421 } |
258 nodeMap->set(identifier.impl(), newNode); | 422 nodeMap->set(identifier.impl(), newNode); |
259 if (newNode->parent() || !object->nextInPreOrder(object->parent())) | 423 if (newNode->parent()) |
260 return newNode.get(); | 424 return newNode.get(); |
261 // Checking if some nodes that were previously counter tree root nodes | 425 // Checking if some nodes that were previously counter tree root nodes |
262 // should become children of this node now. | 426 // should become children of this node now. |
263 CounterMaps& maps = counterMaps(); | 427 CounterMaps& maps = counterMaps(); |
264 RenderObject* stayWithin = object->parent(); | 428 Element* stayWithin = parentElement(object); |
265 for (RenderObject* currentRenderer = object->nextInPreOrder(stayWithin); cur
rentRenderer; currentRenderer = currentRenderer->nextInPreOrder(stayWithin)) { | 429 bool skipDescendants; |
| 430 for (RenderObject* currentRenderer = nextInPreOrder(object, stayWithin); cur
rentRenderer; currentRenderer = nextInPreOrder(currentRenderer, stayWithin, skip
Descendants)) { |
| 431 skipDescendants = false; |
266 if (!currentRenderer->m_hasCounterNodeMap) | 432 if (!currentRenderer->m_hasCounterNodeMap) |
267 continue; | 433 continue; |
268 CounterNode* currentCounter = maps.get(currentRenderer)->get(identifier.
impl()).get(); | 434 CounterNode* currentCounter = maps.get(currentRenderer)->get(identifier.
impl()).get(); |
269 if (!currentCounter) | 435 if (!currentCounter) |
270 continue; | 436 continue; |
| 437 skipDescendants = true; |
271 if (currentCounter->parent()) { | 438 if (currentCounter->parent()) { |
272 ASSERT(newNode->firstChild()); | 439 ASSERT(newNode->firstChild()); |
273 if (currentRenderer->lastChild()) | |
274 currentRenderer = currentRenderer->lastChild(); | |
275 continue; | 440 continue; |
276 } | 441 } |
277 if (stayWithin != currentRenderer->parent() || !currentCounter->hasReset
Type()) | 442 if (stayWithin == parentElement(currentRenderer) && currentCounter->hasR
esetType()) |
278 newNode->insertAfter(currentCounter, newNode->lastChild(), identifie
r); | 443 break; |
279 if (currentRenderer->lastChild()) | 444 newNode->insertAfter(currentCounter, newNode->lastChild(), identifier); |
280 currentRenderer = currentRenderer->lastChild(); | |
281 } | 445 } |
282 return newNode.get(); | 446 return newNode.get(); |
283 } | 447 } |
284 | 448 |
285 RenderCounter::RenderCounter(Document* node, const CounterContent& counter) | 449 RenderCounter::RenderCounter(Document* node, const CounterContent& counter) |
286 : RenderText(node, StringImpl::empty()) | 450 : RenderText(node, StringImpl::empty()) |
287 , m_counter(counter) | 451 , m_counter(counter) |
288 , m_counterNode(0) | 452 , m_counterNode(0) |
289 { | 453 { |
290 } | 454 } |
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
437 continue; | 601 continue; |
438 if (parent) | 602 if (parent) |
439 parent->removeChild(node.get(), it->first.get()); | 603 parent->removeChild(node.get(), it->first.get()); |
440 if (newParent) | 604 if (newParent) |
441 newParent->insertAfter(node.get(), newPreviousSibling, it->first.get
()); | 605 newParent->insertAfter(node.get(), newPreviousSibling, it->first.get
()); |
442 } | 606 } |
443 } | 607 } |
444 | 608 |
445 void RenderCounter::rendererSubtreeAttached(RenderObject* renderer) | 609 void RenderCounter::rendererSubtreeAttached(RenderObject* renderer) |
446 { | 610 { |
| 611 Node* node = renderer->node(); |
| 612 if (node) |
| 613 node = node->parentNode(); |
| 614 else |
| 615 node = renderer->generatingNode(); |
| 616 if (node && !node->attached()) |
| 617 return; // No need to update if the parent is not attached yet |
447 for (RenderObject* descendant = renderer; descendant; descendant = descendan
t->nextInPreOrder(renderer)) | 618 for (RenderObject* descendant = renderer; descendant; descendant = descendan
t->nextInPreOrder(renderer)) |
448 updateCounters(descendant); | 619 updateCounters(descendant); |
449 } | 620 } |
450 | 621 |
451 void RenderCounter::rendererStyleChanged(RenderObject* renderer, const RenderSty
le* oldStyle, const RenderStyle* newStyle) | 622 void RenderCounter::rendererStyleChanged(RenderObject* renderer, const RenderSty
le* oldStyle, const RenderStyle* newStyle) |
452 { | 623 { |
| 624 Node* node = renderer->generatingNode(); |
| 625 if (!node || !node->attached()) |
| 626 return; // cannot have generated content or if it can have, it will be h
andled during attaching |
453 const CounterDirectiveMap* newCounterDirectives; | 627 const CounterDirectiveMap* newCounterDirectives; |
454 const CounterDirectiveMap* oldCounterDirectives; | 628 const CounterDirectiveMap* oldCounterDirectives; |
455 if (oldStyle && (oldCounterDirectives = oldStyle->counterDirectives())) { | 629 if (oldStyle && (oldCounterDirectives = oldStyle->counterDirectives())) { |
456 if (newStyle && (newCounterDirectives = newStyle->counterDirectives()))
{ | 630 if (newStyle && (newCounterDirectives = newStyle->counterDirectives()))
{ |
457 CounterDirectiveMap::const_iterator newMapEnd = newCounterDirectives
->end(); | 631 CounterDirectiveMap::const_iterator newMapEnd = newCounterDirectives
->end(); |
458 CounterDirectiveMap::const_iterator oldMapEnd = oldCounterDirectives
->end(); | 632 CounterDirectiveMap::const_iterator oldMapEnd = oldCounterDirectives
->end(); |
459 for (CounterDirectiveMap::const_iterator it = newCounterDirectives->
begin(); it != newMapEnd; ++it) { | 633 for (CounterDirectiveMap::const_iterator it = newCounterDirectives->
begin(); it != newMapEnd; ++it) { |
460 CounterDirectiveMap::const_iterator oldMapIt = oldCounterDirecti
ves->find(it->first); | 634 CounterDirectiveMap::const_iterator oldMapIt = oldCounterDirecti
ves->find(it->first); |
461 if (oldMapIt != oldMapEnd) { | 635 if (oldMapIt != oldMapEnd) { |
462 if (oldMapIt->second == it->second) | 636 if (oldMapIt->second == it->second) |
(...skipping 19 matching lines...) Expand all Loading... |
482 for (CounterDirectiveMap::const_iterator it = newCounterDirectives->begi
n(); it != newMapEnd; ++it) { | 656 for (CounterDirectiveMap::const_iterator it = newCounterDirectives->begi
n(); it != newMapEnd; ++it) { |
483 // We must create this node here, because the added node may be a no
de with no display such as | 657 // We must create this node here, because the added node may be a no
de with no display such as |
484 // as those created by the increment or reset directives and the re-
layout that will happen will | 658 // as those created by the increment or reset directives and the re-
layout that will happen will |
485 // not catch the change if the node had no children. | 659 // not catch the change if the node had no children. |
486 makeCounterNode(renderer, it->first.get(), false); | 660 makeCounterNode(renderer, it->first.get(), false); |
487 } | 661 } |
488 } | 662 } |
489 } | 663 } |
490 | 664 |
491 } // namespace WebCore | 665 } // namespace WebCore |
| 666 |
| 667 #ifndef NDEBUG |
| 668 |
| 669 void showCounterRendererTree(const WebCore::RenderObject* renderer, const char*
counterName) |
| 670 { |
| 671 if (!renderer) |
| 672 return; |
| 673 const WebCore::RenderObject* root = renderer; |
| 674 while (root->parent()) |
| 675 root = root->parent(); |
| 676 |
| 677 AtomicString identifier(counterName); |
| 678 for (const WebCore::RenderObject* current = root; current; current = current
->nextInPreOrder()) { |
| 679 fprintf(stderr, "%c", (current == renderer) ? '*' : ' '); |
| 680 for (const WebCore::RenderObject* parent = current; parent && parent !=
root; parent = parent->parent()) |
| 681 fprintf(stderr, " "); |
| 682 fprintf(stderr, "%p N:%p P:%p PS:%p NS:%p C:%p\n", |
| 683 current, current->node(), current->parent(), current->previousSiblin
g(), |
| 684 current->nextSibling(), current->m_hasCounterNodeMap? |
| 685 counterName ? WebCore::counterMaps().get(current)->get(identifier.im
pl()).get() : (WebCore::CounterNode*)1 : (WebCore::CounterNode*)0); |
| 686 } |
| 687 } |
| 688 |
| 689 #endif // NDEBUG |
OLD | NEW |