Home | History | Annotate | Download | only in web
      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