Home | History | Annotate | Download | only in core
      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