RenderCounter.cpp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636
  1. /**
  2. * Copyright (C) 2004 Allan Sandfeld Jensen (kde@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. #include "config.h"
  22. #include "RenderCounter.h"
  23. #include "CounterNode.h"
  24. #include "Document.h"
  25. #include "Element.h"
  26. #include "HTMLNames.h"
  27. #include "HTMLOListElement.h"
  28. #include "NodeTraversal.h"
  29. #include "RenderListItem.h"
  30. #include "RenderListMarker.h"
  31. #include "RenderStyle.h"
  32. #include "RenderView.h"
  33. #include <wtf/StdLibExtras.h>
  34. #ifndef NDEBUG
  35. #include <stdio.h>
  36. #endif
  37. namespace WebCore {
  38. using namespace HTMLNames;
  39. typedef HashMap<AtomicString, RefPtr<CounterNode> > CounterMap;
  40. typedef HashMap<const RenderObject*, OwnPtr<CounterMap> > CounterMaps;
  41. static CounterNode* makeCounterNode(RenderObject*, const AtomicString& identifier, bool alwaysCreateCounter);
  42. static CounterMaps& counterMaps()
  43. {
  44. DEFINE_STATIC_LOCAL(CounterMaps, staticCounterMaps, ());
  45. return staticCounterMaps;
  46. }
  47. // This function processes the renderer tree in the order of the DOM tree
  48. // including pseudo elements as defined in CSS 2.1.
  49. static RenderObject* previousInPreOrder(const RenderObject* object)
  50. {
  51. Element* self = toElement(object->node());
  52. Element* previous = ElementTraversal::previousIncludingPseudo(self);
  53. while (previous && !previous->renderer())
  54. previous = ElementTraversal::previousIncludingPseudo(previous);
  55. return previous ? previous->renderer() : 0;
  56. }
  57. // This function processes the renderer tree in the order of the DOM tree
  58. // including pseudo elements as defined in CSS 2.1.
  59. static RenderObject* previousSiblingOrParent(const RenderObject* object)
  60. {
  61. Element* self = toElement(object->node());
  62. Element* previous = ElementTraversal::pseudoAwarePreviousSibling(self);
  63. while (previous && !previous->renderer())
  64. previous = ElementTraversal::pseudoAwarePreviousSibling(previous);
  65. if (previous)
  66. return previous->renderer();
  67. previous = self->parentElement();
  68. return previous ? previous->renderer() : 0;
  69. }
  70. static inline Element* parentElement(RenderObject* object)
  71. {
  72. return toElement(object->node())->parentElement();
  73. }
  74. static inline bool areRenderersElementsSiblings(RenderObject* first, RenderObject* second)
  75. {
  76. return parentElement(first) == parentElement(second);
  77. }
  78. // This function processes the renderer tree in the order of the DOM tree
  79. // including pseudo elements as defined in CSS 2.1.
  80. static RenderObject* nextInPreOrder(const RenderObject* object, const Element* stayWithin, bool skipDescendants = false)
  81. {
  82. Element* self = toElement(object->node());
  83. Element* next = skipDescendants ? ElementTraversal::nextIncludingPseudoSkippingChildren(self, stayWithin) : ElementTraversal::nextIncludingPseudo(self, stayWithin);
  84. while (next && !next->renderer())
  85. next = skipDescendants ? ElementTraversal::nextIncludingPseudoSkippingChildren(next, stayWithin) : ElementTraversal::nextIncludingPseudo(next, stayWithin);
  86. return next ? next->renderer() : 0;
  87. }
  88. static bool planCounter(RenderObject* object, const AtomicString& identifier, bool& isReset, int& value)
  89. {
  90. ASSERT(object);
  91. // Real text nodes don't have their own style so they can't have counters.
  92. // We can't even look at their styles or we'll see extra resets and increments!
  93. if (object->isText() && !object->isBR())
  94. return false;
  95. Node* generatingNode = object->generatingNode();
  96. // We must have a generating node or else we cannot have a counter.
  97. if (!generatingNode)
  98. return false;
  99. RenderStyle* style = object->style();
  100. ASSERT(style);
  101. switch (style->styleType()) {
  102. case NOPSEUDO:
  103. // Sometimes nodes have more then one renderer. Only the first one gets the counter
  104. // LayoutTests/http/tests/css/counter-crash.html
  105. if (generatingNode->renderer() != object)
  106. return false;
  107. break;
  108. case BEFORE:
  109. case AFTER:
  110. break;
  111. default:
  112. return false; // Counters are forbidden from all other pseudo elements.
  113. }
  114. const CounterDirectives directives = style->getCounterDirectives(identifier);
  115. if (directives.isDefined()) {
  116. value = directives.combinedValue();
  117. isReset = directives.isReset();
  118. return true;
  119. }
  120. if (identifier == "list-item") {
  121. if (object->isListItem()) {
  122. if (toRenderListItem(object)->hasExplicitValue()) {
  123. value = toRenderListItem(object)->explicitValue();
  124. isReset = true;
  125. return true;
  126. }
  127. value = 1;
  128. isReset = false;
  129. return true;
  130. }
  131. if (Node* e = object->node()) {
  132. if (e->hasTagName(olTag)) {
  133. value = static_cast<HTMLOListElement*>(e)->start();
  134. isReset = true;
  135. return true;
  136. }
  137. if (e->hasTagName(ulTag) || e->hasTagName(menuTag) || e->hasTagName(dirTag)) {
  138. value = 0;
  139. isReset = true;
  140. return true;
  141. }
  142. }
  143. }
  144. return false;
  145. }
  146. // - Finds the insertion point for the counter described by counterOwner, isReset and
  147. // identifier in the CounterNode tree for identifier and sets parent and
  148. // previousSibling accordingly.
  149. // - The function returns true if the counter whose insertion point is searched is NOT
  150. // the root of the tree.
  151. // - The root of the tree is a counter reference that is not in the scope of any other
  152. // counter with the same identifier.
  153. // - All the counter references with the same identifier as this one that are in
  154. // children or subsequent siblings of the renderer that owns the root of the tree
  155. // form the rest of of the nodes of the tree.
  156. // - The root of the tree is always a reset type reference.
  157. // - A subtree rooted at any reset node in the tree is equivalent to all counter
  158. // references that are in the scope of the counter or nested counter defined by that
  159. // reset node.
  160. // - Non-reset CounterNodes cannot have descendants.
  161. static bool findPlaceForCounter(RenderObject* counterOwner, const AtomicString& identifier, bool isReset, RefPtr<CounterNode>& parent, RefPtr<CounterNode>& previousSibling)
  162. {
  163. // We cannot stop searching for counters with the same identifier before we also
  164. // check this renderer, because it may affect the positioning in the tree of our counter.
  165. RenderObject* searchEndRenderer = previousSiblingOrParent(counterOwner);
  166. // We check renderers in preOrder from the renderer that our counter is attached to
  167. // towards the begining of the document for counters with the same identifier as the one
  168. // we are trying to find a place for. This is the next renderer to be checked.
  169. RenderObject* currentRenderer = previousInPreOrder(counterOwner);
  170. previousSibling = 0;
  171. RefPtr<CounterNode> previousSiblingProtector = 0;
  172. while (currentRenderer) {
  173. CounterNode* currentCounter = makeCounterNode(currentRenderer, identifier, false);
  174. if (searchEndRenderer == currentRenderer) {
  175. // We may be at the end of our search.
  176. if (currentCounter) {
  177. // We have a suitable counter on the EndSearchRenderer.
  178. if (previousSiblingProtector) { // But we already found another counter that we come after.
  179. if (currentCounter->actsAsReset()) {
  180. // We found a reset counter that is on a renderer that is a sibling of ours or a parent.
  181. if (isReset && areRenderersElementsSiblings(currentRenderer, counterOwner)) {
  182. // We are also a reset counter and the previous reset was on a sibling renderer
  183. // hence we are the next sibling of that counter if that reset is not a root or
  184. // we are a root node if that reset is a root.
  185. parent = currentCounter->parent();
  186. previousSibling = parent ? currentCounter : 0;
  187. return parent;
  188. }
  189. // We are not a reset node or the previous reset must be on an ancestor of our owner renderer
  190. // hence we must be a child of that reset counter.
  191. parent = currentCounter;
  192. // In some cases renders can be reparented (ex. nodes inside a table but not in a column or row).
  193. // In these cases the identified previousSibling will be invalid as its parent is different from
  194. // our identified parent.
  195. if (previousSiblingProtector->parent() != currentCounter)
  196. previousSiblingProtector = 0;
  197. previousSibling = previousSiblingProtector.get();
  198. return true;
  199. }
  200. // CurrentCounter, the counter at the EndSearchRenderer, is not reset.
  201. if (!isReset || !areRenderersElementsSiblings(currentRenderer, counterOwner)) {
  202. // If the node we are placing is not reset or we have found a counter that is attached
  203. // to an ancestor of the placed counter's owner renderer we know we are a sibling of that node.
  204. if (currentCounter->parent() != previousSiblingProtector->parent())
  205. return false;
  206. parent = currentCounter->parent();
  207. previousSibling = previousSiblingProtector.get();
  208. return true;
  209. }
  210. } else {
  211. // We are at the potential end of the search, but we had no previous sibling candidate
  212. // In this case we follow pretty much the same logic as above but no ASSERTs about
  213. // previousSibling, and when we are a sibling of the end counter we must set previousSibling
  214. // to currentCounter.
  215. if (currentCounter->actsAsReset()) {
  216. if (isReset && areRenderersElementsSiblings(currentRenderer, counterOwner)) {
  217. parent = currentCounter->parent();
  218. previousSibling = currentCounter;
  219. return parent;
  220. }
  221. parent = currentCounter;
  222. previousSibling = previousSiblingProtector.get();
  223. return true;
  224. }
  225. if (!isReset || !areRenderersElementsSiblings(currentRenderer, counterOwner)) {
  226. parent = currentCounter->parent();
  227. previousSibling = currentCounter;
  228. return true;
  229. }
  230. previousSiblingProtector = currentCounter;
  231. }
  232. }
  233. // We come here if the previous sibling or parent of our owner renderer had no
  234. // good counter, or we are a reset node and the counter on the previous sibling
  235. // of our owner renderer was not a reset counter.
  236. // Set a new goal for the end of the search.
  237. searchEndRenderer = previousSiblingOrParent(currentRenderer);
  238. } else {
  239. // We are searching descendants of a previous sibling of the renderer that the
  240. // counter being placed is attached to.
  241. if (currentCounter) {
  242. // We found a suitable counter.
  243. if (previousSiblingProtector) {
  244. // Since we had a suitable previous counter before, we should only consider this one as our
  245. // previousSibling if it is a reset counter and hence the current previousSibling is its child.
  246. if (currentCounter->actsAsReset()) {
  247. previousSiblingProtector = currentCounter;
  248. // We are no longer interested in previous siblings of the currentRenderer or their children
  249. // as counters they may have attached cannot be the previous sibling of the counter we are placing.
  250. currentRenderer = parentElement(currentRenderer)->renderer();
  251. continue;
  252. }
  253. } else
  254. previousSiblingProtector = currentCounter;
  255. currentRenderer = previousSiblingOrParent(currentRenderer);
  256. continue;
  257. }
  258. }
  259. // This function is designed so that the same test is not done twice in an iteration, except for this one
  260. // which may be done twice in some cases. Rearranging the decision points though, to accommodate this
  261. // performance improvement would create more code duplication than is worthwhile in my oppinion and may further
  262. // impede the readability of this already complex algorithm.
  263. if (previousSiblingProtector)
  264. currentRenderer = previousSiblingOrParent(currentRenderer);
  265. else
  266. currentRenderer = previousInPreOrder(currentRenderer);
  267. }
  268. return false;
  269. }
  270. static CounterNode* makeCounterNode(RenderObject* object, const AtomicString& identifier, bool alwaysCreateCounter)
  271. {
  272. ASSERT(object);
  273. if (object->hasCounterNodeMap()) {
  274. if (CounterMap* nodeMap = counterMaps().get(object)) {
  275. if (CounterNode* node = nodeMap->get(identifier))
  276. return node;
  277. }
  278. }
  279. bool isReset = false;
  280. int value = 0;
  281. if (!planCounter(object, identifier, isReset, value) && !alwaysCreateCounter)
  282. return 0;
  283. RefPtr<CounterNode> newParent = 0;
  284. RefPtr<CounterNode> newPreviousSibling = 0;
  285. RefPtr<CounterNode> newNode = CounterNode::create(object, isReset, value);
  286. if (findPlaceForCounter(object, identifier, isReset, newParent, newPreviousSibling))
  287. newParent->insertAfter(newNode.get(), newPreviousSibling.get(), identifier);
  288. CounterMap* nodeMap;
  289. if (object->hasCounterNodeMap())
  290. nodeMap = counterMaps().get(object);
  291. else {
  292. nodeMap = new CounterMap;
  293. counterMaps().set(object, adoptPtr(nodeMap));
  294. object->setHasCounterNodeMap(true);
  295. }
  296. nodeMap->set(identifier, newNode);
  297. if (newNode->parent())
  298. return newNode.get();
  299. // Checking if some nodes that were previously counter tree root nodes
  300. // should become children of this node now.
  301. CounterMaps& maps = counterMaps();
  302. Element* stayWithin = parentElement(object);
  303. bool skipDescendants;
  304. for (RenderObject* currentRenderer = nextInPreOrder(object, stayWithin); currentRenderer; currentRenderer = nextInPreOrder(currentRenderer, stayWithin, skipDescendants)) {
  305. skipDescendants = false;
  306. if (!currentRenderer->hasCounterNodeMap())
  307. continue;
  308. CounterNode* currentCounter = maps.get(currentRenderer)->get(identifier);
  309. if (!currentCounter)
  310. continue;
  311. skipDescendants = true;
  312. if (currentCounter->parent())
  313. continue;
  314. if (stayWithin == parentElement(currentRenderer) && currentCounter->hasResetType())
  315. break;
  316. newNode->insertAfter(currentCounter, newNode->lastChild(), identifier);
  317. }
  318. return newNode.get();
  319. }
  320. RenderCounter::RenderCounter(Document* node, const CounterContent& counter)
  321. : RenderText(node, StringImpl::empty())
  322. , m_counter(counter)
  323. , m_counterNode(0)
  324. , m_nextForSameCounter(0)
  325. {
  326. view()->addRenderCounter();
  327. }
  328. RenderCounter::~RenderCounter()
  329. {
  330. if (m_counterNode) {
  331. m_counterNode->removeRenderer(this);
  332. ASSERT(!m_counterNode);
  333. }
  334. }
  335. void RenderCounter::willBeDestroyed()
  336. {
  337. if (view())
  338. view()->removeRenderCounter();
  339. RenderText::willBeDestroyed();
  340. }
  341. const char* RenderCounter::renderName() const
  342. {
  343. return "RenderCounter";
  344. }
  345. bool RenderCounter::isCounter() const
  346. {
  347. return true;
  348. }
  349. PassRefPtr<StringImpl> RenderCounter::originalText() const
  350. {
  351. if (!m_counterNode) {
  352. RenderObject* beforeAfterContainer = parent();
  353. while (true) {
  354. if (!beforeAfterContainer)
  355. return 0;
  356. if (!beforeAfterContainer->isAnonymous() && !beforeAfterContainer->isPseudoElement())
  357. return 0; // RenderCounters are restricted to before and after pseudo elements
  358. PseudoId containerStyle = beforeAfterContainer->style()->styleType();
  359. if ((containerStyle == BEFORE) || (containerStyle == AFTER))
  360. break;
  361. beforeAfterContainer = beforeAfterContainer->parent();
  362. }
  363. makeCounterNode(beforeAfterContainer, m_counter.identifier(), true)->addRenderer(const_cast<RenderCounter*>(this));
  364. ASSERT(m_counterNode);
  365. }
  366. CounterNode* child = m_counterNode;
  367. int value = child->actsAsReset() ? child->value() : child->countInParent();
  368. String text = listMarkerText(m_counter.listStyle(), value);
  369. if (!m_counter.separator().isNull()) {
  370. if (!child->actsAsReset())
  371. child = child->parent();
  372. while (CounterNode* parent = child->parent()) {
  373. text = listMarkerText(m_counter.listStyle(), child->countInParent())
  374. + m_counter.separator() + text;
  375. child = parent;
  376. }
  377. }
  378. return text.impl();
  379. }
  380. void RenderCounter::updateCounter()
  381. {
  382. computePreferredLogicalWidths(0);
  383. }
  384. void RenderCounter::computePreferredLogicalWidths(float lead)
  385. {
  386. #ifndef NDEBUG
  387. // FIXME: We shouldn't be modifying the tree in computePreferredLogicalWidths.
  388. // Instead, we should properly hook the appropriate changes in the DOM and modify
  389. // the render tree then. When that's done, we also won't need to override
  390. // computePreferredLogicalWidths at all.
  391. // https://bugs.webkit.org/show_bug.cgi?id=104829
  392. SetLayoutNeededForbiddenScope layoutForbiddenScope(this, false);
  393. #endif
  394. setTextInternal(originalText());
  395. RenderText::computePreferredLogicalWidths(lead);
  396. }
  397. void RenderCounter::invalidate()
  398. {
  399. m_counterNode->removeRenderer(this);
  400. ASSERT(!m_counterNode);
  401. if (documentBeingDestroyed())
  402. return;
  403. setNeedsLayoutAndPrefWidthsRecalc();
  404. }
  405. static void destroyCounterNodeWithoutMapRemoval(const AtomicString& identifier, CounterNode* node)
  406. {
  407. CounterNode* previous;
  408. for (RefPtr<CounterNode> child = node->lastDescendant(); child && child != node; child = previous) {
  409. previous = child->previousInPreOrder();
  410. child->parent()->removeChild(child.get());
  411. ASSERT(counterMaps().get(child->owner())->get(identifier) == child);
  412. counterMaps().get(child->owner())->remove(identifier);
  413. }
  414. if (CounterNode* parent = node->parent())
  415. parent->removeChild(node);
  416. }
  417. void RenderCounter::destroyCounterNodes(RenderObject* owner)
  418. {
  419. CounterMaps& maps = counterMaps();
  420. CounterMaps::iterator mapsIterator = maps.find(owner);
  421. if (mapsIterator == maps.end())
  422. return;
  423. CounterMap* map = mapsIterator->value.get();
  424. CounterMap::const_iterator end = map->end();
  425. for (CounterMap::const_iterator it = map->begin(); it != end; ++it) {
  426. destroyCounterNodeWithoutMapRemoval(it->key, it->value.get());
  427. }
  428. maps.remove(mapsIterator);
  429. owner->setHasCounterNodeMap(false);
  430. }
  431. void RenderCounter::destroyCounterNode(RenderObject* owner, const AtomicString& identifier)
  432. {
  433. CounterMap* map = counterMaps().get(owner);
  434. if (!map)
  435. return;
  436. CounterMap::iterator mapIterator = map->find(identifier);
  437. if (mapIterator == map->end())
  438. return;
  439. destroyCounterNodeWithoutMapRemoval(identifier, mapIterator->value.get());
  440. map->remove(mapIterator);
  441. // We do not delete "map" here even if empty because we expect to reuse
  442. // it soon. In order for a renderer to lose all its counters permanently,
  443. // a style change for the renderer involving removal of all counter
  444. // directives must occur, in which case, RenderCounter::destroyCounterNodes()
  445. // must be called.
  446. // The destruction of the Renderer (possibly caused by the removal of its
  447. // associated DOM node) is the other case that leads to the permanent
  448. // destruction of all counters attached to a Renderer. In this case
  449. // RenderCounter::destroyCounterNodes() must be and is now called, too.
  450. // RenderCounter::destroyCounterNodes() handles destruction of the counter
  451. // map associated with a renderer, so there is no risk in leaking the map.
  452. }
  453. void RenderCounter::rendererRemovedFromTree(RenderObject* renderer)
  454. {
  455. ASSERT(renderer->view());
  456. if (!renderer->view()->hasRenderCounters())
  457. return;
  458. RenderObject* currentRenderer = renderer->lastLeafChild();
  459. if (!currentRenderer)
  460. currentRenderer = renderer;
  461. while (true) {
  462. destroyCounterNodes(currentRenderer);
  463. if (currentRenderer == renderer)
  464. break;
  465. currentRenderer = currentRenderer->previousInPreOrder();
  466. }
  467. }
  468. static void updateCounters(RenderObject* renderer)
  469. {
  470. ASSERT(renderer->style());
  471. const CounterDirectiveMap* directiveMap = renderer->style()->counterDirectives();
  472. if (!directiveMap)
  473. return;
  474. CounterDirectiveMap::const_iterator end = directiveMap->end();
  475. if (!renderer->hasCounterNodeMap()) {
  476. for (CounterDirectiveMap::const_iterator it = directiveMap->begin(); it != end; ++it)
  477. makeCounterNode(renderer, it->key, false);
  478. return;
  479. }
  480. CounterMap* counterMap = counterMaps().get(renderer);
  481. ASSERT(counterMap);
  482. for (CounterDirectiveMap::const_iterator it = directiveMap->begin(); it != end; ++it) {
  483. RefPtr<CounterNode> node = counterMap->get(it->key);
  484. if (!node) {
  485. makeCounterNode(renderer, it->key, false);
  486. continue;
  487. }
  488. RefPtr<CounterNode> newParent = 0;
  489. RefPtr<CounterNode> newPreviousSibling = 0;
  490. findPlaceForCounter(renderer, it->key, node->hasResetType(), newParent, newPreviousSibling);
  491. if (node != counterMap->get(it->key))
  492. continue;
  493. CounterNode* parent = node->parent();
  494. if (newParent == parent && newPreviousSibling == node->previousSibling())
  495. continue;
  496. if (parent)
  497. parent->removeChild(node.get());
  498. if (newParent)
  499. newParent->insertAfter(node.get(), newPreviousSibling.get(), it->key);
  500. }
  501. }
  502. void RenderCounter::rendererSubtreeAttached(RenderObject* renderer)
  503. {
  504. ASSERT(renderer->view());
  505. if (!renderer->view()->hasRenderCounters())
  506. return;
  507. Node* node = renderer->node();
  508. if (node)
  509. node = node->parentNode();
  510. else
  511. node = renderer->generatingNode();
  512. if (node && !node->attached())
  513. return; // No need to update if the parent is not attached yet
  514. for (RenderObject* descendant = renderer; descendant; descendant = descendant->nextInPreOrder(renderer))
  515. updateCounters(descendant);
  516. }
  517. void RenderCounter::rendererStyleChanged(RenderObject* renderer, const RenderStyle* oldStyle, const RenderStyle* newStyle)
  518. {
  519. Node* node = renderer->generatingNode();
  520. if (!node || !node->attached())
  521. return; // cannot have generated content or if it can have, it will be handled during attaching
  522. const CounterDirectiveMap* newCounterDirectives;
  523. const CounterDirectiveMap* oldCounterDirectives;
  524. if (oldStyle && (oldCounterDirectives = oldStyle->counterDirectives())) {
  525. if (newStyle && (newCounterDirectives = newStyle->counterDirectives())) {
  526. CounterDirectiveMap::const_iterator newMapEnd = newCounterDirectives->end();
  527. CounterDirectiveMap::const_iterator oldMapEnd = oldCounterDirectives->end();
  528. for (CounterDirectiveMap::const_iterator it = newCounterDirectives->begin(); it != newMapEnd; ++it) {
  529. CounterDirectiveMap::const_iterator oldMapIt = oldCounterDirectives->find(it->key);
  530. if (oldMapIt != oldMapEnd) {
  531. if (oldMapIt->value == it->value)
  532. continue;
  533. RenderCounter::destroyCounterNode(renderer, it->key);
  534. }
  535. // We must create this node here, because the changed node may be a node with no display such as
  536. // as those created by the increment or reset directives and the re-layout that will happen will
  537. // not catch the change if the node had no children.
  538. makeCounterNode(renderer, it->key, false);
  539. }
  540. // Destroying old counters that do not exist in the new counterDirective map.
  541. for (CounterDirectiveMap::const_iterator it = oldCounterDirectives->begin(); it !=oldMapEnd; ++it) {
  542. if (!newCounterDirectives->contains(it->key))
  543. RenderCounter::destroyCounterNode(renderer, it->key);
  544. }
  545. } else {
  546. if (renderer->hasCounterNodeMap())
  547. RenderCounter::destroyCounterNodes(renderer);
  548. }
  549. } else if (newStyle && (newCounterDirectives = newStyle->counterDirectives())) {
  550. CounterDirectiveMap::const_iterator newMapEnd = newCounterDirectives->end();
  551. for (CounterDirectiveMap::const_iterator it = newCounterDirectives->begin(); it != newMapEnd; ++it) {
  552. // We must create this node here, because the added node may be a node with no display such as
  553. // as those created by the increment or reset directives and the re-layout that will happen will
  554. // not catch the change if the node had no children.
  555. makeCounterNode(renderer, it->key, false);
  556. }
  557. }
  558. }
  559. } // namespace WebCore
  560. #ifndef NDEBUG
  561. void showCounterRendererTree(const WebCore::RenderObject* renderer, const char* counterName)
  562. {
  563. if (!renderer)
  564. return;
  565. const WebCore::RenderObject* root = renderer;
  566. while (root->parent())
  567. root = root->parent();
  568. AtomicString identifier(counterName);
  569. for (const WebCore::RenderObject* current = root; current; current = current->nextInPreOrder()) {
  570. fprintf(stderr, "%c", (current == renderer) ? '*' : ' ');
  571. for (const WebCore::RenderObject* parent = current; parent && parent != root; parent = parent->parent())
  572. fprintf(stderr, " ");
  573. fprintf(stderr, "%p N:%p P:%p PS:%p NS:%p C:%p\n",
  574. current, current->node(), current->parent(), current->previousSibling(),
  575. current->nextSibling(), current->hasCounterNodeMap() ?
  576. counterName ? WebCore::counterMaps().get(current)->get(identifier) : (WebCore::CounterNode*)1 : (WebCore::CounterNode*)0);
  577. }
  578. fflush(stderr);
  579. }
  580. #endif // NDEBUG