Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(127)

Side by Side Diff: chrome/browser/extensions/extension_tabs_module.cc

Issue 9234042: Re-land alexbost's experimental offscreenTabs API. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: more cleanups Created 8 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/extensions/extension_tabs_module.h" 5 #include "chrome/browser/extensions/extension_tabs_module.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <vector> 8 #include <vector>
9 9
10 #include "base/base64.h" 10 #include "base/base64.h"
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
60 #include "ui/gfx/codec/png_codec.h" 60 #include "ui/gfx/codec/png_codec.h"
61 61
62 namespace keys = extension_tabs_module_constants; 62 namespace keys = extension_tabs_module_constants;
63 namespace errors = extension_manifest_errors; 63 namespace errors = extension_manifest_errors;
64 64
65 using content::NavigationController; 65 using content::NavigationController;
66 using content::NavigationEntry; 66 using content::NavigationEntry;
67 using content::OpenURLParams; 67 using content::OpenURLParams;
68 using content::Referrer; 68 using content::Referrer;
69 using content::WebContents; 69 using content::WebContents;
70 using extensions::tabs_module::IsCrashURL;
71 using extensions::tabs_module::ResolvePossiblyRelativeURL;
70 72
71 const int CaptureVisibleTabFunction::kDefaultQuality = 90; 73 const int CaptureVisibleTabFunction::kDefaultQuality = 90;
72 74
73 namespace { 75 namespace {
74 76
75 // |error_message| can optionally be passed in a will be set with an appropriate 77 // |error_message| can optionally be passed in a will be set with an appropriate
76 // message if the window cannot be found by id. 78 // message if the window cannot be found by id.
77 Browser* GetBrowserInProfileWithId(Profile* profile, 79 Browser* GetBrowserInProfileWithId(Profile* profile,
78 const int window_id, 80 const int window_id,
79 bool include_incognito, 81 bool include_incognito,
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
131 browser, tab_strip, contents, tab_index)) 133 browser, tab_strip, contents, tab_index))
132 return true; 134 return true;
133 135
134 if (error_message) 136 if (error_message)
135 *error_message = ExtensionErrorUtils::FormatErrorMessage( 137 *error_message = ExtensionErrorUtils::FormatErrorMessage(
136 keys::kTabNotFoundError, base::IntToString(tab_id)); 138 keys::kTabNotFoundError, base::IntToString(tab_id));
137 139
138 return false; 140 return false;
139 } 141 }
140 142
141 // Takes |url_string| and returns a GURL which is either valid and absolute
142 // or invalid. If |url_string| is not directly interpretable as a valid (it is
143 // likely a relative URL) an attempt is made to resolve it. |extension| is
144 // provided so it can be resolved relative to its extension base
145 // (chrome-extension://<id>/). Using the source frame url would be more correct,
146 // but because the api shipped with urls resolved relative to their extension
147 // base, we decided it wasn't worth breaking existing extensions to fix.
148 GURL ResolvePossiblyRelativeURL(const std::string& url_string,
149 const Extension* extension) {
150 GURL url = GURL(url_string);
151 if (!url.is_valid())
152 url = extension->GetResourceURL(url_string);
153
154 return url;
155 }
156
157 bool IsCrashURL(const GURL& url) {
158 // Check a fixed-up URL, to normalize the scheme and parse hosts correctly.
159 GURL fixed_url =
160 URLFixerUpper::FixupURL(url.possibly_invalid_spec(), std::string());
161 return (fixed_url.SchemeIs(chrome::kChromeUIScheme) &&
162 (fixed_url.host() == chrome::kChromeUIBrowserCrashHost ||
163 fixed_url.host() == chrome::kChromeUICrashHost));
164 }
165
166 // Reads the |value| as either a single integer value or a list of integers. 143 // Reads the |value| as either a single integer value or a list of integers.
167 bool ReadOneOrMoreIntegers( 144 bool ReadOneOrMoreIntegers(
168 Value* value, std::vector<int>* result) { 145 Value* value, std::vector<int>* result) {
169 if (value->IsType(Value::TYPE_INTEGER)) { 146 if (value->IsType(Value::TYPE_INTEGER)) {
170 int tab_id = -1; 147 int tab_id = -1;
171 if (!value->GetAsInteger(&tab_id)) 148 if (!value->GetAsInteger(&tab_id))
172 return false; 149 return false;
173 result->push_back(tab_id); 150 result->push_back(tab_id);
174 return true; 151 return true;
175 152
(...skipping 29 matching lines...) Expand all
205 if (query->HasKey(key)) { 182 if (query->HasKey(key)) {
206 bool value = false; 183 bool value = false;
207 CHECK(query->GetBoolean(key, &value)); 184 CHECK(query->GetBoolean(key, &value));
208 return value ? MATCH_TRUE : MATCH_FALSE; 185 return value ? MATCH_TRUE : MATCH_FALSE;
209 } 186 }
210 return NOT_SET; 187 return NOT_SET;
211 } 188 }
212 189
213 } // namespace 190 } // namespace
214 191
192 namespace extensions {
193 namespace tabs_module {
194
195 GURL ResolvePossiblyRelativeURL(const std::string& url_string,
196 const Extension* extension) {
197 GURL url = GURL(url_string);
198 if (!url.is_valid())
199 url = extension->GetResourceURL(url_string);
200
201 return url;
202 }
203
204 bool IsCrashURL(const GURL& url) {
205 // Check a fixed-up URL, to normalize the scheme and parse hosts correctly.
206 GURL fixed_url =
207 URLFixerUpper::FixupURL(url.possibly_invalid_spec(), std::string());
208 return (fixed_url.SchemeIs(chrome::kChromeUIScheme) &&
209 (fixed_url.host() == chrome::kChromeUIBrowserCrashHost ||
210 fixed_url.host() == chrome::kChromeUICrashHost));
211 }
212
213 } // namespace tabs_module
214 } // namespace extensions
215
215 // Windows --------------------------------------------------------------------- 216 // Windows ---------------------------------------------------------------------
216 217
217 bool GetWindowFunction::RunImpl() { 218 bool GetWindowFunction::RunImpl() {
218 int window_id = extension_misc::kUnknownWindowId; 219 int window_id = extension_misc::kUnknownWindowId;
219 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &window_id)); 220 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &window_id));
220 221
221 bool populate_tabs = false; 222 bool populate_tabs = false;
222 if (HasOptionalArgument(1)) { 223 if (HasOptionalArgument(1)) {
223 DictionaryValue* args = NULL; 224 DictionaryValue* args = NULL;
224 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &args)); 225 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &args));
(...skipping 835 matching lines...) Expand 10 before | Expand all | Expand 10 after
1060 } else { 1061 } else {
1061 EXTENSION_FUNCTION_VALIDATE(tab_value->GetAsInteger(&tab_id)); 1062 EXTENSION_FUNCTION_VALIDATE(tab_value->GetAsInteger(&tab_id));
1062 } 1063 }
1063 1064
1064 int tab_index = -1; 1065 int tab_index = -1;
1065 TabStripModel* tab_strip = NULL; 1066 TabStripModel* tab_strip = NULL;
1066 if (!GetTabById(tab_id, profile(), include_incognito(), 1067 if (!GetTabById(tab_id, profile(), include_incognito(),
1067 NULL, &tab_strip, &contents, &tab_index, &error_)) { 1068 NULL, &tab_strip, &contents, &tab_index, &error_)) {
1068 return false; 1069 return false;
1069 } 1070 }
1070 NavigationController& controller = contents->web_contents()->GetController();
1071 1071
1072 // TODO(rafaelw): handle setting remaining tab properties: 1072 // TODO(rafaelw): handle setting remaining tab properties:
1073 // -title 1073 // -title
1074 // -favIconUrl 1074 // -favIconUrl
1075 1075
1076 // Navigate the tab to a new location if the url is different. 1076 // Navigate the tab to a new location if the url is different.
1077 std::string url_string; 1077 bool is_async = false;
1078 if (update_props->HasKey(keys::kUrlKey)) { 1078 if (!UpdateURLIfPresent(update_props, contents->web_contents(), &is_async))
1079 EXTENSION_FUNCTION_VALIDATE(update_props->GetString( 1079 return false;
1080 keys::kUrlKey, &url_string));
1081 GURL url = ResolvePossiblyRelativeURL(url_string, GetExtension());
1082
1083 if (!url.is_valid()) {
1084 error_ = ExtensionErrorUtils::FormatErrorMessage(keys::kInvalidUrlError,
1085 url_string);
1086 return false;
1087 }
1088
1089 // Don't let the extension crash the browser or renderers.
1090 if (IsCrashURL(url)) {
1091 error_ = keys::kNoCrashBrowserError;
1092 return false;
1093 }
1094
1095 // JavaScript URLs can do the same kinds of things as cross-origin XHR, so
1096 // we need to check host permissions before allowing them.
1097 if (url.SchemeIs(chrome::kJavaScriptScheme)) {
1098 if (!GetExtension()->CanExecuteScriptOnPage(
1099 contents->web_contents()->GetURL(), NULL, &error_)) {
1100 return false;
1101 }
1102
1103 ExtensionMsg_ExecuteCode_Params params;
1104 params.request_id = request_id();
1105 params.extension_id = extension_id();
1106 params.is_javascript = true;
1107 params.code = url.path();
1108 params.all_frames = false;
1109 params.in_main_world = true;
1110
1111 RenderViewHost* render_view_host =
1112 contents->web_contents()->GetRenderViewHost();
1113 render_view_host->Send(
1114 new ExtensionMsg_ExecuteCode(render_view_host->routing_id(),
1115 params));
1116
1117 Observe(contents->web_contents());
1118 AddRef(); // balanced in Observe()
1119
1120 return true;
1121 }
1122
1123 controller.LoadURL(
1124 url, content::Referrer(), content::PAGE_TRANSITION_LINK, std::string());
1125
1126 // The URL of a tab contents never actually changes to a JavaScript URL, so
1127 // this check only makes sense in other cases.
1128 if (!url.SchemeIs(chrome::kJavaScriptScheme))
1129 DCHECK_EQ(url.spec(), contents->web_contents()->GetURL().spec());
1130 }
1131 1080
1132 bool active = false; 1081 bool active = false;
1133 // TODO(rafaelw): Setting |active| from js doesn't make much sense. 1082 // TODO(rafaelw): Setting |active| from js doesn't make much sense.
1134 // Move tab selection management up to window. 1083 // Move tab selection management up to window.
1135 if (update_props->HasKey(keys::kSelectedKey)) 1084 if (update_props->HasKey(keys::kSelectedKey))
1136 EXTENSION_FUNCTION_VALIDATE(update_props->GetBoolean( 1085 EXTENSION_FUNCTION_VALIDATE(update_props->GetBoolean(
1137 keys::kSelectedKey, &active)); 1086 keys::kSelectedKey, &active));
1138 1087
1139 // The 'active' property has replaced 'selected'. 1088 // The 'active' property has replaced 'selected'.
1140 if (update_props->HasKey(keys::kActiveKey)) 1089 if (update_props->HasKey(keys::kActiveKey))
(...skipping 29 matching lines...) Expand all
1170 if (has_callback()) { 1119 if (has_callback()) {
1171 if (GetExtension()->HasAPIPermission(ExtensionAPIPermission::kTab)) { 1120 if (GetExtension()->HasAPIPermission(ExtensionAPIPermission::kTab)) {
1172 result_.reset(ExtensionTabUtil::CreateTabValue(contents->web_contents(), 1121 result_.reset(ExtensionTabUtil::CreateTabValue(contents->web_contents(),
1173 tab_strip, 1122 tab_strip,
1174 tab_index)); 1123 tab_index));
1175 } else { 1124 } else {
1176 result_.reset(Value::CreateNullValue()); 1125 result_.reset(Value::CreateNullValue());
1177 } 1126 }
1178 } 1127 }
1179 1128
1180 SendResponse(true); 1129 if (!is_async)
1130 SendResponse(true);
1131
1181 return true; 1132 return true;
1182 } 1133 }
1183 1134
1135 bool UpdateTabFunction::UpdateURLIfPresent(DictionaryValue* update_props,
1136 WebContents* web_contents,
1137 bool* is_async) {
1138 if (!update_props->HasKey(keys::kUrlKey))
1139 return true;
1140
1141 std::string url_string;
1142 EXTENSION_FUNCTION_VALIDATE(update_props->GetString(
1143 keys::kUrlKey, &url_string));
1144 GURL url = ResolvePossiblyRelativeURL(url_string, GetExtension());
1145
1146 if (!url.is_valid()) {
1147 error_ = ExtensionErrorUtils::FormatErrorMessage(
1148 keys::kInvalidUrlError, url_string);
1149 return false;
1150 }
1151
1152 // Don't let the extension crash the browser or renderers.
1153 if (IsCrashURL(url)) {
1154 error_ = keys::kNoCrashBrowserError;
1155 return false;
1156 }
1157
1158 // JavaScript URLs can do the same kinds of things as cross-origin XHR, so
1159 // we need to check host permissions before allowing them.
1160 if (url.SchemeIs(chrome::kJavaScriptScheme)) {
1161 if (!GetExtension()->CanExecuteScriptOnPage(
1162 web_contents->GetURL(), NULL, &error_)) {
1163 return false;
1164 }
1165
1166 ExtensionMsg_ExecuteCode_Params params;
1167 params.request_id = request_id();
1168 params.extension_id = extension_id();
1169 params.is_javascript = true;
1170 params.code = url.path();
1171 params.all_frames = false;
1172 params.in_main_world = true;
1173
1174 RenderViewHost* render_view_host = web_contents->GetRenderViewHost();
1175 render_view_host->Send(
1176 new ExtensionMsg_ExecuteCode(render_view_host->routing_id(), params));
1177
1178 Observe(web_contents);
1179 AddRef(); // Balanced in OnExecuteCodeFinished().
1180
1181 // Tell the caller to wait for the response.
1182 *is_async = true;
1183 return true;
1184 }
1185
1186 web_contents->GetController().LoadURL(
1187 url, content::Referrer(), content::PAGE_TRANSITION_LINK, std::string());
1188
1189 // The URL of a tab contents never actually changes to a JavaScript URL, so
1190 // this check only makes sense in other cases.
1191 if (!url.SchemeIs(chrome::kJavaScriptScheme))
1192 DCHECK_EQ(url.spec(), web_contents->GetURL().spec());
1193
1194 return true;
1195 }
1196
1184 bool UpdateTabFunction::OnMessageReceived(const IPC::Message& message) { 1197 bool UpdateTabFunction::OnMessageReceived(const IPC::Message& message) {
1185 if (message.type() != ExtensionHostMsg_ExecuteCodeFinished::ID) 1198 if (message.type() != ExtensionHostMsg_ExecuteCodeFinished::ID)
1186 return false; 1199 return false;
1187 1200
1188 int message_request_id = -1; 1201 int message_request_id = -1;
1189 void* iter = NULL; 1202 void* iter = NULL;
1190 if (!message.ReadInt(&iter, &message_request_id)) { 1203 if (!message.ReadInt(&iter, &message_request_id)) {
1191 NOTREACHED() << "malformed extension message"; 1204 NOTREACHED() << "malformed extension message";
1192 return true; 1205 return true;
1193 } 1206 }
(...skipping 12 matching lines...) Expand all
1206 bool success, 1219 bool success,
1207 const std::string& error) { 1220 const std::string& error) {
1208 if (!error.empty()) { 1221 if (!error.empty()) {
1209 CHECK(!success); 1222 CHECK(!success);
1210 error_ = error; 1223 error_ = error;
1211 } 1224 }
1212 1225
1213 SendResponse(success); 1226 SendResponse(success);
1214 1227
1215 Observe(NULL); 1228 Observe(NULL);
1216 Release(); // balanced in Execute() 1229 Release(); // Balanced in UpdateURLIfPresent().
1217 } 1230 }
1218 1231
1219 bool MoveTabsFunction::RunImpl() { 1232 bool MoveTabsFunction::RunImpl() {
1220 Value* tab_value = NULL; 1233 Value* tab_value = NULL;
1221 EXTENSION_FUNCTION_VALIDATE(args_->Get(0, &tab_value)); 1234 EXTENSION_FUNCTION_VALIDATE(args_->Get(0, &tab_value));
1222 1235
1223 std::vector<int> tab_ids; 1236 std::vector<int> tab_ids;
1224 EXTENSION_FUNCTION_VALIDATE(ReadOneOrMoreIntegers(tab_value, &tab_ids)); 1237 EXTENSION_FUNCTION_VALIDATE(ReadOneOrMoreIntegers(tab_value, &tab_ids));
1225 1238
1226 DictionaryValue* update_props = NULL; 1239 DictionaryValue* update_props = NULL;
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after
1409 // is being dragged, or we're in some other nested event loop. This code 1422 // is being dragged, or we're in some other nested event loop. This code
1410 // path should ensure that the tab is safely closed under such 1423 // path should ensure that the tab is safely closed under such
1411 // circumstances, whereas |Browser::CloseTabContents()| does not. 1424 // circumstances, whereas |Browser::CloseTabContents()| does not.
1412 RenderViewHost* render_view_host = 1425 RenderViewHost* render_view_host =
1413 contents->web_contents()->GetRenderViewHost(); 1426 contents->web_contents()->GetRenderViewHost();
1414 render_view_host->delegate()->Close(render_view_host); 1427 render_view_host->delegate()->Close(render_view_host);
1415 } 1428 }
1416 return true; 1429 return true;
1417 } 1430 }
1418 1431
1419 bool CaptureVisibleTabFunction::RunImpl() { 1432 bool CaptureVisibleTabFunction::GetTabToCapture(
1433 WebContents** web_contents, TabContentsWrapper** wrapper) {
1420 Browser* browser = NULL; 1434 Browser* browser = NULL;
1421 // windowId defaults to "current" window. 1435 // windowId defaults to "current" window.
1422 int window_id = extension_misc::kCurrentWindowId; 1436 int window_id = extension_misc::kCurrentWindowId;
1423 1437
1424 if (HasOptionalArgument(0)) 1438 if (HasOptionalArgument(0))
1425 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &window_id)); 1439 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &window_id));
1426 1440
1427 if (!GetBrowserFromWindowID(this, window_id, &browser)) 1441 if (!GetBrowserFromWindowID(this, window_id, &browser))
1428 return false; 1442 return false;
1429 1443
1444 *web_contents = browser->GetSelectedWebContents();
1445 if (*web_contents == NULL) {
1446 error_ = keys::kInternalVisibleTabCaptureError;
1447 return false;
1448 }
1449
1450 *wrapper = browser->GetSelectedTabContentsWrapper();
1451
1452 return true;
1453 };
1454
1455 bool CaptureVisibleTabFunction::RunImpl() {
1456 WebContents* web_contents = NULL;
1457 TabContentsWrapper* wrapper = NULL;
1458 if (!GetTabToCapture(&web_contents, &wrapper))
1459 return false;
1460
1430 image_format_ = FORMAT_JPEG; // Default format is JPEG. 1461 image_format_ = FORMAT_JPEG; // Default format is JPEG.
1431 image_quality_ = kDefaultQuality; // Default quality setting. 1462 image_quality_ = kDefaultQuality; // Default quality setting.
1432 1463
1433 if (HasOptionalArgument(1)) { 1464 if (HasOptionalArgument(1)) {
1434 DictionaryValue* options = NULL; 1465 DictionaryValue* options = NULL;
1435 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &options)); 1466 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &options));
1436 1467
1437 if (options->HasKey(keys::kFormatKey)) { 1468 if (options->HasKey(keys::kFormatKey)) {
1438 std::string format; 1469 std::string format;
1439 EXTENSION_FUNCTION_VALIDATE( 1470 EXTENSION_FUNCTION_VALIDATE(
1440 options->GetString(keys::kFormatKey, &format)); 1471 options->GetString(keys::kFormatKey, &format));
1441 1472
1442 if (format == keys::kFormatValueJpeg) { 1473 if (format == keys::kFormatValueJpeg) {
1443 image_format_ = FORMAT_JPEG; 1474 image_format_ = FORMAT_JPEG;
1444 } else if (format == keys::kFormatValuePng) { 1475 } else if (format == keys::kFormatValuePng) {
1445 image_format_ = FORMAT_PNG; 1476 image_format_ = FORMAT_PNG;
1446 } else { 1477 } else {
1447 // Schema validation should make this unreachable. 1478 // Schema validation should make this unreachable.
1448 EXTENSION_FUNCTION_VALIDATE(0); 1479 EXTENSION_FUNCTION_VALIDATE(0);
1449 } 1480 }
1450 } 1481 }
1451 1482
1452 if (options->HasKey(keys::kQualityKey)) { 1483 if (options->HasKey(keys::kQualityKey)) {
1453 EXTENSION_FUNCTION_VALIDATE( 1484 EXTENSION_FUNCTION_VALIDATE(
1454 options->GetInteger(keys::kQualityKey, &image_quality_)); 1485 options->GetInteger(keys::kQualityKey, &image_quality_));
1455 } 1486 }
1456 } 1487 }
1457 1488
1458 WebContents* web_contents = browser->GetSelectedWebContents();
1459 if (!web_contents) {
1460 error_ = keys::kInternalVisibleTabCaptureError;
1461 return false;
1462 }
1463
1464 // captureVisibleTab() can return an image containing sensitive information 1489 // captureVisibleTab() can return an image containing sensitive information
1465 // that the browser would otherwise protect. Ensure the extension has 1490 // that the browser would otherwise protect. Ensure the extension has
1466 // permission to do this. 1491 // permission to do this.
1467 if (!GetExtension()->CanCaptureVisiblePage(web_contents->GetURL(), &error_)) 1492 if (!GetExtension()->CanCaptureVisiblePage(web_contents->GetURL(), &error_))
1468 return false; 1493 return false;
1469 1494
1470 RenderViewHost* render_view_host = web_contents->GetRenderViewHost();
1471
1472 // If a backing store is cached for the tab we want to capture, 1495 // If a backing store is cached for the tab we want to capture,
1473 // and it can be copied into a bitmap, then use it to generate the image. 1496 // and it can be copied into a bitmap, then use it to generate the image.
1497 RenderViewHost* render_view_host = web_contents->GetRenderViewHost();
1474 BackingStore* backing_store = render_view_host->GetBackingStore(false); 1498 BackingStore* backing_store = render_view_host->GetBackingStore(false);
1475 if (backing_store && CaptureSnapshotFromBackingStore(backing_store)) 1499 if (backing_store && CaptureSnapshotFromBackingStore(backing_store))
1476 return true; 1500 return true;
1477 1501
1478 // Ask the renderer for a snapshot of the tab. 1502 // Ask the renderer for a snapshot of the tab.
1479 TabContentsWrapper* wrapper = browser->GetSelectedTabContentsWrapper();
1480 wrapper->snapshot_tab_helper()->CaptureSnapshot(); 1503 wrapper->snapshot_tab_helper()->CaptureSnapshot();
1481 registrar_.Add(this, 1504 registrar_.Add(this,
1482 chrome::NOTIFICATION_TAB_SNAPSHOT_TAKEN, 1505 chrome::NOTIFICATION_TAB_SNAPSHOT_TAKEN,
1483 content::Source<TabContentsWrapper>(wrapper)); 1506 content::Source<TabContentsWrapper>(wrapper));
1484 AddRef(); // Balanced in CaptureVisibleTabFunction::Observe(). 1507 AddRef(); // Balanced in CaptureVisibleTabFunction::Observe().
1485 1508
1486 return true; 1509 return true;
1487 } 1510 }
1488 1511
1489 // Build the image of a tab's contents out of a backing store. 1512 // Build the image of a tab's contents out of a backing store.
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after
1647 // called for every API call the extension made. 1670 // called for every API call the extension made.
1648 GotLanguage(language); 1671 GotLanguage(language);
1649 } 1672 }
1650 1673
1651 void DetectTabLanguageFunction::GotLanguage(const std::string& language) { 1674 void DetectTabLanguageFunction::GotLanguage(const std::string& language) {
1652 result_.reset(Value::CreateStringValue(language.c_str())); 1675 result_.reset(Value::CreateStringValue(language.c_str()));
1653 SendResponse(true); 1676 SendResponse(true);
1654 1677
1655 Release(); // Balanced in Run() 1678 Release(); // Balanced in Run()
1656 } 1679 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698