Home | History | Annotate | Download | only in inspector
      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 #include "core/inspector/InspectorTimelineAgent.h"
     33 
     34 #include "core/events/Event.h"
     35 #include "core/frame/LocalDOMWindow.h"
     36 #include "core/frame/FrameConsole.h"
     37 #include "core/frame/FrameHost.h"
     38 #include "core/frame/FrameView.h"
     39 #include "core/frame/LocalFrame.h"
     40 #include "core/inspector/IdentifiersFactory.h"
     41 #include "core/inspector/InspectorClient.h"
     42 #include "core/inspector/InspectorCounters.h"
     43 #include "core/inspector/InspectorInstrumentation.h"
     44 #include "core/inspector/InspectorLayerTreeAgent.h"
     45 #include "core/inspector/InspectorNodeIds.h"
     46 #include "core/inspector/InspectorOverlay.h"
     47 #include "core/inspector/InspectorPageAgent.h"
     48 #include "core/inspector/InspectorState.h"
     49 #include "core/inspector/InstrumentingAgents.h"
     50 #include "core/inspector/ScriptCallStack.h"
     51 #include "core/inspector/TimelineRecordFactory.h"
     52 #include "core/inspector/TraceEventDispatcher.h"
     53 #include "core/loader/DocumentLoader.h"
     54 #include "core/page/Page.h"
     55 #include "core/rendering/RenderObject.h"
     56 #include "core/rendering/RenderView.h"
     57 #include "core/xml/XMLHttpRequest.h"
     58 #include "platform/TraceEvent.h"
     59 #include "platform/graphics/DeferredImageDecoder.h"
     60 #include "platform/graphics/GraphicsLayer.h"
     61 #include "platform/network/ResourceRequest.h"
     62 #include "wtf/CurrentTime.h"
     63 #include "wtf/DateMath.h"
     64 
     65 namespace WebCore {
     66 
     67 namespace TimelineAgentState {
     68 static const char enabled[] = "enabled";
     69 static const char started[] = "started";
     70 static const char startedFromProtocol[] = "startedFromProtocol";
     71 static const char timelineMaxCallStackDepth[] = "timelineMaxCallStackDepth";
     72 static const char includeCounters[] = "includeCounters";
     73 static const char includeGPUEvents[] = "includeGPUEvents";
     74 static const char bufferEvents[] = "bufferEvents";
     75 static const char liveEvents[] = "liveEvents";
     76 }
     77 
     78 // Must be kept in sync with WebInspector.TimelineModel.RecordType in TimelineModel.js
     79 namespace TimelineRecordType {
     80 static const char Program[] = "Program";
     81 
     82 static const char EventDispatch[] = "EventDispatch";
     83 static const char ScheduleStyleRecalculation[] = "ScheduleStyleRecalculation";
     84 static const char RecalculateStyles[] = "RecalculateStyles";
     85 static const char InvalidateLayout[] = "InvalidateLayout";
     86 static const char Layout[] = "Layout";
     87 static const char UpdateLayerTree[] = "UpdateLayerTree";
     88 static const char Paint[] = "Paint";
     89 static const char ScrollLayer[] = "ScrollLayer";
     90 static const char ResizeImage[] = "ResizeImage";
     91 static const char CompositeLayers[] = "CompositeLayers";
     92 
     93 static const char ParseHTML[] = "ParseHTML";
     94 
     95 static const char TimerInstall[] = "TimerInstall";
     96 static const char TimerRemove[] = "TimerRemove";
     97 static const char TimerFire[] = "TimerFire";
     98 
     99 static const char EvaluateScript[] = "EvaluateScript";
    100 
    101 static const char MarkLoad[] = "MarkLoad";
    102 static const char MarkDOMContent[] = "MarkDOMContent";
    103 static const char MarkFirstPaint[] = "MarkFirstPaint";
    104 
    105 static const char TimeStamp[] = "TimeStamp";
    106 static const char ConsoleTime[] = "ConsoleTime";
    107 
    108 static const char ResourceSendRequest[] = "ResourceSendRequest";
    109 static const char ResourceReceiveResponse[] = "ResourceReceiveResponse";
    110 static const char ResourceReceivedData[] = "ResourceReceivedData";
    111 static const char ResourceFinish[] = "ResourceFinish";
    112 
    113 static const char XHRReadyStateChange[] = "XHRReadyStateChange";
    114 static const char XHRLoad[] = "XHRLoad";
    115 
    116 static const char FunctionCall[] = "FunctionCall";
    117 static const char GCEvent[] = "GCEvent";
    118 
    119 static const char UpdateCounters[] = "UpdateCounters";
    120 
    121 static const char RequestAnimationFrame[] = "RequestAnimationFrame";
    122 static const char CancelAnimationFrame[] = "CancelAnimationFrame";
    123 static const char FireAnimationFrame[] = "FireAnimationFrame";
    124 
    125 static const char WebSocketCreate[] = "WebSocketCreate";
    126 static const char WebSocketSendHandshakeRequest[] = "WebSocketSendHandshakeRequest";
    127 static const char WebSocketReceiveHandshakeResponse[] = "WebSocketReceiveHandshakeResponse";
    128 static const char WebSocketDestroy[] = "WebSocketDestroy";
    129 
    130 static const char RequestMainThreadFrame[] = "RequestMainThreadFrame";
    131 static const char ActivateLayerTree[] = "ActivateLayerTree";
    132 static const char DrawFrame[] = "DrawFrame";
    133 static const char BeginFrame[] = "BeginFrame";
    134 static const char DecodeImage[] = "DecodeImage";
    135 static const char GPUTask[] = "GPUTask";
    136 static const char Rasterize[] = "Rasterize";
    137 static const char PaintSetup[] = "PaintSetup";
    138 
    139 static const char EmbedderCallback[] = "EmbedderCallback";
    140 }
    141 
    142 using TypeBuilder::Timeline::TimelineEvent;
    143 
    144 struct TimelineRecordEntry {
    145     TimelineRecordEntry(PassRefPtr<TimelineEvent> record, PassRefPtr<JSONObject> data, PassRefPtr<TypeBuilder::Array<TimelineEvent> > children, const String& type)
    146         : record(record)
    147         , data(data)
    148         , children(children)
    149         , type(type)
    150         , skipWhenUnbalanced(false)
    151     {
    152     }
    153     RefPtr<TimelineEvent> record;
    154     RefPtr<JSONObject> data;
    155     RefPtr<TypeBuilder::Array<TimelineEvent> > children;
    156     String type;
    157     bool skipWhenUnbalanced;
    158 };
    159 
    160 class TimelineRecordStack {
    161 private:
    162     struct Entry {
    163         Entry(PassRefPtr<TimelineEvent> record, const String& type)
    164             : record(record)
    165             , children(TypeBuilder::Array<TimelineEvent>::create())
    166 #ifndef NDEBUG
    167             , type(type)
    168 #endif
    169         {
    170         }
    171 
    172         RefPtr<TimelineEvent> record;
    173         RefPtr<TypeBuilder::Array<TimelineEvent> > children;
    174 #ifndef NDEBUG
    175         String type;
    176 #endif
    177     };
    178 
    179 public:
    180     TimelineRecordStack() : m_timelineAgent(0) { }
    181     TimelineRecordStack(InspectorTimelineAgent*);
    182 
    183     void addScopedRecord(PassRefPtr<TimelineEvent> record, const String& type);
    184     void closeScopedRecord(double endTime);
    185     void addInstantRecord(PassRefPtr<TimelineEvent> record);
    186 
    187 #ifndef NDEBUG
    188     bool isOpenRecordOfType(const String& type);
    189 #endif
    190 
    191 private:
    192     void send(PassRefPtr<JSONObject>);
    193 
    194     InspectorTimelineAgent* m_timelineAgent;
    195     Vector<Entry> m_stack;
    196 };
    197 
    198 struct TimelineThreadState {
    199     TimelineThreadState() { }
    200 
    201     TimelineThreadState(InspectorTimelineAgent* timelineAgent)
    202         : recordStack(timelineAgent)
    203         , inKnownLayerTask(false)
    204         , decodedPixelRefId(0)
    205     {
    206     }
    207 
    208     TimelineRecordStack recordStack;
    209     bool inKnownLayerTask;
    210     unsigned long long decodedPixelRefId;
    211 };
    212 
    213 struct TimelineImageInfo {
    214     int backendNodeId;
    215     String url;
    216 
    217     TimelineImageInfo() : backendNodeId(0) { }
    218     TimelineImageInfo(int backendNodeId, String url) : backendNodeId(backendNodeId), url(url) { }
    219 };
    220 
    221 static LocalFrame* frameForExecutionContext(ExecutionContext* context)
    222 {
    223     LocalFrame* frame = 0;
    224     if (context->isDocument())
    225         frame = toDocument(context)->frame();
    226     return frame;
    227 }
    228 
    229 static bool eventHasListeners(const AtomicString& eventType, LocalDOMWindow* window, Node* node, const EventPath& eventPath)
    230 {
    231     if (window && window->hasEventListeners(eventType))
    232         return true;
    233 
    234     if (node->hasEventListeners(eventType))
    235         return true;
    236 
    237     for (size_t i = 0; i < eventPath.size(); i++) {
    238         if (eventPath[i].node()->hasEventListeners(eventType))
    239             return true;
    240     }
    241 
    242     return false;
    243 }
    244 
    245 void InspectorTimelineAgent::didGC(double startTime, double endTime, size_t collectedBytesCount)
    246 {
    247     RefPtr<TimelineEvent> record = TimelineRecordFactory::createGenericRecord(
    248         startTime * msPerSecond,
    249         0,
    250         TimelineRecordType::GCEvent,
    251         TimelineRecordFactory::createGCEventData(collectedBytesCount));
    252     record->setEndTime(endTime * msPerSecond);
    253     double time = timestamp();
    254     addRecordToTimeline(record.release(), time);
    255     if (m_state->getBoolean(TimelineAgentState::includeCounters)) {
    256         addRecordToTimeline(createCountersUpdate(), time);
    257     }
    258 }
    259 
    260 InspectorTimelineAgent::~InspectorTimelineAgent()
    261 {
    262 }
    263 
    264 void InspectorTimelineAgent::setFrontend(InspectorFrontend* frontend)
    265 {
    266     m_frontend = frontend->timeline();
    267 }
    268 
    269 void InspectorTimelineAgent::clearFrontend()
    270 {
    271     ErrorString error;
    272     RefPtr<TypeBuilder::Array<TimelineEvent> > events;
    273     stop(&error, events);
    274     disable(&error);
    275     m_frontend = 0;
    276 }
    277 
    278 void InspectorTimelineAgent::restore()
    279 {
    280     if (m_state->getBoolean(TimelineAgentState::startedFromProtocol)) {
    281         if (m_state->getBoolean(TimelineAgentState::bufferEvents))
    282             m_bufferedEvents = TypeBuilder::Array<TimelineEvent>::create();
    283 
    284         setLiveEvents(m_state->getString(TimelineAgentState::liveEvents));
    285         innerStart();
    286     } else if (isStarted()) {
    287         // Timeline was started from console.timeline, it is not restored.
    288         // Tell front-end timline is no longer collecting.
    289         m_state->setBoolean(TimelineAgentState::started, false);
    290         bool fromConsole = true;
    291         m_frontend->stopped(&fromConsole);
    292     }
    293 }
    294 
    295 void InspectorTimelineAgent::enable(ErrorString*)
    296 {
    297     m_state->setBoolean(TimelineAgentState::enabled, true);
    298 }
    299 
    300 void InspectorTimelineAgent::disable(ErrorString*)
    301 {
    302     m_state->setBoolean(TimelineAgentState::enabled, false);
    303 }
    304 
    305 void InspectorTimelineAgent::start(ErrorString* errorString, const int* maxCallStackDepth, const bool* bufferEvents, const String* liveEvents, const bool* includeCounters, const bool* includeGPUEvents)
    306 {
    307     if (!m_frontend)
    308         return;
    309     m_state->setBoolean(TimelineAgentState::startedFromProtocol, true);
    310 
    311     if (isStarted()) {
    312         *errorString = "Timeline is already started";
    313         return;
    314     }
    315 
    316     if (maxCallStackDepth && *maxCallStackDepth >= 0)
    317         m_maxCallStackDepth = *maxCallStackDepth;
    318     else
    319         m_maxCallStackDepth = 5;
    320 
    321     if (bufferEvents && *bufferEvents) {
    322         m_bufferedEvents = TypeBuilder::Array<TimelineEvent>::create();
    323         m_lastProgressTimestamp = timestamp();
    324     }
    325 
    326     if (liveEvents)
    327         setLiveEvents(*liveEvents);
    328 
    329     m_state->setLong(TimelineAgentState::timelineMaxCallStackDepth, m_maxCallStackDepth);
    330     m_state->setBoolean(TimelineAgentState::includeCounters, includeCounters && *includeCounters);
    331     m_state->setBoolean(TimelineAgentState::includeGPUEvents, includeGPUEvents && *includeGPUEvents);
    332     m_state->setBoolean(TimelineAgentState::bufferEvents, bufferEvents && *bufferEvents);
    333     m_state->setString(TimelineAgentState::liveEvents, liveEvents ? *liveEvents : "");
    334 
    335     innerStart();
    336     bool fromConsole = false;
    337     m_frontend->started(&fromConsole);
    338 }
    339 
    340 bool InspectorTimelineAgent::isStarted()
    341 {
    342     return m_state->getBoolean(TimelineAgentState::started);
    343 }
    344 
    345 void InspectorTimelineAgent::innerStart()
    346 {
    347     if (m_overlay)
    348         m_overlay->startedRecordingProfile();
    349     m_state->setBoolean(TimelineAgentState::started, true);
    350     m_instrumentingAgents->setInspectorTimelineAgent(this);
    351     ScriptGCEvent::addEventListener(this);
    352     if (m_client) {
    353         TraceEventDispatcher* dispatcher = TraceEventDispatcher::instance();
    354         dispatcher->addListener(InstrumentationEvents::BeginFrame, TRACE_EVENT_PHASE_INSTANT, this, &InspectorTimelineAgent::onBeginImplSideFrame, m_client);
    355         dispatcher->addListener(InstrumentationEvents::PaintSetup, TRACE_EVENT_PHASE_BEGIN, this, &InspectorTimelineAgent::onPaintSetupBegin, m_client);
    356         dispatcher->addListener(InstrumentationEvents::PaintSetup, TRACE_EVENT_PHASE_END, this, &InspectorTimelineAgent::onPaintSetupEnd, m_client);
    357         dispatcher->addListener(InstrumentationEvents::RasterTask, TRACE_EVENT_PHASE_BEGIN, this, &InspectorTimelineAgent::onRasterTaskBegin, m_client);
    358         dispatcher->addListener(InstrumentationEvents::RasterTask, TRACE_EVENT_PHASE_END, this, &InspectorTimelineAgent::onRasterTaskEnd, m_client);
    359         dispatcher->addListener(InstrumentationEvents::Layer, TRACE_EVENT_PHASE_DELETE_OBJECT, this, &InspectorTimelineAgent::onLayerDeleted, m_client);
    360         dispatcher->addListener(InstrumentationEvents::RequestMainThreadFrame, TRACE_EVENT_PHASE_INSTANT, this, &InspectorTimelineAgent::onRequestMainThreadFrame, m_client);
    361         dispatcher->addListener(InstrumentationEvents::ActivateLayerTree, TRACE_EVENT_PHASE_INSTANT, this, &InspectorTimelineAgent::onActivateLayerTree, m_client);
    362         dispatcher->addListener(InstrumentationEvents::DrawFrame, TRACE_EVENT_PHASE_INSTANT, this, &InspectorTimelineAgent::onDrawFrame, m_client);
    363         dispatcher->addListener(PlatformInstrumentation::ImageDecodeEvent, TRACE_EVENT_PHASE_BEGIN, this, &InspectorTimelineAgent::onImageDecodeBegin, m_client);
    364         dispatcher->addListener(PlatformInstrumentation::ImageDecodeEvent, TRACE_EVENT_PHASE_END, this, &InspectorTimelineAgent::onImageDecodeEnd, m_client);
    365         dispatcher->addListener(PlatformInstrumentation::DrawLazyPixelRefEvent, TRACE_EVENT_PHASE_INSTANT, this, &InspectorTimelineAgent::onDrawLazyPixelRef, m_client);
    366         dispatcher->addListener(PlatformInstrumentation::DecodeLazyPixelRefEvent, TRACE_EVENT_PHASE_BEGIN, this, &InspectorTimelineAgent::onDecodeLazyPixelRefBegin, m_client);
    367         dispatcher->addListener(PlatformInstrumentation::DecodeLazyPixelRefEvent, TRACE_EVENT_PHASE_END, this, &InspectorTimelineAgent::onDecodeLazyPixelRefEnd, m_client);
    368         dispatcher->addListener(PlatformInstrumentation::LazyPixelRef, TRACE_EVENT_PHASE_DELETE_OBJECT, this, &InspectorTimelineAgent::onLazyPixelRefDeleted, m_client);
    369         dispatcher->addListener(InstrumentationEvents::EmbedderCallback, TRACE_EVENT_PHASE_BEGIN, this, &InspectorTimelineAgent::onEmbedderCallbackBegin, m_client);
    370         dispatcher->addListener(InstrumentationEvents::EmbedderCallback, TRACE_EVENT_PHASE_END, this, &InspectorTimelineAgent::onEmbedderCallbackEnd, m_client);
    371 
    372         if (m_state->getBoolean(TimelineAgentState::includeGPUEvents)) {
    373             m_pendingGPURecord.clear();
    374             m_client->startGPUEventsRecording();
    375         }
    376     }
    377 }
    378 
    379 void InspectorTimelineAgent::stop(ErrorString* errorString, RefPtr<TypeBuilder::Array<TimelineEvent> >& events)
    380 {
    381     m_state->setBoolean(TimelineAgentState::startedFromProtocol, false);
    382     m_state->setBoolean(TimelineAgentState::bufferEvents, false);
    383     m_state->setString(TimelineAgentState::liveEvents, "");
    384 
    385     if (!isStarted()) {
    386         *errorString = "Timeline was not started";
    387         return;
    388     }
    389     innerStop(false);
    390     if (m_bufferedEvents)
    391         events = m_bufferedEvents.release();
    392     m_liveEvents.clear();
    393 }
    394 
    395 void InspectorTimelineAgent::innerStop(bool fromConsole)
    396 {
    397     m_state->setBoolean(TimelineAgentState::started, false);
    398 
    399     if (m_client) {
    400         TraceEventDispatcher::instance()->removeAllListeners(this, m_client);
    401         if (m_state->getBoolean(TimelineAgentState::includeGPUEvents))
    402             m_client->stopGPUEventsRecording();
    403     }
    404     m_instrumentingAgents->setInspectorTimelineAgent(0);
    405     ScriptGCEvent::removeEventListener(this);
    406 
    407     clearRecordStack();
    408     m_threadStates.clear();
    409     m_gpuTask.clear();
    410     m_layerToNodeMap.clear();
    411     m_pixelRefToImageInfo.clear();
    412     m_imageBeingPainted = 0;
    413     m_paintSetupStart = 0;
    414     m_mayEmitFirstPaint = false;
    415 
    416     for (size_t i = 0; i < m_consoleTimelines.size(); ++i) {
    417         String message = String::format("Timeline '%s' terminated.", m_consoleTimelines[i].utf8().data());
    418         mainFrame()->console().addMessage(ConsoleAPIMessageSource, DebugMessageLevel, message);
    419     }
    420     m_consoleTimelines.clear();
    421 
    422     m_frontend->stopped(&fromConsole);
    423     if (m_overlay)
    424         m_overlay->finishedRecordingProfile();
    425 }
    426 
    427 void InspectorTimelineAgent::didBeginFrame(int frameId)
    428 {
    429     TraceEventDispatcher::instance()->processBackgroundEvents();
    430     m_pendingFrameRecord = TimelineRecordFactory::createGenericRecord(timestamp(), 0, TimelineRecordType::BeginFrame, TimelineRecordFactory::createFrameData(frameId));
    431 }
    432 
    433 void InspectorTimelineAgent::didCancelFrame()
    434 {
    435     m_pendingFrameRecord.clear();
    436 }
    437 
    438 bool InspectorTimelineAgent::willCallFunction(ExecutionContext* context, int scriptId, const String& scriptName, int scriptLine)
    439 {
    440     pushCurrentRecord(TimelineRecordFactory::createFunctionCallData(scriptId, scriptName, scriptLine), TimelineRecordType::FunctionCall, true, frameForExecutionContext(context));
    441     return true;
    442 }
    443 
    444 void InspectorTimelineAgent::didCallFunction()
    445 {
    446     didCompleteCurrentRecord(TimelineRecordType::FunctionCall);
    447 }
    448 
    449 bool InspectorTimelineAgent::willDispatchEvent(Document* document, const Event& event, LocalDOMWindow* window, Node* node, const EventPath& eventPath)
    450 {
    451     if (!eventHasListeners(event.type(), window, node, eventPath))
    452         return false;
    453 
    454     pushCurrentRecord(TimelineRecordFactory::createEventDispatchData(event), TimelineRecordType::EventDispatch, false, document->frame());
    455     return true;
    456 }
    457 
    458 bool InspectorTimelineAgent::willDispatchEventOnWindow(const Event& event, LocalDOMWindow* window)
    459 {
    460     if (!window->hasEventListeners(event.type()))
    461         return false;
    462     pushCurrentRecord(TimelineRecordFactory::createEventDispatchData(event), TimelineRecordType::EventDispatch, false, window->frame());
    463     return true;
    464 }
    465 
    466 void InspectorTimelineAgent::didDispatchEvent()
    467 {
    468     didCompleteCurrentRecord(TimelineRecordType::EventDispatch);
    469 }
    470 
    471 void InspectorTimelineAgent::didDispatchEventOnWindow()
    472 {
    473     didDispatchEvent();
    474 }
    475 
    476 void InspectorTimelineAgent::didInvalidateLayout(LocalFrame* frame)
    477 {
    478     appendRecord(JSONObject::create(), TimelineRecordType::InvalidateLayout, true, frame);
    479 }
    480 
    481 bool InspectorTimelineAgent::willLayout(LocalFrame* frame)
    482 {
    483     bool isPartial;
    484     unsigned needsLayoutObjects;
    485     unsigned totalObjects;
    486     frame->countObjectsNeedingLayout(needsLayoutObjects, totalObjects, isPartial);
    487 
    488     pushCurrentRecord(TimelineRecordFactory::createLayoutData(needsLayoutObjects, totalObjects, isPartial), TimelineRecordType::Layout, true, frame);
    489     return true;
    490 }
    491 
    492 void InspectorTimelineAgent::didLayout(RenderObject* root)
    493 {
    494     if (m_recordStack.isEmpty())
    495         return;
    496     TimelineRecordEntry& entry = m_recordStack.last();
    497     ASSERT(entry.type == TimelineRecordType::Layout);
    498     Vector<FloatQuad> quads;
    499     root->absoluteQuads(quads);
    500     if (quads.size() >= 1)
    501         TimelineRecordFactory::setLayoutRoot(entry.data.get(), quads[0], nodeId(root));
    502     else
    503         ASSERT_NOT_REACHED();
    504     didCompleteCurrentRecord(TimelineRecordType::Layout);
    505 }
    506 
    507 void InspectorTimelineAgent::layerTreeDidChange()
    508 {
    509     ASSERT(!m_pendingLayerTreeData);
    510     m_pendingLayerTreeData = m_layerTreeAgent->buildLayerTree();
    511 }
    512 
    513 void InspectorTimelineAgent::willUpdateLayerTree()
    514 {
    515     pushCurrentRecord(JSONObject::create(), TimelineRecordType::UpdateLayerTree, false, 0);
    516 }
    517 
    518 void InspectorTimelineAgent::didUpdateLayerTree()
    519 {
    520     if (m_recordStack.isEmpty())
    521         return;
    522     TimelineRecordEntry& entry = m_recordStack.last();
    523     ASSERT(entry.type == TimelineRecordType::UpdateLayerTree);
    524     if (m_pendingLayerTreeData)
    525         TimelineRecordFactory::setLayerTreeData(entry.data.get(), m_pendingLayerTreeData.release());
    526     didCompleteCurrentRecord(TimelineRecordType::UpdateLayerTree);
    527 }
    528 
    529 void InspectorTimelineAgent::didScheduleStyleRecalculation(Document* document)
    530 {
    531     appendRecord(JSONObject::create(), TimelineRecordType::ScheduleStyleRecalculation, true, document->frame());
    532 }
    533 
    534 bool InspectorTimelineAgent::willRecalculateStyle(Document* document)
    535 {
    536     pushCurrentRecord(JSONObject::create(), TimelineRecordType::RecalculateStyles, true, document->frame());
    537     return true;
    538 }
    539 
    540 void InspectorTimelineAgent::didRecalculateStyle(int elementCount)
    541 {
    542     if (m_recordStack.isEmpty())
    543         return;
    544     TimelineRecordEntry& entry = m_recordStack.last();
    545     ASSERT(entry.type == TimelineRecordType::RecalculateStyles);
    546     TimelineRecordFactory::setStyleRecalcDetails(entry.data.get(), elementCount);
    547     didCompleteCurrentRecord(TimelineRecordType::RecalculateStyles);
    548 }
    549 
    550 void InspectorTimelineAgent::willPaint(RenderObject* renderer, const GraphicsLayer* graphicsLayer)
    551 {
    552     LocalFrame* frame = renderer->frame();
    553 
    554     TraceEventDispatcher::instance()->processBackgroundEvents();
    555     double paintSetupStart = m_paintSetupStart;
    556     m_paintSetupStart = 0;
    557     if (graphicsLayer) {
    558         int layerIdentifier = graphicsLayer->platformLayer()->id();
    559         int nodeIdentifier = nodeId(renderer);
    560         ASSERT(layerIdentifier && nodeIdentifier);
    561         m_layerToNodeMap.set(layerIdentifier, nodeIdentifier);
    562         if (paintSetupStart) {
    563             RefPtr<TimelineEvent> paintSetupRecord = TimelineRecordFactory::createGenericRecord(paintSetupStart, 0, TimelineRecordType::PaintSetup, TimelineRecordFactory::createLayerData(nodeIdentifier));
    564             paintSetupRecord->setEndTime(m_paintSetupEnd);
    565             addRecordToTimeline(paintSetupRecord, paintSetupStart);
    566         }
    567     }
    568     pushCurrentRecord(JSONObject::create(), TimelineRecordType::Paint, true, frame, true);
    569 }
    570 
    571 void InspectorTimelineAgent::didPaint(RenderObject* renderer, const GraphicsLayer* graphicsLayer, GraphicsContext*, const LayoutRect& clipRect)
    572 {
    573     TimelineRecordEntry& entry = m_recordStack.last();
    574     ASSERT(entry.type == TimelineRecordType::Paint);
    575     FloatQuad quad;
    576     localToPageQuad(*renderer, clipRect, &quad);
    577     int graphicsLayerId = graphicsLayer ? graphicsLayer->platformLayer()->id() : 0;
    578     TimelineRecordFactory::setPaintData(entry.data.get(), quad, nodeId(renderer), graphicsLayerId);
    579     didCompleteCurrentRecord(TimelineRecordType::Paint);
    580     if (m_mayEmitFirstPaint && !graphicsLayer) {
    581         m_mayEmitFirstPaint = false;
    582         appendRecord(JSONObject::create(), TimelineRecordType::MarkFirstPaint, false, 0);
    583     }
    584 }
    585 
    586 void InspectorTimelineAgent::willPaintImage(RenderImage* renderImage)
    587 {
    588     ASSERT(!m_imageBeingPainted);
    589     m_imageBeingPainted = renderImage;
    590 }
    591 
    592 void InspectorTimelineAgent::didPaintImage()
    593 {
    594     m_imageBeingPainted = 0;
    595 }
    596 
    597 void InspectorTimelineAgent::willScrollLayer(RenderObject* renderer)
    598 {
    599     pushCurrentRecord(TimelineRecordFactory::createLayerData(nodeId(renderer)), TimelineRecordType::ScrollLayer, false, renderer->frame());
    600 }
    601 
    602 void InspectorTimelineAgent::didScrollLayer()
    603 {
    604     didCompleteCurrentRecord(TimelineRecordType::ScrollLayer);
    605 }
    606 
    607 void InspectorTimelineAgent::willDecodeImage(const String& imageType)
    608 {
    609     RefPtr<JSONObject> data = TimelineRecordFactory::createDecodeImageData(imageType);
    610     if (m_imageBeingPainted)
    611         populateImageDetails(data.get(), *m_imageBeingPainted);
    612     pushCurrentRecord(data, TimelineRecordType::DecodeImage, true, 0);
    613 }
    614 
    615 void InspectorTimelineAgent::didDecodeImage()
    616 {
    617     didCompleteCurrentRecord(TimelineRecordType::DecodeImage);
    618 }
    619 
    620 void InspectorTimelineAgent::willResizeImage(bool shouldCache)
    621 {
    622     RefPtr<JSONObject> data = TimelineRecordFactory::createResizeImageData(shouldCache);
    623     if (m_imageBeingPainted)
    624         populateImageDetails(data.get(), *m_imageBeingPainted);
    625     pushCurrentRecord(data, TimelineRecordType::ResizeImage, true, 0);
    626 }
    627 
    628 void InspectorTimelineAgent::didResizeImage()
    629 {
    630     didCompleteCurrentRecord(TimelineRecordType::ResizeImage);
    631 }
    632 
    633 void InspectorTimelineAgent::willComposite()
    634 {
    635     pushCurrentRecord(JSONObject::create(), TimelineRecordType::CompositeLayers, false, 0);
    636 }
    637 
    638 void InspectorTimelineAgent::didComposite()
    639 {
    640     didCompleteCurrentRecord(TimelineRecordType::CompositeLayers);
    641     if (m_mayEmitFirstPaint) {
    642         m_mayEmitFirstPaint = false;
    643         appendRecord(JSONObject::create(), TimelineRecordType::MarkFirstPaint, false, 0);
    644     }
    645 }
    646 
    647 bool InspectorTimelineAgent::willWriteHTML(Document* document, unsigned startLine)
    648 {
    649     pushCurrentRecord(TimelineRecordFactory::createParseHTMLData(startLine), TimelineRecordType::ParseHTML, true, document->frame());
    650     return true;
    651 }
    652 
    653 void InspectorTimelineAgent::didWriteHTML(unsigned endLine)
    654 {
    655     if (!m_recordStack.isEmpty()) {
    656         TimelineRecordEntry& entry = m_recordStack.last();
    657         entry.data->setNumber("endLine", endLine);
    658         didCompleteCurrentRecord(TimelineRecordType::ParseHTML);
    659     }
    660 }
    661 
    662 void InspectorTimelineAgent::didInstallTimer(ExecutionContext* context, int timerId, int timeout, bool singleShot)
    663 {
    664     appendRecord(TimelineRecordFactory::createTimerInstallData(timerId, timeout, singleShot), TimelineRecordType::TimerInstall, true, frameForExecutionContext(context));
    665 }
    666 
    667 void InspectorTimelineAgent::didRemoveTimer(ExecutionContext* context, int timerId)
    668 {
    669     appendRecord(TimelineRecordFactory::createGenericTimerData(timerId), TimelineRecordType::TimerRemove, true, frameForExecutionContext(context));
    670 }
    671 
    672 bool InspectorTimelineAgent::willFireTimer(ExecutionContext* context, int timerId)
    673 {
    674     pushCurrentRecord(TimelineRecordFactory::createGenericTimerData(timerId), TimelineRecordType::TimerFire, false, frameForExecutionContext(context));
    675     return true;
    676 }
    677 
    678 void InspectorTimelineAgent::didFireTimer()
    679 {
    680     didCompleteCurrentRecord(TimelineRecordType::TimerFire);
    681 }
    682 
    683 bool InspectorTimelineAgent::willDispatchXHRReadyStateChangeEvent(ExecutionContext* context, XMLHttpRequest* request)
    684 {
    685     if (!request->hasEventListeners(EventTypeNames::readystatechange))
    686         return false;
    687     pushCurrentRecord(TimelineRecordFactory::createXHRReadyStateChangeData(request->url().string(), request->readyState()), TimelineRecordType::XHRReadyStateChange, false, frameForExecutionContext(context));
    688     return true;
    689 }
    690 
    691 void InspectorTimelineAgent::didDispatchXHRReadyStateChangeEvent()
    692 {
    693     didCompleteCurrentRecord(TimelineRecordType::XHRReadyStateChange);
    694 }
    695 
    696 bool InspectorTimelineAgent::willDispatchXHRLoadEvent(ExecutionContext* context, XMLHttpRequest* request)
    697 {
    698     if (!request->hasEventListeners(EventTypeNames::load))
    699         return false;
    700     pushCurrentRecord(TimelineRecordFactory::createXHRLoadData(request->url().string()), TimelineRecordType::XHRLoad, true, frameForExecutionContext(context));
    701     return true;
    702 }
    703 
    704 void InspectorTimelineAgent::didDispatchXHRLoadEvent()
    705 {
    706     didCompleteCurrentRecord(TimelineRecordType::XHRLoad);
    707 }
    708 
    709 bool InspectorTimelineAgent::willEvaluateScript(LocalFrame* frame, const String& url, int lineNumber)
    710 {
    711     pushCurrentRecord(TimelineRecordFactory::createEvaluateScriptData(url, lineNumber), TimelineRecordType::EvaluateScript, true, frame);
    712     return true;
    713 }
    714 
    715 void InspectorTimelineAgent::didEvaluateScript()
    716 {
    717     didCompleteCurrentRecord(TimelineRecordType::EvaluateScript);
    718 }
    719 
    720 void InspectorTimelineAgent::willSendRequest(unsigned long identifier, DocumentLoader* loader, const ResourceRequest& request, const ResourceResponse&, const FetchInitiatorInfo&)
    721 {
    722     String requestId = IdentifiersFactory::requestId(identifier);
    723     appendRecord(TimelineRecordFactory::createResourceSendRequestData(requestId, request), TimelineRecordType::ResourceSendRequest, true, loader->frame());
    724 }
    725 
    726 void InspectorTimelineAgent::didReceiveData(LocalFrame* frame, unsigned long identifier, const char*, int, int encodedDataLength)
    727 {
    728     String requestId = IdentifiersFactory::requestId(identifier);
    729     appendRecord(TimelineRecordFactory::createReceiveResourceData(requestId, encodedDataLength), TimelineRecordType::ResourceReceivedData, false, frame);
    730 }
    731 
    732 void InspectorTimelineAgent::didReceiveResourceResponse(LocalFrame* frame, unsigned long identifier, DocumentLoader* loader, const ResourceResponse& response, ResourceLoader* resourceLoader)
    733 {
    734     String requestId = IdentifiersFactory::requestId(identifier);
    735     appendRecord(TimelineRecordFactory::createResourceReceiveResponseData(requestId, response), TimelineRecordType::ResourceReceiveResponse, false, 0);
    736 }
    737 
    738 void InspectorTimelineAgent::didFinishLoadingResource(unsigned long identifier, bool didFail, double finishTime)
    739 {
    740     appendRecord(TimelineRecordFactory::createResourceFinishData(IdentifiersFactory::requestId(identifier), didFail, finishTime), TimelineRecordType::ResourceFinish, false, 0);
    741 }
    742 
    743 void InspectorTimelineAgent::didFinishLoading(unsigned long identifier, DocumentLoader* loader, double monotonicFinishTime, int64_t)
    744 {
    745     didFinishLoadingResource(identifier, false, monotonicFinishTime * msPerSecond);
    746 }
    747 
    748 void InspectorTimelineAgent::didFailLoading(unsigned long identifier, const ResourceError& error)
    749 {
    750     didFinishLoadingResource(identifier, true, 0);
    751 }
    752 
    753 void InspectorTimelineAgent::consoleTimeStamp(ExecutionContext* context, const String& title)
    754 {
    755     appendRecord(TimelineRecordFactory::createTimeStampData(title), TimelineRecordType::TimeStamp, true, frameForExecutionContext(context));
    756 }
    757 
    758 void InspectorTimelineAgent::consoleTime(ExecutionContext* context, const String& message)
    759 {
    760     pushCurrentRecord(TimelineRecordFactory::createConsoleTimeData(message), TimelineRecordType::ConsoleTime, false, frameForExecutionContext(context));
    761     m_recordStack.last().skipWhenUnbalanced = true;
    762 }
    763 
    764 void InspectorTimelineAgent::consoleTimeEnd(ExecutionContext* context, const String& message, ScriptState*)
    765 {
    766     if (m_recordStack.last().type != TimelineRecordType::ConsoleTime)
    767         return;
    768     String originalMessage;
    769     if (m_recordStack.last().data->getString("message", &originalMessage) && message != originalMessage)
    770         return;
    771     // Only complete console.time that is balanced.
    772     didCompleteCurrentRecord(TimelineRecordType::ConsoleTime);
    773 }
    774 
    775 void InspectorTimelineAgent::consoleTimeline(ExecutionContext* context, const String& title, ScriptState* scriptState)
    776 {
    777     if (!m_state->getBoolean(TimelineAgentState::enabled))
    778         return;
    779 
    780     String message = String::format("Timeline '%s' started.", title.utf8().data());
    781     mainFrame()->console().addMessage(ConsoleAPIMessageSource, DebugMessageLevel, message, String(), 0, 0, nullptr, scriptState);
    782     m_consoleTimelines.append(title);
    783     if (!isStarted()) {
    784         innerStart();
    785         bool fromConsole = true;
    786         m_frontend->started(&fromConsole);
    787     }
    788     appendRecord(TimelineRecordFactory::createTimeStampData(message), TimelineRecordType::TimeStamp, true, frameForExecutionContext(context));
    789 }
    790 
    791 void InspectorTimelineAgent::consoleTimelineEnd(ExecutionContext* context, const String& title, ScriptState* scriptState)
    792 {
    793     if (!m_state->getBoolean(TimelineAgentState::enabled))
    794         return;
    795 
    796     size_t index = m_consoleTimelines.find(title);
    797     if (index == kNotFound) {
    798         String message = String::format("Timeline '%s' was not started.", title.utf8().data());
    799         mainFrame()->console().addMessage(ConsoleAPIMessageSource, DebugMessageLevel, message, String(), 0, 0, nullptr, scriptState);
    800         return;
    801     }
    802 
    803     String message = String::format("Timeline '%s' finished.", title.utf8().data());
    804     appendRecord(TimelineRecordFactory::createTimeStampData(message), TimelineRecordType::TimeStamp, true, frameForExecutionContext(context));
    805     m_consoleTimelines.remove(index);
    806     if (!m_consoleTimelines.size() && isStarted() && !m_state->getBoolean(TimelineAgentState::startedFromProtocol)) {
    807         unwindRecordStack();
    808         innerStop(true);
    809     }
    810     mainFrame()->console().addMessage(ConsoleAPIMessageSource, DebugMessageLevel, message, String(), 0, 0, nullptr, scriptState);
    811 }
    812 
    813 void InspectorTimelineAgent::domContentLoadedEventFired(LocalFrame* frame)
    814 {
    815     bool isMainFrame = frame && m_pageAgent && (frame == m_pageAgent->mainFrame());
    816     appendRecord(TimelineRecordFactory::createMarkData(isMainFrame), TimelineRecordType::MarkDOMContent, false, frame);
    817     if (isMainFrame)
    818         m_mayEmitFirstPaint = true;
    819 }
    820 
    821 void InspectorTimelineAgent::loadEventFired(LocalFrame* frame)
    822 {
    823     bool isMainFrame = frame && m_pageAgent && (frame == m_pageAgent->mainFrame());
    824     appendRecord(TimelineRecordFactory::createMarkData(isMainFrame), TimelineRecordType::MarkLoad, false, frame);
    825 }
    826 
    827 void InspectorTimelineAgent::didCommitLoad()
    828 {
    829     clearRecordStack();
    830 }
    831 
    832 void InspectorTimelineAgent::didRequestAnimationFrame(Document* document, int callbackId)
    833 {
    834     appendRecord(TimelineRecordFactory::createAnimationFrameData(callbackId), TimelineRecordType::RequestAnimationFrame, true, document->frame());
    835 }
    836 
    837 void InspectorTimelineAgent::didCancelAnimationFrame(Document* document, int callbackId)
    838 {
    839     appendRecord(TimelineRecordFactory::createAnimationFrameData(callbackId), TimelineRecordType::CancelAnimationFrame, true, document->frame());
    840 }
    841 
    842 bool InspectorTimelineAgent::willFireAnimationFrame(Document* document, int callbackId)
    843 {
    844     pushCurrentRecord(TimelineRecordFactory::createAnimationFrameData(callbackId), TimelineRecordType::FireAnimationFrame, false, document->frame());
    845     return true;
    846 }
    847 
    848 void InspectorTimelineAgent::didFireAnimationFrame()
    849 {
    850     didCompleteCurrentRecord(TimelineRecordType::FireAnimationFrame);
    851 }
    852 
    853 void InspectorTimelineAgent::willProcessTask()
    854 {
    855     pushCurrentRecord(JSONObject::create(), TimelineRecordType::Program, false, 0);
    856 }
    857 
    858 void InspectorTimelineAgent::didProcessTask()
    859 {
    860     didCompleteCurrentRecord(TimelineRecordType::Program);
    861 }
    862 
    863 void InspectorTimelineAgent::didCreateWebSocket(Document* document, unsigned long identifier, const KURL& url, const String& protocol)
    864 {
    865     appendRecord(TimelineRecordFactory::createWebSocketCreateData(identifier, url, protocol), TimelineRecordType::WebSocketCreate, true, document->frame());
    866 }
    867 
    868 void InspectorTimelineAgent::willSendWebSocketHandshakeRequest(Document* document, unsigned long identifier, const WebSocketHandshakeRequest*)
    869 {
    870     appendRecord(TimelineRecordFactory::createGenericWebSocketData(identifier), TimelineRecordType::WebSocketSendHandshakeRequest, true, document->frame());
    871 }
    872 
    873 void InspectorTimelineAgent::didReceiveWebSocketHandshakeResponse(Document* document, unsigned long identifier, const WebSocketHandshakeRequest*, const WebSocketHandshakeResponse*)
    874 {
    875     appendRecord(TimelineRecordFactory::createGenericWebSocketData(identifier), TimelineRecordType::WebSocketReceiveHandshakeResponse, false, document->frame());
    876 }
    877 
    878 void InspectorTimelineAgent::didCloseWebSocket(Document* document, unsigned long identifier)
    879 {
    880     appendRecord(TimelineRecordFactory::createGenericWebSocketData(identifier), TimelineRecordType::WebSocketDestroy, true, document->frame());
    881 }
    882 
    883 void InspectorTimelineAgent::onBeginImplSideFrame(const TraceEventDispatcher::TraceEvent& event)
    884 {
    885     unsigned long long layerTreeId = event.asUInt(InstrumentationEventArguments::LayerTreeId);
    886     if (layerTreeId != m_layerTreeId)
    887         return;
    888     TimelineThreadState& state = threadState(event.threadIdentifier());
    889     state.recordStack.addInstantRecord(createRecordForEvent(event, TimelineRecordType::BeginFrame, JSONObject::create()));
    890 }
    891 
    892 void InspectorTimelineAgent::onPaintSetupBegin(const TraceEventDispatcher::TraceEvent& event)
    893 {
    894     ASSERT(!m_paintSetupStart);
    895     m_paintSetupStart = event.timestamp() * msPerSecond;
    896 }
    897 
    898 void InspectorTimelineAgent::onPaintSetupEnd(const TraceEventDispatcher::TraceEvent& event)
    899 {
    900     ASSERT(m_paintSetupStart);
    901     m_paintSetupEnd = event.timestamp() * msPerSecond;
    902 }
    903 
    904 void InspectorTimelineAgent::onRasterTaskBegin(const TraceEventDispatcher::TraceEvent& event)
    905 {
    906     TimelineThreadState& state = threadState(event.threadIdentifier());
    907     unsigned long long layerId = event.asUInt(InstrumentationEventArguments::LayerId);
    908     ASSERT(layerId);
    909     if (!m_layerToNodeMap.contains(layerId))
    910         return;
    911     ASSERT(!state.inKnownLayerTask);
    912     state.inKnownLayerTask = true;
    913     double timestamp = event.timestamp() * msPerSecond;
    914     RefPtr<JSONObject> data = TimelineRecordFactory::createLayerData(m_layerToNodeMap.get(layerId));
    915     RefPtr<TimelineEvent> record = TimelineRecordFactory::createBackgroundRecord(timestamp, String::number(event.threadIdentifier()), TimelineRecordType::Rasterize, data);
    916     state.recordStack.addScopedRecord(record, TimelineRecordType::Rasterize);
    917 }
    918 
    919 void InspectorTimelineAgent::onRasterTaskEnd(const TraceEventDispatcher::TraceEvent& event)
    920 {
    921     TimelineThreadState& state = threadState(event.threadIdentifier());
    922     if (!state.inKnownLayerTask)
    923         return;
    924     ASSERT(state.recordStack.isOpenRecordOfType(TimelineRecordType::Rasterize));
    925     state.recordStack.closeScopedRecord(event.timestamp() * msPerSecond);
    926     state.inKnownLayerTask = false;
    927 }
    928 
    929 void InspectorTimelineAgent::onImageDecodeBegin(const TraceEventDispatcher::TraceEvent& event)
    930 {
    931     TimelineThreadState& state = threadState(event.threadIdentifier());
    932     if (!state.decodedPixelRefId && !state.inKnownLayerTask)
    933         return;
    934     TimelineImageInfo imageInfo;
    935     if (state.decodedPixelRefId) {
    936         PixelRefToImageInfoMap::const_iterator it = m_pixelRefToImageInfo.find(state.decodedPixelRefId);
    937         if (it != m_pixelRefToImageInfo.end())
    938             imageInfo = it->value;
    939         else
    940             ASSERT_NOT_REACHED();
    941     }
    942     RefPtr<JSONObject> data = JSONObject::create();
    943     TimelineRecordFactory::setImageDetails(data.get(), imageInfo.backendNodeId, imageInfo.url);
    944     double timeestamp = event.timestamp() * msPerSecond;
    945     state.recordStack.addScopedRecord(TimelineRecordFactory::createBackgroundRecord(timeestamp, String::number(event.threadIdentifier()), TimelineRecordType::DecodeImage, data), TimelineRecordType::DecodeImage);
    946 }
    947 
    948 void InspectorTimelineAgent::onImageDecodeEnd(const TraceEventDispatcher::TraceEvent& event)
    949 {
    950     TimelineThreadState& state = threadState(event.threadIdentifier());
    951     if (!state.decodedPixelRefId)
    952         return;
    953     ASSERT(state.recordStack.isOpenRecordOfType(TimelineRecordType::DecodeImage));
    954     state.recordStack.closeScopedRecord(event.timestamp() * msPerSecond);
    955 }
    956 
    957 void InspectorTimelineAgent::onRequestMainThreadFrame(const TraceEventDispatcher::TraceEvent& event)
    958 {
    959     unsigned long long layerTreeId = event.asUInt(InstrumentationEventArguments::LayerTreeId);
    960     if (layerTreeId != m_layerTreeId)
    961         return;
    962     TimelineThreadState& state = threadState(event.threadIdentifier());
    963     state.recordStack.addInstantRecord(createRecordForEvent(event, TimelineRecordType::RequestMainThreadFrame, JSONObject::create()));
    964 }
    965 
    966 void InspectorTimelineAgent::onActivateLayerTree(const TraceEventDispatcher::TraceEvent& event)
    967 {
    968     unsigned long long layerTreeId = event.asUInt(InstrumentationEventArguments::LayerTreeId);
    969     if (layerTreeId != m_layerTreeId)
    970         return;
    971     unsigned long long frameId = event.asUInt(InstrumentationEventArguments::FrameId);
    972     TimelineThreadState& state = threadState(event.threadIdentifier());
    973     state.recordStack.addInstantRecord(createRecordForEvent(event, TimelineRecordType::ActivateLayerTree, TimelineRecordFactory::createFrameData(frameId)));
    974 }
    975 
    976 void InspectorTimelineAgent::onDrawFrame(const TraceEventDispatcher::TraceEvent& event)
    977 {
    978     unsigned long long layerTreeId = event.asUInt(InstrumentationEventArguments::LayerTreeId);
    979     if (layerTreeId != m_layerTreeId)
    980         return;
    981     TimelineThreadState& state = threadState(event.threadIdentifier());
    982     state.recordStack.addInstantRecord(createRecordForEvent(event, TimelineRecordType::DrawFrame, JSONObject::create()));
    983 }
    984 
    985 void InspectorTimelineAgent::onLayerDeleted(const TraceEventDispatcher::TraceEvent& event)
    986 {
    987     unsigned long long id = event.id();
    988     ASSERT(id);
    989     m_layerToNodeMap.remove(id);
    990 }
    991 
    992 void InspectorTimelineAgent::onDecodeLazyPixelRefBegin(const TraceEventDispatcher::TraceEvent& event)
    993 {
    994     TimelineThreadState& state = threadState(event.threadIdentifier());
    995     ASSERT(!state.decodedPixelRefId);
    996     unsigned long long pixelRefId = event.asUInt(PlatformInstrumentation::LazyPixelRef);
    997     ASSERT(pixelRefId);
    998     if (m_pixelRefToImageInfo.contains(pixelRefId))
    999         state.decodedPixelRefId = pixelRefId;
   1000 }
   1001 
   1002 void InspectorTimelineAgent::onDecodeLazyPixelRefEnd(const TraceEventDispatcher::TraceEvent& event)
   1003 {
   1004     threadState(event.threadIdentifier()).decodedPixelRefId = 0;
   1005 }
   1006 
   1007 void InspectorTimelineAgent::onDrawLazyPixelRef(const TraceEventDispatcher::TraceEvent& event)
   1008 {
   1009     unsigned long long pixelRefId = event.asUInt(PlatformInstrumentation::LazyPixelRef);
   1010     ASSERT(pixelRefId);
   1011     if (!m_imageBeingPainted)
   1012         return;
   1013     String url;
   1014     if (const ImageResource* resource = m_imageBeingPainted->cachedImage())
   1015         url = resource->url().string();
   1016     m_pixelRefToImageInfo.set(pixelRefId, TimelineImageInfo(nodeId(m_imageBeingPainted->generatingNode()), url));
   1017 }
   1018 
   1019 void InspectorTimelineAgent::onLazyPixelRefDeleted(const TraceEventDispatcher::TraceEvent& event)
   1020 {
   1021     m_pixelRefToImageInfo.remove(event.id());
   1022 }
   1023 
   1024 void InspectorTimelineAgent::processGPUEvent(const GPUEvent& event)
   1025 {
   1026     double timelineTimestamp = event.timestamp * msPerSecond;
   1027     if (event.phase == GPUEvent::PhaseBegin) {
   1028         m_pendingGPURecord = TimelineRecordFactory::createBackgroundRecord(timelineTimestamp, "gpu", TimelineRecordType::GPUTask, TimelineRecordFactory::createGPUTaskData(event.foreign));
   1029     } else if (m_pendingGPURecord) {
   1030         m_pendingGPURecord->setEndTime(timelineTimestamp);
   1031         sendEvent(m_pendingGPURecord.release());
   1032         if (!event.foreign && m_state->getBoolean(TimelineAgentState::includeCounters)) {
   1033             RefPtr<TypeBuilder::Timeline::Counters> counters = TypeBuilder::Timeline::Counters::create();
   1034             counters->setGpuMemoryUsedKB(static_cast<double>(event.usedGPUMemoryBytes / 1024));
   1035             counters->setGpuMemoryLimitKB(static_cast<double>(event.limitGPUMemoryBytes / 1024));
   1036             sendEvent(TimelineRecordFactory::createBackgroundRecord(timelineTimestamp, "gpu", TimelineRecordType::UpdateCounters, counters.release()->asObject()));
   1037         }
   1038     }
   1039 }
   1040 
   1041 void InspectorTimelineAgent::onEmbedderCallbackBegin(const TraceEventDispatcher::TraceEvent& event)
   1042 {
   1043     TimelineThreadState& state = threadState(event.threadIdentifier());
   1044     double timestamp = event.timestamp() * msPerSecond;
   1045     RefPtr<JSONObject> data = TimelineRecordFactory::createEmbedderCallbackData(event.asString(InstrumentationEventArguments::CallbackName));
   1046     RefPtr<TimelineEvent> record = TimelineRecordFactory::createGenericRecord(timestamp, 0, TimelineRecordType::EmbedderCallback, data);
   1047     state.recordStack.addScopedRecord(record, TimelineRecordType::EmbedderCallback);
   1048 }
   1049 
   1050 void InspectorTimelineAgent::onEmbedderCallbackEnd(const TraceEventDispatcher::TraceEvent& event)
   1051 {
   1052     TimelineThreadState& state = threadState(event.threadIdentifier());
   1053     state.recordStack.closeScopedRecord(event.timestamp() * msPerSecond);
   1054 }
   1055 
   1056 void InspectorTimelineAgent::addRecordToTimeline(PassRefPtr<TimelineEvent> record, double ts)
   1057 {
   1058     commitFrameRecord();
   1059     innerAddRecordToTimeline(record);
   1060     if (m_bufferedEvents && ts - m_lastProgressTimestamp > 300) {
   1061         m_lastProgressTimestamp = ts;
   1062         m_frontend->progress(m_bufferedEvents->length());
   1063     }
   1064 }
   1065 
   1066 void InspectorTimelineAgent::innerAddRecordToTimeline(PassRefPtr<TimelineEvent> record)
   1067 {
   1068     if (m_recordStack.isEmpty()) {
   1069         TraceEventDispatcher::instance()->processBackgroundEvents();
   1070         sendEvent(record);
   1071     } else {
   1072         TimelineRecordEntry& parent = m_recordStack.last();
   1073         parent.children->addItem(record);
   1074         if (m_state->getBoolean(TimelineAgentState::includeCounters))
   1075             parent.children->addItem(createCountersUpdate());
   1076     }
   1077 }
   1078 
   1079 static size_t getUsedHeapSize()
   1080 {
   1081     HeapInfo info;
   1082     ScriptGCEvent::getHeapSize(info);
   1083     return info.usedJSHeapSize;
   1084 }
   1085 
   1086 PassRefPtr<TypeBuilder::Timeline::TimelineEvent> InspectorTimelineAgent::createCountersUpdate()
   1087 {
   1088     RefPtr<TypeBuilder::Timeline::Counters> counters = TypeBuilder::Timeline::Counters::create();
   1089     if (m_inspectorType == PageInspector) {
   1090         counters->setDocuments(InspectorCounters::counterValue(InspectorCounters::DocumentCounter));
   1091         counters->setNodes(InspectorCounters::counterValue(InspectorCounters::NodeCounter));
   1092         counters->setJsEventListeners(InspectorCounters::counterValue(InspectorCounters::JSEventListenerCounter));
   1093     }
   1094     counters->setJsHeapSizeUsed(static_cast<double>(getUsedHeapSize()));
   1095     return TimelineRecordFactory::createGenericRecord(timestamp(), 0, TimelineRecordType::UpdateCounters, counters.release()->asObject());
   1096 }
   1097 
   1098 void InspectorTimelineAgent::setFrameIdentifier(TimelineEvent* record, LocalFrame* frame)
   1099 {
   1100     if (!frame || !m_pageAgent)
   1101         return;
   1102     String frameId;
   1103     if (frame && m_pageAgent)
   1104         frameId = m_pageAgent->frameId(frame);
   1105     record->setFrameId(frameId);
   1106 }
   1107 
   1108 void InspectorTimelineAgent::populateImageDetails(JSONObject* data, const RenderImage& renderImage)
   1109 {
   1110     const ImageResource* resource = renderImage.cachedImage();
   1111     TimelineRecordFactory::setImageDetails(data, nodeId(renderImage.generatingNode()), resource ? resource->url().string() : "");
   1112 }
   1113 
   1114 void InspectorTimelineAgent::didCompleteCurrentRecord(const String& type)
   1115 {
   1116     // An empty stack could merely mean that the timeline agent was turned on in the middle of
   1117     // an event. Don't treat as an error.
   1118     if (!m_recordStack.isEmpty()) {
   1119         if (m_platformInstrumentationClientInstalledAtStackDepth == m_recordStack.size()) {
   1120             m_platformInstrumentationClientInstalledAtStackDepth = 0;
   1121             PlatformInstrumentation::setClient(0);
   1122         }
   1123 
   1124         TimelineRecordEntry entry = m_recordStack.last();
   1125         m_recordStack.removeLast();
   1126         while (entry.type != type && entry.skipWhenUnbalanced && !m_recordStack.isEmpty()) {
   1127             // Discard pending skippable entry, paste its children inplace.
   1128             if (entry.children)
   1129                 m_recordStack.last().children->concat(entry.children);
   1130             entry = m_recordStack.last();
   1131             m_recordStack.removeLast();
   1132         }
   1133         ASSERT(entry.type == type);
   1134         entry.record->setChildren(entry.children);
   1135         double ts = timestamp();
   1136         entry.record->setEndTime(ts);
   1137         addRecordToTimeline(entry.record, ts);
   1138     }
   1139 }
   1140 
   1141 void InspectorTimelineAgent::unwindRecordStack()
   1142 {
   1143     while (!m_recordStack.isEmpty()) {
   1144         TimelineRecordEntry& entry = m_recordStack.last();
   1145         didCompleteCurrentRecord(entry.type);
   1146     }
   1147 }
   1148 
   1149 InspectorTimelineAgent::InspectorTimelineAgent(InspectorPageAgent* pageAgent, InspectorLayerTreeAgent* layerTreeAgent,
   1150     InspectorOverlay* overlay, InspectorType type, InspectorClient* client)
   1151     : InspectorBaseAgent<InspectorTimelineAgent>("Timeline")
   1152     , m_pageAgent(pageAgent)
   1153     , m_layerTreeAgent(layerTreeAgent)
   1154     , m_frontend(0)
   1155     , m_client(client)
   1156     , m_overlay(overlay)
   1157     , m_inspectorType(type)
   1158     , m_id(1)
   1159     , m_layerTreeId(0)
   1160     , m_maxCallStackDepth(5)
   1161     , m_platformInstrumentationClientInstalledAtStackDepth(0)
   1162     , m_imageBeingPainted(0)
   1163     , m_paintSetupStart(0)
   1164     , m_mayEmitFirstPaint(false)
   1165     , m_lastProgressTimestamp(0)
   1166 {
   1167 }
   1168 
   1169 void InspectorTimelineAgent::appendRecord(PassRefPtr<JSONObject> data, const String& type, bool captureCallStack, LocalFrame* frame)
   1170 {
   1171     double ts = timestamp();
   1172     RefPtr<TimelineEvent> record = TimelineRecordFactory::createGenericRecord(ts, captureCallStack ? m_maxCallStackDepth : 0, type, data);
   1173     setFrameIdentifier(record.get(), frame);
   1174     addRecordToTimeline(record.release(), ts);
   1175 }
   1176 
   1177 void InspectorTimelineAgent::sendEvent(PassRefPtr<TimelineEvent> record)
   1178 {
   1179     RefPtr<TimelineEvent> retain = record;
   1180     if (m_bufferedEvents) {
   1181         m_bufferedEvents->addItem(retain);
   1182         if (!m_liveEvents.contains(TimelineRecordFactory::type(retain.get())))
   1183             return;
   1184     }
   1185     m_frontend->eventRecorded(retain.release());
   1186 }
   1187 
   1188 void InspectorTimelineAgent::pushCurrentRecord(PassRefPtr<JSONObject> data, const String& type, bool captureCallStack, LocalFrame* frame, bool hasLowLevelDetails)
   1189 {
   1190     commitFrameRecord();
   1191     RefPtr<TimelineEvent> record = TimelineRecordFactory::createGenericRecord(timestamp(), captureCallStack ? m_maxCallStackDepth : 0, type, data.get());
   1192     setFrameIdentifier(record.get(), frame);
   1193     m_recordStack.append(TimelineRecordEntry(record.release(), data, TypeBuilder::Array<TimelineEvent>::create(), type));
   1194     if (hasLowLevelDetails && !m_platformInstrumentationClientInstalledAtStackDepth && !PlatformInstrumentation::hasClient()) {
   1195         m_platformInstrumentationClientInstalledAtStackDepth = m_recordStack.size();
   1196         PlatformInstrumentation::setClient(this);
   1197     }
   1198 }
   1199 
   1200 TimelineThreadState& InspectorTimelineAgent::threadState(ThreadIdentifier thread)
   1201 {
   1202     ThreadStateMap::iterator it = m_threadStates.find(thread);
   1203     if (it != m_threadStates.end())
   1204         return it->value;
   1205     return m_threadStates.add(thread, TimelineThreadState(this)).storedValue->value;
   1206 }
   1207 
   1208 void InspectorTimelineAgent::commitFrameRecord()
   1209 {
   1210     if (!m_pendingFrameRecord)
   1211         return;
   1212     innerAddRecordToTimeline(m_pendingFrameRecord.release());
   1213 }
   1214 
   1215 void InspectorTimelineAgent::clearRecordStack()
   1216 {
   1217     if (m_platformInstrumentationClientInstalledAtStackDepth) {
   1218         m_platformInstrumentationClientInstalledAtStackDepth = 0;
   1219         PlatformInstrumentation::setClient(0);
   1220     }
   1221     m_pendingFrameRecord.clear();
   1222     m_recordStack.clear();
   1223     m_id++;
   1224 }
   1225 
   1226 void InspectorTimelineAgent::localToPageQuad(const RenderObject& renderer, const LayoutRect& rect, FloatQuad* quad)
   1227 {
   1228     LocalFrame* frame = renderer.frame();
   1229     FrameView* view = frame->view();
   1230     FloatQuad absolute = renderer.localToAbsoluteQuad(FloatQuad(rect));
   1231     quad->setP1(view->contentsToRootView(roundedIntPoint(absolute.p1())));
   1232     quad->setP2(view->contentsToRootView(roundedIntPoint(absolute.p2())));
   1233     quad->setP3(view->contentsToRootView(roundedIntPoint(absolute.p3())));
   1234     quad->setP4(view->contentsToRootView(roundedIntPoint(absolute.p4())));
   1235 }
   1236 
   1237 long long InspectorTimelineAgent::nodeId(Node* node)
   1238 {
   1239     return node ? InspectorNodeIds::idForNode(node)  : 0;
   1240 }
   1241 
   1242 long long InspectorTimelineAgent::nodeId(RenderObject* renderer)
   1243 {
   1244     return InspectorNodeIds::idForNode(renderer->generatingNode());
   1245 }
   1246 
   1247 double InspectorTimelineAgent::timestamp()
   1248 {
   1249     return WTF::monotonicallyIncreasingTime() * msPerSecond;
   1250 }
   1251 
   1252 LocalFrame* InspectorTimelineAgent::mainFrame() const
   1253 {
   1254     if (!m_pageAgent)
   1255         return 0;
   1256     return m_pageAgent->mainFrame();
   1257 }
   1258 
   1259 PassRefPtr<TimelineEvent> InspectorTimelineAgent::createRecordForEvent(const TraceEventDispatcher::TraceEvent& event, const String& type, PassRefPtr<JSONObject> data)
   1260 {
   1261     double timeestamp = event.timestamp() * msPerSecond;
   1262     return TimelineRecordFactory::createBackgroundRecord(timeestamp, String::number(event.threadIdentifier()), type, data);
   1263 }
   1264 
   1265 void InspectorTimelineAgent::setLiveEvents(const String& liveEvents)
   1266 {
   1267     m_liveEvents.clear();
   1268     if (liveEvents.isNull() || liveEvents.isEmpty())
   1269         return;
   1270     Vector<String> eventList;
   1271     liveEvents.split(",", eventList);
   1272     for (Vector<String>::iterator it = eventList.begin(); it != eventList.end(); ++it)
   1273         m_liveEvents.add(*it);
   1274 }
   1275 
   1276 TimelineRecordStack::TimelineRecordStack(InspectorTimelineAgent* timelineAgent)
   1277     : m_timelineAgent(timelineAgent)
   1278 {
   1279 }
   1280 
   1281 void TimelineRecordStack::addScopedRecord(PassRefPtr<TimelineEvent> record, const String& type)
   1282 {
   1283     m_stack.append(Entry(record, type));
   1284 }
   1285 
   1286 void TimelineRecordStack::closeScopedRecord(double endTime)
   1287 {
   1288     if (m_stack.isEmpty())
   1289         return;
   1290     Entry last = m_stack.last();
   1291     m_stack.removeLast();
   1292     last.record->setEndTime(endTime);
   1293     if (last.children->length())
   1294         last.record->setChildren(last.children);
   1295     addInstantRecord(last.record);
   1296 }
   1297 
   1298 void TimelineRecordStack::addInstantRecord(PassRefPtr<TimelineEvent> record)
   1299 {
   1300     if (m_stack.isEmpty())
   1301         m_timelineAgent->sendEvent(record);
   1302     else
   1303         m_stack.last().children->addItem(record);
   1304 }
   1305 
   1306 #ifndef NDEBUG
   1307 bool TimelineRecordStack::isOpenRecordOfType(const String& type)
   1308 {
   1309     return !m_stack.isEmpty() && m_stack.last().type == type;
   1310 }
   1311 #endif
   1312 
   1313 } // namespace WebCore
   1314 
   1315