diff options
Diffstat (limited to 'webkit/glue/devtools/dom_agent_impl.cc')
-rw-r--r-- | webkit/glue/devtools/dom_agent_impl.cc | 598 |
1 files changed, 0 insertions, 598 deletions
diff --git a/webkit/glue/devtools/dom_agent_impl.cc b/webkit/glue/devtools/dom_agent_impl.cc deleted file mode 100644 index bcd477c..0000000 --- a/webkit/glue/devtools/dom_agent_impl.cc +++ /dev/null @@ -1,598 +0,0 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "config.h" - -#include "AtomicString.h" -#include "DOMWindow.h" -#include "Document.h" -#include "Event.h" -#include "EventListener.h" -#include "EventNames.h" -#include "EventTarget.h" -#include "HTMLFrameOwnerElement.h" -#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( - DomAgentImpl* dom_agent_impl) { - return adoptRef(new EventListenerWrapper(dom_agent_impl)); -} - -DomAgentImpl::EventListenerWrapper::EventListenerWrapper( - DomAgentImpl* dom_agent_impl) : dom_agent_impl_(dom_agent_impl) { -} - -void DomAgentImpl::EventListenerWrapper::handleEvent( - Event* event, - bool isWindowEvent) { - dom_agent_impl_->handleEvent(event, isWindowEvent); -} - -DomAgentImpl::DomAgentImpl(DomAgentDelegate* delegate) - : delegate_(delegate), - last_node_id_(1), - document_element_requested_(false) { - event_listener_ = EventListenerWrapper::Create(this); -} - -DomAgentImpl::~DomAgentImpl() { - SetDocument(NULL); -} - -void DomAgentImpl::SetDocument(Document* doc) { - if (doc == GetMainFrameDocument()) { - return; - } - - ListHashSet<RefPtr<Document> > copy = documents_; - for (ListHashSet<RefPtr<Document> >::iterator it = copy.begin(); - it != copy.end(); ++it) { - StopListening((*it).get()); - } - ASSERT(documents_.size() == 0); - - if (doc) { - StartListening(doc); - if (document_element_requested_) { - GetDocumentElement(); - document_element_requested_ = false; - } - } else { - DiscardBindings(); - } -} - -void DomAgentImpl::StartListening(Document* doc) { - if (documents_.contains(doc)) { - return; - } - doc->addEventListener(eventNames().DOMContentLoadedEvent, event_listener_, - false); - doc->addEventListener(eventNames().DOMNodeInsertedEvent, event_listener_, - false); - doc->addEventListener(eventNames().DOMNodeRemovedEvent, event_listener_, - false); - doc->addEventListener(eventNames().DOMNodeRemovedFromDocumentEvent, - event_listener_, true); - doc->addEventListener(eventNames().DOMAttrModifiedEvent, event_listener_, - false); - documents_.add(doc); -} - -void DomAgentImpl::StopListening(Document* doc) { - if (!documents_.contains(doc)) { - return; - } - doc->removeEventListener(eventNames().DOMContentLoadedEvent, - event_listener_.get(), false); - doc->removeEventListener(eventNames().DOMNodeInsertedEvent, - event_listener_.get(), false); - doc->removeEventListener(eventNames().DOMNodeRemovedEvent, - event_listener_.get(), false); - doc->removeEventListener(eventNames().DOMNodeRemovedFromDocumentEvent, - event_listener_.get(), true); - doc->removeEventListener(eventNames().DOMAttrModifiedEvent, - event_listener_.get(), false); - documents_.remove(doc); -} - -int DomAgentImpl::Bind(Node* node) { - HashMap<Node*, int>::iterator it = node_to_id_.find(node); - if (it != node_to_id_.end()) - return it->second; - int id = last_node_id_++; - node_to_id_.set(node, id); - id_to_node_.set(id, node); - return id; -} - -void DomAgentImpl::Unbind(Node* node) { - if (node->isFrameOwnerElement()) { - const HTMLFrameOwnerElement* frame_owner = - static_cast<const HTMLFrameOwnerElement*>(node); - StopListening(frame_owner->contentDocument()); - } - - HashMap<Node*, int>::iterator it = node_to_id_.find(node); - if (it != node_to_id_.end()) { - id_to_node_.remove(id_to_node_.find(it->second)); - children_requested_.remove(children_requested_.find(it->second)); - node_to_id_.remove(it); - } -} - -void DomAgentImpl::PushDocumentElementToClient() { - Element* doc_elem = GetMainFrameDocument()->documentElement(); - if (!node_to_id_.contains(doc_elem)) { - OwnPtr<Value> value(BuildValueForNode(doc_elem, 0)); - delegate_->SetDocumentElement(*value.get()); - } -} - -void DomAgentImpl::PushChildNodesToClient(int element_id) { - Node* node = GetNodeForId(element_id); - if (!node || (node->nodeType() != Node::ELEMENT_NODE)) - return; - if (children_requested_.contains(element_id)) - return; - - Element* element = static_cast<Element*>(node); - OwnPtr<Value> children(BuildValueForElementChildren(element, 1)); - children_requested_.add(element_id); - delegate_->SetChildNodes(element_id, *children.get()); -} - -void DomAgentImpl::DiscardBindings() { - node_to_id_.clear(); - id_to_node_.clear(); - children_requested_.clear(); -} - -Node* DomAgentImpl::GetNodeForId(int id) { - HashMap<int, Node*>::iterator it = id_to_node_.find(id); - if (it != id_to_node_.end()) { - return it->second; - } - return NULL; -} - -int DomAgentImpl::GetIdForNode(Node* node) { - if (node == NULL) { - return 0; - } - HashMap<Node*, int>::iterator it = node_to_id_.find(node); - if (it != node_to_id_.end()) { - return it->second; - } - return 0; -} - -void DomAgentImpl::handleEvent(Event* event, bool isWindowEvent) { - AtomicString type = event->type(); - Node* node = event->target()->toNode(); - - // Remove mapping entry if necessary. - if (type == eventNames().DOMNodeRemovedFromDocumentEvent) { - Unbind(node); - return; - } - - if (type == eventNames().DOMAttrModifiedEvent) { - int id = GetIdForNode(node); - if (!id) { - // Node is not mapped yet -> ignore the event. - return; - } - Element* element = static_cast<Element*>(node); - OwnPtr<Value> attributesValue(BuildValueForElementAttributes(element)); - delegate_->AttributesUpdated(id, *attributesValue.get()); - } else if (type == eventNames().DOMNodeInsertedEvent) { - if (IsWhitespace(node)) { - return; - } - Node* parent = static_cast<MutationEvent*>(event)->relatedNode(); - int parent_id = GetIdForNode(parent); - if (!parent_id) { - // Parent is not mapped yet -> ignore the event. - return; - } - if (!children_requested_.contains(parent_id)) { - // No children are mapped yet -> only notify on changes of hasChildren. - delegate_->HasChildrenUpdated(parent_id, true); - } else { - // Children have been requested -> return value of a new child. - int prev_id = GetIdForNode(InnerPreviousSibling(node)); - OwnPtr<Value> value(BuildValueForNode(node, 0)); - delegate_->ChildNodeInserted(parent_id, prev_id, *value.get()); - } - } else if (type == eventNames().DOMNodeRemovedEvent) { - if (IsWhitespace(node)) { - return; - } - Node* parent = static_cast<MutationEvent*>(event)->relatedNode(); - int parent_id = GetIdForNode(parent); - if (!parent_id) { - // Parent is not mapped yet -> ignore the event. - return; - } - if (!children_requested_.contains(parent_id)) { - // No children are mapped yet -> only notify on changes of hasChildren. - if (InnerChildNodeCount(parent) == 1) - delegate_->HasChildrenUpdated(parent_id, false); - } else { - int id = GetIdForNode(node); - delegate_->ChildNodeRemoved(parent_id, id); - } - } else if (type == eventNames().DOMContentLoadedEvent) { - // Re-push document once it is loaded. - DiscardBindings(); - PushDocumentElementToClient(); - } -} - -void DomAgentImpl::GetDocumentElement() { - Document* main_document = GetMainFrameDocument(); - if (main_document) { - PushDocumentElementToClient(); - } else { - document_element_requested_ = true; - } -} - -void DomAgentImpl::GetChildNodes(int call_id, int element_id) { - PushChildNodesToClient(element_id); - delegate_->DidGetChildNodes(call_id); -} - -int DomAgentImpl::PushNodePathToClient(Node* node_to_select) { - ASSERT(node_to_select); // Invalid input - - // If we are sending information to the client that is currently being - // created. Send root node first. - PushDocumentElementToClient(); - - // Return id in case the node is known. - int result = GetIdForNode(node_to_select); - if (result) - return result; - - Element* element = InnerParentElement(node_to_select); - ASSERT(element); // Node is detached or is a document itself - - Vector<Element*> path; - while (element && !GetIdForNode(element)) { - path.append(element); - element = InnerParentElement(element); - } - // element is known to the client - ASSERT(element); - path.append(element); - for (int i = path.size() - 1; i >= 0; --i) { - int node_id = GetIdForNode(path.at(i)); - ASSERT(node_id); - PushChildNodesToClient(node_id); - } - return GetIdForNode(node_to_select); -} - -void DomAgentImpl::SetAttribute( - int call_id, - int element_id, - const String& name, - const String& value) { - Node* node = GetNodeForId(element_id); - if (node && (node->nodeType() == Node::ELEMENT_NODE)) { - Element* element = static_cast<Element*>(node); - ExceptionCode ec = 0; - element->setAttribute(name, value, ec); - delegate_->DidApplyDomChange(call_id, ec == 0); - } else { - delegate_->DidApplyDomChange(call_id, false); - } -} - -void DomAgentImpl::RemoveAttribute( - int call_id, - int element_id, - const String& name) { - Node* node = GetNodeForId(element_id); - if (node && (node->nodeType() == Node::ELEMENT_NODE)) { - Element* element = static_cast<Element*>(node); - ExceptionCode ec = 0; - element->removeAttribute(name, ec); - delegate_->DidApplyDomChange(call_id, ec == 0); - } else { - delegate_->DidApplyDomChange(call_id, false); - } -} - -void DomAgentImpl::SetTextNodeValue( - int call_id, - int element_id, - const String& value) { - Node* node = GetNodeForId(element_id); - if (node && (node->nodeType() == Node::TEXT_NODE)) { - Text* text_node = static_cast<Text*>(node); - ExceptionCode ec = 0; - // TODO(pfeldman): Add error handling - text_node->replaceWholeText(value, ec); - delegate_->DidApplyDomChange(call_id, ec == 0); - } else { - delegate_->DidApplyDomChange(call_id, false); - } -} - -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 = GetMainFrameDocument(); - 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); - String nodeName; - String nodeValue; - - switch (node->nodeType()) { - case Node::TEXT_NODE: - case Node::COMMENT_NODE: - nodeValue = node->nodeValue(); - break; - case Node::ATTRIBUTE_NODE: - case Node::DOCUMENT_NODE: - case Node::DOCUMENT_FRAGMENT_NODE: - break; - case Node::ELEMENT_NODE: - default: { - nodeName = node->nodeName(); - break; - } - } - - value->Append(Value::CreateIntegerValue(id)); - value->Append(Value::CreateIntegerValue(node->nodeType())); - value->Append(Value::CreateStringValue( - webkit_glue::StringToStdWString(nodeName))); - value->Append(Value::CreateStringValue( - webkit_glue::StringToStdWString(nodeValue))); - - if (node->nodeType() == Node::ELEMENT_NODE) { - Element* element = static_cast<Element*>(node); - value->Append(BuildValueForElementAttributes(element)); - int nodeCount = InnerChildNodeCount(element); - value->Append(Value::CreateIntegerValue(nodeCount)); - OwnPtr<ListValue> children(BuildValueForElementChildren(element, depth)); - if (children->GetSize() > 0) { - value->Append(children.release()); - } - } - return value.release(); -} - -ListValue* DomAgentImpl::BuildValueForElementAttributes(Element* element) { - OwnPtr<ListValue> attributes_value(new ListValue()); - // Go through all attributes and serialize them. - const NamedNodeMap* attr_map = element->attributes(true); - if (!attr_map) { - return attributes_value.release(); - } - unsigned num_attrs = attr_map->length(); - for (unsigned i = 0; i < num_attrs; ++i) { - // Add attribute pair - const Attribute *attribute = attr_map->attributeItem(i); - OwnPtr<Value> name(Value::CreateStringValue( - webkit_glue::StringToStdWString(attribute->name().toString()))); - OwnPtr<Value> value(Value::CreateStringValue( - webkit_glue::StringToStdWString(attribute->value()))); - attributes_value->Append(name.release()); - attributes_value->Append(value.release()); - } - return attributes_value.release(); -} - -ListValue* DomAgentImpl::BuildValueForElementChildren( - Element* element, - int depth) { - OwnPtr<ListValue> children(new ListValue()); - if (depth == 0) { - // Special case the_only text child. - if (InnerChildNodeCount(element) == 1) { - Node *child = InnerFirstChild(element); - if (child->nodeType() == Node::TEXT_NODE) { - children->Append(BuildValueForNode(child, 0)); - } - } - return children.release(); - } else if (depth > 0) { - depth--; - } - - for (Node *child = InnerFirstChild(element); child != NULL; - child = InnerNextSibling(child)) { - children->Append(BuildValueForNode(child, depth)); - } - return children.release(); -} - -Node* DomAgentImpl::InnerFirstChild(Node* node) { - if (node->isFrameOwnerElement()) { - HTMLFrameOwnerElement* frame_owner = - static_cast<HTMLFrameOwnerElement*>(node); - Document* doc = frame_owner->contentDocument(); - if (doc) { - StartListening(doc); - return doc->firstChild(); - } - } - node = node->firstChild(); - while (IsWhitespace(node)) { - node = node->nextSibling(); - } - return node; -} - -Node* DomAgentImpl::InnerNextSibling(Node* node) { - do { - node = node->nextSibling(); - } while (IsWhitespace(node)); - return node; -} - -Node* DomAgentImpl::InnerPreviousSibling(Node* node) { - do { - node = node->previousSibling(); - } while (IsWhitespace(node)); - return node; -} - -int DomAgentImpl::InnerChildNodeCount(Node* node) { - int count = 0; - Node* child = InnerFirstChild(node); - while (child) { - count++; - child = InnerNextSibling(child); - } - return count; -} - -Element* DomAgentImpl::InnerParentElement(Node* node) { - Element* element = node->parentElement(); - if (!element) { - return node->ownerDocument()->ownerElement(); - } - return element; -} - -bool DomAgentImpl::IsWhitespace(Node* node) { - return node != NULL && node->nodeType() == Node::TEXT_NODE && - node->nodeValue().stripWhiteSpace().length() == 0; -} - -Document* DomAgentImpl::GetMainFrameDocument() { - ListHashSet<RefPtr<WebCore::Document> >::iterator it = documents_.begin(); - if (it != documents_.end()) { - return it->get(); - } - return NULL; -} |