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