diff options
Diffstat (limited to 'chromium/extensions/renderer/render_frame_observer_natives.cc')
-rw-r--r-- | chromium/extensions/renderer/render_frame_observer_natives.cc | 107 |
1 files changed, 107 insertions, 0 deletions
diff --git a/chromium/extensions/renderer/render_frame_observer_natives.cc b/chromium/extensions/renderer/render_frame_observer_natives.cc new file mode 100644 index 00000000000..7c507b37993 --- /dev/null +++ b/chromium/extensions/renderer/render_frame_observer_natives.cc @@ -0,0 +1,107 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "extensions/renderer/render_frame_observer_natives.h" + +#include "base/bind.h" +#include "base/macros.h" +#include "base/message_loop/message_loop.h" +#include "content/public/renderer/render_frame.h" +#include "content/public/renderer/render_frame_observer.h" +#include "extensions/renderer/extension_frame_helper.h" +#include "extensions/renderer/script_context.h" + +namespace extensions { + +namespace { + +// Deletes itself when done. +class LoadWatcher : public content::RenderFrameObserver { + public: + LoadWatcher(content::RenderFrame* frame, + const base::Callback<void(bool)>& callback) + : content::RenderFrameObserver(frame), callback_(callback) {} + + void DidCreateDocumentElement() override { + // Defer the callback instead of running it now to avoid re-entrancy caused + // by the JavaScript callback. + ExtensionFrameHelper::Get(render_frame()) + ->ScheduleAtDocumentStart(base::Bind(callback_, true)); + delete this; + } + + void DidFailProvisionalLoad(const blink::WebURLError& error) override { + // Use PostTask to avoid running user scripts while handling this + // DidFailProvisionalLoad notification. + base::MessageLoop::current()->PostTask(FROM_HERE, + base::Bind(callback_, false)); + delete this; + } + + private: + base::Callback<void(bool)> callback_; + + DISALLOW_COPY_AND_ASSIGN(LoadWatcher); +}; + +} // namespace + +RenderFrameObserverNatives::RenderFrameObserverNatives(ScriptContext* 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); + CHECK(args[0]->IsInt32()); + CHECK(args[1]->IsFunction()); + + int frame_id = args[0]->Int32Value(); + + content::RenderFrame* frame = content::RenderFrame::FromRoutingID(frame_id); + if (!frame) { + LOG(WARNING) << "No render frame found to register LoadWatcher."; + return; + } + + v8::Global<v8::Function> v8_callback(context()->isolate(), + 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 |