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