- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / api / tabs / tabs_api.cc
1 // Copyright (c) 2012 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/api/tabs/tabs_api.h"
6
7 #include <algorithm>
8 #include <limits>
9 #include <vector>
10
11 #include "apps/shell_window.h"
12 #include "base/base64.h"
13 #include "base/bind.h"
14 #include "base/command_line.h"
15 #include "base/logging.h"
16 #include "base/memory/ref_counted_memory.h"
17 #include "base/message_loop/message_loop.h"
18 #include "base/prefs/pref_service.h"
19 #include "base/stl_util.h"
20 #include "base/strings/string16.h"
21 #include "base/strings/string_number_conversions.h"
22 #include "base/strings/string_util.h"
23 #include "base/strings/stringprintf.h"
24 #include "base/strings/utf_string_conversions.h"
25 #include "chrome/browser/chrome_notification_types.h"
26 #include "chrome/browser/extensions/api/tabs/tabs_constants.h"
27 #include "chrome/browser/extensions/api/tabs/windows_util.h"
28 #include "chrome/browser/extensions/extension_function_dispatcher.h"
29 #include "chrome/browser/extensions/extension_function_util.h"
30 #include "chrome/browser/extensions/extension_host.h"
31 #include "chrome/browser/extensions/extension_service.h"
32 #include "chrome/browser/extensions/extension_tab_util.h"
33 #include "chrome/browser/extensions/script_executor.h"
34 #include "chrome/browser/extensions/tab_helper.h"
35 #include "chrome/browser/extensions/window_controller.h"
36 #include "chrome/browser/extensions/window_controller_list.h"
37 #include "chrome/browser/prefs/incognito_mode_prefs.h"
38 #include "chrome/browser/profiles/profile.h"
39 #include "chrome/browser/translate/translate_tab_helper.h"
40 #include "chrome/browser/ui/apps/chrome_shell_window_delegate.h"
41 #include "chrome/browser/ui/browser.h"
42 #include "chrome/browser/ui/browser_commands.h"
43 #include "chrome/browser/ui/browser_finder.h"
44 #include "chrome/browser/ui/browser_iterator.h"
45 #include "chrome/browser/ui/browser_navigator.h"
46 #include "chrome/browser/ui/browser_tabstrip.h"
47 #include "chrome/browser/ui/browser_window.h"
48 #include "chrome/browser/ui/host_desktop.h"
49 #include "chrome/browser/ui/panels/panel_manager.h"
50 #include "chrome/browser/ui/tabs/tab_strip_model.h"
51 #include "chrome/browser/ui/window_sizer/window_sizer.h"
52 #include "chrome/browser/web_applications/web_app.h"
53 #include "chrome/common/chrome_switches.h"
54 #include "chrome/common/extensions/api/i18n/default_locale_handler.h"
55 #include "chrome/common/extensions/api/tabs.h"
56 #include "chrome/common/extensions/api/windows.h"
57 #include "chrome/common/extensions/extension.h"
58 #include "chrome/common/extensions/extension_constants.h"
59 #include "chrome/common/extensions/extension_file_util.h"
60 #include "chrome/common/extensions/extension_l10n_util.h"
61 #include "chrome/common/extensions/extension_messages.h"
62 #include "chrome/common/extensions/incognito_handler.h"
63 #include "chrome/common/extensions/message_bundle.h"
64 #include "chrome/common/extensions/permissions/permissions_data.h"
65 #include "chrome/common/pref_names.h"
66 #include "chrome/common/translate/language_detection_details.h"
67 #include "chrome/common/url_constants.h"
68 #include "components/user_prefs/pref_registry_syncable.h"
69 #include "content/public/browser/navigation_controller.h"
70 #include "content/public/browser/navigation_entry.h"
71 #include "content/public/browser/notification_details.h"
72 #include "content/public/browser/notification_source.h"
73 #include "content/public/browser/render_process_host.h"
74 #include "content/public/browser/render_view_host.h"
75 #include "content/public/browser/render_widget_host_view.h"
76 #include "content/public/browser/web_contents.h"
77 #include "content/public/browser/web_contents_view.h"
78 #include "content/public/common/url_constants.h"
79 #include "extensions/browser/file_reader.h"
80 #include "extensions/common/constants.h"
81 #include "extensions/common/error_utils.h"
82 #include "extensions/common/manifest_constants.h"
83 #include "extensions/common/user_script.h"
84 #include "skia/ext/image_operations.h"
85 #include "skia/ext/platform_canvas.h"
86 #include "third_party/skia/include/core/SkBitmap.h"
87 #include "ui/base/models/list_selection_model.h"
88 #include "ui/base/ui_base_types.h"
89 #include "ui/gfx/codec/jpeg_codec.h"
90 #include "ui/gfx/codec/png_codec.h"
91
92 #if defined(OS_WIN)
93 #include "win8/util/win8_util.h"
94 #endif  // OS_WIN
95
96 #if defined(USE_ASH)
97 #include "apps/shell_window_registry.h"
98 #include "ash/ash_switches.h"
99 #include "chrome/browser/extensions/api/tabs/ash_panel_contents.h"
100 #endif
101
102 using apps::ShellWindow;
103 using content::BrowserThread;
104 using content::NavigationController;
105 using content::NavigationEntry;
106 using content::OpenURLParams;
107 using content::Referrer;
108 using content::RenderViewHost;
109 using content::WebContents;
110
111 namespace extensions {
112
113 namespace windows = api::windows;
114 namespace errors = manifest_errors;
115 namespace keys = tabs_constants;
116 namespace tabs = api::tabs;
117 typedef tabs::CaptureVisibleTab::Params::Options FormatEnum;
118
119 using api::tabs::InjectDetails;
120
121 const int TabsCaptureVisibleTabFunction::kDefaultQuality = 90;
122
123 namespace {
124
125 // |error_message| can optionally be passed in a will be set with an appropriate
126 // message if the window cannot be found by id.
127 Browser* GetBrowserInProfileWithId(Profile* profile,
128                                    const int window_id,
129                                    bool include_incognito,
130                                    std::string* error_message) {
131   Profile* incognito_profile =
132       include_incognito && profile->HasOffTheRecordProfile() ?
133           profile->GetOffTheRecordProfile() : NULL;
134   for (chrome::BrowserIterator it; !it.done(); it.Next()) {
135     Browser* browser = *it;
136     if ((browser->profile() == profile ||
137          browser->profile() == incognito_profile) &&
138         ExtensionTabUtil::GetWindowId(browser) == window_id &&
139         browser->window()) {
140       return browser;
141     }
142   }
143
144   if (error_message)
145     *error_message = ErrorUtils::FormatErrorMessage(
146         keys::kWindowNotFoundError, base::IntToString(window_id));
147
148   return NULL;
149 }
150
151 bool GetBrowserFromWindowID(ChromeAsyncExtensionFunction* function,
152                             int window_id,
153                             Browser** browser) {
154   if (window_id == extension_misc::kCurrentWindowId) {
155     *browser = function->GetCurrentBrowser();
156     if (!(*browser) || !(*browser)->window()) {
157       function->SetError(keys::kNoCurrentWindowError);
158       return false;
159     }
160   } else {
161     std::string error;
162     *browser = GetBrowserInProfileWithId(function->GetProfile(),
163                                          window_id,
164                                          function->include_incognito(),
165                                          &error);
166     if (!*browser) {
167       function->SetError(error);
168       return false;
169     }
170   }
171   return true;
172 }
173
174 // |error_message| can optionally be passed in and will be set with an
175 // appropriate message if the tab cannot be found by id.
176 bool GetTabById(int tab_id,
177                 Profile* profile,
178                 bool include_incognito,
179                 Browser** browser,
180                 TabStripModel** tab_strip,
181                 content::WebContents** contents,
182                 int* tab_index,
183                 std::string* error_message) {
184   if (ExtensionTabUtil::GetTabById(tab_id, profile, include_incognito,
185                                    browser, tab_strip, contents, tab_index))
186     return true;
187
188   if (error_message)
189     *error_message = ErrorUtils::FormatErrorMessage(
190         keys::kTabNotFoundError, base::IntToString(tab_id));
191
192   return false;
193 }
194
195 // Returns true if either |boolean| is a null pointer, or if |*boolean| and
196 // |value| are equal. This function is used to check if a tab's parameters match
197 // those of the browser.
198 bool MatchesBool(bool* boolean, bool value) {
199   return !boolean || *boolean == value;
200 }
201
202 Browser* CreateBrowserWindow(const Browser::CreateParams& params,
203                              Profile* profile,
204                              const std::string& extension_id) {
205   bool use_existing_browser_window = false;
206
207 #if defined(OS_WIN)
208   // In windows 8 metro mode we don't allow windows to be created.
209   if (win8::IsSingleWindowMetroMode())
210     use_existing_browser_window = true;
211 #endif  // OS_WIN
212
213   Browser* new_window = NULL;
214   if (use_existing_browser_window)
215     // The false parameter passed below is to ensure that we find a browser
216     // object matching the profile passed in, instead of the original profile
217     new_window = chrome::FindTabbedBrowser(profile, false,
218                                            params.host_desktop_type);
219
220   if (!new_window)
221     new_window = new Browser(params);
222   return new_window;
223 }
224
225 }  // namespace
226
227 // Windows ---------------------------------------------------------------------
228
229 bool WindowsGetFunction::RunImpl() {
230   scoped_ptr<windows::Get::Params> params(windows::Get::Params::Create(*args_));
231   EXTENSION_FUNCTION_VALIDATE(params.get());
232
233   bool populate_tabs = false;
234   if (params->get_info.get() && params->get_info->populate.get())
235     populate_tabs = *params->get_info->populate;
236
237   WindowController* controller;
238   if (!windows_util::GetWindowFromWindowID(this,
239                                            params->window_id,
240                                            &controller)) {
241     return false;
242   }
243
244   if (populate_tabs)
245     SetResult(controller->CreateWindowValueWithTabs(GetExtension()));
246   else
247     SetResult(controller->CreateWindowValue());
248   return true;
249 }
250
251 bool WindowsGetCurrentFunction::RunImpl() {
252   scoped_ptr<windows::GetCurrent::Params> params(
253       windows::GetCurrent::Params::Create(*args_));
254   EXTENSION_FUNCTION_VALIDATE(params.get());
255
256   bool populate_tabs = false;
257   if (params->get_info.get() && params->get_info->populate.get())
258     populate_tabs = *params->get_info->populate;
259
260   WindowController* controller;
261   if (!windows_util::GetWindowFromWindowID(this,
262                                            extension_misc::kCurrentWindowId,
263                                            &controller)) {
264     return false;
265   }
266   if (populate_tabs)
267     SetResult(controller->CreateWindowValueWithTabs(GetExtension()));
268   else
269     SetResult(controller->CreateWindowValue());
270   return true;
271 }
272
273 bool WindowsGetLastFocusedFunction::RunImpl() {
274   scoped_ptr<windows::GetLastFocused::Params> params(
275       windows::GetLastFocused::Params::Create(*args_));
276   EXTENSION_FUNCTION_VALIDATE(params.get());
277
278   bool populate_tabs = false;
279   if (params->get_info.get() && params->get_info->populate.get())
280     populate_tabs = *params->get_info->populate;
281
282   // Note: currently this returns the last active browser. If we decide to
283   // include other window types (e.g. panels), we will need to add logic to
284   // WindowControllerList that mirrors the active behavior of BrowserList.
285   Browser* browser = chrome::FindAnyBrowser(
286       GetProfile(), include_incognito(), chrome::GetActiveDesktop());
287   if (!browser || !browser->window()) {
288     error_ = keys::kNoLastFocusedWindowError;
289     return false;
290   }
291   WindowController* controller =
292       browser->extension_window_controller();
293   if (populate_tabs)
294     SetResult(controller->CreateWindowValueWithTabs(GetExtension()));
295   else
296     SetResult(controller->CreateWindowValue());
297   return true;
298 }
299
300 bool WindowsGetAllFunction::RunImpl() {
301   scoped_ptr<windows::GetAll::Params> params(
302       windows::GetAll::Params::Create(*args_));
303   EXTENSION_FUNCTION_VALIDATE(params.get());
304
305   bool populate_tabs = false;
306   if (params->get_info.get() && params->get_info->populate.get())
307     populate_tabs = *params->get_info->populate;
308
309   base::ListValue* window_list = new base::ListValue();
310   const WindowControllerList::ControllerList& windows =
311       WindowControllerList::GetInstance()->windows();
312   for (WindowControllerList::ControllerList::const_iterator iter =
313            windows.begin();
314        iter != windows.end(); ++iter) {
315     if (!this->CanOperateOnWindow(*iter))
316       continue;
317     if (populate_tabs)
318       window_list->Append((*iter)->CreateWindowValueWithTabs(GetExtension()));
319     else
320       window_list->Append((*iter)->CreateWindowValue());
321   }
322   SetResult(window_list);
323   return true;
324 }
325
326 bool WindowsCreateFunction::ShouldOpenIncognitoWindow(
327     const windows::Create::Params::CreateData* create_data,
328     std::vector<GURL>* urls, bool* is_error) {
329   *is_error = false;
330   const IncognitoModePrefs::Availability incognito_availability =
331       IncognitoModePrefs::GetAvailability(GetProfile()->GetPrefs());
332   bool incognito = false;
333   if (create_data && create_data->incognito) {
334     incognito = *create_data->incognito;
335     if (incognito && incognito_availability == IncognitoModePrefs::DISABLED) {
336       error_ = keys::kIncognitoModeIsDisabled;
337       *is_error = true;
338       return false;
339     }
340     if (!incognito && incognito_availability == IncognitoModePrefs::FORCED) {
341       error_ = keys::kIncognitoModeIsForced;
342       *is_error = true;
343       return false;
344     }
345   } else if (incognito_availability == IncognitoModePrefs::FORCED) {
346     // If incognito argument is not specified explicitly, we default to
347     // incognito when forced so by policy.
348     incognito = true;
349   }
350
351   // Remove all URLs that are not allowed in an incognito session. Note that a
352   // ChromeOS guest session is not considered incognito in this case.
353   if (incognito && !GetProfile()->IsGuestSession()) {
354     std::string first_url_erased;
355     for (size_t i = 0; i < urls->size();) {
356       if (chrome::IsURLAllowedInIncognito((*urls)[i], GetProfile())) {
357         i++;
358       } else {
359         if (first_url_erased.empty())
360           first_url_erased = (*urls)[i].spec();
361         urls->erase(urls->begin() + i);
362       }
363     }
364     if (urls->empty() && !first_url_erased.empty()) {
365       error_ = ErrorUtils::FormatErrorMessage(
366           keys::kURLsNotAllowedInIncognitoError, first_url_erased);
367       *is_error = true;
368       return false;
369     }
370   }
371   return incognito;
372 }
373
374 bool WindowsCreateFunction::RunImpl() {
375   scoped_ptr<windows::Create::Params> params(
376       windows::Create::Params::Create(*args_));
377   EXTENSION_FUNCTION_VALIDATE(params);
378   std::vector<GURL> urls;
379   TabStripModel* source_tab_strip = NULL;
380   int tab_index = -1;
381
382   windows::Create::Params::CreateData* create_data = params->create_data.get();
383
384   // Look for optional url.
385   if (create_data && create_data->url) {
386     std::vector<std::string> url_strings;
387     // First, get all the URLs the client wants to open.
388     if (create_data->url->as_string)
389       url_strings.push_back(*create_data->url->as_string);
390     else if (create_data->url->as_strings)
391       url_strings.swap(*create_data->url->as_strings);
392
393     // Second, resolve, validate and convert them to GURLs.
394     for (std::vector<std::string>::iterator i = url_strings.begin();
395          i != url_strings.end(); ++i) {
396       GURL url = ExtensionTabUtil::ResolvePossiblyRelativeURL(
397           *i, GetExtension());
398       if (!url.is_valid()) {
399         error_ = ErrorUtils::FormatErrorMessage(keys::kInvalidUrlError, *i);
400         return false;
401       }
402       // Don't let the extension crash the browser or renderers.
403       if (ExtensionTabUtil::IsCrashURL(url)) {
404         error_ = keys::kNoCrashBrowserError;
405         return false;
406       }
407       urls.push_back(url);
408     }
409   }
410
411   // Look for optional tab id.
412   if (create_data && create_data->tab_id) {
413     // Find the tab. |source_tab_strip| and |tab_index| will later be used to
414     // move the tab into the created window.
415     if (!GetTabById(*create_data->tab_id,
416                     GetProfile(),
417                     include_incognito(),
418                     NULL,
419                     &source_tab_strip,
420                     NULL,
421                     &tab_index,
422                     &error_))
423       return false;
424   }
425
426   Profile* window_profile = GetProfile();
427   Browser::Type window_type = Browser::TYPE_TABBED;
428   bool create_panel = false;
429
430   // panel_create_mode only applies if create_panel = true
431   PanelManager::CreateMode panel_create_mode = PanelManager::CREATE_AS_DOCKED;
432
433   gfx::Rect window_bounds;
434   bool focused = true;
435   bool saw_focus_key = false;
436   std::string extension_id;
437
438   // Decide whether we are opening a normal window or an incognito window.
439   bool is_error = true;
440   bool open_incognito_window = ShouldOpenIncognitoWindow(create_data, &urls,
441                                                          &is_error);
442   if (is_error) {
443     // error_ member variable is set inside of ShouldOpenIncognitoWindow.
444     return false;
445   }
446   if (open_incognito_window) {
447     window_profile = window_profile->GetOffTheRecordProfile();
448   }
449
450   if (create_data) {
451     // Figure out window type before figuring out bounds so that default
452     // bounds can be set according to the window type.
453     switch (create_data->type) {
454       case windows::Create::Params::CreateData::TYPE_POPUP:
455         window_type = Browser::TYPE_POPUP;
456         extension_id = GetExtension()->id();
457         break;
458       case windows::Create::Params::CreateData::TYPE_PANEL:
459       case windows::Create::Params::CreateData::TYPE_DETACHED_PANEL: {
460         extension_id = GetExtension()->id();
461         bool use_panels = false;
462 #if !defined(OS_ANDROID)
463         use_panels = PanelManager::ShouldUsePanels(extension_id);
464 #endif
465         if (use_panels) {
466           create_panel = true;
467           // Non-ash supports both docked and detached panel types.
468           if (chrome::GetActiveDesktop() != chrome::HOST_DESKTOP_TYPE_ASH &&
469               create_data->type ==
470               windows::Create::Params::CreateData::TYPE_DETACHED_PANEL) {
471             panel_create_mode = PanelManager::CREATE_AS_DETACHED;
472           }
473         } else {
474           window_type = Browser::TYPE_POPUP;
475         }
476         break;
477       }
478       case windows::Create::Params::CreateData::TYPE_NONE:
479       case windows::Create::Params::CreateData::TYPE_NORMAL:
480         break;
481       default:
482         error_ = keys::kInvalidWindowTypeError;
483         return false;
484     }
485
486     // Initialize default window bounds according to window type.
487     if (window_type == Browser::TYPE_TABBED ||
488         window_type == Browser::TYPE_POPUP ||
489         create_panel) {
490       // Try to position the new browser relative to its originating
491       // browser window. The call offsets the bounds by kWindowTilePixels
492       // (defined in WindowSizer to be 10).
493       //
494       // NOTE(rafaelw): It's ok if GetCurrentBrowser() returns NULL here.
495       // GetBrowserWindowBounds will default to saved "default" values for
496       // the app.
497       ui::WindowShowState show_state = ui::SHOW_STATE_DEFAULT;
498       WindowSizer::GetBrowserWindowBoundsAndShowState(std::string(),
499                                                       gfx::Rect(),
500                                                       GetCurrentBrowser(),
501                                                       &window_bounds,
502                                                       &show_state);
503     }
504
505     if (create_panel && PanelManager::CREATE_AS_DETACHED == panel_create_mode) {
506       window_bounds.set_origin(
507           PanelManager::GetInstance()->GetDefaultDetachedPanelOrigin());
508     }
509
510     // Any part of the bounds can optionally be set by the caller.
511     if (create_data->left)
512       window_bounds.set_x(*create_data->left);
513
514     if (create_data->top)
515       window_bounds.set_y(*create_data->top);
516
517     if (create_data->width)
518       window_bounds.set_width(*create_data->width);
519
520     if (create_data->height)
521       window_bounds.set_height(*create_data->height);
522
523     if (create_data->focused) {
524       focused = *create_data->focused;
525       saw_focus_key = true;
526     }
527   }
528
529   if (create_panel) {
530     if (urls.empty())
531       urls.push_back(GURL(chrome::kChromeUINewTabURL));
532
533 #if defined(USE_ASH)
534     if (chrome::GetActiveDesktop() == chrome::HOST_DESKTOP_TYPE_ASH) {
535       ShellWindow::CreateParams create_params;
536       create_params.window_type = ShellWindow::WINDOW_TYPE_V1_PANEL;
537       create_params.bounds = window_bounds;
538       create_params.focused = saw_focus_key && focused;
539       ShellWindow* shell_window = new ShellWindow(
540           window_profile, new ChromeShellWindowDelegate(),
541           GetExtension());
542       AshPanelContents* ash_panel_contents = new AshPanelContents(shell_window);
543       shell_window->Init(urls[0], ash_panel_contents, create_params);
544       SetResult(ash_panel_contents->GetExtensionWindowController()->
545                 CreateWindowValueWithTabs(GetExtension()));
546       return true;
547     }
548 #endif
549     std::string title =
550         web_app::GenerateApplicationNameFromExtensionId(extension_id);
551     // Note: Panels ignore all but the first url provided.
552     Panel* panel = PanelManager::GetInstance()->CreatePanel(
553         title, window_profile, urls[0], window_bounds, panel_create_mode);
554
555     // Unlike other window types, Panels do not take focus by default.
556     if (!saw_focus_key || !focused)
557       panel->ShowInactive();
558     else
559       panel->Show();
560
561     SetResult(
562         panel->extension_window_controller()->CreateWindowValueWithTabs(
563             GetExtension()));
564     return true;
565   }
566
567   // Create a new BrowserWindow.
568   chrome::HostDesktopType host_desktop_type = chrome::GetActiveDesktop();
569   if (create_panel)
570     window_type = Browser::TYPE_POPUP;
571   Browser::CreateParams create_params(window_type, window_profile,
572                                       host_desktop_type);
573   if (extension_id.empty()) {
574     create_params.initial_bounds = window_bounds;
575   } else {
576     create_params = Browser::CreateParams::CreateForApp(
577         window_type,
578         web_app::GenerateApplicationNameFromExtensionId(extension_id),
579         window_bounds,
580         window_profile,
581         host_desktop_type);
582   }
583   create_params.initial_show_state = ui::SHOW_STATE_NORMAL;
584   create_params.host_desktop_type = chrome::GetActiveDesktop();
585
586   Browser* new_window = CreateBrowserWindow(create_params, window_profile,
587                                             extension_id);
588
589   for (std::vector<GURL>::iterator i = urls.begin(); i != urls.end(); ++i) {
590     WebContents* tab = chrome::AddSelectedTabWithURL(
591         new_window, *i, content::PAGE_TRANSITION_LINK);
592     if (create_panel) {
593       TabHelper::FromWebContents(tab)->SetExtensionAppIconById(extension_id);
594     }
595   }
596
597   WebContents* contents = NULL;
598   // Move the tab into the created window only if it's an empty popup or it's
599   // a tabbed window.
600   if ((window_type == Browser::TYPE_POPUP && urls.empty()) ||
601       window_type == Browser::TYPE_TABBED) {
602     if (source_tab_strip)
603       contents = source_tab_strip->DetachWebContentsAt(tab_index);
604     if (contents) {
605       TabStripModel* target_tab_strip = new_window->tab_strip_model();
606       target_tab_strip->InsertWebContentsAt(urls.size(), contents,
607                                             TabStripModel::ADD_NONE);
608     }
609   }
610   // Create a new tab if the created window is still empty. Don't create a new
611   // tab when it is intended to create an empty popup.
612   if (!contents && urls.empty() && window_type != Browser::TYPE_POPUP) {
613     chrome::NewTab(new_window);
614   }
615   chrome::SelectNumberedTab(new_window, 0);
616
617   // Unlike other window types, Panels do not take focus by default.
618   if (!saw_focus_key && create_panel)
619     focused = false;
620
621   if (focused)
622     new_window->window()->Show();
623   else
624     new_window->window()->ShowInactive();
625
626   if (new_window->profile()->IsOffTheRecord() && !include_incognito()) {
627     // Don't expose incognito windows if the extension isn't allowed.
628     SetResult(Value::CreateNullValue());
629   } else {
630     SetResult(
631         new_window->extension_window_controller()->CreateWindowValueWithTabs(
632             GetExtension()));
633   }
634
635   return true;
636 }
637
638 bool WindowsUpdateFunction::RunImpl() {
639   scoped_ptr<windows::Update::Params> params(
640       windows::Update::Params::Create(*args_));
641   EXTENSION_FUNCTION_VALIDATE(params);
642
643   WindowController* controller;
644   if (!windows_util::GetWindowFromWindowID(this, params->window_id,
645                                             &controller))
646     return false;
647
648 #if defined(OS_WIN)
649   // Silently ignore changes on the window for metro mode.
650   if (win8::IsSingleWindowMetroMode()) {
651     SetResult(controller->CreateWindowValue());
652     return true;
653   }
654 #endif
655
656   ui::WindowShowState show_state = ui::SHOW_STATE_DEFAULT;  // No change.
657   switch (params->update_info.state) {
658     case windows::Update::Params::UpdateInfo::STATE_NORMAL:
659       show_state = ui::SHOW_STATE_NORMAL;
660       break;
661     case windows::Update::Params::UpdateInfo::STATE_MINIMIZED:
662       show_state = ui::SHOW_STATE_MINIMIZED;
663       break;
664     case windows::Update::Params::UpdateInfo::STATE_MAXIMIZED:
665       show_state = ui::SHOW_STATE_MAXIMIZED;
666       break;
667     case windows::Update::Params::UpdateInfo::STATE_FULLSCREEN:
668       show_state = ui::SHOW_STATE_FULLSCREEN;
669       break;
670     case windows::Update::Params::UpdateInfo::STATE_NONE:
671       break;
672     default:
673       error_ = keys::kInvalidWindowStateError;
674       return false;
675   }
676
677   if (show_state != ui::SHOW_STATE_FULLSCREEN &&
678       show_state != ui::SHOW_STATE_DEFAULT)
679     controller->SetFullscreenMode(false, GetExtension()->url());
680
681   switch (show_state) {
682     case ui::SHOW_STATE_MINIMIZED:
683       controller->window()->Minimize();
684       break;
685     case ui::SHOW_STATE_MAXIMIZED:
686       controller->window()->Maximize();
687       break;
688     case ui::SHOW_STATE_FULLSCREEN:
689       if (controller->window()->IsMinimized() ||
690           controller->window()->IsMaximized())
691         controller->window()->Restore();
692       controller->SetFullscreenMode(true, GetExtension()->url());
693       break;
694     case ui::SHOW_STATE_NORMAL:
695       controller->window()->Restore();
696       break;
697     default:
698       break;
699   }
700
701   gfx::Rect bounds;
702   if (controller->window()->IsMinimized())
703     bounds = controller->window()->GetRestoredBounds();
704   else
705     bounds = controller->window()->GetBounds();
706   bool set_bounds = false;
707
708   // Any part of the bounds can optionally be set by the caller.
709   if (params->update_info.left) {
710     bounds.set_x(*params->update_info.left);
711     set_bounds = true;
712   }
713
714   if (params->update_info.top) {
715     bounds.set_y(*params->update_info.top);
716     set_bounds = true;
717   }
718
719   if (params->update_info.width) {
720     bounds.set_width(*params->update_info.width);
721     set_bounds = true;
722   }
723
724   if (params->update_info.height) {
725     bounds.set_height(*params->update_info.height);
726     set_bounds = true;
727   }
728
729   if (set_bounds) {
730     if (show_state == ui::SHOW_STATE_MINIMIZED ||
731         show_state == ui::SHOW_STATE_MAXIMIZED ||
732         show_state == ui::SHOW_STATE_FULLSCREEN) {
733       error_ = keys::kInvalidWindowStateError;
734       return false;
735     }
736     // TODO(varkha): Updating bounds during a drag can cause problems and a more
737     // general solution is needed. See http://crbug.com/251813 .
738     controller->window()->SetBounds(bounds);
739   }
740
741   if (params->update_info.focused) {
742     if (*params->update_info.focused) {
743       if (show_state == ui::SHOW_STATE_MINIMIZED) {
744         error_ = keys::kInvalidWindowStateError;
745         return false;
746       }
747       controller->window()->Activate();
748     } else {
749       if (show_state == ui::SHOW_STATE_MAXIMIZED ||
750           show_state == ui::SHOW_STATE_FULLSCREEN) {
751         error_ = keys::kInvalidWindowStateError;
752         return false;
753       }
754       controller->window()->Deactivate();
755     }
756   }
757
758   if (params->update_info.draw_attention)
759     controller->window()->FlashFrame(*params->update_info.draw_attention);
760
761   SetResult(controller->CreateWindowValue());
762
763   return true;
764 }
765
766 bool WindowsRemoveFunction::RunImpl() {
767   scoped_ptr<windows::Remove::Params> params(
768       windows::Remove::Params::Create(*args_));
769   EXTENSION_FUNCTION_VALIDATE(params);
770
771   WindowController* controller;
772   if (!windows_util::GetWindowFromWindowID(this, params->window_id,
773                                            &controller))
774     return false;
775
776 #if defined(OS_WIN)
777   // In Windows 8 metro mode, an existing Browser instance is reused for
778   // hosting the extension tab. We should not be closing it as we don't own it.
779   if (win8::IsSingleWindowMetroMode())
780     return false;
781 #endif
782
783   WindowController::Reason reason;
784   if (!controller->CanClose(&reason)) {
785     if (reason == WindowController::REASON_NOT_EDITABLE)
786       error_ = keys::kTabStripNotEditableError;
787     return false;
788   }
789   controller->window()->Close();
790   return true;
791 }
792
793 // Tabs ------------------------------------------------------------------------
794
795 bool TabsGetSelectedFunction::RunImpl() {
796   // windowId defaults to "current" window.
797   int window_id = extension_misc::kCurrentWindowId;
798
799   scoped_ptr<tabs::GetSelected::Params> params(
800       tabs::GetSelected::Params::Create(*args_));
801   EXTENSION_FUNCTION_VALIDATE(params.get());
802   if (params->window_id.get())
803     window_id = *params->window_id;
804
805   Browser* browser = NULL;
806   if (!GetBrowserFromWindowID(this, window_id, &browser))
807     return false;
808
809   TabStripModel* tab_strip = browser->tab_strip_model();
810   WebContents* contents = tab_strip->GetActiveWebContents();
811   if (!contents) {
812     error_ = keys::kNoSelectedTabError;
813     return false;
814   }
815   SetResult(ExtensionTabUtil::CreateTabValue(contents,
816                                              tab_strip,
817                                              tab_strip->active_index(),
818                                              GetExtension()));
819   return true;
820 }
821
822 bool TabsGetAllInWindowFunction::RunImpl() {
823   scoped_ptr<tabs::GetAllInWindow::Params> params(
824       tabs::GetAllInWindow::Params::Create(*args_));
825   EXTENSION_FUNCTION_VALIDATE(params.get());
826   // windowId defaults to "current" window.
827   int window_id = extension_misc::kCurrentWindowId;
828   if (params->window_id.get())
829     window_id = *params->window_id;
830
831   Browser* browser = NULL;
832   if (!GetBrowserFromWindowID(this, window_id, &browser))
833     return false;
834
835   SetResult(ExtensionTabUtil::CreateTabList(browser, GetExtension()));
836
837   return true;
838 }
839
840 bool TabsQueryFunction::RunImpl() {
841   scoped_ptr<tabs::Query::Params> params(tabs::Query::Params::Create(*args_));
842   EXTENSION_FUNCTION_VALIDATE(params.get());
843
844   bool loading_status_set = params->query_info.status !=
845       tabs::Query::Params::QueryInfo::STATUS_NONE;
846   bool loading = params->query_info.status ==
847       tabs::Query::Params::QueryInfo::STATUS_LOADING;
848
849   // It is o.k. to use URLPattern::SCHEME_ALL here because this function does
850   // not grant access to the content of the tabs, only to seeing their URLs and
851   // meta data.
852   URLPattern url_pattern(URLPattern::SCHEME_ALL, "<all_urls>");
853   if (params->query_info.url.get())
854     url_pattern = URLPattern(URLPattern::SCHEME_ALL, *params->query_info.url);
855
856   std::string title;
857   if (params->query_info.title.get())
858     title = *params->query_info.title;
859
860   int window_id = extension_misc::kUnknownWindowId;
861   if (params->query_info.window_id.get())
862     window_id = *params->query_info.window_id;
863
864   int index = -1;
865   if (params->query_info.index.get())
866     index = *params->query_info.index;
867
868   std::string window_type;
869   if (params->query_info.window_type !=
870       tabs::Query::Params::QueryInfo::WINDOW_TYPE_NONE) {
871     window_type = tabs::Query::Params::QueryInfo::ToString(
872         params->query_info.window_type);
873   }
874
875   base::ListValue* result = new base::ListValue();
876   Browser* last_active_browser = chrome::FindAnyBrowser(
877       GetProfile(), include_incognito(), chrome::GetActiveDesktop());
878   Browser* current_browser = GetCurrentBrowser();
879   for (chrome::BrowserIterator it; !it.done(); it.Next()) {
880     Browser* browser = *it;
881     if (!GetProfile()->IsSameProfile(browser->profile()))
882       continue;
883
884     if (!browser->window())
885       continue;
886
887     if (!include_incognito() && GetProfile() != browser->profile())
888       continue;
889
890     if (window_id >= 0 && window_id != ExtensionTabUtil::GetWindowId(browser))
891       continue;
892
893     if (window_id == extension_misc::kCurrentWindowId &&
894         browser != current_browser) {
895       continue;
896     }
897
898     if (!MatchesBool(params->query_info.current_window.get(),
899                      browser == current_browser)) {
900       continue;
901     }
902
903     if (!MatchesBool(params->query_info.last_focused_window.get(),
904                      browser == last_active_browser)) {
905       continue;
906     }
907
908     if (!window_type.empty() &&
909         window_type !=
910             browser->extension_window_controller()->GetWindowTypeText()) {
911       continue;
912     }
913
914     TabStripModel* tab_strip = browser->tab_strip_model();
915     for (int i = 0; i < tab_strip->count(); ++i) {
916       const WebContents* web_contents = tab_strip->GetWebContentsAt(i);
917
918       if (index > -1 && i != index)
919         continue;
920
921       if (!MatchesBool(params->query_info.highlighted.get(),
922                        tab_strip->IsTabSelected(i))) {
923         continue;
924       }
925
926       if (!MatchesBool(params->query_info.active.get(),
927                        i == tab_strip->active_index())) {
928         continue;
929       }
930
931       if (!MatchesBool(params->query_info.pinned.get(),
932                        tab_strip->IsTabPinned(i))) {
933         continue;
934       }
935
936       if (!title.empty() && !MatchPattern(web_contents->GetTitle(),
937                                           UTF8ToUTF16(title)))
938         continue;
939
940       if (!url_pattern.MatchesURL(web_contents->GetURL()))
941         continue;
942
943       if (loading_status_set && loading != web_contents->IsLoading())
944         continue;
945
946       result->Append(ExtensionTabUtil::CreateTabValue(
947           web_contents, tab_strip, i, GetExtension()));
948     }
949   }
950
951   SetResult(result);
952   return true;
953 }
954
955 bool TabsCreateFunction::RunImpl() {
956   scoped_ptr<tabs::Create::Params> params(tabs::Create::Params::Create(*args_));
957   EXTENSION_FUNCTION_VALIDATE(params.get());
958
959   // windowId defaults to "current" window.
960   int window_id = extension_misc::kCurrentWindowId;
961   if (params->create_properties.window_id.get())
962     window_id = *params->create_properties.window_id;
963
964   Browser* browser = NULL;
965   if (!GetBrowserFromWindowID(this, window_id, &browser))
966     return false;
967
968   // Ensure the selected browser is tabbed.
969   if (!browser->is_type_tabbed() && browser->IsAttemptingToCloseBrowser())
970     browser = chrome::FindTabbedBrowser(
971         GetProfile(), include_incognito(), browser->host_desktop_type());
972
973   if (!browser || !browser->window())
974     return false;
975
976   // TODO(jstritar): Add a constant, chrome.tabs.TAB_ID_ACTIVE, that
977   // represents the active tab.
978   WebContents* opener = NULL;
979   if (params->create_properties.opener_tab_id.get()) {
980     int opener_id = *params->create_properties.opener_tab_id;
981
982     if (!ExtensionTabUtil::GetTabById(opener_id,
983                                       GetProfile(),
984                                       include_incognito(),
985                                       NULL,
986                                       NULL,
987                                       &opener,
988                                       NULL)) {
989       return false;
990     }
991   }
992
993   // TODO(rafaelw): handle setting remaining tab properties:
994   // -title
995   // -favIconUrl
996
997   std::string url_string;
998   GURL url;
999   if (params->create_properties.url.get()) {
1000     url_string = *params->create_properties.url;
1001     url = ExtensionTabUtil::ResolvePossiblyRelativeURL(url_string,
1002                                                        GetExtension());
1003     if (!url.is_valid()) {
1004       error_ = ErrorUtils::FormatErrorMessage(keys::kInvalidUrlError,
1005                                                        url_string);
1006       return false;
1007     }
1008   }
1009
1010   // Don't let extensions crash the browser or renderers.
1011   if (ExtensionTabUtil::IsCrashURL(url)) {
1012     error_ = keys::kNoCrashBrowserError;
1013     return false;
1014   }
1015
1016   // Default to foreground for the new tab. The presence of 'selected' property
1017   // will override this default. This property is deprecated ('active' should
1018   // be used instead).
1019   bool active = true;
1020   if (params->create_properties.selected.get())
1021     active = *params->create_properties.selected;
1022
1023   // The 'active' property has replaced the 'selected' property.
1024   if (params->create_properties.active.get())
1025     active = *params->create_properties.active;
1026
1027   // Default to not pinning the tab. Setting the 'pinned' property to true
1028   // will override this default.
1029   bool pinned = false;
1030   if (params->create_properties.pinned.get())
1031     pinned = *params->create_properties.pinned;
1032
1033   // We can't load extension URLs into incognito windows unless the extension
1034   // uses split mode. Special case to fall back to a tabbed window.
1035   if (url.SchemeIs(kExtensionScheme) &&
1036       !IncognitoInfo::IsSplitMode(GetExtension()) &&
1037       browser->profile()->IsOffTheRecord()) {
1038     Profile* profile = browser->profile()->GetOriginalProfile();
1039     chrome::HostDesktopType desktop_type = browser->host_desktop_type();
1040
1041     browser = chrome::FindTabbedBrowser(profile, false, desktop_type);
1042     if (!browser) {
1043       browser = new Browser(Browser::CreateParams(Browser::TYPE_TABBED,
1044                                                   profile, desktop_type));
1045       browser->window()->Show();
1046     }
1047   }
1048
1049   // If index is specified, honor the value, but keep it bound to
1050   // -1 <= index <= tab_strip->count() where -1 invokes the default behavior.
1051   int index = -1;
1052   if (params->create_properties.index.get())
1053     index = *params->create_properties.index;
1054
1055   TabStripModel* tab_strip = browser->tab_strip_model();
1056
1057   index = std::min(std::max(index, -1), tab_strip->count());
1058
1059   int add_types = active ? TabStripModel::ADD_ACTIVE :
1060                              TabStripModel::ADD_NONE;
1061   add_types |= TabStripModel::ADD_FORCE_INDEX;
1062   if (pinned)
1063     add_types |= TabStripModel::ADD_PINNED;
1064   chrome::NavigateParams navigate_params(
1065       browser, url, content::PAGE_TRANSITION_LINK);
1066   navigate_params.disposition =
1067       active ? NEW_FOREGROUND_TAB : NEW_BACKGROUND_TAB;
1068   navigate_params.tabstrip_index = index;
1069   navigate_params.tabstrip_add_types = add_types;
1070   chrome::Navigate(&navigate_params);
1071
1072   // The tab may have been created in a different window, so make sure we look
1073   // at the right tab strip.
1074   tab_strip = navigate_params.browser->tab_strip_model();
1075   int new_index = tab_strip->GetIndexOfWebContents(
1076       navigate_params.target_contents);
1077   if (opener)
1078     tab_strip->SetOpenerOfWebContentsAt(new_index, opener);
1079
1080   if (active)
1081     navigate_params.target_contents->GetView()->SetInitialFocus();
1082
1083   // Return data about the newly created tab.
1084   if (has_callback()) {
1085     SetResult(ExtensionTabUtil::CreateTabValue(
1086         navigate_params.target_contents,
1087         tab_strip, new_index, GetExtension()));
1088   }
1089
1090   return true;
1091 }
1092
1093 bool TabsDuplicateFunction::RunImpl() {
1094   scoped_ptr<tabs::Duplicate::Params> params(
1095       tabs::Duplicate::Params::Create(*args_));
1096   EXTENSION_FUNCTION_VALIDATE(params.get());
1097   int tab_id = params->tab_id;
1098
1099   Browser* browser = NULL;
1100   TabStripModel* tab_strip = NULL;
1101   int tab_index = -1;
1102   if (!GetTabById(tab_id,
1103                   GetProfile(),
1104                   include_incognito(),
1105                   &browser,
1106                   &tab_strip,
1107                   NULL,
1108                   &tab_index,
1109                   &error_)) {
1110     return false;
1111   }
1112
1113   WebContents* new_contents = chrome::DuplicateTabAt(browser, tab_index);
1114   if (!has_callback())
1115     return true;
1116
1117   // Duplicated tab may not be in the same window as the original, so find
1118   // the window and the tab.
1119   TabStripModel* new_tab_strip = NULL;
1120   int new_tab_index = -1;
1121   ExtensionTabUtil::GetTabStripModel(new_contents,
1122                                      &new_tab_strip,
1123                                      &new_tab_index);
1124   if (!new_tab_strip || new_tab_index == -1) {
1125     return false;
1126   }
1127
1128   // Return data about the newly created tab.
1129   SetResult(ExtensionTabUtil::CreateTabValue(
1130       new_contents,
1131       new_tab_strip, new_tab_index, GetExtension()));
1132
1133   return true;
1134 }
1135
1136 bool TabsGetFunction::RunImpl() {
1137   scoped_ptr<tabs::Get::Params> params(tabs::Get::Params::Create(*args_));
1138   EXTENSION_FUNCTION_VALIDATE(params.get());
1139   int tab_id = params->tab_id;
1140
1141   TabStripModel* tab_strip = NULL;
1142   WebContents* contents = NULL;
1143   int tab_index = -1;
1144   if (!GetTabById(tab_id,
1145                   GetProfile(),
1146                   include_incognito(),
1147                   NULL,
1148                   &tab_strip,
1149                   &contents,
1150                   &tab_index,
1151                   &error_))
1152     return false;
1153
1154   SetResult(ExtensionTabUtil::CreateTabValue(contents,
1155                                              tab_strip,
1156                                              tab_index,
1157                                              GetExtension()));
1158   return true;
1159 }
1160
1161 bool TabsGetCurrentFunction::RunImpl() {
1162   DCHECK(dispatcher());
1163
1164   WebContents* contents = dispatcher()->delegate()->GetAssociatedWebContents();
1165   if (contents)
1166     SetResult(ExtensionTabUtil::CreateTabValue(contents, GetExtension()));
1167
1168   return true;
1169 }
1170
1171 bool TabsHighlightFunction::RunImpl() {
1172   scoped_ptr<tabs::Highlight::Params> params(
1173       tabs::Highlight::Params::Create(*args_));
1174   EXTENSION_FUNCTION_VALIDATE(params.get());
1175
1176   // Get the window id from the params; default to current window if omitted.
1177   int window_id = extension_misc::kCurrentWindowId;
1178   if (params->highlight_info.window_id.get())
1179     window_id = *params->highlight_info.window_id;
1180
1181   Browser* browser = NULL;
1182   if (!GetBrowserFromWindowID(this, window_id, &browser))
1183     return false;
1184
1185   TabStripModel* tabstrip = browser->tab_strip_model();
1186   ui::ListSelectionModel selection;
1187   int active_index = -1;
1188
1189   if (params->highlight_info.tabs.as_integers) {
1190     std::vector<int>& tab_indices = *params->highlight_info.tabs.as_integers;
1191     // Create a new selection model as we read the list of tab indices.
1192     for (size_t i = 0; i < tab_indices.size(); ++i) {
1193       if (!HighlightTab(tabstrip, &selection, &active_index, tab_indices[i]))
1194         return false;
1195     }
1196   } else {
1197     EXTENSION_FUNCTION_VALIDATE(params->highlight_info.tabs.as_integer);
1198     if (!HighlightTab(tabstrip,
1199                       &selection,
1200                       &active_index,
1201                       *params->highlight_info.tabs.as_integer)) {
1202       return false;
1203     }
1204   }
1205
1206   // Make sure they actually specified tabs to select.
1207   if (selection.empty()) {
1208     error_ = keys::kNoHighlightedTabError;
1209     return false;
1210   }
1211
1212   selection.set_active(active_index);
1213   browser->tab_strip_model()->SetSelectionFromModel(selection);
1214   SetResult(
1215       browser->extension_window_controller()->CreateWindowValueWithTabs(
1216           GetExtension()));
1217   return true;
1218 }
1219
1220 bool TabsHighlightFunction::HighlightTab(TabStripModel* tabstrip,
1221                                          ui::ListSelectionModel* selection,
1222                                          int *active_index,
1223                                          int index) {
1224   // Make sure the index is in range.
1225   if (!tabstrip->ContainsIndex(index)) {
1226     error_ = ErrorUtils::FormatErrorMessage(
1227         keys::kTabIndexNotFoundError, base::IntToString(index));
1228     return false;
1229   }
1230
1231   // By default, we make the first tab in the list active.
1232   if (*active_index == -1)
1233     *active_index = index;
1234
1235   selection->AddIndexToSelection(index);
1236   return true;
1237 }
1238
1239 TabsUpdateFunction::TabsUpdateFunction() : web_contents_(NULL) {
1240 }
1241
1242 bool TabsUpdateFunction::RunImpl() {
1243   scoped_ptr<tabs::Update::Params> params(tabs::Update::Params::Create(*args_));
1244   EXTENSION_FUNCTION_VALIDATE(params.get());
1245
1246   int tab_id = -1;
1247   WebContents* contents = NULL;
1248   if (!params->tab_id.get()) {
1249     Browser* browser = GetCurrentBrowser();
1250     if (!browser) {
1251       error_ = keys::kNoCurrentWindowError;
1252       return false;
1253     }
1254     contents = browser->tab_strip_model()->GetActiveWebContents();
1255     if (!contents) {
1256       error_ = keys::kNoSelectedTabError;
1257       return false;
1258     }
1259     tab_id = SessionID::IdForTab(contents);
1260   } else {
1261     tab_id = *params->tab_id;
1262   }
1263
1264   int tab_index = -1;
1265   TabStripModel* tab_strip = NULL;
1266   if (!GetTabById(tab_id,
1267                   GetProfile(),
1268                   include_incognito(),
1269                   NULL,
1270                   &tab_strip,
1271                   &contents,
1272                   &tab_index,
1273                   &error_)) {
1274     return false;
1275   }
1276
1277   web_contents_ = contents;
1278
1279   // TODO(rafaelw): handle setting remaining tab properties:
1280   // -title
1281   // -favIconUrl
1282
1283   // Navigate the tab to a new location if the url is different.
1284   bool is_async = false;
1285   if (params->update_properties.url.get() &&
1286       !UpdateURL(*params->update_properties.url, tab_id, &is_async)) {
1287     return false;
1288   }
1289
1290   bool active = false;
1291   // TODO(rafaelw): Setting |active| from js doesn't make much sense.
1292   // Move tab selection management up to window.
1293   if (params->update_properties.selected.get())
1294     active = *params->update_properties.selected;
1295
1296   // The 'active' property has replaced 'selected'.
1297   if (params->update_properties.active.get())
1298     active = *params->update_properties.active;
1299
1300   if (active) {
1301     if (tab_strip->active_index() != tab_index) {
1302       tab_strip->ActivateTabAt(tab_index, false);
1303       DCHECK_EQ(contents, tab_strip->GetActiveWebContents());
1304     }
1305   }
1306
1307   if (params->update_properties.highlighted.get()) {
1308     bool highlighted = *params->update_properties.highlighted;
1309     if (highlighted != tab_strip->IsTabSelected(tab_index))
1310       tab_strip->ToggleSelectionAt(tab_index);
1311   }
1312
1313   if (params->update_properties.pinned.get()) {
1314     bool pinned = *params->update_properties.pinned;
1315     tab_strip->SetTabPinned(tab_index, pinned);
1316
1317     // Update the tab index because it may move when being pinned.
1318     tab_index = tab_strip->GetIndexOfWebContents(contents);
1319   }
1320
1321   if (params->update_properties.opener_tab_id.get()) {
1322     int opener_id = *params->update_properties.opener_tab_id;
1323
1324     WebContents* opener_contents = NULL;
1325     if (!ExtensionTabUtil::GetTabById(opener_id,
1326                                       GetProfile(),
1327                                       include_incognito(),
1328                                       NULL,
1329                                       NULL,
1330                                       &opener_contents,
1331                                       NULL))
1332       return false;
1333
1334     tab_strip->SetOpenerOfWebContentsAt(tab_index, opener_contents);
1335   }
1336
1337   if (!is_async) {
1338     PopulateResult();
1339     SendResponse(true);
1340   }
1341   return true;
1342 }
1343
1344 bool TabsUpdateFunction::UpdateURL(const std::string &url_string,
1345                                    int tab_id,
1346                                    bool* is_async) {
1347   GURL url = ExtensionTabUtil::ResolvePossiblyRelativeURL(
1348       url_string, GetExtension());
1349
1350   if (!url.is_valid()) {
1351     error_ = ErrorUtils::FormatErrorMessage(
1352         keys::kInvalidUrlError, url_string);
1353     return false;
1354   }
1355
1356   // Don't let the extension crash the browser or renderers.
1357   if (ExtensionTabUtil::IsCrashURL(url)) {
1358     error_ = keys::kNoCrashBrowserError;
1359     return false;
1360   }
1361
1362   // JavaScript URLs can do the same kinds of things as cross-origin XHR, so
1363   // we need to check host permissions before allowing them.
1364   if (url.SchemeIs(content::kJavaScriptScheme)) {
1365     content::RenderProcessHost* process = web_contents_->GetRenderProcessHost();
1366     if (!PermissionsData::CanExecuteScriptOnPage(
1367             GetExtension(),
1368             web_contents_->GetURL(),
1369             web_contents_->GetURL(),
1370             tab_id,
1371             NULL,
1372             process ? process->GetID() : -1,
1373             &error_)) {
1374       return false;
1375     }
1376
1377     TabHelper::FromWebContents(web_contents_)->
1378         script_executor()->ExecuteScript(
1379             extension_id(),
1380             ScriptExecutor::JAVASCRIPT,
1381             url.GetContent(),
1382             ScriptExecutor::TOP_FRAME,
1383             UserScript::DOCUMENT_IDLE,
1384             ScriptExecutor::MAIN_WORLD,
1385             ScriptExecutor::DEFAULT_PROCESS,
1386             GURL(),
1387             ScriptExecutor::NO_RESULT,
1388             base::Bind(&TabsUpdateFunction::OnExecuteCodeFinished, this));
1389
1390     *is_async = true;
1391     return true;
1392   }
1393
1394   web_contents_->GetController().LoadURL(
1395       url, content::Referrer(), content::PAGE_TRANSITION_LINK, std::string());
1396
1397   // The URL of a tab contents never actually changes to a JavaScript URL, so
1398   // this check only makes sense in other cases.
1399   if (!url.SchemeIs(content::kJavaScriptScheme))
1400     DCHECK_EQ(url.spec(), web_contents_->GetURL().spec());
1401
1402   return true;
1403 }
1404
1405 void TabsUpdateFunction::PopulateResult() {
1406   if (!has_callback())
1407     return;
1408
1409   SetResult(ExtensionTabUtil::CreateTabValue(web_contents_, GetExtension()));
1410 }
1411
1412 void TabsUpdateFunction::OnExecuteCodeFinished(
1413     const std::string& error,
1414     int32 on_page_id,
1415     const GURL& url,
1416     const base::ListValue& script_result) {
1417   if (error.empty())
1418     PopulateResult();
1419   else
1420     error_ = error;
1421   SendResponse(error.empty());
1422 }
1423
1424 bool TabsMoveFunction::RunImpl() {
1425   scoped_ptr<tabs::Move::Params> params(tabs::Move::Params::Create(*args_));
1426   EXTENSION_FUNCTION_VALIDATE(params.get());
1427
1428   int new_index = params->move_properties.index;
1429   int* window_id = params->move_properties.window_id.get();
1430   base::ListValue tab_values;
1431
1432   size_t num_tabs = 0;
1433   if (params->tab_ids.as_integers) {
1434     std::vector<int>& tab_ids = *params->tab_ids.as_integers;
1435     num_tabs = tab_ids.size();
1436     for (size_t i = 0; i < tab_ids.size(); ++i) {
1437       if (!MoveTab(tab_ids[i], &new_index, i, &tab_values, window_id))
1438         return false;
1439     }
1440   } else {
1441     EXTENSION_FUNCTION_VALIDATE(params->tab_ids.as_integer);
1442     num_tabs = 1;
1443     if (!MoveTab(*params->tab_ids.as_integer,
1444                  &new_index,
1445                  0,
1446                  &tab_values,
1447                  window_id)) {
1448       return false;
1449     }
1450   }
1451
1452   if (!has_callback())
1453     return true;
1454
1455   // Only return the results as an array if there are multiple tabs.
1456   if (num_tabs > 1) {
1457     SetResult(tab_values.DeepCopy());
1458   } else {
1459     Value* value = NULL;
1460     CHECK(tab_values.Get(0, &value));
1461     SetResult(value->DeepCopy());
1462   }
1463   return true;
1464 }
1465
1466 bool TabsMoveFunction::MoveTab(int tab_id,
1467                                int *new_index,
1468                                int iteration,
1469                                base::ListValue* tab_values,
1470                                int* window_id) {
1471   Browser* source_browser = NULL;
1472   TabStripModel* source_tab_strip = NULL;
1473   WebContents* contents = NULL;
1474   int tab_index = -1;
1475   if (!GetTabById(tab_id,
1476                   GetProfile(),
1477                   include_incognito(),
1478                   &source_browser,
1479                   &source_tab_strip,
1480                   &contents,
1481                   &tab_index,
1482                   &error_)) {
1483     return false;
1484   }
1485
1486   // Don't let the extension move the tab if the user is dragging tabs.
1487   if (!source_browser->window()->IsTabStripEditable()) {
1488     error_ = keys::kTabStripNotEditableError;
1489     return false;
1490   }
1491
1492   // Insert the tabs one after another.
1493   *new_index += iteration;
1494
1495   if (window_id) {
1496     Browser* target_browser = NULL;
1497
1498     if (!GetBrowserFromWindowID(this, *window_id, &target_browser))
1499       return false;
1500
1501     if (!target_browser->window()->IsTabStripEditable()) {
1502       error_ = keys::kTabStripNotEditableError;
1503       return false;
1504     }
1505
1506     if (!target_browser->is_type_tabbed()) {
1507       error_ = keys::kCanOnlyMoveTabsWithinNormalWindowsError;
1508       return false;
1509     }
1510
1511     if (target_browser->profile() != source_browser->profile()) {
1512       error_ = keys::kCanOnlyMoveTabsWithinSameProfileError;
1513       return false;
1514     }
1515
1516     // If windowId is different from the current window, move between windows.
1517     if (ExtensionTabUtil::GetWindowId(target_browser) !=
1518         ExtensionTabUtil::GetWindowId(source_browser)) {
1519       TabStripModel* target_tab_strip = target_browser->tab_strip_model();
1520       WebContents* web_contents =
1521           source_tab_strip->DetachWebContentsAt(tab_index);
1522       if (!web_contents) {
1523         error_ = ErrorUtils::FormatErrorMessage(
1524             keys::kTabNotFoundError, base::IntToString(tab_id));
1525         return false;
1526       }
1527
1528       // Clamp move location to the last position.
1529       // This is ">" because it can append to a new index position.
1530       // -1 means set the move location to the last position.
1531       if (*new_index > target_tab_strip->count() || *new_index < 0)
1532         *new_index = target_tab_strip->count();
1533
1534       target_tab_strip->InsertWebContentsAt(
1535           *new_index, web_contents, TabStripModel::ADD_NONE);
1536
1537       if (has_callback()) {
1538         tab_values->Append(ExtensionTabUtil::CreateTabValue(
1539             web_contents,
1540             target_tab_strip,
1541             *new_index,
1542             GetExtension()));
1543       }
1544
1545       return true;
1546     }
1547   }
1548
1549   // Perform a simple within-window move.
1550   // Clamp move location to the last position.
1551   // This is ">=" because the move must be to an existing location.
1552   // -1 means set the move location to the last position.
1553   if (*new_index >= source_tab_strip->count() || *new_index < 0)
1554     *new_index = source_tab_strip->count() - 1;
1555
1556   if (*new_index != tab_index)
1557     source_tab_strip->MoveWebContentsAt(tab_index, *new_index, false);
1558
1559   if (has_callback()) {
1560     tab_values->Append(ExtensionTabUtil::CreateTabValue(
1561         contents, source_tab_strip, *new_index, GetExtension()));
1562   }
1563
1564   return true;
1565 }
1566
1567 bool TabsReloadFunction::RunImpl() {
1568   scoped_ptr<tabs::Reload::Params> params(
1569       tabs::Reload::Params::Create(*args_));
1570   EXTENSION_FUNCTION_VALIDATE(params.get());
1571
1572   bool bypass_cache = false;
1573   if (params->reload_properties.get() &&
1574       params->reload_properties->bypass_cache.get()) {
1575     bypass_cache = *params->reload_properties->bypass_cache;
1576   }
1577
1578   content::WebContents* web_contents = NULL;
1579
1580   // If |tab_id| is specified, look for it. Otherwise default to selected tab
1581   // in the current window.
1582   if (!params->tab_id.get()) {
1583     Browser* browser = GetCurrentBrowser();
1584     if (!browser) {
1585       error_ = keys::kNoCurrentWindowError;
1586       return false;
1587     }
1588
1589     if (!ExtensionTabUtil::GetDefaultTab(browser, &web_contents, NULL))
1590       return false;
1591   } else {
1592     int tab_id = *params->tab_id;
1593
1594     Browser* browser = NULL;
1595     if (!GetTabById(tab_id,
1596                     GetProfile(),
1597                     include_incognito(),
1598                     &browser,
1599                     NULL,
1600                     &web_contents,
1601                     NULL,
1602                     &error_))
1603     return false;
1604   }
1605
1606   if (web_contents->ShowingInterstitialPage()) {
1607     // This does as same as Browser::ReloadInternal.
1608     NavigationEntry* entry = web_contents->GetController().GetVisibleEntry();
1609     OpenURLParams params(entry->GetURL(), Referrer(), CURRENT_TAB,
1610                          content::PAGE_TRANSITION_RELOAD, false);
1611     GetCurrentBrowser()->OpenURL(params);
1612   } else if (bypass_cache) {
1613     web_contents->GetController().ReloadIgnoringCache(true);
1614   } else {
1615     web_contents->GetController().Reload(true);
1616   }
1617
1618   return true;
1619 }
1620
1621 bool TabsRemoveFunction::RunImpl() {
1622   scoped_ptr<tabs::Remove::Params> params(tabs::Remove::Params::Create(*args_));
1623   EXTENSION_FUNCTION_VALIDATE(params.get());
1624
1625   if (params->tab_ids.as_integers) {
1626     std::vector<int>& tab_ids = *params->tab_ids.as_integers;
1627     for (size_t i = 0; i < tab_ids.size(); ++i) {
1628       if (!RemoveTab(tab_ids[i]))
1629         return false;
1630     }
1631   } else {
1632     EXTENSION_FUNCTION_VALIDATE(params->tab_ids.as_integer);
1633     if (!RemoveTab(*params->tab_ids.as_integer.get()))
1634       return false;
1635   }
1636   return true;
1637 }
1638
1639 bool TabsRemoveFunction::RemoveTab(int tab_id) {
1640   Browser* browser = NULL;
1641   WebContents* contents = NULL;
1642   if (!GetTabById(tab_id,
1643                   GetProfile(),
1644                   include_incognito(),
1645                   &browser,
1646                   NULL,
1647                   &contents,
1648                   NULL,
1649                   &error_)) {
1650     return false;
1651   }
1652
1653   // Don't let the extension remove a tab if the user is dragging tabs around.
1654   if (!browser->window()->IsTabStripEditable()) {
1655     error_ = keys::kTabStripNotEditableError;
1656     return false;
1657   }
1658   // There's a chance that the tab is being dragged, or we're in some other
1659   // nested event loop. This code path ensures that the tab is safely closed
1660   // under such circumstances, whereas |TabStripModel::CloseWebContentsAt()|
1661   // does not.
1662   contents->Close();
1663   return true;
1664 }
1665
1666 bool TabsCaptureVisibleTabFunction::GetTabToCapture(
1667     WebContents** web_contents) {
1668   scoped_ptr<tabs::CaptureVisibleTab::Params> params(
1669       tabs::CaptureVisibleTab::Params::Create(*args_));
1670   EXTENSION_FUNCTION_VALIDATE(params.get());
1671
1672   Browser* browser = NULL;
1673   // windowId defaults to "current" window.
1674   int window_id = extension_misc::kCurrentWindowId;
1675
1676   if (params->window_id.get())
1677     window_id = *params->window_id;
1678
1679   if (!GetBrowserFromWindowID(this, window_id, &browser))
1680     return false;
1681
1682   *web_contents = browser->tab_strip_model()->GetActiveWebContents();
1683   if (*web_contents == NULL) {
1684     error_ = keys::kInternalVisibleTabCaptureError;
1685     return false;
1686   }
1687
1688   return true;
1689 };
1690
1691 bool TabsCaptureVisibleTabFunction::RunImpl() {
1692   scoped_ptr<tabs::CaptureVisibleTab::Params> params(
1693       tabs::CaptureVisibleTab::Params::Create(*args_));
1694   EXTENSION_FUNCTION_VALIDATE(params.get());
1695
1696   PrefService* service = GetProfile()->GetPrefs();
1697   if (service->GetBoolean(prefs::kDisableScreenshots)) {
1698     error_ = keys::kScreenshotsDisabled;
1699     return false;
1700   }
1701
1702   WebContents* web_contents = NULL;
1703   if (!GetTabToCapture(&web_contents))
1704     return false;
1705
1706   image_format_ = FormatEnum::FORMAT_JPEG;  // Default format is JPEG.
1707   image_quality_ = kDefaultQuality;  // Default quality setting.
1708
1709   if (params->options.get()) {
1710     if (params->options->format != FormatEnum::FORMAT_NONE)
1711       image_format_ = params->options->format;
1712
1713     if (params->options->quality.get())
1714       image_quality_ = *params->options->quality;
1715   }
1716
1717   // Use the last committed URL rather than the active URL for permissions
1718   // checking, since the visible page won't be updated until it has been
1719   // committed. A canonical example of this is interstitials, which show the
1720   // URL of the new/loading page (active) but would capture the content of the
1721   // old page (last committed).
1722   //
1723   // TODO(creis): Use WebContents::GetLastCommittedURL instead.
1724   // http://crbug.com/237908.
1725   NavigationEntry* last_committed_entry =
1726       web_contents->GetController().GetLastCommittedEntry();
1727   GURL last_committed_url = last_committed_entry ?
1728       last_committed_entry->GetURL() : GURL();
1729   if (!PermissionsData::CanCaptureVisiblePage(
1730           GetExtension(),
1731           last_committed_url,
1732           SessionID::IdForTab(web_contents),
1733           &error_)) {
1734     return false;
1735   }
1736
1737   RenderViewHost* render_view_host = web_contents->GetRenderViewHost();
1738   content::RenderWidgetHostView* view = render_view_host->GetView();
1739   if (!view) {
1740     error_ = keys::kInternalVisibleTabCaptureError;
1741     return false;
1742   }
1743   render_view_host->CopyFromBackingStore(
1744       gfx::Rect(),
1745       view->GetViewBounds().size(),
1746       base::Bind(&TabsCaptureVisibleTabFunction::CopyFromBackingStoreComplete,
1747                  this));
1748   return true;
1749 }
1750
1751 void TabsCaptureVisibleTabFunction::CopyFromBackingStoreComplete(
1752     bool succeeded,
1753     const SkBitmap& bitmap) {
1754   if (succeeded) {
1755     VLOG(1) << "captureVisibleTab() got image from backing store.";
1756     SendResultFromBitmap(bitmap);
1757     return;
1758   }
1759
1760   WebContents* web_contents = NULL;
1761   if (!GetTabToCapture(&web_contents)) {
1762     SendInternalError();
1763     return;
1764   }
1765
1766   // Ask the renderer for a snapshot of the tab.
1767   content::RenderWidgetHost* render_widget_host =
1768       web_contents->GetRenderViewHost();
1769   if (!render_widget_host) {
1770     SendInternalError();
1771     return;
1772   }
1773
1774   render_widget_host->GetSnapshotFromRenderer(
1775       gfx::Rect(),
1776       base::Bind(
1777           &TabsCaptureVisibleTabFunction::GetSnapshotFromRendererComplete,
1778           this));
1779 }
1780
1781 // If a backing store was not available in
1782 // TabsCaptureVisibleTabFunction::RunImpl, than the renderer was asked for a
1783 // snapshot.
1784 void TabsCaptureVisibleTabFunction::GetSnapshotFromRendererComplete(
1785     bool succeeded,
1786     const SkBitmap& bitmap) {
1787   if (!succeeded) {
1788     SendInternalError();
1789   } else {
1790     VLOG(1) << "captureVisibleTab() got image from renderer.";
1791     SendResultFromBitmap(bitmap);
1792   }
1793 }
1794
1795 void TabsCaptureVisibleTabFunction::SendInternalError() {
1796   error_ = keys::kInternalVisibleTabCaptureError;
1797   SendResponse(false);
1798 }
1799
1800 // Turn a bitmap of the screen into an image, set that image as the result,
1801 // and call SendResponse().
1802 void TabsCaptureVisibleTabFunction::SendResultFromBitmap(
1803     const SkBitmap& screen_capture) {
1804   std::vector<unsigned char> data;
1805   SkAutoLockPixels screen_capture_lock(screen_capture);
1806   bool encoded = false;
1807   std::string mime_type;
1808   switch (image_format_) {
1809     case FormatEnum::FORMAT_JPEG:
1810       encoded = gfx::JPEGCodec::Encode(
1811           reinterpret_cast<unsigned char*>(screen_capture.getAddr32(0, 0)),
1812           gfx::JPEGCodec::FORMAT_SkBitmap,
1813           screen_capture.width(),
1814           screen_capture.height(),
1815           static_cast<int>(screen_capture.rowBytes()),
1816           image_quality_,
1817           &data);
1818       mime_type = keys::kMimeTypeJpeg;
1819       break;
1820     case FormatEnum::FORMAT_PNG:
1821       encoded = gfx::PNGCodec::EncodeBGRASkBitmap(
1822           screen_capture,
1823           true,  // Discard transparency.
1824           &data);
1825       mime_type = keys::kMimeTypePng;
1826       break;
1827     default:
1828       NOTREACHED() << "Invalid image format.";
1829   }
1830
1831   if (!encoded) {
1832     error_ = keys::kInternalVisibleTabCaptureError;
1833     SendResponse(false);
1834     return;
1835   }
1836
1837   std::string base64_result;
1838   base::StringPiece stream_as_string(
1839       reinterpret_cast<const char*>(vector_as_array(&data)), data.size());
1840
1841   base::Base64Encode(stream_as_string, &base64_result);
1842   base64_result.insert(0, base::StringPrintf("data:%s;base64,",
1843                                              mime_type.c_str()));
1844   SetResult(new StringValue(base64_result));
1845   SendResponse(true);
1846 }
1847
1848 void TabsCaptureVisibleTabFunction::RegisterProfilePrefs(
1849     user_prefs::PrefRegistrySyncable* registry) {
1850   registry->RegisterBooleanPref(
1851       prefs::kDisableScreenshots,
1852       false,
1853       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
1854 }
1855
1856 bool TabsDetectLanguageFunction::RunImpl() {
1857   scoped_ptr<tabs::DetectLanguage::Params> params(
1858       tabs::DetectLanguage::Params::Create(*args_));
1859   EXTENSION_FUNCTION_VALIDATE(params.get());
1860
1861   int tab_id = 0;
1862   Browser* browser = NULL;
1863   WebContents* contents = NULL;
1864
1865   // If |tab_id| is specified, look for it. Otherwise default to selected tab
1866   // in the current window.
1867   if (params->tab_id.get()) {
1868     tab_id = *params->tab_id;
1869     if (!GetTabById(tab_id,
1870                     GetProfile(),
1871                     include_incognito(),
1872                     &browser,
1873                     NULL,
1874                     &contents,
1875                     NULL,
1876                     &error_)) {
1877       return false;
1878     }
1879     if (!browser || !contents)
1880       return false;
1881   } else {
1882     browser = GetCurrentBrowser();
1883     if (!browser)
1884       return false;
1885     contents = browser->tab_strip_model()->GetActiveWebContents();
1886     if (!contents)
1887       return false;
1888   }
1889
1890   if (contents->GetController().NeedsReload()) {
1891     // If the tab hasn't been loaded, don't wait for the tab to load.
1892     error_ = keys::kCannotDetermineLanguageOfUnloadedTab;
1893     return false;
1894   }
1895
1896   AddRef();  // Balanced in GotLanguage().
1897
1898   TranslateTabHelper* translate_tab_helper =
1899       TranslateTabHelper::FromWebContents(contents);
1900   if (!translate_tab_helper->language_state().original_language().empty()) {
1901     // Delay the callback invocation until after the current JS call has
1902     // returned.
1903     base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
1904         &TabsDetectLanguageFunction::GotLanguage, this,
1905         translate_tab_helper->language_state().original_language()));
1906     return true;
1907   }
1908   // The tab contents does not know its language yet.  Let's wait until it
1909   // receives it, or until the tab is closed/navigates to some other page.
1910   registrar_.Add(this, chrome::NOTIFICATION_TAB_LANGUAGE_DETERMINED,
1911                  content::Source<WebContents>(contents));
1912   registrar_.Add(
1913       this, chrome::NOTIFICATION_TAB_CLOSING,
1914       content::Source<NavigationController>(&(contents->GetController())));
1915   registrar_.Add(
1916       this, content::NOTIFICATION_NAV_ENTRY_COMMITTED,
1917       content::Source<NavigationController>(&(contents->GetController())));
1918   return true;
1919 }
1920
1921 void TabsDetectLanguageFunction::Observe(
1922     int type,
1923     const content::NotificationSource& source,
1924     const content::NotificationDetails& details) {
1925   std::string language;
1926   if (type == chrome::NOTIFICATION_TAB_LANGUAGE_DETERMINED) {
1927     const LanguageDetectionDetails* lang_det_details =
1928         content::Details<const LanguageDetectionDetails>(details).ptr();
1929     language = lang_det_details->adopted_language;
1930   }
1931
1932   registrar_.RemoveAll();
1933
1934   // Call GotLanguage in all cases as we want to guarantee the callback is
1935   // called for every API call the extension made.
1936   GotLanguage(language);
1937 }
1938
1939 void TabsDetectLanguageFunction::GotLanguage(const std::string& language) {
1940   SetResult(new base::StringValue(language.c_str()));
1941   SendResponse(true);
1942
1943   Release();  // Balanced in Run()
1944 }
1945
1946 ExecuteCodeInTabFunction::ExecuteCodeInTabFunction()
1947     : execute_tab_id_(-1) {
1948 }
1949
1950 ExecuteCodeInTabFunction::~ExecuteCodeInTabFunction() {}
1951
1952 bool ExecuteCodeInTabFunction::HasPermission() {
1953   if (Init() && PermissionsData::HasAPIPermissionForTab(
1954                     extension_.get(), execute_tab_id_, APIPermission::kTab)) {
1955     return true;
1956   }
1957   return ExtensionFunction::HasPermission();
1958 }
1959
1960 bool ExecuteCodeInTabFunction::CanExecuteScriptOnPage() {
1961   content::WebContents* contents = NULL;
1962
1963   // If |tab_id| is specified, look for the tab. Otherwise default to selected
1964   // tab in the current window.
1965   CHECK_GE(execute_tab_id_, 0);
1966   if (!GetTabById(execute_tab_id_,
1967                   GetProfile(),
1968                   include_incognito(),
1969                   NULL,
1970                   NULL,
1971                   &contents,
1972                   NULL,
1973                   &error_)) {
1974     return false;
1975   }
1976
1977   CHECK(contents);
1978
1979   // NOTE: This can give the wrong answer due to race conditions, but it is OK,
1980   // we check again in the renderer.
1981   content::RenderProcessHost* process = contents->GetRenderProcessHost();
1982   if (!PermissionsData::CanExecuteScriptOnPage(
1983           GetExtension(),
1984           contents->GetURL(),
1985           contents->GetURL(),
1986           execute_tab_id_,
1987           NULL,
1988           process ? process->GetID() : -1,
1989           &error_)) {
1990     return false;
1991   }
1992
1993   return true;
1994 }
1995
1996 ScriptExecutor* ExecuteCodeInTabFunction::GetScriptExecutor() {
1997   Browser* browser = NULL;
1998   content::WebContents* contents = NULL;
1999
2000   bool success = GetTabById(execute_tab_id_,
2001                             GetProfile(),
2002                             include_incognito(),
2003                             &browser,
2004                             NULL,
2005                             &contents,
2006                             NULL,
2007                             &error_) &&
2008                  contents && browser;
2009
2010   if (!success)
2011     return NULL;
2012
2013   return TabHelper::FromWebContents(contents)->script_executor();
2014 }
2015
2016 bool ExecuteCodeInTabFunction::IsWebView() const {
2017   return false;
2018 }
2019
2020 bool TabsExecuteScriptFunction::ShouldInsertCSS() const {
2021   return false;
2022 }
2023
2024 void TabsExecuteScriptFunction::OnExecuteCodeFinished(
2025     const std::string& error,
2026     int32 on_page_id,
2027     const GURL& on_url,
2028     const base::ListValue& result) {
2029   if (error.empty())
2030     SetResult(result.DeepCopy());
2031   ExecuteCodeInTabFunction::OnExecuteCodeFinished(error, on_page_id, on_url,
2032                                                   result);
2033 }
2034
2035 bool ExecuteCodeInTabFunction::Init() {
2036   if (details_.get())
2037     return true;
2038
2039   // |tab_id| is optional so it's ok if it's not there.
2040   int tab_id = -1;
2041   if (args_->GetInteger(0, &tab_id))
2042     EXTENSION_FUNCTION_VALIDATE(tab_id >= 0);
2043
2044   // |details| are not optional.
2045   base::DictionaryValue* details_value = NULL;
2046   if (!args_->GetDictionary(1, &details_value))
2047     return false;
2048   scoped_ptr<InjectDetails> details(new InjectDetails());
2049   if (!InjectDetails::Populate(*details_value, details.get()))
2050     return false;
2051
2052   // If the tab ID wasn't given then it needs to be converted to the
2053   // currently active tab's ID.
2054   if (tab_id == -1) {
2055     Browser* browser = GetCurrentBrowser();
2056     if (!browser)
2057       return false;
2058     content::WebContents* web_contents = NULL;
2059     if (!ExtensionTabUtil::GetDefaultTab(browser, &web_contents, &tab_id))
2060       return false;
2061   }
2062
2063   execute_tab_id_ = tab_id;
2064   details_ = details.Pass();
2065   return true;
2066 }
2067
2068 bool TabsInsertCSSFunction::ShouldInsertCSS() const {
2069   return true;
2070 }
2071
2072 }  // namespace extensions