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