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

Side by Side Diff: chrome/browser/extensions/extension_offscreen_tabs_module.cc

Issue 7720002: Chrome Extensions chrome.experimental.offscreenTabs.* API implementation, docs, and test. (Closed) Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: '' Created 9 years, 3 months 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
Property Changes:
Added: svn:eol-style
+ LF
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/browser/extensions/extension_offscreen_tabs_module.h"
6
7 #include <algorithm>
8 #include <hash_map>
9 #include <vector>
10
11 #include "base/base64.h"
12 #include "base/json/json_writer.h"
13 #include "base/memory/ref_counted_memory.h"
14 #include "base/stl_util.h"
15 #include "base/string_number_conversions.h"
16 #include "base/string_util.h"
17 #include "base/values.h"
18 #include "chrome/browser/extensions/extension_event_router.h"
19 #include "chrome/browser/extensions/extension_function_dispatcher.h"
20 #include "chrome/browser/extensions/extension_host.h"
21 #include "chrome/browser/extensions/extension_message_service.h"
22 #include "chrome/browser/extensions/extension_offscreen_tabs_module_constants.h"
23 #include "chrome/browser/extensions/extension_service.h"
24 #include "chrome/browser/extensions/extension_tabs_module.h"
25 #include "chrome/browser/net/url_fixer_upper.h"
26 #include "chrome/browser/profiles/profile.h"
27 #include "chrome/browser/ui/browser.h"
28 #include "chrome/browser/ui/browser_navigator.h"
29 #include "chrome/browser/ui/browser_window.h"
30 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
31 #include "chrome/browser/ui/window_sizer.h"
32 #include "chrome/common/chrome_notification_types.h"
33 #include "chrome/common/extensions/extension.h"
34 #include "chrome/common/extensions/extension_error_utils.h"
35 #include "chrome/common/extensions/extension_messages.h"
36 #include "chrome/common/pref_names.h"
37 #include "chrome/common/url_constants.h"
38 #include "content/browser/renderer_host/backing_store.h"
39 #include "content/browser/renderer_host/render_view_host.h"
40 #include "content/browser/renderer_host/render_view_host_delegate.h"
41 #include "content/browser/tab_contents/navigation_entry.h"
42 #include "content/browser/tab_contents/tab_contents.h"
43 #include "content/browser/tab_contents/tab_contents_view.h"
44 #include "content/common/content_client.h"
45 #include "content/common/notification_service.h"
46 #include "skia/ext/image_operations.h"
47 #include "skia/ext/platform_canvas.h"
48 #include "third_party/skia/include/core/SkBitmap.h"
49 #include "ui/gfx/codec/jpeg_codec.h"
50 #include "ui/gfx/codec/png_codec.h"
51
52 using WebKit::WebInputEvent;
53
54 namespace keys = extension_offscreen_tabs_module_constants;
55
56 namespace {
57
58 // Offscreen Tab ---------------------------------------------------------------
59
60 // This class is responsible for the creation and destruction of offscreen tabs,
61 // as well as dispatching an onUpdated event.
62 class OffscreenTab : public NotificationObserver {
63 public:
64 OffscreenTab();
65 ~OffscreenTab();
sky 2011/09/14 23:34:44 virtual
alexbost 2011/09/15 03:29:49 Done.
66 void Init(const GURL& url,
67 const int width,
68 const int height,
69 const Extension* extension,
70 Profile* profile,
71 ExtensionFunctionDispatcher* dispatcher);
72
73 inline TabContents* contents();
sky 2011/09/14 23:34:44 Sorry, I didn't mean use the inline keyword, inste
alexbost 2011/09/15 03:29:49 I would like to have a method in this class to ret
sky 2011/09/15 20:05:57 The names only need match if you're returning a fi
alexbost 2011/09/15 20:57:57 Done.
74 DictionaryValue* CreateValue(); // Creates an appropriate offscreen tab
sky 2011/09/14 23:34:44 Document caller owns return value.
alexbost 2011/09/15 03:29:49 Done.
75 // object returned by the API.
76
77 void SetUrl(const GURL& url);
78 void SetSize(int width, int height);
79
80 private:
81 virtual void Observe(const int type,
82 const NotificationSource& source,
83 const NotificationDetails& details) OVERRIDE;
84
85 NotificationRegistrar registrar_;
86
87 scoped_ptr<TabContentsWrapper> tab_; // TabContentsWrapper associated with
88 // this offscreen tab.
89
90 DISALLOW_COPY_AND_ASSIGN(OffscreenTab);
91 };
92
93 typedef std::vector<OffscreenTab*> TabVector;
94 typedef TabVector::iterator TabIterator;
95
96 // Tab -------------------------------------------------------------------------
97
98 // This class holds info about a tab that has spawned at least one offscreen tab
sky 2011/09/14 23:34:44 'tab' -> 'tab.'
alexbost 2011/09/15 03:29:49 Done.
99 // We will call such tab the 'parent' of the offscreen tabs it has spawned.
100 // Each Tab keeps track of its child offscreen tabs. The Tab is also responsible
101 // for killing its children when it navigates away or gets closed.
102 class Tab : public NotificationObserver {
103 public:
104 Tab();
105 ~Tab();
sky 2011/09/14 23:34:44 virtual
alexbost 2011/09/15 03:29:49 Done.
106 void Init(TabContents* tab_contents, const std::string& extension_id);
107
108 inline TabContents* contents();
109 inline TabVector* offscreen_tabs();
sky 2011/09/14 23:34:44 const TabVector&
alexbost 2011/09/15 03:29:49 Done.
110 const std::string& GetExtensionId() const;
111
112 void AddOffscreenTab(OffscreenTab *tab);
sky 2011/09/14 23:34:44 Document ownership for these two.
alexbost 2011/09/15 03:29:49 Done.
113 void RemoveOffscreenTab(OffscreenTab *tab);
114
115 private:
116 virtual void Observe(const int type,
117 const NotificationSource& source,
118 const NotificationDetails& details) OVERRIDE;
119
120 NotificationRegistrar registrar_;
121
122 TabContentsWrapper* tab_; // TabContentsWrapper associated with this tab.
sky 2011/09/14 23:34:44 Your description says 'We will call such tab the '
alexbost 2011/09/15 03:29:49 Done.
123 TabVector offscreen_tabs_; // Offscreen tabs spawned by this tab.
124 std::string extension_id_; // Id of the extension running in this tab.
125
126 DISALLOW_COPY_AND_ASSIGN(Tab);
127 };
128
129 // Map -------------------------------------------------------------------------
130
131 // This map keeps track of all tabs that are happy parents of offscreen tabs.
132 class Map {
133 public:
134 Map();
135 ~Map();
136
137 // Gets an offscreen tab by ID.
138 bool GetOffscreenTab(const int tab_id,
139 ExtensionFunctionDispatcher* dispatcher,
140 Profile* profile,
141 OffscreenTab** offscreen_tab,
142 std::string* error_message);
143 // Gets a parent tab by ID.
144 bool GetTab(const int tab_id,
145 Tab** tab,
146 std::string* error_message);
147 // Gets the parent tab of an offscreen tab.
148 bool GetTabOfOffscreenTab(TabContents* offscreen_tab_contents,
149 Tab** tab,
150 std::string* error_message);
151 // Creates a mapping between a parent tab and an offscreen tab.
152 bool AddOffscreenTab(OffscreenTab* offscreen_tab,
153 ExtensionFunctionDispatcher* dispatcher,
154 Profile* profile,
155 const std::string& ext_id,
156 std::string* error_message);
157 // Removes the mapping between a parent tab and an offscreen tab.
158 bool RemoveOffscreenTab(const int tab_id,
159 ExtensionFunctionDispatcher* dispatcher,
160 Profile* profile,
161 std::string* error_message);
162 // Removes a parent tab from the map along with its child offscreen tabs.
163 bool RemoveTab(const int tab_id, std::string* error_message);
164
165 private:
166 typedef base::hash_map<int, Tab*> TabMap;
167 TabMap map;
168
169 DISALLOW_COPY_AND_ASSIGN(Map);
170 };
171
172 // Variables -------------------------------------------------------------------
173
174 Map* map = NULL;
175
176 // We are assuming that offscreen tabs will not be created by background pages
177 // with the exception of the API test background page. We keep track of the
178 // offscreen tabs associated with the test API background page via this variable
179 // These tab contents are created just for convenience and do not do anything.
180 // TODO(alexbost): Think about handling multiple background pages each spawning
181 // offscreen tabs. Would background pages want to spawn offscreen tabs?
182 TabContents* background_page_tab_contents = NULL;
183
184 // Util ------------------------------------------------------------------------
185
186 // Gets the map of parent tabs to offscreen tabs.
187 Map* GetMap() {
188 if (map == NULL)
189 map = new Map();
190
191 return map;
192 }
193
194 // Gets the TabContents associated with the test API background page.
195 TabContents* GetBackgroundPageTabContents(Profile* profile) {
196 if (profile && background_page_tab_contents == NULL) {
197 background_page_tab_contents =
198 new TabContents(profile, NULL, MSG_ROUTING_NONE, NULL, NULL);
199 new TabContentsWrapper(background_page_tab_contents);
200 }
201
202 return background_page_tab_contents;
203 }
204
205 // Gets the contents of the tab that instantiated the extension API call.
206 // In the case of background pages we use tab contents created by us.
207 bool GetCurrentTab(ExtensionFunctionDispatcher* dispatcher,
208 Profile* profile,
209 TabContents** tab_contents,
210 std::string* error_message) {
211 *tab_contents = dispatcher->delegate()->GetAssociatedTabContents();
212
213 // Background page (no associated tab contents).
214 if (!*tab_contents)
215 *tab_contents = GetBackgroundPageTabContents(profile);
216
217 if (*tab_contents)
218 return true;
219
220 *error_message = keys::kCurrentTabNotFound;
221 return false;
222 }
223
224 // TODO(alexbost): Needs refactoring. Similar method in extension_tabs_module.
225 // Takes |url_string| and returns a GURL which is either valid and absolute
226 // or invalid. If |url_string| is not directly interpretable as a valid (it is
227 // likely a relative URL) an attempt is made to resolve it. |extension| is
228 // provided so it can be resolved relative to its extension base
229 // (chrome-extension://<id>/). Using the source frame url would be more correct,
230 // but because the api shipped with urls resolved relative to their extension
231 // base, we decided it wasn't worth breaking existing extensions to fix.
232 GURL ResolvePossiblyRelativeURL(const std::string& url_string,
233 const Extension* extension) {
234 GURL url = GURL(url_string);
235 if (!url.is_valid())
236 url = extension->GetResourceURL(url_string);
237
238 return url;
239 }
240
241 // TODO(alexbost): Needs refactoring. Similar method in extension_tabs_module.
242 bool IsCrashURL(const GURL& url) {
243 // Check a fixed-up URL, to normalize the scheme and parse hosts correctly.
244 GURL fixed_url =
245 URLFixerUpper::FixupURL(url.possibly_invalid_spec(), std::string());
246 return (fixed_url.SchemeIs(chrome::kChromeUIScheme) &&
247 (fixed_url.host() == chrome::kChromeUIBrowserCrashHost ||
248 fixed_url.host() == chrome::kChromeUICrashHost));
249 }
250
251 // Gets the size of a tab.
252 gfx::Size GetTabSize(const TabContentsWrapper* tab) {
253 return tab->view()->GetContainerSize();
sky 2011/09/14 23:34:44 At this point this function isn't saving you much.
alexbost 2011/09/15 03:29:49 Done.
254 }
255
256 // Offscreen Tab ---------------------------------------------------------------
257
258 OffscreenTab::OffscreenTab() {}
259 OffscreenTab::~OffscreenTab() {}
260
261 void OffscreenTab::Init(const GURL& url,
262 const int width,
263 const int height,
264 const Extension* extension,
sky 2011/09/14 23:34:44 It doesn't look like you use extension or dispatch
alexbost 2011/09/15 03:29:49 Done.
265 Profile* profile,
266 ExtensionFunctionDispatcher* dispatcher) {
267 // Create the offscreen tab.
268 TabContents* tab_contents = new TabContents(
269 profile, NULL, MSG_ROUTING_NONE, NULL, NULL);
270 tab_.reset(new TabContentsWrapper(tab_contents));
271
272 SetSize(width, height); // Setting the size starts the renderer.
273 SetUrl(url);
274
275 // Register for tab notifications.
276 registrar_.Add(this,
277 content::NOTIFICATION_NAV_ENTRY_COMMITTED,
278 Source<NavigationController>(&contents()->controller()));
279 }
280
281 inline TabContents* OffscreenTab::contents() {
282 return tab_.get()->tab_contents();
283 }
284
285 DictionaryValue* OffscreenTab::CreateValue() {
286 DictionaryValue* result = new DictionaryValue();
287
288 result->SetInteger(keys::kIdKey, ExtensionTabUtil::GetTabId(contents()));
289 result->SetString(keys::kUrlKey, contents()->GetURL().spec());
290 result->SetInteger(keys::kWidthKey, GetTabSize(
291 TabContentsWrapper::GetCurrentWrapperForContents(contents())).width());
292 result->SetInteger(keys::kHeightKey, GetTabSize(
293 TabContentsWrapper::GetCurrentWrapperForContents(contents())).height());
294
295 return result;
296 }
297
298 void OffscreenTab::SetUrl(const GURL& url) {
299 contents()->controller().LoadURL(
300 url, GURL(), PageTransition::LINK, std::string());
301 }
302
303 void OffscreenTab::SetSize(int width, int height) {
304 contents()->view()->SizeContents(gfx::Size(width, height));
305 }
306
307 void OffscreenTab::Observe(const int type,
308 const NotificationSource& source,
309 const NotificationDetails& details) {
310 DCHECK_EQ(content::NOTIFICATION_NAV_ENTRY_COMMITTED, type);
311
312 DictionaryValue* changed_properties = new DictionaryValue();
313 changed_properties->SetString(keys::kUrlKey, contents()->GetURL().spec());
314
315 ListValue args;
316 args.Append(
317 Value::CreateIntegerValue(ExtensionTabUtil::GetTabId(contents())));
318 args.Append(changed_properties);
319 args.Append(CreateValue());
320 std::string json_args;
321 base::JSONWriter::Write(&args, false, &json_args);
322
323 Tab* tab;
324 DCHECK(GetMap()->GetTabOfOffscreenTab(contents(), &tab, new std::string()));
sky 2011/09/14 23:34:44 DCHECKs aren't compiled in release build, which me
alexbost 2011/09/15 03:29:49 Done.
325
326 ListValue event_args;
327 event_args.Set(0, Value::CreateStringValue(keys::kEventOnUpdated));
328 event_args.Set(1, Value::CreateStringValue(json_args));
329
330 // Dispatch an onUpdated event.
331
332 // The primary use case for broadcasting the event is
333 // when the offscreen tab is generated by a test API background page.
334 if (tab->contents() == GetBackgroundPageTabContents(NULL)) {
335 Profile* profile = Profile::FromBrowserContext(
sky 2011/09/14 23:34:44 Get the profile from tab->tab_->profile().
alexbost 2011/09/15 03:29:49 Done.
336 contents()->browser_context());
337 profile->GetExtensionEventRouter()->DispatchEventToRenderers(
338 keys::kEventOnUpdated, json_args, profile, GURL());
339 // Send a routed event directly to the parent tab.
sky 2011/09/14 23:34:44 Move to line 341, and indent.
alexbost 2011/09/15 03:29:49 Done.
340 } else {
341 tab->contents()->render_view_host()->process()->Send(
342 new ExtensionMsg_MessageInvoke(
343 tab->contents()->render_view_host()->routing_id(),
344 tab->GetExtensionId(),
345 keys::kDispatchEvent,
346 event_args,
347 GURL()));
348 }
349 }
350
351 // Tab -------------------------------------------------------------------------
352
353 Tab::Tab() {}
sky 2011/09/14 23:34:44 initialize tab_
alexbost 2011/09/15 03:29:49 Done.
354 Tab::~Tab() {
355 // Kill child offscreen tabs.
356 STLDeleteElements(&offscreen_tabs_);
357
358 DCHECK(GetMap()->RemoveTab(
sky 2011/09/14 23:34:44 assign to a boolean, then DCHECK(removed).
alexbost 2011/09/15 03:29:49 Done.
359 ExtensionTabUtil::GetTabId(contents()), new std::string()));
360 }
361
362 void Tab::Init(TabContents* tab_contents, const std::string& extension_id) {
363 tab_ = TabContentsWrapper::GetCurrentWrapperForContents(tab_contents);
sky 2011/09/14 23:34:44 How do you know there is TabContentsWrapper associ
alexbost 2011/09/15 03:29:49 I create an artificial TabContentsWrapper in GetBa
sky 2011/09/15 20:05:57 By background page I meant one of these: http://co
alexbost 2011/09/15 20:57:57 I think we are talking about the same background p
sky 2011/09/15 21:41:36 If you're saying that all background pages are rou
alexbost 2011/09/15 23:01:29 If a background page ends up calling this method,
364 extension_id_ = extension_id;
365
366 // Register for tab notifications.
367 registrar_.Add(this,
368 content::NOTIFICATION_NAV_ENTRY_COMMITTED,
369 Source<NavigationController>(&contents()->controller()));
370
371 registrar_.Add(this,
372 content::NOTIFICATION_TAB_CONTENTS_DESTROYED,
373 Source<TabContents>(contents()));
374 }
375
376 inline TabContents* Tab::contents() {
377 return tab_->tab_contents();
378 }
379
380 inline TabVector* Tab::offscreen_tabs() {
381 return &offscreen_tabs_;
382 }
383
384 const std::string& Tab::GetExtensionId() const {
385 return extension_id_;
386 }
387
388 void Tab::AddOffscreenTab(OffscreenTab *tab) {
389 offscreen_tabs_.push_back(tab);
390 }
391
392 void Tab::RemoveOffscreenTab(OffscreenTab *tab) {
393 TabIterator it_tab = std::find(
394 offscreen_tabs_.begin(), offscreen_tabs_.end(), tab);
395 offscreen_tabs_.erase(it_tab);
396 }
397
398 void Tab::Observe(const int type,
399 const NotificationSource& source,
400 const NotificationDetails& details) {
401 DCHECK(type == content::NOTIFICATION_NAV_ENTRY_COMMITTED ||
402 type == content::NOTIFICATION_TAB_CONTENTS_DESTROYED);
403
404 delete this;
405 }
406
407 // Map -------------------------------------------------------------------------
408
409 Map::Map() {}
410 Map::~Map() {}
411
412 bool Map::GetOffscreenTab(const int tab_id,
413 ExtensionFunctionDispatcher* dispatcher,
414 Profile* profile,
415 OffscreenTab** offscreen_tab,
416 std::string* error_message) {
417 // Ensure that the current tab is the parent of the offscreen tab.
418 TabContents* tab_contents = NULL;
419 if (!GetCurrentTab(dispatcher, profile, &tab_contents, error_message))
420 return false;
421
422 Tab* tab = NULL;
423 if (!GetTab(ExtensionTabUtil::GetTabId(tab_contents), &tab, error_message))
424 return false;
425 TabVector* offscreen_tabs = tab->offscreen_tabs();
426
427 for (TabIterator it = offscreen_tabs->begin();
428 it != offscreen_tabs->end(); ++it)
sky 2011/09/14 23:34:44 add {} here
alexbost 2011/09/15 03:29:49 Done.
429 if (ExtensionTabUtil::GetTabId((*it)->contents()) == tab_id) {
430 *offscreen_tab = *it;
431 return true;
432 }
433
434 *error_message = ExtensionErrorUtils::FormatErrorMessage(
435 keys::kOffscreenTabNotFoundError, base::IntToString(tab_id));
436 return false;
437 }
438
439 bool Map::GetTab(const int tab_id, Tab** tab, std::string* error_message) {
440 TabMap::iterator it = map.find(tab_id);
441
442 if (it == map.end()) {
443 *error_message = ExtensionErrorUtils::FormatErrorMessage(
444 keys::kTabNotFoundError, base::IntToString(tab_id));
445 return false;
446 }
447
448 *tab = it->second;
449
450 return true;
451 }
452
453 bool Map::GetTabOfOffscreenTab(TabContents* offscreen_tab_contents,
454 Tab** tab,
455 std::string* error_message) {
456 int offscreen_tab_id = ExtensionTabUtil::GetTabId(offscreen_tab_contents);
457
458 for (TabMap::iterator it = map.begin(); it != map.end(); ++it) {
459 TabVector* offscreen_tabs = it->second->offscreen_tabs();
460 for (TabIterator it_tab = offscreen_tabs->begin();
461 it_tab != offscreen_tabs->end(); ++it_tab) {
462 if ((*it_tab)->contents() == offscreen_tab_contents) {
463 if (!GetTab(it->first, tab, error_message))
464 return false;
465
466 return true;
467 }
468 }
469 }
470
471 *error_message = ExtensionErrorUtils::FormatErrorMessage(
472 keys::kTabOfOffscreenTabNotFoundError,
473 base::IntToString(offscreen_tab_id));
474 return false;
475 }
476
477 bool Map::AddOffscreenTab(OffscreenTab* offscreen_tab,
478 ExtensionFunctionDispatcher* dispatcher,
479 Profile* profile,
480 const std::string& ext_id,
481 std::string* error_message) {
482 // Get parent tab.
483 TabContents* tab_contents = NULL;
484 if (!GetCurrentTab(dispatcher, profile, &tab_contents, error_message))
485 return false;
486 int tab_id = ExtensionTabUtil::GetTabId(tab_contents);
487
488 Tab* tab = NULL;
489 if (!GetTab(tab_id, &tab, error_message)) {
490 tab = map[tab_id] = new Tab();
491 tab->Init(tab_contents, ext_id);
492 }
493
494 tab->AddOffscreenTab(offscreen_tab);
495
496 return true;
497 }
498
499 bool Map::RemoveOffscreenTab(const int tab_id,
500 ExtensionFunctionDispatcher* dispatcher,
501 Profile* profile,
502 std::string* error_message) {
503 OffscreenTab* offscreen_tab = NULL;
504 if (!GetOffscreenTab(tab_id, dispatcher, profile,
505 &offscreen_tab, error_message))
506 return false;
507
508 Tab* tab = NULL;
509 if (!GetTabOfOffscreenTab(offscreen_tab->contents(), &tab, error_message))
510 return false;
511
512 tab->RemoveOffscreenTab(offscreen_tab);
513
514 // If this was the last offscreen tab for the parent tab, remove the parent.
515 if (tab->offscreen_tabs()->empty())
516 map.erase(ExtensionTabUtil::GetTabId(tab->contents()));
517
518 return true;
519 }
520
521 bool Map::RemoveTab(const int tab_id, std::string* error_message) {
522 if (map[tab_id] == NULL) {
sky 2011/09/14 23:34:44 Use find to avoid insertion.
alexbost 2011/09/15 03:29:49 Done.
523 *error_message = ExtensionErrorUtils::FormatErrorMessage(
524 keys::kTabNotFoundError, base::IntToString(tab_id));
525 return false;
526 }
527
528 map.erase(tab_id);
529
530 return true;
531 }
532
533 } // namespace
534
535 // API functions ---------------------------------------------------------------
536
537 // create ----------------------------------------------------------------------
538
539 CreateOffscreenTabFunction::CreateOffscreenTabFunction() {}
540 CreateOffscreenTabFunction::~CreateOffscreenTabFunction() {}
541
542 bool CreateOffscreenTabFunction::RunImpl() {
543 DictionaryValue* create_props;
544 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &create_props));
545
546 std::string url_string;
547 GURL url;
548 EXTENSION_FUNCTION_VALIDATE(
549 create_props->GetString(keys::kUrlKey, &url_string));
550 url = ResolvePossiblyRelativeURL(url_string, GetExtension());
551 if (!url.is_valid()) {
552 error_ = ExtensionErrorUtils::FormatErrorMessage(
553 keys::kInvalidUrlError, url_string);
554 return false;
555 }
556 if (IsCrashURL(url)) {
557 error_ = keys::kNoCrashBrowserError;
558 return false;
559 }
560
561 gfx::Rect window_bounds;
562 bool maximized;
563 if (!create_props->HasKey(keys::kWidthKey) ||
564 !create_props->HasKey(keys::kHeightKey)) {
565 Browser* browser = GetCurrentBrowser();
sky 2011/09/14 23:34:44 How do you know current browser is the one you wan
alexbost 2011/09/15 03:29:49 What would you use instead? Notice, we only use th
sky 2011/09/15 20:05:57 Maybe the size of the tab?
alexbost 2011/09/15 20:57:57 Good catch.
566 if (!browser) {
567 error_ = keys::kNoCurrentWindowError;
568 return false;
569 }
570
571 WindowSizer::GetBrowserWindowBounds(std::string(), gfx::Rect(),
572 browser, &window_bounds,
573 &maximized);
574 }
575
576 int width = window_bounds.width();
577 if (create_props->HasKey(keys::kWidthKey))
578 EXTENSION_FUNCTION_VALIDATE(
579 create_props->GetInteger(keys::kWidthKey, &width));
580
581 int height = window_bounds.height();
582 if (create_props->HasKey(keys::kHeightKey))
583 EXTENSION_FUNCTION_VALIDATE(
584 create_props->GetInteger(keys::kHeightKey, &height));
585
586 OffscreenTab* tab = new OffscreenTab();
587 tab->Init(url, width, height, GetExtension(), profile_, dispatcher());
588
589 // Add the offscreen tab to the map so we don't lose track of it.
590 if (!GetMap()->AddOffscreenTab(tab, dispatcher(), profile_,
591 extension_id(), &error_)) {
592 delete tab; // Prevent leaking of offscreen tab.
593 return false;
594 }
595
596 if (has_callback()) {
597 result_.reset(tab->CreateValue());
598 SendResponse(true);
599 }
600
601 return true;
602 }
603
604 // get -------------------------------------------------------------------------
605
606 GetOffscreenTabFunction::GetOffscreenTabFunction() {}
607 GetOffscreenTabFunction::~GetOffscreenTabFunction() {}
608
609 bool GetOffscreenTabFunction::RunImpl() {
610 int tab_id;
611 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &tab_id));
612
613 OffscreenTab* tab = NULL;
614 if (!GetMap()->
615 GetOffscreenTab(tab_id, dispatcher(), profile_, &tab, &error_)) {
616 error_ = ExtensionErrorUtils::FormatErrorMessage(
617 keys::kOffscreenTabNotFoundError, base::IntToString(tab_id));
sky 2011/09/14 23:34:44 indent 2 more.
alexbost 2011/09/15 03:29:49 Done.
618 return false;
619 }
620
621 result_.reset(tab->CreateValue());
622 SendResponse(true);
623
624 return true;
625 }
626
627 // getAll ----------------------------------------------------------------------
628
629 GetAllOffscreenTabFunction::GetAllOffscreenTabFunction() {}
630 GetAllOffscreenTabFunction::~GetAllOffscreenTabFunction() {}
631
632 bool GetAllOffscreenTabFunction::RunImpl() {
633 TabContents* tab_contents = NULL;
634 if (!GetCurrentTab(dispatcher(), profile_, &tab_contents, &error_))
635 return false;
636
637 Tab* tab = NULL;
638 if (!GetMap()->
639 GetTab(ExtensionTabUtil::GetTabId(tab_contents), &tab, &error_))
640 return false;
641
642 TabVector* offscreen_tabs = tab->offscreen_tabs();
643
644 ListValue* tab_list = new ListValue();
645 for (TabIterator it_tab = offscreen_tabs->begin();
646 it_tab != offscreen_tabs->end(); ++it_tab)
647 tab_list->Append((*it_tab)->CreateValue());
648
649 result_.reset(tab_list);
650 SendResponse(true);
651
652 return true;
653 }
654
655 // remove ----------------------------------------------------------------------
656
657 RemoveOffscreenTabFunction::RemoveOffscreenTabFunction() {}
658 RemoveOffscreenTabFunction::~RemoveOffscreenTabFunction() {}
659
660 bool RemoveOffscreenTabFunction::RunImpl() {
661 int tab_id;
662 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &tab_id));
663
664 OffscreenTab* tab = NULL;
665 if (!GetMap()->GetOffscreenTab(tab_id, dispatcher(), profile_, &tab, &error_))
666 return false;
667
668 if (!GetMap()->RemoveOffscreenTab(tab_id, dispatcher(), profile_, &error_))
669 return false;
670
671 delete tab;
672
673 return true;
674 }
675
676 // sendKeyboardEvent -----------------------------------------------------------
677
678 SendKeyboardEventOffscreenTabFunction::
679 SendKeyboardEventOffscreenTabFunction() {}
680 SendKeyboardEventOffscreenTabFunction::
681 ~SendKeyboardEventOffscreenTabFunction() {}
682
683 bool SendKeyboardEventOffscreenTabFunction::RunImpl() {
684 int tab_id;
685 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &tab_id));
686
687 OffscreenTab* tab = NULL;
688 if (!GetMap()->GetOffscreenTab(tab_id, dispatcher(), profile_, &tab, &error_))
689 return false;
690
691 // JavaScript KeyboardEvent.
692 DictionaryValue* dict = NULL;
693 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &dict));
694
695 NativeWebKeyboardEvent keyboard_event;
696
697 std::string type;
698 if (dict->HasKey(keys::kKeyboardEventTypeKey)) {
699 EXTENSION_FUNCTION_VALIDATE(
700 dict->GetString(keys::kKeyboardEventTypeKey, &type));
701 } else {
702 error_ = keys::kInvalidKeyboardEventObjectError;
703 return false;
704 }
705
706 if (type.compare(keys::kKeyboardEventTypeValueKeypress) == 0) {
707 keyboard_event.type = WebInputEvent::Char;
708 } else if (type.compare(keys::kKeyboardEventTypeValueKeydown) == 0) {
709 keyboard_event.type = WebInputEvent::KeyDown;
710 } else if (type.compare(keys::kKeyboardEventTypeValueKeyup) == 0) {
711 keyboard_event.type = WebInputEvent::KeyUp;
712 } else {
713 error_ = keys::kInvalidKeyboardEventObjectError;
714 return false;
715 }
716
717 int key_code;
718 if (dict->HasKey(keys::kKeyboardEventKeyCodeKey)) {
719 EXTENSION_FUNCTION_VALIDATE(
720 dict->GetInteger(keys::kKeyboardEventKeyCodeKey, &key_code));
721 } else {
722 error_ = keys::kInvalidKeyboardEventObjectError;
723 return false;
724 }
725
726 keyboard_event.nativeKeyCode = key_code;
727 keyboard_event.windowsKeyCode = key_code;
728 keyboard_event.setKeyIdentifierFromWindowsKeyCode();
729
730 // Keypress = type character
731 if (type.compare(keys::kKeyboardEventTypeValueKeypress) == 0) {
732 int char_code;
733 if (dict->HasKey(keys::kKeyboardEventCharCodeKey)) {
734 EXTENSION_FUNCTION_VALIDATE(
735 dict->GetInteger(keys::kKeyboardEventCharCodeKey, &char_code));
736 keyboard_event.text[0] = char_code;
737 keyboard_event.unmodifiedText[0] = char_code;
738 } else {
739 error_ = keys::kInvalidKeyboardEventObjectError;
740 return false;
741 }
742 }
743
744 bool alt_key;
745 if (dict->HasKey(keys::kKeyboardEventAltKeyKey))
746 EXTENSION_FUNCTION_VALIDATE(
747 dict->GetBoolean(keys::kKeyboardEventAltKeyKey, &alt_key));
748 if (alt_key)
749 keyboard_event.modifiers |= WebInputEvent::AltKey;
750
751 bool ctrl_key;
752 if (dict->HasKey(keys::kKeyboardEventCtrlKeyKey))
753 EXTENSION_FUNCTION_VALIDATE(
754 dict->GetBoolean(keys::kKeyboardEventCtrlKeyKey, &ctrl_key));
755 if (ctrl_key)
756 keyboard_event.modifiers |= WebInputEvent::ControlKey;
757
758 bool meta_key = false;
759 if (dict->HasKey(keys::kMouseEventMetaKeyKey))
760 EXTENSION_FUNCTION_VALIDATE(
761 dict->GetBoolean(keys::kMouseEventMetaKeyKey, &meta_key));
762 if (meta_key)
763 keyboard_event.modifiers |= WebInputEvent::MetaKey;
764
765 bool shift_key;
766 if (dict->HasKey(keys::kKeyboardEventShiftKeyKey))
767 EXTENSION_FUNCTION_VALIDATE(
768 dict->GetBoolean(keys::kKeyboardEventShiftKeyKey, &shift_key));
769 if (shift_key)
770 keyboard_event.modifiers |= WebInputEvent::ShiftKey;
771
772 // Forward the event.
773 tab->contents()->render_view_host()->
774 ForwardKeyboardEvent(keyboard_event);
775
776 if (has_callback()) {
777 result_.reset(tab->CreateValue());
778 SendResponse(true);
779 }
780
781 return true;
782 }
783
784 // sendMouseEvent --------------------------------------------------------------
785
786 SendMouseEventOffscreenTabFunction::SendMouseEventOffscreenTabFunction() {}
787 SendMouseEventOffscreenTabFunction::~SendMouseEventOffscreenTabFunction() {}
788
789 bool SendMouseEventOffscreenTabFunction::RunImpl() {
790 int tab_id;
791 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &tab_id));
792
793 OffscreenTab* tab = NULL;
794 if (!GetMap()->GetOffscreenTab(tab_id, dispatcher(), profile_, &tab, &error_))
795 return false;
796
797 // JavaScript MouseEvent.
798 DictionaryValue* dict = NULL;
799 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &dict));
800
801 std::string type;
802 if (dict->HasKey(keys::kMouseEventTypeKey)) {
803 EXTENSION_FUNCTION_VALIDATE(
804 dict->GetString(keys::kMouseEventTypeKey, &type));
805 } else {
806 error_ = keys::kInvalidMouseEventObjectError;
807 return false;
808 }
809
810 if (type.compare(keys::kMouseEventTypeValueMousewheel) == 0) {
811 WebKit::WebMouseWheelEvent wheel_event;
812
813 wheel_event.type = WebInputEvent::MouseWheel;
814
815 if (dict->HasKey(keys::kMouseEventWheelDeltaXKey) &&
816 dict->HasKey(keys::kMouseEventWheelDeltaYKey)) {
817 int delta_x, delta_y;
818 EXTENSION_FUNCTION_VALIDATE(
819 dict->GetInteger(keys::kMouseEventWheelDeltaXKey, &delta_x));
820 EXTENSION_FUNCTION_VALIDATE(
821 dict->GetInteger(keys::kMouseEventWheelDeltaYKey, &delta_y));
822 wheel_event.deltaX = delta_x;
823 wheel_event.deltaY = delta_y;
824 } else {
825 error_ = keys::kInvalidMouseEventObjectError;
826 return false;
827 }
828
829 // Forward the event.
830 tab->contents()->render_view_host()->ForwardWheelEvent(wheel_event);
831 } else {
832 WebKit::WebMouseEvent mouse_event;
833
834 if (type.compare(keys::kMouseEventTypeValueMousedown) == 0 ||
835 type.compare(keys::kMouseEventTypeValueClick) == 0) {
836 mouse_event.type = WebKit::WebInputEvent::MouseDown;
837 } else if (type.compare(keys::kMouseEventTypeValueMouseup) == 0) {
838 mouse_event.type = WebKit::WebInputEvent::MouseUp;
839 } else if (type.compare(keys::kMouseEventTypeValueMousemove) == 0) {
840 mouse_event.type = WebKit::WebInputEvent::MouseMove;
841 } else {
842 error_ = keys::kInvalidMouseEventObjectError;
843 return false;
844 }
845
846 int button;
847 if (dict->HasKey(keys::kMouseEventButtonKey)) {
848 EXTENSION_FUNCTION_VALIDATE(
849 dict->GetInteger(keys::kMouseEventButtonKey, &button));
850 } else {
851 error_ = keys::kInvalidMouseEventObjectError;
852 return false;
853 }
854
855 if (button == keys::kMouseEventButtonValueLeft) {
856 mouse_event.button = WebKit::WebMouseEvent::ButtonLeft;
857 } else if (button == keys::kMouseEventButtonValueMiddle) {
858 mouse_event.button = WebKit::WebMouseEvent::ButtonMiddle;
859 } else if (button == keys::kMouseEventButtonValueRight) {
860 mouse_event.button = WebKit::WebMouseEvent::ButtonRight;
861 } else {
862 error_ = keys::kInvalidMouseEventObjectError;
863 return false;
864 }
865
866 if (HasOptionalArgument(2) && HasOptionalArgument(3)) {
867 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(2, &mouse_event.x));
868 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(3, &mouse_event.y));
869 } else {
870 error_ = keys::kNoMouseCoordinatesError;
871 return false;
872 }
873
874 bool alt_key = false;
875 if (dict->HasKey(keys::kMouseEventAltKeyKey))
876 EXTENSION_FUNCTION_VALIDATE(
877 dict->GetBoolean(keys::kMouseEventAltKeyKey, &alt_key));
878 if (alt_key)
879 mouse_event.modifiers |= WebInputEvent::AltKey;
880
881 bool ctrl_key = false;
882 if (dict->HasKey(keys::kMouseEventCtrlKeyKey))
883 EXTENSION_FUNCTION_VALIDATE(
884 dict->GetBoolean(keys::kMouseEventCtrlKeyKey, &ctrl_key));
885 if (ctrl_key)
886 mouse_event.modifiers |= WebInputEvent::ControlKey;
887
888 bool meta_key = false;
889 if (dict->HasKey(keys::kMouseEventMetaKeyKey))
890 EXTENSION_FUNCTION_VALIDATE(
891 dict->GetBoolean(keys::kMouseEventMetaKeyKey, &meta_key));
892 if (meta_key)
893 mouse_event.modifiers |= WebInputEvent::MetaKey;
894
895 bool shift_key = false;
896 if (dict->HasKey(keys::kMouseEventShiftKeyKey))
897 EXTENSION_FUNCTION_VALIDATE(
898 dict->GetBoolean(keys::kMouseEventShiftKeyKey, &shift_key));
899 if (shift_key)
900 mouse_event.modifiers |= WebInputEvent::ShiftKey;
901
902 mouse_event.clickCount = 1;
903
904 // Forward the event.
905 tab->contents()->render_view_host()->ForwardMouseEvent(mouse_event);
906
907 // If the event is a click,
908 // fire a mouseup event in addition to the mousedown.
909 if (type.compare(keys::kMouseEventTypeValueClick) == 0) {
910 mouse_event.type = WebKit::WebInputEvent::MouseUp;
911 tab->contents()->render_view_host()->ForwardMouseEvent(mouse_event);
912 }
913 }
914
915 if (has_callback()) {
916 result_.reset(tab->CreateValue());
917 SendResponse(true);
918 }
919
920 return true;
921 }
922
923 // toDataUrl -------------------------------------------------------------------
924
925 ToDataUrlOffscreenTabFunction::ToDataUrlOffscreenTabFunction() {}
926 ToDataUrlOffscreenTabFunction::~ToDataUrlOffscreenTabFunction() {}
927
928 // TODO(alexbost): Needs refactoring. Similar method in extension_tabs_module.
929 // TODO(alexbost): We want to optimize this function in order to get more image
930 // updates on the browser side. One improvement would be to implement another
931 // hash map in order to get offscreen tabs in O(1).
932 bool ToDataUrlOffscreenTabFunction::RunImpl() {
933 int tab_id;
934 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &tab_id));
935
936
937 OffscreenTab* tab = NULL;
938 if (!GetMap()->GetOffscreenTab(tab_id, dispatcher(), profile_, &tab, &error_))
939 return false;
940
941 image_format_ = FORMAT_JPEG; // Default format is JPEG.
942 image_quality_ = kDefaultQuality; // Default quality setting.
943
944 if (HasOptionalArgument(1)) {
945 DictionaryValue* options;
946 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &options));
947
948 if (options->HasKey(keys::kFormatKey)) {
949 std::string format;
950 EXTENSION_FUNCTION_VALIDATE(
951 options->GetString(keys::kFormatKey, &format));
952
953 if (format == keys::kFormatValueJpeg) {
954 image_format_ = FORMAT_JPEG;
955 } else if (format == keys::kFormatValuePng) {
956 image_format_ = FORMAT_PNG;
957 } else {
958 // Schema validation should make this unreachable.
959 EXTENSION_FUNCTION_VALIDATE(0);
960 }
961 }
962
963 if (options->HasKey(keys::kQualityKey)) {
964 EXTENSION_FUNCTION_VALIDATE(
965 options->GetInteger(keys::kQualityKey, &image_quality_));
966 }
967 }
968
969 // captureVisibleTab() can return an image containing sensitive information
970 // that the browser would otherwise protect. Ensure the extension has
971 // permission to do this.
972 if (!GetExtension()->
973 CanCaptureVisiblePage(tab->contents()->GetURL(), &error_))
974 return false;
975
976 // The backing store approach works on Linux but not on Mac.
977 // TODO(alexbost): Test on Windows
978 #if !defined(OS_MACOSX)
979 RenderViewHost* render_view_host = tab->contents()->render_view_host();
980
981 // If a backing store is cached for the tab we want to capture,
982 // and it can be copied into a bitmap, then use it to generate the image.
983 BackingStore* backing_store = render_view_host->GetBackingStore(false);
984 if (backing_store && CaptureSnapshotFromBackingStore(backing_store))
985 return true;
986 #endif
987
988 // Ask the renderer for a snapshot of the tab.
989 TabContentsWrapper* tab_wrapper =
990 TabContentsWrapper::GetCurrentWrapperForContents(tab->contents());
991 tab_wrapper->CaptureSnapshot();
992 registrar_.Add(this,
993 chrome::NOTIFICATION_TAB_SNAPSHOT_TAKEN,
994 Source<TabContentsWrapper>(tab_wrapper));
995
996 AddRef(); // Balanced in ToDataUrlOffscreenTabFunction::Observe().
997
998 return true;
999 }
1000
1001 // TODO(alexbost): Needs refactoring. Similar method in extension_tabs_module.
1002 // Build the image of a tab's contents out of a backing store.
1003 // This may fail if we can not copy a backing store into a bitmap.
1004 // For example, some uncommon X11 visual modes are not supported by
1005 // CopyFromBackingStore().
1006 bool ToDataUrlOffscreenTabFunction::CaptureSnapshotFromBackingStore(
1007 BackingStore* backing_store) {
1008
1009 skia::PlatformCanvas temp_canvas;
1010 if (!backing_store->CopyFromBackingStore(gfx::Rect(backing_store->size()),
1011 &temp_canvas)) {
1012 return false;
1013 }
1014 VLOG(1) << "captureVisibleTab() got image from backing store.";
1015
1016 SendResultFromBitmap(
1017 skia::GetTopDevice(temp_canvas)->accessBitmap(false));
1018 return true;
1019 }
1020
1021 // TODO(alexbost): Needs refactoring. Similar method in extension_tabs_module.
1022 void ToDataUrlOffscreenTabFunction::Observe(const int type,
1023 const NotificationSource& source,
1024 const NotificationDetails& details) {
1025 DCHECK(type == chrome::NOTIFICATION_TAB_SNAPSHOT_TAKEN);
1026
1027 const SkBitmap *screen_capture = Details<const SkBitmap>(details).ptr();
1028 const bool error = screen_capture->empty();
1029
1030 if (error) {
1031 error_ = keys::kInternalVisibleTabCaptureError;
1032 SendResponse(false);
1033 } else {
1034 VLOG(1) << "Got image from renderer.";
1035 SendResultFromBitmap(*screen_capture);
1036 }
1037
1038 Release(); // Balanced in ToDataUrlOffscreenTabFunction::RunImpl().
1039 }
1040
1041 // TODO(alexbost): Needs refactoring. Similar method in extension_tabs_module.
1042 // Turn a bitmap of the screen into an image, set that image as the result,
1043 // and call SendResponse().
1044 void ToDataUrlOffscreenTabFunction::SendResultFromBitmap(
1045 const SkBitmap& screen_capture) {
1046 std::vector<unsigned char> data;
1047 SkAutoLockPixels screen_capture_lock(screen_capture);
1048 bool encoded = false;
1049 std::string mime_type;
1050 switch (image_format_) {
1051 case FORMAT_JPEG:
1052 encoded = gfx::JPEGCodec::Encode(
1053 reinterpret_cast<unsigned char*>(screen_capture.getAddr32(0, 0)),
1054 gfx::JPEGCodec::FORMAT_SkBitmap,
1055 screen_capture.width(),
1056 screen_capture.height(),
1057 static_cast<int>(screen_capture.rowBytes()),
1058 image_quality_,
1059 &data);
1060 mime_type = keys::kMimeTypeJpeg;
1061 break;
1062 case FORMAT_PNG:
1063 encoded = gfx::PNGCodec::EncodeBGRASkBitmap(
1064 screen_capture,
1065 true, // Discard transparency.
1066 &data);
1067 mime_type = keys::kMimeTypePng;
1068 break;
1069 default:
1070 NOTREACHED() << "Invalid image format.";
1071 }
1072
1073 if (!encoded) {
1074 error_ = keys::kInternalVisibleTabCaptureError;
1075 SendResponse(false);
1076 return;
1077 }
1078
1079 std::string base64_result;
1080 base::StringPiece stream_as_string(
1081 reinterpret_cast<const char*>(vector_as_array(&data)), data.size());
1082
1083 base::Base64Encode(stream_as_string, &base64_result);
1084 base64_result.insert(0, base::StringPrintf("data:%s;base64,",
1085 mime_type.c_str()));
1086 result_.reset(new StringValue(base64_result));
1087 SendResponse(true);
1088 }
1089
1090 // update ----------------------------------------------------------------------
1091
1092 UpdateOffscreenTabFunction::UpdateOffscreenTabFunction() {}
1093 UpdateOffscreenTabFunction::~UpdateOffscreenTabFunction() {}
1094
1095 // TODO(alexbost): Needs refactoring. Similar method in extension_tabs_module.
1096 bool UpdateOffscreenTabFunction::RunImpl() {
1097 int tab_id;
1098 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &tab_id));
1099
1100 OffscreenTab* tab = NULL;
1101 if (!GetMap()->GetOffscreenTab(tab_id, dispatcher(), profile_, &tab, &error_))
1102 return false;
1103
1104 DictionaryValue* update_props;
1105 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &update_props));
1106
1107 // Url
1108 if (update_props->HasKey(keys::kUrlKey)) {
1109 std::string url_string;
1110 GURL url;
1111 EXTENSION_FUNCTION_VALIDATE(
1112 update_props->GetString(keys::kUrlKey, &url_string));
1113 url = ResolvePossiblyRelativeURL(url_string, GetExtension());
1114 if (!url.is_valid()) {
1115 error_ = ExtensionErrorUtils::FormatErrorMessage(
1116 keys::kInvalidUrlError, url_string);
1117 return false;
1118 }
1119 if (IsCrashURL(url)) {
1120 error_ = keys::kNoCrashBrowserError;
1121 return false;
1122 }
1123
1124 // JavaScript URLs can do the same kinds of things as cross-origin XHR, so
1125 // we need to check host permissions before allowing them.
1126 if (url.SchemeIs(chrome::kJavaScriptScheme)) {
1127 if (!GetExtension()->CanExecuteScriptOnPage(
1128 tab->contents()->GetURL(), NULL, &error_)) {
1129 return false;
1130 }
1131
1132 ExtensionMsg_ExecuteCode_Params params;
1133 params.request_id = request_id();
1134 params.extension_id = extension_id();
1135 params.is_javascript = true;
1136 params.code = url.path();
1137 params.all_frames = false;
1138 params.in_main_world = true;
1139
1140 RenderViewHost* render_view_host =
1141 tab->contents()->render_view_host();
1142 render_view_host->Send(
1143 new ExtensionMsg_ExecuteCode(render_view_host->routing_id(),
1144 params));
1145
1146 Observe(tab->contents());
1147 AddRef(); // balanced in Observe()
1148
1149 return true;
1150 }
1151
1152 tab->SetUrl(url);
1153
1154 // The URL of a tab contents never actually changes to a JavaScript URL, so
1155 // this check only makes sense in other cases.
1156 if (!url.SchemeIs(chrome::kJavaScriptScheme))
1157 DCHECK_EQ(url.spec(), tab->contents()->GetURL().spec());
1158 }
1159
1160 // Width and height
1161 if (update_props->HasKey(keys::kWidthKey) ||
1162 update_props->HasKey(keys::kHeightKey)) {
1163 int width;
1164 if (update_props->HasKey(keys::kWidthKey))
1165 EXTENSION_FUNCTION_VALIDATE(
1166 update_props->GetInteger(keys::kWidthKey, &width));
1167 else
1168 GetTabSize(TabContentsWrapper::GetCurrentWrapperForContents(
1169 tab->contents())).width();
1170
1171 int height;
1172 if (update_props->HasKey(keys::kHeightKey))
1173 EXTENSION_FUNCTION_VALIDATE(
1174 update_props->GetInteger(keys::kHeightKey, &height));
1175 else
1176 GetTabSize(TabContentsWrapper::GetCurrentWrapperForContents(
1177 tab->contents())).height();
1178
1179 tab->SetSize(width, height);
1180 }
1181
1182 // Callback
1183 if (has_callback()) {
1184 result_.reset(tab->CreateValue());
1185 SendResponse(true);
1186 }
1187
1188 return true;
1189 }
1190
1191 // TODO(alexbost): Needs refactoring. Similar method in extension_tabs_module.
1192 bool UpdateOffscreenTabFunction::OnMessageReceived(
1193 const IPC::Message& message) {
1194 if (message.type() != ExtensionHostMsg_ExecuteCodeFinished::ID)
1195 return false;
1196
1197 int message_request_id;
1198 void* iter = NULL;
1199 if (!message.ReadInt(&iter, &message_request_id)) {
1200 NOTREACHED() << "malformed extension message";
1201 return true;
1202 }
1203
1204 if (message_request_id != request_id())
1205 return false;
1206
1207 IPC_BEGIN_MESSAGE_MAP(UpdateOffscreenTabFunction, message)
1208 IPC_MESSAGE_HANDLER(ExtensionHostMsg_ExecuteCodeFinished,
1209 OnExecuteCodeFinished)
1210 IPC_END_MESSAGE_MAP()
1211 return true;
1212 }
1213
1214 // TODO(alexbost): Needs refactoring. Similar method in extension_tabs_module.
1215 void UpdateOffscreenTabFunction::OnExecuteCodeFinished(int request_id,
1216 bool success,
1217 const std::string& error) {
1218 if (!error.empty()) {
1219 CHECK(!success);
1220 error_ = error;
1221 }
1222
1223 SendResponse(success);
1224
1225 Observe(NULL);
1226 Release(); // balanced in Execute()
1227 }
1228
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698