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