// 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 "mojo/edk/js/waiting_callback.h" #include "base/bind.h" #include "base/message_loop/message_loop.h" #include "gin/per_context_data.h" namespace mojo { namespace edk { namespace js { namespace { v8::Local GetHiddenPropertyName(v8::Isolate* isolate) { return v8::Private::ForApi( isolate, gin::StringToV8(isolate, "::mojo::js::WaitingCallback")); } } // namespace gin::WrapperInfo WaitingCallback::kWrapperInfo = { gin::kEmbedderNativeGin }; // static gin::Handle WaitingCallback::Create( v8::Isolate* isolate, v8::Local callback, gin::Handle handle_wrapper, MojoHandleSignals signals, bool one_shot) { gin::Handle waiting_callback = gin::CreateHandle( isolate, new WaitingCallback(isolate, callback, one_shot)); MojoResult result = waiting_callback->watcher_.Watch( handle_wrapper->get(), signals, base::Bind(&WaitingCallback::OnHandleReady, base::Unretained(waiting_callback.get()))); // The signals may already be unsatisfiable. if (result == MOJO_RESULT_FAILED_PRECONDITION) waiting_callback->OnHandleReady(MOJO_RESULT_FAILED_PRECONDITION); return waiting_callback; } void WaitingCallback::Cancel() { if (watcher_.IsWatching()) watcher_.Cancel(); } WaitingCallback::WaitingCallback(v8::Isolate* isolate, v8::Local callback, bool one_shot) : one_shot_(one_shot), watcher_(FROM_HERE, SimpleWatcher::ArmingPolicy::AUTOMATIC), weak_factory_(this) { v8::Local context = isolate->GetCurrentContext(); runner_ = gin::PerContextData::From(context)->runner()->GetWeakPtr(); v8::Maybe result = GetWrapper(isolate).ToLocalChecked()->SetPrivate( context, GetHiddenPropertyName(isolate), callback); DCHECK(result.IsJust() && result.FromJust()); } WaitingCallback::~WaitingCallback() { Cancel(); } void WaitingCallback::OnHandleReady(MojoResult result) { if (!runner_) return; gin::Runner::Scope scope(runner_.get()); v8::Isolate* isolate = runner_->GetContextHolder()->isolate(); v8::Local wrapper; if (!GetWrapper(isolate).ToLocal(&wrapper)) { Cancel(); return; } v8::Local hidden_value = wrapper ->GetPrivate(runner_->GetContextHolder()->context(), GetHiddenPropertyName(isolate)) .ToLocalChecked(); v8::Local callback; bool convert_result = gin::ConvertFromV8(isolate, hidden_value, &callback); DCHECK(convert_result); v8::Local args[] = {gin::ConvertToV8(isolate, result)}; runner_->Call(callback, runner_->global(), 1, args); if (one_shot_ || result == MOJO_RESULT_CANCELLED) { runner_.reset(); Cancel(); } } } // namespace js } // namespace edk } // namespace mojo