| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/renderer/extensions/chrome_webstore_bindings.h" | 5 #include "chrome/renderer/extensions/chrome_webstore_bindings.h" |
| 6 | 6 |
| 7 #include "base/lazy_instance.h" | 7 #include "base/lazy_instance.h" |
| 8 #include "base/string_util.h" | 8 #include "base/string_util.h" |
| 9 #include "chrome/common/extensions/extension.h" | 9 #include "chrome/common/extensions/extension.h" |
| 10 #include "chrome/renderer/extensions/callback_map.h" |
| 10 #include "chrome/renderer/extensions/extension_helper.h" | 11 #include "chrome/renderer/extensions/extension_helper.h" |
| 11 #include "content/renderer/render_view.h" | 12 #include "content/renderer/render_view.h" |
| 12 #include "googleurl/src/gurl.h" | 13 #include "googleurl/src/gurl.h" |
| 13 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h" | 14 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h" |
| 14 #include "third_party/WebKit/Source/WebKit/chromium/public/WebElement.h" | 15 #include "third_party/WebKit/Source/WebKit/chromium/public/WebElement.h" |
| 15 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" | 16 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" |
| 16 #include "third_party/WebKit/Source/WebKit/chromium/public/WebNode.h" | 17 #include "third_party/WebKit/Source/WebKit/chromium/public/WebNode.h" |
| 17 #include "third_party/WebKit/Source/WebKit/chromium/public/WebNodeList.h" | 18 #include "third_party/WebKit/Source/WebKit/chromium/public/WebNodeList.h" |
| 18 #include "v8/include/v8.h" | 19 #include "v8/include/v8.h" |
| 19 | 20 |
| 21 using extensions_v8_util::CallbackMap; |
| 20 using WebKit::WebDocument; | 22 using WebKit::WebDocument; |
| 21 using WebKit::WebElement; | 23 using WebKit::WebElement; |
| 22 using WebKit::WebFrame; | 24 using WebKit::WebFrame; |
| 23 using WebKit::WebNode; | 25 using WebKit::WebNode; |
| 24 using WebKit::WebNodeList; | 26 using WebKit::WebNodeList; |
| 25 | 27 |
| 26 namespace { | 28 namespace { |
| 27 | 29 |
| 28 const char kWebstoreV8ExtensionName[] = "v8/ChromeWebstore"; | 30 const char kWebstoreV8ExtensionName[] = "v8/ChromeWebstore"; |
| 29 | 31 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 42 const char kNoWebstoreItemLinkFoundError[] = | 44 const char kNoWebstoreItemLinkFoundError[] = |
| 43 "No Chrome Web Store item link found."; | 45 "No Chrome Web Store item link found."; |
| 44 const char kInvalidWebstoreItemUrlError[] = | 46 const char kInvalidWebstoreItemUrlError[] = |
| 45 "Invalid Chrome Web Store item URL."; | 47 "Invalid Chrome Web Store item URL."; |
| 46 | 48 |
| 47 // chrome.webstore.install() calls generate an install ID so that the install's | 49 // chrome.webstore.install() calls generate an install ID so that the install's |
| 48 // callbacks may be fired when the browser notifies us of install completion | 50 // callbacks may be fired when the browser notifies us of install completion |
| 49 // (successful or not) via HandleInstallResponse. | 51 // (successful or not) via HandleInstallResponse. |
| 50 int g_next_install_id = 0; | 52 int g_next_install_id = 0; |
| 51 | 53 |
| 52 // Callbacks are kept track of in maps keyed by install ID. Values are weak | |
| 53 // references to functions. Entries are automatically removed when functions | |
| 54 // get garbage collected. | |
| 55 typedef std::map<int, v8::Persistent<v8::Function> > CallbackMap; | |
| 56 | |
| 57 base::LazyInstance<CallbackMap> g_success_callbacks(base::LINKER_INITIALIZED); | 54 base::LazyInstance<CallbackMap> g_success_callbacks(base::LINKER_INITIALIZED); |
| 58 base::LazyInstance<CallbackMap> g_failure_callbacks(base::LINKER_INITIALIZED); | 55 base::LazyInstance<CallbackMap> g_failure_callbacks(base::LINKER_INITIALIZED); |
| 59 | 56 |
| 60 // Extra data to be passed to MakeWeak/RemoveFromCallbackMap to know which entry | |
| 61 // to remove from which map. | |
| 62 struct CallbackMapData { | |
| 63 CallbackMap* callback_map; | |
| 64 int install_id; | |
| 65 }; | |
| 66 | |
| 67 // Disposes of a callback function and its corresponding entry in the callback | |
| 68 // map. | |
| 69 static void RemoveFromCallbackMap(v8::Persistent<v8::Value> context, | |
| 70 void* data) { | |
| 71 CallbackMapData* callback_map_data = static_cast<CallbackMapData*>(data); | |
| 72 callback_map_data->callback_map->erase(callback_map_data->install_id); | |
| 73 delete callback_map_data; | |
| 74 context.Dispose(); | |
| 75 } | |
| 76 | |
| 77 // Adds |callback_param| (assumed to be a function) to |callback_map| under the | |
| 78 // |install_id| key. Will be removed from the map when the value is about to be | |
| 79 // GCed. | |
| 80 static void AddToCallbackMap(int install_id, | |
| 81 v8::Local<v8::Value> callback_param, | |
| 82 CallbackMap* callback_map) { | |
| 83 CHECK(callback_param->IsFunction()); | |
| 84 CallbackMapData* callback_map_data = new CallbackMapData(); | |
| 85 callback_map_data->install_id = install_id; | |
| 86 callback_map_data->callback_map = callback_map; | |
| 87 | |
| 88 v8::Local<v8::Function> function = v8::Function::Cast(*callback_param); | |
| 89 v8::Persistent<v8::Function> wrapper = | |
| 90 v8::Persistent<v8::Function>::New(function); | |
| 91 (*callback_map)[install_id] = wrapper; | |
| 92 wrapper.MakeWeak(callback_map_data, RemoveFromCallbackMap); | |
| 93 } | |
| 94 | |
| 95 } // anonymous namespace | 57 } // anonymous namespace |
| 96 | 58 |
| 97 class ExtensionImpl : public v8::Extension { | 59 class ExtensionImpl : public v8::Extension { |
| 98 public: | 60 public: |
| 99 ExtensionImpl() : | 61 ExtensionImpl() : |
| 100 v8::Extension( | 62 v8::Extension( |
| 101 kWebstoreV8ExtensionName, | 63 kWebstoreV8ExtensionName, |
| 102 "var chrome = chrome || {};" | 64 "var chrome = chrome || {};" |
| 103 "if (!chrome.webstore) {" | 65 "if (!chrome.webstore) {" |
| 104 " chrome.webstore = new function() {" | 66 " chrome.webstore = new function() {" |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 140 std::string error; | 102 std::string error; |
| 141 if (!GetWebstoreItemIdFromFrame( | 103 if (!GetWebstoreItemIdFromFrame( |
| 142 frame, preferred_store_link_url, &webstore_item_id, &error)) { | 104 frame, preferred_store_link_url, &webstore_item_id, &error)) { |
| 143 v8::ThrowException(v8::String::New(error.c_str())); | 105 v8::ThrowException(v8::String::New(error.c_str())); |
| 144 return v8::Undefined(); | 106 return v8::Undefined(); |
| 145 } | 107 } |
| 146 | 108 |
| 147 int install_id = g_next_install_id++; | 109 int install_id = g_next_install_id++; |
| 148 if (args.Length() >= 2 && !args[1]->IsUndefined()) { | 110 if (args.Length() >= 2 && !args[1]->IsUndefined()) { |
| 149 if (args[1]->IsFunction()) { | 111 if (args[1]->IsFunction()) { |
| 150 AddToCallbackMap(install_id, args[1], g_success_callbacks.Pointer()); | 112 g_success_callbacks.Get().Add(install_id, v8::Function::Cast(*args[1])); |
| 151 } else { | 113 } else { |
| 152 v8::ThrowException(v8::String::New(kSuccessCallbackNotAFunctionError)); | 114 v8::ThrowException(v8::String::New(kSuccessCallbackNotAFunctionError)); |
| 153 return v8::Undefined(); | 115 return v8::Undefined(); |
| 154 } | 116 } |
| 155 } | 117 } |
| 156 if (args.Length() >= 3 && !args[2]->IsUndefined()) { | 118 if (args.Length() >= 3 && !args[2]->IsUndefined()) { |
| 157 if (args[2]->IsFunction()) { | 119 if (args[2]->IsFunction()) { |
| 158 AddToCallbackMap(install_id, args[2], g_failure_callbacks.Pointer()); | 120 g_failure_callbacks.Get().Add(install_id, v8::Function::Cast(*args[2])); |
| 159 } else { | 121 } else { |
| 160 v8::ThrowException(v8::String::New(kFailureCallbackNotAFunctionError)); | 122 v8::ThrowException(v8::String::New(kFailureCallbackNotAFunctionError)); |
| 161 return v8::Undefined(); | 123 return v8::Undefined(); |
| 162 } | 124 } |
| 163 } | 125 } |
| 164 | 126 |
| 165 ExtensionHelper* helper = ExtensionHelper::Get(render_view); | 127 ExtensionHelper* helper = ExtensionHelper::Get(render_view); |
| 166 helper->InlineWebstoreInstall( | 128 helper->InlineWebstoreInstall( |
| 167 install_id, webstore_item_id, frame->document().url()); | 129 install_id, webstore_item_id, frame->document().url()); |
| 168 return v8::Undefined(); | 130 return v8::Undefined(); |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 263 | 225 |
| 264 // static | 226 // static |
| 265 v8::Extension* ChromeWebstoreExtension::Get() { | 227 v8::Extension* ChromeWebstoreExtension::Get() { |
| 266 return new ExtensionImpl(); | 228 return new ExtensionImpl(); |
| 267 } | 229 } |
| 268 | 230 |
| 269 // static | 231 // static |
| 270 void ChromeWebstoreExtension::HandleInstallResponse(int install_id, | 232 void ChromeWebstoreExtension::HandleInstallResponse(int install_id, |
| 271 bool success, | 233 bool success, |
| 272 const std::string& error) { | 234 const std::string& error) { |
| 273 CallbackMap* callback_map = | 235 CallbackMap& callback_map = |
| 274 success ? g_success_callbacks.Pointer() : g_failure_callbacks.Pointer(); | 236 success ? g_success_callbacks.Get() : g_failure_callbacks.Get(); |
| 275 CallbackMap::iterator iter = callback_map->find(install_id); | |
| 276 | 237 |
| 277 if (iter == callback_map->end() || iter->second.IsEmpty()) return; | 238 v8::Persistent<v8::Function> function = callback_map.Remove(install_id); |
| 278 const v8::Persistent<v8::Function>& function = (*iter).second; | 239 if (function.IsEmpty()) |
| 240 return; |
| 279 | 241 |
| 280 v8::HandleScope handle_scope; | 242 v8::HandleScope handle_scope; |
| 281 v8::Context::Scope context_scope(function->CreationContext()); | 243 v8::Context::Scope context_scope(function->CreationContext()); |
| 282 v8::Handle<v8::Value> argv[1]; | 244 v8::Handle<v8::Value> argv[1]; |
| 283 argv[0] = v8::String::New(error.c_str()); | 245 argv[0] = v8::String::New(error.c_str()); |
| 284 function->Call(v8::Object::New(), arraysize(argv), argv); | 246 function->Call(v8::Object::New(), arraysize(argv), argv); |
| 285 | |
| 286 callback_map->erase(iter); | |
| 287 } | 247 } |
| OLD | NEW |