Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(18)

Unified Diff: third_party/WebKit/Source/web/SuspendableScriptExecutor.cpp

Issue 2454433002: [Extensions + Blink] Account for user gesture in v8 function calls (Closed)
Patch Set: script state changes Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/WebKit/Source/web/SuspendableScriptExecutor.cpp
diff --git a/third_party/WebKit/Source/web/SuspendableScriptExecutor.cpp b/third_party/WebKit/Source/web/SuspendableScriptExecutor.cpp
index 20aba329814e771e03d166318aecd919a4079194..79f0972c9cbedee48f96def7d05cd04c622dab56 100644
--- a/third_party/WebKit/Source/web/SuspendableScriptExecutor.cpp
+++ b/third_party/WebKit/Source/web/SuspendableScriptExecutor.cpp
@@ -7,6 +7,7 @@
#include "bindings/core/v8/ScriptController.h"
#include "bindings/core/v8/ScriptSourceCode.h"
#include "bindings/core/v8/V8PersistentValueVector.h"
+#include "bindings/core/v8/WindowProxy.h"
#include "core/dom/Document.h"
#include "core/dom/DocumentUserGestureToken.h"
#include "core/frame/LocalFrame.h"
@@ -29,6 +30,7 @@ class WebScriptExecutor : public SuspendableScriptExecutor::Executor {
bool userGesture);
Vector<v8::Local<v8::Value>> execute(LocalFrame*) override;
+ 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.
DEFINE_INLINE_VIRTUAL_TRACE() {
visitor->trace(m_sources);
@@ -74,6 +76,17 @@ Vector<v8::Local<v8::Value>> WebScriptExecutor::execute(LocalFrame* frame) {
return results;
}
+ScriptState* WebScriptExecutor::getScriptState(LocalFrame* frame) {
+ if (!m_worldID)
+ return ScriptState::forMainWorld(frame);
+
+ 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
+ v8::Isolate::GetCurrent(), m_worldID, m_extensionGroup);
+ WindowProxy* windowProxy = frame->script().windowProxy(*world);
+ 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.
+ : nullptr;
+}
+
class V8FunctionExecutor : public SuspendableScriptExecutor::Executor {
public:
V8FunctionExecutor(v8::Isolate*,
@@ -84,12 +97,16 @@ class V8FunctionExecutor : public SuspendableScriptExecutor::Executor {
v8::Local<v8::Value> argv[]);
Vector<v8::Local<v8::Value>> execute(LocalFrame*) override;
+ ScriptState* getScriptState(LocalFrame*) override {
+ return m_scriptState.get();
+ }
private:
ScopedPersistent<v8::Function> m_function;
ScopedPersistent<v8::Value> m_receiver;
V8PersistentValueVector<v8::Value> m_args;
RefPtr<ScriptState> m_scriptState;
+ RefPtr<UserGestureToken> m_gestureToken;
};
V8FunctionExecutor::V8FunctionExecutor(v8::Isolate* isolate,
@@ -101,7 +118,8 @@ V8FunctionExecutor::V8FunctionExecutor(v8::Isolate* isolate,
: m_function(isolate, function),
m_receiver(isolate, receiver),
m_args(isolate),
- m_scriptState(scriptState) {
+ m_scriptState(scriptState),
+ m_gestureToken(UserGestureIndicator::currentToken()) {
m_args.ReserveCapacity(argc);
for (int i = 0; i < argc; ++i)
m_args.Append(argv[i]);
@@ -110,20 +128,31 @@ V8FunctionExecutor::V8FunctionExecutor(v8::Isolate* isolate,
Vector<v8::Local<v8::Value>> V8FunctionExecutor::execute(LocalFrame* frame) {
v8::Isolate* isolate = v8::Isolate::GetCurrent();
Vector<v8::Local<v8::Value>> results;
- if (!m_scriptState->contextIsValid())
- return results;
- ScriptState::Scope scope(m_scriptState.get());
+ DCHECK(m_scriptState->contextIsValid());
v8::Local<v8::Value> singleResult;
Vector<v8::Local<v8::Value>> args;
args.reserveCapacity(m_args.Size());
for (size_t i = 0; i < m_args.Size(); ++i)
args.append(m_args.Get(i));
- if (V8ScriptRunner::callFunction(m_function.newLocal(isolate),
- frame->document(),
- m_receiver.newLocal(isolate), args.size(),
- args.data(), toIsolate(frame))
- .ToLocal(&singleResult))
- results.append(singleResult);
+ {
+ std::unique_ptr<UserGestureIndicator> gestureIndicator;
+ // It's important that we don't pass the gesture if it's already the
+ // current token, because otherwise once this goes out of scope, the gesture
+ // is removed and is no longer considered to be processing. Thus, if
+ // execute() were called re-entrantly, we would lose the gesture while it
+ // 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
+ if (m_gestureToken &&
+ UserGestureIndicator::currentToken() != m_gestureToken) {
+ gestureIndicator =
+ wrapUnique(new UserGestureIndicator(m_gestureToken.release()));
+ }
+ if (V8ScriptRunner::callFunction(m_function.newLocal(isolate),
+ frame->document(),
+ m_receiver.newLocal(isolate), args.size(),
+ args.data(), toIsolate(frame))
+ .ToLocal(&singleResult))
+ results.append(singleResult);
+ }
return results;
}
@@ -199,16 +228,24 @@ void SuspendableScriptExecutor::run() {
}
void SuspendableScriptExecutor::executeAndDestroySelf() {
- v8::HandleScope scope(v8::Isolate::GetCurrent());
- Vector<v8::Local<v8::Value>> results = m_executor->execute(m_frame);
+ ScriptState* scriptState = m_executor->getScriptState(m_frame);
+ 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
+ ScriptState::Scope scriptScope(scriptState);
+ Vector<v8::Local<v8::Value>> results = m_executor->execute(m_frame);
- // The script may have removed the frame, in which case contextDestroyed()
- // will have handled the disposal/callback.
- if (!m_frame->client())
- return;
+ // The script may have removed the frame, in which case contextDestroyed()
+ // will have handled the disposal/callback.
+ 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.
+ return;
+
+ // We need to call the callback before scriptScope goes out of scope.
+ 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
+ m_callback->completed(results);
+ } else {
+ if (m_callback)
+ m_callback->completed(Vector<v8::Local<v8::Value>>());
+ }
- if (m_callback)
- m_callback->completed(results);
dispose();
}

Powered by Google App Engine
This is Rietveld 408576698