Commit b2cf607c authored by hansmuller's avatar hansmuller Committed by Commit bot

JavaScript Content Handler Version 0.0

BUG=403645

Review URL: https://codereview.chromium.org/467263006

Cr-Commit-Position: refs/heads/master@{#294621}
parent 56f97b71
......@@ -4,6 +4,8 @@
#include "gin/modules/module_runner_delegate.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "gin/modules/module_registry.h"
#include "gin/object_template_builder.h"
#include "gin/public/context_holder.h"
......@@ -20,6 +22,11 @@ ModuleRunnerDelegate::~ModuleRunnerDelegate() {
void ModuleRunnerDelegate::AddBuiltinModule(const std::string& id,
ModuleGetter getter) {
builtin_modules_[id] = base::Bind(getter);
}
void ModuleRunnerDelegate::AddBuiltinModule(const std::string& id,
const ModuleGetterCallback& getter) {
builtin_modules_[id] = getter;
}
......@@ -46,9 +53,10 @@ void ModuleRunnerDelegate::DidCreateContext(ShellRunner* runner) {
ModuleRegistry* registry = ModuleRegistry::From(context);
v8::Isolate* isolate = runner->GetContextHolder()->isolate();
for (BuiltinModuleMap::const_iterator it = builtin_modules_.begin();
it != builtin_modules_.end(); ++it) {
registry->AddBuiltinModule(isolate, it->first, it->second(isolate));
registry->AddBuiltinModule(isolate, it->first, it->second.Run(isolate));
}
}
......
......@@ -7,14 +7,17 @@
#include <map>
#include "base/callback.h"
#include "base/compiler_specific.h"
#include "gin/gin_export.h"
#include "gin/modules/file_module_provider.h"
#include "gin/shell_runner.h"
#include "v8/include/v8.h"
namespace gin {
typedef v8::Local<v8::Value> (*ModuleGetter)(v8::Isolate* isolate);
typedef base::Callback<v8::Local<v8::Value>(v8::Isolate*)> ModuleGetterCallback;
// Emebedders that use AMD modules will probably want to use a RunnerDelegate
// that inherits from ModuleRunnerDelegate. ModuleRunnerDelegate lets embedders
......@@ -26,12 +29,14 @@ class GIN_EXPORT ModuleRunnerDelegate : public ShellRunnerDelegate {
virtual ~ModuleRunnerDelegate();
void AddBuiltinModule(const std::string& id, ModuleGetter getter);
void AddBuiltinModule(const std::string& id,
const ModuleGetterCallback& getter);
protected:
void AttemptToLoadMoreModules(Runner* runner);
private:
typedef std::map<std::string, ModuleGetter> BuiltinModuleMap;
typedef std::map<std::string, ModuleGetterCallback> BuiltinModuleMap;
// From ShellRunnerDelegate:
virtual v8::Handle<v8::ObjectTemplate> GetGlobalTemplate(
......
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "mojo/apps/js/application_delegate_impl.h"
#include "mojo/apps/js/js_app.h"
#include "mojo/public/cpp/application/application_impl.h"
namespace mojo {
namespace apps {
ContentHandlerImpl::ContentHandlerImpl(ApplicationDelegateImpl* app)
: content_handler_(app) {
}
ContentHandlerImpl::~ContentHandlerImpl() {
}
void ContentHandlerImpl::OnConnect(
const mojo::String& url,
URLResponsePtr content,
InterfaceRequest<ServiceProvider> service_provider) {
content_handler_->StartJSApp(url.To<std::string>(), content.Pass());
}
ApplicationDelegateImpl::ApplicationDelegateImpl()
: application_impl_(NULL), content_handler_factory_(this) {
}
void ApplicationDelegateImpl::Initialize(ApplicationImpl* app) {
application_impl_ = app;
}
ApplicationDelegateImpl::~ApplicationDelegateImpl() {
}
bool ApplicationDelegateImpl::ConfigureIncomingConnection(
ApplicationConnection* connection) {
connection->AddService(&content_handler_factory_);
return true;
}
void ApplicationDelegateImpl::StartJSApp(const std::string& url,
URLResponsePtr content) {
JSApp* app = new JSApp(this, url, content.Pass());
app_vector_.push_back(app);
// TODO(hansmuller): deal with the Start() return value.
app->Start();
}
void ApplicationDelegateImpl::QuitJSApp(JSApp* app) {
AppVector::iterator itr =
std::find(app_vector_.begin(), app_vector_.end(), app);
if (itr != app_vector_.end())
app_vector_.erase(itr);
}
void ApplicationDelegateImpl::ConnectToService(
ScopedMessagePipeHandle pipe_handle,
const std::string& application_url,
const std::string& interface_name) {
CHECK(application_impl_);
ServiceProvider* service_provider =
application_impl_->ConnectToApplication(application_url)
->GetServiceProvider();
service_provider->ConnectToService(interface_name, pipe_handle.Pass());
}
} // namespace apps
} // namespace mojo
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef MOJO_APPS_JS_CONTENT_HANDLER_H_
#define MOJO_APPS_JS_CONTENT_HANDLER_H_
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_vector.h"
#include "mojo/public/cpp/application/application_delegate.h"
#include "mojo/public/cpp/application/interface_factory_impl.h"
#include "mojo/services/public/interfaces/content_handler/content_handler.mojom.h"
namespace mojo {
class ApplcationImpl;
namespace apps {
class ApplicationDelegateImpl;
class JSApp;
// Starts a new JSApp for each OnConnect call().
class ContentHandlerImpl : public InterfaceImpl<ContentHandler> {
public:
ContentHandlerImpl(ApplicationDelegateImpl* content_handler);
virtual ~ContentHandlerImpl();
private:
virtual void OnConnect(const mojo::String& url,
URLResponsePtr content,
InterfaceRequest<ServiceProvider> service_provider)
MOJO_OVERRIDE;
ApplicationDelegateImpl* content_handler_;
};
// Manages the JSApps started by this content handler. This class owns the one
// reference to the Mojo shell. JSApps post a task to the content handler's
// thread to connect to a service or to quit.l
class ApplicationDelegateImpl : public ApplicationDelegate {
public:
ApplicationDelegateImpl();
virtual ~ApplicationDelegateImpl();
void StartJSApp(const std::string& url, URLResponsePtr content);
void QuitJSApp(JSApp* app);
void ConnectToService(ScopedMessagePipeHandle pipe_handle,
const std::string& application_url,
const std::string& interface_name);
private:
typedef ScopedVector<JSApp> AppVector;
// ApplicationDelegate methods
virtual void Initialize(ApplicationImpl* app) MOJO_OVERRIDE;
virtual bool ConfigureIncomingConnection(ApplicationConnection* connection)
MOJO_OVERRIDE;
ApplicationImpl* application_impl_;
InterfaceFactoryImplWithContext<ContentHandlerImpl, ApplicationDelegateImpl>
content_handler_factory_;
AppVector app_vector_;
};
} // namespace apps
} // namespace mojo
#endif // MOJO_APPS_JS_CONTENT_HANDLER_H_
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "mojo/apps/js/js_app.h"
#include "base/bind.h"
#include "gin/array_buffer.h"
#include "gin/converter.h"
#include "mojo/apps/js/application_delegate_impl.h"
#include "mojo/apps/js/mojo_module.h"
#include "mojo/common/data_pipe_utils.h"
namespace mojo {
namespace apps {
JSApp::JSApp(ApplicationDelegateImpl* content_handler_app,
const std::string& url,
URLResponsePtr content)
: content_handler_app_(content_handler_app),
url_(url),
content_(content.Pass()),
thread_("Mojo JS " + url),
content_handler_task_runner_(
base::MessageLoop::current()->task_runner()) {
CHECK(on_content_handler_thread());
runner_delegate_.AddBuiltinModule(Mojo::kModuleName,
base::Bind(Mojo::GetModule, this));
}
JSApp::~JSApp() {
}
bool JSApp::Start() {
CHECK(!js_app_task_runner_.get() && on_content_handler_thread());
base::Thread::Options thread_options(base::MessageLoop::TYPE_IO, 0);
thread_.StartWithOptions(thread_options);
// TODO(hansmuller): check thread_.StartWithOptions() return value.
// TODO(hansmuller): need to funnel Run() failures back to the caller.
thread_.message_loop()->PostTask(
FROM_HERE, base::Bind(&JSApp::Run, base::Unretained(this)));
return true;
}
void JSApp::Quit() {
CHECK(on_js_app_thread());
// The the terminate operation is posted to the message_loop so that
// the shell_runner isn't destroyed before this JS function returns.
thread_.message_loop()->PostTask(
FROM_HERE, base::Bind(&JSApp::Terminate, base::Unretained(this)));
}
Handle JSApp::ConnectToService(const std::string& application_url,
const std::string& interface_name) {
CHECK(on_js_app_thread());
MessagePipe pipe;
content_handler_task_runner_->PostTask(
FROM_HERE,
base::Bind(&ApplicationDelegateImpl::ConnectToService,
base::Unretained(content_handler_app_),
base::Passed(pipe.handle1.Pass()),
application_url,
interface_name));
return pipe.handle0.release();
}
void JSApp::Run() {
CHECK(!js_app_task_runner_.get() && !on_content_handler_thread());
js_app_task_runner_ = base::MessageLoop::current()->task_runner();
// TODO(hansmuller): check the return value and fail gracefully.
std::string module;
common::BlockingCopyToString(content_->body.Pass(), &module);
gin::IsolateHolder::Initialize(gin::IsolateHolder::kStrictMode,
gin::ArrayBufferAllocator::SharedInstance());
isolate_holder_.reset(new gin::IsolateHolder());
shell_runner_.reset(
new gin::ShellRunner(&runner_delegate_, isolate_holder_->isolate()));
// TODO(hansmuller): exiting this scope here is OK?
gin::Runner::Scope scope(shell_runner_.get());
shell_runner_->Run(module.c_str(), url_.c_str());
}
void JSApp::Terminate() {
shell_runner_.reset(NULL);
// This JSApp's thread must be stopped on the thread that started it. Ask the
// content_handler_app_ to erase its AppVector entry for this app, which
// implicitly destroys this JSApp and stops its thread.
content_handler_task_runner_->PostTask(
FROM_HERE,
base::Bind(&ApplicationDelegateImpl::QuitJSApp,
base::Unretained(content_handler_app_),
base::Unretained(this)));
}
bool JSApp::on_content_handler_thread() const {
return content_handler_task_runner_.get() &&
content_handler_task_runner_.get() ==
base::MessageLoop::current()->task_runner().get();
}
bool JSApp::on_js_app_thread() const {
return js_app_task_runner_.get() &&
js_app_task_runner_.get() ==
base::MessageLoop::current()->task_runner().get();
}
} // namespace apps
} // namespace mojo
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef MOJO_APPS_JS_JS_APP_H_
#define MOJO_APPS_JS_JS_APP_H_
#include "base/memory/ref_counted.h"
#include "base/single_thread_task_runner.h"
#include "base/threading/thread.h"
#include "gin/public/isolate_holder.h"
#include "gin/shell_runner.h"
#include "mojo/apps/js/mojo_runner_delegate.h"
#include "mojo/services/public/interfaces/content_handler/content_handler.mojom.h"
namespace mojo {
namespace apps {
class JSApp;
class ApplicationDelegateImpl;
// Each JavaScript app started by content handler runs on its own thread and
// in its own V8 isolate. This class represents one running JS app.
//
// The lifetime of this class is defined by the content handler's internal
// "app_vector" list.
class JSApp {
public:
JSApp(ApplicationDelegateImpl* content_handler_app,
const std::string& url,
URLResponsePtr content);
~JSApp();
bool Start();
void Quit();
Handle ConnectToService(const std::string& application_url,
const std::string& interface_name);
private:
void Run();
void Terminate();
// Used to CHECK that we're running on the correct thread.
bool on_content_handler_thread() const;
bool on_js_app_thread() const;
ApplicationDelegateImpl* content_handler_app_;
std::string url_;
URLResponsePtr content_;
base::Thread thread_;
scoped_refptr<base::SingleThreadTaskRunner> content_handler_task_runner_;
scoped_refptr<base::SingleThreadTaskRunner> js_app_task_runner_;
MojoRunnerDelegate runner_delegate_;
scoped_ptr<gin::IsolateHolder> isolate_holder_;
scoped_ptr<gin::ShellRunner> shell_runner_;
DISALLOW_COPY_AND_ASSIGN(JSApp);
};
} // namespace apps
} // namespace mojo
#endif // MOJO_APPS_JS_JS_APP_H_
// Copyright 2013 The Chromium Authors. All rights reserved.
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/message_loop/message_loop.h"
#include "gin/array_buffer.h"
#include "gin/public/isolate_holder.h"
#include "mojo/apps/js/mojo_runner_delegate.h"
#include "mojo/public/cpp/system/core.h"
#include "mojo/public/cpp/system/macros.h"
#include "base/i18n/icu_util.h"
#include "mojo/apps/js/application_delegate_impl.h"
#include "mojo/public/c/system/main.h"
#include "mojo/public/cpp/application/application_runner_chromium.h"
#if defined(WIN32)
#if !defined(CDECL)
#define CDECL __cdecl
#endif
#define MOJO_APPS_JS_EXPORT __declspec(dllexport)
#else
#define CDECL
#define MOJO_APPS_JS_EXPORT __attribute__((visibility("default")))
#endif
namespace mojo {
namespace apps {
void Start(MojoHandle pipe, const std::string& module) {
base::MessageLoop loop;
gin::IsolateHolder::Initialize(gin::IsolateHolder::kStrictMode,
gin::ArrayBufferAllocator::SharedInstance());
gin::IsolateHolder instance;
MojoRunnerDelegate delegate;
gin::ShellRunner runner(&delegate, instance.isolate());
delegate.Start(&runner, pipe, module);
base::MessageLoop::current()->Run();
}
} // namespace apps
} // namespace mojo
extern "C" MOJO_APPS_JS_EXPORT MojoResult CDECL MojoMain(MojoHandle pipe) {
mojo::apps::Start(pipe, "mojo/apps/js/main");
return MOJO_RESULT_OK;
MojoResult MojoMain(MojoHandle shell_handle) {
base::i18n::InitializeICU();
mojo::ApplicationRunnerChromium runner(
new mojo::apps::ApplicationDelegateImpl());
return runner.Run(shell_handle);
}
This diff is collapsed.
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "mojo/apps/js/mojo_module.h"
#include "gin/arguments.h"
#include "gin/converter.h"
#include "gin/object_template_builder.h"
#include "gin/per_isolate_data.h"
#include "mojo/apps/js/js_app.h"
#include "mojo/apps/js/mojo_module.h"
#include "mojo/bindings/js/handle.h"
#include "mojo/common/data_pipe_utils.h"
namespace mojo {
namespace apps {
namespace {
gin::WrapperInfo g_wrapper_info = {gin::kEmbedderNativeGin};
} // namespace
const char Mojo::kModuleName[] = "mojo";
v8::Local<v8::Value> Mojo::GetModule(JSApp* js_app, v8::Isolate* isolate) {
gin::PerIsolateData* data = gin::PerIsolateData::From(isolate);
v8::Local<v8::ObjectTemplate> templ =
data->GetObjectTemplate(&g_wrapper_info);
if (templ.IsEmpty()) {
templ = gin::ObjectTemplateBuilder(isolate)
.SetMethod("connectToService",
base::Bind(&JSApp::ConnectToService,
base::Unretained(js_app)))
.SetMethod("quit",
base::Bind(&JSApp::Quit, base::Unretained(js_app)))
.Build();
data->SetObjectTemplate(&g_wrapper_info, templ);
}
return templ->NewInstance();
}
} // namespace apps
} // namespace mojo
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef MOJO_APPS_JS_MOJO_MODULE_H_
#define MOJO_APPS_JS_MOJO_MODULE_H_
#include "gin/gin_export.h"
#include "v8/include/v8.h"
namespace mojo {
namespace apps {
class JSApp;
class Mojo {
public:
static const char kModuleName[];
static v8::Local<v8::Value> GetModule(JSApp* js_app, v8::Isolate* isolate);
};
} // namespace apps
} // namespace mojo
#endif // MOJO_APPS_JS_MOJO_MODULE_H_
......@@ -14,20 +14,17 @@
namespace mojo {
namespace common {
namespace {
bool BlockingCopyToFile(ScopedDataPipeConsumerHandle source,
const base::FilePath& destination) {
base::ScopedFILE fp(base::OpenFile(destination, "wb"));
if (!fp)
return false;
bool BlockingCopyHelper(ScopedDataPipeConsumerHandle source,
const base::Callback<size_t(const void*, uint32_t)>& write_bytes) {
for (;;) {
const void* buffer;
uint32_t num_bytes;
MojoResult result = BeginReadDataRaw(source.get(), &buffer, &num_bytes,
MOJO_READ_DATA_FLAG_NONE);
MojoResult result = BeginReadDataRaw(
source.get(), &buffer, &num_bytes, MOJO_READ_DATA_FLAG_NONE);
if (result == MOJO_RESULT_OK) {
size_t bytes_written = fwrite(buffer, 1, num_bytes, fp.get());
size_t bytes_written = write_bytes.Run(buffer, num_bytes);
result = EndReadDataRaw(source.get(), num_bytes);
if (bytes_written < num_bytes || result != MOJO_RESULT_OK)
return false;
......@@ -51,9 +48,35 @@ bool BlockingCopyToFile(ScopedDataPipeConsumerHandle source,
return false;
}
void CompleteBlockingCopyToFile(const base::Callback<void(bool)>& callback,
bool result) {
callback.Run(result);
size_t CopyToStringHelper(
std::string* result, const void* buffer, uint32_t num_bytes) {
result->append(static_cast<const char*>(buffer), num_bytes);
return num_bytes;
}
size_t CopyToFileHelper(FILE* fp, const void* buffer, uint32_t num_bytes) {
return fwrite(buffer, 1, num_bytes, fp);
}
} // namespace
// TODO(hansmuller): Add a max_size parameter.
bool BlockingCopyToString(ScopedDataPipeConsumerHandle source,
std::string* result) {
CHECK(result);
result->clear();
return BlockingCopyHelper(
source.Pass(), base::Bind(&CopyToStringHelper, result));
}
bool BlockingCopyToFile(ScopedDataPipeConsumerHandle source,
const base::FilePath& destination) {
base::ScopedFILE fp(base::OpenFile(destination, "wb"));
if (!fp)
return false;
return BlockingCopyHelper(
source.Pass(), base::Bind(&CopyToFileHelper, fp.get()));
}
void CopyToFile(ScopedDataPipeConsumerHandle source,
......
......@@ -5,6 +5,8 @@
#ifndef MOJO_SHELL_DATA_PIPE_UTILS_H_
#define MOJO_SHELL_DATA_PIPE_UTILS_H_
#include <string>
#include "base/callback_forward.h"
#include "mojo/common/mojo_common_export.h"
#include "mojo/public/cpp/system/core.h"
......@@ -26,6 +28,13 @@ void MOJO_COMMON_EXPORT CopyToFile(
base::TaskRunner* task_runner,
const base::Callback<void(bool /*success*/)>& callback);
// Copies the data from |source| into |contents| and returns true on success and
// false on error. In case of I/O error, |contents| holds the data that could
// be read from source before the error occurred.
bool MOJO_COMMON_EXPORT BlockingCopyToString(
ScopedDataPipeConsumerHandle source,
std::string* contents);
} // namespace common
} // namespace mojo
......
......@@ -12,6 +12,7 @@
'type': 'static_library',
'dependencies': [
'../base/base.gyp:base',
'../base/base.gyp:base_i18n',
'../gin/gin.gyp:gin',
'../ui/gl/gl.gyp:gl',
'../v8/tools/gyp/v8.gyp:v8',
......@@ -80,10 +81,17 @@
'target_name': 'mojo_js',
'type': 'loadable_module',
'dependencies': [
'mojo_base.gyp:mojo_application_chromium',
'mojo_base.gyp:mojo_cpp_bindings',
'mojo_base.gyp:mojo_utility',
'mojo_content_handler_bindings',
'mojo_js_lib',
'<(mojo_system_for_loadable_module)',
],
'sources': [
'apps/js/application_delegate_impl.cc',
'apps/js/js_app.cc',
'apps/js/mojo_module.cc',
'apps/js/main.cc',
],
},
......
......@@ -188,9 +188,9 @@ define("mojo/public/js/bindings/validator", [
return structClass.validate(this, structOffset);
}
Validator.prototype.validateStringPointer = function(offset) {
Validator.prototype.validateStringPointer = function(offset, nullable) {
return this.validateArrayPointer(
offset, codec.Uint8.encodedSize, 0, codec.Uint8);
offset, codec.Uint8.encodedSize, 0, codec.Uint8, nullable);
}
// Similar to Array_Data<T>::Validate()
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment