1 // Copyright (c) 1997 James Clark
2 // See the file copying.txt for copying permission.
8 #include "Interpreter.h"
10 #ifdef DSSSL_NAMESPACE
11 namespace DSSSL_NAMESPACE {
19 Pattern::Pattern(IList<Element> &ancestors)
20 : trivial_(computeTrivial(ancestors))
22 ancestors_.swap(ancestors);
25 bool Pattern::computeTrivial(const IList<Element> &ancestors)
27 IListIter<Element> iter(ancestors);
30 if (!iter.cur()->trivial())
38 Pattern::Element::Element(const StringC &gi)
39 : gi_(gi), minRepeat_(1), maxRepeat_(1)
43 bool Pattern::Element::matches(const NodePtr &nd, MatchContext &context) const
46 if (!nd->hasGi(GroveString(gi_.data(), gi_.size())))
51 if (nd->getGi(tem) != accessOK)
54 for (IListIter<Qualifier> iter(qualifiers_); !iter.done(); iter.next())
55 if (!iter.cur()->satisfies(nd, context))
60 bool Pattern::Element::trivial() const
64 for (IListIter<Qualifier> iter(qualifiers_); !iter.done(); iter.next())
65 if (!iter.cur()->vacuous())
70 void Pattern::Element::contributeSpecificity(int *s) const
73 s[giSpecificity] += minRepeat_;
74 for (IListIter<Qualifier> iter(qualifiers_); !iter.done(); iter.next())
75 iter.cur()->contributeSpecificity(s);
76 if (minRepeat_ != maxRepeat_)
77 s[repeatSpecificity] -= 1;
80 Pattern::Qualifier::~Qualifier()
84 bool Pattern::Qualifier::vacuous() const
89 bool Pattern::Qualifier::matchAttribute(const StringC &name,
92 MatchContext &context)
94 NamedNodeListPtr atts;
95 if (nd->getAttributes(atts) != accessOK)
98 if (atts->namedNode(GroveString(name.data(), name.size()), att) != accessOK)
101 if (att->getImplied(implied) == accessOK && implied)
104 if (att->tokens(tokens) == accessOK) {
105 if (tokens.size() != value.size())
108 NamedNodeListPtr normalizer;
109 if (att->firstChild(node) != accessOK
110 || node->getEntity(node) != accessOK
111 || node->getGroveRoot(node) != accessOK
112 || node->getEntities(normalizer) != accessOK)
115 tem.resize(normalizer->normalize(&tem[0], tem.size()));
116 if (tokens != GroveString(tem.data(), tem.size()))
122 if (att->firstChild(tem) == accessOK) {
125 if (tem->charChunk(context, chunk) == accessOK)
126 s.append(chunk.data(), chunk.size());
127 } while (tem.assignNextChunkSibling() == accessOK);
135 Pattern::ChildrenQualifier::ChildrenQualifier(IList<Element> &children)
137 children.swap(children_);
140 bool Pattern::ChildrenQualifier::satisfies(const NodePtr &nd,
141 MatchContext &context) const
143 ASSERT(!children_.empty());
145 if (nd->firstChild(child) != accessOK)
147 Vector<const Element *> toMatch;
148 for (IListIter<Element> iter(children_); !iter.done(); iter.next())
149 toMatch.push_back(iter.cur());
152 for (size_t i = 0; i < toMatch.size(); i++) {
153 if (!toMatch[i]->matches(child, context)) {
155 toMatch[j] = toMatch[i];
162 } while (child.assignNextChunkSibling() == accessOK);
166 void Pattern::ChildrenQualifier::contributeSpecificity(int *s) const
168 for (IListIter<Element> iter(children_); !iter.done(); iter.next())
169 iter.cur()->contributeSpecificity(s);
172 Pattern::IdQualifier::IdQualifier(const StringC &id)
177 bool Pattern::IdQualifier::satisfies(const NodePtr &nd, MatchContext &context) const
180 if (nd->getId(nodeId) == accessOK) {
181 size_t len = id_.size();
182 if (nodeId.size() == len) {
184 Interpreter::normalizeGeneralName(nd, tem);
185 GroveString patternId(tem.data(), tem.size());
186 if (patternId == nodeId)
190 const Vector<StringC> &idAtts = context.idAttributeNames();
191 for (size_t i = 0; i < idAtts.size(); i++)
192 if (matchAttribute(idAtts[i], id_, nd, context))
197 void Pattern::IdQualifier::contributeSpecificity(int *s) const
199 s[idSpecificity] += 1;
202 Pattern::ClassQualifier::ClassQualifier(const StringC &cls)
207 bool Pattern::ClassQualifier::satisfies(const NodePtr &nd, MatchContext &context) const
209 const Vector<StringC> &classAtts = context.classAttributeNames();
210 for (size_t i = 0; i < classAtts.size(); i++)
211 if (matchAttribute(classAtts[i], class_, nd, context))
216 void Pattern::ClassQualifier::contributeSpecificity(int *s) const
218 s[classSpecificity] += 1;
221 Pattern::AttributeHasValueQualifier::AttributeHasValueQualifier(const StringC &name)
226 bool Pattern::AttributeHasValueQualifier::satisfies(const NodePtr &nd, MatchContext &context) const
228 NamedNodeListPtr atts;
229 if (nd->getAttributes(atts) != accessOK)
232 if (atts->namedNode(GroveString(name_.data(), name_.size()), att) != accessOK)
235 if (att->getImplied(implied) == accessOK && implied)
240 void Pattern::AttributeHasValueQualifier::contributeSpecificity(int *s) const
242 s[attributeSpecificity] += 1;
245 Pattern::AttributeMissingValueQualifier::AttributeMissingValueQualifier(const StringC &name)
250 bool Pattern::AttributeMissingValueQualifier::satisfies(const NodePtr &nd, MatchContext &context) const
252 NamedNodeListPtr atts;
253 if (nd->getAttributes(atts) != accessOK)
256 if (atts->namedNode(GroveString(name_.data(), name_.size()), att) != accessOK)
259 if (att->getImplied(implied) == accessOK && implied)
264 void Pattern::AttributeMissingValueQualifier::contributeSpecificity(int *s) const
266 s[attributeSpecificity] += 1;
269 Pattern::AttributeQualifier::AttributeQualifier(const StringC &name, const StringC &value)
270 : name_(name), value_(value)
274 bool Pattern::AttributeQualifier::satisfies(const NodePtr &nd, MatchContext &context) const
276 return matchAttribute(name_, value_, nd, context);
279 void Pattern::AttributeQualifier::contributeSpecificity(int *s) const
281 s[attributeSpecificity] += 1;
284 void Pattern::PositionQualifier::contributeSpecificity(int *s) const
286 s[positionSpecificity] += 1;
289 bool Pattern::FirstOfTypeQualifier::satisfies(const NodePtr &nd, MatchContext &context) const
294 if (nd->firstSibling(tem) != accessOK)
295 return 1; // must be document element
296 while (*tem != *nd) {
298 if (tem->getGi(temType) == accessOK && temType == ndType)
300 tem.assignNextChunkSibling();
305 bool Pattern::LastOfTypeQualifier::satisfies(const NodePtr &nd, MatchContext &context) const
308 if (nd->nextChunkSibling(tem) != accessOK)
314 if (tem->getGi(temType) == accessOK && temType == ndType)
316 } while (tem.assignNextChunkSibling() == accessOK);
320 bool Pattern::FirstOfAnyQualifier::satisfies(const NodePtr &nd, MatchContext &) const
323 if (nd->firstSibling(tem) != accessOK)
324 return 1; // must be document element
325 while (*tem != *nd) {
327 if (tem->getGi(temType) == accessOK)
329 tem.assignNextChunkSibling();
334 bool Pattern::LastOfAnyQualifier::satisfies(const NodePtr &nd, MatchContext &context) const
337 if (nd->nextChunkSibling(tem) != accessOK)
343 if (tem->getGi(temType) == accessOK)
345 } while (tem.assignNextChunkSibling() == accessOK);
349 void Pattern::OnlyQualifier::contributeSpecificity(int *s) const
351 s[onlySpecificity] += 1;
354 bool Pattern::OnlyOfTypeQualifier::satisfies(const NodePtr &nd, MatchContext &context) const
359 if (nd->firstSibling(tem) != accessOK)
360 return 1; // must be document element
364 if (tem->getGi(temType) == accessOK && temType == ndType) {
368 } while (tem.assignNextChunkSibling() == accessOK);
372 bool Pattern::OnlyOfAnyQualifier::satisfies(const NodePtr &nd, MatchContext &context) const
375 if (nd->firstSibling(tem) != accessOK)
376 return 1; // must be document element
380 if (tem->getGi(temType) == accessOK) {
384 } while (tem.assignNextChunkSibling() == accessOK);
388 bool Pattern::VacuousQualifier::vacuous() const
393 Pattern::PriorityQualifier::PriorityQualifier(long n)
398 void Pattern::PriorityQualifier::contributeSpecificity(int *s) const
400 s[prioritySpecificity] += n_;
403 bool Pattern::PriorityQualifier::satisfies(const NodePtr &, MatchContext &) const
408 Pattern::ImportanceQualifier::ImportanceQualifier(long n)
413 void Pattern::ImportanceQualifier::contributeSpecificity(int *s) const
415 s[importanceSpecificity] += n_;
418 bool Pattern::ImportanceQualifier::satisfies(const NodePtr &, MatchContext &) const
423 bool Pattern::matchAncestors1(const IListIter<Element> &ancestors,
425 MatchContext &context)
427 const Element &r = *ancestors.cur();
429 for (Repeat i = 0; i < r.minRepeat(); i++) {
430 if (!tem || !r.matches(tem, context))
432 if (tem->getParent(tem) != accessOK)
435 Repeat i = r.minRepeat();
437 IListIter<Element> up(ancestors);
439 if (matchAncestors(up, tem, context))
441 if (i == r.maxRepeat() || !tem || !r.matches(tem, context))
444 if (tem->getParent(tem) != accessOK)
450 void Pattern::computeSpecificity(int *s) const
452 for (int i = 0; i < nSpecificity; i++)
454 for (IListIter<Element> iter(ancestors_); !iter.done(); iter.next())
455 iter.cur()->contributeSpecificity(s);
458 int Pattern::compareSpecificity(const Pattern &pattern1, const Pattern &pattern2)
460 int s1[nSpecificity];
461 int s2[nSpecificity];
462 int i; // declare here to avoid gcc bug
463 pattern1.computeSpecificity(s1);
464 pattern2.computeSpecificity(s2);
465 for (i = 0; i < nSpecificity; i++) {
467 return s1[i] > s2[i] ? -1 : 1;
472 #ifdef DSSSL_NAMESPACE