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 "ui/gfx/image/image_skia.h" | 5 #include "ui/gfx/image/image_skia.h" |
6 | 6 |
| 7 #include "base/logging.h" |
| 8 #include "base/threading/simple_thread.h" |
7 #include "testing/gtest/include/gtest/gtest.h" | 9 #include "testing/gtest/include/gtest/gtest.h" |
8 #include "third_party/skia/include/core/SkBitmap.h" | 10 #include "third_party/skia/include/core/SkBitmap.h" |
9 #include "ui/base/layout.h" | 11 #include "ui/base/layout.h" |
10 #include "ui/gfx/image/image_skia_rep.h" | 12 #include "ui/gfx/image/image_skia_rep.h" |
11 #include "ui/gfx/image/image_skia_source.h" | 13 #include "ui/gfx/image/image_skia_source.h" |
12 #include "ui/gfx/size.h" | 14 #include "ui/gfx/size.h" |
13 | 15 |
| 16 // Duplicated from base/threading/non_thread_safe.h so that we can be |
| 17 // good citizens there and undef the macro. |
| 18 #if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) |
| 19 #define ENABLE_NON_THREAD_SAFE 1 |
| 20 #else |
| 21 #define ENABLE_NON_THREAD_SAFE 0 |
| 22 #endif |
| 23 |
14 namespace gfx { | 24 namespace gfx { |
15 | 25 |
16 namespace { | 26 namespace { |
17 | 27 |
18 class FixedSource : public ImageSkiaSource { | 28 class FixedSource : public ImageSkiaSource { |
19 public: | 29 public: |
20 FixedSource(const ImageSkiaRep& image) : image_(image) {} | 30 FixedSource(const ImageSkiaRep& image) : image_(image) {} |
21 | 31 |
22 virtual ~FixedSource() { | 32 virtual ~FixedSource() { |
23 } | 33 } |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
60 virtual ImageSkiaRep GetImageForScale(ui::ScaleFactor scale_factor) OVERRIDE { | 70 virtual ImageSkiaRep GetImageForScale(ui::ScaleFactor scale_factor) OVERRIDE { |
61 return gfx::ImageSkiaRep(); | 71 return gfx::ImageSkiaRep(); |
62 } | 72 } |
63 | 73 |
64 private: | 74 private: |
65 DISALLOW_COPY_AND_ASSIGN(NullSource); | 75 DISALLOW_COPY_AND_ASSIGN(NullSource); |
66 }; | 76 }; |
67 | 77 |
68 } // namespace | 78 } // namespace |
69 | 79 |
| 80 namespace test { |
| 81 class TestOnThread : public base::SimpleThread { |
| 82 public: |
| 83 explicit TestOnThread(ImageSkia* image_skia) |
| 84 : SimpleThread("image_skia_on_thread"), |
| 85 image_skia_(image_skia), |
| 86 can_read_(false), |
| 87 can_modify_(false) { |
| 88 } |
| 89 |
| 90 virtual void Run() OVERRIDE { |
| 91 can_read_ = image_skia_->CanRead(); |
| 92 can_modify_ = image_skia_->CanModify(); |
| 93 if (can_read_) |
| 94 image_skia_->image_reps(); |
| 95 } |
| 96 |
| 97 void StartAndJoin() { |
| 98 Start(); |
| 99 Join(); |
| 100 } |
| 101 |
| 102 bool can_read() const { return can_read_; } |
| 103 |
| 104 bool can_modify() const { return can_modify_; } |
| 105 |
| 106 private: |
| 107 ImageSkia* image_skia_; |
| 108 |
| 109 bool can_read_; |
| 110 bool can_modify_; |
| 111 |
| 112 DISALLOW_COPY_AND_ASSIGN(TestOnThread); |
| 113 }; |
| 114 |
| 115 } // namespace test |
| 116 |
70 TEST(ImageSkiaTest, FixedSource) { | 117 TEST(ImageSkiaTest, FixedSource) { |
71 ImageSkiaRep image(Size(100, 200), ui::SCALE_FACTOR_100P); | 118 ImageSkiaRep image(Size(100, 200), ui::SCALE_FACTOR_100P); |
72 ImageSkia image_skia(new FixedSource(image), Size(100, 200)); | 119 ImageSkia image_skia(new FixedSource(image), Size(100, 200)); |
73 EXPECT_EQ(0U, image_skia.image_reps().size()); | 120 EXPECT_EQ(0U, image_skia.image_reps().size()); |
74 | 121 |
75 const ImageSkiaRep& result_100p = | 122 const ImageSkiaRep& result_100p = |
76 image_skia.GetRepresentation(ui::SCALE_FACTOR_100P); | 123 image_skia.GetRepresentation(ui::SCALE_FACTOR_100P); |
77 EXPECT_EQ(100, result_100p.GetWidth()); | 124 EXPECT_EQ(100, result_100p.GetWidth()); |
78 EXPECT_EQ(200, result_100p.GetHeight()); | 125 EXPECT_EQ(200, result_100p.GetHeight()); |
79 EXPECT_EQ(ui::SCALE_FACTOR_100P, result_100p.scale_factor()); | 126 EXPECT_EQ(ui::SCALE_FACTOR_100P, result_100p.scale_factor()); |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
116 EXPECT_EQ(2U, image_skia.image_reps().size()); | 163 EXPECT_EQ(2U, image_skia.image_reps().size()); |
117 | 164 |
118 // Get the representation again and make sure it doesn't | 165 // Get the representation again and make sure it doesn't |
119 // generate new image skia rep. | 166 // generate new image skia rep. |
120 image_skia.GetRepresentation(ui::SCALE_FACTOR_100P); | 167 image_skia.GetRepresentation(ui::SCALE_FACTOR_100P); |
121 EXPECT_EQ(2U, image_skia.image_reps().size()); | 168 EXPECT_EQ(2U, image_skia.image_reps().size()); |
122 image_skia.GetRepresentation(ui::SCALE_FACTOR_200P); | 169 image_skia.GetRepresentation(ui::SCALE_FACTOR_200P); |
123 EXPECT_EQ(2U, image_skia.image_reps().size()); | 170 EXPECT_EQ(2U, image_skia.image_reps().size()); |
124 } | 171 } |
125 | 172 |
126 #if defined(OS_MACOSX) | 173 // Tests that image_reps returns all of the representations in the |
127 | |
128 // Tests that GetRepresentations returns all of the representations in the | |
129 // image when there are multiple representations for a scale factor. | 174 // image when there are multiple representations for a scale factor. |
130 // This currently is the case with ImageLoadingTracker::LoadImages, to | 175 // This currently is the case with ImageLoadingTracker::LoadImages. |
131 // load the application shortcut icon on Mac in particular. | 176 TEST(ImageSkiaTest, ManyRepsPerScaleFactor) { |
132 TEST(ImageSkiaTest, GetRepresentationsManyRepsPerScaleFactor) { | |
133 const int kSmallIcon1x = 16; | 177 const int kSmallIcon1x = 16; |
134 const int kSmallIcon2x = 32; | 178 const int kSmallIcon2x = 32; |
135 const int kLargeIcon1x = 32; | 179 const int kLargeIcon1x = 32; |
136 | 180 |
137 ImageSkia image(new NullSource(), gfx::Size(kSmallIcon1x, kSmallIcon1x)); | 181 ImageSkia image(new NullSource(), gfx::Size(kSmallIcon1x, kSmallIcon1x)); |
138 // Simulate a source which loads images on a delay. Upon | 182 // Simulate a source which loads images on a delay. Upon |
139 // GetImageForScaleFactor, it immediately returns null and starts loading | 183 // GetImageForScaleFactor, it immediately returns null and starts loading |
140 // image reps slowly. | 184 // image reps slowly. |
141 image.GetRepresentation(ui::SCALE_FACTOR_100P); | 185 image.GetRepresentation(ui::SCALE_FACTOR_100P); |
142 image.GetRepresentation(ui::SCALE_FACTOR_200P); | 186 image.GetRepresentation(ui::SCALE_FACTOR_200P); |
143 | 187 |
144 // After a lengthy amount of simulated time, finally loaded image reps. | 188 // After a lengthy amount of simulated time, finally loaded image reps. |
145 image.AddRepresentation(ImageSkiaRep( | 189 image.AddRepresentation(ImageSkiaRep( |
146 gfx::Size(kSmallIcon1x, kSmallIcon1x), ui::SCALE_FACTOR_100P)); | 190 gfx::Size(kSmallIcon1x, kSmallIcon1x), ui::SCALE_FACTOR_100P)); |
147 image.AddRepresentation(ImageSkiaRep( | 191 image.AddRepresentation(ImageSkiaRep( |
148 gfx::Size(kSmallIcon2x, kSmallIcon2x), ui::SCALE_FACTOR_200P)); | 192 gfx::Size(kSmallIcon2x, kSmallIcon2x), ui::SCALE_FACTOR_200P)); |
149 image.AddRepresentation(ImageSkiaRep( | 193 image.AddRepresentation(ImageSkiaRep( |
150 gfx::Size(kLargeIcon1x, kLargeIcon1x), ui::SCALE_FACTOR_100P)); | 194 gfx::Size(kLargeIcon1x, kLargeIcon1x), ui::SCALE_FACTOR_100P)); |
151 | 195 |
152 std::vector<ImageSkiaRep> image_reps = image.GetRepresentations(); | 196 std::vector<ImageSkiaRep> image_reps = image.image_reps(); |
153 EXPECT_EQ(3u, image_reps.size()); | 197 EXPECT_EQ(3u, image_reps.size()); |
154 | 198 |
155 int num_1x = 0; | 199 int num_1x = 0; |
156 int num_2x = 0; | 200 int num_2x = 0; |
157 for (size_t i = 0; i < image_reps.size(); ++i) { | 201 for (size_t i = 0; i < image_reps.size(); ++i) { |
158 if (image_reps[i].scale_factor() == ui::SCALE_FACTOR_100P) | 202 if (image_reps[i].scale_factor() == ui::SCALE_FACTOR_100P) |
159 num_1x++; | 203 num_1x++; |
160 else if (image_reps[i].scale_factor() == ui::SCALE_FACTOR_200P) | 204 else if (image_reps[i].scale_factor() == ui::SCALE_FACTOR_200P) |
161 num_2x++; | 205 num_2x++; |
162 } | 206 } |
163 EXPECT_EQ(2, num_1x); | 207 EXPECT_EQ(2, num_1x); |
164 EXPECT_EQ(1, num_2x); | 208 EXPECT_EQ(1, num_2x); |
165 } | 209 } |
166 | 210 |
167 #endif // OS_MACOSX | |
168 | |
169 TEST(ImageSkiaTest, GetBitmap) { | 211 TEST(ImageSkiaTest, GetBitmap) { |
170 ImageSkia image_skia(new DynamicSource(Size(100, 200)), Size(100, 200)); | 212 ImageSkia image_skia(new DynamicSource(Size(100, 200)), Size(100, 200)); |
171 const SkBitmap* bitmap = image_skia.bitmap(); | 213 const SkBitmap* bitmap = image_skia.bitmap(); |
172 EXPECT_NE(static_cast<SkBitmap*>(NULL), bitmap); | 214 EXPECT_NE(static_cast<SkBitmap*>(NULL), bitmap); |
173 EXPECT_FALSE(bitmap->isNull()); | 215 EXPECT_FALSE(bitmap->isNull()); |
174 } | 216 } |
175 | 217 |
176 TEST(ImageSkiaTest, GetBitmapFromEmpty) { | 218 TEST(ImageSkiaTest, GetBitmapFromEmpty) { |
177 // Create an image with 1 representation and remove it so the ImageSkiaStorage | 219 // Create an image with 1 representation and remove it so the ImageSkiaStorage |
178 // is left with no representations. | 220 // is left with no representations. |
(...skipping 30 matching lines...) Expand all Loading... |
209 ImageSkia copy = image; | 251 ImageSkia copy = image; |
210 copy.AddRepresentation(gfx::ImageSkiaRep(gfx::Size(10, 10), | 252 copy.AddRepresentation(gfx::ImageSkiaRep(gfx::Size(10, 10), |
211 ui::SCALE_FACTOR_200P)); | 253 ui::SCALE_FACTOR_200P)); |
212 unrelated.AddRepresentation(gfx::ImageSkiaRep(gfx::Size(10, 10), | 254 unrelated.AddRepresentation(gfx::ImageSkiaRep(gfx::Size(10, 10), |
213 ui::SCALE_FACTOR_100P)); | 255 ui::SCALE_FACTOR_100P)); |
214 EXPECT_TRUE(image.BackedBySameObjectAs(copy)); | 256 EXPECT_TRUE(image.BackedBySameObjectAs(copy)); |
215 EXPECT_FALSE(image.BackedBySameObjectAs(unrelated)); | 257 EXPECT_FALSE(image.BackedBySameObjectAs(unrelated)); |
216 EXPECT_FALSE(copy.BackedBySameObjectAs(unrelated)); | 258 EXPECT_FALSE(copy.BackedBySameObjectAs(unrelated)); |
217 } | 259 } |
218 | 260 |
| 261 #if ENABLE_NON_THREAD_SAFE |
| 262 TEST(ImageSkiaTest, EmptyOnThreadTest) { |
| 263 ImageSkia empty; |
| 264 test::TestOnThread empty_on_thread(&empty); |
| 265 empty_on_thread.Start(); |
| 266 empty_on_thread.Join(); |
| 267 EXPECT_TRUE(empty_on_thread.can_read()); |
| 268 EXPECT_TRUE(empty_on_thread.can_modify()); |
| 269 } |
| 270 |
| 271 TEST(ImageSkiaTest, StaticOnThreadTest) { |
| 272 ImageSkia image(ImageSkiaRep(Size(100, 200), ui::SCALE_FACTOR_100P)); |
| 273 EXPECT_FALSE(image.IsThreadSafe()); |
| 274 |
| 275 test::TestOnThread image_on_thread(&image); |
| 276 // an image that was never accessed on this thread can be |
| 277 // read by other thread. |
| 278 image_on_thread.StartAndJoin(); |
| 279 EXPECT_TRUE(image_on_thread.can_read()); |
| 280 EXPECT_TRUE(image_on_thread.can_modify()); |
| 281 EXPECT_FALSE(image.CanRead()); |
| 282 EXPECT_FALSE(image.CanModify()); |
| 283 |
| 284 image.DetachStorageFromThread(); |
| 285 // An image is accessed by this thread, |
| 286 // so other thread cannot read/modify it. |
| 287 image.image_reps(); |
| 288 test::TestOnThread image_on_thread2(&image); |
| 289 image_on_thread2.StartAndJoin(); |
| 290 EXPECT_FALSE(image_on_thread2.can_read()); |
| 291 EXPECT_FALSE(image_on_thread2.can_modify()); |
| 292 EXPECT_TRUE(image.CanRead()); |
| 293 EXPECT_TRUE(image.CanModify()); |
| 294 |
| 295 image.DetachStorageFromThread(); |
| 296 ImageSkia deep_copy = image.DeepCopy(); |
| 297 EXPECT_FALSE(deep_copy.IsThreadSafe()); |
| 298 test::TestOnThread deepcopy_on_thread(&deep_copy); |
| 299 deepcopy_on_thread.StartAndJoin(); |
| 300 EXPECT_TRUE(deepcopy_on_thread.can_read()); |
| 301 EXPECT_TRUE(deepcopy_on_thread.can_modify()); |
| 302 EXPECT_FALSE(deep_copy.CanRead()); |
| 303 EXPECT_FALSE(deep_copy.CanModify()); |
| 304 |
| 305 ImageSkia deep_copy2 = image.DeepCopy(); |
| 306 EXPECT_EQ(1U, deep_copy2.image_reps().size()); |
| 307 // Access it from current thread so that it can't be |
| 308 // accessed from another thread. |
| 309 deep_copy2.image_reps(); |
| 310 EXPECT_FALSE(deep_copy2.IsThreadSafe()); |
| 311 test::TestOnThread deepcopy2_on_thread(&deep_copy2); |
| 312 deepcopy2_on_thread.StartAndJoin(); |
| 313 EXPECT_FALSE(deepcopy2_on_thread.can_read()); |
| 314 EXPECT_FALSE(deepcopy2_on_thread.can_modify()); |
| 315 EXPECT_TRUE(deep_copy2.CanRead()); |
| 316 EXPECT_TRUE(deep_copy2.CanModify()); |
| 317 |
| 318 image.DetachStorageFromThread(); |
| 319 image.SetReadOnly(); |
| 320 // A read-only ImageSkia with no source is thread safe. |
| 321 EXPECT_TRUE(image.IsThreadSafe()); |
| 322 test::TestOnThread readonly_on_thread(&image); |
| 323 readonly_on_thread.StartAndJoin(); |
| 324 EXPECT_TRUE(readonly_on_thread.can_read()); |
| 325 EXPECT_FALSE(readonly_on_thread.can_modify()); |
| 326 EXPECT_TRUE(image.CanRead()); |
| 327 EXPECT_FALSE(image.CanModify()); |
| 328 |
| 329 image.DetachStorageFromThread(); |
| 330 image.MakeThreadSafe(); |
| 331 EXPECT_TRUE(image.IsThreadSafe()); |
| 332 test::TestOnThread threadsafe_on_thread(&image); |
| 333 threadsafe_on_thread.StartAndJoin(); |
| 334 EXPECT_TRUE(threadsafe_on_thread.can_read()); |
| 335 EXPECT_FALSE(threadsafe_on_thread.can_modify()); |
| 336 EXPECT_TRUE(image.CanRead()); |
| 337 EXPECT_FALSE(image.CanModify()); |
| 338 } |
| 339 |
| 340 TEST(ImageSkiaTest, SourceOnThreadTest) { |
| 341 ImageSkia image(new DynamicSource(Size(100, 200)), Size(100, 200)); |
| 342 EXPECT_FALSE(image.IsThreadSafe()); |
| 343 |
| 344 test::TestOnThread image_on_thread(&image); |
| 345 image_on_thread.StartAndJoin(); |
| 346 // an image that was never accessed on this thread can be |
| 347 // read by other thread. |
| 348 EXPECT_TRUE(image_on_thread.can_read()); |
| 349 EXPECT_TRUE(image_on_thread.can_modify()); |
| 350 EXPECT_FALSE(image.CanRead()); |
| 351 EXPECT_FALSE(image.CanModify()); |
| 352 |
| 353 image.DetachStorageFromThread(); |
| 354 // An image is accessed by this thread, |
| 355 // so other thread cannot read/modify it. |
| 356 image.image_reps(); |
| 357 test::TestOnThread image_on_thread2(&image); |
| 358 image_on_thread2.StartAndJoin(); |
| 359 EXPECT_FALSE(image_on_thread2.can_read()); |
| 360 EXPECT_FALSE(image_on_thread2.can_modify()); |
| 361 EXPECT_TRUE(image.CanRead()); |
| 362 EXPECT_TRUE(image.CanModify()); |
| 363 |
| 364 image.DetachStorageFromThread(); |
| 365 image.SetReadOnly(); |
| 366 EXPECT_FALSE(image.IsThreadSafe()); |
| 367 test::TestOnThread readonly_on_thread(&image); |
| 368 readonly_on_thread.StartAndJoin(); |
| 369 EXPECT_TRUE(readonly_on_thread.can_read()); |
| 370 EXPECT_FALSE(readonly_on_thread.can_modify()); |
| 371 EXPECT_FALSE(image.CanRead()); |
| 372 EXPECT_FALSE(image.CanModify()); |
| 373 |
| 374 image.DetachStorageFromThread(); |
| 375 image.MakeThreadSafe(); |
| 376 EXPECT_TRUE(image.IsThreadSafe()); |
| 377 // Check if image reps are generated for supported scale factors. |
| 378 EXPECT_EQ(ui::GetSupportedScaleFactors().size(), |
| 379 image.image_reps().size()); |
| 380 test::TestOnThread threadsafe_on_thread(&image); |
| 381 threadsafe_on_thread.StartAndJoin(); |
| 382 EXPECT_TRUE(threadsafe_on_thread.can_read()); |
| 383 EXPECT_FALSE(threadsafe_on_thread.can_modify()); |
| 384 EXPECT_TRUE(image.CanRead()); |
| 385 EXPECT_FALSE(image.CanModify()); |
| 386 } |
| 387 #endif // ENABLE_NON_THREAD_SAFE |
| 388 |
| 389 // Just in case we ever get lumped together with other compilation units. |
| 390 #undef ENABLE_NON_THREAD_SAFE |
| 391 |
219 } // namespace gfx | 392 } // namespace gfx |
OLD | NEW |