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
33#if ENABLE(INSPECTOR)
34
35#include "InspectorDOMAgent.h"
36
37#include "Attr.h"
38#include "CSSComputedStyleDeclaration.h"
39#include "CSSPropertyNames.h"
40#include "CSSPropertySourceData.h"
41#include "CSSRule.h"
42#include "CSSRuleList.h"
43#include "CSSStyleRule.h"
44#include "CSSStyleSheet.h"
45#include "CharacterData.h"
46#include "ContainerNode.h"
47#include "Cookie.h"
48#include "CookieJar.h"
49#include "DOMEditor.h"
50#include "DOMPatchSupport.h"
51#include "DOMWindow.h"
52#include "Document.h"
53#include "DocumentFragment.h"
54#include "DocumentType.h"
55#include "Element.h"
56#include "ElementShadow.h"
57#include "Event.h"
58#include "EventContext.h"
59#include "EventListener.h"
60#include "EventNames.h"
61#include "EventTarget.h"
62#include "File.h"
63#include "FileList.h"
64#include "Frame.h"
65#include "FrameTree.h"
66#include "HTMLElement.h"
67#include "HTMLFrameOwnerElement.h"
68#include "HTMLInputElement.h"
69#include "HTMLNames.h"
70#include "HTMLTemplateElement.h"
71#include "HitTestResult.h"
72#include "IdentifiersFactory.h"
73#include "InjectedScriptManager.h"
74#include "InspectorClient.h"
75#include "InspectorFrontend.h"
76#include "InspectorHistory.h"
77#include "InspectorOverlay.h"
78#include "InspectorPageAgent.h"
79#include "InspectorState.h"
80#include "InstrumentingAgents.h"
81#include "IntRect.h"
82#include "MutationEvent.h"
83#include "Node.h"
84#include "NodeList.h"
85#include "NodeTraversal.h"
86#include "Page.h"
87#include "Pasteboard.h"
88#include "RenderStyle.h"
89#include "RenderStyleConstants.h"
90#include "ScriptEventListener.h"
91#include "Settings.h"
92#include "ShadowRoot.h"
93#include "StylePropertySet.h"
94#include "StyleResolver.h"
95#include "StyleSheetList.h"
96#include "Text.h"
97#include "XPathResult.h"
98
99#include "htmlediting.h"
100#include "markup.h"
101
102#include <wtf/text/CString.h>
103#include <wtf/text/WTFString.h>
104#include <wtf/HashSet.h>
105#include <wtf/ListHashSet.h>
106#include <wtf/OwnPtr.h>
107#include <wtf/Vector.h>
108
109namespace WebCore {
110
111using namespace HTMLNames;
112
113namespace DOMAgentState {
114static const char documentRequested[] = "documentRequested";
115};
116
117static const size_t maxTextSize = 10000;
118static const UChar ellipsisUChar[] = { 0x2026, 0 };
119
120static Color parseColor(const RefPtr<InspectorObject>* colorObject)
121{
122    if (!colorObject || !(*colorObject))
123        return Color::transparent;
124
125    int r;
126    int g;
127    int b;
128    bool success = (*colorObject)->getNumber("r", &r);
129    success |= (*colorObject)->getNumber("g", &g);
130    success |= (*colorObject)->getNumber("b", &b);
131    if (!success)
132        return Color::transparent;
133
134    double a;
135    success = (*colorObject)->getNumber("a", &a);
136    if (!success)
137        return Color(r, g, b);
138
139    // Clamp alpha to the [0..1] range.
140    if (a < 0)
141        a = 0;
142    else if (a > 1)
143        a = 1;
144
145    return Color(r, g, b, static_cast<int>(a * 255));
146}
147
148static Color parseConfigColor(const String& fieldName, InspectorObject* configObject)
149{
150    const RefPtr<InspectorObject> colorObject = configObject->getObject(fieldName);
151    return parseColor(&colorObject);
152}
153
154static bool parseQuad(const RefPtr<InspectorArray>& quadArray, FloatQuad* quad)
155{
156    if (!quadArray)
157        return false;
158    const size_t coordinatesInQuad = 8;
159    double coordinates[coordinatesInQuad];
160    if (quadArray->length() != coordinatesInQuad)
161        return false;
162    for (size_t i = 0; i < coordinatesInQuad; ++i) {
163        if (!quadArray->get(i)->asNumber(coordinates + i))
164            return false;
165    }
166    quad->setP1(FloatPoint(coordinates[0], coordinates[1]));
167    quad->setP2(FloatPoint(coordinates[2], coordinates[3]));
168    quad->setP3(FloatPoint(coordinates[4], coordinates[5]));
169    quad->setP4(FloatPoint(coordinates[6], coordinates[7]));
170
171    return true;
172}
173
174class RevalidateStyleAttributeTask {
175    WTF_MAKE_FAST_ALLOCATED;
176public:
177    RevalidateStyleAttributeTask(InspectorDOMAgent*);
178    void scheduleFor(Element*);
179    void reset() { m_timer.stop(); }
180    void onTimer(Timer<RevalidateStyleAttributeTask>*);
181
182private:
183    InspectorDOMAgent* m_domAgent;
184    Timer<RevalidateStyleAttributeTask> m_timer;
185    HashSet<RefPtr<Element> > m_elements;
186};
187
188RevalidateStyleAttributeTask::RevalidateStyleAttributeTask(InspectorDOMAgent* domAgent)
189    : m_domAgent(domAgent)
190    , m_timer(this, &RevalidateStyleAttributeTask::onTimer)
191{
192}
193
194void RevalidateStyleAttributeTask::scheduleFor(Element* element)
195{
196    m_elements.add(element);
197    if (!m_timer.isActive())
198        m_timer.startOneShot(0);
199}
200
201void RevalidateStyleAttributeTask::onTimer(Timer<RevalidateStyleAttributeTask>*)
202{
203    // The timer is stopped on m_domAgent destruction, so this method will never be called after m_domAgent has been destroyed.
204    Vector<Element*> elements;
205    for (HashSet<RefPtr<Element> >::iterator it = m_elements.begin(), end = m_elements.end(); it != end; ++it)
206        elements.append(it->get());
207    m_domAgent->styleAttributeInvalidated(elements);
208
209    m_elements.clear();
210}
211
212String InspectorDOMAgent::toErrorString(const ExceptionCode& ec)
213{
214    if (ec) {
215        ExceptionCodeDescription description(ec);
216        return description.name;
217    }
218    return "";
219}
220
221InspectorDOMAgent::InspectorDOMAgent(InstrumentingAgents* instrumentingAgents, InspectorPageAgent* pageAgent, InspectorCompositeState* inspectorState, InjectedScriptManager* injectedScriptManager, InspectorOverlay* overlay, InspectorClient* client)
222    : InspectorBaseAgent<InspectorDOMAgent>("DOM", instrumentingAgents, inspectorState)
223    , m_pageAgent(pageAgent)
224    , m_injectedScriptManager(injectedScriptManager)
225    , m_overlay(overlay)
226    , m_client(client)
227    , m_frontend(0)
228    , m_domListener(0)
229    , m_lastNodeId(1)
230    , m_lastBackendNodeId(-1)
231    , m_searchingForNode(false)
232    , m_suppressAttributeModifiedEvent(false)
233{
234}
235
236InspectorDOMAgent::~InspectorDOMAgent()
237{
238    reset();
239    ASSERT(!m_searchingForNode);
240}
241
242void InspectorDOMAgent::setFrontend(InspectorFrontend* frontend)
243{
244    ASSERT(!m_frontend);
245    m_history = adoptPtr(new InspectorHistory());
246    m_domEditor = adoptPtr(new DOMEditor(m_history.get()));
247
248    m_frontend = frontend->dom();
249    m_instrumentingAgents->setInspectorDOMAgent(this);
250    m_document = m_pageAgent->mainFrame()->document();
251
252    if (m_nodeToFocus)
253        focusNode();
254}
255
256void InspectorDOMAgent::clearFrontend()
257{
258    ASSERT(m_frontend);
259
260    m_history.clear();
261    m_domEditor.clear();
262
263    ErrorString error;
264    setSearchingForNode(&error, false, 0);
265    hideHighlight(&error);
266
267    m_frontend = 0;
268    m_instrumentingAgents->setInspectorDOMAgent(0);
269    m_state->setBoolean(DOMAgentState::documentRequested, false);
270    reset();
271}
272
273void InspectorDOMAgent::restore()
274{
275    // Reset document to avoid early return from setDocument.
276    m_document = 0;
277    setDocument(m_pageAgent->mainFrame()->document());
278}
279
280Vector<Document*> InspectorDOMAgent::documents()
281{
282    Vector<Document*> result;
283    for (Frame* frame = m_document->frame(); frame; frame = frame->tree()->traverseNext()) {
284        Document* document = frame->document();
285        if (!document)
286            continue;
287        result.append(document);
288    }
289    return result;
290}
291
292void InspectorDOMAgent::reset()
293{
294    if (m_history)
295        m_history->reset();
296    m_searchResults.clear();
297    discardBindings();
298    if (m_revalidateStyleAttrTask)
299        m_revalidateStyleAttrTask->reset();
300    m_document = 0;
301}
302
303void InspectorDOMAgent::setDOMListener(DOMListener* listener)
304{
305    m_domListener = listener;
306}
307
308void InspectorDOMAgent::setDocument(Document* doc)
309{
310    if (doc == m_document.get())
311        return;
312
313    reset();
314
315    m_document = doc;
316
317    if (!m_state->getBoolean(DOMAgentState::documentRequested))
318        return;
319
320    // Immediately communicate 0 document or document that has finished loading.
321    if (!doc || !doc->parsing())
322        m_frontend->documentUpdated();
323}
324
325void InspectorDOMAgent::releaseDanglingNodes()
326{
327    m_danglingNodeToIdMaps.clear();
328}
329
330int InspectorDOMAgent::bind(Node* node, NodeToIdMap* nodesMap)
331{
332    int id = nodesMap->get(node);
333    if (id)
334        return id;
335    id = m_lastNodeId++;
336    nodesMap->set(node, id);
337    m_idToNode.set(id, node);
338    m_idToNodesMap.set(id, nodesMap);
339    return id;
340}
341
342void InspectorDOMAgent::unbind(Node* node, NodeToIdMap* nodesMap)
343{
344    int id = nodesMap->get(node);
345    if (!id)
346        return;
347
348    m_idToNode.remove(id);
349
350    if (node->isFrameOwnerElement()) {
351        const HTMLFrameOwnerElement* frameOwner = static_cast<const HTMLFrameOwnerElement*>(node);
352        Document* contentDocument = frameOwner->contentDocument();
353        if (m_domListener)
354            m_domListener->didRemoveDocument(contentDocument);
355        if (contentDocument)
356            unbind(contentDocument, nodesMap);
357    }
358
359    if (node->isElementNode()) {
360        if (ElementShadow* shadow = toElement(node)->shadow()) {
361            if (ShadowRoot* root = shadow->shadowRoot())
362                unbind(root, nodesMap);
363        }
364    }
365
366    nodesMap->remove(node);
367    if (m_domListener)
368        m_domListener->didRemoveDOMNode(node);
369
370    bool childrenRequested = m_childrenRequested.contains(id);
371    if (childrenRequested) {
372        // Unbind subtree known to client recursively.
373        m_childrenRequested.remove(id);
374        Node* child = innerFirstChild(node);
375        while (child) {
376            unbind(child, nodesMap);
377            child = innerNextSibling(child);
378        }
379    }
380}
381
382Node* InspectorDOMAgent::assertNode(ErrorString* errorString, int nodeId)
383{
384    Node* node = nodeForId(nodeId);
385    if (!node) {
386        *errorString = "Could not find node with given id";
387        return 0;
388    }
389    return node;
390}
391
392Document* InspectorDOMAgent::assertDocument(ErrorString* errorString, int nodeId)
393{
394    Node* node = assertNode(errorString, nodeId);
395    if (!node)
396        return 0;
397
398    if (!(node->isDocumentNode())) {
399        *errorString = "Document is not available";
400        return 0;
401    }
402    return toDocument(node);
403}
404
405Element* InspectorDOMAgent::assertElement(ErrorString* errorString, int nodeId)
406{
407    Node* node = assertNode(errorString, nodeId);
408    if (!node)
409        return 0;
410
411    if (node->nodeType() != Node::ELEMENT_NODE) {
412        *errorString = "Node is not an Element";
413        return 0;
414    }
415    return toElement(node);
416}
417
418Node* InspectorDOMAgent::assertEditableNode(ErrorString* errorString, int nodeId)
419{
420    Node* node = assertNode(errorString, nodeId);
421    if (!node)
422        return 0;
423
424    if (node->isInShadowTree()) {
425        *errorString = "Can not edit nodes from shadow trees";
426        return 0;
427    }
428
429    return node;
430}
431
432Element* InspectorDOMAgent::assertEditableElement(ErrorString* errorString, int nodeId)
433{
434    Element* element = assertElement(errorString, nodeId);
435    if (!element)
436        return 0;
437
438    if (element->isInShadowTree()) {
439        *errorString = "Can not edit elements from shadow trees";
440        return 0;
441    }
442    return element;
443}
444
445void InspectorDOMAgent::getDocument(ErrorString* errorString, RefPtr<TypeBuilder::DOM::Node>& root)
446{
447    m_state->setBoolean(DOMAgentState::documentRequested, true);
448
449    if (!m_document) {
450        *errorString = "Document is not available";
451        return;
452    }
453
454    // Reset backend state.
455    RefPtr<Document> doc = m_document;
456    reset();
457    m_document = doc;
458
459    root = buildObjectForNode(m_document.get(), 2, &m_documentNodeToIdMap);
460}
461
462void InspectorDOMAgent::pushChildNodesToFrontend(int nodeId, int depth)
463{
464    Node* node = nodeForId(nodeId);
465    if (!node || (node->nodeType() != Node::ELEMENT_NODE && node->nodeType() != Node::DOCUMENT_NODE && node->nodeType() != Node::DOCUMENT_FRAGMENT_NODE))
466        return;
467
468    NodeToIdMap* nodeMap = m_idToNodesMap.get(nodeId);
469
470    if (m_childrenRequested.contains(nodeId)) {
471        if (depth <= 1)
472            return;
473
474        depth--;
475
476        for (node = innerFirstChild(node); node; node = innerNextSibling(node)) {
477            int childNodeId = nodeMap->get(node);
478            ASSERT(childNodeId);
479            pushChildNodesToFrontend(childNodeId, depth);
480        }
481
482        return;
483    }
484
485    RefPtr<TypeBuilder::Array<TypeBuilder::DOM::Node> > children = buildArrayForContainerChildren(node, depth, nodeMap);
486    m_frontend->setChildNodes(nodeId, children.release());
487}
488
489void InspectorDOMAgent::discardBindings()
490{
491    m_documentNodeToIdMap.clear();
492    m_idToNode.clear();
493    releaseDanglingNodes();
494    m_childrenRequested.clear();
495    m_backendIdToNode.clear();
496    m_nodeGroupToBackendIdMap.clear();
497}
498
499int InspectorDOMAgent::pushNodeToFrontend(ErrorString* errorString, int documentNodeId, Node* nodeToPush)
500{
501    Document* document = assertDocument(errorString, documentNodeId);
502    if (!document)
503        return 0;
504    if (nodeToPush->document() != document) {
505        *errorString = "Node is not part of the document with given id";
506        return 0;
507    }
508
509    return pushNodePathToFrontend(nodeToPush);
510}
511
512Node* InspectorDOMAgent::nodeForId(int id)
513{
514    if (!id)
515        return 0;
516
517    HashMap<int, Node*>::iterator it = m_idToNode.find(id);
518    if (it != m_idToNode.end())
519        return it->value;
520    return 0;
521}
522
523void InspectorDOMAgent::requestChildNodes(ErrorString* errorString, int nodeId, const int* depth)
524{
525    int sanitizedDepth;
526
527    if (!depth)
528        sanitizedDepth = 1;
529    else if (*depth == -1)
530        sanitizedDepth = INT_MAX;
531    else if (*depth > 0)
532        sanitizedDepth = *depth;
533    else {
534        *errorString = "Please provide a positive integer as a depth or -1 for entire subtree";
535        return;
536    }
537
538    pushChildNodesToFrontend(nodeId, sanitizedDepth);
539}
540
541void InspectorDOMAgent::querySelector(ErrorString* errorString, int nodeId, const String& selectors, int* elementId)
542{
543    *elementId = 0;
544    Node* node = assertNode(errorString, nodeId);
545    if (!node)
546        return;
547
548    ExceptionCode ec = 0;
549    RefPtr<Element> element = node->querySelector(selectors, ec);
550    if (ec) {
551        *errorString = "DOM Error while querying";
552        return;
553    }
554
555    if (element)
556        *elementId = pushNodePathToFrontend(element.get());
557}
558
559void InspectorDOMAgent::querySelectorAll(ErrorString* errorString, int nodeId, const String& selectors, RefPtr<TypeBuilder::Array<int> >& result)
560{
561    Node* node = assertNode(errorString, nodeId);
562    if (!node)
563        return;
564
565    ExceptionCode ec = 0;
566    RefPtr<NodeList> nodes = node->querySelectorAll(selectors, ec);
567    if (ec) {
568        *errorString = "DOM Error while querying";
569        return;
570    }
571
572    result = TypeBuilder::Array<int>::create();
573
574    for (unsigned i = 0; i < nodes->length(); ++i)
575        result->addItem(pushNodePathToFrontend(nodes->item(i)));
576}
577
578int InspectorDOMAgent::pushNodePathToFrontend(Node* nodeToPush)
579{
580    ASSERT(nodeToPush);  // Invalid input
581
582    if (!m_document)
583        return 0;
584    if (!m_documentNodeToIdMap.contains(m_document))
585        return 0;
586
587    // Return id in case the node is known.
588    int result = m_documentNodeToIdMap.get(nodeToPush);
589    if (result)
590        return result;
591
592    Node* node = nodeToPush;
593    Vector<Node*> path;
594    NodeToIdMap* danglingMap = 0;
595
596    while (true) {
597        Node* parent = innerParentNode(node);
598        if (!parent) {
599            // Node being pushed is detached -> push subtree root.
600            OwnPtr<NodeToIdMap> newMap = adoptPtr(new NodeToIdMap);
601            danglingMap = newMap.get();
602            m_danglingNodeToIdMaps.append(newMap.release());
603            RefPtr<TypeBuilder::Array<TypeBuilder::DOM::Node> > children = TypeBuilder::Array<TypeBuilder::DOM::Node>::create();
604            children->addItem(buildObjectForNode(node, 0, danglingMap));
605            m_frontend->setChildNodes(0, children);
606            break;
607        } else {
608            path.append(parent);
609            if (m_documentNodeToIdMap.get(parent))
610                break;
611            else
612                node = parent;
613        }
614    }
615
616    NodeToIdMap* map = danglingMap ? danglingMap : &m_documentNodeToIdMap;
617    for (int i = path.size() - 1; i >= 0; --i) {
618        int nodeId = map->get(path.at(i));
619        ASSERT(nodeId);
620        pushChildNodesToFrontend(nodeId);
621    }
622    return map->get(nodeToPush);
623}
624
625int InspectorDOMAgent::boundNodeId(Node* node)
626{
627    return m_documentNodeToIdMap.get(node);
628}
629
630BackendNodeId InspectorDOMAgent::backendNodeIdForNode(Node* node, const String& nodeGroup)
631{
632    if (!node)
633        return 0;
634
635    if (!m_nodeGroupToBackendIdMap.contains(nodeGroup))
636        m_nodeGroupToBackendIdMap.set(nodeGroup, NodeToBackendIdMap());
637
638    NodeToBackendIdMap& map = m_nodeGroupToBackendIdMap.find(nodeGroup)->value;
639    BackendNodeId id = map.get(node);
640    if (!id) {
641        id = --m_lastBackendNodeId;
642        map.set(node, id);
643        m_backendIdToNode.set(id, std::make_pair(node, nodeGroup));
644    }
645
646    return id;
647}
648
649void InspectorDOMAgent::releaseBackendNodeIds(ErrorString* errorString, const String& nodeGroup)
650{
651    if (m_nodeGroupToBackendIdMap.contains(nodeGroup)) {
652        NodeToBackendIdMap& map = m_nodeGroupToBackendIdMap.find(nodeGroup)->value;
653        for (NodeToBackendIdMap::iterator it = map.begin(); it != map.end(); ++it)
654            m_backendIdToNode.remove(it->value);
655        m_nodeGroupToBackendIdMap.remove(nodeGroup);
656        return;
657    }
658    *errorString = "Group name not found";
659}
660
661void InspectorDOMAgent::setAttributeValue(ErrorString* errorString, int elementId, const String& name, const String& value)
662{
663    Element* element = assertEditableElement(errorString, elementId);
664    if (!element)
665        return;
666
667    m_domEditor->setAttribute(element, name, value, errorString);
668}
669
670void InspectorDOMAgent::setAttributesAsText(ErrorString* errorString, int elementId, const String& text, const String* const name)
671{
672    Element* element = assertEditableElement(errorString, elementId);
673    if (!element)
674        return;
675
676    RefPtr<HTMLElement> parsedElement = createHTMLElement(element->document(), spanTag);
677    ExceptionCode ec = 0;
678    parsedElement.get()->setInnerHTML("<span " + text + "></span>", ec);
679    if (ec) {
680        *errorString = InspectorDOMAgent::toErrorString(ec);
681        return;
682    }
683
684    Node* child = parsedElement->firstChild();
685    if (!child) {
686        *errorString = "Could not parse value as attributes";
687        return;
688    }
689
690    Element* childElement = toElement(child);
691    if (!childElement->hasAttributes() && name) {
692        m_domEditor->removeAttribute(element, *name, errorString);
693        return;
694    }
695
696    bool foundOriginalAttribute = false;
697    unsigned numAttrs = childElement->attributeCount();
698    for (unsigned i = 0; i < numAttrs; ++i) {
699        // Add attribute pair
700        const Attribute* attribute = childElement->attributeItem(i);
701        foundOriginalAttribute = foundOriginalAttribute || (name && attribute->name().toString() == *name);
702        if (!m_domEditor->setAttribute(element, attribute->name().toString(), attribute->value(), errorString))
703            return;
704    }
705
706    if (!foundOriginalAttribute && name && !name->stripWhiteSpace().isEmpty())
707        m_domEditor->removeAttribute(element, *name, errorString);
708}
709
710void InspectorDOMAgent::removeAttribute(ErrorString* errorString, int elementId, const String& name)
711{
712    Element* element = assertEditableElement(errorString, elementId);
713    if (!element)
714        return;
715
716    m_domEditor->removeAttribute(element, name, errorString);
717}
718
719void InspectorDOMAgent::removeNode(ErrorString* errorString, int nodeId)
720{
721    Node* node = assertEditableNode(errorString, nodeId);
722    if (!node)
723        return;
724
725    ContainerNode* parentNode = node->parentNode();
726    if (!parentNode) {
727        *errorString = "Can not remove detached node";
728        return;
729    }
730
731    m_domEditor->removeChild(parentNode, node, errorString);
732}
733
734void InspectorDOMAgent::setNodeName(ErrorString* errorString, int nodeId, const String& tagName, int* newId)
735{
736    *newId = 0;
737
738    Node* oldNode = nodeForId(nodeId);
739    if (!oldNode || !oldNode->isElementNode())
740        return;
741
742    ExceptionCode ec = 0;
743    RefPtr<Element> newElem = oldNode->document()->createElement(tagName, ec);
744    if (ec)
745        return;
746
747    // Copy over the original node's attributes.
748    newElem->cloneAttributesFromElement(*toElement(oldNode));
749
750    // Copy over the original node's children.
751    Node* child;
752    while ((child = oldNode->firstChild())) {
753        if (!m_domEditor->insertBefore(newElem.get(), child, 0, errorString))
754            return;
755    }
756
757    // Replace the old node with the new node
758    ContainerNode* parent = oldNode->parentNode();
759    if (!m_domEditor->insertBefore(parent, newElem.get(), oldNode->nextSibling(), errorString))
760        return;
761    if (!m_domEditor->removeChild(parent, oldNode, errorString))
762        return;
763
764    *newId = pushNodePathToFrontend(newElem.get());
765    if (m_childrenRequested.contains(nodeId))
766        pushChildNodesToFrontend(*newId);
767}
768
769void InspectorDOMAgent::getOuterHTML(ErrorString* errorString, int nodeId, WTF::String* outerHTML)
770{
771    Node* node = assertNode(errorString, nodeId);
772    if (!node)
773        return;
774
775    *outerHTML = createMarkup(node);
776}
777
778void InspectorDOMAgent::setOuterHTML(ErrorString* errorString, int nodeId, const String& outerHTML)
779{
780    if (!nodeId) {
781        DOMPatchSupport domPatchSupport(m_domEditor.get(), m_document.get());
782        domPatchSupport.patchDocument(outerHTML);
783        return;
784    }
785
786    Node* node = assertEditableNode(errorString, nodeId);
787    if (!node)
788        return;
789
790    Document* document = node->isDocumentNode() ? toDocument(node) : node->ownerDocument();
791    if (!document || (!document->isHTMLDocument() && !document->isXHTMLDocument()
792#if ENABLE(SVG)
793        && !document->isSVGDocument()
794#endif
795    )) {
796        *errorString = "Not an HTML/XML document";
797        return;
798    }
799
800    Node* newNode = 0;
801    if (!m_domEditor->setOuterHTML(node, outerHTML, &newNode, errorString))
802        return;
803
804    if (!newNode) {
805        // The only child node has been deleted.
806        return;
807    }
808
809    int newId = pushNodePathToFrontend(newNode);
810
811    bool childrenRequested = m_childrenRequested.contains(nodeId);
812    if (childrenRequested)
813        pushChildNodesToFrontend(newId);
814}
815
816void InspectorDOMAgent::setNodeValue(ErrorString* errorString, int nodeId, const String& value)
817{
818    Node* node = assertEditableNode(errorString, nodeId);
819    if (!node)
820        return;
821
822    if (node->nodeType() != Node::TEXT_NODE) {
823        *errorString = "Can only set value of text nodes";
824        return;
825    }
826
827    m_domEditor->replaceWholeText(toText(node), value, errorString);
828}
829
830void InspectorDOMAgent::getEventListenersForNode(ErrorString* errorString, int nodeId, const String* objectGroup, RefPtr<TypeBuilder::Array<TypeBuilder::DOM::EventListener> >& listenersArray)
831{
832    listenersArray = TypeBuilder::Array<TypeBuilder::DOM::EventListener>::create();
833    Node* node = assertNode(errorString, nodeId);
834    if (!node)
835        return;
836    Vector<EventListenerInfo> eventInformation;
837    getEventListeners(node, eventInformation, true);
838
839    // Get Capturing Listeners (in this order)
840    size_t eventInformationLength = eventInformation.size();
841    for (size_t i = 0; i < eventInformationLength; ++i) {
842        const EventListenerInfo& info = eventInformation[i];
843        const EventListenerVector& vector = info.eventListenerVector;
844        for (size_t j = 0; j < vector.size(); ++j) {
845            const RegisteredEventListener& listener = vector[j];
846            if (listener.useCapture)
847                listenersArray->addItem(buildObjectForEventListener(listener, info.eventType, info.node, objectGroup));
848        }
849    }
850
851    // Get Bubbling Listeners (reverse order)
852    for (size_t i = eventInformationLength; i; --i) {
853        const EventListenerInfo& info = eventInformation[i - 1];
854        const EventListenerVector& vector = info.eventListenerVector;
855        for (size_t j = 0; j < vector.size(); ++j) {
856            const RegisteredEventListener& listener = vector[j];
857            if (!listener.useCapture)
858                listenersArray->addItem(buildObjectForEventListener(listener, info.eventType, info.node, objectGroup));
859        }
860    }
861}
862
863void InspectorDOMAgent::getEventListeners(Node* node, Vector<EventListenerInfo>& eventInformation, bool includeAncestors)
864{
865    // The Node's Ancestors including self.
866    Vector<Node*> ancestors;
867    // Push this node as the firs element.
868    ancestors.append(node);
869    if (includeAncestors) {
870        for (ContainerNode* ancestor = node->parentOrShadowHostNode(); ancestor; ancestor = ancestor->parentOrShadowHostNode())
871            ancestors.append(ancestor);
872    }
873
874    // Nodes and their Listeners for the concerned event types (order is top to bottom)
875    for (size_t i = ancestors.size(); i; --i) {
876        Node* ancestor = ancestors[i - 1];
877        EventTargetData* d = ancestor->eventTargetData();
878        if (!d)
879            continue;
880        // Get the list of event types this Node is concerned with
881        Vector<AtomicString> eventTypes = d->eventListenerMap.eventTypes();
882        for (size_t j = 0; j < eventTypes.size(); ++j) {
883            AtomicString& type = eventTypes[j];
884            const EventListenerVector& listeners = ancestor->getEventListeners(type);
885            EventListenerVector filteredListeners;
886            filteredListeners.reserveCapacity(listeners.size());
887            for (size_t k = 0; k < listeners.size(); ++k) {
888                if (listeners[k].listener->type() == EventListener::JSEventListenerType)
889                    filteredListeners.append(listeners[k]);
890            }
891            if (!filteredListeners.isEmpty())
892                eventInformation.append(EventListenerInfo(ancestor, type, filteredListeners));
893        }
894    }
895}
896
897void InspectorDOMAgent::performSearch(ErrorString*, const String& whitespaceTrimmedQuery, String* searchId, int* resultCount)
898{
899    // FIXME: Few things are missing here:
900    // 1) Search works with node granularity - number of matches within node is not calculated.
901    // 2) There is no need to push all search results to the front-end at a time, pushing next / previous result
902    //    is sufficient.
903
904    unsigned queryLength = whitespaceTrimmedQuery.length();
905    bool startTagFound = !whitespaceTrimmedQuery.find('<');
906    bool endTagFound = whitespaceTrimmedQuery.reverseFind('>') + 1 == queryLength;
907    bool startQuoteFound = !whitespaceTrimmedQuery.find('"');
908    bool endQuoteFound = whitespaceTrimmedQuery.reverseFind('"') + 1 == queryLength;
909    bool exactAttributeMatch = startQuoteFound && endQuoteFound;
910
911    String tagNameQuery = whitespaceTrimmedQuery;
912    String attributeQuery = whitespaceTrimmedQuery;
913    if (startTagFound)
914        tagNameQuery = tagNameQuery.right(tagNameQuery.length() - 1);
915    if (endTagFound)
916        tagNameQuery = tagNameQuery.left(tagNameQuery.length() - 1);
917    if (startQuoteFound)
918        attributeQuery = attributeQuery.right(attributeQuery.length() - 1);
919    if (endQuoteFound)
920        attributeQuery = attributeQuery.left(attributeQuery.length() - 1);
921
922    Vector<Document*> docs = documents();
923    ListHashSet<Node*> resultCollector;
924
925    for (Vector<Document*>::iterator it = docs.begin(); it != docs.end(); ++it) {
926        Document* document = *it;
927        Node* node = document->documentElement();
928        if (!node)
929            continue;
930
931        // Manual plain text search.
932        while ((node = NodeTraversal::next(node, document->documentElement()))) {
933            switch (node->nodeType()) {
934            case Node::TEXT_NODE:
935            case Node::COMMENT_NODE:
936            case Node::CDATA_SECTION_NODE: {
937                String text = node->nodeValue();
938                if (text.findIgnoringCase(whitespaceTrimmedQuery) != notFound)
939                    resultCollector.add(node);
940                break;
941            }
942            case Node::ELEMENT_NODE: {
943                if ((!startTagFound && !endTagFound && (node->nodeName().findIgnoringCase(tagNameQuery) != notFound))
944                    || (startTagFound && endTagFound && equalIgnoringCase(node->nodeName(), tagNameQuery))
945                    || (startTagFound && !endTagFound && node->nodeName().startsWith(tagNameQuery, false))
946                    || (!startTagFound && endTagFound && node->nodeName().endsWith(tagNameQuery, false))) {
947                    resultCollector.add(node);
948                    break;
949                }
950                // Go through all attributes and serialize them.
951                const Element* element = toElement(node);
952                if (!element->hasAttributes())
953                    break;
954
955                unsigned numAttrs = element->attributeCount();
956                for (unsigned i = 0; i < numAttrs; ++i) {
957                    // Add attribute pair
958                    const Attribute* attribute = element->attributeItem(i);
959                    if (attribute->localName().find(whitespaceTrimmedQuery) != notFound) {
960                        resultCollector.add(node);
961                        break;
962                    }
963                    size_t foundPosition = attribute->value().find(attributeQuery);
964                    if (foundPosition != notFound) {
965                        if (!exactAttributeMatch || (!foundPosition && attribute->value().length() == attributeQuery.length())) {
966                            resultCollector.add(node);
967                            break;
968                        }
969                    }
970                }
971                break;
972            }
973            default:
974                break;
975            }
976        }
977
978        // XPath evaluation
979        for (Vector<Document*>::iterator it = docs.begin(); it != docs.end(); ++it) {
980            Document* document = *it;
981            ExceptionCode ec = 0;
982            RefPtr<XPathResult> result = document->evaluate(whitespaceTrimmedQuery, document, 0, XPathResult::ORDERED_NODE_SNAPSHOT_TYPE, 0, ec);
983            if (ec || !result)
984                continue;
985
986            unsigned long size = result->snapshotLength(ec);
987            for (unsigned long i = 0; !ec && i < size; ++i) {
988                Node* node = result->snapshotItem(i, ec);
989                if (ec)
990                    break;
991
992                if (node->nodeType() == Node::ATTRIBUTE_NODE)
993                    node = static_cast<Attr*>(node)->ownerElement();
994                resultCollector.add(node);
995            }
996        }
997
998        // Selector evaluation
999        for (Vector<Document*>::iterator it = docs.begin(); it != docs.end(); ++it) {
1000            Document* document = *it;
1001            ExceptionCode ec = 0;
1002            RefPtr<NodeList> nodeList = document->querySelectorAll(whitespaceTrimmedQuery, ec);
1003            if (ec || !nodeList)
1004                continue;
1005
1006            unsigned size = nodeList->length();
1007            for (unsigned i = 0; i < size; ++i)
1008                resultCollector.add(nodeList->item(i));
1009        }
1010    }
1011
1012    *searchId = IdentifiersFactory::createIdentifier();
1013    SearchResults::iterator resultsIt = m_searchResults.add(*searchId, Vector<RefPtr<Node> >()).iterator;
1014
1015    for (ListHashSet<Node*>::iterator it = resultCollector.begin(); it != resultCollector.end(); ++it)
1016        resultsIt->value.append(*it);
1017
1018    *resultCount = resultsIt->value.size();
1019}
1020
1021void InspectorDOMAgent::getSearchResults(ErrorString* errorString, const String& searchId, int fromIndex, int toIndex, RefPtr<TypeBuilder::Array<int> >& nodeIds)
1022{
1023    SearchResults::iterator it = m_searchResults.find(searchId);
1024    if (it == m_searchResults.end()) {
1025        *errorString = "No search session with given id found";
1026        return;
1027    }
1028
1029    int size = it->value.size();
1030    if (fromIndex < 0 || toIndex > size || fromIndex >= toIndex) {
1031        *errorString = "Invalid search result range";
1032        return;
1033    }
1034
1035    nodeIds = TypeBuilder::Array<int>::create();
1036    for (int i = fromIndex; i < toIndex; ++i)
1037        nodeIds->addItem(pushNodePathToFrontend((it->value)[i].get()));
1038}
1039
1040void InspectorDOMAgent::discardSearchResults(ErrorString*, const String& searchId)
1041{
1042    m_searchResults.remove(searchId);
1043}
1044
1045bool InspectorDOMAgent::handleMousePress()
1046{
1047    if (!m_searchingForNode)
1048        return false;
1049
1050    if (Node* node = m_overlay->highlightedNode()) {
1051        inspect(node);
1052        return true;
1053    }
1054    return false;
1055}
1056
1057bool InspectorDOMAgent::handleTouchEvent(Node* node)
1058{
1059    if (!m_searchingForNode)
1060        return false;
1061    if (node && m_inspectModeHighlightConfig) {
1062        m_overlay->highlightNode(node, *m_inspectModeHighlightConfig);
1063        inspect(node);
1064        return true;
1065    }
1066    return false;
1067}
1068
1069void InspectorDOMAgent::inspect(Node* inspectedNode)
1070{
1071    ErrorString error;
1072    RefPtr<Node> node = inspectedNode;
1073    setSearchingForNode(&error, false, 0);
1074
1075    if (node->nodeType() != Node::ELEMENT_NODE && node->nodeType() != Node::DOCUMENT_NODE)
1076        node = node->parentNode();
1077    m_nodeToFocus = node;
1078
1079    focusNode();
1080}
1081
1082void InspectorDOMAgent::focusNode()
1083{
1084    if (!m_frontend)
1085        return;
1086
1087    ASSERT(m_nodeToFocus);
1088
1089    RefPtr<Node> node = m_nodeToFocus.get();
1090    m_nodeToFocus = 0;
1091
1092    Document* document = node->ownerDocument();
1093    if (!document)
1094        return;
1095    Frame* frame = document->frame();
1096    if (!frame)
1097        return;
1098
1099    InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(mainWorldScriptState(frame));
1100    if (injectedScript.hasNoValue())
1101        return;
1102
1103    injectedScript.inspectNode(node.get());
1104}
1105
1106void InspectorDOMAgent::mouseDidMoveOverElement(const HitTestResult& result, unsigned)
1107{
1108    if (!m_searchingForNode)
1109        return;
1110
1111    Node* node = result.innerNode();
1112    while (node && node->nodeType() == Node::TEXT_NODE)
1113        node = node->parentNode();
1114    if (node && m_inspectModeHighlightConfig)
1115        m_overlay->highlightNode(node, *m_inspectModeHighlightConfig);
1116}
1117
1118void InspectorDOMAgent::setSearchingForNode(ErrorString* errorString, bool enabled, InspectorObject* highlightInspectorObject)
1119{
1120    if (m_searchingForNode == enabled)
1121        return;
1122    m_searchingForNode = enabled;
1123    if (enabled) {
1124        m_inspectModeHighlightConfig = highlightConfigFromInspectorObject(errorString, highlightInspectorObject);
1125        if (!m_inspectModeHighlightConfig)
1126            return;
1127    } else
1128        hideHighlight(errorString);
1129}
1130
1131PassOwnPtr<HighlightConfig> InspectorDOMAgent::highlightConfigFromInspectorObject(ErrorString* errorString, InspectorObject* highlightInspectorObject)
1132{
1133    if (!highlightInspectorObject) {
1134        *errorString = "Internal error: highlight configuration parameter is missing";
1135        return nullptr;
1136    }
1137
1138    OwnPtr<HighlightConfig> highlightConfig = adoptPtr(new HighlightConfig());
1139    bool showInfo = false; // Default: false (do not show a tooltip).
1140    highlightInspectorObject->getBoolean("showInfo", &showInfo);
1141    highlightConfig->showInfo = showInfo;
1142    bool showRulers = false; // Default: false (do not show rulers).
1143    highlightInspectorObject->getBoolean("showRulers", &showRulers);
1144    highlightConfig->showRulers = showRulers;
1145    highlightConfig->content = parseConfigColor("contentColor", highlightInspectorObject);
1146    highlightConfig->contentOutline = parseConfigColor("contentOutlineColor", highlightInspectorObject);
1147    highlightConfig->padding = parseConfigColor("paddingColor", highlightInspectorObject);
1148    highlightConfig->border = parseConfigColor("borderColor", highlightInspectorObject);
1149    highlightConfig->margin = parseConfigColor("marginColor", highlightInspectorObject);
1150    return highlightConfig.release();
1151}
1152
1153void InspectorDOMAgent::setInspectModeEnabled(ErrorString* errorString, bool enabled, const RefPtr<InspectorObject>* highlightConfig)
1154{
1155    setSearchingForNode(errorString, enabled, highlightConfig ? highlightConfig->get() : 0);
1156}
1157
1158void InspectorDOMAgent::highlightRect(ErrorString*, int x, int y, int width, int height, const RefPtr<InspectorObject>* color, const RefPtr<InspectorObject>* outlineColor, const bool* usePageCoordinates)
1159{
1160    OwnPtr<FloatQuad> quad = adoptPtr(new FloatQuad(FloatRect(x, y, width, height)));
1161    innerHighlightQuad(quad.release(), color, outlineColor, usePageCoordinates);
1162}
1163
1164void InspectorDOMAgent::highlightQuad(ErrorString* errorString, const RefPtr<InspectorArray>& quadArray, const RefPtr<InspectorObject>* color, const RefPtr<InspectorObject>* outlineColor, const bool* usePageCoordinates)
1165{
1166    OwnPtr<FloatQuad> quad = adoptPtr(new FloatQuad());
1167    if (!parseQuad(quadArray, quad.get())) {
1168        *errorString = "Invalid Quad format";
1169        return;
1170    }
1171    innerHighlightQuad(quad.release(), color, outlineColor, usePageCoordinates);
1172}
1173
1174void InspectorDOMAgent::innerHighlightQuad(PassOwnPtr<FloatQuad> quad, const RefPtr<InspectorObject>* color, const RefPtr<InspectorObject>* outlineColor, const bool* usePageCoordinates)
1175{
1176    OwnPtr<HighlightConfig> highlightConfig = adoptPtr(new HighlightConfig());
1177    highlightConfig->content = parseColor(color);
1178    highlightConfig->contentOutline = parseColor(outlineColor);
1179    highlightConfig->usePageCoordinates = usePageCoordinates ? *usePageCoordinates : false;
1180    m_overlay->highlightQuad(quad, *highlightConfig);
1181}
1182
1183void InspectorDOMAgent::highlightNode(ErrorString* errorString, const RefPtr<InspectorObject>& highlightInspectorObject, const int* nodeId, const String* objectId)
1184{
1185    Node* node = 0;
1186    if (nodeId) {
1187        node = assertNode(errorString, *nodeId);
1188    } else if (objectId) {
1189        InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(*objectId);
1190        node = injectedScript.nodeForObjectId(*objectId);
1191        if (!node)
1192            *errorString = "Node for given objectId not found";
1193    } else
1194        *errorString = "Either nodeId or objectId must be specified";
1195
1196    if (!node)
1197        return;
1198
1199    OwnPtr<HighlightConfig> highlightConfig = highlightConfigFromInspectorObject(errorString, highlightInspectorObject.get());
1200    if (!highlightConfig)
1201        return;
1202
1203    m_overlay->highlightNode(node, *highlightConfig);
1204}
1205
1206void InspectorDOMAgent::highlightFrame(
1207    ErrorString*,
1208    const String& frameId,
1209    const RefPtr<InspectorObject>* color,
1210    const RefPtr<InspectorObject>* outlineColor)
1211{
1212    Frame* frame = m_pageAgent->frameForId(frameId);
1213    if (frame && frame->ownerElement()) {
1214        OwnPtr<HighlightConfig> highlightConfig = adoptPtr(new HighlightConfig());
1215        highlightConfig->showInfo = true; // Always show tooltips for frames.
1216        highlightConfig->content = parseColor(color);
1217        highlightConfig->contentOutline = parseColor(outlineColor);
1218        m_overlay->highlightNode(frame->ownerElement(), *highlightConfig);
1219    }
1220}
1221
1222void InspectorDOMAgent::hideHighlight(ErrorString*)
1223{
1224    m_overlay->hideHighlight();
1225}
1226
1227void InspectorDOMAgent::moveTo(ErrorString* errorString, int nodeId, int targetElementId, const int* const anchorNodeId, int* newNodeId)
1228{
1229    Node* node = assertEditableNode(errorString, nodeId);
1230    if (!node)
1231        return;
1232
1233    Element* targetElement = assertEditableElement(errorString, targetElementId);
1234    if (!targetElement)
1235        return;
1236
1237    Node* anchorNode = 0;
1238    if (anchorNodeId && *anchorNodeId) {
1239        anchorNode = assertEditableNode(errorString, *anchorNodeId);
1240        if (!anchorNode)
1241            return;
1242        if (anchorNode->parentNode() != targetElement) {
1243            *errorString = "Anchor node must be child of the target element";
1244            return;
1245        }
1246    }
1247
1248    if (!m_domEditor->insertBefore(targetElement, node, anchorNode, errorString))
1249        return;
1250
1251    *newNodeId = pushNodePathToFrontend(node);
1252}
1253
1254void InspectorDOMAgent::undo(ErrorString* errorString)
1255{
1256    ExceptionCode ec = 0;
1257    m_history->undo(ec);
1258    *errorString = InspectorDOMAgent::toErrorString(ec);
1259}
1260
1261void InspectorDOMAgent::redo(ErrorString* errorString)
1262{
1263    ExceptionCode ec = 0;
1264    m_history->redo(ec);
1265    *errorString = InspectorDOMAgent::toErrorString(ec);
1266}
1267
1268void InspectorDOMAgent::markUndoableState(ErrorString*)
1269{
1270    m_history->markUndoableState();
1271}
1272
1273void InspectorDOMAgent::focus(ErrorString* errorString, int nodeId)
1274{
1275    Element* element = assertElement(errorString, nodeId);
1276    if (!element)
1277        return;
1278    if (!element->isFocusable()) {
1279        *errorString = "Element is not focusable";
1280        return;
1281    }
1282    element->focus();
1283}
1284
1285void InspectorDOMAgent::setFileInputFiles(ErrorString* errorString, int nodeId, const RefPtr<InspectorArray>& files)
1286{
1287    if (!m_client->canSetFileInputFiles()) {
1288        *errorString = "Cannot set file input files";
1289        return;
1290    }
1291
1292    Node* node = assertNode(errorString, nodeId);
1293    if (!node)
1294        return;
1295    HTMLInputElement* element = node->toInputElement();
1296    if (!element || !element->isFileUpload()) {
1297        *errorString = "Node is not a file input element";
1298        return;
1299    }
1300
1301    RefPtr<FileList> fileList = FileList::create();
1302    for (InspectorArray::const_iterator iter = files->begin(); iter != files->end(); ++iter) {
1303        String path;
1304        if (!(*iter)->asString(&path)) {
1305            *errorString = "Files must be strings";
1306            return;
1307        }
1308        fileList->append(File::create(path));
1309    }
1310    element->setFiles(fileList);
1311}
1312
1313void InspectorDOMAgent::resolveNode(ErrorString* errorString, int nodeId, const String* const objectGroup, RefPtr<TypeBuilder::Runtime::RemoteObject>& result)
1314{
1315    String objectGroupName = objectGroup ? *objectGroup : "";
1316    Node* node = nodeForId(nodeId);
1317    if (!node) {
1318        *errorString = "No node with given id found";
1319        return;
1320    }
1321    RefPtr<TypeBuilder::Runtime::RemoteObject> object = resolveNode(node, objectGroupName);
1322    if (!object) {
1323        *errorString = "Node with given id does not belong to the document";
1324        return;
1325    }
1326    result = object;
1327}
1328
1329void InspectorDOMAgent::getAttributes(ErrorString* errorString, int nodeId, RefPtr<TypeBuilder::Array<String> >& result)
1330{
1331    Element* element = assertElement(errorString, nodeId);
1332    if (!element)
1333        return;
1334
1335    result = buildArrayForElementAttributes(element);
1336}
1337
1338void InspectorDOMAgent::requestNode(ErrorString*, const String& objectId, int* nodeId)
1339{
1340    InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(objectId);
1341    Node* node = injectedScript.nodeForObjectId(objectId);
1342    if (node)
1343        *nodeId = pushNodePathToFrontend(node);
1344    else
1345        *nodeId = 0;
1346}
1347
1348// static
1349String InspectorDOMAgent::documentURLString(Document* document)
1350{
1351    if (!document || document->url().isNull())
1352        return "";
1353    return document->url().string();
1354}
1355
1356static String documentBaseURLString(Document* document)
1357{
1358    return document->completeURL("").string();
1359}
1360
1361PassRefPtr<TypeBuilder::DOM::Node> InspectorDOMAgent::buildObjectForNode(Node* node, int depth, NodeToIdMap* nodesMap)
1362{
1363    int id = bind(node, nodesMap);
1364    String nodeName;
1365    String localName;
1366    String nodeValue;
1367
1368    switch (node->nodeType()) {
1369    case Node::TEXT_NODE:
1370    case Node::COMMENT_NODE:
1371    case Node::CDATA_SECTION_NODE:
1372        nodeValue = node->nodeValue();
1373        if (nodeValue.length() > maxTextSize) {
1374            nodeValue = nodeValue.left(maxTextSize);
1375            nodeValue.append(ellipsisUChar);
1376        }
1377        break;
1378    case Node::ATTRIBUTE_NODE:
1379        localName = node->localName();
1380        break;
1381    case Node::DOCUMENT_FRAGMENT_NODE:
1382    case Node::DOCUMENT_NODE:
1383    case Node::ELEMENT_NODE:
1384    default:
1385        nodeName = node->nodeName();
1386        localName = node->localName();
1387        break;
1388    }
1389
1390    RefPtr<TypeBuilder::DOM::Node> value = TypeBuilder::DOM::Node::create()
1391        .setNodeId(id)
1392        .setNodeType(static_cast<int>(node->nodeType()))
1393        .setNodeName(nodeName)
1394        .setLocalName(localName)
1395        .setNodeValue(nodeValue);
1396
1397    if (node->isContainerNode()) {
1398        int nodeCount = innerChildNodeCount(node);
1399        value->setChildNodeCount(nodeCount);
1400        RefPtr<TypeBuilder::Array<TypeBuilder::DOM::Node> > children = buildArrayForContainerChildren(node, depth, nodesMap);
1401        if (children->length() > 0)
1402            value->setChildren(children.release());
1403    }
1404
1405    if (node->isElementNode()) {
1406        Element* element = toElement(node);
1407        value->setAttributes(buildArrayForElementAttributes(element));
1408        if (node->isFrameOwnerElement()) {
1409            HTMLFrameOwnerElement* frameOwner = static_cast<HTMLFrameOwnerElement*>(node);
1410            Frame* frame = frameOwner->contentFrame();
1411            if (frame)
1412                value->setFrameId(m_pageAgent->frameId(frame));
1413            Document* doc = frameOwner->contentDocument();
1414            if (doc)
1415                value->setContentDocument(buildObjectForNode(doc, 0, nodesMap));
1416        }
1417
1418        ElementShadow* shadow = element->shadow();
1419        if (shadow) {
1420            RefPtr<TypeBuilder::Array<TypeBuilder::DOM::Node> > shadowRoots = TypeBuilder::Array<TypeBuilder::DOM::Node>::create();
1421            if (ShadowRoot* root = shadow->shadowRoot())
1422                shadowRoots->addItem(buildObjectForNode(root, 0, nodesMap));
1423            value->setShadowRoots(shadowRoots);
1424        }
1425
1426#if ENABLE(TEMPLATE_ELEMENT)
1427        if (element->hasTagName(HTMLNames::templateTag))
1428            value->setTemplateContent(buildObjectForNode(static_cast<HTMLTemplateElement*>(element)->content(), 0, nodesMap));
1429#endif
1430
1431    } else if (node->isDocumentNode()) {
1432        Document* document = toDocument(node);
1433        value->setDocumentURL(documentURLString(document));
1434        value->setBaseURL(documentBaseURLString(document));
1435        value->setXmlVersion(document->xmlVersion());
1436    } else if (node->nodeType() == Node::DOCUMENT_TYPE_NODE) {
1437        DocumentType* docType = static_cast<DocumentType*>(node);
1438        value->setPublicId(docType->publicId());
1439        value->setSystemId(docType->systemId());
1440        value->setInternalSubset(docType->internalSubset());
1441    } else if (node->isAttributeNode()) {
1442        Attr* attribute = static_cast<Attr*>(node);
1443        value->setName(attribute->name());
1444        value->setValue(attribute->value());
1445    }
1446    return value.release();
1447}
1448
1449PassRefPtr<TypeBuilder::Array<String> > InspectorDOMAgent::buildArrayForElementAttributes(Element* element)
1450{
1451    RefPtr<TypeBuilder::Array<String> > attributesValue = TypeBuilder::Array<String>::create();
1452    // Go through all attributes and serialize them.
1453    if (!element->hasAttributes())
1454        return attributesValue.release();
1455    unsigned numAttrs = element->attributeCount();
1456    for (unsigned i = 0; i < numAttrs; ++i) {
1457        // Add attribute pair
1458        const Attribute* attribute = element->attributeItem(i);
1459        attributesValue->addItem(attribute->name().toString());
1460        attributesValue->addItem(attribute->value());
1461    }
1462    return attributesValue.release();
1463}
1464
1465PassRefPtr<TypeBuilder::Array<TypeBuilder::DOM::Node> > InspectorDOMAgent::buildArrayForContainerChildren(Node* container, int depth, NodeToIdMap* nodesMap)
1466{
1467    RefPtr<TypeBuilder::Array<TypeBuilder::DOM::Node> > children = TypeBuilder::Array<TypeBuilder::DOM::Node>::create();
1468    if (depth == 0) {
1469        // Special-case the only text child - pretend that container's children have been requested.
1470        Node* firstChild = container->firstChild();
1471        if (firstChild && firstChild->nodeType() == Node::TEXT_NODE && !firstChild->nextSibling()) {
1472            children->addItem(buildObjectForNode(firstChild, 0, nodesMap));
1473            m_childrenRequested.add(bind(container, nodesMap));
1474        }
1475        return children.release();
1476    }
1477
1478    Node* child = innerFirstChild(container);
1479    depth--;
1480    m_childrenRequested.add(bind(container, nodesMap));
1481
1482    while (child) {
1483        children->addItem(buildObjectForNode(child, depth, nodesMap));
1484        child = innerNextSibling(child);
1485    }
1486    return children.release();
1487}
1488
1489PassRefPtr<TypeBuilder::DOM::EventListener> InspectorDOMAgent::buildObjectForEventListener(const RegisteredEventListener& registeredEventListener, const AtomicString& eventType, Node* node, const String* objectGroupId)
1490{
1491    RefPtr<EventListener> eventListener = registeredEventListener.listener;
1492    Document* document = node->document();
1493    RefPtr<TypeBuilder::DOM::EventListener> value = TypeBuilder::DOM::EventListener::create()
1494        .setType(eventType)
1495        .setUseCapture(registeredEventListener.useCapture)
1496        .setIsAttribute(eventListener->isAttribute())
1497        .setNodeId(pushNodePathToFrontend(node))
1498        .setHandlerBody(eventListenerHandlerBody(document, eventListener.get()));
1499    if (objectGroupId) {
1500        ScriptValue functionValue = eventListenerHandler(document, eventListener.get());
1501        if (!functionValue.hasNoValue()) {
1502            Frame* frame = document->frame();
1503            if (frame) {
1504                ScriptState* scriptState = eventListenerHandlerScriptState(frame, eventListener.get());
1505                if (scriptState) {
1506                    InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(scriptState);
1507                    if (!injectedScript.hasNoValue()) {
1508                        RefPtr<TypeBuilder::Runtime::RemoteObject> valueJson = injectedScript.wrapObject(functionValue, *objectGroupId);
1509                        value->setHandler(valueJson);
1510                    }
1511                }
1512            }
1513        }
1514    }
1515    String sourceName;
1516    String scriptId;
1517    int lineNumber;
1518    if (eventListenerHandlerLocation(node->document(), eventListener.get(), sourceName, scriptId, lineNumber)) {
1519        RefPtr<TypeBuilder::Debugger::Location> location = TypeBuilder::Debugger::Location::create()
1520            .setScriptId(scriptId)
1521            .setLineNumber(lineNumber);
1522        value->setLocation(location);
1523        if (!sourceName.isEmpty())
1524            value->setSourceName(sourceName);
1525    }
1526    return value.release();
1527}
1528
1529Node* InspectorDOMAgent::innerFirstChild(Node* node)
1530{
1531    node = node->firstChild();
1532    while (isWhitespace(node))
1533        node = node->nextSibling();
1534    return node;
1535}
1536
1537Node* InspectorDOMAgent::innerNextSibling(Node* node)
1538{
1539    do {
1540        node = node->nextSibling();
1541    } while (isWhitespace(node));
1542    return node;
1543}
1544
1545Node* InspectorDOMAgent::innerPreviousSibling(Node* node)
1546{
1547    do {
1548        node = node->previousSibling();
1549    } while (isWhitespace(node));
1550    return node;
1551}
1552
1553unsigned InspectorDOMAgent::innerChildNodeCount(Node* node)
1554{
1555    unsigned count = 0;
1556    Node* child = innerFirstChild(node);
1557    while (child) {
1558        count++;
1559        child = innerNextSibling(child);
1560    }
1561    return count;
1562}
1563
1564Node* InspectorDOMAgent::innerParentNode(Node* node)
1565{
1566    if (node->isDocumentNode()) {
1567        Document* document = toDocument(node);
1568        return document->ownerElement();
1569    }
1570    return node->parentNode();
1571}
1572
1573bool InspectorDOMAgent::isWhitespace(Node* node)
1574{
1575    //TODO: pull ignoreWhitespace setting from the frontend and use here.
1576    return node && node->nodeType() == Node::TEXT_NODE && node->nodeValue().stripWhiteSpace().length() == 0;
1577}
1578
1579void InspectorDOMAgent::mainFrameDOMContentLoaded()
1580{
1581    // Re-push document once it is loaded.
1582    discardBindings();
1583    if (m_state->getBoolean(DOMAgentState::documentRequested))
1584        m_frontend->documentUpdated();
1585}
1586
1587void InspectorDOMAgent::loadEventFired(Document* document)
1588{
1589    Element* frameOwner = document->ownerElement();
1590    if (!frameOwner)
1591        return;
1592
1593    int frameOwnerId = m_documentNodeToIdMap.get(frameOwner);
1594    if (!frameOwnerId)
1595        return;
1596
1597    // Re-add frame owner element together with its new children.
1598    int parentId = m_documentNodeToIdMap.get(innerParentNode(frameOwner));
1599    m_frontend->childNodeRemoved(parentId, frameOwnerId);
1600    unbind(frameOwner, &m_documentNodeToIdMap);
1601
1602    RefPtr<TypeBuilder::DOM::Node> value = buildObjectForNode(frameOwner, 0, &m_documentNodeToIdMap);
1603    Node* previousSibling = innerPreviousSibling(frameOwner);
1604    int prevId = previousSibling ? m_documentNodeToIdMap.get(previousSibling) : 0;
1605    m_frontend->childNodeInserted(parentId, prevId, value.release());
1606}
1607
1608void InspectorDOMAgent::didInsertDOMNode(Node* node)
1609{
1610    if (isWhitespace(node))
1611        return;
1612
1613    // We could be attaching existing subtree. Forget the bindings.
1614    unbind(node, &m_documentNodeToIdMap);
1615
1616    ContainerNode* parent = node->parentNode();
1617    if (!parent)
1618        return;
1619
1620    int parentId = m_documentNodeToIdMap.get(parent);
1621    // Return if parent is not mapped yet.
1622    if (!parentId)
1623        return;
1624
1625    if (!m_childrenRequested.contains(parentId)) {
1626        // No children are mapped yet -> only notify on changes of hasChildren.
1627        m_frontend->childNodeCountUpdated(parentId, innerChildNodeCount(parent));
1628    } else {
1629        // Children have been requested -> return value of a new child.
1630        Node* prevSibling = innerPreviousSibling(node);
1631        int prevId = prevSibling ? m_documentNodeToIdMap.get(prevSibling) : 0;
1632        RefPtr<TypeBuilder::DOM::Node> value = buildObjectForNode(node, 0, &m_documentNodeToIdMap);
1633        m_frontend->childNodeInserted(parentId, prevId, value.release());
1634    }
1635}
1636
1637void InspectorDOMAgent::didRemoveDOMNode(Node* node)
1638{
1639    if (isWhitespace(node))
1640        return;
1641
1642    ContainerNode* parent = node->parentNode();
1643
1644    // If parent is not mapped yet -> ignore the event.
1645    if (!m_documentNodeToIdMap.contains(parent))
1646        return;
1647
1648    int parentId = m_documentNodeToIdMap.get(parent);
1649
1650    if (!m_childrenRequested.contains(parentId)) {
1651        // No children are mapped yet -> only notify on changes of hasChildren.
1652        if (innerChildNodeCount(parent) == 1)
1653            m_frontend->childNodeCountUpdated(parentId, 0);
1654    } else
1655        m_frontend->childNodeRemoved(parentId, m_documentNodeToIdMap.get(node));
1656    unbind(node, &m_documentNodeToIdMap);
1657}
1658
1659void InspectorDOMAgent::willModifyDOMAttr(Element*, const AtomicString& oldValue, const AtomicString& newValue)
1660{
1661    m_suppressAttributeModifiedEvent = (oldValue == newValue);
1662}
1663
1664void InspectorDOMAgent::didModifyDOMAttr(Element* element, const AtomicString& name, const AtomicString& value)
1665{
1666    bool shouldSuppressEvent = m_suppressAttributeModifiedEvent;
1667    m_suppressAttributeModifiedEvent = false;
1668    if (shouldSuppressEvent)
1669        return;
1670
1671    int id = boundNodeId(element);
1672    // If node is not mapped yet -> ignore the event.
1673    if (!id)
1674        return;
1675
1676    if (m_domListener)
1677        m_domListener->didModifyDOMAttr(element);
1678
1679    m_frontend->attributeModified(id, name, value);
1680}
1681
1682void InspectorDOMAgent::didRemoveDOMAttr(Element* element, const AtomicString& name)
1683{
1684    int id = boundNodeId(element);
1685    // If node is not mapped yet -> ignore the event.
1686    if (!id)
1687        return;
1688
1689    if (m_domListener)
1690        m_domListener->didModifyDOMAttr(element);
1691
1692    m_frontend->attributeRemoved(id, name);
1693}
1694
1695void InspectorDOMAgent::styleAttributeInvalidated(const Vector<Element*>& elements)
1696{
1697    RefPtr<TypeBuilder::Array<int> > nodeIds = TypeBuilder::Array<int>::create();
1698    for (unsigned i = 0, size = elements.size(); i < size; ++i) {
1699        Element* element = elements.at(i);
1700        int id = boundNodeId(element);
1701        // If node is not mapped yet -> ignore the event.
1702        if (!id)
1703            continue;
1704
1705        if (m_domListener)
1706            m_domListener->didModifyDOMAttr(element);
1707        nodeIds->addItem(id);
1708    }
1709    m_frontend->inlineStyleInvalidated(nodeIds.release());
1710}
1711
1712void InspectorDOMAgent::characterDataModified(CharacterData* characterData)
1713{
1714    int id = m_documentNodeToIdMap.get(characterData);
1715    if (!id) {
1716        // Push text node if it is being created.
1717        didInsertDOMNode(characterData);
1718        return;
1719    }
1720    m_frontend->characterDataModified(id, characterData->data());
1721}
1722
1723void InspectorDOMAgent::didInvalidateStyleAttr(Node* node)
1724{
1725    int id = m_documentNodeToIdMap.get(node);
1726    // If node is not mapped yet -> ignore the event.
1727    if (!id)
1728        return;
1729
1730    if (!m_revalidateStyleAttrTask)
1731        m_revalidateStyleAttrTask = adoptPtr(new RevalidateStyleAttributeTask(this));
1732    m_revalidateStyleAttrTask->scheduleFor(toElement(node));
1733}
1734
1735void InspectorDOMAgent::didPushShadowRoot(Element* host, ShadowRoot* root)
1736{
1737    int hostId = m_documentNodeToIdMap.get(host);
1738    if (hostId)
1739        m_frontend->shadowRootPushed(hostId, buildObjectForNode(root, 0, &m_documentNodeToIdMap));
1740}
1741
1742void InspectorDOMAgent::willPopShadowRoot(Element* host, ShadowRoot* root)
1743{
1744    int hostId = m_documentNodeToIdMap.get(host);
1745    int rootId = m_documentNodeToIdMap.get(root);
1746    if (hostId && rootId)
1747        m_frontend->shadowRootPopped(hostId, rootId);
1748}
1749
1750void InspectorDOMAgent::frameDocumentUpdated(Frame* frame)
1751{
1752    Document* document = frame->document();
1753    if (!document)
1754        return;
1755
1756    Page* page = frame->page();
1757    ASSERT(page);
1758    if (frame != page->mainFrame())
1759        return;
1760
1761    // Only update the main frame document, nested frame document updates are not required
1762    // (will be handled by loadEventFired()).
1763    setDocument(document);
1764}
1765
1766Node* InspectorDOMAgent::nodeForPath(const String& path)
1767{
1768    // The path is of form "1,HTML,2,BODY,1,DIV"
1769    if (!m_document)
1770        return 0;
1771
1772    Node* node = m_document.get();
1773    Vector<String> pathTokens;
1774    path.split(",", false, pathTokens);
1775    if (!pathTokens.size())
1776        return 0;
1777    for (size_t i = 0; i < pathTokens.size() - 1; i += 2) {
1778        bool success = true;
1779        unsigned childNumber = pathTokens[i].toUInt(&success);
1780        if (!success)
1781            return 0;
1782        if (childNumber >= innerChildNodeCount(node))
1783            return 0;
1784
1785        Node* child = innerFirstChild(node);
1786        String childName = pathTokens[i + 1];
1787        for (size_t j = 0; child && j < childNumber; ++j)
1788            child = innerNextSibling(child);
1789
1790        if (!child || child->nodeName() != childName)
1791            return 0;
1792        node = child;
1793    }
1794    return node;
1795}
1796
1797void InspectorDOMAgent::pushNodeByPathToFrontend(ErrorString* errorString, const String& path, int* nodeId)
1798{
1799    if (Node* node = nodeForPath(path))
1800        *nodeId = pushNodePathToFrontend(node);
1801    else
1802        *errorString = "No node with given path found";
1803}
1804
1805void InspectorDOMAgent::pushNodeByBackendIdToFrontend(ErrorString* errorString, BackendNodeId backendNodeId, int* nodeId)
1806{
1807    if (!m_backendIdToNode.contains(backendNodeId)) {
1808        *errorString = "No node with given backend id found";
1809        return;
1810    }
1811
1812    Node* node = m_backendIdToNode.get(backendNodeId).first;
1813    String nodeGroup = m_backendIdToNode.get(backendNodeId).second;
1814    *nodeId = pushNodePathToFrontend(node);
1815
1816    if (nodeGroup == "") {
1817        m_backendIdToNode.remove(backendNodeId);
1818        m_nodeGroupToBackendIdMap.find(nodeGroup)->value.remove(node);
1819    }
1820}
1821
1822PassRefPtr<TypeBuilder::Runtime::RemoteObject> InspectorDOMAgent::resolveNode(Node* node, const String& objectGroup)
1823{
1824    Document* document = node->isDocumentNode() ? node->document() : node->ownerDocument();
1825    Frame* frame = document ? document->frame() : 0;
1826    if (!frame)
1827        return 0;
1828
1829    InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(mainWorldScriptState(frame));
1830    if (injectedScript.hasNoValue())
1831        return 0;
1832
1833    return injectedScript.wrapNode(node, objectGroup);
1834}
1835
1836} // namespace WebCore
1837
1838#endif // ENABLE(INSPECTOR)
1839