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 "WebDevToolsAgentImpl.h"
     33 
     34 #include "InspectorBackendDispatcher.h"
     35 #include "InspectorFrontend.h"
     36 #include "InspectorProtocolVersion.h"
     37 #include "WebDataSource.h"
     38 #include "WebDevToolsAgentClient.h"
     39 #include "WebFrameImpl.h"
     40 #include "WebInputEventConversion.h"
     41 #include "WebMemoryUsageInfo.h"
     42 #include "WebViewClient.h"
     43 #include "WebViewImpl.h"
     44 #include "bindings/v8/PageScriptDebugServer.h"
     45 #include "bindings/v8/ScriptController.h"
     46 #include "bindings/v8/V8Binding.h"
     47 #include "bindings/v8/V8Utilities.h"
     48 #include "core/dom/ExceptionCode.h"
     49 #include "core/inspector/InjectedScriptHost.h"
     50 #include "core/inspector/InspectorController.h"
     51 #include "core/loader/cache/MemoryCache.h"
     52 #include "core/page/Frame.h"
     53 #include "core/page/FrameView.h"
     54 #include "core/page/Page.h"
     55 #include "core/page/PageGroup.h"
     56 #include "core/platform/JSONValues.h"
     57 #include "core/platform/graphics/GraphicsContext.h"
     58 #include "core/platform/network/ResourceError.h"
     59 #include "core/platform/network/ResourceRequest.h"
     60 #include "core/platform/network/ResourceResponse.h"
     61 #include "core/rendering/RenderView.h"
     62 #include "public/platform/Platform.h"
     63 #include "public/platform/WebRect.h"
     64 #include "public/platform/WebString.h"
     65 #include "public/platform/WebURL.h"
     66 #include "public/platform/WebURLError.h"
     67 #include "public/platform/WebURLRequest.h"
     68 #include "public/platform/WebURLResponse.h"
     69 #include "wtf/CurrentTime.h"
     70 #include "wtf/MathExtras.h"
     71 #include "wtf/Noncopyable.h"
     72 #include "wtf/OwnPtr.h"
     73 #include "wtf/text/WTFString.h"
     74 
     75 using namespace WebCore;
     76 using namespace std;
     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 WebKit {
     84 
     85 class ClientMessageLoopAdapter : public PageScriptDebugServer::ClientMessageLoop {
     86 public:
     87     static void ensureClientMessageLoopCreated(WebDevToolsAgentClient* client)
     88     {
     89         if (s_instance)
     90             return;
     91         OwnPtr<ClientMessageLoopAdapter> instance = adoptPtr(new ClientMessageLoopAdapter(adoptPtr(client->createClientMessageLoop())));
     92         s_instance = instance.get();
     93         PageScriptDebugServer::shared().setClientMessageLoop(instance.release());
     94     }
     95 
     96     static void inspectedViewClosed(WebViewImpl* view)
     97     {
     98         if (s_instance)
     99             s_instance->m_frozenViews.remove(view);
    100     }
    101 
    102     static void didNavigate()
    103     {
    104         // Release render thread if necessary.
    105         if (s_instance && s_instance->m_running)
    106             PageScriptDebugServer::shared().continueProgram();
    107     }
    108 
    109 private:
    110     ClientMessageLoopAdapter(PassOwnPtr<WebKit::WebDevToolsAgentClient::WebKitClientMessageLoop> messageLoop)
    111         : m_running(false)
    112         , m_messageLoop(messageLoop) { }
    113 
    114 
    115     virtual void run(Page* page)
    116     {
    117         if (m_running)
    118             return;
    119         m_running = true;
    120 
    121         Vector<WebViewImpl*> views;
    122 
    123         // 1. Disable input events.
    124         HashSet<Page*>::const_iterator end =  page->group().pages().end();
    125         for (HashSet<Page*>::const_iterator it =  page->group().pages().begin(); it != end; ++it) {
    126             WebViewImpl* view = WebViewImpl::fromPage(*it);
    127             if (!view)
    128                 continue;
    129             m_frozenViews.add(view);
    130             views.append(view);
    131             view->setIgnoreInputEvents(true);
    132         }
    133 
    134         // 2. Disable active objects
    135         WebView::willEnterModalLoop();
    136 
    137         // 3. Process messages until quitNow is called.
    138         m_messageLoop->run();
    139 
    140         // 4. Resume active objects
    141         WebView::didExitModalLoop();
    142 
    143         // 5. Resume input events.
    144         for (Vector<WebViewImpl*>::iterator it = views.begin(); it != views.end(); ++it) {
    145             if (m_frozenViews.contains(*it)) {
    146                 // The view was not closed during the dispatch.
    147                 (*it)->setIgnoreInputEvents(false);
    148             }
    149         }
    150 
    151         // 6. All views have been resumed, clear the set.
    152         m_frozenViews.clear();
    153 
    154         m_running = false;
    155     }
    156 
    157     virtual void quitNow()
    158     {
    159         m_messageLoop->quitNow();
    160     }
    161 
    162     bool m_running;
    163     OwnPtr<WebKit::WebDevToolsAgentClient::WebKitClientMessageLoop> m_messageLoop;
    164     typedef HashSet<WebViewImpl*> FrozenViewsSet;
    165     FrozenViewsSet m_frozenViews;
    166     // FIXME: The ownership model for s_instance is somewhat complicated. Can we make this simpler?
    167     static ClientMessageLoopAdapter* s_instance;
    168 };
    169 
    170 ClientMessageLoopAdapter* ClientMessageLoopAdapter::s_instance = 0;
    171 
    172 class DebuggerTask : public PageScriptDebugServer::Task {
    173 public:
    174     DebuggerTask(PassOwnPtr<WebDevToolsAgent::MessageDescriptor> descriptor)
    175         : m_descriptor(descriptor)
    176     {
    177     }
    178 
    179     virtual ~DebuggerTask() { }
    180     virtual void run()
    181     {
    182         if (WebDevToolsAgent* webagent = m_descriptor->agent())
    183             webagent->dispatchOnInspectorBackend(m_descriptor->message());
    184     }
    185 
    186 private:
    187     OwnPtr<WebDevToolsAgent::MessageDescriptor> m_descriptor;
    188 };
    189 
    190 class DeviceMetricsSupport {
    191 public:
    192     DeviceMetricsSupport(WebViewImpl* webView)
    193         : m_webView(webView)
    194         , m_fitWindow(false)
    195         , m_originalZoomFactor(0)
    196     {
    197     }
    198 
    199     ~DeviceMetricsSupport()
    200     {
    201         restore();
    202     }
    203 
    204     void setDeviceMetrics(int width, int height, float textZoomFactor, bool fitWindow)
    205     {
    206         WebCore::FrameView* view = frameView();
    207         if (!view)
    208             return;
    209 
    210         m_emulatedFrameSize = WebSize(width, height);
    211         m_fitWindow = fitWindow;
    212         m_originalZoomFactor = 0;
    213         m_webView->setTextZoomFactor(textZoomFactor);
    214         applySizeOverrideInternal(view, FitWindowAllowed);
    215         autoZoomPageToFitWidth(view->frame());
    216 
    217         m_webView->sendResizeEventAndRepaint();
    218     }
    219 
    220     void autoZoomPageToFitWidthOnNavigation(Frame* frame)
    221     {
    222         FrameView* frameView = frame->view();
    223         applySizeOverrideInternal(frameView, FitWindowNotAllowed);
    224         m_originalZoomFactor = 0;
    225         applySizeOverrideInternal(frameView, FitWindowAllowed);
    226         autoZoomPageToFitWidth(frame);
    227     }
    228 
    229     void autoZoomPageToFitWidth(Frame* frame)
    230     {
    231         if (!frame)
    232             return;
    233 
    234         frame->setTextZoomFactor(m_webView->textZoomFactor());
    235         ensureOriginalZoomFactor(frame->view());
    236         Document* document = frame->document();
    237         float numerator = document->renderView() ? document->renderView()->viewWidth() : frame->view()->contentsWidth();
    238         float factor = m_originalZoomFactor * (numerator / m_emulatedFrameSize.width);
    239         frame->setPageAndTextZoomFactors(factor, m_webView->textZoomFactor());
    240         document->styleResolverChanged(RecalcStyleImmediately);
    241         document->updateLayout();
    242     }
    243 
    244     void webViewResized()
    245     {
    246         if (!m_fitWindow)
    247             return;
    248 
    249         applySizeOverrideIfNecessary();
    250         autoZoomPageToFitWidth(m_webView->mainFrameImpl()->frame());
    251     }
    252 
    253     void applySizeOverrideIfNecessary()
    254     {
    255         FrameView* view = frameView();
    256         if (!view)
    257             return;
    258 
    259         applySizeOverrideInternal(view, FitWindowAllowed);
    260     }
    261 
    262 private:
    263     enum FitWindowFlag { FitWindowAllowed, FitWindowNotAllowed };
    264 
    265     void ensureOriginalZoomFactor(FrameView* frameView)
    266     {
    267         if (m_originalZoomFactor)
    268             return;
    269 
    270         m_webView->setPageScaleFactor(1, WebPoint());
    271         m_webView->setZoomLevel(0);
    272         WebSize scaledEmulatedSize = scaledEmulatedFrameSize(frameView);
    273         double denominator = frameView->contentsWidth();
    274         if (!denominator)
    275             denominator = 1;
    276         m_originalZoomFactor = static_cast<double>(scaledEmulatedSize.width) / denominator;
    277     }
    278 
    279     void restore()
    280     {
    281         WebCore::FrameView* view = frameView();
    282         if (!view)
    283             return;
    284 
    285         m_webView->setZoomLevel(0);
    286         m_webView->setTextZoomFactor(1);
    287         view->setHorizontalScrollbarLock(false);
    288         view->setVerticalScrollbarLock(false);
    289         view->setScrollbarModes(ScrollbarAuto, ScrollbarAuto, false, false);
    290         view->setFrameRect(IntRect(IntPoint(), IntSize(m_webView->size())));
    291         m_webView->sendResizeEventAndRepaint();
    292     }
    293 
    294     WebSize scaledEmulatedFrameSize(FrameView* frameView)
    295     {
    296         if (!m_fitWindow)
    297             return m_emulatedFrameSize;
    298 
    299         WebSize scrollbarDimensions = forcedScrollbarDimensions(frameView);
    300 
    301         int overrideWidth = m_emulatedFrameSize.width;
    302         int overrideHeight = m_emulatedFrameSize.height;
    303 
    304         WebSize webViewSize = m_webView->size();
    305         int availableViewWidth = max(webViewSize.width - scrollbarDimensions.width, 1);
    306         int availableViewHeight = max(webViewSize.height - scrollbarDimensions.height, 1);
    307 
    308         double widthRatio = static_cast<double>(overrideWidth) / availableViewWidth;
    309         double heightRatio = static_cast<double>(overrideHeight) / availableViewHeight;
    310         double dimensionRatio = max(widthRatio, heightRatio);
    311         overrideWidth = static_cast<int>(ceil(static_cast<double>(overrideWidth) / dimensionRatio));
    312         overrideHeight = static_cast<int>(ceil(static_cast<double>(overrideHeight) / dimensionRatio));
    313 
    314         return WebSize(overrideWidth, overrideHeight);
    315     }
    316 
    317     WebSize forcedScrollbarDimensions(FrameView* frameView)
    318     {
    319         frameView->setScrollbarModes(ScrollbarAlwaysOn, ScrollbarAlwaysOn, true, true);
    320 
    321         int verticalScrollbarWidth = 0;
    322         int horizontalScrollbarHeight = 0;
    323         if (Scrollbar* verticalBar = frameView->verticalScrollbar())
    324             verticalScrollbarWidth = !verticalBar->isOverlayScrollbar() ? verticalBar->width() : 0;
    325         if (Scrollbar* horizontalBar = frameView->horizontalScrollbar())
    326             horizontalScrollbarHeight = !horizontalBar->isOverlayScrollbar() ? horizontalBar->height() : 0;
    327         return WebSize(verticalScrollbarWidth, horizontalScrollbarHeight);
    328     }
    329 
    330     void applySizeOverrideInternal(FrameView* frameView, FitWindowFlag fitWindowFlag)
    331     {
    332         WebSize scrollbarDimensions = forcedScrollbarDimensions(frameView);
    333 
    334         WebSize effectiveEmulatedSize = (fitWindowFlag == FitWindowAllowed) ? scaledEmulatedFrameSize(frameView) : m_emulatedFrameSize;
    335         int overrideWidth = effectiveEmulatedSize.width + scrollbarDimensions.width;
    336         int overrideHeight = effectiveEmulatedSize.height + scrollbarDimensions.height;
    337 
    338         if (IntSize(overrideWidth, overrideHeight) != frameView->size())
    339             frameView->resize(overrideWidth, overrideHeight);
    340 
    341         Document* doc = frameView->frame()->document();
    342         doc->styleResolverChanged(RecalcStyleImmediately);
    343         doc->updateLayout();
    344     }
    345 
    346     WebCore::FrameView* frameView()
    347     {
    348         return m_webView->mainFrameImpl() ? m_webView->mainFrameImpl()->frameView() : 0;
    349     }
    350 
    351     WebViewImpl* m_webView;
    352     WebSize m_emulatedFrameSize;
    353     bool m_fitWindow;
    354     double m_originalZoomFactor;
    355 };
    356 
    357 WebDevToolsAgentImpl::WebDevToolsAgentImpl(
    358     WebViewImpl* webViewImpl,
    359     WebDevToolsAgentClient* client)
    360     : m_hostId(client->hostIdentifier())
    361     , m_client(client)
    362     , m_webViewImpl(webViewImpl)
    363     , m_attached(false)
    364 {
    365     ASSERT(m_hostId > 0);
    366     ClientMessageLoopAdapter::ensureClientMessageLoopCreated(m_client);
    367 }
    368 
    369 WebDevToolsAgentImpl::~WebDevToolsAgentImpl()
    370 {
    371     ClientMessageLoopAdapter::inspectedViewClosed(m_webViewImpl);
    372     if (m_attached)
    373         WebKit::Platform::current()->currentThread()->removeTaskObserver(this);
    374 }
    375 
    376 void WebDevToolsAgentImpl::attach()
    377 {
    378     if (m_attached)
    379         return;
    380 
    381     inspectorController()->connectFrontend(this);
    382     inspectorController()->webViewResized(m_webViewImpl->size());
    383     WebKit::Platform::current()->currentThread()->addTaskObserver(this);
    384     m_attached = true;
    385 }
    386 
    387 void WebDevToolsAgentImpl::reattach(const WebString& savedState)
    388 {
    389     if (m_attached)
    390         return;
    391 
    392     inspectorController()->reuseFrontend(this, savedState);
    393     WebKit::Platform::current()->currentThread()->addTaskObserver(this);
    394     m_attached = true;
    395 }
    396 
    397 void WebDevToolsAgentImpl::detach()
    398 {
    399     WebKit::Platform::current()->currentThread()->removeTaskObserver(this);
    400 
    401     // Prevent controller from sending messages to the frontend.
    402     InspectorController* ic = inspectorController();
    403     ic->disconnectFrontend();
    404     ic->hideHighlight();
    405     m_attached = false;
    406 }
    407 
    408 void WebDevToolsAgentImpl::didNavigate()
    409 {
    410     ClientMessageLoopAdapter::didNavigate();
    411 }
    412 
    413 void WebDevToolsAgentImpl::didBeginFrame()
    414 {
    415     if (InspectorController* ic = inspectorController())
    416         ic->didBeginFrame();
    417 }
    418 
    419 void WebDevToolsAgentImpl::didCancelFrame()
    420 {
    421     if (InspectorController* ic = inspectorController())
    422         ic->didCancelFrame();
    423 }
    424 
    425 void WebDevToolsAgentImpl::willComposite()
    426 {
    427     if (InspectorController* ic = inspectorController())
    428         ic->willComposite();
    429 }
    430 
    431 void WebDevToolsAgentImpl::didComposite()
    432 {
    433     if (InspectorController* ic = inspectorController())
    434         ic->didComposite();
    435 }
    436 
    437 void WebDevToolsAgentImpl::didCreateScriptContext(WebFrameImpl* webframe, int worldId)
    438 {
    439     // Skip non main world contexts.
    440     if (worldId)
    441         return;
    442     if (WebCore::Frame* frame = webframe->frame())
    443         frame->script()->setContextDebugId(m_hostId);
    444 }
    445 
    446 void WebDevToolsAgentImpl::mainFrameViewCreated(WebFrameImpl* webFrame)
    447 {
    448     if (m_metricsSupport)
    449         m_metricsSupport->applySizeOverrideIfNecessary();
    450 }
    451 
    452 bool WebDevToolsAgentImpl::metricsOverridden()
    453 {
    454     return !!m_metricsSupport;
    455 }
    456 
    457 void WebDevToolsAgentImpl::webViewResized(const WebSize& size)
    458 {
    459     if (m_metricsSupport)
    460         m_metricsSupport->webViewResized();
    461     if (InspectorController* ic = inspectorController())
    462         ic->webViewResized(m_metricsSupport ? IntSize(size.width, size.height) : IntSize());
    463 }
    464 
    465 bool WebDevToolsAgentImpl::handleInputEvent(WebCore::Page* page, const WebInputEvent& inputEvent)
    466 {
    467     if (!m_attached)
    468         return false;
    469 
    470     InspectorController* ic = inspectorController();
    471     if (!ic)
    472         return false;
    473 
    474     if (WebInputEvent::isGestureEventType(inputEvent.type) && inputEvent.type == WebInputEvent::GestureTap) {
    475         // Only let GestureTab in (we only need it and we know PlatformGestureEventBuilder supports it).
    476         PlatformGestureEvent gestureEvent = PlatformGestureEventBuilder(page->mainFrame()->view(), *static_cast<const WebGestureEvent*>(&inputEvent));
    477         return ic->handleGestureEvent(page->mainFrame(), gestureEvent);
    478     }
    479     if (WebInputEvent::isMouseEventType(inputEvent.type) && inputEvent.type != WebInputEvent::MouseEnter) {
    480         // PlatformMouseEventBuilder does not work with MouseEnter type, so we filter it out manually.
    481         PlatformMouseEvent mouseEvent = PlatformMouseEventBuilder(page->mainFrame()->view(), *static_cast<const WebMouseEvent*>(&inputEvent));
    482         return ic->handleMouseEvent(page->mainFrame(), mouseEvent);
    483     }
    484     if (WebInputEvent::isTouchEventType(inputEvent.type)) {
    485         PlatformTouchEvent touchEvent = PlatformTouchEventBuilder(page->mainFrame()->view(), *static_cast<const WebTouchEvent*>(&inputEvent));
    486         return ic->handleTouchEvent(page->mainFrame(), touchEvent);
    487     }
    488     return false;
    489 }
    490 
    491 void WebDevToolsAgentImpl::overrideDeviceMetrics(int width, int height, float fontScaleFactor, bool fitWindow)
    492 {
    493     if (!width && !height) {
    494         if (m_metricsSupport)
    495             m_metricsSupport.clear();
    496         if (InspectorController* ic = inspectorController())
    497             ic->webViewResized(IntSize());
    498         return;
    499     }
    500 
    501     if (!m_metricsSupport)
    502         m_metricsSupport = adoptPtr(new DeviceMetricsSupport(m_webViewImpl));
    503 
    504     m_metricsSupport->setDeviceMetrics(width, height, fontScaleFactor, fitWindow);
    505     if (InspectorController* ic = inspectorController()) {
    506         WebSize size = m_webViewImpl->size();
    507         ic->webViewResized(IntSize(size.width, size.height));
    508     }
    509 }
    510 
    511 void WebDevToolsAgentImpl::autoZoomPageToFitWidth()
    512 {
    513     if (m_metricsSupport)
    514         m_metricsSupport->autoZoomPageToFitWidthOnNavigation(m_webViewImpl->mainFrameImpl()->frame());
    515 }
    516 
    517 void WebDevToolsAgentImpl::getAllocatedObjects(HashSet<const void*>& set)
    518 {
    519     class CountingVisitor : public WebDevToolsAgentClient::AllocatedObjectVisitor {
    520     public:
    521         CountingVisitor() : m_totalObjectsCount(0)
    522         {
    523         }
    524 
    525         virtual bool visitObject(const void* ptr)
    526         {
    527             ++m_totalObjectsCount;
    528             return true;
    529         }
    530         size_t totalObjectsCount() const
    531         {
    532             return m_totalObjectsCount;
    533         }
    534 
    535     private:
    536         size_t m_totalObjectsCount;
    537     };
    538 
    539     CountingVisitor counter;
    540     m_client->visitAllocatedObjects(&counter);
    541 
    542     class PointerCollector : public WebDevToolsAgentClient::AllocatedObjectVisitor {
    543     public:
    544         explicit PointerCollector(size_t maxObjectsCount)
    545             : m_maxObjectsCount(maxObjectsCount)
    546             , m_index(0)
    547             , m_success(true)
    548             , m_pointers(new const void*[maxObjectsCount])
    549         {
    550         }
    551         virtual ~PointerCollector()
    552         {
    553             delete[] m_pointers;
    554         }
    555         virtual bool visitObject(const void* ptr)
    556         {
    557             if (m_index == m_maxObjectsCount) {
    558                 m_success = false;
    559                 return false;
    560             }
    561             m_pointers[m_index++] = ptr;
    562             return true;
    563         }
    564 
    565         bool success() const { return m_success; }
    566 
    567         void copyTo(HashSet<const void*>& set)
    568         {
    569             for (size_t i = 0; i < m_index; i++)
    570                 set.add(m_pointers[i]);
    571         }
    572 
    573     private:
    574         const size_t m_maxObjectsCount;
    575         size_t m_index;
    576         bool m_success;
    577         const void** m_pointers;
    578     };
    579 
    580     // Double size to allow room for all objects that may have been allocated
    581     // since we counted them.
    582     size_t estimatedMaxObjectsCount = counter.totalObjectsCount() * 2;
    583     while (true) {
    584         PointerCollector collector(estimatedMaxObjectsCount);
    585         m_client->visitAllocatedObjects(&collector);
    586         if (collector.success()) {
    587             collector.copyTo(set);
    588             break;
    589         }
    590         estimatedMaxObjectsCount *= 2;
    591     }
    592 }
    593 
    594 void WebDevToolsAgentImpl::dumpUncountedAllocatedObjects(const HashMap<const void*, size_t>& map)
    595 {
    596     class InstrumentedObjectSizeProvider : public WebDevToolsAgentClient::InstrumentedObjectSizeProvider {
    597     public:
    598         InstrumentedObjectSizeProvider(const HashMap<const void*, size_t>& map) : m_map(map) { }
    599         virtual size_t objectSize(const void* ptr) const
    600         {
    601             HashMap<const void*, size_t>::const_iterator i = m_map.find(ptr);
    602             return i == m_map.end() ? 0 : i->value;
    603         }
    604 
    605     private:
    606         const HashMap<const void*, size_t>& m_map;
    607     };
    608 
    609     InstrumentedObjectSizeProvider provider(map);
    610     m_client->dumpUncountedAllocatedObjects(&provider);
    611 }
    612 
    613 void WebDevToolsAgentImpl::setTraceEventCallback(TraceEventCallback callback)
    614 {
    615     m_client->setTraceEventCallback(callback);
    616 }
    617 
    618 void WebDevToolsAgentImpl::dispatchKeyEvent(const PlatformKeyboardEvent& event)
    619 {
    620     WebKeyboardEvent webEvent = WebKeyboardEventBuilder(event);
    621     if (!webEvent.keyIdentifier[0] && webEvent.type != WebInputEvent::Char)
    622         webEvent.setKeyIdentifierFromWindowsKeyCode();
    623     m_webViewImpl->handleInputEvent(webEvent);
    624 }
    625 
    626 void WebDevToolsAgentImpl::dispatchMouseEvent(const PlatformMouseEvent& event)
    627 {
    628     WebMouseEvent webEvent = WebMouseEventBuilder(m_webViewImpl->mainFrameImpl()->frameView(), event);
    629     m_webViewImpl->handleInputEvent(webEvent);
    630 }
    631 
    632 void WebDevToolsAgentImpl::dispatchOnInspectorBackend(const WebString& message)
    633 {
    634     inspectorController()->dispatchMessageFromFrontend(message);
    635 }
    636 
    637 void WebDevToolsAgentImpl::inspectElementAt(const WebPoint& point)
    638 {
    639     m_webViewImpl->inspectElementAt(point);
    640 }
    641 
    642 InspectorController* WebDevToolsAgentImpl::inspectorController()
    643 {
    644     if (Page* page = m_webViewImpl->page())
    645         return page->inspectorController();
    646     return 0;
    647 }
    648 
    649 Frame* WebDevToolsAgentImpl::mainFrame()
    650 {
    651     if (Page* page = m_webViewImpl->page())
    652         return page->mainFrame();
    653     return 0;
    654 }
    655 
    656 // WebPageOverlay
    657 void WebDevToolsAgentImpl::paintPageOverlay(WebCanvas* canvas)
    658 {
    659     InspectorController* ic = inspectorController();
    660     if (ic) {
    661         GraphicsContext context(canvas);
    662         context.setCertainlyOpaque(false);
    663         ic->drawHighlight(context);
    664     }
    665 }
    666 
    667 void WebDevToolsAgentImpl::highlight()
    668 {
    669     m_webViewImpl->addPageOverlay(this, OverlayZOrders::highlight);
    670 }
    671 
    672 void WebDevToolsAgentImpl::hideHighlight()
    673 {
    674     m_webViewImpl->removePageOverlay(this);
    675 }
    676 
    677 bool WebDevToolsAgentImpl::sendMessageToFrontend(const String& message)
    678 {
    679     WebDevToolsAgentImpl* devToolsAgent = static_cast<WebDevToolsAgentImpl*>(m_webViewImpl->devToolsAgent());
    680     if (!devToolsAgent)
    681         return false;
    682     m_client->sendMessageToInspectorFrontend(message);
    683     return true;
    684 }
    685 
    686 void WebDevToolsAgentImpl::updateInspectorStateCookie(const String& state)
    687 {
    688     m_client->saveAgentRuntimeState(state);
    689 }
    690 
    691 void WebDevToolsAgentImpl::clearBrowserCache()
    692 {
    693     m_client->clearBrowserCache();
    694 }
    695 
    696 void WebDevToolsAgentImpl::clearBrowserCookies()
    697 {
    698     m_client->clearBrowserCookies();
    699 }
    700 
    701 void WebDevToolsAgentImpl::setProcessId(long processId)
    702 {
    703     inspectorController()->setProcessId(processId);
    704 }
    705 
    706 void WebDevToolsAgentImpl::setLayerTreeId(int layerTreeId)
    707 {
    708     inspectorController()->setLayerTreeId(layerTreeId);
    709 }
    710 
    711 void WebDevToolsAgentImpl::evaluateInWebInspector(long callId, const WebString& script)
    712 {
    713     InspectorController* ic = inspectorController();
    714     ic->evaluateForTestInFrontend(callId, script);
    715 }
    716 
    717 void WebDevToolsAgentImpl::willProcessTask()
    718 {
    719     if (InspectorController* ic = inspectorController())
    720         ic->willProcessTask();
    721 }
    722 
    723 void WebDevToolsAgentImpl::didProcessTask()
    724 {
    725     if (InspectorController* ic = inspectorController())
    726         ic->didProcessTask();
    727 }
    728 
    729 WebString WebDevToolsAgent::inspectorProtocolVersion()
    730 {
    731     return WebCore::inspectorProtocolVersion();
    732 }
    733 
    734 bool WebDevToolsAgent::supportsInspectorProtocolVersion(const WebString& version)
    735 {
    736     return WebCore::supportsInspectorProtocolVersion(version);
    737 }
    738 
    739 void WebDevToolsAgent::interruptAndDispatch(MessageDescriptor* rawDescriptor)
    740 {
    741     // rawDescriptor can't be a PassOwnPtr because interruptAndDispatch is a WebKit API function.
    742     OwnPtr<MessageDescriptor> descriptor = adoptPtr(rawDescriptor);
    743     OwnPtr<DebuggerTask> task = adoptPtr(new DebuggerTask(descriptor.release()));
    744     PageScriptDebugServer::interruptAndRun(task.release(), v8::Isolate::GetCurrent());
    745 }
    746 
    747 bool WebDevToolsAgent::shouldInterruptForMessage(const WebString& message)
    748 {
    749     String commandName;
    750     if (!InspectorBackendDispatcher::getCommandName(message, &commandName))
    751         return false;
    752     return commandName == InspectorBackendDispatcher::commandNames[InspectorBackendDispatcher::kDebugger_pauseCmd]
    753         || commandName == InspectorBackendDispatcher::commandNames[InspectorBackendDispatcher::kDebugger_setBreakpointCmd]
    754         || commandName == InspectorBackendDispatcher::commandNames[InspectorBackendDispatcher::kDebugger_setBreakpointByUrlCmd]
    755         || commandName == InspectorBackendDispatcher::commandNames[InspectorBackendDispatcher::kDebugger_removeBreakpointCmd]
    756         || commandName == InspectorBackendDispatcher::commandNames[InspectorBackendDispatcher::kDebugger_setBreakpointsActiveCmd]
    757         || commandName == InspectorBackendDispatcher::commandNames[InspectorBackendDispatcher::kProfiler_startCmd]
    758         || commandName == InspectorBackendDispatcher::commandNames[InspectorBackendDispatcher::kProfiler_stopCmd]
    759         || commandName == InspectorBackendDispatcher::commandNames[InspectorBackendDispatcher::kProfiler_getCPUProfileCmd]
    760         || commandName == InspectorBackendDispatcher::commandNames[InspectorBackendDispatcher::kHeapProfiler_getHeapSnapshotCmd];
    761 }
    762 
    763 void WebDevToolsAgent::processPendingMessages()
    764 {
    765     PageScriptDebugServer::shared().runPendingTasks();
    766 }
    767 
    768 } // namespace WebKit
    769