| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ui/wm/core/shadow.h" | 5 #include "ui/wm/core/shadow.h" |
| 6 | 6 |
| 7 #include "base/lazy_instance.h" | |
| 8 #include "ui/base/resource/resource_bundle.h" | 7 #include "ui/base/resource/resource_bundle.h" |
| 9 #include "ui/compositor/layer.h" | 8 #include "ui/compositor/layer.h" |
| 10 #include "ui/compositor/scoped_layer_animation_settings.h" | 9 #include "ui/compositor/scoped_layer_animation_settings.h" |
| 11 #include "ui/gfx/geometry/insets.h" | 10 #include "ui/gfx/geometry/insets.h" |
| 12 #include "ui/gfx/image/image_skia_operations.h" | 11 #include "ui/gfx/shadow_util.h" |
| 13 #include "ui/wm/core/shadow_types.h" | 12 #include "ui/wm/core/shadow_types.h" |
| 14 | 13 |
| 15 namespace wm { | 14 namespace wm { |
| 16 | 15 |
| 17 namespace { | 16 namespace { |
| 18 | 17 |
| 19 // Rounded corners are overdrawn on top of the window's content layer, | 18 // Rounded corners are overdrawn on top of the window's content layer, |
| 20 // we need to exclude them from the occlusion area. | 19 // we need to exclude them from the occlusion area. |
| 21 const int kRoundedCornerRadius = 2; | 20 const int kRoundedCornerRadius = 2; |
| 22 | 21 |
| 23 // Duration for opacity animation in milliseconds. | 22 // Duration for opacity animation in milliseconds. |
| 24 const int kShadowAnimationDurationMs = 100; | 23 const int kShadowAnimationDurationMs = 100; |
| 25 | 24 |
| 26 struct ShadowDetails { | |
| 27 // Description of the shadows. | |
| 28 gfx::ShadowValues values; | |
| 29 // Cached ninebox image based on |values|. | |
| 30 gfx::ImageSkia ninebox_image; | |
| 31 }; | |
| 32 | |
| 33 // Map from elevation to a cached shadow. | |
| 34 using ShadowDetailsMap = std::map<int, ShadowDetails>; | |
| 35 base::LazyInstance<ShadowDetailsMap> g_shadow_cache = LAZY_INSTANCE_INITIALIZER; | |
| 36 | |
| 37 const ShadowDetails& GetDetailsForElevation(int elevation) { | |
| 38 auto iter = g_shadow_cache.Get().find(elevation); | |
| 39 if (iter != g_shadow_cache.Get().end()) | |
| 40 return iter->second; | |
| 41 | |
| 42 auto insertion = | |
| 43 g_shadow_cache.Get().insert(std::make_pair(elevation, ShadowDetails())); | |
| 44 DCHECK(insertion.second); | |
| 45 ShadowDetails* shadow = &insertion.first->second; | |
| 46 // To match the CSS notion of blur (spread outside the bounding box) to the | |
| 47 // Skia notion of blur (spread outside and inside the bounding box), we have | |
| 48 // to double the designer-provided blur values. | |
| 49 const int kBlurCorrection = 2; | |
| 50 // "Key shadow": y offset is elevation and blur is twice the elevation. | |
| 51 shadow->values.emplace_back(gfx::Vector2d(0, elevation), | |
| 52 kBlurCorrection * elevation * 2, | |
| 53 SkColorSetA(SK_ColorBLACK, 0x3d)); | |
| 54 // "Ambient shadow": no offset and blur matches the elevation. | |
| 55 shadow->values.emplace_back(gfx::Vector2d(), kBlurCorrection * elevation, | |
| 56 SkColorSetA(SK_ColorBLACK, 0x1f)); | |
| 57 // To see what this looks like for elevation 24, try this CSS: | |
| 58 // box-shadow: 0 24px 48px rgba(0, 0, 0, .24), | |
| 59 // 0 0 24px rgba(0, 0, 0, .12); | |
| 60 shadow->ninebox_image = gfx::ImageSkiaOperations::CreateShadowNinebox( | |
| 61 shadow->values, kRoundedCornerRadius); | |
| 62 return *shadow; | |
| 63 } | |
| 64 | |
| 65 } // namespace | 25 } // namespace |
| 66 | 26 |
| 67 Shadow::Shadow() : desired_elevation_(ShadowElevation::NONE) {} | 27 Shadow::Shadow() : desired_elevation_(ShadowElevation::NONE) {} |
| 68 | 28 |
| 69 Shadow::~Shadow() {} | 29 Shadow::~Shadow() {} |
| 70 | 30 |
| 71 void Shadow::Init(ShadowElevation elevation) { | 31 void Shadow::Init(ShadowElevation elevation) { |
| 72 desired_elevation_ = elevation; | 32 desired_elevation_ = elevation; |
| 73 layer_.reset(new ui::Layer(ui::LAYER_NOT_DRAWN)); | 33 layer_.reset(new ui::Layer(ui::LAYER_NOT_DRAWN)); |
| 74 RecreateShadowLayer(); | 34 RecreateShadowLayer(); |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 133 | 93 |
| 134 UpdateLayerBounds(); | 94 UpdateLayerBounds(); |
| 135 } | 95 } |
| 136 | 96 |
| 137 void Shadow::UpdateLayerBounds() { | 97 void Shadow::UpdateLayerBounds() { |
| 138 if (content_bounds_.IsEmpty()) | 98 if (content_bounds_.IsEmpty()) |
| 139 return; | 99 return; |
| 140 | 100 |
| 141 // The ninebox assumption breaks down when the window is too small for the | 101 // The ninebox assumption breaks down when the window is too small for the |
| 142 // desired elevation. The height/width of |blur_region| will be 4 * elevation | 102 // desired elevation. The height/width of |blur_region| will be 4 * elevation |
| 143 // (see GetDetailsForElevation), so cap elevation at the most we can handle. | 103 // (see ShadowDetails::Get), so cap elevation at the most we can handle. |
| 144 const int smaller_dimension = | 104 const int smaller_dimension = |
| 145 std::min(content_bounds_.width(), content_bounds_.height()); | 105 std::min(content_bounds_.width(), content_bounds_.height()); |
| 146 const int size_adjusted_elevation = | 106 const int size_adjusted_elevation = |
| 147 std::min((smaller_dimension - 2 * kRoundedCornerRadius) / 4, | 107 std::min((smaller_dimension - 2 * kRoundedCornerRadius) / 4, |
| 148 static_cast<int>(desired_elevation_)); | 108 static_cast<int>(desired_elevation_)); |
| 149 const ShadowDetails& details = | 109 const auto& details = |
| 150 GetDetailsForElevation(size_adjusted_elevation); | 110 gfx::ShadowDetails::Get(size_adjusted_elevation, kRoundedCornerRadius); |
| 151 gfx::Insets blur_region = gfx::ShadowValue::GetBlurRegion(details.values) + | 111 gfx::Insets blur_region = gfx::ShadowValue::GetBlurRegion(details.values) + |
| 152 gfx::Insets(kRoundedCornerRadius); | 112 gfx::Insets(kRoundedCornerRadius); |
| 153 if (size_adjusted_elevation != effective_elevation_) { | 113 if (size_adjusted_elevation != effective_elevation_) { |
| 154 shadow_layer_->UpdateNinePatchLayerImage(details.ninebox_image); | 114 shadow_layer_->UpdateNinePatchLayerImage(details.ninebox_image); |
| 155 // The ninebox grid is defined in terms of the image size. The shadow blurs | 115 // The ninebox grid is defined in terms of the image size. The shadow blurs |
| 156 // in both inward and outward directions from the edge of the contents, so | 116 // in both inward and outward directions from the edge of the contents, so |
| 157 // the aperture goes further inside the image than the shadow margins (which | 117 // the aperture goes further inside the image than the shadow margins (which |
| 158 // represent exterior blur). | 118 // represent exterior blur). |
| 159 gfx::Rect aperture(details.ninebox_image.size()); | 119 gfx::Rect aperture(details.ninebox_image.size()); |
| 160 aperture.Inset(blur_region); | 120 aperture.Inset(blur_region); |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 199 occlusion_bounds.Inset(-margins + gfx::Insets(kRoundedCornerRadius)); | 159 occlusion_bounds.Inset(-margins + gfx::Insets(kRoundedCornerRadius)); |
| 200 shadow_layer_->UpdateNinePatchOcclusion(occlusion_bounds); | 160 shadow_layer_->UpdateNinePatchOcclusion(occlusion_bounds); |
| 201 | 161 |
| 202 // The border is the same inset as the aperture. | 162 // The border is the same inset as the aperture. |
| 203 shadow_layer_->UpdateNinePatchLayerBorder( | 163 shadow_layer_->UpdateNinePatchLayerBorder( |
| 204 gfx::Rect(blur_region.left(), blur_region.top(), blur_region.width(), | 164 gfx::Rect(blur_region.left(), blur_region.top(), blur_region.width(), |
| 205 blur_region.height())); | 165 blur_region.height())); |
| 206 } | 166 } |
| 207 | 167 |
| 208 } // namespace wm | 168 } // namespace wm |
| OLD | NEW |