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 
5 #include "ui/compositor_extra/shadow.h"
6 
7 #include "base/macros.h"
8 #include "base/test/test_discardable_memory_allocator.h"
9 #include "testing/gtest/include/gtest/gtest.h"
10 #include "ui/compositor/layer.h"
11 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
12 #include "ui/gfx/geometry/insets.h"
13 #include "ui/gfx/shadow_util.h"
14 #include "ui/gfx/shadow_value.h"
15 
16 namespace ui {
17 namespace {
18 
19 constexpr int kElevationLarge = 24;
20 constexpr int kElevationSmall = 6;
21 
InsetsForElevation(int elevation)22 gfx::Insets InsetsForElevation(int elevation) {
23   return -gfx::Insets(2 * elevation) + gfx::Insets(elevation, 0, -elevation, 0);
24 }
25 
NineboxImageSizeForElevationAndCornerRadius(int elevation,int corner_radius)26 gfx::Size NineboxImageSizeForElevationAndCornerRadius(int elevation,
27                                                       int corner_radius) {
28   auto values = gfx::ShadowValue::MakeMdShadowValues(elevation);
29   gfx::Rect bounds(0, 0, 1, 1);
30   bounds.Inset(-gfx::ShadowValue::GetBlurRegion(values));
31   bounds.Inset(-gfx::Insets(corner_radius));
32   return bounds.size();
33 }
34 
35 class ShadowTest : public testing::Test {
36  protected:
ShadowTest()37   ShadowTest() {}
~ShadowTest()38   ~ShadowTest() override {}
39 
SetUp()40   void SetUp() override {
41     base::DiscardableMemoryAllocator::SetInstance(
42         &discardable_memory_allocator_);
43   }
44 
TearDown()45   void TearDown() override {
46     base::DiscardableMemoryAllocator::SetInstance(nullptr);
47   }
48 
49  private:
50   base::TestDiscardableMemoryAllocator discardable_memory_allocator_;
51 
52   DISALLOW_COPY_AND_ASSIGN(ShadowTest);
53 };
54 
55 // Test if the proper content bounds is calculated based on the current style.
TEST_F(ShadowTest,SetContentBounds)56 TEST_F(ShadowTest, SetContentBounds) {
57   ScopedAnimationDurationScaleMode zero_duration_mode(
58       ScopedAnimationDurationScaleMode::ZERO_DURATION);
59   // Verify that layer bounds are outset from content bounds.
60   Shadow shadow;
61   {
62     shadow.Init(kElevationLarge);
63     gfx::Rect content_bounds(100, 100, 300, 300);
64     shadow.SetContentBounds(content_bounds);
65     EXPECT_EQ(content_bounds, shadow.content_bounds());
66     gfx::Rect shadow_bounds(content_bounds);
67     shadow_bounds.Inset(InsetsForElevation(kElevationLarge));
68     EXPECT_EQ(shadow_bounds, shadow.layer()->bounds());
69   }
70 
71   {
72     shadow.SetElevation(kElevationSmall);
73     gfx::Rect content_bounds(100, 100, 300, 300);
74     shadow.SetContentBounds(content_bounds);
75     EXPECT_EQ(content_bounds, shadow.content_bounds());
76     gfx::Rect shadow_bounds(content_bounds);
77     shadow_bounds.Inset(InsetsForElevation(kElevationSmall));
78     EXPECT_EQ(shadow_bounds, shadow.layer()->bounds());
79   }
80 }
81 
82 // Test that the elevation is reduced when the contents are too small to handle
83 // the full elevation.
TEST_F(ShadowTest,AdjustElevationForSmallContents)84 TEST_F(ShadowTest, AdjustElevationForSmallContents) {
85   Shadow shadow;
86   shadow.Init(kElevationLarge);
87   {
88     gfx::Rect content_bounds(100, 100, 300, 300);
89     shadow.SetContentBounds(content_bounds);
90     gfx::Rect shadow_bounds(content_bounds);
91     shadow_bounds.Inset(InsetsForElevation(kElevationLarge));
92     EXPECT_EQ(shadow_bounds, shadow.layer()->bounds());
93   }
94 
95   {
96     constexpr int kWidth = 80;
97     gfx::Rect content_bounds(100, 100, kWidth, 300);
98     shadow.SetContentBounds(content_bounds);
99     gfx::Rect shadow_bounds(content_bounds);
100     shadow_bounds.Inset(InsetsForElevation((kWidth - 4) / 4));
101     EXPECT_EQ(shadow_bounds, shadow.layer()->bounds());
102   }
103 
104   {
105     constexpr int kHeight = 80;
106     gfx::Rect content_bounds(100, 100, 300, kHeight);
107     shadow.SetContentBounds(content_bounds);
108     gfx::Rect shadow_bounds(content_bounds);
109     shadow_bounds.Inset(InsetsForElevation((kHeight - 4) / 4));
110     EXPECT_EQ(shadow_bounds, shadow.layer()->bounds());
111   }
112 }
113 
114 // Test that rounded corner radius is handled correctly.
TEST_F(ShadowTest,AdjustRoundedCornerRadius)115 TEST_F(ShadowTest, AdjustRoundedCornerRadius) {
116   Shadow shadow;
117   shadow.Init(kElevationSmall);
118   gfx::Rect content_bounds(100, 100, 300, 300);
119   shadow.SetContentBounds(content_bounds);
120   EXPECT_EQ(content_bounds, shadow.content_bounds());
121   shadow.SetRoundedCornerRadius(0);
122   gfx::Rect shadow_bounds(content_bounds);
123   shadow_bounds.Inset(InsetsForElevation(kElevationSmall));
124   EXPECT_EQ(shadow_bounds, shadow.layer()->bounds());
125   EXPECT_EQ(NineboxImageSizeForElevationAndCornerRadius(6, 0),
126             shadow.details_for_testing()->ninebox_image.size());
127 }
128 
129 }  // namespace
130 }  // namespace ui
131