Chromium Code Reviews| Index: extensions/renderer/render_frame_observer_natives.cc |
| diff --git a/extensions/renderer/render_frame_observer_natives.cc b/extensions/renderer/render_frame_observer_natives.cc |
| index c3a147ddd4b657ec3e31f4cb9807918185a54084..1c1f06e87f3217890d3519e426f51be50ebc4542 100644 |
| --- a/extensions/renderer/render_frame_observer_natives.cc |
| +++ b/extensions/renderer/render_frame_observer_natives.cc |
| @@ -19,43 +19,29 @@ namespace { |
| // Deletes itself when done. |
| class LoadWatcher : public content::RenderFrameObserver { |
| public: |
| - LoadWatcher(ScriptContext* context, |
| - content::RenderFrame* frame, |
| - v8::Local<v8::Function> cb) |
| - : content::RenderFrameObserver(frame), |
| - context_(context), |
| - callback_(context->isolate(), cb) { |
| - if (ExtensionFrameHelper::Get(frame)-> |
| - did_create_current_document_element()) { |
| - // If the document element is already created, then we can call the |
| - // callback immediately (though post it to the message loop so as to not |
| - // call it re-entrantly). |
| - // The Unretained is safe because this class manages its own lifetime. |
| - base::MessageLoop::current()->PostTask( |
| - FROM_HERE, |
| - base::Bind(&LoadWatcher::CallbackAndDie, base::Unretained(this), |
| - true)); |
| - } |
| + LoadWatcher(content::RenderFrame* frame, |
| + const base::Callback<void(bool)>& callback) |
| + : content::RenderFrameObserver(frame), callback_(callback) {} |
| + |
| + void DidCreateDocumentElement() override { |
| + // The callback must be run as soon as the root element is available. |
| + // Running the callback may trigger DidCreateDocumentElement or |
| + // DidFailProvisionalLoad, so delete this before running the callback. |
| + base::Callback<void(bool)> callback = callback_; |
| + delete this; |
| + callback.Run(true); |
| } |
| - void DidCreateDocumentElement() override { CallbackAndDie(true); } |
| - |
| void DidFailProvisionalLoad(const blink::WebURLError& error) override { |
| - CallbackAndDie(false); |
| - } |
| - |
| - private: |
| - void CallbackAndDie(bool succeeded) { |
| - v8::Isolate* isolate = context_->isolate(); |
| - v8::HandleScope handle_scope(isolate); |
| - v8::Local<v8::Value> args[] = {v8::Boolean::New(isolate, succeeded)}; |
| - context_->CallFunction(v8::Local<v8::Function>::New(isolate, callback_), |
| - arraysize(args), args); |
| + // Use PostTask to avoid running user scripts while handling this |
| + // DidFailProvisionalLoad notification. |
| + base::MessageLoop::current()->PostTask(FROM_HERE, |
| + base::Bind(callback_, false)); |
| delete this; |
| } |
| - ScriptContext* context_; |
| - v8::Global<v8::Function> callback_; |
| + private: |
| + base::Callback<void(bool)> callback_; |
| DISALLOW_COPY_AND_ASSIGN(LoadWatcher); |
| }; |
| @@ -63,13 +49,20 @@ class LoadWatcher : public content::RenderFrameObserver { |
| } // namespace |
| RenderFrameObserverNatives::RenderFrameObserverNatives(ScriptContext* context) |
| - : ObjectBackedNativeHandler(context) { |
| + : ObjectBackedNativeHandler(context), weak_ptr_factory_(this) { |
| RouteFunction( |
| "OnDocumentElementCreated", |
| base::Bind(&RenderFrameObserverNatives::OnDocumentElementCreated, |
| base::Unretained(this))); |
| } |
| +RenderFrameObserverNatives::~RenderFrameObserverNatives() {} |
| + |
| +void RenderFrameObserverNatives::Invalidate() { |
| + weak_ptr_factory_.InvalidateWeakPtrs(); |
| + ObjectBackedNativeHandler::Invalidate(); |
| +} |
| + |
| void RenderFrameObserverNatives::OnDocumentElementCreated( |
| const v8::FunctionCallbackInfo<v8::Value>& args) { |
| CHECK(args.Length() == 2); |
| @@ -84,9 +77,32 @@ void RenderFrameObserverNatives::OnDocumentElementCreated( |
| return; |
| } |
| - new LoadWatcher(context(), frame, args[1].As<v8::Function>()); |
| + v8::Global<v8::Function> v8_callback(context()->isolate(), |
|
Devlin
2016/02/10 20:30:47
Something else I just thought of:
v8::Globals are
robwu
2016/02/10 20:45:49
I don't know, I'm a complete noob with V8 (I just
Devlin
2016/02/10 20:59:00
Let's go with this for now - it's certainly better
|
| + args[1].As<v8::Function>()); |
| + base::Callback<void(bool)> callback( |
| + base::Bind(&RenderFrameObserverNatives::InvokeCallback, |
| + weak_ptr_factory_.GetWeakPtr(), base::Passed(&v8_callback))); |
| + if (ExtensionFrameHelper::Get(frame)->did_create_current_document_element()) { |
| + // If the document element is already created, then we can call the callback |
| + // immediately (though use PostTask to ensure that the callback is called |
| + // asynchronously). |
| + base::MessageLoop::current()->PostTask(FROM_HERE, |
| + base::Bind(callback, true)); |
| + } else { |
| + new LoadWatcher(frame, callback); |
| + } |
| args.GetReturnValue().Set(true); |
| } |
| +void RenderFrameObserverNatives::InvokeCallback( |
| + v8::Global<v8::Function> callback, |
| + bool succeeded) { |
| + v8::Isolate* isolate = context()->isolate(); |
| + v8::HandleScope handle_scope(isolate); |
| + v8::Local<v8::Value> args[] = {v8::Boolean::New(isolate, succeeded)}; |
| + context()->CallFunction(v8::Local<v8::Function>::New(isolate, callback), |
| + arraysize(args), args); |
| +} |
| + |
| } // namespace extensions |