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 "core/inspector/InspectorDOMAgent.h"
33
34#include "bindings/core/v8/ExceptionState.h"
35#include "bindings/core/v8/ScriptEventListener.h"
36#include "core/InputTypeNames.h"
37#include "core/dom/Attr.h"
38#include "core/dom/CharacterData.h"
39#include "core/dom/ContainerNode.h"
40#include "core/dom/DOMException.h"
41#include "core/dom/Document.h"
42#include "core/dom/DocumentFragment.h"
43#include "core/dom/DocumentType.h"
44#include "core/dom/Element.h"
45#include "core/dom/Node.h"
46#include "core/dom/PseudoElement.h"
47#include "core/dom/StaticNodeList.h"
48#include "core/dom/Text.h"
49#include "core/dom/shadow/ElementShadow.h"
50#include "core/dom/shadow/ShadowRoot.h"
51#include "core/editing/markup.h"
52#include "core/events/EventListener.h"
53#include "core/events/EventTarget.h"
54#include "core/fileapi/File.h"
55#include "core/fileapi/FileList.h"
56#include "core/frame/LocalFrame.h"
57#include "core/html/HTMLFrameOwnerElement.h"
58#include "core/html/HTMLInputElement.h"
59#include "core/html/HTMLLinkElement.h"
60#include "core/html/HTMLTemplateElement.h"
61#include "core/html/imports/HTMLImportChild.h"
62#include "core/html/imports/HTMLImportLoader.h"
63#include "core/inspector/DOMEditor.h"
64#include "core/inspector/DOMPatchSupport.h"
65#include "core/inspector/IdentifiersFactory.h"
66#include "core/inspector/InspectorHistory.h"
67#include "core/inspector/InspectorNodeIds.h"
68#include "core/inspector/InspectorOverlay.h"
69#include "core/inspector/InspectorPageAgent.h"
70#include "core/inspector/InspectorState.h"
71#include "core/inspector/InstrumentingAgents.h"
72#include "core/loader/DocumentLoader.h"
73#include "core/page/FrameTree.h"
74#include "core/page/Page.h"
75#include "core/rendering/HitTestResult.h"
76#include "core/rendering/RenderView.h"
77#include "core/xml/DocumentXPathEvaluator.h"
78#include "core/xml/XPathResult.h"
79#include "platform/PlatformGestureEvent.h"
80#include "platform/PlatformMouseEvent.h"
81#include "platform/PlatformTouchEvent.h"
82#include "wtf/ListHashSet.h"
83#include "wtf/text/CString.h"
84#include "wtf/text/WTFString.h"
85
86namespace blink {
87
88using namespace HTMLNames;
89
90namespace DOMAgentState {
91static const char domAgentEnabled[] = "domAgentEnabled";
92};
93
94static const size_t maxTextSize = 10000;
95static const UChar ellipsisUChar[] = { 0x2026, 0 };
96
97static Color parseColor(const RefPtr<JSONObject>* colorObject)
98{
99    if (!colorObject || !(*colorObject))
100        return Color::transparent;
101
102    int r;
103    int g;
104    int b;
105    bool success = (*colorObject)->getNumber("r", &r);
106    success |= (*colorObject)->getNumber("g", &g);
107    success |= (*colorObject)->getNumber("b", &b);
108    if (!success)
109        return Color::transparent;
110
111    double a;
112    success = (*colorObject)->getNumber("a", &a);
113    if (!success)
114        return Color(r, g, b);
115
116    // Clamp alpha to the [0..1] range.
117    if (a < 0)
118        a = 0;
119    else if (a > 1)
120        a = 1;
121
122    return Color(r, g, b, static_cast<int>(a * 255));
123}
124
125static Color parseConfigColor(const String& fieldName, JSONObject* configObject)
126{
127    const RefPtr<JSONObject> colorObject = configObject->getObject(fieldName);
128    return parseColor(&colorObject);
129}
130
131static bool parseQuad(const RefPtr<JSONArray>& quadArray, FloatQuad* quad)
132{
133    if (!quadArray)
134        return false;
135    const size_t coordinatesInQuad = 8;
136    double coordinates[coordinatesInQuad];
137    if (quadArray->length() != coordinatesInQuad)
138        return false;
139    for (size_t i = 0; i < coordinatesInQuad; ++i) {
140        if (!quadArray->get(i)->asNumber(coordinates + i))
141            return false;
142    }
143    quad->setP1(FloatPoint(coordinates[0], coordinates[1]));
144    quad->setP2(FloatPoint(coordinates[2], coordinates[3]));
145    quad->setP3(FloatPoint(coordinates[4], coordinates[5]));
146    quad->setP4(FloatPoint(coordinates[6], coordinates[7]));
147
148    return true;
149}
150
151static Node* hoveredNodeForPoint(LocalFrame* frame, const IntPoint& point, bool ignorePointerEventsNone)
152{
153    HitTestRequest::HitTestRequestType hitType = HitTestRequest::Move | HitTestRequest::ReadOnly | HitTestRequest::AllowChildFrameContent;
154    if (ignorePointerEventsNone)
155        hitType |= HitTestRequest::IgnorePointerEventsNone;
156    HitTestRequest request(hitType);
157    HitTestResult result(frame->view()->windowToContents(point));
158    frame->contentRenderer()->hitTest(request, result);
159    Node* node = result.innerPossiblyPseudoNode();
160    while (node && node->nodeType() == Node::TEXT_NODE)
161        node = node->parentNode();
162    return node;
163}
164
165static Node* hoveredNodeForEvent(LocalFrame* frame, const PlatformGestureEvent& event, bool ignorePointerEventsNone)
166{
167    return hoveredNodeForPoint(frame, event.position(), ignorePointerEventsNone);
168}
169
170static Node* hoveredNodeForEvent(LocalFrame* frame, const PlatformMouseEvent& event, bool ignorePointerEventsNone)
171{
172    return hoveredNodeForPoint(frame, event.position(), ignorePointerEventsNone);
173}
174
175static Node* hoveredNodeForEvent(LocalFrame* frame, const PlatformTouchEvent& event, bool ignorePointerEventsNone)
176{
177    const Vector<PlatformTouchPoint>& points = event.touchPoints();
178    if (!points.size())
179        return 0;
180    return hoveredNodeForPoint(frame, roundedIntPoint(points[0].pos()), ignorePointerEventsNone);
181}
182
183class RevalidateStyleAttributeTask FINAL : public NoBaseWillBeGarbageCollectedFinalized<RevalidateStyleAttributeTask> {
184    WTF_MAKE_FAST_ALLOCATED_WILL_BE_REMOVED;
185public:
186    explicit RevalidateStyleAttributeTask(InspectorDOMAgent*);
187    void scheduleFor(Element*);
188    void reset() { m_timer.stop(); }
189    void onTimer(Timer<RevalidateStyleAttributeTask>*);
190    void trace(Visitor*);
191
192private:
193    RawPtrWillBeMember<InspectorDOMAgent> m_domAgent;
194    Timer<RevalidateStyleAttributeTask> m_timer;
195    WillBeHeapHashSet<RefPtrWillBeMember<Element> > m_elements;
196};
197
198RevalidateStyleAttributeTask::RevalidateStyleAttributeTask(InspectorDOMAgent* domAgent)
199    : m_domAgent(domAgent)
200    , m_timer(this, &RevalidateStyleAttributeTask::onTimer)
201{
202}
203
204void RevalidateStyleAttributeTask::scheduleFor(Element* element)
205{
206    m_elements.add(element);
207    if (!m_timer.isActive())
208        m_timer.startOneShot(0, FROM_HERE);
209}
210
211void RevalidateStyleAttributeTask::onTimer(Timer<RevalidateStyleAttributeTask>*)
212{
213    // The timer is stopped on m_domAgent destruction, so this method will never be called after m_domAgent has been destroyed.
214    WillBeHeapVector<RawPtrWillBeMember<Element> > elements;
215    for (WillBePersistentHeapHashSet<RefPtrWillBeMember<Element> >::iterator it = m_elements.begin(), end = m_elements.end(); it != end; ++it)
216        elements.append(it->get());
217    m_domAgent->styleAttributeInvalidated(elements);
218
219    m_elements.clear();
220}
221
222void RevalidateStyleAttributeTask::trace(Visitor* visitor)
223{
224    visitor->trace(m_domAgent);
225#if ENABLE(OILPAN)
226    visitor->trace(m_elements);
227#endif
228}
229
230String InspectorDOMAgent::toErrorString(ExceptionState& exceptionState)
231{
232    if (exceptionState.hadException())
233        return DOMException::getErrorName(exceptionState.code()) + " " + exceptionState.message();
234    return "";
235}
236
237InspectorDOMAgent::InspectorDOMAgent(InspectorPageAgent* pageAgent, InjectedScriptManager* injectedScriptManager, InspectorOverlay* overlay)
238    : InspectorBaseAgent<InspectorDOMAgent>("DOM")
239    , m_pageAgent(pageAgent)
240    , m_injectedScriptManager(injectedScriptManager)
241    , m_overlay(overlay)
242    , m_frontend(0)
243    , m_domListener(nullptr)
244    , m_documentNodeToIdMap(adoptPtrWillBeNoop(new NodeToIdMap()))
245    , m_lastNodeId(1)
246    , m_searchingForNode(NotSearching)
247    , m_suppressAttributeModifiedEvent(false)
248    , m_listener(nullptr)
249{
250}
251
252InspectorDOMAgent::~InspectorDOMAgent()
253{
254#if !ENABLE(OILPAN)
255    reset();
256    ASSERT(m_searchingForNode == NotSearching);
257#endif
258}
259
260void InspectorDOMAgent::setFrontend(InspectorFrontend* frontend)
261{
262    ASSERT(!m_frontend);
263    m_history = adoptPtrWillBeNoop(new InspectorHistory());
264    m_domEditor = adoptPtrWillBeNoop(new DOMEditor(m_history.get()));
265
266    m_frontend = frontend->dom();
267    m_instrumentingAgents->setInspectorDOMAgent(this);
268    m_document = m_pageAgent->mainFrame()->document();
269}
270
271void InspectorDOMAgent::clearFrontend()
272{
273    ASSERT(m_frontend);
274
275    m_history.clear();
276    m_domEditor.clear();
277
278    ErrorString error;
279    setSearchingForNode(&error, NotSearching, 0);
280    hideHighlight(&error);
281
282    m_frontend = 0;
283    m_instrumentingAgents->setInspectorDOMAgent(0);
284    disable(0);
285    reset();
286}
287
288void InspectorDOMAgent::restore()
289{
290    if (!enabled())
291        return;
292    innerEnable();
293    notifyDocumentUpdated();
294}
295
296WillBeHeapVector<RawPtrWillBeMember<Document> > InspectorDOMAgent::documents()
297{
298    WillBeHeapVector<RawPtrWillBeMember<Document> > result;
299    for (Frame* frame = m_document->frame(); frame; frame = frame->tree().traverseNext()) {
300        if (!frame->isLocalFrame())
301            continue;
302        Document* document = toLocalFrame(frame)->document();
303        if (!document)
304            continue;
305        result.append(document);
306    }
307    return result;
308}
309
310void InspectorDOMAgent::reset()
311{
312    discardFrontendBindings();
313    m_document = nullptr;
314}
315
316void InspectorDOMAgent::setDOMListener(DOMListener* listener)
317{
318    m_domListener = listener;
319}
320
321void InspectorDOMAgent::setDocument(Document* doc)
322{
323    if (doc == m_document.get())
324        return;
325
326    reset();
327
328    m_document = doc;
329
330    if (!enabled())
331        return;
332
333    // Immediately communicate 0 document or document that has finished loading.
334    if (!doc || !doc->parsing())
335        m_frontend->documentUpdated();
336}
337
338void InspectorDOMAgent::releaseDanglingNodes()
339{
340    m_danglingNodeToIdMaps.clear();
341}
342
343int InspectorDOMAgent::bind(Node* node, NodeToIdMap* nodesMap)
344{
345    int id = nodesMap->get(node);
346    if (id)
347        return id;
348    id = m_lastNodeId++;
349    nodesMap->set(node, id);
350    m_idToNode.set(id, node);
351    m_idToNodesMap.set(id, nodesMap);
352    return id;
353}
354
355void InspectorDOMAgent::unbind(Node* node, NodeToIdMap* nodesMap)
356{
357    int id = nodesMap->get(node);
358    if (!id)
359        return;
360
361    m_idToNode.remove(id);
362    m_idToNodesMap.remove(id);
363
364    if (node->isFrameOwnerElement()) {
365        Document* contentDocument = toHTMLFrameOwnerElement(node)->contentDocument();
366        if (m_domListener)
367            m_domListener->didRemoveDocument(contentDocument);
368        if (contentDocument)
369            unbind(contentDocument, nodesMap);
370    }
371
372    for (ShadowRoot* root = node->youngestShadowRoot(); root; root = root->olderShadowRoot())
373        unbind(root, nodesMap);
374
375    if (node->isElementNode()) {
376        Element* element = toElement(node);
377        if (element->pseudoElement(BEFORE))
378            unbind(element->pseudoElement(BEFORE), nodesMap);
379        if (element->pseudoElement(AFTER))
380            unbind(element->pseudoElement(AFTER), nodesMap);
381
382        if (isHTMLLinkElement(*element)) {
383            HTMLLinkElement& linkElement = toHTMLLinkElement(*element);
384            if (linkElement.isImport() && linkElement.import())
385                unbind(linkElement.import(), nodesMap);
386        }
387    }
388
389    nodesMap->remove(node);
390    if (m_domListener)
391        m_domListener->didRemoveDOMNode(node);
392
393    bool childrenRequested = m_childrenRequested.contains(id);
394    if (childrenRequested) {
395        // Unbind subtree known to client recursively.
396        m_childrenRequested.remove(id);
397        Node* child = innerFirstChild(node);
398        while (child) {
399            unbind(child, nodesMap);
400            child = innerNextSibling(child);
401        }
402    }
403    if (nodesMap == m_documentNodeToIdMap.get())
404        m_cachedChildCount.remove(id);
405}
406
407Node* InspectorDOMAgent::assertNode(ErrorString* errorString, int nodeId)
408{
409    Node* node = nodeForId(nodeId);
410    if (!node) {
411        *errorString = "Could not find node with given id";
412        return 0;
413    }
414    return node;
415}
416
417Document* InspectorDOMAgent::assertDocument(ErrorString* errorString, int nodeId)
418{
419    Node* node = assertNode(errorString, nodeId);
420    if (!node)
421        return 0;
422
423    if (!(node->isDocumentNode())) {
424        *errorString = "Document is not available";
425        return 0;
426    }
427    return toDocument(node);
428}
429
430Element* InspectorDOMAgent::assertElement(ErrorString* errorString, int nodeId)
431{
432    Node* node = assertNode(errorString, nodeId);
433    if (!node)
434        return 0;
435
436    if (!node->isElementNode()) {
437        *errorString = "Node is not an Element";
438        return 0;
439    }
440    return toElement(node);
441}
442
443static ShadowRoot* userAgentShadowRoot(Node* node)
444{
445    if (!node || !node->isInShadowTree())
446        return 0;
447
448    Node* candidate = node;
449    while (candidate && !candidate->isShadowRoot())
450        candidate = candidate->parentOrShadowHostNode();
451    ASSERT(candidate);
452    ShadowRoot* shadowRoot = toShadowRoot(candidate);
453
454    return shadowRoot->type() == ShadowRoot::UserAgentShadowRoot ? shadowRoot : 0;
455}
456
457Node* InspectorDOMAgent::assertEditableNode(ErrorString* errorString, int nodeId)
458{
459    Node* node = assertNode(errorString, nodeId);
460    if (!node)
461        return 0;
462
463    if (node->isInShadowTree()) {
464        if (node->isShadowRoot()) {
465            *errorString = "Cannot edit shadow roots";
466            return 0;
467        }
468        if (userAgentShadowRoot(node)) {
469            *errorString = "Cannot edit nodes from user-agent shadow trees";
470            return 0;
471        }
472    }
473
474    if (node->isPseudoElement()) {
475        *errorString = "Cannot edit pseudo elements";
476        return 0;
477    }
478
479    return node;
480}
481
482Node* InspectorDOMAgent::assertEditableChildNode(ErrorString* errorString, Element* parentElement, int nodeId)
483{
484    Node* node = assertEditableNode(errorString, nodeId);
485    if (!node)
486        return 0;
487    if (node->parentNode() != parentElement) {
488        *errorString = "Anchor node must be child of the target element";
489        return 0;
490    }
491    return node;
492}
493
494Element* InspectorDOMAgent::assertEditableElement(ErrorString* errorString, int nodeId)
495{
496    Element* element = assertElement(errorString, nodeId);
497    if (!element)
498        return 0;
499
500    if (element->isInShadowTree() && userAgentShadowRoot(element)) {
501        *errorString = "Cannot edit elements from user-agent shadow trees";
502        return 0;
503    }
504
505    if (element->isPseudoElement()) {
506        *errorString = "Cannot edit pseudo elements";
507        return 0;
508    }
509
510    return element;
511}
512
513void InspectorDOMAgent::innerEnable()
514{
515    m_state->setBoolean(DOMAgentState::domAgentEnabled, true);
516    if (m_listener)
517        m_listener->domAgentWasEnabled();
518}
519
520void InspectorDOMAgent::enable(ErrorString*)
521{
522    if (enabled())
523        return;
524    innerEnable();
525    notifyDocumentUpdated();
526}
527
528void InspectorDOMAgent::notifyDocumentUpdated()
529{
530    m_document = nullptr;
531    setDocument(m_pageAgent->mainFrame()->document());
532}
533
534bool InspectorDOMAgent::enabled() const
535{
536    return m_state->getBoolean(DOMAgentState::domAgentEnabled);
537}
538
539void InspectorDOMAgent::disable(ErrorString* errorString)
540{
541    if (!enabled()) {
542        if (errorString)
543            *errorString = "DOM agent hasn't been enabled";
544        return;
545    }
546    m_state->setBoolean(DOMAgentState::domAgentEnabled, false);
547    reset();
548    if (m_listener)
549        m_listener->domAgentWasDisabled();
550}
551
552void InspectorDOMAgent::getDocument(ErrorString* errorString, RefPtr<TypeBuilder::DOM::Node>& root)
553{
554    // Backward compatibility. Mark agent as enabled when it requests document.
555    if (!enabled())
556        innerEnable();
557
558    if (!m_document) {
559        *errorString = "Document is not available";
560        return;
561    }
562
563    discardFrontendBindings();
564
565    root = buildObjectForNode(m_document.get(), 2, m_documentNodeToIdMap.get());
566}
567
568void InspectorDOMAgent::pushChildNodesToFrontend(int nodeId, int depth)
569{
570    Node* node = nodeForId(nodeId);
571    if (!node || (!node->isElementNode() && !node->isDocumentNode() && !node->isDocumentFragment()))
572        return;
573
574    NodeToIdMap* nodeMap = m_idToNodesMap.get(nodeId);
575
576    if (m_childrenRequested.contains(nodeId)) {
577        if (depth <= 1)
578            return;
579
580        depth--;
581
582        for (node = innerFirstChild(node); node; node = innerNextSibling(node)) {
583            int childNodeId = nodeMap->get(node);
584            ASSERT(childNodeId);
585            pushChildNodesToFrontend(childNodeId, depth);
586        }
587
588        return;
589    }
590
591    RefPtr<TypeBuilder::Array<TypeBuilder::DOM::Node> > children = buildArrayForContainerChildren(node, depth, nodeMap);
592    m_frontend->setChildNodes(nodeId, children.release());
593}
594
595void InspectorDOMAgent::discardFrontendBindings()
596{
597    if (m_history)
598        m_history->reset();
599    m_searchResults.clear();
600    m_documentNodeToIdMap->clear();
601    m_idToNode.clear();
602    m_idToNodesMap.clear();
603    releaseDanglingNodes();
604    m_childrenRequested.clear();
605    m_cachedChildCount.clear();
606    if (m_revalidateStyleAttrTask)
607        m_revalidateStyleAttrTask->reset();
608}
609
610Node* InspectorDOMAgent::nodeForId(int id)
611{
612    if (!id)
613        return 0;
614
615    WillBeHeapHashMap<int, RawPtrWillBeMember<Node> >::iterator it = m_idToNode.find(id);
616    if (it != m_idToNode.end())
617        return it->value;
618    return 0;
619}
620
621void InspectorDOMAgent::requestChildNodes(ErrorString* errorString, int nodeId, const int* depth)
622{
623    int sanitizedDepth;
624
625    if (!depth)
626        sanitizedDepth = 1;
627    else if (*depth == -1)
628        sanitizedDepth = INT_MAX;
629    else if (*depth > 0)
630        sanitizedDepth = *depth;
631    else {
632        *errorString = "Please provide a positive integer as a depth or -1 for entire subtree";
633        return;
634    }
635
636    pushChildNodesToFrontend(nodeId, sanitizedDepth);
637}
638
639void InspectorDOMAgent::querySelector(ErrorString* errorString, int nodeId, const String& selectors, int* elementId)
640{
641    *elementId = 0;
642    Node* node = assertNode(errorString, nodeId);
643    if (!node || !node->isContainerNode())
644        return;
645
646    TrackExceptionState exceptionState;
647    RefPtrWillBeRawPtr<Element> element = toContainerNode(node)->querySelector(AtomicString(selectors), exceptionState);
648    if (exceptionState.hadException()) {
649        *errorString = "DOM Error while querying";
650        return;
651    }
652
653    if (element)
654        *elementId = pushNodePathToFrontend(element.get());
655}
656
657void InspectorDOMAgent::querySelectorAll(ErrorString* errorString, int nodeId, const String& selectors, RefPtr<TypeBuilder::Array<int> >& result)
658{
659    Node* node = assertNode(errorString, nodeId);
660    if (!node || !node->isContainerNode())
661        return;
662
663    TrackExceptionState exceptionState;
664    RefPtrWillBeRawPtr<StaticElementList> elements = toContainerNode(node)->querySelectorAll(AtomicString(selectors), exceptionState);
665    if (exceptionState.hadException()) {
666        *errorString = "DOM Error while querying";
667        return;
668    }
669
670    result = TypeBuilder::Array<int>::create();
671
672    for (unsigned i = 0; i < elements->length(); ++i)
673        result->addItem(pushNodePathToFrontend(elements->item(i)));
674}
675
676int InspectorDOMAgent::pushNodePathToFrontend(Node* nodeToPush)
677{
678    ASSERT(nodeToPush);  // Invalid input
679
680    if (!m_document)
681        return 0;
682    if (!m_documentNodeToIdMap->contains(m_document))
683        return 0;
684
685    // Return id in case the node is known.
686    int result = m_documentNodeToIdMap->get(nodeToPush);
687    if (result)
688        return result;
689
690    Node* node = nodeToPush;
691    WillBeHeapVector<RawPtrWillBeMember<Node> > path;
692    NodeToIdMap* danglingMap = 0;
693
694    while (true) {
695        Node* parent = innerParentNode(node);
696        if (!parent) {
697            // Node being pushed is detached -> push subtree root.
698            OwnPtrWillBeRawPtr<NodeToIdMap> newMap = adoptPtrWillBeNoop(new NodeToIdMap);
699            danglingMap = newMap.get();
700            m_danglingNodeToIdMaps.append(newMap.release());
701            RefPtr<TypeBuilder::Array<TypeBuilder::DOM::Node> > children = TypeBuilder::Array<TypeBuilder::DOM::Node>::create();
702            children->addItem(buildObjectForNode(node, 0, danglingMap));
703            m_frontend->setChildNodes(0, children);
704            break;
705        } else {
706            path.append(parent);
707            if (m_documentNodeToIdMap->get(parent))
708                break;
709            node = parent;
710        }
711    }
712
713    NodeToIdMap* map = danglingMap ? danglingMap : m_documentNodeToIdMap.get();
714    for (int i = path.size() - 1; i >= 0; --i) {
715        int nodeId = map->get(path.at(i).get());
716        ASSERT(nodeId);
717        pushChildNodesToFrontend(nodeId);
718    }
719    return map->get(nodeToPush);
720}
721
722int InspectorDOMAgent::boundNodeId(Node* node)
723{
724    return m_documentNodeToIdMap->get(node);
725}
726
727void InspectorDOMAgent::setAttributeValue(ErrorString* errorString, int elementId, const String& name, const String& value)
728{
729    Element* element = assertEditableElement(errorString, elementId);
730    if (!element)
731        return;
732
733    m_domEditor->setAttribute(element, name, value, errorString);
734}
735
736void InspectorDOMAgent::setAttributesAsText(ErrorString* errorString, int elementId, const String& text, const String* const name)
737{
738    Element* element = assertEditableElement(errorString, elementId);
739    if (!element)
740        return;
741
742    String markup = "<span " + text + "></span>";
743    RefPtrWillBeRawPtr<DocumentFragment> fragment = element->document().createDocumentFragment();
744
745    bool shouldIgnoreCase = element->document().isHTMLDocument() && element->isHTMLElement();
746    // Not all elements can represent the context (i.e. IFRAME), hence using document.body.
747    if (shouldIgnoreCase && element->document().body())
748        fragment->parseHTML(markup, element->document().body(), AllowScriptingContent);
749    else
750        fragment->parseXML(markup, 0, AllowScriptingContent);
751
752    Element* parsedElement = fragment->firstChild() && fragment->firstChild()->isElementNode() ? toElement(fragment->firstChild()) : 0;
753    if (!parsedElement) {
754        *errorString = "Could not parse value as attributes";
755        return;
756    }
757
758    String caseAdjustedName = name ? (shouldIgnoreCase ? name->lower() : *name) : String();
759
760    AttributeCollection attributes = parsedElement->attributes();
761    if (attributes.isEmpty() && name) {
762        m_domEditor->removeAttribute(element, caseAdjustedName, errorString);
763        return;
764    }
765
766    bool foundOriginalAttribute = false;
767    AttributeCollection::iterator end = attributes.end();
768    for (AttributeCollection::iterator it = attributes.begin(); it != end; ++it) {
769        // Add attribute pair
770        String attributeName = it->name().toString();
771        if (shouldIgnoreCase)
772            attributeName = attributeName.lower();
773        foundOriginalAttribute |= name && attributeName == caseAdjustedName;
774        if (!m_domEditor->setAttribute(element, attributeName, it->value(), errorString))
775            return;
776    }
777
778    if (!foundOriginalAttribute && name && !name->stripWhiteSpace().isEmpty())
779        m_domEditor->removeAttribute(element, caseAdjustedName, errorString);
780}
781
782void InspectorDOMAgent::removeAttribute(ErrorString* errorString, int elementId, const String& name)
783{
784    Element* element = assertEditableElement(errorString, elementId);
785    if (!element)
786        return;
787
788    m_domEditor->removeAttribute(element, name, errorString);
789}
790
791void InspectorDOMAgent::removeNode(ErrorString* errorString, int nodeId)
792{
793    Node* node = assertEditableNode(errorString, nodeId);
794    if (!node)
795        return;
796
797    ContainerNode* parentNode = node->parentNode();
798    if (!parentNode) {
799        *errorString = "Cannot remove detached node";
800        return;
801    }
802
803    m_domEditor->removeChild(parentNode, node, errorString);
804}
805
806void InspectorDOMAgent::setNodeName(ErrorString* errorString, int nodeId, const String& tagName, int* newId)
807{
808    *newId = 0;
809
810    Node* oldNode = nodeForId(nodeId);
811    if (!oldNode || !oldNode->isElementNode())
812        return;
813
814    TrackExceptionState exceptionState;
815    RefPtrWillBeRawPtr<Element> newElem = oldNode->document().createElement(AtomicString(tagName), exceptionState);
816    if (exceptionState.hadException())
817        return;
818
819    // Copy over the original node's attributes.
820    newElem->cloneAttributesFromElement(*toElement(oldNode));
821
822    // Copy over the original node's children.
823    for (Node* child = oldNode->firstChild(); child; child = oldNode->firstChild()) {
824        if (!m_domEditor->insertBefore(newElem.get(), child, 0, errorString))
825            return;
826    }
827
828    // Replace the old node with the new node
829    ContainerNode* parent = oldNode->parentNode();
830    if (!m_domEditor->insertBefore(parent, newElem.get(), oldNode->nextSibling(), errorString))
831        return;
832    if (!m_domEditor->removeChild(parent, oldNode, errorString))
833        return;
834
835    *newId = pushNodePathToFrontend(newElem.get());
836    if (m_childrenRequested.contains(nodeId))
837        pushChildNodesToFrontend(*newId);
838}
839
840void InspectorDOMAgent::getOuterHTML(ErrorString* errorString, int nodeId, WTF::String* outerHTML)
841{
842    Node* node = assertNode(errorString, nodeId);
843    if (!node)
844        return;
845
846    *outerHTML = createMarkup(node);
847}
848
849void InspectorDOMAgent::setOuterHTML(ErrorString* errorString, int nodeId, const String& outerHTML)
850{
851    if (!nodeId) {
852        ASSERT(m_document);
853        DOMPatchSupport domPatchSupport(m_domEditor.get(), *m_document.get());
854        domPatchSupport.patchDocument(outerHTML);
855        return;
856    }
857
858    Node* node = assertEditableNode(errorString, nodeId);
859    if (!node)
860        return;
861
862    Document* document = node->isDocumentNode() ? toDocument(node) : node->ownerDocument();
863    if (!document || (!document->isHTMLDocument() && !document->isXMLDocument())) {
864        *errorString = "Not an HTML/XML document";
865        return;
866    }
867
868    Node* newNode = 0;
869    if (!m_domEditor->setOuterHTML(node, outerHTML, &newNode, errorString))
870        return;
871
872    if (!newNode) {
873        // The only child node has been deleted.
874        return;
875    }
876
877    int newId = pushNodePathToFrontend(newNode);
878
879    bool childrenRequested = m_childrenRequested.contains(nodeId);
880    if (childrenRequested)
881        pushChildNodesToFrontend(newId);
882}
883
884void InspectorDOMAgent::setNodeValue(ErrorString* errorString, int nodeId, const String& value)
885{
886    Node* node = assertEditableNode(errorString, nodeId);
887    if (!node)
888        return;
889
890    if (node->nodeType() != Node::TEXT_NODE) {
891        *errorString = "Can only set value of text nodes";
892        return;
893    }
894
895    m_domEditor->replaceWholeText(toText(node), value, errorString);
896}
897
898void InspectorDOMAgent::getEventListenersForNode(ErrorString* errorString, int nodeId, const String* objectGroup, RefPtr<TypeBuilder::Array<TypeBuilder::DOM::EventListener> >& listenersArray)
899{
900    listenersArray = TypeBuilder::Array<TypeBuilder::DOM::EventListener>::create();
901    Node* node = assertNode(errorString, nodeId);
902    if (!node)
903        return;
904    Vector<EventListenerInfo> eventInformation;
905    getEventListeners(node, eventInformation, true);
906
907    // Get Capturing Listeners (in this order)
908    size_t eventInformationLength = eventInformation.size();
909    for (size_t i = 0; i < eventInformationLength; ++i) {
910        const EventListenerInfo& info = eventInformation[i];
911        const EventListenerVector& vector = info.eventListenerVector;
912        for (size_t j = 0; j < vector.size(); ++j) {
913            const RegisteredEventListener& listener = vector[j];
914            if (listener.useCapture) {
915                RefPtr<TypeBuilder::DOM::EventListener> listenerObject = buildObjectForEventListener(listener, info.eventType, info.eventTarget->toNode(), objectGroup);
916                if (listenerObject)
917                    listenersArray->addItem(listenerObject);
918            }
919        }
920    }
921
922    // Get Bubbling Listeners (reverse order)
923    for (size_t i = eventInformationLength; i; --i) {
924        const EventListenerInfo& info = eventInformation[i - 1];
925        const EventListenerVector& vector = info.eventListenerVector;
926        for (size_t j = 0; j < vector.size(); ++j) {
927            const RegisteredEventListener& listener = vector[j];
928            if (!listener.useCapture) {
929                RefPtr<TypeBuilder::DOM::EventListener> listenerObject = buildObjectForEventListener(listener, info.eventType, info.eventTarget->toNode(), objectGroup);
930                if (listenerObject)
931                    listenersArray->addItem(listenerObject);
932            }
933        }
934    }
935}
936
937void InspectorDOMAgent::getEventListeners(EventTarget* target, Vector<EventListenerInfo>& eventInformation, bool includeAncestors)
938{
939    // The Node's Ancestors including self.
940    Vector<EventTarget*> ancestors;
941    ancestors.append(target);
942    if (includeAncestors) {
943        Node* node = target->toNode();
944        for (ContainerNode* ancestor = node ? node->parentOrShadowHostNode() : 0; ancestor; ancestor = ancestor->parentOrShadowHostNode())
945            ancestors.append(ancestor);
946    }
947
948    // Nodes and their Listeners for the concerned event types (order is top to bottom)
949    for (size_t i = ancestors.size(); i; --i) {
950        EventTarget* ancestor = ancestors[i - 1];
951        Vector<AtomicString> eventTypes = ancestor->eventTypes();
952        for (size_t j = 0; j < eventTypes.size(); ++j) {
953            AtomicString& type = eventTypes[j];
954            const EventListenerVector& listeners = ancestor->getEventListeners(type);
955            EventListenerVector filteredListeners;
956            filteredListeners.reserveCapacity(listeners.size());
957            for (size_t k = 0; k < listeners.size(); ++k) {
958                if (listeners[k].listener->type() == EventListener::JSEventListenerType)
959                    filteredListeners.append(listeners[k]);
960            }
961            if (!filteredListeners.isEmpty())
962                eventInformation.append(EventListenerInfo(ancestor, type, filteredListeners));
963        }
964    }
965}
966
967static Node* nextNodeWithShadowDOMInMind(const Node& current, const Node* stayWithin, bool includeUserAgentShadowDOM)
968{
969    // At first traverse the subtree.
970    if (current.isElementNode()) {
971        const Element& element = toElement(current);
972        ElementShadow* elementShadow = element.shadow();
973        if (elementShadow) {
974            ShadowRoot* shadowRoot = elementShadow->youngestShadowRoot();
975            if (shadowRoot) {
976                if (shadowRoot->type() == ShadowRoot::AuthorShadowRoot || includeUserAgentShadowDOM)
977                    return shadowRoot;
978            }
979        }
980    }
981    if (current.hasChildren())
982        return current.firstChild();
983
984    // Then traverse siblings of the node itself and its ancestors.
985    const Node* node = &current;
986    do {
987        if (node == stayWithin)
988            return 0;
989        if (node->isShadowRoot()) {
990            const ShadowRoot* shadowRoot = toShadowRoot(node);
991            if (shadowRoot->olderShadowRoot())
992                return shadowRoot->olderShadowRoot();
993            Node* host = shadowRoot->host();
994            if (host && host->hasChildren())
995                return host->firstChild();
996        }
997        if (node->nextSibling())
998            return node->nextSibling();
999        node = node->isShadowRoot() ? toShadowRoot(node)->host() : node->parentNode();
1000    } while (node);
1001
1002    return 0;
1003}
1004
1005void InspectorDOMAgent::performSearch(ErrorString*, const String& whitespaceTrimmedQuery, const bool* optionalIncludeUserAgentShadowDOM, String* searchId, int* resultCount)
1006{
1007    // FIXME: Few things are missing here:
1008    // 1) Search works with node granularity - number of matches within node is not calculated.
1009    // 2) There is no need to push all search results to the front-end at a time, pushing next / previous result
1010    //    is sufficient.
1011
1012    bool includeUserAgentShadowDOM = optionalIncludeUserAgentShadowDOM ? *optionalIncludeUserAgentShadowDOM : false;
1013
1014    unsigned queryLength = whitespaceTrimmedQuery.length();
1015    bool startTagFound = !whitespaceTrimmedQuery.find('<');
1016    bool endTagFound = whitespaceTrimmedQuery.reverseFind('>') + 1 == queryLength;
1017    bool startQuoteFound = !whitespaceTrimmedQuery.find('"');
1018    bool endQuoteFound = whitespaceTrimmedQuery.reverseFind('"') + 1 == queryLength;
1019    bool exactAttributeMatch = startQuoteFound && endQuoteFound;
1020
1021    String tagNameQuery = whitespaceTrimmedQuery;
1022    String attributeQuery = whitespaceTrimmedQuery;
1023    if (startTagFound)
1024        tagNameQuery = tagNameQuery.right(tagNameQuery.length() - 1);
1025    if (endTagFound)
1026        tagNameQuery = tagNameQuery.left(tagNameQuery.length() - 1);
1027    if (startQuoteFound)
1028        attributeQuery = attributeQuery.right(attributeQuery.length() - 1);
1029    if (endQuoteFound)
1030        attributeQuery = attributeQuery.left(attributeQuery.length() - 1);
1031
1032    WillBeHeapVector<RawPtrWillBeMember<Document> > docs = documents();
1033    WillBeHeapListHashSet<RawPtrWillBeMember<Node> > resultCollector;
1034
1035    for (WillBeHeapVector<RawPtrWillBeMember<Document> >::iterator it = docs.begin(); it != docs.end(); ++it) {
1036        Document* document = *it;
1037        Node* documentElement = document->documentElement();
1038        Node* node = documentElement;
1039        if (!node)
1040            continue;
1041
1042        // Manual plain text search.
1043        for (node = nextNodeWithShadowDOMInMind(*node, documentElement, includeUserAgentShadowDOM); node; node = nextNodeWithShadowDOMInMind(*node, documentElement, includeUserAgentShadowDOM)) {
1044            switch (node->nodeType()) {
1045            case Node::TEXT_NODE:
1046            case Node::COMMENT_NODE:
1047            case Node::CDATA_SECTION_NODE: {
1048                String text = node->nodeValue();
1049                if (text.findIgnoringCase(whitespaceTrimmedQuery) != kNotFound)
1050                    resultCollector.add(node);
1051                break;
1052            }
1053            case Node::ELEMENT_NODE: {
1054                if ((!startTagFound && !endTagFound && (node->nodeName().findIgnoringCase(tagNameQuery) != kNotFound))
1055                    || (startTagFound && endTagFound && equalIgnoringCase(node->nodeName(), tagNameQuery))
1056                    || (startTagFound && !endTagFound && node->nodeName().startsWith(tagNameQuery, false))
1057                    || (!startTagFound && endTagFound && node->nodeName().endsWith(tagNameQuery, false))) {
1058                    resultCollector.add(node);
1059                    break;
1060                }
1061                // Go through all attributes and serialize them.
1062                const Element* element = toElement(node);
1063                AttributeCollection attributes = element->attributes();
1064                AttributeCollection::iterator end = attributes.end();
1065                for (AttributeCollection::iterator it = attributes.begin(); it != end; ++it) {
1066                    // Add attribute pair
1067                    if (it->localName().find(whitespaceTrimmedQuery, 0, false) != kNotFound) {
1068                        resultCollector.add(node);
1069                        break;
1070                    }
1071                    size_t foundPosition = it->value().find(attributeQuery, 0, false);
1072                    if (foundPosition != kNotFound) {
1073                        if (!exactAttributeMatch || (!foundPosition && it->value().length() == attributeQuery.length())) {
1074                            resultCollector.add(node);
1075                            break;
1076                        }
1077                    }
1078                }
1079                break;
1080            }
1081            default:
1082                break;
1083            }
1084        }
1085
1086        // XPath evaluation
1087        for (WillBeHeapVector<RawPtrWillBeMember<Document> >::iterator it = docs.begin(); it != docs.end(); ++it) {
1088            Document* document = *it;
1089            ASSERT(document);
1090            TrackExceptionState exceptionState;
1091            RefPtrWillBeRawPtr<XPathResult> result = DocumentXPathEvaluator::evaluate(*document, whitespaceTrimmedQuery, document, nullptr, XPathResult::ORDERED_NODE_SNAPSHOT_TYPE, 0, exceptionState);
1092            if (exceptionState.hadException() || !result)
1093                continue;
1094
1095            unsigned long size = result->snapshotLength(exceptionState);
1096            for (unsigned long i = 0; !exceptionState.hadException() && i < size; ++i) {
1097                Node* node = result->snapshotItem(i, exceptionState);
1098                if (exceptionState.hadException())
1099                    break;
1100
1101                if (node->nodeType() == Node::ATTRIBUTE_NODE)
1102                    node = toAttr(node)->ownerElement();
1103                resultCollector.add(node);
1104            }
1105        }
1106
1107        // Selector evaluation
1108        for (WillBeHeapVector<RawPtrWillBeMember<Document> >::iterator it = docs.begin(); it != docs.end(); ++it) {
1109            Document* document = *it;
1110            TrackExceptionState exceptionState;
1111            RefPtrWillBeRawPtr<StaticElementList> elementList = document->querySelectorAll(AtomicString(whitespaceTrimmedQuery), exceptionState);
1112            if (exceptionState.hadException() || !elementList)
1113                continue;
1114
1115            unsigned size = elementList->length();
1116            for (unsigned i = 0; i < size; ++i)
1117                resultCollector.add(elementList->item(i));
1118        }
1119    }
1120
1121    *searchId = IdentifiersFactory::createIdentifier();
1122    WillBeHeapVector<RefPtrWillBeMember<Node> >* resultsIt = &m_searchResults.add(*searchId, WillBeHeapVector<RefPtrWillBeMember<Node> >()).storedValue->value;
1123
1124    for (WillBeHeapListHashSet<RawPtrWillBeMember<Node> >::iterator it = resultCollector.begin(); it != resultCollector.end(); ++it)
1125        resultsIt->append(*it);
1126
1127    *resultCount = resultsIt->size();
1128}
1129
1130void InspectorDOMAgent::getSearchResults(ErrorString* errorString, const String& searchId, int fromIndex, int toIndex, RefPtr<TypeBuilder::Array<int> >& nodeIds)
1131{
1132    SearchResults::iterator it = m_searchResults.find(searchId);
1133    if (it == m_searchResults.end()) {
1134        *errorString = "No search session with given id found";
1135        return;
1136    }
1137
1138    int size = it->value.size();
1139    if (fromIndex < 0 || toIndex > size || fromIndex >= toIndex) {
1140        *errorString = "Invalid search result range";
1141        return;
1142    }
1143
1144    nodeIds = TypeBuilder::Array<int>::create();
1145    for (int i = fromIndex; i < toIndex; ++i)
1146        nodeIds->addItem(pushNodePathToFrontend((it->value)[i].get()));
1147}
1148
1149void InspectorDOMAgent::discardSearchResults(ErrorString*, const String& searchId)
1150{
1151    m_searchResults.remove(searchId);
1152}
1153
1154bool InspectorDOMAgent::handleMousePress()
1155{
1156    if (m_searchingForNode == NotSearching)
1157        return false;
1158
1159    if (Node* node = m_overlay->highlightedNode()) {
1160        inspect(node);
1161        return true;
1162    }
1163    return false;
1164}
1165
1166bool InspectorDOMAgent::handleGestureEvent(LocalFrame* frame, const PlatformGestureEvent& event)
1167{
1168    if (m_searchingForNode == NotSearching || event.type() != PlatformEvent::GestureTap)
1169        return false;
1170    Node* node = hoveredNodeForEvent(frame, event, false);
1171    if (node && m_inspectModeHighlightConfig) {
1172        m_overlay->highlightNode(node, 0 /* eventTarget */, *m_inspectModeHighlightConfig, false);
1173        inspect(node);
1174        return true;
1175    }
1176    return false;
1177}
1178
1179bool InspectorDOMAgent::handleTouchEvent(LocalFrame* frame, const PlatformTouchEvent& event)
1180{
1181    if (m_searchingForNode == NotSearching)
1182        return false;
1183    Node* node = hoveredNodeForEvent(frame, event, false);
1184    if (node && m_inspectModeHighlightConfig) {
1185        m_overlay->highlightNode(node, 0 /* eventTarget */, *m_inspectModeHighlightConfig, false);
1186        inspect(node);
1187        return true;
1188    }
1189    return false;
1190}
1191
1192void InspectorDOMAgent::inspect(Node* inspectedNode)
1193{
1194    if (!m_frontend || !inspectedNode)
1195        return;
1196
1197    Node* node = inspectedNode;
1198    while (node && !node->isElementNode() && !node->isDocumentNode() && !node->isDocumentFragment())
1199        node = node->parentOrShadowHostNode();
1200
1201    if (!node)
1202        return;
1203
1204    int nodeId = pushNodePathToFrontend(node);
1205    if (nodeId)
1206        m_frontend->inspectNodeRequested(nodeId);
1207}
1208
1209bool InspectorDOMAgent::handleMouseMove(LocalFrame* frame, const PlatformMouseEvent& event)
1210{
1211    if (m_searchingForNode == NotSearching)
1212        return false;
1213
1214    if (!frame->view() || !frame->contentRenderer())
1215        return true;
1216    Node* node = hoveredNodeForEvent(frame, event, event.shiftKey());
1217
1218    // Do not highlight within UA shadow root unless requested.
1219    if (m_searchingForNode != SearchingForUAShadow) {
1220        ShadowRoot* uaShadowRoot = userAgentShadowRoot(node);
1221        if (uaShadowRoot)
1222            node = uaShadowRoot->host();
1223    }
1224
1225    // Shadow roots don't have boxes - use host element instead.
1226    if (node && node->isShadowRoot())
1227        node = node->parentOrShadowHostNode();
1228
1229    if (!node)
1230        return true;
1231
1232    Node* eventTarget = event.shiftKey() ? hoveredNodeForEvent(frame, event, false) : 0;
1233    if (eventTarget == node)
1234        eventTarget = 0;
1235
1236    if (node && m_inspectModeHighlightConfig)
1237        m_overlay->highlightNode(node, eventTarget, *m_inspectModeHighlightConfig, event.ctrlKey() || event.metaKey());
1238    return true;
1239}
1240
1241void InspectorDOMAgent::setSearchingForNode(ErrorString* errorString, SearchMode searchMode, JSONObject* highlightInspectorObject)
1242{
1243    if (m_searchingForNode == searchMode)
1244        return;
1245
1246    m_searchingForNode = searchMode;
1247    m_overlay->setInspectModeEnabled(searchMode != NotSearching);
1248    if (searchMode != NotSearching) {
1249        m_inspectModeHighlightConfig = highlightConfigFromInspectorObject(errorString, highlightInspectorObject);
1250        if (!m_inspectModeHighlightConfig)
1251            return;
1252    } else
1253        hideHighlight(errorString);
1254}
1255
1256PassOwnPtr<HighlightConfig> InspectorDOMAgent::highlightConfigFromInspectorObject(ErrorString* errorString, JSONObject* highlightInspectorObject)
1257{
1258    if (!highlightInspectorObject) {
1259        *errorString = "Internal error: highlight configuration parameter is missing";
1260        return nullptr;
1261    }
1262
1263    OwnPtr<HighlightConfig> highlightConfig = adoptPtr(new HighlightConfig());
1264    bool showInfo = false; // Default: false (do not show a tooltip).
1265    highlightInspectorObject->getBoolean("showInfo", &showInfo);
1266    highlightConfig->showInfo = showInfo;
1267    bool showRulers = false; // Default: false (do not show rulers).
1268    highlightInspectorObject->getBoolean("showRulers", &showRulers);
1269    highlightConfig->showRulers = showRulers;
1270    bool showExtensionLines = false; // Default: false (do not show extension lines).
1271    highlightInspectorObject->getBoolean("showExtensionLines", &showExtensionLines);
1272    highlightConfig->showExtensionLines = showExtensionLines;
1273    highlightConfig->content = parseConfigColor("contentColor", highlightInspectorObject);
1274    highlightConfig->contentOutline = parseConfigColor("contentOutlineColor", highlightInspectorObject);
1275    highlightConfig->padding = parseConfigColor("paddingColor", highlightInspectorObject);
1276    highlightConfig->border = parseConfigColor("borderColor", highlightInspectorObject);
1277    highlightConfig->margin = parseConfigColor("marginColor", highlightInspectorObject);
1278    highlightConfig->eventTarget = parseConfigColor("eventTargetColor", highlightInspectorObject);
1279    highlightConfig->shape = parseConfigColor("shapeColor", highlightInspectorObject);
1280    highlightConfig->shapeMargin = parseConfigColor("shapeMarginColor", highlightInspectorObject);
1281
1282    return highlightConfig.release();
1283}
1284
1285void InspectorDOMAgent::setInspectModeEnabled(ErrorString* errorString, bool enabled, const bool* inspectUAShadowDOM, const RefPtr<JSONObject>* highlightConfig)
1286{
1287    if (enabled && !pushDocumentUponHandlelessOperation(errorString))
1288        return;
1289    SearchMode searchMode = enabled ? (asBool(inspectUAShadowDOM) ? SearchingForUAShadow : SearchingForNormal) : NotSearching;
1290    setSearchingForNode(errorString, searchMode, highlightConfig ? highlightConfig->get() : 0);
1291}
1292
1293void InspectorDOMAgent::highlightRect(ErrorString*, int x, int y, int width, int height, const RefPtr<JSONObject>* color, const RefPtr<JSONObject>* outlineColor)
1294{
1295    OwnPtr<FloatQuad> quad = adoptPtr(new FloatQuad(FloatRect(x, y, width, height)));
1296    innerHighlightQuad(quad.release(), color, outlineColor);
1297}
1298
1299void InspectorDOMAgent::highlightQuad(ErrorString* errorString, const RefPtr<JSONArray>& quadArray, const RefPtr<JSONObject>* color, const RefPtr<JSONObject>* outlineColor)
1300{
1301    OwnPtr<FloatQuad> quad = adoptPtr(new FloatQuad());
1302    if (!parseQuad(quadArray, quad.get())) {
1303        *errorString = "Invalid Quad format";
1304        return;
1305    }
1306    innerHighlightQuad(quad.release(), color, outlineColor);
1307}
1308
1309void InspectorDOMAgent::innerHighlightQuad(PassOwnPtr<FloatQuad> quad, const RefPtr<JSONObject>* color, const RefPtr<JSONObject>* outlineColor)
1310{
1311    OwnPtr<HighlightConfig> highlightConfig = adoptPtr(new HighlightConfig());
1312    highlightConfig->content = parseColor(color);
1313    highlightConfig->contentOutline = parseColor(outlineColor);
1314    m_overlay->highlightQuad(quad, *highlightConfig);
1315}
1316
1317void InspectorDOMAgent::highlightNode(ErrorString* errorString, const RefPtr<JSONObject>& highlightInspectorObject, const int* nodeId, const String* objectId)
1318{
1319    Node* node = 0;
1320    if (nodeId) {
1321        node = assertNode(errorString, *nodeId);
1322    } else if (objectId) {
1323        InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(*objectId);
1324        node = injectedScript.nodeForObjectId(*objectId);
1325        if (!node)
1326            *errorString = "Node for given objectId not found";
1327    } else
1328        *errorString = "Either nodeId or objectId must be specified";
1329
1330    if (!node)
1331        return;
1332
1333    OwnPtr<HighlightConfig> highlightConfig = highlightConfigFromInspectorObject(errorString, highlightInspectorObject.get());
1334    if (!highlightConfig)
1335        return;
1336
1337    m_overlay->highlightNode(node, 0 /* eventTarget */, *highlightConfig, false);
1338}
1339
1340void InspectorDOMAgent::highlightFrame(
1341    ErrorString*,
1342    const String& frameId,
1343    const RefPtr<JSONObject>* color,
1344    const RefPtr<JSONObject>* outlineColor)
1345{
1346    LocalFrame* frame = m_pageAgent->frameForId(frameId);
1347    // FIXME: Inspector doesn't currently work cross process.
1348    if (frame && frame->deprecatedLocalOwner()) {
1349        OwnPtr<HighlightConfig> highlightConfig = adoptPtr(new HighlightConfig());
1350        highlightConfig->showInfo = true; // Always show tooltips for frames.
1351        highlightConfig->content = parseColor(color);
1352        highlightConfig->contentOutline = parseColor(outlineColor);
1353        m_overlay->highlightNode(frame->deprecatedLocalOwner(), 0 /* eventTarget */, *highlightConfig, false);
1354    }
1355}
1356
1357void InspectorDOMAgent::hideHighlight(ErrorString*)
1358{
1359    m_overlay->hideHighlight();
1360}
1361
1362void InspectorDOMAgent::copyTo(ErrorString* errorString, int nodeId, int targetElementId, const int* const anchorNodeId, int* newNodeId)
1363{
1364    Node* node = assertEditableNode(errorString, nodeId);
1365    if (!node)
1366        return;
1367
1368    Element* targetElement = assertEditableElement(errorString, targetElementId);
1369    if (!targetElement)
1370        return;
1371
1372    Node* anchorNode = 0;
1373    if (anchorNodeId && *anchorNodeId) {
1374        anchorNode = assertEditableChildNode(errorString, targetElement, *anchorNodeId);
1375        if (!anchorNode)
1376            return;
1377    }
1378
1379    // The clone is deep by default.
1380    RefPtrWillBeRawPtr<Node> clonedNode = node->cloneNode(true);
1381    if (!clonedNode) {
1382        *errorString = "Failed to clone node";
1383        return;
1384    }
1385    if (!m_domEditor->insertBefore(targetElement, clonedNode, anchorNode, errorString))
1386        return;
1387
1388    *newNodeId = pushNodePathToFrontend(clonedNode.get());
1389}
1390
1391void InspectorDOMAgent::moveTo(ErrorString* errorString, int nodeId, int targetElementId, const int* const anchorNodeId, int* newNodeId)
1392{
1393    Node* node = assertEditableNode(errorString, nodeId);
1394    if (!node)
1395        return;
1396
1397    Element* targetElement = assertEditableElement(errorString, targetElementId);
1398    if (!targetElement)
1399        return;
1400
1401    Node* current = targetElement;
1402    while (current) {
1403        if (current == node) {
1404            *errorString = "Unable to move node into self or descendant";
1405            return;
1406        }
1407        current = current->parentNode();
1408    }
1409
1410    Node* anchorNode = 0;
1411    if (anchorNodeId && *anchorNodeId) {
1412        anchorNode = assertEditableChildNode(errorString, targetElement, *anchorNodeId);
1413        if (!anchorNode)
1414            return;
1415    }
1416
1417    if (!m_domEditor->insertBefore(targetElement, node, anchorNode, errorString))
1418        return;
1419
1420    *newNodeId = pushNodePathToFrontend(node);
1421}
1422
1423void InspectorDOMAgent::undo(ErrorString* errorString)
1424{
1425    TrackExceptionState exceptionState;
1426    m_history->undo(exceptionState);
1427    *errorString = InspectorDOMAgent::toErrorString(exceptionState);
1428}
1429
1430void InspectorDOMAgent::redo(ErrorString* errorString)
1431{
1432    TrackExceptionState exceptionState;
1433    m_history->redo(exceptionState);
1434    *errorString = InspectorDOMAgent::toErrorString(exceptionState);
1435}
1436
1437void InspectorDOMAgent::markUndoableState(ErrorString*)
1438{
1439    m_history->markUndoableState();
1440}
1441
1442void InspectorDOMAgent::focus(ErrorString* errorString, int nodeId)
1443{
1444    Element* element = assertElement(errorString, nodeId);
1445    if (!element)
1446        return;
1447
1448    element->document().updateLayoutIgnorePendingStylesheets();
1449    if (!element->isFocusable()) {
1450        *errorString = "Element is not focusable";
1451        return;
1452    }
1453    element->focus();
1454}
1455
1456void InspectorDOMAgent::setFileInputFiles(ErrorString* errorString, int nodeId, const RefPtr<JSONArray>& files)
1457{
1458    Node* node = assertNode(errorString, nodeId);
1459    if (!node)
1460        return;
1461    if (!isHTMLInputElement(*node) || toHTMLInputElement(*node).type() != InputTypeNames::file) {
1462        *errorString = "Node is not a file input element";
1463        return;
1464    }
1465
1466    RefPtrWillBeRawPtr<FileList> fileList = FileList::create();
1467    for (JSONArray::const_iterator iter = files->begin(); iter != files->end(); ++iter) {
1468        String path;
1469        if (!(*iter)->asString(&path)) {
1470            *errorString = "Files must be strings";
1471            return;
1472        }
1473        fileList->append(File::create(path));
1474    }
1475    toHTMLInputElement(node)->setFiles(fileList);
1476}
1477
1478void InspectorDOMAgent::getBoxModel(ErrorString* errorString, int nodeId, RefPtr<TypeBuilder::DOM::BoxModel>& model)
1479{
1480    Node* node = assertNode(errorString, nodeId);
1481    if (!node)
1482        return;
1483
1484    bool result = m_overlay->getBoxModel(node, model);
1485    if (!result)
1486        *errorString = "Could not compute box model.";
1487
1488}
1489
1490void InspectorDOMAgent::getNodeForLocation(ErrorString* errorString, int x, int y, int* nodeId)
1491{
1492    if (!pushDocumentUponHandlelessOperation(errorString))
1493        return;
1494    HitTestRequest request(HitTestRequest::Move | HitTestRequest::ReadOnly | HitTestRequest::AllowChildFrameContent);
1495    HitTestResult result(IntPoint(x, y));
1496    m_document->frame()->contentRenderer()->hitTest(request, result);
1497    Node* node = result.innerPossiblyPseudoNode();
1498    while (node && node->nodeType() == Node::TEXT_NODE)
1499        node = node->parentNode();
1500    if (!node) {
1501        *errorString = "No node found at given location";
1502        return;
1503    }
1504    *nodeId = pushNodePathToFrontend(node);
1505}
1506
1507void InspectorDOMAgent::resolveNode(ErrorString* errorString, int nodeId, const String* const objectGroup, RefPtr<TypeBuilder::Runtime::RemoteObject>& result)
1508{
1509    String objectGroupName = objectGroup ? *objectGroup : "";
1510    Node* node = nodeForId(nodeId);
1511    if (!node) {
1512        *errorString = "No node with given id found";
1513        return;
1514    }
1515    RefPtr<TypeBuilder::Runtime::RemoteObject> object = resolveNode(node, objectGroupName);
1516    if (!object) {
1517        *errorString = "Node with given id does not belong to the document";
1518        return;
1519    }
1520    result = object;
1521}
1522
1523void InspectorDOMAgent::getAttributes(ErrorString* errorString, int nodeId, RefPtr<TypeBuilder::Array<String> >& result)
1524{
1525    Element* element = assertElement(errorString, nodeId);
1526    if (!element)
1527        return;
1528
1529    result = buildArrayForElementAttributes(element);
1530}
1531
1532void InspectorDOMAgent::requestNode(ErrorString*, const String& objectId, int* nodeId)
1533{
1534    InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(objectId);
1535    Node* node = injectedScript.nodeForObjectId(objectId);
1536    if (node)
1537        *nodeId = pushNodePathToFrontend(node);
1538    else
1539        *nodeId = 0;
1540}
1541
1542// static
1543String InspectorDOMAgent::documentURLString(Document* document)
1544{
1545    if (!document || document->url().isNull())
1546        return "";
1547    return document->url().string();
1548}
1549
1550static String documentBaseURLString(Document* document)
1551{
1552    return document->completeURL("").string();
1553}
1554
1555static TypeBuilder::DOM::ShadowRootType::Enum shadowRootType(ShadowRoot* shadowRoot)
1556{
1557    switch (shadowRoot->type()) {
1558    case ShadowRoot::UserAgentShadowRoot:
1559        return TypeBuilder::DOM::ShadowRootType::User_agent;
1560    case ShadowRoot::AuthorShadowRoot:
1561        return TypeBuilder::DOM::ShadowRootType::Author;
1562    }
1563    ASSERT_NOT_REACHED();
1564    return TypeBuilder::DOM::ShadowRootType::User_agent;
1565}
1566
1567PassRefPtr<TypeBuilder::DOM::Node> InspectorDOMAgent::buildObjectForNode(Node* node, int depth, NodeToIdMap* nodesMap)
1568{
1569    int id = bind(node, nodesMap);
1570    String nodeName;
1571    String localName;
1572    String nodeValue;
1573
1574    switch (node->nodeType()) {
1575    case Node::TEXT_NODE:
1576    case Node::COMMENT_NODE:
1577    case Node::CDATA_SECTION_NODE:
1578        nodeValue = node->nodeValue();
1579        if (nodeValue.length() > maxTextSize)
1580            nodeValue = nodeValue.left(maxTextSize) + ellipsisUChar;
1581        break;
1582    case Node::ATTRIBUTE_NODE:
1583        localName = node->localName();
1584        break;
1585    case Node::DOCUMENT_FRAGMENT_NODE:
1586    case Node::DOCUMENT_NODE:
1587    case Node::ELEMENT_NODE:
1588    default:
1589        nodeName = node->nodeName();
1590        localName = node->localName();
1591        break;
1592    }
1593
1594    RefPtr<TypeBuilder::DOM::Node> value = TypeBuilder::DOM::Node::create()
1595        .setNodeId(id)
1596        .setNodeType(static_cast<int>(node->nodeType()))
1597        .setNodeName(nodeName)
1598        .setLocalName(localName)
1599        .setNodeValue(nodeValue);
1600
1601    bool forcePushChildren = false;
1602    if (node->isElementNode()) {
1603        Element* element = toElement(node);
1604        value->setAttributes(buildArrayForElementAttributes(element));
1605
1606        if (node->isFrameOwnerElement()) {
1607            HTMLFrameOwnerElement* frameOwner = toHTMLFrameOwnerElement(node);
1608            LocalFrame* frame = (frameOwner->contentFrame() && frameOwner->contentFrame()->isLocalFrame()) ? toLocalFrame(frameOwner->contentFrame()) : 0;
1609            if (frame)
1610                value->setFrameId(m_pageAgent->frameId(frame));
1611            if (Document* doc = frameOwner->contentDocument())
1612                value->setContentDocument(buildObjectForNode(doc, 0, nodesMap));
1613        }
1614
1615        ElementShadow* shadow = element->shadow();
1616        if (shadow) {
1617            RefPtr<TypeBuilder::Array<TypeBuilder::DOM::Node> > shadowRoots = TypeBuilder::Array<TypeBuilder::DOM::Node>::create();
1618            for (ShadowRoot* root = shadow->youngestShadowRoot(); root; root = root->olderShadowRoot())
1619                shadowRoots->addItem(buildObjectForNode(root, 0, nodesMap));
1620            value->setShadowRoots(shadowRoots);
1621            forcePushChildren = true;
1622        }
1623
1624        if (isHTMLLinkElement(*element)) {
1625            HTMLLinkElement& linkElement = toHTMLLinkElement(*element);
1626            if (linkElement.isImport() && linkElement.import() && innerParentNode(linkElement.import()) == linkElement)
1627                value->setImportedDocument(buildObjectForNode(linkElement.import(), 0, nodesMap));
1628            forcePushChildren = true;
1629        }
1630
1631        if (isHTMLTemplateElement(*element)) {
1632            value->setTemplateContent(buildObjectForNode(toHTMLTemplateElement(*element).content(), 0, nodesMap));
1633            forcePushChildren = true;
1634        }
1635
1636        switch (element->pseudoId()) {
1637        case BEFORE:
1638            value->setPseudoType(TypeBuilder::DOM::PseudoType::Before);
1639            break;
1640        case AFTER:
1641            value->setPseudoType(TypeBuilder::DOM::PseudoType::After);
1642            break;
1643        default: {
1644            RefPtr<TypeBuilder::Array<TypeBuilder::DOM::Node> > pseudoElements = buildArrayForPseudoElements(element, nodesMap);
1645            if (pseudoElements) {
1646                value->setPseudoElements(pseudoElements.release());
1647                forcePushChildren = true;
1648            }
1649            break;
1650        }
1651        }
1652    } else if (node->isDocumentNode()) {
1653        Document* document = toDocument(node);
1654        value->setDocumentURL(documentURLString(document));
1655        value->setBaseURL(documentBaseURLString(document));
1656        value->setXmlVersion(document->xmlVersion());
1657    } else if (node->isDocumentTypeNode()) {
1658        DocumentType* docType = toDocumentType(node);
1659        value->setPublicId(docType->publicId());
1660        value->setSystemId(docType->systemId());
1661    } else if (node->isAttributeNode()) {
1662        Attr* attribute = toAttr(node);
1663        value->setName(attribute->name());
1664        value->setValue(attribute->value());
1665    } else if (node->isShadowRoot()) {
1666        value->setShadowRootType(shadowRootType(toShadowRoot(node)));
1667    }
1668
1669    if (node->isContainerNode()) {
1670        int nodeCount = innerChildNodeCount(node);
1671        value->setChildNodeCount(nodeCount);
1672        if (nodesMap == m_documentNodeToIdMap)
1673            m_cachedChildCount.set(id, nodeCount);
1674        if (forcePushChildren && !depth)
1675            depth = 1;
1676        RefPtr<TypeBuilder::Array<TypeBuilder::DOM::Node> > children = buildArrayForContainerChildren(node, depth, nodesMap);
1677        if (children->length() > 0 || depth) // Push children along with shadow in any case.
1678            value->setChildren(children.release());
1679    }
1680
1681    return value.release();
1682}
1683
1684PassRefPtr<TypeBuilder::Array<String> > InspectorDOMAgent::buildArrayForElementAttributes(Element* element)
1685{
1686    RefPtr<TypeBuilder::Array<String> > attributesValue = TypeBuilder::Array<String>::create();
1687    // Go through all attributes and serialize them.
1688    AttributeCollection attributes = element->attributes();
1689    AttributeCollection::iterator end = attributes.end();
1690    for (AttributeCollection::iterator it = attributes.begin(); it != end; ++it) {
1691        // Add attribute pair
1692        attributesValue->addItem(it->name().toString());
1693        attributesValue->addItem(it->value());
1694    }
1695    return attributesValue.release();
1696}
1697
1698PassRefPtr<TypeBuilder::Array<TypeBuilder::DOM::Node> > InspectorDOMAgent::buildArrayForContainerChildren(Node* container, int depth, NodeToIdMap* nodesMap)
1699{
1700    RefPtr<TypeBuilder::Array<TypeBuilder::DOM::Node> > children = TypeBuilder::Array<TypeBuilder::DOM::Node>::create();
1701    if (depth == 0) {
1702        // Special-case the only text child - pretend that container's children have been requested.
1703        Node* firstChild = container->firstChild();
1704        if (firstChild && firstChild->nodeType() == Node::TEXT_NODE && !firstChild->nextSibling()) {
1705            children->addItem(buildObjectForNode(firstChild, 0, nodesMap));
1706            m_childrenRequested.add(bind(container, nodesMap));
1707        }
1708        return children.release();
1709    }
1710
1711    Node* child = innerFirstChild(container);
1712    depth--;
1713    m_childrenRequested.add(bind(container, nodesMap));
1714
1715    while (child) {
1716        children->addItem(buildObjectForNode(child, depth, nodesMap));
1717        child = innerNextSibling(child);
1718    }
1719    return children.release();
1720}
1721
1722PassRefPtr<TypeBuilder::DOM::EventListener> InspectorDOMAgent::buildObjectForEventListener(const RegisteredEventListener& registeredEventListener, const AtomicString& eventType, Node* node, const String* objectGroupId)
1723{
1724    RefPtr<EventListener> eventListener = registeredEventListener.listener;
1725    String sourceName;
1726    String scriptId;
1727    int lineNumber;
1728    int columnNumber;
1729    if (!eventListenerHandlerLocation(&node->document(), eventListener.get(), sourceName, scriptId, lineNumber, columnNumber))
1730        return nullptr;
1731
1732    Document& document = node->document();
1733    RefPtr<TypeBuilder::Debugger::Location> location = TypeBuilder::Debugger::Location::create()
1734        .setScriptId(scriptId)
1735        .setLineNumber(lineNumber);
1736    location->setColumnNumber(columnNumber);
1737    RefPtr<TypeBuilder::DOM::EventListener> value = TypeBuilder::DOM::EventListener::create()
1738        .setType(eventType)
1739        .setUseCapture(registeredEventListener.useCapture)
1740        .setIsAttribute(eventListener->isAttribute())
1741        .setNodeId(pushNodePathToFrontend(node))
1742        .setHandlerBody(eventListenerHandlerBody(&document, eventListener.get()))
1743        .setLocation(location);
1744    if (objectGroupId) {
1745        ScriptValue functionValue = eventListenerHandler(&document, eventListener.get());
1746        if (!functionValue.isEmpty()) {
1747            LocalFrame* frame = document.frame();
1748            if (frame) {
1749                ScriptState* scriptState = eventListenerHandlerScriptState(frame, eventListener.get());
1750                if (scriptState) {
1751                    InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(scriptState);
1752                    if (!injectedScript.isEmpty()) {
1753                        RefPtr<TypeBuilder::Runtime::RemoteObject> valueJson = injectedScript.wrapObject(functionValue, *objectGroupId);
1754                        value->setHandler(valueJson);
1755                    }
1756                }
1757            }
1758        }
1759    }
1760    if (!sourceName.isEmpty())
1761        value->setSourceName(sourceName);
1762    return value.release();
1763}
1764
1765PassRefPtr<TypeBuilder::Array<TypeBuilder::DOM::Node> > InspectorDOMAgent::buildArrayForPseudoElements(Element* element, NodeToIdMap* nodesMap)
1766{
1767    if (!element->pseudoElement(BEFORE) && !element->pseudoElement(AFTER))
1768        return nullptr;
1769
1770    RefPtr<TypeBuilder::Array<TypeBuilder::DOM::Node> > pseudoElements = TypeBuilder::Array<TypeBuilder::DOM::Node>::create();
1771    if (element->pseudoElement(BEFORE))
1772        pseudoElements->addItem(buildObjectForNode(element->pseudoElement(BEFORE), 0, nodesMap));
1773    if (element->pseudoElement(AFTER))
1774        pseudoElements->addItem(buildObjectForNode(element->pseudoElement(AFTER), 0, nodesMap));
1775    return pseudoElements.release();
1776}
1777
1778Node* InspectorDOMAgent::innerFirstChild(Node* node)
1779{
1780    node = node->firstChild();
1781    while (isWhitespace(node))
1782        node = node->nextSibling();
1783    return node;
1784}
1785
1786Node* InspectorDOMAgent::innerNextSibling(Node* node)
1787{
1788    do {
1789        node = node->nextSibling();
1790    } while (isWhitespace(node));
1791    return node;
1792}
1793
1794Node* InspectorDOMAgent::innerPreviousSibling(Node* node)
1795{
1796    do {
1797        node = node->previousSibling();
1798    } while (isWhitespace(node));
1799    return node;
1800}
1801
1802unsigned InspectorDOMAgent::innerChildNodeCount(Node* node)
1803{
1804    unsigned count = 0;
1805    Node* child = innerFirstChild(node);
1806    while (child) {
1807        count++;
1808        child = innerNextSibling(child);
1809    }
1810    return count;
1811}
1812
1813Node* InspectorDOMAgent::innerParentNode(Node* node)
1814{
1815    if (node->isDocumentNode()) {
1816        Document* document = toDocument(node);
1817        if (HTMLImportLoader* loader = document->importLoader())
1818            return loader->firstImport()->link();
1819        return document->ownerElement();
1820    }
1821    return node->parentOrShadowHostNode();
1822}
1823
1824bool InspectorDOMAgent::isWhitespace(Node* node)
1825{
1826    //TODO: pull ignoreWhitespace setting from the frontend and use here.
1827    return node && node->nodeType() == Node::TEXT_NODE && node->nodeValue().stripWhiteSpace().length() == 0;
1828}
1829
1830void InspectorDOMAgent::domContentLoadedEventFired(LocalFrame* frame)
1831{
1832    if (!frame->isMainFrame())
1833        return;
1834
1835    // Re-push document once it is loaded.
1836    discardFrontendBindings();
1837    if (enabled())
1838        m_frontend->documentUpdated();
1839}
1840
1841void InspectorDOMAgent::invalidateFrameOwnerElement(LocalFrame* frame)
1842{
1843    HTMLFrameOwnerElement* frameOwner = frame->document()->ownerElement();
1844    if (!frameOwner)
1845        return;
1846
1847    int frameOwnerId = m_documentNodeToIdMap->get(frameOwner);
1848    if (!frameOwnerId)
1849        return;
1850
1851    // Re-add frame owner element together with its new children.
1852    int parentId = m_documentNodeToIdMap->get(innerParentNode(frameOwner));
1853    m_frontend->childNodeRemoved(parentId, frameOwnerId);
1854    unbind(frameOwner, m_documentNodeToIdMap.get());
1855
1856    RefPtr<TypeBuilder::DOM::Node> value = buildObjectForNode(frameOwner, 0, m_documentNodeToIdMap.get());
1857    Node* previousSibling = innerPreviousSibling(frameOwner);
1858    int prevId = previousSibling ? m_documentNodeToIdMap->get(previousSibling) : 0;
1859    m_frontend->childNodeInserted(parentId, prevId, value.release());
1860}
1861
1862void InspectorDOMAgent::didCommitLoad(LocalFrame* frame, DocumentLoader* loader)
1863{
1864    // FIXME: If "frame" is always guarenteed to be in the same Page as loader->frame()
1865    // then all we need to check here is loader->frame()->isMainFrame()
1866    // and we don't need "frame" at all.
1867    if (!frame->page()->mainFrame()->isLocalFrame())
1868        return;
1869    LocalFrame* mainFrame = frame->page()->deprecatedLocalMainFrame();
1870    if (loader->frame() != mainFrame) {
1871        invalidateFrameOwnerElement(loader->frame());
1872        return;
1873    }
1874
1875    setDocument(mainFrame->document());
1876}
1877
1878void InspectorDOMAgent::didInsertDOMNode(Node* node)
1879{
1880    if (isWhitespace(node))
1881        return;
1882
1883    // We could be attaching existing subtree. Forget the bindings.
1884    unbind(node, m_documentNodeToIdMap.get());
1885
1886    ContainerNode* parent = node->parentNode();
1887    if (!parent)
1888        return;
1889    int parentId = m_documentNodeToIdMap->get(parent);
1890    // Return if parent is not mapped yet.
1891    if (!parentId)
1892        return;
1893
1894    if (!m_childrenRequested.contains(parentId)) {
1895        // No children are mapped yet -> only notify on changes of child count.
1896        int count = m_cachedChildCount.get(parentId) + 1;
1897        m_cachedChildCount.set(parentId, count);
1898        m_frontend->childNodeCountUpdated(parentId, count);
1899    } else {
1900        // Children have been requested -> return value of a new child.
1901        Node* prevSibling = innerPreviousSibling(node);
1902        int prevId = prevSibling ? m_documentNodeToIdMap->get(prevSibling) : 0;
1903        RefPtr<TypeBuilder::DOM::Node> value = buildObjectForNode(node, 0, m_documentNodeToIdMap.get());
1904        m_frontend->childNodeInserted(parentId, prevId, value.release());
1905    }
1906}
1907
1908void InspectorDOMAgent::willRemoveDOMNode(Node* node)
1909{
1910    if (isWhitespace(node))
1911        return;
1912
1913    ContainerNode* parent = node->parentNode();
1914
1915    // If parent is not mapped yet -> ignore the event.
1916    if (!m_documentNodeToIdMap->contains(parent))
1917        return;
1918
1919    int parentId = m_documentNodeToIdMap->get(parent);
1920
1921    if (!m_childrenRequested.contains(parentId)) {
1922        // No children are mapped yet -> only notify on changes of child count.
1923        int count = m_cachedChildCount.get(parentId) - 1;
1924        m_cachedChildCount.set(parentId, count);
1925        m_frontend->childNodeCountUpdated(parentId, count);
1926    } else {
1927        m_frontend->childNodeRemoved(parentId, m_documentNodeToIdMap->get(node));
1928    }
1929    unbind(node, m_documentNodeToIdMap.get());
1930}
1931
1932void InspectorDOMAgent::willModifyDOMAttr(Element*, const AtomicString& oldValue, const AtomicString& newValue)
1933{
1934    m_suppressAttributeModifiedEvent = (oldValue == newValue);
1935}
1936
1937void InspectorDOMAgent::didModifyDOMAttr(Element* element, const AtomicString& name, const AtomicString& value)
1938{
1939    bool shouldSuppressEvent = m_suppressAttributeModifiedEvent;
1940    m_suppressAttributeModifiedEvent = false;
1941    if (shouldSuppressEvent)
1942        return;
1943
1944    int id = boundNodeId(element);
1945    // If node is not mapped yet -> ignore the event.
1946    if (!id)
1947        return;
1948
1949    if (m_domListener)
1950        m_domListener->didModifyDOMAttr(element);
1951
1952    m_frontend->attributeModified(id, name, value);
1953}
1954
1955void InspectorDOMAgent::didRemoveDOMAttr(Element* element, const AtomicString& name)
1956{
1957    int id = boundNodeId(element);
1958    // If node is not mapped yet -> ignore the event.
1959    if (!id)
1960        return;
1961
1962    if (m_domListener)
1963        m_domListener->didModifyDOMAttr(element);
1964
1965    m_frontend->attributeRemoved(id, name);
1966}
1967
1968void InspectorDOMAgent::styleAttributeInvalidated(const WillBeHeapVector<RawPtrWillBeMember<Element> >& elements)
1969{
1970    RefPtr<TypeBuilder::Array<int> > nodeIds = TypeBuilder::Array<int>::create();
1971    for (unsigned i = 0, size = elements.size(); i < size; ++i) {
1972        Element* element = elements.at(i);
1973        int id = boundNodeId(element);
1974        // If node is not mapped yet -> ignore the event.
1975        if (!id)
1976            continue;
1977
1978        if (m_domListener)
1979            m_domListener->didModifyDOMAttr(element);
1980        nodeIds->addItem(id);
1981    }
1982    m_frontend->inlineStyleInvalidated(nodeIds.release());
1983}
1984
1985void InspectorDOMAgent::characterDataModified(CharacterData* characterData)
1986{
1987    int id = m_documentNodeToIdMap->get(characterData);
1988    if (!id) {
1989        // Push text node if it is being created.
1990        didInsertDOMNode(characterData);
1991        return;
1992    }
1993    m_frontend->characterDataModified(id, characterData->data());
1994}
1995
1996void InspectorDOMAgent::didInvalidateStyleAttr(Node* node)
1997{
1998    int id = m_documentNodeToIdMap->get(node);
1999    // If node is not mapped yet -> ignore the event.
2000    if (!id)
2001        return;
2002
2003    if (!m_revalidateStyleAttrTask)
2004        m_revalidateStyleAttrTask = adoptPtrWillBeNoop(new RevalidateStyleAttributeTask(this));
2005    m_revalidateStyleAttrTask->scheduleFor(toElement(node));
2006}
2007
2008void InspectorDOMAgent::didPushShadowRoot(Element* host, ShadowRoot* root)
2009{
2010    if (!host->ownerDocument())
2011        return;
2012
2013    int hostId = m_documentNodeToIdMap->get(host);
2014    if (!hostId)
2015        return;
2016
2017    pushChildNodesToFrontend(hostId, 1);
2018    m_frontend->shadowRootPushed(hostId, buildObjectForNode(root, 0, m_documentNodeToIdMap.get()));
2019}
2020
2021void InspectorDOMAgent::willPopShadowRoot(Element* host, ShadowRoot* root)
2022{
2023    if (!host->ownerDocument())
2024        return;
2025
2026    int hostId = m_documentNodeToIdMap->get(host);
2027    int rootId = m_documentNodeToIdMap->get(root);
2028    if (hostId && rootId)
2029        m_frontend->shadowRootPopped(hostId, rootId);
2030}
2031
2032void InspectorDOMAgent::frameDocumentUpdated(LocalFrame* frame)
2033{
2034    Document* document = frame->document();
2035    if (!document)
2036        return;
2037
2038    Page* page = frame->page();
2039    ASSERT(page);
2040    if (frame != page->mainFrame())
2041        return;
2042
2043    // Only update the main frame document, nested frame document updates are not required
2044    // (will be handled by invalidateFrameOwnerElement()).
2045    setDocument(document);
2046}
2047
2048void InspectorDOMAgent::pseudoElementCreated(PseudoElement* pseudoElement)
2049{
2050    Element* parent = pseudoElement->parentOrShadowHostElement();
2051    if (!parent)
2052        return;
2053    int parentId = m_documentNodeToIdMap->get(parent);
2054    if (!parentId)
2055        return;
2056
2057    pushChildNodesToFrontend(parentId, 1);
2058    m_frontend->pseudoElementAdded(parentId, buildObjectForNode(pseudoElement, 0, m_documentNodeToIdMap.get()));
2059}
2060
2061void InspectorDOMAgent::pseudoElementDestroyed(PseudoElement* pseudoElement)
2062{
2063    int pseudoElementId = m_documentNodeToIdMap->get(pseudoElement);
2064    if (!pseudoElementId)
2065        return;
2066
2067    // If a PseudoElement is bound, its parent element must be bound, too.
2068    Element* parent = pseudoElement->parentOrShadowHostElement();
2069    ASSERT(parent);
2070    int parentId = m_documentNodeToIdMap->get(parent);
2071    ASSERT(parentId);
2072
2073    unbind(pseudoElement, m_documentNodeToIdMap.get());
2074    m_frontend->pseudoElementRemoved(parentId, pseudoElementId);
2075}
2076
2077static ShadowRoot* shadowRootForNode(Node* node, const String& type)
2078{
2079    if (!node->isElementNode())
2080        return 0;
2081    if (type == "a")
2082        return toElement(node)->shadowRoot();
2083    if (type == "u")
2084        return toElement(node)->userAgentShadowRoot();
2085    return 0;
2086}
2087
2088Node* InspectorDOMAgent::nodeForPath(const String& path)
2089{
2090    // The path is of form "1,HTML,2,BODY,1,DIV" (<index> and <nodeName> interleaved).
2091    // <index> may also be "a" (author shadow root) or "u" (user-agent shadow root),
2092    // in which case <nodeName> MUST be "#document-fragment".
2093    if (!m_document)
2094        return 0;
2095
2096    Node* node = m_document.get();
2097    Vector<String> pathTokens;
2098    path.split(',', pathTokens);
2099    if (!pathTokens.size())
2100        return 0;
2101    for (size_t i = 0; i < pathTokens.size() - 1; i += 2) {
2102        bool success = true;
2103        String& indexValue = pathTokens[i];
2104        unsigned childNumber = indexValue.toUInt(&success);
2105        Node* child;
2106        if (!success) {
2107            child = shadowRootForNode(node, indexValue);
2108        } else {
2109            if (childNumber >= innerChildNodeCount(node))
2110                return 0;
2111
2112            child = innerFirstChild(node);
2113        }
2114        String childName = pathTokens[i + 1];
2115        for (size_t j = 0; child && j < childNumber; ++j)
2116            child = innerNextSibling(child);
2117
2118        if (!child || child->nodeName() != childName)
2119            return 0;
2120        node = child;
2121    }
2122    return node;
2123}
2124
2125void InspectorDOMAgent::pushNodeByPathToFrontend(ErrorString* errorString, const String& path, int* nodeId)
2126{
2127    if (Node* node = nodeForPath(path))
2128        *nodeId = pushNodePathToFrontend(node);
2129    else
2130        *errorString = "No node with given path found";
2131}
2132
2133void InspectorDOMAgent::pushNodesByBackendIdsToFrontend(ErrorString* errorString, const RefPtr<JSONArray>& backendNodeIds, RefPtr<TypeBuilder::Array<int> >& result)
2134{
2135    result = TypeBuilder::Array<int>::create();
2136    for (JSONArray::const_iterator it = backendNodeIds->begin(); it != backendNodeIds->end(); ++it) {
2137        int backendNodeId;
2138
2139        if (!(*it)->asNumber(&backendNodeId)) {
2140            *errorString = "Invalid argument type";
2141            return;
2142        }
2143
2144        Node* node = InspectorNodeIds::nodeForId(backendNodeId);
2145        if (node && node->document().page() == m_pageAgent->page())
2146            result->addItem(pushNodePathToFrontend(node));
2147        else
2148            result->addItem(0);
2149    }
2150}
2151
2152void InspectorDOMAgent::getRelayoutBoundary(ErrorString* errorString, int nodeId, int* relayoutBoundaryNodeId)
2153{
2154    Node* node = assertNode(errorString, nodeId);
2155    if (!node)
2156        return;
2157    RenderObject* renderer = node->renderer();
2158    if (!renderer) {
2159        *errorString = "No renderer for node, perhaps orphan or hidden node";
2160        return;
2161    }
2162    while (renderer && !renderer->isDocumentElement() && !renderer->isRelayoutBoundaryForInspector())
2163        renderer = renderer->container();
2164    Node* resultNode = renderer ? renderer->generatingNode() : node->ownerDocument();
2165    *relayoutBoundaryNodeId = pushNodePathToFrontend(resultNode);
2166}
2167
2168PassRefPtr<TypeBuilder::Runtime::RemoteObject> InspectorDOMAgent::resolveNode(Node* node, const String& objectGroup)
2169{
2170    Document* document = node->isDocumentNode() ? &node->document() : node->ownerDocument();
2171    LocalFrame* frame = document ? document->frame() : 0;
2172    if (!frame)
2173        return nullptr;
2174
2175    InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(ScriptState::forMainWorld(frame));
2176    if (injectedScript.isEmpty())
2177        return nullptr;
2178
2179    return injectedScript.wrapNode(node, objectGroup);
2180}
2181
2182bool InspectorDOMAgent::pushDocumentUponHandlelessOperation(ErrorString* errorString)
2183{
2184    if (!m_documentNodeToIdMap->contains(m_document)) {
2185        RefPtr<TypeBuilder::DOM::Node> root;
2186        getDocument(errorString, root);
2187        return errorString->isEmpty();
2188    }
2189    return true;
2190}
2191
2192void InspectorDOMAgent::trace(Visitor* visitor)
2193{
2194    visitor->trace(m_domListener);
2195    visitor->trace(m_pageAgent);
2196    visitor->trace(m_injectedScriptManager);
2197#if ENABLE(OILPAN)
2198    visitor->trace(m_documentNodeToIdMap);
2199    visitor->trace(m_danglingNodeToIdMaps);
2200    visitor->trace(m_idToNode);
2201    visitor->trace(m_idToNodesMap);
2202    visitor->trace(m_document);
2203    visitor->trace(m_revalidateStyleAttrTask);
2204    visitor->trace(m_searchResults);
2205#endif
2206    visitor->trace(m_history);
2207    visitor->trace(m_domEditor);
2208    visitor->trace(m_listener);
2209    InspectorBaseAgent::trace(visitor);
2210}
2211
2212} // namespace blink
2213
2214