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