OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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/api/developer_private/extension_info_generat
or.h" | 5 #include "chrome/browser/extensions/api/developer_private/extension_info_generat
or.h" |
6 | 6 |
| 7 #include "base/base64.h" |
7 #include "base/strings/utf_string_conversions.h" | 8 #include "base/strings/utf_string_conversions.h" |
8 #include "chrome/browser/extensions/api/developer_private/inspectable_views_find
er.h" | 9 #include "chrome/browser/extensions/api/developer_private/inspectable_views_find
er.h" |
9 #include "chrome/browser/extensions/api/extension_action/extension_action_api.h" | 10 #include "chrome/browser/extensions/api/extension_action/extension_action_api.h" |
10 #include "chrome/browser/extensions/error_console/error_console.h" | 11 #include "chrome/browser/extensions/error_console/error_console.h" |
11 #include "chrome/browser/extensions/extension_service.h" | 12 #include "chrome/browser/extensions/extension_service.h" |
12 #include "chrome/browser/extensions/extension_ui_util.h" | 13 #include "chrome/browser/extensions/extension_ui_util.h" |
13 #include "chrome/browser/extensions/extension_util.h" | 14 #include "chrome/browser/extensions/extension_util.h" |
14 #include "chrome/browser/extensions/path_util.h" | 15 #include "chrome/browser/extensions/path_util.h" |
15 #include "chrome/browser/extensions/shared_module_service.h" | 16 #include "chrome/browser/extensions/shared_module_service.h" |
16 #include "chrome/browser/profiles/profile.h" | 17 #include "chrome/browser/profiles/profile.h" |
17 #include "chrome/browser/ui/webui/extensions/extension_icon_source.h" | 18 #include "chrome/browser/ui/webui/extensions/extension_icon_source.h" |
18 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h" | 19 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h" |
19 #include "chrome/grit/generated_resources.h" | 20 #include "chrome/grit/generated_resources.h" |
20 #include "content/public/browser/render_view_host.h" | 21 #include "content/public/browser/render_view_host.h" |
21 #include "extensions/browser/extension_error.h" | 22 #include "extensions/browser/extension_error.h" |
22 #include "extensions/browser/extension_prefs.h" | 23 #include "extensions/browser/extension_prefs.h" |
23 #include "extensions/browser/extension_registry.h" | 24 #include "extensions/browser/extension_registry.h" |
24 #include "extensions/browser/extension_system.h" | 25 #include "extensions/browser/extension_system.h" |
| 26 #include "extensions/browser/image_loader.h" |
25 #include "extensions/browser/warning_service.h" | 27 #include "extensions/browser/warning_service.h" |
26 #include "extensions/common/extension_set.h" | 28 #include "extensions/common/extension_set.h" |
27 #include "extensions/common/feature_switch.h" | 29 #include "extensions/common/feature_switch.h" |
28 #include "extensions/common/install_warning.h" | 30 #include "extensions/common/install_warning.h" |
29 #include "extensions/common/manifest.h" | 31 #include "extensions/common/manifest.h" |
30 #include "extensions/common/manifest_handlers/background_info.h" | 32 #include "extensions/common/manifest_handlers/background_info.h" |
| 33 #include "extensions/common/manifest_handlers/icons_handler.h" |
31 #include "extensions/common/manifest_handlers/offline_enabled_info.h" | 34 #include "extensions/common/manifest_handlers/offline_enabled_info.h" |
32 #include "extensions/common/manifest_handlers/options_page_info.h" | 35 #include "extensions/common/manifest_handlers/options_page_info.h" |
33 #include "extensions/common/manifest_url_handlers.h" | 36 #include "extensions/common/manifest_url_handlers.h" |
34 #include "extensions/common/permissions/permissions_data.h" | 37 #include "extensions/common/permissions/permissions_data.h" |
| 38 #include "extensions/grit/extensions_browser_resources.h" |
35 #include "ui/base/l10n/l10n_util.h" | 39 #include "ui/base/l10n/l10n_util.h" |
| 40 #include "ui/base/resource/resource_bundle.h" |
| 41 #include "ui/gfx/codec/png_codec.h" |
| 42 #include "ui/gfx/color_utils.h" |
| 43 #include "ui/gfx/image/image.h" |
| 44 #include "ui/gfx/skbitmap_operations.h" |
36 | 45 |
37 namespace extensions { | 46 namespace extensions { |
38 | 47 |
39 namespace developer = api::developer_private; | 48 namespace developer = api::developer_private; |
40 | 49 |
41 namespace { | 50 namespace { |
42 | 51 |
43 // Given a Manifest::Type, converts it into its developer_private | 52 // Given a Manifest::Type, converts it into its developer_private |
44 // counterpart. | 53 // counterpart. |
45 developer::ExtensionType GetExtensionType(Manifest::Type manifest_type) { | 54 developer::ExtensionType GetExtensionType(Manifest::Type manifest_type) { |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
135 | 144 |
136 } // namespace | 145 } // namespace |
137 | 146 |
138 ExtensionInfoGenerator::ExtensionInfoGenerator( | 147 ExtensionInfoGenerator::ExtensionInfoGenerator( |
139 content::BrowserContext* browser_context) | 148 content::BrowserContext* browser_context) |
140 : browser_context_(browser_context), | 149 : browser_context_(browser_context), |
141 extension_system_(ExtensionSystem::Get(browser_context)), | 150 extension_system_(ExtensionSystem::Get(browser_context)), |
142 extension_prefs_(ExtensionPrefs::Get(browser_context)), | 151 extension_prefs_(ExtensionPrefs::Get(browser_context)), |
143 extension_action_api_(ExtensionActionAPI::Get(browser_context)), | 152 extension_action_api_(ExtensionActionAPI::Get(browser_context)), |
144 warning_service_(WarningService::Get(browser_context)), | 153 warning_service_(WarningService::Get(browser_context)), |
145 error_console_(ErrorConsole::Get(browser_context)) { | 154 error_console_(ErrorConsole::Get(browser_context)), |
| 155 image_loader_(ImageLoader::Get(browser_context)), |
| 156 pending_image_loads_(0u), |
| 157 weak_factory_(this) { |
146 } | 158 } |
147 | 159 |
148 ExtensionInfoGenerator::~ExtensionInfoGenerator() { | 160 ExtensionInfoGenerator::~ExtensionInfoGenerator() { |
149 } | 161 } |
150 | 162 |
151 scoped_ptr<developer::ExtensionInfo> | 163 void ExtensionInfoGenerator::CreateExtensionInfo( |
152 ExtensionInfoGenerator::CreateExtensionInfo(const Extension& extension, | 164 const std::string& id, |
153 developer::ExtensionState state) { | 165 const ExtensionInfosCallback& callback) { |
| 166 DCHECK(callback_.is_null() && list_.empty()) << |
| 167 "Only a single generation can be running at a time!"; |
| 168 ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context_); |
| 169 |
| 170 developer::ExtensionState state = developer::EXTENSION_STATE_NONE; |
| 171 const Extension* ext = nullptr; |
| 172 if ((ext = registry->enabled_extensions().GetByID(id)) != nullptr) |
| 173 state = developer::EXTENSION_STATE_ENABLED; |
| 174 else if ((ext = registry->disabled_extensions().GetByID(id)) != nullptr) |
| 175 state = developer::EXTENSION_STATE_DISABLED; |
| 176 else if ((ext = registry->terminated_extensions().GetByID(id)) != nullptr) |
| 177 state = developer::EXTENSION_STATE_TERMINATED; |
| 178 |
| 179 if (ext && ui_util::ShouldDisplayInExtensionSettings(ext, browser_context_)) |
| 180 CreateExtensionInfoHelper(*ext, state); |
| 181 |
| 182 if (pending_image_loads_ == 0) { |
| 183 // Don't call the callback re-entrantly. |
| 184 base::MessageLoop::current()->PostTask(FROM_HERE, |
| 185 base::Bind(callback, list_)); |
| 186 list_.clear(); |
| 187 } else { |
| 188 callback_ = callback; |
| 189 } |
| 190 } |
| 191 |
| 192 void ExtensionInfoGenerator::CreateExtensionsInfo( |
| 193 bool include_disabled, |
| 194 bool include_terminated, |
| 195 const ExtensionInfosCallback& callback) { |
| 196 auto add_to_list = [this](const ExtensionSet& extensions, |
| 197 developer::ExtensionState state) { |
| 198 for (const scoped_refptr<const Extension>& extension : extensions) { |
| 199 if (ui_util::ShouldDisplayInExtensionSettings(extension.get(), |
| 200 browser_context_)) { |
| 201 CreateExtensionInfoHelper(*extension, state); |
| 202 } |
| 203 } |
| 204 }; |
| 205 |
| 206 ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context_); |
| 207 add_to_list(registry->enabled_extensions(), |
| 208 developer::EXTENSION_STATE_ENABLED); |
| 209 if (include_disabled) { |
| 210 add_to_list(registry->disabled_extensions(), |
| 211 developer::EXTENSION_STATE_DISABLED); |
| 212 } |
| 213 if (include_terminated) { |
| 214 add_to_list(registry->terminated_extensions(), |
| 215 developer::EXTENSION_STATE_TERMINATED); |
| 216 } |
| 217 |
| 218 if (pending_image_loads_ == 0) { |
| 219 // Don't call the callback re-entrantly. |
| 220 base::MessageLoop::current()->PostTask(FROM_HERE, |
| 221 base::Bind(callback, list_)); |
| 222 list_.clear(); |
| 223 } else { |
| 224 callback_ = callback; |
| 225 } |
| 226 } |
| 227 |
| 228 void ExtensionInfoGenerator::CreateExtensionInfoHelper( |
| 229 const Extension& extension, |
| 230 developer::ExtensionState state) { |
154 scoped_ptr<developer::ExtensionInfo> info(new developer::ExtensionInfo()); | 231 scoped_ptr<developer::ExtensionInfo> info(new developer::ExtensionInfo()); |
155 | 232 |
156 // Don't consider the button hidden with the redesign, because "hidden" | 233 // Don't consider the button hidden with the redesign, because "hidden" |
157 // buttons are now just hidden in the wrench menu. | 234 // buttons are now just hidden in the wrench menu. |
158 info->action_button_hidden = | 235 info->action_button_hidden = |
159 !extension_action_api_->GetBrowserActionVisibility(extension.id()) && | 236 !extension_action_api_->GetBrowserActionVisibility(extension.id()) && |
160 !FeatureSwitch::extension_action_redesign()->IsEnabled(); | 237 !FeatureSwitch::extension_action_redesign()->IsEnabled(); |
161 | 238 |
162 // Blacklist text. | 239 // Blacklist text. |
163 int blacklist_text = -1; | 240 int blacklist_text = -1; |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
210 | 287 |
211 // File access. | 288 // File access. |
212 info->file_access.is_enabled = extension.wants_file_access(); | 289 info->file_access.is_enabled = extension.wants_file_access(); |
213 info->file_access.is_active = | 290 info->file_access.is_active = |
214 util::AllowFileAccess(extension.id(), browser_context_); | 291 util::AllowFileAccess(extension.id(), browser_context_); |
215 | 292 |
216 // Home page. | 293 // Home page. |
217 info->home_page.url = ManifestURL::GetHomepageURL(&extension).spec(); | 294 info->home_page.url = ManifestURL::GetHomepageURL(&extension).spec(); |
218 info->home_page.specified = ManifestURL::SpecifiedHomepageURL(&extension); | 295 info->home_page.specified = ManifestURL::SpecifiedHomepageURL(&extension); |
219 | 296 |
220 bool is_enabled = state == developer::EXTENSION_STATE_ENABLED; | |
221 | |
222 // TODO(devlin): This won't work with apps (CORS). We should convert to data | |
223 // urls. | |
224 info->icon_url = | |
225 ExtensionIconSource::GetIconURL(&extension, | |
226 extension_misc::EXTENSION_ICON_MEDIUM, | |
227 ExtensionIconSet::MATCH_BIGGER, | |
228 !is_enabled, | |
229 nullptr).spec(); | |
230 | |
231 info->id = extension.id(); | 297 info->id = extension.id(); |
232 | 298 |
233 // Incognito access. | 299 // Incognito access. |
234 info->incognito_access.is_enabled = extension.can_be_incognito_enabled(); | 300 info->incognito_access.is_enabled = extension.can_be_incognito_enabled(); |
235 info->incognito_access.is_active = | 301 info->incognito_access.is_active = |
236 util::IsIncognitoEnabled(extension.id(), browser_context_); | 302 util::IsIncognitoEnabled(extension.id(), browser_context_); |
237 | 303 |
238 Profile* profile = Profile::FromBrowserContext(browser_context_); | 304 Profile* profile = Profile::FromBrowserContext(browser_context_); |
239 info->installed_by_custodian = | 305 info->installed_by_custodian = |
240 util::IsExtensionSupervised(&extension, profile); | 306 util::IsExtensionSupervised(&extension, profile); |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
350 | 416 |
351 info->type = GetExtensionType(extension.manifest()->type()); | 417 info->type = GetExtensionType(extension.manifest()->type()); |
352 | 418 |
353 info->update_url = ManifestURL::GetUpdateURL(&extension).spec(); | 419 info->update_url = ManifestURL::GetUpdateURL(&extension).spec(); |
354 | 420 |
355 info->user_may_modify = | 421 info->user_may_modify = |
356 management_policy->UserMayModifySettings(&extension, nullptr); | 422 management_policy->UserMayModifySettings(&extension, nullptr); |
357 | 423 |
358 info->version = extension.GetVersionForDisplay(); | 424 info->version = extension.GetVersionForDisplay(); |
359 | 425 |
| 426 bool is_enabled = state == developer::EXTENSION_STATE_ENABLED; |
360 if (state != developer::EXTENSION_STATE_TERMINATED) { | 427 if (state != developer::EXTENSION_STATE_TERMINATED) { |
361 info->views = InspectableViewsFinder(profile). | 428 info->views = InspectableViewsFinder(profile). |
362 GetViewsForExtension(extension, is_enabled); | 429 GetViewsForExtension(extension, is_enabled); |
363 } | 430 } |
364 return info.Pass(); | 431 |
| 432 // The icon. |
| 433 ExtensionResource icon = |
| 434 IconsInfo::GetIconResource(&extension, |
| 435 extension_misc::EXTENSION_ICON_MEDIUM, |
| 436 ExtensionIconSet::MATCH_BIGGER); |
| 437 if (icon.empty()) { |
| 438 info->icon_url = GetDefaultIconUrl(extension.is_app(), !is_enabled); |
| 439 list_.push_back(make_linked_ptr(info.release())); |
| 440 } else { |
| 441 ++pending_image_loads_; |
| 442 // Max size of 128x128 is a random guess at a nice balance between being |
| 443 // overly eager to resize and sending across gigantic data urls. (The icon |
| 444 // used by the url is 48x48). |
| 445 gfx::Size max_size(128, 128); |
| 446 image_loader_->LoadImageAsync( |
| 447 &extension, |
| 448 icon, |
| 449 max_size, |
| 450 base::Bind(&ExtensionInfoGenerator::OnImageLoaded, |
| 451 weak_factory_.GetWeakPtr(), |
| 452 base::Passed(info.Pass()))); |
| 453 } |
365 } | 454 } |
366 | 455 |
367 scoped_ptr<api::developer_private::ExtensionInfo> | 456 const std::string& ExtensionInfoGenerator::GetDefaultIconUrl( |
368 ExtensionInfoGenerator::CreateExtensionInfo(const std::string& id) { | 457 bool is_app, |
369 ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context_); | 458 bool is_greyscale) { |
370 | 459 std::string* str; |
371 const Extension* enabled = registry->enabled_extensions().GetByID(id); | 460 if (is_app) { |
372 if (enabled && | 461 str = is_greyscale ? &default_disabled_app_icon_url_ : |
373 ui_util::ShouldDisplayInExtensionSettings(enabled, browser_context_)) { | 462 &default_app_icon_url_; |
374 return CreateExtensionInfo(*enabled, developer::EXTENSION_STATE_ENABLED); | 463 } else { |
| 464 str = is_greyscale ? &default_disabled_extension_icon_url_ : |
| 465 &default_extension_icon_url_; |
375 } | 466 } |
376 | 467 |
377 const Extension* disabled = registry->disabled_extensions().GetByID(id); | 468 if (str->empty()) { |
378 if (disabled && | 469 *str = GetIconUrlFromImage( |
379 ui_util::ShouldDisplayInExtensionSettings(disabled, browser_context_)) { | 470 ui::ResourceBundle::GetSharedInstance().GetImageNamed( |
380 return CreateExtensionInfo(*disabled, developer::EXTENSION_STATE_DISABLED); | 471 is_app ? IDR_APP_DEFAULT_ICON : IDR_EXTENSION_DEFAULT_ICON), |
| 472 is_greyscale); |
381 } | 473 } |
382 | 474 |
383 const Extension* terminated = registry->terminated_extensions().GetByID(id); | 475 return *str; |
384 if (terminated && | 476 } |
385 ui_util::ShouldDisplayInExtensionSettings(terminated, browser_context_)) { | 477 |
386 return CreateExtensionInfo(*terminated, | 478 std::string ExtensionInfoGenerator::GetIconUrlFromImage( |
387 developer::EXTENSION_STATE_TERMINATED); | 479 const gfx::Image& image, |
| 480 bool should_greyscale) { |
| 481 scoped_refptr<base::RefCountedMemory> data; |
| 482 if (should_greyscale) { |
| 483 color_utils::HSL shift = {-1, 0, 0.6}; |
| 484 SkBitmap bitmap = |
| 485 SkBitmapOperations::CreateHSLShiftedBitmap(*image.ToSkBitmap(), shift); |
| 486 scoped_refptr<base::RefCountedBytes> image_bytes( |
| 487 new base::RefCountedBytes()); |
| 488 gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, false, &image_bytes->data()); |
| 489 data = image_bytes; |
| 490 } else { |
| 491 data = image.As1xPNGBytes(); |
388 } | 492 } |
389 | 493 |
390 return scoped_ptr<api::developer_private::ExtensionInfo>(); | 494 std::string base_64; |
| 495 base::Base64Encode(std::string(data->front_as<char>(), data->size()), |
| 496 &base_64); |
| 497 const char kDataUrlPrefix[] = "data:image/png;base64,"; |
| 498 return GURL(kDataUrlPrefix + base_64).spec(); |
391 } | 499 } |
392 | 500 |
393 ExtensionInfoGenerator::ExtensionInfoList | 501 void ExtensionInfoGenerator::OnImageLoaded( |
394 ExtensionInfoGenerator::CreateExtensionsInfo(bool include_disabled, | 502 scoped_ptr<developer::ExtensionInfo> info, |
395 bool include_terminated) { | 503 const gfx::Image& icon) { |
396 std::vector<linked_ptr<developer::ExtensionInfo>> list; | 504 info->icon_url = GetIconUrlFromImage( |
397 auto add_to_list = [this, &list](const ExtensionSet& extensions, | 505 icon, info->state != developer::EXTENSION_STATE_ENABLED); |
398 developer::ExtensionState state) { | 506 list_.push_back(make_linked_ptr(info.release())); |
399 for (const scoped_refptr<const Extension>& extension : extensions) { | |
400 if (ui_util::ShouldDisplayInExtensionSettings(extension.get(), | |
401 browser_context_)) { | |
402 scoped_ptr<developer::ExtensionInfo> info = | |
403 CreateExtensionInfo(*extension, state); | |
404 list.push_back(make_linked_ptr(info.release())); | |
405 } | |
406 } | |
407 }; | |
408 | 507 |
409 ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context_); | 508 --pending_image_loads_; |
410 add_to_list(registry->enabled_extensions(), | 509 |
411 developer::EXTENSION_STATE_ENABLED); | 510 if (pending_image_loads_ == 0) { // All done! |
412 if (include_disabled) { | 511 // We assign to a temporary and Reset() so that at the end of the method, |
413 add_to_list(registry->disabled_extensions(), | 512 // any stored refs are destroyed. |
414 developer::EXTENSION_STATE_DISABLED); | 513 ExtensionInfosCallback callback = callback_; |
| 514 callback_.Reset(); |
| 515 callback.Run(list_); |
| 516 list_.clear(); |
415 } | 517 } |
416 if (include_terminated) { | |
417 add_to_list(registry->terminated_extensions(), | |
418 developer::EXTENSION_STATE_TERMINATED); | |
419 } | |
420 | |
421 return list; | |
422 } | 518 } |
423 | 519 |
424 } // namespace extensions | 520 } // namespace extensions |
OLD | NEW |