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