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/bindings/js/core.h"
6
7 #include "base/bind.h"
8 #include "base/logging.h"
9 #include "gin/arguments.h"
10 #include "gin/array_buffer.h"
11 #include "gin/converter.h"
12 #include "gin/dictionary.h"
13 #include "gin/function_template.h"
14 #include "gin/handle.h"
15 #include "gin/object_template_builder.h"
16 #include "gin/per_isolate_data.h"
17 #include "gin/public/wrapper_info.h"
18 #include "gin/wrappable.h"
19 #include "mojo/bindings/js/handle.h"
20
21 namespace mojo {
22 namespace js {
23
24 namespace {
25
CloseHandle(gin::Handle<gin::HandleWrapper> handle)26 MojoResult CloseHandle(gin::Handle<gin::HandleWrapper> handle) {
27 if (!handle->get().is_valid())
28 return MOJO_RESULT_INVALID_ARGUMENT;
29 handle->Close();
30 return MOJO_RESULT_OK;
31 }
32
WaitHandle(mojo::Handle handle,MojoHandleSignals signals,MojoDeadline deadline)33 MojoResult WaitHandle(mojo::Handle handle,
34 MojoHandleSignals signals,
35 MojoDeadline deadline) {
36 return MojoWait(handle.value(), signals, deadline);
37 }
38
WaitMany(const std::vector<mojo::Handle> & handles,const std::vector<MojoHandleSignals> & signals,MojoDeadline deadline)39 MojoResult WaitMany(
40 const std::vector<mojo::Handle>& handles,
41 const std::vector<MojoHandleSignals>& signals,
42 MojoDeadline deadline) {
43 return mojo::WaitMany(handles, signals, deadline);
44 }
45
CreateMessagePipe(const gin::Arguments & args)46 gin::Dictionary CreateMessagePipe(const gin::Arguments& args) {
47 MojoHandle handle0 = MOJO_HANDLE_INVALID;
48 MojoHandle handle1 = MOJO_HANDLE_INVALID;
49 // TODO(vtl): Add support for the options struct.
50 MojoResult result = MojoCreateMessagePipe(NULL, &handle0, &handle1);
51 CHECK(result == MOJO_RESULT_OK);
52
53 gin::Dictionary dictionary = gin::Dictionary::CreateEmpty(args.isolate());
54 dictionary.Set("handle0", mojo::Handle(handle0));
55 dictionary.Set("handle1", mojo::Handle(handle1));
56 return dictionary;
57 }
58
WriteMessage(mojo::Handle handle,const gin::ArrayBufferView & buffer,const std::vector<gin::Handle<gin::HandleWrapper>> & handles,MojoWriteMessageFlags flags)59 MojoResult WriteMessage(
60 mojo::Handle handle,
61 const gin::ArrayBufferView& buffer,
62 const std::vector<gin::Handle<gin::HandleWrapper> >& handles,
63 MojoWriteMessageFlags flags) {
64 std::vector<MojoHandle> raw_handles(handles.size());
65 for (size_t i = 0; i < handles.size(); ++i)
66 raw_handles[i] = handles[i]->get().value();
67 MojoResult rv = MojoWriteMessage(handle.value(),
68 buffer.bytes(),
69 static_cast<uint32_t>(buffer.num_bytes()),
70 raw_handles.empty() ? NULL : &raw_handles[0],
71 static_cast<uint32_t>(raw_handles.size()),
72 flags);
73 // MojoWriteMessage takes ownership of the handles upon success, so
74 // release them here.
75 if (rv == MOJO_RESULT_OK) {
76 for (size_t i = 0; i < handles.size(); ++i)
77 ignore_result(handles[i]->release());
78 }
79 return rv;
80 }
81
ReadMessage(const gin::Arguments & args,mojo::Handle handle,MojoReadMessageFlags flags)82 gin::Dictionary ReadMessage(const gin::Arguments& args,
83 mojo::Handle handle,
84 MojoReadMessageFlags flags) {
85 uint32_t num_bytes = 0;
86 uint32_t num_handles = 0;
87 MojoResult result = MojoReadMessage(
88 handle.value(), NULL, &num_bytes, NULL, &num_handles, flags);
89 if (result != MOJO_RESULT_RESOURCE_EXHAUSTED) {
90 gin::Dictionary dictionary = gin::Dictionary::CreateEmpty(args.isolate());
91 dictionary.Set("result", result);
92 return dictionary;
93 }
94
95 v8::Handle<v8::ArrayBuffer> array_buffer =
96 v8::ArrayBuffer::New(args.isolate(), num_bytes);
97 std::vector<mojo::Handle> handles(num_handles);
98
99 gin::ArrayBuffer buffer;
100 ConvertFromV8(args.isolate(), array_buffer, &buffer);
101 CHECK(buffer.num_bytes() == num_bytes);
102
103 result = MojoReadMessage(handle.value(),
104 buffer.bytes(),
105 &num_bytes,
106 handles.empty() ? NULL :
107 reinterpret_cast<MojoHandle*>(&handles[0]),
108 &num_handles,
109 flags);
110
111 CHECK(buffer.num_bytes() == num_bytes);
112 CHECK(handles.size() == num_handles);
113
114 gin::Dictionary dictionary = gin::Dictionary::CreateEmpty(args.isolate());
115 dictionary.Set("result", result);
116 dictionary.Set("buffer", array_buffer);
117 dictionary.Set("handles", handles);
118 return dictionary;
119 }
120
CreateDataPipe(const gin::Arguments & args,v8::Handle<v8::Value> options_value)121 gin::Dictionary CreateDataPipe(const gin::Arguments& args,
122 v8::Handle<v8::Value> options_value) {
123 gin::Dictionary dictionary = gin::Dictionary::CreateEmpty(args.isolate());
124 dictionary.Set("result", MOJO_RESULT_INVALID_ARGUMENT);
125
126 MojoHandle producer_handle = MOJO_HANDLE_INVALID;
127 MojoHandle consumer_handle = MOJO_HANDLE_INVALID;
128 MojoResult result = MOJO_RESULT_OK;
129
130 if (options_value->IsObject()) {
131 gin::Dictionary options_dict(args.isolate(), options_value->ToObject());
132 MojoCreateDataPipeOptions options;
133 // For future struct_size, we can probably infer that from the presence of
134 // properties in options_dict. For now, it's always 16.
135 options.struct_size = 16;
136 // Ideally these would be optional. But the interface makes it hard to
137 // typecheck them then.
138 if (!options_dict.Get("flags", &options.flags) ||
139 !options_dict.Get("elementNumBytes", &options.element_num_bytes) ||
140 !options_dict.Get("capacityNumBytes", &options.capacity_num_bytes)) {
141 return dictionary;
142 }
143
144 result = MojoCreateDataPipe(&options, &producer_handle, &consumer_handle);
145 } else if (options_value->IsNull() || options_value->IsUndefined()) {
146 result = MojoCreateDataPipe(NULL, &producer_handle, &consumer_handle);
147 } else {
148 return dictionary;
149 }
150
151 CHECK_EQ(MOJO_RESULT_OK, result);
152
153 dictionary.Set("result", result);
154 dictionary.Set("producerHandle", mojo::Handle(producer_handle));
155 dictionary.Set("consumerHandle", mojo::Handle(consumer_handle));
156 return dictionary;
157 }
158
WriteData(const gin::Arguments & args,mojo::Handle handle,const gin::ArrayBufferView & buffer,MojoWriteDataFlags flags)159 gin::Dictionary WriteData(const gin::Arguments& args,
160 mojo::Handle handle,
161 const gin::ArrayBufferView& buffer,
162 MojoWriteDataFlags flags) {
163 uint32_t num_bytes = static_cast<uint32_t>(buffer.num_bytes());
164 MojoResult result =
165 MojoWriteData(handle.value(), buffer.bytes(), &num_bytes, flags);
166 gin::Dictionary dictionary = gin::Dictionary::CreateEmpty(args.isolate());
167 dictionary.Set("result", result);
168 dictionary.Set("numBytes", num_bytes);
169 return dictionary;
170 }
171
ReadData(const gin::Arguments & args,mojo::Handle handle,MojoReadDataFlags flags)172 gin::Dictionary ReadData(const gin::Arguments& args,
173 mojo::Handle handle,
174 MojoReadDataFlags flags) {
175 uint32_t num_bytes = 0;
176 MojoResult result = MojoReadData(
177 handle.value(), NULL, &num_bytes, MOJO_READ_DATA_FLAG_QUERY);
178 if (result != MOJO_RESULT_OK) {
179 gin::Dictionary dictionary = gin::Dictionary::CreateEmpty(args.isolate());
180 dictionary.Set("result", result);
181 return dictionary;
182 }
183
184 v8::Handle<v8::ArrayBuffer> array_buffer =
185 v8::ArrayBuffer::New(args.isolate(), num_bytes);
186 gin::ArrayBuffer buffer;
187 ConvertFromV8(args.isolate(), array_buffer, &buffer);
188 CHECK_EQ(num_bytes, buffer.num_bytes());
189
190 result = MojoReadData(handle.value(), buffer.bytes(), &num_bytes, flags);
191 CHECK_EQ(num_bytes, buffer.num_bytes());
192
193 gin::Dictionary dictionary = gin::Dictionary::CreateEmpty(args.isolate());
194 dictionary.Set("result", result);
195 dictionary.Set("buffer", array_buffer);
196 return dictionary;
197 }
198
199 gin::WrapperInfo g_wrapper_info = { gin::kEmbedderNativeGin };
200
201 } // namespace
202
203 const char Core::kModuleName[] = "mojo/public/js/bindings/core";
204
GetModule(v8::Isolate * isolate)205 v8::Local<v8::Value> Core::GetModule(v8::Isolate* isolate) {
206 gin::PerIsolateData* data = gin::PerIsolateData::From(isolate);
207 v8::Local<v8::ObjectTemplate> templ = data->GetObjectTemplate(
208 &g_wrapper_info);
209
210 if (templ.IsEmpty()) {
211 templ = gin::ObjectTemplateBuilder(isolate)
212 // TODO(mpcomplete): Should these just be methods on the JS Handle
213 // object?
214 .SetMethod("close", CloseHandle)
215 .SetMethod("wait", WaitHandle)
216 .SetMethod("waitMany", WaitMany)
217 .SetMethod("createMessagePipe", CreateMessagePipe)
218 .SetMethod("writeMessage", WriteMessage)
219 .SetMethod("readMessage", ReadMessage)
220 .SetMethod("createDataPipe", CreateDataPipe)
221 .SetMethod("writeData", WriteData)
222 .SetMethod("readData", ReadData)
223
224 .SetValue("RESULT_OK", MOJO_RESULT_OK)
225 .SetValue("RESULT_CANCELLED", MOJO_RESULT_CANCELLED)
226 .SetValue("RESULT_UNKNOWN", MOJO_RESULT_UNKNOWN)
227 .SetValue("RESULT_INVALID_ARGUMENT", MOJO_RESULT_INVALID_ARGUMENT)
228 .SetValue("RESULT_DEADLINE_EXCEEDED", MOJO_RESULT_DEADLINE_EXCEEDED)
229 .SetValue("RESULT_NOT_FOUND", MOJO_RESULT_NOT_FOUND)
230 .SetValue("RESULT_ALREADY_EXISTS", MOJO_RESULT_ALREADY_EXISTS)
231 .SetValue("RESULT_PERMISSION_DENIED", MOJO_RESULT_PERMISSION_DENIED)
232 .SetValue("RESULT_RESOURCE_EXHAUSTED", MOJO_RESULT_RESOURCE_EXHAUSTED)
233 .SetValue("RESULT_FAILED_PRECONDITION", MOJO_RESULT_FAILED_PRECONDITION)
234 .SetValue("RESULT_ABORTED", MOJO_RESULT_ABORTED)
235 .SetValue("RESULT_OUT_OF_RANGE", MOJO_RESULT_OUT_OF_RANGE)
236 .SetValue("RESULT_UNIMPLEMENTED", MOJO_RESULT_UNIMPLEMENTED)
237 .SetValue("RESULT_INTERNAL", MOJO_RESULT_INTERNAL)
238 .SetValue("RESULT_UNAVAILABLE", MOJO_RESULT_UNAVAILABLE)
239 .SetValue("RESULT_DATA_LOSS", MOJO_RESULT_DATA_LOSS)
240 .SetValue("RESULT_BUSY", MOJO_RESULT_BUSY)
241 .SetValue("RESULT_SHOULD_WAIT", MOJO_RESULT_SHOULD_WAIT)
242
243 .SetValue("DEADLINE_INDEFINITE", MOJO_DEADLINE_INDEFINITE)
244
245 .SetValue("HANDLE_SIGNAL_NONE", MOJO_HANDLE_SIGNAL_NONE)
246 .SetValue("HANDLE_SIGNAL_READABLE", MOJO_HANDLE_SIGNAL_READABLE)
247 .SetValue("HANDLE_SIGNAL_READABLE", MOJO_HANDLE_SIGNAL_READABLE)
248
249 .SetValue("WRITE_MESSAGE_FLAG_NONE", MOJO_WRITE_MESSAGE_FLAG_NONE)
250
251 .SetValue("READ_MESSAGE_FLAG_NONE", MOJO_READ_MESSAGE_FLAG_NONE)
252 .SetValue("READ_MESSAGE_FLAG_MAY_DISCARD",
253 MOJO_READ_MESSAGE_FLAG_MAY_DISCARD)
254
255 .SetValue("CREATE_DATA_PIPE_OPTIONS_FLAG_NONE",
256 MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE)
257 .SetValue("CREATE_DATA_PIPE_OPTIONS_FLAG_MAY_DISCARD",
258 MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_MAY_DISCARD)
259
260 .SetValue("WRITE_DATA_FLAG_NONE", MOJO_WRITE_DATA_FLAG_NONE)
261 .SetValue("WRITE_DATA_FLAG_ALL_OR_NONE",
262 MOJO_WRITE_DATA_FLAG_ALL_OR_NONE)
263
264 .SetValue("READ_DATA_FLAG_NONE", MOJO_READ_DATA_FLAG_NONE)
265 .SetValue("READ_DATA_FLAG_ALL_OR_NONE",
266 MOJO_READ_DATA_FLAG_ALL_OR_NONE)
267 .SetValue("READ_DATA_FLAG_DISCARD", MOJO_READ_DATA_FLAG_DISCARD)
268 .SetValue("READ_DATA_FLAG_QUERY", MOJO_READ_DATA_FLAG_QUERY)
269 .Build();
270
271 data->SetObjectTemplate(&g_wrapper_info, templ);
272 }
273
274 return templ->NewInstance();
275 }
276
277 } // namespace js
278 } // namespace mojo
279