• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2     Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
3 
4     This library is free software; you can redistribute it and/or
5     modify it under the terms of the GNU Library General Public
6     License as published by the Free Software Foundation; either
7     version 2 of the License, or (at your option) any later version.
8 
9     This library is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12     Library General Public License for more details.
13 
14     You should have received a copy of the GNU Library General Public License
15     along with this library; see the file COPYING.LIB.  If not, write to
16     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17     Boston, MA 02110-1301, USA.
18 */
19 
20 #include "config.h"
21 #include "qwebelement.h"
22 
23 #include "CSSComputedStyleDeclaration.h"
24 #include "CSSMutableStyleDeclaration.h"
25 #include "CSSParser.h"
26 #include "CSSRule.h"
27 #include "CSSRuleList.h"
28 #include "CSSStyleRule.h"
29 #include "CString.h"
30 #include "Document.h"
31 #include "DocumentFragment.h"
32 #include "FrameView.h"
33 #include "GraphicsContext.h"
34 #include "HTMLElement.h"
35 #include "JSGlobalObject.h"
36 #include "JSHTMLElement.h"
37 #include "JSObject.h"
38 #include "NodeList.h"
39 #include "PropertyNameArray.h"
40 #include "RenderImage.h"
41 #include "StaticNodeList.h"
42 #include "qt_runtime.h"
43 #include "qwebframe.h"
44 #include "qwebframe_p.h"
45 #include "runtime_root.h"
46 #include <parser/SourceCode.h>
47 #include <wtf/Vector.h>
48 
49 #include <QPainter>
50 
51 using namespace WebCore;
52 
53 class QWebElementPrivate {
54 public:
55 };
56 
57 /*!
58     \class QWebElement
59     \since 4.6
60     \brief The QWebElement class provides convenient access to DOM elements in
61     a QWebFrame.
62     \inmodule QtWebKit
63 
64     A QWebElement object allows easy access to the document model, represented
65     by a tree-like structure of DOM elements. The root of the tree is called
66     the document element and can be accessed using
67     QWebFrame::documentElement().
68 
69     Specific elements can be accessed using findAll() and findFirst(). These
70     elements are identified using CSS selectors. The code snippet below
71     demonstrates the use of findAll().
72 
73     \snippet webkitsnippets/webelement/main.cpp FindAll
74 
75     The first list contains all \c span elements in the document. The second
76     list contains \c span elements that are children of \c p, classified with
77     \c intro.
78 
79     Using findFirst() is more efficient than calling findAll(), and extracting
80     the first element only in the list returned.
81 
82     Alternatively you can traverse the document manually using firstChild() and
83     nextSibling():
84 
85     \snippet webkitsnippets/webelement/main.cpp Traversing with QWebElement
86 
87     The underlying content of QWebElement is explicitly shared. Creating a copy
88     of a QWebElement does not create a copy of the content. Instead, both
89     instances point to the same element.
90 
91     The element's attributes can be read using attribute() and modified with
92     setAttribute().
93 
94     The contents of child elements can be converted to plain text with
95     toPlainText(); to XHTML using toInnerXml(). To include the element's tag in
96     the output, use toOuterXml().
97 
98     It is possible to replace the contents of child elements using
99     setPlainText() and setInnerXml(). To replace the element itself and its
100     contents, use setOuterXml().
101 
102     \section1 Examples
103 
104     The \l{DOM Traversal Example} shows one way to traverse documents in a running
105     example.
106 
107     The \l{Simple Selector Example} can be used to experiment with the searching
108     features of this class and provides sample code you can start working with.
109 */
110 
111 /*!
112     Constructs a null web element.
113 */
QWebElement()114 QWebElement::QWebElement()
115     : d(0)
116     , m_element(0)
117 {
118 }
119 
120 /*!
121     \internal
122 */
QWebElement(WebCore::Element * domElement)123 QWebElement::QWebElement(WebCore::Element* domElement)
124     : d(0)
125     , m_element(domElement)
126 {
127     if (m_element)
128         m_element->ref();
129 }
130 
131 /*!
132     \internal
133 */
QWebElement(WebCore::Node * node)134 QWebElement::QWebElement(WebCore::Node* node)
135     : d(0)
136     , m_element(0)
137 {
138     if (node && node->isHTMLElement()) {
139         m_element = static_cast<HTMLElement*>(node);
140         m_element->ref();
141     }
142 }
143 
144 /*!
145     Constructs a copy of \a other.
146 */
QWebElement(const QWebElement & other)147 QWebElement::QWebElement(const QWebElement &other)
148     : d(0)
149     , m_element(other.m_element)
150 {
151     if (m_element)
152         m_element->ref();
153 }
154 
155 /*!
156     Assigns \a other to this element and returns a reference to this element.
157 */
operator =(const QWebElement & other)158 QWebElement &QWebElement::operator=(const QWebElement &other)
159 {
160     // ### handle "d" assignment
161     if (this != &other) {
162         Element *otherElement = other.m_element;
163         if (otherElement)
164             otherElement->ref();
165         if (m_element)
166             m_element->deref();
167         m_element = otherElement;
168     }
169     return *this;
170 }
171 
172 /*!
173     Destroys the element. However, the underlying DOM element is not destroyed.
174 */
~QWebElement()175 QWebElement::~QWebElement()
176 {
177     delete d;
178     if (m_element)
179         m_element->deref();
180 }
181 
operator ==(const QWebElement & o) const182 bool QWebElement::operator==(const QWebElement& o) const
183 {
184     return m_element == o.m_element;
185 }
186 
operator !=(const QWebElement & o) const187 bool QWebElement::operator!=(const QWebElement& o) const
188 {
189     return m_element != o.m_element;
190 }
191 
192 /*!
193     Returns true if the element is a null element; otherwise returns false.
194 */
isNull() const195 bool QWebElement::isNull() const
196 {
197     return !m_element;
198 }
199 
200 /*!
201     Returns a new list of child elements matching the given CSS selector
202     \a selectorQuery. If there are no matching elements, an empty list is
203     returned.
204 
205     \l{Standard CSS2 selector} syntax is used for the query.
206 
207     \note This search is performed recursively.
208 
209     \sa findFirst()
210 */
findAll(const QString & selectorQuery) const211 QWebElementCollection QWebElement::findAll(const QString &selectorQuery) const
212 {
213     return QWebElementCollection(*this, selectorQuery);
214 }
215 
216 /*!
217     Returns the first child element that matches the given CSS selector
218     \a selectorQuery.
219 
220     \l{Standard CSS2 selector} syntax is used for the query.
221 
222     \note This search is performed recursively.
223 
224     \sa findAll()
225 */
findFirst(const QString & selectorQuery) const226 QWebElement QWebElement::findFirst(const QString &selectorQuery) const
227 {
228     if (!m_element)
229         return QWebElement();
230     ExceptionCode exception = 0; // ###
231     return QWebElement(m_element->querySelector(selectorQuery, exception).get());
232 }
233 
234 /*!
235     Replaces the existing content of this element with \a text.
236 
237     This is equivalent to setting the HTML innerText property.
238 
239     \sa toPlainText()
240 */
setPlainText(const QString & text)241 void QWebElement::setPlainText(const QString &text)
242 {
243     if (!m_element || !m_element->isHTMLElement())
244         return;
245     ExceptionCode exception = 0;
246     static_cast<HTMLElement*>(m_element)->setInnerText(text, exception);
247 }
248 
249 /*!
250     Returns the text between the start and the end tag of this
251     element.
252 
253     This is equivalent to reading the HTML innerText property.
254 
255     \sa setPlainText()
256 */
toPlainText() const257 QString QWebElement::toPlainText() const
258 {
259     if (!m_element || !m_element->isHTMLElement())
260         return QString();
261     return static_cast<HTMLElement*>(m_element)->innerText();
262 }
263 
264 /*!
265     Replaces the contents of this element as well as its own tag with
266     \a markup. The string may contain HTML or XML tags, which is parsed and
267     formatted before insertion into the document.
268 
269     \note This is currently only implemented for (X)HTML elements.
270 
271     \sa toOuterXml(), toInnerXml(), setInnerXml()
272 */
setOuterXml(const QString & markup)273 void QWebElement::setOuterXml(const QString &markup)
274 {
275     if (!m_element || !m_element->isHTMLElement())
276         return;
277 
278     ExceptionCode exception = 0;
279 
280     static_cast<HTMLElement*>(m_element)->setOuterHTML(markup, exception);
281 }
282 
283 /*!
284     Returns this element converted to XML, including the start and the end
285     tags as well as its attributes.
286 
287     \note This is currently implemented for (X)HTML elements only.
288 
289     \sa setOuterXml(), setInnerXml(), toInnerXml()
290 */
toOuterXml() const291 QString QWebElement::toOuterXml() const
292 {
293     if (!m_element || !m_element->isHTMLElement())
294         return QString();
295 
296     return static_cast<HTMLElement*>(m_element)->outerHTML();
297 }
298 
299 /*!
300     Replaces the contents of this element with \a markup. The string may
301     contain HTML or XML tags, which is parsed and formatted before insertion
302     into the document.
303 
304     \note This is currently implemented for (X)HTML elements only.
305 
306     \sa toInnerXml(), toOuterXml(), setOuterXml()
307 */
setInnerXml(const QString & markup)308 void QWebElement::setInnerXml(const QString &markup)
309 {
310     if (!m_element || !m_element->isHTMLElement())
311         return;
312 
313     ExceptionCode exception = 0;
314 
315     static_cast<HTMLElement*>(m_element)->setInnerHTML(markup, exception);
316 }
317 
318 /*!
319     Returns the XML content between the element's start and end tags.
320 
321     \note This is currently implemented for (X)HTML elements only.
322 
323     \sa setInnerXml(), setOuterXml(), toOuterXml()
324 */
toInnerXml() const325 QString QWebElement::toInnerXml() const
326 {
327     if (!m_element || !m_element->isHTMLElement())
328         return QString();
329 
330     return static_cast<HTMLElement*>(m_element)->innerHTML();
331 }
332 
333 /*!
334     Adds an attribute with the given \a name and \a value. If an attribute with
335     the same name exists, its value is replaced by \a value.
336 
337     \sa attribute(), attributeNS(), setAttributeNS()
338 */
setAttribute(const QString & name,const QString & value)339 void QWebElement::setAttribute(const QString &name, const QString &value)
340 {
341     if (!m_element)
342         return;
343     ExceptionCode exception = 0;
344     m_element->setAttribute(name, value, exception);
345 }
346 
347 /*!
348     Adds an attribute with the given \a name in \a namespaceUri with \a value.
349     If an attribute with the same name exists, its value is replaced by
350     \a value.
351 
352     \sa attributeNS(), attribute(), setAttribute()
353 */
setAttributeNS(const QString & namespaceUri,const QString & name,const QString & value)354 void QWebElement::setAttributeNS(const QString &namespaceUri, const QString &name, const QString &value)
355 {
356     if (!m_element)
357         return;
358     WebCore::ExceptionCode exception = 0;
359     m_element->setAttributeNS(namespaceUri, name, value, exception);
360 }
361 
362 /*!
363     Returns the attribute with the given \a name. If the attribute does not
364     exist, \a defaultValue is returned.
365 
366     \sa setAttribute(), setAttributeNS(), attributeNS()
367 */
attribute(const QString & name,const QString & defaultValue) const368 QString QWebElement::attribute(const QString &name, const QString &defaultValue) const
369 {
370     if (!m_element)
371         return QString();
372     if (m_element->hasAttribute(name))
373         return m_element->getAttribute(name);
374     else
375         return defaultValue;
376 }
377 
378 /*!
379     Returns the attribute with the given \a name in \a namespaceUri. If the
380     attribute does not exist, \a defaultValue is returned.
381 
382     \sa setAttributeNS(), setAttribute(), attribute()
383 */
attributeNS(const QString & namespaceUri,const QString & name,const QString & defaultValue) const384 QString QWebElement::attributeNS(const QString &namespaceUri, const QString &name, const QString &defaultValue) const
385 {
386     if (!m_element)
387         return QString();
388     if (m_element->hasAttributeNS(namespaceUri, name))
389         return m_element->getAttributeNS(namespaceUri, name);
390     else
391         return defaultValue;
392 }
393 
394 /*!
395     Returns true if this element has an attribute with the given \a name;
396     otherwise returns false.
397 
398     \sa attribute(), setAttribute()
399 */
hasAttribute(const QString & name) const400 bool QWebElement::hasAttribute(const QString &name) const
401 {
402     if (!m_element)
403         return false;
404     return m_element->hasAttribute(name);
405 }
406 
407 /*!
408     Returns true if this element has an attribute with the given \a name, in
409     \a namespaceUri; otherwise returns false.
410 
411     \sa attributeNS(), setAttributeNS()
412 */
hasAttributeNS(const QString & namespaceUri,const QString & name) const413 bool QWebElement::hasAttributeNS(const QString &namespaceUri, const QString &name) const
414 {
415     if (!m_element)
416         return false;
417     return m_element->hasAttributeNS(namespaceUri, name);
418 }
419 
420 /*!
421     Removes the attribute with the given \a name from this element.
422 
423     \sa attribute(), setAttribute(), hasAttribute()
424 */
removeAttribute(const QString & name)425 void QWebElement::removeAttribute(const QString &name)
426 {
427     if (!m_element)
428         return;
429     ExceptionCode exception = 0;
430     m_element->removeAttribute(name, exception);
431 }
432 
433 /*!
434     Removes the attribute with the given \a name, in \a namespaceUri, from this
435     element.
436 
437     \sa attributeNS(), setAttributeNS(), hasAttributeNS()
438 */
removeAttributeNS(const QString & namespaceUri,const QString & name)439 void QWebElement::removeAttributeNS(const QString &namespaceUri, const QString &name)
440 {
441     if (!m_element)
442         return;
443     WebCore::ExceptionCode exception = 0;
444     m_element->removeAttributeNS(namespaceUri, name, exception);
445 }
446 
447 /*!
448     Returns true if the element has any attributes defined; otherwise returns
449     false;
450 
451     \sa attribute(), setAttribute()
452 */
hasAttributes() const453 bool QWebElement::hasAttributes() const
454 {
455     if (!m_element)
456         return false;
457     return m_element->hasAttributes();
458 }
459 
460 /*!
461     Return the list of attributes for the namespace given as \a namespaceUri.
462 
463     \sa attribute(), setAttribute()
464 */
attributeNames(const QString & namespaceUri) const465 QStringList QWebElement::attributeNames(const QString& namespaceUri) const
466 {
467     if (!m_element)
468         return QStringList();
469 
470     QStringList attributeNameList;
471     const NamedNodeMap* const attrs = m_element->attributes(/* read only = */ true);
472     if (attrs) {
473         const String namespaceUriString(namespaceUri); // convert QString -> String once
474         const unsigned attrsCount = attrs->length();
475         for (unsigned i = 0; i < attrsCount; ++i) {
476             const Attribute* const attribute = attrs->attributeItem(i);
477             if (namespaceUriString == attribute->namespaceURI())
478                 attributeNameList.append(attribute->localName());
479         }
480     }
481     return attributeNameList;
482 }
483 
484 /*!
485     Returns true if the element has keyboard input focus; otherwise, returns false
486 
487     \sa setFocus()
488 */
hasFocus() const489 bool QWebElement::hasFocus() const
490 {
491     if (!m_element)
492         return false;
493     if (m_element->document())
494         return m_element == m_element->document()->focusedNode();
495     return false;
496 }
497 
498 /*!
499     Gives keyboard input focus to this element
500 
501     \sa hasFocus()
502 */
setFocus()503 void QWebElement::setFocus()
504 {
505     if (!m_element)
506         return;
507     if (m_element->document() && m_element->isFocusable())
508         m_element->document()->setFocusedNode(m_element);
509 }
510 
511 /*!
512     Returns the geometry of this element, relative to its containing frame.
513 
514     \sa tagName()
515 */
geometry() const516 QRect QWebElement::geometry() const
517 {
518     if (!m_element)
519         return QRect();
520     return m_element->getRect();
521 }
522 
523 /*!
524     Returns the tag name of this element.
525 
526     \sa geometry()
527 */
tagName() const528 QString QWebElement::tagName() const
529 {
530     if (!m_element)
531         return QString();
532     return m_element->tagName();
533 }
534 
535 /*!
536     Returns the namespace prefix of the element. If the element has no\
537     namespace prefix, empty string is returned.
538 */
prefix() const539 QString QWebElement::prefix() const
540 {
541     if (!m_element)
542         return QString();
543     return m_element->prefix();
544 }
545 
546 /*!
547     Returns the local name of the element. If the element does not use
548     namespaces, an empty string is returned.
549 */
localName() const550 QString QWebElement::localName() const
551 {
552     if (!m_element)
553         return QString();
554     return m_element->localName();
555 }
556 
557 /*!
558     Returns the namespace URI of this element. If the element has no namespace
559     URI, an empty string is returned.
560 */
namespaceUri() const561 QString QWebElement::namespaceUri() const
562 {
563     if (!m_element)
564         return QString();
565     return m_element->namespaceURI();
566 }
567 
568 /*!
569     Returns the parent element of this elemen. If this element is the root
570     document element, a null element is returned.
571 */
parent() const572 QWebElement QWebElement::parent() const
573 {
574     if (m_element)
575         return QWebElement(m_element->parentElement());
576     return QWebElement();
577 }
578 
579 /*!
580     Returns the element's first child.
581 
582     \sa lastChild(), previousSibling(), nextSibling()
583 */
firstChild() const584 QWebElement QWebElement::firstChild() const
585 {
586     if (!m_element)
587         return QWebElement();
588     for (Node* child = m_element->firstChild(); child; child = child->nextSibling()) {
589         if (!child->isElementNode())
590             continue;
591         Element* e = static_cast<Element*>(child);
592         return QWebElement(e);
593     }
594     return QWebElement();
595 }
596 
597 /*!
598     Returns the element's last child.
599 
600     \sa firstChild(), previousSibling(), nextSibling()
601 */
lastChild() const602 QWebElement QWebElement::lastChild() const
603 {
604     if (!m_element)
605         return QWebElement();
606     for (Node* child = m_element->lastChild(); child; child = child->previousSibling()) {
607         if (!child->isElementNode())
608             continue;
609         Element* e = static_cast<Element*>(child);
610         return QWebElement(e);
611     }
612     return QWebElement();
613 }
614 
615 /*!
616     Returns the element's next sibling.
617 
618     \sa firstChild(), previousSibling(), lastChild()
619 */
nextSibling() const620 QWebElement QWebElement::nextSibling() const
621 {
622     if (!m_element)
623         return QWebElement();
624     for (Node* sib = m_element->nextSibling(); sib; sib = sib->nextSibling()) {
625         if (!sib->isElementNode())
626             continue;
627         Element* e = static_cast<Element*>(sib);
628         return QWebElement(e);
629     }
630     return QWebElement();
631 }
632 
633 /*!
634     Returns the element's previous sibling.
635 
636     \sa firstChild(), nextSibling(), lastChild()
637 */
previousSibling() const638 QWebElement QWebElement::previousSibling() const
639 {
640     if (!m_element)
641         return QWebElement();
642     for (Node* sib = m_element->previousSibling(); sib; sib = sib->previousSibling()) {
643         if (!sib->isElementNode())
644             continue;
645         Element* e = static_cast<Element*>(sib);
646         return QWebElement(e);
647     }
648     return QWebElement();
649 }
650 
651 /*!
652     Returns the document which this element belongs to.
653 */
document() const654 QWebElement QWebElement::document() const
655 {
656     if (!m_element)
657         return QWebElement();
658     Document* document = m_element->document();
659     if (!document)
660         return QWebElement();
661     return QWebElement(document->documentElement());
662 }
663 
664 /*!
665     Returns the web frame which this element is a part of. If the element is a
666     null element, null is returned.
667 */
webFrame() const668 QWebFrame *QWebElement::webFrame() const
669 {
670     if (!m_element)
671         return 0;
672 
673     Document* document = m_element->document();
674     if (!document)
675         return 0;
676 
677     Frame* frame = document->frame();
678     if (!frame)
679         return 0;
680     return QWebFramePrivate::kit(frame);
681 }
682 
setupScriptContext(WebCore::Element * element,JSC::JSValue & thisValue,ScriptState * & state,ScriptController * & scriptController)683 static bool setupScriptContext(WebCore::Element* element, JSC::JSValue& thisValue, ScriptState*& state, ScriptController*& scriptController)
684 {
685     if (!element)
686         return false;
687 
688     Document* document = element->document();
689     if (!document)
690         return false;
691 
692     Frame* frame = document->frame();
693     if (!frame)
694         return false;
695 
696     scriptController = frame->script();
697     if (!scriptController)
698         return false;
699 
700     state = scriptController->globalObject(mainThreadNormalWorld())->globalExec();
701     if (!state)
702         return false;
703 
704     thisValue = toJS(state, element);
705     if (!thisValue)
706         return false;
707 
708     return true;
709 }
710 
711 
712 /*!
713     Executes \a scriptSource with this element as \c this object.
714 */
evaluateJavaScript(const QString & scriptSource)715 QVariant QWebElement::evaluateJavaScript(const QString& scriptSource)
716 {
717     if (scriptSource.isEmpty())
718         return QVariant();
719 
720     ScriptState* state = 0;
721     JSC::JSValue thisValue;
722     ScriptController* scriptController = 0;
723 
724     if (!setupScriptContext(m_element, thisValue, state, scriptController))
725         return QVariant();
726 
727     JSC::ScopeChain& scopeChain = state->dynamicGlobalObject()->globalScopeChain();
728     JSC::UString script((const UChar*)scriptSource.data(), scriptSource.length());
729     JSC::Completion completion = JSC::evaluate(state, scopeChain, JSC::makeSource(script), thisValue);
730     if ((completion.complType() != JSC::ReturnValue) && (completion.complType() != JSC::Normal))
731         return QVariant();
732 
733     JSC::JSValue result = completion.value();
734     if (!result)
735         return QVariant();
736 
737     int distance = 0;
738     return JSC::Bindings::convertValueToQVariant(state, result, QMetaType::Void, &distance);
739 }
740 
741 /*!
742     \enum QWebElement::StyleResolveStrategy
743 
744     This enum describes how QWebElement's styleProperty resolves the given
745     property name.
746 
747     \value InlineStyle Return the property value as it is defined in
748            the element, without respecting style inheritance and other CSS
749            rules.
750     \value CascadedStyle The property's value is determined using the
751            inheritance and importance rules defined in the document's
752            stylesheet.
753     \value ComputedStyle The property's value is the absolute value
754            of the style property resolved from the environment.
755 */
756 
757 /*!
758     Returns the value of the style with the given \a name using the specified
759     \a strategy. If a style with \a name does not exist, an empty string is
760     returned.
761 
762     In CSS, the cascading part depends on which CSS rule has priority and is
763     thus applied. Generally, the last defined rule has priority. Thus, an
764     inline style rule has priority over an embedded block style rule, which
765     in return has priority over an external style rule.
766 
767     If the "!important" declaration is set on one of those, the declaration
768     receives highest priority, unless other declarations also use the
769     "!important" declaration. Then, the last "!important" declaration takes
770     predecence.
771 
772     \sa setStyleProperty()
773 */
774 
styleProperty(const QString & name,StyleResolveStrategy strategy) const775 QString QWebElement::styleProperty(const QString &name, StyleResolveStrategy strategy) const
776 {
777     if (!m_element || !m_element->isStyledElement())
778         return QString();
779 
780     int propID = cssPropertyID(name);
781 
782     if (!propID)
783         return QString();
784 
785     CSSStyleDeclaration* style = static_cast<StyledElement*>(m_element)->style();
786 
787     if (strategy == InlineStyle)
788         return style->getPropertyValue(propID);
789 
790     if (strategy == CascadedStyle) {
791         if (style->getPropertyPriority(propID))
792             return style->getPropertyValue(propID);
793 
794         // We are going to resolve the style property by walking through the
795         // list of non-inline matched CSS rules for the element, looking for
796         // the highest priority definition.
797 
798         // Get an array of matched CSS rules for the given element sorted
799         // by importance and inheritance order. This include external CSS
800         // declarations, as well as embedded and inline style declarations.
801 
802         DOMWindow* domWindow = m_element->document()->frame()->domWindow();
803         if (RefPtr<CSSRuleList> rules = domWindow->getMatchedCSSRules(m_element, "")) {
804             for (int i = rules->length(); i > 0; --i) {
805                 CSSStyleRule* rule = static_cast<CSSStyleRule*>(rules->item(i - 1));
806 
807                 if (rule->style()->getPropertyPriority(propID))
808                     return rule->style()->getPropertyValue(propID);
809 
810                 if (style->getPropertyValue(propID).isEmpty())
811                     style = rule->style();
812             }
813         }
814 
815         return style->getPropertyValue(propID);
816     }
817 
818     if (strategy == ComputedStyle) {
819         if (!m_element || !m_element->isStyledElement())
820             return QString();
821 
822         int propID = cssPropertyID(name);
823 
824         RefPtr<CSSComputedStyleDeclaration> style = computedStyle(m_element);
825         if (!propID || !style)
826             return QString();
827 
828         return style->getPropertyValue(propID);
829     }
830 
831     return QString();
832 }
833 
834 /*!
835     Sets the value of the inline style with the given \a name to \a value.
836 
837     Setting a value, does not necessarily mean that it will become the applied
838     value, due to the fact that the style property's value might have been set
839     earlier with a higher priority in external or embedded style declarations.
840 
841     In order to ensure that the value will be applied, you may have to append
842     "!important" to the value.
843 */
setStyleProperty(const QString & name,const QString & value)844 void QWebElement::setStyleProperty(const QString &name, const QString &value)
845 {
846     if (!m_element || !m_element->isStyledElement())
847         return;
848 
849     int propID = cssPropertyID(name);
850     CSSStyleDeclaration* style = static_cast<StyledElement*>(m_element)->style();
851     if (!propID || !style)
852         return;
853 
854     ExceptionCode exception = 0;
855     style->setProperty(name, value, exception);
856 }
857 
858 /*!
859     Returns the list of classes of this element.
860 */
classes() const861 QStringList QWebElement::classes() const
862 {
863     if (!hasAttribute(QLatin1String("class")))
864         return QStringList();
865 
866     QStringList classes =  attribute(QLatin1String("class")).simplified().split(QLatin1Char(' '), QString::SkipEmptyParts);
867 #if QT_VERSION >= 0x040500
868     classes.removeDuplicates();
869 #else
870     int n = classes.size();
871     int j = 0;
872     QSet<QString> seen;
873     seen.reserve(n);
874     for (int i = 0; i < n; ++i) {
875         const QString& s = classes.at(i);
876         if (seen.contains(s))
877             continue;
878         seen.insert(s);
879         if (j != i)
880             classes[j] = s;
881         ++j;
882     }
883     if (n != j)
884         classes.erase(classes.begin() + j, classes.end());
885 #endif
886     return classes;
887 }
888 
889 /*!
890     Returns true if this element has a class with the given \a name; otherwise
891     returns false.
892 */
hasClass(const QString & name) const893 bool QWebElement::hasClass(const QString &name) const
894 {
895     QStringList list = classes();
896     return list.contains(name);
897 }
898 
899 /*!
900     Adds the specified class with the given \a name to the element.
901 */
addClass(const QString & name)902 void QWebElement::addClass(const QString &name)
903 {
904     QStringList list = classes();
905     if (!list.contains(name)) {
906         list.append(name);
907         QString value = list.join(QLatin1String(" "));
908         setAttribute(QLatin1String("class"), value);
909     }
910 }
911 
912 /*!
913     Removes the specified class with the given \a name from the element.
914 */
removeClass(const QString & name)915 void QWebElement::removeClass(const QString &name)
916 {
917     QStringList list = classes();
918     if (list.contains(name)) {
919         list.removeAll(name);
920         QString value = list.join(QLatin1String(" "));
921         setAttribute(QLatin1String("class"), value);
922     }
923 }
924 
925 /*!
926     Adds the specified class with the given \a name if it is not present. If
927     the class is already present, it will be removed.
928 */
toggleClass(const QString & name)929 void QWebElement::toggleClass(const QString &name)
930 {
931     QStringList list = classes();
932     if (list.contains(name))
933         list.removeAll(name);
934     else
935         list.append(name);
936 
937     QString value = list.join(QLatin1String(" "));
938     setAttribute(QLatin1String("class"), value);
939 }
940 
941 /*!
942     Appends the given \a element as the element's last child.
943 
944     If \a element is the child of another element, it is re-parented to this
945     element. If \a element is a child of this element, then its position in
946     the list of children is changed.
947 
948     Calling this function on a null element does nothing.
949 
950     \sa prependInside(), prependOutside(), appendOutside()
951 */
appendInside(const QWebElement & element)952 void QWebElement::appendInside(const QWebElement &element)
953 {
954     if (!m_element || element.isNull())
955         return;
956 
957     ExceptionCode exception = 0;
958     m_element->appendChild(element.m_element, exception);
959 }
960 
961 /*!
962     Appends the result of parsing \a markup as the element's last child.
963 
964     Calling this function on a null element does nothing.
965 
966     \sa prependInside(), prependOutside(), appendOutside()
967 */
appendInside(const QString & markup)968 void QWebElement::appendInside(const QString &markup)
969 {
970     if (!m_element)
971         return;
972 
973     if (!m_element->isHTMLElement())
974         return;
975 
976     HTMLElement* htmlElement = static_cast<HTMLElement*>(m_element);
977     RefPtr<DocumentFragment> fragment = htmlElement->createContextualFragment(markup);
978 
979     ExceptionCode exception = 0;
980     m_element->appendChild(fragment, exception);
981 }
982 
983 /*!
984     Prepends \a element as the element's first child.
985 
986     If \a element is the child of another element, it is re-parented to this
987     element. If \a element is a child of this element, then its position in
988     the list of children is changed.
989 
990     Calling this function on a null element does nothing.
991 
992     \sa appendInside(), prependOutside(), appendOutside()
993 */
prependInside(const QWebElement & element)994 void QWebElement::prependInside(const QWebElement &element)
995 {
996     if (!m_element || element.isNull())
997         return;
998 
999     ExceptionCode exception = 0;
1000 
1001     if (m_element->hasChildNodes())
1002         m_element->insertBefore(element.m_element, m_element->firstChild(), exception);
1003     else
1004         m_element->appendChild(element.m_element, exception);
1005 }
1006 
1007 /*!
1008     Prepends the result of parsing \a markup as the element's first child.
1009 
1010     Calling this function on a null element does nothing.
1011 
1012     \sa appendInside(), prependOutside(), appendOutside()
1013 */
prependInside(const QString & markup)1014 void QWebElement::prependInside(const QString &markup)
1015 {
1016     if (!m_element)
1017         return;
1018 
1019     if (!m_element->isHTMLElement())
1020         return;
1021 
1022     HTMLElement* htmlElement = static_cast<HTMLElement*>(m_element);
1023     RefPtr<DocumentFragment> fragment = htmlElement->createContextualFragment(markup);
1024 
1025     ExceptionCode exception = 0;
1026 
1027     if (m_element->hasChildNodes())
1028         m_element->insertBefore(fragment, m_element->firstChild(), exception);
1029     else
1030         m_element->appendChild(fragment, exception);
1031 }
1032 
1033 
1034 /*!
1035     Inserts the given \a element before this element.
1036 
1037     If \a element is the child of another element, it is re-parented to the
1038     parent of this element.
1039 
1040     Calling this function on a null element does nothing.
1041 
1042     \sa appendInside(), prependInside(), appendOutside()
1043 */
prependOutside(const QWebElement & element)1044 void QWebElement::prependOutside(const QWebElement &element)
1045 {
1046     if (!m_element || element.isNull())
1047         return;
1048 
1049     if (!m_element->parent())
1050         return;
1051 
1052     ExceptionCode exception = 0;
1053     m_element->parent()->insertBefore(element.m_element, m_element, exception);
1054 }
1055 
1056 /*!
1057     Inserts the result of parsing \a markup before this element.
1058 
1059     Calling this function on a null element does nothing.
1060 
1061     \sa appendInside(), prependInside(), appendOutside()
1062 */
prependOutside(const QString & markup)1063 void QWebElement::prependOutside(const QString &markup)
1064 {
1065     if (!m_element)
1066         return;
1067 
1068     if (!m_element->parent())
1069         return;
1070 
1071     if (!m_element->isHTMLElement())
1072         return;
1073 
1074     HTMLElement* htmlElement = static_cast<HTMLElement*>(m_element);
1075     RefPtr<DocumentFragment> fragment = htmlElement->createContextualFragment(markup);
1076 
1077     ExceptionCode exception = 0;
1078     m_element->parent()->insertBefore(fragment, m_element, exception);
1079 }
1080 
1081 /*!
1082     Inserts the given \a element after this element.
1083 
1084     If \a element is the child of another element, it is re-parented to the
1085     parent of this element.
1086 
1087     Calling this function on a null element does nothing.
1088 
1089     \sa appendInside(), prependInside(), prependOutside()
1090 */
appendOutside(const QWebElement & element)1091 void QWebElement::appendOutside(const QWebElement &element)
1092 {
1093     if (!m_element || element.isNull())
1094         return;
1095 
1096     if (!m_element->parent())
1097         return;
1098 
1099     ExceptionCode exception = 0;
1100     if (!m_element->nextSibling())
1101         m_element->parent()->appendChild(element.m_element, exception);
1102     else
1103         m_element->parent()->insertBefore(element.m_element, m_element->nextSibling(), exception);
1104 }
1105 
1106 /*!
1107     Inserts the result of parsing \a markup after this element.
1108 
1109     Calling this function on a null element does nothing.
1110 
1111     \sa appendInside(), prependInside(), prependOutside()
1112 */
appendOutside(const QString & markup)1113 void QWebElement::appendOutside(const QString &markup)
1114 {
1115     if (!m_element)
1116         return;
1117 
1118     if (!m_element->parent())
1119         return;
1120 
1121     if (!m_element->isHTMLElement())
1122         return;
1123 
1124     HTMLElement* htmlElement = static_cast<HTMLElement*>(m_element);
1125     RefPtr<DocumentFragment> fragment = htmlElement->createContextualFragment(markup);
1126 
1127     ExceptionCode exception = 0;
1128     if (!m_element->nextSibling())
1129         m_element->parent()->appendChild(fragment, exception);
1130     else
1131         m_element->parent()->insertBefore(fragment, m_element->nextSibling(), exception);
1132 }
1133 
1134 /*!
1135     Returns a clone of this element.
1136 
1137     The clone may be inserted at any point in the document.
1138 
1139     \sa appendInside(), prependInside(), prependOutside(), appendOutside()
1140 */
clone() const1141 QWebElement QWebElement::clone() const
1142 {
1143     if (!m_element)
1144         return QWebElement();
1145 
1146     return QWebElement(m_element->cloneElementWithChildren().get());
1147 }
1148 
1149 /*!
1150     Removes this element from the document and returns a reference to it.
1151 
1152     The element is still valid after removal, and can be inserted into other
1153     parts of the document.
1154 
1155     \sa removeAllChildren(), removeFromDocument()
1156 */
takeFromDocument()1157 QWebElement &QWebElement::takeFromDocument()
1158 {
1159     if (!m_element)
1160         return *this;
1161 
1162     ExceptionCode exception = 0;
1163     m_element->remove(exception);
1164 
1165     return *this;
1166 }
1167 
1168 /*!
1169     Removes this element from the document and makes it a null element.
1170 
1171     \sa removeAllChildren(), takeFromDocument()
1172 */
removeFromDocument()1173 void QWebElement::removeFromDocument()
1174 {
1175     if (!m_element)
1176         return;
1177 
1178     ExceptionCode exception = 0;
1179     m_element->remove(exception);
1180     m_element->deref();
1181     m_element = 0;
1182 }
1183 
1184 /*!
1185     Removes all children from this element.
1186 
1187     \sa removeFromDocument(), takeFromDocument()
1188 */
removeAllChildren()1189 void QWebElement::removeAllChildren()
1190 {
1191     if (!m_element)
1192         return;
1193 
1194     m_element->removeAllChildren();
1195 }
1196 
findInsertionPoint(PassRefPtr<Node> root)1197 static RefPtr<Node> findInsertionPoint(PassRefPtr<Node> root)
1198 {
1199     RefPtr<Node> node = root;
1200 
1201     // Go as far down the tree as possible.
1202     while (node->hasChildNodes() && node->firstChild()->isElementNode())
1203         node = node->firstChild();
1204 
1205     // TODO: Implement SVG support
1206     if (node->isHTMLElement()) {
1207         HTMLElement* element = static_cast<HTMLElement*>(node.get());
1208 
1209         // The insert point could be a non-enclosable tag and it can thus
1210         // never have children, so go one up. Get the parent element, and not
1211         // note as a root note will always exist.
1212         if (element->endTagRequirement() == TagStatusForbidden)
1213             node = node->parentElement();
1214     }
1215 
1216     return node;
1217 }
1218 
1219 /*!
1220     Encloses the contents of this element with \a element. This element becomes
1221     the child of the deepest descendant within \a element.
1222 
1223     ### illustration
1224 
1225     \sa encloseWith()
1226 */
encloseContentsWith(const QWebElement & element)1227 void QWebElement::encloseContentsWith(const QWebElement &element)
1228 {
1229     if (!m_element || element.isNull())
1230         return;
1231 
1232     RefPtr<Node> insertionPoint = findInsertionPoint(element.m_element);
1233 
1234     if (!insertionPoint)
1235         return;
1236 
1237     ExceptionCode exception = 0;
1238 
1239     // reparent children
1240     for (RefPtr<Node> child = m_element->firstChild(); child;) {
1241         RefPtr<Node> next = child->nextSibling();
1242         insertionPoint->appendChild(child, exception);
1243         child = next;
1244     }
1245 
1246     if (m_element->hasChildNodes())
1247         m_element->insertBefore(element.m_element, m_element->firstChild(), exception);
1248     else
1249         m_element->appendChild(element.m_element, exception);
1250 }
1251 
1252 /*!
1253     Encloses the contents of this element with the result of parsing \a markup.
1254     This element becomes the child of the deepest descendant within \a markup.
1255 
1256     \sa encloseWith()
1257 */
encloseContentsWith(const QString & markup)1258 void QWebElement::encloseContentsWith(const QString &markup)
1259 {
1260     if (!m_element)
1261         return;
1262 
1263     if (!m_element->parent())
1264         return;
1265 
1266     if (!m_element->isHTMLElement())
1267         return;
1268 
1269     HTMLElement* htmlElement = static_cast<HTMLElement*>(m_element);
1270     RefPtr<DocumentFragment> fragment = htmlElement->createContextualFragment(markup);
1271 
1272     if (!fragment || !fragment->firstChild())
1273         return;
1274 
1275     RefPtr<Node> insertionPoint = findInsertionPoint(fragment->firstChild());
1276 
1277     if (!insertionPoint)
1278         return;
1279 
1280     ExceptionCode exception = 0;
1281 
1282     // reparent children
1283     for (RefPtr<Node> child = m_element->firstChild(); child;) {
1284         RefPtr<Node> next = child->nextSibling();
1285         insertionPoint->appendChild(child, exception);
1286         child = next;
1287     }
1288 
1289     if (m_element->hasChildNodes())
1290         m_element->insertBefore(fragment, m_element->firstChild(), exception);
1291     else
1292         m_element->appendChild(fragment, exception);
1293 }
1294 
1295 /*!
1296     Encloses this element with \a element. This element becomes the child of
1297     the deepest descendant within \a element.
1298 
1299     \sa replace()
1300 */
encloseWith(const QWebElement & element)1301 void QWebElement::encloseWith(const QWebElement &element)
1302 {
1303     if (!m_element || element.isNull())
1304         return;
1305 
1306     RefPtr<Node> insertionPoint = findInsertionPoint(element.m_element);
1307 
1308     if (!insertionPoint)
1309         return;
1310 
1311     // Keep reference to these two nodes before pulling out this element and
1312     // wrapping it in the fragment. The reason for doing it in this order is
1313     // that once the fragment has been added to the document it is empty, so
1314     // we no longer have access to the nodes it contained.
1315     Node* parentNode = m_element->parent();
1316     Node* siblingNode = m_element->nextSibling();
1317 
1318     ExceptionCode exception = 0;
1319     insertionPoint->appendChild(m_element, exception);
1320 
1321     if (!siblingNode)
1322         parentNode->appendChild(element.m_element, exception);
1323     else
1324         parentNode->insertBefore(element.m_element, siblingNode, exception);
1325 }
1326 
1327 /*!
1328     Encloses this element with the result of parsing \a markup. This element
1329     becomes the child of the deepest descendant within \a markup.
1330 
1331     \sa replace()
1332 */
encloseWith(const QString & markup)1333 void QWebElement::encloseWith(const QString &markup)
1334 {
1335     if (!m_element)
1336         return;
1337 
1338     if (!m_element->parent())
1339         return;
1340 
1341     if (!m_element->isHTMLElement())
1342         return;
1343 
1344     HTMLElement* htmlElement = static_cast<HTMLElement*>(m_element);
1345     RefPtr<DocumentFragment> fragment = htmlElement->createContextualFragment(markup);
1346 
1347     if (!fragment || !fragment->firstChild())
1348         return;
1349 
1350     RefPtr<Node> insertionPoint = findInsertionPoint(fragment->firstChild());
1351 
1352     if (!insertionPoint)
1353         return;
1354 
1355     // Keep reference to these two nodes before pulling out this element and
1356     // wrapping it in the fragment. The reason for doing it in this order is
1357     // that once the fragment has been added to the document it is empty, so
1358     // we no longer have access to the nodes it contained.
1359     Node* parentNode = m_element->parent();
1360     Node* siblingNode = m_element->nextSibling();
1361 
1362     ExceptionCode exception = 0;
1363     insertionPoint->appendChild(m_element, exception);
1364 
1365     if (!siblingNode)
1366         parentNode->appendChild(fragment, exception);
1367     else
1368         parentNode->insertBefore(fragment, siblingNode, exception);
1369 }
1370 
1371 /*!
1372     Replaces this element with \a element.
1373 
1374     This method will not replace the <html>, <head> or <body> elements.
1375 
1376     \sa encloseWith()
1377 */
replace(const QWebElement & element)1378 void QWebElement::replace(const QWebElement &element)
1379 {
1380     if (!m_element || element.isNull())
1381         return;
1382 
1383     appendOutside(element);
1384     takeFromDocument();
1385 }
1386 
1387 /*!
1388     Replaces this element with the result of parsing \a markup.
1389 
1390     This method will not replace the <html>, <head> or <body> elements.
1391 
1392     \sa encloseWith()
1393 */
replace(const QString & markup)1394 void QWebElement::replace(const QString &markup)
1395 {
1396     if (!m_element)
1397         return;
1398 
1399     appendOutside(markup);
1400     takeFromDocument();
1401 }
1402 
1403 /*!
1404     \internal
1405     Walk \a node's parents until a valid QWebElement is found.
1406     For example, a WebCore::Text node is not a valid Html QWebElement, but its
1407     enclosing p tag is.
1408 */
enclosingElement(WebCore::Node * node)1409 QWebElement QWebElement::enclosingElement(WebCore::Node* node)
1410 {
1411     QWebElement element(node);
1412 
1413     while (element.isNull() && node) {
1414         node = node->parentNode();
1415         element = QWebElement(node);
1416     }
1417     return element;
1418 }
1419 
1420 /*!
1421     \fn inline bool QWebElement::operator==(const QWebElement& o) const;
1422 
1423     Returns true if this element points to the same underlying DOM object as
1424     \a o; otherwise returns false.
1425 */
1426 
1427 /*!
1428     \fn inline bool QWebElement::operator!=(const QWebElement& o) const;
1429 
1430     Returns true if this element points to a different underlying DOM object
1431     than \a o; otherwise returns false.
1432 */
1433 
1434 
1435 /*!
1436   Render the element into \a painter .
1437 */
render(QPainter * painter)1438 void QWebElement::render(QPainter* painter)
1439 {
1440     WebCore::Element* e = m_element;
1441     Document* doc = e ? e->document() : 0;
1442     if (!doc)
1443         return;
1444 
1445     Frame* frame = doc->frame();
1446     if (!frame || !frame->view() || !frame->contentRenderer())
1447         return;
1448 
1449     FrameView* view = frame->view();
1450 
1451     view->layoutIfNeededRecursive();
1452 
1453     IntRect rect = e->getRect();
1454 
1455     if (rect.size().isEmpty())
1456         return;
1457 
1458     GraphicsContext context(painter);
1459 
1460     context.save();
1461     context.translate(-rect.x(), -rect.y());
1462     view->setNodeToDraw(e);
1463     view->paintContents(&context, rect);
1464     view->setNodeToDraw(0);
1465     context.restore();
1466 }
1467 
1468 class QWebElementCollectionPrivate : public QSharedData
1469 {
1470 public:
1471     static QWebElementCollectionPrivate* create(const PassRefPtr<Node> &context, const QString &query);
1472 
1473     RefPtr<NodeList> m_result;
1474 
1475 private:
QWebElementCollectionPrivate()1476     inline QWebElementCollectionPrivate() {}
1477 };
1478 
create(const PassRefPtr<Node> & context,const QString & query)1479 QWebElementCollectionPrivate* QWebElementCollectionPrivate::create(const PassRefPtr<Node> &context, const QString &query)
1480 {
1481     if (!context)
1482         return 0;
1483 
1484     // Let WebKit do the hard work hehehe
1485     ExceptionCode exception = 0; // ###
1486     RefPtr<NodeList> nodes = context->querySelectorAll(query, exception);
1487     if (!nodes)
1488         return 0;
1489 
1490     QWebElementCollectionPrivate* priv = new QWebElementCollectionPrivate;
1491     priv->m_result = nodes;
1492     return priv;
1493 }
1494 
1495 /*!
1496     \class QWebElementCollection
1497     \since 4.6
1498     \brief The QWebElementCollection class represents a collection of web elements.
1499     \preliminary
1500 
1501     Elements in a document can be selected using QWebElement::findAll() or using the
1502     QWebElement constructor. The collection is composed by choosing all elements in the
1503     document that match a specified CSS selector expression.
1504 
1505     The number of selected elements is provided through the count() property. Individual
1506     elements can be retrieved by index using at().
1507 
1508     It is also possible to iterate through all elements in the collection using Qt's foreach
1509     macro:
1510 
1511     \code
1512         QWebElementCollection collection = document.findAll("p");
1513         foreach (QWebElement paraElement, collection) {
1514             ...
1515         }
1516     \endcode
1517 */
1518 
1519 /*!
1520     Constructs an empty collection.
1521 */
QWebElementCollection()1522 QWebElementCollection::QWebElementCollection()
1523 {
1524 }
1525 
1526 /*!
1527     Constructs a copy of \a other.
1528 */
QWebElementCollection(const QWebElementCollection & other)1529 QWebElementCollection::QWebElementCollection(const QWebElementCollection &other)
1530     : d(other.d)
1531 {
1532 }
1533 
1534 /*!
1535     Constructs a collection of elements from the list of child elements of \a contextElement that
1536     match the specified CSS selector \a query.
1537 */
QWebElementCollection(const QWebElement & contextElement,const QString & query)1538 QWebElementCollection::QWebElementCollection(const QWebElement &contextElement, const QString &query)
1539 {
1540     d = QExplicitlySharedDataPointer<QWebElementCollectionPrivate>(QWebElementCollectionPrivate::create(contextElement.m_element, query));
1541 }
1542 
1543 /*!
1544     Assigns \a other to this collection and returns a reference to this collection.
1545 */
operator =(const QWebElementCollection & other)1546 QWebElementCollection &QWebElementCollection::operator=(const QWebElementCollection &other)
1547 {
1548     d = other.d;
1549     return *this;
1550 }
1551 
1552 /*!
1553     Destroys the collection.
1554 */
~QWebElementCollection()1555 QWebElementCollection::~QWebElementCollection()
1556 {
1557 }
1558 
1559 /*! \fn QWebElementCollection &QWebElementCollection::operator+=(const QWebElementCollection &other)
1560 
1561     Appends the items of the \a other list to this list and returns a
1562     reference to this list.
1563 
1564     \sa operator+(), append()
1565 */
1566 
1567 /*!
1568     Returns a collection that contains all the elements of this collection followed
1569     by all the elements in the \a other collection. Duplicates may occur in the result.
1570 
1571     \sa operator+=()
1572 */
operator +(const QWebElementCollection & other) const1573 QWebElementCollection QWebElementCollection::operator+(const QWebElementCollection &other) const
1574 {
1575     QWebElementCollection n = *this; n.d.detach(); n += other; return n;
1576 }
1577 
1578 /*!
1579     Extends the collection by appending all items of \a other.
1580 
1581     The resulting collection may include duplicate elements.
1582 
1583     \sa operator+=()
1584 */
append(const QWebElementCollection & other)1585 void QWebElementCollection::append(const QWebElementCollection &other)
1586 {
1587     if (!d) {
1588         *this = other;
1589         return;
1590     }
1591     if (!other.d)
1592         return;
1593     Vector<RefPtr<Node> > nodes;
1594     RefPtr<NodeList> results[] = { d->m_result, other.d->m_result };
1595     nodes.reserveInitialCapacity(results[0]->length() + results[1]->length());
1596 
1597     for (int i = 0; i < 2; ++i) {
1598         int j = 0;
1599         Node* n = results[i]->item(j);
1600         while (n) {
1601             nodes.append(n);
1602             n = results[i]->item(++j);
1603         }
1604     }
1605 
1606     d->m_result = StaticNodeList::adopt(nodes);
1607 }
1608 
1609 /*!
1610     Returns the number of elements in the collection.
1611 */
count() const1612 int QWebElementCollection::count() const
1613 {
1614     if (!d)
1615         return 0;
1616     return d->m_result->length();
1617 }
1618 
1619 /*!
1620     Returns the element at index position \a i in the collection.
1621 */
at(int i) const1622 QWebElement QWebElementCollection::at(int i) const
1623 {
1624     if (!d)
1625         return QWebElement();
1626     Node* n = d->m_result->item(i);
1627     return QWebElement(static_cast<Element*>(n));
1628 }
1629 
1630 /*!
1631     \fn const QWebElement QWebElementCollection::operator[](int position) const
1632 
1633     Returns the element at the specified \a position in the collection.
1634 */
1635 
1636 /*! \fn QWebElement QWebElementCollection::first() const
1637 
1638     Returns the first element in the collection.
1639 
1640     \sa last(), operator[](), at(), count()
1641 */
1642 
1643 /*! \fn QWebElement QWebElementCollection::last() const
1644 
1645     Returns the last element in the collection.
1646 
1647     \sa first(), operator[](), at(), count()
1648 */
1649 
1650 /*!
1651     Returns a QList object with the elements contained in this collection.
1652 */
toList() const1653 QList<QWebElement> QWebElementCollection::toList() const
1654 {
1655     if (!d)
1656         return QList<QWebElement>();
1657     QList<QWebElement> elements;
1658     int i = 0;
1659     Node* n = d->m_result->item(i);
1660     while (n) {
1661         if (n->isElementNode())
1662             elements.append(QWebElement(static_cast<Element*>(n)));
1663         n = d->m_result->item(++i);
1664     }
1665     return elements;
1666 }
1667 
1668 /*!
1669     \fn QWebElementCollection::const_iterator QWebElementCollection::begin() const
1670 
1671     Returns an STL-style iterator pointing to the first element in the collection.
1672 
1673     \sa end()
1674 */
1675 
1676 /*!
1677     \fn QWebElementCollection::const_iterator QWebElementCollection::end() const
1678 
1679     Returns an STL-style iterator pointing to the imaginary element after the
1680     last element in the list.
1681 
1682     \sa begin()
1683 */
1684 
1685 /*!
1686     \class QWebElementCollection::const_iterator
1687     \since 4.6
1688     \brief The QWebElementCollection::const_iterator class provides an STL-style const iterator for QWebElementCollection.
1689 
1690     QWebElementCollection provides STL style const iterators for fast low-level access to the elements.
1691 
1692     QWebElementCollection::const_iterator allows you to iterate over a QWebElementCollection.
1693 */
1694 
1695 /*!
1696     \fn QWebElementCollection::const_iterator::const_iterator(const const_iterator &other)
1697 
1698     Constructs a copy of \a other.
1699 */
1700 
1701 /*!
1702     \fn QWebElementCollection::const_iterator::const_iterator(const QWebElementCollection *collection, int index)
1703     \internal
1704 */
1705 
1706 /*!
1707     \fn const QWebElement QWebElementCollection::const_iterator::operator*() const
1708 
1709     Returns the current element.
1710 */
1711 
1712 /*!
1713     \fn bool QWebElementCollection::const_iterator::operator==(const const_iterator &other) const
1714 
1715     Returns true if \a other points to the same item as this iterator;
1716     otherwise returns false.
1717 
1718     \sa operator!=()
1719 */
1720 
1721 /*!
1722     \fn bool QWebElementCollection::const_iterator::operator!=(const const_iterator &other) const
1723 
1724     Returns true if \a other points to a different element than this;
1725     iterator; otherwise returns false.
1726 
1727     \sa operator==()
1728 */
1729 
1730 /*!
1731     \fn QWebElementCollection::const_iterator &QWebElementCollection::const_iterator::operator++()
1732 
1733     The prefix ++ operator (\c{++it}) advances the iterator to the next element in the collection
1734     and returns an iterator to the new current element.
1735 
1736     Calling this function on QWebElementCollection::end() leads to undefined results.
1737 
1738     \sa operator--()
1739 */
1740 
1741 /*!
1742     \fn QWebElementCollection::const_iterator QWebElementCollection::const_iterator::operator++(int)
1743 
1744     \overload
1745 
1746     The postfix ++ operator (\c{it++}) advances the iterator to the next element in the collection
1747     and returns an iterator to the previously current element.
1748 
1749     Calling this function on QWebElementCollection::end() leads to undefined results.
1750 */
1751 
1752 /*!
1753     \fn QWebElementCollection::const_iterator &QWebElementCollection::const_iterator::operator--()
1754 
1755     The prefix -- operator (\c{--it}) makes the preceding element current and returns an
1756     iterator to the new current element.
1757 
1758     Calling this function on QWebElementCollection::begin() leads to undefined results.
1759 
1760     \sa operator++()
1761 */
1762 
1763 /*!
1764     \fn QWebElementCollection::const_iterator QWebElementCollection::const_iterator::operator--(int)
1765 
1766     \overload
1767 
1768     The postfix -- operator (\c{it--}) makes the preceding element current and returns
1769     an iterator to the previously current element.
1770 */
1771 
1772 /*!
1773     \fn QWebElementCollection::const_iterator &QWebElementCollection::const_iterator::operator+=(int j)
1774 
1775     Advances the iterator by \a j elements. If \a j is negative, the iterator goes backward.
1776 
1777     \sa operator-=(), operator+()
1778 */
1779 
1780 /*!
1781     \fn QWebElementCollection::const_iterator &QWebElementCollection::const_iterator::operator-=(int j)
1782 
1783     Makes the iterator go back by \a j elements. If \a j is negative, the iterator goes forward.
1784 
1785     \sa operator+=(), operator-()
1786 */
1787 
1788 /*!
1789     \fn QWebElementCollection::const_iterator QWebElementCollection::const_iterator::operator+(int j) const
1790 
1791     Returns an iterator to the element at \a j positions forward from this iterator. If \a j
1792     is negative, the iterator goes backward.
1793 
1794     \sa operator-(), operator+=()
1795 */
1796 
1797 /*!
1798     \fn QWebElementCollection::const_iterator QWebElementCollection::const_iterator::operator-(int j) const
1799 
1800     Returns an iterator to the element at \a j positiosn backward from this iterator.
1801     If \a j is negative, the iterator goes forward.
1802 
1803     \sa operator+(), operator-=()
1804 */
1805 
1806 /*!
1807     \fn int QWebElementCollection::const_iterator::operator-(const_iterator other) const
1808 
1809     Returns the number of elements between the item point to by \a other
1810     and the element pointed to by this iterator.
1811 */
1812 
1813 /*!
1814     \fn bool QWebElementCollection::const_iterator::operator<(const const_iterator &other) const
1815 
1816     Returns true if the element pointed to by this iterator is less than the element pointed to
1817     by the \a other iterator.
1818 */
1819 
1820 /*!
1821     \fn bool QWebElementCollection::const_iterator::operator<=(const const_iterator &other) const
1822 
1823     Returns true if the element pointed to by this iterator is less than or equal to the
1824     element pointed to by the \a other iterator.
1825 */
1826 
1827 /*!
1828     \fn bool QWebElementCollection::const_iterator::operator>(const const_iterator &other) const
1829 
1830     Returns true if the element pointed to by this iterator is greater than the element pointed to
1831     by the \a other iterator.
1832 */
1833 
1834 /*!
1835     \fn bool QWebElementCollection::const_iterator::operator>=(const const_iterator &other) const
1836 
1837     Returns true if the element pointed to by this iterator is greater than or equal to the
1838     element pointed to by the \a other iterator.
1839 */
1840 
1841 /*!
1842     \fn QWebElementCollection::iterator QWebElementCollection::begin()
1843 
1844     Returns an STL-style iterator pointing to the first element in the collection.
1845 
1846     \sa end()
1847 */
1848 
1849 /*!
1850     \fn QWebElementCollection::iterator QWebElementCollection::end()
1851 
1852     Returns an STL-style iterator pointing to the imaginary element after the
1853     last element in the list.
1854 
1855     \sa begin()
1856 */
1857 
1858 /*!
1859     \fn QWebElementCollection::const_iterator QWebElementCollection::constBegin() const
1860 
1861     Returns an STL-style iterator pointing to the first element in the collection.
1862 
1863     \sa end()
1864 */
1865 
1866 /*!
1867     \fn QWebElementCollection::const_iterator QWebElementCollection::constEnd() const
1868 
1869     Returns an STL-style iterator pointing to the imaginary element after the
1870     last element in the list.
1871 
1872     \sa begin()
1873 */
1874 
1875 /*!
1876     \class QWebElementCollection::iterator
1877     \since 4.6
1878     \brief The QWebElementCollection::iterator class provides an STL-style iterator for QWebElementCollection.
1879 
1880     QWebElementCollection provides STL style iterators for fast low-level access to the elements.
1881 
1882     QWebElementCollection::iterator allows you to iterate over a QWebElementCollection.
1883 */
1884 
1885 /*!
1886     \fn QWebElementCollection::iterator::iterator(const iterator &other)
1887 
1888     Constructs a copy of \a other.
1889 */
1890 
1891 /*!
1892     \fn QWebElementCollection::iterator::iterator(const QWebElementCollection *collection, int index)
1893     \internal
1894 */
1895 
1896 /*!
1897     \fn const QWebElement QWebElementCollection::iterator::operator*() const
1898 
1899     Returns the current element.
1900 */
1901 
1902 /*!
1903     \fn bool QWebElementCollection::iterator::operator==(const iterator &other) const
1904 
1905     Returns true if \a other points to the same item as this iterator;
1906     otherwise returns false.
1907 
1908     \sa operator!=()
1909 */
1910 
1911 /*!
1912     \fn bool QWebElementCollection::iterator::operator!=(const iterator &other) const
1913 
1914     Returns true if \a other points to a different element than this;
1915     iterator; otherwise returns false.
1916 
1917     \sa operator==()
1918 */
1919 
1920 /*!
1921     \fn QWebElementCollection::iterator &QWebElementCollection::iterator::operator++()
1922 
1923     The prefix ++ operator (\c{++it}) advances the iterator to the next element in the collection
1924     and returns an iterator to the new current element.
1925 
1926     Calling this function on QWebElementCollection::end() leads to undefined results.
1927 
1928     \sa operator--()
1929 */
1930 
1931 /*!
1932     \fn QWebElementCollection::iterator QWebElementCollection::iterator::operator++(int)
1933 
1934     \overload
1935 
1936     The postfix ++ operator (\c{it++}) advances the iterator to the next element in the collection
1937     and returns an iterator to the previously current element.
1938 
1939     Calling this function on QWebElementCollection::end() leads to undefined results.
1940 */
1941 
1942 /*!
1943     \fn QWebElementCollection::iterator &QWebElementCollection::iterator::operator--()
1944 
1945     The prefix -- operator (\c{--it}) makes the preceding element current and returns an
1946     iterator to the new current element.
1947 
1948     Calling this function on QWebElementCollection::begin() leads to undefined results.
1949 
1950     \sa operator++()
1951 */
1952 
1953 /*!
1954     \fn QWebElementCollection::iterator QWebElementCollection::iterator::operator--(int)
1955 
1956     \overload
1957 
1958     The postfix -- operator (\c{it--}) makes the preceding element current and returns
1959     an iterator to the previously current element.
1960 */
1961 
1962 /*!
1963     \fn QWebElementCollection::iterator &QWebElementCollection::iterator::operator+=(int j)
1964 
1965     Advances the iterator by \a j elements. If \a j is negative, the iterator goes backward.
1966 
1967     \sa operator-=(), operator+()
1968 */
1969 
1970 /*!
1971     \fn QWebElementCollection::iterator &QWebElementCollection::iterator::operator-=(int j)
1972 
1973     Makes the iterator go back by \a j elements. If \a j is negative, the iterator goes forward.
1974 
1975     \sa operator+=(), operator-()
1976 */
1977 
1978 /*!
1979     \fn QWebElementCollection::iterator QWebElementCollection::iterator::operator+(int j) const
1980 
1981     Returns an iterator to the element at \a j positions forward from this iterator. If \a j
1982     is negative, the iterator goes backward.
1983 
1984     \sa operator-(), operator+=()
1985 */
1986 
1987 /*!
1988     \fn QWebElementCollection::iterator QWebElementCollection::iterator::operator-(int j) const
1989 
1990     Returns an iterator to the element at \a j positiosn backward from this iterator.
1991     If \a j is negative, the iterator goes forward.
1992 
1993     \sa operator+(), operator-=()
1994 */
1995 
1996 /*!
1997     \fn int QWebElementCollection::iterator::operator-(iterator other) const
1998 
1999     Returns the number of elements between the item point to by \a other
2000     and the element pointed to by this iterator.
2001 */
2002 
2003 /*!
2004     \fn bool QWebElementCollection::iterator::operator<(const iterator &other) const
2005 
2006     Returns true if the element pointed to by this iterator is less than the element pointed to
2007     by the \a other iterator.
2008 */
2009 
2010 /*!
2011     \fn bool QWebElementCollection::iterator::operator<=(const iterator &other) const
2012 
2013     Returns true if the element pointed to by this iterator is less than or equal to the
2014     element pointed to by the \a other iterator.
2015 */
2016 
2017 /*!
2018     \fn bool QWebElementCollection::iterator::operator>(const iterator &other) const
2019 
2020     Returns true if the element pointed to by this iterator is greater than the element pointed to
2021     by the \a other iterator.
2022 */
2023 
2024 /*!
2025     \fn bool QWebElementCollection::iterator::operator>=(const iterator &other) const
2026 
2027     Returns true if the element pointed to by this iterator is greater than or equal to the
2028     element pointed to by the \a other iterator.
2029 */
2030