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