chromium/services/accessibility/features/mojo/mojo.cc

// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "services/accessibility/features/mojo/mojo.h"

#include <memory>

#include "base/logging.h"
#include "gin/arguments.h"
#include "gin/converter.h"
#include "gin/data_object_builder.h"
#include "gin/handle.h"
#include "gin/public/wrapper_info.h"
#include "mojo/public/c/system/types.h"
#include "mojo/public/cpp/bindings/generic_pending_receiver.h"
#include "mojo/public/cpp/system/message_pipe.h"
#include "services/accessibility/features/mojo/mojo_handle.h"
#include "services/accessibility/features/registered_wrappable.h"
#include "services/accessibility/features/v8_manager.h"
#include "v8/include/v8-context.h"
#include "v8/include/v8-isolate.h"
#include "v8/include/v8-local-handle.h"
#include "v8/include/v8-primitive.h"

namespace ax {

// static
gin::WrapperInfo Mojo::kWrapperInfo = {gin::kEmbedderNativeGin};

// static
gin::Handle<Mojo> Mojo::Create(v8::Local<v8::Context> context) {
  return gin::CreateHandle(context->GetIsolate(), new Mojo(context));
}

gin::ObjectTemplateBuilder Mojo::GetObjectTemplateBuilder(
    v8::Isolate* isolate) {
  return gin::Wrappable<Mojo>::GetObjectTemplateBuilder(isolate)
      .SetMethod("bindInterface", &Mojo::BindInterface)
      .SetMethod("createMessagePipe", &Mojo::CreateMessagePipe)
      .SetValue("RESULT_OK", MOJO_RESULT_OK)
      .SetValue("RESULT_CANCELLED", MOJO_RESULT_CANCELLED)
      .SetValue("RESULT_UNKNOWN", MOJO_RESULT_UNKNOWN)
      .SetValue("RESULT_INVALID_ARGUMENT", MOJO_RESULT_INVALID_ARGUMENT)
      .SetValue("RESULT_DEADLINE_EXCEEDED", MOJO_RESULT_DEADLINE_EXCEEDED)
      .SetValue("RESULT_NOT_FOUND", MOJO_RESULT_NOT_FOUND)
      .SetValue("RESULT_ALREADY_EXISTS", MOJO_RESULT_ALREADY_EXISTS)
      .SetValue("RESULT_PERMISSION_DENIED", MOJO_RESULT_PERMISSION_DENIED)
      .SetValue("RESULT_RESOURCE_EXHAUSTED", MOJO_RESULT_RESOURCE_EXHAUSTED)
      .SetValue("RESULT_FAILED_PRECONDITION", MOJO_RESULT_FAILED_PRECONDITION)
      .SetValue("RESULT_ABORTED", MOJO_RESULT_ABORTED)
      .SetValue("RESULT_OUT_OF_RANGE", MOJO_RESULT_OUT_OF_RANGE)
      .SetValue("RESULT_UNIMPLEMENTED", MOJO_RESULT_UNIMPLEMENTED)
      .SetValue("RESULT_INTERNAL", MOJO_RESULT_INTERNAL)
      .SetValue("RESULT_UNAVAILABLE", MOJO_RESULT_UNAVAILABLE)
      .SetValue("RESULT_DATA_LOSS", MOJO_RESULT_DATA_LOSS)
      .SetValue("RESULT_BUSY", MOJO_RESULT_BUSY)
      .SetValue("RESULT_SHOULD_WAIT", MOJO_RESULT_SHOULD_WAIT);
}

void Mojo::CreateMessagePipe(gin::Arguments* arguments) {
  v8::Isolate* isolate = arguments->isolate();
  CHECK(isolate);
  v8::HandleScope handle_scope(isolate);

  CHECK(arguments);

  MojoCreateMessagePipeOptions options = {/*struct_size=*/0};
  options.struct_size = sizeof(::MojoCreateMessagePipeOptions);
  options.flags = MOJO_CREATE_MESSAGE_PIPE_FLAG_NONE;

  mojo::ScopedMessagePipeHandle handle0, handle1;
  MojoResult result = mojo::CreateMessagePipe(&options, &handle0, &handle1);

  // Create a result of the form blink::CreateMessagePipeResult, see
  // third_party/blink/renderer/core/mojo/mojo_create_message_pipe_result.idl.
  gin::DataObjectBuilder v8_result_dict(isolate);
  v8_result_dict.Set("result", result);

  if (result == MOJO_RESULT_OK) {
    v8::Local<v8::Context> context = arguments->GetHolderCreationContext();
    v8_result_dict
        .Set("handle0", MojoHandle::Create(context, mojo::ScopedHandle::From(
                                                        std::move(handle0))))
        .Set("handle1", MojoHandle::Create(context, mojo::ScopedHandle::From(
                                                        std::move(handle1))));
  }

  arguments->Return(v8_result_dict.Build());
}

void Mojo::BindInterface(gin::Arguments* arguments) {
  v8::Isolate* isolate = arguments->isolate();
  CHECK(isolate);
  v8::HandleScope handle_scope(isolate);

  // The arguments are defined in third_party/blink/renderer/core/mojo/mojo.idl:
  // static void bindInterface(DOMString interfaceName, MojoHandle
  // request_handle, optional MojoScope scope = "context"); In this
  // implementation, the MojoScope is unused.
  v8::LocalVector<v8::Value> args = arguments->GetAll();
  v8::Local<v8::String> v8_interface_name = args[0].As<v8::String>();
  std::string interface_name;
  gin::ConvertFromV8(isolate, v8_interface_name, &interface_name);

  gin::Handle<MojoHandle> gin_handle;
  if (!gin::ConvertFromV8(isolate, args[1], &gin_handle)) {
    LOG(ERROR) << "Failed to get handle from Mojo::BindInterface";
    return;
  }
  auto handle = mojo::ScopedMessagePipeHandle::From(gin_handle->TakeHandle());

  mojo::GenericPendingReceiver receiver(interface_name, std::move(handle));

  // Use the context's global object to get the pointer to the V8 manager in
  // order to bind this receiver.
  v8::Local<v8::Context> context = arguments->GetHolderCreationContext();
  CHECK(!context.IsEmpty());
  V8Environment::GetFromContext(context)->BindInterface(interface_name,
                                                        std::move(receiver));
}

Mojo::Mojo(v8::Local<v8::Context> context) : RegisteredWrappable(context) {}

}  // namespace ax