• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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