summaryrefslogtreecommitdiffstats
path: root/chrome/renderer/module_system.cc
blob: 691843f352cca231075c16afdfa36f72ea8a467a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
// Copyright (c) 2012 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 "chrome/renderer/module_system.h"

#include "base/bind.h"
#include "chrome/renderer/static_v8_external_string_resource.h"
#include "grit/renderer_resources.h"
#include "ui/base/resource/resource_bundle.h"

namespace {

} // namespace

ModuleSystem::ModuleSystem(SourceMap* source_map)
    : source_map_(source_map),
      natives_enabled_(true) {
  RouteFunction("GetSource",
      base::Bind(&ModuleSystem::GetSource, base::Unretained(this)));
  RouteFunction("GetNative",
      base::Bind(&ModuleSystem::GetNative, base::Unretained(this)));
}

ModuleSystem::~ModuleSystem() {
}

void ModuleSystem::Require(const std::string& module_name) {
  v8::HandleScope handle_scope;
  v8::Handle<v8::Value> argv[] = {
    v8::String::New(module_name.c_str()),
  };
  v8::Handle<v8::Object> global(v8::Context::GetCurrent()->Global());
  GetOrCreateRequire()->Call(global, arraysize(argv), argv);
}

void ModuleSystem::RegisterNativeHandler(const std::string& name,
    scoped_ptr<NativeHandler> native_handler) {
  native_handler_map_[name] =
      linked_ptr<NativeHandler>(native_handler.release());
}

void ModuleSystem::RunString(const std::string& code, const std::string& name) {
  v8::HandleScope handle_scope;
  RunString(v8::String::New(code.c_str()), v8::String::New(name.c_str()));
}

v8::Handle<v8::Function> ModuleSystem::CreateRequire() {
  v8::HandleScope handle_scope;
  v8::Handle<v8::Object> bootstrap = NewInstance();
  // NOTE v8 takes ownership of the StaticV8ExternalAsciiStringResource.
  v8::Handle<v8::String> source = v8::String::NewExternal(
      new StaticV8ExternalAsciiStringResource(GetResource(IDR_REQUIRE_JS)));
  v8::Handle<v8::Value> result = RunString(source,
                                           v8::String::New("require.js"));
  v8::Handle<v8::Function> require_factory =
      v8::Handle<v8::Function>::Cast(result);
  CHECK(!require_factory.IsEmpty())
      << "require.js should define a function that returns a require() "
      << "function";
  v8::Handle<v8::Value> argv[] = {
    bootstrap,
  };
  v8::Handle<v8::Object> global(v8::Context::GetCurrent()->Global());
  v8::Handle<v8::Value> require = require_factory->Call(
      global, arraysize(argv), argv);
  global->SetHiddenValue(v8::String::New("require"), require);
  return handle_scope.Close(v8::Handle<v8::Function>::Cast(require));
}

v8::Handle<v8::Value> ModuleSystem::RunString(v8::Handle<v8::String> code,
                                              v8::Handle<v8::String> name) {
  v8::HandleScope handle_scope;
  return handle_scope.Close(v8::Script::New(code, name)->Run());
}

v8::Handle<v8::Value> ModuleSystem::GetSource(const v8::Arguments& args) {
  CHECK_EQ(1, args.Length());

  v8::HandleScope handle_scope;
  std::string module_name = *v8::String::AsciiValue(args[0]->ToString());
  if (!source_map_->Contains(module_name))
    return v8::Undefined();
  return handle_scope.Close(source_map_->GetSource(module_name));
}

v8::Handle<v8::Value> ModuleSystem::GetNative(const v8::Arguments& args) {
  CHECK_EQ(1, args.Length());
  if (!natives_enabled_)
    return ThrowException("Natives disabled");
  std::string native_name = *v8::String::AsciiValue(args[0]->ToString());
  NativeHandlerMap::iterator i = native_handler_map_.find(native_name);
  if (i == native_handler_map_.end())
    return v8::Undefined();
  return i->second->NewInstance();
}

base::StringPiece ModuleSystem::GetResource(int resourceId) {
  const ResourceBundle& resource_bundle = ResourceBundle::GetSharedInstance();
  return resource_bundle.GetRawDataResource(resourceId);
}

v8::Handle<v8::Value> ModuleSystem::ThrowException(const std::string& message) {
  return v8::ThrowException(v8::String::New(message.c_str()));
}

v8::Handle<v8::Function> ModuleSystem::GetOrCreateRequire() {
  v8::HandleScope handle_scope;
  v8::Handle<v8::String> require_string = v8::String::New("require");
  v8::Handle<v8::Object> global(v8::Context::GetCurrent()->Global());
  {
    v8::Handle<v8::Function> require =
        v8::Handle<v8::Function>::Cast(global->GetHiddenValue(require_string));
    if (!require.IsEmpty())
      return handle_scope.Close(require);
  }
  v8::Handle<v8::Function> require(CreateRequire());
  global->SetHiddenValue(require_string, require);
  return handle_scope.Close(require);
}