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