1 // Copyright (c) 1996 James Clark
2 // See the file copying.txt for copying permission.
3 
4 #include "stylelib.h"
5 #include "NumberCache.h"
6 #include "macros.h"
7 
8 #ifdef DSSSL_NAMESPACE
9 namespace DSSSL_NAMESPACE {
10 #endif
11 
NumberCache()12 NumberCache::NumberCache()
13 {
14 }
15 
16 inline
advance(NodePtr & node)17 void advance(NodePtr &node)
18 {
19   if (node.assignNextChunkAfter() != accessOK)
20     CANNOT_HAPPEN();
21 }
22 
23 // This caching scheme will be defeated (but not disastrously so)
24 // by numbering both notes and footnotes, say, per chapter.
25 
elementNumberAfter(const NodePtr & node,const StringC & gi,const StringC & resetGi)26 unsigned long NumberCache::elementNumberAfter(const NodePtr &node, const StringC &gi,
27 					      const StringC &resetGi)
28 {
29   NodePtr start;
30   NodePtr lastMatch;
31   unsigned long resetCount = 0;
32   unsigned long count = 0;
33   ElementEntry *entry = elementNumbers_.lookup(resetGi);
34   if (entry) {
35     unsigned long nodeIndex, entryIndex;
36     bool useSubnode = 1;
37     node->elementIndex(nodeIndex);
38     unsigned long nodeGroveIndex = node->groveIndex();
39     if (entry->node) {
40       if (*entry->node == *node)
41 	return 0;
42       entry->node->elementIndex(entryIndex);
43       if (entryIndex < nodeIndex && entry->node->groveIndex() == nodeGroveIndex) {
44 	start = lastMatch = entry->node;
45 	advance(start);
46 	resetCount = entry->num;
47       }
48       else
49 	useSubnode = 0;
50     }
51     if (entry->subNode && useSubnode) {
52       GroveString tem;
53       if (entry->subNode->getGi(tem) == accessOK
54 	  && tem == GroveString(gi.data(), gi.size())) {
55 	if (*entry->subNode == *node)
56 	  return entry->subNum;
57 	entry->subNode->elementIndex(entryIndex);
58 	if (entryIndex < nodeIndex && entry->subNode->groveIndex() == nodeGroveIndex) {
59 	  start = entry->subNode;
60 	  advance(start);
61 	  count = entry->subNum;
62 	}
63       }
64     }
65   }
66   else
67     elementNumbers_.insert(entry = new ElementEntry(resetGi));
68   if (!start) {
69     node->getGroveRoot(start);
70     start->getDocumentElement(start);
71   }
72   for (;;) {
73     GroveString tem;
74     if (start->getGi(tem) == accessOK) {
75       if (tem == GroveString(resetGi.data(), resetGi.size())) {
76 	lastMatch = start;
77 	resetCount++;
78 	count = 0;
79       }
80       else if (tem == GroveString(gi.data(), gi.size()))
81 	count++;
82     }
83     if (*start == *node)
84       break;
85     advance(start);
86   }
87   entry->node = lastMatch;
88   entry->num = resetCount;
89   entry->subNode = node;
90   entry->subNum = count;
91   return count;
92 }
93 
elementNumber(const NodePtr & node,const StringC & gi)94 unsigned long NumberCache::elementNumber(const NodePtr &node, const StringC &gi)
95 {
96   NodePtr start;
97   NodePtr lastMatch;
98   unsigned long count = 0;
99   ElementEntry *entry = elementNumbers_.lookup(gi);
100   if (entry && entry->node) {
101     if (*entry->node == *node) {
102       lastMatch = node;
103       return entry->num;
104     }
105     unsigned long nodeIndex, entryIndex;
106     entry->node->elementIndex(entryIndex);
107     node->elementIndex(nodeIndex);
108     if (entryIndex < nodeIndex && node->groveIndex() == entry->node->groveIndex()) {
109       lastMatch = start = entry->node;
110       count = entry->num;
111       advance(start);
112     }
113   }
114   if (!start) {
115     node->getGroveRoot(start);
116     start->getDocumentElement(start);
117   }
118   for (;;) {
119     GroveString tem;
120     if (start->getGi(tem) == accessOK && tem == GroveString(gi.data(), gi.size())) {
121       lastMatch = start;
122       count++;
123     }
124     if (*start == *node)
125       break;
126     advance(start);
127   }
128   if (count) {
129     ASSERT(lastMatch);
130     if (!entry)
131       elementNumbers_.insert(entry = new ElementEntry(gi));
132     entry->node = lastMatch;
133     entry->subNode.clear();
134     entry->num = count;
135   }
136   return count;
137 }
138 
childNumber(const NodePtr & node,unsigned long & result)139 bool NumberCache::childNumber(const NodePtr &node, unsigned long &result)
140 {
141   GroveString gs;
142   if (node->getGi(gs) != accessOK)
143     return 0;
144   NodePtr tem;
145   if (node->getParent(tem) != accessOK) {
146     // must be document element
147     result = 0;
148     return 1;
149   }
150   NodePtr parent(tem);
151   unsigned level = 0;
152   while (tem->getParent(tem) == accessOK)
153     level++;
154   StringC gi(gs.data(), gs.size());
155   if (level >= childNumbers_.size())
156     childNumbers_.resize(level + 1);
157   NodePtr start;
158   unsigned long count = 0;
159   Entry *entry = childNumbers_[level].lookup(gi);
160   if (entry) {
161     if (*entry->node == *node) {
162       result = entry->num;
163       return 1;
164     }
165     // Start counting from the cached entry if it has the same
166     // parent as us and it is before us.
167     NodePtr entryParent;
168     entry->node->getParent(entryParent);
169     if (*entryParent == *parent) {
170       unsigned long nodeIndex, entryIndex;
171       entry->node->elementIndex(entryIndex);
172       node->elementIndex(nodeIndex);
173       if (entryIndex < nodeIndex && node->groveIndex() == entry->node->groveIndex()) {
174 	start = entry->node;
175 	count = entry->num;
176       }
177     }
178   }
179   else {
180     entry = new Entry(gi);
181     childNumbers_[level].insert(entry);
182   }
183   if (!start)
184     node->firstSibling(start);
185   while (*start != *node) {
186     GroveString tem;
187     if (start->getGi(tem) == accessOK && tem == gs)
188       count++;
189     if (start.assignNextChunkSibling() != accessOK)
190       CANNOT_HAPPEN();
191   }
192   entry->node = node;
193   entry->num = count;
194   result = count;
195   return 1;
196 }
197 
Entry(const StringC & name)198 NumberCache::Entry::Entry(const StringC &name)
199 : Named(name)
200 {
201 }
202 
ElementEntry(const StringC & name)203 NumberCache::ElementEntry::ElementEntry(const StringC &name)
204 : NumberCache::Entry(name)
205 {
206 }
207 
208 #ifdef DSSSL_NAMESPACE
209 }
210 #endif
211 
212