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