summaryrefslogtreecommitdiffstats
path: root/webkit/glue/devtools/dom_agent_impl.cc
diff options
context:
space:
mode:
authorpfeldman@chromium.org <pfeldman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-03-25 10:56:58 +0000
committerpfeldman@chromium.org <pfeldman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-03-25 10:56:58 +0000
commit3bd1ac2ee1c845bcd8daecf9fe83928db0c672c9 (patch)
treed5c8932ca4a01d7509b63c24460653bd3d59cb15 /webkit/glue/devtools/dom_agent_impl.cc
parent146e53ce74beec8c5094f144ff8ad277d76b3a38 (diff)
downloadchromium_src-3bd1ac2ee1c845bcd8daecf9fe83928db0c672c9.zip
chromium_src-3bd1ac2ee1c845bcd8daecf9fe83928db0c672c9.tar.gz
chromium_src-3bd1ac2ee1c845bcd8daecf9fe83928db0c672c9.tar.bz2
DevTools: Element Panel search implementation.
Review URL: http://codereview.chromium.org/47009 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@12442 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/glue/devtools/dom_agent_impl.cc')
-rw-r--r--webkit/glue/devtools/dom_agent_impl.cc110
1 files changed, 110 insertions, 0 deletions
diff --git a/webkit/glue/devtools/dom_agent_impl.cc b/webkit/glue/devtools/dom_agent_impl.cc
index 34e1be5..6d6471c 100644
--- a/webkit/glue/devtools/dom_agent_impl.cc
+++ b/webkit/glue/devtools/dom_agent_impl.cc
@@ -14,18 +14,32 @@
#include "markup.h"
#include "MutationEvent.h"
#include "Node.h"
+#include "NodeList.h"
#include "PlatformString.h"
#include "Text.h"
+#include "XPathResult.h"
+#include <wtf/HashSet.h>
#include <wtf/OwnPtr.h>
+#include <wtf/RefPtr.h>
#include <wtf/Vector.h>
#undef LOG
+#include "base/string_util.h"
#include "base/values.h"
#include "webkit/glue/devtools/dom_agent_impl.h"
#include "webkit/glue/glue_util.h"
using namespace WebCore;
+const char DomAgentImpl::kExactTagNames[] = "//*[name() == '%s')]";
+const char DomAgentImpl::kPartialTagNames[] = "//*[contains(name(), '%s')]";
+const char DomAgentImpl::kStartOfTagNames[] = "//*[starts-with(name(), '%s')]";
+const char DomAgentImpl::kPartialTagNamesAndAttributeValues[] =
+ "//*[contains(name(), '%s') or contains(@*, '%s')]";
+const char DomAgentImpl::kPartialAttributeValues[] = "//*[contains(@*, '%s')]";
+const char DomAgentImpl::kPlainText[] =
+ "//text()[contains(., '%s')] | //comment()[contains(., '%s')]";
+
// static
PassRefPtr<DomAgentImpl::EventListenerWrapper>
DomAgentImpl::EventListenerWrapper::Create(
@@ -305,6 +319,102 @@ void DomAgentImpl::SetTextNodeValue(int element_id, const String& value) {
}
}
+void DomAgentImpl::PerformSearch(int call_id, const String& query) {
+ String tag_name_query = query;
+ String attribute_name_query = query;
+
+ bool start_tag_found = tag_name_query.startsWith("<", true);
+ bool end_tag_found = tag_name_query.endsWith(">", true);
+
+ if (start_tag_found || end_tag_found) {
+ int tag_name_query_length = tag_name_query.length();
+ int start = start_tag_found ? 1 : 0;
+ int end = end_tag_found ? tag_name_query_length - 1 : tag_name_query_length;
+ tag_name_query = tag_name_query.substring(start, end - start);
+ }
+
+ Vector<String> xpath_queries;
+ xpath_queries.append(String::format(kPlainText, query.utf8().data(),
+ query.utf8().data()));
+ if (tag_name_query.length() && start_tag_found && end_tag_found) {
+ xpath_queries.append(String::format(kExactTagNames,
+ tag_name_query.utf8().data()));
+ } else if (tag_name_query.length() && start_tag_found) {
+ xpath_queries.append(String::format(kStartOfTagNames,
+ tag_name_query.utf8().data()));
+ } else if (tag_name_query.length() && end_tag_found) {
+ // FIXME(pfeldman): we should have a matchEndOfTagNames search function if
+ // endTagFound is true but not startTagFound.
+ // This requires ends-with() support in XPath, WebKit only supports
+ // starts-with() and contains().
+ xpath_queries.append(String::format(kPartialTagNames,
+ tag_name_query.utf8().data()));
+ } else if (query == "//*" || query == "*") {
+ // These queries will match every node. Matching everything isn't useful
+ // and can be slow for large pages, so limit the search functions list to
+ // plain text and attribute matching.
+ xpath_queries.append(String::format(kPartialAttributeValues,
+ query.utf8().data()));
+ } else {
+ // TODO(pfeldman): Add more patterns.
+ xpath_queries.append(String::format(kPartialTagNamesAndAttributeValues,
+ tag_name_query.utf8().data(),
+ query.utf8().data()));
+ }
+
+ ExceptionCode ec = 0;
+ Vector<Document*> search_documents;
+ Document* main_document = (*documents_.begin()).get();
+ search_documents.append(main_document);
+
+ // Find all frames, iframes and object elements to search their documents.
+ RefPtr<NodeList> node_list = main_document->querySelectorAll(
+ "iframe, frame, object", ec);
+ if (ec) {
+ ListValue list;
+ delegate_->DidPerformSearch(call_id, list);
+ return;
+ }
+ for (unsigned int i = 0; i < node_list->length(); ++i) {
+ Node* node = node_list->item(i);
+ if (node->isFrameOwnerElement()) {
+ const HTMLFrameOwnerElement* frame_owner =
+ static_cast<const HTMLFrameOwnerElement*>(node);
+ if (frame_owner->contentDocument()) {
+ search_documents.append(search_documents);
+ }
+ }
+ }
+
+ HashSet<int> node_ids;
+ for (Vector<Document*>::iterator it = search_documents.begin();
+ it != search_documents.end(); ++it) {
+ for (Vector<String>::iterator qit = xpath_queries.begin();
+ qit != xpath_queries.end(); ++qit) {
+ String query = *qit;
+ RefPtr<XPathResult> result = (*it)->evaluate(query, *it, NULL,
+ XPathResult::UNORDERED_NODE_ITERATOR_TYPE, 0, ec);
+ if (ec) {
+ ListValue list;
+ delegate_->DidPerformSearch(call_id, list);
+ return;
+ }
+ Node* node = result->iterateNext(ec);
+ while (node && !ec) {
+ node_ids.add(PushNodePathToClient(node));
+ node = result->iterateNext(ec);
+ }
+ }
+ }
+
+ ListValue list;
+ for (HashSet<int>::iterator it = node_ids.begin();
+ it != node_ids.end(); ++it) {
+ list.Append(Value::CreateIntegerValue(*it));
+ }
+ delegate_->DidPerformSearch(call_id, list);
+}
+
ListValue* DomAgentImpl::BuildValueForNode(Node* node, int depth) {
OwnPtr<ListValue> value(new ListValue());
int id = Bind(node);