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/core/v8/ScriptCallStackFactory.h"
9#include "bindings/core/v8/ScriptGCEvent.h"
10#include "bindings/core/v8/ScriptSourceCode.h"
11#include "core/events/Event.h"
12#include "core/frame/FrameView.h"
13#include "core/frame/LocalFrame.h"
14#include "core/inspector/IdentifiersFactory.h"
15#include "core/inspector/InspectorNodeIds.h"
16#include "core/inspector/ScriptCallStack.h"
17#include "core/page/Page.h"
18#include "core/rendering/RenderImage.h"
19#include "core/rendering/RenderLayer.h"
20#include "core/rendering/RenderObject.h"
21#include "core/workers/WorkerThread.h"
22#include "core/xml/XMLHttpRequest.h"
23#include "platform/JSONValues.h"
24#include "platform/TracedValue.h"
25#include "platform/graphics/GraphicsLayer.h"
26#include "platform/network/ResourceRequest.h"
27#include "platform/network/ResourceResponse.h"
28#include "platform/weborigin/KURL.h"
29#include "wtf/Vector.h"
30#include <inttypes.h>
31
32namespace blink {
33
34static const unsigned maxInvalidationTrackingCallstackSize = 5;
35
36namespace {
37
38class JSCallStack : public TraceEvent::ConvertableToTraceFormat  {
39public:
40    explicit JSCallStack(PassRefPtrWillBeRawPtr<ScriptCallStack> callstack)
41    {
42        m_serialized = callstack ? callstack->buildInspectorArray()->toJSONString() : "[]";
43        ASSERT(m_serialized.isSafeToSendToAnotherThread());
44    }
45    virtual String asTraceFormat() const
46    {
47        return m_serialized;
48    }
49
50private:
51    String m_serialized;
52};
53
54String toHexString(const void* p)
55{
56    return String::format("0x%" PRIx64, static_cast<uint64>(reinterpret_cast<intptr_t>(p)));
57}
58
59}
60
61PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorLayoutEvent::beginData(FrameView* frameView)
62{
63    bool isPartial;
64    unsigned needsLayoutObjects;
65    unsigned totalObjects;
66    LocalFrame& frame = frameView->frame();
67    frame.countObjectsNeedingLayout(needsLayoutObjects, totalObjects, isPartial);
68
69    RefPtr<TracedValue> value = TracedValue::create();
70    value->setInteger("dirtyObjects", needsLayoutObjects);
71    value->setInteger("totalObjects", totalObjects);
72    value->setBoolean("partialLayout", isPartial);
73    value->setString("frame", toHexString(&frame));
74    return value;
75}
76
77static void createQuad(TracedValue* value, const char* name, const FloatQuad& quad)
78{
79    value->beginArray(name);
80    value->pushDouble(quad.p1().x());
81    value->pushDouble(quad.p1().y());
82    value->pushDouble(quad.p2().x());
83    value->pushDouble(quad.p2().y());
84    value->pushDouble(quad.p3().x());
85    value->pushDouble(quad.p3().y());
86    value->pushDouble(quad.p4().x());
87    value->pushDouble(quad.p4().y());
88    value->endArray();
89}
90
91static void setGeneratingNodeInfo(TracedValue* value, const RenderObject* renderer, const char* idFieldName, const char* nameFieldName = 0)
92{
93    Node* node = 0;
94    for (; renderer && !node; renderer = renderer->parent())
95        node = renderer->generatingNode();
96    if (!node)
97        return;
98    value->setInteger(idFieldName, InspectorNodeIds::idForNode(node));
99    if (nameFieldName)
100        value->setString(nameFieldName, node->debugName());
101}
102
103PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorLayoutEvent::endData(RenderObject* rootForThisLayout)
104{
105    Vector<FloatQuad> quads;
106    rootForThisLayout->absoluteQuads(quads);
107
108    RefPtr<TracedValue> value = TracedValue::create();
109    if (quads.size() >= 1) {
110        createQuad(value.get(), "root", quads[0]);
111        setGeneratingNodeInfo(value.get(), rootForThisLayout, "rootNode");
112    } else {
113        ASSERT_NOT_REACHED();
114    }
115    return value;
116}
117
118PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorLayoutInvalidationTrackingEvent::data(const RenderObject* renderer)
119{
120    ASSERT(renderer);
121    RefPtr<TracedValue> value = TracedValue::create();
122    value->setString("frame", toHexString(renderer->frame()));
123    setGeneratingNodeInfo(value.get(), renderer, "nodeId", "nodeName");
124    RefPtrWillBeRawPtr<ScriptCallStack> callstack = createScriptCallStack(maxInvalidationTrackingCallstackSize, true);
125    value->setString("callstack", callstack ? callstack->buildInspectorArray()->toJSONString() : "[]");
126    return value;
127}
128
129PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorPaintInvalidationTrackingEvent::data(const RenderObject* renderer, const RenderObject* paintContainer)
130{
131    ASSERT(renderer);
132    RefPtr<TracedValue> value = TracedValue::create();
133    value->setString("frame", toHexString(renderer->frame()));
134    setGeneratingNodeInfo(value.get(), paintContainer, "paintId");
135    setGeneratingNodeInfo(value.get(), renderer, "nodeId", "nodeName");
136    return value;
137}
138
139PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorSendRequestEvent::data(unsigned long identifier, LocalFrame* frame, const ResourceRequest& request)
140{
141    String requestId = IdentifiersFactory::requestId(identifier);
142
143    RefPtr<TracedValue> value = TracedValue::create();
144    value->setString("requestId", requestId);
145    value->setString("frame", toHexString(frame));
146    value->setString("url", request.url().string());
147    value->setString("requestMethod", request.httpMethod());
148    return value;
149}
150
151PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorReceiveResponseEvent::data(unsigned long identifier, LocalFrame* frame, const ResourceResponse& response)
152{
153    String requestId = IdentifiersFactory::requestId(identifier);
154
155    RefPtr<TracedValue> value = TracedValue::create();
156    value->setString("requestId", requestId);
157    value->setString("frame", toHexString(frame));
158    value->setInteger("statusCode", response.httpStatusCode());
159    value->setString("mimeType", response.mimeType().string().isolatedCopy());
160    return value;
161}
162
163PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorReceiveDataEvent::data(unsigned long identifier, LocalFrame* frame, int encodedDataLength)
164{
165    String requestId = IdentifiersFactory::requestId(identifier);
166
167    RefPtr<TracedValue> value = TracedValue::create();
168    value->setString("requestId", requestId);
169    value->setString("frame", toHexString(frame));
170    value->setInteger("encodedDataLength", encodedDataLength);
171    return value;
172}
173
174PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorResourceFinishEvent::data(unsigned long identifier, double finishTime, bool didFail)
175{
176    String requestId = IdentifiersFactory::requestId(identifier);
177
178    RefPtr<TracedValue> value = TracedValue::create();
179    value->setString("requestId", requestId);
180    value->setBoolean("didFail", didFail);
181    if (finishTime)
182        value->setDouble("networkTime", finishTime);
183    return value;
184}
185
186static LocalFrame* frameForExecutionContext(ExecutionContext* context)
187{
188    LocalFrame* frame = 0;
189    if (context->isDocument())
190        frame = toDocument(context)->frame();
191    return frame;
192}
193
194static PassRefPtr<TracedValue> genericTimerData(ExecutionContext* context, int timerId)
195{
196    RefPtr<TracedValue> value = TracedValue::create();
197    value->setInteger("timerId", timerId);
198    if (LocalFrame* frame = frameForExecutionContext(context))
199        value->setString("frame", toHexString(frame));
200    return value.release();
201}
202
203PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorTimerInstallEvent::data(ExecutionContext* context, int timerId, int timeout, bool singleShot)
204{
205    RefPtr<TracedValue> value = genericTimerData(context, timerId);
206    value->setInteger("timeout", timeout);
207    value->setBoolean("singleShot", singleShot);
208    return value;
209}
210
211PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorTimerRemoveEvent::data(ExecutionContext* context, int timerId)
212{
213    return genericTimerData(context, timerId);
214}
215
216PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorTimerFireEvent::data(ExecutionContext* context, int timerId)
217{
218    return genericTimerData(context, timerId);
219}
220
221PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorAnimationFrameEvent::data(Document* document, int callbackId)
222{
223    RefPtr<TracedValue> value = TracedValue::create();
224    value->setInteger("id", callbackId);
225    value->setString("frame", toHexString(document->frame()));
226    return value;
227}
228
229PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorWebSocketCreateEvent::data(Document* document, unsigned long identifier, const KURL& url, const String& protocol)
230{
231    RefPtr<TracedValue> value = TracedValue::create();
232    value->setInteger("identifier", identifier);
233    value->setString("url", url.string());
234    value->setString("frame", toHexString(document->frame()));
235    if (!protocol.isNull())
236        value->setString("webSocketProtocol", protocol);
237    return value;
238}
239
240PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorWebSocketEvent::data(Document* document, unsigned long identifier)
241{
242    RefPtr<TracedValue> value = TracedValue::create();
243    value->setInteger("identifier", identifier);
244    value->setString("frame", toHexString(document->frame()));
245    return value;
246}
247
248PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorParseHtmlEvent::beginData(Document* document, unsigned startLine)
249{
250    RefPtr<TracedValue> value = TracedValue::create();
251    value->setInteger("startLine", startLine);
252    value->setString("frame", toHexString(document->frame()));
253    return value;
254}
255
256PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorXhrReadyStateChangeEvent::data(ExecutionContext* context, XMLHttpRequest* request)
257{
258    RefPtr<TracedValue> value = TracedValue::create();
259    value->setString("url", request->url().string());
260    value->setInteger("readyState", request->readyState());
261    if (LocalFrame* frame = frameForExecutionContext(context))
262        value->setString("frame", toHexString(frame));
263    return value;
264}
265
266PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorXhrLoadEvent::data(ExecutionContext* context, XMLHttpRequest* request)
267{
268    RefPtr<TracedValue> value = TracedValue::create();
269    value->setString("url", request->url().string());
270    if (LocalFrame* frame = frameForExecutionContext(context))
271        value->setString("frame", toHexString(frame));
272    return value;
273}
274
275static void localToPageQuad(const RenderObject& renderer, const LayoutRect& rect, FloatQuad* quad)
276{
277    LocalFrame* frame = renderer.frame();
278    FrameView* view = frame->view();
279    FloatQuad absolute = renderer.localToAbsoluteQuad(FloatQuad(rect));
280    quad->setP1(view->contentsToRootView(roundedIntPoint(absolute.p1())));
281    quad->setP2(view->contentsToRootView(roundedIntPoint(absolute.p2())));
282    quad->setP3(view->contentsToRootView(roundedIntPoint(absolute.p3())));
283    quad->setP4(view->contentsToRootView(roundedIntPoint(absolute.p4())));
284}
285
286const char InspectorLayerInvalidationTrackingEvent::SquashingLayerGeometryWasUpdated[] = "Squashing layer geometry was updated.";
287const char InspectorLayerInvalidationTrackingEvent::AddedToSquashingLayer[] = "The layer may have been added to an already-existing squashing layer.";
288const char InspectorLayerInvalidationTrackingEvent::RemovedFromSquashingLayer[] = "Removed the layer from a squashing layer.";
289const char InspectorLayerInvalidationTrackingEvent::ReflectionLayerChanged[] = "Reflection layer change.";
290const char InspectorLayerInvalidationTrackingEvent::NewCompositedLayer[] = "Assigned a new composited layer.";
291const char InspectorLayerInvalidationTrackingEvent::AncestorRequiresNewLayer[] = "A new composited layer is needed based on the RenderLayer's compositing ancestor's properties.";
292
293PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorLayerInvalidationTrackingEvent::data(const RenderLayer* layer, const char* reason)
294{
295    const RenderObject* paintInvalidationContainer = layer->renderer()->containerForPaintInvalidation();
296
297    RefPtr<TracedValue> value = TracedValue::create();
298    value->setString("frame", toHexString(paintInvalidationContainer->frame()));
299    setGeneratingNodeInfo(value.get(), paintInvalidationContainer, "paintId");
300    value->setString("reason", reason);
301    return value;
302}
303
304PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorPaintEvent::data(RenderObject* renderer, const LayoutRect& clipRect, const GraphicsLayer* graphicsLayer)
305{
306    RefPtr<TracedValue> value = TracedValue::create();
307    value->setString("frame", toHexString(renderer->frame()));
308    FloatQuad quad;
309    localToPageQuad(*renderer, clipRect, &quad);
310    createQuad(value.get(), "clip", quad);
311    setGeneratingNodeInfo(value.get(), renderer, "nodeId");
312    int graphicsLayerId = graphicsLayer ? graphicsLayer->platformLayer()->id() : 0;
313    value->setInteger("layerId", graphicsLayerId);
314    return value;
315}
316
317PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorMarkLoadEvent::data(LocalFrame* frame)
318{
319    RefPtr<TracedValue> value = TracedValue::create();
320    value->setString("frame", toHexString(frame));
321    bool isMainFrame = frame && frame->isMainFrame();
322    value->setBoolean("isMainFrame", isMainFrame);
323    return value;
324}
325
326PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorScrollLayerEvent::data(RenderObject* renderer)
327{
328    RefPtr<TracedValue> value = TracedValue::create();
329    value->setString("frame", toHexString(renderer->frame()));
330    setGeneratingNodeInfo(value.get(), renderer, "nodeId");
331    return value;
332}
333
334PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorEvaluateScriptEvent::data(LocalFrame* frame, const String& url, int lineNumber)
335{
336    RefPtr<TracedValue> value = TracedValue::create();
337    value->setString("frame", toHexString(frame));
338    value->setString("url", url);
339    value->setInteger("lineNumber", lineNumber);
340    return value;
341}
342
343PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorFunctionCallEvent::data(ExecutionContext* context, int scriptId, const String& scriptName, int scriptLine)
344{
345    RefPtr<TracedValue> value = TracedValue::create();
346    value->setString("scriptId", String::number(scriptId));
347    value->setString("scriptName", scriptName);
348    value->setInteger("scriptLine", scriptLine);
349    if (LocalFrame* frame = frameForExecutionContext(context))
350        value->setString("frame", toHexString(frame));
351    return value;
352}
353
354PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorPaintImageEvent::data(const RenderImage& renderImage)
355{
356    RefPtr<TracedValue> value = TracedValue::create();
357    setGeneratingNodeInfo(value.get(), &renderImage, "nodeId");
358    if (const ImageResource* resource = renderImage.cachedImage())
359        value->setString("url", resource->url().string());
360    return value;
361}
362
363static size_t usedHeapSize()
364{
365    HeapInfo info;
366    ScriptGCEvent::getHeapSize(info);
367    return info.usedJSHeapSize;
368}
369
370PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorUpdateCountersEvent::data()
371{
372    RefPtr<TracedValue> value = TracedValue::create();
373    if (isMainThread()) {
374        value->setInteger("documents", InspectorCounters::counterValue(InspectorCounters::DocumentCounter));
375        value->setInteger("nodes", InspectorCounters::counterValue(InspectorCounters::NodeCounter));
376        value->setInteger("jsEventListeners", InspectorCounters::counterValue(InspectorCounters::JSEventListenerCounter));
377    }
378    value->setDouble("jsHeapSizeUsed", static_cast<double>(usedHeapSize()));
379    return value;
380}
381
382PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorCallStackEvent::currentCallStack()
383{
384    return adoptRef(new JSCallStack(createScriptCallStack(ScriptCallStack::maxCallStackSizeToCapture, true)));
385}
386
387PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorEventDispatchEvent::data(const Event& event)
388{
389    RefPtr<TracedValue> value = TracedValue::create();
390    value->setString("type", event.type());
391    return value;
392}
393
394PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorTimeStampEvent::data(ExecutionContext* context, const String& message)
395{
396    RefPtr<TracedValue> value = TracedValue::create();
397    value->setString("message", message);
398    if (LocalFrame* frame = frameForExecutionContext(context))
399        value->setString("frame", toHexString(frame));
400    return value;
401}
402
403PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorTracingSessionIdForWorkerEvent::data(const String& sessionId, WorkerThread* workerThread)
404{
405    RefPtr<TracedValue> value = TracedValue::create();
406    value->setString("sessionId", sessionId);
407    value->setDouble("workerThreadId", workerThread->platformThreadId());
408    return value;
409}
410
411}
412