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/extension_helper.h" | 10 #include "chrome/renderer/extensions/extension_helper.h" |
| 11 #include "chrome/renderer/weak_v8_function_map.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 |
20 using WebKit::WebDocument; | 21 using WebKit::WebDocument; |
(...skipping 21 matching lines...) Expand all Loading... |
42 const char kNoWebstoreItemLinkFoundError[] = | 43 const char kNoWebstoreItemLinkFoundError[] = |
43 "No Chrome Web Store item link found."; | 44 "No Chrome Web Store item link found."; |
44 const char kInvalidWebstoreItemUrlError[] = | 45 const char kInvalidWebstoreItemUrlError[] = |
45 "Invalid Chrome Web Store item URL."; | 46 "Invalid Chrome Web Store item URL."; |
46 | 47 |
47 // chrome.webstore.install() calls generate an install ID so that the install's | 48 // 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 | 49 // callbacks may be fired when the browser notifies us of install completion |
49 // (successful or not) via HandleInstallResponse. | 50 // (successful or not) via HandleInstallResponse. |
50 int g_next_install_id = 0; | 51 int g_next_install_id = 0; |
51 | 52 |
52 // Callbacks are kept track of in maps keyed by install ID. Values are weak | 53 base::LazyInstance<WeakV8FunctionMap> g_success_callbacks( |
53 // references to functions. Entries are automatically removed when functions | 54 base::LINKER_INITIALIZED); |
54 // get garbage collected. | 55 base::LazyInstance<WeakV8FunctionMap> g_failure_callbacks( |
55 typedef std::map<int, v8::Persistent<v8::Function> > CallbackMap; | 56 base::LINKER_INITIALIZED); |
56 | |
57 base::LazyInstance<CallbackMap> g_success_callbacks(base::LINKER_INITIALIZED); | |
58 base::LazyInstance<CallbackMap> g_failure_callbacks(base::LINKER_INITIALIZED); | |
59 | |
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 | 57 |
95 } // anonymous namespace | 58 } // anonymous namespace |
96 | 59 |
97 class ExtensionImpl : public v8::Extension { | 60 class ExtensionImpl : public v8::Extension { |
98 public: | 61 public: |
99 ExtensionImpl() : | 62 ExtensionImpl() : |
100 v8::Extension( | 63 v8::Extension( |
101 kWebstoreV8ExtensionName, | 64 kWebstoreV8ExtensionName, |
102 "var chrome = chrome || {};" | 65 "var chrome = chrome || {};" |
103 "if (!chrome.webstore) {" | 66 "if (!chrome.webstore) {" |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
140 std::string error; | 103 std::string error; |
141 if (!GetWebstoreItemIdFromFrame( | 104 if (!GetWebstoreItemIdFromFrame( |
142 frame, preferred_store_link_url, &webstore_item_id, &error)) { | 105 frame, preferred_store_link_url, &webstore_item_id, &error)) { |
143 v8::ThrowException(v8::String::New(error.c_str())); | 106 v8::ThrowException(v8::String::New(error.c_str())); |
144 return v8::Undefined(); | 107 return v8::Undefined(); |
145 } | 108 } |
146 | 109 |
147 int install_id = g_next_install_id++; | 110 int install_id = g_next_install_id++; |
148 if (args.Length() >= 2 && !args[1]->IsUndefined()) { | 111 if (args.Length() >= 2 && !args[1]->IsUndefined()) { |
149 if (args[1]->IsFunction()) { | 112 if (args[1]->IsFunction()) { |
150 AddToCallbackMap(install_id, args[1], g_success_callbacks.Pointer()); | 113 g_success_callbacks.Get().Add(install_id, v8::Function::Cast(*args[1])); |
151 } else { | 114 } else { |
152 v8::ThrowException(v8::String::New(kSuccessCallbackNotAFunctionError)); | 115 v8::ThrowException(v8::String::New(kSuccessCallbackNotAFunctionError)); |
153 return v8::Undefined(); | 116 return v8::Undefined(); |
154 } | 117 } |
155 } | 118 } |
156 if (args.Length() >= 3 && !args[2]->IsUndefined()) { | 119 if (args.Length() >= 3 && !args[2]->IsUndefined()) { |
157 if (args[2]->IsFunction()) { | 120 if (args[2]->IsFunction()) { |
158 AddToCallbackMap(install_id, args[2], g_failure_callbacks.Pointer()); | 121 g_failure_callbacks.Get().Add(install_id, v8::Function::Cast(*args[2])); |
159 } else { | 122 } else { |
160 v8::ThrowException(v8::String::New(kFailureCallbackNotAFunctionError)); | 123 v8::ThrowException(v8::String::New(kFailureCallbackNotAFunctionError)); |
161 return v8::Undefined(); | 124 return v8::Undefined(); |
162 } | 125 } |
163 } | 126 } |
164 | 127 |
165 ExtensionHelper* helper = ExtensionHelper::Get(render_view); | 128 ExtensionHelper* helper = ExtensionHelper::Get(render_view); |
166 helper->InlineWebstoreInstall( | 129 helper->InlineWebstoreInstall( |
167 install_id, webstore_item_id, frame->document().url()); | 130 install_id, webstore_item_id, frame->document().url()); |
168 return v8::Undefined(); | 131 return v8::Undefined(); |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
263 | 226 |
264 // static | 227 // static |
265 v8::Extension* ChromeWebstoreExtension::Get() { | 228 v8::Extension* ChromeWebstoreExtension::Get() { |
266 return new ExtensionImpl(); | 229 return new ExtensionImpl(); |
267 } | 230 } |
268 | 231 |
269 // static | 232 // static |
270 void ChromeWebstoreExtension::HandleInstallResponse(int install_id, | 233 void ChromeWebstoreExtension::HandleInstallResponse(int install_id, |
271 bool success, | 234 bool success, |
272 const std::string& error) { | 235 const std::string& error) { |
273 CallbackMap* callback_map = | 236 WeakV8FunctionMap& callback_map = |
274 success ? g_success_callbacks.Pointer() : g_failure_callbacks.Pointer(); | 237 success ? g_success_callbacks.Get() : g_failure_callbacks.Get(); |
275 CallbackMap::iterator iter = callback_map->find(install_id); | |
276 | 238 |
277 if (iter == callback_map->end() || iter->second.IsEmpty()) return; | 239 v8::Persistent<v8::Function> function = callback_map.Remove(install_id); |
278 const v8::Persistent<v8::Function>& function = (*iter).second; | 240 if (function.IsEmpty()) |
| 241 return; |
279 | 242 |
280 v8::HandleScope handle_scope; | 243 v8::HandleScope handle_scope; |
281 v8::Context::Scope context_scope(function->CreationContext()); | 244 v8::Context::Scope context_scope(function->CreationContext()); |
282 v8::Handle<v8::Value> argv[1]; | 245 v8::Handle<v8::Value> argv[1]; |
283 argv[0] = v8::String::New(error.c_str()); | 246 argv[0] = v8::String::New(error.c_str()); |
284 function->Call(v8::Object::New(), arraysize(argv), argv); | 247 function->Call(v8::Object::New(), arraysize(argv), argv); |
285 | |
286 callback_map->erase(iter); | |
287 } | 248 } |
OLD | NEW |