| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 864 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1089 } | 1090 } |
| 1090 | 1091 |
| 1091 int tab_index = -1; | 1092 int tab_index = -1; |
| 1092 TabStripModel* tab_strip = NULL; | 1093 TabStripModel* tab_strip = NULL; |
| 1093 if (!GetTabById(tab_id, profile(), include_incognito(), | 1094 if (!GetTabById(tab_id, profile(), include_incognito(), |
| 1094 NULL, &tab_strip, &contents, &tab_index, &error_)) { | 1095 NULL, &tab_strip, &contents, &tab_index, &error_)) { |
| 1095 return false; | 1096 return false; |
| 1096 } | 1097 } |
| 1097 | 1098 |
| 1098 web_contents_ = contents->web_contents(); | 1099 web_contents_ = contents->web_contents(); |
| 1099 NavigationController& controller = web_contents_->GetController(); | |
| 1100 | 1100 |
| 1101 // TODO(rafaelw): handle setting remaining tab properties: | 1101 // TODO(rafaelw): handle setting remaining tab properties: |
| 1102 // -title | 1102 // -title |
| 1103 // -favIconUrl | 1103 // -favIconUrl |
| 1104 | 1104 |
| 1105 // We wait to fire the callback when executing 'javascript:' URLs in tabs. | 1105 // Navigate the tab to a new location if the url is different. |
| 1106 bool is_async = false; | 1106 bool is_async = false; |
| 1107 | 1107 if (!UpdateURLIfPresent(update_props, &is_async)) |
| 1108 // Navigate the tab to a new location if the url is different. | 1108 return false; |
| 1109 std::string url_string; | |
| 1110 if (update_props->HasKey(keys::kUrlKey)) { | |
| 1111 EXTENSION_FUNCTION_VALIDATE(update_props->GetString( | |
| 1112 keys::kUrlKey, &url_string)); | |
| 1113 GURL url = ResolvePossiblyRelativeURL(url_string, GetExtension()); | |
| 1114 | |
| 1115 if (!url.is_valid()) { | |
| 1116 error_ = ExtensionErrorUtils::FormatErrorMessage(keys::kInvalidUrlError, | |
| 1117 url_string); | |
| 1118 return false; | |
| 1119 } | |
| 1120 | |
| 1121 // Don't let the extension crash the browser or renderers. | |
| 1122 if (IsCrashURL(url)) { | |
| 1123 error_ = keys::kNoCrashBrowserError; | |
| 1124 return false; | |
| 1125 } | |
| 1126 | |
| 1127 // JavaScript URLs can do the same kinds of things as cross-origin XHR, so | |
| 1128 // we need to check host permissions before allowing them. | |
| 1129 if (url.SchemeIs(chrome::kJavaScriptScheme)) { | |
| 1130 if (!GetExtension()->CanExecuteScriptOnPage( | |
| 1131 web_contents_->GetURL(), NULL, &error_)) { | |
| 1132 return false; | |
| 1133 } | |
| 1134 | |
| 1135 ExtensionMsg_ExecuteCode_Params params; | |
| 1136 params.request_id = request_id(); | |
| 1137 params.extension_id = extension_id(); | |
| 1138 params.is_javascript = true; | |
| 1139 params.code = url.path(); | |
| 1140 params.all_frames = false; | |
| 1141 params.in_main_world = true; | |
| 1142 | |
| 1143 RenderViewHost* render_view_host = web_contents_->GetRenderViewHost(); | |
| 1144 render_view_host->Send( | |
| 1145 new ExtensionMsg_ExecuteCode(render_view_host->routing_id(), | |
| 1146 params)); | |
| 1147 | |
| 1148 Observe(web_contents_); | |
| 1149 AddRef(); // Balanced in OnExecuteCodeFinished(). | |
| 1150 | |
| 1151 is_async = true; | |
| 1152 } | |
| 1153 | |
| 1154 controller.LoadURL( | |
| 1155 url, content::Referrer(), content::PAGE_TRANSITION_LINK, std::string()); | |
| 1156 | |
| 1157 // The URL of a tab contents never actually changes to a JavaScript URL, so | |
| 1158 // this check only makes sense in other cases. | |
| 1159 if (!url.SchemeIs(chrome::kJavaScriptScheme)) | |
| 1160 DCHECK_EQ(url.spec(), web_contents_->GetURL().spec()); | |
| 1161 } | |
| 1162 | 1109 |
| 1163 bool active = false; | 1110 bool active = false; |
| 1164 // TODO(rafaelw): Setting |active| from js doesn't make much sense. | 1111 // TODO(rafaelw): Setting |active| from js doesn't make much sense. |
| 1165 // Move tab selection management up to window. | 1112 // Move tab selection management up to window. |
| 1166 if (update_props->HasKey(keys::kSelectedKey)) | 1113 if (update_props->HasKey(keys::kSelectedKey)) |
| 1167 EXTENSION_FUNCTION_VALIDATE(update_props->GetBoolean( | 1114 EXTENSION_FUNCTION_VALIDATE(update_props->GetBoolean( |
| 1168 keys::kSelectedKey, &active)); | 1115 keys::kSelectedKey, &active)); |
| 1169 | 1116 |
| 1170 // The 'active' property has replaced 'selected'. | 1117 // The 'active' property has replaced 'selected'. |
| 1171 if (update_props->HasKey(keys::kActiveKey)) | 1118 if (update_props->HasKey(keys::kActiveKey)) |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1213 tab_index, &opener_contents->web_contents()->GetController()); | 1160 tab_index, &opener_contents->web_contents()->GetController()); |
| 1214 } | 1161 } |
| 1215 | 1162 |
| 1216 if (!is_async) { | 1163 if (!is_async) { |
| 1217 PopulateResult(); | 1164 PopulateResult(); |
| 1218 SendResponse(true); | 1165 SendResponse(true); |
| 1219 } | 1166 } |
| 1220 return true; | 1167 return true; |
| 1221 } | 1168 } |
| 1222 | 1169 |
| 1170 bool UpdateTabFunction::UpdateURLIfPresent(DictionaryValue* update_props, |
| 1171 bool* is_async) { |
| 1172 if (!update_props->HasKey(keys::kUrlKey)) |
| 1173 return true; |
| 1174 |
| 1175 std::string url_string; |
| 1176 EXTENSION_FUNCTION_VALIDATE(update_props->GetString( |
| 1177 keys::kUrlKey, &url_string)); |
| 1178 GURL url = ResolvePossiblyRelativeURL(url_string, GetExtension()); |
| 1179 |
| 1180 if (!url.is_valid()) { |
| 1181 error_ = ExtensionErrorUtils::FormatErrorMessage( |
| 1182 keys::kInvalidUrlError, url_string); |
| 1183 return false; |
| 1184 } |
| 1185 |
| 1186 // Don't let the extension crash the browser or renderers. |
| 1187 if (IsCrashURL(url)) { |
| 1188 error_ = keys::kNoCrashBrowserError; |
| 1189 return false; |
| 1190 } |
| 1191 |
| 1192 // JavaScript URLs can do the same kinds of things as cross-origin XHR, so |
| 1193 // we need to check host permissions before allowing them. |
| 1194 if (url.SchemeIs(chrome::kJavaScriptScheme)) { |
| 1195 if (!GetExtension()->CanExecuteScriptOnPage( |
| 1196 web_contents_->GetURL(), NULL, &error_)) { |
| 1197 return false; |
| 1198 } |
| 1199 |
| 1200 ExtensionMsg_ExecuteCode_Params params; |
| 1201 params.request_id = request_id(); |
| 1202 params.extension_id = extension_id(); |
| 1203 params.is_javascript = true; |
| 1204 params.code = url.path(); |
| 1205 params.all_frames = false; |
| 1206 params.in_main_world = true; |
| 1207 |
| 1208 RenderViewHost* render_view_host = web_contents_->GetRenderViewHost(); |
| 1209 render_view_host->Send( |
| 1210 new ExtensionMsg_ExecuteCode(render_view_host->routing_id(), params)); |
| 1211 |
| 1212 Observe(web_contents_); |
| 1213 AddRef(); // Balanced in OnExecuteCodeFinished(). |
| 1214 |
| 1215 *is_async = true; |
| 1216 return true; |
| 1217 } |
| 1218 |
| 1219 web_contents_->GetController().LoadURL( |
| 1220 url, content::Referrer(), content::PAGE_TRANSITION_LINK, std::string()); |
| 1221 |
| 1222 // The URL of a tab contents never actually changes to a JavaScript URL, so |
| 1223 // this check only makes sense in other cases. |
| 1224 if (!url.SchemeIs(chrome::kJavaScriptScheme)) |
| 1225 DCHECK_EQ(url.spec(), web_contents_->GetURL().spec()); |
| 1226 |
| 1227 return true; |
| 1228 } |
| 1229 |
| 1223 void UpdateTabFunction::PopulateResult() { | 1230 void UpdateTabFunction::PopulateResult() { |
| 1224 if (!has_callback()) | 1231 if (!has_callback()) |
| 1225 return; | 1232 return; |
| 1226 | 1233 |
| 1227 if (GetExtension()->HasAPIPermission(ExtensionAPIPermission::kTab) && | 1234 if (GetExtension()->HasAPIPermission(ExtensionAPIPermission::kTab) && |
| 1228 web_contents_ != NULL) { | 1235 web_contents_ != NULL) { |
| 1229 result_.reset(ExtensionTabUtil::CreateTabValue(web_contents_)); | 1236 result_.reset(ExtensionTabUtil::CreateTabValue(web_contents_)); |
| 1230 } else { | 1237 } else { |
| 1231 result_.reset(Value::CreateNullValue()); | 1238 result_.reset(Value::CreateNullValue()); |
| 1232 } | 1239 } |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1264 if (!error.empty()) { | 1271 if (!error.empty()) { |
| 1265 CHECK(!success); | 1272 CHECK(!success); |
| 1266 error_ = error; | 1273 error_ = error; |
| 1267 } | 1274 } |
| 1268 | 1275 |
| 1269 if (success) | 1276 if (success) |
| 1270 PopulateResult(); | 1277 PopulateResult(); |
| 1271 SendResponse(success); | 1278 SendResponse(success); |
| 1272 | 1279 |
| 1273 Observe(NULL); | 1280 Observe(NULL); |
| 1274 Release(); // Balanced in RunImpl(). | 1281 Release(); // Balanced in UpdateURLIfPresent(). |
| 1275 } | 1282 } |
| 1276 | 1283 |
| 1277 bool MoveTabsFunction::RunImpl() { | 1284 bool MoveTabsFunction::RunImpl() { |
| 1278 Value* tab_value = NULL; | 1285 Value* tab_value = NULL; |
| 1279 EXTENSION_FUNCTION_VALIDATE(args_->Get(0, &tab_value)); | 1286 EXTENSION_FUNCTION_VALIDATE(args_->Get(0, &tab_value)); |
| 1280 | 1287 |
| 1281 std::vector<int> tab_ids; | 1288 std::vector<int> tab_ids; |
| 1282 EXTENSION_FUNCTION_VALIDATE(ReadOneOrMoreIntegers(tab_value, &tab_ids)); | 1289 EXTENSION_FUNCTION_VALIDATE(ReadOneOrMoreIntegers(tab_value, &tab_ids)); |
| 1283 | 1290 |
| 1284 DictionaryValue* update_props = NULL; | 1291 DictionaryValue* update_props = NULL; |
| (...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1467 // is being dragged, or we're in some other nested event loop. This code | 1474 // is being dragged, or we're in some other nested event loop. This code |
| 1468 // path should ensure that the tab is safely closed under such | 1475 // path should ensure that the tab is safely closed under such |
| 1469 // circumstances, whereas |Browser::CloseTabContents()| does not. | 1476 // circumstances, whereas |Browser::CloseTabContents()| does not. |
| 1470 RenderViewHost* render_view_host = | 1477 RenderViewHost* render_view_host = |
| 1471 contents->web_contents()->GetRenderViewHost(); | 1478 contents->web_contents()->GetRenderViewHost(); |
| 1472 render_view_host->delegate()->Close(render_view_host); | 1479 render_view_host->delegate()->Close(render_view_host); |
| 1473 } | 1480 } |
| 1474 return true; | 1481 return true; |
| 1475 } | 1482 } |
| 1476 | 1483 |
| 1477 bool CaptureVisibleTabFunction::RunImpl() { | 1484 bool CaptureVisibleTabFunction::GetTabToCapture( |
| 1485 WebContents** web_contents, TabContentsWrapper** wrapper) { |
| 1478 Browser* browser = NULL; | 1486 Browser* browser = NULL; |
| 1479 // windowId defaults to "current" window. | 1487 // windowId defaults to "current" window. |
| 1480 int window_id = extension_misc::kCurrentWindowId; | 1488 int window_id = extension_misc::kCurrentWindowId; |
| 1481 | 1489 |
| 1482 if (HasOptionalArgument(0)) | 1490 if (HasOptionalArgument(0)) |
| 1483 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &window_id)); | 1491 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &window_id)); |
| 1484 | 1492 |
| 1485 if (!GetBrowserFromWindowID(this, window_id, &browser)) | 1493 if (!GetBrowserFromWindowID(this, window_id, &browser)) |
| 1486 return false; | 1494 return false; |
| 1487 | 1495 |
| 1496 *web_contents = browser->GetSelectedWebContents(); |
| 1497 if (*web_contents == NULL) { |
| 1498 error_ = keys::kInternalVisibleTabCaptureError; |
| 1499 return false; |
| 1500 } |
| 1501 |
| 1502 *wrapper = browser->GetSelectedTabContentsWrapper(); |
| 1503 |
| 1504 return true; |
| 1505 }; |
| 1506 |
| 1507 bool CaptureVisibleTabFunction::RunImpl() { |
| 1508 WebContents* web_contents = NULL; |
| 1509 TabContentsWrapper* wrapper = NULL; |
| 1510 if (!GetTabToCapture(&web_contents, &wrapper)) |
| 1511 return false; |
| 1512 |
| 1488 image_format_ = FORMAT_JPEG; // Default format is JPEG. | 1513 image_format_ = FORMAT_JPEG; // Default format is JPEG. |
| 1489 image_quality_ = kDefaultQuality; // Default quality setting. | 1514 image_quality_ = kDefaultQuality; // Default quality setting. |
| 1490 | 1515 |
| 1491 if (HasOptionalArgument(1)) { | 1516 if (HasOptionalArgument(1)) { |
| 1492 DictionaryValue* options = NULL; | 1517 DictionaryValue* options = NULL; |
| 1493 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &options)); | 1518 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &options)); |
| 1494 | 1519 |
| 1495 if (options->HasKey(keys::kFormatKey)) { | 1520 if (options->HasKey(keys::kFormatKey)) { |
| 1496 std::string format; | 1521 std::string format; |
| 1497 EXTENSION_FUNCTION_VALIDATE( | 1522 EXTENSION_FUNCTION_VALIDATE( |
| 1498 options->GetString(keys::kFormatKey, &format)); | 1523 options->GetString(keys::kFormatKey, &format)); |
| 1499 | 1524 |
| 1500 if (format == keys::kFormatValueJpeg) { | 1525 if (format == keys::kFormatValueJpeg) { |
| 1501 image_format_ = FORMAT_JPEG; | 1526 image_format_ = FORMAT_JPEG; |
| 1502 } else if (format == keys::kFormatValuePng) { | 1527 } else if (format == keys::kFormatValuePng) { |
| 1503 image_format_ = FORMAT_PNG; | 1528 image_format_ = FORMAT_PNG; |
| 1504 } else { | 1529 } else { |
| 1505 // Schema validation should make this unreachable. | 1530 // Schema validation should make this unreachable. |
| 1506 EXTENSION_FUNCTION_VALIDATE(0); | 1531 EXTENSION_FUNCTION_VALIDATE(0); |
| 1507 } | 1532 } |
| 1508 } | 1533 } |
| 1509 | 1534 |
| 1510 if (options->HasKey(keys::kQualityKey)) { | 1535 if (options->HasKey(keys::kQualityKey)) { |
| 1511 EXTENSION_FUNCTION_VALIDATE( | 1536 EXTENSION_FUNCTION_VALIDATE( |
| 1512 options->GetInteger(keys::kQualityKey, &image_quality_)); | 1537 options->GetInteger(keys::kQualityKey, &image_quality_)); |
| 1513 } | 1538 } |
| 1514 } | 1539 } |
| 1515 | 1540 |
| 1516 WebContents* web_contents = browser->GetSelectedWebContents(); | |
| 1517 if (!web_contents) { | |
| 1518 error_ = keys::kInternalVisibleTabCaptureError; | |
| 1519 return false; | |
| 1520 } | |
| 1521 | |
| 1522 // captureVisibleTab() can return an image containing sensitive information | 1541 // captureVisibleTab() can return an image containing sensitive information |
| 1523 // that the browser would otherwise protect. Ensure the extension has | 1542 // that the browser would otherwise protect. Ensure the extension has |
| 1524 // permission to do this. | 1543 // permission to do this. |
| 1525 if (!GetExtension()->CanCaptureVisiblePage(web_contents->GetURL(), &error_)) | 1544 if (!GetExtension()->CanCaptureVisiblePage(web_contents->GetURL(), &error_)) |
| 1526 return false; | 1545 return false; |
| 1527 | 1546 |
| 1528 RenderViewHost* render_view_host = web_contents->GetRenderViewHost(); | |
| 1529 | |
| 1530 // If a backing store is cached for the tab we want to capture, | 1547 // If a backing store is cached for the tab we want to capture, |
| 1531 // and it can be copied into a bitmap, then use it to generate the image. | 1548 // and it can be copied into a bitmap, then use it to generate the image. |
| 1532 BackingStore* backing_store = render_view_host->GetBackingStore(false); | 1549 if (CaptureSnapshotFromBackingStore(web_contents)) |
| 1533 if (backing_store && CaptureSnapshotFromBackingStore(backing_store)) | |
| 1534 return true; | 1550 return true; |
| 1535 | 1551 |
| 1536 // Ask the renderer for a snapshot of the tab. | 1552 // Ask the renderer for a snapshot of the tab. |
| 1537 TabContentsWrapper* wrapper = browser->GetSelectedTabContentsWrapper(); | |
| 1538 wrapper->snapshot_tab_helper()->CaptureSnapshot(); | 1553 wrapper->snapshot_tab_helper()->CaptureSnapshot(); |
| 1539 registrar_.Add(this, | 1554 registrar_.Add(this, |
| 1540 chrome::NOTIFICATION_TAB_SNAPSHOT_TAKEN, | 1555 chrome::NOTIFICATION_TAB_SNAPSHOT_TAKEN, |
| 1541 content::Source<TabContentsWrapper>(wrapper)); | 1556 content::Source<TabContentsWrapper>(wrapper)); |
| 1542 AddRef(); // Balanced in CaptureVisibleTabFunction::Observe(). | 1557 AddRef(); // Balanced in CaptureVisibleTabFunction::Observe(). |
| 1543 | 1558 |
| 1544 return true; | 1559 return true; |
| 1545 } | 1560 } |
| 1546 | 1561 |
| 1547 // Build the image of a tab's contents out of a backing store. | 1562 // Build the image of a tab's contents out of a backing store. |
| 1548 // This may fail if we can not copy a backing store into a bitmap. | 1563 // This may fail if we can not copy a backing store into a bitmap. |
| 1549 // For example, some uncommon X11 visual modes are not supported by | 1564 // For example, some uncommon X11 visual modes are not supported by |
| 1550 // CopyFromBackingStore(). | 1565 // CopyFromBackingStore(). |
| 1551 bool CaptureVisibleTabFunction::CaptureSnapshotFromBackingStore( | 1566 bool CaptureVisibleTabFunction::CaptureSnapshotFromBackingStore( |
| 1552 BackingStore* backing_store) { | 1567 WebContents* web_contents) { |
| 1568 BackingStore* backing_store = |
| 1569 web_contents->GetRenderViewHost()->GetBackingStore(false); |
| 1570 if (!backing_store) |
| 1571 return false; |
| 1553 | 1572 |
| 1554 skia::PlatformCanvas temp_canvas; | 1573 skia::PlatformCanvas temp_canvas; |
| 1555 if (!backing_store->CopyFromBackingStore(gfx::Rect(backing_store->size()), | 1574 if (!backing_store->CopyFromBackingStore(gfx::Rect(backing_store->size()), |
| 1556 &temp_canvas)) { | 1575 &temp_canvas)) { |
| 1557 return false; | 1576 return false; |
| 1558 } | 1577 } |
| 1559 VLOG(1) << "captureVisibleTab() got image from backing store."; | 1578 VLOG(1) << "captureVisibleTab() got image from backing store."; |
| 1560 | 1579 |
| 1561 SendResultFromBitmap( | 1580 SendResultFromBitmap( |
| 1562 skia::GetTopDevice(temp_canvas)->accessBitmap(false)); | 1581 skia::GetTopDevice(temp_canvas)->accessBitmap(false)); |
| (...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1705 // called for every API call the extension made. | 1724 // called for every API call the extension made. |
| 1706 GotLanguage(language); | 1725 GotLanguage(language); |
| 1707 } | 1726 } |
| 1708 | 1727 |
| 1709 void DetectTabLanguageFunction::GotLanguage(const std::string& language) { | 1728 void DetectTabLanguageFunction::GotLanguage(const std::string& language) { |
| 1710 result_.reset(Value::CreateStringValue(language.c_str())); | 1729 result_.reset(Value::CreateStringValue(language.c_str())); |
| 1711 SendResponse(true); | 1730 SendResponse(true); |
| 1712 | 1731 |
| 1713 Release(); // Balanced in Run() | 1732 Release(); // Balanced in Run() |
| 1714 } | 1733 } |
| OLD | NEW |