1/*
2* Copyright (C) 2009 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#include "InspectorTimelineAgent.h"
33
34#if ENABLE(INSPECTOR)
35
36#include "Event.h"
37#include "InspectorFrontend.h"
38#include "IntRect.h"
39#include "ResourceRequest.h"
40#include "ResourceResponse.h"
41#include "TimelineRecordFactory.h"
42
43#include <wtf/CurrentTime.h>
44
45namespace WebCore {
46
47InspectorTimelineAgent::InspectorTimelineAgent(InspectorFrontend* frontend)
48    : m_frontend(frontend)
49{
50    ASSERT(m_frontend);
51}
52
53InspectorTimelineAgent::~InspectorTimelineAgent()
54{
55}
56
57void InspectorTimelineAgent::willDispatchEvent(const Event& event)
58{
59    pushCurrentRecord(TimelineRecordFactory::createEventDispatchData(m_frontend, event),
60        EventDispatchTimelineRecordType);
61}
62
63void InspectorTimelineAgent::didDispatchEvent()
64{
65    didCompleteCurrentRecord(EventDispatchTimelineRecordType);
66}
67
68void InspectorTimelineAgent::willLayout()
69{
70    pushCurrentRecord(m_frontend->newScriptObject(), LayoutTimelineRecordType);
71}
72
73void InspectorTimelineAgent::didLayout()
74{
75    didCompleteCurrentRecord(LayoutTimelineRecordType);
76}
77
78void InspectorTimelineAgent::willRecalculateStyle()
79{
80    pushCurrentRecord(m_frontend->newScriptObject(), RecalculateStylesTimelineRecordType);
81}
82
83void InspectorTimelineAgent::didRecalculateStyle()
84{
85    didCompleteCurrentRecord(RecalculateStylesTimelineRecordType);
86}
87
88void InspectorTimelineAgent::willPaint(const IntRect& rect)
89{
90    pushCurrentRecord(TimelineRecordFactory::createPaintData(m_frontend, rect), PaintTimelineRecordType);
91}
92
93void InspectorTimelineAgent::didPaint()
94{
95    didCompleteCurrentRecord(PaintTimelineRecordType);
96}
97
98void InspectorTimelineAgent::willWriteHTML(unsigned int length, unsigned int startLine)
99{
100    pushCurrentRecord(TimelineRecordFactory::createParseHTMLData(m_frontend, length, startLine), ParseHTMLTimelineRecordType);
101}
102
103void InspectorTimelineAgent::didWriteHTML(unsigned int endLine)
104{
105    if (!m_recordStack.isEmpty()) {
106        TimelineRecordEntry entry = m_recordStack.last();
107        entry.data.set("endLine", endLine);
108        didCompleteCurrentRecord(ParseHTMLTimelineRecordType);
109    }
110}
111
112void InspectorTimelineAgent::didInstallTimer(int timerId, int timeout, bool singleShot)
113{
114    ScriptObject record = TimelineRecordFactory::createGenericRecord(m_frontend, currentTimeInMilliseconds());
115    record.set("data", TimelineRecordFactory::createTimerInstallData(m_frontend, timerId, timeout, singleShot));
116    addRecordToTimeline(record, TimerInstallTimelineRecordType);
117}
118
119void InspectorTimelineAgent::didRemoveTimer(int timerId)
120{
121    ScriptObject record = TimelineRecordFactory::createGenericRecord(m_frontend, currentTimeInMilliseconds());
122    record.set("data", TimelineRecordFactory::createGenericTimerData(m_frontend, timerId));
123    addRecordToTimeline(record, TimerRemoveTimelineRecordType);
124}
125
126void InspectorTimelineAgent::willFireTimer(int timerId)
127{
128    pushCurrentRecord(TimelineRecordFactory::createGenericTimerData(m_frontend, timerId), TimerFireTimelineRecordType);
129}
130
131void InspectorTimelineAgent::didFireTimer()
132{
133    didCompleteCurrentRecord(TimerFireTimelineRecordType);
134}
135
136void InspectorTimelineAgent::willChangeXHRReadyState(const String& url, int readyState)
137{
138    pushCurrentRecord(TimelineRecordFactory::createXHRReadyStateChangeData(m_frontend, url, readyState), XHRReadyStateChangeRecordType);
139}
140
141void InspectorTimelineAgent::didChangeXHRReadyState()
142{
143    didCompleteCurrentRecord(XHRReadyStateChangeRecordType);
144}
145
146void InspectorTimelineAgent::willLoadXHR(const String& url)
147{
148    pushCurrentRecord(TimelineRecordFactory::createXHRLoadData(m_frontend, url), XHRLoadRecordType);
149}
150
151void InspectorTimelineAgent::didLoadXHR()
152{
153    didCompleteCurrentRecord(XHRLoadRecordType);
154}
155
156void InspectorTimelineAgent::willEvaluateScript(const String& url, int lineNumber)
157{
158    pushCurrentRecord(TimelineRecordFactory::createEvaluateScriptData(m_frontend, url, lineNumber), EvaluateScriptTimelineRecordType);
159}
160
161void InspectorTimelineAgent::didEvaluateScript()
162{
163    didCompleteCurrentRecord(EvaluateScriptTimelineRecordType);
164}
165
166void InspectorTimelineAgent::willSendResourceRequest(unsigned long identifier, bool isMainResource,
167    const ResourceRequest& request)
168{
169    ScriptObject record = TimelineRecordFactory::createGenericRecord(m_frontend, currentTimeInMilliseconds());
170    record.set("data", TimelineRecordFactory::createResourceSendRequestData(m_frontend, identifier, isMainResource, request));
171    record.set("type", ResourceSendRequestTimelineRecordType);
172    m_frontend->addRecordToTimeline(record);
173}
174
175void InspectorTimelineAgent::didReceiveResourceResponse(unsigned long identifier, const ResourceResponse& response)
176{
177    ScriptObject record = TimelineRecordFactory::createGenericRecord(m_frontend, currentTimeInMilliseconds());
178    record.set("data", TimelineRecordFactory::createResourceReceiveResponseData(m_frontend, identifier, response));
179    record.set("type", ResourceReceiveResponseTimelineRecordType);
180    m_frontend->addRecordToTimeline(record);
181}
182
183void InspectorTimelineAgent::didFinishLoadingResource(unsigned long identifier, bool didFail)
184{
185    ScriptObject record = TimelineRecordFactory::createGenericRecord(m_frontend, currentTimeInMilliseconds());
186    record.set("data", TimelineRecordFactory::createResourceFinishData(m_frontend, identifier, didFail));
187    record.set("type", ResourceFinishTimelineRecordType);
188    m_frontend->addRecordToTimeline(record);
189}
190
191void InspectorTimelineAgent::didMarkTimeline(const String& message)
192{
193    ScriptObject record = TimelineRecordFactory::createGenericRecord(m_frontend, currentTimeInMilliseconds());
194    record.set("data", TimelineRecordFactory::createMarkTimelineData(m_frontend, message));
195    addRecordToTimeline(record, MarkTimelineRecordType);
196}
197
198void InspectorTimelineAgent::reset()
199{
200    m_recordStack.clear();
201}
202
203void InspectorTimelineAgent::resetFrontendProxyObject(InspectorFrontend* frontend)
204{
205    ASSERT(frontend);
206    reset();
207    m_frontend = frontend;
208}
209
210void InspectorTimelineAgent::addRecordToTimeline(ScriptObject record, TimelineRecordType type)
211{
212    record.set("type", type);
213    if (m_recordStack.isEmpty())
214        m_frontend->addRecordToTimeline(record);
215    else {
216        TimelineRecordEntry parent = m_recordStack.last();
217        parent.children.set(parent.children.length(), record);
218    }
219}
220
221void InspectorTimelineAgent::didCompleteCurrentRecord(TimelineRecordType type)
222{
223    // An empty stack could merely mean that the timeline agent was turned on in the middle of
224    // an event.  Don't treat as an error.
225    if (!m_recordStack.isEmpty()) {
226        TimelineRecordEntry entry = m_recordStack.last();
227        m_recordStack.removeLast();
228        ASSERT(entry.type == type);
229        entry.record.set("data", entry.data);
230        entry.record.set("children", entry.children);
231        entry.record.set("endTime", currentTimeInMilliseconds());
232        addRecordToTimeline(entry.record, type);
233    }
234}
235
236double InspectorTimelineAgent::currentTimeInMilliseconds()
237{
238    return currentTime() * 1000.0;
239}
240
241void InspectorTimelineAgent::pushCurrentRecord(ScriptObject data, TimelineRecordType type)
242{
243    m_recordStack.append(TimelineRecordEntry(TimelineRecordFactory::createGenericRecord(m_frontend, currentTimeInMilliseconds()), data, m_frontend->newScriptArray(), type));
244}
245
246} // namespace WebCore
247
248#endif // ENABLE(INSPECTOR)
249