| 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 |