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