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