1/*
2 * Copyright (C) 2009 Apple Inc. All rights reserved.
3 * Copyright (C) 2011 Google Inc. All rights reserved.
4 * Copyright (C) 2009 Joseph Pecoraro
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1.  Redistributions of source code must retain the above copyright
11 *     notice, this list of conditions and the following disclaimer.
12 * 2.  Redistributions in binary form must reproduce the above copyright
13 *     notice, this list of conditions and the following disclaimer in the
14 *     documentation and/or other materials provided with the distribution.
15 * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
16 *     its contributors may be used to endorse or promote products derived
17 *     from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include "config.h"
32#include "InspectorDOMAgent.h"
33
34#if ENABLE(INSPECTOR)
35
36#include "Attr.h"
37#include "CSSComputedStyleDeclaration.h"
38#include "CSSMutableStyleDeclaration.h"
39#include "CSSPropertyNames.h"
40#include "CSSPropertySourceData.h"
41#include "CSSRule.h"
42#include "CSSRuleList.h"
43#include "CSSStyleRule.h"
44#include "CSSStyleSelector.h"
45#include "CSSStyleSheet.h"
46#include "CharacterData.h"
47#include "ContainerNode.h"
48#include "Cookie.h"
49#include "CookieJar.h"
50#include "DOMNodeHighlighter.h"
51#include "DOMWindow.h"
52#include "Document.h"
53#include "DocumentType.h"
54#include "Event.h"
55#include "EventContext.h"
56#include "EventListener.h"
57#include "EventNames.h"
58#include "EventTarget.h"
59#include "Frame.h"
60#include "FrameTree.h"
61#include "HitTestResult.h"
62#include "HTMLElement.h"
63#include "HTMLFrameOwnerElement.h"
64#include "InjectedScriptManager.h"
65#include "InspectorClient.h"
66#include "InspectorFrontend.h"
67#include "InspectorResourceAgent.h"
68#include "InspectorState.h"
69#include "InstrumentingAgents.h"
70#include "MutationEvent.h"
71#include "Node.h"
72#include "NodeList.h"
73#include "Page.h"
74#include "Pasteboard.h"
75#include "PlatformString.h"
76#include "RenderStyle.h"
77#include "RenderStyleConstants.h"
78#include "ScriptEventListener.h"
79#include "StyleSheetList.h"
80#include "Text.h"
81
82#if ENABLE(XPATH)
83#include "XPathResult.h"
84#endif
85
86#include "markup.h"
87
88#include <wtf/text/CString.h>
89#include <wtf/text/StringConcatenate.h>
90#include <wtf/HashSet.h>
91#include <wtf/ListHashSet.h>
92#include <wtf/OwnPtr.h>
93#include <wtf/Vector.h>
94#include <wtf/text/AtomicString.h>
95
96namespace WebCore {
97
98namespace DOMAgentState {
99static const char documentRequested[] = "documentRequested";
100};
101
102class MatchJob {
103public:
104    virtual void match(ListHashSet<Node*>& resultCollector) = 0;
105    virtual ~MatchJob() { }
106
107protected:
108    MatchJob(Document* document, const String& query)
109        : m_document(document)
110        , m_query(query) { }
111
112    void addNodesToResults(PassRefPtr<NodeList> nodes, ListHashSet<Node*>& resultCollector)
113    {
114        for (unsigned i = 0; nodes && i < nodes->length(); ++i)
115            resultCollector.add(nodes->item(i));
116    }
117
118    RefPtr<Document> m_document;
119    String m_query;
120};
121
122class RevalidateStyleAttributeTask {
123public:
124    RevalidateStyleAttributeTask(InspectorDOMAgent*);
125    void scheduleFor(Element*);
126    void reset() { m_timer.stop(); }
127    void onTimer(Timer<RevalidateStyleAttributeTask>*);
128
129private:
130    InspectorDOMAgent* m_domAgent;
131    Timer<RevalidateStyleAttributeTask> m_timer;
132    HashSet<RefPtr<Element> > m_elements;
133};
134
135namespace {
136
137class MatchExactIdJob : public WebCore::MatchJob {
138public:
139    MatchExactIdJob(Document* document, const String& query) : WebCore::MatchJob(document, query) { }
140    virtual ~MatchExactIdJob() { }
141
142protected:
143    virtual void match(ListHashSet<Node*>& resultCollector)
144    {
145        if (m_query.isEmpty())
146            return;
147
148        Element* element = m_document->getElementById(m_query);
149        if (element)
150            resultCollector.add(element);
151    }
152};
153
154class MatchExactClassNamesJob : public WebCore::MatchJob {
155public:
156    MatchExactClassNamesJob(Document* document, const String& query) : WebCore::MatchJob(document, query) { }
157    virtual ~MatchExactClassNamesJob() { }
158
159    virtual void match(ListHashSet<Node*>& resultCollector)
160    {
161        if (!m_query.isEmpty())
162            addNodesToResults(m_document->getElementsByClassName(m_query), resultCollector);
163    }
164};
165
166class MatchExactTagNamesJob : public WebCore::MatchJob {
167public:
168    MatchExactTagNamesJob(Document* document, const String& query) : WebCore::MatchJob(document, query) { }
169    virtual ~MatchExactTagNamesJob() { }
170
171    virtual void match(ListHashSet<Node*>& resultCollector)
172    {
173        if (!m_query.isEmpty())
174            addNodesToResults(m_document->getElementsByName(m_query), resultCollector);
175    }
176};
177
178class MatchQuerySelectorAllJob : public WebCore::MatchJob {
179public:
180    MatchQuerySelectorAllJob(Document* document, const String& query) : WebCore::MatchJob(document, query) { }
181    virtual ~MatchQuerySelectorAllJob() { }
182
183    virtual void match(ListHashSet<Node*>& resultCollector)
184    {
185        if (m_query.isEmpty())
186            return;
187
188        ExceptionCode ec = 0;
189        RefPtr<NodeList> list = m_document->querySelectorAll(m_query, ec);
190        if (!ec)
191            addNodesToResults(list, resultCollector);
192    }
193};
194
195class MatchXPathJob : public WebCore::MatchJob {
196public:
197    MatchXPathJob(Document* document, const String& query) : WebCore::MatchJob(document, query) { }
198    virtual ~MatchXPathJob() { }
199
200    virtual void match(ListHashSet<Node*>& resultCollector)
201    {
202#if ENABLE(XPATH)
203        if (m_query.isEmpty())
204            return;
205
206        ExceptionCode ec = 0;
207        RefPtr<XPathResult> result = m_document->evaluate(m_query, m_document.get(), 0, XPathResult::ORDERED_NODE_SNAPSHOT_TYPE, 0, ec);
208        if (ec || !result)
209            return;
210
211        unsigned long size = result->snapshotLength(ec);
212        for (unsigned long i = 0; !ec && i < size; ++i) {
213            Node* node = result->snapshotItem(i, ec);
214            if (ec)
215                break;
216
217            if (node->nodeType() == Node::ATTRIBUTE_NODE)
218                node = static_cast<Attr*>(node)->ownerElement();
219            resultCollector.add(node);
220        }
221#else
222        UNUSED_PARAM(resultCollector);
223#endif
224    }
225};
226
227class MatchPlainTextJob : public MatchXPathJob {
228public:
229    MatchPlainTextJob(Document* document, const String& query) : MatchXPathJob(document, query)
230    {
231        m_query = "//text()[contains(., '" + m_query + "')] | //comment()[contains(., '" + m_query + "')]";
232    }
233    virtual ~MatchPlainTextJob() { }
234};
235
236}
237
238RevalidateStyleAttributeTask::RevalidateStyleAttributeTask(InspectorDOMAgent* domAgent)
239    : m_domAgent(domAgent)
240    , m_timer(this, &RevalidateStyleAttributeTask::onTimer)
241{
242}
243
244void RevalidateStyleAttributeTask::scheduleFor(Element* element)
245{
246    m_elements.add(element);
247    if (!m_timer.isActive())
248        m_timer.startOneShot(0);
249}
250
251void RevalidateStyleAttributeTask::onTimer(Timer<RevalidateStyleAttributeTask>*)
252{
253    // The timer is stopped on m_domAgent destruction, so this method will never be called after m_domAgent has been destroyed.
254    for (HashSet<RefPtr<Element> >::iterator it = m_elements.begin(), end = m_elements.end(); it != end; ++it)
255        m_domAgent->didModifyDOMAttr(it->get());
256
257    m_elements.clear();
258}
259
260InspectorDOMAgent::InspectorDOMAgent(InstrumentingAgents* instrumentingAgents, Page* inspectedPage, InspectorClient* client, InspectorState* inspectorState, InjectedScriptManager* injectedScriptManager)
261    : m_instrumentingAgents(instrumentingAgents)
262    , m_inspectedPage(inspectedPage)
263    , m_client(client)
264    , m_inspectorState(inspectorState)
265    , m_injectedScriptManager(injectedScriptManager)
266    , m_frontend(0)
267    , m_domListener(0)
268    , m_lastNodeId(1)
269    , m_matchJobsTimer(this, &InspectorDOMAgent::onMatchJobsTimer)
270    , m_searchingForNode(false)
271{
272}
273
274InspectorDOMAgent::~InspectorDOMAgent()
275{
276    reset();
277    ASSERT(!m_highlightedNode);
278    ASSERT(!m_searchingForNode);
279}
280
281void InspectorDOMAgent::setFrontend(InspectorFrontend* frontend)
282{
283    ASSERT(!m_frontend);
284    m_frontend = frontend->dom();
285    m_instrumentingAgents->setInspectorDOMAgent(this);
286    m_document = m_inspectedPage->mainFrame()->document();
287
288    if (m_nodeToFocus)
289        focusNode();
290}
291
292void InspectorDOMAgent::clearFrontend()
293{
294    ASSERT(m_frontend);
295    setSearchingForNode(false);
296
297    ErrorString error;
298    hideHighlight(&error);
299
300    m_frontend = 0;
301    m_instrumentingAgents->setInspectorDOMAgent(0);
302    m_inspectorState->setBoolean(DOMAgentState::documentRequested, false);
303    reset();
304}
305
306void InspectorDOMAgent::restore()
307{
308    // Reset document to avoid early return from setDocument.
309    m_document = 0;
310    setDocument(m_inspectedPage->mainFrame()->document());
311}
312
313Vector<Document*> InspectorDOMAgent::documents()
314{
315    Vector<Document*> result;
316    for (Frame* frame = m_document->frame(); frame; frame = frame->tree()->traverseNext()) {
317        Document* document = frame->document();
318        if (!document)
319            continue;
320        result.append(document);
321    }
322    return result;
323}
324
325void InspectorDOMAgent::reset()
326{
327    ErrorString error;
328    cancelSearch(&error);
329    discardBindings();
330    if (m_revalidateStyleAttrTask)
331        m_revalidateStyleAttrTask->reset();
332    m_document = 0;
333}
334
335void InspectorDOMAgent::setDOMListener(DOMListener* listener)
336{
337    m_domListener = listener;
338}
339
340void InspectorDOMAgent::setDocument(Document* doc)
341{
342    if (doc == m_document.get())
343        return;
344
345    reset();
346
347    m_document = doc;
348
349    if (!m_inspectorState->getBoolean(DOMAgentState::documentRequested))
350        return;
351
352    // Immediately communicate 0 document or document that has finished loading.
353    if (!doc || !doc->parsing())
354        m_frontend->documentUpdated();
355}
356
357void InspectorDOMAgent::releaseDanglingNodes()
358{
359    deleteAllValues(m_danglingNodeToIdMaps);
360    m_danglingNodeToIdMaps.clear();
361}
362
363int InspectorDOMAgent::bind(Node* node, NodeToIdMap* nodesMap)
364{
365    int id = nodesMap->get(node);
366    if (id)
367        return id;
368    id = m_lastNodeId++;
369    nodesMap->set(node, id);
370    m_idToNode.set(id, node);
371    m_idToNodesMap.set(id, nodesMap);
372    return id;
373}
374
375void InspectorDOMAgent::unbind(Node* node, NodeToIdMap* nodesMap)
376{
377    if (node->isFrameOwnerElement()) {
378        const HTMLFrameOwnerElement* frameOwner = static_cast<const HTMLFrameOwnerElement*>(node);
379        if (m_domListener)
380            m_domListener->didRemoveDocument(frameOwner->contentDocument());
381    }
382
383    int id = nodesMap->get(node);
384    if (!id)
385        return;
386    m_idToNode.remove(id);
387    nodesMap->remove(node);
388    bool childrenRequested = m_childrenRequested.contains(id);
389    if (childrenRequested) {
390        // Unbind subtree known to client recursively.
391        m_childrenRequested.remove(id);
392        Node* child = innerFirstChild(node);
393        while (child) {
394            unbind(child, nodesMap);
395            child = innerNextSibling(child);
396        }
397    }
398}
399
400Node* InspectorDOMAgent::assertNode(ErrorString* errorString, int nodeId)
401{
402    Node* node = nodeForId(nodeId);
403    if (!node) {
404        *errorString = "Could not find node with given id";
405        return 0;
406    }
407    return node;
408}
409
410Element* InspectorDOMAgent::assertElement(ErrorString* errorString, int nodeId)
411{
412    Node* node = assertNode(errorString, nodeId);
413    if (!node)
414        return 0;
415
416    if (node->nodeType() != Node::ELEMENT_NODE) {
417        *errorString = "Node is not an Element";
418        return 0;
419    }
420    return toElement(node);
421}
422
423
424HTMLElement* InspectorDOMAgent::assertHTMLElement(ErrorString* errorString, int nodeId)
425{
426    Element* element = assertElement(errorString, nodeId);
427    if (!element)
428        return 0;
429
430    if (!element->isHTMLElement()) {
431        *errorString = "Node is not an HTML Element";
432        return 0;
433    }
434    return toHTMLElement(element);
435}
436
437void InspectorDOMAgent::getDocument(ErrorString*, RefPtr<InspectorObject>* root)
438{
439    m_inspectorState->setBoolean(DOMAgentState::documentRequested, true);
440
441    if (!m_document)
442        return;
443
444    // Reset backend state.
445    RefPtr<Document> doc = m_document;
446    reset();
447    m_document = doc;
448
449    *root = buildObjectForNode(m_document.get(), 2, &m_documentNodeToIdMap);
450}
451
452void InspectorDOMAgent::pushChildNodesToFrontend(int nodeId)
453{
454    Node* node = nodeForId(nodeId);
455    if (!node || (node->nodeType() != Node::ELEMENT_NODE && node->nodeType() != Node::DOCUMENT_NODE && node->nodeType() != Node::DOCUMENT_FRAGMENT_NODE))
456        return;
457    if (m_childrenRequested.contains(nodeId))
458        return;
459
460    NodeToIdMap* nodeMap = m_idToNodesMap.get(nodeId);
461    RefPtr<InspectorArray> children = buildArrayForContainerChildren(node, 1, nodeMap);
462    m_frontend->setChildNodes(nodeId, children.release());
463}
464
465void InspectorDOMAgent::discardBindings()
466{
467    m_documentNodeToIdMap.clear();
468    m_idToNode.clear();
469    releaseDanglingNodes();
470    m_childrenRequested.clear();
471}
472
473Node* InspectorDOMAgent::nodeForId(int id)
474{
475    if (!id)
476        return 0;
477
478    HashMap<int, Node*>::iterator it = m_idToNode.find(id);
479    if (it != m_idToNode.end())
480        return it->second;
481    return 0;
482}
483
484void InspectorDOMAgent::getChildNodes(ErrorString*, int nodeId)
485{
486    pushChildNodesToFrontend(nodeId);
487}
488
489void InspectorDOMAgent::querySelector(ErrorString* errorString, int nodeId, const String& selectors, int* elementId)
490{
491    *elementId = 0;
492    Node* node = assertNode(errorString, nodeId);
493    if (!node)
494        return;
495
496    ExceptionCode ec = 0;
497    RefPtr<Element> element = node->querySelector(selectors, ec);
498    if (ec) {
499        *errorString = "DOM Error while querying";
500        return;
501    }
502
503    if (element)
504        *elementId = pushNodePathToFrontend(element.get());
505}
506
507void InspectorDOMAgent::querySelectorAll(ErrorString* errorString, int nodeId, const String& selectors, RefPtr<InspectorArray>* result)
508{
509    Node* node = assertNode(errorString, nodeId);
510    if (!node)
511        return;
512
513    ExceptionCode ec = 0;
514    RefPtr<NodeList> nodes = node->querySelectorAll(selectors, ec);
515    if (ec) {
516        *errorString = "DOM Error while querying";
517        return;
518    }
519
520    for (unsigned i = 0; i < nodes->length(); ++i)
521        (*result)->pushNumber(pushNodePathToFrontend(nodes->item(i)));
522}
523
524int InspectorDOMAgent::pushNodePathToFrontend(Node* nodeToPush)
525{
526    ASSERT(nodeToPush);  // Invalid input
527
528    if (!m_document)
529        return 0;
530    if (!m_documentNodeToIdMap.contains(m_document))
531        return 0;
532
533    // Return id in case the node is known.
534    int result = m_documentNodeToIdMap.get(nodeToPush);
535    if (result)
536        return result;
537
538    Node* node = nodeToPush;
539    Vector<Node*> path;
540    NodeToIdMap* danglingMap = 0;
541
542    while (true) {
543        Node* parent = innerParentNode(node);
544        if (!parent) {
545            // Node being pushed is detached -> push subtree root.
546            danglingMap = new NodeToIdMap();
547            m_danglingNodeToIdMaps.append(danglingMap);
548            RefPtr<InspectorArray> children = InspectorArray::create();
549            children->pushObject(buildObjectForNode(node, 0, danglingMap));
550            m_frontend->setChildNodes(0, children);
551            break;
552        } else {
553            path.append(parent);
554            if (m_documentNodeToIdMap.get(parent))
555                break;
556            else
557                node = parent;
558        }
559    }
560
561    NodeToIdMap* map = danglingMap ? danglingMap : &m_documentNodeToIdMap;
562    for (int i = path.size() - 1; i >= 0; --i) {
563        int nodeId = map->get(path.at(i));
564        ASSERT(nodeId);
565        pushChildNodesToFrontend(nodeId);
566    }
567    return map->get(nodeToPush);
568}
569
570int InspectorDOMAgent::boundNodeId(Node* node)
571{
572    return m_documentNodeToIdMap.get(node);
573}
574
575void InspectorDOMAgent::setAttribute(ErrorString* errorString, int elementId, const String& name, const String& value)
576{
577    Element* element = assertElement(errorString, elementId);
578    if (element) {
579        ExceptionCode ec = 0;
580        element->setAttribute(name, value, ec);
581        if (ec)
582            *errorString = "Exception while setting attribute value";
583    }
584}
585
586void InspectorDOMAgent::removeAttribute(ErrorString* errorString, int elementId, const String& name)
587{
588    Element* element = assertElement(errorString, elementId);
589    if (element) {
590        ExceptionCode ec = 0;
591        element->removeAttribute(name, ec);
592        if (ec)
593            *errorString = "Exception while removing attribute";
594    }
595}
596
597void InspectorDOMAgent::removeNode(ErrorString* errorString, int nodeId)
598{
599    Node* node = assertNode(errorString, nodeId);
600    if (!node)
601        return;
602
603    ContainerNode* parentNode = node->parentNode();
604    if (!parentNode) {
605        *errorString = "Can not remove detached node";
606        return;
607    }
608
609    ExceptionCode ec = 0;
610    parentNode->removeChild(node, ec);
611    if (ec)
612        *errorString = "Could not remove node due to DOM exception";
613}
614
615void InspectorDOMAgent::setNodeName(ErrorString*, int nodeId, const String& tagName, int* newId)
616{
617    *newId = 0;
618
619    Node* oldNode = nodeForId(nodeId);
620    if (!oldNode || !oldNode->isElementNode())
621        return;
622
623    ExceptionCode ec = 0;
624    RefPtr<Element> newElem = oldNode->document()->createElement(tagName, ec);
625    if (ec)
626        return;
627
628    // Copy over the original node's attributes.
629    Element* oldElem = static_cast<Element*>(oldNode);
630    newElem->copyNonAttributeProperties(oldElem);
631    if (oldElem->attributes())
632        newElem->attributes()->setAttributes(*(oldElem->attributes(true)));
633
634    // Copy over the original node's children.
635    Node* child;
636    while ((child = oldNode->firstChild()))
637        newElem->appendChild(child, ec);
638
639    // Replace the old node with the new node
640    ContainerNode* parent = oldNode->parentNode();
641    parent->insertBefore(newElem, oldNode->nextSibling(), ec);
642    parent->removeChild(oldNode, ec);
643
644    if (ec)
645        return;
646
647    *newId = pushNodePathToFrontend(newElem.get());
648    if (m_childrenRequested.contains(nodeId))
649        pushChildNodesToFrontend(*newId);
650}
651
652void InspectorDOMAgent::getOuterHTML(ErrorString* errorString, int nodeId, WTF::String* outerHTML)
653{
654    HTMLElement* element = assertHTMLElement(errorString, nodeId);
655    if (element)
656        *outerHTML = element->outerHTML();
657}
658
659void InspectorDOMAgent::setOuterHTML(ErrorString* errorString, int nodeId, const String& outerHTML, int* newId)
660{
661    HTMLElement* htmlElement = assertHTMLElement(errorString, nodeId);
662    if (!htmlElement)
663        return;
664
665    bool requiresTotalUpdate = htmlElement->tagName() == "HTML" || htmlElement->tagName() == "BODY" || htmlElement->tagName() == "HEAD";
666
667    bool childrenRequested = m_childrenRequested.contains(nodeId);
668    Node* previousSibling = htmlElement->previousSibling();
669    ContainerNode* parentNode = htmlElement->parentNode();
670
671    ExceptionCode ec = 0;
672    htmlElement->setOuterHTML(outerHTML, ec);
673    if (ec)
674        return;
675
676    if (requiresTotalUpdate) {
677        RefPtr<Document> document = m_document;
678        reset();
679        setDocument(document.get());
680        *newId = 0;
681        return;
682    }
683
684    Node* newNode = previousSibling ? previousSibling->nextSibling() : parentNode->firstChild();
685    if (!newNode) {
686        // The only child node has been deleted.
687        *newId = 0;
688        return;
689    }
690
691    *newId = pushNodePathToFrontend(newNode);
692    if (childrenRequested)
693        pushChildNodesToFrontend(*newId);
694}
695
696void InspectorDOMAgent::setNodeValue(ErrorString* errorString, int nodeId, const String& value)
697{
698    Node* node = assertNode(errorString, nodeId);
699    if (!node)
700        return;
701
702    if (node->nodeType() != Node::TEXT_NODE) {
703        *errorString = "Can only set value of text nodes";
704        return;
705    }
706
707    Text* textNode = static_cast<Text*>(node);
708    ExceptionCode ec = 0;
709    textNode->replaceWholeText(value, ec);
710    if (ec)
711        *errorString = "DOM Error while setting the node value";
712}
713
714void InspectorDOMAgent::getEventListenersForNode(ErrorString*, int nodeId, RefPtr<InspectorArray>* listenersArray)
715{
716    Node* node = nodeForId(nodeId);
717    EventTargetData* d;
718
719    // Quick break if a null node or no listeners at all
720    if (!node || !(d = node->eventTargetData()))
721        return;
722
723    // Get the list of event types this Node is concerned with
724    Vector<AtomicString> eventTypes;
725    const EventListenerMap& listenerMap = d->eventListenerMap;
726    EventListenerMap::const_iterator end = listenerMap.end();
727    for (EventListenerMap::const_iterator iter = listenerMap.begin(); iter != end; ++iter)
728        eventTypes.append(iter->first);
729
730    // Quick break if no useful listeners
731    size_t eventTypesLength = eventTypes.size();
732    if (!eventTypesLength)
733        return;
734
735    // The Node's Ancestors (not including self)
736    Vector<ContainerNode*> ancestors;
737    for (ContainerNode* ancestor = node->parentOrHostNode(); ancestor; ancestor = ancestor->parentOrHostNode())
738        ancestors.append(ancestor);
739
740    // Nodes and their Listeners for the concerned event types (order is top to bottom)
741    Vector<EventListenerInfo> eventInformation;
742    for (size_t i = ancestors.size(); i; --i) {
743        ContainerNode* ancestor = ancestors[i - 1];
744        for (size_t j = 0; j < eventTypesLength; ++j) {
745            AtomicString& type = eventTypes[j];
746            if (ancestor->hasEventListeners(type))
747                eventInformation.append(EventListenerInfo(ancestor, type, ancestor->getEventListeners(type)));
748        }
749    }
750
751    // Insert the Current Node at the end of that list (last in capturing, first in bubbling)
752    for (size_t i = 0; i < eventTypesLength; ++i) {
753        const AtomicString& type = eventTypes[i];
754        eventInformation.append(EventListenerInfo(node, type, node->getEventListeners(type)));
755    }
756
757    // Get Capturing Listeners (in this order)
758    size_t eventInformationLength = eventInformation.size();
759    for (size_t i = 0; i < eventInformationLength; ++i) {
760        const EventListenerInfo& info = eventInformation[i];
761        const EventListenerVector& vector = info.eventListenerVector;
762        for (size_t j = 0; j < vector.size(); ++j) {
763            const RegisteredEventListener& listener = vector[j];
764            if (listener.useCapture)
765                (*listenersArray)->pushObject(buildObjectForEventListener(listener, info.eventType, info.node));
766        }
767    }
768
769    // Get Bubbling Listeners (reverse order)
770    for (size_t i = eventInformationLength; i; --i) {
771        const EventListenerInfo& info = eventInformation[i - 1];
772        const EventListenerVector& vector = info.eventListenerVector;
773        for (size_t j = 0; j < vector.size(); ++j) {
774            const RegisteredEventListener& listener = vector[j];
775            if (!listener.useCapture)
776                (*listenersArray)->pushObject(buildObjectForEventListener(listener, info.eventType, info.node));
777        }
778    }
779}
780
781void InspectorDOMAgent::performSearch(ErrorString* error, const String& whitespaceTrimmedQuery, const bool* const runSynchronously)
782{
783    // FIXME: Few things are missing here:
784    // 1) Search works with node granularity - number of matches within node is not calculated.
785    // 2) There is no need to push all search results to the front-end at a time, pushing next / previous result
786    //    is sufficient.
787
788    unsigned queryLength = whitespaceTrimmedQuery.length();
789    bool startTagFound = !whitespaceTrimmedQuery.find('<');
790    bool endTagFound = whitespaceTrimmedQuery.reverseFind('>') + 1 == queryLength;
791
792    String tagNameQuery = whitespaceTrimmedQuery;
793    if (startTagFound || endTagFound)
794        tagNameQuery = tagNameQuery.substring(startTagFound ? 1 : 0, endTagFound ? queryLength - 1 : queryLength);
795    if (!Document::isValidName(tagNameQuery))
796        tagNameQuery = "";
797
798    String attributeNameQuery = whitespaceTrimmedQuery;
799    if (!Document::isValidName(attributeNameQuery))
800        attributeNameQuery = "";
801
802    String escapedQuery = whitespaceTrimmedQuery;
803    escapedQuery.replace("'", "\\'");
804    String escapedTagNameQuery = tagNameQuery;
805    escapedTagNameQuery.replace("'", "\\'");
806
807    // Clear pending jobs.
808    cancelSearch(error);
809
810    // Find all frames, iframes and object elements to search their documents.
811    Vector<Document*> docs = documents();
812    for (Vector<Document*>::iterator it = docs.begin(); it != docs.end(); ++it) {
813        Document* document = *it;
814
815        if (!tagNameQuery.isEmpty() && startTagFound && endTagFound) {
816            m_pendingMatchJobs.append(new MatchExactTagNamesJob(document, tagNameQuery));
817            m_pendingMatchJobs.append(new MatchPlainTextJob(document, escapedQuery));
818            continue;
819        }
820
821        if (!tagNameQuery.isEmpty() && startTagFound) {
822            m_pendingMatchJobs.append(new MatchXPathJob(document, "//*[starts-with(name(), '" + escapedTagNameQuery + "')]"));
823            m_pendingMatchJobs.append(new MatchPlainTextJob(document, escapedQuery));
824            continue;
825        }
826
827        if (!tagNameQuery.isEmpty() && endTagFound) {
828            // FIXME: we should have a matchEndOfTagNames search function if endTagFound is true but not startTagFound.
829            // This requires ends-with() support in XPath, WebKit only supports starts-with() and contains().
830            m_pendingMatchJobs.append(new MatchXPathJob(document, "//*[contains(name(), '" + escapedTagNameQuery + "')]"));
831            m_pendingMatchJobs.append(new MatchPlainTextJob(document, escapedQuery));
832            continue;
833        }
834
835        bool matchesEveryNode = whitespaceTrimmedQuery == "//*" || whitespaceTrimmedQuery == "*";
836        if (matchesEveryNode) {
837            // These queries will match every node. Matching everything isn't useful and can be slow for large pages,
838            // so limit the search functions list to plain text and attribute matching for these.
839            m_pendingMatchJobs.append(new MatchXPathJob(document, "//*[contains(@*, '" + escapedQuery + "')]"));
840            m_pendingMatchJobs.append(new MatchPlainTextJob(document, escapedQuery));
841            continue;
842        }
843
844        m_pendingMatchJobs.append(new MatchExactIdJob(document, whitespaceTrimmedQuery));
845        m_pendingMatchJobs.append(new MatchExactClassNamesJob(document, whitespaceTrimmedQuery));
846        m_pendingMatchJobs.append(new MatchExactTagNamesJob(document, tagNameQuery));
847        m_pendingMatchJobs.append(new MatchQuerySelectorAllJob(document, "[" + attributeNameQuery + "]"));
848        m_pendingMatchJobs.append(new MatchQuerySelectorAllJob(document, whitespaceTrimmedQuery));
849        m_pendingMatchJobs.append(new MatchXPathJob(document, "//*[contains(@*, '" + escapedQuery + "')]"));
850        if (!tagNameQuery.isEmpty())
851            m_pendingMatchJobs.append(new MatchXPathJob(document, "//*[contains(name(), '" + escapedTagNameQuery + "')]"));
852        m_pendingMatchJobs.append(new MatchPlainTextJob(document, escapedQuery));
853        m_pendingMatchJobs.append(new MatchXPathJob(document, whitespaceTrimmedQuery));
854    }
855
856    if (runSynchronously && *runSynchronously) {
857        // For tests.
858        ListHashSet<Node*> resultCollector;
859        for (Deque<MatchJob*>::iterator it = m_pendingMatchJobs.begin(); it != m_pendingMatchJobs.end(); ++it)
860            (*it)->match(resultCollector);
861        reportNodesAsSearchResults(resultCollector);
862        cancelSearch(error);
863        return;
864    }
865    m_matchJobsTimer.startOneShot(0);
866}
867
868void InspectorDOMAgent::cancelSearch(ErrorString*)
869{
870    if (m_matchJobsTimer.isActive())
871        m_matchJobsTimer.stop();
872    deleteAllValues(m_pendingMatchJobs);
873    m_pendingMatchJobs.clear();
874    m_searchResults.clear();
875}
876
877bool InspectorDOMAgent::handleMousePress()
878{
879    if (!m_searchingForNode)
880        return false;
881
882    if (m_highlightedNode) {
883        RefPtr<Node> node = m_highlightedNode;
884        setSearchingForNode(false);
885        inspect(node.get());
886    }
887    return true;
888}
889
890void InspectorDOMAgent::inspect(Node* node)
891{
892    if (node->nodeType() != Node::ELEMENT_NODE && node->nodeType() != Node::DOCUMENT_NODE)
893        node = node->parentNode();
894    m_nodeToFocus = node;
895
896    focusNode();
897}
898
899void InspectorDOMAgent::focusNode()
900{
901    if (!m_frontend)
902        return;
903
904    ASSERT(m_nodeToFocus);
905
906    RefPtr<Node> node = m_nodeToFocus.get();
907    m_nodeToFocus = 0;
908
909    Document* document = node->ownerDocument();
910    if (!document)
911        return;
912    Frame* frame = document->frame();
913    if (!frame)
914        return;
915
916    InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(mainWorldScriptState(frame));
917    if (injectedScript.hasNoValue())
918        return;
919
920    injectedScript.inspectNode(node.get());
921}
922
923void InspectorDOMAgent::mouseDidMoveOverElement(const HitTestResult& result, unsigned)
924{
925    if (!m_searchingForNode)
926        return;
927
928    Node* node = result.innerNode();
929    while (node && node->nodeType() == Node::TEXT_NODE)
930        node = node->parentNode();
931    if (node) {
932        ErrorString error;
933        highlight(&error, node);
934    }
935}
936
937void InspectorDOMAgent::setSearchingForNode(bool enabled)
938{
939    if (m_searchingForNode == enabled)
940        return;
941    m_searchingForNode = enabled;
942    if (!enabled) {
943        ErrorString error;
944        hideHighlight(&error);
945    }
946}
947
948void InspectorDOMAgent::setSearchingForNode(ErrorString*, bool enabled)
949{
950    setSearchingForNode(enabled);
951}
952
953void InspectorDOMAgent::highlight(ErrorString*, Node* node)
954{
955    ASSERT_ARG(node, node);
956    m_highlightedNode = node;
957    m_client->highlight(node);
958}
959
960void InspectorDOMAgent::highlightDOMNode(ErrorString* error, int nodeId)
961{
962    if (Node* node = nodeForId(nodeId))
963        highlight(error, node);
964}
965
966void InspectorDOMAgent::highlightFrame(ErrorString* error, const String& frameId)
967{
968    Frame* frame = m_instrumentingAgents->inspectorResourceAgent()->frameForId(frameId);
969    if (frame && frame->ownerElement())
970        highlight(error, frame->ownerElement());
971}
972
973void InspectorDOMAgent::hideHighlight(ErrorString*)
974{
975    m_highlightedNode = 0;
976    m_client->hideHighlight();
977}
978
979void InspectorDOMAgent::resolveNode(ErrorString* error, int nodeId, RefPtr<InspectorObject>* result)
980{
981    Node* node = nodeForId(nodeId);
982    if (!node) {
983        *error = "No node with given id found.";
984        return;
985    }
986    *result = resolveNode(node);
987}
988
989void InspectorDOMAgent::pushNodeToFrontend(ErrorString*, const String& objectId, int* nodeId)
990{
991    InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(objectId);
992    Node* node = injectedScript.nodeForObjectId(objectId);
993    if (node)
994        *nodeId = pushNodePathToFrontend(node);
995    else
996        *nodeId = 0;
997}
998
999String InspectorDOMAgent::documentURLString(Document* document) const
1000{
1001    if (!document || document->url().isNull())
1002        return "";
1003    return document->url().string();
1004}
1005
1006PassRefPtr<InspectorObject> InspectorDOMAgent::buildObjectForNode(Node* node, int depth, NodeToIdMap* nodesMap)
1007{
1008    RefPtr<InspectorObject> value = InspectorObject::create();
1009
1010    int id = bind(node, nodesMap);
1011    String nodeName;
1012    String localName;
1013    String nodeValue;
1014
1015    switch (node->nodeType()) {
1016        case Node::TEXT_NODE:
1017        case Node::COMMENT_NODE:
1018        case Node::CDATA_SECTION_NODE:
1019            nodeValue = node->nodeValue();
1020            break;
1021        case Node::ATTRIBUTE_NODE:
1022            localName = node->localName();
1023            break;
1024        case Node::DOCUMENT_FRAGMENT_NODE:
1025            break;
1026        case Node::DOCUMENT_NODE:
1027        case Node::ELEMENT_NODE:
1028        default:
1029            nodeName = node->nodeName();
1030            localName = node->localName();
1031            break;
1032    }
1033
1034    value->setNumber("id", id);
1035    value->setNumber("nodeType", node->nodeType());
1036    value->setString("nodeName", nodeName);
1037    value->setString("localName", localName);
1038    value->setString("nodeValue", nodeValue);
1039
1040    if (node->nodeType() == Node::ELEMENT_NODE || node->nodeType() == Node::DOCUMENT_NODE || node->nodeType() == Node::DOCUMENT_FRAGMENT_NODE) {
1041        int nodeCount = innerChildNodeCount(node);
1042        value->setNumber("childNodeCount", nodeCount);
1043        RefPtr<InspectorArray> children = buildArrayForContainerChildren(node, depth, nodesMap);
1044        if (children->length() > 0)
1045            value->setArray("children", children.release());
1046
1047        if (node->nodeType() == Node::ELEMENT_NODE) {
1048            Element* element = static_cast<Element*>(node);
1049            value->setArray("attributes", buildArrayForElementAttributes(element));
1050            if (node->isFrameOwnerElement()) {
1051                HTMLFrameOwnerElement* frameOwner = static_cast<HTMLFrameOwnerElement*>(node);
1052                value->setString("documentURL", documentURLString(frameOwner->contentDocument()));
1053            }
1054        } else if (node->nodeType() == Node::DOCUMENT_NODE) {
1055            Document* document = static_cast<Document*>(node);
1056            value->setString("documentURL", documentURLString(document));
1057        }
1058    } else if (node->nodeType() == Node::DOCUMENT_TYPE_NODE) {
1059        DocumentType* docType = static_cast<DocumentType*>(node);
1060        value->setString("publicId", docType->publicId());
1061        value->setString("systemId", docType->systemId());
1062        value->setString("internalSubset", docType->internalSubset());
1063    } else if (node->nodeType() == Node::ATTRIBUTE_NODE) {
1064        Attr* attribute = static_cast<Attr*>(node);
1065        value->setString("name", attribute->name());
1066        value->setString("value", attribute->value());
1067    }
1068    return value.release();
1069}
1070
1071PassRefPtr<InspectorArray> InspectorDOMAgent::buildArrayForElementAttributes(Element* element)
1072{
1073    RefPtr<InspectorArray> attributesValue = InspectorArray::create();
1074    // Go through all attributes and serialize them.
1075    const NamedNodeMap* attrMap = element->attributes(true);
1076    if (!attrMap)
1077        return attributesValue.release();
1078    unsigned numAttrs = attrMap->length();
1079    for (unsigned i = 0; i < numAttrs; ++i) {
1080        // Add attribute pair
1081        const Attribute *attribute = attrMap->attributeItem(i);
1082        attributesValue->pushString(attribute->name().toString());
1083        attributesValue->pushString(attribute->value());
1084    }
1085    return attributesValue.release();
1086}
1087
1088PassRefPtr<InspectorArray> InspectorDOMAgent::buildArrayForContainerChildren(Node* container, int depth, NodeToIdMap* nodesMap)
1089{
1090    RefPtr<InspectorArray> children = InspectorArray::create();
1091    Node* child = innerFirstChild(container);
1092
1093    if (depth == 0) {
1094        // Special-case the only text child - pretend that container's children have been requested.
1095        if (child && child->nodeType() == Node::TEXT_NODE && !innerNextSibling(child))
1096            return buildArrayForContainerChildren(container, 1, nodesMap);
1097        return children.release();
1098    }
1099
1100    depth--;
1101    m_childrenRequested.add(bind(container, nodesMap));
1102
1103    while (child) {
1104        children->pushObject(buildObjectForNode(child, depth, nodesMap));
1105        child = innerNextSibling(child);
1106    }
1107    return children.release();
1108}
1109
1110PassRefPtr<InspectorObject> InspectorDOMAgent::buildObjectForEventListener(const RegisteredEventListener& registeredEventListener, const AtomicString& eventType, Node* node)
1111{
1112    RefPtr<EventListener> eventListener = registeredEventListener.listener;
1113    RefPtr<InspectorObject> value = InspectorObject::create();
1114    value->setString("type", eventType);
1115    value->setBoolean("useCapture", registeredEventListener.useCapture);
1116    value->setBoolean("isAttribute", eventListener->isAttribute());
1117    value->setNumber("nodeId", pushNodePathToFrontend(node));
1118    value->setString("listenerBody", eventListenerHandlerBody(node->document(), eventListener.get()));
1119    String sourceName;
1120    int lineNumber;
1121    if (eventListenerHandlerLocation(node->document(), eventListener.get(), sourceName, lineNumber)) {
1122        value->setString("sourceName", sourceName);
1123        value->setNumber("lineNumber", lineNumber);
1124    }
1125    return value.release();
1126}
1127
1128Node* InspectorDOMAgent::innerFirstChild(Node* node)
1129{
1130    if (node->isFrameOwnerElement()) {
1131        HTMLFrameOwnerElement* frameOwner = static_cast<HTMLFrameOwnerElement*>(node);
1132        Document* doc = frameOwner->contentDocument();
1133        if (doc)
1134            return doc->firstChild();
1135    }
1136    node = node->firstChild();
1137    while (isWhitespace(node))
1138        node = node->nextSibling();
1139    return node;
1140}
1141
1142Node* InspectorDOMAgent::innerNextSibling(Node* node)
1143{
1144    do {
1145        node = node->nextSibling();
1146    } while (isWhitespace(node));
1147    return node;
1148}
1149
1150Node* InspectorDOMAgent::innerPreviousSibling(Node* node)
1151{
1152    do {
1153        node = node->previousSibling();
1154    } while (isWhitespace(node));
1155    return node;
1156}
1157
1158unsigned InspectorDOMAgent::innerChildNodeCount(Node* node)
1159{
1160    unsigned count = 0;
1161    Node* child = innerFirstChild(node);
1162    while (child) {
1163        count++;
1164        child = innerNextSibling(child);
1165    }
1166    return count;
1167}
1168
1169Node* InspectorDOMAgent::innerParentNode(Node* node)
1170{
1171    ContainerNode* parent = node->parentNode();
1172    if (parent && parent->isDocumentNode())
1173        return static_cast<Document*>(parent)->ownerElement();
1174    return parent;
1175}
1176
1177bool InspectorDOMAgent::isWhitespace(Node* node)
1178{
1179    //TODO: pull ignoreWhitespace setting from the frontend and use here.
1180    return node && node->nodeType() == Node::TEXT_NODE && node->nodeValue().stripWhiteSpace().length() == 0;
1181}
1182
1183void InspectorDOMAgent::mainFrameDOMContentLoaded()
1184{
1185    // Re-push document once it is loaded.
1186    discardBindings();
1187    if (m_inspectorState->getBoolean(DOMAgentState::documentRequested))
1188        m_frontend->documentUpdated();
1189}
1190
1191void InspectorDOMAgent::loadEventFired(Document* document)
1192{
1193    Element* frameOwner = document->ownerElement();
1194    if (!frameOwner)
1195        return;
1196
1197    int frameOwnerId = m_documentNodeToIdMap.get(frameOwner);
1198    if (!frameOwnerId)
1199        return;
1200
1201    if (!m_childrenRequested.contains(frameOwnerId)) {
1202        // No children are mapped yet -> only notify on changes of hasChildren.
1203        m_frontend->childNodeCountUpdated(frameOwnerId, innerChildNodeCount(frameOwner));
1204    } else {
1205        // Re-add frame owner element together with its new children.
1206        int parentId = m_documentNodeToIdMap.get(innerParentNode(frameOwner));
1207        m_frontend->childNodeRemoved(parentId, frameOwnerId);
1208        RefPtr<InspectorObject> value = buildObjectForNode(frameOwner, 0, &m_documentNodeToIdMap);
1209        Node* previousSibling = innerPreviousSibling(frameOwner);
1210        int prevId = previousSibling ? m_documentNodeToIdMap.get(previousSibling) : 0;
1211        m_frontend->childNodeInserted(parentId, prevId, value.release());
1212        // Invalidate children requested flag for the element.
1213        m_childrenRequested.remove(m_childrenRequested.find(frameOwnerId));
1214    }
1215}
1216
1217void InspectorDOMAgent::didInsertDOMNode(Node* node)
1218{
1219    if (isWhitespace(node))
1220        return;
1221
1222    // We could be attaching existing subtree. Forget the bindings.
1223    unbind(node, &m_documentNodeToIdMap);
1224
1225    ContainerNode* parent = node->parentNode();
1226    int parentId = m_documentNodeToIdMap.get(parent);
1227    // Return if parent is not mapped yet.
1228    if (!parentId)
1229        return;
1230
1231    if (!m_childrenRequested.contains(parentId)) {
1232        // No children are mapped yet -> only notify on changes of hasChildren.
1233        m_frontend->childNodeCountUpdated(parentId, innerChildNodeCount(parent));
1234    } else {
1235        // Children have been requested -> return value of a new child.
1236        Node* prevSibling = innerPreviousSibling(node);
1237        int prevId = prevSibling ? m_documentNodeToIdMap.get(prevSibling) : 0;
1238        RefPtr<InspectorObject> value = buildObjectForNode(node, 0, &m_documentNodeToIdMap);
1239        m_frontend->childNodeInserted(parentId, prevId, value.release());
1240    }
1241}
1242
1243void InspectorDOMAgent::didRemoveDOMNode(Node* node)
1244{
1245    if (isWhitespace(node))
1246        return;
1247
1248    ContainerNode* parent = node->parentNode();
1249    int parentId = m_documentNodeToIdMap.get(parent);
1250    // If parent is not mapped yet -> ignore the event.
1251    if (!parentId)
1252        return;
1253
1254    if (m_domListener)
1255        m_domListener->didRemoveDOMNode(node);
1256
1257    if (!m_childrenRequested.contains(parentId)) {
1258        // No children are mapped yet -> only notify on changes of hasChildren.
1259        if (innerChildNodeCount(parent) == 1)
1260            m_frontend->childNodeCountUpdated(parentId, 0);
1261    } else
1262        m_frontend->childNodeRemoved(parentId, m_documentNodeToIdMap.get(node));
1263    unbind(node, &m_documentNodeToIdMap);
1264}
1265
1266void InspectorDOMAgent::didModifyDOMAttr(Element* element)
1267{
1268    int id = m_documentNodeToIdMap.get(element);
1269    // If node is not mapped yet -> ignore the event.
1270    if (!id)
1271        return;
1272
1273    if (m_domListener)
1274        m_domListener->didModifyDOMAttr(element);
1275
1276    m_frontend->attributesUpdated(id, buildArrayForElementAttributes(element));
1277}
1278
1279void InspectorDOMAgent::characterDataModified(CharacterData* characterData)
1280{
1281    int id = m_documentNodeToIdMap.get(characterData);
1282    if (!id)
1283        return;
1284    m_frontend->characterDataModified(id, characterData->data());
1285}
1286
1287void InspectorDOMAgent::didInvalidateStyleAttr(Node* node)
1288{
1289    int id = m_documentNodeToIdMap.get(node);
1290    // If node is not mapped yet -> ignore the event.
1291    if (!id)
1292        return;
1293
1294    if (!m_revalidateStyleAttrTask)
1295        m_revalidateStyleAttrTask = new RevalidateStyleAttributeTask(this);
1296    m_revalidateStyleAttrTask->scheduleFor(static_cast<Element*>(node));
1297}
1298
1299Node* InspectorDOMAgent::nodeForPath(const String& path)
1300{
1301    // The path is of form "1,HTML,2,BODY,1,DIV"
1302    if (!m_document)
1303        return 0;
1304
1305    Node* node = m_document.get();
1306    Vector<String> pathTokens;
1307    path.split(",", false, pathTokens);
1308    if (!pathTokens.size())
1309        return 0;
1310    for (size_t i = 0; i < pathTokens.size() - 1; i += 2) {
1311        bool success = true;
1312        unsigned childNumber = pathTokens[i].toUInt(&success);
1313        if (!success)
1314            return 0;
1315        if (childNumber >= innerChildNodeCount(node))
1316            return 0;
1317
1318        Node* child = innerFirstChild(node);
1319        String childName = pathTokens[i + 1];
1320        for (size_t j = 0; child && j < childNumber; ++j)
1321            child = innerNextSibling(child);
1322
1323        if (!child || child->nodeName() != childName)
1324            return 0;
1325        node = child;
1326    }
1327    return node;
1328}
1329
1330PassRefPtr<InspectorArray> InspectorDOMAgent::toArray(const Vector<String>& data)
1331{
1332    RefPtr<InspectorArray> result = InspectorArray::create();
1333    for (unsigned i = 0; i < data.size(); ++i)
1334        result->pushString(data[i]);
1335    return result.release();
1336}
1337
1338void InspectorDOMAgent::onMatchJobsTimer(Timer<InspectorDOMAgent>*)
1339{
1340    if (!m_pendingMatchJobs.size()) {
1341        ErrorString error;
1342        cancelSearch(&error);
1343        return;
1344    }
1345
1346    ListHashSet<Node*> resultCollector;
1347    MatchJob* job = m_pendingMatchJobs.takeFirst();
1348    job->match(resultCollector);
1349    delete job;
1350
1351    reportNodesAsSearchResults(resultCollector);
1352
1353    m_matchJobsTimer.startOneShot(0.025);
1354}
1355
1356void InspectorDOMAgent::reportNodesAsSearchResults(ListHashSet<Node*>& resultCollector)
1357{
1358    RefPtr<InspectorArray> nodeIds = InspectorArray::create();
1359    for (ListHashSet<Node*>::iterator it = resultCollector.begin(); it != resultCollector.end(); ++it) {
1360        if (m_searchResults.contains(*it))
1361            continue;
1362        m_searchResults.add(*it);
1363        nodeIds->pushNumber(pushNodePathToFrontend(*it));
1364    }
1365    m_frontend->searchResults(nodeIds.release());
1366}
1367
1368void InspectorDOMAgent::copyNode(ErrorString*, int nodeId)
1369{
1370    Node* node = nodeForId(nodeId);
1371    if (!node)
1372        return;
1373    String markup = createMarkup(node);
1374    Pasteboard::generalPasteboard()->writePlainText(markup);
1375}
1376
1377void InspectorDOMAgent::pushNodeByPathToFrontend(ErrorString*, const String& path, int* nodeId)
1378{
1379    if (Node* node = nodeForPath(path))
1380        *nodeId = pushNodePathToFrontend(node);
1381}
1382
1383PassRefPtr<InspectorObject> InspectorDOMAgent::resolveNode(Node* node)
1384{
1385    Document* document = node->ownerDocument();
1386    Frame* frame = document ? document->frame() : 0;
1387    if (!frame)
1388        return 0;
1389
1390    InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(mainWorldScriptState(frame));
1391    if (injectedScript.hasNoValue())
1392        return 0;
1393
1394    return injectedScript.wrapNode(node);
1395}
1396
1397void InspectorDOMAgent::drawNodeHighlight(GraphicsContext& context) const
1398{
1399    if (!m_highlightedNode)
1400        return;
1401
1402    DOMNodeHighlighter::DrawNodeHighlight(context, m_highlightedNode.get());
1403}
1404
1405} // namespace WebCore
1406
1407#endif // ENABLE(INSPECTOR)
1408