Home | History | Annotate | Download | only in java
      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 "content/renderer/java/gin_java_bridge_object.h"
      6 
      7 #include "base/strings/utf_string_conversions.h"
      8 #include "content/common/android/gin_java_bridge_errors.h"
      9 #include "content/common/android/gin_java_bridge_value.h"
     10 #include "content/public/renderer/v8_value_converter.h"
     11 #include "content/renderer/java/gin_java_bridge_value_converter.h"
     12 #include "gin/function_template.h"
     13 #include "third_party/WebKit/public/web/WebFrame.h"
     14 #include "third_party/WebKit/public/web/WebKit.h"
     15 
     16 namespace content {
     17 
     18 namespace {
     19 
     20 const char kMethodInvocationErrorMessage[] =
     21     "Java bridge method invocation error";
     22 
     23 }  // namespace
     24 
     25 
     26 // static
     27 GinJavaBridgeObject* GinJavaBridgeObject::InjectNamed(
     28     blink::WebFrame* frame,
     29     const base::WeakPtr<GinJavaBridgeDispatcher>& dispatcher,
     30     const std::string& object_name,
     31     GinJavaBridgeDispatcher::ObjectID object_id) {
     32   v8::Isolate* isolate = blink::mainThreadIsolate();
     33   v8::HandleScope handle_scope(isolate);
     34   v8::Handle<v8::Context> context = frame->mainWorldScriptContext();
     35   if (context.IsEmpty())
     36     return NULL;
     37 
     38   GinJavaBridgeObject* object =
     39       new GinJavaBridgeObject(isolate, dispatcher, object_id);
     40 
     41   v8::Context::Scope context_scope(context);
     42   v8::Handle<v8::Object> global = context->Global();
     43   gin::Handle<GinJavaBridgeObject> controller =
     44       gin::CreateHandle(isolate, object);
     45   // WrappableBase instance deletes itself in case of a wrapper
     46   // creation failure, thus there is no need to delete |object|.
     47   if (controller.IsEmpty())
     48     return NULL;
     49 
     50   global->Set(gin::StringToV8(isolate, object_name), controller.ToV8());
     51   return object;
     52 }
     53 
     54 // static
     55 GinJavaBridgeObject* GinJavaBridgeObject::InjectAnonymous(
     56     const base::WeakPtr<GinJavaBridgeDispatcher>& dispatcher,
     57     GinJavaBridgeDispatcher::ObjectID object_id) {
     58   return new GinJavaBridgeObject(
     59       blink::mainThreadIsolate(), dispatcher, object_id);
     60 }
     61 
     62 GinJavaBridgeObject::GinJavaBridgeObject(
     63     v8::Isolate* isolate,
     64     const base::WeakPtr<GinJavaBridgeDispatcher>& dispatcher,
     65     GinJavaBridgeDispatcher::ObjectID object_id)
     66     : gin::NamedPropertyInterceptor(isolate, this),
     67       dispatcher_(dispatcher),
     68       object_id_(object_id),
     69       converter_(new GinJavaBridgeValueConverter()) {
     70 }
     71 
     72 GinJavaBridgeObject::~GinJavaBridgeObject() {
     73   if (dispatcher_)
     74     dispatcher_->OnGinJavaBridgeObjectDeleted(object_id_);
     75 }
     76 
     77 gin::ObjectTemplateBuilder GinJavaBridgeObject::GetObjectTemplateBuilder(
     78     v8::Isolate* isolate) {
     79   return gin::Wrappable<GinJavaBridgeObject>::GetObjectTemplateBuilder(isolate)
     80       .AddNamedPropertyInterceptor();
     81 }
     82 
     83 v8::Local<v8::Value> GinJavaBridgeObject::GetNamedProperty(
     84     v8::Isolate* isolate,
     85     const std::string& property) {
     86   std::map<std::string, bool>::iterator method_pos =
     87       known_methods_.find(property);
     88   if (method_pos == known_methods_.end()) {
     89     if (!dispatcher_) {
     90       return v8::Local<v8::Value>();
     91     }
     92     known_methods_[property] = dispatcher_->HasJavaMethod(object_id_, property);
     93   }
     94   if (known_methods_[property]) {
     95     return gin::CreateFunctionTemplate(
     96                isolate,
     97                base::Bind(&GinJavaBridgeObject::InvokeMethod,
     98                           base::Unretained(this),
     99                           property))->GetFunction();
    100   } else {
    101     return v8::Local<v8::Value>();
    102   }
    103 }
    104 
    105 std::vector<std::string> GinJavaBridgeObject::EnumerateNamedProperties(
    106     v8::Isolate* isolate) {
    107   std::set<std::string> method_names;
    108   if (dispatcher_)
    109     dispatcher_->GetJavaMethods(object_id_, &method_names);
    110   return std::vector<std::string> (method_names.begin(), method_names.end());
    111 }
    112 
    113 v8::Handle<v8::Value> GinJavaBridgeObject::InvokeMethod(
    114     const std::string& name,
    115     gin::Arguments* args) {
    116   if (!dispatcher_) {
    117     args->isolate()->ThrowException(v8::Exception::Error(gin::StringToV8(
    118         args->isolate(), kMethodInvocationErrorMessage)));
    119     return v8::Undefined(args->isolate());
    120   }
    121 
    122   base::ListValue arguments;
    123   {
    124     v8::HandleScope handle_scope(args->isolate());
    125     v8::Handle<v8::Context> context = args->isolate()->GetCurrentContext();
    126     v8::Handle<v8::Value> val;
    127     while (args->GetNext(&val)) {
    128       scoped_ptr<base::Value> arg(converter_->FromV8Value(val, context));
    129       if (arg.get()) {
    130         arguments.Append(arg.release());
    131       } else {
    132         arguments.Append(base::Value::CreateNullValue());
    133       }
    134     }
    135   }
    136 
    137   GinJavaBridgeError error;
    138   scoped_ptr<base::Value> result = dispatcher_->InvokeJavaMethod(
    139       object_id_, name, arguments, &error);
    140   if (!result.get()) {
    141     args->isolate()->ThrowException(v8::Exception::Error(gin::StringToV8(
    142         args->isolate(), GinJavaBridgeErrorToString(error))));
    143     return v8::Undefined(args->isolate());
    144   }
    145   if (!result->IsType(base::Value::TYPE_BINARY)) {
    146     return converter_->ToV8Value(result.get(),
    147                                  args->isolate()->GetCurrentContext());
    148   }
    149 
    150   scoped_ptr<const GinJavaBridgeValue> gin_value =
    151       GinJavaBridgeValue::FromValue(result.get());
    152   if (gin_value->IsType(GinJavaBridgeValue::TYPE_OBJECT_ID)) {
    153     GinJavaBridgeObject* result = NULL;
    154     GinJavaBridgeDispatcher::ObjectID object_id;
    155     if (gin_value->GetAsObjectID(&object_id)) {
    156       result = dispatcher_->GetObject(object_id);
    157     }
    158     if (result) {
    159       gin::Handle<GinJavaBridgeObject> controller =
    160           gin::CreateHandle(args->isolate(), result);
    161       if (controller.IsEmpty())
    162         return v8::Undefined(args->isolate());
    163       return controller.ToV8();
    164     }
    165   } else if (gin_value->IsType(GinJavaBridgeValue::TYPE_NONFINITE)) {
    166     float float_value;
    167     gin_value->GetAsNonFinite(&float_value);
    168     return v8::Number::New(args->isolate(), float_value);
    169   }
    170   return v8::Undefined(args->isolate());
    171 }
    172 
    173 gin::WrapperInfo GinJavaBridgeObject::kWrapperInfo = {gin::kEmbedderNativeGin};
    174 
    175 }  // namespace content
    176