1 /* 2 * Copyright (C) 2010-2011 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 "web/WebDevToolsAgentImpl.h" 33 34 #include "bindings/core/v8/PageScriptDebugServer.h" 35 #include "bindings/core/v8/ScriptController.h" 36 #include "bindings/core/v8/V8Binding.h" 37 #include "core/InspectorBackendDispatcher.h" 38 #include "core/InspectorFrontend.h" 39 #include "core/dom/ExceptionCode.h" 40 #include "core/fetch/MemoryCache.h" 41 #include "core/frame/FrameView.h" 42 #include "core/frame/LocalFrame.h" 43 #include "core/frame/Settings.h" 44 #include "core/inspector/InjectedScriptHost.h" 45 #include "core/inspector/InspectorController.h" 46 #include "core/page/FocusController.h" 47 #include "core/page/Page.h" 48 #include "core/rendering/RenderView.h" 49 #include "platform/JSONValues.h" 50 #include "platform/RuntimeEnabledFeatures.h" 51 #include "platform/TraceEvent.h" 52 #include "platform/graphics/GraphicsContext.h" 53 #include "platform/network/ResourceError.h" 54 #include "platform/network/ResourceRequest.h" 55 #include "platform/network/ResourceResponse.h" 56 #include "public/platform/Platform.h" 57 #include "public/platform/WebRect.h" 58 #include "public/platform/WebString.h" 59 #include "public/platform/WebURL.h" 60 #include "public/platform/WebURLError.h" 61 #include "public/platform/WebURLRequest.h" 62 #include "public/platform/WebURLResponse.h" 63 #include "public/web/WebDataSource.h" 64 #include "public/web/WebDevToolsAgentClient.h" 65 #include "public/web/WebDeviceEmulationParams.h" 66 #include "public/web/WebMemoryUsageInfo.h" 67 #include "public/web/WebSettings.h" 68 #include "public/web/WebViewClient.h" 69 #include "web/WebInputEventConversion.h" 70 #include "web/WebLocalFrameImpl.h" 71 #include "web/WebViewImpl.h" 72 #include "wtf/CurrentTime.h" 73 #include "wtf/MathExtras.h" 74 #include "wtf/Noncopyable.h" 75 #include "wtf/ProcessID.h" 76 #include "wtf/text/WTFString.h" 77 78 namespace OverlayZOrders { 79 // Use 99 as a big z-order number so that highlight is above other overlays. 80 static const int highlight = 99; 81 } 82 83 namespace blink { 84 85 static int s_nextDebuggerId = 1; 86 87 class ClientMessageLoopAdapter : public PageScriptDebugServer::ClientMessageLoop { 88 public: 89 static void ensureClientMessageLoopCreated(WebDevToolsAgentClient* client) 90 { 91 if (s_instance) 92 return; 93 OwnPtr<ClientMessageLoopAdapter> instance = adoptPtr(new ClientMessageLoopAdapter(adoptPtr(client->createClientMessageLoop()))); 94 s_instance = instance.get(); 95 PageScriptDebugServer::shared().setClientMessageLoop(instance.release()); 96 } 97 98 static void inspectedViewClosed(WebViewImpl* view) 99 { 100 if (s_instance) 101 s_instance->m_frozenViews.remove(view); 102 } 103 104 static void didNavigate() 105 { 106 // Release render thread if necessary. 107 if (s_instance && s_instance->m_running) 108 PageScriptDebugServer::shared().continueProgram(); 109 } 110 111 private: 112 ClientMessageLoopAdapter(PassOwnPtr<WebDevToolsAgentClient::WebKitClientMessageLoop> messageLoop) 113 : m_running(false) 114 , m_messageLoop(messageLoop) { } 115 116 117 virtual void run(Page* page) 118 { 119 if (m_running) 120 return; 121 m_running = true; 122 123 // 0. Flush pending frontend messages. 124 WebViewImpl* viewImpl = WebViewImpl::fromPage(page); 125 WebDevToolsAgentImpl* agent = static_cast<WebDevToolsAgentImpl*>(viewImpl->devToolsAgent()); 126 agent->flushPendingFrontendMessages(); 127 128 Vector<WebViewImpl*> views; 129 130 // 1. Disable input events. 131 const HashSet<Page*>& pages = Page::ordinaryPages(); 132 HashSet<Page*>::const_iterator end = pages.end(); 133 for (HashSet<Page*>::const_iterator it = pages.begin(); it != end; ++it) { 134 WebViewImpl* view = WebViewImpl::fromPage(*it); 135 if (!view) 136 continue; 137 m_frozenViews.add(view); 138 views.append(view); 139 view->setIgnoreInputEvents(true); 140 } 141 // Notify embedder about pausing. 142 agent->client()->willEnterDebugLoop(); 143 144 // 2. Disable active objects 145 WebView::willEnterModalLoop(); 146 147 // 3. Process messages until quitNow is called. 148 m_messageLoop->run(); 149 150 // 4. Resume active objects 151 WebView::didExitModalLoop(); 152 153 // 5. Resume input events. 154 for (Vector<WebViewImpl*>::iterator it = views.begin(); it != views.end(); ++it) { 155 if (m_frozenViews.contains(*it)) { 156 // The view was not closed during the dispatch. 157 (*it)->setIgnoreInputEvents(false); 158 } 159 } 160 agent->client()->didExitDebugLoop(); 161 162 // 6. All views have been resumed, clear the set. 163 m_frozenViews.clear(); 164 165 m_running = false; 166 } 167 168 virtual void quitNow() 169 { 170 m_messageLoop->quitNow(); 171 } 172 173 bool m_running; 174 OwnPtr<WebDevToolsAgentClient::WebKitClientMessageLoop> m_messageLoop; 175 typedef HashSet<WebViewImpl*> FrozenViewsSet; 176 FrozenViewsSet m_frozenViews; 177 // FIXME: The ownership model for s_instance is somewhat complicated. Can we make this simpler? 178 static ClientMessageLoopAdapter* s_instance; 179 }; 180 181 ClientMessageLoopAdapter* ClientMessageLoopAdapter::s_instance = 0; 182 183 class DebuggerTask : public PageScriptDebugServer::Task { 184 public: 185 DebuggerTask(PassOwnPtr<WebDevToolsAgent::MessageDescriptor> descriptor) 186 : m_descriptor(descriptor) 187 { 188 } 189 190 virtual ~DebuggerTask() { } 191 virtual void run() 192 { 193 if (WebDevToolsAgent* webagent = m_descriptor->agent()) 194 webagent->dispatchOnInspectorBackend(m_descriptor->message()); 195 } 196 197 private: 198 OwnPtr<WebDevToolsAgent::MessageDescriptor> m_descriptor; 199 }; 200 201 WebDevToolsAgentImpl::WebDevToolsAgentImpl( 202 WebViewImpl* webViewImpl, 203 WebDevToolsAgentClient* client) 204 : m_debuggerId(s_nextDebuggerId++) 205 , m_layerTreeId(0) 206 , m_client(client) 207 , m_webViewImpl(webViewImpl) 208 , m_attached(false) 209 , m_generatingEvent(false) 210 , m_webViewDidLayoutOnceAfterLoad(false) 211 , m_deviceMetricsEnabled(false) 212 , m_emulateMobileEnabled(false) 213 , m_originalViewportEnabled(false) 214 , m_isOverlayScrollbarsEnabled(false) 215 , m_originalMinimumPageScaleFactor(0) 216 , m_originalMaximumPageScaleFactor(0) 217 , m_pageScaleLimitsOverriden(false) 218 , m_touchEventEmulationEnabled(false) 219 { 220 ASSERT(isMainThread()); 221 222 long processId = WTF::getCurrentProcessID(); 223 ASSERT(processId > 0); 224 inspectorController()->setProcessId(processId); 225 226 ASSERT(m_debuggerId > 0); 227 ClientMessageLoopAdapter::ensureClientMessageLoopCreated(m_client); 228 } 229 230 WebDevToolsAgentImpl::~WebDevToolsAgentImpl() 231 { 232 ClientMessageLoopAdapter::inspectedViewClosed(m_webViewImpl); 233 if (m_attached) 234 Platform::current()->currentThread()->removeTaskObserver(this); 235 } 236 237 void WebDevToolsAgentImpl::attach(const WebString& hostId) 238 { 239 if (m_attached) 240 return; 241 242 inspectorController()->connectFrontend(hostId, this); 243 Platform::current()->currentThread()->addTaskObserver(this); 244 m_attached = true; 245 } 246 247 void WebDevToolsAgentImpl::reattach(const WebString& hostId, const WebString& savedState) 248 { 249 if (m_attached) 250 return; 251 252 inspectorController()->reuseFrontend(hostId, this, savedState); 253 Platform::current()->currentThread()->addTaskObserver(this); 254 m_attached = true; 255 } 256 257 void WebDevToolsAgentImpl::detach() 258 { 259 Platform::current()->currentThread()->removeTaskObserver(this); 260 261 // Prevent controller from sending messages to the frontend. 262 InspectorController* ic = inspectorController(); 263 ic->disconnectFrontend(); 264 m_attached = false; 265 } 266 267 void WebDevToolsAgentImpl::continueProgram() 268 { 269 ClientMessageLoopAdapter::didNavigate(); 270 } 271 272 void WebDevToolsAgentImpl::didBeginFrame(int frameId) 273 { 274 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "BeginMainThreadFrame", "layerTreeId", m_layerTreeId); 275 if (InspectorController* ic = inspectorController()) 276 ic->didBeginFrame(frameId); 277 } 278 279 void WebDevToolsAgentImpl::didCancelFrame() 280 { 281 if (InspectorController* ic = inspectorController()) 282 ic->didCancelFrame(); 283 } 284 285 void WebDevToolsAgentImpl::willComposite() 286 { 287 TRACE_EVENT_BEGIN1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "CompositeLayers", "layerTreeId", m_layerTreeId); 288 if (InspectorController* ic = inspectorController()) 289 ic->willComposite(); 290 } 291 292 void WebDevToolsAgentImpl::didComposite() 293 { 294 TRACE_EVENT_END0(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "CompositeLayers"); 295 if (InspectorController* ic = inspectorController()) 296 ic->didComposite(); 297 } 298 299 void WebDevToolsAgentImpl::didCreateScriptContext(WebLocalFrameImpl* webframe, int worldId) 300 { 301 if (LocalFrame* frame = webframe->frame()) 302 frame->script().setWorldDebugId(worldId, m_debuggerId); 303 // Skip non main world contexts. 304 if (worldId) 305 return; 306 m_webViewDidLayoutOnceAfterLoad = false; 307 } 308 309 bool WebDevToolsAgentImpl::handleInputEvent(Page* page, const WebInputEvent& inputEvent) 310 { 311 if (!m_attached && !m_generatingEvent) 312 return false; 313 314 // FIXME: This workaround is required for touch emulation on Mac, where 315 // compositor-side pinch handling is not enabled. See http://crbug.com/138003. 316 bool isPinch = inputEvent.type == WebInputEvent::GesturePinchBegin || inputEvent.type == WebInputEvent::GesturePinchUpdate || inputEvent.type == WebInputEvent::GesturePinchEnd; 317 if (isPinch && m_touchEventEmulationEnabled) { 318 FrameView* frameView = page->deprecatedLocalMainFrame()->view(); 319 PlatformGestureEventBuilder gestureEvent(frameView, static_cast<const WebGestureEvent&>(inputEvent)); 320 float pageScaleFactor = page->pageScaleFactor(); 321 if (gestureEvent.type() == PlatformEvent::GesturePinchBegin) { 322 m_lastPinchAnchorCss = adoptPtr(new IntPoint(frameView->scrollPosition() + gestureEvent.position())); 323 m_lastPinchAnchorDip = adoptPtr(new IntPoint(gestureEvent.position())); 324 m_lastPinchAnchorDip->scale(pageScaleFactor, pageScaleFactor); 325 } 326 if (gestureEvent.type() == PlatformEvent::GesturePinchUpdate && m_lastPinchAnchorCss) { 327 float newPageScaleFactor = pageScaleFactor * gestureEvent.scale(); 328 IntPoint anchorCss(*m_lastPinchAnchorDip.get()); 329 anchorCss.scale(1.f / newPageScaleFactor, 1.f / newPageScaleFactor); 330 m_webViewImpl->setPageScaleFactor(newPageScaleFactor); 331 m_webViewImpl->setMainFrameScrollOffset(*m_lastPinchAnchorCss.get() - toIntSize(anchorCss)); 332 } 333 if (gestureEvent.type() == PlatformEvent::GesturePinchEnd) { 334 m_lastPinchAnchorCss.clear(); 335 m_lastPinchAnchorDip.clear(); 336 } 337 return true; 338 } 339 340 InspectorController* ic = inspectorController(); 341 if (!ic) 342 return false; 343 344 if (WebInputEvent::isGestureEventType(inputEvent.type) && inputEvent.type == WebInputEvent::GestureTap) { 345 // Only let GestureTab in (we only need it and we know PlatformGestureEventBuilder supports it). 346 PlatformGestureEvent gestureEvent = PlatformGestureEventBuilder(page->deprecatedLocalMainFrame()->view(), static_cast<const WebGestureEvent&>(inputEvent)); 347 return ic->handleGestureEvent(toLocalFrame(page->mainFrame()), gestureEvent); 348 } 349 if (WebInputEvent::isMouseEventType(inputEvent.type) && inputEvent.type != WebInputEvent::MouseEnter) { 350 // PlatformMouseEventBuilder does not work with MouseEnter type, so we filter it out manually. 351 PlatformMouseEvent mouseEvent = PlatformMouseEventBuilder(page->deprecatedLocalMainFrame()->view(), static_cast<const WebMouseEvent&>(inputEvent)); 352 return ic->handleMouseEvent(toLocalFrame(page->mainFrame()), mouseEvent); 353 } 354 if (WebInputEvent::isTouchEventType(inputEvent.type)) { 355 PlatformTouchEvent touchEvent = PlatformTouchEventBuilder(page->deprecatedLocalMainFrame()->view(), static_cast<const WebTouchEvent&>(inputEvent)); 356 return ic->handleTouchEvent(toLocalFrame(page->mainFrame()), touchEvent); 357 } 358 if (WebInputEvent::isKeyboardEventType(inputEvent.type)) { 359 PlatformKeyboardEvent keyboardEvent = PlatformKeyboardEventBuilder(static_cast<const WebKeyboardEvent&>(inputEvent)); 360 return ic->handleKeyboardEvent(page->deprecatedLocalMainFrame(), keyboardEvent); 361 } 362 return false; 363 } 364 365 void WebDevToolsAgentImpl::didLayout() 366 { 367 m_webViewDidLayoutOnceAfterLoad = true; 368 } 369 370 void WebDevToolsAgentImpl::setDeviceMetricsOverride(int width, int height, float deviceScaleFactor, bool mobile, bool fitWindow, float scale, float offsetX, float offsetY) 371 { 372 if (!m_deviceMetricsEnabled) { 373 m_deviceMetricsEnabled = true; 374 m_webViewImpl->setBackgroundColorOverride(Color::darkGray); 375 } 376 if (mobile) 377 enableMobileEmulation(); 378 else 379 disableMobileEmulation(); 380 381 WebDeviceEmulationParams params; 382 params.screenPosition = mobile ? WebDeviceEmulationParams::Mobile : WebDeviceEmulationParams::Desktop; 383 params.deviceScaleFactor = deviceScaleFactor; 384 params.viewSize = WebSize(width, height); 385 params.fitToView = fitWindow; 386 params.scale = scale; 387 params.offset = WebFloatPoint(offsetX, offsetY); 388 m_client->enableDeviceEmulation(params); 389 } 390 391 void WebDevToolsAgentImpl::clearDeviceMetricsOverride() 392 { 393 if (m_deviceMetricsEnabled) { 394 m_deviceMetricsEnabled = false; 395 m_webViewImpl->setBackgroundColorOverride(Color::transparent); 396 disableMobileEmulation(); 397 m_client->disableDeviceEmulation(); 398 } 399 } 400 401 void WebDevToolsAgentImpl::setTouchEventEmulationEnabled(bool enabled) 402 { 403 m_client->setTouchEventEmulationEnabled(enabled, enabled); 404 m_touchEventEmulationEnabled = enabled; 405 updatePageScaleFactorLimits(); 406 } 407 408 void WebDevToolsAgentImpl::enableMobileEmulation() 409 { 410 if (m_emulateMobileEnabled) 411 return; 412 m_emulateMobileEnabled = true; 413 m_isOverlayScrollbarsEnabled = RuntimeEnabledFeatures::overlayScrollbarsEnabled(); 414 RuntimeEnabledFeatures::setOverlayScrollbarsEnabled(true); 415 m_originalViewportEnabled = RuntimeEnabledFeatures::cssViewportEnabled(); 416 RuntimeEnabledFeatures::setCSSViewportEnabled(true); 417 m_webViewImpl->settings()->setViewportEnabled(true); 418 m_webViewImpl->settings()->setViewportMetaEnabled(true); 419 m_webViewImpl->settings()->setShrinksViewportContentToFit(true); 420 m_webViewImpl->setIgnoreViewportTagScaleLimits(true); 421 m_webViewImpl->setZoomFactorOverride(1); 422 updatePageScaleFactorLimits(); 423 } 424 425 void WebDevToolsAgentImpl::disableMobileEmulation() 426 { 427 if (!m_emulateMobileEnabled) 428 return; 429 RuntimeEnabledFeatures::setOverlayScrollbarsEnabled(m_isOverlayScrollbarsEnabled); 430 RuntimeEnabledFeatures::setCSSViewportEnabled(m_originalViewportEnabled); 431 m_webViewImpl->settings()->setViewportEnabled(false); 432 m_webViewImpl->settings()->setViewportMetaEnabled(false); 433 m_webViewImpl->settings()->setShrinksViewportContentToFit(false); 434 m_webViewImpl->setIgnoreViewportTagScaleLimits(false); 435 m_webViewImpl->setZoomFactorOverride(0); 436 m_emulateMobileEnabled = false; 437 updatePageScaleFactorLimits(); 438 } 439 440 void WebDevToolsAgentImpl::updatePageScaleFactorLimits() 441 { 442 if (m_touchEventEmulationEnabled || m_emulateMobileEnabled) { 443 if (!m_pageScaleLimitsOverriden) { 444 m_originalMinimumPageScaleFactor = m_webViewImpl->minimumPageScaleFactor(); 445 m_originalMaximumPageScaleFactor = m_webViewImpl->maximumPageScaleFactor(); 446 m_pageScaleLimitsOverriden = true; 447 } 448 if (m_emulateMobileEnabled) { 449 m_webViewImpl->setPageScaleFactorLimits(-1, -1); 450 m_webViewImpl->setInitialPageScaleOverride(-1); 451 } else { 452 m_webViewImpl->setPageScaleFactorLimits(1, 4); 453 m_webViewImpl->setInitialPageScaleOverride(1); 454 } 455 } else { 456 if (m_pageScaleLimitsOverriden) { 457 m_pageScaleLimitsOverriden = false; 458 m_webViewImpl->setPageScaleFactorLimits(m_originalMinimumPageScaleFactor, m_originalMaximumPageScaleFactor); 459 m_webViewImpl->setInitialPageScaleOverride(1); 460 } 461 } 462 } 463 464 void WebDevToolsAgentImpl::setTraceEventCallback(const String& categoryFilter, TraceEventCallback callback) 465 { 466 m_client->setTraceEventCallback(categoryFilter, callback); 467 } 468 469 void WebDevToolsAgentImpl::resetTraceEventCallback() 470 { 471 m_client->resetTraceEventCallback(); 472 } 473 474 void WebDevToolsAgentImpl::enableTracing(const String& categoryFilter) 475 { 476 m_client->enableTracing(categoryFilter); 477 } 478 479 void WebDevToolsAgentImpl::disableTracing() 480 { 481 m_client->disableTracing(); 482 } 483 484 void WebDevToolsAgentImpl::startGPUEventsRecording() 485 { 486 m_client->startGPUEventsRecording(); 487 } 488 489 void WebDevToolsAgentImpl::stopGPUEventsRecording() 490 { 491 m_client->stopGPUEventsRecording(); 492 } 493 494 void WebDevToolsAgentImpl::processGPUEvent(const GPUEvent& event) 495 { 496 if (InspectorController* ic = inspectorController()) 497 ic->processGPUEvent(event.timestamp, event.phase, event.foreign, event.usedGPUMemoryBytes, event.limitGPUMemoryBytes); 498 } 499 500 void WebDevToolsAgentImpl::dispatchKeyEvent(const PlatformKeyboardEvent& event) 501 { 502 if (!m_webViewImpl->page()->focusController().isFocused()) 503 m_webViewImpl->setFocus(true); 504 505 m_generatingEvent = true; 506 WebKeyboardEvent webEvent = WebKeyboardEventBuilder(event); 507 if (!webEvent.keyIdentifier[0] && webEvent.type != WebInputEvent::Char) 508 webEvent.setKeyIdentifierFromWindowsKeyCode(); 509 m_webViewImpl->handleInputEvent(webEvent); 510 m_generatingEvent = false; 511 } 512 513 void WebDevToolsAgentImpl::dispatchMouseEvent(const PlatformMouseEvent& event) 514 { 515 if (!m_webViewImpl->page()->focusController().isFocused()) 516 m_webViewImpl->setFocus(true); 517 518 m_generatingEvent = true; 519 WebMouseEvent webEvent = WebMouseEventBuilder(m_webViewImpl->mainFrameImpl()->frameView(), event); 520 m_webViewImpl->handleInputEvent(webEvent); 521 m_generatingEvent = false; 522 } 523 524 void WebDevToolsAgentImpl::dispatchOnInspectorBackend(const WebString& message) 525 { 526 inspectorController()->dispatchMessageFromFrontend(message); 527 } 528 529 void WebDevToolsAgentImpl::inspectElementAt(const WebPoint& point) 530 { 531 m_webViewImpl->inspectElementAt(point); 532 } 533 534 InspectorController* WebDevToolsAgentImpl::inspectorController() 535 { 536 if (Page* page = m_webViewImpl->page()) 537 return &page->inspectorController(); 538 return 0; 539 } 540 541 LocalFrame* WebDevToolsAgentImpl::mainFrame() 542 { 543 if (Page* page = m_webViewImpl->page()) 544 return page->deprecatedLocalMainFrame(); 545 return 0; 546 } 547 548 // WebPageOverlay 549 void WebDevToolsAgentImpl::paintPageOverlay(WebCanvas* canvas) 550 { 551 InspectorController* ic = inspectorController(); 552 if (ic) { 553 GraphicsContext context(canvas); 554 context.setCertainlyOpaque(false); 555 ic->drawHighlight(context); 556 } 557 } 558 559 void WebDevToolsAgentImpl::highlight() 560 { 561 if (!m_webViewDidLayoutOnceAfterLoad) { 562 m_webViewDidLayoutOnceAfterLoad = true; 563 m_webViewImpl->layout(); 564 } 565 m_webViewImpl->addPageOverlay(this, OverlayZOrders::highlight); 566 } 567 568 void WebDevToolsAgentImpl::hideHighlight() 569 { 570 m_webViewImpl->removePageOverlay(this); 571 } 572 573 void WebDevToolsAgentImpl::sendMessageToFrontend(PassRefPtr<JSONObject> message) 574 { 575 m_frontendMessageQueue.append(message); 576 } 577 578 void WebDevToolsAgentImpl::flush() 579 { 580 flushPendingFrontendMessages(); 581 } 582 583 void WebDevToolsAgentImpl::updateInspectorStateCookie(const String& state) 584 { 585 m_client->saveAgentRuntimeState(state); 586 } 587 588 void WebDevToolsAgentImpl::resumeStartup() 589 { 590 m_client->resumeStartup(); 591 } 592 593 void WebDevToolsAgentImpl::setLayerTreeId(int layerTreeId) 594 { 595 m_layerTreeId = layerTreeId; 596 inspectorController()->setLayerTreeId(layerTreeId); 597 } 598 599 void WebDevToolsAgentImpl::evaluateInWebInspector(long callId, const WebString& script) 600 { 601 InspectorController* ic = inspectorController(); 602 ic->evaluateForTestInFrontend(callId, script); 603 } 604 605 void WebDevToolsAgentImpl::flushPendingFrontendMessages() 606 { 607 InspectorController* ic = inspectorController(); 608 ic->flushPendingFrontendMessages(); 609 610 for (size_t i = 0; i < m_frontendMessageQueue.size(); ++i) 611 m_client->sendMessageToInspectorFrontend(m_frontendMessageQueue[i]->toJSONString()); 612 m_frontendMessageQueue.clear(); 613 } 614 615 void WebDevToolsAgentImpl::willProcessTask() 616 { 617 if (!m_attached) 618 return; 619 if (InspectorController* ic = inspectorController()) 620 ic->willProcessTask(); 621 TRACE_EVENT_BEGIN0(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "Program"); 622 } 623 624 void WebDevToolsAgentImpl::didProcessTask() 625 { 626 if (!m_attached) 627 return; 628 if (InspectorController* ic = inspectorController()) 629 ic->didProcessTask(); 630 TRACE_EVENT_END0(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "Program"); 631 flushPendingFrontendMessages(); 632 } 633 634 void WebDevToolsAgent::interruptAndDispatch(MessageDescriptor* rawDescriptor) 635 { 636 // rawDescriptor can't be a PassOwnPtr because interruptAndDispatch is a WebKit API function. 637 OwnPtr<MessageDescriptor> descriptor = adoptPtr(rawDescriptor); 638 OwnPtr<DebuggerTask> task = adoptPtr(new DebuggerTask(descriptor.release())); 639 PageScriptDebugServer::interruptAndRun(task.release()); 640 } 641 642 bool WebDevToolsAgent::shouldInterruptForMessage(const WebString& message) 643 { 644 String commandName; 645 if (!InspectorBackendDispatcher::getCommandName(message, &commandName)) 646 return false; 647 return commandName == InspectorBackendDispatcher::commandName(InspectorBackendDispatcher::kDebugger_pauseCmd) 648 || commandName == InspectorBackendDispatcher::commandName(InspectorBackendDispatcher::kDebugger_setBreakpointCmd) 649 || commandName == InspectorBackendDispatcher::commandName(InspectorBackendDispatcher::kDebugger_setBreakpointByUrlCmd) 650 || commandName == InspectorBackendDispatcher::commandName(InspectorBackendDispatcher::kDebugger_removeBreakpointCmd) 651 || commandName == InspectorBackendDispatcher::commandName(InspectorBackendDispatcher::kDebugger_setBreakpointsActiveCmd); 652 } 653 654 void WebDevToolsAgent::processPendingMessages() 655 { 656 PageScriptDebugServer::shared().runPendingTasks(); 657 } 658 659 } // namespace blink 660