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/object_backed_native_handler.h"
6
7#include "base/logging.h"
8#include "base/memory/linked_ptr.h"
9#include "extensions/renderer/console.h"
10#include "extensions/renderer/module_system.h"
11#include "extensions/renderer/script_context.h"
12#include "v8/include/v8.h"
13
14namespace extensions {
15
16namespace {
17// Key for the base::Bound routed function.
18const char* kHandlerFunction = "handler_function";
19}  // namespace
20
21ObjectBackedNativeHandler::ObjectBackedNativeHandler(ScriptContext* context)
22    : router_data_(context->v8_context()->GetIsolate()),
23      context_(context),
24      object_template_(
25          v8::ObjectTemplate::New(context->v8_context()->GetIsolate())) {}
26
27ObjectBackedNativeHandler::~ObjectBackedNativeHandler() { Invalidate(); }
28
29v8::Handle<v8::Object> ObjectBackedNativeHandler::NewInstance() {
30  return object_template_.NewHandle(v8::Isolate::GetCurrent())->NewInstance();
31}
32
33// static
34void ObjectBackedNativeHandler::Router(
35    const v8::FunctionCallbackInfo<v8::Value>& args) {
36  v8::HandleScope handle_scope(args.GetIsolate());
37  v8::Handle<v8::Object> data = args.Data().As<v8::Object>();
38
39  v8::Handle<v8::Value> handler_function_value =
40      data->Get(v8::String::NewFromUtf8(args.GetIsolate(), kHandlerFunction));
41  // See comment in header file for why we do this.
42  if (handler_function_value.IsEmpty() ||
43      handler_function_value->IsUndefined()) {
44    console::Error(args.GetIsolate()->GetCallingContext(),
45                   "Extension view no longer exists");
46    return;
47  }
48  DCHECK(handler_function_value->IsExternal());
49  static_cast<HandlerFunction*>(
50      handler_function_value.As<v8::External>()->Value())->Run(args);
51}
52
53void ObjectBackedNativeHandler::RouteFunction(
54    const std::string& name,
55    const HandlerFunction& handler_function) {
56  v8::Isolate* isolate = v8::Isolate::GetCurrent();
57  v8::HandleScope handle_scope(isolate);
58  v8::Context::Scope context_scope(context_->v8_context());
59
60  v8::Local<v8::Object> data = v8::Object::New(isolate);
61  data->Set(
62      v8::String::NewFromUtf8(isolate, kHandlerFunction),
63      v8::External::New(isolate, new HandlerFunction(handler_function)));
64  v8::Handle<v8::FunctionTemplate> function_template =
65      v8::FunctionTemplate::New(isolate, Router, data);
66  object_template_.NewHandle(isolate)
67      ->Set(isolate, name.c_str(), function_template);
68  router_data_.Append(data);
69}
70
71v8::Isolate* ObjectBackedNativeHandler::GetIsolate() const {
72  return context_->isolate();
73}
74
75void ObjectBackedNativeHandler::Invalidate() {
76  if (!is_valid())
77    return;
78  v8::Isolate* isolate = v8::Isolate::GetCurrent();
79  v8::HandleScope handle_scope(isolate);
80  v8::Context::Scope context_scope(context_->v8_context());
81
82  for (size_t i = 0; i < router_data_.Size(); i++) {
83    v8::Handle<v8::Object> data = router_data_.Get(i);
84    v8::Handle<v8::Value> handler_function_value =
85        data->Get(v8::String::NewFromUtf8(isolate, kHandlerFunction));
86    CHECK(!handler_function_value.IsEmpty());
87    delete static_cast<HandlerFunction*>(
88        handler_function_value.As<v8::External>()->Value());
89    data->Delete(v8::String::NewFromUtf8(isolate, kHandlerFunction));
90  }
91  router_data_.Clear();
92  object_template_.reset();
93  context_ = NULL;
94  NativeHandler::Invalidate();
95}
96
97}  // namespace extensions
98