1/*
2* Copyright (C) 2012 Google Inc. All rights reserved.
3* Copyright (C) 2014 University of Washington.
4* Copyright (C) 2015-2016 Apple Inc. All rights reserved.
5*
6* Redistribution and use in source and binary forms, with or without
7* modification, are permitted provided that the following conditions are
8* met:
9*
10* * Redistributions of source code must retain the above copyright
11* notice, this list of conditions and the following disclaimer.
12* * Redistributions in binary form must reproduce the above
13* copyright notice, this list of conditions and the following disclaimer
14* in the documentation and/or other materials provided with the
15* distribution.
16* * Neither the name of Google Inc. nor the names of its
17* contributors may be used to endorse or promote products derived from
18* this software without specific prior written permission.
19*
20* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31*/
32
33#pragma once
34
35#include "InspectorWebAgentBase.h"
36#include "LayoutRect.h"
37#include <JavaScriptCore/InspectorBackendDispatchers.h>
38#include <JavaScriptCore/InspectorFrontendDispatchers.h>
39#include <JavaScriptCore/ScriptDebugListener.h>
40#include <wtf/JSONValues.h>
41#include <wtf/Vector.h>
42
43namespace WebCore {
44
45class Event;
46class FloatQuad;
47class Frame;
48class RenderObject;
49class RunLoopObserver;
50
51typedef String ErrorString;
52
53enum class TimelineRecordType {
54 EventDispatch,
55 ScheduleStyleRecalculation,
56 RecalculateStyles,
57 InvalidateLayout,
58 Layout,
59 Paint,
60 Composite,
61 RenderingFrame,
62
63 TimerInstall,
64 TimerRemove,
65 TimerFire,
66
67 EvaluateScript,
68
69 TimeStamp,
70 Time,
71 TimeEnd,
72
73 FunctionCall,
74 ProbeSample,
75 ConsoleProfile,
76
77 RequestAnimationFrame,
78 CancelAnimationFrame,
79 FireAnimationFrame,
80
81 ObserverCallback,
82};
83
84class InspectorTimelineAgent final
85 : public InspectorAgentBase
86 , public Inspector::TimelineBackendDispatcherHandler
87 , public Inspector::ScriptDebugListener {
88 WTF_MAKE_NONCOPYABLE(InspectorTimelineAgent);
89 WTF_MAKE_FAST_ALLOCATED;
90public:
91 InspectorTimelineAgent(WebAgentContext&);
92 virtual ~InspectorTimelineAgent();
93
94 void didCreateFrontendAndBackend(Inspector::FrontendRouter*, Inspector::BackendDispatcher*) final;
95 void willDestroyFrontendAndBackend(Inspector::DisconnectReason) final;
96
97 void start(ErrorString&, const int* maxCallStackDepth = nullptr) final;
98 void stop(ErrorString&) final;
99 void setAutoCaptureEnabled(ErrorString&, bool) final;
100 void setInstruments(ErrorString&, const JSON::Array&) final;
101
102 int id() const { return m_id; }
103
104 void didCommitLoad();
105
106 // Methods called from WebCore.
107 void startFromConsole(JSC::ExecState*, const String& title);
108 void stopFromConsole(JSC::ExecState*, const String& title);
109
110 // InspectorInstrumentation
111 void didInstallTimer(int timerId, Seconds timeout, bool singleShot, Frame*);
112 void didRemoveTimer(int timerId, Frame*);
113 void willFireTimer(int timerId, Frame*);
114 void didFireTimer();
115 void willCallFunction(const String& scriptName, int scriptLine, int scriptColumn, Frame*);
116 void didCallFunction(Frame*);
117 void willDispatchEvent(const Event&, Frame*);
118 void didDispatchEvent(bool defaultPrevented);
119 void willEvaluateScript(const String&, int lineNumber, int columnNumber, Frame&);
120 void didEvaluateScript(Frame&);
121 void didInvalidateLayout(Frame&);
122 void willLayout(Frame&);
123 void didLayout(RenderObject&);
124 void willComposite(Frame&);
125 void didComposite();
126 void willPaint(Frame&);
127 void didPaint(RenderObject&, const LayoutRect&);
128 void willRecalculateStyle(Frame*);
129 void didRecalculateStyle();
130 void didScheduleStyleRecalculation(Frame*);
131 void didTimeStamp(Frame&, const String&);
132 void didRequestAnimationFrame(int callbackId, Frame*);
133 void didCancelAnimationFrame(int callbackId, Frame*);
134 void willFireAnimationFrame(int callbackId, Frame*);
135 void didFireAnimationFrame();
136 void willFireObserverCallback(const String& callbackType, Frame*);
137 void didFireObserverCallback();
138 void time(Frame&, const String&);
139 void timeEnd(Frame&, const String&);
140 void mainFrameStartedLoading();
141 void mainFrameNavigated();
142
143private:
144 // ScriptDebugListener
145 void didParseSource(JSC::SourceID, const Script&) final { }
146 void failedToParseSource(const String&, const String&, int, int, const String&) final { }
147 void didPause(JSC::ExecState&, JSC::JSValue, JSC::JSValue) final { }
148 void didContinue() final { }
149
150 void breakpointActionLog(JSC::ExecState&, const String&) final { }
151 void breakpointActionSound(int) final { }
152 void breakpointActionProbe(JSC::ExecState&, const Inspector::ScriptBreakpointAction&, unsigned batchId, unsigned sampleId, JSC::JSValue result) final;
153
154 void startProgrammaticCapture();
155 void stopProgrammaticCapture();
156
157 enum class InstrumentState { Start, Stop };
158 void toggleInstruments(InstrumentState);
159 void toggleScriptProfilerInstrument(InstrumentState);
160 void toggleHeapInstrument(InstrumentState);
161 void toggleCPUInstrument(InstrumentState);
162 void toggleMemoryInstrument(InstrumentState);
163 void toggleTimelineInstrument(InstrumentState);
164 void disableBreakpoints();
165 void enableBreakpoints();
166
167 friend class TimelineRecordStack;
168
169 struct TimelineRecordEntry {
170 TimelineRecordEntry()
171 : type(TimelineRecordType::EventDispatch) { }
172 TimelineRecordEntry(RefPtr<JSON::Object>&& record, RefPtr<JSON::Object>&& data, RefPtr<JSON::Array>&& children, TimelineRecordType type)
173 : record(WTFMove(record))
174 , data(WTFMove(data))
175 , children(WTFMove(children))
176 , type(type)
177 {
178 }
179
180 RefPtr<JSON::Object> record;
181 RefPtr<JSON::Object> data;
182 RefPtr<JSON::Array> children;
183 TimelineRecordType type;
184 };
185
186 void internalStart(const int* maxCallStackDepth = nullptr);
187 void internalStop();
188 double timestamp();
189
190 void sendEvent(RefPtr<JSON::Object>&&);
191 void appendRecord(RefPtr<JSON::Object>&& data, TimelineRecordType, bool captureCallStack, Frame*);
192 void pushCurrentRecord(RefPtr<JSON::Object>&&, TimelineRecordType, bool captureCallStack, Frame*);
193 void pushCurrentRecord(const TimelineRecordEntry& record) { m_recordStack.append(record); }
194
195 TimelineRecordEntry createRecordEntry(RefPtr<JSON::Object>&& data, TimelineRecordType, bool captureCallStack, Frame*);
196
197 void setFrameIdentifier(JSON::Object* record, Frame*);
198
199 void didCompleteRecordEntry(const TimelineRecordEntry&);
200 void didCompleteCurrentRecord(TimelineRecordType);
201
202 void addRecordToTimeline(RefPtr<JSON::Object>&&, TimelineRecordType);
203 void clearRecordStack();
204
205 void localToPageQuad(const RenderObject&, const LayoutRect&, FloatQuad*);
206
207 std::unique_ptr<Inspector::TimelineFrontendDispatcher> m_frontendDispatcher;
208 RefPtr<Inspector::TimelineBackendDispatcher> m_backendDispatcher;
209
210 Vector<TimelineRecordEntry> m_recordStack;
211 Vector<TimelineRecordEntry> m_pendingConsoleProfileRecords;
212
213 int m_id { 1 };
214 int m_maxCallStackDepth { 5 };
215
216 bool m_enabled { false };
217 bool m_enabledFromFrontend { false };
218 bool m_programmaticCaptureRestoreBreakpointActiveValue { false };
219
220 bool m_autoCaptureEnabled { false };
221 enum class AutoCapturePhase { None, BeforeLoad, FirstNavigation, AfterFirstNavigation };
222 AutoCapturePhase m_autoCapturePhase { AutoCapturePhase::None };
223 Vector<Inspector::Protocol::Timeline::Instrument> m_instruments;
224
225#if PLATFORM(COCOA)
226 std::unique_ptr<WebCore::RunLoopObserver> m_frameStartObserver;
227 std::unique_ptr<WebCore::RunLoopObserver> m_frameStopObserver;
228#endif
229 int m_runLoopNestingLevel { 0 };
230 bool m_startedComposite { false };
231};
232
233} // namespace WebCore
234