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_dispatcher.h" 6 7 #include "base/strings/string_number_conversions.h" 8 #include "base/strings/utf_string_conversions.h" 9 #include "content/common/gin_java_bridge_messages.h" 10 #include "content/public/renderer/render_frame.h" 11 #include "content/renderer/java/gin_java_bridge_object.h" 12 #include "third_party/WebKit/public/web/WebLocalFrame.h" 13 #include "third_party/WebKit/public/web/WebView.h" 14 15 namespace content { 16 17 GinJavaBridgeDispatcher::GinJavaBridgeDispatcher(RenderFrame* render_frame) 18 : RenderFrameObserver(render_frame), 19 inside_did_clear_window_object_(false) { 20 } 21 22 GinJavaBridgeDispatcher::~GinJavaBridgeDispatcher() { 23 } 24 25 bool GinJavaBridgeDispatcher::OnMessageReceived(const IPC::Message& msg) { 26 bool handled = true; 27 IPC_BEGIN_MESSAGE_MAP(GinJavaBridgeDispatcher, msg) 28 IPC_MESSAGE_HANDLER(GinJavaBridgeMsg_AddNamedObject, OnAddNamedObject) 29 IPC_MESSAGE_HANDLER(GinJavaBridgeMsg_RemoveNamedObject, OnRemoveNamedObject) 30 IPC_MESSAGE_UNHANDLED(handled = false) 31 IPC_END_MESSAGE_MAP() 32 return handled; 33 } 34 35 namespace { 36 37 class ScopedFlag { 38 public: 39 ScopedFlag(bool* flag) : flag_(flag) { 40 DCHECK(!*flag_); 41 *flag_ = true; 42 } 43 ~ScopedFlag() { 44 DCHECK(*flag_); 45 *flag_ = false; 46 } 47 private: 48 bool* flag_; 49 50 DISALLOW_COPY_AND_ASSIGN(ScopedFlag); 51 }; 52 53 } // namespace 54 55 void GinJavaBridgeDispatcher::DidClearWindowObject() { 56 // Accessing window object when adding properties to it may trigger 57 // a nested call to DidClearWindowObject. 58 if (inside_did_clear_window_object_) 59 return; 60 ScopedFlag flag(&inside_did_clear_window_object_); 61 for (NamedObjectMap::const_iterator iter = named_objects_.begin(); 62 iter != named_objects_.end(); ++iter) { 63 // Always create a new GinJavaBridgeObject, so we don't pull any of the V8 64 // wrapper's custom properties into the context of the page we have 65 // navigated to. The old GinJavaBridgeObject will be automatically 66 // deleted after its wrapper will be collected. 67 // On the browser side, we ignore wrapper deletion events for named objects, 68 // as they are only removed upon embedder's request (RemoveNamedObject). 69 if (objects_.Lookup(iter->second)) 70 objects_.Remove(iter->second); 71 GinJavaBridgeObject* object = GinJavaBridgeObject::InjectNamed( 72 render_frame()->GetWebFrame(), AsWeakPtr(), iter->first, iter->second); 73 if (object) { 74 objects_.AddWithID(object, iter->second); 75 } else { 76 // Inform the host about wrapper creation failure. 77 render_frame()->Send(new GinJavaBridgeHostMsg_ObjectWrapperDeleted( 78 routing_id(), iter->second)); 79 } 80 } 81 } 82 83 void GinJavaBridgeDispatcher::OnAddNamedObject( 84 const std::string& name, 85 ObjectID object_id) { 86 // Added objects only become available after page reload, so here they 87 // are only added into the internal map. 88 named_objects_.insert(std::make_pair(name, object_id)); 89 } 90 91 void GinJavaBridgeDispatcher::OnRemoveNamedObject(const std::string& name) { 92 // Removal becomes in effect on next reload. We simply removing the entry 93 // from the map here. 94 NamedObjectMap::iterator iter = named_objects_.find(name); 95 DCHECK(iter != named_objects_.end()); 96 named_objects_.erase(iter); 97 } 98 99 void GinJavaBridgeDispatcher::GetJavaMethods( 100 ObjectID object_id, 101 std::set<std::string>* methods) { 102 render_frame()->Send(new GinJavaBridgeHostMsg_GetMethods( 103 routing_id(), object_id, methods)); 104 } 105 106 bool GinJavaBridgeDispatcher::HasJavaMethod(ObjectID object_id, 107 const std::string& method_name) { 108 bool result; 109 render_frame()->Send(new GinJavaBridgeHostMsg_HasMethod( 110 routing_id(), object_id, method_name, &result)); 111 return result; 112 } 113 114 scoped_ptr<base::Value> GinJavaBridgeDispatcher::InvokeJavaMethod( 115 ObjectID object_id, 116 const std::string& method_name, 117 const base::ListValue& arguments, 118 GinJavaBridgeError* error) { 119 base::ListValue result_wrapper; 120 render_frame()->Send( 121 new GinJavaBridgeHostMsg_InvokeMethod(routing_id(), 122 object_id, 123 method_name, 124 arguments, 125 &result_wrapper, 126 error)); 127 base::Value* result; 128 if (result_wrapper.Get(0, &result)) { 129 return scoped_ptr<base::Value>(result->DeepCopy()); 130 } else { 131 return scoped_ptr<base::Value>(); 132 } 133 } 134 135 GinJavaBridgeObject* GinJavaBridgeDispatcher::GetObject(ObjectID object_id) { 136 GinJavaBridgeObject* result = objects_.Lookup(object_id); 137 if (!result) { 138 result = GinJavaBridgeObject::InjectAnonymous(AsWeakPtr(), object_id); 139 if (result) 140 objects_.AddWithID(result, object_id); 141 } 142 return result; 143 } 144 145 void GinJavaBridgeDispatcher::OnGinJavaBridgeObjectDeleted(ObjectID object_id) { 146 if (!objects_.Lookup(object_id)) 147 return; 148 objects_.Remove(object_id); 149 render_frame()->Send( 150 new GinJavaBridgeHostMsg_ObjectWrapperDeleted(routing_id(), object_id)); 151 } 152 153 } // namespace content 154