File indexing completed on 2024-04-28 11:39:38

0001 /*
0002  * This file is part of the DOM implementation for KDE.
0003  *
0004  * Copyright  (C) 2010 Maksim Orlovich (maksim@kde.org)
0005  *
0006  * This library is free software; you can redistribute it and/or
0007  * modify it under the terms of the GNU Library General Public
0008  * License as published by the Free Software Foundation; either
0009  * version 2 of the License, or (at your option) any later version.
0010  *
0011  * This library is distributed in the hope that it will be useful,
0012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014  * Library General Public License for more details.
0015  *
0016  * You should have received a copy of the GNU Library General Public License
0017  * along with this library; see the file COPYING.LIB.  If not, write to
0018  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0019  * Boston, MA 02110-1301, USA.
0020  */
0021 
0022 #include "wa_selectors.h"
0023 #include "xml/dom_nodeimpl.h"
0024 #include "xml/dom_elementimpl.h"
0025 #include "xml/dom_nodelistimpl.h"
0026 #include <wtf/RefPtr.h>
0027 
0028 #include "css/cssparser.h"
0029 #include "css/cssstyleselector.h"
0030 
0031 using namespace DOM;
0032 
0033 namespace khtml
0034 {
0035 
0036 namespace SelectorQuery
0037 {
0038 
0039 static WTF::PassRefPtr<DOM::NodeListImpl>  querySelectorImp(bool justOne, DOM::NodeImpl *root, const DOM::DOMString &query, int &ec)
0040 {
0041     // Parse the query.
0042     CSSParser p;
0043     QList<CSSSelector *> selectors = p.parseSelectorList(root->document(), query);
0044 
0045     if (selectors.isEmpty()) {
0046         ec = DOMException::SYNTAX_ERR;
0047         return nullptr;
0048     }
0049 
0050     khtml::CSSStyleSelector *styleSelector = root->document()->styleSelector();
0051 
0052     // ### not in the spec.
0053     if (!styleSelector) {
0054         ec = DOMException::INVALID_STATE_ERR;
0055         return nullptr;
0056     }
0057 
0058     // Check for matches. We specialize some paths for common selectors.
0059     DOM::StaticNodeListImpl *matches = new DOM::StaticNodeListImpl;
0060 
0061     bool requiresClass = true;
0062     bool requiresId    = true;
0063     for (int i = 0; i < selectors.size(); ++i) {
0064         if (selectors[i]->match != CSSSelector::Class) {
0065             requiresClass = false;
0066         }
0067         if (selectors[i]->match != CSSSelector::Id) {
0068             requiresId    = false;
0069         }
0070     }
0071 
0072     for (DOM::NodeImpl *cur = root; cur; cur = cur->traverseNextNode(root)) {
0073         if (requiresClass && !cur->hasClass()) {
0074             continue;
0075         }
0076 
0077         if (requiresId && !cur->hasID()) {
0078             continue;
0079         }
0080 
0081         DOM::ElementImpl *e = nullptr;
0082         if (cur->isElementNode()) {
0083             e = static_cast<DOM::ElementImpl *>(cur);
0084         }
0085 
0086         if (e && styleSelector->isMatchedByAnySelector(e, selectors)) {
0087             matches->append(e);
0088             if (justOne) {
0089                 break;
0090             }
0091         }
0092     }
0093 
0094     // Cleanup the selectors.
0095     qDeleteAll(selectors);
0096 
0097     // all done
0098     return matches;
0099 }
0100 
0101 WTF::PassRefPtr<DOM::ElementImpl> querySelector(DOM::NodeImpl *root, const DOM::DOMString &query, int &ec)
0102 {
0103     WTF::RefPtr<DOM::NodeListImpl> nl = querySelectorImp(true, root, query, ec);
0104 
0105     if (nl && nl->length()) {
0106         return static_cast<DOM::ElementImpl *>(nl->item(0));
0107     }
0108 
0109     return nullptr;
0110 }
0111 
0112 WTF::PassRefPtr<DOM::NodeListImpl> querySelectorAll(DOM::NodeImpl *root, const DOM::DOMString &query, int &ec)
0113 {
0114     return querySelectorImp(false, root, query, ec);
0115 }
0116 
0117 } // namespace SelectorQuery
0118 
0119 } // namespace khtml
0120