Home | History | Annotate | Download | only in inspector
      1 /*
      2  * Copyright (C) 2012 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 "core/inspector/InspectorCanvasAgent.h"
     33 
     34 #include "HTMLNames.h"
     35 #include "InspectorFrontend.h"
     36 #include "bindings/v8/ScriptObject.h"
     37 #include "bindings/v8/ScriptProfiler.h"
     38 #include "bindings/v8/ScriptState.h"
     39 #include "core/html/HTMLCanvasElement.h"
     40 #include "core/inspector/BindingVisitors.h"
     41 #include "core/inspector/InjectedScript.h"
     42 #include "core/inspector/InjectedScriptCanvasModule.h"
     43 #include "core/inspector/InjectedScriptManager.h"
     44 #include "core/inspector/InspectorPageAgent.h"
     45 #include "core/inspector/InspectorState.h"
     46 #include "core/inspector/InstrumentingAgents.h"
     47 #include "core/loader/DocumentLoader.h"
     48 #include "core/page/DOMWindow.h"
     49 #include "core/page/Frame.h"
     50 
     51 using WebCore::TypeBuilder::Array;
     52 using WebCore::TypeBuilder::Canvas::ResourceId;
     53 using WebCore::TypeBuilder::Canvas::ResourceState;
     54 using WebCore::TypeBuilder::Canvas::TraceLog;
     55 using WebCore::TypeBuilder::Canvas::TraceLogId;
     56 using WebCore::TypeBuilder::Network::FrameId;
     57 using WebCore::TypeBuilder::Runtime::RemoteObject;
     58 
     59 namespace WebCore {
     60 
     61 namespace CanvasAgentState {
     62 static const char canvasAgentEnabled[] = "canvasAgentEnabled";
     63 };
     64 
     65 InspectorCanvasAgent::InspectorCanvasAgent(InstrumentingAgents* instrumentingAgents, InspectorCompositeState* state, InspectorPageAgent* pageAgent, InjectedScriptManager* injectedScriptManager)
     66     : InspectorBaseAgent<InspectorCanvasAgent>("Canvas", instrumentingAgents, state)
     67     , m_pageAgent(pageAgent)
     68     , m_injectedScriptManager(injectedScriptManager)
     69     , m_frontend(0)
     70     , m_enabled(false)
     71 {
     72 }
     73 
     74 InspectorCanvasAgent::~InspectorCanvasAgent()
     75 {
     76 }
     77 
     78 void InspectorCanvasAgent::setFrontend(InspectorFrontend* frontend)
     79 {
     80     ASSERT(frontend);
     81     m_frontend = frontend->canvas();
     82 }
     83 
     84 void InspectorCanvasAgent::clearFrontend()
     85 {
     86     m_frontend = 0;
     87     disable(0);
     88 }
     89 
     90 void InspectorCanvasAgent::restore()
     91 {
     92     if (m_state->getBoolean(CanvasAgentState::canvasAgentEnabled)) {
     93         ErrorString error;
     94         enable(&error);
     95     }
     96 }
     97 
     98 void InspectorCanvasAgent::enable(ErrorString*)
     99 {
    100     if (m_enabled)
    101         return;
    102     m_enabled = true;
    103     m_state->setBoolean(CanvasAgentState::canvasAgentEnabled, m_enabled);
    104     m_instrumentingAgents->setInspectorCanvasAgent(this);
    105     findFramesWithUninstrumentedCanvases();
    106 }
    107 
    108 void InspectorCanvasAgent::disable(ErrorString*)
    109 {
    110     m_enabled = false;
    111     m_state->setBoolean(CanvasAgentState::canvasAgentEnabled, m_enabled);
    112     m_instrumentingAgents->setInspectorCanvasAgent(0);
    113     m_framesWithUninstrumentedCanvases.clear();
    114     if (m_frontend)
    115         m_frontend->traceLogsRemoved(0, 0);
    116 }
    117 
    118 void InspectorCanvasAgent::dropTraceLog(ErrorString* errorString, const TraceLogId& traceLogId)
    119 {
    120     InjectedScriptCanvasModule module = injectedScriptCanvasModule(errorString, traceLogId);
    121     if (!module.hasNoValue())
    122         module.dropTraceLog(errorString, traceLogId);
    123 }
    124 
    125 void InspectorCanvasAgent::hasUninstrumentedCanvases(ErrorString* errorString, bool* result)
    126 {
    127     if (!checkIsEnabled(errorString))
    128         return;
    129     for (FramesWithUninstrumentedCanvases::const_iterator it = m_framesWithUninstrumentedCanvases.begin(); it != m_framesWithUninstrumentedCanvases.end(); ++it) {
    130         if (it->value) {
    131             *result = true;
    132             return;
    133         }
    134     }
    135     *result = false;
    136 }
    137 
    138 void InspectorCanvasAgent::captureFrame(ErrorString* errorString, const FrameId* frameId, TraceLogId* traceLogId)
    139 {
    140     Frame* frame = frameId ? m_pageAgent->assertFrame(errorString, *frameId) : m_pageAgent->mainFrame();
    141     if (!frame)
    142         return;
    143     InjectedScriptCanvasModule module = injectedScriptCanvasModule(errorString, mainWorldScriptState(frame));
    144     if (!module.hasNoValue())
    145         module.captureFrame(errorString, traceLogId);
    146 }
    147 
    148 void InspectorCanvasAgent::startCapturing(ErrorString* errorString, const FrameId* frameId, TraceLogId* traceLogId)
    149 {
    150     Frame* frame = frameId ? m_pageAgent->assertFrame(errorString, *frameId) : m_pageAgent->mainFrame();
    151     if (!frame)
    152         return;
    153     InjectedScriptCanvasModule module = injectedScriptCanvasModule(errorString, mainWorldScriptState(frame));
    154     if (!module.hasNoValue())
    155         module.startCapturing(errorString, traceLogId);
    156 }
    157 
    158 void InspectorCanvasAgent::stopCapturing(ErrorString* errorString, const TraceLogId& traceLogId)
    159 {
    160     InjectedScriptCanvasModule module = injectedScriptCanvasModule(errorString, traceLogId);
    161     if (!module.hasNoValue())
    162         module.stopCapturing(errorString, traceLogId);
    163 }
    164 
    165 void InspectorCanvasAgent::getTraceLog(ErrorString* errorString, const TraceLogId& traceLogId, const int* startOffset, const int* maxLength, RefPtr<TraceLog>& traceLog)
    166 {
    167     InjectedScriptCanvasModule module = injectedScriptCanvasModule(errorString, traceLogId);
    168     if (!module.hasNoValue())
    169         module.traceLog(errorString, traceLogId, startOffset, maxLength, &traceLog);
    170 }
    171 
    172 void InspectorCanvasAgent::replayTraceLog(ErrorString* errorString, const TraceLogId& traceLogId, int stepNo, RefPtr<ResourceState>& result, double* replayTime)
    173 {
    174     InjectedScriptCanvasModule module = injectedScriptCanvasModule(errorString, traceLogId);
    175     if (!module.hasNoValue())
    176         module.replayTraceLog(errorString, traceLogId, stepNo, &result, replayTime);
    177 }
    178 
    179 void InspectorCanvasAgent::getResourceState(ErrorString* errorString, const TraceLogId& traceLogId, const ResourceId& resourceId, RefPtr<ResourceState>& result)
    180 {
    181     InjectedScriptCanvasModule module = injectedScriptCanvasModule(errorString, traceLogId);
    182     if (!module.hasNoValue())
    183         module.resourceState(errorString, traceLogId, resourceId, &result);
    184 }
    185 
    186 void InspectorCanvasAgent::evaluateTraceLogCallArgument(ErrorString* errorString, const TraceLogId& traceLogId, int callIndex, int argumentIndex, const String* objectGroup, RefPtr<RemoteObject>& result, RefPtr<ResourceState>& resourceState)
    187 {
    188     InjectedScriptCanvasModule module = injectedScriptCanvasModule(errorString, traceLogId);
    189     if (!module.hasNoValue())
    190         module.evaluateTraceLogCallArgument(errorString, traceLogId, callIndex, argumentIndex, objectGroup ? *objectGroup : String(), &result, &resourceState);
    191 }
    192 
    193 ScriptObject InspectorCanvasAgent::wrapCanvas2DRenderingContextForInstrumentation(const ScriptObject& context)
    194 {
    195     ErrorString error;
    196     InjectedScriptCanvasModule module = injectedScriptCanvasModule(&error, context);
    197     if (module.hasNoValue())
    198         return ScriptObject();
    199     return notifyRenderingContextWasWrapped(module.wrapCanvas2DContext(context));
    200 }
    201 
    202 ScriptObject InspectorCanvasAgent::wrapWebGLRenderingContextForInstrumentation(const ScriptObject& glContext)
    203 {
    204     ErrorString error;
    205     InjectedScriptCanvasModule module = injectedScriptCanvasModule(&error, glContext);
    206     if (module.hasNoValue())
    207         return ScriptObject();
    208     return notifyRenderingContextWasWrapped(module.wrapWebGLContext(glContext));
    209 }
    210 
    211 ScriptObject InspectorCanvasAgent::notifyRenderingContextWasWrapped(const ScriptObject& wrappedContext)
    212 {
    213     ASSERT(m_frontend);
    214     ScriptState* scriptState = wrappedContext.scriptState();
    215     DOMWindow* domWindow = 0;
    216     if (scriptState)
    217         domWindow = scriptState->domWindow();
    218     Frame* frame = domWindow ? domWindow->frame() : 0;
    219     if (frame && !m_framesWithUninstrumentedCanvases.contains(frame))
    220         m_framesWithUninstrumentedCanvases.set(frame, false);
    221     String frameId = m_pageAgent->frameId(frame);
    222     if (!frameId.isEmpty())
    223         m_frontend->contextCreated(frameId);
    224     return wrappedContext;
    225 }
    226 
    227 InjectedScriptCanvasModule InspectorCanvasAgent::injectedScriptCanvasModule(ErrorString* errorString, ScriptState* scriptState)
    228 {
    229     if (!checkIsEnabled(errorString))
    230         return InjectedScriptCanvasModule();
    231     InjectedScriptCanvasModule module = InjectedScriptCanvasModule::moduleForState(m_injectedScriptManager, scriptState);
    232     if (module.hasNoValue()) {
    233         ASSERT_NOT_REACHED();
    234         *errorString = "Internal error: no Canvas module";
    235     }
    236     return module;
    237 }
    238 
    239 InjectedScriptCanvasModule InspectorCanvasAgent::injectedScriptCanvasModule(ErrorString* errorString, const ScriptObject& scriptObject)
    240 {
    241     if (!checkIsEnabled(errorString))
    242         return InjectedScriptCanvasModule();
    243     if (scriptObject.hasNoValue()) {
    244         ASSERT_NOT_REACHED();
    245         *errorString = "Internal error: original ScriptObject has no value";
    246         return InjectedScriptCanvasModule();
    247     }
    248     return injectedScriptCanvasModule(errorString, scriptObject.scriptState());
    249 }
    250 
    251 InjectedScriptCanvasModule InspectorCanvasAgent::injectedScriptCanvasModule(ErrorString* errorString, const String& objectId)
    252 {
    253     if (!checkIsEnabled(errorString))
    254         return InjectedScriptCanvasModule();
    255     InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(objectId);
    256     if (injectedScript.hasNoValue()) {
    257         *errorString = "Inspected frame has gone";
    258         return InjectedScriptCanvasModule();
    259     }
    260     return injectedScriptCanvasModule(errorString, injectedScript.scriptState());
    261 }
    262 
    263 void InspectorCanvasAgent::findFramesWithUninstrumentedCanvases()
    264 {
    265     class NodeVisitor : public WrappedNodeVisitor {
    266     public:
    267         NodeVisitor(Page* page, FramesWithUninstrumentedCanvases& result)
    268             : m_page(page)
    269             , m_framesWithUninstrumentedCanvases(result)
    270         {
    271         }
    272 
    273         virtual void visitNode(Node* node) OVERRIDE
    274         {
    275             if (!node->hasTagName(HTMLNames::canvasTag) || !node->document() || !node->document()->frame())
    276                 return;
    277 
    278             Frame* frame = node->document()->frame();
    279             if (frame->page() != m_page)
    280                 return;
    281 
    282             if (toHTMLCanvasElement(node)->renderingContext())
    283                 m_framesWithUninstrumentedCanvases.set(frame, true);
    284         }
    285 
    286     private:
    287         Page* m_page;
    288         FramesWithUninstrumentedCanvases& m_framesWithUninstrumentedCanvases;
    289     } nodeVisitor(m_pageAgent->page(), m_framesWithUninstrumentedCanvases);
    290 
    291     m_framesWithUninstrumentedCanvases.clear();
    292     ScriptProfiler::visitNodeWrappers(&nodeVisitor);
    293 
    294     if (m_frontend) {
    295         for (FramesWithUninstrumentedCanvases::const_iterator it = m_framesWithUninstrumentedCanvases.begin(); it != m_framesWithUninstrumentedCanvases.end(); ++it) {
    296             String frameId = m_pageAgent->frameId(it->key);
    297             if (!frameId.isEmpty())
    298                 m_frontend->contextCreated(frameId);
    299         }
    300     }
    301 }
    302 
    303 bool InspectorCanvasAgent::checkIsEnabled(ErrorString* errorString) const
    304 {
    305     if (m_enabled)
    306         return true;
    307     *errorString = "Canvas agent is not enabled";
    308     return false;
    309 }
    310 
    311 void InspectorCanvasAgent::didCommitLoad(Frame*, DocumentLoader* loader)
    312 {
    313     if (!m_enabled)
    314         return;
    315     Frame* frame = loader->frame();
    316     if (frame == m_pageAgent->mainFrame()) {
    317         for (FramesWithUninstrumentedCanvases::iterator it = m_framesWithUninstrumentedCanvases.begin(); it != m_framesWithUninstrumentedCanvases.end(); ++it)
    318             it->value = false;
    319         m_frontend->traceLogsRemoved(0, 0);
    320     } else {
    321         while (frame) {
    322             if (m_framesWithUninstrumentedCanvases.contains(frame))
    323                 m_framesWithUninstrumentedCanvases.set(frame, false);
    324             if (m_pageAgent->hasIdForFrame(frame)) {
    325                 String frameId = m_pageAgent->frameId(frame);
    326                 m_frontend->traceLogsRemoved(&frameId, 0);
    327             }
    328             frame = frame->tree()->traverseNext();
    329         }
    330     }
    331 }
    332 
    333 void InspectorCanvasAgent::frameDetachedFromParent(Frame* frame)
    334 {
    335     if (m_enabled)
    336         m_framesWithUninstrumentedCanvases.remove(frame);
    337 }
    338 
    339 void InspectorCanvasAgent::didBeginFrame()
    340 {
    341     if (!m_enabled)
    342         return;
    343     ErrorString error;
    344     for (FramesWithUninstrumentedCanvases::const_iterator it = m_framesWithUninstrumentedCanvases.begin(); it != m_framesWithUninstrumentedCanvases.end(); ++it) {
    345         InjectedScriptCanvasModule module = injectedScriptCanvasModule(&error, mainWorldScriptState(it->key));
    346         if (!module.hasNoValue())
    347             module.markFrameEnd();
    348     }
    349 }
    350 
    351 } // namespace WebCore
    352 
    353