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 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 33 MojoResult WaitHandle(mojo::Handle handle, 34 MojoHandleSignals signals, 35 MojoDeadline deadline) { 36 return MojoWait(handle.value(), signals, deadline); 37 } 38 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 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 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 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 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 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 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 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