extension_tabs_module.cc revision 731df977c0511bca2206b5f333555b1205ff1f43
1c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Copyright (c) 2010 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
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/base64.h"
83345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/string_number_conversions.h"
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/string_util.h"
103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/stringprintf.h"
113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/utf_string_conversions.h"
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/browser.h"
13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/browser_list.h"
14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/browser_window.h"
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/extensions/extension_function_dispatcher.h"
16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/extensions/extension_host.h"
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/extensions/extension_infobar_delegate.h"
18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/extensions/extension_tabs_module_constants.h"
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/extensions/extensions_service.h"
20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/profile.h"
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/renderer_host/backing_store.h"
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/renderer_host/render_view_host.h"
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/renderer_host/render_view_host_delegate.h"
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/tab_contents/navigation_entry.h"
25731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "chrome/browser/tab_contents/tab_contents_view.h"
26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/tab_contents/tab_contents.h"
27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/tabs/tab_strip_model.h"
28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/window_sizer.h"
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/extensions/extension.h"
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/extensions/extension_error_utils.h"
31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/url_constants.h"
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "gfx/codec/jpeg_codec.h"
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "gfx/codec/png_codec.h"
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "skia/ext/image_operations.h"
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "skia/ext/platform_canvas.h"
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "third_party/skia/include/core/SkBitmap.h"
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace keys = extension_tabs_module_constants;
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int CaptureVisibleTabFunction::kDefaultQuality = 90;
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Forward declare static helper functions defined below.
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// |error_message| can optionally be passed in a will be set with an appropriate
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// message if the window cannot be found by id.
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic Browser* GetBrowserInProfileWithId(Profile* profile,
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                          const int window_id,
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                          bool include_incognito,
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                          std::string* error_message);
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// |error_message| can optionally be passed in and will be set with an
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// appropriate message if the tab cannot be found by id.
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic bool GetTabById(int tab_id, Profile* profile,
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                       bool include_incognito,
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                       Browser** browser,
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                       TabStripModel** tab_strip,
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                       TabContents** contents,
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                       int* tab_index, std::string* error_message);
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Takes |url_string| and returns a GURL which is either valid and absolute
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// or invalid. If |url_string| is not directly interpretable as a valid (it is
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// likely a relative URL) an attempt is made to resolve it. |extension| is
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// provided so it can be resolved relative to its extension base
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// (chrome-extension://<id>/). Using the source frame url would be more correct,
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// but because the api shipped with urls resolved relative to their extension
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// base, we decided it wasn't worth breaking existing extensions to fix.
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic GURL ResolvePossiblyRelativeURL(std::string url_string,
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                       Extension* extension);
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Return the type name for a browser window type.
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic std::string GetWindowTypeText(Browser::Type type);
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint ExtensionTabUtil::GetWindowId(const Browser* browser) {
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return browser->session_id().id();
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint ExtensionTabUtil::GetTabId(const TabContents* tab_contents) {
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return tab_contents->controller().session_id().id();
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstd::string ExtensionTabUtil::GetTabStatusText(bool is_loading) {
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return is_loading ? keys::kStatusValueLoading : keys::kStatusValueComplete;
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint ExtensionTabUtil::GetWindowIdOfTab(const TabContents* tab_contents) {
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return tab_contents->controller().window_id().id();
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochDictionaryValue* ExtensionTabUtil::CreateTabValue(
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const TabContents* contents) {
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Find the tab strip and index of this guy.
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (BrowserList::const_iterator it = BrowserList::begin();
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      it != BrowserList::end(); ++it) {
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    TabStripModel* tab_strip = (*it)->tabstrip_model();
95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int tab_index = tab_strip->GetIndexOfTabContents(contents);
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (tab_index != -1) {
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return ExtensionTabUtil::CreateTabValue(contents, tab_strip, tab_index);
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Couldn't find it.  This can happen if the tab is being dragged.
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return ExtensionTabUtil::CreateTabValue(contents, NULL, -1);
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochListValue* ExtensionTabUtil::CreateTabList(const Browser* browser) {
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ListValue* tab_list = new ListValue();
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TabStripModel* tab_strip = browser->tabstrip_model();
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (int i = 0; i < tab_strip->count(); ++i) {
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    tab_list->Append(ExtensionTabUtil::CreateTabValue(
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        tab_strip->GetTabContentsAt(i), tab_strip, i));
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return tab_list;
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochDictionaryValue* ExtensionTabUtil::CreateTabValue(
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const TabContents* contents, TabStripModel* tab_strip, int tab_index) {
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DictionaryValue* result = new DictionaryValue();
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  result->SetInteger(keys::kIdKey, ExtensionTabUtil::GetTabId(contents));
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  result->SetInteger(keys::kIndexKey, tab_index);
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  result->SetInteger(keys::kWindowIdKey,
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                     ExtensionTabUtil::GetWindowIdOfTab(contents));
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  result->SetString(keys::kUrlKey, contents->GetURL().spec());
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  result->SetString(keys::kStatusKey, GetTabStatusText(contents->is_loading()));
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  result->SetBoolean(keys::kSelectedKey,
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                     tab_strip && tab_index == tab_strip->selected_index());
1273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  result->SetString(keys::kTitleKey, contents->GetTitle());
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  result->SetBoolean(keys::kIncognitoKey,
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                     contents->profile()->IsOffTheRecord());
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!contents->is_loading()) {
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    NavigationEntry* entry = contents->controller().GetActiveEntry();
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (entry) {
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (entry->favicon().is_valid())
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        result->SetString(keys::kFavIconUrlKey, entry->favicon().url().spec());
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return result;
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// if |populate| is true, each window gets a list property |tabs| which contains
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// fully populated tab objects.
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochDictionaryValue* ExtensionTabUtil::CreateWindowValue(const Browser* browser,
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                     bool populate_tabs) {
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(browser);
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(browser->window());
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DictionaryValue* result = new DictionaryValue();
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  result->SetInteger(keys::kIdKey, ExtensionTabUtil::GetWindowId(browser));
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  result->SetBoolean(keys::kIncognitoKey,
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                     browser->profile()->IsOffTheRecord());
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  result->SetBoolean(keys::kFocusedKey, browser->window()->IsActive());
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gfx::Rect bounds = browser->window()->GetRestoredBounds();
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  result->SetInteger(keys::kLeftKey, bounds.x());
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  result->SetInteger(keys::kTopKey, bounds.y());
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  result->SetInteger(keys::kWidthKey, bounds.width());
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  result->SetInteger(keys::kHeightKey, bounds.height());
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  result->SetString(keys::kWindowTypeKey, GetWindowTypeText(browser->type()));
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (populate_tabs) {
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    result->Set(keys::kTabsKey, ExtensionTabUtil::CreateTabList(browser));
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return result;
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool ExtensionTabUtil::GetDefaultTab(Browser* browser, TabContents** contents,
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                     int* tab_id) {
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(browser);
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(contents);
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(tab_id);
173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  *contents = browser->tabstrip_model()->GetSelectedTabContents();
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (*contents) {
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (tab_id)
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      *tab_id = ExtensionTabUtil::GetTabId(*contents);
178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return true;
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return false;
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool ExtensionTabUtil::GetTabById(int tab_id, Profile* profile,
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                  bool include_incognito,
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                  Browser** browser,
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                  TabStripModel** tab_strip,
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                  TabContents** contents,
189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                  int* tab_index) {
190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Browser* target_browser;
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TabStripModel* target_tab_strip;
192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TabContents* target_contents;
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Profile* incognito_profile =
1943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      include_incognito && profile->HasOffTheRecordProfile() ?
1953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          profile->GetOffTheRecordProfile() : NULL;
196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (BrowserList::const_iterator iter = BrowserList::begin();
197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       iter != BrowserList::end(); ++iter) {
198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    target_browser = *iter;
199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (target_browser->profile() == profile ||
200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        target_browser->profile() == incognito_profile) {
201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      target_tab_strip = target_browser->tabstrip_model();
202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      for (int i = 0; i < target_tab_strip->count(); ++i) {
203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        target_contents = target_tab_strip->GetTabContentsAt(i);
204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (target_contents->controller().session_id().id() == tab_id) {
205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          if (browser)
206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            *browser = target_browser;
207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          if (tab_strip)
208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            *tab_strip = target_tab_strip;
209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          if (contents)
210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            *contents = target_contents;
211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          if (tab_index)
212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            *tab_index = i;
213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          return true;
214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        }
215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return false;
219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Windows ---------------------------------------------------------------------
222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool GetWindowFunction::RunImpl() {
224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int window_id;
225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &window_id));
226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Browser* browser = GetBrowserInProfileWithId(profile(), window_id,
228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                               include_incognito(), &error_);
229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!browser || !browser->window()) {
230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    error_ = ExtensionErrorUtils::FormatErrorMessage(
2313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        keys::kWindowNotFoundError, base::IntToString(window_id));
232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  result_.reset(ExtensionTabUtil::CreateWindowValue(browser, false));
236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool GetCurrentWindowFunction::RunImpl() {
240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Browser* browser = GetCurrentBrowser();
241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!browser || !browser->window()) {
242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    error_ = keys::kNoCurrentWindowError;
243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  result_.reset(ExtensionTabUtil::CreateWindowValue(browser, false));
246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool GetLastFocusedWindowFunction::RunImpl() {
250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Browser* browser = BrowserList::FindBrowserWithType(
251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      profile(), Browser::TYPE_ANY, include_incognito());
252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!browser || !browser->window()) {
253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    error_ = keys::kNoLastFocusedWindowError;
254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  result_.reset(ExtensionTabUtil::CreateWindowValue(browser, false));
257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool GetAllWindowsFunction::RunImpl() {
261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool populate_tabs = false;
262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (HasOptionalArgument(0)) {
263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DictionaryValue* args;
264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args));
265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (args->HasKey(keys::kPopulateKey)) {
267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      EXTENSION_FUNCTION_VALIDATE(args->GetBoolean(keys::kPopulateKey,
268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          &populate_tabs));
269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  result_.reset(new ListValue());
273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Profile* incognito_profile =
2743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      include_incognito() && profile()->HasOffTheRecordProfile() ?
2753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          profile()->GetOffTheRecordProfile() : NULL;
276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (BrowserList::const_iterator browser = BrowserList::begin();
277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    browser != BrowserList::end(); ++browser) {
278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Only examine browsers in the current profile that have windows.
279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (((*browser)->profile() == profile() ||
280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch           (*browser)->profile() == incognito_profile) &&
281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          (*browser)->window()) {
282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        static_cast<ListValue*>(result_.get())->
283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          Append(ExtensionTabUtil::CreateWindowValue(*browser, populate_tabs));
284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool CreateWindowFunction::RunImpl() {
291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DictionaryValue* args = NULL;
292731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  std::vector<GURL> urls;
293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (HasOptionalArgument(0))
295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args));
296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Look for optional url.
298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (args) {
299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (args->HasKey(keys::kUrlKey)) {
300731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      Value* url_value;
301731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      std::vector<std::string> url_strings;
302731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      args->Get(keys::kUrlKey, &url_value);
303731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
304731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      // First, get all the URLs the client wants to open.
305731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      if (url_value->IsType(Value::TYPE_STRING)) {
306731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        std::string url_string;
307731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        url_value->GetAsString(&url_string);
308731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        url_strings.push_back(url_string);
309731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      } else if (url_value->IsType(Value::TYPE_LIST)) {
310731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        const ListValue* url_list = static_cast<const ListValue*>(url_value);
311731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        for (size_t i = 0; i < url_list->GetSize(); ++i) {
312731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          std::string url_string;
313731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          EXTENSION_FUNCTION_VALIDATE(url_list->GetString(i, &url_string));
314731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          url_strings.push_back(url_string);
315731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        }
316731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      }
317731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
318731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      // Second, resolve, validate and convert them to GURLs.
319731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      for (std::vector<std::string>::iterator i = url_strings.begin();
320731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick           i != url_strings.end(); ++i) {
321731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        GURL url = ResolvePossiblyRelativeURL(*i, GetExtension());
322731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        if (!url.is_valid()) {
323731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          error_ = ExtensionErrorUtils::FormatErrorMessage(
324731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick              keys::kInvalidUrlError, *i);
325731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          return false;
326731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        }
327731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        urls.push_back(url);
328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Try to position the new browser relative its originating browser window.
333731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  gfx::Rect  window_bounds;
334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool maximized;
335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The call offsets the bounds by kWindowTilePixels (defined in WindowSizer to
336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // be 10)
337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //
338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // NOTE(rafaelw): It's ok if GetCurrentBrowser() returns NULL here.
339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // GetBrowserWindowBounds will default to saved "default" values for the app.
340731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  WindowSizer::GetBrowserWindowBounds(std::string(), gfx::Rect(),
341731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                      GetCurrentBrowser(), &window_bounds,
342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                      &maximized);
343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
344731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // Calculate popup bounds separately. In ChromiumOS the default is 0x0 which
345731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // indicates default window sizes in PanelBrowserView. In other OSs popups
346731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // use the same default bounds as windows.
347731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  gfx::Rect popup_bounds;
348731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#if !defined(OS_CHROMEOS)
349731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  popup_bounds = window_bounds;  // Use window size as default for popups
350731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#endif
351731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Profile* window_profile = profile();
353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Browser::Type window_type = Browser::TYPE_NORMAL;
354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (args) {
356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Any part of the bounds can optionally be set by the caller.
357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int bounds_val;
358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (args->HasKey(keys::kLeftKey)) {
359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      EXTENSION_FUNCTION_VALIDATE(args->GetInteger(keys::kLeftKey,
360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                   &bounds_val));
361731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      window_bounds.set_x(bounds_val);
362731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      popup_bounds.set_x(bounds_val);
363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (args->HasKey(keys::kTopKey)) {
366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      EXTENSION_FUNCTION_VALIDATE(args->GetInteger(keys::kTopKey,
367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                   &bounds_val));
368731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      window_bounds.set_y(bounds_val);
369731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      popup_bounds.set_y(bounds_val);
370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
372c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (args->HasKey(keys::kWidthKey)) {
373c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      EXTENSION_FUNCTION_VALIDATE(args->GetInteger(keys::kWidthKey,
374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                   &bounds_val));
375731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      window_bounds.set_width(bounds_val);
376731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      popup_bounds.set_width(bounds_val);
377c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
379c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (args->HasKey(keys::kHeightKey)) {
380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      EXTENSION_FUNCTION_VALIDATE(args->GetInteger(keys::kHeightKey,
381c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                   &bounds_val));
382731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      window_bounds.set_height(bounds_val);
383731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      popup_bounds.set_height(bounds_val);
384c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
386c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bool incognito = false;
387c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (args->HasKey(keys::kIncognitoKey)) {
388c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      EXTENSION_FUNCTION_VALIDATE(args->GetBoolean(keys::kIncognitoKey,
389c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                   &incognito));
390c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (incognito)
391c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        window_profile = window_profile->GetOffTheRecordProfile();
392c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
393c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
394c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::string type_str;
395c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (args->HasKey(keys::kWindowTypeKey)) {
396c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      EXTENSION_FUNCTION_VALIDATE(args->GetString(keys::kWindowTypeKey,
397c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                  &type_str));
398c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (type_str == keys::kWindowTypeValueNormal) {
399c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        window_type = Browser::TYPE_NORMAL;
400c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      } else if (type_str == keys::kWindowTypeValuePopup) {
401731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        window_type = Browser::TYPE_APP_POPUP;
402c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      } else {
403c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        EXTENSION_FUNCTION_VALIDATE(false);
404c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
405c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
406c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
407c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
408731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  Browser* new_window = Browser::CreateForType(window_type, window_profile);
409731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  for (std::vector<GURL>::iterator i = urls.begin(); i != urls.end(); ++i) {
410731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    Browser::AddTabWithURLParams addTabParams =
411731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        Browser::AddTabWithURLParams(*i, PageTransition::LINK);
412731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    new_window->AddTabWithURL(&addTabParams);
413731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
414731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (urls.size() == 0)
415731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    new_window->NewTab();
416731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  new_window->SelectNumberedTab(0);
417731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (window_type & Browser::TYPE_POPUP)
418731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    new_window->window()->SetBounds(popup_bounds);
419731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  else
420731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    new_window->window()->SetBounds(window_bounds);
421c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  new_window->window()->Show();
422c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
423c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (new_window->profile()->IsOffTheRecord() && !include_incognito()) {
424c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Don't expose incognito windows if the extension isn't allowed.
425c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    result_.reset(Value::CreateNullValue());
426c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
427731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    result_.reset(ExtensionTabUtil::CreateWindowValue(new_window, true));
428c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
429c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
430c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
431c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
432c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
433c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool UpdateWindowFunction::RunImpl() {
434c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int window_id;
435c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &window_id));
436c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DictionaryValue* update_props;
437c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &update_props));
438c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
439c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Browser* browser = GetBrowserInProfileWithId(profile(), window_id,
440c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                               include_incognito(), &error_);
441c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!browser || !browser->window()) {
442c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    error_ = ExtensionErrorUtils::FormatErrorMessage(
4433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        keys::kWindowNotFoundError, base::IntToString(window_id));
444c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
445c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
446c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
447c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gfx::Rect bounds = browser->window()->GetRestoredBounds();
448c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Any part of the bounds can optionally be set by the caller.
449c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int bounds_val;
450c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (update_props->HasKey(keys::kLeftKey)) {
451c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    EXTENSION_FUNCTION_VALIDATE(update_props->GetInteger(
452c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        keys::kLeftKey,
453c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        &bounds_val));
454c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bounds.set_x(bounds_val);
455c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
456c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
457c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (update_props->HasKey(keys::kTopKey)) {
458c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    EXTENSION_FUNCTION_VALIDATE(update_props->GetInteger(
459c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        keys::kTopKey,
460c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        &bounds_val));
461c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bounds.set_y(bounds_val);
462c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
463c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
464c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (update_props->HasKey(keys::kWidthKey)) {
465c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    EXTENSION_FUNCTION_VALIDATE(update_props->GetInteger(
466c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        keys::kWidthKey,
467c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        &bounds_val));
468c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bounds.set_width(bounds_val);
469c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
470c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
471c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (update_props->HasKey(keys::kHeightKey)) {
472c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    EXTENSION_FUNCTION_VALIDATE(update_props->GetInteger(
473c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        keys::kHeightKey,
474c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        &bounds_val));
475c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bounds.set_height(bounds_val);
476c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
477c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  browser->window()->SetBounds(bounds);
478731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
479731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  bool selected_val = false;
480731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (update_props->HasKey(keys::kFocusedKey)) {
481731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    EXTENSION_FUNCTION_VALIDATE(update_props->GetBoolean(
482731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        keys::kFocusedKey, &selected_val));
483731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (selected_val)
484731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      browser->window()->Activate();
485731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    else
486731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      browser->window()->Deactivate();
487731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
488731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
489c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  result_.reset(ExtensionTabUtil::CreateWindowValue(browser, false));
490c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
491c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
492c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
493c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
494c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool RemoveWindowFunction::RunImpl() {
495c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int window_id;
496c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &window_id));
497c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
498c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Browser* browser = GetBrowserInProfileWithId(profile(), window_id,
499c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                               include_incognito(), &error_);
500c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!browser)
501c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
502c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
503c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  browser->CloseWindow();
504c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
505c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
506c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
507c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
508c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Tabs ------------------------------------------------------------------------
509c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
510c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool GetSelectedTabFunction::RunImpl() {
511c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Browser* browser;
512c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // windowId defaults to "current" window.
513c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int window_id = -1;
514c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
515c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (HasOptionalArgument(0)) {
516c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &window_id));
517c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    browser = GetBrowserInProfileWithId(profile(), window_id,
518c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                        include_incognito(), &error_);
519c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
520c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    browser = GetCurrentBrowser();
521c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!browser)
522c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      error_ = keys::kNoCurrentWindowError;
523c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
524c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!browser)
525c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
526c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
527c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TabStripModel* tab_strip = browser->tabstrip_model();
528c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TabContents* contents = tab_strip->GetSelectedTabContents();
529c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!contents) {
530c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    error_ = keys::kNoSelectedTabError;
531c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
532c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
533c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  result_.reset(ExtensionTabUtil::CreateTabValue(contents, tab_strip,
534c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      tab_strip->selected_index()));
535c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
536c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
537c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
538c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool GetAllTabsInWindowFunction::RunImpl() {
539c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Browser* browser;
540c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // windowId defaults to "current" window.
541c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int window_id = -1;
542c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (HasOptionalArgument(0)) {
543c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &window_id));
544c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    browser = GetBrowserInProfileWithId(profile(), window_id,
545c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                        include_incognito(), &error_);
546c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
547c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    browser = GetCurrentBrowser();
548c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!browser)
549c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      error_ = keys::kNoCurrentWindowError;
550c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
551c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!browser)
552c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
553c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
554c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  result_.reset(ExtensionTabUtil::CreateTabList(browser));
555c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
556c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
557c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
558c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
559c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool CreateTabFunction::RunImpl() {
560c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DictionaryValue* args;
561c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args));
562c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
563c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Browser *browser;
564c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // windowId defaults to "current" window.
565c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int window_id = -1;
566c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (args->HasKey(keys::kWindowIdKey)) {
567c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    EXTENSION_FUNCTION_VALIDATE(args->GetInteger(
568c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        keys::kWindowIdKey, &window_id));
569c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    browser = GetBrowserInProfileWithId(profile(), window_id,
570c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                        include_incognito(), &error_);
571c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
572c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    browser = GetCurrentBrowser();
573c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!browser)
574c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      error_ = keys::kNoCurrentWindowError;
575c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
576c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!browser)
577c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
578c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
579c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // TODO(rafaelw): handle setting remaining tab properties:
580c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // -title
581c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // -favIconUrl
582c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
583c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string url_string;
584c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GURL url;
585c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (args->HasKey(keys::kUrlKey)) {
586c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    EXTENSION_FUNCTION_VALIDATE(args->GetString(keys::kUrlKey,
587c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                &url_string));
588c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    url = ResolvePossiblyRelativeURL(url_string, GetExtension());
589c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!url.is_valid()) {
590c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      error_ = ExtensionErrorUtils::FormatErrorMessage(keys::kInvalidUrlError,
591c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                       url_string);
592c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
593c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
594c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
595c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
596c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Default to foreground for the new tab. The presence of 'selected' property
597c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // will override this default.
598c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool selected = true;
599c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (args->HasKey(keys::kSelectedKey))
600c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    EXTENSION_FUNCTION_VALIDATE(args->GetBoolean(keys::kSelectedKey,
601c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                 &selected));
602c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
603c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We can't load extension URLs into incognito windows. Special case to
604c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // fall back to a normal window.
605c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (url.SchemeIs(chrome::kExtensionScheme) &&
606c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      browser->profile()->IsOffTheRecord()) {
607c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Profile* profile = browser->profile()->GetOriginalProfile();
608c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    browser = BrowserList::FindBrowserWithType(profile,
609c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                               Browser::TYPE_NORMAL, false);
610c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!browser) {
611c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      browser = Browser::Create(profile);
612c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      browser->window()->Show();
613c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
614c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
615c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
616731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // If index is specified, honor the value, but keep it bound to
617731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // -1 <= index <= tab_strip->count() where -1 invokes the default behavior.
618731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  int index = -1;
619731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (args->HasKey(keys::kIndexKey))
620731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    EXTENSION_FUNCTION_VALIDATE(args->GetInteger(keys::kIndexKey, &index));
621731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
622c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TabStripModel* tab_strip = browser->tabstrip_model();
623c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
624731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  index = std::min(std::max(index, -1), tab_strip->count());
625c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
626c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int add_types = selected ? TabStripModel::ADD_SELECTED :
627c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             TabStripModel::ADD_NONE;
628c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  add_types |= TabStripModel::ADD_FORCE_INDEX;
629731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  Browser::AddTabWithURLParams params(url, PageTransition::LINK);
630731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  params.index = index;
631731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  params.add_types = add_types;
632731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  TabContents* contents = browser->AddTabWithURL(&params);
6333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  index = browser->tabstrip_model()->GetIndexOfTabContents(contents);
634c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
635c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (selected)
636731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    contents->view()->SetInitialFocus();
637c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
638c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Return data about the newly created tab.
639c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (has_callback())
6403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    result_.reset(ExtensionTabUtil::CreateTabValue(contents,
6413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                                   browser->tabstrip_model(),
6423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                                   index));
643c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
644c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
645c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
646c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
647c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool GetTabFunction::RunImpl() {
648c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int tab_id;
649c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &tab_id));
650c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
651c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TabStripModel* tab_strip = NULL;
652c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TabContents* contents = NULL;
653c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int tab_index = -1;
654c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!GetTabById(tab_id, profile(), include_incognito(),
655c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                  NULL, &tab_strip, &contents, &tab_index, &error_))
656c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
657c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
658c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  result_.reset(ExtensionTabUtil::CreateTabValue(contents, tab_strip,
659c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      tab_index));
660c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
661c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
662c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
663c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool GetCurrentTabFunction::RunImpl() {
664c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(dispatcher());
665c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
666c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TabContents* contents = dispatcher()->delegate()->associated_tab_contents();
667c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (contents)
668c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    result_.reset(ExtensionTabUtil::CreateTabValue(contents));
669c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
670c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
671c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
672c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
673c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool UpdateTabFunction::RunImpl() {
674c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int tab_id;
675c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &tab_id));
676c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DictionaryValue* update_props;
677c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &update_props));
678c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
679c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TabStripModel* tab_strip = NULL;
680c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TabContents* contents = NULL;
681c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int tab_index = -1;
682c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!GetTabById(tab_id, profile(), include_incognito(),
683c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                  NULL, &tab_strip, &contents, &tab_index, &error_))
684c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
685c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
686c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  NavigationController& controller = contents->controller();
687c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
688c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // TODO(rafaelw): handle setting remaining tab properties:
689c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // -title
690c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // -favIconUrl
691c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
692c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Navigate the tab to a new location if the url different.
693c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string url_string;
694c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (update_props->HasKey(keys::kUrlKey)) {
695c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    EXTENSION_FUNCTION_VALIDATE(update_props->GetString(
696c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        keys::kUrlKey, &url_string));
697c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    GURL url = ResolvePossiblyRelativeURL(url_string, GetExtension());
698c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
699c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!url.is_valid()) {
700c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      error_ = ExtensionErrorUtils::FormatErrorMessage(keys::kInvalidUrlError,
701c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                       url_string);
702c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
703c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
704c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
705c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // JavaScript URLs can do the same kinds of things as cross-origin XHR, so
706c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // we need to check host permissions before allowing them.
707c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (url.SchemeIs(chrome::kJavaScriptScheme)) {
708731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      Extension* extension = GetExtension();
709731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      const std::vector<URLPattern> host_permissions =
710731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          extension->host_permissions();
711731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      if (!Extension::CanExecuteScriptOnPage(
712731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick              contents->GetURL(),
713731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick              extension->CanExecuteScriptEverywhere(),
714731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick              &host_permissions,
715731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick              NULL,
716731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick              &error_)) {
717c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return false;
718731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      }
719c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
720c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // TODO(aa): How does controller queue URLs? Is there any chance that this
721c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // JavaScript URL will end up applying to something other than
722c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // controller->GetURL()?
723c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
724c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
725c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (tab_strip->IsTabPinned(tab_index)) {
726c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Don't allow changing the url of pinned tabs.
727c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      error_ = keys::kCannotUpdatePinnedTab;
728c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
729c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
730c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
731c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    controller.LoadURL(url, GURL(), PageTransition::LINK);
732c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
733c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // The URL of a tab contents never actually changes to a JavaScript URL, so
734c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // this check only makes sense in other cases.
735c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!url.SchemeIs(chrome::kJavaScriptScheme))
736c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      DCHECK_EQ(url.spec(), contents->GetURL().spec());
737c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
738c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
739c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool selected = false;
740c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // TODO(rafaelw): Setting |selected| from js doesn't make much sense.
741c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Move tab selection management up to window.
742c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (update_props->HasKey(keys::kSelectedKey)) {
743c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    EXTENSION_FUNCTION_VALIDATE(update_props->GetBoolean(
744c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        keys::kSelectedKey,
745c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        &selected));
746c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (selected) {
747c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (tab_strip->selected_index() != tab_index) {
748c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        tab_strip->SelectTabContentsAt(tab_index, false);
749c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        DCHECK_EQ(contents, tab_strip->GetSelectedTabContents());
750c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
751c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      contents->Focus();
752c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
753c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
754c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
755c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (has_callback())
756c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    result_.reset(ExtensionTabUtil::CreateTabValue(contents, tab_strip,
757c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        tab_index));
758c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
759c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
760c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
761c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
762c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool MoveTabFunction::RunImpl() {
763c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int tab_id;
764c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &tab_id));
765c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DictionaryValue* update_props;
766c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &update_props));
767c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
768c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int new_index;
769c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXTENSION_FUNCTION_VALIDATE(update_props->GetInteger(
770c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      keys::kIndexKey, &new_index));
771c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXTENSION_FUNCTION_VALIDATE(new_index >= 0);
772c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
773c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Browser* source_browser = NULL;
774c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TabStripModel* source_tab_strip = NULL;
775c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TabContents* contents = NULL;
776c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int tab_index = -1;
777c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!GetTabById(tab_id, profile(), include_incognito(),
778c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                  &source_browser, &source_tab_strip, &contents,
779c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                  &tab_index, &error_))
780c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
781c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
782c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (source_browser->type() != Browser::TYPE_NORMAL) {
783c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    error_ = keys::kCanOnlyMoveTabsWithinNormalWindowsError;
784c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
785c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
786c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
787c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (update_props->HasKey(keys::kWindowIdKey)) {
788c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Browser* target_browser;
789c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int window_id;
790c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    EXTENSION_FUNCTION_VALIDATE(update_props->GetInteger(
791c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        keys::kWindowIdKey, &window_id));
792c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    target_browser = GetBrowserInProfileWithId(profile(), window_id,
793c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                               include_incognito(), &error_);
794c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!target_browser)
795c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
796c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
797c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (target_browser->type() != Browser::TYPE_NORMAL) {
798c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      error_ = keys::kCanOnlyMoveTabsWithinNormalWindowsError;
799c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
800c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
801c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
802c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // If windowId is different from the current window, move between windows.
803c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (ExtensionTabUtil::GetWindowId(target_browser) !=
804c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        ExtensionTabUtil::GetWindowId(source_browser)) {
805c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      TabStripModel* target_tab_strip = target_browser->tabstrip_model();
806c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      contents = source_tab_strip->DetachTabContentsAt(tab_index);
807c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (!contents) {
808c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        error_ = ExtensionErrorUtils::FormatErrorMessage(
8093345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick            keys::kTabNotFoundError, base::IntToString(tab_id));
810c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return false;
811c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
812c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
813c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Clamp move location to the last position.
814c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // This is ">" because it can append to a new index position.
815c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (new_index > target_tab_strip->count())
816c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        new_index = target_tab_strip->count();
817c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
818c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      target_tab_strip->InsertTabContentsAt(new_index, contents,
819c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                            TabStripModel::ADD_NONE);
820c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
821c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (has_callback())
822c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        result_.reset(ExtensionTabUtil::CreateTabValue(contents,
823c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            target_tab_strip, new_index));
824c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
825c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return true;
826c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
827c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
828c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
829c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Perform a simple within-window move.
830c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Clamp move location to the last position.
831c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // This is ">=" because the move must be to an existing location.
832c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (new_index >= source_tab_strip->count())
833c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    new_index = source_tab_strip->count() - 1;
834c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
835c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (new_index != tab_index)
836c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    source_tab_strip->MoveTabContentsAt(tab_index, new_index, false);
837c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
838c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (has_callback())
839c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    result_.reset(ExtensionTabUtil::CreateTabValue(contents, source_tab_strip,
840c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        new_index));
841c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
842c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
843c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
844c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
845c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool RemoveTabFunction::RunImpl() {
846c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int tab_id;
847c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &tab_id));
848c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
849c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Browser* browser = NULL;
850c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TabContents* contents = NULL;
851c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!GetTabById(tab_id, profile(), include_incognito(),
852c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                  &browser, NULL, &contents, NULL, &error_))
853c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
854c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
855c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Close the tab in this convoluted way, since there's a chance that the tab
856c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // is being dragged, or we're in some other nested event loop. This code path
857c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // should ensure that the tab is safely closed under such circumstances,
858c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // whereas |Browser::CloseTabContents()| does not.
859c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  RenderViewHost* render_view_host = contents->render_view_host();
860c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  render_view_host->delegate()->Close(render_view_host);
861c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
862c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
863c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
864c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool CaptureVisibleTabFunction::RunImpl() {
865c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Browser* browser;
866c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // windowId defaults to "current" window.
867c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int window_id = -1;
868c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
869c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (HasOptionalArgument(0)) {
870c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &window_id));
871c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    browser = GetBrowserInProfileWithId(profile(), window_id,
872c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                        include_incognito(), &error_);
873c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
874c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    browser = GetCurrentBrowser();
875c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
876c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
877c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!browser) {
878c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    error_ = keys::kNoCurrentWindowError;
879c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
880c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
881c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
882c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  image_format_ = FORMAT_JPEG;  // Default format is JPEG.
883c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  image_quality_ = kDefaultQuality;  // Default quality setting.
884c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
885c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (HasOptionalArgument(1)) {
886c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DictionaryValue* options;
887c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &options));
888c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
889c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (options->HasKey(keys::kFormatKey)) {
890c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      std::string format;
891c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      EXTENSION_FUNCTION_VALIDATE(
892c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          options->GetString(keys::kFormatKey, &format));
893c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
894c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (format == keys::kFormatValueJpeg) {
895c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        image_format_ = FORMAT_JPEG;
896c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      } else if (format == keys::kFormatValuePng) {
897c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        image_format_ = FORMAT_PNG;
898c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      } else {
899c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // Schema validation should make this unreachable.
900c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        EXTENSION_FUNCTION_VALIDATE(0);
901c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
902c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
903c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
904c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (options->HasKey(keys::kQualityKey)) {
905c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      EXTENSION_FUNCTION_VALIDATE(
906c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          options->GetInteger(keys::kQualityKey, &image_quality_));
907c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
908c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
909c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
910c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TabContents* tab_contents = browser->GetSelectedTabContents();
911c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!tab_contents) {
912c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    error_ = keys::kInternalVisibleTabCaptureError;
913c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
914c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
915c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  RenderViewHost* render_view_host = tab_contents->render_view_host();
916c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
917c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If a backing store is cached for the tab we want to capture,
918c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // and it can be copied into a bitmap, then use it to generate the image.
919c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BackingStore* backing_store = render_view_host->GetBackingStore(false);
920c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (backing_store && CaptureSnapshotFromBackingStore(backing_store))
921c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return true;
922c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
923c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Ask the renderer for a snapshot of the tab.
924c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  render_view_host->CaptureSnapshot();
925c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  registrar_.Add(this,
926c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 NotificationType::TAB_SNAPSHOT_TAKEN,
927c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 NotificationService::AllSources());
928c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  AddRef();  // Balanced in CaptureVisibleTabFunction::Observe().
929c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
930c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
931c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
932c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
933c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Build the image of a tab's contents out of a backing store.
934c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// This may fail if we can not copy a backing store into a bitmap.
935c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// For example, some uncommon X11 visual modes are not supported by
936c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// CopyFromBackingStore().
937c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool CaptureVisibleTabFunction::CaptureSnapshotFromBackingStore(
938c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    BackingStore* backing_store) {
939c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
940c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  skia::PlatformCanvas temp_canvas;
941c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!backing_store->CopyFromBackingStore(gfx::Rect(backing_store->size()),
942c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                           &temp_canvas)) {
943c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
944c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
945c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  LOG(INFO) << "captureVisibleTab() Got image from backing store.";
946c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
947c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SendResultFromBitmap(
948c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      temp_canvas.getTopPlatformDevice().accessBitmap(false));
949c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
950c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
951c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
952c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// If a backing store was not available in CaptureVisibleTabFunction::RunImpl,
953c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// than the renderer was asked for a snapshot.  Listen for a notification
954c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// that the snapshot is available.
955c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid CaptureVisibleTabFunction::Observe(NotificationType type,
956c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                        const NotificationSource& source,
957c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                        const NotificationDetails& details) {
958c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(type == NotificationType::TAB_SNAPSHOT_TAKEN);
959c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
960c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const SkBitmap *screen_capture = Details<const SkBitmap>(details).ptr();
961c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const bool error = screen_capture->empty();
962c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
963c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (error) {
964c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    error_ = keys::kInternalVisibleTabCaptureError;
965c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SendResponse(false);
966c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
967c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LOG(INFO) << "captureVisibleTab() Got image from renderer.";
968c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SendResultFromBitmap(*screen_capture);
969c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
970c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
971c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Release();  // Balanced in CaptureVisibleTabFunction::RunImpl().
972c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
973c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
974c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Turn a bitmap of the screen into an image, set that image as the result,
975c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// and call SendResponse().
976c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid CaptureVisibleTabFunction::SendResultFromBitmap(
977c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const SkBitmap& screen_capture) {
978c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_refptr<RefCountedBytes> image_data(new RefCountedBytes);
979c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SkAutoLockPixels screen_capture_lock(screen_capture);
980c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool encoded = false;
981c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string mime_type;
982c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  switch (image_format_) {
983c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case FORMAT_JPEG:
984c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      encoded = gfx::JPEGCodec::Encode(
985c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          reinterpret_cast<unsigned char*>(screen_capture.getAddr32(0, 0)),
986731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          gfx::JPEGCodec::FORMAT_SkBitmap,
987c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          screen_capture.width(),
988c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          screen_capture.height(),
989c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          static_cast<int>(screen_capture.rowBytes()),
990c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          image_quality_,
991c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          &image_data->data);
992c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      mime_type = keys::kMimeTypeJpeg;
993c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      break;
994c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case FORMAT_PNG:
995c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      encoded = gfx::PNGCodec::EncodeBGRASkBitmap(
996c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          screen_capture,
997c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          true,  // Discard transparency.
998c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          &image_data->data);
999c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      mime_type = keys::kMimeTypePng;
1000c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      break;
1001c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    default:
1002c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NOTREACHED() << "Invalid image format.";
1003c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1004c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1005c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!encoded) {
1006c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    error_ = ExtensionErrorUtils::FormatErrorMessage(
1007c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        keys::kInternalVisibleTabCaptureError, "");
1008c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SendResponse(false);
1009c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
1010c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1011c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1012c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string base64_result;
1013c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string stream_as_string;
1014c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  stream_as_string.resize(image_data->data.size());
1015c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  memcpy(&stream_as_string[0],
1016c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      reinterpret_cast<const char*>(&image_data->data[0]),
1017c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      image_data->data.size());
1018c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1019c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  base::Base64Encode(stream_as_string, &base64_result);
10203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  base64_result.insert(0, base::StringPrintf("data:%s;base64,",
10213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                             mime_type.c_str()));
1022c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  result_.reset(new StringValue(base64_result));
1023c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SendResponse(true);
1024c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1025c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1026c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool DetectTabLanguageFunction::RunImpl() {
1027c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int tab_id = 0;
1028c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Browser* browser = NULL;
1029c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TabContents* contents = NULL;
1030c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1031c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If |tab_id| is specified, look for it. Otherwise default to selected tab
1032c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // in the current window.
1033c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (HasOptionalArgument(0)) {
1034c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &tab_id));
1035c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!GetTabById(tab_id, profile(), include_incognito(),
1036c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                    &browser, NULL, &contents, NULL, &error_)) {
1037c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
1038c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
1039c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!browser || !contents)
1040c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
1041c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
1042c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    browser = GetCurrentBrowser();
1043c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!browser)
1044c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
1045c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    contents = browser->tabstrip_model()->GetSelectedTabContents();
1046c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!contents)
1047c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
1048c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1049c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1050c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (contents->controller().needs_reload()) {
1051731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    // If the tab hasn't been loaded, don't wait for the tab to load.
1052c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    error_ = keys::kCannotDetermineLanguageOfUnloadedTab;
1053c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
1054c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1055c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1056c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  AddRef();  // Balanced in GotLanguage()
1057c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1058c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!contents->language_state().original_language().empty()) {
1059c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Delay the callback invocation until after the current JS call has
1060c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // returned.
1061c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
1062c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        this, &DetectTabLanguageFunction::GotLanguage,
1063c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        contents->language_state().original_language()));
1064c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return true;
1065c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1066c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The tab contents does not know its language yet.  Let's  wait until it
1067c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // receives it, or until the tab is closed/navigates to some other page.
1068c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  registrar_.Add(this, NotificationType::TAB_LANGUAGE_DETERMINED,
1069c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 Source<TabContents>(contents));
1070c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  registrar_.Add(this, NotificationType::TAB_CLOSING,
1071c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 Source<NavigationController>(&(contents->controller())));
1072c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  registrar_.Add(this, NotificationType::NAV_ENTRY_COMMITTED,
1073c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 Source<NavigationController>(&(contents->controller())));
1074c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
1075c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1076c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1077c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DetectTabLanguageFunction::Observe(NotificationType type,
1078c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                        const NotificationSource& source,
1079c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                        const NotificationDetails& details) {
1080c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string language;
1081c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (type == NotificationType::TAB_LANGUAGE_DETERMINED)
1082c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    language = *Details<std::string>(details).ptr();
1083c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1084c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  registrar_.RemoveAll();
1085c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1086c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Call GotLanguage in all cases as we want to guarantee the callback is
1087c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // called for every API call the extension made.
1088c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GotLanguage(language);
1089c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1090c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1091c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DetectTabLanguageFunction::GotLanguage(const std::string& language) {
1092c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  result_.reset(Value::CreateStringValue(language.c_str()));
1093c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SendResponse(true);
1094c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1095c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Release();  // Balanced in Run()
1096c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1097c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1098c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static helpers
1099c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic Browser* GetBrowserInProfileWithId(Profile* profile,
1101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                          const int window_id,
1102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                          bool include_incognito,
1103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                          std::string* error_message) {
1104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Profile* incognito_profile =
11053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      include_incognito && profile->HasOffTheRecordProfile() ?
11063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          profile->GetOffTheRecordProfile() : NULL;
1107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (BrowserList::const_iterator browser = BrowserList::begin();
1108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       browser != BrowserList::end(); ++browser) {
1109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (((*browser)->profile() == profile ||
1110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch         (*browser)->profile() == incognito_profile) &&
1111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        ExtensionTabUtil::GetWindowId(*browser) == window_id)
1112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return *browser;
1113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (error_message)
1116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    *error_message = ExtensionErrorUtils::FormatErrorMessage(
11173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        keys::kWindowNotFoundError, base::IntToString(window_id));
1118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return NULL;
1120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic bool GetTabById(int tab_id, Profile* profile,
1123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                       bool include_incognito,
1124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                       Browser** browser,
1125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                       TabStripModel** tab_strip,
1126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                       TabContents** contents,
1127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                       int* tab_index,
1128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                       std::string* error_message) {
1129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (ExtensionTabUtil::GetTabById(tab_id, profile, include_incognito,
1130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                   browser, tab_strip, contents, tab_index))
1131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return true;
1132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (error_message)
1134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    *error_message = ExtensionErrorUtils::FormatErrorMessage(
11353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        keys::kTabNotFoundError, base::IntToString(tab_id));
1136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return false;
1138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic std::string GetWindowTypeText(Browser::Type type) {
1141731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if ((type & Browser::TYPE_POPUP) == Browser::TYPE_POPUP)
1142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return keys::kWindowTypeValuePopup;
1143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1144731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if ((type & Browser::TYPE_APP) == Browser::TYPE_APP)
1145731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return keys::kWindowTypeValueApp;
1146731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
1147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(type == Browser::TYPE_NORMAL);
1148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return keys::kWindowTypeValueNormal;
1149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic GURL ResolvePossiblyRelativeURL(std::string url_string,
1152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                       Extension* extension) {
1153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GURL url = GURL(url_string);
1154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!url.is_valid())
1155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    url = extension->GetResourceURL(url_string);
1156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return url;
1158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1159