image_util_unittest.cc 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. // Copyright 2014 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include <string>
  5. #include "base/files/file.h"
  6. #include "base/files/file_path.h"
  7. #include "base/files/file_util.h"
  8. #include "base/path_service.h"
  9. #include "base/strings/string_split.h"
  10. #include "base/test/metrics/histogram_tester.h"
  11. #include "extensions/common/extension_paths.h"
  12. #include "extensions/common/image_util.h"
  13. #include "extensions/test/logging_timer.h"
  14. #include "testing/gtest/include/gtest/gtest.h"
  15. #include "third_party/skia/include/core/SkBitmap.h"
  16. #include "third_party/skia/include/core/SkColor.h"
  17. #include "ui/gfx/codec/png_codec.h"
  18. #include "ui/gfx/color_utils.h"
  19. #include "url/gurl.h"
  20. namespace extensions {
  21. TEST(ImageUtilTest, IsIconSufficientlyVisible) {
  22. base::FilePath test_dir;
  23. ASSERT_TRUE(base::PathService::Get(DIR_TEST_DATA, &test_dir));
  24. base::FilePath icon_path;
  25. const std::string metric_name =
  26. "Extensions.IsRenderedIconSufficientlyVisibleTime";
  27. {
  28. base::HistogramTester histogram_tester;
  29. // This icon has all transparent pixels, so it will fail.
  30. icon_path = test_dir.AppendASCII("transparent_icon.png");
  31. SkBitmap transparent_icon;
  32. ASSERT_TRUE(image_util::LoadPngFromFile(icon_path, &transparent_icon));
  33. EXPECT_FALSE(image_util::IsIconSufficientlyVisible(transparent_icon));
  34. EXPECT_FALSE(image_util::IsRenderedIconSufficientlyVisible(transparent_icon,
  35. SK_ColorWHITE));
  36. histogram_tester.ExpectTotalCount(metric_name, 1);
  37. }
  38. {
  39. base::HistogramTester histogram_tester;
  40. // Test with an icon that has one opaque pixel.
  41. icon_path = test_dir.AppendASCII("one_pixel_opaque_icon.png");
  42. SkBitmap visible_icon;
  43. ASSERT_TRUE(image_util::LoadPngFromFile(icon_path, &visible_icon));
  44. EXPECT_FALSE(image_util::IsIconSufficientlyVisible(visible_icon));
  45. EXPECT_FALSE(image_util::IsRenderedIconSufficientlyVisible(visible_icon,
  46. SK_ColorWHITE));
  47. histogram_tester.ExpectTotalCount(metric_name, 1);
  48. }
  49. {
  50. base::HistogramTester histogram_tester;
  51. // Test with an icon that has one transparent pixel.
  52. icon_path = test_dir.AppendASCII("one_pixel_transparent_icon.png");
  53. SkBitmap visible_icon;
  54. ASSERT_TRUE(image_util::LoadPngFromFile(icon_path, &visible_icon));
  55. EXPECT_TRUE(image_util::IsIconSufficientlyVisible(visible_icon));
  56. EXPECT_TRUE(image_util::IsRenderedIconSufficientlyVisible(visible_icon,
  57. SK_ColorWHITE));
  58. histogram_tester.ExpectTotalCount(metric_name, 1);
  59. }
  60. {
  61. base::HistogramTester histogram_tester;
  62. // Test with an icon that is completely opaque.
  63. icon_path = test_dir.AppendASCII("opaque_icon.png");
  64. SkBitmap visible_icon;
  65. ASSERT_TRUE(image_util::LoadPngFromFile(icon_path, &visible_icon));
  66. EXPECT_TRUE(image_util::IsIconSufficientlyVisible(visible_icon));
  67. EXPECT_TRUE(image_util::IsRenderedIconSufficientlyVisible(visible_icon,
  68. SK_ColorWHITE));
  69. histogram_tester.ExpectTotalCount(metric_name, 1);
  70. }
  71. {
  72. base::HistogramTester histogram_tester;
  73. // Test with an icon that is rectangular.
  74. icon_path = test_dir.AppendASCII("rectangle.png");
  75. SkBitmap visible_icon;
  76. ASSERT_TRUE(image_util::LoadPngFromFile(icon_path, &visible_icon));
  77. EXPECT_TRUE(image_util::IsIconSufficientlyVisible(visible_icon));
  78. EXPECT_TRUE(image_util::IsRenderedIconSufficientlyVisible(visible_icon,
  79. SK_ColorWHITE));
  80. histogram_tester.ExpectTotalCount(metric_name, 1);
  81. }
  82. {
  83. base::HistogramTester histogram_tester;
  84. // Test with a solid color icon that is completely opaque. Use the icon's
  85. // color as the background color in the call to analyze its visibility.
  86. // It should be invisible in this case.
  87. icon_path = test_dir.AppendASCII("grey_21x21.png");
  88. SkBitmap solid_icon;
  89. ASSERT_TRUE(image_util::LoadPngFromFile(icon_path, &solid_icon));
  90. const SkColor pixel_color = solid_icon.getColor(0, 0);
  91. EXPECT_FALSE(
  92. image_util::IsRenderedIconSufficientlyVisible(solid_icon, pixel_color));
  93. histogram_tester.ExpectTotalCount(metric_name, 1);
  94. }
  95. {
  96. base::HistogramTester histogram_tester;
  97. // Test with a two-color icon that is completely opaque. Use one of the
  98. // icon's colors as the background color in the call to analyze its
  99. // visibility. It should be visible in this case.
  100. icon_path = test_dir.AppendASCII("two_color_21x21.png");
  101. SkBitmap two_color_icon;
  102. ASSERT_TRUE(image_util::LoadPngFromFile(icon_path, &two_color_icon));
  103. const SkColor pixel_color = two_color_icon.getColor(0, 0);
  104. EXPECT_TRUE(image_util::IsRenderedIconSufficientlyVisible(two_color_icon,
  105. pixel_color));
  106. histogram_tester.ExpectTotalCount(metric_name, 1);
  107. }
  108. }
  109. TEST(ImageUtilTest, IconTooLargeForAnalysis) {
  110. base::FilePath test_dir;
  111. ASSERT_TRUE(base::PathService::Get(DIR_TEST_DATA, &test_dir));
  112. // This is a large icon which is entirely black, so it would be
  113. // visible. However, it exceeds the max allowed size for analysis,
  114. // so it will fail.
  115. base::FilePath icon_path = test_dir.AppendASCII("3000x3000.png");
  116. SkBitmap large_icon;
  117. SkBitmap rendered_icon;
  118. ASSERT_TRUE(image_util::LoadPngFromFile(icon_path, &large_icon));
  119. EXPECT_FALSE(image_util::RenderIconForVisibilityAnalysis(
  120. large_icon, SK_ColorWHITE, &rendered_icon));
  121. // Shrink the icon so it's under the limit. It should be visible.
  122. const SkImageInfo& image_info = large_icon.info();
  123. SkImageInfo new_image_info = SkImageInfo::Make(
  124. 128, 128, image_info.colorType(), image_info.alphaType());
  125. ASSERT_TRUE(large_icon.setInfo(new_image_info));
  126. EXPECT_TRUE(image_util::RenderIconForVisibilityAnalysis(
  127. large_icon, SK_ColorWHITE, &rendered_icon));
  128. EXPECT_FALSE(rendered_icon.empty());
  129. }
  130. TEST(ImageUtilTest, MANUAL_IsIconSufficientlyVisiblePerfTest) {
  131. base::FilePath test_dir;
  132. ASSERT_TRUE(base::PathService::Get(DIR_TEST_DATA, &test_dir));
  133. base::FilePath icon_path;
  134. // This icon has all transparent pixels.
  135. icon_path = test_dir.AppendASCII("transparent_icon.png");
  136. SkBitmap invisible_icon;
  137. ASSERT_TRUE(image_util::LoadPngFromFile(icon_path, &invisible_icon));
  138. // This icon is completely opaque.
  139. icon_path = test_dir.AppendASCII("opaque_icon.png");
  140. SkBitmap visible_icon;
  141. ASSERT_TRUE(image_util::LoadPngFromFile(icon_path, &visible_icon));
  142. static constexpr char kInvisibleTimerId[] = "InvisibleIcon";
  143. static constexpr char kVisibleTimerId[] = "VisibleIcon";
  144. static constexpr char kInvisibleRenderedTimerId[] = "InvisibleRenderedIcon";
  145. static constexpr char kVisibleRenderedTimerId[] = "VisibleRenderedIcon";
  146. constexpr int kIterations = 100000;
  147. for (int i = 0; i < kIterations; ++i) {
  148. LoggingTimer timer(kInvisibleTimerId);
  149. EXPECT_FALSE(image_util::IsIconSufficientlyVisible(invisible_icon));
  150. }
  151. for (int i = 0; i < kIterations; ++i) {
  152. LoggingTimer timer(kVisibleTimerId);
  153. EXPECT_TRUE(image_util::IsIconSufficientlyVisible(visible_icon));
  154. }
  155. for (int i = 0; i < kIterations; ++i) {
  156. LoggingTimer timer(kInvisibleRenderedTimerId);
  157. EXPECT_FALSE(image_util::IsRenderedIconSufficientlyVisible(invisible_icon,
  158. SK_ColorWHITE));
  159. }
  160. for (int i = 0; i < kIterations; ++i) {
  161. LoggingTimer timer(kVisibleRenderedTimerId);
  162. EXPECT_TRUE(image_util::IsRenderedIconSufficientlyVisible(visible_icon,
  163. SK_ColorWHITE));
  164. }
  165. LoggingTimer::Print();
  166. }
  167. namespace {
  168. void WriteRenderedIcon(const SkBitmap& icon,
  169. SkColor background_color,
  170. const base::FilePath& rendered_icon_path) {
  171. SkBitmap bitmap;
  172. DCHECK(image_util::RenderIconForVisibilityAnalysis(icon, background_color,
  173. &bitmap));
  174. std::vector<unsigned char> output_data;
  175. ASSERT_TRUE(gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, false, &output_data));
  176. const int bytes_to_write = output_data.size();
  177. ASSERT_EQ(bytes_to_write,
  178. base::WriteFile(rendered_icon_path,
  179. reinterpret_cast<const char*>(&output_data[0]),
  180. bytes_to_write));
  181. }
  182. } // namespace
  183. TEST(ImageUtilTest, DISABLED_AnalyzeAllDownloadedIcons) {
  184. // See the README in extensions/test/data/icon_visibility for more details
  185. // on running this test.
  186. // TODO(crbug.com/805600): Remove this test when the bug is closed.
  187. base::FilePath test_dir;
  188. ASSERT_TRUE(base::PathService::Get(DIR_TEST_DATA, &test_dir));
  189. test_dir = test_dir.AppendASCII("icon_visibility");
  190. base::FilePath icons_file_path = test_dir.AppendASCII("source_urls.txt");
  191. std::string file_data;
  192. ASSERT_TRUE(base::ReadFileToString(icons_file_path, &file_data));
  193. base::FilePath output_file_path =
  194. test_dir.AppendASCII("invisible_source_urls.txt");
  195. base::File output_file(output_file_path, base::File::FLAG_CREATE_ALWAYS |
  196. base::File::FLAG_WRITE);
  197. ASSERT_TRUE(output_file.IsValid());
  198. base::FilePath rendered_icon_path = test_dir.AppendASCII("rendered_pngs");
  199. ASSERT_TRUE(base::CreateDirectory(rendered_icon_path));
  200. base::FilePath downloaded_icons_path = test_dir.AppendASCII("pngs");
  201. ASSERT_TRUE(base::DirectoryExists(downloaded_icons_path));
  202. const std::vector<base::StringPiece> urls = base::SplitStringPiece(
  203. file_data, "\n", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
  204. for (const base::StringPiece url : urls) {
  205. const std::string file_name = GURL(url).ExtractFileName();
  206. base::FilePath icon_path = downloaded_icons_path.AppendASCII(file_name);
  207. SkBitmap current_icon;
  208. ASSERT_TRUE(image_util::LoadPngFromFile(icon_path, &current_icon));
  209. if (!image_util::IsRenderedIconSufficientlyVisible(current_icon,
  210. SK_ColorWHITE)) {
  211. output_file.WriteAtCurrentPos(url.data(), url.length());
  212. output_file.WriteAtCurrentPos("\n", 1);
  213. WriteRenderedIcon(current_icon, SK_ColorWHITE,
  214. rendered_icon_path.AppendASCII(file_name + ".png"));
  215. }
  216. }
  217. }
  218. } // namespace extensions