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