KHtml

functions.cpp
1 /*
2  * functions.cc - Copyright 2005 Frerich Raabe <[email protected]>
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 #include "functions.h"
26 
27 #include "xml/dom_docimpl.h"
28 #include "xml/dom_nodeimpl.h"
29 #include "xml/dom_nodelistimpl.h"
30 #include "xml/dom_elementimpl.h"
31 #include "kjs/operations.h"
32 
33 #include <QtDebug>
34 
35 #include <math.h>
36 
37 using namespace DOM;
38 
39 namespace khtml
40 {
41 namespace XPath
42 {
43 
44 #define DEFINE_FUNCTION_CREATOR(Class) \
45  static Function *create##Class() { return new Class; }
46 
47 class Interval
48 {
49 public:
50  static const int Inf = -1;
51 
52  Interval();
53  Interval(int value);
54  Interval(int min, int max);
55 
56  bool contains(int value) const;
57 
58  QString asString() const;
59 
60 private:
61  int m_min;
62  int m_max;
63 };
64 
65 class FunLast : public Function
66 {
67 public:
68  bool isConstant() const override;
69 
70 private:
71  Value doEvaluate() const override;
72 };
73 
74 class FunPosition : public Function
75 {
76 public:
77  bool isConstant() const override;
78 
79 private:
80  Value doEvaluate() const override;
81 };
82 
83 class FunCount : public Function
84 {
85 public:
86  bool isConstant() const override;
87 
88 private:
89  Value doEvaluate() const override;
90 };
91 
92 // Base for various node-property functions, that have
93 // the same node picking logic. It passes the proper node,
94 // if any, or otherwise returns an empty string by itself
95 class NodeFunction : public Function
96 {
97 private:
98  Value doEvaluate() const override;
99  virtual Value evaluateOnNode(DOM::NodeImpl *node) const = 0;
100 };
101 
102 class FunLocalName : public NodeFunction
103 {
104 public:
105  bool isConstant() const override;
106 
107 private:
108  Value evaluateOnNode(DOM::NodeImpl *node) const override;
109 };
110 
111 class FunNamespaceURI : public NodeFunction
112 {
113 public:
114  bool isConstant() const override;
115 
116 private:
117  Value evaluateOnNode(DOM::NodeImpl *node) const override;
118 };
119 
120 class FunName : public NodeFunction
121 {
122 public:
123  bool isConstant() const override;
124 
125 private:
126  Value evaluateOnNode(DOM::NodeImpl *node) const override;
127 };
128 
129 class FunId : public Function
130 {
131 private:
132  Value doEvaluate() const override;
133 };
134 
135 class FunString : public Function
136 {
137 private:
138  Value doEvaluate() const override;
139 };
140 
141 class FunConcat : public Function
142 {
143 private:
144  Value doEvaluate() const override;
145 };
146 
147 class FunStartsWith : public Function
148 {
149 private:
150  Value doEvaluate() const override;
151 };
152 
153 class FunContains : public Function
154 {
155 private:
156  Value doEvaluate() const override;
157 };
158 
159 class FunSubstringBefore : public Function
160 {
161 private:
162  Value doEvaluate() const override;
163 };
164 
165 class FunSubstringAfter : public Function
166 {
167 private:
168  Value doEvaluate() const override;
169 };
170 
171 class FunSubstring : public Function
172 {
173 private:
174  Value doEvaluate() const override;
175 };
176 
177 class FunStringLength : public Function
178 {
179 private:
180  Value doEvaluate() const override;
181 };
182 
183 class FunNormalizeSpace : public Function
184 {
185 private:
186  Value doEvaluate() const override;
187 };
188 
189 class FunTranslate : public Function
190 {
191 private:
192  Value doEvaluate() const override;
193 };
194 
195 class FunBoolean : public Function
196 {
197 private:
198  Value doEvaluate() const override;
199 };
200 
201 class FunNot : public Function
202 {
203 private:
204  Value doEvaluate() const override;
205 };
206 
207 class FunTrue : public Function
208 {
209 public:
210  bool isConstant() const override;
211 
212 private:
213  Value doEvaluate() const override;
214 };
215 
216 class FunFalse : public Function
217 {
218 public:
219  bool isConstant() const override;
220 
221 private:
222  Value doEvaluate() const override;
223 };
224 
225 class FunLang : public Function
226 {
227 public:
228  bool isConstant() const override;
229 
230 private:
231  Value doEvaluate() const override;
232 };
233 
234 class FunNumber : public Function
235 {
236 private:
237  Value doEvaluate() const override;
238 };
239 
240 class FunSum : public Function
241 {
242 private:
243  Value doEvaluate() const override;
244 };
245 
246 class FunFloor : public Function
247 {
248 private:
249  Value doEvaluate() const override;
250 };
251 
252 class FunCeiling : public Function
253 {
254 private:
255  Value doEvaluate() const override;
256 };
257 
258 class FunRound : public Function
259 {
260 private:
261  Value doEvaluate() const override;
262 };
263 
264 DEFINE_FUNCTION_CREATOR(FunLast)
265 DEFINE_FUNCTION_CREATOR(FunPosition)
266 DEFINE_FUNCTION_CREATOR(FunCount)
267 DEFINE_FUNCTION_CREATOR(FunLocalName)
268 DEFINE_FUNCTION_CREATOR(FunNamespaceURI)
269 DEFINE_FUNCTION_CREATOR(FunName)
270 DEFINE_FUNCTION_CREATOR(FunId)
271 
272 DEFINE_FUNCTION_CREATOR(FunString)
273 DEFINE_FUNCTION_CREATOR(FunConcat)
274 DEFINE_FUNCTION_CREATOR(FunStartsWith)
275 DEFINE_FUNCTION_CREATOR(FunContains)
276 DEFINE_FUNCTION_CREATOR(FunSubstringBefore)
277 DEFINE_FUNCTION_CREATOR(FunSubstringAfter)
278 DEFINE_FUNCTION_CREATOR(FunSubstring)
279 DEFINE_FUNCTION_CREATOR(FunStringLength)
280 DEFINE_FUNCTION_CREATOR(FunNormalizeSpace)
281 DEFINE_FUNCTION_CREATOR(FunTranslate)
282 
283 DEFINE_FUNCTION_CREATOR(FunBoolean)
284 DEFINE_FUNCTION_CREATOR(FunNot)
285 DEFINE_FUNCTION_CREATOR(FunTrue)
286 DEFINE_FUNCTION_CREATOR(FunFalse)
287 DEFINE_FUNCTION_CREATOR(FunLang)
288 
289 DEFINE_FUNCTION_CREATOR(FunNumber)
290 DEFINE_FUNCTION_CREATOR(FunSum)
291 DEFINE_FUNCTION_CREATOR(FunFloor)
292 DEFINE_FUNCTION_CREATOR(FunCeiling)
293 DEFINE_FUNCTION_CREATOR(FunRound)
294 
295 #undef DEFINE_FUNCTION_CREATOR
296 
297 Interval::Interval()
298  : m_min(Inf),
299  m_max(Inf)
300 {
301 }
302 
303 Interval::Interval(int value)
304  : m_min(value),
305  m_max(value)
306 {
307 }
308 
309 Interval::Interval(int min, int max)
310  : m_min(min),
311  m_max(max)
312 {
313 }
314 
315 bool Interval::contains(int value) const
316 {
317  if (m_min == Inf && m_max == Inf) {
318  return true;
319  }
320 
321  if (m_min == Inf) {
322  return value <= m_max;
323  }
324 
325  if (m_max == Inf) {
326  return value >= m_min;
327  }
328 
329  return value >= m_min && value <= m_max;
330 }
331 
332 QString Interval::asString() const
333 {
334  QString s = "[";
335 
336  if (m_min == Inf) {
337  s += "-Infinity";
338  } else {
339  s += QString::number(m_min);
340  }
341 
342  s += "..";
343 
344  if (m_max == Inf) {
345  s += "Infinity";
346  } else {
347  s += QString::number(m_max);
348  }
349 
350  s += "]";
351 
352  return s;
353 }
354 
355 void Function::setArguments(const QList<Expression *> &args)
356 {
357  foreach (Expression *arg, args) {
358  addSubExpression(arg);
359  }
360 }
361 
362 void Function::setName(const DOM::DOMString &name)
363 {
364  m_name = name;
365 }
366 
367 QString Function::dump() const
368 {
369  if (argCount() == 0) {
370  return QString("<function name=\"%1\"/>").arg(name().string());
371  }
372 
373  QString s = QString("<function name=\"%1\">").arg(name().string());
374  for (unsigned int i = 0; i < argCount(); ++i) {
375  s += "<operand>" + arg(i)->dump() + "</operand>";
376  }
377  s += "</function>";
378  return s;
379 }
380 
381 Expression *Function::arg(int i)
382 {
383  return subExpr(i);
384 }
385 
386 const Expression *Function::arg(int i) const
387 {
388  return subExpr(i);
389 }
390 
391 unsigned int Function::argCount() const
392 {
393  return subExprCount();
394 }
395 
396 DOM::DOMString Function::name() const
397 {
398  return m_name;
399 }
400 
401 Value FunLast::doEvaluate() const
402 {
403  return Value(double(Expression::evaluationContext().size));
404 }
405 
406 bool FunLast::isConstant() const
407 {
408  return false;
409 }
410 
411 Value FunPosition::doEvaluate() const
412 {
413  return Value(double(Expression::evaluationContext().position));
414 }
415 
416 bool FunPosition::isConstant() const
417 {
418  return false;
419 }
420 
421 Value NodeFunction::doEvaluate() const
422 {
423  NodeImpl *node = nullptr;
424  if (argCount() > 0) {
425  Value a = arg(0)->evaluate();
426  if (a.isNodeset() && a.toNodeset()->length()) {
427  node = a.toNodeset()->first();
428  }
429  } else {
430  // no argument -> default to context node
431  node = evaluationContext().node;
432  }
433 
434  if (!node) {
435  return Value(DOMString());
436  }
437 
438  return evaluateOnNode(node);
439 }
440 
441 bool FunLocalName::isConstant() const
442 {
443  return false;
444 }
445 
446 Value FunLocalName::evaluateOnNode(DOM::NodeImpl *node) const
447 {
448  DOM::DOMString n;
449  switch (node->nodeType()) {
450  case Node::PROCESSING_INSTRUCTION_NODE:
451  n = node->nodeName(); // target name
452  break;
453  default:
454  n = node->localName();
455  }
456  return Value(n);
457 }
458 
459 bool FunNamespaceURI::isConstant() const
460 {
461  return false;
462 }
463 
464 Value FunNamespaceURI::evaluateOnNode(DOM::NodeImpl *node) const
465 {
466  return Value(node->namespaceURI());
467 }
468 
469 Value FunId::doEvaluate() const
470 {
471  Value a = arg(0)->evaluate();
472 
473  WTF::Vector<DOM::DOMString> ids;
474 
475  QString queryString; // whitespace-separated IDs
476  if (a.isNodeset()) {
477  DomNodeList set = a.toNodeset();
478  for (unsigned long i = 0; i < set->length(); ++i) {
479  queryString += stringValue(set->item(i)).string() + QLatin1Char(' ');
480  }
481  } else {
482  queryString = a.toString().string();
483  }
484 
485  QStringList qids = queryString.simplified().split(' ');
486  for (int i = 0; i < qids.size(); ++i) {
487  ids.append(DOM::DOMString(qids[i]));
488  }
489 
490  DomNodeList out = new StaticNodeListImpl();
491  DOM::DocumentImpl *doc = Expression::evaluationContext().node->document();
492 
493  for (unsigned i = 0; i < ids.size(); ++i) {
494  DOM::ElementImpl *e = doc->getElementById(ids[i]);
495 
496  if (e) {
497  out->append(e);
498  }
499  }
500 
501  return Value(out);
502 }
503 
504 bool FunName::isConstant() const
505 {
506  return false;
507 }
508 
509 Value FunName::evaluateOnNode(DOM::NodeImpl *node) const
510 {
511  DOM::DOMString n;
512  switch (node->nodeType()) {
513  case Node::TEXT_NODE:
514  case Node::CDATA_SECTION_NODE:
515  case Node::COMMENT_NODE:
516  case Node::DOCUMENT_NODE:
517  // All of these have an empty XPath name
518  break;
519  case Node::ELEMENT_NODE: {
520  n = static_cast<DOM::ElementImpl *>(node)->nonCaseFoldedTagName();
521  break;
522  }
523  default:
524  n = node->nodeName();
525  }
526  return Value(n);
527 }
528 
529 Value FunCount::doEvaluate() const
530 {
531  Value a = arg(0)->evaluate();
532  if (!a.isNodeset()) {
533  Expression::reportInvalidExpressionErr();
534  qCWarning(KHTML_LOG) << "count() expects <nodeset>";
535  return Value();
536  }
537  a.toNodeset()->normalizeUpto(StaticNodeListImpl::AxisOrder);
538 
539  return Value(double(a.toNodeset()->length()));
540 }
541 
542 bool FunCount::isConstant() const
543 {
544  return false;
545 }
546 
547 Value FunString::doEvaluate() const
548 {
549  if (argCount() == 0) {
550  DOMString s = Value(Expression::evaluationContext().node).toString();
551  return Value(s);
552  }
553  return Value(arg(0)->evaluate().toString());
554 }
555 
556 Value FunConcat::doEvaluate() const
557 {
558  QString str;
559  for (unsigned int i = 0; i < argCount(); ++i) {
560  str.append(arg(i)->evaluate().toString().string());
561  }
562  return Value(DOMString(str));
563 }
564 
565 Value FunStartsWith::doEvaluate() const
566 {
567  DOMString s1 = arg(0)->evaluate().toString();
568  DOMString s2 = arg(1)->evaluate().toString();
569 
570  if (s2.isEmpty()) {
571  return Value(true);
572  }
573 
574  return Value(s1.startsWith(s2));
575 }
576 
577 Value FunContains::doEvaluate() const
578 {
579  QString s1 = arg(0)->evaluate().toString().string();
580  QString s2 = arg(1)->evaluate().toString().string();
581 
582  if (s2.isEmpty()) {
583  return Value(true);
584  }
585 
586  return Value(s1.contains(s2));
587 }
588 
589 Value FunSubstringBefore::doEvaluate() const
590 {
591  QString s1 = arg(0)->evaluate().toString().string();
592  QString s2 = arg(1)->evaluate().toString().string();
593 
594  if (s2.isEmpty()) {
595  return Value(DOMString());
596  }
597 
598  int i = s1.indexOf(s2);
599  if (i == -1) {
600  return Value(DOMString());
601  }
602 
603  return Value(DOMString(s1.left(i)));
604 }
605 
606 Value FunSubstringAfter::doEvaluate() const
607 {
608  QString s1 = arg(0)->evaluate().toString().string();
609  QString s2 = arg(1)->evaluate().toString().string();
610 
611  if (s2.isEmpty()) {
612  return Value(s1);
613  }
614 
615  int i = s1.indexOf(s2);
616  if (i == -1) {
617  return Value(DOMString());
618  }
619 
620  return Value(DOMString(s1.mid(i + s2.length())));
621 }
622 
623 Value FunSubstring::doEvaluate() const
624 {
625  QString s = arg(0)->evaluate().toString().string();
626  long pos = long(qRound(arg(1)->evaluate().toNumber()));
627  bool haveLength = argCount() == 3;
628  long len = -1;
629  if (haveLength) {
630  len = long(qRound(arg(2)->evaluate().toNumber()));
631  }
632 
633  if (pos > long(s.length())) {
634  return Value(DOMString());
635  }
636 
637  if (haveLength && pos < 1) {
638  len -= 1 - pos;
639  pos = 1;
640  if (len < 1) {
641  return Value(DOMString());
642  }
643  }
644 
645  return Value(DOMString(s.mid(pos - 1, len)));
646 }
647 
648 Value FunStringLength::doEvaluate() const
649 {
650  if (argCount() == 0) {
651  DOMString s = Value(Expression::evaluationContext().node).toString();
652  return Value(double(s.length()));
653  }
654 
655  return Value(double(arg(0)->evaluate().toString().length()));
656 }
657 
658 Value FunNormalizeSpace::doEvaluate() const
659 {
660  if (argCount() == 0) {
661  DOMString s = Value(Expression::evaluationContext().node).toString();
662  return Value(DOMString(s.string().simplified()));
663  }
664 
665  QString s = arg(0)->evaluate().toString().string();
666  s = s.simplified();
667  return Value(DOMString(s));
668 }
669 
670 Value FunTranslate::doEvaluate() const
671 {
672  QString s1 = arg(0)->evaluate().toString().string();
673  QString s2 = arg(1)->evaluate().toString().string();
674  QString s3 = arg(2)->evaluate().toString().string();
675  QString newString;
676 
677  for (int i1 = 0; i1 < s1.length(); ++i1) {
678  QChar ch = s1[ i1 ];
679  int i2 = s2.indexOf(ch);
680  if (i2 == -1) {
681  newString += ch;
682  } else if (i2 < s3.length()) {
683  newString += s3[ i2 ];
684  }
685  }
686 
687  return Value(DOMString(newString));
688 }
689 
690 Value FunBoolean::doEvaluate() const
691 {
692  return Value(arg(0)->evaluate().toBoolean());
693 }
694 
695 Value FunNot::doEvaluate() const
696 {
697  return Value(!arg(0)->evaluate().toBoolean());
698 }
699 
700 Value FunTrue::doEvaluate() const
701 {
702  return Value(true);
703 }
704 
705 bool FunTrue::isConstant() const
706 {
707  return true;
708 }
709 
710 #ifdef __GNUC__
711 #warning "This looks bogus"
712 #endif
713 
714 Value FunLang::doEvaluate() const
715 {
716  QString lang = arg(0)->evaluate().toString().string();
717 
718  NodeImpl *node = evaluationContext().node;
719 
720  DOMString langNodeValue;
721 
722  while (node) {
723  if (node->isElementNode()) {
724  langNodeValue = static_cast<ElementImpl *>(node)->getAttribute("xml:lang");
725  if (!langNodeValue.isNull()) {
726  break;
727  }
728  }
729  node = xpathParentNode(node);
730  }
731 
732  if (langNodeValue.isNull()) {
733  return Value(false);
734  }
735 
736  // extract 'en' out of 'en-us'
737  QString langNodeValueString = langNodeValue.string();
738  QString langNodeBaseString = langNodeValueString.left(langNodeValueString.indexOf('-'));
739 
740  return Value(langNodeValueString.toLower() == lang.toLower() ||
741  langNodeBaseString.toLower() == lang.toLower());
742 }
743 
744 bool FunLang::isConstant() const
745 {
746  return false;
747 }
748 
749 Value FunFalse::doEvaluate() const
750 {
751  return Value(false);
752 }
753 
754 bool FunFalse::isConstant() const
755 {
756  return true;
757 }
758 
759 Value FunNumber::doEvaluate() const
760 {
761  Value vi;
762  if (argCount() == 0) {
763  // Spec'd: convert context node to singleton nodeset, call
764  // string on that --> that's just stringValue on that node.
765  // then we call number on that string
766  vi = Value(stringValue(evaluationContext().node));
767  } else {
768  vi = arg(0)->evaluate();
769  }
770 
771  return Value(vi.toNumber());
772 }
773 
774 Value FunSum::doEvaluate() const
775 {
776  Value a = arg(0)->evaluate();
777  if (!a.isNodeset()) {
778  Expression::reportInvalidExpressionErr();
779  qCWarning(KHTML_LOG) << "sum() expects <nodeset>";
780  return Value(0.0);
781  }
782 
783  double sum = 0.0;
784  const DomNodeList nodes = a.toNodeset();
785  for (unsigned long n = 0; n < nodes->length(); ++n) {
786  NodeImpl *node = nodes->item(n);
787  sum += Value(stringValue(node)).toNumber();
788  }
789  return Value(sum);
790 }
791 
792 Value FunFloor::doEvaluate() const
793 {
794  const double num = arg(0)->evaluate().toNumber();
795 
796  if (KJS::isNaN(num) || KJS::isInf(num)) {
797  return Value(num);
798  }
799 
800  return Value(floor(num));
801 }
802 
803 Value FunCeiling::doEvaluate() const
804 {
805  const double num = arg(0)->evaluate().toNumber();
806 
807  if (KJS::isNaN(num) || KJS::isInf(num)) {
808  return Value(num);
809  }
810 
811  return Value(ceil(num));
812 }
813 
814 Value FunRound::doEvaluate() const
815 {
816  return Value(double(qRound(arg(0)->evaluate().toNumber())));
817 }
818 
819 struct FunctionLibrary::FunctionRec {
820  typedef Function *(*FactoryFn)();
821 
822  FactoryFn factoryFn;
823  Interval args;
824 };
825 
826 struct FunctionMapping {
827  const char *name;
828  FunctionLibrary::FunctionRec function;
829 };
830 
831 static FunctionMapping functions[] = {
832  { "last", { &createFunLast, 0 } },
833  { "last", { &createFunLast, 0 } },
834  { "position", { &createFunPosition, 0 } },
835  { "count", { &createFunCount, 1 } },
836  { "sum", { &createFunSum, 1 } },
837  { "local-name", { &createFunLocalName, Interval(0, 1) } },
838  { "namespace-uri", { &createFunNamespaceURI, Interval(0, 1) } },
839  { "id", { &createFunId, 1 } },
840  { "name", { &createFunName, Interval(0, 1) } },
841 
842  { "string", { &createFunString, Interval(0, 1) } },
843  { "concat", { &createFunConcat, Interval(2, Interval::Inf) } },
844  { "starts-with", { &createFunStartsWith, 2 } },
845  { "contains", { &createFunContains, 2 } },
846  { "substring-before", { &createFunSubstringBefore, 2 } },
847  { "substring-after", { &createFunSubstringAfter, 2 } },
848  { "substring", { &createFunSubstring, Interval(2, 3) } },
849  { "string-length", { &createFunStringLength, Interval(0, 1) } },
850  { "normalize-space", { &createFunNormalizeSpace, Interval(0, 1) } },
851  { "translate", { &createFunTranslate, 3 } },
852 
853  { "boolean", { &createFunBoolean, 1 } },
854  { "not", { &createFunNot, 1 } },
855  { "true", { &createFunTrue, 0 } },
856  { "false", { &createFunFalse, 0 } },
857  { "lang", { &createFunLang, 1 } },
858 
859  { "number", { &createFunNumber, Interval(0, 1) } },
860  { "floor", { &createFunFloor, 1 } },
861  { "ceiling", { &createFunCeiling, 1 } },
862  { "round", { &createFunRound, 1 } }
863 };
864 static const unsigned int numFunctions = sizeof(functions) / sizeof(functions[ 0 ]);
865 
866 FunctionLibrary &FunctionLibrary::self()
867 {
868  static FunctionLibrary instance;
869  return instance;
870 }
871 
872 FunctionLibrary::FunctionLibrary()
873 {
874  for (unsigned int i = 0; i < numFunctions; ++i) {
875  m_functionDict.insert(functions[ i ].name, functions[ i ].function);
876  }
877 }
878 
879 Function *FunctionLibrary::getFunction(const DOM::DOMString &name,
880  const QList<Expression *> &args) const
881 {
882  if (!m_functionDict.contains(name)) {
883  qCWarning(KHTML_LOG) << "Function '" << name << "' not supported by this implementation.";
884 
885  return nullptr;
886  }
887 
888  FunctionRec functionRec = m_functionDict[ name ];
889  if (!functionRec.args.contains(args.count())) {
890  qCWarning(KHTML_LOG) << "Function '" << name << "' requires " << functionRec.args.asString() << " arguments, but " << args.count() << " given.";
891  return nullptr;
892  }
893 
894  Function *function = functionRec.factoryFn();
895  function->setArguments(args);
896  function->setName(name);
897  return function;
898 }
899 
900 } //namespace XPath
901 } //namespace khtml
902 
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const const
QString & append(QChar ch)
QString name(const QVariant &location)
This file is part of the HTML rendering engine for KDE.
QString simplified() const const
int size() const const
QString number(int n, int base)
int count(const T &value) const const
void append(const T &value)
bool isEmpty() const const
QStringList split(const QString &sep, QString::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
This class implements the basic string we use in the DOM.
Definition: dom_string.h:44
QString toLower() const const
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
This library provides a full-featured HTML parser and widget.
QString mid(int position, int n) const const
char * toString(const T &value)
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
int length() const const
QString left(int n) const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Sat Oct 16 2021 22:47:53 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.