1 | /* |
2 | * Copyright (C) 2009-2017 Apple Inc. All rights reserved. |
3 | * Copyright (C) 2011 Google Inc. All rights reserved. |
4 | * |
5 | * Redistribution and use in source and binary forms, with or without |
6 | * modification, are permitted provided that the following conditions |
7 | * are met: |
8 | * |
9 | * 1. Redistributions of source code must retain the above copyright |
10 | * notice, this list of conditions and the following disclaimer. |
11 | * 2. Redistributions in binary form must reproduce the above copyright |
12 | * notice, this list of conditions and the following disclaimer in the |
13 | * documentation and/or other materials provided with the distribution. |
14 | * 3. Neither the name of Apple Inc. ("Apple") nor the names of |
15 | * its contributors may be used to endorse or promote products derived |
16 | * from this software without specific prior written permission. |
17 | * |
18 | * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY |
19 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
20 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
21 | * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY |
22 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
23 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
24 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
25 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
26 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
27 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
28 | */ |
29 | |
30 | #pragma once |
31 | |
32 | #include "EventTarget.h" |
33 | #include "InspectorWebAgentBase.h" |
34 | #include "Timer.h" |
35 | #include <JavaScriptCore/InspectorBackendDispatchers.h> |
36 | #include <JavaScriptCore/InspectorFrontendDispatchers.h> |
37 | #include <wtf/HashMap.h> |
38 | #include <wtf/HashSet.h> |
39 | #include <wtf/JSONValues.h> |
40 | #include <wtf/RefPtr.h> |
41 | #include <wtf/Vector.h> |
42 | #include <wtf/text/AtomicString.h> |
43 | |
44 | namespace Inspector { |
45 | class InjectedScriptManager; |
46 | } |
47 | |
48 | namespace JSC { |
49 | class ExecState; |
50 | class JSValue; |
51 | } |
52 | |
53 | namespace WebCore { |
54 | |
55 | class AccessibilityObject; |
56 | class CharacterData; |
57 | class DOMEditor; |
58 | class Document; |
59 | class Element; |
60 | class Event; |
61 | class Exception; |
62 | class FloatQuad; |
63 | class Frame; |
64 | class InspectorHistory; |
65 | class InspectorOverlay; |
66 | #if ENABLE(VIDEO) |
67 | class HTMLMediaElement; |
68 | #endif |
69 | class HitTestResult; |
70 | class Node; |
71 | class Page; |
72 | class PseudoElement; |
73 | class RevalidateStyleAttributeTask; |
74 | class ShadowRoot; |
75 | |
76 | struct HighlightConfig; |
77 | |
78 | typedef String ErrorString; |
79 | |
80 | class InspectorDOMAgent final : public InspectorAgentBase, public Inspector::DOMBackendDispatcherHandler { |
81 | WTF_MAKE_NONCOPYABLE(InspectorDOMAgent); |
82 | WTF_MAKE_FAST_ALLOCATED; |
83 | public: |
84 | InspectorDOMAgent(PageAgentContext&, InspectorOverlay*); |
85 | virtual ~InspectorDOMAgent(); |
86 | |
87 | static String toErrorString(ExceptionCode); |
88 | static String toErrorString(Exception&&); |
89 | |
90 | void didCreateFrontendAndBackend(Inspector::FrontendRouter*, Inspector::BackendDispatcher*) override; |
91 | void willDestroyFrontendAndBackend(Inspector::DisconnectReason) override; |
92 | |
93 | Vector<Document*> documents(); |
94 | void reset(); |
95 | |
96 | // Methods called from the frontend for DOM nodes inspection. |
97 | void querySelector(ErrorString&, int nodeId, const String& selectors, int* elementId) override; |
98 | void querySelectorAll(ErrorString&, int nodeId, const String& selectors, RefPtr<JSON::ArrayOf<int>>& result) override; |
99 | void getDocument(ErrorString&, RefPtr<Inspector::Protocol::DOM::Node>& root) override; |
100 | void requestChildNodes(ErrorString&, int nodeId, const int* depth) override; |
101 | void setAttributeValue(ErrorString&, int elementId, const String& name, const String& value) override; |
102 | void setAttributesAsText(ErrorString&, int elementId, const String& text, const String* name) override; |
103 | void removeAttribute(ErrorString&, int elementId, const String& name) override; |
104 | void removeNode(ErrorString&, int nodeId) override; |
105 | void setNodeName(ErrorString&, int nodeId, const String& name, int* newId) override; |
106 | void getOuterHTML(ErrorString&, int nodeId, WTF::String* outerHTML) override; |
107 | void setOuterHTML(ErrorString&, int nodeId, const String& outerHTML) override; |
108 | void insertAdjacentHTML(ErrorString&, int nodeId, const String& position, const String& html) override; |
109 | void setNodeValue(ErrorString&, int nodeId, const String& value) override; |
110 | void getSupportedEventNames(ErrorString&, RefPtr<JSON::ArrayOf<String>>& eventNames) override; |
111 | void getDataBindingsForNode(ErrorString&, int nodeId, RefPtr<JSON::ArrayOf<Inspector::Protocol::DOM::DataBinding>>& dataArray) override; |
112 | void getAssociatedDataForNode(ErrorString&, int nodeId, Optional<String>& associatedData) override; |
113 | void getEventListenersForNode(ErrorString&, int nodeId, RefPtr<JSON::ArrayOf<Inspector::Protocol::DOM::EventListener>>& listenersArray) override; |
114 | void setEventListenerDisabled(ErrorString&, int eventListenerId, bool disabled) override; |
115 | void setBreakpointForEventListener(ErrorString&, int eventListenerId) override; |
116 | void removeBreakpointForEventListener(ErrorString&, int eventListenerId) override; |
117 | void getAccessibilityPropertiesForNode(ErrorString&, int nodeId, RefPtr<Inspector::Protocol::DOM::AccessibilityProperties>& axProperties) override; |
118 | void performSearch(ErrorString&, const String& query, const JSON::Array* nodeIds, const bool* caseSensitive, String* searchId, int* resultCount) override; |
119 | void getSearchResults(ErrorString&, const String& searchId, int fromIndex, int toIndex, RefPtr<JSON::ArrayOf<int>>&) override; |
120 | void discardSearchResults(ErrorString&, const String& searchId) override; |
121 | void resolveNode(ErrorString&, int nodeId, const String* objectGroup, RefPtr<Inspector::Protocol::Runtime::RemoteObject>& result) override; |
122 | void getAttributes(ErrorString&, int nodeId, RefPtr<JSON::ArrayOf<String>>& result) override; |
123 | void setInspectModeEnabled(ErrorString&, bool enabled, const JSON::Object* highlightConfig) override; |
124 | void requestNode(ErrorString&, const String& objectId, int* nodeId) override; |
125 | void pushNodeByPathToFrontend(ErrorString&, const String& path, int* nodeId) override; |
126 | void hideHighlight(ErrorString&) override; |
127 | void highlightRect(ErrorString&, int x, int y, int width, int height, const JSON::Object* color, const JSON::Object* outlineColor, const bool* usePageCoordinates) override; |
128 | void highlightQuad(ErrorString&, const JSON::Array& quad, const JSON::Object* color, const JSON::Object* outlineColor, const bool* usePageCoordinates) override; |
129 | void highlightSelector(ErrorString&, const JSON::Object& highlightConfig, const String& selectorString, const String* frameId) override; |
130 | void highlightNode(ErrorString&, const JSON::Object& highlightConfig, const int* nodeId, const String* objectId) override; |
131 | void highlightNodeList(ErrorString&, const JSON::Array& nodeIds, const JSON::Object& highlightConfig) override; |
132 | void highlightFrame(ErrorString&, const String& frameId, const JSON::Object* color, const JSON::Object* outlineColor) override; |
133 | void moveTo(ErrorString&, int nodeId, int targetNodeId, const int* anchorNodeId, int* newNodeId) override; |
134 | void undo(ErrorString&) override; |
135 | void redo(ErrorString&) override; |
136 | void markUndoableState(ErrorString&) override; |
137 | void focus(ErrorString&, int nodeId) override; |
138 | void setInspectedNode(ErrorString&, int nodeId) override; |
139 | |
140 | // InspectorInstrumentation |
141 | int identifierForNode(Node&); |
142 | void addEventListenersToNode(Node&); |
143 | void didInsertDOMNode(Node&); |
144 | void didRemoveDOMNode(Node&); |
145 | void willModifyDOMAttr(Element&, const AtomicString& oldValue, const AtomicString& newValue); |
146 | void didModifyDOMAttr(Element&, const AtomicString& name, const AtomicString& value); |
147 | void didRemoveDOMAttr(Element&, const AtomicString& name); |
148 | void characterDataModified(CharacterData&); |
149 | void didInvalidateStyleAttr(Element&); |
150 | void didPushShadowRoot(Element& host, ShadowRoot&); |
151 | void willPopShadowRoot(Element& host, ShadowRoot&); |
152 | void didChangeCustomElementState(Element&); |
153 | bool handleTouchEvent(Node&); |
154 | void didCommitLoad(Document*); |
155 | void frameDocumentUpdated(Frame&); |
156 | void pseudoElementCreated(PseudoElement&); |
157 | void pseudoElementDestroyed(PseudoElement&); |
158 | void didAddEventListener(EventTarget&); |
159 | void willRemoveEventListener(EventTarget&, const AtomicString& eventType, EventListener&, bool capture); |
160 | bool isEventListenerDisabled(EventTarget&, const AtomicString& eventType, EventListener&, bool capture); |
161 | void eventDidResetAfterDispatch(const Event&); |
162 | |
163 | // Callbacks that don't directly correspond to an instrumentation entry point. |
164 | void setDocument(Document*); |
165 | void releaseDanglingNodes(); |
166 | |
167 | void styleAttributeInvalidated(const Vector<Element*>& elements); |
168 | |
169 | int pushNodeToFrontend(ErrorString&, int documentNodeId, Node*); |
170 | Node* nodeForId(int nodeId); |
171 | int boundNodeId(const Node*); |
172 | |
173 | static String documentURLString(Document*); |
174 | |
175 | RefPtr<Inspector::Protocol::Runtime::RemoteObject> resolveNode(Node*, const String& objectGroup); |
176 | bool handleMousePress(); |
177 | void mouseDidMoveOverElement(const HitTestResult&, unsigned modifierFlags); |
178 | void inspect(Node*); |
179 | void focusNode(); |
180 | |
181 | InspectorHistory* history() { return m_history.get(); } |
182 | |
183 | // We represent embedded doms as a part of the same hierarchy. Hence we treat children of frame owners differently. |
184 | // We also skip whitespace text nodes conditionally. Following methods encapsulate these specifics. |
185 | static Node* innerFirstChild(Node*); |
186 | static Node* innerNextSibling(Node*); |
187 | static Node* innerPreviousSibling(Node*); |
188 | static unsigned innerChildNodeCount(Node*); |
189 | static Node* innerParentNode(Node*); |
190 | |
191 | Node* assertNode(ErrorString&, int nodeId); |
192 | Element* assertElement(ErrorString&, int nodeId); |
193 | Document* assertDocument(ErrorString&, int nodeId); |
194 | |
195 | static Node* scriptValueAsNode(JSC::JSValue); |
196 | static JSC::JSValue nodeAsScriptValue(JSC::ExecState&, Node*); |
197 | |
198 | bool hasBreakpointForEventListener(EventTarget&, const AtomicString& eventType, EventListener&, bool capture); |
199 | int idForEventListener(EventTarget&, const AtomicString& eventType, EventListener&, bool capture); |
200 | |
201 | private: |
202 | #if ENABLE(VIDEO) |
203 | void mediaMetricsTimerFired(); |
204 | #endif |
205 | |
206 | void highlightMousedOverNode(); |
207 | void setSearchingForNode(ErrorString&, bool enabled, const JSON::Object* highlightConfig); |
208 | std::unique_ptr<HighlightConfig> highlightConfigFromInspectorObject(ErrorString&, const JSON::Object* highlightInspectorObject); |
209 | |
210 | // Node-related methods. |
211 | typedef HashMap<RefPtr<Node>, int> NodeToIdMap; |
212 | int bind(Node*, NodeToIdMap*); |
213 | void unbind(Node*, NodeToIdMap*); |
214 | |
215 | Node* assertEditableNode(ErrorString&, int nodeId); |
216 | Element* assertEditableElement(ErrorString&, int nodeId); |
217 | |
218 | int pushNodePathToFrontend(Node*); |
219 | void pushChildNodesToFrontend(int nodeId, int depth = 1); |
220 | |
221 | Ref<Inspector::Protocol::DOM::Node> buildObjectForNode(Node*, int depth, NodeToIdMap*); |
222 | Ref<JSON::ArrayOf<String>> buildArrayForElementAttributes(Element*); |
223 | Ref<JSON::ArrayOf<Inspector::Protocol::DOM::Node>> buildArrayForContainerChildren(Node* container, int depth, NodeToIdMap* nodesMap); |
224 | RefPtr<JSON::ArrayOf<Inspector::Protocol::DOM::Node>> buildArrayForPseudoElements(const Element&, NodeToIdMap* nodesMap); |
225 | Ref<Inspector::Protocol::DOM::EventListener> buildObjectForEventListener(const RegisteredEventListener&, int identifier, EventTarget&, const AtomicString& eventType, bool disabled, bool hasBreakpoint); |
226 | RefPtr<Inspector::Protocol::DOM::AccessibilityProperties> buildObjectForAccessibilityProperties(Node*); |
227 | void processAccessibilityChildren(AccessibilityObject&, JSON::ArrayOf<int>&); |
228 | |
229 | Node* nodeForPath(const String& path); |
230 | Node* nodeForObjectId(const String& objectId); |
231 | |
232 | void discardBindings(); |
233 | |
234 | void innerHighlightQuad(std::unique_ptr<FloatQuad>, const JSON::Object* color, const JSON::Object* outlineColor, const bool* usePageCoordinates); |
235 | |
236 | Inspector::InjectedScriptManager& m_injectedScriptManager; |
237 | std::unique_ptr<Inspector::DOMFrontendDispatcher> m_frontendDispatcher; |
238 | RefPtr<Inspector::DOMBackendDispatcher> m_backendDispatcher; |
239 | Page& m_inspectedPage; |
240 | InspectorOverlay* m_overlay { nullptr }; |
241 | NodeToIdMap m_documentNodeToIdMap; |
242 | // Owns node mappings for dangling nodes. |
243 | Vector<std::unique_ptr<NodeToIdMap>> m_danglingNodeToIdMaps; |
244 | HashMap<int, Node*> m_idToNode; |
245 | HashMap<int, NodeToIdMap*> m_idToNodesMap; |
246 | HashSet<int> m_childrenRequested; |
247 | int m_lastNodeId { 1 }; |
248 | RefPtr<Document> m_document; |
249 | typedef HashMap<String, Vector<RefPtr<Node>>> SearchResults; |
250 | SearchResults m_searchResults; |
251 | std::unique_ptr<RevalidateStyleAttributeTask> m_revalidateStyleAttrTask; |
252 | RefPtr<Node> m_nodeToFocus; |
253 | RefPtr<Node> m_mousedOverNode; |
254 | RefPtr<Node> m_inspectedNode; |
255 | std::unique_ptr<HighlightConfig> m_inspectModeHighlightConfig; |
256 | std::unique_ptr<InspectorHistory> m_history; |
257 | std::unique_ptr<DOMEditor> m_domEditor; |
258 | bool m_searchingForNode { false }; |
259 | bool m_suppressAttributeModifiedEvent { false }; |
260 | bool m_suppressEventListenerChangedEvent { false }; |
261 | bool m_documentRequested { false }; |
262 | |
263 | #if ENABLE(VIDEO) |
264 | Timer m_mediaMetricsTimer; |
265 | struct MediaMetrics { |
266 | unsigned displayCompositedFrames { 0 }; |
267 | bool isPowerEfficient { false }; |
268 | |
269 | MediaMetrics() { } |
270 | |
271 | MediaMetrics(unsigned displayCompositedFrames) |
272 | : displayCompositedFrames(displayCompositedFrames) |
273 | { |
274 | } |
275 | }; |
276 | |
277 | // The pointer key for this map should not be used for anything other than matching. |
278 | HashMap<HTMLMediaElement*, MediaMetrics> m_mediaMetrics; |
279 | #endif |
280 | |
281 | struct InspectorEventListener { |
282 | int identifier { 1 }; |
283 | RefPtr<EventTarget> eventTarget; |
284 | RefPtr<EventListener> eventListener; |
285 | AtomicString eventType; |
286 | bool useCapture { false }; |
287 | bool disabled { false }; |
288 | bool hasBreakpoint { false }; |
289 | |
290 | InspectorEventListener() { } |
291 | |
292 | InspectorEventListener(int identifier, EventTarget& target, const AtomicString& type, EventListener& listener, bool capture) |
293 | : identifier(identifier) |
294 | , eventTarget(&target) |
295 | , eventListener(&listener) |
296 | , eventType(type) |
297 | , useCapture(capture) |
298 | { |
299 | } |
300 | |
301 | bool matches(EventTarget& target, const AtomicString& type, EventListener& listener, bool capture) |
302 | { |
303 | if (eventTarget.get() != &target) |
304 | return false; |
305 | if (eventListener.get() != &listener) |
306 | return false; |
307 | if (eventType != type) |
308 | return false; |
309 | if (useCapture != capture) |
310 | return false; |
311 | return true; |
312 | } |
313 | }; |
314 | |
315 | friend class EventFiredCallback; |
316 | |
317 | HashSet<const Event*> m_dispatchedEvents; |
318 | HashMap<int, InspectorEventListener> m_eventListenerEntries; |
319 | int m_lastEventListenerId { 1 }; |
320 | }; |
321 | |
322 | } // namespace WebCore |
323 | |