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