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