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