Web Inspector: remove unused metrics and commands from the Timeline agent
[WebKit-https.git] / Source / WebCore / inspector / InspectorTimelineAgent.cpp
1 /*
2 * Copyright (C) 2013 Google Inc. All rights reserved.
3 * Copyright (C) 2014 University of Washington.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 *     * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *     * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
14 * distribution.
15 *     * Neither the name of Google Inc. nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include "config.h"
33
34 #if ENABLE(INSPECTOR)
35
36 #include "InspectorTimelineAgent.h"
37
38 #include "Event.h"
39 #include "Frame.h"
40 #include "FrameView.h"
41 #include "InspectorClient.h"
42 #include "InspectorInstrumentation.h"
43 #include "InspectorPageAgent.h"
44 #include "InspectorWebFrontendDispatchers.h"
45 #include "InstrumentingAgents.h"
46 #include "IntRect.h"
47 #include "JSDOMWindow.h"
48 #include "PageScriptDebugServer.h"
49 #include "RenderElement.h"
50 #include "RenderView.h"
51 #include "ResourceRequest.h"
52 #include "ResourceResponse.h"
53 #include "ScriptProfiler.h"
54 #include "ScriptState.h"
55 #include "TimelineRecordFactory.h"
56 #include <inspector/IdentifiersFactory.h>
57 #include <inspector/ScriptBreakpoint.h>
58 #include <wtf/CurrentTime.h>
59
60 using namespace Inspector;
61
62 namespace WebCore {
63
64 void TimelineTimeConverter::reset()
65 {
66     m_startOffset = monotonicallyIncreasingTime() - currentTime();
67 }
68
69 InspectorTimelineAgent::~InspectorTimelineAgent()
70 {
71 }
72
73 void InspectorTimelineAgent::didCreateFrontendAndBackend(Inspector::InspectorFrontendChannel* frontendChannel, InspectorBackendDispatcher* backendDispatcher)
74 {
75     m_frontendDispatcher = std::make_unique<InspectorTimelineFrontendDispatcher>(frontendChannel);
76     m_backendDispatcher = InspectorTimelineBackendDispatcher::create(backendDispatcher, this);
77 }
78
79 void InspectorTimelineAgent::willDestroyFrontendAndBackend(InspectorDisconnectReason)
80 {
81     m_frontendDispatcher = nullptr;
82     m_backendDispatcher.clear();
83
84     ErrorString error;
85     stop(&error);
86 }
87
88 void InspectorTimelineAgent::start(ErrorString*, const int* maxCallStackDepth)
89 {
90     if (!m_frontendDispatcher)
91         return;
92
93     if (maxCallStackDepth && *maxCallStackDepth > 0)
94         m_maxCallStackDepth = *maxCallStackDepth;
95     else
96         m_maxCallStackDepth = 5;
97
98     m_timeConverter.reset();
99
100     m_instrumentingAgents->setInspectorTimelineAgent(this);
101     PageScriptDebugServer::shared().addListener(this, page());
102     m_enabled = true;
103 }
104
105 void InspectorTimelineAgent::stop(ErrorString*)
106 {
107     if (!m_enabled)
108         return;
109
110     m_weakFactory.revokeAll();
111     m_instrumentingAgents->setInspectorTimelineAgent(nullptr);
112     PageScriptDebugServer::shared().removeListener(this, page(), true);
113
114     clearRecordStack();
115
116     m_enabled = false;
117 }
118
119 void InspectorTimelineAgent::willCallFunction(const String& scriptName, int scriptLine, Frame* frame)
120 {
121     pushCurrentRecord(TimelineRecordFactory::createFunctionCallData(scriptName, scriptLine), TimelineRecordType::FunctionCall, true, frame);
122
123     if (frame && !m_recordingProfile) {
124         m_recordingProfile = true;
125         ScriptProfiler::start(toJSDOMWindow(frame, debuggerWorld())->globalExec(), ASCIILiteral("Timeline FunctionCall"));
126     }
127 }
128
129 void InspectorTimelineAgent::didCallFunction(Frame* frame)
130 {
131     if (frame && m_recordingProfile) {
132         if (m_recordStack.isEmpty())
133             return;
134
135         TimelineRecordEntry& entry = m_recordStack.last();
136         ASSERT(entry.type == TimelineRecordType::FunctionCall);
137
138         RefPtr<ScriptProfile> profile = ScriptProfiler::stop(toJSDOMWindow(frame, debuggerWorld())->globalExec(), ASCIILiteral("Timeline FunctionCall"));
139         if (profile)
140             TimelineRecordFactory::appendProfile(entry.data.get(), profile.release());
141
142         m_recordingProfile = false;
143     }
144
145     didCompleteCurrentRecord(TimelineRecordType::FunctionCall);
146 }
147
148 void InspectorTimelineAgent::willDispatchEvent(const Event& event, Frame* frame)
149 {
150     pushCurrentRecord(TimelineRecordFactory::createEventDispatchData(event), TimelineRecordType::EventDispatch, false, frame);
151 }
152
153 void InspectorTimelineAgent::didDispatchEvent()
154 {
155     didCompleteCurrentRecord(TimelineRecordType::EventDispatch);
156 }
157
158 void InspectorTimelineAgent::didInvalidateLayout(Frame* frame)
159 {
160     appendRecord(InspectorObject::create(), TimelineRecordType::InvalidateLayout, true, frame);
161 }
162
163 void InspectorTimelineAgent::willLayout(Frame* frame)
164 {
165     RenderObject* root = frame->view()->layoutRoot();
166     bool partialLayout = !!root;
167
168     if (!partialLayout)
169         root = frame->contentRenderer();
170
171     unsigned dirtyObjects = 0;
172     unsigned totalObjects = 0;
173     for (RenderObject* o = root; o; o = o->nextInPreOrder(root)) {
174         ++totalObjects;
175         if (o->needsLayout())
176             ++dirtyObjects;
177     }
178     pushCurrentRecord(TimelineRecordFactory::createLayoutData(dirtyObjects, totalObjects, partialLayout), TimelineRecordType::Layout, true, frame);
179 }
180
181 void InspectorTimelineAgent::didLayout(RenderObject* root)
182 {
183     if (m_recordStack.isEmpty())
184         return;
185     TimelineRecordEntry& entry = m_recordStack.last();
186     ASSERT(entry.type == TimelineRecordType::Layout);
187     Vector<FloatQuad> quads;
188     root->absoluteQuads(quads);
189     if (quads.size() >= 1)
190         TimelineRecordFactory::appendLayoutRoot(entry.data.get(), quads[0]);
191     else
192         ASSERT_NOT_REACHED();
193     didCompleteCurrentRecord(TimelineRecordType::Layout);
194 }
195
196 void InspectorTimelineAgent::didScheduleStyleRecalculation(Frame* frame)
197 {
198     appendRecord(InspectorObject::create(), TimelineRecordType::ScheduleStyleRecalculation, true, frame);
199 }
200
201 void InspectorTimelineAgent::willRecalculateStyle(Frame* frame)
202 {
203     pushCurrentRecord(InspectorObject::create(), TimelineRecordType::RecalculateStyles, true, frame);
204 }
205
206 void InspectorTimelineAgent::didRecalculateStyle()
207 {
208     didCompleteCurrentRecord(TimelineRecordType::RecalculateStyles);
209 }
210
211 void InspectorTimelineAgent::willPaint(Frame* frame)
212 {
213     pushCurrentRecord(InspectorObject::create(), TimelineRecordType::Paint, true, frame);
214 }
215
216 void InspectorTimelineAgent::didPaint(RenderObject* renderer, const LayoutRect& clipRect)
217 {
218     TimelineRecordEntry& entry = m_recordStack.last();
219     ASSERT(entry.type == TimelineRecordType::Paint);
220     FloatQuad quad;
221     localToPageQuad(*renderer, clipRect, &quad);
222     entry.data = TimelineRecordFactory::createPaintData(quad);
223     didCompleteCurrentRecord(TimelineRecordType::Paint);
224 }
225
226 void InspectorTimelineAgent::willScroll(Frame* frame)
227 {
228     pushCurrentRecord(InspectorObject::create(), TimelineRecordType::ScrollLayer, false, frame);
229 }
230
231 void InspectorTimelineAgent::didScroll()
232 {
233     didCompleteCurrentRecord(TimelineRecordType::ScrollLayer);
234 }
235
236 void InspectorTimelineAgent::willWriteHTML(unsigned startLine, Frame* frame)
237 {
238     pushCurrentRecord(TimelineRecordFactory::createParseHTMLData(startLine), TimelineRecordType::ParseHTML, true, frame);
239 }
240
241 void InspectorTimelineAgent::didWriteHTML(unsigned endLine)
242 {
243     if (!m_recordStack.isEmpty()) {
244         TimelineRecordEntry entry = m_recordStack.last();
245         entry.data->setNumber("endLine", endLine);
246         didCompleteCurrentRecord(TimelineRecordType::ParseHTML);
247     }
248 }
249
250 void InspectorTimelineAgent::didInstallTimer(int timerId, int timeout, bool singleShot, Frame* frame)
251 {
252     appendRecord(TimelineRecordFactory::createTimerInstallData(timerId, timeout, singleShot), TimelineRecordType::TimerInstall, true, frame);
253 }
254
255 void InspectorTimelineAgent::didRemoveTimer(int timerId, Frame* frame)
256 {
257     appendRecord(TimelineRecordFactory::createGenericTimerData(timerId), TimelineRecordType::TimerRemove, true, frame);
258 }
259
260 void InspectorTimelineAgent::willFireTimer(int timerId, Frame* frame)
261 {
262     pushCurrentRecord(TimelineRecordFactory::createGenericTimerData(timerId), TimelineRecordType::TimerFire, false, frame);
263 }
264
265 void InspectorTimelineAgent::didFireTimer()
266 {
267     didCompleteCurrentRecord(TimelineRecordType::TimerFire);
268 }
269
270 void InspectorTimelineAgent::willDispatchXHRReadyStateChangeEvent(const String& url, int readyState, Frame* frame)
271 {
272     pushCurrentRecord(TimelineRecordFactory::createXHRReadyStateChangeData(url, readyState), TimelineRecordType::XHRReadyStateChange, false, frame);
273 }
274
275 void InspectorTimelineAgent::didDispatchXHRReadyStateChangeEvent()
276 {
277     didCompleteCurrentRecord(TimelineRecordType::XHRReadyStateChange);
278 }
279
280 void InspectorTimelineAgent::willDispatchXHRLoadEvent(const String& url, Frame* frame)
281 {
282     pushCurrentRecord(TimelineRecordFactory::createXHRLoadData(url), TimelineRecordType::XHRLoad, true, frame);
283 }
284
285 void InspectorTimelineAgent::didDispatchXHRLoadEvent()
286 {
287     didCompleteCurrentRecord(TimelineRecordType::XHRLoad);
288 }
289
290 void InspectorTimelineAgent::willEvaluateScript(const String& url, int lineNumber, Frame* frame)
291 {
292     pushCurrentRecord(TimelineRecordFactory::createEvaluateScriptData(url, lineNumber), TimelineRecordType::EvaluateScript, true, frame);
293
294     if (frame && !m_recordingProfile) {
295         m_recordingProfile = true;
296         ScriptProfiler::start(toJSDOMWindow(frame, debuggerWorld())->globalExec(), ASCIILiteral("Timeline EvaluateScript"));
297     }
298 }
299
300 void InspectorTimelineAgent::didEvaluateScript(Frame* frame)
301 {
302     if (frame && m_recordingProfile) {
303         if (m_recordStack.isEmpty())
304             return;
305
306         TimelineRecordEntry& entry = m_recordStack.last();
307         ASSERT(entry.type == TimelineRecordType::EvaluateScript);
308
309         RefPtr<ScriptProfile> profile = ScriptProfiler::stop(toJSDOMWindow(frame, debuggerWorld())->globalExec(), ASCIILiteral("Timeline EvaluateScript"));
310         if (profile)
311             TimelineRecordFactory::appendProfile(entry.data.get(), profile.release());
312
313         m_recordingProfile = false;
314     }
315
316     didCompleteCurrentRecord(TimelineRecordType::EvaluateScript);
317 }
318
319 void InspectorTimelineAgent::didScheduleResourceRequest(const String& url, Frame* frame)
320 {
321     appendRecord(TimelineRecordFactory::createScheduleResourceRequestData(url), TimelineRecordType::ScheduleResourceRequest, true, frame);
322 }
323
324 void InspectorTimelineAgent::willSendResourceRequest(unsigned long identifier, const ResourceRequest& request, Frame* frame)
325 {
326     String requestId = IdentifiersFactory::requestId(identifier);
327     appendRecord(TimelineRecordFactory::createResourceSendRequestData(requestId, request), TimelineRecordType::ResourceSendRequest, true, frame);
328 }
329
330 void InspectorTimelineAgent::willReceiveResourceData(unsigned long identifier, Frame* frame, int length)
331 {
332     String requestId = IdentifiersFactory::requestId(identifier);
333     pushCurrentRecord(TimelineRecordFactory::createReceiveResourceData(requestId, length), TimelineRecordType::ResourceReceivedData, false, frame);
334 }
335
336 void InspectorTimelineAgent::didReceiveResourceData()
337 {
338     didCompleteCurrentRecord(TimelineRecordType::ResourceReceivedData);
339 }
340
341 void InspectorTimelineAgent::willReceiveResourceResponse(unsigned long identifier, const ResourceResponse& response, Frame* frame)
342 {
343     String requestId = IdentifiersFactory::requestId(identifier);
344     pushCurrentRecord(TimelineRecordFactory::createResourceReceiveResponseData(requestId, response), TimelineRecordType::ResourceReceiveResponse, false, frame);
345 }
346
347 void InspectorTimelineAgent::didReceiveResourceResponse()
348 {
349     didCompleteCurrentRecord(TimelineRecordType::ResourceReceiveResponse);
350 }
351
352 void InspectorTimelineAgent::didFinishLoadingResource(unsigned long identifier, bool didFail, double finishTime, Frame* frame)
353 {
354     appendRecord(TimelineRecordFactory::createResourceFinishData(IdentifiersFactory::requestId(identifier), didFail, finishTime * 1000), TimelineRecordType::ResourceFinish, false, frame);
355 }
356
357 void InspectorTimelineAgent::didTimeStamp(Frame* frame, const String& message)
358 {
359     appendRecord(TimelineRecordFactory::createTimeStampData(message), TimelineRecordType::TimeStamp, true, frame);
360 }
361
362 void InspectorTimelineAgent::time(Frame* frame, const String& message)
363 {
364     appendRecord(TimelineRecordFactory::createTimeStampData(message), TimelineRecordType::Time, true, frame);
365 }
366
367 void InspectorTimelineAgent::timeEnd(Frame* frame, const String& message)
368 {
369     appendRecord(TimelineRecordFactory::createTimeStampData(message), TimelineRecordType::TimeEnd, true, frame);
370 }
371
372 void InspectorTimelineAgent::didMarkDOMContentEvent(Frame* frame)
373 {
374     bool isMainFrame = frame && m_pageAgent && (frame == m_pageAgent->mainFrame());
375     appendRecord(TimelineRecordFactory::createMarkData(isMainFrame), TimelineRecordType::MarkDOMContent, false, frame);
376 }
377
378 void InspectorTimelineAgent::didMarkLoadEvent(Frame* frame)
379 {
380     bool isMainFrame = frame && m_pageAgent && (frame == m_pageAgent->mainFrame());
381     appendRecord(TimelineRecordFactory::createMarkData(isMainFrame), TimelineRecordType::MarkLoad, false, frame);
382 }
383
384 void InspectorTimelineAgent::didCommitLoad()
385 {
386     clearRecordStack();
387 }
388
389 void InspectorTimelineAgent::didRequestAnimationFrame(int callbackId, Frame* frame)
390 {
391     appendRecord(TimelineRecordFactory::createAnimationFrameData(callbackId), TimelineRecordType::RequestAnimationFrame, true, frame);
392 }
393
394 void InspectorTimelineAgent::didCancelAnimationFrame(int callbackId, Frame* frame)
395 {
396     appendRecord(TimelineRecordFactory::createAnimationFrameData(callbackId), TimelineRecordType::CancelAnimationFrame, true, frame);
397 }
398
399 void InspectorTimelineAgent::willFireAnimationFrame(int callbackId, Frame* frame)
400 {
401     pushCurrentRecord(TimelineRecordFactory::createAnimationFrameData(callbackId), TimelineRecordType::FireAnimationFrame, false, frame);
402 }
403
404 void InspectorTimelineAgent::didFireAnimationFrame()
405 {
406     didCompleteCurrentRecord(TimelineRecordType::FireAnimationFrame);
407 }
408
409 #if ENABLE(WEB_SOCKETS)
410 void InspectorTimelineAgent::didCreateWebSocket(unsigned long identifier, const URL& url, const String& protocol, Frame* frame)
411 {
412     appendRecord(TimelineRecordFactory::createWebSocketCreateData(identifier, url, protocol), TimelineRecordType::WebSocketCreate, true, frame);
413 }
414
415 void InspectorTimelineAgent::willSendWebSocketHandshakeRequest(unsigned long identifier, Frame* frame)
416 {
417     appendRecord(TimelineRecordFactory::createGenericWebSocketData(identifier), TimelineRecordType::WebSocketSendHandshakeRequest, true, frame);
418 }
419
420 void InspectorTimelineAgent::didReceiveWebSocketHandshakeResponse(unsigned long identifier, Frame* frame)
421 {
422     appendRecord(TimelineRecordFactory::createGenericWebSocketData(identifier), TimelineRecordType::WebSocketReceiveHandshakeResponse, false, frame);
423 }
424
425 void InspectorTimelineAgent::didDestroyWebSocket(unsigned long identifier, Frame* frame)
426 {
427     appendRecord(TimelineRecordFactory::createGenericWebSocketData(identifier), TimelineRecordType::WebSocketDestroy, true, frame);
428 }
429 #endif // ENABLE(WEB_SOCKETS)
430
431 // ScriptDebugListener
432
433 void InspectorTimelineAgent::breakpointActionProbe(JSC::ExecState* exec, const Inspector::ScriptBreakpointAction& action, int hitCount, const Deprecated::ScriptValue&)
434 {
435     ASSERT(exec);
436
437     ScriptExecutionContext* context = scriptExecutionContextFromExecState(exec);
438     Document* document = (context && context->isDocument()) ? toDocument(context) : nullptr;
439     Frame* frame = document ? document->frame() : nullptr;
440     appendRecord(TimelineRecordFactory::createProbeSampleData(action, hitCount), TimelineRecordType::ProbeSample, false, frame);
441 }
442
443 static Inspector::TypeBuilder::Timeline::EventType::Enum toProtocol(TimelineRecordType type)
444 {
445     switch (type) {
446     case TimelineRecordType::EventDispatch:
447         return Inspector::TypeBuilder::Timeline::EventType::EventDispatch;
448     case TimelineRecordType::ScheduleStyleRecalculation:
449         return Inspector::TypeBuilder::Timeline::EventType::ScheduleStyleRecalculation;
450     case TimelineRecordType::RecalculateStyles:
451         return Inspector::TypeBuilder::Timeline::EventType::RecalculateStyles;
452     case TimelineRecordType::InvalidateLayout:
453         return Inspector::TypeBuilder::Timeline::EventType::InvalidateLayout;
454     case TimelineRecordType::Layout:
455         return Inspector::TypeBuilder::Timeline::EventType::Layout;
456     case TimelineRecordType::Paint:
457         return Inspector::TypeBuilder::Timeline::EventType::Paint;
458     case TimelineRecordType::ScrollLayer:
459         return Inspector::TypeBuilder::Timeline::EventType::ScrollLayer;
460     case TimelineRecordType::ResizeImage:
461         return Inspector::TypeBuilder::Timeline::EventType::ResizeImage;
462
463     case TimelineRecordType::ParseHTML:
464         return Inspector::TypeBuilder::Timeline::EventType::ParseHTML;
465
466     case TimelineRecordType::TimerInstall:
467         return Inspector::TypeBuilder::Timeline::EventType::TimerInstall;
468     case TimelineRecordType::TimerRemove:
469         return Inspector::TypeBuilder::Timeline::EventType::TimerRemove;
470     case TimelineRecordType::TimerFire:
471         return Inspector::TypeBuilder::Timeline::EventType::TimerFire;
472
473     case TimelineRecordType::EvaluateScript:
474         return Inspector::TypeBuilder::Timeline::EventType::EvaluateScript;
475
476     case TimelineRecordType::MarkLoad:
477         return Inspector::TypeBuilder::Timeline::EventType::MarkLoad;
478     case TimelineRecordType::MarkDOMContent:
479         return Inspector::TypeBuilder::Timeline::EventType::MarkDOMContent;
480
481     case TimelineRecordType::TimeStamp:
482         return Inspector::TypeBuilder::Timeline::EventType::TimeStamp;
483     case TimelineRecordType::Time:
484         return Inspector::TypeBuilder::Timeline::EventType::Time;
485     case TimelineRecordType::TimeEnd:
486         return Inspector::TypeBuilder::Timeline::EventType::TimeEnd;
487
488     case TimelineRecordType::ScheduleResourceRequest:
489         return Inspector::TypeBuilder::Timeline::EventType::ScheduleResourceRequest;
490     case TimelineRecordType::ResourceSendRequest:
491         return Inspector::TypeBuilder::Timeline::EventType::ResourceSendRequest;
492     case TimelineRecordType::ResourceReceiveResponse:
493         return Inspector::TypeBuilder::Timeline::EventType::ResourceReceiveResponse;
494     case TimelineRecordType::ResourceReceivedData:
495         return Inspector::TypeBuilder::Timeline::EventType::ResourceReceivedData;
496     case TimelineRecordType::ResourceFinish:
497         return Inspector::TypeBuilder::Timeline::EventType::ResourceFinish;
498
499     case TimelineRecordType::XHRReadyStateChange:
500         return Inspector::TypeBuilder::Timeline::EventType::XHRReadyStateChange;
501     case TimelineRecordType::XHRLoad:
502         return Inspector::TypeBuilder::Timeline::EventType::XHRLoad;
503
504     case TimelineRecordType::FunctionCall:
505         return Inspector::TypeBuilder::Timeline::EventType::FunctionCall;
506     case TimelineRecordType::ProbeSample:
507         return Inspector::TypeBuilder::Timeline::EventType::ProbeSample;
508
509     case TimelineRecordType::RequestAnimationFrame:
510         return Inspector::TypeBuilder::Timeline::EventType::RequestAnimationFrame;
511     case TimelineRecordType::CancelAnimationFrame:
512         return Inspector::TypeBuilder::Timeline::EventType::CancelAnimationFrame;
513     case TimelineRecordType::FireAnimationFrame:
514         return Inspector::TypeBuilder::Timeline::EventType::FireAnimationFrame;
515
516     case TimelineRecordType::WebSocketCreate:
517         return Inspector::TypeBuilder::Timeline::EventType::WebSocketCreate;
518     case TimelineRecordType::WebSocketSendHandshakeRequest:
519         return Inspector::TypeBuilder::Timeline::EventType::WebSocketSendHandshakeRequest;
520     case TimelineRecordType::WebSocketReceiveHandshakeResponse:
521         return Inspector::TypeBuilder::Timeline::EventType::WebSocketReceiveHandshakeResponse;
522     case TimelineRecordType::WebSocketDestroy:
523         return Inspector::TypeBuilder::Timeline::EventType::WebSocketDestroy;
524     }
525
526     return Inspector::TypeBuilder::Timeline::EventType::TimeStamp;
527 }
528
529 void InspectorTimelineAgent::addRecordToTimeline(PassRefPtr<InspectorObject> prpRecord, TimelineRecordType type)
530 {
531     prpRecord->setString("type", Inspector::TypeBuilder::getWebEnumConstantValue(toProtocol(type)));
532
533     RefPtr<Inspector::TypeBuilder::Timeline::TimelineEvent> record = Inspector::TypeBuilder::Timeline::TimelineEvent::runtimeCast(prpRecord);
534
535     if (m_recordStack.isEmpty())
536         sendEvent(record.release());
537     else {
538         TimelineRecordEntry parent = m_recordStack.last();
539         parent.children->pushObject(record.release());
540     }
541 }
542
543 void InspectorTimelineAgent::setFrameIdentifier(InspectorObject* record, Frame* frame)
544 {
545     if (!frame || !m_pageAgent)
546         return;
547     String frameId;
548     if (frame && m_pageAgent)
549         frameId = m_pageAgent->frameId(frame);
550     record->setString("frameId", frameId);
551 }
552
553 void InspectorTimelineAgent::didCompleteCurrentRecord(TimelineRecordType type)
554 {
555     // An empty stack could merely mean that the timeline agent was turned on in the middle of
556     // an event.  Don't treat as an error.
557     if (!m_recordStack.isEmpty()) {
558         TimelineRecordEntry entry = m_recordStack.last();
559         m_recordStack.removeLast();
560         ASSERT(entry.type == type);
561         entry.record->setObject("data", entry.data);
562         entry.record->setArray("children", entry.children);
563         entry.record->setNumber("endTime", timestamp());
564         addRecordToTimeline(entry.record, type);
565     }
566 }
567
568 InspectorTimelineAgent::InspectorTimelineAgent(InstrumentingAgents* instrumentingAgents, InspectorPageAgent* pageAgent, InspectorType type, InspectorClient* client)
569     : InspectorAgentBase(ASCIILiteral("Timeline"), instrumentingAgents)
570     , m_pageAgent(pageAgent)
571     , m_id(1)
572     , m_maxCallStackDepth(5)
573     , m_inspectorType(type)
574     , m_client(client)
575     , m_weakFactory(this)
576     , m_enabled(false)
577     , m_recordingProfile(false)
578 {
579 }
580
581 void InspectorTimelineAgent::appendRecord(PassRefPtr<InspectorObject> data, TimelineRecordType type, bool captureCallStack, Frame* frame)
582 {
583     RefPtr<InspectorObject> record = TimelineRecordFactory::createGenericRecord(timestamp(), captureCallStack ? m_maxCallStackDepth : 0);
584     record->setObject("data", data);
585     setFrameIdentifier(record.get(), frame);
586     addRecordToTimeline(record.release(), type);
587 }
588
589 void InspectorTimelineAgent::sendEvent(PassRefPtr<InspectorObject> event)
590 {
591     // FIXME: runtimeCast is a hack. We do it because we can't build TimelineEvent directly now.
592     RefPtr<Inspector::TypeBuilder::Timeline::TimelineEvent> recordChecked = Inspector::TypeBuilder::Timeline::TimelineEvent::runtimeCast(event);
593     m_frontendDispatcher->eventRecorded(recordChecked.release());
594 }
595
596 void InspectorTimelineAgent::pushCurrentRecord(PassRefPtr<InspectorObject> data, TimelineRecordType type, bool captureCallStack, Frame* frame)
597 {
598     RefPtr<InspectorObject> record = TimelineRecordFactory::createGenericRecord(timestamp(), captureCallStack ? m_maxCallStackDepth : 0);
599     setFrameIdentifier(record.get(), frame);
600     m_recordStack.append(TimelineRecordEntry(record.release(), data, InspectorArray::create(), type));
601 }
602
603 void InspectorTimelineAgent::clearRecordStack()
604 {
605     m_recordStack.clear();
606     m_id++;
607 }
608
609 void InspectorTimelineAgent::localToPageQuad(const RenderObject& renderer, const LayoutRect& rect, FloatQuad* quad)
610 {
611     const FrameView& frameView = renderer.view().frameView();
612     FloatQuad absolute = renderer.localToAbsoluteQuad(FloatQuad(rect));
613     quad->setP1(frameView.contentsToRootView(roundedIntPoint(absolute.p1())));
614     quad->setP2(frameView.contentsToRootView(roundedIntPoint(absolute.p2())));
615     quad->setP3(frameView.contentsToRootView(roundedIntPoint(absolute.p3())));
616     quad->setP4(frameView.contentsToRootView(roundedIntPoint(absolute.p4())));
617 }
618
619 double InspectorTimelineAgent::timestamp()
620 {
621     return m_timeConverter.fromMonotonicallyIncreasingTime(monotonicallyIncreasingTime());
622 }
623
624 Page* InspectorTimelineAgent::page()
625 {
626     return m_pageAgent ? m_pageAgent->page() : nullptr;
627 }
628
629 } // namespace WebCore
630
631 #endif // ENABLE(INSPECTOR)