172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/extensions/extension_tabs_module.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include <algorithm>
821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include <vector>
921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/base64.h"
113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/string_number_conversions.h"
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/string_util.h"
133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/stringprintf.h"
143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/utf_string_conversions.h"
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/extensions/extension_function_dispatcher.h"
16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/extensions/extension_host.h"
1721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/extensions/extension_service.h"
18ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/extensions/extension_tabs_module_constants.h"
1921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/profiles/profile.h"
20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/tabs/tab_strip_model.h"
21ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/translate/translate_tab_helper.h"
224a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "chrome/browser/ui/browser.h"
23ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/ui/browser_list.h"
244a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "chrome/browser/ui/browser_navigator.h"
25ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/ui/browser_window.h"
2621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
2721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/ui/window_sizer.h"
28ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/common/chrome_switches.h"
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/extensions/extension.h"
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/extensions/extension_error_utils.h"
31ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/common/extensions/extension_messages.h"
3272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/common/pref_names.h"
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/url_constants.h"
34dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/renderer_host/backing_store.h"
35dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/renderer_host/render_view_host.h"
36dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/renderer_host/render_view_host_delegate.h"
37dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/tab_contents/navigation_entry.h"
38dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/tab_contents/tab_contents.h"
39ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/browser/tab_contents/tab_contents_view.h"
40ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_service.h"
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "skia/ext/image_operations.h"
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "skia/ext/platform_canvas.h"
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "third_party/skia/include/core/SkBitmap.h"
4472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/gfx/codec/jpeg_codec.h"
4572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/gfx/codec/png_codec.h"
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace keys = extension_tabs_module_constants;
48ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsennamespace errors = extension_manifest_errors;
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int CaptureVisibleTabFunction::kDefaultQuality = 90;
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Forward declare static helper functions defined below.
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// |error_message| can optionally be passed in a will be set with an appropriate
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// message if the window cannot be found by id.
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic Browser* GetBrowserInProfileWithId(Profile* profile,
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                          const int window_id,
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                          bool include_incognito,
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                          std::string* error_message);
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// |error_message| can optionally be passed in and will be set with an
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// appropriate message if the tab cannot be found by id.
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic bool GetTabById(int tab_id, Profile* profile,
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                       bool include_incognito,
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                       Browser** browser,
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                       TabStripModel** tab_strip,
67201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                       TabContentsWrapper** contents,
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                       int* tab_index, std::string* error_message);
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Takes |url_string| and returns a GURL which is either valid and absolute
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// or invalid. If |url_string| is not directly interpretable as a valid (it is
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// likely a relative URL) an attempt is made to resolve it. |extension| is
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// provided so it can be resolved relative to its extension base
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// (chrome-extension://<id>/). Using the source frame url would be more correct,
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// but because the api shipped with urls resolved relative to their extension
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// base, we decided it wasn't worth breaking existing extensions to fix.
77ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenstatic GURL ResolvePossiblyRelativeURL(const std::string& url_string,
78513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                                       const Extension* extension);
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Return the type name for a browser window type.
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic std::string GetWindowTypeText(Browser::Type type);
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint ExtensionTabUtil::GetWindowId(const Browser* browser) {
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return browser->session_id().id();
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint ExtensionTabUtil::GetTabId(const TabContents* tab_contents) {
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return tab_contents->controller().session_id().id();
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstd::string ExtensionTabUtil::GetTabStatusText(bool is_loading) {
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return is_loading ? keys::kStatusValueLoading : keys::kStatusValueComplete;
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint ExtensionTabUtil::GetWindowIdOfTab(const TabContents* tab_contents) {
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return tab_contents->controller().window_id().id();
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochDictionaryValue* ExtensionTabUtil::CreateTabValue(
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const TabContents* contents) {
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Find the tab strip and index of this guy.
102513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  TabStripModel* tab_strip = NULL;
103513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  int tab_index;
104513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (ExtensionTabUtil::GetTabStripModel(contents, &tab_strip, &tab_index))
105513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    return ExtensionTabUtil::CreateTabValue(contents, tab_strip, tab_index);
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Couldn't find it.  This can happen if the tab is being dragged.
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return ExtensionTabUtil::CreateTabValue(contents, NULL, -1);
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochListValue* ExtensionTabUtil::CreateTabList(const Browser* browser) {
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ListValue* tab_list = new ListValue();
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TabStripModel* tab_strip = browser->tabstrip_model();
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (int i = 0; i < tab_strip->count(); ++i) {
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    tab_list->Append(ExtensionTabUtil::CreateTabValue(
116201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch        tab_strip->GetTabContentsAt(i)->tab_contents(), tab_strip, i));
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return tab_list;
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochDictionaryValue* ExtensionTabUtil::CreateTabValue(
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const TabContents* contents, TabStripModel* tab_strip, int tab_index) {
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DictionaryValue* result = new DictionaryValue();
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  result->SetInteger(keys::kIdKey, ExtensionTabUtil::GetTabId(contents));
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  result->SetInteger(keys::kIndexKey, tab_index);
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  result->SetInteger(keys::kWindowIdKey,
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                     ExtensionTabUtil::GetWindowIdOfTab(contents));
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  result->SetString(keys::kUrlKey, contents->GetURL().spec());
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  result->SetString(keys::kStatusKey, GetTabStatusText(contents->is_loading()));
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  result->SetBoolean(keys::kSelectedKey,
132ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                     tab_strip && tab_index == tab_strip->active_index());
133513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  result->SetBoolean(keys::kPinnedKey,
134513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                     tab_strip && tab_strip->IsTabPinned(tab_index));
1353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  result->SetString(keys::kTitleKey, contents->GetTitle());
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  result->SetBoolean(keys::kIncognitoKey,
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                     contents->profile()->IsOffTheRecord());
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!contents->is_loading()) {
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    NavigationEntry* entry = contents->controller().GetActiveEntry();
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (entry) {
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (entry->favicon().is_valid())
143ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        result->SetString(keys::kFaviconUrlKey, entry->favicon().url().spec());
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return result;
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// if |populate| is true, each window gets a list property |tabs| which contains
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// fully populated tab objects.
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochDictionaryValue* ExtensionTabUtil::CreateWindowValue(const Browser* browser,
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                     bool populate_tabs) {
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(browser);
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(browser->window());
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DictionaryValue* result = new DictionaryValue();
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  result->SetInteger(keys::kIdKey, ExtensionTabUtil::GetWindowId(browser));
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  result->SetBoolean(keys::kIncognitoKey,
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                     browser->profile()->IsOffTheRecord());
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  result->SetBoolean(keys::kFocusedKey, browser->window()->IsActive());
16172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  gfx::Rect bounds;
16272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (browser->window()->IsMaximized() || browser->window()->IsFullscreen())
16372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    bounds = browser->window()->GetBounds();
16472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  else
16572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    bounds = browser->window()->GetRestoredBounds();
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  result->SetInteger(keys::kLeftKey, bounds.x());
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  result->SetInteger(keys::kTopKey, bounds.y());
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  result->SetInteger(keys::kWidthKey, bounds.width());
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  result->SetInteger(keys::kHeightKey, bounds.height());
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  result->SetString(keys::kWindowTypeKey, GetWindowTypeText(browser->type()));
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (populate_tabs) {
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    result->Set(keys::kTabsKey, ExtensionTabUtil::CreateTabList(browser));
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return result;
178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
180513209b27ff55e2841eac0e4120199c23acce758Ben Murdochbool ExtensionTabUtil::GetTabStripModel(const TabContents* tab_contents,
181513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                                        TabStripModel** tab_strip_model,
182513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                                        int* tab_index) {
183513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  DCHECK(tab_contents);
184513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  DCHECK(tab_strip_model);
185513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  DCHECK(tab_index);
186513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
187513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  for (BrowserList::const_iterator it = BrowserList::begin();
188513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      it != BrowserList::end(); ++it) {
189513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    TabStripModel* tab_strip = (*it)->tabstrip_model();
190201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    int index = tab_strip->GetWrapperIndex(tab_contents);
191513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    if (index != -1) {
192513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      *tab_strip_model = tab_strip;
193513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      *tab_index = index;
194513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      return true;
195513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    }
196513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
197513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
198513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return false;
199513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
200513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
201201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochbool ExtensionTabUtil::GetDefaultTab(Browser* browser,
202201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                                     TabContentsWrapper** contents,
203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                     int* tab_id) {
204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(browser);
205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(contents);
206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(tab_id);
207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
208201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  *contents = browser->GetSelectedTabContentsWrapper();
209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (*contents) {
210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (tab_id)
211201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      *tab_id = ExtensionTabUtil::GetTabId((*contents)->tab_contents());
212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return true;
213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return false;
216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool ExtensionTabUtil::GetTabById(int tab_id, Profile* profile,
219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                  bool include_incognito,
220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                  Browser** browser,
221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                  TabStripModel** tab_strip,
222201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                                  TabContentsWrapper** contents,
223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                  int* tab_index) {
224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Profile* incognito_profile =
2253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      include_incognito && profile->HasOffTheRecordProfile() ?
2263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          profile->GetOffTheRecordProfile() : NULL;
227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (BrowserList::const_iterator iter = BrowserList::begin();
228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       iter != BrowserList::end(); ++iter) {
229201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    Browser* target_browser = *iter;
230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (target_browser->profile() == profile ||
231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        target_browser->profile() == incognito_profile) {
232201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      TabStripModel* target_tab_strip = target_browser->tabstrip_model();
233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      for (int i = 0; i < target_tab_strip->count(); ++i) {
234201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch        TabContentsWrapper* target_contents =
235201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch            target_tab_strip->GetTabContentsAt(i);
236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (target_contents->controller().session_id().id() == tab_id) {
237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          if (browser)
238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            *browser = target_browser;
239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          if (tab_strip)
240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            *tab_strip = target_tab_strip;
241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          if (contents)
242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            *contents = target_contents;
243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          if (tab_index)
244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            *tab_index = i;
245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          return true;
246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        }
247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return false;
251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Windows ---------------------------------------------------------------------
254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool GetWindowFunction::RunImpl() {
256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int window_id;
257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &window_id));
258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Browser* browser = GetBrowserInProfileWithId(profile(), window_id,
260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                               include_incognito(), &error_);
261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!browser || !browser->window()) {
262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    error_ = ExtensionErrorUtils::FormatErrorMessage(
2633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        keys::kWindowNotFoundError, base::IntToString(window_id));
264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  result_.reset(ExtensionTabUtil::CreateWindowValue(browser, false));
268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool GetCurrentWindowFunction::RunImpl() {
272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Browser* browser = GetCurrentBrowser();
273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!browser || !browser->window()) {
274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    error_ = keys::kNoCurrentWindowError;
275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  result_.reset(ExtensionTabUtil::CreateWindowValue(browser, false));
278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool GetLastFocusedWindowFunction::RunImpl() {
282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Browser* browser = BrowserList::FindBrowserWithType(
283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      profile(), Browser::TYPE_ANY, include_incognito());
284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!browser || !browser->window()) {
285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    error_ = keys::kNoLastFocusedWindowError;
286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  result_.reset(ExtensionTabUtil::CreateWindowValue(browser, false));
289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool GetAllWindowsFunction::RunImpl() {
293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool populate_tabs = false;
294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (HasOptionalArgument(0)) {
295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DictionaryValue* args;
296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args));
297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (args->HasKey(keys::kPopulateKey)) {
299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      EXTENSION_FUNCTION_VALIDATE(args->GetBoolean(keys::kPopulateKey,
300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          &populate_tabs));
301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  result_.reset(new ListValue());
305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Profile* incognito_profile =
3063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      include_incognito() && profile()->HasOffTheRecordProfile() ?
3073345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          profile()->GetOffTheRecordProfile() : NULL;
308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (BrowserList::const_iterator browser = BrowserList::begin();
309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    browser != BrowserList::end(); ++browser) {
310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Only examine browsers in the current profile that have windows.
311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (((*browser)->profile() == profile() ||
312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch           (*browser)->profile() == incognito_profile) &&
313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          (*browser)->window()) {
314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        static_cast<ListValue*>(result_.get())->
315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          Append(ExtensionTabUtil::CreateWindowValue(*browser, populate_tabs));
316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool CreateWindowFunction::RunImpl() {
323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DictionaryValue* args = NULL;
324731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  std::vector<GURL> urls;
32521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  TabContentsWrapper* contents = NULL;
326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (HasOptionalArgument(0))
328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args));
329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Look for optional url.
331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (args) {
332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (args->HasKey(keys::kUrlKey)) {
333731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      Value* url_value;
334731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      std::vector<std::string> url_strings;
335731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      args->Get(keys::kUrlKey, &url_value);
336731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
337731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      // First, get all the URLs the client wants to open.
338731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      if (url_value->IsType(Value::TYPE_STRING)) {
339731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        std::string url_string;
340731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        url_value->GetAsString(&url_string);
341731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        url_strings.push_back(url_string);
342731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      } else if (url_value->IsType(Value::TYPE_LIST)) {
343731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        const ListValue* url_list = static_cast<const ListValue*>(url_value);
344731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        for (size_t i = 0; i < url_list->GetSize(); ++i) {
345731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          std::string url_string;
346731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          EXTENSION_FUNCTION_VALIDATE(url_list->GetString(i, &url_string));
347731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          url_strings.push_back(url_string);
348731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        }
349731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      }
350731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
351731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      // Second, resolve, validate and convert them to GURLs.
352731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      for (std::vector<std::string>::iterator i = url_strings.begin();
353731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick           i != url_strings.end(); ++i) {
354731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        GURL url = ResolvePossiblyRelativeURL(*i, GetExtension());
355731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        if (!url.is_valid()) {
356731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          error_ = ExtensionErrorUtils::FormatErrorMessage(
357731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick              keys::kInvalidUrlError, *i);
358731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          return false;
359731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        }
360731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        urls.push_back(url);
361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
365dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // Don't let the extension crash the browser or renderers.
366dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  GURL browser_crash(chrome::kAboutBrowserCrash);
367dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  GURL renderer_crash(chrome::kAboutCrashURL);
368dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (std::find(urls.begin(), urls.end(), browser_crash) != urls.end() ||
369dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      std::find(urls.begin(), urls.end(), renderer_crash) != urls.end()) {
370dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    error_ = keys::kNoCrashBrowserError;
371dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    return false;
372dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
373dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
37421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // Look for optional tab id.
37521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (args) {
37621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    int tab_id;
37721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    if (args->HasKey(keys::kTabIdKey)) {
37821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      EXTENSION_FUNCTION_VALIDATE(args->GetInteger(keys::kTabIdKey, &tab_id));
37921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
38021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      // Find the tab and detach it from the original window.
38121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      Browser* source_browser = NULL;
38221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      TabStripModel* source_tab_strip = NULL;
38321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      int tab_index = -1;
38421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      if (!GetTabById(tab_id, profile(), include_incognito(),
38521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                      &source_browser, &source_tab_strip, &contents,
38621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                      &tab_index, &error_))
38721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen        return false;
38821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      contents = source_tab_strip->DetachTabContentsAt(tab_index);
38921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      if (!contents) {
39021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen        error_ = ExtensionErrorUtils::FormatErrorMessage(
39121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen            keys::kTabNotFoundError, base::IntToString(tab_id));
39221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen        return false;
39321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      }
39421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    }
39521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
39621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
397c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Try to position the new browser relative its originating browser window.
398731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  gfx::Rect  window_bounds;
399c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool maximized;
400c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The call offsets the bounds by kWindowTilePixels (defined in WindowSizer to
401c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // be 10)
402c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //
403c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // NOTE(rafaelw): It's ok if GetCurrentBrowser() returns NULL here.
404c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // GetBrowserWindowBounds will default to saved "default" values for the app.
405731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  WindowSizer::GetBrowserWindowBounds(std::string(), gfx::Rect(),
406731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                      GetCurrentBrowser(), &window_bounds,
407c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                      &maximized);
408c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
409731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // Calculate popup bounds separately. In ChromiumOS the default is 0x0 which
410731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // indicates default window sizes in PanelBrowserView. In other OSs popups
411731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // use the same default bounds as windows.
412731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  gfx::Rect popup_bounds;
413731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#if !defined(OS_CHROMEOS)
414731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  popup_bounds = window_bounds;  // Use window size as default for popups
415731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#endif
416731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
417c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Profile* window_profile = profile();
418c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Browser::Type window_type = Browser::TYPE_NORMAL;
419ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  bool focused = true;
420c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
421c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (args) {
422c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Any part of the bounds can optionally be set by the caller.
423c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int bounds_val;
424c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (args->HasKey(keys::kLeftKey)) {
425c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      EXTENSION_FUNCTION_VALIDATE(args->GetInteger(keys::kLeftKey,
426c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                   &bounds_val));
427731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      window_bounds.set_x(bounds_val);
428731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      popup_bounds.set_x(bounds_val);
429c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
430c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
431c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (args->HasKey(keys::kTopKey)) {
432c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      EXTENSION_FUNCTION_VALIDATE(args->GetInteger(keys::kTopKey,
433c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                   &bounds_val));
434731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      window_bounds.set_y(bounds_val);
435731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      popup_bounds.set_y(bounds_val);
436c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
437c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
438c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (args->HasKey(keys::kWidthKey)) {
439c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      EXTENSION_FUNCTION_VALIDATE(args->GetInteger(keys::kWidthKey,
440c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                   &bounds_val));
441731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      window_bounds.set_width(bounds_val);
442731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      popup_bounds.set_width(bounds_val);
443c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
444c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
445c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (args->HasKey(keys::kHeightKey)) {
446c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      EXTENSION_FUNCTION_VALIDATE(args->GetInteger(keys::kHeightKey,
447c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                   &bounds_val));
448731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      window_bounds.set_height(bounds_val);
449731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      popup_bounds.set_height(bounds_val);
450c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
451c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
452c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bool incognito = false;
453c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (args->HasKey(keys::kIncognitoKey)) {
454c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      EXTENSION_FUNCTION_VALIDATE(args->GetBoolean(keys::kIncognitoKey,
455c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                   &incognito));
45672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      if (!profile_->GetPrefs()->GetBoolean(prefs::kIncognitoEnabled)) {
45772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        error_ = keys::kIncognitoModeIsDisabled;
45872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        return false;
45972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      }
46072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
461c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (incognito)
462c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        window_profile = window_profile->GetOffTheRecordProfile();
463c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
464c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
465ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (args->HasKey(keys::kFocusedKey))
466ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      EXTENSION_FUNCTION_VALIDATE(args->GetBoolean(keys::kFocusedKey,
467ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                                   &focused));
468ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
469c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::string type_str;
470c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (args->HasKey(keys::kWindowTypeKey)) {
471c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      EXTENSION_FUNCTION_VALIDATE(args->GetString(keys::kWindowTypeKey,
472c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                  &type_str));
473c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (type_str == keys::kWindowTypeValueNormal) {
474c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        window_type = Browser::TYPE_NORMAL;
475c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      } else if (type_str == keys::kWindowTypeValuePopup) {
476731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        window_type = Browser::TYPE_APP_POPUP;
477ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      } else if (type_str == keys::kWindowTypeValuePanel) {
478ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        if (GetExtension()->HasApiPermission(
479ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                Extension::kExperimentalPermission)) {
480ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          window_type = Browser::TYPE_APP_PANEL;
481ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        } else {
482ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          error_ = errors::kExperimentalFeature;
483ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          return false;
484ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        }
485c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      } else {
486c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        EXTENSION_FUNCTION_VALIDATE(false);
487c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
488c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
489c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
490c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
491731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  Browser* new_window = Browser::CreateForType(window_type, window_profile);
492513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  for (std::vector<GURL>::iterator i = urls.begin(); i != urls.end(); ++i)
493513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    new_window->AddSelectedTabWithURL(*i, PageTransition::LINK);
49421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (contents) {
49521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    TabStripModel* target_tab_strip = new_window->tabstrip_model();
49621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    target_tab_strip->InsertTabContentsAt(urls.size(), contents,
49721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                          TabStripModel::ADD_NONE);
498dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  } else if (urls.empty()) {
499731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    new_window->NewTab();
50021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
501731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  new_window->SelectNumberedTab(0);
502731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (window_type & Browser::TYPE_POPUP)
503731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    new_window->window()->SetBounds(popup_bounds);
504731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  else
505731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    new_window->window()->SetBounds(window_bounds);
506ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
507ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (focused)
508ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    new_window->window()->Show();
509ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  else
510ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    new_window->window()->ShowInactive();
511c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
512c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (new_window->profile()->IsOffTheRecord() && !include_incognito()) {
513c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Don't expose incognito windows if the extension isn't allowed.
514c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    result_.reset(Value::CreateNullValue());
515c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
516731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    result_.reset(ExtensionTabUtil::CreateWindowValue(new_window, true));
517c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
518c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
519c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
520c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
521c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
522c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool UpdateWindowFunction::RunImpl() {
523c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int window_id;
524c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &window_id));
525c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DictionaryValue* update_props;
526c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &update_props));
527c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
528c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Browser* browser = GetBrowserInProfileWithId(profile(), window_id,
529c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                               include_incognito(), &error_);
530c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!browser || !browser->window()) {
531c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    error_ = ExtensionErrorUtils::FormatErrorMessage(
5323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        keys::kWindowNotFoundError, base::IntToString(window_id));
533c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
534c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
535c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
536c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gfx::Rect bounds = browser->window()->GetRestoredBounds();
53772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  bool set_bounds = false;
538c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Any part of the bounds can optionally be set by the caller.
539c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int bounds_val;
540c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (update_props->HasKey(keys::kLeftKey)) {
541c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    EXTENSION_FUNCTION_VALIDATE(update_props->GetInteger(
542c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        keys::kLeftKey,
543c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        &bounds_val));
544c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bounds.set_x(bounds_val);
54572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    set_bounds = true;
546c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
547c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
548c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (update_props->HasKey(keys::kTopKey)) {
549c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    EXTENSION_FUNCTION_VALIDATE(update_props->GetInteger(
550c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        keys::kTopKey,
551c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        &bounds_val));
552c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bounds.set_y(bounds_val);
55372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    set_bounds = true;
554c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
555c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
556c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (update_props->HasKey(keys::kWidthKey)) {
557c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    EXTENSION_FUNCTION_VALIDATE(update_props->GetInteger(
558c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        keys::kWidthKey,
559c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        &bounds_val));
560c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bounds.set_width(bounds_val);
56172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    set_bounds = true;
562c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
563c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
564c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (update_props->HasKey(keys::kHeightKey)) {
565c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    EXTENSION_FUNCTION_VALIDATE(update_props->GetInteger(
566c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        keys::kHeightKey,
567c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        &bounds_val));
568c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bounds.set_height(bounds_val);
56972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    set_bounds = true;
570c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
57172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (set_bounds)
57272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    browser->window()->SetBounds(bounds);
573731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
574731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  bool selected_val = false;
575731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (update_props->HasKey(keys::kFocusedKey)) {
576731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    EXTENSION_FUNCTION_VALIDATE(update_props->GetBoolean(
577731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        keys::kFocusedKey, &selected_val));
578731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (selected_val)
579731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      browser->window()->Activate();
580731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    else
581731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      browser->window()->Deactivate();
582731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
583731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
584c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  result_.reset(ExtensionTabUtil::CreateWindowValue(browser, false));
585c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
586c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
587c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
588c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
589c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool RemoveWindowFunction::RunImpl() {
590c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int window_id;
591c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &window_id));
592c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
593c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Browser* browser = GetBrowserInProfileWithId(profile(), window_id,
594c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                               include_incognito(), &error_);
595c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!browser)
596c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
597c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
59821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // Don't let the extension remove the window if the user is dragging tabs
59921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // in that window.
60021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (!browser->IsTabStripEditable()) {
60121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    error_ = keys::kTabStripNotEditableError;
60221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    return false;
60321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
60421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
605c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  browser->CloseWindow();
606c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
607c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
608c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
609c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
610c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Tabs ------------------------------------------------------------------------
611c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
612c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool GetSelectedTabFunction::RunImpl() {
613c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Browser* browser;
614c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // windowId defaults to "current" window.
615c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int window_id = -1;
616c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
617c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (HasOptionalArgument(0)) {
618c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &window_id));
619c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    browser = GetBrowserInProfileWithId(profile(), window_id,
620c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                        include_incognito(), &error_);
621c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
622c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    browser = GetCurrentBrowser();
623c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!browser)
624c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      error_ = keys::kNoCurrentWindowError;
625c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
626c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!browser)
627c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
628c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
629c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TabStripModel* tab_strip = browser->tabstrip_model();
630201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  TabContentsWrapper* contents = tab_strip->GetSelectedTabContents();
631c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!contents) {
632c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    error_ = keys::kNoSelectedTabError;
633c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
634c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
635201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  result_.reset(ExtensionTabUtil::CreateTabValue(contents->tab_contents(),
636201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      tab_strip,
637ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      tab_strip->active_index()));
638c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
639c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
640c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
641c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool GetAllTabsInWindowFunction::RunImpl() {
642c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Browser* browser;
643c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // windowId defaults to "current" window.
644c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int window_id = -1;
645c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (HasOptionalArgument(0)) {
646c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &window_id));
647c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    browser = GetBrowserInProfileWithId(profile(), window_id,
648c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                        include_incognito(), &error_);
649c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
650c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    browser = GetCurrentBrowser();
651c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!browser)
652c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      error_ = keys::kNoCurrentWindowError;
653c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
654c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!browser)
655c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
656c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
657c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  result_.reset(ExtensionTabUtil::CreateTabList(browser));
658c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
659c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
660c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
661c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
662c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool CreateTabFunction::RunImpl() {
663c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DictionaryValue* args;
664c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args));
665c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
666c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Browser *browser;
667c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // windowId defaults to "current" window.
668c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int window_id = -1;
669c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (args->HasKey(keys::kWindowIdKey)) {
670c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    EXTENSION_FUNCTION_VALIDATE(args->GetInteger(
671c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        keys::kWindowIdKey, &window_id));
672c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    browser = GetBrowserInProfileWithId(profile(), window_id,
673c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                        include_incognito(), &error_);
674c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
675c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    browser = GetCurrentBrowser();
676c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!browser)
677c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      error_ = keys::kNoCurrentWindowError;
678c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
679c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!browser)
680c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
681c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
682c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // TODO(rafaelw): handle setting remaining tab properties:
683c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // -title
684c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // -favIconUrl
685c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
686c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string url_string;
687c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GURL url;
688c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (args->HasKey(keys::kUrlKey)) {
689c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    EXTENSION_FUNCTION_VALIDATE(args->GetString(keys::kUrlKey,
690c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                &url_string));
691c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    url = ResolvePossiblyRelativeURL(url_string, GetExtension());
692c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!url.is_valid()) {
693c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      error_ = ExtensionErrorUtils::FormatErrorMessage(keys::kInvalidUrlError,
694c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                       url_string);
695c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
696c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
697c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
698c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
699dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // Don't let extensions crash the browser or renderers.
700dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (url == GURL(chrome::kAboutBrowserCrash) ||
701dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      url == GURL(chrome::kAboutCrashURL)) {
702dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    error_ = keys::kNoCrashBrowserError;
703dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    return false;
704dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
705dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
706c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Default to foreground for the new tab. The presence of 'selected' property
707c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // will override this default.
708c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool selected = true;
709c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (args->HasKey(keys::kSelectedKey))
710c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    EXTENSION_FUNCTION_VALIDATE(args->GetBoolean(keys::kSelectedKey,
711c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                 &selected));
712c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
713513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // Default to not pinning the tab. Setting the 'pinned' property to true
714513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // will override this default.
715513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  bool pinned = false;
716513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (args->HasKey(keys::kPinnedKey))
717513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    EXTENSION_FUNCTION_VALIDATE(args->GetBoolean(keys::kPinnedKey, &pinned));
718513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
719513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // We can't load extension URLs into incognito windows unless the extension
720513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // uses split mode. Special case to fall back to a normal window.
721c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (url.SchemeIs(chrome::kExtensionScheme) &&
722513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      !GetExtension()->incognito_split_mode() &&
723c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      browser->profile()->IsOffTheRecord()) {
724c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Profile* profile = browser->profile()->GetOriginalProfile();
725c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    browser = BrowserList::FindBrowserWithType(profile,
726c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                               Browser::TYPE_NORMAL, false);
727c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!browser) {
728c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      browser = Browser::Create(profile);
729c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      browser->window()->Show();
730c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
731c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
732c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
733731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // If index is specified, honor the value, but keep it bound to
734731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // -1 <= index <= tab_strip->count() where -1 invokes the default behavior.
735731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  int index = -1;
736731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (args->HasKey(keys::kIndexKey))
737731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    EXTENSION_FUNCTION_VALIDATE(args->GetInteger(keys::kIndexKey, &index));
738731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
739c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TabStripModel* tab_strip = browser->tabstrip_model();
740c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
741731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  index = std::min(std::max(index, -1), tab_strip->count());
742c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
743ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int add_types = selected ? TabStripModel::ADD_ACTIVE :
744c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             TabStripModel::ADD_NONE;
745c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  add_types |= TabStripModel::ADD_FORCE_INDEX;
746513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (pinned)
747513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    add_types |= TabStripModel::ADD_PINNED;
748513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  browser::NavigateParams params(browser, url, PageTransition::LINK);
749513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  params.disposition = selected ? NEW_FOREGROUND_TAB : NEW_BACKGROUND_TAB;
750513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  params.tabstrip_index = index;
751513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  params.tabstrip_add_types = add_types;
752513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  browser::Navigate(&params);
753c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
754c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (selected)
755513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    params.target_contents->view()->SetInitialFocus();
756c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
757c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Return data about the newly created tab.
758513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (has_callback()) {
759513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    result_.reset(ExtensionTabUtil::CreateTabValue(
760201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch        params.target_contents->tab_contents(),
761513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        params.browser->tabstrip_model(),
762513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        params.browser->tabstrip_model()->GetIndexOfTabContents(
763513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch            params.target_contents)));
764513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
765c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
766c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
767c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
768c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
769c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool GetTabFunction::RunImpl() {
770c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int tab_id;
771c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &tab_id));
772c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
773c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TabStripModel* tab_strip = NULL;
774201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  TabContentsWrapper* contents = NULL;
775c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int tab_index = -1;
776c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!GetTabById(tab_id, profile(), include_incognito(),
777c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                  NULL, &tab_strip, &contents, &tab_index, &error_))
778c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
779c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
780201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  result_.reset(ExtensionTabUtil::CreateTabValue(contents->tab_contents(),
781201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      tab_strip,
782c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      tab_index));
783c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
784c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
785c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
786c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool GetCurrentTabFunction::RunImpl() {
787c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(dispatcher());
788c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
789c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TabContents* contents = dispatcher()->delegate()->associated_tab_contents();
790c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (contents)
791c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    result_.reset(ExtensionTabUtil::CreateTabValue(contents));
792c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
793c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
794c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
795c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
796ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenUpdateTabFunction::UpdateTabFunction()
797ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    : ALLOW_THIS_IN_INITIALIZER_LIST(registrar_(this)) {
798ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
799ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
800c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool UpdateTabFunction::RunImpl() {
801c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int tab_id;
802c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &tab_id));
803c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DictionaryValue* update_props;
804c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &update_props));
805c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
806c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TabStripModel* tab_strip = NULL;
807201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  TabContentsWrapper* contents = NULL;
808c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int tab_index = -1;
809c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!GetTabById(tab_id, profile(), include_incognito(),
810c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                  NULL, &tab_strip, &contents, &tab_index, &error_))
811c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
812c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
813c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  NavigationController& controller = contents->controller();
814c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
815c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // TODO(rafaelw): handle setting remaining tab properties:
816c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // -title
817c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // -favIconUrl
818c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
819c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Navigate the tab to a new location if the url different.
820c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string url_string;
821c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (update_props->HasKey(keys::kUrlKey)) {
822c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    EXTENSION_FUNCTION_VALIDATE(update_props->GetString(
823c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        keys::kUrlKey, &url_string));
824c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    GURL url = ResolvePossiblyRelativeURL(url_string, GetExtension());
825c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
826c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!url.is_valid()) {
827c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      error_ = ExtensionErrorUtils::FormatErrorMessage(keys::kInvalidUrlError,
828c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                       url_string);
829c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
830c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
831c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
832dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    // Don't let the extension crash the browser or renderers.
833dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    if (url == GURL(chrome::kAboutBrowserCrash) ||
834dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        url == GURL(chrome::kAboutCrashURL)) {
835dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      error_ = keys::kNoCrashBrowserError;
836dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      return false;
837dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    }
838dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
839c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // JavaScript URLs can do the same kinds of things as cross-origin XHR, so
840c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // we need to check host permissions before allowing them.
841c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (url.SchemeIs(chrome::kJavaScriptScheme)) {
84272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      if (!GetExtension()->CanExecuteScriptOnPage(
84372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen              contents->tab_contents()->GetURL(), NULL, &error_)) {
844c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return false;
845731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      }
846c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
847ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      ExtensionMsg_ExecuteCode_Params params;
848ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      params.request_id = request_id();
849ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      params.extension_id = extension_id();
850ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      params.is_javascript = true;
851ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      params.code = url.path();
852ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      params.all_frames = false;
853ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      params.in_main_world = true;
854ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
855ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      RenderViewHost* render_view_host =
856ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          contents->tab_contents()->render_view_host();
857ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      render_view_host->Send(
858ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          new ExtensionMsg_ExecuteCode(render_view_host->routing_id(),
859ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                       params));
860ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
861ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      registrar_.Observe(contents->tab_contents());
862ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      AddRef();  // balanced in Observe()
863ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
864ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      return true;
865c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
866c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
867c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    controller.LoadURL(url, GURL(), PageTransition::LINK);
868c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
869c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // The URL of a tab contents never actually changes to a JavaScript URL, so
870c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // this check only makes sense in other cases.
871c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!url.SchemeIs(chrome::kJavaScriptScheme))
872201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      DCHECK_EQ(url.spec(), contents->tab_contents()->GetURL().spec());
873c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
874c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
875c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool selected = false;
876c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // TODO(rafaelw): Setting |selected| from js doesn't make much sense.
877c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Move tab selection management up to window.
878c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (update_props->HasKey(keys::kSelectedKey)) {
879c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    EXTENSION_FUNCTION_VALIDATE(update_props->GetBoolean(
880c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        keys::kSelectedKey,
881c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        &selected));
882c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (selected) {
883ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (tab_strip->active_index() != tab_index) {
884ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        tab_strip->ActivateTabAt(tab_index, false);
885c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        DCHECK_EQ(contents, tab_strip->GetSelectedTabContents());
886c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
887201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      contents->tab_contents()->Focus();
888c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
889c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
890c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
891513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  bool pinned = false;
892513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (update_props->HasKey(keys::kPinnedKey)) {
893513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    EXTENSION_FUNCTION_VALIDATE(update_props->GetBoolean(keys::kPinnedKey,
894513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                                                         &pinned));
895513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    tab_strip->SetTabPinned(tab_index, pinned);
896513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
897513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    // Update the tab index because it may move when being pinned.
898513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    tab_index = tab_strip->GetIndexOfTabContents(contents);
899513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
900513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
901c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (has_callback())
902201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    result_.reset(ExtensionTabUtil::CreateTabValue(contents->tab_contents(),
903201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch        tab_strip,
904c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        tab_index));
905c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
906ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  SendResponse(true);
907ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return true;
908ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
909ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
910ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool UpdateTabFunction::OnMessageReceived(const IPC::Message& message) {
911ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (message.type() != ExtensionHostMsg_ExecuteCodeFinished::ID)
912ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return false;
913ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
914ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int message_request_id;
915ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  void* iter = NULL;
916ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!message.ReadInt(&iter, &message_request_id)) {
917ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    NOTREACHED() << "malformed extension message";
918ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return true;
919ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
920ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
921ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (message_request_id != request_id())
922ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return false;
923ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
924ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  IPC_BEGIN_MESSAGE_MAP(UpdateTabFunction, message)
925ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    IPC_MESSAGE_HANDLER(ExtensionHostMsg_ExecuteCodeFinished,
926ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                        OnExecuteCodeFinished)
927ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  IPC_END_MESSAGE_MAP()
928c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
929c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
930c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
931ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid UpdateTabFunction::OnExecuteCodeFinished(int request_id,
932ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                              bool success,
933ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                              const std::string& error) {
934ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!error.empty()) {
935ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    CHECK(!success);
936ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    error_ = error;
937ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
938ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
939ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  SendResponse(success);
940ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
941ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  registrar_.Observe(NULL);
942ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  Release();  // balanced in Execute()
943ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
944ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
945c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool MoveTabFunction::RunImpl() {
946c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int tab_id;
947c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &tab_id));
948c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DictionaryValue* update_props;
949c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &update_props));
950c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
951c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int new_index;
952c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXTENSION_FUNCTION_VALIDATE(update_props->GetInteger(
953c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      keys::kIndexKey, &new_index));
954c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXTENSION_FUNCTION_VALIDATE(new_index >= 0);
955c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
956c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Browser* source_browser = NULL;
957c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TabStripModel* source_tab_strip = NULL;
958201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  TabContentsWrapper* contents = NULL;
959c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int tab_index = -1;
960c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!GetTabById(tab_id, profile(), include_incognito(),
961c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                  &source_browser, &source_tab_strip, &contents,
962c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                  &tab_index, &error_))
963c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
964c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
96521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // Don't let the extension move the tab if the user is dragging tabs.
96621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (!source_browser->IsTabStripEditable()) {
96721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    error_ = keys::kTabStripNotEditableError;
968c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
969c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
970c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
971c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (update_props->HasKey(keys::kWindowIdKey)) {
972c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Browser* target_browser;
973c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int window_id;
974c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    EXTENSION_FUNCTION_VALIDATE(update_props->GetInteger(
975c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        keys::kWindowIdKey, &window_id));
976c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    target_browser = GetBrowserInProfileWithId(profile(), window_id,
977c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                               include_incognito(), &error_);
978c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!target_browser)
979c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
980c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
98121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    if (!target_browser->IsTabStripEditable()) {
98221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      error_ = keys::kTabStripNotEditableError;
98321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      return false;
98421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    }
98521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
986c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (target_browser->type() != Browser::TYPE_NORMAL) {
987c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      error_ = keys::kCanOnlyMoveTabsWithinNormalWindowsError;
988c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
989c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
990c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
99172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (target_browser->profile() != source_browser->profile()) {
99272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      error_ = keys::kCanOnlyMoveTabsWithinSameProfileError;
99372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      return false;
99472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    }
99572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
996c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // If windowId is different from the current window, move between windows.
997c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (ExtensionTabUtil::GetWindowId(target_browser) !=
998c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        ExtensionTabUtil::GetWindowId(source_browser)) {
999c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      TabStripModel* target_tab_strip = target_browser->tabstrip_model();
1000c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      contents = source_tab_strip->DetachTabContentsAt(tab_index);
1001c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (!contents) {
1002c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        error_ = ExtensionErrorUtils::FormatErrorMessage(
10033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick            keys::kTabNotFoundError, base::IntToString(tab_id));
1004c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return false;
1005c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
1006c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1007c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Clamp move location to the last position.
1008c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // This is ">" because it can append to a new index position.
1009c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (new_index > target_tab_strip->count())
1010c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        new_index = target_tab_strip->count();
1011c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1012c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      target_tab_strip->InsertTabContentsAt(new_index, contents,
1013c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                            TabStripModel::ADD_NONE);
1014c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1015c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (has_callback())
1016201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch        result_.reset(ExtensionTabUtil::CreateTabValue(contents->tab_contents(),
1017c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            target_tab_strip, new_index));
1018c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1019c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return true;
1020c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
1021c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1022c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1023c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Perform a simple within-window move.
1024c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Clamp move location to the last position.
1025c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // This is ">=" because the move must be to an existing location.
1026c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (new_index >= source_tab_strip->count())
1027c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    new_index = source_tab_strip->count() - 1;
1028c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1029c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (new_index != tab_index)
1030c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    source_tab_strip->MoveTabContentsAt(tab_index, new_index, false);
1031c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1032c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (has_callback())
1033201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    result_.reset(ExtensionTabUtil::CreateTabValue(contents->tab_contents(),
1034ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                                   source_tab_strip,
1035ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                                   new_index));
1036c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
1037c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1038c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1039c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1040c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool RemoveTabFunction::RunImpl() {
1041c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int tab_id;
1042c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &tab_id));
1043c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1044c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Browser* browser = NULL;
1045201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  TabContentsWrapper* contents = NULL;
1046c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!GetTabById(tab_id, profile(), include_incognito(),
1047c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                  &browser, NULL, &contents, NULL, &error_))
1048c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
1049c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
105021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // Don't let the extension remove a tab if the user is dragging tabs around.
105121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (!browser->IsTabStripEditable()) {
105221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    error_ = keys::kTabStripNotEditableError;
105321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    return false;
105421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
105521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
1056c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Close the tab in this convoluted way, since there's a chance that the tab
1057c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // is being dragged, or we're in some other nested event loop. This code path
1058c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // should ensure that the tab is safely closed under such circumstances,
1059c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // whereas |Browser::CloseTabContents()| does not.
1060c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  RenderViewHost* render_view_host = contents->render_view_host();
1061c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  render_view_host->delegate()->Close(render_view_host);
1062c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
1063c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1064c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1065c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool CaptureVisibleTabFunction::RunImpl() {
1066c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Browser* browser;
1067c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // windowId defaults to "current" window.
1068c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int window_id = -1;
1069c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1070c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (HasOptionalArgument(0)) {
1071c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &window_id));
1072c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    browser = GetBrowserInProfileWithId(profile(), window_id,
1073c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                        include_incognito(), &error_);
1074c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
1075c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    browser = GetCurrentBrowser();
1076c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1077c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1078c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!browser) {
1079c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    error_ = keys::kNoCurrentWindowError;
1080c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
1081c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1082c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1083c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  image_format_ = FORMAT_JPEG;  // Default format is JPEG.
1084c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  image_quality_ = kDefaultQuality;  // Default quality setting.
1085c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1086c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (HasOptionalArgument(1)) {
1087c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DictionaryValue* options;
1088c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &options));
1089c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1090c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (options->HasKey(keys::kFormatKey)) {
1091c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      std::string format;
1092c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      EXTENSION_FUNCTION_VALIDATE(
1093c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          options->GetString(keys::kFormatKey, &format));
1094c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1095c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (format == keys::kFormatValueJpeg) {
1096c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        image_format_ = FORMAT_JPEG;
1097c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      } else if (format == keys::kFormatValuePng) {
1098c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        image_format_ = FORMAT_PNG;
1099c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      } else {
1100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // Schema validation should make this unreachable.
1101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        EXTENSION_FUNCTION_VALIDATE(0);
1102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
1103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
1104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (options->HasKey(keys::kQualityKey)) {
1106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      EXTENSION_FUNCTION_VALIDATE(
1107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          options->GetInteger(keys::kQualityKey, &image_quality_));
1108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
1109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TabContents* tab_contents = browser->GetSelectedTabContents();
1112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!tab_contents) {
1113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    error_ = keys::kInternalVisibleTabCaptureError;
1114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
1115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1116dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
1117dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // captureVisibleTab() can return an image containing sensitive information
1118dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // that the browser would otherwise protect.  Ensure the extension has
1119dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // permission to do this.
1120dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (!GetExtension()->CanCaptureVisiblePage(tab_contents->GetURL(), &error_))
1121dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    return false;
1122dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
1123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  RenderViewHost* render_view_host = tab_contents->render_view_host();
1124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If a backing store is cached for the tab we want to capture,
1126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // and it can be copied into a bitmap, then use it to generate the image.
1127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BackingStore* backing_store = render_view_host->GetBackingStore(false);
1128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (backing_store && CaptureSnapshotFromBackingStore(backing_store))
1129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return true;
1130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Ask the renderer for a snapshot of the tab.
1132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  render_view_host->CaptureSnapshot();
1133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  registrar_.Add(this,
1134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 NotificationType::TAB_SNAPSHOT_TAKEN,
1135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 NotificationService::AllSources());
1136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  AddRef();  // Balanced in CaptureVisibleTabFunction::Observe().
1137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
1139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Build the image of a tab's contents out of a backing store.
1142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// This may fail if we can not copy a backing store into a bitmap.
1143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// For example, some uncommon X11 visual modes are not supported by
1144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// CopyFromBackingStore().
1145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool CaptureVisibleTabFunction::CaptureSnapshotFromBackingStore(
1146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    BackingStore* backing_store) {
1147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  skia::PlatformCanvas temp_canvas;
1149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!backing_store->CopyFromBackingStore(gfx::Rect(backing_store->size()),
1150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                           &temp_canvas)) {
1151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
1152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1153513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  VLOG(1) << "captureVisibleTab() got image from backing store.";
1154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SendResultFromBitmap(
1156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      temp_canvas.getTopPlatformDevice().accessBitmap(false));
1157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
1158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// If a backing store was not available in CaptureVisibleTabFunction::RunImpl,
1161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// than the renderer was asked for a snapshot.  Listen for a notification
1162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// that the snapshot is available.
1163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid CaptureVisibleTabFunction::Observe(NotificationType type,
1164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                        const NotificationSource& source,
1165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                        const NotificationDetails& details) {
1166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(type == NotificationType::TAB_SNAPSHOT_TAKEN);
1167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const SkBitmap *screen_capture = Details<const SkBitmap>(details).ptr();
1169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const bool error = screen_capture->empty();
1170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (error) {
1172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    error_ = keys::kInternalVisibleTabCaptureError;
1173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SendResponse(false);
1174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
1175513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    VLOG(1) << "captureVisibleTab() got image from renderer.";
1176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SendResultFromBitmap(*screen_capture);
1177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Release();  // Balanced in CaptureVisibleTabFunction::RunImpl().
1180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Turn a bitmap of the screen into an image, set that image as the result,
1183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// and call SendResponse().
1184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid CaptureVisibleTabFunction::SendResultFromBitmap(
1185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const SkBitmap& screen_capture) {
1186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_refptr<RefCountedBytes> image_data(new RefCountedBytes);
1187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SkAutoLockPixels screen_capture_lock(screen_capture);
1188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool encoded = false;
1189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string mime_type;
1190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  switch (image_format_) {
1191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case FORMAT_JPEG:
1192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      encoded = gfx::JPEGCodec::Encode(
1193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          reinterpret_cast<unsigned char*>(screen_capture.getAddr32(0, 0)),
1194731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          gfx::JPEGCodec::FORMAT_SkBitmap,
1195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          screen_capture.width(),
1196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          screen_capture.height(),
1197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          static_cast<int>(screen_capture.rowBytes()),
1198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          image_quality_,
1199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          &image_data->data);
1200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      mime_type = keys::kMimeTypeJpeg;
1201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      break;
1202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case FORMAT_PNG:
1203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      encoded = gfx::PNGCodec::EncodeBGRASkBitmap(
1204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          screen_capture,
1205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          true,  // Discard transparency.
1206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          &image_data->data);
1207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      mime_type = keys::kMimeTypePng;
1208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      break;
1209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    default:
1210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NOTREACHED() << "Invalid image format.";
1211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!encoded) {
1214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    error_ = ExtensionErrorUtils::FormatErrorMessage(
1215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        keys::kInternalVisibleTabCaptureError, "");
1216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SendResponse(false);
1217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
1218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string base64_result;
1221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string stream_as_string;
1222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  stream_as_string.resize(image_data->data.size());
1223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  memcpy(&stream_as_string[0],
1224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      reinterpret_cast<const char*>(&image_data->data[0]),
1225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      image_data->data.size());
1226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  base::Base64Encode(stream_as_string, &base64_result);
12283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  base64_result.insert(0, base::StringPrintf("data:%s;base64,",
12293345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                             mime_type.c_str()));
1230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  result_.reset(new StringValue(base64_result));
1231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SendResponse(true);
1232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool DetectTabLanguageFunction::RunImpl() {
1235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int tab_id = 0;
1236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Browser* browser = NULL;
1237201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  TabContentsWrapper* contents = NULL;
1238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If |tab_id| is specified, look for it. Otherwise default to selected tab
1240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // in the current window.
1241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (HasOptionalArgument(0)) {
1242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &tab_id));
1243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!GetTabById(tab_id, profile(), include_incognito(),
1244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                    &browser, NULL, &contents, NULL, &error_)) {
1245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
1246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
1247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!browser || !contents)
1248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
1249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
1250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    browser = GetCurrentBrowser();
1251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!browser)
1252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
1253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    contents = browser->tabstrip_model()->GetSelectedTabContents();
1254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!contents)
1255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
1256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (contents->controller().needs_reload()) {
1259731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    // If the tab hasn't been loaded, don't wait for the tab to load.
1260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    error_ = keys::kCannotDetermineLanguageOfUnloadedTab;
1261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
1262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  AddRef();  // Balanced in GotLanguage()
1265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1266ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  TranslateTabHelper* helper = contents->translate_tab_helper();
1267ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!helper->language_state().original_language().empty()) {
1268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Delay the callback invocation until after the current JS call has
1269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // returned.
1270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
1271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        this, &DetectTabLanguageFunction::GotLanguage,
1272ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        helper->language_state().original_language()));
1273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return true;
1274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The tab contents does not know its language yet.  Let's  wait until it
1276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // receives it, or until the tab is closed/navigates to some other page.
1277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  registrar_.Add(this, NotificationType::TAB_LANGUAGE_DETERMINED,
1278201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                 Source<TabContents>(contents->tab_contents()));
1279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  registrar_.Add(this, NotificationType::TAB_CLOSING,
1280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 Source<NavigationController>(&(contents->controller())));
1281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  registrar_.Add(this, NotificationType::NAV_ENTRY_COMMITTED,
1282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 Source<NavigationController>(&(contents->controller())));
1283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
1284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DetectTabLanguageFunction::Observe(NotificationType type,
1287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                        const NotificationSource& source,
1288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                        const NotificationDetails& details) {
1289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string language;
1290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (type == NotificationType::TAB_LANGUAGE_DETERMINED)
1291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    language = *Details<std::string>(details).ptr();
1292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  registrar_.RemoveAll();
1294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Call GotLanguage in all cases as we want to guarantee the callback is
1296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // called for every API call the extension made.
1297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GotLanguage(language);
1298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DetectTabLanguageFunction::GotLanguage(const std::string& language) {
1301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  result_.reset(Value::CreateStringValue(language.c_str()));
1302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SendResponse(true);
1303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Release();  // Balanced in Run()
1305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static helpers
1308ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// TODO(jhawkins): Move these to unnamed namespace and remove static modifier.
1309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic Browser* GetBrowserInProfileWithId(Profile* profile,
1311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                          const int window_id,
1312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                          bool include_incognito,
1313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                          std::string* error_message) {
1314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Profile* incognito_profile =
13153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      include_incognito && profile->HasOffTheRecordProfile() ?
13163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          profile->GetOffTheRecordProfile() : NULL;
1317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (BrowserList::const_iterator browser = BrowserList::begin();
1318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       browser != BrowserList::end(); ++browser) {
1319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (((*browser)->profile() == profile ||
1320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch         (*browser)->profile() == incognito_profile) &&
1321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        ExtensionTabUtil::GetWindowId(*browser) == window_id)
1322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return *browser;
1323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (error_message)
1326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    *error_message = ExtensionErrorUtils::FormatErrorMessage(
13273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        keys::kWindowNotFoundError, base::IntToString(window_id));
1328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return NULL;
1330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic bool GetTabById(int tab_id, Profile* profile,
1333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                       bool include_incognito,
1334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                       Browser** browser,
1335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                       TabStripModel** tab_strip,
1336201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                       TabContentsWrapper** contents,
1337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                       int* tab_index,
1338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                       std::string* error_message) {
1339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (ExtensionTabUtil::GetTabById(tab_id, profile, include_incognito,
1340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                   browser, tab_strip, contents, tab_index))
1341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return true;
1342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (error_message)
1344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    *error_message = ExtensionErrorUtils::FormatErrorMessage(
13453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        keys::kTabNotFoundError, base::IntToString(tab_id));
1346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return false;
1348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic std::string GetWindowTypeText(Browser::Type type) {
1351ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (type == Browser::TYPE_APP_PANEL &&
1352ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      CommandLine::ForCurrentProcess()->HasSwitch(
1353ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          switches::kEnableExperimentalExtensionApis))
1354ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return keys::kWindowTypeValuePanel;
1355ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
1356731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if ((type & Browser::TYPE_POPUP) == Browser::TYPE_POPUP)
1357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return keys::kWindowTypeValuePopup;
1358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1359731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if ((type & Browser::TYPE_APP) == Browser::TYPE_APP)
1360731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return keys::kWindowTypeValueApp;
1361731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
1362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(type == Browser::TYPE_NORMAL);
1363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return keys::kWindowTypeValueNormal;
1364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1366ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenstatic GURL ResolvePossiblyRelativeURL(const std::string& url_string,
1367513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                                       const Extension* extension) {
1368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GURL url = GURL(url_string);
1369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!url.is_valid())
1370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    url = extension->GetResourceURL(url_string);
1371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1372c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return url;
1373c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1374