Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(291)

Side by Side Diff: chrome/renderer/extensions/extension_process_bindings.cc

Issue 8540012: Enable extension APIs for content scripts. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase Created 9 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "chrome/renderer/extensions/extension_process_bindings.h"
6
7 #include <map>
8 #include <set>
9 #include <string>
10 #include <vector>
11
12 #include "base/callback.h"
13 #include "base/command_line.h"
14 #include "base/json/json_reader.h"
15 #include "base/lazy_instance.h"
16 #include "base/memory/scoped_ptr.h"
17 #include "base/string_number_conversions.h"
18 #include "base/string_util.h"
19 #include "base/utf_string_conversions.h"
20 #include "chrome/common/extensions/extension.h"
21 #include "chrome/common/extensions/extension_action.h"
22 #include "chrome/common/extensions/extension_constants.h"
23 #include "chrome/common/extensions/extension_messages.h"
24 #include "chrome/common/extensions/extension_set.h"
25 #include "chrome/common/extensions/url_pattern.h"
26 #include "chrome/common/render_messages.h"
27 #include "chrome/common/url_constants.h"
28 #include "chrome/common/chrome_view_types.h"
29 #include "content/public/renderer/render_view.h"
30 #include "content/public/renderer/render_view_visitor.h"
31 #include "chrome/renderer/chrome_render_process_observer.h"
32 #include "chrome/renderer/extensions/chrome_v8_context.h"
33 #include "chrome/renderer/extensions/chrome_v8_context_set.h"
34 #include "chrome/renderer/extensions/chrome_v8_extension.h"
35 #include "chrome/renderer/extensions/event_bindings.h"
36 #include "chrome/renderer/extensions/extension_dispatcher.h"
37 #include "chrome/renderer/extensions/extension_helper.h"
38 #include "chrome/renderer/extensions/renderer_extension_bindings.h"
39 #include "chrome/renderer/extensions/user_script_slave.h"
40 #include "chrome/renderer/static_v8_external_string_resource.h"
41 #include "content/public/renderer/render_view.h"
42 #include "grit/common_resources.h"
43 #include "grit/renderer_resources.h"
44 #include "third_party/WebKit/Source/WebKit/chromium/public/WebBlob.h"
45 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h"
46 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
47 #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
48 #include "third_party/skia/include/core/SkBitmap.h"
49 #include "third_party/skia/include/core/SkColor.h"
50 #include "ui/base/resource/resource_bundle.h"
51 #include "v8/include/v8.h"
52 #include "webkit/glue/webkit_glue.h"
53
54 using WebKit::WebFrame;
55 using WebKit::WebView;
56
57 namespace {
58
59 const char* kExtensionDeps[] = {
60 "extensions/event.js",
61 "extensions/json_schema.js",
62 "extensions/renderer_extension_bindings.js",
63 "extensions/apitest.js"
64 };
65
66 // Contains info relevant to a pending API request.
67 struct PendingRequest {
68 public :
69 PendingRequest(v8::Persistent<v8::Context> context, const std::string& name,
70 const std::string& extension_id)
71 : context(context), name(name), extension_id(extension_id) {
72 }
73 v8::Persistent<v8::Context> context;
74 std::string name;
75 std::string extension_id;
76 };
77 typedef std::map<int, linked_ptr<PendingRequest> > PendingRequestMap;
78
79 base::LazyInstance<PendingRequestMap> g_pending_requests(
80 base::LINKER_INITIALIZED);
81
82 // A RenderViewVisitor class that iterates through the set of available
83 // views, looking for a view of the given type, in the given browser window
84 // and within the given extension.
85 // Used to accumulate the list of views associated with an extension.
86 class ExtensionViewAccumulator : public content::RenderViewVisitor {
87 public:
88 ExtensionViewAccumulator(const std::string& extension_id,
89 int browser_window_id,
90 content::ViewType view_type)
91 : extension_id_(extension_id),
92 browser_window_id_(browser_window_id),
93 view_type_(view_type),
94 views_(v8::Array::New()),
95 index_(0) {
96 }
97
98 v8::Local<v8::Array> views() { return views_; }
99
100 virtual bool Visit(content::RenderView* render_view) {
101 ExtensionHelper* helper = ExtensionHelper::Get(render_view);
102 if (!ViewTypeMatches(helper->view_type(), view_type_))
103 return true;
104
105 GURL url = render_view->GetWebView()->mainFrame()->document().url();
106 if (!url.SchemeIs(chrome::kExtensionScheme))
107 return true;
108 const std::string& extension_id = url.host();
109 if (extension_id != extension_id_)
110 return true;
111
112 if (browser_window_id_ != extension_misc::kUnknownWindowId &&
113 helper->browser_window_id() != browser_window_id_) {
114 return true;
115 }
116
117 v8::Local<v8::Context> context =
118 render_view->GetWebView()->mainFrame()->mainWorldScriptContext();
119 if (!context.IsEmpty()) {
120 v8::Local<v8::Value> window = context->Global();
121 DCHECK(!window.IsEmpty());
122
123 if (!OnMatchedView(window))
124 return false;
125 }
126 return true;
127 }
128
129 private:
130 // Called on each view found matching the search criteria. Returns false
131 // to terminate the iteration.
132 bool OnMatchedView(v8::Local<v8::Value> view_window) {
133 views_->Set(v8::Integer::New(index_), view_window);
134 index_++;
135
136 if (view_type_ == chrome::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE)
137 return false; // There can be only one...
138
139 return true;
140 }
141
142 // Returns true is |type| "isa" |match|.
143 static bool ViewTypeMatches(content::ViewType type, content::ViewType match) {
144 if (type == match)
145 return true;
146
147 // INVALID means match all.
148 if (match == content::VIEW_TYPE_INVALID)
149 return true;
150
151 return false;
152 }
153
154 std::string extension_id_;
155 int browser_window_id_;
156 content::ViewType view_type_;
157 v8::Local<v8::Array> views_;
158 int index_;
159 };
160
161 class ExtensionImpl : public ChromeV8Extension {
162 public:
163 explicit ExtensionImpl(ExtensionDispatcher* extension_dispatcher)
164 : ChromeV8Extension("extensions/extension_process_bindings.js",
165 IDR_EXTENSION_PROCESS_BINDINGS_JS,
166 arraysize(kExtensionDeps),
167 kExtensionDeps,
168 extension_dispatcher) {
169 }
170 ~ExtensionImpl() {}
171
172 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
173 v8::Handle<v8::String> name) {
174 if (name->Equals(v8::String::New("GetExtensionAPIDefinition"))) {
175 return v8::FunctionTemplate::New(GetExtensionAPIDefinition);
176 } else if (name->Equals(v8::String::New("GetExtensionViews"))) {
177 return v8::FunctionTemplate::New(GetExtensionViews,
178 v8::External::New(this));
179 } else if (name->Equals(v8::String::New("GetNextRequestId"))) {
180 return v8::FunctionTemplate::New(GetNextRequestId);
181 } else if (name->Equals(v8::String::New("OpenChannelToTab"))) {
182 return v8::FunctionTemplate::New(OpenChannelToTab);
183 } else if (name->Equals(v8::String::New("GetNextContextMenuId"))) {
184 return v8::FunctionTemplate::New(GetNextContextMenuId);
185 } else if (name->Equals(v8::String::New("GetNextTtsEventId"))) {
186 return v8::FunctionTemplate::New(GetNextTtsEventId);
187 } else if (name->Equals(v8::String::New("GetCurrentPageActions"))) {
188 return v8::FunctionTemplate::New(GetCurrentPageActions,
189 v8::External::New(this));
190 } else if (name->Equals(v8::String::New("StartRequest"))) {
191 return v8::FunctionTemplate::New(StartRequest,
192 v8::External::New(this));
193 } else if (name->Equals(v8::String::New("GetRenderViewId"))) {
194 return v8::FunctionTemplate::New(GetRenderViewId);
195 } else if (name->Equals(v8::String::New("SetIconCommon"))) {
196 return v8::FunctionTemplate::New(SetIconCommon,
197 v8::External::New(this));
198 } else if (name->Equals(v8::String::New("GetUniqueSubEventName"))) {
199 return v8::FunctionTemplate::New(GetUniqueSubEventName);
200 } else if (name->Equals(v8::String::New("GetLocalFileSystem"))) {
201 return v8::FunctionTemplate::New(GetLocalFileSystem);
202 } else if (name->Equals(v8::String::New("DecodeJPEG"))) {
203 return v8::FunctionTemplate::New(DecodeJPEG, v8::External::New(this));
204 } else if (name->Equals(v8::String::New("CreateBlob"))) {
205 return v8::FunctionTemplate::New(CreateBlob, v8::External::New(this));
206 }
207
208 return ChromeV8Extension::GetNativeFunction(name);
209 }
210
211 private:
212 static v8::Handle<v8::Value> GetExtensionAPIDefinition(
213 const v8::Arguments& args) {
214 return v8::String::NewExternal(
215 new StaticV8ExternalAsciiStringResource(
216 ResourceBundle::GetSharedInstance().GetRawDataResource(
217 IDR_EXTENSION_API_JSON)));
218 }
219
220 static v8::Handle<v8::Value> GetExtensionViews(const v8::Arguments& args) {
221 if (args.Length() != 2)
222 return v8::Undefined();
223
224 if (!args[0]->IsInt32() || !args[1]->IsString())
225 return v8::Undefined();
226
227 // |browser_window_id| == extension_misc::kUnknownWindowId means getting
228 // views attached to any browser window.
229 int browser_window_id = args[0]->Int32Value();
230
231 std::string view_type_string = *v8::String::Utf8Value(args[1]->ToString());
232 StringToUpperASCII(&view_type_string);
233 // |view_type| == content::VIEW_TYPE_INVALID means getting any type of
234 // views.
235 content::ViewType view_type = content::VIEW_TYPE_INVALID;
236 if (view_type_string == chrome::kViewTypeBackgroundPage) {
237 view_type = chrome::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE;
238 } else if (view_type_string == chrome::kViewTypeInfobar) {
239 view_type = chrome::VIEW_TYPE_EXTENSION_INFOBAR;
240 } else if (view_type_string == chrome::kViewTypeNotification) {
241 view_type = chrome::VIEW_TYPE_NOTIFICATION;
242 } else if (view_type_string == chrome::kViewTypeTabContents) {
243 view_type = content::VIEW_TYPE_TAB_CONTENTS;
244 } else if (view_type_string == chrome::kViewTypePopup) {
245 view_type = chrome::VIEW_TYPE_EXTENSION_POPUP;
246 } else if (view_type_string == chrome::kViewTypeExtensionDialog) {
247 view_type = chrome::VIEW_TYPE_EXTENSION_DIALOG;
248 } else if (view_type_string != chrome::kViewTypeAll) {
249 return v8::Undefined();
250 }
251
252 ExtensionImpl* v8_extension = GetFromArguments<ExtensionImpl>(args);
253 const ::Extension* extension =
254 v8_extension->GetExtensionForCurrentRenderView();
255 if (!extension)
256 return v8::Undefined();
257
258 ExtensionViewAccumulator accumulator(extension->id(), browser_window_id,
259 view_type);
260 content::RenderView::ForEach(&accumulator);
261 return accumulator.views();
262 }
263
264 static v8::Handle<v8::Value> GetNextRequestId(const v8::Arguments& args) {
265 static int next_request_id = 0;
266 return v8::Integer::New(next_request_id++);
267 }
268
269 // Attach an event name to an object.
270 static v8::Handle<v8::Value> GetUniqueSubEventName(
271 const v8::Arguments& args) {
272 static int next_event_id = 0;
273 DCHECK(args.Length() == 1);
274 DCHECK(args[0]->IsString());
275 std::string event_name(*v8::String::AsciiValue(args[0]));
276 std::string unique_event_name =
277 event_name + "/" + base::IntToString(++next_event_id);
278 return v8::String::New(unique_event_name.c_str());
279 }
280
281 static v8::Handle<v8::Value> GetLocalFileSystem(
282 const v8::Arguments& args) {
283 DCHECK(args.Length() == 2);
284 DCHECK(args[0]->IsString());
285 DCHECK(args[1]->IsString());
286 std::string name(*v8::String::Utf8Value(args[0]));
287 std::string path(*v8::String::Utf8Value(args[1]));
288
289 WebFrame* webframe = WebFrame::frameForCurrentContext();
290 return webframe->createFileSystem(WebKit::WebFileSystem::TypeExternal,
291 WebKit::WebString::fromUTF8(name.c_str()),
292 WebKit::WebString::fromUTF8(path.c_str()));
293 }
294
295 // Decodes supplied JPEG byte array to image pixel array.
296 static v8::Handle<v8::Value> DecodeJPEG(const v8::Arguments& args) {
297 static const char* kAllowedIds[] = {
298 "haiffjcadagjlijoggckpgfnoeiflnem",
299 "gnedhmakppccajfpfiihfcdlnpgomkcf",
300 "fjcibdnjlbfnbfdjneajpipnlcppleek",
301 "oflbaaikkabfdfkimeclgkackhdkpnip" // Testing extension.
302 };
303 static const std::vector<std::string> allowed_ids(
304 kAllowedIds, kAllowedIds + arraysize(kAllowedIds));
305
306 ExtensionImpl* v8_extension = GetFromArguments<ExtensionImpl>(args);
307 const ::Extension* extension =
308 v8_extension->GetExtensionForCurrentRenderView();
309 if (!extension)
310 return v8::Undefined();
311 if (allowed_ids.end() == std::find(
312 allowed_ids.begin(), allowed_ids.end(), extension->id())) {
313 return v8::Undefined();
314 }
315
316 DCHECK(args.Length() == 1);
317 DCHECK(args[0]->IsArray());
318 v8::Local<v8::Object> jpeg_array = args[0]->ToObject();
319 size_t jpeg_length =
320 jpeg_array->Get(v8::String::New("length"))->Int32Value();
321
322 // Put input JPEG array into string for DecodeImage().
323 std::string jpeg_array_string;
324 jpeg_array_string.reserve(jpeg_length);
325
326 // Unfortunately we cannot request continuous backing store of the
327 // |jpeg_array| object as it might not have one. So we make
328 // element copy here.
329 // Note(mnaganov): If it is not fast enough
330 // (and main constraints might be in repetition of v8 API calls),
331 // change the argument type from Array to String and use
332 // String::Write().
333 // Note(vitalyr): Another option is to use Int8Array for inputs and
334 // Int32Array for output.
335 for (size_t i = 0; i != jpeg_length; ++i) {
336 jpeg_array_string.push_back(
337 jpeg_array->Get(v8::Integer::New(i))->Int32Value());
338 }
339
340 // Decode and verify resulting image metrics.
341 SkBitmap bitmap;
342 if (!webkit_glue::DecodeImage(jpeg_array_string, &bitmap))
343 return v8::Undefined();
344 if (bitmap.config() != SkBitmap::kARGB_8888_Config)
345 return v8::Undefined();
346 const int width = bitmap.width();
347 const int height = bitmap.height();
348 SkAutoLockPixels lockpixels(bitmap);
349 const uint32_t* pixels = static_cast<uint32_t*>(bitmap.getPixels());
350 if (!pixels)
351 return v8::Undefined();
352
353 // Compose output array. This API call only accepts kARGB_8888_Config images
354 // so we rely on each pixel occupying 4 bytes.
355 // Note(mnaganov): to speed this up, you may use backing store
356 // technique from CreateExternalArray() of v8/src/d8.cc.
357 v8::Local<v8::Array> bitmap_array(v8::Array::New(width * height));
358 for (int i = 0; i != width * height; ++i) {
359 bitmap_array->Set(v8::Integer::New(i),
360 v8::Integer::New(pixels[i] & 0xFFFFFF));
361 }
362 return bitmap_array;
363 }
364
365 // Creates a Blob with the content of the specified file.
366 static v8::Handle<v8::Value> CreateBlob(const v8::Arguments& args) {
367 CHECK(args.Length() == 2);
368 CHECK(args[0]->IsString());
369 CHECK(args[1]->IsInt32());
370 WebKit::WebString path(UTF8ToUTF16(*v8::String::Utf8Value(args[0])));
371 WebKit::WebBlob blob =
372 WebKit::WebBlob::createFromFile(path, args[1]->Int32Value());
373 return blob.toV8Value();
374 }
375
376 // Creates a new messaging channel to the tab with the given ID.
377 static v8::Handle<v8::Value> OpenChannelToTab(const v8::Arguments& args) {
378 // Get the current RenderView so that we can send a routed IPC message from
379 // the correct source.
380 content::RenderView* renderview = GetCurrentRenderView();
381 if (!renderview)
382 return v8::Undefined();
383
384 if (args.Length() >= 3 && args[0]->IsInt32() && args[1]->IsString() &&
385 args[2]->IsString()) {
386 int tab_id = args[0]->Int32Value();
387 std::string extension_id = *v8::String::Utf8Value(args[1]->ToString());
388 std::string channel_name = *v8::String::Utf8Value(args[2]->ToString());
389 int port_id = -1;
390 renderview->Send(new ExtensionHostMsg_OpenChannelToTab(
391 renderview->GetRoutingId(), tab_id, extension_id, channel_name,
392 &port_id));
393 return v8::Integer::New(port_id);
394 }
395 return v8::Undefined();
396 }
397
398 static v8::Handle<v8::Value> GetNextContextMenuId(const v8::Arguments& args) {
399 // Note: this works because contextMenus.create() only works in the
400 // extension process. If that API is opened up to content scripts, this
401 // will need to change. See crbug.com/77023
402 static int next_context_menu_id = 1;
403 return v8::Integer::New(next_context_menu_id++);
404 }
405
406 static v8::Handle<v8::Value> GetNextTtsEventId(const v8::Arguments& args) {
407 // Note: this works because the TTS API only works in the
408 // extension process, not content scripts.
409 static int next_tts_event_id = 1;
410 return v8::Integer::New(next_tts_event_id++);
411 }
412
413 static v8::Handle<v8::Value> GetCurrentPageActions(
414 const v8::Arguments& args) {
415 ExtensionImpl* v8_extension = GetFromArguments<ExtensionImpl>(args);
416 std::string extension_id = *v8::String::Utf8Value(args[0]->ToString());
417 const ::Extension* extension =
418 v8_extension->extension_dispatcher_->extensions()->GetByID(
419 extension_id);
420 CHECK(!extension_id.empty());
421 if (!extension)
422 return v8::Undefined();
423
424 v8::Local<v8::Array> page_action_vector = v8::Array::New();
425 if (extension->page_action()) {
426 std::string id = extension->page_action()->id();
427 page_action_vector->Set(v8::Integer::New(0),
428 v8::String::New(id.c_str(), id.size()));
429 }
430
431 return page_action_vector;
432 }
433
434 // Common code for starting an API request to the browser. |value_args|
435 // contains the request's arguments.
436 // Steals value_args contents for efficiency.
437 static v8::Handle<v8::Value> StartRequestCommon(
438 const v8::Arguments& args, ListValue* value_args) {
439 ExtensionImpl* v8_extension = GetFromArguments<ExtensionImpl>(args);
440
441 const ChromeV8ContextSet& contexts =
442 v8_extension->extension_dispatcher()->v8_context_set();
443 ChromeV8Context* current_context = contexts.GetCurrent();
444 if (!current_context)
445 return v8::Undefined();
446
447 // Get the current RenderView so that we can send a routed IPC message from
448 // the correct source.
449 content::RenderView* renderview = current_context->GetRenderView();
450 if (!renderview)
451 return v8::Undefined();
452
453 std::string name = *v8::String::AsciiValue(args[0]);
454 const std::set<std::string>& function_names =
455 v8_extension->extension_dispatcher_->function_names();
456 if (function_names.find(name) == function_names.end()) {
457 NOTREACHED() << "Unexpected function " << name;
458 return v8::Undefined();
459 }
460
461 // TODO(aa): add this to ChromeV8Context.
462 if (!v8_extension->CheckPermissionForCurrentRenderView(name))
463 return v8::Undefined();
464
465 GURL source_url;
466 WebFrame* webframe = current_context->web_frame();
467 if (webframe)
468 source_url = webframe->document().url();
469
470 int request_id = args[2]->Int32Value();
471 bool has_callback = args[3]->BooleanValue();
472 bool for_io_thread = args[4]->BooleanValue();
473
474 v8::Persistent<v8::Context> v8_context =
475 v8::Persistent<v8::Context>::New(v8::Context::GetCurrent());
476 DCHECK(!v8_context.IsEmpty());
477 g_pending_requests.Get()[request_id].reset(new PendingRequest(
478 v8_context, name, current_context->extension_id()));
479
480 ExtensionHostMsg_Request_Params params;
481 params.name = name;
482 params.arguments.Swap(value_args);
483 params.source_url = source_url;
484 params.request_id = request_id;
485 params.has_callback = has_callback;
486 params.user_gesture =
487 webframe ? webframe->isProcessingUserGesture() : false;
488 if (for_io_thread) {
489 renderview->Send(new ExtensionHostMsg_RequestForIOThread(
490 renderview->GetRoutingId(), params));
491 } else {
492 renderview->Send(new ExtensionHostMsg_Request(
493 renderview->GetRoutingId(), params));
494 }
495
496 return v8::Undefined();
497 }
498
499 // Starts an API request to the browser, with an optional callback. The
500 // callback will be dispatched to EventBindings::HandleResponse.
501 static v8::Handle<v8::Value> StartRequest(const v8::Arguments& args) {
502 std::string str_args = *v8::String::Utf8Value(args[1]);
503 base::JSONReader reader;
504 scoped_ptr<Value> value_args;
505 value_args.reset(reader.JsonToValue(str_args, false, false));
506
507 // Since we do the serialization in the v8 extension, we should always get
508 // valid JSON.
509 if (!value_args.get() || !value_args->IsType(Value::TYPE_LIST)) {
510 NOTREACHED() << "Invalid JSON passed to StartRequest.";
511 return v8::Undefined();
512 }
513
514 return StartRequestCommon(args, static_cast<ListValue*>(value_args.get()));
515 }
516
517 static bool ConvertImageDataToBitmapValue(
518 const v8::Arguments& args, Value** bitmap_value) {
519 v8::Local<v8::Object> extension_args = args[1]->ToObject();
520 v8::Local<v8::Object> details =
521 extension_args->Get(v8::String::New("0"))->ToObject();
522 v8::Local<v8::Object> image_data =
523 details->Get(v8::String::New("imageData"))->ToObject();
524 v8::Local<v8::Object> data =
525 image_data->Get(v8::String::New("data"))->ToObject();
526 int width = image_data->Get(v8::String::New("width"))->Int32Value();
527 int height = image_data->Get(v8::String::New("height"))->Int32Value();
528
529 int data_length = data->Get(v8::String::New("length"))->Int32Value();
530 if (data_length != 4 * width * height) {
531 NOTREACHED() << "Invalid argument to setIcon. Expecting ImageData.";
532 return false;
533 }
534
535 SkBitmap bitmap;
536 bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
537 bitmap.allocPixels();
538 bitmap.eraseARGB(0, 0, 0, 0);
539
540 uint32_t* pixels = bitmap.getAddr32(0, 0);
541 for (int t = 0; t < width*height; t++) {
542 // |data| is RGBA, pixels is ARGB.
543 pixels[t] = SkPreMultiplyColor(
544 ((data->Get(v8::Integer::New(4*t + 3))->Int32Value() & 0xFF) << 24) |
545 ((data->Get(v8::Integer::New(4*t + 0))->Int32Value() & 0xFF) << 16) |
546 ((data->Get(v8::Integer::New(4*t + 1))->Int32Value() & 0xFF) << 8) |
547 ((data->Get(v8::Integer::New(4*t + 2))->Int32Value() & 0xFF) << 0));
548 }
549
550 // Construct the Value object.
551 IPC::Message bitmap_pickle;
552 IPC::WriteParam(&bitmap_pickle, bitmap);
553 *bitmap_value = base::BinaryValue::CreateWithCopiedBuffer(
554 static_cast<const char*>(bitmap_pickle.data()), bitmap_pickle.size());
555
556 return true;
557 }
558
559 // A special request for setting the extension action icon and the sidebar
560 // mini tab icon. This function accepts a canvas ImageData object, so it needs
561 // to do extra processing before sending the request to the browser.
562 static v8::Handle<v8::Value> SetIconCommon(
563 const v8::Arguments& args) {
564 Value* bitmap_value = NULL;
565 if (!ConvertImageDataToBitmapValue(args, &bitmap_value))
566 return v8::Undefined();
567
568 v8::Local<v8::Object> extension_args = args[1]->ToObject();
569 v8::Local<v8::Object> details =
570 extension_args->Get(v8::String::New("0"))->ToObject();
571
572 DictionaryValue* dict = new DictionaryValue();
573 dict->Set("imageData", bitmap_value);
574
575 if (details->Has(v8::String::New("tabId"))) {
576 dict->SetInteger("tabId",
577 details->Get(v8::String::New("tabId"))->Int32Value());
578 }
579
580 ListValue list_value;
581 list_value.Append(dict);
582
583 return StartRequestCommon(args, &list_value);
584 }
585
586 static v8::Handle<v8::Value> GetRenderViewId(const v8::Arguments& args) {
587 content::RenderView* renderview = GetCurrentRenderView();
588 if (!renderview)
589 return v8::Undefined();
590 return v8::Integer::New(renderview->GetRoutingId());
591 }
592 };
593
594 } // namespace
595
596 v8::Extension* ExtensionProcessBindings::Get(
597 ExtensionDispatcher* extension_dispatcher) {
598 static v8::Extension* extension = new ExtensionImpl(extension_dispatcher);
599 CHECK_EQ(extension_dispatcher,
600 static_cast<ExtensionImpl*>(extension)->extension_dispatcher());
601 return extension;
602 }
603
604 // static
605 void ExtensionProcessBindings::HandleResponse(
606 const ChromeV8ContextSet& contexts,
607 int request_id,
608 bool success,
609 const std::string& response,
610 const std::string& error,
611 std::string* extension_id) {
612 PendingRequestMap::iterator request =
613 g_pending_requests.Get().find(request_id);
614 if (request == g_pending_requests.Get().end()) {
615 // This should not be able to happen since we only remove requests when they
616 // are handled.
617 LOG(ERROR) << "Could not find specified request id: " << request_id;
618 return;
619 }
620
621 ChromeV8Context* v8_context =
622 contexts.GetByV8Context(request->second->context);
623 if (!v8_context)
624 return; // The frame went away.
625
626 v8::HandleScope handle_scope;
627 v8::Handle<v8::Value> argv[5];
628 argv[0] = v8::Integer::New(request_id);
629 argv[1] = v8::String::New(request->second->name.c_str());
630 argv[2] = v8::Boolean::New(success);
631 argv[3] = v8::String::New(response.c_str());
632 argv[4] = v8::String::New(error.c_str());
633
634 v8::Handle<v8::Value> retval;
635 CHECK(v8_context->CallChromeHiddenMethod("handleResponse",
636 arraysize(argv),
637 argv,
638 &retval));
639 // In debug, the js will validate the callback parameters and return a
640 // string if a validation error has occured.
641 #ifndef NDEBUG
642 if (!retval.IsEmpty() && !retval->IsUndefined()) {
643 std::string error = *v8::String::AsciiValue(retval);
644 DCHECK(false) << error;
645 }
646 #endif
647
648 // Save the extension id before erasing the request.
649 *extension_id = request->second->extension_id;
650
651 request->second->context.Dispose();
652 request->second->context.Clear();
653 g_pending_requests.Get().erase(request);
654 }
655
656 // static
657 bool ExtensionProcessBindings::HasPendingRequests(
658 const std::string& extension_id) {
659 for (PendingRequestMap::const_iterator it = g_pending_requests.Get().begin();
660 it != g_pending_requests.Get().end(); ++it) {
661 if (it->second->extension_id == extension_id)
662 return true;
663 }
664 return false;
665 }
OLDNEW
« no previous file with comments | « chrome/renderer/extensions/extension_process_bindings.h ('k') | chrome/renderer/extensions/miscellaneous_bindings.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698