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