Home | History | Annotate | Download | only in js
      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