Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "services/js/js_app.h" | 5 #include "services/js/js_app.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "gin/array_buffer.h" | 8 #include "base/message_loop/message_loop.h" |
| 9 #include "gin/converter.h" | 9 #include "gin/converter.h" |
| 10 #include "gin/modules/module_registry.h" | |
| 11 #include "gin/try_catch.h" | |
| 10 #include "mojo/common/data_pipe_utils.h" | 12 #include "mojo/common/data_pipe_utils.h" |
| 13 #include "mojo/edk/js/core.h" | |
| 14 #include "mojo/edk/js/handle.h" | |
| 15 #include "mojo/edk/js/support.h" | |
| 16 #include "mojo/public/cpp/bindings/interface_request.h" | |
| 17 #include "services/js/js_app_shell.h" | |
| 11 #include "services/js/mojo_bridge_module.h" | 18 #include "services/js/mojo_bridge_module.h" |
| 12 | 19 |
| 13 namespace mojo { | 20 namespace mojo { |
| 14 namespace js { | 21 namespace js { |
| 15 | 22 |
| 23 const char JSApp::kMainModuleName[] = "main"; | |
| 24 | |
| 16 JSApp::JSApp(ShellPtr shell, URLResponsePtr response) : shell_(shell.Pass()) { | 25 JSApp::JSApp(ShellPtr shell, URLResponsePtr response) : shell_(shell.Pass()) { |
| 17 // TODO(hansmuller): handle load failure here and below. | 26 isolate_holder_.AddRunMicrotasksObserver(); |
| 27 | |
| 18 DCHECK(!response.is_null()); | 28 DCHECK(!response.is_null()); |
| 19 file_name_ = response->url; | 29 std::string url(response->url); |
| 20 bool result = common::BlockingCopyToString(response->body.Pass(), &source_); | 30 std::string source; |
| 21 DCHECK(result); | 31 DCHECK(common::BlockingCopyToString(response->body.Pass(), &source)); |
|
abarth-chromium
2014/11/24 23:47:24
s/DCHECK/CHECK/
If you use DCHECK, this call will
hansmuller
2014/11/25 00:31:55
Done.
| |
| 22 | 32 |
| 23 runner_delegate.AddBuiltinModule(MojoInternals::kModuleName, | 33 v8::Isolate* isolate = isolate_holder_.isolate(); |
| 24 base::Bind(MojoInternals::GetModule, this)); | 34 shell_runner_.reset(new gin::ShellRunner(&runner_delegate_, isolate)); |
| 35 gin::Runner::Scope scope(shell_runner_.get()); | |
| 36 shell_runner_->Run(source.c_str(), kMainModuleName); | |
| 37 | |
| 38 gin::ModuleRegistry::LoadModuleCallback on_app_loaded = | |
| 39 base::Bind(&JSApp::OnAppLoaded, base::Unretained(this), url); | |
|
abarth-chromium
2014/11/24 23:47:24
I'd just inline this into the one place its used.
hansmuller
2014/11/25 00:31:55
Done.
| |
| 40 | |
| 41 gin::ModuleRegistry* registry = | |
| 42 gin::ModuleRegistry::From(shell_runner_->GetContextHolder()->context()); | |
| 43 registry->LoadModule(isolate, kMainModuleName, on_app_loaded); | |
| 44 } | |
| 45 | |
| 46 JSApp::~JSApp() { | |
| 47 app_instance_.Reset(); | |
| 48 } | |
| 49 | |
| 50 | |
| 51 void JSApp::OnAppLoaded(std::string url, v8::Handle<v8::Value> main_module) { | |
| 52 gin::Runner::Scope scope(shell_runner_.get()); | |
| 53 gin::TryCatch try_catch; | |
| 54 v8::Isolate* isolate = isolate_holder_.isolate(); | |
| 55 | |
| 56 v8::Handle<v8::Value> argv[] = { | |
| 57 gin::ConvertToV8(isolate, JSAppShell::Create(isolate, this)), | |
| 58 gin::ConvertToV8(isolate, url) | |
| 59 }; | |
| 60 | |
| 61 v8::Handle<v8::Function> app_class; | |
| 62 CHECK(gin::ConvertFromV8(isolate, main_module, &app_class)); | |
| 63 app_instance_.Reset(isolate, app_class->NewInstance(arraysize(argv), argv)); | |
| 64 if (try_catch.HasCaught()) | |
| 65 runner_delegate_.UnhandledException(shell_runner_.get(), try_catch); | |
| 66 | |
| 25 shell_.set_client(this); | 67 shell_.set_client(this); |
| 26 } | 68 } |
| 27 | 69 |
| 28 JSApp::~JSApp() { | 70 void JSApp::ConnectToApplication(const std::string& application_url, |
| 71 ScopedMessagePipeHandle service_provider) { | |
| 72 shell_->ConnectToApplication( | |
| 73 application_url, MakeRequest<ServiceProvider>(service_provider.Pass())); | |
| 74 } | |
| 75 | |
| 76 void JSApp::CallAppInstanceMethod( | |
| 77 std::string name, int argc, v8::Handle<v8::Value> argv[]) { | |
| 78 v8::Isolate* isolate = isolate_holder_.isolate(); | |
| 79 v8::Local<v8::Object> app = | |
| 80 v8::Local<v8::Object>::New(isolate, app_instance_); | |
| 81 v8::Handle<v8::Value> key = gin::StringToV8(isolate, name); | |
| 82 if (!app->Has(key)) // Method doesn't exist. | |
| 83 return; | |
| 84 v8::Handle<v8::Value> value = app->Get(key); | |
|
abarth-chromium
2014/11/24 23:47:24
You shouldn't separate Has and Get. Instead, you
hansmuller
2014/11/25 00:31:55
Good point. I'm applying IsFunction() to the resul
| |
| 85 v8::Handle<v8::Function> app_method; | |
| 86 CHECK(gin::ConvertFromV8(isolate, value, &app_method)); | |
|
abarth-chromium
2014/11/24 23:47:24
Do we really want to crash if someone stores a non
hansmuller
2014/11/25 00:31:55
Since I'm allowing the function to not be defined
| |
| 87 shell_runner_->Call(app_method, app, argc, argv); | |
| 88 } | |
| 89 | |
| 90 void JSApp::Initialize(Array<String> app_args) { | |
| 91 gin::Runner::Scope scope(shell_runner_.get()); | |
| 92 v8::Isolate* isolate = isolate_holder_.isolate(); | |
| 93 v8::Handle<v8::Value> argv[] = { | |
| 94 gin::ConvertToV8(isolate, app_args.To<std::vector<std::string>>()), | |
| 95 }; | |
| 96 CallAppInstanceMethod("initialize", 1, argv); | |
| 97 } | |
| 98 | |
| 99 void JSApp::AcceptConnection(const String& requestor_url, | |
| 100 ServiceProviderPtr provider) { | |
| 101 gin::Runner::Scope scope(shell_runner_.get()); | |
| 102 v8::Isolate* isolate = isolate_holder_.isolate(); | |
| 103 v8::Handle<v8::Value> argv[] = { | |
| 104 gin::ConvertToV8(isolate, requestor_url.To<std::string>()), | |
| 105 gin::ConvertToV8(isolate, provider.PassMessagePipe().get()), | |
| 106 }; | |
| 107 CallAppInstanceMethod("acceptConnection", arraysize(argv), argv); | |
| 29 } | 108 } |
| 30 | 109 |
| 31 void JSApp::Quit() { | 110 void JSApp::Quit() { |
| 32 isolate_holder_.RemoveRunMicrotasksObserver(); | 111 isolate_holder_.RemoveRunMicrotasksObserver(); |
| 33 base::MessageLoop::current()->PostTask( | 112 base::MessageLoop::current()->PostTask( |
| 34 FROM_HERE, base::Bind(&JSApp::QuitInternal, base::Unretained(this))); | 113 FROM_HERE, base::Bind(&JSApp::QuitInternal, base::Unretained(this))); |
| 35 } | 114 } |
| 36 | 115 |
| 37 MessagePipeHandle JSApp::ConnectToApplication( | |
| 38 const std::string& application_url) { | |
| 39 MessagePipe pipe; | |
| 40 InterfaceRequest<ServiceProvider> request = | |
| 41 MakeRequest<ServiceProvider>(pipe.handle1.Pass()); | |
| 42 shell_->ConnectToApplication(application_url, request.Pass()); | |
| 43 return pipe.handle0.Pass().release(); | |
| 44 } | |
| 45 | |
| 46 MessagePipeHandle JSApp::RequestorMessagePipeHandle() { | |
| 47 return requestor_handle_.get(); | |
| 48 } | |
| 49 | |
| 50 void JSApp::AcceptConnection(const String& requestor_url, | |
| 51 ServiceProviderPtr provider) { | |
| 52 requestor_handle_ = provider.PassMessagePipe(); | |
| 53 | |
| 54 isolate_holder_.AddRunMicrotasksObserver(); | |
| 55 shell_runner_.reset( | |
| 56 new gin::ShellRunner(&runner_delegate, isolate_holder_.isolate())); | |
| 57 gin::Runner::Scope scope(shell_runner_.get()); | |
| 58 shell_runner_->Run(source_.c_str(), file_name_.c_str()); | |
| 59 } | |
| 60 | |
| 61 void JSApp::Initialize(Array<String> args) { | |
| 62 } | |
| 63 | |
| 64 void JSApp::QuitInternal() { | 116 void JSApp::QuitInternal() { |
| 65 shell_runner_.reset(); | 117 shell_runner_.reset(); |
| 66 base::MessageLoop::current()->QuitWhenIdle(); | 118 base::MessageLoop::current()->QuitWhenIdle(); |
| 67 } | 119 } |
| 68 | 120 |
| 69 } // namespace js | 121 } // namespace js |
| 70 } // namespace mojo | 122 } // namespace mojo |
| 123 | |
| OLD | NEW |