Remove TimelineTraceEventProcessor since no current ports use it
[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 "IdentifiersFactory.h"
41 #include "InspectorClient.h"
42 #include "InspectorCounters.h"
43 #include "InspectorFrontend.h"
44 #include "InspectorInstrumentation.h"
45 #include "InspectorMemoryAgent.h"
46 #include "InspectorPageAgent.h"
47 #include "InspectorState.h"
48 #include "InstrumentingAgents.h"
49 #include "IntRect.h"
50 #include "RenderObject.h"
51 #include "RenderView.h"
52 #include "ResourceRequest.h"
53 #include "ResourceResponse.h"
54 #include "TimelineRecordFactory.h"
55
56 #include <wtf/CurrentTime.h>
57
58 namespace WebCore {
59
60 namespace TimelineAgentState {
61 static const char timelineAgentEnabled[] = "timelineAgentEnabled";
62 static const char timelineMaxCallStackDepth[] = "timelineMaxCallStackDepth";
63 static const char includeDomCounters[] = "includeDomCounters";
64 static const char includeNativeMemoryStatistics[] = "includeNativeMemoryStatistics";
65 }
66
67 // Must be kept in sync with WebInspector.TimelineModel.RecordType in TimelineModel.js
68 namespace TimelineRecordType {
69 static const char Program[] = "Program";
70
71 static const char EventDispatch[] = "EventDispatch";
72 static const char BeginFrame[] = "BeginFrame";
73 static const char ScheduleStyleRecalculation[] = "ScheduleStyleRecalculation";
74 static const char RecalculateStyles[] = "RecalculateStyles";
75 static const char InvalidateLayout[] = "InvalidateLayout";
76 static const char Layout[] = "Layout";
77 static const char Paint[] = "Paint";
78 static const char ScrollLayer[] = "ScrollLayer";
79 static const char ResizeImage[] = "ResizeImage";
80 static const char CompositeLayers[] = "CompositeLayers";
81
82 static const char ParseHTML[] = "ParseHTML";
83
84 static const char TimerInstall[] = "TimerInstall";
85 static const char TimerRemove[] = "TimerRemove";
86 static const char TimerFire[] = "TimerFire";
87
88 static const char EvaluateScript[] = "EvaluateScript";
89
90 static const char MarkLoad[] = "MarkLoad";
91 static const char MarkDOMContent[] = "MarkDOMContent";
92
93 static const char TimeStamp[] = "TimeStamp";
94 static const char Time[] = "Time";
95 static const char TimeEnd[] = "TimeEnd";
96
97 static const char ScheduleResourceRequest[] = "ScheduleResourceRequest";
98 static const char ResourceSendRequest[] = "ResourceSendRequest";
99 static const char ResourceReceiveResponse[] = "ResourceReceiveResponse";
100 static const char ResourceReceivedData[] = "ResourceReceivedData";
101 static const char ResourceFinish[] = "ResourceFinish";
102
103 static const char XHRReadyStateChange[] = "XHRReadyStateChange";
104 static const char XHRLoad[] = "XHRLoad";
105
106 static const char FunctionCall[] = "FunctionCall";
107 static const char GCEvent[] = "GCEvent";
108
109 static const char RequestAnimationFrame[] = "RequestAnimationFrame";
110 static const char CancelAnimationFrame[] = "CancelAnimationFrame";
111 static const char FireAnimationFrame[] = "FireAnimationFrame";
112
113 static const char WebSocketCreate[] = "WebSocketCreate";
114 static const char WebSocketSendHandshakeRequest[] = "WebSocketSendHandshakeRequest";
115 static const char WebSocketReceiveHandshakeResponse[] = "WebSocketReceiveHandshakeResponse";
116 static const char WebSocketDestroy[] = "WebSocketDestroy";
117
118 // Event names visible to other modules.
119 const char DecodeImage[] = "DecodeImage";
120 const char Rasterize[] = "Rasterize";
121 }
122
123 void TimelineTimeConverter::reset()
124 {
125     m_startOffset = monotonicallyIncreasingTime() - currentTime();
126 }
127
128 void InspectorTimelineAgent::pushGCEventRecords()
129 {
130     if (!m_gcEvents.size())
131         return;
132
133     GCEvents events = m_gcEvents;
134     m_gcEvents.clear();
135     for (GCEvents::iterator i = events.begin(); i != events.end(); ++i) {
136         RefPtr<InspectorObject> record = TimelineRecordFactory::createGenericRecord(m_timeConverter.fromMonotonicallyIncreasingTime(i->startTime), m_maxCallStackDepth);
137         record->setObject("data", TimelineRecordFactory::createGCEventData(i->collectedBytes));
138         record->setNumber("endTime", m_timeConverter.fromMonotonicallyIncreasingTime(i->endTime));
139         addRecordToTimeline(record.release(), TimelineRecordType::GCEvent);
140     }
141 }
142
143 void InspectorTimelineAgent::didGC(double startTime, double endTime, size_t collectedBytesCount)
144 {
145     m_gcEvents.append(GCEvent(startTime, endTime, collectedBytesCount));
146 }
147
148 InspectorTimelineAgent::~InspectorTimelineAgent()
149 {
150     clearFrontend();
151 }
152
153 void InspectorTimelineAgent::setFrontend(InspectorFrontend* frontend)
154 {
155     m_frontend = frontend->timeline();
156 }
157
158 void InspectorTimelineAgent::clearFrontend()
159 {
160     ErrorString error;
161     stop(&error);
162     m_frontend = 0;
163 }
164
165 void InspectorTimelineAgent::restore()
166 {
167     if (m_state->getBoolean(TimelineAgentState::timelineAgentEnabled)) {
168         m_maxCallStackDepth = m_state->getLong(TimelineAgentState::timelineMaxCallStackDepth);
169         ErrorString error;
170         bool includeDomCounters = m_state->getBoolean(TimelineAgentState::includeDomCounters);
171         bool includeNativeMemoryStatistics = m_state->getBoolean(TimelineAgentState::includeNativeMemoryStatistics);
172         start(&error, &m_maxCallStackDepth, &includeDomCounters, &includeNativeMemoryStatistics);
173     }
174 }
175
176 void InspectorTimelineAgent::start(ErrorString*, const int* maxCallStackDepth, const bool* includeDomCounters, const bool* includeNativeMemoryStatistics)
177 {
178     if (!m_frontend)
179         return;
180
181     if (maxCallStackDepth && *maxCallStackDepth > 0)
182         m_maxCallStackDepth = *maxCallStackDepth;
183     else
184         m_maxCallStackDepth = 5;
185     m_state->setLong(TimelineAgentState::timelineMaxCallStackDepth, m_maxCallStackDepth);
186     m_state->setBoolean(TimelineAgentState::includeDomCounters, includeDomCounters && *includeDomCounters);
187     m_state->setBoolean(TimelineAgentState::includeNativeMemoryStatistics, includeNativeMemoryStatistics && *includeNativeMemoryStatistics);
188     m_timeConverter.reset();
189
190     m_instrumentingAgents->setInspectorTimelineAgent(this);
191     ScriptGCEvent::addEventListener(this);
192     m_state->setBoolean(TimelineAgentState::timelineAgentEnabled, true);
193 }
194
195 void InspectorTimelineAgent::stop(ErrorString*)
196 {
197     if (!m_state->getBoolean(TimelineAgentState::timelineAgentEnabled))
198         return;
199
200     m_weakFactory.revokeAll();
201     m_instrumentingAgents->setInspectorTimelineAgent(0);
202     ScriptGCEvent::removeEventListener(this);
203
204     clearRecordStack();
205     m_gcEvents.clear();
206
207     m_state->setBoolean(TimelineAgentState::timelineAgentEnabled, false);
208 }
209
210 void InspectorTimelineAgent::canMonitorMainThread(ErrorString*, bool* result)
211 {
212     *result = m_client && m_client->canMonitorMainThread();
213 }
214
215 void InspectorTimelineAgent::supportsFrameInstrumentation(ErrorString*, bool* result)
216 {
217     *result = m_client && m_client->supportsFrameInstrumentation();
218 }
219
220 void InspectorTimelineAgent::didBeginFrame()
221 {
222     m_pendingFrameRecord = TimelineRecordFactory::createGenericRecord(timestamp(), 0);
223 }
224
225 void InspectorTimelineAgent::didCancelFrame()
226 {
227     m_pendingFrameRecord.clear();
228 }
229
230 void InspectorTimelineAgent::willCallFunction(const String& scriptName, int scriptLine, Frame* frame)
231 {
232     pushCurrentRecord(TimelineRecordFactory::createFunctionCallData(scriptName, scriptLine), TimelineRecordType::FunctionCall, true, frame);
233 }
234
235 void InspectorTimelineAgent::didCallFunction()
236 {
237     didCompleteCurrentRecord(TimelineRecordType::FunctionCall);
238 }
239
240 void InspectorTimelineAgent::willDispatchEvent(const Event& event, Frame* frame)
241 {
242     pushCurrentRecord(TimelineRecordFactory::createEventDispatchData(event), TimelineRecordType::EventDispatch, false, frame);
243 }
244
245 void InspectorTimelineAgent::didDispatchEvent()
246 {
247     didCompleteCurrentRecord(TimelineRecordType::EventDispatch);
248 }
249
250 void InspectorTimelineAgent::didInvalidateLayout(Frame* frame)
251 {
252     appendRecord(InspectorObject::create(), TimelineRecordType::InvalidateLayout, true, frame);
253 }
254
255 void InspectorTimelineAgent::willLayout(Frame* frame)
256 {
257     RenderObject* root = frame->view()->layoutRoot();
258     bool partialLayout = !!root;
259
260     if (!partialLayout)
261         root = frame->contentRenderer();
262
263     unsigned dirtyObjects = 0;
264     unsigned totalObjects = 0;
265     for (RenderObject* o = root; o; o = o->nextInPreOrder(root)) {
266         ++totalObjects;
267         if (o->needsLayout())
268             ++dirtyObjects;
269     }
270     pushCurrentRecord(TimelineRecordFactory::createLayoutData(dirtyObjects, totalObjects, partialLayout), TimelineRecordType::Layout, true, frame);
271 }
272
273 void InspectorTimelineAgent::didLayout(RenderObject* root)
274 {
275     if (m_recordStack.isEmpty())
276         return;
277     TimelineRecordEntry& entry = m_recordStack.last();
278     ASSERT(entry.type == TimelineRecordType::Layout);
279     Vector<FloatQuad> quads;
280     root->absoluteQuads(quads);
281     if (quads.size() >= 1)
282         TimelineRecordFactory::appendLayoutRoot(entry.data.get(), quads[0]);
283     else
284         ASSERT_NOT_REACHED();
285     didCompleteCurrentRecord(TimelineRecordType::Layout);
286 }
287
288 void InspectorTimelineAgent::didScheduleStyleRecalculation(Frame* frame)
289 {
290     appendRecord(InspectorObject::create(), TimelineRecordType::ScheduleStyleRecalculation, true, frame);
291 }
292
293 void InspectorTimelineAgent::willRecalculateStyle(Frame* frame)
294 {
295     pushCurrentRecord(InspectorObject::create(), TimelineRecordType::RecalculateStyles, true, frame);
296 }
297
298 void InspectorTimelineAgent::didRecalculateStyle()
299 {
300     didCompleteCurrentRecord(TimelineRecordType::RecalculateStyles);
301 }
302
303 void InspectorTimelineAgent::willPaint(Frame* frame)
304 {
305     pushCurrentRecord(InspectorObject::create(), TimelineRecordType::Paint, true, frame, true);
306 }
307
308 void InspectorTimelineAgent::didPaint(RenderObject* renderer, const LayoutRect& clipRect)
309 {
310     TimelineRecordEntry& entry = m_recordStack.last();
311     ASSERT(entry.type == TimelineRecordType::Paint);
312     FloatQuad quad;
313     localToPageQuad(*renderer, clipRect, &quad);
314     entry.data = TimelineRecordFactory::createPaintData(quad);
315     didCompleteCurrentRecord(TimelineRecordType::Paint);
316 }
317
318 void InspectorTimelineAgent::willScroll(Frame* frame)
319 {
320     pushCurrentRecord(InspectorObject::create(), TimelineRecordType::ScrollLayer, false, frame);
321 }
322
323 void InspectorTimelineAgent::didScroll()
324 {
325     didCompleteCurrentRecord(TimelineRecordType::ScrollLayer);
326 }
327
328 void InspectorTimelineAgent::willDecodeImage(const String& imageType)
329 {
330     pushCurrentRecord(TimelineRecordFactory::createDecodeImageData(imageType), TimelineRecordType::DecodeImage, true, 0);
331 }
332
333 void InspectorTimelineAgent::didDecodeImage()
334 {
335     didCompleteCurrentRecord(TimelineRecordType::DecodeImage);
336 }
337
338 void InspectorTimelineAgent::willResizeImage(bool shouldCache)
339 {
340     pushCurrentRecord(TimelineRecordFactory::createResizeImageData(shouldCache), TimelineRecordType::ResizeImage, true, 0);
341 }
342
343 void InspectorTimelineAgent::didResizeImage()
344 {
345     didCompleteCurrentRecord(TimelineRecordType::ResizeImage);
346 }
347
348 void InspectorTimelineAgent::willComposite()
349 {
350     pushCurrentRecord(InspectorObject::create(), TimelineRecordType::CompositeLayers, false, 0);
351 }
352
353 void InspectorTimelineAgent::didComposite()
354 {
355     didCompleteCurrentRecord(TimelineRecordType::CompositeLayers);
356 }
357
358 void InspectorTimelineAgent::willWriteHTML(unsigned startLine, Frame* frame)
359 {
360     pushCurrentRecord(TimelineRecordFactory::createParseHTMLData(startLine), TimelineRecordType::ParseHTML, true, frame);
361 }
362
363 void InspectorTimelineAgent::didWriteHTML(unsigned endLine)
364 {
365     if (!m_recordStack.isEmpty()) {
366         TimelineRecordEntry entry = m_recordStack.last();
367         entry.data->setNumber("endLine", endLine);
368         didCompleteCurrentRecord(TimelineRecordType::ParseHTML);
369     }
370 }
371
372 void InspectorTimelineAgent::didInstallTimer(int timerId, int timeout, bool singleShot, Frame* frame)
373 {
374     appendRecord(TimelineRecordFactory::createTimerInstallData(timerId, timeout, singleShot), TimelineRecordType::TimerInstall, true, frame);
375 }
376
377 void InspectorTimelineAgent::didRemoveTimer(int timerId, Frame* frame)
378 {
379     appendRecord(TimelineRecordFactory::createGenericTimerData(timerId), TimelineRecordType::TimerRemove, true, frame);
380 }
381
382 void InspectorTimelineAgent::willFireTimer(int timerId, Frame* frame)
383 {
384     pushCurrentRecord(TimelineRecordFactory::createGenericTimerData(timerId), TimelineRecordType::TimerFire, false, frame);
385 }
386
387 void InspectorTimelineAgent::didFireTimer()
388 {
389     didCompleteCurrentRecord(TimelineRecordType::TimerFire);
390 }
391
392 void InspectorTimelineAgent::willDispatchXHRReadyStateChangeEvent(const String& url, int readyState, Frame* frame)
393 {
394     pushCurrentRecord(TimelineRecordFactory::createXHRReadyStateChangeData(url, readyState), TimelineRecordType::XHRReadyStateChange, false, frame);
395 }
396
397 void InspectorTimelineAgent::didDispatchXHRReadyStateChangeEvent()
398 {
399     didCompleteCurrentRecord(TimelineRecordType::XHRReadyStateChange);
400 }
401
402 void InspectorTimelineAgent::willDispatchXHRLoadEvent(const String& url, Frame* frame)
403 {
404     pushCurrentRecord(TimelineRecordFactory::createXHRLoadData(url), TimelineRecordType::XHRLoad, true, frame);
405 }
406
407 void InspectorTimelineAgent::didDispatchXHRLoadEvent()
408 {
409     didCompleteCurrentRecord(TimelineRecordType::XHRLoad);
410 }
411
412 void InspectorTimelineAgent::willEvaluateScript(const String& url, int lineNumber, Frame* frame)
413 {
414     pushCurrentRecord(TimelineRecordFactory::createEvaluateScriptData(url, lineNumber), TimelineRecordType::EvaluateScript, true, frame);
415 }
416
417 void InspectorTimelineAgent::didEvaluateScript()
418 {
419     didCompleteCurrentRecord(TimelineRecordType::EvaluateScript);
420 }
421
422 void InspectorTimelineAgent::didScheduleResourceRequest(const String& url, Frame* frame)
423 {
424     appendRecord(TimelineRecordFactory::createScheduleResourceRequestData(url), TimelineRecordType::ScheduleResourceRequest, true, frame);
425 }
426
427 void InspectorTimelineAgent::willSendResourceRequest(unsigned long identifier, const ResourceRequest& request, Frame* frame)
428 {
429     String requestId = IdentifiersFactory::requestId(identifier);
430     appendRecord(TimelineRecordFactory::createResourceSendRequestData(requestId, request), TimelineRecordType::ResourceSendRequest, true, frame);
431 }
432
433 void InspectorTimelineAgent::willReceiveResourceData(unsigned long identifier, Frame* frame, int length)
434 {
435     String requestId = IdentifiersFactory::requestId(identifier);
436     pushCurrentRecord(TimelineRecordFactory::createReceiveResourceData(requestId, length), TimelineRecordType::ResourceReceivedData, false, frame);
437 }
438
439 void InspectorTimelineAgent::didReceiveResourceData()
440 {
441     didCompleteCurrentRecord(TimelineRecordType::ResourceReceivedData);
442 }
443
444 void InspectorTimelineAgent::willReceiveResourceResponse(unsigned long identifier, const ResourceResponse& response, Frame* frame)
445 {
446     String requestId = IdentifiersFactory::requestId(identifier);
447     pushCurrentRecord(TimelineRecordFactory::createResourceReceiveResponseData(requestId, response), TimelineRecordType::ResourceReceiveResponse, false, frame);
448 }
449
450 void InspectorTimelineAgent::didReceiveResourceResponse()
451 {
452     didCompleteCurrentRecord(TimelineRecordType::ResourceReceiveResponse);
453 }
454
455 void InspectorTimelineAgent::didFinishLoadingResource(unsigned long identifier, bool didFail, double finishTime, Frame* frame)
456 {
457     appendRecord(TimelineRecordFactory::createResourceFinishData(IdentifiersFactory::requestId(identifier), didFail, finishTime * 1000), TimelineRecordType::ResourceFinish, false, frame);
458 }
459
460 void InspectorTimelineAgent::didTimeStamp(Frame* frame, const String& message)
461 {
462     appendRecord(TimelineRecordFactory::createTimeStampData(message), TimelineRecordType::TimeStamp, true, frame);
463 }
464
465 void InspectorTimelineAgent::time(Frame* frame, const String& message)
466 {
467     appendRecord(TimelineRecordFactory::createTimeStampData(message), TimelineRecordType::Time, true, frame);
468 }
469
470 void InspectorTimelineAgent::timeEnd(Frame* frame, const String& message)
471 {
472     appendRecord(TimelineRecordFactory::createTimeStampData(message), TimelineRecordType::TimeEnd, true, frame);
473 }
474
475 void InspectorTimelineAgent::didMarkDOMContentEvent(Frame* frame)
476 {
477     bool isMainFrame = frame && m_pageAgent && (frame == m_pageAgent->mainFrame());
478     appendRecord(TimelineRecordFactory::createMarkData(isMainFrame), TimelineRecordType::MarkDOMContent, false, frame);
479 }
480
481 void InspectorTimelineAgent::didMarkLoadEvent(Frame* frame)
482 {
483     bool isMainFrame = frame && m_pageAgent && (frame == m_pageAgent->mainFrame());
484     appendRecord(TimelineRecordFactory::createMarkData(isMainFrame), TimelineRecordType::MarkLoad, false, frame);
485 }
486
487 void InspectorTimelineAgent::didCommitLoad()
488 {
489     clearRecordStack();
490 }
491
492 void InspectorTimelineAgent::didRequestAnimationFrame(int callbackId, Frame* frame)
493 {
494     appendRecord(TimelineRecordFactory::createAnimationFrameData(callbackId), TimelineRecordType::RequestAnimationFrame, true, frame);
495 }
496
497 void InspectorTimelineAgent::didCancelAnimationFrame(int callbackId, Frame* frame)
498 {
499     appendRecord(TimelineRecordFactory::createAnimationFrameData(callbackId), TimelineRecordType::CancelAnimationFrame, true, frame);
500 }
501
502 void InspectorTimelineAgent::willFireAnimationFrame(int callbackId, Frame* frame)
503 {
504     pushCurrentRecord(TimelineRecordFactory::createAnimationFrameData(callbackId), TimelineRecordType::FireAnimationFrame, false, frame);
505 }
506
507 void InspectorTimelineAgent::didFireAnimationFrame()
508 {
509     didCompleteCurrentRecord(TimelineRecordType::FireAnimationFrame);
510 }
511
512 void InspectorTimelineAgent::willProcessTask()
513 {
514     pushCurrentRecord(InspectorObject::create(), TimelineRecordType::Program, false, 0);
515 }
516
517 void InspectorTimelineAgent::didProcessTask()
518 {
519     didCompleteCurrentRecord(TimelineRecordType::Program);
520 }
521
522 #if ENABLE(WEB_SOCKETS)
523 void InspectorTimelineAgent::didCreateWebSocket(unsigned long identifier, const KURL& url, const String& protocol, Frame* frame)
524 {
525     appendRecord(TimelineRecordFactory::createWebSocketCreateData(identifier, url, protocol), TimelineRecordType::WebSocketCreate, true, frame);
526 }
527
528 void InspectorTimelineAgent::willSendWebSocketHandshakeRequest(unsigned long identifier, Frame* frame)
529 {
530     appendRecord(TimelineRecordFactory::createGenericWebSocketData(identifier), TimelineRecordType::WebSocketSendHandshakeRequest, true, frame);
531 }
532
533 void InspectorTimelineAgent::didReceiveWebSocketHandshakeResponse(unsigned long identifier, Frame* frame)
534 {
535     appendRecord(TimelineRecordFactory::createGenericWebSocketData(identifier), TimelineRecordType::WebSocketReceiveHandshakeResponse, false, frame);
536 }
537
538 void InspectorTimelineAgent::didDestroyWebSocket(unsigned long identifier, Frame* frame)
539 {
540     appendRecord(TimelineRecordFactory::createGenericWebSocketData(identifier), TimelineRecordType::WebSocketDestroy, true, frame);
541 }
542 #endif // ENABLE(WEB_SOCKETS)
543
544 void InspectorTimelineAgent::addRecordToTimeline(PassRefPtr<InspectorObject> record, const String& type)
545 {
546     commitFrameRecord();
547     innerAddRecordToTimeline(record, type);
548 }
549
550 void InspectorTimelineAgent::innerAddRecordToTimeline(PassRefPtr<InspectorObject> prpRecord, const String& type)
551 {
552     prpRecord->setString("type", type);
553     RefPtr<TypeBuilder::Timeline::TimelineEvent> record = TypeBuilder::Timeline::TimelineEvent::runtimeCast(prpRecord);
554     if (type == TimelineRecordType::Program)
555         setNativeHeapStatistics(record.get());
556     else
557         setDOMCounters(record.get());
558
559     if (m_recordStack.isEmpty())
560         sendEvent(record.release());
561     else {
562         TimelineRecordEntry parent = m_recordStack.last();
563         parent.children->pushObject(record.release());
564     }
565 }
566
567 static size_t getUsedHeapSize()
568 {
569     HeapInfo info;
570     ScriptGCEvent::getHeapSize(info);
571     return info.usedJSHeapSize;
572 }
573
574 void InspectorTimelineAgent::setDOMCounters(TypeBuilder::Timeline::TimelineEvent* record)
575 {
576     record->setUsedHeapSize(getUsedHeapSize());
577
578     if (m_state->getBoolean(TimelineAgentState::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         int listenerCount = ThreadLocalInspectorCounters::current().counterValue(ThreadLocalInspectorCounters::JSEventListenerCounter);
586         RefPtr<TypeBuilder::Timeline::DOMCounters> counters = TypeBuilder::Timeline::DOMCounters::create()
587             .setDocuments(documentCount)
588             .setNodes(nodeCount)
589             .setJsEventListeners(listenerCount);
590         record->setCounters(counters.release());
591     }
592 }
593
594 // FIXME: This entire function can probably be removed, since it's a no-op.
595 void InspectorTimelineAgent::setNativeHeapStatistics(TypeBuilder::Timeline::TimelineEvent* record)
596 {
597     if (!m_memoryAgent)
598         return;
599     if (!m_state->getBoolean(TimelineAgentState::includeNativeMemoryStatistics))
600         return;
601     RefPtr<InspectorObject> stats = InspectorObject::create();
602     stats->setNumber("PrivateBytes", 0);
603     record->setNativeHeapStatistics(stats.release());
604 }
605
606 void InspectorTimelineAgent::setFrameIdentifier(InspectorObject* record, Frame* frame)
607 {
608     if (!frame || !m_pageAgent)
609         return;
610     String frameId;
611     if (frame && m_pageAgent)
612         frameId = m_pageAgent->frameId(frame);
613     record->setString("frameId", frameId);
614 }
615
616 void InspectorTimelineAgent::didCompleteCurrentRecord(const String& type)
617 {
618     // An empty stack could merely mean that the timeline agent was turned on in the middle of
619     // an event.  Don't treat as an error.
620     if (!m_recordStack.isEmpty()) {
621         if (m_platformInstrumentationClientInstalledAtStackDepth == m_recordStack.size()) {
622             m_platformInstrumentationClientInstalledAtStackDepth = 0;
623             PlatformInstrumentation::setClient(0);
624         }
625
626         pushGCEventRecords();
627         TimelineRecordEntry entry = m_recordStack.last();
628         m_recordStack.removeLast();
629         ASSERT(entry.type == type);
630         entry.record->setObject("data", entry.data);
631         entry.record->setArray("children", entry.children);
632         entry.record->setNumber("endTime", timestamp());
633         size_t usedHeapSizeDelta = getUsedHeapSize() - entry.usedHeapSizeAtStart;
634         if (usedHeapSizeDelta)
635             entry.record->setNumber("usedHeapSizeDelta", usedHeapSizeDelta);
636         addRecordToTimeline(entry.record, type);
637     }
638 }
639
640 InspectorTimelineAgent::InspectorTimelineAgent(InstrumentingAgents* instrumentingAgents, InspectorPageAgent* pageAgent, InspectorMemoryAgent* memoryAgent, InspectorCompositeState* state, InspectorType type, InspectorClient* client)
641     : InspectorBaseAgent<InspectorTimelineAgent>("Timeline", instrumentingAgents, state)
642     , m_pageAgent(pageAgent)
643     , m_memoryAgent(memoryAgent)
644     , m_frontend(0)
645     , m_id(1)
646     , m_maxCallStackDepth(5)
647     , m_platformInstrumentationClientInstalledAtStackDepth(0)
648     , m_inspectorType(type)
649     , m_client(client)
650     , m_weakFactory(this)
651 {
652 }
653
654 void InspectorTimelineAgent::appendRecord(PassRefPtr<InspectorObject> data, const String& type, bool captureCallStack, Frame* frame)
655 {
656     pushGCEventRecords();
657     RefPtr<InspectorObject> record = TimelineRecordFactory::createGenericRecord(timestamp(), captureCallStack ? m_maxCallStackDepth : 0);
658     record->setObject("data", data);
659     setFrameIdentifier(record.get(), frame);
660     addRecordToTimeline(record.release(), type);
661 }
662
663 void InspectorTimelineAgent::sendEvent(PassRefPtr<InspectorObject> event)
664 {
665     // FIXME: runtimeCast is a hack. We do it because we can't build TimelineEvent directly now.
666     RefPtr<TypeBuilder::Timeline::TimelineEvent> recordChecked = TypeBuilder::Timeline::TimelineEvent::runtimeCast(event);
667     m_frontend->eventRecorded(recordChecked.release());
668 }
669
670 void InspectorTimelineAgent::pushCurrentRecord(PassRefPtr<InspectorObject> data, const String& type, bool captureCallStack, Frame* frame, bool hasLowLevelDetails)
671 {
672     pushGCEventRecords();
673     commitFrameRecord();
674     RefPtr<InspectorObject> record = TimelineRecordFactory::createGenericRecord(timestamp(), captureCallStack ? m_maxCallStackDepth : 0);
675     setFrameIdentifier(record.get(), frame);
676     m_recordStack.append(TimelineRecordEntry(record.release(), data, InspectorArray::create(), type, getUsedHeapSize()));
677     if (hasLowLevelDetails && !m_platformInstrumentationClientInstalledAtStackDepth && !PlatformInstrumentation::hasClient()) {
678         m_platformInstrumentationClientInstalledAtStackDepth = m_recordStack.size();
679         PlatformInstrumentation::setClient(this);
680     }
681 }
682
683 void InspectorTimelineAgent::commitFrameRecord()
684 {
685     if (!m_pendingFrameRecord)
686         return;
687     
688     m_pendingFrameRecord->setObject("data", InspectorObject::create());
689     innerAddRecordToTimeline(m_pendingFrameRecord.release(), TimelineRecordType::BeginFrame);
690 }
691
692 void InspectorTimelineAgent::clearRecordStack()
693 {
694     if (m_platformInstrumentationClientInstalledAtStackDepth) {
695         m_platformInstrumentationClientInstalledAtStackDepth = 0;
696         PlatformInstrumentation::setClient(0);
697     }
698     m_pendingFrameRecord.clear();
699     m_recordStack.clear();
700     m_id++;
701 }
702
703 void InspectorTimelineAgent::localToPageQuad(const RenderObject& renderer, const LayoutRect& rect, FloatQuad* quad)
704 {
705     const FrameView& frameView = renderer.view().frameView();
706     FloatQuad absolute = renderer.localToAbsoluteQuad(FloatQuad(rect));
707     quad->setP1(frameView.contentsToRootView(roundedIntPoint(absolute.p1())));
708     quad->setP2(frameView.contentsToRootView(roundedIntPoint(absolute.p2())));
709     quad->setP3(frameView.contentsToRootView(roundedIntPoint(absolute.p3())));
710     quad->setP4(frameView.contentsToRootView(roundedIntPoint(absolute.p4())));
711 }
712
713 double InspectorTimelineAgent::timestamp()
714 {
715     return m_timeConverter.fromMonotonicallyIncreasingTime(monotonicallyIncreasingTime());
716 }
717
718 Page* InspectorTimelineAgent::page()
719 {
720     return m_pageAgent ? m_pageAgent->page() : 0;
721 }
722
723 } // namespace WebCore
724
725 #endif // ENABLE(INSPECTOR)