summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/extensions/api/extension_action/extension_action_api.cc2
-rw-r--r--chrome/browser/extensions/app_sync_data.cc6
-rw-r--r--chrome/browser/extensions/app_sync_data.h6
-rw-r--r--chrome/browser/extensions/bookmark_app_helper.cc194
-rw-r--r--chrome/browser/extensions/bookmark_app_helper.h2
-rw-r--r--chrome/browser/extensions/bookmark_app_helper_unittest.cc60
-rw-r--r--chrome/browser/extensions/convert_web_app.cc5
-rw-r--r--chrome/browser/extensions/extension_sync_service.cc10
-rw-r--r--chrome/browser/sync/test/integration/two_client_apps_sync_test.cc4
-rw-r--r--chrome/browser/ui/cocoa/browser_window_cocoa.mm2
-rw-r--r--chrome/browser/ui/views/extensions/bookmark_app_bubble_view.cc2
-rw-r--r--chrome/chrome_common.gypi2
-rw-r--r--chrome/common/extensions/api/_manifest_features.json4
-rw-r--r--chrome/common/extensions/chrome_manifest_handlers.cc2
-rw-r--r--chrome/common/extensions/manifest_handlers/app_icon_color_info.cc84
-rw-r--r--chrome/common/extensions/manifest_handlers/app_icon_color_info.h49
-rw-r--r--chrome/common/web_application_info.cc3
-rw-r--r--chrome/common/web_application_info.h4
-rw-r--r--extensions/BUILD.gn2
-rw-r--r--extensions/DEPS1
-rw-r--r--extensions/browser/BUILD.gn2
-rw-r--r--extensions/browser/DEPS1
-rw-r--r--extensions/browser/api/app_window/app_window_api.cc2
-rw-r--r--extensions/common/BUILD.gn2
-rw-r--r--extensions/common/image_util.cc (renamed from extensions/browser/image_util.cc)8
-rw-r--r--extensions/common/image_util.h (renamed from extensions/browser/image_util.h)7
-rw-r--r--extensions/common/image_util_unittest.cc (renamed from extensions/browser/image_util_unittest.cc)2
-rw-r--r--extensions/common/manifest_constants.cc2
-rw-r--r--extensions/common/manifest_constants.h2
-rw-r--r--extensions/extensions.gyp6
-rw-r--r--sync/protocol/app_specifics.proto4
31 files changed, 304 insertions, 178 deletions
diff --git a/chrome/browser/extensions/api/extension_action/extension_action_api.cc b/chrome/browser/extensions/api/extension_action/extension_action_api.cc
index fb05935..de3d55c 100644
--- a/chrome/browser/extensions/api/extension_action/extension_action_api.cc
+++ b/chrome/browser/extensions/api/extension_action/extension_action_api.cc
@@ -26,10 +26,10 @@
#include "extensions/browser/extension_function_registry.h"
#include "extensions/browser/extension_host.h"
#include "extensions/browser/extension_registry.h"
-#include "extensions/browser/image_util.h"
#include "extensions/browser/notification_types.h"
#include "extensions/common/error_utils.h"
#include "extensions/common/feature_switch.h"
+#include "extensions/common/image_util.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/image/image_skia.h"
diff --git a/chrome/browser/extensions/app_sync_data.cc b/chrome/browser/extensions/app_sync_data.cc
index 1ecbb24c..6ee99da 100644
--- a/chrome/browser/extensions/app_sync_data.cc
+++ b/chrome/browser/extensions/app_sync_data.cc
@@ -4,6 +4,7 @@
#include "chrome/browser/extensions/app_sync_data.h"
+#include "chrome/common/extensions/manifest_handlers/app_icon_color_info.h"
#include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
#include "extensions/common/extension.h"
#include "sync/api/sync_data.h"
@@ -41,6 +42,7 @@ AppSyncData::AppSyncData(const Extension& extension,
if (extension.from_bookmark()) {
bookmark_app_description_ = extension.description();
bookmark_app_url_ = AppLaunchInfo::GetLaunchWebURL(&extension).spec();
+ bookmark_app_icon_color_ = AppIconColorInfo::GetIconColorString(&extension);
}
}
@@ -84,6 +86,9 @@ void AppSyncData::PopulateAppSpecifics(sync_pb::AppSpecifics* specifics) const {
if (!bookmark_app_description_.empty())
specifics->set_bookmark_app_description(bookmark_app_description_);
+ if (!bookmark_app_icon_color_.empty())
+ specifics->set_bookmark_app_icon_color(bookmark_app_icon_color_);
+
extension_sync_data_.PopulateExtensionSpecifics(
specifics->mutable_extension());
}
@@ -101,6 +106,7 @@ void AppSyncData::PopulateFromAppSpecifics(
bookmark_app_url_ = specifics.bookmark_app_url();
bookmark_app_description_ = specifics.bookmark_app_description();
+ bookmark_app_icon_color_ = specifics.bookmark_app_icon_color();
}
void AppSyncData::PopulateFromSyncData(const syncer::SyncData& sync_data) {
diff --git a/chrome/browser/extensions/app_sync_data.h b/chrome/browser/extensions/app_sync_data.h
index 5bf97b4..82f49ea 100644
--- a/chrome/browser/extensions/app_sync_data.h
+++ b/chrome/browser/extensions/app_sync_data.h
@@ -9,6 +9,7 @@
#include "extensions/common/constants.h"
#include "sync/api/string_ordinal.h"
#include "sync/api/sync_change.h"
+#include "third_party/skia/include/core/SkColor.h"
namespace syncer {
class SyncData;
@@ -70,6 +71,10 @@ class AppSyncData {
return bookmark_app_description_;
}
+ const std::string& bookmark_app_icon_color() const {
+ return bookmark_app_icon_color_;
+ }
+
private:
// Convert an AppSyncData back out to a sync structure.
void PopulateAppSpecifics(sync_pb::AppSpecifics* specifics) const;
@@ -85,6 +90,7 @@ class AppSyncData {
extensions::LaunchType launch_type_;
std::string bookmark_app_url_;
std::string bookmark_app_description_;
+ std::string bookmark_app_icon_color_;
};
} // namespace extensions
diff --git a/chrome/browser/extensions/bookmark_app_helper.cc b/chrome/browser/extensions/bookmark_app_helper.cc
index c9fcb08..bf2cd70 100644
--- a/chrome/browser/extensions/bookmark_app_helper.cc
+++ b/chrome/browser/extensions/bookmark_app_helper.cc
@@ -112,6 +112,64 @@ void OnIconsLoaded(
callback.Run(web_app_info);
}
+std::set<int> SizesToGenerate() {
+ // Generate container icons from smaller icons.
+ const int kIconSizesToGenerate[] = {
+ extension_misc::EXTENSION_ICON_SMALL,
+ extension_misc::EXTENSION_ICON_MEDIUM,
+ };
+ return std::set<int>(kIconSizesToGenerate,
+ kIconSizesToGenerate + arraysize(kIconSizesToGenerate));
+}
+
+void GenerateIcons(std::set<int> generate_sizes,
+ const GURL& app_url,
+ SkColor generated_icon_color,
+ std::map<int, SkBitmap>* bitmap_map) {
+ // The letter that will be painted on the generated icon.
+ char icon_letter = ' ';
+ std::string domain_and_registry(
+ net::registry_controlled_domains::GetDomainAndRegistry(
+ app_url,
+ net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES));
+ if (!domain_and_registry.empty()) {
+ icon_letter = domain_and_registry[0];
+ } else if (!app_url.host().empty()) {
+ icon_letter = app_url.host()[0];
+ }
+
+ // If no color has been specified, use a dark gray so it will stand out on the
+ // black shelf.
+ if (generated_icon_color == SK_ColorTRANSPARENT)
+ generated_icon_color = SK_ColorDKGRAY;
+
+ for (std::set<int>::const_iterator it = generate_sizes.begin();
+ it != generate_sizes.end(); ++it) {
+ extensions::BookmarkAppHelper::GenerateIcon(
+ bitmap_map, *it, generated_icon_color, icon_letter);
+ // Also generate the 2x resource for this size.
+ extensions::BookmarkAppHelper::GenerateIcon(
+ bitmap_map, *it * 2, generated_icon_color, icon_letter);
+ }
+}
+
+void ReplaceWebAppIcons(std::map<int, SkBitmap> bitmap_map,
+ WebApplicationInfo* web_app_info) {
+ web_app_info->icons.clear();
+
+ // Populate the icon data into the WebApplicationInfo we are using to
+ // install the bookmark app.
+ for (std::map<int, SkBitmap>::const_iterator bitmap_map_it =
+ bitmap_map.begin();
+ bitmap_map_it != bitmap_map.end(); ++bitmap_map_it) {
+ WebApplicationInfo::IconInfo icon_info;
+ icon_info.data = bitmap_map_it->second;
+ icon_info.width = icon_info.data.width();
+ icon_info.height = icon_info.data.height();
+ web_app_info->icons.push_back(icon_info);
+ }
+}
+
} // namespace
namespace extensions {
@@ -145,42 +203,6 @@ void BookmarkAppHelper::UpdateWebAppInfoFromManifest(
}
// static
-std::map<int, SkBitmap> BookmarkAppHelper::ConstrainBitmapsToSizes(
- const std::vector<SkBitmap>& bitmaps,
- const std::set<int>& sizes) {
- std::map<int, SkBitmap> output_bitmaps;
- std::map<int, SkBitmap> ordered_bitmaps;
- for (std::vector<SkBitmap>::const_iterator it = bitmaps.begin();
- it != bitmaps.end();
- ++it) {
- DCHECK(it->width() == it->height());
- ordered_bitmaps[it->width()] = *it;
- }
-
- std::set<int>::const_iterator sizes_it = sizes.begin();
- std::map<int, SkBitmap>::const_iterator bitmaps_it = ordered_bitmaps.begin();
- while (sizes_it != sizes.end() && bitmaps_it != ordered_bitmaps.end()) {
- int size = *sizes_it;
- // Find the closest not-smaller bitmap.
- bitmaps_it = ordered_bitmaps.lower_bound(size);
- ++sizes_it;
- // Ensure the bitmap is valid and smaller than the next allowed size.
- if (bitmaps_it != ordered_bitmaps.end() &&
- (sizes_it == sizes.end() || bitmaps_it->second.width() < *sizes_it)) {
- // Resize the bitmap if it does not exactly match the desired size.
- output_bitmaps[size] = bitmaps_it->second.width() == size
- ? bitmaps_it->second
- : skia::ImageOperations::Resize(
- bitmaps_it->second,
- skia::ImageOperations::RESIZE_LANCZOS3,
- size,
- size);
- }
- }
- return output_bitmaps;
-}
-
-// static
void BookmarkAppHelper::GenerateIcon(std::map<int, SkBitmap>* bitmaps,
int output_size,
SkColor color,
@@ -260,12 +282,6 @@ void BookmarkAppHelper::OnIconsDownloaded(
return;
}
- // Add the downloaded icons. Extensions only allow certain icon sizes. First
- // populate icons that match the allowed sizes exactly and then downscale
- // remaining icons to the closest allowed size that doesn't yet have an icon.
- std::set<int> allowed_sizes(extension_misc::kExtensionIconSizes,
- extension_misc::kExtensionIconSizes +
- extension_misc::kNumExtensionIconSizes);
std::vector<SkBitmap> downloaded_icons;
for (FaviconDownloader::FaviconMap::const_iterator map_it = bitmaps.begin();
map_it != bitmaps.end();
@@ -291,70 +307,33 @@ void BookmarkAppHelper::OnIconsDownloaded(
downloaded_icons.push_back(icon);
}
- web_app_info_.icons.clear();
-
- // If there are icons that don't match the accepted icon sizes, find the
- // closest bigger icon to the accepted sizes and resize the icon to it. An
- // icon will be resized and used for at most one size.
- std::map<int, SkBitmap> resized_bitmaps(
- ConstrainBitmapsToSizes(downloaded_icons, allowed_sizes));
+ // Add the downloaded icons. Extensions only allow certain icon sizes. First
+ // populate icons that match the allowed sizes exactly and then downscale
+ // remaining icons to the closest allowed size that doesn't yet have an icon.
+ std::set<int> allowed_sizes(extension_misc::kExtensionIconSizes,
+ extension_misc::kExtensionIconSizes +
+ extension_misc::kNumExtensionIconSizes);
- // Generate container icons from smaller icons.
- const int kIconSizesToGenerate[] = {extension_misc::EXTENSION_ICON_SMALL,
- extension_misc::EXTENSION_ICON_MEDIUM, };
- const std::set<int> generate_sizes(
- kIconSizesToGenerate,
- kIconSizesToGenerate + arraysize(kIconSizesToGenerate));
-
- // Only generate icons if larger icons don't exist. This means the app
- // launcher and the taskbar will do their best downsizing large icons and
- // these icons are only generated as a last resort against upscaling a smaller
- // icon.
- if (resized_bitmaps.lower_bound(*generate_sizes.rbegin()) ==
- resized_bitmaps.end()) {
- GURL app_url = web_app_info_.app_url;
-
- // The letter that will be painted on the generated icon.
- char icon_letter = ' ';
- std::string domain_and_registry(
- net::registry_controlled_domains::GetDomainAndRegistry(
- app_url,
- net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES));
- if (!domain_and_registry.empty()) {
- icon_letter = domain_and_registry[0];
- } else if (!app_url.host().empty()) {
- icon_letter = app_url.host()[0];
- }
+ web_app_info_.generated_icon_color = SK_ColorTRANSPARENT;
+ // Determine the color that will be used for the icon's background. For this
+ // the dominant color of the first icon found is used.
+ if (downloaded_icons.size()) {
+ color_utils::GridSampler sampler;
+ web_app_info_.generated_icon_color =
+ color_utils::CalculateKMeanColorOfBitmap(downloaded_icons[0]);
+ }
- // The color that will be used for the icon's background.
- SkColor background_color = SK_ColorBLACK;
- if (resized_bitmaps.size()) {
- color_utils::GridSampler sampler;
- background_color = color_utils::CalculateKMeanColorOfBitmap(
- resized_bitmaps.begin()->second);
- }
+ std::set<int> generate_sizes = SizesToGenerate();
- for (std::set<int>::const_iterator it = generate_sizes.begin();
- it != generate_sizes.end();
- ++it) {
- GenerateIcon(&resized_bitmaps, *it, background_color, icon_letter);
- // Also generate the 2x resource for this size.
- GenerateIcon(&resized_bitmaps, *it * 2, background_color, icon_letter);
- }
- }
+ std::map<int, SkBitmap> generated_icons;
+ // Icons are always generated, replacing the icons that were downloaded. This
+ // is done so that the icons are consistent across machines.
+ // TODO(benwells): Use blob sync once it is available to sync the downloaded
+ // icons, and then only generate when there are required sizes missing.
+ GenerateIcons(generate_sizes, web_app_info_.app_url,
+ web_app_info_.generated_icon_color, &generated_icons);
- // Populate the icon data into the WebApplicationInfo we are using to
- // install the bookmark app.
- for (std::map<int, SkBitmap>::const_iterator resized_bitmaps_it =
- resized_bitmaps.begin();
- resized_bitmaps_it != resized_bitmaps.end();
- ++resized_bitmaps_it) {
- WebApplicationInfo::IconInfo icon_info;
- icon_info.data = resized_bitmaps_it->second;
- icon_info.width = icon_info.data.width();
- icon_info.height = icon_info.data.height();
- web_app_info_.icons.push_back(icon_info);
- }
+ ReplaceWebAppIcons(generated_icons, &web_app_info_);
// Install the app.
crx_installer_->InstallWebApp(web_app_info_);
@@ -384,11 +363,18 @@ void BookmarkAppHelper::Observe(int type,
}
void CreateOrUpdateBookmarkApp(ExtensionService* service,
- WebApplicationInfo& web_app_info) {
+ WebApplicationInfo* web_app_info) {
scoped_refptr<extensions::CrxInstaller> installer(
extensions::CrxInstaller::CreateSilent(service));
installer->set_error_on_unsupported_requirements(true);
- installer->InstallWebApp(web_app_info);
+ if (web_app_info->icons.empty()) {
+ std::map<int, SkBitmap> bitmap_map;
+ GenerateIcons(SizesToGenerate(), web_app_info->app_url,
+ web_app_info->generated_icon_color, &bitmap_map);
+ ReplaceWebAppIcons(bitmap_map, web_app_info);
+ }
+
+ installer->InstallWebApp(*web_app_info);
}
void GetWebApplicationInfoFromApp(
diff --git a/chrome/browser/extensions/bookmark_app_helper.h b/chrome/browser/extensions/bookmark_app_helper.h
index 434def6..31442a6 100644
--- a/chrome/browser/extensions/bookmark_app_helper.h
+++ b/chrome/browser/extensions/bookmark_app_helper.h
@@ -107,7 +107,7 @@ class BookmarkAppHelper : public content::NotificationObserver {
// Creates or updates a bookmark app from the given |web_app_info|. Icons will
// not be downloaded so only supplied icon data will be used.
void CreateOrUpdateBookmarkApp(ExtensionService* service,
- WebApplicationInfo& web_app_info);
+ WebApplicationInfo* web_app_info);
// Retrieves the WebApplicationInfo that represents a given bookmark app.
// |callback| will be called with a WebApplicationInfo which is populated with
diff --git a/chrome/browser/extensions/bookmark_app_helper_unittest.cc b/chrome/browser/extensions/bookmark_app_helper_unittest.cc
index 7afd55a..36cab55 100644
--- a/chrome/browser/extensions/bookmark_app_helper_unittest.cc
+++ b/chrome/browser/extensions/bookmark_app_helper_unittest.cc
@@ -83,14 +83,6 @@ SkBitmap CreateSquareBitmapWithColor(int size, SkColor color) {
return bitmap;
}
-void ValidateBitmapSizeAndColor(SkBitmap bitmap, int size, SkColor color) {
- // Obtain pixel lock to access pixels.
- SkAutoLockPixels lock(bitmap);
- EXPECT_EQ(color, bitmap.getColor(0, 0));
- EXPECT_EQ(size, bitmap.width());
- EXPECT_EQ(size, bitmap.height());
-}
-
WebApplicationInfo::IconInfo CreateIconInfoWithBitmap(int size, SkColor color) {
WebApplicationInfo::IconInfo icon_info;
icon_info.width = size;
@@ -234,9 +226,10 @@ TEST_F(BookmarkAppHelperExtensionServiceTest, CreateBookmarkAppNoContents) {
EXPECT_EQ(kAppTitle, extension->name());
EXPECT_EQ(kAppDescription, extension->description());
EXPECT_EQ(GURL(kAppUrl), AppLaunchInfo::GetLaunchWebURL(extension));
- EXPECT_FALSE(
- IconsInfo::GetIconResource(
- extension, kIconSizeTiny, ExtensionIconSet::MATCH_EXACTLY).empty());
+ // The tiny icon should have been removed and only the generated ones used.
+ EXPECT_TRUE(
+ IconsInfo::GetIconResource(extension, kIconSizeTiny,
+ ExtensionIconSet::MATCH_EXACTLY).empty());
EXPECT_FALSE(
IconsInfo::GetIconResource(
extension, kIconSizeSmall, ExtensionIconSet::MATCH_EXACTLY).empty());
@@ -262,7 +255,7 @@ TEST_F(BookmarkAppHelperExtensionServiceTest, CreateAndUpdateBookmarkApp) {
web_app_info.icons.push_back(
CreateIconInfoWithBitmap(kIconSizeSmall, SK_ColorRED));
- extensions::CreateOrUpdateBookmarkApp(service_, web_app_info);
+ extensions::CreateOrUpdateBookmarkApp(service_, &web_app_info);
base::RunLoop().RunUntilIdle();
{
@@ -281,7 +274,7 @@ TEST_F(BookmarkAppHelperExtensionServiceTest, CreateAndUpdateBookmarkApp) {
web_app_info.title = base::UTF8ToUTF16(kAlternativeAppTitle);
web_app_info.icons[0] = CreateIconInfoWithBitmap(kIconSizeLarge, SK_ColorRED);
- extensions::CreateOrUpdateBookmarkApp(service_, web_app_info);
+ extensions::CreateOrUpdateBookmarkApp(service_, &web_app_info);
base::RunLoop().RunUntilIdle();
{
@@ -312,7 +305,7 @@ TEST_F(BookmarkAppHelperExtensionServiceTest, GetWebApplicationInfo) {
web_app_info.icons.push_back(
CreateIconInfoWithBitmap(kIconSizeLarge, SK_ColorRED));
- extensions::CreateOrUpdateBookmarkApp(service_, web_app_info);
+ extensions::CreateOrUpdateBookmarkApp(service_, &web_app_info);
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1u, registry()->enabled_extensions().size());
@@ -364,45 +357,6 @@ TEST_F(BookmarkAppHelperTest, UpdateWebAppInfoFromManifest) {
EXPECT_EQ(GURL(kAppIcon3), web_app_info.icons[1].url);
}
-TEST_F(BookmarkAppHelperTest, ConstrainBitmapsToSizes) {
- std::set<int> desired_sizes;
- desired_sizes.insert(16);
- desired_sizes.insert(32);
- desired_sizes.insert(128);
- desired_sizes.insert(256);
-
- {
- std::vector<SkBitmap> bitmaps;
- bitmaps.push_back(CreateSquareBitmapWithColor(16, SK_ColorRED));
- bitmaps.push_back(CreateSquareBitmapWithColor(32, SK_ColorGREEN));
- bitmaps.push_back(CreateSquareBitmapWithColor(48, SK_ColorBLUE));
- bitmaps.push_back(CreateSquareBitmapWithColor(144, SK_ColorYELLOW));
-
- std::map<int, SkBitmap> results(
- BookmarkAppHelper::ConstrainBitmapsToSizes(bitmaps, desired_sizes));
-
- EXPECT_EQ(3u, results.size());
- ValidateBitmapSizeAndColor(results[16], 16, SK_ColorRED);
- ValidateBitmapSizeAndColor(results[32], 32, SK_ColorGREEN);
- ValidateBitmapSizeAndColor(results[128], 128, SK_ColorYELLOW);
- }
- {
- std::vector<SkBitmap> bitmaps;
- bitmaps.push_back(CreateSquareBitmapWithColor(512, SK_ColorRED));
- bitmaps.push_back(CreateSquareBitmapWithColor(18, SK_ColorGREEN));
- bitmaps.push_back(CreateSquareBitmapWithColor(33, SK_ColorBLUE));
- bitmaps.push_back(CreateSquareBitmapWithColor(17, SK_ColorYELLOW));
-
- std::map<int, SkBitmap> results(
- BookmarkAppHelper::ConstrainBitmapsToSizes(bitmaps, desired_sizes));
-
- EXPECT_EQ(3u, results.size());
- ValidateBitmapSizeAndColor(results[16], 16, SK_ColorYELLOW);
- ValidateBitmapSizeAndColor(results[32], 32, SK_ColorBLUE);
- ValidateBitmapSizeAndColor(results[256], 256, SK_ColorRED);
- }
-}
-
TEST_F(BookmarkAppHelperTest, IsValidBookmarkAppUrl) {
EXPECT_TRUE(IsValidBookmarkAppUrl(GURL("https://www.chromium.org")));
EXPECT_TRUE(IsValidBookmarkAppUrl(GURL("http://www.chromium.org/path")));
diff --git a/chrome/browser/extensions/convert_web_app.cc b/chrome/browser/extensions/convert_web_app.cc
index d6da449..04becdc 100644
--- a/chrome/browser/extensions/convert_web_app.cc
+++ b/chrome/browser/extensions/convert_web_app.cc
@@ -25,6 +25,7 @@
#include "extensions/common/constants.h"
#include "extensions/common/extension.h"
#include "extensions/common/file_util.h"
+#include "extensions/common/image_util.h"
#include "extensions/common/manifest_constants.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/codec/png_codec.h"
@@ -106,6 +107,10 @@ scoped_refptr<Extension> ConvertWebAppToExtension(
root->SetString(keys::kVersion, ConvertTimeToExtensionVersion(create_time));
root->SetString(keys::kDescription, base::UTF16ToUTF8(web_app.description));
root->SetString(keys::kLaunchWebURL, web_app.app_url.spec());
+ if (web_app.generated_icon_color != SK_ColorTRANSPARENT) {
+ root->SetString(keys::kAppIconColor, image_util::GenerateCSSColorString(
+ web_app.generated_icon_color));
+ }
// Add the icons.
base::DictionaryValue* icons = new base::DictionaryValue();
diff --git a/chrome/browser/extensions/extension_sync_service.cc b/chrome/browser/extensions/extension_sync_service.cc
index 895da02..cd8d3aa 100644
--- a/chrome/browser/extensions/extension_sync_service.cc
+++ b/chrome/browser/extensions/extension_sync_service.cc
@@ -32,6 +32,7 @@
#include "extensions/common/extension.h"
#include "extensions/common/extension_icon_set.h"
#include "extensions/common/feature_switch.h"
+#include "extensions/common/image_util.h"
#include "extensions/common/manifest_constants.h"
#include "extensions/common/manifest_handlers/icons_handler.h"
#include "sync/api/sync_change.h"
@@ -56,7 +57,7 @@ void OnWebApplicationInfoLoaded(
// Use the old icons if they exist.
synced_info.icons = loaded_info.icons;
- CreateOrUpdateBookmarkApp(extension_service.get(), synced_info);
+ CreateOrUpdateBookmarkApp(extension_service.get(), &synced_info);
}
} // namespace
@@ -388,10 +389,15 @@ void ExtensionSyncService::ProcessBookmarkAppSyncData(
base::UTF8ToUTF16(app_sync_data.extension_sync_data().name());
web_app_info.description =
base::UTF8ToUTF16(app_sync_data.bookmark_app_description());
+ if (!app_sync_data.bookmark_app_icon_color().empty()) {
+ extensions::image_util::ParseCSSColorString(
+ app_sync_data.bookmark_app_icon_color(),
+ &web_app_info.generated_icon_color);
+ }
// If the bookmark app already exists, keep the old icons.
if (!extension) {
- CreateOrUpdateBookmarkApp(extension_service_, web_app_info);
+ CreateOrUpdateBookmarkApp(extension_service_, &web_app_info);
} else {
app_sync_data.extension_sync_data().name();
GetWebApplicationInfoFromApp(profile_,
diff --git a/chrome/browser/sync/test/integration/two_client_apps_sync_test.cc b/chrome/browser/sync/test/integration/two_client_apps_sync_test.cc
index 8cf9393..58d590a 100644
--- a/chrome/browser/sync/test/integration/two_client_apps_sync_test.cc
+++ b/chrome/browser/sync/test/integration/two_client_apps_sync_test.cc
@@ -443,7 +443,7 @@ IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest, BookmarkApp) {
extensions::NOTIFICATION_CRX_INSTALLER_DONE,
content::NotificationService::AllSources());
extensions::CreateOrUpdateBookmarkApp(GetExtensionService(GetProfile(0)),
- web_app_info);
+ &web_app_info);
windowed_observer.Wait();
EXPECT_EQ(num_extensions,
GetExtensionRegistry(GetProfile(0))->enabled_extensions().size());
@@ -453,7 +453,7 @@ IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest, BookmarkApp) {
extensions::NOTIFICATION_CRX_INSTALLER_DONE,
content::NotificationService::AllSources());
extensions::CreateOrUpdateBookmarkApp(GetExtensionService(verifier()),
- web_app_info);
+ &web_app_info);
windowed_observer.Wait();
EXPECT_EQ(num_extensions,
GetExtensionRegistry(verifier())->enabled_extensions().size());
diff --git a/chrome/browser/ui/cocoa/browser_window_cocoa.mm b/chrome/browser/ui/cocoa/browser_window_cocoa.mm
index 53a2039..485ebb1 100644
--- a/chrome/browser/ui/cocoa/browser_window_cocoa.mm
+++ b/chrome/browser/ui/cocoa/browser_window_cocoa.mm
@@ -585,7 +585,7 @@ void BrowserWindowCocoa::ShowBookmarkAppBubble(
if (![original_title isEqualToString:new_title]) {
WebApplicationInfo new_web_app_info(web_app_info);
new_web_app_info.title = base::SysNSStringToUTF16(new_title);
- extensions::CreateOrUpdateBookmarkApp(service, new_web_app_info);
+ extensions::CreateOrUpdateBookmarkApp(service, &new_web_app_info);
}
extensions::ExtensionRegistry* registry =
diff --git a/chrome/browser/ui/views/extensions/bookmark_app_bubble_view.cc b/chrome/browser/ui/views/extensions/bookmark_app_bubble_view.cc
index 1b1e0dc..566b751 100644
--- a/chrome/browser/ui/views/extensions/bookmark_app_bubble_view.cc
+++ b/chrome/browser/ui/views/extensions/bookmark_app_bubble_view.cc
@@ -273,5 +273,5 @@ void BookmarkAppBubbleView::ApplyEdits() {
install_info.title = title_tf_->text();
extensions::CreateOrUpdateBookmarkApp(GetExtensionService(profile_),
- install_info);
+ &install_info);
}
diff --git a/chrome/chrome_common.gypi b/chrome/chrome_common.gypi
index 7596433..4367f67 100644
--- a/chrome/chrome_common.gypi
+++ b/chrome/chrome_common.gypi
@@ -177,6 +177,8 @@
'common/extensions/features/feature_channel.h',
'common/extensions/image_writer/image_writer_util_mac.cc',
'common/extensions/image_writer/image_writer_util_mac.h',
+ 'common/extensions/manifest_handlers/app_icon_color_info.cc',
+ 'common/extensions/manifest_handlers/app_icon_color_info.h',
'common/extensions/manifest_handlers/app_isolation_info.cc',
'common/extensions/manifest_handlers/app_isolation_info.h',
'common/extensions/manifest_handlers/app_launch_info.cc',
diff --git a/chrome/common/extensions/api/_manifest_features.json b/chrome/common/extensions/api/_manifest_features.json
index 72aba14..0eda5b5 100644
--- a/chrome/common/extensions/api/_manifest_features.json
+++ b/chrome/common/extensions/api/_manifest_features.json
@@ -20,6 +20,10 @@
"channel": "stable",
"extension_types": ["shared_module"]
},
+ "app.icon_color": {
+ "channel": "stable",
+ "extension_types": ["hosted_app"]
+ },
"app.isolation": {
"channel": "stable",
// Platform apps always have isolated storage, thus they cannot specify it
diff --git a/chrome/common/extensions/chrome_manifest_handlers.cc b/chrome/common/extensions/chrome_manifest_handlers.cc
index 9194d7d..cbde83c 100644
--- a/chrome/common/extensions/chrome_manifest_handlers.cc
+++ b/chrome/common/extensions/chrome_manifest_handlers.cc
@@ -18,6 +18,7 @@
#include "chrome/common/extensions/api/system_indicator/system_indicator_handler.h"
#include "chrome/common/extensions/api/url_handlers/url_handlers_parser.h"
#include "chrome/common/extensions/chrome_manifest_url_handlers.h"
+#include "chrome/common/extensions/manifest_handlers/app_icon_color_info.h"
#include "chrome/common/extensions/manifest_handlers/app_isolation_info.h"
#include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
#include "chrome/common/extensions/manifest_handlers/automation.h"
@@ -37,6 +38,7 @@ namespace extensions {
void RegisterChromeManifestHandlers() {
DCHECK(!ManifestHandler::IsRegistrationFinalized());
(new AboutPageHandler)->Register();
+ (new AppIconColorHandler)->Register();
(new AppIsolationHandler)->Register();
(new AppLaunchManifestHandler)->Register();
(new AutomationHandler)->Register();
diff --git a/chrome/common/extensions/manifest_handlers/app_icon_color_info.cc b/chrome/common/extensions/manifest_handlers/app_icon_color_info.cc
new file mode 100644
index 0000000..01e83d67
--- /dev/null
+++ b/chrome/common/extensions/manifest_handlers/app_icon_color_info.cc
@@ -0,0 +1,84 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/extensions/manifest_handlers/app_icon_color_info.h"
+
+#include "base/lazy_instance.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "extensions/common/image_util.h"
+#include "extensions/common/manifest.h"
+#include "extensions/common/manifest_constants.h"
+
+namespace extensions {
+
+namespace keys = manifest_keys;
+namespace errors = manifest_errors;
+
+namespace {
+
+static base::LazyInstance<AppIconColorInfo> g_empty_app_icon_color_info =
+ LAZY_INSTANCE_INITIALIZER;
+
+const AppIconColorInfo& GetInfo(const Extension* extension) {
+ AppIconColorInfo* info = static_cast<AppIconColorInfo*>(
+ extension->GetManifestData(keys::kAppIconColor));
+ return info ? *info : g_empty_app_icon_color_info.Get();
+}
+
+} // namespace
+
+AppIconColorInfo::AppIconColorInfo() : icon_color_(SK_ColorTRANSPARENT) {
+}
+
+AppIconColorInfo::~AppIconColorInfo() {
+}
+
+// static
+SkColor AppIconColorInfo::GetIconColor(const Extension* extension) {
+ return GetInfo(extension).icon_color_;
+}
+
+// static
+const std::string& AppIconColorInfo::GetIconColorString(
+ const Extension* extension) {
+ return GetInfo(extension).icon_color_string_;
+}
+
+AppIconColorHandler::AppIconColorHandler() {
+}
+
+AppIconColorHandler::~AppIconColorHandler() {
+}
+
+bool AppIconColorHandler::Parse(Extension* extension, base::string16* error) {
+ scoped_ptr<AppIconColorInfo> app_icon_color_info(new AppIconColorInfo);
+
+ const base::Value* temp = NULL;
+ if (extension->manifest()->Get(keys::kAppIconColor, &temp)) {
+ if (!temp->GetAsString(&app_icon_color_info->icon_color_string_)) {
+ *error =
+ base::UTF8ToUTF16(extensions::manifest_errors::kInvalidAppIconColor);
+ return false;
+ }
+
+ if (!image_util::ParseCSSColorString(
+ app_icon_color_info->icon_color_string_,
+ &app_icon_color_info->icon_color_)) {
+ *error =
+ base::UTF8ToUTF16(extensions::manifest_errors::kInvalidAppIconColor);
+ return false;
+ }
+ }
+
+ extension->SetManifestData(keys::kAppIconColor,
+ app_icon_color_info.release());
+ return true;
+}
+
+const std::vector<std::string> AppIconColorHandler::Keys() const {
+ return SingleKey(keys::kAppIconColor);
+}
+
+} // namespace extensions
diff --git a/chrome/common/extensions/manifest_handlers/app_icon_color_info.h b/chrome/common/extensions/manifest_handlers/app_icon_color_info.h
new file mode 100644
index 0000000..e44e301
--- /dev/null
+++ b/chrome/common/extensions/manifest_handlers/app_icon_color_info.h
@@ -0,0 +1,49 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_EXTENSIONS_MANIFEST_HANDLERS_APP_ICON_COLOR_INFO_H_
+#define CHROME_COMMON_EXTENSIONS_MANIFEST_HANDLERS_APP_ICON_COLOR_INFO_H_
+
+#include "extensions/common/extension.h"
+#include "extensions/common/manifest_handler.h"
+#include "third_party/skia/include/core/SkColor.h"
+
+namespace base {
+class DictionaryValue;
+}
+
+namespace extensions {
+
+// A structure to hold the parsed app icon color data.
+struct AppIconColorInfo : public Extension::ManifestData {
+ AppIconColorInfo();
+ ~AppIconColorInfo() override;
+
+ static SkColor GetIconColor(const Extension* extension);
+ static const std::string& GetIconColorString(const Extension* extension);
+
+ // The color to use if icons need to be generated for the app.
+ SkColor icon_color_;
+
+ // The string representation of the icon color.
+ std::string icon_color_string_;
+};
+
+// Parses the "app.icon_color" manifest key.
+class AppIconColorHandler : public ManifestHandler {
+ public:
+ AppIconColorHandler();
+ ~AppIconColorHandler() override;
+
+ bool Parse(Extension* extension, base::string16* error) override;
+
+ private:
+ const std::vector<std::string> Keys() const override;
+
+ DISALLOW_COPY_AND_ASSIGN(AppIconColorHandler);
+};
+
+} // namespace extensions
+
+#endif // CHROME_COMMON_EXTENSIONS_MANIFEST_HANDLERS_APP_ICON_COLOR_INFO_H_
diff --git a/chrome/common/web_application_info.cc b/chrome/common/web_application_info.cc
index 68a1dbe..5a01d62 100644
--- a/chrome/common/web_application_info.cc
+++ b/chrome/common/web_application_info.cc
@@ -11,7 +11,8 @@ WebApplicationInfo::IconInfo::~IconInfo() {
}
WebApplicationInfo::WebApplicationInfo()
- : mobile_capable(MOBILE_CAPABLE_UNSPECIFIED) {
+ : mobile_capable(MOBILE_CAPABLE_UNSPECIFIED),
+ generated_icon_color(SK_ColorTRANSPARENT) {
}
WebApplicationInfo::~WebApplicationInfo() {
diff --git a/chrome/common/web_application_info.h b/chrome/common/web_application_info.h
index 114d53e..b90dbd8 100644
--- a/chrome/common/web_application_info.h
+++ b/chrome/common/web_application_info.h
@@ -10,6 +10,7 @@
#include "base/strings/string16.h"
#include "third_party/skia/include/core/SkBitmap.h"
+#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/size.h"
#include "url/gurl.h"
@@ -49,6 +50,9 @@ struct WebApplicationInfo {
// Whether the page is marked as mobile-capable, including apple specific meta
// tag.
MobileCapable mobile_capable;
+
+ // The color to use if an icon needs to be generated for the web app.
+ SkColor generated_icon_color;
};
#endif // CHROME_COMMON_WEB_APPLICATION_INFO_H_
diff --git a/extensions/BUILD.gn b/extensions/BUILD.gn
index ee5a09f..4a0fbe6 100644
--- a/extensions/BUILD.gn
+++ b/extensions/BUILD.gn
@@ -193,7 +193,6 @@ if (false) {
"browser/file_reader_unittest.cc",
"browser/guest_view/guest_view_manager_unittest.cc",
"browser/image_loader_unittest.cc",
- "browser/image_util_unittest.cc",
"browser/info_map_unittest.cc",
"browser/lazy_background_task_queue_unittest.cc",
"browser/management_policy_unittest.cc",
@@ -217,6 +216,7 @@ if (false) {
"common/extension_resource_unittest.cc",
"common/extension_set_unittest.cc",
"common/file_util_unittest.cc",
+ "common/image_util_unittest.cc",
"common/manifest_handler_unittest.cc",
"common/manifest_handlers/content_capabilities_manifest_unittest.cc",
"common/manifest_handlers/oauth2_manifest_unittest.cc",
diff --git a/extensions/DEPS b/extensions/DEPS
index 1aaa24c..b237be8 100644
--- a/extensions/DEPS
+++ b/extensions/DEPS
@@ -12,6 +12,7 @@ include_rules = [
"+grit/extensions_renderer_resources.h",
"+grit/extensions_resources.h",
"+mojo/public",
+ "+third_party/skia/include",
"+testing",
# Minimal UI dependencies. There are two good rules for UI dependencies here:
diff --git a/extensions/browser/BUILD.gn b/extensions/browser/BUILD.gn
index ec4c4dd..fee6426 100644
--- a/extensions/browser/BUILD.gn
+++ b/extensions/browser/BUILD.gn
@@ -412,8 +412,6 @@ source_set("browser") {
"image_loader.h",
"image_loader_factory.cc",
"image_loader_factory.h",
- "image_util.cc",
- "image_util.h",
"info_map.cc",
"info_map.h",
"install/crx_installer_error.h",
diff --git a/extensions/browser/DEPS b/extensions/browser/DEPS
index ca34eba..eb71651 100644
--- a/extensions/browser/DEPS
+++ b/extensions/browser/DEPS
@@ -19,7 +19,6 @@ include_rules = [
"+sync",
"+third_party/leveldatabase",
"+third_party/re2",
- "+third_party/skia/include",
"+third_party/WebKit/public/web",
]
diff --git a/extensions/browser/api/app_window/app_window_api.cc b/extensions/browser/api/app_window/app_window_api.cc
index e5f23e6..f0a4e83 100644
--- a/extensions/browser/api/app_window/app_window_api.cc
+++ b/extensions/browser/api/app_window/app_window_api.cc
@@ -21,9 +21,9 @@
#include "extensions/browser/app_window/app_window_registry.h"
#include "extensions/browser/app_window/native_app_window.h"
#include "extensions/browser/extensions_browser_client.h"
-#include "extensions/browser/image_util.h"
#include "extensions/common/api/app_window.h"
#include "extensions/common/features/simple_feature.h"
+#include "extensions/common/image_util.h"
#include "extensions/common/manifest.h"
#include "extensions/common/permissions/permissions_data.h"
#include "extensions/common/switches.h"
diff --git a/extensions/common/BUILD.gn b/extensions/common/BUILD.gn
index 54c712f..e25b766 100644
--- a/extensions/common/BUILD.gn
+++ b/extensions/common/BUILD.gn
@@ -104,6 +104,8 @@ if (enable_extensions) {
"file_util.h",
"guest_view/guest_view_constants.cc",
"guest_view/guest_view_constants.h",
+ "image_util.cc",
+ "image_util.h",
"install_warning.cc",
"install_warning.h",
"manifest.cc",
diff --git a/extensions/browser/image_util.cc b/extensions/common/image_util.cc
index 2454a63..4b16367 100644
--- a/extensions/browser/image_util.cc
+++ b/extensions/common/image_util.cc
@@ -2,12 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "extensions/browser/image_util.h"
+#include "extensions/common/image_util.h"
#include <stdint.h>
#include <vector>
#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
#include "third_party/skia/include/core/SkColor.h"
namespace extensions {
@@ -41,5 +42,10 @@ bool ParseCSSColorString(const std::string& color_string, SkColor* result) {
return true;
}
+std::string GenerateCSSColorString(SkColor color) {
+ return base::StringPrintf("#%02X%02X%02X", SkColorGetR(color),
+ SkColorGetG(color), SkColorGetB(color));
+}
+
} // namespace image_util
} // namespace extensions
diff --git a/extensions/browser/image_util.h b/extensions/common/image_util.h
index 2886b66..e9d2dfd 100644
--- a/extensions/browser/image_util.h
+++ b/extensions/common/image_util.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef EXTENSIONS_BROWSER_IMAGE_UTIL_H_
-#define EXTENSIONS_BROWSER_IMAGE_UTIL_H_
+#ifndef EXTENSIONS_COMMON_IMAGE_UTIL_H_
+#define EXTENSIONS_COMMON_IMAGE_UTIL_H_
#include <string>
@@ -16,6 +16,9 @@ namespace image_util {
// Parses a string like #FF9982 or #EEE to a color. Returns true for success.
bool ParseCSSColorString(const std::string& color_string, SkColor* result);
+// Creates a string like #FF9982 from a color.
+std::string GenerateCSSColorString(SkColor color);
+
} // namespace image_util
} // namespace extensions
diff --git a/extensions/browser/image_util_unittest.cc b/extensions/common/image_util_unittest.cc
index 5dd0cee3..ca13ab2 100644
--- a/extensions/browser/image_util_unittest.cc
+++ b/extensions/common/image_util_unittest.cc
@@ -4,7 +4,7 @@
#include <string>
-#include "extensions/browser/image_util.h"
+#include "extensions/common/image_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkColor.h"
diff --git a/extensions/common/manifest_constants.cc b/extensions/common/manifest_constants.cc
index a7c287a..e8099df 100644
--- a/extensions/common/manifest_constants.cc
+++ b/extensions/common/manifest_constants.cc
@@ -12,6 +12,7 @@ const char kAboutPage[] = "about_page";
const char kAllFrames[] = "all_frames";
const char kAltKey[] = "altKey";
const char kApp[] = "app";
+const char kAppIconColor[] = "app.icon_color";
const char kAutomation[] = "automation";
const char kBackgroundAllowJsAccess[] = "background.allow_js_access";
const char kBackgroundPage[] = "background.page";
@@ -279,6 +280,7 @@ const char kInvalidAboutPageExpectRelativePath[] =
"Invalid value for 'about_page'. Value must be a relative path.";
const char kInvalidAllFrames[] =
"Invalid value for 'content_scripts[*].all_frames'.";
+const char kInvalidAppIconColor[] = "Invalid value for app.icon_color.";
const char kInvalidBackground[] =
"Invalid value for 'background_page'.";
const char kInvalidBackgroundAllowJsAccess[] =
diff --git a/extensions/common/manifest_constants.h b/extensions/common/manifest_constants.h
index d0e1d88..4c137ce 100644
--- a/extensions/common/manifest_constants.h
+++ b/extensions/common/manifest_constants.h
@@ -14,6 +14,7 @@ extern const char kAboutPage[];
extern const char kAllFrames[];
extern const char kAltKey[];
extern const char kApp[];
+extern const char kAppIconColor[];
extern const char kAutomation[];
extern const char kBackgroundAllowJsAccess[];
extern const char kBackgroundPage[];
@@ -258,6 +259,7 @@ extern const char kExperimentalFlagRequired[];
extern const char kInvalidAboutPage[];
extern const char kInvalidAboutPageExpectRelativePath[];
extern const char kInvalidAllFrames[];
+extern const char kInvalidAppIconColor[];
extern const char kInvalidBackground[];
extern const char kInvalidBackgroundAllowJsAccess[];
extern const char kInvalidBackgroundCombination[];
diff --git a/extensions/extensions.gyp b/extensions/extensions.gyp
index e7c350c..f4b6a83 100644
--- a/extensions/extensions.gyp
+++ b/extensions/extensions.gyp
@@ -148,6 +148,8 @@
'common/file_util.h',
'common/guest_view/guest_view_constants.cc',
'common/guest_view/guest_view_constants.h',
+ 'common/image_util.cc',
+ 'common/image_util.h',
'common/install_warning.cc',
'common/install_warning.h',
'common/manifest.cc',
@@ -692,8 +694,6 @@
'browser/image_loader.h',
'browser/image_loader_factory.cc',
'browser/image_loader_factory.h',
- 'browser/image_util.cc',
- 'browser/image_util.h',
'browser/info_map.cc',
'browser/info_map.h',
'browser/install/crx_installer_error.h',
@@ -1209,7 +1209,6 @@
'browser/file_reader_unittest.cc',
'browser/guest_view/guest_view_manager_unittest.cc',
'browser/image_loader_unittest.cc',
- 'browser/image_util_unittest.cc',
'browser/info_map_unittest.cc',
'browser/lazy_background_task_queue_unittest.cc',
'browser/management_policy_unittest.cc',
@@ -1237,6 +1236,7 @@
'common/features/complex_feature_unittest.cc',
'common/features/simple_feature_unittest.cc',
'common/file_util_unittest.cc',
+ 'common/image_util_unittest.cc',
'common/manifest_handler_unittest.cc',
'common/manifest_handlers/content_capabilities_manifest_unittest.cc',
'common/manifest_handlers/default_locale_manifest_unittest.cc',
diff --git a/sync/protocol/app_specifics.proto b/sync/protocol/app_specifics.proto
index e2f9ef8..a43ea2f 100644
--- a/sync/protocol/app_specifics.proto
+++ b/sync/protocol/app_specifics.proto
@@ -75,4 +75,8 @@ message AppSpecifics {
// This is the description of a bookmark app.
optional string bookmark_app_description = 7;
+
+ // This is the color to use when generating bookmark app icons. The string is
+ // in #rrggbb or #rgb syntax, e.g. #d8d8d8.
+ optional string bookmark_app_icon_color = 8;
}