OLD | NEW |
| (Empty) |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include "base/basictypes.h" | |
6 #include "base/compiler_specific.h" | |
7 #include "base/file_path.h" | |
8 #include "base/file_util.h" | |
9 #include "base/memory/scoped_ptr.h" | |
10 #include "base/path_service.h" | |
11 #include "base/string_util.h" | |
12 #include "testing/gtest/include/gtest/gtest.h" | |
13 #include "ui/gfx/canvas.h" | |
14 #include "ui/gfx/codec/png_codec.h" | |
15 #include "ui/gfx/compositor/compositor_observer.h" | |
16 #include "ui/gfx/compositor/layer.h" | |
17 #include "ui/gfx/compositor/layer_animation_sequence.h" | |
18 #include "ui/gfx/compositor/test/test_compositor_host.h" | |
19 #include "ui/gfx/gfx_paths.h" | |
20 #include "ui/gfx/skia_util.h" | |
21 | |
22 #include "ui/gfx/compositor/compositor_setup.h" | |
23 | |
24 namespace ui { | |
25 | |
26 namespace { | |
27 | |
28 // Encodes a bitmap into a PNG and write to disk. Returns true on success. The | |
29 // parent directory does not have to exist. | |
30 bool WritePNGFile(const SkBitmap& bitmap, const FilePath& file_path) { | |
31 std::vector<unsigned char> png_data; | |
32 if (gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, true, &png_data) && | |
33 file_util::CreateDirectory(file_path.DirName())) { | |
34 char* data = reinterpret_cast<char*>(&png_data[0]); | |
35 int size = static_cast<int>(png_data.size()); | |
36 return file_util::WriteFile(file_path, data, size) == size; | |
37 } | |
38 return false; | |
39 } | |
40 | |
41 // Reads and decodes a PNG image to a bitmap. Returns true on success. The PNG | |
42 // should have been encoded using |gfx::PNGCodec::Encode|. | |
43 bool ReadPNGFile(const FilePath& file_path, SkBitmap* bitmap) { | |
44 DCHECK(bitmap); | |
45 std::string png_data; | |
46 return file_util::ReadFileToString(file_path, &png_data) && | |
47 gfx::PNGCodec::Decode(reinterpret_cast<unsigned char*>(&png_data[0]), | |
48 png_data.length(), | |
49 bitmap); | |
50 } | |
51 | |
52 // Compares with a PNG file on disk, and returns true if it is the same as | |
53 // the given image. |ref_img_path| is absolute. | |
54 bool IsSameAsPNGFile(const SkBitmap& gen_bmp, FilePath ref_img_path) { | |
55 SkBitmap ref_bmp; | |
56 if (!ReadPNGFile(ref_img_path, &ref_bmp)) { | |
57 LOG(ERROR) << "Cannot read reference image: " << ref_img_path.value(); | |
58 return false; | |
59 } | |
60 | |
61 if (ref_bmp.width() != gen_bmp.width() || | |
62 ref_bmp.height() != gen_bmp.height()) { | |
63 LOG(ERROR) | |
64 << "Dimensions do not match (Expected) vs (Actual):" | |
65 << "(" << ref_bmp.width() << "x" << ref_bmp.height() | |
66 << ") vs. " | |
67 << "(" << gen_bmp.width() << "x" << gen_bmp.height() << ")"; | |
68 return false; | |
69 } | |
70 | |
71 // Compare pixels and create a simple diff image. | |
72 int diff_pixels_count = 0; | |
73 SkAutoLockPixels lock_bmp(gen_bmp); | |
74 SkAutoLockPixels lock_ref_bmp(ref_bmp); | |
75 // The reference images were saved with no alpha channel. Use the mask to | |
76 // set alpha to 0. | |
77 uint32_t kAlphaMask = 0x00FFFFFF; | |
78 for (int x = 0; x < gen_bmp.width(); ++x) { | |
79 for (int y = 0; y < gen_bmp.height(); ++y) { | |
80 if ((*gen_bmp.getAddr32(x, y) & kAlphaMask) != | |
81 (*ref_bmp.getAddr32(x, y) & kAlphaMask)) { | |
82 ++diff_pixels_count; | |
83 } | |
84 } | |
85 } | |
86 | |
87 if (diff_pixels_count != 0) { | |
88 LOG(ERROR) << "Images differ by pixel count: " << diff_pixels_count; | |
89 return false; | |
90 } | |
91 | |
92 return true; | |
93 } | |
94 | |
95 // Returns a comma-separated list of the names of |layer|'s children in | |
96 // bottom-to-top stacking order. | |
97 std::string GetLayerChildrenNames(const Layer& layer) { | |
98 std::string names; | |
99 for (std::vector<Layer*>::const_iterator it = layer.children().begin(); | |
100 it != layer.children().end(); ++it) { | |
101 if (!names.empty()) | |
102 names += ","; | |
103 names += (*it)->name(); | |
104 } | |
105 return names; | |
106 } | |
107 | |
108 | |
109 // There are three test classes in here that configure the Compositor and | |
110 // Layer's slightly differently: | |
111 // - LayerWithNullDelegateTest uses NullLayerDelegate as the LayerDelegate. This | |
112 // is typically the base class you want to use. | |
113 // - LayerWithDelegateTest uses LayerDelegate on the delegates. | |
114 // - LayerWithRealCompositorTest when a real compositor is required for testing. | |
115 // - Slow because they bring up a window and run the real compositor. This | |
116 // is typically not what you want. | |
117 | |
118 class ColoredLayer : public Layer, public LayerDelegate { | |
119 public: | |
120 explicit ColoredLayer(SkColor color) | |
121 : Layer(LAYER_TEXTURED), | |
122 color_(color) { | |
123 set_delegate(this); | |
124 } | |
125 | |
126 virtual ~ColoredLayer() { } | |
127 | |
128 // Overridden from LayerDelegate: | |
129 virtual void OnPaintLayer(gfx::Canvas* canvas) OVERRIDE { | |
130 canvas->DrawColor(color_); | |
131 } | |
132 | |
133 private: | |
134 SkColor color_; | |
135 }; | |
136 | |
137 class LayerWithRealCompositorTest : public testing::Test { | |
138 public: | |
139 LayerWithRealCompositorTest() { | |
140 if (PathService::Get(gfx::DIR_TEST_DATA, &test_data_directory_)) { | |
141 test_data_directory_ = test_data_directory_.AppendASCII("compositor"); | |
142 } else { | |
143 LOG(ERROR) << "Could not open test data directory."; | |
144 } | |
145 } | |
146 virtual ~LayerWithRealCompositorTest() {} | |
147 | |
148 // Overridden from testing::Test: | |
149 virtual void SetUp() OVERRIDE { | |
150 DisableTestCompositor(); | |
151 const gfx::Rect host_bounds(10, 10, 500, 500); | |
152 window_.reset(TestCompositorHost::Create(host_bounds)); | |
153 window_->Show(); | |
154 } | |
155 | |
156 virtual void TearDown() OVERRIDE { | |
157 } | |
158 | |
159 Compositor* GetCompositor() { | |
160 return window_->GetCompositor(); | |
161 } | |
162 | |
163 Layer* CreateLayer(LayerType type) { | |
164 return new Layer(type); | |
165 } | |
166 | |
167 Layer* CreateColorLayer(SkColor color, const gfx::Rect& bounds) { | |
168 Layer* layer = new ColoredLayer(color); | |
169 layer->SetBounds(bounds); | |
170 return layer; | |
171 } | |
172 | |
173 Layer* CreateNoTextureLayer(const gfx::Rect& bounds) { | |
174 Layer* layer = CreateLayer(LAYER_NOT_DRAWN); | |
175 layer->SetBounds(bounds); | |
176 return layer; | |
177 } | |
178 | |
179 void DrawTree(Layer* root) { | |
180 GetCompositor()->SetRootLayer(root); | |
181 GetCompositor()->Draw(false); | |
182 } | |
183 | |
184 bool ReadPixels(SkBitmap* bitmap) { | |
185 return GetCompositor()->ReadPixels(bitmap, | |
186 gfx::Rect(GetCompositor()->size())); | |
187 } | |
188 | |
189 void RunPendingMessages() { | |
190 MessageLoopForUI::current()->RunAllPending(); | |
191 } | |
192 | |
193 // Invalidates the entire contents of the layer. | |
194 void SchedulePaintForLayer(Layer* layer) { | |
195 layer->SchedulePaint( | |
196 gfx::Rect(0, 0, layer->bounds().width(), layer->bounds().height())); | |
197 } | |
198 | |
199 const FilePath& test_data_directory() const { return test_data_directory_; } | |
200 | |
201 private: | |
202 scoped_ptr<TestCompositorHost> window_; | |
203 | |
204 // The root directory for test files. | |
205 FilePath test_data_directory_; | |
206 | |
207 DISALLOW_COPY_AND_ASSIGN(LayerWithRealCompositorTest); | |
208 }; | |
209 | |
210 // LayerDelegate that paints colors to the layer. | |
211 class TestLayerDelegate : public LayerDelegate { | |
212 public: | |
213 explicit TestLayerDelegate() : color_index_(0) {} | |
214 virtual ~TestLayerDelegate() {} | |
215 | |
216 void AddColor(SkColor color) { | |
217 colors_.push_back(color); | |
218 } | |
219 | |
220 const gfx::Size& paint_size() const { return paint_size_; } | |
221 int color_index() const { return color_index_; } | |
222 | |
223 // Overridden from LayerDelegate: | |
224 virtual void OnPaintLayer(gfx::Canvas* canvas) OVERRIDE { | |
225 SkBitmap contents = canvas->ExtractBitmap(); | |
226 paint_size_ = gfx::Size(contents.width(), contents.height()); | |
227 canvas->FillRect(gfx::Rect(paint_size_), colors_[color_index_]); | |
228 color_index_ = (color_index_ + 1) % static_cast<int>(colors_.size()); | |
229 } | |
230 | |
231 private: | |
232 std::vector<SkColor> colors_; | |
233 int color_index_; | |
234 gfx::Size paint_size_; | |
235 | |
236 DISALLOW_COPY_AND_ASSIGN(TestLayerDelegate); | |
237 }; | |
238 | |
239 // LayerDelegate that verifies that a layer was asked to update its canvas. | |
240 class DrawTreeLayerDelegate : public LayerDelegate { | |
241 public: | |
242 DrawTreeLayerDelegate() : painted_(false) {} | |
243 virtual ~DrawTreeLayerDelegate() {} | |
244 | |
245 void Reset() { | |
246 painted_ = false; | |
247 } | |
248 | |
249 bool painted() const { return painted_; } | |
250 | |
251 private: | |
252 // Overridden from LayerDelegate: | |
253 virtual void OnPaintLayer(gfx::Canvas* canvas) OVERRIDE { | |
254 painted_ = true; | |
255 } | |
256 | |
257 bool painted_; | |
258 | |
259 DISALLOW_COPY_AND_ASSIGN(DrawTreeLayerDelegate); | |
260 }; | |
261 | |
262 // The simplest possible layer delegate. Does nothing. | |
263 class NullLayerDelegate : public LayerDelegate { | |
264 public: | |
265 NullLayerDelegate() {} | |
266 virtual ~NullLayerDelegate() {} | |
267 | |
268 private: | |
269 // Overridden from LayerDelegate: | |
270 virtual void OnPaintLayer(gfx::Canvas* canvas) OVERRIDE { | |
271 } | |
272 | |
273 DISALLOW_COPY_AND_ASSIGN(NullLayerDelegate); | |
274 }; | |
275 | |
276 // Remembers if it has been notified. | |
277 class TestCompositorObserver : public CompositorObserver { | |
278 public: | |
279 TestCompositorObserver() : started_(false), ended_(false) {} | |
280 | |
281 bool notified() const { return started_ && ended_; } | |
282 | |
283 void Reset() { | |
284 started_ = false; | |
285 ended_ = false; | |
286 } | |
287 | |
288 private: | |
289 virtual void OnCompositingStarted(Compositor* compositor) OVERRIDE { | |
290 started_ = true; | |
291 } | |
292 | |
293 virtual void OnCompositingEnded(Compositor* compositor) OVERRIDE { | |
294 ended_ = true; | |
295 } | |
296 | |
297 bool started_; | |
298 bool ended_; | |
299 | |
300 DISALLOW_COPY_AND_ASSIGN(TestCompositorObserver); | |
301 }; | |
302 | |
303 } // namespace | |
304 | |
305 #if defined(OS_WIN) | |
306 // These are disabled on windows as they don't run correctly on the buildbot. | |
307 // Reenable once we move to the real compositor. | |
308 #define MAYBE_Delegate DISABLED_Delegate | |
309 #define MAYBE_Draw DISABLED_Draw | |
310 #define MAYBE_DrawTree DISABLED_DrawTree | |
311 #define MAYBE_Hierarchy DISABLED_Hierarchy | |
312 #define MAYBE_HierarchyNoTexture DISABLED_HierarchyNoTexture | |
313 #define MAYBE_DrawPixels DISABLED_DrawPixels | |
314 #define MAYBE_SetRootLayer DISABLED_SetRootLayer | |
315 #define MAYBE_CompositorObservers DISABLED_CompositorObservers | |
316 #define MAYBE_ModifyHierarchy DISABLED_ModifyHierarchy | |
317 #define MAYBE_Opacity DISABLED_Opacity | |
318 #else | |
319 #define MAYBE_Delegate DISABLED_Delegate | |
320 #define MAYBE_Draw Draw | |
321 #define MAYBE_DrawTree DISABLED_DrawTree | |
322 #define MAYBE_Hierarchy Hierarchy | |
323 #define MAYBE_HierarchyNoTexture DISABLED_HierarchyNoTexture | |
324 #define MAYBE_DrawPixels DrawPixels | |
325 #define MAYBE_SetRootLayer SetRootLayer | |
326 #define MAYBE_CompositorObservers DISABLED_CompositorObservers | |
327 #define MAYBE_ModifyHierarchy ModifyHierarchy | |
328 #define MAYBE_Opacity Opacity | |
329 #endif | |
330 | |
331 TEST_F(LayerWithRealCompositorTest, MAYBE_Draw) { | |
332 scoped_ptr<Layer> layer(CreateColorLayer(SK_ColorRED, | |
333 gfx::Rect(20, 20, 50, 50))); | |
334 DrawTree(layer.get()); | |
335 } | |
336 | |
337 // Create this hierarchy: | |
338 // L1 - red | |
339 // +-- L2 - blue | |
340 // | +-- L3 - yellow | |
341 // +-- L4 - magenta | |
342 // | |
343 TEST_F(LayerWithRealCompositorTest, MAYBE_Hierarchy) { | |
344 scoped_ptr<Layer> l1(CreateColorLayer(SK_ColorRED, | |
345 gfx::Rect(20, 20, 400, 400))); | |
346 scoped_ptr<Layer> l2(CreateColorLayer(SK_ColorBLUE, | |
347 gfx::Rect(10, 10, 350, 350))); | |
348 scoped_ptr<Layer> l3(CreateColorLayer(SK_ColorYELLOW, | |
349 gfx::Rect(5, 5, 25, 25))); | |
350 scoped_ptr<Layer> l4(CreateColorLayer(SK_ColorMAGENTA, | |
351 gfx::Rect(300, 300, 100, 100))); | |
352 | |
353 l1->Add(l2.get()); | |
354 l1->Add(l4.get()); | |
355 l2->Add(l3.get()); | |
356 | |
357 DrawTree(l1.get()); | |
358 } | |
359 | |
360 class LayerWithDelegateTest : public testing::Test, public CompositorDelegate { | |
361 public: | |
362 LayerWithDelegateTest() : schedule_draw_invoked_(false) {} | |
363 virtual ~LayerWithDelegateTest() {} | |
364 | |
365 // Overridden from testing::Test: | |
366 virtual void SetUp() OVERRIDE { | |
367 ui::SetupTestCompositor(); | |
368 compositor_.reset(new Compositor( | |
369 this, gfx::kNullAcceleratedWidget, gfx::Size(1000, 1000))); | |
370 } | |
371 | |
372 virtual void TearDown() OVERRIDE { | |
373 } | |
374 | |
375 Compositor* compositor() { return compositor_.get(); } | |
376 | |
377 virtual Layer* CreateLayer(LayerType type) { | |
378 return new Layer(type); | |
379 } | |
380 | |
381 Layer* CreateColorLayer(SkColor color, const gfx::Rect& bounds) { | |
382 Layer* layer = new ColoredLayer(color); | |
383 layer->SetBounds(bounds); | |
384 return layer; | |
385 } | |
386 | |
387 virtual Layer* CreateNoTextureLayer(const gfx::Rect& bounds) { | |
388 Layer* layer = CreateLayer(LAYER_NOT_DRAWN); | |
389 layer->SetBounds(bounds); | |
390 return layer; | |
391 } | |
392 | |
393 void DrawTree(Layer* root) { | |
394 compositor()->SetRootLayer(root); | |
395 compositor()->Draw(false); | |
396 } | |
397 | |
398 // Invalidates the entire contents of the layer. | |
399 void SchedulePaintForLayer(Layer* layer) { | |
400 layer->SchedulePaint( | |
401 gfx::Rect(0, 0, layer->bounds().width(), layer->bounds().height())); | |
402 } | |
403 | |
404 // Invokes DrawTree on the compositor. | |
405 void Draw() { | |
406 compositor_->Draw(false); | |
407 } | |
408 | |
409 // CompositorDelegate overrides. | |
410 virtual void ScheduleDraw() OVERRIDE { | |
411 schedule_draw_invoked_ = true; | |
412 } | |
413 | |
414 protected: | |
415 // Set to true when ScheduleDraw (CompositorDelegate override) is invoked. | |
416 bool schedule_draw_invoked_; | |
417 | |
418 private: | |
419 scoped_ptr<Compositor> compositor_; | |
420 | |
421 DISALLOW_COPY_AND_ASSIGN(LayerWithDelegateTest); | |
422 }; | |
423 | |
424 // L1 | |
425 // +-- L2 | |
426 TEST_F(LayerWithDelegateTest, ConvertPointToLayer_Simple) { | |
427 scoped_ptr<Layer> l1(CreateColorLayer(SK_ColorRED, | |
428 gfx::Rect(20, 20, 400, 400))); | |
429 scoped_ptr<Layer> l2(CreateColorLayer(SK_ColorBLUE, | |
430 gfx::Rect(10, 10, 350, 350))); | |
431 l1->Add(l2.get()); | |
432 DrawTree(l1.get()); | |
433 | |
434 gfx::Point point1_in_l2_coords(5, 5); | |
435 Layer::ConvertPointToLayer(l2.get(), l1.get(), &point1_in_l2_coords); | |
436 gfx::Point point1_in_l1_coords(15, 15); | |
437 EXPECT_EQ(point1_in_l1_coords, point1_in_l2_coords); | |
438 | |
439 gfx::Point point2_in_l1_coords(5, 5); | |
440 Layer::ConvertPointToLayer(l1.get(), l2.get(), &point2_in_l1_coords); | |
441 gfx::Point point2_in_l2_coords(-5, -5); | |
442 EXPECT_EQ(point2_in_l2_coords, point2_in_l1_coords); | |
443 } | |
444 | |
445 // L1 | |
446 // +-- L2 | |
447 // +-- L3 | |
448 TEST_F(LayerWithDelegateTest, ConvertPointToLayer_Medium) { | |
449 scoped_ptr<Layer> l1(CreateColorLayer(SK_ColorRED, | |
450 gfx::Rect(20, 20, 400, 400))); | |
451 scoped_ptr<Layer> l2(CreateColorLayer(SK_ColorBLUE, | |
452 gfx::Rect(10, 10, 350, 350))); | |
453 scoped_ptr<Layer> l3(CreateColorLayer(SK_ColorYELLOW, | |
454 gfx::Rect(10, 10, 100, 100))); | |
455 l1->Add(l2.get()); | |
456 l2->Add(l3.get()); | |
457 DrawTree(l1.get()); | |
458 | |
459 gfx::Point point1_in_l3_coords(5, 5); | |
460 Layer::ConvertPointToLayer(l3.get(), l1.get(), &point1_in_l3_coords); | |
461 gfx::Point point1_in_l1_coords(25, 25); | |
462 EXPECT_EQ(point1_in_l1_coords, point1_in_l3_coords); | |
463 | |
464 gfx::Point point2_in_l1_coords(5, 5); | |
465 Layer::ConvertPointToLayer(l1.get(), l3.get(), &point2_in_l1_coords); | |
466 gfx::Point point2_in_l3_coords(-15, -15); | |
467 EXPECT_EQ(point2_in_l3_coords, point2_in_l1_coords); | |
468 } | |
469 | |
470 TEST_F(LayerWithRealCompositorTest, MAYBE_Delegate) { | |
471 scoped_ptr<Layer> l1(CreateColorLayer(SK_ColorBLACK, | |
472 gfx::Rect(20, 20, 400, 400))); | |
473 GetCompositor()->SetRootLayer(l1.get()); | |
474 RunPendingMessages(); | |
475 | |
476 TestLayerDelegate delegate; | |
477 l1->set_delegate(&delegate); | |
478 delegate.AddColor(SK_ColorWHITE); | |
479 delegate.AddColor(SK_ColorYELLOW); | |
480 delegate.AddColor(SK_ColorGREEN); | |
481 | |
482 l1->SchedulePaint(gfx::Rect(0, 0, 400, 400)); | |
483 RunPendingMessages(); | |
484 EXPECT_EQ(delegate.color_index(), 1); | |
485 EXPECT_EQ(delegate.paint_size(), l1->bounds().size()); | |
486 | |
487 l1->SchedulePaint(gfx::Rect(10, 10, 200, 200)); | |
488 RunPendingMessages(); | |
489 EXPECT_EQ(delegate.color_index(), 2); | |
490 EXPECT_EQ(delegate.paint_size(), gfx::Size(200, 200)); | |
491 | |
492 l1->SchedulePaint(gfx::Rect(5, 5, 50, 50)); | |
493 RunPendingMessages(); | |
494 EXPECT_EQ(delegate.color_index(), 0); | |
495 EXPECT_EQ(delegate.paint_size(), gfx::Size(50, 50)); | |
496 } | |
497 | |
498 TEST_F(LayerWithRealCompositorTest, MAYBE_DrawTree) { | |
499 scoped_ptr<Layer> l1(CreateColorLayer(SK_ColorRED, | |
500 gfx::Rect(20, 20, 400, 400))); | |
501 scoped_ptr<Layer> l2(CreateColorLayer(SK_ColorBLUE, | |
502 gfx::Rect(10, 10, 350, 350))); | |
503 scoped_ptr<Layer> l3(CreateColorLayer(SK_ColorYELLOW, | |
504 gfx::Rect(10, 10, 100, 100))); | |
505 l1->Add(l2.get()); | |
506 l2->Add(l3.get()); | |
507 | |
508 GetCompositor()->SetRootLayer(l1.get()); | |
509 RunPendingMessages(); | |
510 | |
511 DrawTreeLayerDelegate d1; | |
512 l1->set_delegate(&d1); | |
513 DrawTreeLayerDelegate d2; | |
514 l2->set_delegate(&d2); | |
515 DrawTreeLayerDelegate d3; | |
516 l3->set_delegate(&d3); | |
517 | |
518 l2->SchedulePaint(gfx::Rect(5, 5, 5, 5)); | |
519 RunPendingMessages(); | |
520 EXPECT_FALSE(d1.painted()); | |
521 EXPECT_TRUE(d2.painted()); | |
522 EXPECT_FALSE(d3.painted()); | |
523 } | |
524 | |
525 // Tests no-texture Layers. | |
526 // Create this hierarchy: | |
527 // L1 - red | |
528 // +-- L2 - NO TEXTURE | |
529 // | +-- L3 - yellow | |
530 // +-- L4 - magenta | |
531 // | |
532 TEST_F(LayerWithRealCompositorTest, MAYBE_HierarchyNoTexture) { | |
533 scoped_ptr<Layer> l1(CreateColorLayer(SK_ColorRED, | |
534 gfx::Rect(20, 20, 400, 400))); | |
535 scoped_ptr<Layer> l2(CreateNoTextureLayer(gfx::Rect(10, 10, 350, 350))); | |
536 scoped_ptr<Layer> l3(CreateColorLayer(SK_ColorYELLOW, | |
537 gfx::Rect(5, 5, 25, 25))); | |
538 scoped_ptr<Layer> l4(CreateColorLayer(SK_ColorMAGENTA, | |
539 gfx::Rect(300, 300, 100, 100))); | |
540 | |
541 l1->Add(l2.get()); | |
542 l1->Add(l4.get()); | |
543 l2->Add(l3.get()); | |
544 | |
545 GetCompositor()->SetRootLayer(l1.get()); | |
546 RunPendingMessages(); | |
547 | |
548 DrawTreeLayerDelegate d2; | |
549 l2->set_delegate(&d2); | |
550 DrawTreeLayerDelegate d3; | |
551 l3->set_delegate(&d3); | |
552 | |
553 l2->SchedulePaint(gfx::Rect(5, 5, 5, 5)); | |
554 l3->SchedulePaint(gfx::Rect(5, 5, 5, 5)); | |
555 RunPendingMessages(); | |
556 | |
557 // |d2| should not have received a paint notification since it has no texture. | |
558 EXPECT_FALSE(d2.painted()); | |
559 // |d3| should have received a paint notification. | |
560 EXPECT_TRUE(d3.painted()); | |
561 } | |
562 | |
563 class LayerWithNullDelegateTest : public LayerWithDelegateTest { | |
564 public: | |
565 LayerWithNullDelegateTest() {} | |
566 virtual ~LayerWithNullDelegateTest() {} | |
567 | |
568 // Overridden from testing::Test: | |
569 virtual void SetUp() OVERRIDE { | |
570 LayerWithDelegateTest::SetUp(); | |
571 default_layer_delegate_.reset(new NullLayerDelegate()); | |
572 } | |
573 | |
574 virtual void TearDown() OVERRIDE { | |
575 } | |
576 | |
577 Layer* CreateLayer(LayerType type) OVERRIDE { | |
578 Layer* layer = new Layer(type); | |
579 layer->set_delegate(default_layer_delegate_.get()); | |
580 return layer; | |
581 } | |
582 | |
583 Layer* CreateTextureRootLayer(const gfx::Rect& bounds) { | |
584 Layer* layer = CreateTextureLayer(bounds); | |
585 compositor()->SetRootLayer(layer); | |
586 return layer; | |
587 } | |
588 | |
589 Layer* CreateTextureLayer(const gfx::Rect& bounds) { | |
590 Layer* layer = CreateLayer(LAYER_TEXTURED); | |
591 layer->SetBounds(bounds); | |
592 return layer; | |
593 } | |
594 | |
595 Layer* CreateNoTextureLayer(const gfx::Rect& bounds) OVERRIDE { | |
596 Layer* layer = CreateLayer(LAYER_NOT_DRAWN); | |
597 layer->SetBounds(bounds); | |
598 return layer; | |
599 } | |
600 | |
601 void RunPendingMessages() { | |
602 MessageLoopForUI::current()->RunAllPending(); | |
603 } | |
604 | |
605 private: | |
606 scoped_ptr<NullLayerDelegate> default_layer_delegate_; | |
607 | |
608 DISALLOW_COPY_AND_ASSIGN(LayerWithNullDelegateTest); | |
609 }; | |
610 | |
611 // Various visibile/drawn assertions. | |
612 TEST_F(LayerWithNullDelegateTest, Visibility) { | |
613 scoped_ptr<Layer> l1(new Layer(LAYER_TEXTURED)); | |
614 scoped_ptr<Layer> l2(new Layer(LAYER_TEXTURED)); | |
615 scoped_ptr<Layer> l3(new Layer(LAYER_TEXTURED)); | |
616 l1->Add(l2.get()); | |
617 l2->Add(l3.get()); | |
618 | |
619 NullLayerDelegate delegate; | |
620 l1->set_delegate(&delegate); | |
621 l2->set_delegate(&delegate); | |
622 l3->set_delegate(&delegate); | |
623 | |
624 // Layers should initially be drawn. | |
625 EXPECT_TRUE(l1->IsDrawn()); | |
626 EXPECT_TRUE(l2->IsDrawn()); | |
627 EXPECT_TRUE(l3->IsDrawn()); | |
628 EXPECT_EQ(1.f, l1->web_layer().opacity()); | |
629 EXPECT_EQ(1.f, l2->web_layer().opacity()); | |
630 EXPECT_EQ(1.f, l3->web_layer().opacity()); | |
631 | |
632 compositor()->SetRootLayer(l1.get()); | |
633 | |
634 Draw(); | |
635 | |
636 l1->SetVisible(false); | |
637 EXPECT_FALSE(l1->IsDrawn()); | |
638 EXPECT_FALSE(l2->IsDrawn()); | |
639 EXPECT_FALSE(l3->IsDrawn()); | |
640 EXPECT_EQ(0.f, l1->web_layer().opacity()); | |
641 | |
642 l3->SetVisible(false); | |
643 EXPECT_FALSE(l1->IsDrawn()); | |
644 EXPECT_FALSE(l2->IsDrawn()); | |
645 EXPECT_FALSE(l3->IsDrawn()); | |
646 EXPECT_EQ(0.f, l3->web_layer().opacity()); | |
647 | |
648 l1->SetVisible(true); | |
649 EXPECT_TRUE(l1->IsDrawn()); | |
650 EXPECT_TRUE(l2->IsDrawn()); | |
651 EXPECT_FALSE(l3->IsDrawn()); | |
652 EXPECT_EQ(1.f, l1->web_layer().opacity()); | |
653 } | |
654 | |
655 // Checks that stacking-related methods behave as advertised. | |
656 TEST_F(LayerWithNullDelegateTest, Stacking) { | |
657 scoped_ptr<Layer> root(new Layer(LAYER_NOT_DRAWN)); | |
658 scoped_ptr<Layer> l1(new Layer(LAYER_TEXTURED)); | |
659 scoped_ptr<Layer> l2(new Layer(LAYER_TEXTURED)); | |
660 scoped_ptr<Layer> l3(new Layer(LAYER_TEXTURED)); | |
661 l1->set_name("1"); | |
662 l2->set_name("2"); | |
663 l3->set_name("3"); | |
664 root->Add(l3.get()); | |
665 root->Add(l2.get()); | |
666 root->Add(l1.get()); | |
667 | |
668 // Layers' children are stored in bottom-to-top order. | |
669 EXPECT_EQ("3,2,1", GetLayerChildrenNames(*root.get())); | |
670 | |
671 root->StackAtTop(l3.get()); | |
672 EXPECT_EQ("2,1,3", GetLayerChildrenNames(*root.get())); | |
673 | |
674 root->StackAtTop(l1.get()); | |
675 EXPECT_EQ("2,3,1", GetLayerChildrenNames(*root.get())); | |
676 | |
677 root->StackAtTop(l1.get()); | |
678 EXPECT_EQ("2,3,1", GetLayerChildrenNames(*root.get())); | |
679 | |
680 root->StackAbove(l2.get(), l3.get()); | |
681 EXPECT_EQ("3,2,1", GetLayerChildrenNames(*root.get())); | |
682 | |
683 root->StackAbove(l1.get(), l3.get()); | |
684 EXPECT_EQ("3,1,2", GetLayerChildrenNames(*root.get())); | |
685 | |
686 root->StackAbove(l2.get(), l1.get()); | |
687 EXPECT_EQ("3,1,2", GetLayerChildrenNames(*root.get())); | |
688 | |
689 root->StackAtBottom(l2.get()); | |
690 EXPECT_EQ("2,3,1", GetLayerChildrenNames(*root.get())); | |
691 | |
692 root->StackAtBottom(l3.get()); | |
693 EXPECT_EQ("3,2,1", GetLayerChildrenNames(*root.get())); | |
694 | |
695 root->StackAtBottom(l3.get()); | |
696 EXPECT_EQ("3,2,1", GetLayerChildrenNames(*root.get())); | |
697 | |
698 root->StackBelow(l2.get(), l3.get()); | |
699 EXPECT_EQ("2,3,1", GetLayerChildrenNames(*root.get())); | |
700 | |
701 root->StackBelow(l1.get(), l3.get()); | |
702 EXPECT_EQ("2,1,3", GetLayerChildrenNames(*root.get())); | |
703 | |
704 root->StackBelow(l3.get(), l2.get()); | |
705 EXPECT_EQ("3,2,1", GetLayerChildrenNames(*root.get())); | |
706 | |
707 root->StackBelow(l3.get(), l2.get()); | |
708 EXPECT_EQ("3,2,1", GetLayerChildrenNames(*root.get())); | |
709 | |
710 root->StackBelow(l3.get(), l1.get()); | |
711 EXPECT_EQ("2,3,1", GetLayerChildrenNames(*root.get())); | |
712 } | |
713 | |
714 // Verifies SetBounds triggers the appropriate painting/drawing. | |
715 TEST_F(LayerWithNullDelegateTest, SetBoundsSchedulesPaint) { | |
716 scoped_ptr<Layer> l1(CreateTextureLayer(gfx::Rect(0, 0, 200, 200))); | |
717 compositor()->SetRootLayer(l1.get()); | |
718 | |
719 Draw(); | |
720 | |
721 schedule_draw_invoked_ = false; | |
722 l1->SetBounds(gfx::Rect(5, 5, 200, 200)); | |
723 | |
724 // The CompositorDelegate (us) should have been told to draw for a move. | |
725 EXPECT_TRUE(schedule_draw_invoked_); | |
726 | |
727 schedule_draw_invoked_ = false; | |
728 l1->SetBounds(gfx::Rect(5, 5, 100, 100)); | |
729 | |
730 // The CompositorDelegate (us) should have been told to draw for a resize. | |
731 EXPECT_TRUE(schedule_draw_invoked_); | |
732 } | |
733 | |
734 // Checks that pixels are actually drawn to the screen with a read back. | |
735 TEST_F(LayerWithRealCompositorTest, MAYBE_DrawPixels) { | |
736 scoped_ptr<Layer> layer(CreateColorLayer(SK_ColorRED, | |
737 gfx::Rect(0, 0, 500, 500))); | |
738 scoped_ptr<Layer> layer2(CreateColorLayer(SK_ColorBLUE, | |
739 gfx::Rect(0, 0, 500, 10))); | |
740 | |
741 layer->Add(layer2.get()); | |
742 | |
743 DrawTree(layer.get()); | |
744 | |
745 SkBitmap bitmap; | |
746 gfx::Size size = GetCompositor()->size(); | |
747 ASSERT_TRUE(GetCompositor()->ReadPixels(&bitmap, | |
748 gfx::Rect(0, 10, | |
749 size.width(), size.height() - 10))); | |
750 ASSERT_FALSE(bitmap.empty()); | |
751 | |
752 SkAutoLockPixels lock(bitmap); | |
753 bool is_all_red = true; | |
754 for (int x = 0; is_all_red && x < 500; x++) | |
755 for (int y = 0; is_all_red && y < 490; y++) | |
756 is_all_red = is_all_red && (bitmap.getColor(x, y) == SK_ColorRED); | |
757 | |
758 EXPECT_TRUE(is_all_red); | |
759 } | |
760 | |
761 // Checks the logic around Compositor::SetRootLayer and Layer::SetCompositor. | |
762 TEST_F(LayerWithRealCompositorTest, MAYBE_SetRootLayer) { | |
763 Compositor* compositor = GetCompositor(); | |
764 scoped_ptr<Layer> l1(CreateColorLayer(SK_ColorRED, | |
765 gfx::Rect(20, 20, 400, 400))); | |
766 scoped_ptr<Layer> l2(CreateColorLayer(SK_ColorBLUE, | |
767 gfx::Rect(10, 10, 350, 350))); | |
768 | |
769 EXPECT_EQ(NULL, l1->GetCompositor()); | |
770 EXPECT_EQ(NULL, l2->GetCompositor()); | |
771 | |
772 compositor->SetRootLayer(l1.get()); | |
773 EXPECT_EQ(compositor, l1->GetCompositor()); | |
774 | |
775 l1->Add(l2.get()); | |
776 EXPECT_EQ(compositor, l2->GetCompositor()); | |
777 | |
778 l1->Remove(l2.get()); | |
779 EXPECT_EQ(NULL, l2->GetCompositor()); | |
780 | |
781 l1->Add(l2.get()); | |
782 EXPECT_EQ(compositor, l2->GetCompositor()); | |
783 | |
784 compositor->SetRootLayer(NULL); | |
785 EXPECT_EQ(NULL, l1->GetCompositor()); | |
786 EXPECT_EQ(NULL, l2->GetCompositor()); | |
787 } | |
788 | |
789 // Checks that compositor observers are notified when: | |
790 // - DrawTree is called, | |
791 // - After ScheduleDraw is called, or | |
792 // - Whenever SetBounds, SetOpacity or SetTransform are called. | |
793 // TODO(vollick): could be reorganized into compositor_unittest.cc | |
794 TEST_F(LayerWithRealCompositorTest, MAYBE_CompositorObservers) { | |
795 scoped_ptr<Layer> l1(CreateColorLayer(SK_ColorRED, | |
796 gfx::Rect(20, 20, 400, 400))); | |
797 scoped_ptr<Layer> l2(CreateColorLayer(SK_ColorBLUE, | |
798 gfx::Rect(10, 10, 350, 350))); | |
799 l1->Add(l2.get()); | |
800 TestCompositorObserver observer; | |
801 GetCompositor()->AddObserver(&observer); | |
802 | |
803 // Explicitly called DrawTree should cause the observers to be notified. | |
804 // NOTE: this call to DrawTree sets l1 to be the compositor's root layer. | |
805 DrawTree(l1.get()); | |
806 RunPendingMessages(); | |
807 EXPECT_TRUE(observer.notified()); | |
808 | |
809 // As should scheduling a draw and waiting. | |
810 observer.Reset(); | |
811 l1->ScheduleDraw(); | |
812 RunPendingMessages(); | |
813 EXPECT_TRUE(observer.notified()); | |
814 | |
815 // Moving, but not resizing, a layer should alert the observers. | |
816 observer.Reset(); | |
817 l2->SetBounds(gfx::Rect(0, 0, 350, 350)); | |
818 RunPendingMessages(); | |
819 EXPECT_TRUE(observer.notified()); | |
820 | |
821 // So should resizing a layer. | |
822 observer.Reset(); | |
823 l2->SetBounds(gfx::Rect(0, 0, 400, 400)); | |
824 RunPendingMessages(); | |
825 EXPECT_TRUE(observer.notified()); | |
826 | |
827 // Opacity changes should alert the observers. | |
828 observer.Reset(); | |
829 l2->SetOpacity(0.5f); | |
830 RunPendingMessages(); | |
831 EXPECT_TRUE(observer.notified()); | |
832 | |
833 // So should setting the opacity back. | |
834 observer.Reset(); | |
835 l2->SetOpacity(1.0f); | |
836 RunPendingMessages(); | |
837 EXPECT_TRUE(observer.notified()); | |
838 | |
839 // Setting the transform of a layer should alert the observers. | |
840 observer.Reset(); | |
841 Transform transform; | |
842 transform.ConcatTranslate(-200, -200); | |
843 transform.ConcatRotate(90.0f); | |
844 transform.ConcatTranslate(200, 200); | |
845 l2->SetTransform(transform); | |
846 RunPendingMessages(); | |
847 EXPECT_TRUE(observer.notified()); | |
848 | |
849 GetCompositor()->RemoveObserver(&observer); | |
850 | |
851 // Opacity changes should no longer alert the removed observer. | |
852 observer.Reset(); | |
853 l2->SetOpacity(0.5f); | |
854 RunPendingMessages(); | |
855 EXPECT_FALSE(observer.notified()); | |
856 } | |
857 | |
858 // Checks that modifying the hierarchy correctly affects final composite. | |
859 TEST_F(LayerWithRealCompositorTest, MAYBE_ModifyHierarchy) { | |
860 GetCompositor()->WidgetSizeChanged(gfx::Size(50, 50)); | |
861 | |
862 // l0 | |
863 // +-l11 | |
864 // | +-l21 | |
865 // +-l12 | |
866 scoped_ptr<Layer> l0(CreateColorLayer(SK_ColorRED, | |
867 gfx::Rect(0, 0, 50, 50))); | |
868 scoped_ptr<Layer> l11(CreateColorLayer(SK_ColorGREEN, | |
869 gfx::Rect(0, 0, 25, 25))); | |
870 scoped_ptr<Layer> l21(CreateColorLayer(SK_ColorMAGENTA, | |
871 gfx::Rect(0, 0, 15, 15))); | |
872 scoped_ptr<Layer> l12(CreateColorLayer(SK_ColorBLUE, | |
873 gfx::Rect(10, 10, 25, 25))); | |
874 | |
875 FilePath ref_img1 = test_data_directory().AppendASCII("ModifyHierarchy1.png"); | |
876 FilePath ref_img2 = test_data_directory().AppendASCII("ModifyHierarchy2.png"); | |
877 SkBitmap bitmap; | |
878 | |
879 l0->Add(l11.get()); | |
880 l11->Add(l21.get()); | |
881 l0->Add(l12.get()); | |
882 DrawTree(l0.get()); | |
883 ASSERT_TRUE(ReadPixels(&bitmap)); | |
884 ASSERT_FALSE(bitmap.empty()); | |
885 // WritePNGFile(bitmap, ref_img1); | |
886 EXPECT_TRUE(IsSameAsPNGFile(bitmap, ref_img1)); | |
887 | |
888 l0->StackAtTop(l11.get()); | |
889 DrawTree(l0.get()); | |
890 ASSERT_TRUE(ReadPixels(&bitmap)); | |
891 ASSERT_FALSE(bitmap.empty()); | |
892 // WritePNGFile(bitmap, ref_img2); | |
893 EXPECT_TRUE(IsSameAsPNGFile(bitmap, ref_img2)); | |
894 | |
895 // l11 is already at the front, should have no effect. | |
896 l0->StackAtTop(l11.get()); | |
897 DrawTree(l0.get()); | |
898 ASSERT_TRUE(ReadPixels(&bitmap)); | |
899 ASSERT_FALSE(bitmap.empty()); | |
900 EXPECT_TRUE(IsSameAsPNGFile(bitmap, ref_img2)); | |
901 | |
902 // l11 is already at the front, should have no effect. | |
903 l0->StackAbove(l11.get(), l12.get()); | |
904 DrawTree(l0.get()); | |
905 ASSERT_TRUE(ReadPixels(&bitmap)); | |
906 ASSERT_FALSE(bitmap.empty()); | |
907 EXPECT_TRUE(IsSameAsPNGFile(bitmap, ref_img2)); | |
908 | |
909 // should restore to original configuration | |
910 l0->StackAbove(l12.get(), l11.get()); | |
911 DrawTree(l0.get()); | |
912 ASSERT_TRUE(ReadPixels(&bitmap)); | |
913 ASSERT_FALSE(bitmap.empty()); | |
914 EXPECT_TRUE(IsSameAsPNGFile(bitmap, ref_img1)); | |
915 } | |
916 | |
917 // Opacity is rendered correctly. | |
918 // Checks that modifying the hierarchy correctly affects final composite. | |
919 TEST_F(LayerWithRealCompositorTest, MAYBE_Opacity) { | |
920 GetCompositor()->WidgetSizeChanged(gfx::Size(50, 50)); | |
921 | |
922 // l0 | |
923 // +-l11 | |
924 scoped_ptr<Layer> l0(CreateColorLayer(SK_ColorRED, | |
925 gfx::Rect(0, 0, 50, 50))); | |
926 scoped_ptr<Layer> l11(CreateColorLayer(SK_ColorGREEN, | |
927 gfx::Rect(0, 0, 25, 25))); | |
928 | |
929 FilePath ref_img = test_data_directory().AppendASCII("Opacity.png"); | |
930 | |
931 l11->SetOpacity(0.75); | |
932 l0->Add(l11.get()); | |
933 DrawTree(l0.get()); | |
934 SkBitmap bitmap; | |
935 ASSERT_TRUE(ReadPixels(&bitmap)); | |
936 ASSERT_FALSE(bitmap.empty()); | |
937 // WritePNGFile(bitmap, ref_img); | |
938 EXPECT_TRUE(IsSameAsPNGFile(bitmap, ref_img)); | |
939 } | |
940 | |
941 namespace { | |
942 | |
943 class SchedulePaintLayerDelegate : public LayerDelegate { | |
944 public: | |
945 SchedulePaintLayerDelegate() : paint_count_(0), layer_(NULL) {} | |
946 | |
947 virtual ~SchedulePaintLayerDelegate() {} | |
948 | |
949 void set_layer(Layer* layer) { | |
950 layer_ = layer; | |
951 layer_->set_delegate(this); | |
952 } | |
953 | |
954 void SetSchedulePaintRect(const gfx::Rect& rect) { | |
955 schedule_paint_rect_ = rect; | |
956 } | |
957 | |
958 int GetPaintCountAndClear() { | |
959 int value = paint_count_; | |
960 paint_count_ = 0; | |
961 return value; | |
962 } | |
963 | |
964 const gfx::Rect& last_clip_rect() const { return last_clip_rect_; } | |
965 | |
966 private: | |
967 // Overridden from LayerDelegate: | |
968 virtual void OnPaintLayer(gfx::Canvas* canvas) OVERRIDE { | |
969 paint_count_++; | |
970 if (!schedule_paint_rect_.IsEmpty()) { | |
971 layer_->SchedulePaint(schedule_paint_rect_); | |
972 schedule_paint_rect_ = gfx::Rect(); | |
973 } | |
974 SkRect sk_clip_rect; | |
975 if (canvas->sk_canvas()->getClipBounds(&sk_clip_rect)) | |
976 last_clip_rect_ = gfx::SkRectToRect(sk_clip_rect); | |
977 } | |
978 | |
979 int paint_count_; | |
980 Layer* layer_; | |
981 gfx::Rect schedule_paint_rect_; | |
982 gfx::Rect last_clip_rect_; | |
983 | |
984 DISALLOW_COPY_AND_ASSIGN(SchedulePaintLayerDelegate); | |
985 }; | |
986 | |
987 } // namespace | |
988 | |
989 // Verifies that if SchedulePaint is invoked during painting the layer is still | |
990 // marked dirty. | |
991 TEST_F(LayerWithDelegateTest, SchedulePaintFromOnPaintLayer) { | |
992 scoped_ptr<Layer> root(CreateColorLayer(SK_ColorRED, | |
993 gfx::Rect(0, 0, 500, 500))); | |
994 SchedulePaintLayerDelegate child_delegate; | |
995 scoped_ptr<Layer> child(CreateColorLayer(SK_ColorBLUE, | |
996 gfx::Rect(0, 0, 200, 200))); | |
997 child_delegate.set_layer(child.get()); | |
998 | |
999 root->Add(child.get()); | |
1000 | |
1001 SchedulePaintForLayer(root.get()); | |
1002 DrawTree(root.get()); | |
1003 schedule_draw_invoked_ = false; | |
1004 child->SchedulePaint(gfx::Rect(0, 0, 20, 20)); | |
1005 child_delegate.GetPaintCountAndClear(); | |
1006 EXPECT_TRUE(schedule_draw_invoked_); | |
1007 schedule_draw_invoked_ = false; | |
1008 // Set a rect so that when OnPaintLayer() is invoked SchedulePaint is invoked | |
1009 // again. | |
1010 child_delegate.SetSchedulePaintRect(gfx::Rect(10, 10, 30, 30)); | |
1011 DrawTree(root.get()); | |
1012 // |child| should have been painted once. | |
1013 EXPECT_EQ(1, child_delegate.GetPaintCountAndClear()); | |
1014 // ScheduleDraw() should have been invoked. | |
1015 EXPECT_TRUE(schedule_draw_invoked_); | |
1016 // Because SchedulePaint() was invoked from OnPaintLayer() |child| should | |
1017 // still need to be painted. | |
1018 DrawTree(root.get()); | |
1019 EXPECT_EQ(1, child_delegate.GetPaintCountAndClear()); | |
1020 EXPECT_TRUE(child_delegate.last_clip_rect().Contains( | |
1021 gfx::Rect(10, 10, 30, 30))); | |
1022 } | |
1023 | |
1024 } // namespace ui | |
OLD | NEW |