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