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 |