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.
5 #include "chrome/browser/extensions/api/tabs/tabs_api.h"
11 #include "apps/app_window.h"
12 #include "base/bind.h"
13 #include "base/command_line.h"
14 #include "base/logging.h"
15 #include "base/memory/ref_counted_memory.h"
16 #include "base/message_loop/message_loop.h"
17 #include "base/prefs/pref_service.h"
18 #include "base/stl_util.h"
19 #include "base/strings/string16.h"
20 #include "base/strings/string_number_conversions.h"
21 #include "base/strings/string_util.h"
22 #include "base/strings/utf_string_conversions.h"
23 #include "chrome/browser/chrome_notification_types.h"
24 #include "chrome/browser/extensions/api/tabs/tabs_constants.h"
25 #include "chrome/browser/extensions/api/tabs/windows_util.h"
26 #include "chrome/browser/extensions/extension_service.h"
27 #include "chrome/browser/extensions/extension_tab_util.h"
28 #include "chrome/browser/extensions/script_executor.h"
29 #include "chrome/browser/extensions/tab_helper.h"
30 #include "chrome/browser/extensions/window_controller.h"
31 #include "chrome/browser/extensions/window_controller_list.h"
32 #include "chrome/browser/prefs/incognito_mode_prefs.h"
33 #include "chrome/browser/profiles/profile.h"
34 #include "chrome/browser/translate/translate_tab_helper.h"
35 #include "chrome/browser/ui/apps/chrome_app_window_delegate.h"
36 #include "chrome/browser/ui/browser.h"
37 #include "chrome/browser/ui/browser_commands.h"
38 #include "chrome/browser/ui/browser_finder.h"
39 #include "chrome/browser/ui/browser_iterator.h"
40 #include "chrome/browser/ui/browser_navigator.h"
41 #include "chrome/browser/ui/browser_tabstrip.h"
42 #include "chrome/browser/ui/browser_window.h"
43 #include "chrome/browser/ui/host_desktop.h"
44 #include "chrome/browser/ui/panels/panel_manager.h"
45 #include "chrome/browser/ui/tabs/tab_strip_model.h"
46 #include "chrome/browser/ui/window_sizer/window_sizer.h"
47 #include "chrome/browser/web_applications/web_app.h"
48 #include "chrome/common/chrome_switches.h"
49 #include "chrome/common/extensions/api/i18n/default_locale_handler.h"
50 #include "chrome/common/extensions/api/tabs.h"
51 #include "chrome/common/extensions/api/windows.h"
52 #include "chrome/common/extensions/extension_constants.h"
53 #include "chrome/common/pref_names.h"
54 #include "chrome/common/url_constants.h"
55 #include "components/translate/core/common/language_detection_details.h"
56 #include "components/user_prefs/pref_registry_syncable.h"
57 #include "content/public/browser/navigation_controller.h"
58 #include "content/public/browser/navigation_entry.h"
59 #include "content/public/browser/notification_details.h"
60 #include "content/public/browser/notification_source.h"
61 #include "content/public/browser/render_process_host.h"
62 #include "content/public/browser/render_view_host.h"
63 #include "content/public/browser/render_widget_host_view.h"
64 #include "content/public/browser/web_contents.h"
65 #include "content/public/common/url_constants.h"
66 #include "extensions/browser/extension_function_dispatcher.h"
67 #include "extensions/browser/extension_function_util.h"
68 #include "extensions/browser/extension_host.h"
69 #include "extensions/browser/file_reader.h"
70 #include "extensions/common/error_utils.h"
71 #include "extensions/common/extension.h"
72 #include "extensions/common/extension_l10n_util.h"
73 #include "extensions/common/extension_messages.h"
74 #include "extensions/common/manifest_constants.h"
75 #include "extensions/common/message_bundle.h"
76 #include "extensions/common/permissions/permissions_data.h"
77 #include "extensions/common/user_script.h"
78 #include "skia/ext/image_operations.h"
79 #include "skia/ext/platform_canvas.h"
80 #include "third_party/skia/include/core/SkBitmap.h"
81 #include "ui/base/models/list_selection_model.h"
82 #include "ui/base/ui_base_types.h"
85 #include "apps/app_window_registry.h"
86 #include "ash/ash_switches.h"
87 #include "chrome/browser/extensions/api/tabs/ash_panel_contents.h"
90 using apps::AppWindow;
91 using content::BrowserThread;
92 using content::NavigationController;
93 using content::NavigationEntry;
94 using content::OpenURLParams;
95 using content::Referrer;
96 using content::WebContents;
98 namespace extensions {
100 namespace windows = api::windows;
101 namespace keys = tabs_constants;
102 namespace tabs = api::tabs;
104 using api::tabs::InjectDetails;
108 bool GetBrowserFromWindowID(ChromeUIThreadExtensionFunction* function,
114 ExtensionTabUtil::GetBrowserFromWindowID(function, window_id, &error);
116 function->SetError(error);
124 // |error_message| can optionally be passed in and will be set with an
125 // appropriate message if the tab cannot be found by id.
126 bool GetTabById(int tab_id,
128 bool include_incognito,
130 TabStripModel** tab_strip,
131 content::WebContents** contents,
133 std::string* error_message) {
134 if (ExtensionTabUtil::GetTabById(tab_id, profile, include_incognito,
135 browser, tab_strip, contents, tab_index))
139 *error_message = ErrorUtils::FormatErrorMessage(
140 keys::kTabNotFoundError, base::IntToString(tab_id));
145 // Returns true if either |boolean| is a null pointer, or if |*boolean| and
146 // |value| are equal. This function is used to check if a tab's parameters match
147 // those of the browser.
148 bool MatchesBool(bool* boolean, bool value) {
149 return !boolean || *boolean == value;
152 template <typename T>
153 void AssignOptionalValue(const scoped_ptr<T>& source,
154 scoped_ptr<T>& destination) {
156 destination.reset(new T(*source.get()));
162 // Windows ---------------------------------------------------------------------
164 bool WindowsGetFunction::RunSync() {
165 scoped_ptr<windows::Get::Params> params(windows::Get::Params::Create(*args_));
166 EXTENSION_FUNCTION_VALIDATE(params.get());
168 bool populate_tabs = false;
169 if (params->get_info.get() && params->get_info->populate.get())
170 populate_tabs = *params->get_info->populate;
172 WindowController* controller;
173 if (!windows_util::GetWindowFromWindowID(this,
180 SetResult(controller->CreateWindowValueWithTabs(GetExtension()));
182 SetResult(controller->CreateWindowValue());
186 bool WindowsGetCurrentFunction::RunSync() {
187 scoped_ptr<windows::GetCurrent::Params> params(
188 windows::GetCurrent::Params::Create(*args_));
189 EXTENSION_FUNCTION_VALIDATE(params.get());
191 bool populate_tabs = false;
192 if (params->get_info.get() && params->get_info->populate.get())
193 populate_tabs = *params->get_info->populate;
195 WindowController* controller;
196 if (!windows_util::GetWindowFromWindowID(this,
197 extension_misc::kCurrentWindowId,
202 SetResult(controller->CreateWindowValueWithTabs(GetExtension()));
204 SetResult(controller->CreateWindowValue());
208 bool WindowsGetLastFocusedFunction::RunSync() {
209 scoped_ptr<windows::GetLastFocused::Params> params(
210 windows::GetLastFocused::Params::Create(*args_));
211 EXTENSION_FUNCTION_VALIDATE(params.get());
213 bool populate_tabs = false;
214 if (params->get_info.get() && params->get_info->populate.get())
215 populate_tabs = *params->get_info->populate;
217 // Note: currently this returns the last active browser. If we decide to
218 // include other window types (e.g. panels), we will need to add logic to
219 // WindowControllerList that mirrors the active behavior of BrowserList.
220 Browser* browser = chrome::FindAnyBrowser(
221 GetProfile(), include_incognito(), chrome::GetActiveDesktop());
222 if (!browser || !browser->window()) {
223 error_ = keys::kNoLastFocusedWindowError;
226 WindowController* controller =
227 browser->extension_window_controller();
229 SetResult(controller->CreateWindowValueWithTabs(GetExtension()));
231 SetResult(controller->CreateWindowValue());
235 bool WindowsGetAllFunction::RunSync() {
236 scoped_ptr<windows::GetAll::Params> params(
237 windows::GetAll::Params::Create(*args_));
238 EXTENSION_FUNCTION_VALIDATE(params.get());
240 bool populate_tabs = false;
241 if (params->get_info.get() && params->get_info->populate.get())
242 populate_tabs = *params->get_info->populate;
244 base::ListValue* window_list = new base::ListValue();
245 const WindowControllerList::ControllerList& windows =
246 WindowControllerList::GetInstance()->windows();
247 for (WindowControllerList::ControllerList::const_iterator iter =
249 iter != windows.end(); ++iter) {
250 if (!this->CanOperateOnWindow(*iter))
253 window_list->Append((*iter)->CreateWindowValueWithTabs(GetExtension()));
255 window_list->Append((*iter)->CreateWindowValue());
257 SetResult(window_list);
261 bool WindowsCreateFunction::ShouldOpenIncognitoWindow(
262 const windows::Create::Params::CreateData* create_data,
263 std::vector<GURL>* urls, bool* is_error) {
265 const IncognitoModePrefs::Availability incognito_availability =
266 IncognitoModePrefs::GetAvailability(GetProfile()->GetPrefs());
267 bool incognito = false;
268 if (create_data && create_data->incognito) {
269 incognito = *create_data->incognito;
270 if (incognito && incognito_availability == IncognitoModePrefs::DISABLED) {
271 error_ = keys::kIncognitoModeIsDisabled;
275 if (!incognito && incognito_availability == IncognitoModePrefs::FORCED) {
276 error_ = keys::kIncognitoModeIsForced;
280 } else if (incognito_availability == IncognitoModePrefs::FORCED) {
281 // If incognito argument is not specified explicitly, we default to
282 // incognito when forced so by policy.
286 // Remove all URLs that are not allowed in an incognito session. Note that a
287 // ChromeOS guest session is not considered incognito in this case.
288 if (incognito && !GetProfile()->IsGuestSession()) {
289 std::string first_url_erased;
290 for (size_t i = 0; i < urls->size();) {
291 if (chrome::IsURLAllowedInIncognito((*urls)[i], GetProfile())) {
294 if (first_url_erased.empty())
295 first_url_erased = (*urls)[i].spec();
296 urls->erase(urls->begin() + i);
299 if (urls->empty() && !first_url_erased.empty()) {
300 error_ = ErrorUtils::FormatErrorMessage(
301 keys::kURLsNotAllowedInIncognitoError, first_url_erased);
309 bool WindowsCreateFunction::RunSync() {
310 scoped_ptr<windows::Create::Params> params(
311 windows::Create::Params::Create(*args_));
312 EXTENSION_FUNCTION_VALIDATE(params);
313 std::vector<GURL> urls;
314 TabStripModel* source_tab_strip = NULL;
317 windows::Create::Params::CreateData* create_data = params->create_data.get();
319 // Look for optional url.
320 if (create_data && create_data->url) {
321 std::vector<std::string> url_strings;
322 // First, get all the URLs the client wants to open.
323 if (create_data->url->as_string)
324 url_strings.push_back(*create_data->url->as_string);
325 else if (create_data->url->as_strings)
326 url_strings.swap(*create_data->url->as_strings);
328 // Second, resolve, validate and convert them to GURLs.
329 for (std::vector<std::string>::iterator i = url_strings.begin();
330 i != url_strings.end(); ++i) {
331 GURL url = ExtensionTabUtil::ResolvePossiblyRelativeURL(
333 if (!url.is_valid()) {
334 error_ = ErrorUtils::FormatErrorMessage(keys::kInvalidUrlError, *i);
337 // Don't let the extension crash the browser or renderers.
338 if (ExtensionTabUtil::IsCrashURL(url)) {
339 error_ = keys::kNoCrashBrowserError;
346 // Look for optional tab id.
347 if (create_data && create_data->tab_id) {
348 // Find the tab. |source_tab_strip| and |tab_index| will later be used to
349 // move the tab into the created window.
350 if (!GetTabById(*create_data->tab_id,
361 Profile* window_profile = GetProfile();
362 Browser::Type window_type = Browser::TYPE_TABBED;
363 bool create_panel = false;
365 // panel_create_mode only applies if create_panel = true
366 PanelManager::CreateMode panel_create_mode = PanelManager::CREATE_AS_DOCKED;
368 gfx::Rect window_bounds;
370 bool saw_focus_key = false;
371 std::string extension_id;
373 // Decide whether we are opening a normal window or an incognito window.
374 bool is_error = true;
375 bool open_incognito_window = ShouldOpenIncognitoWindow(create_data, &urls,
378 // error_ member variable is set inside of ShouldOpenIncognitoWindow.
381 if (open_incognito_window) {
382 window_profile = window_profile->GetOffTheRecordProfile();
386 // Figure out window type before figuring out bounds so that default
387 // bounds can be set according to the window type.
388 switch (create_data->type) {
389 case windows::Create::Params::CreateData::TYPE_POPUP:
390 window_type = Browser::TYPE_POPUP;
391 extension_id = GetExtension()->id();
393 case windows::Create::Params::CreateData::TYPE_PANEL:
394 case windows::Create::Params::CreateData::TYPE_DETACHED_PANEL: {
395 extension_id = GetExtension()->id();
396 bool use_panels = false;
397 #if !defined(OS_ANDROID)
398 use_panels = PanelManager::ShouldUsePanels(extension_id);
402 // Non-ash supports both docked and detached panel types.
403 if (chrome::GetActiveDesktop() != chrome::HOST_DESKTOP_TYPE_ASH &&
405 windows::Create::Params::CreateData::TYPE_DETACHED_PANEL) {
406 panel_create_mode = PanelManager::CREATE_AS_DETACHED;
409 window_type = Browser::TYPE_POPUP;
413 case windows::Create::Params::CreateData::TYPE_NONE:
414 case windows::Create::Params::CreateData::TYPE_NORMAL:
417 error_ = keys::kInvalidWindowTypeError;
421 // Initialize default window bounds according to window type.
422 if (window_type == Browser::TYPE_TABBED ||
423 window_type == Browser::TYPE_POPUP ||
425 // Try to position the new browser relative to its originating
426 // browser window. The call offsets the bounds by kWindowTilePixels
427 // (defined in WindowSizer to be 10).
429 // NOTE(rafaelw): It's ok if GetCurrentBrowser() returns NULL here.
430 // GetBrowserWindowBounds will default to saved "default" values for
432 ui::WindowShowState show_state = ui::SHOW_STATE_DEFAULT;
433 WindowSizer::GetBrowserWindowBoundsAndShowState(std::string(),
440 if (create_panel && PanelManager::CREATE_AS_DETACHED == panel_create_mode) {
441 window_bounds.set_origin(
442 PanelManager::GetInstance()->GetDefaultDetachedPanelOrigin());
445 // Any part of the bounds can optionally be set by the caller.
446 if (create_data->left)
447 window_bounds.set_x(*create_data->left);
449 if (create_data->top)
450 window_bounds.set_y(*create_data->top);
452 if (create_data->width)
453 window_bounds.set_width(*create_data->width);
455 if (create_data->height)
456 window_bounds.set_height(*create_data->height);
458 if (create_data->focused) {
459 focused = *create_data->focused;
460 saw_focus_key = true;
466 urls.push_back(GURL(chrome::kChromeUINewTabURL));
469 if (chrome::GetActiveDesktop() == chrome::HOST_DESKTOP_TYPE_ASH) {
470 AppWindow::CreateParams create_params;
471 create_params.window_type = AppWindow::WINDOW_TYPE_V1_PANEL;
472 create_params.window_spec.bounds = window_bounds;
473 create_params.focused = saw_focus_key && focused;
474 AppWindow* app_window = new AppWindow(
475 window_profile, new ChromeAppWindowDelegate(), GetExtension());
476 AshPanelContents* ash_panel_contents = new AshPanelContents(app_window);
477 app_window->Init(urls[0], ash_panel_contents, create_params);
478 SetResult(ash_panel_contents->GetExtensionWindowController()->
479 CreateWindowValueWithTabs(GetExtension()));
484 web_app::GenerateApplicationNameFromExtensionId(extension_id);
485 // Note: Panels ignore all but the first url provided.
486 Panel* panel = PanelManager::GetInstance()->CreatePanel(
487 title, window_profile, urls[0], window_bounds, panel_create_mode);
489 // Unlike other window types, Panels do not take focus by default.
490 if (!saw_focus_key || !focused)
491 panel->ShowInactive();
496 panel->extension_window_controller()->CreateWindowValueWithTabs(
501 // Create a new BrowserWindow.
502 chrome::HostDesktopType host_desktop_type = chrome::GetActiveDesktop();
504 window_type = Browser::TYPE_POPUP;
505 Browser::CreateParams create_params(window_type, window_profile,
507 if (extension_id.empty()) {
508 create_params.initial_bounds = window_bounds;
510 create_params = Browser::CreateParams::CreateForApp(
511 web_app::GenerateApplicationNameFromExtensionId(extension_id),
512 false /* trusted_source */,
517 create_params.initial_show_state = ui::SHOW_STATE_NORMAL;
518 create_params.host_desktop_type = chrome::GetActiveDesktop();
520 Browser* new_window = new Browser(create_params);
522 for (std::vector<GURL>::iterator i = urls.begin(); i != urls.end(); ++i) {
523 WebContents* tab = chrome::AddSelectedTabWithURL(
524 new_window, *i, content::PAGE_TRANSITION_LINK);
526 TabHelper::FromWebContents(tab)->SetExtensionAppIconById(extension_id);
530 WebContents* contents = NULL;
531 // Move the tab into the created window only if it's an empty popup or it's
533 if ((window_type == Browser::TYPE_POPUP && urls.empty()) ||
534 window_type == Browser::TYPE_TABBED) {
535 if (source_tab_strip)
536 contents = source_tab_strip->DetachWebContentsAt(tab_index);
538 TabStripModel* target_tab_strip = new_window->tab_strip_model();
539 target_tab_strip->InsertWebContentsAt(urls.size(), contents,
540 TabStripModel::ADD_NONE);
543 // Create a new tab if the created window is still empty. Don't create a new
544 // tab when it is intended to create an empty popup.
545 if (!contents && urls.empty() && window_type != Browser::TYPE_POPUP) {
546 chrome::NewTab(new_window);
548 chrome::SelectNumberedTab(new_window, 0);
550 // Unlike other window types, Panels do not take focus by default.
551 if (!saw_focus_key && create_panel)
555 new_window->window()->Show();
557 new_window->window()->ShowInactive();
559 if (new_window->profile()->IsOffTheRecord() &&
560 !GetProfile()->IsOffTheRecord() && !include_incognito()) {
561 // Don't expose incognito windows if extension itself works in non-incognito
562 // profile and CanCrossIncognito isn't allowed.
563 SetResult(base::Value::CreateNullValue());
566 new_window->extension_window_controller()->CreateWindowValueWithTabs(
573 bool WindowsUpdateFunction::RunSync() {
574 scoped_ptr<windows::Update::Params> params(
575 windows::Update::Params::Create(*args_));
576 EXTENSION_FUNCTION_VALIDATE(params);
578 WindowController* controller;
579 if (!windows_util::GetWindowFromWindowID(this, params->window_id,
583 ui::WindowShowState show_state = ui::SHOW_STATE_DEFAULT; // No change.
584 switch (params->update_info.state) {
585 case windows::Update::Params::UpdateInfo::STATE_NORMAL:
586 show_state = ui::SHOW_STATE_NORMAL;
588 case windows::Update::Params::UpdateInfo::STATE_MINIMIZED:
589 show_state = ui::SHOW_STATE_MINIMIZED;
591 case windows::Update::Params::UpdateInfo::STATE_MAXIMIZED:
592 show_state = ui::SHOW_STATE_MAXIMIZED;
594 case windows::Update::Params::UpdateInfo::STATE_FULLSCREEN:
595 show_state = ui::SHOW_STATE_FULLSCREEN;
597 case windows::Update::Params::UpdateInfo::STATE_NONE:
600 error_ = keys::kInvalidWindowStateError;
604 if (show_state != ui::SHOW_STATE_FULLSCREEN &&
605 show_state != ui::SHOW_STATE_DEFAULT)
606 controller->SetFullscreenMode(false, GetExtension()->url());
608 switch (show_state) {
609 case ui::SHOW_STATE_MINIMIZED:
610 controller->window()->Minimize();
612 case ui::SHOW_STATE_MAXIMIZED:
613 controller->window()->Maximize();
615 case ui::SHOW_STATE_FULLSCREEN:
616 if (controller->window()->IsMinimized() ||
617 controller->window()->IsMaximized())
618 controller->window()->Restore();
619 controller->SetFullscreenMode(true, GetExtension()->url());
621 case ui::SHOW_STATE_NORMAL:
622 controller->window()->Restore();
629 if (controller->window()->IsMinimized())
630 bounds = controller->window()->GetRestoredBounds();
632 bounds = controller->window()->GetBounds();
633 bool set_bounds = false;
635 // Any part of the bounds can optionally be set by the caller.
636 if (params->update_info.left) {
637 bounds.set_x(*params->update_info.left);
641 if (params->update_info.top) {
642 bounds.set_y(*params->update_info.top);
646 if (params->update_info.width) {
647 bounds.set_width(*params->update_info.width);
651 if (params->update_info.height) {
652 bounds.set_height(*params->update_info.height);
657 if (show_state == ui::SHOW_STATE_MINIMIZED ||
658 show_state == ui::SHOW_STATE_MAXIMIZED ||
659 show_state == ui::SHOW_STATE_FULLSCREEN) {
660 error_ = keys::kInvalidWindowStateError;
663 // TODO(varkha): Updating bounds during a drag can cause problems and a more
664 // general solution is needed. See http://crbug.com/251813 .
665 controller->window()->SetBounds(bounds);
668 if (params->update_info.focused) {
669 if (*params->update_info.focused) {
670 if (show_state == ui::SHOW_STATE_MINIMIZED) {
671 error_ = keys::kInvalidWindowStateError;
674 controller->window()->Activate();
676 if (show_state == ui::SHOW_STATE_MAXIMIZED ||
677 show_state == ui::SHOW_STATE_FULLSCREEN) {
678 error_ = keys::kInvalidWindowStateError;
681 controller->window()->Deactivate();
685 if (params->update_info.draw_attention)
686 controller->window()->FlashFrame(*params->update_info.draw_attention);
688 SetResult(controller->CreateWindowValue());
693 bool WindowsRemoveFunction::RunSync() {
694 scoped_ptr<windows::Remove::Params> params(
695 windows::Remove::Params::Create(*args_));
696 EXTENSION_FUNCTION_VALIDATE(params);
698 WindowController* controller;
699 if (!windows_util::GetWindowFromWindowID(this, params->window_id,
703 WindowController::Reason reason;
704 if (!controller->CanClose(&reason)) {
705 if (reason == WindowController::REASON_NOT_EDITABLE)
706 error_ = keys::kTabStripNotEditableError;
709 controller->window()->Close();
713 // Tabs ------------------------------------------------------------------------
715 bool TabsGetSelectedFunction::RunSync() {
716 // windowId defaults to "current" window.
717 int window_id = extension_misc::kCurrentWindowId;
719 scoped_ptr<tabs::GetSelected::Params> params(
720 tabs::GetSelected::Params::Create(*args_));
721 EXTENSION_FUNCTION_VALIDATE(params.get());
722 if (params->window_id.get())
723 window_id = *params->window_id;
725 Browser* browser = NULL;
726 if (!GetBrowserFromWindowID(this, window_id, &browser))
729 TabStripModel* tab_strip = browser->tab_strip_model();
730 WebContents* contents = tab_strip->GetActiveWebContents();
732 error_ = keys::kNoSelectedTabError;
735 SetResult(ExtensionTabUtil::CreateTabValue(contents,
737 tab_strip->active_index(),
742 bool TabsGetAllInWindowFunction::RunSync() {
743 scoped_ptr<tabs::GetAllInWindow::Params> params(
744 tabs::GetAllInWindow::Params::Create(*args_));
745 EXTENSION_FUNCTION_VALIDATE(params.get());
746 // windowId defaults to "current" window.
747 int window_id = extension_misc::kCurrentWindowId;
748 if (params->window_id.get())
749 window_id = *params->window_id;
751 Browser* browser = NULL;
752 if (!GetBrowserFromWindowID(this, window_id, &browser))
755 SetResult(ExtensionTabUtil::CreateTabList(browser, GetExtension()));
760 bool TabsQueryFunction::RunSync() {
761 scoped_ptr<tabs::Query::Params> params(tabs::Query::Params::Create(*args_));
762 EXTENSION_FUNCTION_VALIDATE(params.get());
764 bool loading_status_set = params->query_info.status !=
765 tabs::Query::Params::QueryInfo::STATUS_NONE;
766 bool loading = params->query_info.status ==
767 tabs::Query::Params::QueryInfo::STATUS_LOADING;
769 // It is o.k. to use URLPattern::SCHEME_ALL here because this function does
770 // not grant access to the content of the tabs, only to seeing their URLs and
772 URLPattern url_pattern(URLPattern::SCHEME_ALL, "<all_urls>");
773 if (params->query_info.url.get())
774 url_pattern = URLPattern(URLPattern::SCHEME_ALL, *params->query_info.url);
777 if (params->query_info.title.get())
778 title = *params->query_info.title;
780 int window_id = extension_misc::kUnknownWindowId;
781 if (params->query_info.window_id.get())
782 window_id = *params->query_info.window_id;
785 if (params->query_info.index.get())
786 index = *params->query_info.index;
788 std::string window_type;
789 if (params->query_info.window_type !=
790 tabs::Query::Params::QueryInfo::WINDOW_TYPE_NONE) {
791 window_type = tabs::Query::Params::QueryInfo::ToString(
792 params->query_info.window_type);
795 base::ListValue* result = new base::ListValue();
796 Browser* last_active_browser = chrome::FindAnyBrowser(
797 GetProfile(), include_incognito(), chrome::GetActiveDesktop());
798 Browser* current_browser = GetCurrentBrowser();
799 for (chrome::BrowserIterator it; !it.done(); it.Next()) {
800 Browser* browser = *it;
801 if (!GetProfile()->IsSameProfile(browser->profile()))
804 if (!browser->window())
807 if (!include_incognito() && GetProfile() != browser->profile())
810 if (window_id >= 0 && window_id != ExtensionTabUtil::GetWindowId(browser))
813 if (window_id == extension_misc::kCurrentWindowId &&
814 browser != current_browser) {
818 if (!MatchesBool(params->query_info.current_window.get(),
819 browser == current_browser)) {
823 if (!MatchesBool(params->query_info.last_focused_window.get(),
824 browser == last_active_browser)) {
828 if (!window_type.empty() &&
830 browser->extension_window_controller()->GetWindowTypeText()) {
834 TabStripModel* tab_strip = browser->tab_strip_model();
835 for (int i = 0; i < tab_strip->count(); ++i) {
836 WebContents* web_contents = tab_strip->GetWebContentsAt(i);
838 if (index > -1 && i != index)
841 if (!MatchesBool(params->query_info.highlighted.get(),
842 tab_strip->IsTabSelected(i))) {
846 if (!MatchesBool(params->query_info.active.get(),
847 i == tab_strip->active_index())) {
851 if (!MatchesBool(params->query_info.pinned.get(),
852 tab_strip->IsTabPinned(i))) {
856 if (!title.empty() && !MatchPattern(web_contents->GetTitle(),
857 base::UTF8ToUTF16(title)))
860 if (!url_pattern.MatchesURL(web_contents->GetURL()))
863 if (loading_status_set && loading != web_contents->IsLoading())
866 result->Append(ExtensionTabUtil::CreateTabValue(
867 web_contents, tab_strip, i, GetExtension()));
875 bool TabsCreateFunction::RunSync() {
876 scoped_ptr<tabs::Create::Params> params(tabs::Create::Params::Create(*args_));
877 EXTENSION_FUNCTION_VALIDATE(params.get());
879 ExtensionTabUtil::OpenTabParams options;
880 AssignOptionalValue(params->create_properties.window_id, options.window_id);
881 AssignOptionalValue(params->create_properties.opener_tab_id,
882 options.opener_tab_id);
883 AssignOptionalValue(params->create_properties.selected, options.active);
884 // The 'active' property has replaced the 'selected' property.
885 AssignOptionalValue(params->create_properties.active, options.active);
886 AssignOptionalValue(params->create_properties.pinned, options.pinned);
887 AssignOptionalValue(params->create_properties.index, options.index);
888 AssignOptionalValue(params->create_properties.url, options.url);
891 scoped_ptr<base::DictionaryValue> result(
892 ExtensionTabUtil::OpenTab(this, options, &error));
898 // Return data about the newly created tab.
899 if (has_callback()) {
900 SetResult(result.release());
905 bool TabsDuplicateFunction::RunSync() {
906 scoped_ptr<tabs::Duplicate::Params> params(
907 tabs::Duplicate::Params::Create(*args_));
908 EXTENSION_FUNCTION_VALIDATE(params.get());
909 int tab_id = params->tab_id;
911 Browser* browser = NULL;
912 TabStripModel* tab_strip = NULL;
914 if (!GetTabById(tab_id,
925 WebContents* new_contents = chrome::DuplicateTabAt(browser, tab_index);
929 // Duplicated tab may not be in the same window as the original, so find
930 // the window and the tab.
931 TabStripModel* new_tab_strip = NULL;
932 int new_tab_index = -1;
933 ExtensionTabUtil::GetTabStripModel(new_contents,
936 if (!new_tab_strip || new_tab_index == -1) {
940 // Return data about the newly created tab.
941 SetResult(ExtensionTabUtil::CreateTabValue(
943 new_tab_strip, new_tab_index, GetExtension()));
948 bool TabsGetFunction::RunSync() {
949 scoped_ptr<tabs::Get::Params> params(tabs::Get::Params::Create(*args_));
950 EXTENSION_FUNCTION_VALIDATE(params.get());
951 int tab_id = params->tab_id;
953 TabStripModel* tab_strip = NULL;
954 WebContents* contents = NULL;
956 if (!GetTabById(tab_id,
966 SetResult(ExtensionTabUtil::CreateTabValue(contents,
973 bool TabsGetCurrentFunction::RunSync() {
974 DCHECK(dispatcher());
976 WebContents* contents = dispatcher()->delegate()->GetAssociatedWebContents();
978 SetResult(ExtensionTabUtil::CreateTabValue(contents, GetExtension()));
983 bool TabsHighlightFunction::RunSync() {
984 scoped_ptr<tabs::Highlight::Params> params(
985 tabs::Highlight::Params::Create(*args_));
986 EXTENSION_FUNCTION_VALIDATE(params.get());
988 // Get the window id from the params; default to current window if omitted.
989 int window_id = extension_misc::kCurrentWindowId;
990 if (params->highlight_info.window_id.get())
991 window_id = *params->highlight_info.window_id;
993 Browser* browser = NULL;
994 if (!GetBrowserFromWindowID(this, window_id, &browser))
997 TabStripModel* tabstrip = browser->tab_strip_model();
998 ui::ListSelectionModel selection;
999 int active_index = -1;
1001 if (params->highlight_info.tabs.as_integers) {
1002 std::vector<int>& tab_indices = *params->highlight_info.tabs.as_integers;
1003 // Create a new selection model as we read the list of tab indices.
1004 for (size_t i = 0; i < tab_indices.size(); ++i) {
1005 if (!HighlightTab(tabstrip, &selection, &active_index, tab_indices[i]))
1009 EXTENSION_FUNCTION_VALIDATE(params->highlight_info.tabs.as_integer);
1010 if (!HighlightTab(tabstrip,
1013 *params->highlight_info.tabs.as_integer)) {
1018 // Make sure they actually specified tabs to select.
1019 if (selection.empty()) {
1020 error_ = keys::kNoHighlightedTabError;
1024 selection.set_active(active_index);
1025 browser->tab_strip_model()->SetSelectionFromModel(selection);
1027 browser->extension_window_controller()->CreateWindowValueWithTabs(
1032 bool TabsHighlightFunction::HighlightTab(TabStripModel* tabstrip,
1033 ui::ListSelectionModel* selection,
1036 // Make sure the index is in range.
1037 if (!tabstrip->ContainsIndex(index)) {
1038 error_ = ErrorUtils::FormatErrorMessage(
1039 keys::kTabIndexNotFoundError, base::IntToString(index));
1043 // By default, we make the first tab in the list active.
1044 if (*active_index == -1)
1045 *active_index = index;
1047 selection->AddIndexToSelection(index);
1051 TabsUpdateFunction::TabsUpdateFunction() : web_contents_(NULL) {
1054 bool TabsUpdateFunction::RunAsync() {
1055 scoped_ptr<tabs::Update::Params> params(tabs::Update::Params::Create(*args_));
1056 EXTENSION_FUNCTION_VALIDATE(params.get());
1059 WebContents* contents = NULL;
1060 if (!params->tab_id.get()) {
1061 Browser* browser = GetCurrentBrowser();
1063 error_ = keys::kNoCurrentWindowError;
1066 contents = browser->tab_strip_model()->GetActiveWebContents();
1068 error_ = keys::kNoSelectedTabError;
1071 tab_id = SessionID::IdForTab(contents);
1073 tab_id = *params->tab_id;
1077 TabStripModel* tab_strip = NULL;
1078 if (!GetTabById(tab_id,
1080 include_incognito(),
1089 web_contents_ = contents;
1091 // TODO(rafaelw): handle setting remaining tab properties:
1095 // Navigate the tab to a new location if the url is different.
1096 bool is_async = false;
1097 if (params->update_properties.url.get() &&
1098 !UpdateURL(*params->update_properties.url, tab_id, &is_async)) {
1102 bool active = false;
1103 // TODO(rafaelw): Setting |active| from js doesn't make much sense.
1104 // Move tab selection management up to window.
1105 if (params->update_properties.selected.get())
1106 active = *params->update_properties.selected;
1108 // The 'active' property has replaced 'selected'.
1109 if (params->update_properties.active.get())
1110 active = *params->update_properties.active;
1113 if (tab_strip->active_index() != tab_index) {
1114 tab_strip->ActivateTabAt(tab_index, false);
1115 DCHECK_EQ(contents, tab_strip->GetActiveWebContents());
1119 if (params->update_properties.highlighted.get()) {
1120 bool highlighted = *params->update_properties.highlighted;
1121 if (highlighted != tab_strip->IsTabSelected(tab_index))
1122 tab_strip->ToggleSelectionAt(tab_index);
1125 if (params->update_properties.pinned.get()) {
1126 bool pinned = *params->update_properties.pinned;
1127 tab_strip->SetTabPinned(tab_index, pinned);
1129 // Update the tab index because it may move when being pinned.
1130 tab_index = tab_strip->GetIndexOfWebContents(contents);
1133 if (params->update_properties.opener_tab_id.get()) {
1134 int opener_id = *params->update_properties.opener_tab_id;
1136 WebContents* opener_contents = NULL;
1137 if (!ExtensionTabUtil::GetTabById(opener_id,
1139 include_incognito(),
1146 tab_strip->SetOpenerOfWebContentsAt(tab_index, opener_contents);
1156 bool TabsUpdateFunction::UpdateURL(const std::string &url_string,
1159 GURL url = ExtensionTabUtil::ResolvePossiblyRelativeURL(
1160 url_string, GetExtension());
1162 if (!url.is_valid()) {
1163 error_ = ErrorUtils::FormatErrorMessage(
1164 keys::kInvalidUrlError, url_string);
1168 // Don't let the extension crash the browser or renderers.
1169 if (ExtensionTabUtil::IsCrashURL(url)) {
1170 error_ = keys::kNoCrashBrowserError;
1174 // JavaScript URLs can do the same kinds of things as cross-origin XHR, so
1175 // we need to check host permissions before allowing them.
1176 if (url.SchemeIs(content::kJavaScriptScheme)) {
1177 content::RenderProcessHost* process = web_contents_->GetRenderProcessHost();
1178 if (!PermissionsData::CanExecuteScriptOnPage(
1180 web_contents_->GetURL(),
1181 web_contents_->GetURL(),
1184 process ? process->GetID() : -1,
1189 TabHelper::FromWebContents(web_contents_)->script_executor()->ExecuteScript(
1191 ScriptExecutor::JAVASCRIPT,
1193 ScriptExecutor::TOP_FRAME,
1194 UserScript::DOCUMENT_IDLE,
1195 ScriptExecutor::MAIN_WORLD,
1196 ScriptExecutor::DEFAULT_PROCESS,
1200 ScriptExecutor::NO_RESULT,
1201 base::Bind(&TabsUpdateFunction::OnExecuteCodeFinished, this));
1207 web_contents_->GetController().LoadURL(
1208 url, content::Referrer(), content::PAGE_TRANSITION_LINK, std::string());
1210 // The URL of a tab contents never actually changes to a JavaScript URL, so
1211 // this check only makes sense in other cases.
1212 if (!url.SchemeIs(content::kJavaScriptScheme))
1213 DCHECK_EQ(url.spec(), web_contents_->GetURL().spec());
1218 void TabsUpdateFunction::PopulateResult() {
1219 if (!has_callback())
1222 SetResult(ExtensionTabUtil::CreateTabValue(web_contents_, GetExtension()));
1225 void TabsUpdateFunction::OnExecuteCodeFinished(
1226 const std::string& error,
1229 const base::ListValue& script_result) {
1234 SendResponse(error.empty());
1237 bool TabsMoveFunction::RunSync() {
1238 scoped_ptr<tabs::Move::Params> params(tabs::Move::Params::Create(*args_));
1239 EXTENSION_FUNCTION_VALIDATE(params.get());
1241 int new_index = params->move_properties.index;
1242 int* window_id = params->move_properties.window_id.get();
1243 scoped_ptr<base::ListValue> tab_values(new base::ListValue());
1245 size_t num_tabs = 0;
1246 if (params->tab_ids.as_integers) {
1247 std::vector<int>& tab_ids = *params->tab_ids.as_integers;
1248 num_tabs = tab_ids.size();
1249 for (size_t i = 0; i < tab_ids.size(); ++i) {
1250 if (!MoveTab(tab_ids[i], &new_index, i, tab_values.get(), window_id))
1254 EXTENSION_FUNCTION_VALIDATE(params->tab_ids.as_integer);
1256 if (!MoveTab(*params->tab_ids.as_integer,
1265 if (!has_callback())
1268 if (num_tabs == 0) {
1269 error_ = "No tabs given.";
1271 } else if (num_tabs == 1) {
1272 scoped_ptr<base::Value> value;
1273 CHECK(tab_values.get()->Remove(0, &value));
1274 SetResult(value.release());
1276 // Only return the results as an array if there are multiple tabs.
1277 SetResult(tab_values.release());
1283 bool TabsMoveFunction::MoveTab(int tab_id,
1286 base::ListValue* tab_values,
1288 Browser* source_browser = NULL;
1289 TabStripModel* source_tab_strip = NULL;
1290 WebContents* contents = NULL;
1292 if (!GetTabById(tab_id,
1294 include_incognito(),
1303 // Don't let the extension move the tab if the user is dragging tabs.
1304 if (!source_browser->window()->IsTabStripEditable()) {
1305 error_ = keys::kTabStripNotEditableError;
1309 // Insert the tabs one after another.
1310 *new_index += iteration;
1313 Browser* target_browser = NULL;
1315 if (!GetBrowserFromWindowID(this, *window_id, &target_browser))
1318 if (!target_browser->window()->IsTabStripEditable()) {
1319 error_ = keys::kTabStripNotEditableError;
1323 if (!target_browser->is_type_tabbed()) {
1324 error_ = keys::kCanOnlyMoveTabsWithinNormalWindowsError;
1328 if (target_browser->profile() != source_browser->profile()) {
1329 error_ = keys::kCanOnlyMoveTabsWithinSameProfileError;
1333 // If windowId is different from the current window, move between windows.
1334 if (ExtensionTabUtil::GetWindowId(target_browser) !=
1335 ExtensionTabUtil::GetWindowId(source_browser)) {
1336 TabStripModel* target_tab_strip = target_browser->tab_strip_model();
1337 WebContents* web_contents =
1338 source_tab_strip->DetachWebContentsAt(tab_index);
1339 if (!web_contents) {
1340 error_ = ErrorUtils::FormatErrorMessage(
1341 keys::kTabNotFoundError, base::IntToString(tab_id));
1345 // Clamp move location to the last position.
1346 // This is ">" because it can append to a new index position.
1347 // -1 means set the move location to the last position.
1348 if (*new_index > target_tab_strip->count() || *new_index < 0)
1349 *new_index = target_tab_strip->count();
1351 target_tab_strip->InsertWebContentsAt(
1352 *new_index, web_contents, TabStripModel::ADD_NONE);
1354 if (has_callback()) {
1355 tab_values->Append(ExtensionTabUtil::CreateTabValue(
1366 // Perform a simple within-window move.
1367 // Clamp move location to the last position.
1368 // This is ">=" because the move must be to an existing location.
1369 // -1 means set the move location to the last position.
1370 if (*new_index >= source_tab_strip->count() || *new_index < 0)
1371 *new_index = source_tab_strip->count() - 1;
1373 if (*new_index != tab_index)
1374 source_tab_strip->MoveWebContentsAt(tab_index, *new_index, false);
1376 if (has_callback()) {
1377 tab_values->Append(ExtensionTabUtil::CreateTabValue(
1378 contents, source_tab_strip, *new_index, GetExtension()));
1384 bool TabsReloadFunction::RunSync() {
1385 scoped_ptr<tabs::Reload::Params> params(
1386 tabs::Reload::Params::Create(*args_));
1387 EXTENSION_FUNCTION_VALIDATE(params.get());
1389 bool bypass_cache = false;
1390 if (params->reload_properties.get() &&
1391 params->reload_properties->bypass_cache.get()) {
1392 bypass_cache = *params->reload_properties->bypass_cache;
1395 content::WebContents* web_contents = NULL;
1397 // If |tab_id| is specified, look for it. Otherwise default to selected tab
1398 // in the current window.
1399 if (!params->tab_id.get()) {
1400 Browser* browser = GetCurrentBrowser();
1402 error_ = keys::kNoCurrentWindowError;
1406 if (!ExtensionTabUtil::GetDefaultTab(browser, &web_contents, NULL))
1409 int tab_id = *params->tab_id;
1411 Browser* browser = NULL;
1412 if (!GetTabById(tab_id,
1414 include_incognito(),
1423 if (web_contents->ShowingInterstitialPage()) {
1424 // This does as same as Browser::ReloadInternal.
1425 NavigationEntry* entry = web_contents->GetController().GetVisibleEntry();
1426 OpenURLParams params(entry->GetURL(), Referrer(), CURRENT_TAB,
1427 content::PAGE_TRANSITION_RELOAD, false);
1428 GetCurrentBrowser()->OpenURL(params);
1429 } else if (bypass_cache) {
1430 web_contents->GetController().ReloadIgnoringCache(true);
1432 web_contents->GetController().Reload(true);
1438 bool TabsRemoveFunction::RunSync() {
1439 scoped_ptr<tabs::Remove::Params> params(tabs::Remove::Params::Create(*args_));
1440 EXTENSION_FUNCTION_VALIDATE(params.get());
1442 if (params->tab_ids.as_integers) {
1443 std::vector<int>& tab_ids = *params->tab_ids.as_integers;
1444 for (size_t i = 0; i < tab_ids.size(); ++i) {
1445 if (!RemoveTab(tab_ids[i]))
1449 EXTENSION_FUNCTION_VALIDATE(params->tab_ids.as_integer);
1450 if (!RemoveTab(*params->tab_ids.as_integer.get()))
1456 bool TabsRemoveFunction::RemoveTab(int tab_id) {
1457 Browser* browser = NULL;
1458 WebContents* contents = NULL;
1459 if (!GetTabById(tab_id,
1461 include_incognito(),
1470 // Don't let the extension remove a tab if the user is dragging tabs around.
1471 if (!browser->window()->IsTabStripEditable()) {
1472 error_ = keys::kTabStripNotEditableError;
1475 // There's a chance that the tab is being dragged, or we're in some other
1476 // nested event loop. This code path ensures that the tab is safely closed
1477 // under such circumstances, whereas |TabStripModel::CloseWebContentsAt()|
1483 bool TabsCaptureVisibleTabFunction::IsScreenshotEnabled() {
1484 PrefService* service = GetProfile()->GetPrefs();
1485 if (service->GetBoolean(prefs::kDisableScreenshots)) {
1486 error_ = keys::kScreenshotsDisabled;
1492 WebContents* TabsCaptureVisibleTabFunction::GetWebContentsForID(int window_id) {
1493 Browser* browser = NULL;
1494 if (!GetBrowserFromWindowID(this, window_id, &browser))
1497 WebContents* contents = browser->tab_strip_model()->GetActiveWebContents();
1499 error_ = keys::kInternalVisibleTabCaptureError;
1503 if (!PermissionsData::CanCaptureVisiblePage(GetExtension(),
1504 SessionID::IdForTab(contents),
1511 void TabsCaptureVisibleTabFunction::OnCaptureFailure(FailureReason reason) {
1512 error_ = keys::kInternalVisibleTabCaptureError;
1513 SendResponse(false);
1516 void TabsCaptureVisibleTabFunction::RegisterProfilePrefs(
1517 user_prefs::PrefRegistrySyncable* registry) {
1518 registry->RegisterBooleanPref(
1519 prefs::kDisableScreenshots,
1521 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
1524 bool TabsDetectLanguageFunction::RunAsync() {
1525 scoped_ptr<tabs::DetectLanguage::Params> params(
1526 tabs::DetectLanguage::Params::Create(*args_));
1527 EXTENSION_FUNCTION_VALIDATE(params.get());
1530 Browser* browser = NULL;
1531 WebContents* contents = NULL;
1533 // If |tab_id| is specified, look for it. Otherwise default to selected tab
1534 // in the current window.
1535 if (params->tab_id.get()) {
1536 tab_id = *params->tab_id;
1537 if (!GetTabById(tab_id,
1539 include_incognito(),
1547 if (!browser || !contents)
1550 browser = GetCurrentBrowser();
1553 contents = browser->tab_strip_model()->GetActiveWebContents();
1558 if (contents->GetController().NeedsReload()) {
1559 // If the tab hasn't been loaded, don't wait for the tab to load.
1560 error_ = keys::kCannotDetermineLanguageOfUnloadedTab;
1564 AddRef(); // Balanced in GotLanguage().
1566 TranslateTabHelper* translate_tab_helper =
1567 TranslateTabHelper::FromWebContents(contents);
1568 if (!translate_tab_helper->GetLanguageState().original_language().empty()) {
1569 // Delay the callback invocation until after the current JS call has
1571 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
1572 &TabsDetectLanguageFunction::GotLanguage, this,
1573 translate_tab_helper->GetLanguageState().original_language()));
1576 // The tab contents does not know its language yet. Let's wait until it
1577 // receives it, or until the tab is closed/navigates to some other page.
1578 registrar_.Add(this, chrome::NOTIFICATION_TAB_LANGUAGE_DETERMINED,
1579 content::Source<WebContents>(contents));
1581 this, chrome::NOTIFICATION_TAB_CLOSING,
1582 content::Source<NavigationController>(&(contents->GetController())));
1584 this, content::NOTIFICATION_NAV_ENTRY_COMMITTED,
1585 content::Source<NavigationController>(&(contents->GetController())));
1589 void TabsDetectLanguageFunction::Observe(
1591 const content::NotificationSource& source,
1592 const content::NotificationDetails& details) {
1593 std::string language;
1594 if (type == chrome::NOTIFICATION_TAB_LANGUAGE_DETERMINED) {
1595 const LanguageDetectionDetails* lang_det_details =
1596 content::Details<const LanguageDetectionDetails>(details).ptr();
1597 language = lang_det_details->adopted_language;
1600 registrar_.RemoveAll();
1602 // Call GotLanguage in all cases as we want to guarantee the callback is
1603 // called for every API call the extension made.
1604 GotLanguage(language);
1607 void TabsDetectLanguageFunction::GotLanguage(const std::string& language) {
1608 SetResult(new base::StringValue(language.c_str()));
1611 Release(); // Balanced in Run()
1614 ExecuteCodeInTabFunction::ExecuteCodeInTabFunction()
1615 : execute_tab_id_(-1) {
1618 ExecuteCodeInTabFunction::~ExecuteCodeInTabFunction() {}
1620 bool ExecuteCodeInTabFunction::HasPermission() {
1621 if (Init() && PermissionsData::HasAPIPermissionForTab(
1622 extension_.get(), execute_tab_id_, APIPermission::kTab)) {
1625 return ExtensionFunction::HasPermission();
1628 bool ExecuteCodeInTabFunction::CanExecuteScriptOnPage() {
1629 content::WebContents* contents = NULL;
1631 // If |tab_id| is specified, look for the tab. Otherwise default to selected
1632 // tab in the current window.
1633 CHECK_GE(execute_tab_id_, 0);
1634 if (!GetTabById(execute_tab_id_,
1636 include_incognito(),
1647 // NOTE: This can give the wrong answer due to race conditions, but it is OK,
1648 // we check again in the renderer.
1649 content::RenderProcessHost* process = contents->GetRenderProcessHost();
1650 if (!PermissionsData::CanExecuteScriptOnPage(
1656 process ? process->GetID() : -1,
1664 ScriptExecutor* ExecuteCodeInTabFunction::GetScriptExecutor() {
1665 Browser* browser = NULL;
1666 content::WebContents* contents = NULL;
1668 bool success = GetTabById(execute_tab_id_,
1670 include_incognito(),
1676 contents && browser;
1681 return TabHelper::FromWebContents(contents)->script_executor();
1684 bool ExecuteCodeInTabFunction::IsWebView() const {
1688 const GURL& ExecuteCodeInTabFunction::GetWebViewSrc() const {
1689 return GURL::EmptyGURL();
1692 bool TabsExecuteScriptFunction::ShouldInsertCSS() const {
1696 void TabsExecuteScriptFunction::OnExecuteCodeFinished(
1697 const std::string& error,
1700 const base::ListValue& result) {
1702 SetResult(result.DeepCopy());
1703 ExecuteCodeInTabFunction::OnExecuteCodeFinished(error, on_page_id, on_url,
1707 bool ExecuteCodeInTabFunction::Init() {
1711 // |tab_id| is optional so it's ok if it's not there.
1713 if (args_->GetInteger(0, &tab_id))
1714 EXTENSION_FUNCTION_VALIDATE(tab_id >= 0);
1716 // |details| are not optional.
1717 base::DictionaryValue* details_value = NULL;
1718 if (!args_->GetDictionary(1, &details_value))
1720 scoped_ptr<InjectDetails> details(new InjectDetails());
1721 if (!InjectDetails::Populate(*details_value, details.get()))
1724 // If the tab ID wasn't given then it needs to be converted to the
1725 // currently active tab's ID.
1727 Browser* browser = GetCurrentBrowser();
1730 content::WebContents* web_contents = NULL;
1731 if (!ExtensionTabUtil::GetDefaultTab(browser, &web_contents, &tab_id))
1735 execute_tab_id_ = tab_id;
1736 details_ = details.Pass();
1740 bool TabsInsertCSSFunction::ShouldInsertCSS() const {
1744 } // namespace extensions