Chromium Code Reviews| 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 "base/json/json_file_value_serializer.h" | 5 #include "base/json/json_file_value_serializer.h" |
| 6 #include "base/macros.h" | 6 #include "base/macros.h" |
| 7 #include "base/message_loop/message_loop.h" | 7 #include "base/message_loop/message_loop.h" |
| 8 #include "base/path_service.h" | 8 #include "base/path_service.h" |
| 9 #include "base/run_loop.h" | 9 #include "base/run_loop.h" |
| 10 #include "base/values.h" | 10 #include "base/values.h" |
| 11 #include "build/build_config.h" | 11 #include "build/build_config.h" |
| 12 #include "chrome/browser/extensions/extension_icon_manager.h" | 12 #include "chrome/browser/extensions/extension_icon_manager.h" |
| 13 #include "chrome/common/chrome_paths.h" | 13 #include "chrome/common/chrome_paths.h" |
| 14 #include "chrome/test/base/testing_profile.h" | 14 #include "chrome/test/base/testing_profile.h" |
| 15 #include "components/crx_file/id_util.h" | 15 #include "components/crx_file/id_util.h" |
| 16 #include "content/public/test/test_browser_thread.h" | 16 #include "content/public/test/test_browser_thread.h" |
| 17 #include "extensions/common/extension.h" | 17 #include "extensions/common/extension.h" |
| 18 #include "testing/gtest/include/gtest/gtest.h" | 18 #include "testing/gtest/include/gtest/gtest.h" |
| 19 #include "ui/base/layout.h" | |
| 20 #include "ui/gfx/favicon_size.h" | |
| 21 #include "ui/gfx/image/image.h" | |
| 22 #include "ui/gfx/image/image_skia.h" | |
| 23 #include "ui/gfx/image/image_unittest_util.h" | |
| 19 #include "ui/gfx/skia_util.h" | 24 #include "ui/gfx/skia_util.h" |
| 20 | 25 |
| 26 namespace extensions { | |
| 27 namespace { | |
| 28 | |
| 21 using content::BrowserThread; | 29 using content::BrowserThread; |
| 22 using extensions::Extension; | |
| 23 using extensions::Manifest; | |
| 24 | 30 |
| 25 // Our test class that takes care of managing the necessary threads for loading | 31 // Our test class that takes care of managing the necessary threads for loading |
| 26 // extension icons, and waiting for those loads to happen. | 32 // extension icons, and waiting for those loads to happen. |
| 27 class ExtensionIconManagerTest : public testing::Test { | 33 class ExtensionIconManagerTest : public testing::Test { |
| 28 public: | 34 public: |
| 29 ExtensionIconManagerTest() : | 35 ExtensionIconManagerTest() : |
| 30 unwaited_image_loads_(0), | 36 unwaited_image_loads_(0), |
| 31 waiting_(false), | 37 waiting_(false), |
| 32 ui_thread_(BrowserThread::UI, &ui_loop_), | 38 ui_thread_(BrowserThread::UI, &ui_loop_), |
| 33 file_thread_(BrowserThread::FILE), | 39 file_thread_(BrowserThread::FILE), |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 88 } | 94 } |
| 89 | 95 |
| 90 private: | 96 private: |
| 91 ExtensionIconManagerTest* test_; | 97 ExtensionIconManagerTest* test_; |
| 92 | 98 |
| 93 DISALLOW_COPY_AND_ASSIGN(TestIconManager); | 99 DISALLOW_COPY_AND_ASSIGN(TestIconManager); |
| 94 }; | 100 }; |
| 95 | 101 |
| 96 // Returns the default icon that ExtensionIconManager gives when an extension | 102 // Returns the default icon that ExtensionIconManager gives when an extension |
| 97 // doesn't have an icon. | 103 // doesn't have an icon. |
| 98 SkBitmap GetDefaultIcon() { | 104 gfx::Image GetDefaultIcon() { |
| 99 std::string dummy_id = crx_file::id_util::GenerateId("whatever"); | 105 std::string dummy_id = crx_file::id_util::GenerateId("whatever"); |
| 100 ExtensionIconManager manager; | 106 ExtensionIconManager manager; |
| 101 return manager.GetIcon(dummy_id); | 107 return manager.GetIcon(dummy_id); |
| 102 } | 108 } |
| 103 | 109 |
| 104 // Tests loading an icon for an extension, removing it, then re-loading it. | 110 // Tests loading an icon for an extension, removing it, then re-loading it. |
| 105 TEST_F(ExtensionIconManagerTest, LoadRemoveLoad) { | 111 TEST_F(ExtensionIconManagerTest, LoadRemoveLoad) { |
| 106 std::unique_ptr<Profile> profile(new TestingProfile()); | 112 std::unique_ptr<Profile> profile(new TestingProfile()); |
| 107 SkBitmap default_icon = GetDefaultIcon(); | 113 gfx::Image default_icon = GetDefaultIcon(); |
| 108 | 114 |
| 109 base::FilePath test_dir; | 115 base::FilePath test_dir; |
| 110 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir)); | 116 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir)); |
| 111 base::FilePath manifest_path = test_dir.AppendASCII( | 117 base::FilePath manifest_path = test_dir.AppendASCII( |
| 112 "extensions/image_loading_tracker/app.json"); | 118 "extensions/image_loading_tracker/app.json"); |
| 113 | 119 |
| 114 JSONFileValueDeserializer deserializer(manifest_path); | 120 JSONFileValueDeserializer deserializer(manifest_path); |
| 115 std::unique_ptr<base::DictionaryValue> manifest = | 121 std::unique_ptr<base::DictionaryValue> manifest = |
| 116 base::DictionaryValue::From(deserializer.Deserialize(NULL, NULL)); | 122 base::DictionaryValue::From(deserializer.Deserialize(NULL, NULL)); |
| 117 ASSERT_TRUE(manifest.get() != NULL); | 123 ASSERT_TRUE(manifest.get() != NULL); |
| 118 | 124 |
| 119 std::string error; | 125 std::string error; |
| 120 scoped_refptr<Extension> extension( | 126 scoped_refptr<Extension> extension( |
| 121 Extension::Create(manifest_path.DirName(), Manifest::INVALID_LOCATION, | 127 Extension::Create(manifest_path.DirName(), Manifest::INVALID_LOCATION, |
| 122 *manifest, Extension::NO_FLAGS, &error)); | 128 *manifest, Extension::NO_FLAGS, &error)); |
| 123 ASSERT_TRUE(extension.get()); | 129 ASSERT_TRUE(extension.get()); |
| 124 TestIconManager icon_manager(this); | 130 TestIconManager icon_manager(this); |
| 125 | 131 |
| 126 // Load the icon and grab the bitmap. | 132 // Load the icon. |
| 127 icon_manager.LoadIcon(profile.get(), extension.get()); | 133 icon_manager.LoadIcon(profile.get(), extension.get()); |
| 128 WaitForImageLoad(); | 134 WaitForImageLoad(); |
| 129 SkBitmap first_icon = icon_manager.GetIcon(extension->id()); | 135 gfx::Image first_icon = icon_manager.GetIcon(extension->id()); |
| 130 EXPECT_FALSE(gfx::BitmapsAreEqual(first_icon, default_icon)); | 136 EXPECT_FALSE(gfx::test::AreImagesEqual(first_icon, default_icon)); |
| 131 | 137 |
| 132 // Remove the icon from the manager. | 138 // Remove the icon from the manager. |
| 133 icon_manager.RemoveIcon(extension->id()); | 139 icon_manager.RemoveIcon(extension->id()); |
| 134 | 140 |
| 135 // Now re-load the icon - we should get the same result bitmap (and not the | 141 // Now re-load the icon - we should get the same result bitmap (and not the |
| 136 // default icon). | 142 // default icon). |
| 137 icon_manager.LoadIcon(profile.get(), extension.get()); | 143 icon_manager.LoadIcon(profile.get(), extension.get()); |
| 138 WaitForImageLoad(); | 144 WaitForImageLoad(); |
| 139 SkBitmap second_icon = icon_manager.GetIcon(extension->id()); | 145 gfx::Image second_icon = icon_manager.GetIcon(extension->id()); |
| 140 EXPECT_FALSE(gfx::BitmapsAreEqual(second_icon, default_icon)); | 146 EXPECT_FALSE(gfx::test::AreImagesEqual(second_icon, default_icon)); |
| 141 | 147 |
| 142 EXPECT_TRUE(gfx::BitmapsAreEqual(first_icon, second_icon)); | 148 EXPECT_TRUE(gfx::test::AreImagesEqual(first_icon, second_icon)); |
| 143 } | 149 } |
| 144 | 150 |
| 145 #if defined(OS_CHROMEOS) | 151 #if defined(OS_CHROMEOS) |
| 146 // Tests loading an icon for a component extension. | 152 // Tests loading an icon for a component extension. |
| 147 TEST_F(ExtensionIconManagerTest, LoadComponentExtensionResource) { | 153 TEST_F(ExtensionIconManagerTest, LoadComponentExtensionResource) { |
| 148 std::unique_ptr<Profile> profile(new TestingProfile()); | 154 std::unique_ptr<Profile> profile(new TestingProfile()); |
| 149 SkBitmap default_icon = GetDefaultIcon(); | 155 gfx::Image default_icon = GetDefaultIcon(); |
| 150 | 156 |
| 151 base::FilePath test_dir; | 157 base::FilePath test_dir; |
| 152 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir)); | 158 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir)); |
| 153 base::FilePath manifest_path = test_dir.AppendASCII( | 159 base::FilePath manifest_path = test_dir.AppendASCII( |
| 154 "extensions/file_manager/app.json"); | 160 "extensions/file_manager/app.json"); |
| 155 | 161 |
| 156 JSONFileValueDeserializer deserializer(manifest_path); | 162 JSONFileValueDeserializer deserializer(manifest_path); |
| 157 std::unique_ptr<base::DictionaryValue> manifest = | 163 std::unique_ptr<base::DictionaryValue> manifest = |
| 158 base::DictionaryValue::From(deserializer.Deserialize(NULL, NULL)); | 164 base::DictionaryValue::From(deserializer.Deserialize(NULL, NULL)); |
| 159 ASSERT_TRUE(manifest.get() != NULL); | 165 ASSERT_TRUE(manifest.get() != NULL); |
| 160 | 166 |
| 161 std::string error; | 167 std::string error; |
| 162 scoped_refptr<Extension> extension(Extension::Create( | 168 scoped_refptr<Extension> extension(Extension::Create( |
| 163 manifest_path.DirName(), Manifest::COMPONENT, *manifest.get(), | 169 manifest_path.DirName(), Manifest::COMPONENT, *manifest.get(), |
| 164 Extension::NO_FLAGS, &error)); | 170 Extension::NO_FLAGS, &error)); |
| 165 ASSERT_TRUE(extension.get()); | 171 ASSERT_TRUE(extension.get()); |
| 166 | 172 |
| 167 TestIconManager icon_manager(this); | 173 TestIconManager icon_manager(this); |
| 168 // Load the icon and grab the bitmap. | 174 // Load the icon. |
| 169 icon_manager.LoadIcon(profile.get(), extension.get()); | 175 icon_manager.LoadIcon(profile.get(), extension.get()); |
| 170 WaitForImageLoad(); | 176 WaitForImageLoad(); |
| 171 SkBitmap first_icon = icon_manager.GetIcon(extension->id()); | 177 gfx::Image first_icon = icon_manager.GetIcon(extension->id()); |
| 172 EXPECT_FALSE(gfx::BitmapsAreEqual(first_icon, default_icon)); | 178 EXPECT_FALSE(gfx::test::AreImagesEqual(first_icon, default_icon)); |
| 173 | 179 |
| 174 // Remove the icon from the manager. | 180 // Remove the icon from the manager. |
| 175 icon_manager.RemoveIcon(extension->id()); | 181 icon_manager.RemoveIcon(extension->id()); |
| 176 | 182 |
| 177 // Now re-load the icon - we should get the same result bitmap (and not the | 183 // Now re-load the icon - we should get the same result bitmap (and not the |
| 178 // default icon). | 184 // default icon). |
| 179 icon_manager.LoadIcon(profile.get(), extension.get()); | 185 icon_manager.LoadIcon(profile.get(), extension.get()); |
| 180 WaitForImageLoad(); | 186 WaitForImageLoad(); |
| 181 SkBitmap second_icon = icon_manager.GetIcon(extension->id()); | 187 gfx::Image second_icon = icon_manager.GetIcon(extension->id()); |
| 182 EXPECT_FALSE(gfx::BitmapsAreEqual(second_icon, default_icon)); | 188 EXPECT_FALSE(gfx::test::AreImagesEqual(second_icon, default_icon)); |
| 183 | 189 |
| 184 EXPECT_TRUE(gfx::BitmapsAreEqual(first_icon, second_icon)); | 190 EXPECT_TRUE(gfx::test::AreImagesEqual(first_icon, second_icon)); |
| 185 } | 191 } |
| 186 #endif | 192 #endif |
| 193 | |
| 194 // Test what bitmaps are loaded when various combinations of scale factors are | |
| 195 // supported. | |
| 196 TEST_F(ExtensionIconManagerTest, ScaleFactors) { | |
| 197 auto profile = base::MakeUnique<TestingProfile>(); | |
| 198 const gfx::Image default_icon = GetDefaultIcon(); | |
| 199 | |
| 200 base::FilePath test_dir; | |
| 201 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir)); | |
| 202 base::FilePath manifest_path = | |
| 203 test_dir.AppendASCII("extensions/context_menus/icons/manifest.json"); | |
| 204 | |
| 205 JSONFileValueDeserializer deserializer(manifest_path); | |
| 206 std::unique_ptr<base::DictionaryValue> manifest = | |
| 207 base::DictionaryValue::From(deserializer.Deserialize(nullptr, nullptr)); | |
| 208 ASSERT_TRUE(manifest); | |
| 209 | |
| 210 std::string error; | |
| 211 scoped_refptr<Extension> extension( | |
| 212 Extension::Create(manifest_path.DirName(), Manifest::INVALID_LOCATION, | |
| 213 *manifest, Extension::NO_FLAGS, &error)); | |
| 214 ASSERT_TRUE(extension); | |
| 215 | |
| 216 int kMaxIconSizeInManifest = 32; | |
|
Devlin
2016/12/16 19:54:54
nitty nit: the kFoo naming implies this should be
Evan Stade
2016/12/16 21:37:04
Done.
| |
| 217 std::vector<std::vector<ui::ScaleFactor>> supported_scales = { | |
| 218 // Base case. | |
| 219 {ui::SCALE_FACTOR_100P}, | |
| 220 // Two scale factors. | |
| 221 {ui::SCALE_FACTOR_100P, ui::SCALE_FACTOR_200P}, | |
| 222 // A scale factor that is in between two of the provided icon sizes | |
| 223 // (should use the larger one and scale down). | |
| 224 {ui::SCALE_FACTOR_125P}, | |
| 225 // One scale factor for which we have an icon, one scale factor for which | |
| 226 // we don't. | |
| 227 {ui::SCALE_FACTOR_100P, ui::SCALE_FACTOR_300P}, | |
| 228 // Just a scale factor where we don't have any icon. This falls back to | |
| 229 // the default icon. | |
| 230 {ui::SCALE_FACTOR_300P}}; | |
| 231 | |
| 232 for (size_t i = 0; i < supported_scales.size(); ++i) { | |
| 233 SCOPED_TRACE(testing::Message() << "Test case: " << i); | |
| 234 ui::test::ScopedSetSupportedScaleFactors scoped(supported_scales[i]); | |
| 235 TestIconManager icon_manager(this); | |
| 236 | |
| 237 icon_manager.LoadIcon(profile.get(), extension.get()); | |
| 238 WaitForImageLoad(); | |
| 239 gfx::Image icon = icon_manager.GetIcon(extension->id()); | |
| 240 | |
| 241 // Determine if the default icon fallback will be used. We'll use the | |
| 242 // default when none of the supported scale factors can find an appropriate | |
| 243 // icon. | |
| 244 bool should_fall_back_to_default = true; | |
| 245 for (auto supported_scale : supported_scales[i]) { | |
| 246 if (gfx::kFaviconSize * ui::GetScaleForScaleFactor(supported_scale) <= | |
| 247 kMaxIconSizeInManifest) { | |
| 248 should_fall_back_to_default = false; | |
| 249 break; | |
| 250 } | |
| 251 } | |
| 252 if (should_fall_back_to_default) { | |
| 253 EXPECT_TRUE(gfx::test::AreImagesEqual(icon, default_icon)); | |
| 254 continue; | |
| 255 } | |
| 256 | |
| 257 gfx::ImageSkia image_skia = icon.AsImageSkia(); | |
| 258 | |
| 259 for (int scale_factor_iter = ui::SCALE_FACTOR_NONE + 1; | |
| 260 scale_factor_iter < ui::NUM_SCALE_FACTORS; ++scale_factor_iter) { | |
| 261 auto scale_factor = static_cast<ui::ScaleFactor>(scale_factor_iter); | |
| 262 float scale = ui::GetScaleForScaleFactor(scale_factor); | |
| 263 SCOPED_TRACE(testing::Message() << "Scale: " << scale); | |
| 264 | |
| 265 const bool has_representation = image_skia.HasRepresentation(scale); | |
| 266 // We shouldn't have a representation if the extension didn't provide a | |
| 267 // big enough icon. | |
| 268 if (gfx::kFaviconSize * scale > kMaxIconSizeInManifest) | |
| 269 EXPECT_FALSE(has_representation); | |
| 270 else | |
| 271 EXPECT_EQ(ui::IsSupportedScale(scale), has_representation); | |
| 272 } | |
| 273 } | |
| 274 } | |
| 275 | |
| 276 } // namespace | |
| 277 } // namespace extensions | |
| OLD | NEW |