Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "web/SuspendableScriptExecutor.h" | 5 #include "web/SuspendableScriptExecutor.h" |
| 6 | 6 |
| 7 #include "bindings/core/v8/ScriptController.h" | 7 #include "bindings/core/v8/ScriptController.h" |
| 8 #include "bindings/core/v8/ScriptSourceCode.h" | 8 #include "bindings/core/v8/ScriptSourceCode.h" |
| 9 #include "bindings/core/v8/V8PersistentValueVector.h" | 9 #include "bindings/core/v8/V8PersistentValueVector.h" |
| 10 #include "bindings/core/v8/WindowProxy.h" | |
| 10 #include "core/dom/Document.h" | 11 #include "core/dom/Document.h" |
| 11 #include "core/dom/DocumentUserGestureToken.h" | 12 #include "core/dom/DocumentUserGestureToken.h" |
| 12 #include "core/frame/LocalFrame.h" | 13 #include "core/frame/LocalFrame.h" |
| 13 #include "platform/UserGestureIndicator.h" | 14 #include "platform/UserGestureIndicator.h" |
| 14 #include "public/platform/WebVector.h" | 15 #include "public/platform/WebVector.h" |
| 15 #include "public/web/WebScriptExecutionCallback.h" | 16 #include "public/web/WebScriptExecutionCallback.h" |
| 16 #include "wtf/PtrUtil.h" | 17 #include "wtf/PtrUtil.h" |
| 17 #include "wtf/Vector.h" | 18 #include "wtf/Vector.h" |
| 18 #include <memory> | 19 #include <memory> |
| 19 | 20 |
| 20 namespace blink { | 21 namespace blink { |
| 21 | 22 |
| 22 namespace { | 23 namespace { |
| 23 | 24 |
| 24 class WebScriptExecutor : public SuspendableScriptExecutor::Executor { | 25 class WebScriptExecutor : public SuspendableScriptExecutor::Executor { |
| 25 public: | 26 public: |
| 26 WebScriptExecutor(const HeapVector<ScriptSourceCode>& sources, | 27 WebScriptExecutor(const HeapVector<ScriptSourceCode>& sources, |
| 27 int worldID, | 28 int worldID, |
| 28 int extensionGroup, | 29 int extensionGroup, |
| 29 bool userGesture); | 30 bool userGesture); |
| 30 | 31 |
| 31 Vector<v8::Local<v8::Value>> execute(LocalFrame*) override; | 32 Vector<v8::Local<v8::Value>> execute(LocalFrame*) override; |
| 33 ScriptState* getScriptState(LocalFrame*) override; | |
|
dcheng
2016/10/29 04:36:21
It is possible to bind ScriptState when we create
Devlin
2016/10/29 17:45:50
Potentially (and I was going to do this originally
dcheng
2016/11/01 00:14:05
I think that this is OK, and will be simpler overa
Devlin
2016/11/03 01:17:08
Done.
| |
| 32 | 34 |
| 33 DEFINE_INLINE_VIRTUAL_TRACE() { | 35 DEFINE_INLINE_VIRTUAL_TRACE() { |
| 34 visitor->trace(m_sources); | 36 visitor->trace(m_sources); |
| 35 SuspendableScriptExecutor::Executor::trace(visitor); | 37 SuspendableScriptExecutor::Executor::trace(visitor); |
| 36 } | 38 } |
| 37 | 39 |
| 38 private: | 40 private: |
| 39 HeapVector<ScriptSourceCode> m_sources; | 41 HeapVector<ScriptSourceCode> m_sources; |
| 40 int m_worldID; | 42 int m_worldID; |
| 41 int m_extensionGroup; | 43 int m_extensionGroup; |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 67 } else { | 69 } else { |
| 68 v8::Local<v8::Value> scriptValue = | 70 v8::Local<v8::Value> scriptValue = |
| 69 frame->script().executeScriptInMainWorldAndReturnValue( | 71 frame->script().executeScriptInMainWorldAndReturnValue( |
| 70 m_sources.first()); | 72 m_sources.first()); |
| 71 results.append(scriptValue); | 73 results.append(scriptValue); |
| 72 } | 74 } |
| 73 | 75 |
| 74 return results; | 76 return results; |
| 75 } | 77 } |
| 76 | 78 |
| 79 ScriptState* WebScriptExecutor::getScriptState(LocalFrame* frame) { | |
| 80 if (!m_worldID) | |
| 81 return ScriptState::forMainWorld(frame); | |
| 82 | |
| 83 RefPtr<DOMWrapperWorld> world = DOMWrapperWorld::ensureIsolatedWorld( | |
|
haraken
2016/10/29 01:41:06
Can you implement DOMWwrapperWorld::fromWorldId(in
Devlin
2016/10/31 17:00:46
Done. It's a little awkward because it requires p
| |
| 84 v8::Isolate::GetCurrent(), m_worldID, m_extensionGroup); | |
| 85 WindowProxy* windowProxy = frame->script().windowProxy(*world); | |
| 86 return windowProxy->isContextInitialized() ? windowProxy->getScriptState() | |
|
haraken
2016/10/29 01:41:06
You can just use ScriptState::forWorld(world).
Devlin
2016/10/31 17:00:47
Ah, handy. Done.
| |
| 87 : nullptr; | |
| 88 } | |
| 89 | |
| 77 class V8FunctionExecutor : public SuspendableScriptExecutor::Executor { | 90 class V8FunctionExecutor : public SuspendableScriptExecutor::Executor { |
| 78 public: | 91 public: |
| 79 V8FunctionExecutor(v8::Isolate*, | 92 V8FunctionExecutor(v8::Isolate*, |
| 80 ScriptState*, | 93 ScriptState*, |
| 81 v8::Local<v8::Function>, | 94 v8::Local<v8::Function>, |
| 82 v8::Local<v8::Value> receiver, | 95 v8::Local<v8::Value> receiver, |
| 83 int argc, | 96 int argc, |
| 84 v8::Local<v8::Value> argv[]); | 97 v8::Local<v8::Value> argv[]); |
| 85 | 98 |
| 86 Vector<v8::Local<v8::Value>> execute(LocalFrame*) override; | 99 Vector<v8::Local<v8::Value>> execute(LocalFrame*) override; |
| 100 ScriptState* getScriptState(LocalFrame*) override { | |
| 101 return m_scriptState.get(); | |
| 102 } | |
| 87 | 103 |
| 88 private: | 104 private: |
| 89 ScopedPersistent<v8::Function> m_function; | 105 ScopedPersistent<v8::Function> m_function; |
| 90 ScopedPersistent<v8::Value> m_receiver; | 106 ScopedPersistent<v8::Value> m_receiver; |
| 91 V8PersistentValueVector<v8::Value> m_args; | 107 V8PersistentValueVector<v8::Value> m_args; |
| 92 RefPtr<ScriptState> m_scriptState; | 108 RefPtr<ScriptState> m_scriptState; |
| 109 RefPtr<UserGestureToken> m_gestureToken; | |
| 93 }; | 110 }; |
| 94 | 111 |
| 95 V8FunctionExecutor::V8FunctionExecutor(v8::Isolate* isolate, | 112 V8FunctionExecutor::V8FunctionExecutor(v8::Isolate* isolate, |
| 96 ScriptState* scriptState, | 113 ScriptState* scriptState, |
| 97 v8::Local<v8::Function> function, | 114 v8::Local<v8::Function> function, |
| 98 v8::Local<v8::Value> receiver, | 115 v8::Local<v8::Value> receiver, |
| 99 int argc, | 116 int argc, |
| 100 v8::Local<v8::Value> argv[]) | 117 v8::Local<v8::Value> argv[]) |
| 101 : m_function(isolate, function), | 118 : m_function(isolate, function), |
| 102 m_receiver(isolate, receiver), | 119 m_receiver(isolate, receiver), |
| 103 m_args(isolate), | 120 m_args(isolate), |
| 104 m_scriptState(scriptState) { | 121 m_scriptState(scriptState), |
| 122 m_gestureToken(UserGestureIndicator::currentToken()) { | |
| 105 m_args.ReserveCapacity(argc); | 123 m_args.ReserveCapacity(argc); |
| 106 for (int i = 0; i < argc; ++i) | 124 for (int i = 0; i < argc; ++i) |
| 107 m_args.Append(argv[i]); | 125 m_args.Append(argv[i]); |
| 108 } | 126 } |
| 109 | 127 |
| 110 Vector<v8::Local<v8::Value>> V8FunctionExecutor::execute(LocalFrame* frame) { | 128 Vector<v8::Local<v8::Value>> V8FunctionExecutor::execute(LocalFrame* frame) { |
| 111 v8::Isolate* isolate = v8::Isolate::GetCurrent(); | 129 v8::Isolate* isolate = v8::Isolate::GetCurrent(); |
| 112 Vector<v8::Local<v8::Value>> results; | 130 Vector<v8::Local<v8::Value>> results; |
| 113 if (!m_scriptState->contextIsValid()) | 131 DCHECK(m_scriptState->contextIsValid()); |
| 114 return results; | |
| 115 ScriptState::Scope scope(m_scriptState.get()); | |
| 116 v8::Local<v8::Value> singleResult; | 132 v8::Local<v8::Value> singleResult; |
| 117 Vector<v8::Local<v8::Value>> args; | 133 Vector<v8::Local<v8::Value>> args; |
| 118 args.reserveCapacity(m_args.Size()); | 134 args.reserveCapacity(m_args.Size()); |
| 119 for (size_t i = 0; i < m_args.Size(); ++i) | 135 for (size_t i = 0; i < m_args.Size(); ++i) |
| 120 args.append(m_args.Get(i)); | 136 args.append(m_args.Get(i)); |
| 121 if (V8ScriptRunner::callFunction(m_function.newLocal(isolate), | 137 { |
| 122 frame->document(), | 138 std::unique_ptr<UserGestureIndicator> gestureIndicator; |
| 123 m_receiver.newLocal(isolate), args.size(), | 139 // It's important that we don't pass the gesture if it's already the |
| 124 args.data(), toIsolate(frame)) | 140 // current token, because otherwise once this goes out of scope, the gesture |
| 125 .ToLocal(&singleResult)) | 141 // is removed and is no longer considered to be processing. Thus, if |
| 126 results.append(singleResult); | 142 // execute() were called re-entrantly, we would lose the gesture while it |
| 143 // should still be being processed. | |
|
Devlin
2016/10/28 20:31:37
Continuing the crazy fun.
If we pass m_gestureTok
dcheng
2016/10/29 04:36:21
I feel like it would be surprising if this were di
Devlin
2016/10/29 17:45:50
Extensions code can do this, given how many times
| |
| 144 if (m_gestureToken && | |
| 145 UserGestureIndicator::currentToken() != m_gestureToken) { | |
| 146 gestureIndicator = | |
| 147 wrapUnique(new UserGestureIndicator(m_gestureToken.release())); | |
| 148 } | |
| 149 if (V8ScriptRunner::callFunction(m_function.newLocal(isolate), | |
| 150 frame->document(), | |
| 151 m_receiver.newLocal(isolate), args.size(), | |
| 152 args.data(), toIsolate(frame)) | |
| 153 .ToLocal(&singleResult)) | |
| 154 results.append(singleResult); | |
| 155 } | |
| 127 return results; | 156 return results; |
| 128 } | 157 } |
| 129 | 158 |
| 130 } // namespace | 159 } // namespace |
| 131 | 160 |
| 132 void SuspendableScriptExecutor::createAndRun( | 161 void SuspendableScriptExecutor::createAndRun( |
| 133 LocalFrame* frame, | 162 LocalFrame* frame, |
| 134 int worldID, | 163 int worldID, |
| 135 const HeapVector<ScriptSourceCode>& sources, | 164 const HeapVector<ScriptSourceCode>& sources, |
| 136 int extensionGroup, | 165 int extensionGroup, |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 192 if (!context->activeDOMObjectsAreSuspended()) { | 221 if (!context->activeDOMObjectsAreSuspended()) { |
| 193 suspendIfNeeded(); | 222 suspendIfNeeded(); |
| 194 executeAndDestroySelf(); | 223 executeAndDestroySelf(); |
| 195 return; | 224 return; |
| 196 } | 225 } |
| 197 startOneShot(0, BLINK_FROM_HERE); | 226 startOneShot(0, BLINK_FROM_HERE); |
| 198 suspendIfNeeded(); | 227 suspendIfNeeded(); |
| 199 } | 228 } |
| 200 | 229 |
| 201 void SuspendableScriptExecutor::executeAndDestroySelf() { | 230 void SuspendableScriptExecutor::executeAndDestroySelf() { |
| 202 v8::HandleScope scope(v8::Isolate::GetCurrent()); | 231 ScriptState* scriptState = m_executor->getScriptState(m_frame); |
| 203 Vector<v8::Local<v8::Value>> results = m_executor->execute(m_frame); | 232 if (scriptState && scriptState->contextIsValid()) { |
|
dcheng
2016/10/29 04:36:21
Is it possible to get here if there is not valid S
Devlin
2016/10/31 17:00:47
I'd prefer to not remove any checks just yet since
| |
| 233 ScriptState::Scope scriptScope(scriptState); | |
| 234 Vector<v8::Local<v8::Value>> results = m_executor->execute(m_frame); | |
| 204 | 235 |
| 205 // The script may have removed the frame, in which case contextDestroyed() | 236 // The script may have removed the frame, in which case contextDestroyed() |
| 206 // will have handled the disposal/callback. | 237 // will have handled the disposal/callback. |
| 207 if (!m_frame->client()) | 238 if (!m_frame->client()) |
|
dcheng
2016/10/29 04:36:21
Can we just check lifecycleContext() here?
Devlin
2016/10/31 17:00:46
I think so. Done.
| |
| 208 return; | 239 return; |
| 209 | 240 |
| 210 if (m_callback) | 241 // We need to call the callback before scriptScope goes out of scope. |
| 211 m_callback->completed(results); | 242 if (m_callback) |
|
dcheng
2016/10/29 04:36:21
Nit: is it possible to remove this if ()? It seems
Devlin
2016/10/29 17:45:49
Extensions code can often do this, since we only c
| |
| 243 m_callback->completed(results); | |
| 244 } else { | |
| 245 if (m_callback) | |
| 246 m_callback->completed(Vector<v8::Local<v8::Value>>()); | |
| 247 } | |
| 248 | |
| 212 dispose(); | 249 dispose(); |
| 213 } | 250 } |
| 214 | 251 |
| 215 void SuspendableScriptExecutor::dispose() { | 252 void SuspendableScriptExecutor::dispose() { |
| 216 // Remove object as a ContextLifecycleObserver. | 253 // Remove object as a ContextLifecycleObserver. |
| 217 ActiveDOMObject::clearContext(); | 254 ActiveDOMObject::clearContext(); |
| 218 m_keepAlive.clear(); | 255 m_keepAlive.clear(); |
| 219 stop(); | 256 stop(); |
| 220 } | 257 } |
| 221 | 258 |
| 222 DEFINE_TRACE(SuspendableScriptExecutor) { | 259 DEFINE_TRACE(SuspendableScriptExecutor) { |
| 223 visitor->trace(m_frame); | 260 visitor->trace(m_frame); |
| 224 visitor->trace(m_executor); | 261 visitor->trace(m_executor); |
| 225 SuspendableTimer::trace(visitor); | 262 SuspendableTimer::trace(visitor); |
| 226 } | 263 } |
| 227 | 264 |
| 228 } // namespace blink | 265 } // namespace blink |
| OLD | NEW |