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