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: 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: 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 47 V8SchemaRegistry::V8SchemaRegistry() {} 48 49 V8SchemaRegistry::~V8SchemaRegistry() { 50 for (SchemaCache::iterator i = schema_cache_.begin(); 51 i != schema_cache_.end(); ++i) { 52 i->second.dispose(); 53 } 54 } 55 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 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 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 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