Home | History | Annotate | Download | only in rendering
      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