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