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/tab_helper.h"
29 #include "chrome/browser/extensions/window_controller.h"
30 #include "chrome/browser/extensions/window_controller_list.h"
31 #include "chrome/browser/prefs/incognito_mode_prefs.h"
32 #include "chrome/browser/profiles/profile.h"
33 #include "chrome/browser/translate/chrome_translate_client.h"
34 #include "chrome/browser/ui/apps/chrome_app_delegate.h"
35 #include "chrome/browser/ui/browser.h"
36 #include "chrome/browser/ui/browser_commands.h"
37 #include "chrome/browser/ui/browser_finder.h"
38 #include "chrome/browser/ui/browser_iterator.h"
39 #include "chrome/browser/ui/browser_navigator.h"
40 #include "chrome/browser/ui/browser_tabstrip.h"
41 #include "chrome/browser/ui/browser_window.h"
42 #include "chrome/browser/ui/host_desktop.h"
43 #include "chrome/browser/ui/panels/panel_manager.h"
44 #include "chrome/browser/ui/tabs/tab_strip_model.h"
45 #include "chrome/browser/ui/window_sizer/window_sizer.h"
46 #include "chrome/browser/ui/zoom/zoom_controller.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/pref_registry/pref_registry_syncable.h"
56 #include "components/translate/core/browser/language_state.h"
57 #include "components/translate/core/common/language_detection_details.h"
58 #include "content/public/browser/navigation_controller.h"
59 #include "content/public/browser/navigation_entry.h"
60 #include "content/public/browser/notification_details.h"
61 #include "content/public/browser/notification_source.h"
62 #include "content/public/browser/render_process_host.h"
63 #include "content/public/browser/render_view_host.h"
64 #include "content/public/browser/render_widget_host_view.h"
65 #include "content/public/browser/web_contents.h"
66 #include "content/public/common/url_constants.h"
67 #include "extensions/browser/extension_function_dispatcher.h"
68 #include "extensions/browser/extension_function_util.h"
69 #include "extensions/browser/extension_host.h"
70 #include "extensions/browser/file_reader.h"
71 #include "extensions/browser/script_executor.h"
72 #include "extensions/common/constants.h"
73 #include "extensions/common/error_utils.h"
74 #include "extensions/common/extension.h"
75 #include "extensions/common/extension_messages.h"
76 #include "extensions/common/manifest_constants.h"
77 #include "extensions/common/message_bundle.h"
78 #include "extensions/common/permissions/permissions_data.h"
79 #include "extensions/common/user_script.h"
80 #include "skia/ext/image_operations.h"
81 #include "skia/ext/platform_canvas.h"
82 #include "third_party/skia/include/core/SkBitmap.h"
83 #include "ui/base/models/list_selection_model.h"
84 #include "ui/base/ui_base_types.h"
87 #include "apps/app_window_registry.h"
88 #include "ash/ash_switches.h"
89 #include "chrome/browser/extensions/api/tabs/ash_panel_contents.h"
92 using apps::AppWindow;
93 using content::BrowserThread;
94 using content::NavigationController;
95 using content::NavigationEntry;
96 using content::OpenURLParams;
97 using content::Referrer;
98 using content::WebContents;
100 namespace extensions {
102 namespace windows = api::windows;
103 namespace keys = tabs_constants;
104 namespace tabs = api::tabs;
106 using api::tabs::InjectDetails;
110 bool GetBrowserFromWindowID(ChromeUIThreadExtensionFunction* function,
116 ExtensionTabUtil::GetBrowserFromWindowID(function, window_id, &error);
118 function->SetError(error);
126 // |error_message| can optionally be passed in and will be set with an
127 // appropriate message if the tab cannot be found by id.
128 bool GetTabById(int tab_id,
130 bool include_incognito,
132 TabStripModel** tab_strip,
133 content::WebContents** contents,
135 std::string* error_message) {
136 if (ExtensionTabUtil::GetTabById(tab_id, profile, include_incognito,
137 browser, tab_strip, contents, tab_index)) {
142 *error_message = ErrorUtils::FormatErrorMessage(
143 keys::kTabNotFoundError, base::IntToString(tab_id));
149 // Returns true if either |boolean| is a null pointer, or if |*boolean| and
150 // |value| are equal. This function is used to check if a tab's parameters match
151 // those of the browser.
152 bool MatchesBool(bool* boolean, bool value) {
153 return !boolean || *boolean == value;
156 template <typename T>
157 void AssignOptionalValue(const scoped_ptr<T>& source,
158 scoped_ptr<T>& destination) {
160 destination.reset(new T(*source.get()));
166 void ZoomModeToZoomSettings(ZoomController::ZoomMode zoom_mode,
167 api::tabs::ZoomSettings* zoom_settings) {
168 DCHECK(zoom_settings);
170 case ZoomController::ZOOM_MODE_DEFAULT:
171 zoom_settings->mode = api::tabs::ZoomSettings::MODE_AUTOMATIC;
172 zoom_settings->scope = api::tabs::ZoomSettings::SCOPE_PER_ORIGIN;
174 case ZoomController::ZOOM_MODE_ISOLATED:
175 zoom_settings->mode = api::tabs::ZoomSettings::MODE_AUTOMATIC;
176 zoom_settings->scope = api::tabs::ZoomSettings::SCOPE_PER_TAB;
178 case ZoomController::ZOOM_MODE_MANUAL:
179 zoom_settings->mode = api::tabs::ZoomSettings::MODE_MANUAL;
180 zoom_settings->scope = api::tabs::ZoomSettings::SCOPE_PER_TAB;
182 case ZoomController::ZOOM_MODE_DISABLED:
183 zoom_settings->mode = api::tabs::ZoomSettings::MODE_DISABLED;
184 zoom_settings->scope = api::tabs::ZoomSettings::SCOPE_PER_TAB;
189 // Windows ---------------------------------------------------------------------
191 bool WindowsGetFunction::RunSync() {
192 scoped_ptr<windows::Get::Params> params(windows::Get::Params::Create(*args_));
193 EXTENSION_FUNCTION_VALIDATE(params.get());
195 bool populate_tabs = false;
196 if (params->get_info.get() && params->get_info->populate.get())
197 populate_tabs = *params->get_info->populate;
199 WindowController* controller;
200 if (!windows_util::GetWindowFromWindowID(this,
207 SetResult(controller->CreateWindowValueWithTabs(extension()));
209 SetResult(controller->CreateWindowValue());
213 bool WindowsGetCurrentFunction::RunSync() {
214 scoped_ptr<windows::GetCurrent::Params> params(
215 windows::GetCurrent::Params::Create(*args_));
216 EXTENSION_FUNCTION_VALIDATE(params.get());
218 bool populate_tabs = false;
219 if (params->get_info.get() && params->get_info->populate.get())
220 populate_tabs = *params->get_info->populate;
222 WindowController* controller;
223 if (!windows_util::GetWindowFromWindowID(this,
224 extension_misc::kCurrentWindowId,
229 SetResult(controller->CreateWindowValueWithTabs(extension()));
231 SetResult(controller->CreateWindowValue());
235 bool WindowsGetLastFocusedFunction::RunSync() {
236 scoped_ptr<windows::GetLastFocused::Params> params(
237 windows::GetLastFocused::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 // Note: currently this returns the last active browser. If we decide to
245 // include other window types (e.g. panels), we will need to add logic to
246 // WindowControllerList that mirrors the active behavior of BrowserList.
247 Browser* browser = chrome::FindAnyBrowser(
248 GetProfile(), include_incognito(), chrome::GetActiveDesktop());
249 if (!browser || !browser->window()) {
250 error_ = keys::kNoLastFocusedWindowError;
253 WindowController* controller =
254 browser->extension_window_controller();
256 SetResult(controller->CreateWindowValueWithTabs(extension()));
258 SetResult(controller->CreateWindowValue());
262 bool WindowsGetAllFunction::RunSync() {
263 scoped_ptr<windows::GetAll::Params> params(
264 windows::GetAll::Params::Create(*args_));
265 EXTENSION_FUNCTION_VALIDATE(params.get());
267 bool populate_tabs = false;
268 if (params->get_info.get() && params->get_info->populate.get())
269 populate_tabs = *params->get_info->populate;
271 base::ListValue* window_list = new base::ListValue();
272 const WindowControllerList::ControllerList& windows =
273 WindowControllerList::GetInstance()->windows();
274 for (WindowControllerList::ControllerList::const_iterator iter =
276 iter != windows.end(); ++iter) {
277 if (!this->CanOperateOnWindow(*iter))
280 window_list->Append((*iter)->CreateWindowValueWithTabs(extension()));
282 window_list->Append((*iter)->CreateWindowValue());
284 SetResult(window_list);
288 bool WindowsCreateFunction::ShouldOpenIncognitoWindow(
289 const windows::Create::Params::CreateData* create_data,
290 std::vector<GURL>* urls, bool* is_error) {
292 const IncognitoModePrefs::Availability incognito_availability =
293 IncognitoModePrefs::GetAvailability(GetProfile()->GetPrefs());
294 bool incognito = false;
295 if (create_data && create_data->incognito) {
296 incognito = *create_data->incognito;
297 if (incognito && incognito_availability == IncognitoModePrefs::DISABLED) {
298 error_ = keys::kIncognitoModeIsDisabled;
302 if (!incognito && incognito_availability == IncognitoModePrefs::FORCED) {
303 error_ = keys::kIncognitoModeIsForced;
307 } else if (incognito_availability == IncognitoModePrefs::FORCED) {
308 // If incognito argument is not specified explicitly, we default to
309 // incognito when forced so by policy.
313 // Remove all URLs that are not allowed in an incognito session. Note that a
314 // ChromeOS guest session is not considered incognito in this case.
315 if (incognito && !GetProfile()->IsGuestSession()) {
316 std::string first_url_erased;
317 for (size_t i = 0; i < urls->size();) {
318 if (chrome::IsURLAllowedInIncognito((*urls)[i], GetProfile())) {
321 if (first_url_erased.empty())
322 first_url_erased = (*urls)[i].spec();
323 urls->erase(urls->begin() + i);
326 if (urls->empty() && !first_url_erased.empty()) {
327 error_ = ErrorUtils::FormatErrorMessage(
328 keys::kURLsNotAllowedInIncognitoError, first_url_erased);
336 bool WindowsCreateFunction::RunSync() {
337 scoped_ptr<windows::Create::Params> params(
338 windows::Create::Params::Create(*args_));
339 EXTENSION_FUNCTION_VALIDATE(params);
340 std::vector<GURL> urls;
341 TabStripModel* source_tab_strip = NULL;
344 windows::Create::Params::CreateData* create_data = params->create_data.get();
346 // Look for optional url.
347 if (create_data && create_data->url) {
348 std::vector<std::string> url_strings;
349 // First, get all the URLs the client wants to open.
350 if (create_data->url->as_string)
351 url_strings.push_back(*create_data->url->as_string);
352 else if (create_data->url->as_strings)
353 url_strings.swap(*create_data->url->as_strings);
355 // Second, resolve, validate and convert them to GURLs.
356 for (std::vector<std::string>::iterator i = url_strings.begin();
357 i != url_strings.end(); ++i) {
358 GURL url = ExtensionTabUtil::ResolvePossiblyRelativeURL(*i, extension());
359 if (!url.is_valid()) {
360 error_ = ErrorUtils::FormatErrorMessage(keys::kInvalidUrlError, *i);
363 // Don't let the extension crash the browser or renderers.
364 if (ExtensionTabUtil::IsCrashURL(url)) {
365 error_ = keys::kNoCrashBrowserError;
372 // Look for optional tab id.
373 if (create_data && create_data->tab_id) {
374 // Find the tab. |source_tab_strip| and |tab_index| will later be used to
375 // move the tab into the created window.
376 if (!GetTabById(*create_data->tab_id,
387 Profile* window_profile = GetProfile();
388 Browser::Type window_type = Browser::TYPE_TABBED;
389 bool create_panel = false;
391 // panel_create_mode only applies if create_panel = true
392 PanelManager::CreateMode panel_create_mode = PanelManager::CREATE_AS_DOCKED;
394 gfx::Rect window_bounds;
396 bool saw_focus_key = false;
397 std::string extension_id;
399 // Decide whether we are opening a normal window or an incognito window.
400 bool is_error = true;
401 bool open_incognito_window = ShouldOpenIncognitoWindow(create_data, &urls,
404 // error_ member variable is set inside of ShouldOpenIncognitoWindow.
407 if (open_incognito_window) {
408 window_profile = window_profile->GetOffTheRecordProfile();
412 // Figure out window type before figuring out bounds so that default
413 // bounds can be set according to the window type.
414 switch (create_data->type) {
415 case windows::Create::Params::CreateData::TYPE_POPUP:
416 window_type = Browser::TYPE_POPUP;
417 extension_id = extension()->id();
419 case windows::Create::Params::CreateData::TYPE_PANEL:
420 case windows::Create::Params::CreateData::TYPE_DETACHED_PANEL: {
421 extension_id = extension()->id();
422 bool use_panels = PanelManager::ShouldUsePanels(extension_id);
425 // Non-ash supports both docked and detached panel types.
426 if (chrome::GetActiveDesktop() != chrome::HOST_DESKTOP_TYPE_ASH &&
428 windows::Create::Params::CreateData::TYPE_DETACHED_PANEL) {
429 panel_create_mode = PanelManager::CREATE_AS_DETACHED;
432 window_type = Browser::TYPE_POPUP;
436 case windows::Create::Params::CreateData::TYPE_NONE:
437 case windows::Create::Params::CreateData::TYPE_NORMAL:
440 error_ = keys::kInvalidWindowTypeError;
444 // Initialize default window bounds according to window type.
445 if (window_type == Browser::TYPE_TABBED ||
446 window_type == Browser::TYPE_POPUP ||
448 // Try to position the new browser relative to its originating
449 // browser window. The call offsets the bounds by kWindowTilePixels
450 // (defined in WindowSizer to be 10).
452 // NOTE(rafaelw): It's ok if GetCurrentBrowser() returns NULL here.
453 // GetBrowserWindowBounds will default to saved "default" values for
455 ui::WindowShowState show_state = ui::SHOW_STATE_DEFAULT;
456 WindowSizer::GetBrowserWindowBoundsAndShowState(std::string(),
463 if (create_panel && PanelManager::CREATE_AS_DETACHED == panel_create_mode) {
464 window_bounds.set_origin(
465 PanelManager::GetInstance()->GetDefaultDetachedPanelOrigin());
468 // Any part of the bounds can optionally be set by the caller.
469 if (create_data->left)
470 window_bounds.set_x(*create_data->left);
472 if (create_data->top)
473 window_bounds.set_y(*create_data->top);
475 if (create_data->width)
476 window_bounds.set_width(*create_data->width);
478 if (create_data->height)
479 window_bounds.set_height(*create_data->height);
481 if (create_data->focused) {
482 focused = *create_data->focused;
483 saw_focus_key = true;
489 urls.push_back(GURL(chrome::kChromeUINewTabURL));
492 if (chrome::GetActiveDesktop() == chrome::HOST_DESKTOP_TYPE_ASH) {
493 AppWindow::CreateParams create_params;
494 create_params.window_type = AppWindow::WINDOW_TYPE_V1_PANEL;
495 create_params.window_spec.bounds = window_bounds;
496 create_params.focused = saw_focus_key && focused;
497 AppWindow* app_window =
498 new AppWindow(window_profile, new ChromeAppDelegate(), extension());
499 AshPanelContents* ash_panel_contents = new AshPanelContents(app_window);
500 app_window->Init(urls[0], ash_panel_contents, create_params);
501 SetResult(ash_panel_contents->GetExtensionWindowController()
502 ->CreateWindowValueWithTabs(extension()));
507 web_app::GenerateApplicationNameFromExtensionId(extension_id);
508 // Note: Panels ignore all but the first url provided.
509 Panel* panel = PanelManager::GetInstance()->CreatePanel(
510 title, window_profile, urls[0], window_bounds, panel_create_mode);
512 // Unlike other window types, Panels do not take focus by default.
513 if (!saw_focus_key || !focused)
514 panel->ShowInactive();
518 SetResult(panel->extension_window_controller()->CreateWindowValueWithTabs(
523 // Create a new BrowserWindow.
524 chrome::HostDesktopType host_desktop_type = chrome::GetActiveDesktop();
526 window_type = Browser::TYPE_POPUP;
527 Browser::CreateParams create_params(window_type, window_profile,
529 if (extension_id.empty()) {
530 create_params.initial_bounds = window_bounds;
532 create_params = Browser::CreateParams::CreateForApp(
533 web_app::GenerateApplicationNameFromExtensionId(extension_id),
534 false /* trusted_source */,
539 create_params.initial_show_state = ui::SHOW_STATE_NORMAL;
540 create_params.host_desktop_type = chrome::GetActiveDesktop();
542 Browser* new_window = new Browser(create_params);
544 for (std::vector<GURL>::iterator i = urls.begin(); i != urls.end(); ++i) {
545 WebContents* tab = chrome::AddSelectedTabWithURL(
546 new_window, *i, content::PAGE_TRANSITION_LINK);
548 TabHelper::FromWebContents(tab)->SetExtensionAppIconById(extension_id);
552 WebContents* contents = NULL;
553 // Move the tab into the created window only if it's an empty popup or it's
555 if ((window_type == Browser::TYPE_POPUP && urls.empty()) ||
556 window_type == Browser::TYPE_TABBED) {
557 if (source_tab_strip)
558 contents = source_tab_strip->DetachWebContentsAt(tab_index);
560 TabStripModel* target_tab_strip = new_window->tab_strip_model();
561 target_tab_strip->InsertWebContentsAt(urls.size(), contents,
562 TabStripModel::ADD_NONE);
565 // Create a new tab if the created window is still empty. Don't create a new
566 // tab when it is intended to create an empty popup.
567 if (!contents && urls.empty() && window_type != Browser::TYPE_POPUP) {
568 chrome::NewTab(new_window);
570 chrome::SelectNumberedTab(new_window, 0);
572 // Unlike other window types, Panels do not take focus by default.
573 if (!saw_focus_key && create_panel)
577 new_window->window()->Show();
579 new_window->window()->ShowInactive();
581 if (new_window->profile()->IsOffTheRecord() &&
582 !GetProfile()->IsOffTheRecord() && !include_incognito()) {
583 // Don't expose incognito windows if extension itself works in non-incognito
584 // profile and CanCrossIncognito isn't allowed.
585 SetResult(base::Value::CreateNullValue());
588 new_window->extension_window_controller()->CreateWindowValueWithTabs(
595 bool WindowsUpdateFunction::RunSync() {
596 scoped_ptr<windows::Update::Params> params(
597 windows::Update::Params::Create(*args_));
598 EXTENSION_FUNCTION_VALIDATE(params);
600 WindowController* controller;
601 if (!windows_util::GetWindowFromWindowID(this, params->window_id,
605 ui::WindowShowState show_state = ui::SHOW_STATE_DEFAULT; // No change.
606 switch (params->update_info.state) {
607 case windows::Update::Params::UpdateInfo::STATE_NORMAL:
608 show_state = ui::SHOW_STATE_NORMAL;
610 case windows::Update::Params::UpdateInfo::STATE_MINIMIZED:
611 show_state = ui::SHOW_STATE_MINIMIZED;
613 case windows::Update::Params::UpdateInfo::STATE_MAXIMIZED:
614 show_state = ui::SHOW_STATE_MAXIMIZED;
616 case windows::Update::Params::UpdateInfo::STATE_FULLSCREEN:
617 show_state = ui::SHOW_STATE_FULLSCREEN;
619 case windows::Update::Params::UpdateInfo::STATE_NONE:
622 error_ = keys::kInvalidWindowStateError;
626 if (show_state != ui::SHOW_STATE_FULLSCREEN &&
627 show_state != ui::SHOW_STATE_DEFAULT)
628 controller->SetFullscreenMode(false, extension()->url());
630 switch (show_state) {
631 case ui::SHOW_STATE_MINIMIZED:
632 controller->window()->Minimize();
634 case ui::SHOW_STATE_MAXIMIZED:
635 controller->window()->Maximize();
637 case ui::SHOW_STATE_FULLSCREEN:
638 if (controller->window()->IsMinimized() ||
639 controller->window()->IsMaximized())
640 controller->window()->Restore();
641 controller->SetFullscreenMode(true, extension()->url());
643 case ui::SHOW_STATE_NORMAL:
644 controller->window()->Restore();
651 if (controller->window()->IsMinimized())
652 bounds = controller->window()->GetRestoredBounds();
654 bounds = controller->window()->GetBounds();
655 bool set_bounds = false;
657 // Any part of the bounds can optionally be set by the caller.
658 if (params->update_info.left) {
659 bounds.set_x(*params->update_info.left);
663 if (params->update_info.top) {
664 bounds.set_y(*params->update_info.top);
668 if (params->update_info.width) {
669 bounds.set_width(*params->update_info.width);
673 if (params->update_info.height) {
674 bounds.set_height(*params->update_info.height);
679 if (show_state == ui::SHOW_STATE_MINIMIZED ||
680 show_state == ui::SHOW_STATE_MAXIMIZED ||
681 show_state == ui::SHOW_STATE_FULLSCREEN) {
682 error_ = keys::kInvalidWindowStateError;
685 // TODO(varkha): Updating bounds during a drag can cause problems and a more
686 // general solution is needed. See http://crbug.com/251813 .
687 controller->window()->SetBounds(bounds);
690 if (params->update_info.focused) {
691 if (*params->update_info.focused) {
692 if (show_state == ui::SHOW_STATE_MINIMIZED) {
693 error_ = keys::kInvalidWindowStateError;
696 controller->window()->Activate();
698 if (show_state == ui::SHOW_STATE_MAXIMIZED ||
699 show_state == ui::SHOW_STATE_FULLSCREEN) {
700 error_ = keys::kInvalidWindowStateError;
703 controller->window()->Deactivate();
707 if (params->update_info.draw_attention)
708 controller->window()->FlashFrame(*params->update_info.draw_attention);
710 SetResult(controller->CreateWindowValue());
715 bool WindowsRemoveFunction::RunSync() {
716 scoped_ptr<windows::Remove::Params> params(
717 windows::Remove::Params::Create(*args_));
718 EXTENSION_FUNCTION_VALIDATE(params);
720 WindowController* controller;
721 if (!windows_util::GetWindowFromWindowID(this, params->window_id,
725 WindowController::Reason reason;
726 if (!controller->CanClose(&reason)) {
727 if (reason == WindowController::REASON_NOT_EDITABLE)
728 error_ = keys::kTabStripNotEditableError;
731 controller->window()->Close();
735 // Tabs ------------------------------------------------------------------------
737 bool TabsGetSelectedFunction::RunSync() {
738 // windowId defaults to "current" window.
739 int window_id = extension_misc::kCurrentWindowId;
741 scoped_ptr<tabs::GetSelected::Params> params(
742 tabs::GetSelected::Params::Create(*args_));
743 EXTENSION_FUNCTION_VALIDATE(params.get());
744 if (params->window_id.get())
745 window_id = *params->window_id;
747 Browser* browser = NULL;
748 if (!GetBrowserFromWindowID(this, window_id, &browser))
751 TabStripModel* tab_strip = browser->tab_strip_model();
752 WebContents* contents = tab_strip->GetActiveWebContents();
754 error_ = keys::kNoSelectedTabError;
757 SetResult(ExtensionTabUtil::CreateTabValue(
758 contents, tab_strip, tab_strip->active_index(), extension()));
762 bool TabsGetAllInWindowFunction::RunSync() {
763 scoped_ptr<tabs::GetAllInWindow::Params> params(
764 tabs::GetAllInWindow::Params::Create(*args_));
765 EXTENSION_FUNCTION_VALIDATE(params.get());
766 // windowId defaults to "current" window.
767 int window_id = extension_misc::kCurrentWindowId;
768 if (params->window_id.get())
769 window_id = *params->window_id;
771 Browser* browser = NULL;
772 if (!GetBrowserFromWindowID(this, window_id, &browser))
775 SetResult(ExtensionTabUtil::CreateTabList(browser, extension()));
780 bool TabsQueryFunction::RunSync() {
781 scoped_ptr<tabs::Query::Params> params(tabs::Query::Params::Create(*args_));
782 EXTENSION_FUNCTION_VALIDATE(params.get());
784 bool loading_status_set = params->query_info.status !=
785 tabs::Query::Params::QueryInfo::STATUS_NONE;
786 bool loading = params->query_info.status ==
787 tabs::Query::Params::QueryInfo::STATUS_LOADING;
789 // It is o.k. to use URLPattern::SCHEME_ALL here because this function does
790 // not grant access to the content of the tabs, only to seeing their URLs and
792 URLPattern url_pattern(URLPattern::SCHEME_ALL, "<all_urls>");
793 if (params->query_info.url.get())
794 url_pattern = URLPattern(URLPattern::SCHEME_ALL, *params->query_info.url);
797 if (params->query_info.title.get())
798 title = *params->query_info.title;
800 int window_id = extension_misc::kUnknownWindowId;
801 if (params->query_info.window_id.get())
802 window_id = *params->query_info.window_id;
805 if (params->query_info.index.get())
806 index = *params->query_info.index;
808 std::string window_type;
809 if (params->query_info.window_type !=
810 tabs::Query::Params::QueryInfo::WINDOW_TYPE_NONE) {
811 window_type = tabs::Query::Params::QueryInfo::ToString(
812 params->query_info.window_type);
815 base::ListValue* result = new base::ListValue();
816 Browser* last_active_browser = chrome::FindAnyBrowser(
817 GetProfile(), include_incognito(), chrome::GetActiveDesktop());
818 Browser* current_browser = GetCurrentBrowser();
819 for (chrome::BrowserIterator it; !it.done(); it.Next()) {
820 Browser* browser = *it;
821 if (!GetProfile()->IsSameProfile(browser->profile()))
824 if (!browser->window())
827 if (!include_incognito() && GetProfile() != browser->profile())
830 if (window_id >= 0 && window_id != ExtensionTabUtil::GetWindowId(browser))
833 if (window_id == extension_misc::kCurrentWindowId &&
834 browser != current_browser) {
838 if (!MatchesBool(params->query_info.current_window.get(),
839 browser == current_browser)) {
843 if (!MatchesBool(params->query_info.last_focused_window.get(),
844 browser == last_active_browser)) {
848 if (!window_type.empty() &&
850 browser->extension_window_controller()->GetWindowTypeText()) {
854 TabStripModel* tab_strip = browser->tab_strip_model();
855 for (int i = 0; i < tab_strip->count(); ++i) {
856 WebContents* web_contents = tab_strip->GetWebContentsAt(i);
858 if (index > -1 && i != index)
861 if (!MatchesBool(params->query_info.highlighted.get(),
862 tab_strip->IsTabSelected(i))) {
866 if (!MatchesBool(params->query_info.active.get(),
867 i == tab_strip->active_index())) {
871 if (!MatchesBool(params->query_info.pinned.get(),
872 tab_strip->IsTabPinned(i))) {
876 if (!title.empty() && !MatchPattern(web_contents->GetTitle(),
877 base::UTF8ToUTF16(title)))
880 if (!url_pattern.MatchesURL(web_contents->GetURL()))
883 if (loading_status_set && loading != web_contents->IsLoading())
886 result->Append(ExtensionTabUtil::CreateTabValue(
887 web_contents, tab_strip, i, extension()));
895 bool TabsCreateFunction::RunSync() {
896 scoped_ptr<tabs::Create::Params> params(tabs::Create::Params::Create(*args_));
897 EXTENSION_FUNCTION_VALIDATE(params.get());
899 ExtensionTabUtil::OpenTabParams options;
900 AssignOptionalValue(params->create_properties.window_id, options.window_id);
901 AssignOptionalValue(params->create_properties.opener_tab_id,
902 options.opener_tab_id);
903 AssignOptionalValue(params->create_properties.selected, options.active);
904 // The 'active' property has replaced the 'selected' property.
905 AssignOptionalValue(params->create_properties.active, options.active);
906 AssignOptionalValue(params->create_properties.pinned, options.pinned);
907 AssignOptionalValue(params->create_properties.index, options.index);
908 AssignOptionalValue(params->create_properties.url, options.url);
911 scoped_ptr<base::DictionaryValue> result(
912 ExtensionTabUtil::OpenTab(this, options, &error));
918 // Return data about the newly created tab.
919 if (has_callback()) {
920 SetResult(result.release());
925 bool TabsDuplicateFunction::RunSync() {
926 scoped_ptr<tabs::Duplicate::Params> params(
927 tabs::Duplicate::Params::Create(*args_));
928 EXTENSION_FUNCTION_VALIDATE(params.get());
929 int tab_id = params->tab_id;
931 Browser* browser = NULL;
932 TabStripModel* tab_strip = NULL;
934 if (!GetTabById(tab_id,
945 WebContents* new_contents = chrome::DuplicateTabAt(browser, tab_index);
949 // Duplicated tab may not be in the same window as the original, so find
950 // the window and the tab.
951 TabStripModel* new_tab_strip = NULL;
952 int new_tab_index = -1;
953 ExtensionTabUtil::GetTabStripModel(new_contents,
956 if (!new_tab_strip || new_tab_index == -1) {
960 // Return data about the newly created tab.
961 SetResult(ExtensionTabUtil::CreateTabValue(
962 new_contents, new_tab_strip, new_tab_index, extension()));
967 bool TabsGetFunction::RunSync() {
968 scoped_ptr<tabs::Get::Params> params(tabs::Get::Params::Create(*args_));
969 EXTENSION_FUNCTION_VALIDATE(params.get());
970 int tab_id = params->tab_id;
972 TabStripModel* tab_strip = NULL;
973 WebContents* contents = NULL;
975 if (!GetTabById(tab_id,
985 SetResult(ExtensionTabUtil::CreateTabValue(
986 contents, tab_strip, tab_index, extension()));
990 bool TabsGetCurrentFunction::RunSync() {
991 DCHECK(dispatcher());
993 // Return the caller, if it's a tab. If not the result isn't an error but an
994 // empty tab (hence returning true).
995 WebContents* caller_contents =
996 WebContents::FromRenderViewHost(render_view_host());
997 if (caller_contents && ExtensionTabUtil::GetTabId(caller_contents) >= 0)
998 SetResult(ExtensionTabUtil::CreateTabValue(caller_contents, extension()));
1003 bool TabsHighlightFunction::RunSync() {
1004 scoped_ptr<tabs::Highlight::Params> params(
1005 tabs::Highlight::Params::Create(*args_));
1006 EXTENSION_FUNCTION_VALIDATE(params.get());
1008 // Get the window id from the params; default to current window if omitted.
1009 int window_id = extension_misc::kCurrentWindowId;
1010 if (params->highlight_info.window_id.get())
1011 window_id = *params->highlight_info.window_id;
1013 Browser* browser = NULL;
1014 if (!GetBrowserFromWindowID(this, window_id, &browser))
1017 TabStripModel* tabstrip = browser->tab_strip_model();
1018 ui::ListSelectionModel selection;
1019 int active_index = -1;
1021 if (params->highlight_info.tabs.as_integers) {
1022 std::vector<int>& tab_indices = *params->highlight_info.tabs.as_integers;
1023 // Create a new selection model as we read the list of tab indices.
1024 for (size_t i = 0; i < tab_indices.size(); ++i) {
1025 if (!HighlightTab(tabstrip, &selection, &active_index, tab_indices[i]))
1029 EXTENSION_FUNCTION_VALIDATE(params->highlight_info.tabs.as_integer);
1030 if (!HighlightTab(tabstrip,
1033 *params->highlight_info.tabs.as_integer)) {
1038 // Make sure they actually specified tabs to select.
1039 if (selection.empty()) {
1040 error_ = keys::kNoHighlightedTabError;
1044 selection.set_active(active_index);
1045 browser->tab_strip_model()->SetSelectionFromModel(selection);
1046 SetResult(browser->extension_window_controller()->CreateWindowValueWithTabs(
1051 bool TabsHighlightFunction::HighlightTab(TabStripModel* tabstrip,
1052 ui::ListSelectionModel* selection,
1055 // Make sure the index is in range.
1056 if (!tabstrip->ContainsIndex(index)) {
1057 error_ = ErrorUtils::FormatErrorMessage(
1058 keys::kTabIndexNotFoundError, base::IntToString(index));
1062 // By default, we make the first tab in the list active.
1063 if (*active_index == -1)
1064 *active_index = index;
1066 selection->AddIndexToSelection(index);
1070 TabsUpdateFunction::TabsUpdateFunction() : web_contents_(NULL) {
1073 bool TabsUpdateFunction::RunAsync() {
1074 scoped_ptr<tabs::Update::Params> params(tabs::Update::Params::Create(*args_));
1075 EXTENSION_FUNCTION_VALIDATE(params.get());
1078 WebContents* contents = NULL;
1079 if (!params->tab_id.get()) {
1080 Browser* browser = GetCurrentBrowser();
1082 error_ = keys::kNoCurrentWindowError;
1085 contents = browser->tab_strip_model()->GetActiveWebContents();
1087 error_ = keys::kNoSelectedTabError;
1090 tab_id = SessionID::IdForTab(contents);
1092 tab_id = *params->tab_id;
1096 TabStripModel* tab_strip = NULL;
1097 if (!GetTabById(tab_id,
1099 include_incognito(),
1108 web_contents_ = contents;
1110 // TODO(rafaelw): handle setting remaining tab properties:
1114 // Navigate the tab to a new location if the url is different.
1115 bool is_async = false;
1116 if (params->update_properties.url.get() &&
1117 !UpdateURL(*params->update_properties.url, tab_id, &is_async)) {
1121 bool active = false;
1122 // TODO(rafaelw): Setting |active| from js doesn't make much sense.
1123 // Move tab selection management up to window.
1124 if (params->update_properties.selected.get())
1125 active = *params->update_properties.selected;
1127 // The 'active' property has replaced 'selected'.
1128 if (params->update_properties.active.get())
1129 active = *params->update_properties.active;
1132 if (tab_strip->active_index() != tab_index) {
1133 tab_strip->ActivateTabAt(tab_index, false);
1134 DCHECK_EQ(contents, tab_strip->GetActiveWebContents());
1138 if (params->update_properties.highlighted.get()) {
1139 bool highlighted = *params->update_properties.highlighted;
1140 if (highlighted != tab_strip->IsTabSelected(tab_index))
1141 tab_strip->ToggleSelectionAt(tab_index);
1144 if (params->update_properties.pinned.get()) {
1145 bool pinned = *params->update_properties.pinned;
1146 tab_strip->SetTabPinned(tab_index, pinned);
1148 // Update the tab index because it may move when being pinned.
1149 tab_index = tab_strip->GetIndexOfWebContents(contents);
1152 if (params->update_properties.opener_tab_id.get()) {
1153 int opener_id = *params->update_properties.opener_tab_id;
1155 WebContents* opener_contents = NULL;
1156 if (!ExtensionTabUtil::GetTabById(opener_id,
1158 include_incognito(),
1165 tab_strip->SetOpenerOfWebContentsAt(tab_index, opener_contents);
1175 bool TabsUpdateFunction::UpdateURL(const std::string &url_string,
1179 ExtensionTabUtil::ResolvePossiblyRelativeURL(url_string, extension());
1181 if (!url.is_valid()) {
1182 error_ = ErrorUtils::FormatErrorMessage(
1183 keys::kInvalidUrlError, url_string);
1187 // Don't let the extension crash the browser or renderers.
1188 if (ExtensionTabUtil::IsCrashURL(url)) {
1189 error_ = keys::kNoCrashBrowserError;
1193 // JavaScript URLs can do the same kinds of things as cross-origin XHR, so
1194 // we need to check host permissions before allowing them.
1195 if (url.SchemeIs(url::kJavaScriptScheme)) {
1196 content::RenderProcessHost* process = web_contents_->GetRenderProcessHost();
1197 if (!extension()->permissions_data()->CanAccessPage(
1199 web_contents_->GetURL(),
1200 web_contents_->GetURL(),
1202 process ? process->GetID() : -1,
1207 TabHelper::FromWebContents(web_contents_)->script_executor()->ExecuteScript(
1209 ScriptExecutor::JAVASCRIPT,
1211 ScriptExecutor::TOP_FRAME,
1212 ScriptExecutor::DONT_MATCH_ABOUT_BLANK,
1213 UserScript::DOCUMENT_IDLE,
1214 ScriptExecutor::MAIN_WORLD,
1215 ScriptExecutor::DEFAULT_PROCESS,
1219 ScriptExecutor::NO_RESULT,
1220 base::Bind(&TabsUpdateFunction::OnExecuteCodeFinished, this));
1226 web_contents_->GetController().LoadURL(
1227 url, content::Referrer(), content::PAGE_TRANSITION_LINK, std::string());
1229 // The URL of a tab contents never actually changes to a JavaScript URL, so
1230 // this check only makes sense in other cases.
1231 if (!url.SchemeIs(url::kJavaScriptScheme))
1232 DCHECK_EQ(url.spec(), web_contents_->GetURL().spec());
1237 void TabsUpdateFunction::PopulateResult() {
1238 if (!has_callback())
1241 SetResult(ExtensionTabUtil::CreateTabValue(web_contents_, extension()));
1244 void TabsUpdateFunction::OnExecuteCodeFinished(
1245 const std::string& error,
1247 const base::ListValue& script_result) {
1252 SendResponse(error.empty());
1255 bool TabsMoveFunction::RunSync() {
1256 scoped_ptr<tabs::Move::Params> params(tabs::Move::Params::Create(*args_));
1257 EXTENSION_FUNCTION_VALIDATE(params.get());
1259 int new_index = params->move_properties.index;
1260 int* window_id = params->move_properties.window_id.get();
1261 scoped_ptr<base::ListValue> tab_values(new base::ListValue());
1263 size_t num_tabs = 0;
1264 if (params->tab_ids.as_integers) {
1265 std::vector<int>& tab_ids = *params->tab_ids.as_integers;
1266 num_tabs = tab_ids.size();
1267 for (size_t i = 0; i < tab_ids.size(); ++i) {
1268 if (!MoveTab(tab_ids[i], &new_index, i, tab_values.get(), window_id))
1272 EXTENSION_FUNCTION_VALIDATE(params->tab_ids.as_integer);
1274 if (!MoveTab(*params->tab_ids.as_integer,
1283 if (!has_callback())
1286 if (num_tabs == 0) {
1287 error_ = "No tabs given.";
1289 } else if (num_tabs == 1) {
1290 scoped_ptr<base::Value> value;
1291 CHECK(tab_values.get()->Remove(0, &value));
1292 SetResult(value.release());
1294 // Only return the results as an array if there are multiple tabs.
1295 SetResult(tab_values.release());
1301 bool TabsMoveFunction::MoveTab(int tab_id,
1304 base::ListValue* tab_values,
1306 Browser* source_browser = NULL;
1307 TabStripModel* source_tab_strip = NULL;
1308 WebContents* contents = NULL;
1310 if (!GetTabById(tab_id,
1312 include_incognito(),
1321 // Don't let the extension move the tab if the user is dragging tabs.
1322 if (!source_browser->window()->IsTabStripEditable()) {
1323 error_ = keys::kTabStripNotEditableError;
1327 // Insert the tabs one after another.
1328 *new_index += iteration;
1331 Browser* target_browser = NULL;
1333 if (!GetBrowserFromWindowID(this, *window_id, &target_browser))
1336 if (!target_browser->window()->IsTabStripEditable()) {
1337 error_ = keys::kTabStripNotEditableError;
1341 if (!target_browser->is_type_tabbed()) {
1342 error_ = keys::kCanOnlyMoveTabsWithinNormalWindowsError;
1346 if (target_browser->profile() != source_browser->profile()) {
1347 error_ = keys::kCanOnlyMoveTabsWithinSameProfileError;
1351 // If windowId is different from the current window, move between windows.
1352 if (ExtensionTabUtil::GetWindowId(target_browser) !=
1353 ExtensionTabUtil::GetWindowId(source_browser)) {
1354 TabStripModel* target_tab_strip = target_browser->tab_strip_model();
1355 WebContents* web_contents =
1356 source_tab_strip->DetachWebContentsAt(tab_index);
1357 if (!web_contents) {
1358 error_ = ErrorUtils::FormatErrorMessage(
1359 keys::kTabNotFoundError, base::IntToString(tab_id));
1363 // Clamp move location to the last position.
1364 // This is ">" because it can append to a new index position.
1365 // -1 means set the move location to the last position.
1366 if (*new_index > target_tab_strip->count() || *new_index < 0)
1367 *new_index = target_tab_strip->count();
1369 target_tab_strip->InsertWebContentsAt(
1370 *new_index, web_contents, TabStripModel::ADD_NONE);
1372 if (has_callback()) {
1373 tab_values->Append(ExtensionTabUtil::CreateTabValue(
1374 web_contents, target_tab_strip, *new_index, extension()));
1381 // Perform a simple within-window move.
1382 // Clamp move location to the last position.
1383 // This is ">=" because the move must be to an existing location.
1384 // -1 means set the move location to the last position.
1385 if (*new_index >= source_tab_strip->count() || *new_index < 0)
1386 *new_index = source_tab_strip->count() - 1;
1388 if (*new_index != tab_index)
1389 source_tab_strip->MoveWebContentsAt(tab_index, *new_index, false);
1391 if (has_callback()) {
1392 tab_values->Append(ExtensionTabUtil::CreateTabValue(
1393 contents, source_tab_strip, *new_index, extension()));
1399 bool TabsReloadFunction::RunSync() {
1400 scoped_ptr<tabs::Reload::Params> params(
1401 tabs::Reload::Params::Create(*args_));
1402 EXTENSION_FUNCTION_VALIDATE(params.get());
1404 bool bypass_cache = false;
1405 if (params->reload_properties.get() &&
1406 params->reload_properties->bypass_cache.get()) {
1407 bypass_cache = *params->reload_properties->bypass_cache;
1410 content::WebContents* web_contents = NULL;
1412 // If |tab_id| is specified, look for it. Otherwise default to selected tab
1413 // in the current window.
1414 if (!params->tab_id.get()) {
1415 Browser* browser = GetCurrentBrowser();
1417 error_ = keys::kNoCurrentWindowError;
1421 if (!ExtensionTabUtil::GetDefaultTab(browser, &web_contents, NULL))
1424 int tab_id = *params->tab_id;
1426 Browser* browser = NULL;
1427 if (!GetTabById(tab_id,
1429 include_incognito(),
1439 if (web_contents->ShowingInterstitialPage()) {
1440 // This does as same as Browser::ReloadInternal.
1441 NavigationEntry* entry = web_contents->GetController().GetVisibleEntry();
1442 OpenURLParams params(entry->GetURL(), Referrer(), CURRENT_TAB,
1443 content::PAGE_TRANSITION_RELOAD, false);
1444 GetCurrentBrowser()->OpenURL(params);
1445 } else if (bypass_cache) {
1446 web_contents->GetController().ReloadIgnoringCache(true);
1448 web_contents->GetController().Reload(true);
1454 bool TabsRemoveFunction::RunSync() {
1455 scoped_ptr<tabs::Remove::Params> params(tabs::Remove::Params::Create(*args_));
1456 EXTENSION_FUNCTION_VALIDATE(params.get());
1458 if (params->tab_ids.as_integers) {
1459 std::vector<int>& tab_ids = *params->tab_ids.as_integers;
1460 for (size_t i = 0; i < tab_ids.size(); ++i) {
1461 if (!RemoveTab(tab_ids[i]))
1465 EXTENSION_FUNCTION_VALIDATE(params->tab_ids.as_integer);
1466 if (!RemoveTab(*params->tab_ids.as_integer.get()))
1472 bool TabsRemoveFunction::RemoveTab(int tab_id) {
1473 Browser* browser = NULL;
1474 WebContents* contents = NULL;
1475 if (!GetTabById(tab_id,
1477 include_incognito(),
1486 // Don't let the extension remove a tab if the user is dragging tabs around.
1487 if (!browser->window()->IsTabStripEditable()) {
1488 error_ = keys::kTabStripNotEditableError;
1491 // There's a chance that the tab is being dragged, or we're in some other
1492 // nested event loop. This code path ensures that the tab is safely closed
1493 // under such circumstances, whereas |TabStripModel::CloseWebContentsAt()|
1499 bool TabsCaptureVisibleTabFunction::IsScreenshotEnabled() {
1500 PrefService* service = GetProfile()->GetPrefs();
1501 if (service->GetBoolean(prefs::kDisableScreenshots)) {
1502 error_ = keys::kScreenshotsDisabled;
1508 WebContents* TabsCaptureVisibleTabFunction::GetWebContentsForID(int window_id) {
1509 Browser* browser = NULL;
1510 if (!GetBrowserFromWindowID(this, window_id, &browser))
1513 WebContents* contents = browser->tab_strip_model()->GetActiveWebContents();
1515 error_ = keys::kInternalVisibleTabCaptureError;
1519 if (!extension()->permissions_data()->CanCaptureVisiblePage(
1520 SessionID::IdForTab(contents), &error_)) {
1526 void TabsCaptureVisibleTabFunction::OnCaptureFailure(FailureReason reason) {
1527 error_ = keys::kInternalVisibleTabCaptureError;
1528 SendResponse(false);
1531 void TabsCaptureVisibleTabFunction::RegisterProfilePrefs(
1532 user_prefs::PrefRegistrySyncable* registry) {
1533 registry->RegisterBooleanPref(
1534 prefs::kDisableScreenshots,
1536 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
1539 bool TabsDetectLanguageFunction::RunAsync() {
1540 scoped_ptr<tabs::DetectLanguage::Params> params(
1541 tabs::DetectLanguage::Params::Create(*args_));
1542 EXTENSION_FUNCTION_VALIDATE(params.get());
1545 Browser* browser = NULL;
1546 WebContents* contents = NULL;
1548 // If |tab_id| is specified, look for it. Otherwise default to selected tab
1549 // in the current window.
1550 if (params->tab_id.get()) {
1551 tab_id = *params->tab_id;
1552 if (!GetTabById(tab_id,
1554 include_incognito(),
1562 if (!browser || !contents)
1565 browser = GetCurrentBrowser();
1568 contents = browser->tab_strip_model()->GetActiveWebContents();
1573 if (contents->GetController().NeedsReload()) {
1574 // If the tab hasn't been loaded, don't wait for the tab to load.
1575 error_ = keys::kCannotDetermineLanguageOfUnloadedTab;
1579 AddRef(); // Balanced in GotLanguage().
1581 ChromeTranslateClient* chrome_translate_client =
1582 ChromeTranslateClient::FromWebContents(contents);
1583 if (!chrome_translate_client->GetLanguageState()
1584 .original_language()
1586 // Delay the callback invocation until after the current JS call has
1588 base::MessageLoop::current()->PostTask(
1591 &TabsDetectLanguageFunction::GotLanguage,
1593 chrome_translate_client->GetLanguageState().original_language()));
1596 // The tab contents does not know its language yet. Let's wait until it
1597 // receives it, or until the tab is closed/navigates to some other page.
1598 registrar_.Add(this, chrome::NOTIFICATION_TAB_LANGUAGE_DETERMINED,
1599 content::Source<WebContents>(contents));
1601 this, chrome::NOTIFICATION_TAB_CLOSING,
1602 content::Source<NavigationController>(&(contents->GetController())));
1604 this, content::NOTIFICATION_NAV_ENTRY_COMMITTED,
1605 content::Source<NavigationController>(&(contents->GetController())));
1609 void TabsDetectLanguageFunction::Observe(
1611 const content::NotificationSource& source,
1612 const content::NotificationDetails& details) {
1613 std::string language;
1614 if (type == chrome::NOTIFICATION_TAB_LANGUAGE_DETERMINED) {
1615 const translate::LanguageDetectionDetails* lang_det_details =
1616 content::Details<const translate::LanguageDetectionDetails>(details)
1618 language = lang_det_details->adopted_language;
1621 registrar_.RemoveAll();
1623 // Call GotLanguage in all cases as we want to guarantee the callback is
1624 // called for every API call the extension made.
1625 GotLanguage(language);
1628 void TabsDetectLanguageFunction::GotLanguage(const std::string& language) {
1629 SetResult(new base::StringValue(language.c_str()));
1632 Release(); // Balanced in Run()
1635 ExecuteCodeInTabFunction::ExecuteCodeInTabFunction()
1636 : execute_tab_id_(-1) {
1639 ExecuteCodeInTabFunction::~ExecuteCodeInTabFunction() {}
1641 bool ExecuteCodeInTabFunction::HasPermission() {
1643 extension_->permissions_data()->HasAPIPermissionForTab(
1644 execute_tab_id_, APIPermission::kTab)) {
1647 return ExtensionFunction::HasPermission();
1650 bool ExecuteCodeInTabFunction::CanExecuteScriptOnPage() {
1651 content::WebContents* contents = NULL;
1653 // If |tab_id| is specified, look for the tab. Otherwise default to selected
1654 // tab in the current window.
1655 CHECK_GE(execute_tab_id_, 0);
1656 if (!GetTabById(execute_tab_id_,
1658 include_incognito(),
1669 // NOTE: This can give the wrong answer due to race conditions, but it is OK,
1670 // we check again in the renderer.
1671 content::RenderProcessHost* process = contents->GetRenderProcessHost();
1672 if (!extension()->permissions_data()->CanAccessPage(
1677 process ? process->GetID() : -1,
1685 ScriptExecutor* ExecuteCodeInTabFunction::GetScriptExecutor() {
1686 Browser* browser = NULL;
1687 content::WebContents* contents = NULL;
1689 bool success = GetTabById(execute_tab_id_,
1691 include_incognito(),
1697 contents && browser;
1702 return TabHelper::FromWebContents(contents)->script_executor();
1705 bool ExecuteCodeInTabFunction::IsWebView() const {
1709 const GURL& ExecuteCodeInTabFunction::GetWebViewSrc() const {
1710 return GURL::EmptyGURL();
1713 bool TabsExecuteScriptFunction::ShouldInsertCSS() const {
1717 void TabsExecuteScriptFunction::OnExecuteCodeFinished(
1718 const std::string& error,
1720 const base::ListValue& result) {
1722 SetResult(result.DeepCopy());
1723 ExecuteCodeInTabFunction::OnExecuteCodeFinished(error, on_url, result);
1726 bool ExecuteCodeInTabFunction::Init() {
1730 // |tab_id| is optional so it's ok if it's not there.
1732 if (args_->GetInteger(0, &tab_id))
1733 EXTENSION_FUNCTION_VALIDATE(tab_id >= 0);
1735 // |details| are not optional.
1736 base::DictionaryValue* details_value = NULL;
1737 if (!args_->GetDictionary(1, &details_value))
1739 scoped_ptr<InjectDetails> details(new InjectDetails());
1740 if (!InjectDetails::Populate(*details_value, details.get()))
1743 // If the tab ID wasn't given then it needs to be converted to the
1744 // currently active tab's ID.
1746 Browser* browser = GetCurrentBrowser();
1749 content::WebContents* web_contents = NULL;
1750 if (!ExtensionTabUtil::GetDefaultTab(browser, &web_contents, &tab_id))
1754 execute_tab_id_ = tab_id;
1755 details_ = details.Pass();
1759 bool TabsInsertCSSFunction::ShouldInsertCSS() const {
1763 content::WebContents* ZoomAPIFunction::GetWebContents(int tab_id) {
1764 content::WebContents* web_contents = NULL;
1766 // We assume this call leaves web_contents unchanged if it is unsuccessful.
1769 include_incognito(),
1770 NULL /* ignore Browser* output */,
1771 NULL /* ignore TabStripModel* output */,
1773 NULL /* ignore int tab_index output */,
1776 Browser* browser = GetCurrentBrowser();
1778 error_ = keys::kNoCurrentWindowError;
1779 else if (!ExtensionTabUtil::GetDefaultTab(browser, &web_contents, NULL))
1780 error_ = keys::kNoSelectedTabError;
1782 return web_contents;
1785 bool TabsSetZoomFunction::RunAsync() {
1786 scoped_ptr<tabs::SetZoom::Params> params(
1787 tabs::SetZoom::Params::Create(*args_));
1788 EXTENSION_FUNCTION_VALIDATE(params);
1790 int tab_id = params->tab_id ? *params->tab_id : -1;
1791 WebContents* web_contents = GetWebContents(tab_id);
1795 GURL url(web_contents->GetVisibleURL());
1796 if (PermissionsData::IsRestrictedUrl(url, url, extension(), &error_))
1799 ZoomController* zoom_controller =
1800 ZoomController::FromWebContents(web_contents);
1801 double zoom_level = content::ZoomFactorToZoomLevel(params->zoom_factor);
1803 if (!zoom_controller->SetZoomLevelByExtension(zoom_level, extension())) {
1804 // Tried to zoom a tab in disabled mode.
1805 error_ = keys::kCannotZoomDisabledTabError;
1813 bool TabsGetZoomFunction::RunAsync() {
1814 scoped_ptr<tabs::GetZoom::Params> params(
1815 tabs::GetZoom::Params::Create(*args_));
1816 EXTENSION_FUNCTION_VALIDATE(params);
1818 int tab_id = params->tab_id ? *params->tab_id : -1;
1819 WebContents* web_contents = GetWebContents(tab_id);
1824 ZoomController::FromWebContents(web_contents)->GetZoomLevel();
1825 double zoom_factor = content::ZoomLevelToZoomFactor(zoom_level);
1826 results_ = tabs::GetZoom::Results::Create(zoom_factor);
1831 bool TabsSetZoomSettingsFunction::RunAsync() {
1832 using api::tabs::ZoomSettings;
1834 scoped_ptr<tabs::SetZoomSettings::Params> params(
1835 tabs::SetZoomSettings::Params::Create(*args_));
1836 EXTENSION_FUNCTION_VALIDATE(params);
1838 int tab_id = params->tab_id ? *params->tab_id : -1;
1839 WebContents* web_contents = GetWebContents(tab_id);
1843 GURL url(web_contents->GetVisibleURL());
1844 if (PermissionsData::IsRestrictedUrl(url, url, extension(), &error_))
1847 // "per-origin" scope is only available in "automatic" mode.
1848 if (params->zoom_settings.scope == ZoomSettings::SCOPE_PER_ORIGIN &&
1849 params->zoom_settings.mode != ZoomSettings::MODE_AUTOMATIC &&
1850 params->zoom_settings.mode != ZoomSettings::MODE_NONE) {
1851 error_ = keys::kPerOriginOnlyInAutomaticError;
1855 // Determine the correct internal zoom mode to set |web_contents| to from the
1856 // user-specified |zoom_settings|.
1857 ZoomController::ZoomMode zoom_mode = ZoomController::ZOOM_MODE_DEFAULT;
1858 switch (params->zoom_settings.mode) {
1859 case ZoomSettings::MODE_NONE:
1860 case ZoomSettings::MODE_AUTOMATIC:
1861 switch (params->zoom_settings.scope) {
1862 case ZoomSettings::SCOPE_NONE:
1863 case ZoomSettings::SCOPE_PER_ORIGIN:
1864 zoom_mode = ZoomController::ZOOM_MODE_DEFAULT;
1866 case ZoomSettings::SCOPE_PER_TAB:
1867 zoom_mode = ZoomController::ZOOM_MODE_ISOLATED;
1870 case ZoomSettings::MODE_MANUAL:
1871 zoom_mode = ZoomController::ZOOM_MODE_MANUAL;
1873 case ZoomSettings::MODE_DISABLED:
1874 zoom_mode = ZoomController::ZOOM_MODE_DISABLED;
1877 ZoomController::FromWebContents(web_contents)->SetZoomMode(zoom_mode);
1883 bool TabsGetZoomSettingsFunction::RunAsync() {
1884 scoped_ptr<tabs::GetZoomSettings::Params> params(
1885 tabs::GetZoomSettings::Params::Create(*args_));
1886 EXTENSION_FUNCTION_VALIDATE(params);
1888 int tab_id = params->tab_id ? *params->tab_id : -1;
1889 WebContents* web_contents = GetWebContents(tab_id);
1892 ZoomController* zoom_controller =
1893 ZoomController::FromWebContents(web_contents);
1895 ZoomController::ZoomMode zoom_mode = zoom_controller->zoom_mode();
1896 api::tabs::ZoomSettings zoom_settings;
1897 ZoomModeToZoomSettings(zoom_mode, &zoom_settings);
1899 results_ = api::tabs::GetZoomSettings::Results::Create(zoom_settings);
1904 } // namespace extensions