Roll src/third_party/WebKit d9c6159:8139f33 (svn 201974:201975)
[chromium-blink-merge.git] / extensions / renderer / wake_event_page.cc
blob1bc43042c79e092bb839c21d7ae56a1fe7326d00
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "extensions/renderer/wake_event_page.h"
7 #include "base/atomic_sequence_num.h"
8 #include "base/bind.h"
9 #include "base/bind_helpers.h"
10 #include "base/logging.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "content/public/renderer/render_thread.h"
13 #include "extensions/common/extension_messages.h"
14 #include "extensions/renderer/object_backed_native_handler.h"
15 #include "extensions/renderer/script_context.h"
16 #include "extensions/renderer/v8_helpers.h"
17 #include "ipc/ipc_message.h"
18 #include "ipc/ipc_message_macros.h"
20 namespace extensions {
22 using namespace v8_helpers;
24 namespace {
26 base::LazyInstance<WakeEventPage> g_instance = LAZY_INSTANCE_INITIALIZER;
28 } // namespace
30 class WakeEventPage::WakeEventPageNativeHandler
31 : public ObjectBackedNativeHandler {
32 public:
33 // Handles own lifetime.
34 WakeEventPageNativeHandler(ScriptContext* context,
35 const std::string& name,
36 const MakeRequestCallback& make_request)
37 : ObjectBackedNativeHandler(context),
38 make_request_(make_request),
39 weak_ptr_factory_(this) {
40 // Use Unretained not a WeakPtr because RouteFunction is tied to the
41 // lifetime of this, so there is no way for DoWakeEventPage to be called
42 // after destruction.
43 RouteFunction(name, base::Bind(&WakeEventPageNativeHandler::DoWakeEventPage,
44 base::Unretained(this)));
45 // Delete self on invalidation. base::Unretained because by definition this
46 // can't be deleted before it's deleted.
47 context->AddInvalidationObserver(base::Bind(
48 &WakeEventPageNativeHandler::DeleteSelf, base::Unretained(this)));
51 ~WakeEventPageNativeHandler() override {}
53 private:
54 void DeleteSelf() {
55 Invalidate();
56 delete this;
59 // Called by JavaScript with a single argument, the function to call when the
60 // event page has been woken.
61 void DoWakeEventPage(const v8::FunctionCallbackInfo<v8::Value>& args) {
62 CHECK_EQ(1, args.Length());
63 CHECK(args[0]->IsFunction());
64 v8::Global<v8::Function> callback(args.GetIsolate(),
65 args[0].As<v8::Function>());
67 const std::string& extension_id = context()->GetExtensionID();
68 CHECK(!extension_id.empty());
70 make_request_.Run(
71 extension_id,
72 base::Bind(&WakeEventPageNativeHandler::OnEventPageIsAwake,
73 weak_ptr_factory_.GetWeakPtr(), base::Passed(&callback)));
76 void OnEventPageIsAwake(v8::Global<v8::Function> callback, bool success) {
77 v8::Isolate* isolate = context()->isolate();
78 v8::HandleScope handle_scope(isolate);
79 v8::Local<v8::Value> args[] = {
80 v8::Boolean::New(isolate, success),
82 context()->CallFunction(v8::Local<v8::Function>::New(isolate, callback),
83 arraysize(args), args);
86 MakeRequestCallback make_request_;
87 base::WeakPtrFactory<WakeEventPageNativeHandler> weak_ptr_factory_;
89 DISALLOW_COPY_AND_ASSIGN(WakeEventPageNativeHandler);
92 // static
93 WakeEventPage* WakeEventPage::Get() {
94 return g_instance.Pointer();
97 void WakeEventPage::Init(content::RenderThread* render_thread) {
98 DCHECK(render_thread);
99 DCHECK_EQ(content::RenderThread::Get(), render_thread);
100 DCHECK(!message_filter_);
102 message_filter_ = render_thread->GetSyncMessageFilter();
103 render_thread->AddObserver(this);
106 v8::Local<v8::Function> WakeEventPage::GetForContext(ScriptContext* context) {
107 DCHECK(message_filter_);
109 v8::Isolate* isolate = context->isolate();
110 v8::EscapableHandleScope handle_scope(isolate);
111 v8::Handle<v8::Context> v8_context = context->v8_context();
112 v8::Context::Scope context_scope(v8_context);
114 // Cache the imported function as a hidden property on the global object of
115 // |v8_context|. Creating it isn't free.
116 v8::Local<v8::String> kWakeEventPageKey =
117 ToV8StringUnsafe(isolate, "WakeEventPage");
118 v8::Local<v8::Value> wake_event_page =
119 v8_context->Global()->GetHiddenValue(kWakeEventPageKey);
121 if (wake_event_page.IsEmpty()) {
122 // Implement this using a NativeHandler, which requires a function name
123 // (arbitrary in this case). Handles own lifetime.
124 const char* kFunctionName = "WakeEventPage";
125 WakeEventPageNativeHandler* native_handler = new WakeEventPageNativeHandler(
126 context, kFunctionName, base::Bind(&WakeEventPage::MakeRequest,
127 weak_ptr_factory_.GetWeakPtr()));
129 // Extract and cache the wake-event-page function from the native handler.
130 wake_event_page = GetPropertyUnsafe(
131 v8_context, native_handler->NewInstance(), kFunctionName);
132 v8_context->Global()->SetHiddenValue(kWakeEventPageKey, wake_event_page);
135 CHECK(wake_event_page->IsFunction());
136 return handle_scope.Escape(wake_event_page.As<v8::Function>());
139 WakeEventPage::RequestData::RequestData(const OnResponseCallback& on_response)
140 : on_response(on_response) {}
142 WakeEventPage::RequestData::~RequestData() {}
144 WakeEventPage::WakeEventPage() : weak_ptr_factory_(this) {}
146 WakeEventPage::~WakeEventPage() {}
148 void WakeEventPage::MakeRequest(const std::string& extension_id,
149 const OnResponseCallback& on_response) {
150 static base::AtomicSequenceNumber sequence_number;
151 int request_id = sequence_number.GetNext();
152 requests_.set(request_id, make_scoped_ptr(new RequestData(on_response)));
153 message_filter_->Send(
154 new ExtensionHostMsg_WakeEventPage(request_id, extension_id));
157 bool WakeEventPage::OnControlMessageReceived(const IPC::Message& message) {
158 bool handled = true;
159 IPC_BEGIN_MESSAGE_MAP(WakeEventPage, message)
160 IPC_MESSAGE_HANDLER(ExtensionMsg_WakeEventPageResponse,
161 OnWakeEventPageResponse)
162 IPC_MESSAGE_UNHANDLED(handled = false)
163 IPC_END_MESSAGE_MAP()
164 return handled;
167 void WakeEventPage::OnWakeEventPageResponse(int request_id, bool success) {
168 scoped_ptr<RequestData> request_data = requests_.take(request_id);
169 CHECK(request_data);
170 request_data->on_response.Run(success);
173 } // namespace extensions