68964918f3f530437818120968aefec76e8a0492
[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::canMonitorMainThread(ErrorString*, bool* result)
120 {
121     *result = m_client && m_client->canMonitorMainThread();
122 }
123
124 void InspectorTimelineAgent::supportsFrameInstrumentation(ErrorString*, bool* result)
125 {
126     *result = m_client && m_client->supportsFrameInstrumentation();
127 }
128
129 void InspectorTimelineAgent::didBeginFrame()
130 {
131     m_pendingFrameRecord = TimelineRecordFactory::createGenericRecord(timestamp(), 0);
132 }
133
134 void InspectorTimelineAgent::didCancelFrame()
135 {
136     m_pendingFrameRecord.clear();
137 }
138
139 void InspectorTimelineAgent::willCallFunction(const String& scriptName, int scriptLine, Frame* frame)
140 {
141     pushCurrentRecord(TimelineRecordFactory::createFunctionCallData(scriptName, scriptLine), TimelineRecordType::FunctionCall, true, frame);
142
143     if (frame && !m_recordingProfile) {
144         m_recordingProfile = true;
145         ScriptProfiler::start(toJSDOMWindow(frame, debuggerWorld())->globalExec(), ASCIILiteral("Timeline FunctionCall"));
146     }
147 }
148
149 void InspectorTimelineAgent::didCallFunction(Frame* frame)
150 {
151     if (frame && m_recordingProfile) {
152         if (m_recordStack.isEmpty())
153             return;
154
155         TimelineRecordEntry& entry = m_recordStack.last();
156         ASSERT(entry.type == TimelineRecordType::FunctionCall);
157
158         RefPtr<ScriptProfile> profile = ScriptProfiler::stop(toJSDOMWindow(frame, debuggerWorld())->globalExec(), ASCIILiteral("Timeline FunctionCall"));
159         if (profile)
160             TimelineRecordFactory::appendProfile(entry.data.get(), profile.release());
161
162         m_recordingProfile = false;
163     }
164
165     didCompleteCurrentRecord(TimelineRecordType::FunctionCall);
166 }
167
168 void InspectorTimelineAgent::willDispatchEvent(const Event& event, Frame* frame)
169 {
170     pushCurrentRecord(TimelineRecordFactory::createEventDispatchData(event), TimelineRecordType::EventDispatch, false, frame);
171 }
172
173 void InspectorTimelineAgent::didDispatchEvent()
174 {
175     didCompleteCurrentRecord(TimelineRecordType::EventDispatch);
176 }
177
178 void InspectorTimelineAgent::didInvalidateLayout(Frame* frame)
179 {
180     appendRecord(InspectorObject::create(), TimelineRecordType::InvalidateLayout, true, frame);
181 }
182
183 void InspectorTimelineAgent::willLayout(Frame* frame)
184 {
185     RenderObject* root = frame->view()->layoutRoot();
186     bool partialLayout = !!root;
187
188     if (!partialLayout)
189         root = frame->contentRenderer();
190
191     unsigned dirtyObjects = 0;
192     unsigned totalObjects = 0;
193     for (RenderObject* o = root; o; o = o->nextInPreOrder(root)) {
194         ++totalObjects;
195         if (o->needsLayout())
196             ++dirtyObjects;
197     }
198     pushCurrentRecord(TimelineRecordFactory::createLayoutData(dirtyObjects, totalObjects, partialLayout), TimelineRecordType::Layout, true, frame);
199 }
200
201 void InspectorTimelineAgent::didLayout(RenderObject* root)
202 {
203     if (m_recordStack.isEmpty())
204         return;
205     TimelineRecordEntry& entry = m_recordStack.last();
206     ASSERT(entry.type == TimelineRecordType::Layout);
207     Vector<FloatQuad> quads;
208     root->absoluteQuads(quads);
209     if (quads.size() >= 1)
210         TimelineRecordFactory::appendLayoutRoot(entry.data.get(), quads[0]);
211     else
212         ASSERT_NOT_REACHED();
213     didCompleteCurrentRecord(TimelineRecordType::Layout);
214 }
215
216 void InspectorTimelineAgent::didScheduleStyleRecalculation(Frame* frame)
217 {
218     appendRecord(InspectorObject::create(), TimelineRecordType::ScheduleStyleRecalculation, true, frame);
219 }
220
221 void InspectorTimelineAgent::willRecalculateStyle(Frame* frame)
222 {
223     pushCurrentRecord(InspectorObject::create(), TimelineRecordType::RecalculateStyles, true, frame);
224 }
225
226 void InspectorTimelineAgent::didRecalculateStyle()
227 {
228     didCompleteCurrentRecord(TimelineRecordType::RecalculateStyles);
229 }
230
231 void InspectorTimelineAgent::willPaint(Frame* frame)
232 {
233     pushCurrentRecord(InspectorObject::create(), TimelineRecordType::Paint, true, frame);
234 }
235
236 void InspectorTimelineAgent::didPaint(RenderObject* renderer, const LayoutRect& clipRect)
237 {
238     TimelineRecordEntry& entry = m_recordStack.last();
239     ASSERT(entry.type == TimelineRecordType::Paint);
240     FloatQuad quad;
241     localToPageQuad(*renderer, clipRect, &quad);
242     entry.data = TimelineRecordFactory::createPaintData(quad);
243     didCompleteCurrentRecord(TimelineRecordType::Paint);
244 }
245
246 void InspectorTimelineAgent::willScroll(Frame* frame)
247 {
248     pushCurrentRecord(InspectorObject::create(), TimelineRecordType::ScrollLayer, false, frame);
249 }
250
251 void InspectorTimelineAgent::didScroll()
252 {
253     didCompleteCurrentRecord(TimelineRecordType::ScrollLayer);
254 }
255
256 void InspectorTimelineAgent::willComposite()
257 {
258     pushCurrentRecord(InspectorObject::create(), TimelineRecordType::CompositeLayers, false, nullptr);
259 }
260
261 void InspectorTimelineAgent::didComposite()
262 {
263     didCompleteCurrentRecord(TimelineRecordType::CompositeLayers);
264 }
265
266 void InspectorTimelineAgent::willWriteHTML(unsigned startLine, Frame* frame)
267 {
268     pushCurrentRecord(TimelineRecordFactory::createParseHTMLData(startLine), TimelineRecordType::ParseHTML, true, frame);
269 }
270
271 void InspectorTimelineAgent::didWriteHTML(unsigned endLine)
272 {
273     if (!m_recordStack.isEmpty()) {
274         TimelineRecordEntry entry = m_recordStack.last();
275         entry.data->setNumber("endLine", endLine);
276         didCompleteCurrentRecord(TimelineRecordType::ParseHTML);
277     }
278 }
279
280 void InspectorTimelineAgent::didInstallTimer(int timerId, int timeout, bool singleShot, Frame* frame)
281 {
282     appendRecord(TimelineRecordFactory::createTimerInstallData(timerId, timeout, singleShot), TimelineRecordType::TimerInstall, true, frame);
283 }
284
285 void InspectorTimelineAgent::didRemoveTimer(int timerId, Frame* frame)
286 {
287     appendRecord(TimelineRecordFactory::createGenericTimerData(timerId), TimelineRecordType::TimerRemove, true, frame);
288 }
289
290 void InspectorTimelineAgent::willFireTimer(int timerId, Frame* frame)
291 {
292     pushCurrentRecord(TimelineRecordFactory::createGenericTimerData(timerId), TimelineRecordType::TimerFire, false, frame);
293 }
294
295 void InspectorTimelineAgent::didFireTimer()
296 {
297     didCompleteCurrentRecord(TimelineRecordType::TimerFire);
298 }
299
300 void InspectorTimelineAgent::willDispatchXHRReadyStateChangeEvent(const String& url, int readyState, Frame* frame)
301 {
302     pushCurrentRecord(TimelineRecordFactory::createXHRReadyStateChangeData(url, readyState), TimelineRecordType::XHRReadyStateChange, false, frame);
303 }
304
305 void InspectorTimelineAgent::didDispatchXHRReadyStateChangeEvent()
306 {
307     didCompleteCurrentRecord(TimelineRecordType::XHRReadyStateChange);
308 }
309
310 void InspectorTimelineAgent::willDispatchXHRLoadEvent(const String& url, Frame* frame)
311 {
312     pushCurrentRecord(TimelineRecordFactory::createXHRLoadData(url), TimelineRecordType::XHRLoad, true, frame);
313 }
314
315 void InspectorTimelineAgent::didDispatchXHRLoadEvent()
316 {
317     didCompleteCurrentRecord(TimelineRecordType::XHRLoad);
318 }
319
320 void InspectorTimelineAgent::willEvaluateScript(const String& url, int lineNumber, Frame* frame)
321 {
322     pushCurrentRecord(TimelineRecordFactory::createEvaluateScriptData(url, lineNumber), TimelineRecordType::EvaluateScript, true, frame);
323
324     if (frame && !m_recordingProfile) {
325         m_recordingProfile = true;
326         ScriptProfiler::start(toJSDOMWindow(frame, debuggerWorld())->globalExec(), ASCIILiteral("Timeline EvaluateScript"));
327     }
328 }
329
330 void InspectorTimelineAgent::didEvaluateScript(Frame* frame)
331 {
332     if (frame && m_recordingProfile) {
333         if (m_recordStack.isEmpty())
334             return;
335
336         TimelineRecordEntry& entry = m_recordStack.last();
337         ASSERT(entry.type == TimelineRecordType::EvaluateScript);
338
339         RefPtr<ScriptProfile> profile = ScriptProfiler::stop(toJSDOMWindow(frame, debuggerWorld())->globalExec(), ASCIILiteral("Timeline EvaluateScript"));
340         if (profile)
341             TimelineRecordFactory::appendProfile(entry.data.get(), profile.release());
342
343         m_recordingProfile = false;
344     }
345
346     didCompleteCurrentRecord(TimelineRecordType::EvaluateScript);
347 }
348
349 void InspectorTimelineAgent::didScheduleResourceRequest(const String& url, Frame* frame)
350 {
351     appendRecord(TimelineRecordFactory::createScheduleResourceRequestData(url), TimelineRecordType::ScheduleResourceRequest, true, frame);
352 }
353
354 void InspectorTimelineAgent::willSendResourceRequest(unsigned long identifier, const ResourceRequest& request, Frame* frame)
355 {
356     String requestId = IdentifiersFactory::requestId(identifier);
357     appendRecord(TimelineRecordFactory::createResourceSendRequestData(requestId, request), TimelineRecordType::ResourceSendRequest, true, frame);
358 }
359
360 void InspectorTimelineAgent::willReceiveResourceData(unsigned long identifier, Frame* frame, int length)
361 {
362     String requestId = IdentifiersFactory::requestId(identifier);
363     pushCurrentRecord(TimelineRecordFactory::createReceiveResourceData(requestId, length), TimelineRecordType::ResourceReceivedData, false, frame);
364 }
365
366 void InspectorTimelineAgent::didReceiveResourceData()
367 {
368     didCompleteCurrentRecord(TimelineRecordType::ResourceReceivedData);
369 }
370
371 void InspectorTimelineAgent::willReceiveResourceResponse(unsigned long identifier, const ResourceResponse& response, Frame* frame)
372 {
373     String requestId = IdentifiersFactory::requestId(identifier);
374     pushCurrentRecord(TimelineRecordFactory::createResourceReceiveResponseData(requestId, response), TimelineRecordType::ResourceReceiveResponse, false, frame);
375 }
376
377 void InspectorTimelineAgent::didReceiveResourceResponse()
378 {
379     didCompleteCurrentRecord(TimelineRecordType::ResourceReceiveResponse);
380 }
381
382 void InspectorTimelineAgent::didFinishLoadingResource(unsigned long identifier, bool didFail, double finishTime, Frame* frame)
383 {
384     appendRecord(TimelineRecordFactory::createResourceFinishData(IdentifiersFactory::requestId(identifier), didFail, finishTime * 1000), TimelineRecordType::ResourceFinish, false, frame);
385 }
386
387 void InspectorTimelineAgent::didTimeStamp(Frame* frame, const String& message)
388 {
389     appendRecord(TimelineRecordFactory::createTimeStampData(message), TimelineRecordType::TimeStamp, true, frame);
390 }
391
392 void InspectorTimelineAgent::time(Frame* frame, const String& message)
393 {
394     appendRecord(TimelineRecordFactory::createTimeStampData(message), TimelineRecordType::Time, true, frame);
395 }
396
397 void InspectorTimelineAgent::timeEnd(Frame* frame, const String& message)
398 {
399     appendRecord(TimelineRecordFactory::createTimeStampData(message), TimelineRecordType::TimeEnd, true, frame);
400 }
401
402 void InspectorTimelineAgent::didMarkDOMContentEvent(Frame* frame)
403 {
404     bool isMainFrame = frame && m_pageAgent && (frame == m_pageAgent->mainFrame());
405     appendRecord(TimelineRecordFactory::createMarkData(isMainFrame), TimelineRecordType::MarkDOMContent, false, frame);
406 }
407
408 void InspectorTimelineAgent::didMarkLoadEvent(Frame* frame)
409 {
410     bool isMainFrame = frame && m_pageAgent && (frame == m_pageAgent->mainFrame());
411     appendRecord(TimelineRecordFactory::createMarkData(isMainFrame), TimelineRecordType::MarkLoad, false, frame);
412 }
413
414 void InspectorTimelineAgent::didCommitLoad()
415 {
416     clearRecordStack();
417 }
418
419 void InspectorTimelineAgent::didRequestAnimationFrame(int callbackId, Frame* frame)
420 {
421     appendRecord(TimelineRecordFactory::createAnimationFrameData(callbackId), TimelineRecordType::RequestAnimationFrame, true, frame);
422 }
423
424 void InspectorTimelineAgent::didCancelAnimationFrame(int callbackId, Frame* frame)
425 {
426     appendRecord(TimelineRecordFactory::createAnimationFrameData(callbackId), TimelineRecordType::CancelAnimationFrame, true, frame);
427 }
428
429 void InspectorTimelineAgent::willFireAnimationFrame(int callbackId, Frame* frame)
430 {
431     pushCurrentRecord(TimelineRecordFactory::createAnimationFrameData(callbackId), TimelineRecordType::FireAnimationFrame, false, frame);
432 }
433
434 void InspectorTimelineAgent::didFireAnimationFrame()
435 {
436     didCompleteCurrentRecord(TimelineRecordType::FireAnimationFrame);
437 }
438
439 #if ENABLE(WEB_SOCKETS)
440 void InspectorTimelineAgent::didCreateWebSocket(unsigned long identifier, const URL& url, const String& protocol, Frame* frame)
441 {
442     appendRecord(TimelineRecordFactory::createWebSocketCreateData(identifier, url, protocol), TimelineRecordType::WebSocketCreate, true, frame);
443 }
444
445 void InspectorTimelineAgent::willSendWebSocketHandshakeRequest(unsigned long identifier, Frame* frame)
446 {
447     appendRecord(TimelineRecordFactory::createGenericWebSocketData(identifier), TimelineRecordType::WebSocketSendHandshakeRequest, true, frame);
448 }
449
450 void InspectorTimelineAgent::didReceiveWebSocketHandshakeResponse(unsigned long identifier, Frame* frame)
451 {
452     appendRecord(TimelineRecordFactory::createGenericWebSocketData(identifier), TimelineRecordType::WebSocketReceiveHandshakeResponse, false, frame);
453 }
454
455 void InspectorTimelineAgent::didDestroyWebSocket(unsigned long identifier, Frame* frame)
456 {
457     appendRecord(TimelineRecordFactory::createGenericWebSocketData(identifier), TimelineRecordType::WebSocketDestroy, true, frame);
458 }
459 #endif // ENABLE(WEB_SOCKETS)
460
461 // ScriptDebugListener
462
463 void InspectorTimelineAgent::breakpointActionProbe(JSC::ExecState* exec, const Inspector::ScriptBreakpointAction& action, int hitCount, const Deprecated::ScriptValue&)
464 {
465     ASSERT(exec);
466
467     ScriptExecutionContext* context = scriptExecutionContextFromExecState(exec);
468     Document* document = (context && context->isDocument()) ? toDocument(context) : nullptr;
469     Frame* frame = document ? document->frame() : nullptr;
470     appendRecord(TimelineRecordFactory::createProbeSampleData(action, hitCount), TimelineRecordType::ProbeSample, false, frame);
471 }
472
473 void InspectorTimelineAgent::addRecordToTimeline(PassRefPtr<InspectorObject> record, TimelineRecordType type)
474 {
475     commitFrameRecord();
476     innerAddRecordToTimeline(record, type);
477 }
478
479 static Inspector::TypeBuilder::Timeline::EventType::Enum toProtocol(TimelineRecordType type)
480 {
481     switch (type) {
482     case TimelineRecordType::EventDispatch:
483         return Inspector::TypeBuilder::Timeline::EventType::EventDispatch;
484     case TimelineRecordType::BeginFrame:
485         return Inspector::TypeBuilder::Timeline::EventType::BeginFrame;
486     case TimelineRecordType::ScheduleStyleRecalculation:
487         return Inspector::TypeBuilder::Timeline::EventType::ScheduleStyleRecalculation;
488     case TimelineRecordType::RecalculateStyles:
489         return Inspector::TypeBuilder::Timeline::EventType::RecalculateStyles;
490     case TimelineRecordType::InvalidateLayout:
491         return Inspector::TypeBuilder::Timeline::EventType::InvalidateLayout;
492     case TimelineRecordType::Layout:
493         return Inspector::TypeBuilder::Timeline::EventType::Layout;
494     case TimelineRecordType::Paint:
495         return Inspector::TypeBuilder::Timeline::EventType::Paint;
496     case TimelineRecordType::ScrollLayer:
497         return Inspector::TypeBuilder::Timeline::EventType::ScrollLayer;
498     case TimelineRecordType::ResizeImage:
499         return Inspector::TypeBuilder::Timeline::EventType::ResizeImage;
500     case TimelineRecordType::CompositeLayers:
501         return Inspector::TypeBuilder::Timeline::EventType::CompositeLayers;
502
503     case TimelineRecordType::ParseHTML:
504         return Inspector::TypeBuilder::Timeline::EventType::ParseHTML;
505
506     case TimelineRecordType::TimerInstall:
507         return Inspector::TypeBuilder::Timeline::EventType::TimerInstall;
508     case TimelineRecordType::TimerRemove:
509         return Inspector::TypeBuilder::Timeline::EventType::TimerRemove;
510     case TimelineRecordType::TimerFire:
511         return Inspector::TypeBuilder::Timeline::EventType::TimerFire;
512
513     case TimelineRecordType::EvaluateScript:
514         return Inspector::TypeBuilder::Timeline::EventType::EvaluateScript;
515
516     case TimelineRecordType::MarkLoad:
517         return Inspector::TypeBuilder::Timeline::EventType::MarkLoad;
518     case TimelineRecordType::MarkDOMContent:
519         return Inspector::TypeBuilder::Timeline::EventType::MarkDOMContent;
520
521     case TimelineRecordType::TimeStamp:
522         return Inspector::TypeBuilder::Timeline::EventType::TimeStamp;
523     case TimelineRecordType::Time:
524         return Inspector::TypeBuilder::Timeline::EventType::Time;
525     case TimelineRecordType::TimeEnd:
526         return Inspector::TypeBuilder::Timeline::EventType::TimeEnd;
527
528     case TimelineRecordType::ScheduleResourceRequest:
529         return Inspector::TypeBuilder::Timeline::EventType::ScheduleResourceRequest;
530     case TimelineRecordType::ResourceSendRequest:
531         return Inspector::TypeBuilder::Timeline::EventType::ResourceSendRequest;
532     case TimelineRecordType::ResourceReceiveResponse:
533         return Inspector::TypeBuilder::Timeline::EventType::ResourceReceiveResponse;
534     case TimelineRecordType::ResourceReceivedData:
535         return Inspector::TypeBuilder::Timeline::EventType::ResourceReceivedData;
536     case TimelineRecordType::ResourceFinish:
537         return Inspector::TypeBuilder::Timeline::EventType::ResourceFinish;
538
539     case TimelineRecordType::XHRReadyStateChange:
540         return Inspector::TypeBuilder::Timeline::EventType::XHRReadyStateChange;
541     case TimelineRecordType::XHRLoad:
542         return Inspector::TypeBuilder::Timeline::EventType::XHRLoad;
543
544     case TimelineRecordType::FunctionCall:
545         return Inspector::TypeBuilder::Timeline::EventType::FunctionCall;
546     case TimelineRecordType::ProbeSample:
547         return Inspector::TypeBuilder::Timeline::EventType::ProbeSample;
548
549     case TimelineRecordType::RequestAnimationFrame:
550         return Inspector::TypeBuilder::Timeline::EventType::RequestAnimationFrame;
551     case TimelineRecordType::CancelAnimationFrame:
552         return Inspector::TypeBuilder::Timeline::EventType::CancelAnimationFrame;
553     case TimelineRecordType::FireAnimationFrame:
554         return Inspector::TypeBuilder::Timeline::EventType::FireAnimationFrame;
555
556     case TimelineRecordType::WebSocketCreate:
557         return Inspector::TypeBuilder::Timeline::EventType::WebSocketCreate;
558     case TimelineRecordType::WebSocketSendHandshakeRequest:
559         return Inspector::TypeBuilder::Timeline::EventType::WebSocketSendHandshakeRequest;
560     case TimelineRecordType::WebSocketReceiveHandshakeResponse:
561         return Inspector::TypeBuilder::Timeline::EventType::WebSocketReceiveHandshakeResponse;
562     case TimelineRecordType::WebSocketDestroy:
563         return Inspector::TypeBuilder::Timeline::EventType::WebSocketDestroy;
564     }
565
566     return Inspector::TypeBuilder::Timeline::EventType::TimeStamp;
567 }
568
569 void InspectorTimelineAgent::innerAddRecordToTimeline(PassRefPtr<InspectorObject> prpRecord, TimelineRecordType type)
570 {
571     prpRecord->setString("type", Inspector::TypeBuilder::getWebEnumConstantValue(toProtocol(type)));
572
573     RefPtr<Inspector::TypeBuilder::Timeline::TimelineEvent> record = Inspector::TypeBuilder::Timeline::TimelineEvent::runtimeCast(prpRecord);
574
575     if (m_recordStack.isEmpty())
576         sendEvent(record.release());
577     else {
578         TimelineRecordEntry parent = m_recordStack.last();
579         parent.children->pushObject(record.release());
580     }
581 }
582
583 static size_t usedHeapSize()
584 {
585     return JSDOMWindow::commonVM().heap.size();
586 }
587
588 void InspectorTimelineAgent::setFrameIdentifier(InspectorObject* record, Frame* frame)
589 {
590     if (!frame || !m_pageAgent)
591         return;
592     String frameId;
593     if (frame && m_pageAgent)
594         frameId = m_pageAgent->frameId(frame);
595     record->setString("frameId", frameId);
596 }
597
598 void InspectorTimelineAgent::didCompleteCurrentRecord(TimelineRecordType type)
599 {
600     // An empty stack could merely mean that the timeline agent was turned on in the middle of
601     // an event.  Don't treat as an error.
602     if (!m_recordStack.isEmpty()) {
603         TimelineRecordEntry entry = m_recordStack.last();
604         m_recordStack.removeLast();
605         ASSERT(entry.type == type);
606         entry.record->setObject("data", entry.data);
607         entry.record->setArray("children", entry.children);
608         entry.record->setNumber("endTime", timestamp());
609         size_t usedHeapSizeDelta = usedHeapSize() - entry.usedHeapSizeAtStart;
610         if (usedHeapSizeDelta)
611             entry.record->setNumber("usedHeapSizeDelta", usedHeapSizeDelta);
612         addRecordToTimeline(entry.record, type);
613     }
614 }
615
616 InspectorTimelineAgent::InspectorTimelineAgent(InstrumentingAgents* instrumentingAgents, InspectorPageAgent* pageAgent, InspectorType type, InspectorClient* client)
617     : InspectorAgentBase(ASCIILiteral("Timeline"), instrumentingAgents)
618     , m_pageAgent(pageAgent)
619     , m_id(1)
620     , m_maxCallStackDepth(5)
621     , m_inspectorType(type)
622     , m_client(client)
623     , m_weakFactory(this)
624     , m_enabled(false)
625     , m_recordingProfile(false)
626 {
627 }
628
629 void InspectorTimelineAgent::appendRecord(PassRefPtr<InspectorObject> data, TimelineRecordType type, bool captureCallStack, Frame* frame)
630 {
631     RefPtr<InspectorObject> record = TimelineRecordFactory::createGenericRecord(timestamp(), captureCallStack ? m_maxCallStackDepth : 0);
632     record->setObject("data", data);
633     setFrameIdentifier(record.get(), frame);
634     addRecordToTimeline(record.release(), type);
635 }
636
637 void InspectorTimelineAgent::sendEvent(PassRefPtr<InspectorObject> event)
638 {
639     // FIXME: runtimeCast is a hack. We do it because we can't build TimelineEvent directly now.
640     RefPtr<Inspector::TypeBuilder::Timeline::TimelineEvent> recordChecked = Inspector::TypeBuilder::Timeline::TimelineEvent::runtimeCast(event);
641     m_frontendDispatcher->eventRecorded(recordChecked.release());
642 }
643
644 void InspectorTimelineAgent::pushCurrentRecord(PassRefPtr<InspectorObject> data, TimelineRecordType type, bool captureCallStack, Frame* frame)
645 {
646     commitFrameRecord();
647     RefPtr<InspectorObject> record = TimelineRecordFactory::createGenericRecord(timestamp(), captureCallStack ? m_maxCallStackDepth : 0);
648     setFrameIdentifier(record.get(), frame);
649     m_recordStack.append(TimelineRecordEntry(record.release(), data, InspectorArray::create(), type, usedHeapSize()));
650 }
651
652 void InspectorTimelineAgent::commitFrameRecord()
653 {
654     if (!m_pendingFrameRecord)
655         return;
656     
657     m_pendingFrameRecord->setObject("data", InspectorObject::create());
658     innerAddRecordToTimeline(m_pendingFrameRecord.release(), TimelineRecordType::BeginFrame);
659 }
660
661 void InspectorTimelineAgent::clearRecordStack()
662 {
663     m_pendingFrameRecord.clear();
664     m_recordStack.clear();
665     m_id++;
666 }
667
668 void InspectorTimelineAgent::localToPageQuad(const RenderObject& renderer, const LayoutRect& rect, FloatQuad* quad)
669 {
670     const FrameView& frameView = renderer.view().frameView();
671     FloatQuad absolute = renderer.localToAbsoluteQuad(FloatQuad(rect));
672     quad->setP1(frameView.contentsToRootView(roundedIntPoint(absolute.p1())));
673     quad->setP2(frameView.contentsToRootView(roundedIntPoint(absolute.p2())));
674     quad->setP3(frameView.contentsToRootView(roundedIntPoint(absolute.p3())));
675     quad->setP4(frameView.contentsToRootView(roundedIntPoint(absolute.p4())));
676 }
677
678 double InspectorTimelineAgent::timestamp()
679 {
680     return m_timeConverter.fromMonotonicallyIncreasingTime(monotonicallyIncreasingTime());
681 }
682
683 Page* InspectorTimelineAgent::page()
684 {
685     return m_pageAgent ? m_pageAgent->page() : nullptr;
686 }
687
688 } // namespace WebCore
689
690 #endif // ENABLE(INSPECTOR)