1/* 2* Copyright (C) 2013 Google Inc. All rights reserved. 3* Copyright (C) 2014 University of Washington. 4* 5* Redistribution and use in source and binary forms, with or without 6* modification, are permitted provided that the following conditions are 7* met: 8* 9* * Redistributions of source code must retain the above copyright 10* notice, this list of conditions and the following disclaimer. 11* * Redistributions in binary form must reproduce the above 12* copyright notice, this list of conditions and the following disclaimer 13* in the documentation and/or other materials provided with the 14* distribution. 15* * Neither the name of Google Inc. nor the names of its 16* contributors may be used to endorse or promote products derived from 17* this software without specific prior written permission. 18* 19* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30*/ 31 32#include "config.h" 33 34#if ENABLE(INSPECTOR) 35 36#include "InspectorTimelineAgent.h" 37 38#include "Event.h" 39#include "Frame.h" 40#include "FrameView.h" 41#include "InspectorClient.h" 42#include "InspectorInstrumentation.h" 43#include "InspectorPageAgent.h" 44#include "InspectorWebFrontendDispatchers.h" 45#include "InstrumentingAgents.h" 46#include "IntRect.h" 47#include "JSDOMWindow.h" 48#include "PageScriptDebugServer.h" 49#include "RenderElement.h" 50#include "RenderView.h" 51#include "ResourceRequest.h" 52#include "ResourceResponse.h" 53#include "ScriptState.h" 54#include "TimelineRecordFactory.h" 55#include <inspector/IdentifiersFactory.h> 56#include <inspector/ScriptBreakpoint.h> 57#include <profiler/LegacyProfiler.h> 58#include <wtf/CurrentTime.h> 59 60using namespace Inspector; 61 62namespace WebCore { 63 64void TimelineTimeConverter::reset() 65{ 66 m_startOffset = monotonicallyIncreasingTime() - currentTime(); 67} 68 69InspectorTimelineAgent::~InspectorTimelineAgent() 70{ 71} 72 73void InspectorTimelineAgent::didCreateFrontendAndBackend(Inspector::InspectorFrontendChannel* frontendChannel, InspectorBackendDispatcher* backendDispatcher) 74{ 75 m_frontendDispatcher = std::make_unique<InspectorTimelineFrontendDispatcher>(frontendChannel); 76 m_backendDispatcher = InspectorTimelineBackendDispatcher::create(backendDispatcher, this); 77 78 m_instrumentingAgents->setPersistentInspectorTimelineAgent(this); 79 80 if (m_scriptDebugServer) 81 m_scriptDebugServer->recompileAllJSFunctions(); 82} 83 84void InspectorTimelineAgent::willDestroyFrontendAndBackend(InspectorDisconnectReason reason) 85{ 86 m_frontendDispatcher = nullptr; 87 m_backendDispatcher.clear(); 88 89 m_instrumentingAgents->setPersistentInspectorTimelineAgent(nullptr); 90 91 if (reason != InspectorDisconnectReason::InspectedTargetDestroyed) { 92 if (m_scriptDebugServer) 93 m_scriptDebugServer->recompileAllJSFunctions(); 94 } 95 96 ErrorString error; 97 stop(&error); 98} 99 100void InspectorTimelineAgent::start(ErrorString*, const int* maxCallStackDepth) 101{ 102 m_enabledFromFrontend = true; 103 104 internalStart(maxCallStackDepth); 105} 106 107void InspectorTimelineAgent::stop(ErrorString*) 108{ 109 internalStop(); 110 111 m_enabledFromFrontend = false; 112} 113 114void InspectorTimelineAgent::internalStart(const int* maxCallStackDepth) 115{ 116 if (maxCallStackDepth && *maxCallStackDepth > 0) 117 m_maxCallStackDepth = *maxCallStackDepth; 118 else 119 m_maxCallStackDepth = 5; 120 121 m_timeConverter.reset(); 122 123 m_instrumentingAgents->setInspectorTimelineAgent(this); 124 125 if (m_scriptDebugServer) 126 m_scriptDebugServer->addListener(this); 127 128 m_enabled = true; 129 130 if (m_frontendDispatcher) 131 m_frontendDispatcher->recordingStarted(); 132} 133 134void InspectorTimelineAgent::internalStop() 135{ 136 if (!m_enabled) 137 return; 138 139 m_instrumentingAgents->setInspectorTimelineAgent(nullptr); 140 141 if (m_scriptDebugServer) 142 m_scriptDebugServer->removeListener(this, true); 143 144 clearRecordStack(); 145 146 m_enabled = false; 147 148 if (m_frontendDispatcher) 149 m_frontendDispatcher->recordingStopped(); 150} 151 152void InspectorTimelineAgent::setPageScriptDebugServer(PageScriptDebugServer* scriptDebugServer) 153{ 154 ASSERT(!m_enabled); 155 ASSERT(!m_scriptDebugServer); 156 157 m_scriptDebugServer = scriptDebugServer; 158} 159 160static inline void startProfiling(JSC::ExecState* exec, const String& title) 161{ 162 JSC::LegacyProfiler::profiler()->startProfiling(exec, title); 163} 164 165static inline PassRefPtr<JSC::Profile> stopProfiling(JSC::ExecState* exec, const String& title) 166{ 167 return JSC::LegacyProfiler::profiler()->stopProfiling(exec, title); 168} 169 170static inline void startProfiling(Frame* frame, const String& title) 171{ 172 startProfiling(toJSDOMWindow(frame, debuggerWorld())->globalExec(), title); 173} 174 175static inline PassRefPtr<JSC::Profile> stopProfiling(Frame* frame, const String& title) 176{ 177 return stopProfiling(toJSDOMWindow(frame, debuggerWorld())->globalExec(), title); 178} 179 180void InspectorTimelineAgent::startFromConsole(JSC::ExecState* exec, const String &title) 181{ 182 // Only allow recording of a profile if it is anonymous (empty title) or does not match 183 // the title of an already recording profile. 184 if (!title.isEmpty()) { 185 for (const TimelineRecordEntry& record : m_pendingConsoleProfileRecords) { 186 String recordTitle; 187 record.data->getString(ASCIILiteral("title"), &recordTitle); 188 if (recordTitle == title) 189 return; 190 } 191 } 192 193 if (!m_enabled && m_pendingConsoleProfileRecords.isEmpty()) 194 internalStart(); 195 196 startProfiling(exec, title); 197 198 m_pendingConsoleProfileRecords.append(createRecordEntry(TimelineRecordFactory::createConsoleProfileData(title), TimelineRecordType::ConsoleProfile, true, frameFromExecState(exec))); 199} 200 201PassRefPtr<JSC::Profile> InspectorTimelineAgent::stopFromConsole(JSC::ExecState* exec, const String& title) 202{ 203 // Stop profiles in reverse order. If the title is empty, then stop the last profile. 204 // Otherwise, match the title of the profile to stop. 205 for (ptrdiff_t i = m_pendingConsoleProfileRecords.size() - 1; i >= 0; --i) { 206 const TimelineRecordEntry& record = m_pendingConsoleProfileRecords[i]; 207 208 String recordTitle; 209 record.data->getString(ASCIILiteral("title"), &recordTitle); 210 211 if (title.isEmpty() || recordTitle == title) { 212 RefPtr<JSC::Profile> profile = stopProfiling(exec, title); 213 if (profile) 214 TimelineRecordFactory::appendProfile(record.data.get(), profile); 215 216 didCompleteRecordEntry(record); 217 218 m_pendingConsoleProfileRecords.remove(i); 219 220 if (!m_enabledFromFrontend && m_pendingConsoleProfileRecords.isEmpty()) 221 internalStop(); 222 223 return profile.release(); 224 } 225 } 226 227 return nullptr; 228} 229 230void InspectorTimelineAgent::willCallFunction(const String& scriptName, int scriptLine, Frame* frame) 231{ 232 pushCurrentRecord(TimelineRecordFactory::createFunctionCallData(scriptName, scriptLine), TimelineRecordType::FunctionCall, true, frame); 233 234 if (frame && !m_recordingProfileDepth) { 235 ++m_recordingProfileDepth; 236 startProfiling(frame, ASCIILiteral("Timeline FunctionCall")); 237 } 238} 239 240void InspectorTimelineAgent::didCallFunction(Frame* frame) 241{ 242 if (frame && m_recordingProfileDepth) { 243 --m_recordingProfileDepth; 244 ASSERT(m_recordingProfileDepth >= 0); 245 246 if (!m_recordingProfileDepth) { 247 if (m_recordStack.isEmpty()) 248 return; 249 250 TimelineRecordEntry& entry = m_recordStack.last(); 251 ASSERT(entry.type == TimelineRecordType::FunctionCall); 252 253 RefPtr<JSC::Profile> profile = stopProfiling(frame, ASCIILiteral("Timeline FunctionCall")); 254 if (profile) 255 TimelineRecordFactory::appendProfile(entry.data.get(), profile.release()); 256 } 257 } 258 259 didCompleteCurrentRecord(TimelineRecordType::FunctionCall); 260} 261 262void InspectorTimelineAgent::willDispatchEvent(const Event& event, Frame* frame) 263{ 264 pushCurrentRecord(TimelineRecordFactory::createEventDispatchData(event), TimelineRecordType::EventDispatch, false, frame); 265} 266 267void InspectorTimelineAgent::didDispatchEvent() 268{ 269 didCompleteCurrentRecord(TimelineRecordType::EventDispatch); 270} 271 272void InspectorTimelineAgent::didInvalidateLayout(Frame* frame) 273{ 274 appendRecord(InspectorObject::create(), TimelineRecordType::InvalidateLayout, true, frame); 275} 276 277void InspectorTimelineAgent::willLayout(Frame* frame) 278{ 279 RenderObject* root = frame->view()->layoutRoot(); 280 bool partialLayout = !!root; 281 282 if (!partialLayout) 283 root = frame->contentRenderer(); 284 285 unsigned dirtyObjects = 0; 286 unsigned totalObjects = 0; 287 for (RenderObject* o = root; o; o = o->nextInPreOrder(root)) { 288 ++totalObjects; 289 if (o->needsLayout()) 290 ++dirtyObjects; 291 } 292 pushCurrentRecord(TimelineRecordFactory::createLayoutData(dirtyObjects, totalObjects, partialLayout), TimelineRecordType::Layout, true, frame); 293} 294 295void InspectorTimelineAgent::didLayout(RenderObject* root) 296{ 297 if (m_recordStack.isEmpty()) 298 return; 299 TimelineRecordEntry& entry = m_recordStack.last(); 300 ASSERT(entry.type == TimelineRecordType::Layout); 301 Vector<FloatQuad> quads; 302 root->absoluteQuads(quads); 303 if (quads.size() >= 1) 304 TimelineRecordFactory::appendLayoutRoot(entry.data.get(), quads[0]); 305 else 306 ASSERT_NOT_REACHED(); 307 didCompleteCurrentRecord(TimelineRecordType::Layout); 308} 309 310void InspectorTimelineAgent::didScheduleStyleRecalculation(Frame* frame) 311{ 312 appendRecord(InspectorObject::create(), TimelineRecordType::ScheduleStyleRecalculation, true, frame); 313} 314 315void InspectorTimelineAgent::willRecalculateStyle(Frame* frame) 316{ 317 pushCurrentRecord(InspectorObject::create(), TimelineRecordType::RecalculateStyles, true, frame); 318} 319 320void InspectorTimelineAgent::didRecalculateStyle() 321{ 322 didCompleteCurrentRecord(TimelineRecordType::RecalculateStyles); 323} 324 325void InspectorTimelineAgent::willPaint(Frame* frame) 326{ 327 pushCurrentRecord(InspectorObject::create(), TimelineRecordType::Paint, true, frame); 328} 329 330void InspectorTimelineAgent::didPaint(RenderObject* renderer, const LayoutRect& clipRect) 331{ 332 TimelineRecordEntry& entry = m_recordStack.last(); 333 ASSERT(entry.type == TimelineRecordType::Paint); 334 FloatQuad quad; 335 localToPageQuad(*renderer, clipRect, &quad); 336 entry.data = TimelineRecordFactory::createPaintData(quad); 337 didCompleteCurrentRecord(TimelineRecordType::Paint); 338} 339 340void InspectorTimelineAgent::willScroll(Frame* frame) 341{ 342 pushCurrentRecord(InspectorObject::create(), TimelineRecordType::ScrollLayer, false, frame); 343} 344 345void InspectorTimelineAgent::didScroll() 346{ 347 didCompleteCurrentRecord(TimelineRecordType::ScrollLayer); 348} 349 350void InspectorTimelineAgent::willWriteHTML(unsigned startLine, Frame* frame) 351{ 352 pushCurrentRecord(TimelineRecordFactory::createParseHTMLData(startLine), TimelineRecordType::ParseHTML, true, frame); 353} 354 355void InspectorTimelineAgent::didWriteHTML(unsigned endLine) 356{ 357 if (!m_recordStack.isEmpty()) { 358 const TimelineRecordEntry& entry = m_recordStack.last(); 359 entry.data->setNumber("endLine", endLine); 360 didCompleteCurrentRecord(TimelineRecordType::ParseHTML); 361 } 362} 363 364void InspectorTimelineAgent::didInstallTimer(int timerId, int timeout, bool singleShot, Frame* frame) 365{ 366 appendRecord(TimelineRecordFactory::createTimerInstallData(timerId, timeout, singleShot), TimelineRecordType::TimerInstall, true, frame); 367} 368 369void InspectorTimelineAgent::didRemoveTimer(int timerId, Frame* frame) 370{ 371 appendRecord(TimelineRecordFactory::createGenericTimerData(timerId), TimelineRecordType::TimerRemove, true, frame); 372} 373 374void InspectorTimelineAgent::willFireTimer(int timerId, Frame* frame) 375{ 376 pushCurrentRecord(TimelineRecordFactory::createGenericTimerData(timerId), TimelineRecordType::TimerFire, false, frame); 377} 378 379void InspectorTimelineAgent::didFireTimer() 380{ 381 didCompleteCurrentRecord(TimelineRecordType::TimerFire); 382} 383 384void InspectorTimelineAgent::willDispatchXHRReadyStateChangeEvent(const String& url, int readyState, Frame* frame) 385{ 386 pushCurrentRecord(TimelineRecordFactory::createXHRReadyStateChangeData(url, readyState), TimelineRecordType::XHRReadyStateChange, false, frame); 387} 388 389void InspectorTimelineAgent::didDispatchXHRReadyStateChangeEvent() 390{ 391 didCompleteCurrentRecord(TimelineRecordType::XHRReadyStateChange); 392} 393 394void InspectorTimelineAgent::willDispatchXHRLoadEvent(const String& url, Frame* frame) 395{ 396 pushCurrentRecord(TimelineRecordFactory::createXHRLoadData(url), TimelineRecordType::XHRLoad, true, frame); 397} 398 399void InspectorTimelineAgent::didDispatchXHRLoadEvent() 400{ 401 didCompleteCurrentRecord(TimelineRecordType::XHRLoad); 402} 403 404void InspectorTimelineAgent::willEvaluateScript(const String& url, int lineNumber, Frame* frame) 405{ 406 pushCurrentRecord(TimelineRecordFactory::createEvaluateScriptData(url, lineNumber), TimelineRecordType::EvaluateScript, true, frame); 407 408 if (frame && !m_recordingProfileDepth) { 409 ++m_recordingProfileDepth; 410 startProfiling(frame, ASCIILiteral("Timeline EvaluateScript")); 411 } 412} 413 414void InspectorTimelineAgent::didEvaluateScript(Frame* frame) 415{ 416 if (frame && m_recordingProfileDepth) { 417 --m_recordingProfileDepth; 418 ASSERT(m_recordingProfileDepth >= 0); 419 420 if (!m_recordingProfileDepth) { 421 if (m_recordStack.isEmpty()) 422 return; 423 424 TimelineRecordEntry& entry = m_recordStack.last(); 425 ASSERT(entry.type == TimelineRecordType::EvaluateScript); 426 427 RefPtr<JSC::Profile> profile = stopProfiling(frame, ASCIILiteral("Timeline EvaluateScript")); 428 if (profile) 429 TimelineRecordFactory::appendProfile(entry.data.get(), profile.release()); 430 } 431 } 432 433 didCompleteCurrentRecord(TimelineRecordType::EvaluateScript); 434} 435 436void InspectorTimelineAgent::didScheduleResourceRequest(const String& url, Frame* frame) 437{ 438 appendRecord(TimelineRecordFactory::createScheduleResourceRequestData(url), TimelineRecordType::ScheduleResourceRequest, true, frame); 439} 440 441void InspectorTimelineAgent::willSendResourceRequest(unsigned long identifier, const ResourceRequest& request, Frame* frame) 442{ 443 String requestId = IdentifiersFactory::requestId(identifier); 444 appendRecord(TimelineRecordFactory::createResourceSendRequestData(requestId, request), TimelineRecordType::ResourceSendRequest, true, frame); 445} 446 447void InspectorTimelineAgent::willReceiveResourceData(unsigned long identifier, Frame* frame, int length) 448{ 449 String requestId = IdentifiersFactory::requestId(identifier); 450 pushCurrentRecord(TimelineRecordFactory::createReceiveResourceData(requestId, length), TimelineRecordType::ResourceReceivedData, false, frame); 451} 452 453void InspectorTimelineAgent::didReceiveResourceData() 454{ 455 didCompleteCurrentRecord(TimelineRecordType::ResourceReceivedData); 456} 457 458void InspectorTimelineAgent::willReceiveResourceResponse(unsigned long identifier, const ResourceResponse& response, Frame* frame) 459{ 460 String requestId = IdentifiersFactory::requestId(identifier); 461 pushCurrentRecord(TimelineRecordFactory::createResourceReceiveResponseData(requestId, response), TimelineRecordType::ResourceReceiveResponse, false, frame); 462} 463 464void InspectorTimelineAgent::didReceiveResourceResponse() 465{ 466 didCompleteCurrentRecord(TimelineRecordType::ResourceReceiveResponse); 467} 468 469void InspectorTimelineAgent::didFinishLoadingResource(unsigned long identifier, bool didFail, double finishTime, Frame* frame) 470{ 471 appendRecord(TimelineRecordFactory::createResourceFinishData(IdentifiersFactory::requestId(identifier), didFail, finishTime * 1000), TimelineRecordType::ResourceFinish, false, frame); 472} 473 474void InspectorTimelineAgent::didTimeStamp(Frame* frame, const String& message) 475{ 476 appendRecord(TimelineRecordFactory::createTimeStampData(message), TimelineRecordType::TimeStamp, true, frame); 477} 478 479void InspectorTimelineAgent::time(Frame* frame, const String& message) 480{ 481 appendRecord(TimelineRecordFactory::createTimeStampData(message), TimelineRecordType::Time, true, frame); 482} 483 484void InspectorTimelineAgent::timeEnd(Frame* frame, const String& message) 485{ 486 appendRecord(TimelineRecordFactory::createTimeStampData(message), TimelineRecordType::TimeEnd, true, frame); 487} 488 489void InspectorTimelineAgent::didMarkDOMContentEvent(Frame* frame) 490{ 491 bool isMainFrame = frame && m_pageAgent && (frame == m_pageAgent->mainFrame()); 492 appendRecord(TimelineRecordFactory::createMarkData(isMainFrame), TimelineRecordType::MarkDOMContent, false, frame); 493} 494 495void InspectorTimelineAgent::didMarkLoadEvent(Frame* frame) 496{ 497 bool isMainFrame = frame && m_pageAgent && (frame == m_pageAgent->mainFrame()); 498 appendRecord(TimelineRecordFactory::createMarkData(isMainFrame), TimelineRecordType::MarkLoad, false, frame); 499} 500 501void InspectorTimelineAgent::didCommitLoad() 502{ 503 clearRecordStack(); 504} 505 506void InspectorTimelineAgent::didRequestAnimationFrame(int callbackId, Frame* frame) 507{ 508 appendRecord(TimelineRecordFactory::createAnimationFrameData(callbackId), TimelineRecordType::RequestAnimationFrame, true, frame); 509} 510 511void InspectorTimelineAgent::didCancelAnimationFrame(int callbackId, Frame* frame) 512{ 513 appendRecord(TimelineRecordFactory::createAnimationFrameData(callbackId), TimelineRecordType::CancelAnimationFrame, true, frame); 514} 515 516void InspectorTimelineAgent::willFireAnimationFrame(int callbackId, Frame* frame) 517{ 518 pushCurrentRecord(TimelineRecordFactory::createAnimationFrameData(callbackId), TimelineRecordType::FireAnimationFrame, false, frame); 519} 520 521void InspectorTimelineAgent::didFireAnimationFrame() 522{ 523 didCompleteCurrentRecord(TimelineRecordType::FireAnimationFrame); 524} 525 526#if ENABLE(WEB_SOCKETS) 527void InspectorTimelineAgent::didCreateWebSocket(unsigned long identifier, const URL& url, const String& protocol, Frame* frame) 528{ 529 appendRecord(TimelineRecordFactory::createWebSocketCreateData(identifier, url, protocol), TimelineRecordType::WebSocketCreate, true, frame); 530} 531 532void InspectorTimelineAgent::willSendWebSocketHandshakeRequest(unsigned long identifier, Frame* frame) 533{ 534 appendRecord(TimelineRecordFactory::createGenericWebSocketData(identifier), TimelineRecordType::WebSocketSendHandshakeRequest, true, frame); 535} 536 537void InspectorTimelineAgent::didReceiveWebSocketHandshakeResponse(unsigned long identifier, Frame* frame) 538{ 539 appendRecord(TimelineRecordFactory::createGenericWebSocketData(identifier), TimelineRecordType::WebSocketReceiveHandshakeResponse, false, frame); 540} 541 542void InspectorTimelineAgent::didDestroyWebSocket(unsigned long identifier, Frame* frame) 543{ 544 appendRecord(TimelineRecordFactory::createGenericWebSocketData(identifier), TimelineRecordType::WebSocketDestroy, true, frame); 545} 546#endif // ENABLE(WEB_SOCKETS) 547 548// ScriptDebugListener 549 550void InspectorTimelineAgent::breakpointActionProbe(JSC::ExecState* exec, const Inspector::ScriptBreakpointAction& action, int hitCount, const Deprecated::ScriptValue&) 551{ 552 ASSERT(exec); 553 554 appendRecord(TimelineRecordFactory::createProbeSampleData(action, hitCount), TimelineRecordType::ProbeSample, false, frameFromExecState(exec)); 555} 556 557static Inspector::TypeBuilder::Timeline::EventType::Enum toProtocol(TimelineRecordType type) 558{ 559 switch (type) { 560 case TimelineRecordType::EventDispatch: 561 return Inspector::TypeBuilder::Timeline::EventType::EventDispatch; 562 case TimelineRecordType::ScheduleStyleRecalculation: 563 return Inspector::TypeBuilder::Timeline::EventType::ScheduleStyleRecalculation; 564 case TimelineRecordType::RecalculateStyles: 565 return Inspector::TypeBuilder::Timeline::EventType::RecalculateStyles; 566 case TimelineRecordType::InvalidateLayout: 567 return Inspector::TypeBuilder::Timeline::EventType::InvalidateLayout; 568 case TimelineRecordType::Layout: 569 return Inspector::TypeBuilder::Timeline::EventType::Layout; 570 case TimelineRecordType::Paint: 571 return Inspector::TypeBuilder::Timeline::EventType::Paint; 572 case TimelineRecordType::ScrollLayer: 573 return Inspector::TypeBuilder::Timeline::EventType::ScrollLayer; 574 case TimelineRecordType::ResizeImage: 575 return Inspector::TypeBuilder::Timeline::EventType::ResizeImage; 576 577 case TimelineRecordType::ParseHTML: 578 return Inspector::TypeBuilder::Timeline::EventType::ParseHTML; 579 580 case TimelineRecordType::TimerInstall: 581 return Inspector::TypeBuilder::Timeline::EventType::TimerInstall; 582 case TimelineRecordType::TimerRemove: 583 return Inspector::TypeBuilder::Timeline::EventType::TimerRemove; 584 case TimelineRecordType::TimerFire: 585 return Inspector::TypeBuilder::Timeline::EventType::TimerFire; 586 587 case TimelineRecordType::EvaluateScript: 588 return Inspector::TypeBuilder::Timeline::EventType::EvaluateScript; 589 590 case TimelineRecordType::MarkLoad: 591 return Inspector::TypeBuilder::Timeline::EventType::MarkLoad; 592 case TimelineRecordType::MarkDOMContent: 593 return Inspector::TypeBuilder::Timeline::EventType::MarkDOMContent; 594 595 case TimelineRecordType::TimeStamp: 596 return Inspector::TypeBuilder::Timeline::EventType::TimeStamp; 597 case TimelineRecordType::Time: 598 return Inspector::TypeBuilder::Timeline::EventType::Time; 599 case TimelineRecordType::TimeEnd: 600 return Inspector::TypeBuilder::Timeline::EventType::TimeEnd; 601 602 case TimelineRecordType::ScheduleResourceRequest: 603 return Inspector::TypeBuilder::Timeline::EventType::ScheduleResourceRequest; 604 case TimelineRecordType::ResourceSendRequest: 605 return Inspector::TypeBuilder::Timeline::EventType::ResourceSendRequest; 606 case TimelineRecordType::ResourceReceiveResponse: 607 return Inspector::TypeBuilder::Timeline::EventType::ResourceReceiveResponse; 608 case TimelineRecordType::ResourceReceivedData: 609 return Inspector::TypeBuilder::Timeline::EventType::ResourceReceivedData; 610 case TimelineRecordType::ResourceFinish: 611 return Inspector::TypeBuilder::Timeline::EventType::ResourceFinish; 612 613 case TimelineRecordType::XHRReadyStateChange: 614 return Inspector::TypeBuilder::Timeline::EventType::XHRReadyStateChange; 615 case TimelineRecordType::XHRLoad: 616 return Inspector::TypeBuilder::Timeline::EventType::XHRLoad; 617 618 case TimelineRecordType::FunctionCall: 619 return Inspector::TypeBuilder::Timeline::EventType::FunctionCall; 620 case TimelineRecordType::ProbeSample: 621 return Inspector::TypeBuilder::Timeline::EventType::ProbeSample; 622 case TimelineRecordType::ConsoleProfile: 623 return Inspector::TypeBuilder::Timeline::EventType::ConsoleProfile; 624 625 case TimelineRecordType::RequestAnimationFrame: 626 return Inspector::TypeBuilder::Timeline::EventType::RequestAnimationFrame; 627 case TimelineRecordType::CancelAnimationFrame: 628 return Inspector::TypeBuilder::Timeline::EventType::CancelAnimationFrame; 629 case TimelineRecordType::FireAnimationFrame: 630 return Inspector::TypeBuilder::Timeline::EventType::FireAnimationFrame; 631 632 case TimelineRecordType::WebSocketCreate: 633 return Inspector::TypeBuilder::Timeline::EventType::WebSocketCreate; 634 case TimelineRecordType::WebSocketSendHandshakeRequest: 635 return Inspector::TypeBuilder::Timeline::EventType::WebSocketSendHandshakeRequest; 636 case TimelineRecordType::WebSocketReceiveHandshakeResponse: 637 return Inspector::TypeBuilder::Timeline::EventType::WebSocketReceiveHandshakeResponse; 638 case TimelineRecordType::WebSocketDestroy: 639 return Inspector::TypeBuilder::Timeline::EventType::WebSocketDestroy; 640 } 641 642 return Inspector::TypeBuilder::Timeline::EventType::TimeStamp; 643} 644 645void InspectorTimelineAgent::addRecordToTimeline(PassRefPtr<InspectorObject> prpRecord, TimelineRecordType type) 646{ 647 prpRecord->setString("type", Inspector::TypeBuilder::getWebEnumConstantValue(toProtocol(type))); 648 649 RefPtr<Inspector::TypeBuilder::Timeline::TimelineEvent> record = Inspector::TypeBuilder::Timeline::TimelineEvent::runtimeCast(prpRecord); 650 651 if (m_recordStack.isEmpty()) 652 sendEvent(record.release()); 653 else { 654 const TimelineRecordEntry& parent = m_recordStack.last(); 655 parent.children->pushObject(record.release()); 656 } 657} 658 659void InspectorTimelineAgent::setFrameIdentifier(InspectorObject* record, Frame* frame) 660{ 661 if (!frame || !m_pageAgent) 662 return; 663 String frameId; 664 if (frame && m_pageAgent) 665 frameId = m_pageAgent->frameId(frame); 666 record->setString("frameId", frameId); 667} 668 669void InspectorTimelineAgent::didCompleteRecordEntry(const TimelineRecordEntry& entry) 670{ 671 entry.record->setObject(ASCIILiteral("data"), entry.data); 672 entry.record->setArray(ASCIILiteral("children"), entry.children); 673 entry.record->setNumber(ASCIILiteral("endTime"), timestamp()); 674 addRecordToTimeline(entry.record, entry.type); 675} 676 677void InspectorTimelineAgent::didCompleteCurrentRecord(TimelineRecordType type) 678{ 679 // An empty stack could merely mean that the timeline agent was turned on in the middle of 680 // an event. Don't treat as an error. 681 if (!m_recordStack.isEmpty()) { 682 TimelineRecordEntry entry = m_recordStack.last(); 683 m_recordStack.removeLast(); 684 ASSERT_UNUSED(type, entry.type == type); 685 didCompleteRecordEntry(entry); 686 } 687} 688 689InspectorTimelineAgent::InspectorTimelineAgent(InstrumentingAgents* instrumentingAgents, InspectorPageAgent* pageAgent, InspectorType type, InspectorClient* client) 690 : InspectorAgentBase(ASCIILiteral("Timeline"), instrumentingAgents) 691 , m_pageAgent(pageAgent) 692 , m_scriptDebugServer(nullptr) 693 , m_id(1) 694 , m_maxCallStackDepth(5) 695 , m_inspectorType(type) 696 , m_client(client) 697 , m_recordingProfileDepth(0) 698 , m_enabled(false) 699 , m_enabledFromFrontend(false) 700{ 701} 702 703void InspectorTimelineAgent::appendRecord(PassRefPtr<InspectorObject> data, TimelineRecordType type, bool captureCallStack, Frame* frame) 704{ 705 RefPtr<InspectorObject> record = TimelineRecordFactory::createGenericRecord(timestamp(), captureCallStack ? m_maxCallStackDepth : 0); 706 record->setObject("data", data); 707 setFrameIdentifier(record.get(), frame); 708 addRecordToTimeline(record.release(), type); 709} 710 711void InspectorTimelineAgent::sendEvent(PassRefPtr<InspectorObject> event) 712{ 713 if (!m_frontendDispatcher) 714 return; 715 716 // FIXME: runtimeCast is a hack. We do it because we can't build TimelineEvent directly now. 717 RefPtr<Inspector::TypeBuilder::Timeline::TimelineEvent> recordChecked = Inspector::TypeBuilder::Timeline::TimelineEvent::runtimeCast(event); 718 m_frontendDispatcher->eventRecorded(recordChecked.release()); 719} 720 721InspectorTimelineAgent::TimelineRecordEntry InspectorTimelineAgent::createRecordEntry(PassRefPtr<InspectorObject> data, TimelineRecordType type, bool captureCallStack, Frame* frame) 722{ 723 RefPtr<InspectorObject> record = TimelineRecordFactory::createGenericRecord(timestamp(), captureCallStack ? m_maxCallStackDepth : 0); 724 setFrameIdentifier(record.get(), frame); 725 return TimelineRecordEntry(record.release(), data, InspectorArray::create(), type); 726} 727 728void InspectorTimelineAgent::pushCurrentRecord(PassRefPtr<InspectorObject> data, TimelineRecordType type, bool captureCallStack, Frame* frame) 729{ 730 pushCurrentRecord(createRecordEntry(data, type, captureCallStack, frame)); 731} 732 733void InspectorTimelineAgent::clearRecordStack() 734{ 735 m_recordStack.clear(); 736 m_id++; 737} 738 739void InspectorTimelineAgent::localToPageQuad(const RenderObject& renderer, const LayoutRect& rect, FloatQuad* quad) 740{ 741 const FrameView& frameView = renderer.view().frameView(); 742 FloatQuad absolute = renderer.localToAbsoluteQuad(FloatQuad(rect)); 743 quad->setP1(frameView.contentsToRootView(roundedIntPoint(absolute.p1()))); 744 quad->setP2(frameView.contentsToRootView(roundedIntPoint(absolute.p2()))); 745 quad->setP3(frameView.contentsToRootView(roundedIntPoint(absolute.p3()))); 746 quad->setP4(frameView.contentsToRootView(roundedIntPoint(absolute.p4()))); 747} 748 749double InspectorTimelineAgent::timestamp() 750{ 751 return m_timeConverter.fromMonotonicallyIncreasingTime(monotonicallyIncreasingTime()); 752} 753 754Page* InspectorTimelineAgent::page() 755{ 756 return m_pageAgent ? m_pageAgent->page() : nullptr; 757} 758 759} // namespace WebCore 760 761#endif // ENABLE(INSPECTOR) 762