• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
InjectNamed(blink::WebFrame * frame,const base::WeakPtr<GinJavaBridgeDispatcher> & dispatcher,const std::string & object_name,GinJavaBridgeDispatcher::ObjectID object_id)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
InjectAnonymous(const base::WeakPtr<GinJavaBridgeDispatcher> & dispatcher,GinJavaBridgeDispatcher::ObjectID object_id)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 
GinJavaBridgeObject(v8::Isolate * isolate,const base::WeakPtr<GinJavaBridgeDispatcher> & dispatcher,GinJavaBridgeDispatcher::ObjectID object_id)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 
~GinJavaBridgeObject()72 GinJavaBridgeObject::~GinJavaBridgeObject() {
73   if (dispatcher_)
74     dispatcher_->OnGinJavaBridgeObjectDeleted(object_id_);
75 }
76 
GetObjectTemplateBuilder(v8::Isolate * isolate)77 gin::ObjectTemplateBuilder GinJavaBridgeObject::GetObjectTemplateBuilder(
78     v8::Isolate* isolate) {
79   return gin::Wrappable<GinJavaBridgeObject>::GetObjectTemplateBuilder(isolate)
80       .AddNamedPropertyInterceptor();
81 }
82 
GetNamedProperty(v8::Isolate * isolate,const std::string & property)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 
EnumerateNamedProperties(v8::Isolate * isolate)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 
InvokeMethod(const std::string & name,gin::Arguments * args)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