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
3 // found in the LICENSE file.
4 
5 #include "mojo/edk/js/waiting_callback.h"
6 
7 #include "base/bind.h"
8 #include "base/message_loop/message_loop.h"
9 #include "gin/per_context_data.h"
10 
11 namespace mojo {
12 namespace edk {
13 namespace js {
14 
15 namespace {
16 
GetHiddenPropertyName(v8::Isolate * isolate)17 v8::Handle<v8::Private> GetHiddenPropertyName(v8::Isolate* isolate) {
18   return v8::Private::ForApi(
19       isolate, gin::StringToV8(isolate, "::mojo::js::WaitingCallback"));
20 }
21 
22 }  // namespace
23 
24 gin::WrapperInfo WaitingCallback::kWrapperInfo = { gin::kEmbedderNativeGin };
25 
26 // static
Create(v8::Isolate * isolate,v8::Handle<v8::Function> callback,gin::Handle<HandleWrapper> handle_wrapper,MojoHandleSignals signals,bool one_shot)27 gin::Handle<WaitingCallback> WaitingCallback::Create(
28     v8::Isolate* isolate,
29     v8::Handle<v8::Function> callback,
30     gin::Handle<HandleWrapper> handle_wrapper,
31     MojoHandleSignals signals,
32     bool one_shot) {
33   gin::Handle<WaitingCallback> waiting_callback = gin::CreateHandle(
34       isolate, new WaitingCallback(isolate, callback, one_shot));
35   MojoResult result = waiting_callback->watcher_.Start(
36       handle_wrapper->get(), signals,
37       base::Bind(&WaitingCallback::OnHandleReady,
38                  base::Unretained(waiting_callback.get())));
39 
40   // The signals may already be unsatisfiable.
41   if (result == MOJO_RESULT_FAILED_PRECONDITION)
42     waiting_callback->OnHandleReady(MOJO_RESULT_FAILED_PRECONDITION);
43 
44   return waiting_callback;
45 }
46 
Cancel()47 void WaitingCallback::Cancel() {
48   if (watcher_.IsWatching())
49     watcher_.Cancel();
50 }
51 
WaitingCallback(v8::Isolate * isolate,v8::Handle<v8::Function> callback,bool one_shot)52 WaitingCallback::WaitingCallback(v8::Isolate* isolate,
53                                  v8::Handle<v8::Function> callback,
54                                  bool one_shot)
55     : one_shot_(one_shot),
56       weak_factory_(this) {
57   v8::Handle<v8::Context> context = isolate->GetCurrentContext();
58   runner_ = gin::PerContextData::From(context)->runner()->GetWeakPtr();
59   GetWrapper(isolate)
60       ->SetPrivate(context, GetHiddenPropertyName(isolate), callback)
61       .FromJust();
62 }
63 
~WaitingCallback()64 WaitingCallback::~WaitingCallback() {
65   Cancel();
66 }
67 
OnHandleReady(MojoResult result)68 void WaitingCallback::OnHandleReady(MojoResult result) {
69   if (!runner_)
70     return;
71 
72   gin::Runner::Scope scope(runner_.get());
73   v8::Isolate* isolate = runner_->GetContextHolder()->isolate();
74 
75   v8::Handle<v8::Value> hidden_value =
76       GetWrapper(isolate)
77           ->GetPrivate(runner_->GetContextHolder()->context(),
78                        GetHiddenPropertyName(isolate))
79           .ToLocalChecked();
80   v8::Handle<v8::Function> callback;
81   CHECK(gin::ConvertFromV8(isolate, hidden_value, &callback));
82 
83   v8::Handle<v8::Value> args[] = { gin::ConvertToV8(isolate, result) };
84   runner_->Call(callback, runner_->global(), 1, args);
85 
86   if (one_shot_ || result == MOJO_RESULT_CANCELLED) {
87     runner_.reset();
88     Cancel();
89   }
90 }
91 
92 }  // namespace js
93 }  // namespace edk
94 }  // namespace mojo
95