1 // Copyright (c) 2012 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 // TODO(dcarney): Remove this when UnsafePersistent is removed.
6 #define V8_ALLOW_ACCESS_TO_RAW_HANDLE_CONSTRUCTOR
7
8 #include "chrome/renderer/extensions/v8_schema_registry.h"
9
10 #include "base/logging.h"
11 #include "base/values.h"
12 #include "chrome/renderer/extensions/chrome_v8_context.h"
13 #include "chrome/renderer/extensions/object_backed_native_handler.h"
14 #include "content/public/renderer/v8_value_converter.h"
15 #include "extensions/common/extension_api.h"
16
17 using content::V8ValueConverter;
18
19 namespace extensions {
20
21 namespace {
22
23 class SchemaRegistryNativeHandler : public ObjectBackedNativeHandler {
24 public:
SchemaRegistryNativeHandler(V8SchemaRegistry * registry,scoped_ptr<ChromeV8Context> context)25 SchemaRegistryNativeHandler(V8SchemaRegistry* registry,
26 scoped_ptr<ChromeV8Context> context)
27 : ObjectBackedNativeHandler(context.get()),
28 context_(context.Pass()),
29 registry_(registry) {
30 RouteFunction("GetSchema",
31 base::Bind(&SchemaRegistryNativeHandler::GetSchema,
32 base::Unretained(this)));
33 }
34
35 private:
GetSchema(const v8::FunctionCallbackInfo<v8::Value> & args)36 void GetSchema(const v8::FunctionCallbackInfo<v8::Value>& args) {
37 args.GetReturnValue().Set(
38 registry_->GetSchema(*v8::String::Utf8Value(args[0])));
39 }
40
41 scoped_ptr<ChromeV8Context> context_;
42 V8SchemaRegistry* registry_;
43 };
44
45 } // namespace
46
V8SchemaRegistry()47 V8SchemaRegistry::V8SchemaRegistry() {}
48
~V8SchemaRegistry()49 V8SchemaRegistry::~V8SchemaRegistry() {
50 for (SchemaCache::iterator i = schema_cache_.begin();
51 i != schema_cache_.end(); ++i) {
52 i->second.dispose();
53 }
54 }
55
AsNativeHandler()56 scoped_ptr<NativeHandler> V8SchemaRegistry::AsNativeHandler() {
57 scoped_ptr<ChromeV8Context> context(new ChromeV8Context(
58 GetOrCreateContext(v8::Isolate::GetCurrent()),
59 NULL, // no frame
60 NULL, // no extension
61 Feature::UNSPECIFIED_CONTEXT));
62 return scoped_ptr<NativeHandler>(
63 new SchemaRegistryNativeHandler(this, context.Pass()));
64 }
65
GetSchemas(const std::vector<std::string> & apis)66 v8::Handle<v8::Array> V8SchemaRegistry::GetSchemas(
67 const std::vector<std::string>& apis) {
68 v8::Isolate* isolate = v8::Isolate::GetCurrent();
69 v8::EscapableHandleScope handle_scope(isolate);
70 v8::Context::Scope context_scope(GetOrCreateContext(isolate));
71
72 v8::Local<v8::Array> v8_apis(v8::Array::New(isolate, apis.size()));
73 size_t api_index = 0;
74 for (std::vector<std::string>::const_iterator i = apis.begin();
75 i != apis.end(); ++i) {
76 v8_apis->Set(api_index++, GetSchema(*i));
77 }
78 return handle_scope.Escape(v8_apis);
79 }
80
GetSchema(const std::string & api)81 v8::Handle<v8::Object> V8SchemaRegistry::GetSchema(const std::string& api) {
82
83 SchemaCache::iterator maybe_schema = schema_cache_.find(api);
84 if (maybe_schema != schema_cache_.end())
85 return maybe_schema->second.newLocal(v8::Isolate::GetCurrent());
86
87 v8::Isolate* isolate = v8::Isolate::GetCurrent();
88 v8::EscapableHandleScope handle_scope(isolate);
89 v8::Handle<v8::Context> context = GetOrCreateContext(isolate);
90 v8::Context::Scope context_scope(context);
91
92 const base::DictionaryValue* schema =
93 ExtensionAPI::GetSharedInstance()->GetSchema(api);
94 CHECK(schema) << api;
95 scoped_ptr<V8ValueConverter> v8_value_converter(V8ValueConverter::create());
96 v8::Handle<v8::Value> value = v8_value_converter->ToV8Value(schema, context);
97 CHECK(!value.IsEmpty());
98
99 v8::Persistent<v8::Object> v8_schema(context->GetIsolate(),
100 v8::Handle<v8::Object>::Cast(value));
101 v8::Local<v8::Object> to_return =
102 v8::Local<v8::Object>::New(isolate, v8_schema);
103 schema_cache_[api] = UnsafePersistent<v8::Object>(&v8_schema);
104 return handle_scope.Escape(to_return);
105 }
106
GetOrCreateContext(v8::Isolate * isolate)107 v8::Handle<v8::Context> V8SchemaRegistry::GetOrCreateContext(
108 v8::Isolate* isolate) {
109 // It's ok to create local handles in this function, since this is only called
110 // when we have a HandleScope.
111 if (context_.IsEmpty()) {
112 v8::Handle<v8::Context> context = v8::Context::New(isolate);
113 context_.reset(context);
114 return context;
115 }
116 return context_.NewHandle(isolate);
117 }
118
119 } // namespace extensions
120