1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "config.h"
6#include "core/inspector/InspectorTraceEvents.h"
7
8#include "bindings/v8/ScriptCallStackFactory.h"
9#include "bindings/v8/ScriptGCEvent.h"
10#include "bindings/v8/ScriptSourceCode.h"
11#include "core/frame/FrameView.h"
12#include "core/frame/LocalFrame.h"
13#include "core/inspector/IdentifiersFactory.h"
14#include "core/inspector/InspectorNodeIds.h"
15#include "core/inspector/ScriptCallStack.h"
16#include "core/page/Page.h"
17#include "core/rendering/RenderImage.h"
18#include "core/rendering/RenderObject.h"
19#include "core/xml/XMLHttpRequest.h"
20#include "platform/JSONValues.h"
21#include "platform/TracedValue.h"
22#include "platform/graphics/GraphicsLayer.h"
23#include "platform/network/ResourceRequest.h"
24#include "platform/network/ResourceResponse.h"
25#include "platform/weborigin/KURL.h"
26#include "wtf/Vector.h"
27#include <inttypes.h>
28
29namespace WebCore {
30
31namespace {
32
33class JSCallStack : public TraceEvent::ConvertableToTraceFormat  {
34public:
35    explicit JSCallStack(PassRefPtrWillBeRawPtr<ScriptCallStack> callstack) : m_callstack(callstack) { }
36    virtual String asTraceFormat() const
37    {
38        if (!m_callstack)
39            return "null";
40        return m_callstack->buildInspectorArray()->toJSONString();
41    }
42
43private:
44    RefPtrWillBePersistent<ScriptCallStack> m_callstack;
45};
46
47String toHexString(void* p)
48{
49    return String::format("0x%" PRIx64, static_cast<uint64>(reinterpret_cast<intptr_t>(p)));
50}
51
52}
53
54PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorLayoutEvent::beginData(FrameView* frameView)
55{
56    bool isPartial;
57    unsigned needsLayoutObjects;
58    unsigned totalObjects;
59    LocalFrame& frame = frameView->frame();
60    frame.countObjectsNeedingLayout(needsLayoutObjects, totalObjects, isPartial);
61
62    RefPtr<JSONObject> data = JSONObject::create();
63    data->setNumber("dirtyObjects", needsLayoutObjects);
64    data->setNumber("totalObjects", totalObjects);
65    data->setBoolean("partialLayout", isPartial);
66    data->setString("frame", toHexString(&frame));
67    return TracedValue::fromJSONValue(data);
68}
69
70static PassRefPtr<JSONArray> createQuad(const FloatQuad& quad)
71{
72    RefPtr<JSONArray> array = JSONArray::create();
73    array->pushNumber(quad.p1().x());
74    array->pushNumber(quad.p1().y());
75    array->pushNumber(quad.p2().x());
76    array->pushNumber(quad.p2().y());
77    array->pushNumber(quad.p3().x());
78    array->pushNumber(quad.p3().y());
79    array->pushNumber(quad.p4().x());
80    array->pushNumber(quad.p4().y());
81    return array.release();
82}
83
84PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorLayoutEvent::endData(RenderObject* rootForThisLayout)
85{
86    Vector<FloatQuad> quads;
87    rootForThisLayout->absoluteQuads(quads);
88
89    RefPtr<JSONObject> data = JSONObject::create();
90    if (quads.size() >= 1) {
91        data->setArray("root", createQuad(quads[0]));
92        int rootNodeId = InspectorNodeIds::idForNode(rootForThisLayout->generatingNode());
93        data->setNumber("rootNode", rootNodeId);
94    } else {
95        ASSERT_NOT_REACHED();
96    }
97    return TracedValue::fromJSONValue(data);
98}
99
100PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorSendRequestEvent::data(unsigned long identifier, LocalFrame* frame, const ResourceRequest& request)
101{
102    String requestId = IdentifiersFactory::requestId(identifier);
103
104    RefPtr<JSONObject> data = JSONObject::create();
105    data->setString("requestId", requestId);
106    data->setString("frame", toHexString(frame));
107    data->setString("url", request.url().string());
108    data->setString("requestMethod", request.httpMethod());
109    return TracedValue::fromJSONValue(data);
110}
111
112PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorReceiveResponseEvent::data(unsigned long identifier, LocalFrame* frame, const ResourceResponse& response)
113{
114    String requestId = IdentifiersFactory::requestId(identifier);
115
116    RefPtr<JSONObject> data = JSONObject::create();
117    data->setString("requestId", requestId);
118    data->setString("frame", toHexString(frame));
119    data->setNumber("statusCode", response.httpStatusCode());
120    data->setString("mimeType", response.mimeType().string().isolatedCopy());
121    return TracedValue::fromJSONValue(data);
122}
123
124PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorReceiveDataEvent::data(unsigned long identifier, LocalFrame* frame, int encodedDataLength)
125{
126    String requestId = IdentifiersFactory::requestId(identifier);
127
128    RefPtr<JSONObject> data = JSONObject::create();
129    data->setString("requestId", requestId);
130    data->setString("frame", toHexString(frame));
131    data->setNumber("encodedDataLength", encodedDataLength);
132    return TracedValue::fromJSONValue(data);
133}
134
135PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorResourceFinishEvent::data(unsigned long identifier, double finishTime, bool didFail)
136{
137    String requestId = IdentifiersFactory::requestId(identifier);
138
139    RefPtr<JSONObject> data = JSONObject::create();
140    data->setString("requestId", requestId);
141    data->setBoolean("didFail", didFail);
142    if (finishTime)
143        data->setNumber("networkTime", finishTime);
144    return TracedValue::fromJSONValue(data);
145}
146
147static LocalFrame* frameForExecutionContext(ExecutionContext* context)
148{
149    LocalFrame* frame = 0;
150    if (context->isDocument())
151        frame = toDocument(context)->frame();
152    return frame;
153}
154
155static PassRefPtr<JSONObject> genericTimerData(ExecutionContext* context, int timerId)
156{
157    RefPtr<JSONObject> data = JSONObject::create();
158    data->setNumber("timerId", timerId);
159    if (LocalFrame* frame = frameForExecutionContext(context))
160        data->setString("frame", toHexString(frame));
161    return data.release();
162}
163
164PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorTimerInstallEvent::data(ExecutionContext* context, int timerId, int timeout, bool singleShot)
165{
166    RefPtr<JSONObject> data = genericTimerData(context, timerId);
167    data->setNumber("timeout", timeout);
168    data->setBoolean("singleShot", singleShot);
169    return TracedValue::fromJSONValue(data);
170}
171
172PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorTimerRemoveEvent::data(ExecutionContext* context, int timerId)
173{
174    return TracedValue::fromJSONValue(genericTimerData(context, timerId));
175}
176
177PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorTimerFireEvent::data(ExecutionContext* context, int timerId)
178{
179    return TracedValue::fromJSONValue(genericTimerData(context, timerId));
180}
181
182PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorAnimationFrameEvent::data(Document* document, int callbackId)
183{
184    RefPtr<JSONObject> data = JSONObject::create();
185    data->setNumber("id", callbackId);
186    data->setString("frame", toHexString(document->frame()));
187    return TracedValue::fromJSONValue(data);
188}
189
190PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorWebSocketCreateEvent::data(Document* document, unsigned long identifier, const KURL& url, const String& protocol)
191{
192    RefPtr<JSONObject> data = JSONObject::create();
193    data->setNumber("identifier", identifier);
194    data->setString("url", url.string());
195    data->setString("frame", toHexString(document->frame()));
196    if (!protocol.isNull())
197        data->setString("webSocketProtocol", protocol);
198    return TracedValue::fromJSONValue(data);
199}
200
201PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorWebSocketEvent::data(Document* document, unsigned long identifier)
202{
203    RefPtr<JSONObject> data = JSONObject::create();
204    data->setNumber("identifier", identifier);
205    data->setString("frame", toHexString(document->frame()));
206    return TracedValue::fromJSONValue(data);
207}
208
209PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorParseHtmlEvent::beginData(Document* document, unsigned startLine)
210{
211    RefPtr<JSONObject> data = JSONObject::create();
212    data->setNumber("startLine", startLine);
213    data->setString("frame", toHexString(document->frame()));
214    return TracedValue::fromJSONValue(data);
215}
216
217PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorXhrReadyStateChangeEvent::data(ExecutionContext* context, XMLHttpRequest* request)
218{
219    RefPtr<JSONObject> data = JSONObject::create();
220    data->setString("url", request->url().string());
221    data->setNumber("readyState", request->readyState());
222    if (LocalFrame* frame = frameForExecutionContext(context))
223        data->setString("frame", toHexString(frame));
224    return TracedValue::fromJSONValue(data);
225}
226
227PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorXhrLoadEvent::data(ExecutionContext* context, XMLHttpRequest* request)
228{
229    RefPtr<JSONObject> data = JSONObject::create();
230    data->setString("url", request->url().string());
231    if (LocalFrame* frame = frameForExecutionContext(context))
232        data->setString("frame", toHexString(frame));
233    return TracedValue::fromJSONValue(data);
234}
235
236static void localToPageQuad(const RenderObject& renderer, const LayoutRect& rect, FloatQuad* quad)
237{
238    LocalFrame* frame = renderer.frame();
239    FrameView* view = frame->view();
240    FloatQuad absolute = renderer.localToAbsoluteQuad(FloatQuad(rect));
241    quad->setP1(view->contentsToRootView(roundedIntPoint(absolute.p1())));
242    quad->setP2(view->contentsToRootView(roundedIntPoint(absolute.p2())));
243    quad->setP3(view->contentsToRootView(roundedIntPoint(absolute.p3())));
244    quad->setP4(view->contentsToRootView(roundedIntPoint(absolute.p4())));
245}
246
247PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorPaintEvent::data(RenderObject* renderer, const LayoutRect& clipRect, const GraphicsLayer* graphicsLayer)
248{
249    RefPtr<JSONObject> data = JSONObject::create();
250    data->setString("frame", toHexString(renderer->frame()));
251    FloatQuad quad;
252    localToPageQuad(*renderer, clipRect, &quad);
253    data->setArray("clip", createQuad(quad));
254    int nodeId = InspectorNodeIds::idForNode(renderer->generatingNode());
255    data->setNumber("nodeId", nodeId);
256    int graphicsLayerId = graphicsLayer ? graphicsLayer->platformLayer()->id() : 0;
257    data->setNumber("layerId", graphicsLayerId);
258    return TracedValue::fromJSONValue(data);
259}
260
261PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorMarkLoadEvent::data(LocalFrame* frame)
262{
263    RefPtr<JSONObject> data = JSONObject::create();
264    data->setString("frame", toHexString(frame));
265    bool isMainFrame = frame && frame->page()->mainFrame() == frame;
266    data->setBoolean("isMainFrame", isMainFrame);
267    return TracedValue::fromJSONValue(data);
268}
269
270PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorScrollLayerEvent::data(RenderObject* renderer)
271{
272    RefPtr<JSONObject> data = JSONObject::create();
273    data->setString("frame", toHexString(renderer->frame()));
274    int nodeId = InspectorNodeIds::idForNode(renderer->generatingNode());
275    data->setNumber("nodeId", nodeId);
276    return TracedValue::fromJSONValue(data);
277}
278
279PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorEvaluateScriptEvent::data(LocalFrame* frame, const String& url, int lineNumber)
280{
281    RefPtr<JSONObject> data = JSONObject::create();
282    data->setString("frame", toHexString(frame));
283    data->setString("url", url);
284    data->setNumber("lineNumber", lineNumber);
285    return TracedValue::fromJSONValue(data);
286}
287
288PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorFunctionCallEvent::data(ExecutionContext* context, int scriptId, const String& scriptName, int scriptLine)
289{
290    RefPtr<JSONObject> data = JSONObject::create();
291    data->setString("scriptId", String::number(scriptId));
292    data->setString("scriptName", scriptName);
293    data->setNumber("scriptLine", scriptLine);
294    if (LocalFrame* frame = frameForExecutionContext(context))
295        data->setString("frame", toHexString(frame));
296    return TracedValue::fromJSONValue(data);
297}
298
299PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorPaintImageEvent::data(const RenderImage& renderImage)
300{
301    RefPtr<JSONObject> data = JSONObject::create();
302    data->setNumber("nodeId", InspectorNodeIds::idForNode(renderImage.generatingNode()));
303
304    if (const ImageResource* resource = renderImage.cachedImage())
305        data->setString("url", resource->url().string());
306
307    return TracedValue::fromJSONValue(data);
308}
309
310static size_t usedHeapSize()
311{
312    HeapInfo info;
313    ScriptGCEvent::getHeapSize(info);
314    return info.usedJSHeapSize;
315}
316
317PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorUpdateCountersEvent::data()
318{
319    RefPtr<JSONObject> data = JSONObject::create();
320    if (isMainThread()) {
321        data->setNumber("documents", InspectorCounters::counterValue(InspectorCounters::DocumentCounter));
322        data->setNumber("nodes", InspectorCounters::counterValue(InspectorCounters::NodeCounter));
323        data->setNumber("jsEventListeners", InspectorCounters::counterValue(InspectorCounters::JSEventListenerCounter));
324    }
325    data->setNumber("jsHeapSizeUsed", static_cast<double>(usedHeapSize()));
326    return TracedValue::fromJSONValue(data);
327}
328
329PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorCallStackEvent::currentCallStack()
330{
331    return adoptRef(new JSCallStack(createScriptCallStack(ScriptCallStack::maxCallStackSizeToCapture, true)));
332}
333
334}
335