10529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// Copyright 2014 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
50529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "extensions/renderer/v8_schema_registry.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/renderer/v8_value_converter.h"
100f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "extensions/common/extension_api.h"
11a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "extensions/renderer/object_backed_native_handler.h"
120529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "extensions/renderer/script_context.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::V8ValueConverter;
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace extensions {
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)namespace {
19868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
20868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)class SchemaRegistryNativeHandler : public ObjectBackedNativeHandler {
21868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) public:
22868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  SchemaRegistryNativeHandler(V8SchemaRegistry* registry,
230529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                              scoped_ptr<ScriptContext> context)
24868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      : ObjectBackedNativeHandler(context.get()),
25868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        context_(context.Pass()),
26868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        registry_(registry) {
27868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    RouteFunction("GetSchema",
280529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                  base::Bind(&SchemaRegistryNativeHandler::GetSchema,
290529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                             base::Unretained(this)));
30868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
31868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
32868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) private:
337d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  void GetSchema(const v8::FunctionCallbackInfo<v8::Value>& args) {
347d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    args.GetReturnValue().Set(
350529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        registry_->GetSchema(*v8::String::Utf8Value(args[0])));
36868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
37868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
380529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  scoped_ptr<ScriptContext> context_;
39868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  V8SchemaRegistry* registry_;
40868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)};
41868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
42868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}  // namespace
43868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
440529e5d033099cbfc42635f6f6183833b09dff6eBen MurdochV8SchemaRegistry::V8SchemaRegistry() {
450529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
470529e5d033099cbfc42635f6f6183833b09dff6eBen MurdochV8SchemaRegistry::~V8SchemaRegistry() {
480529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
50868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)scoped_ptr<NativeHandler> V8SchemaRegistry::AsNativeHandler() {
510529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  scoped_ptr<ScriptContext> context(
520529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      new ScriptContext(GetOrCreateContext(v8::Isolate::GetCurrent()),
530529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                        NULL,  // no frame
540529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                        NULL,  // no extension
551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                        Feature::UNSPECIFIED_CONTEXT,
561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                        NULL,  // no effective extension
570529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                        Feature::UNSPECIFIED_CONTEXT));
58868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return scoped_ptr<NativeHandler>(
59868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      new SchemaRegistryNativeHandler(this, context.Pass()));
60868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
61868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)v8::Handle<v8::Array> V8SchemaRegistry::GetSchemas(
637d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const std::vector<std::string>& apis) {
647d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  v8::Isolate* isolate = v8::Isolate::GetCurrent();
65a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  v8::EscapableHandleScope handle_scope(isolate);
667d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  v8::Context::Scope context_scope(GetOrCreateContext(isolate));
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
68a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  v8::Local<v8::Array> v8_apis(v8::Array::New(isolate, apis.size()));
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t api_index = 0;
707d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  for (std::vector<std::string>::const_iterator i = apis.begin();
710529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch       i != apis.end();
720529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch       ++i) {
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    v8_apis->Set(api_index++, GetSchema(*i));
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
75a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  return handle_scope.Escape(v8_apis);
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)v8::Handle<v8::Object> V8SchemaRegistry::GetSchema(const std::string& api) {
79c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (schema_cache_ != NULL) {
80c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    v8::Local<v8::Object> cached_schema = schema_cache_->Get(api);
81c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    if (!cached_schema.IsEmpty()) {
82c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      return cached_schema;
83c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    }
84c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
86c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // Slow path: Need to build schema first.
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
887d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  v8::Isolate* isolate = v8::Isolate::GetCurrent();
89a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  v8::EscapableHandleScope handle_scope(isolate);
907d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  v8::Handle<v8::Context> context = GetOrCreateContext(isolate);
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  v8::Context::Scope context_scope(context);
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const base::DictionaryValue* schema =
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ExtensionAPI::GetSharedInstance()->GetSchema(api);
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(schema) << api;
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<V8ValueConverter> v8_value_converter(V8ValueConverter::create());
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  v8::Handle<v8::Value> value = v8_value_converter->ToV8Value(schema, context);
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CHECK(!value.IsEmpty());
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
100c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  v8::Local<v8::Object> v8_schema(v8::Handle<v8::Object>::Cast(value));
101c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  schema_cache_->Set(api, v8_schema);
102c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
103c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  return handle_scope.Escape(v8_schema);
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1067d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)v8::Handle<v8::Context> V8SchemaRegistry::GetOrCreateContext(
1077d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    v8::Isolate* isolate) {
108c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // It's ok to create local handles in this function, since this is only called
109c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // when we have a HandleScope.
110116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!context_holder_) {
111116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    context_holder_.reset(new gin::ContextHolder(isolate));
112116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    context_holder_->SetContext(v8::Context::New(isolate));
113c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    schema_cache_.reset(new SchemaCache(isolate));
114116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return context_holder_->context();
115c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
116116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return context_holder_->context();
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace extensions
120