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 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 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 55 Shadow::Shadow() : style_(STYLE_ACTIVE), interior_inset_(0) { 56 } 57 58 Shadow::~Shadow() { 59 } 60 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 69 void Shadow::SetContentBounds(const gfx::Rect& content_bounds) { 70 content_bounds_ = content_bounds; 71 UpdateImageGridBounds(); 72 } 73 74 ui::Layer* Shadow::layer() const { 75 return image_grid_->layer(); 76 } 77 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 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 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 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