• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "ui/wm/core/shadow.h"
6 
7 #include "grit/ui_resources.h"
8 #include "ui/base/resource/resource_bundle.h"
9 #include "ui/compositor/scoped_layer_animation_settings.h"
10 #include "ui/wm/core/image_grid.h"
11 
12 namespace {
13 
14 // Shadow opacity for different styles.
15 const float kActiveShadowOpacity = 1.0f;
16 const float kInactiveShadowOpacity = 0.2f;
17 const float kSmallShadowOpacity = 1.0f;
18 
19 // Interior inset for different styles.
20 const int kActiveInteriorInset = 0;
21 const int kInactiveInteriorInset = 0;
22 const int kSmallInteriorInset = 5;
23 
24 // Duration for opacity animation in milliseconds.
25 const int kShadowAnimationDurationMs = 100;
26 
GetOpacityForStyle(wm::Shadow::Style style)27 float GetOpacityForStyle(wm::Shadow::Style style) {
28   switch (style) {
29     case wm::Shadow::STYLE_ACTIVE:
30       return kActiveShadowOpacity;
31     case wm::Shadow::STYLE_INACTIVE:
32       return kInactiveShadowOpacity;
33     case wm::Shadow::STYLE_SMALL:
34       return kSmallShadowOpacity;
35   }
36   return 1.0f;
37 }
38 
GetInteriorInsetForStyle(wm::Shadow::Style style)39 int GetInteriorInsetForStyle(wm::Shadow::Style style) {
40   switch (style) {
41     case wm::Shadow::STYLE_ACTIVE:
42       return kActiveInteriorInset;
43     case wm::Shadow::STYLE_INACTIVE:
44       return kInactiveInteriorInset;
45     case wm::Shadow::STYLE_SMALL:
46       return kSmallInteriorInset;
47   }
48   return 0;
49 }
50 
51 }  // namespace
52 
53 namespace wm {
54 
Shadow()55 Shadow::Shadow() : style_(STYLE_ACTIVE), interior_inset_(0) {
56 }
57 
~Shadow()58 Shadow::~Shadow() {
59 }
60 
Init(Style style)61 void Shadow::Init(Style style) {
62   style_ = style;
63   image_grid_.reset(new ImageGrid);
64   UpdateImagesForStyle();
65   image_grid_->layer()->set_name("Shadow");
66   image_grid_->layer()->SetOpacity(GetOpacityForStyle(style_));
67 }
68 
SetContentBounds(const gfx::Rect & content_bounds)69 void Shadow::SetContentBounds(const gfx::Rect& content_bounds) {
70   content_bounds_ = content_bounds;
71   UpdateImageGridBounds();
72 }
73 
layer() const74 ui::Layer* Shadow::layer() const {
75   return image_grid_->layer();
76 }
77 
SetStyle(Style style)78 void Shadow::SetStyle(Style style) {
79   if (style_ == style)
80     return;
81 
82   Style old_style = style_;
83   style_ = style;
84 
85   // Stop waiting for any as yet unfinished implicit animations.
86   StopObservingImplicitAnimations();
87 
88   // If we're switching to or from the small style, don't bother with
89   // animations.
90   if (style == STYLE_SMALL || old_style == STYLE_SMALL) {
91     UpdateImagesForStyle();
92     image_grid_->layer()->SetOpacity(GetOpacityForStyle(style));
93     return;
94   }
95 
96   // If we're becoming active, switch images now.  Because the inactive image
97   // has a very low opacity the switch isn't noticeable and this approach
98   // allows us to use only a single set of shadow images at a time.
99   if (style == STYLE_ACTIVE) {
100     UpdateImagesForStyle();
101     // Opacity was baked into inactive image, start opacity low to match.
102     image_grid_->layer()->SetOpacity(kInactiveShadowOpacity);
103   }
104 
105   {
106     // Property sets within this scope will be implicitly animated.
107     ui::ScopedLayerAnimationSettings settings(layer()->GetAnimator());
108     settings.AddObserver(this);
109     settings.SetTransitionDuration(
110         base::TimeDelta::FromMilliseconds(kShadowAnimationDurationMs));
111     switch (style_) {
112       case STYLE_ACTIVE:
113         image_grid_->layer()->SetOpacity(kActiveShadowOpacity);
114         break;
115       case STYLE_INACTIVE:
116         image_grid_->layer()->SetOpacity(kInactiveShadowOpacity);
117         break;
118       default:
119         NOTREACHED() << "Unhandled style " << style_;
120         break;
121     }
122   }
123 }
124 
OnImplicitAnimationsCompleted()125 void Shadow::OnImplicitAnimationsCompleted() {
126   // If we just finished going inactive, switch images.  This doesn't cause
127   // a visual pop because the inactive image opacity is so low.
128   if (style_ == STYLE_INACTIVE) {
129     UpdateImagesForStyle();
130     // Opacity is baked into inactive image, so set fully opaque.
131     image_grid_->layer()->SetOpacity(1.0f);
132   }
133 }
134 
UpdateImagesForStyle()135 void Shadow::UpdateImagesForStyle() {
136   ResourceBundle& res = ResourceBundle::GetSharedInstance();
137   switch (style_) {
138     case STYLE_ACTIVE:
139       image_grid_->SetImages(
140           &res.GetImageNamed(IDR_AURA_SHADOW_ACTIVE_TOP_LEFT),
141           &res.GetImageNamed(IDR_AURA_SHADOW_ACTIVE_TOP),
142           &res.GetImageNamed(IDR_AURA_SHADOW_ACTIVE_TOP_RIGHT),
143           &res.GetImageNamed(IDR_AURA_SHADOW_ACTIVE_LEFT),
144           NULL,
145           &res.GetImageNamed(IDR_AURA_SHADOW_ACTIVE_RIGHT),
146           &res.GetImageNamed(IDR_AURA_SHADOW_ACTIVE_BOTTOM_LEFT),
147           &res.GetImageNamed(IDR_AURA_SHADOW_ACTIVE_BOTTOM),
148           &res.GetImageNamed(IDR_AURA_SHADOW_ACTIVE_BOTTOM_RIGHT));
149       break;
150     case STYLE_INACTIVE:
151       image_grid_->SetImages(
152           &res.GetImageNamed(IDR_AURA_SHADOW_INACTIVE_TOP_LEFT),
153           &res.GetImageNamed(IDR_AURA_SHADOW_INACTIVE_TOP),
154           &res.GetImageNamed(IDR_AURA_SHADOW_INACTIVE_TOP_RIGHT),
155           &res.GetImageNamed(IDR_AURA_SHADOW_INACTIVE_LEFT),
156           NULL,
157           &res.GetImageNamed(IDR_AURA_SHADOW_INACTIVE_RIGHT),
158           &res.GetImageNamed(IDR_AURA_SHADOW_INACTIVE_BOTTOM_LEFT),
159           &res.GetImageNamed(IDR_AURA_SHADOW_INACTIVE_BOTTOM),
160           &res.GetImageNamed(IDR_AURA_SHADOW_INACTIVE_BOTTOM_RIGHT));
161       break;
162     case STYLE_SMALL:
163       image_grid_->SetImages(
164           &res.GetImageNamed(IDR_WINDOW_BUBBLE_SHADOW_SMALL_TOP_LEFT),
165           &res.GetImageNamed(IDR_WINDOW_BUBBLE_SHADOW_SMALL_TOP),
166           &res.GetImageNamed(IDR_WINDOW_BUBBLE_SHADOW_SMALL_TOP_RIGHT),
167           &res.GetImageNamed(IDR_WINDOW_BUBBLE_SHADOW_SMALL_LEFT),
168           NULL,
169           &res.GetImageNamed(IDR_WINDOW_BUBBLE_SHADOW_SMALL_RIGHT),
170           &res.GetImageNamed(IDR_WINDOW_BUBBLE_SHADOW_SMALL_BOTTOM_LEFT),
171           &res.GetImageNamed(IDR_WINDOW_BUBBLE_SHADOW_SMALL_BOTTOM),
172           &res.GetImageNamed(IDR_WINDOW_BUBBLE_SHADOW_SMALL_BOTTOM_RIGHT));
173       break;
174     default:
175       NOTREACHED() << "Unhandled style " << style_;
176       break;
177   }
178 
179   // Update interior inset for style.
180   interior_inset_ = GetInteriorInsetForStyle(style_);
181 
182   // Image sizes may have changed.
183   UpdateImageGridBounds();
184 }
185 
UpdateImageGridBounds()186 void Shadow::UpdateImageGridBounds() {
187   // Update bounds based on content bounds and image sizes.
188   gfx::Rect image_grid_bounds = content_bounds_;
189   image_grid_bounds.Inset(interior_inset_, interior_inset_);
190   image_grid_->SetContentBounds(image_grid_bounds);
191 }
192 
193 }  // namespace wm
194