Chromium Code Reviews| 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 "third_party/skia/include/core/SkBitmap.h" | 7 #include "base/lazy_instance.h" |
| 8 #include "ui/base/resource/resource_bundle.h" | 8 #include "ui/base/resource/resource_bundle.h" |
| 9 #include "ui/compositor/layer.h" | 9 #include "ui/compositor/layer.h" |
| 10 #include "ui/compositor/scoped_layer_animation_settings.h" | 10 #include "ui/compositor/scoped_layer_animation_settings.h" |
| 11 #include "ui/resources/grit/ui_resources.h" | 11 #include "ui/gfx/geometry/insets.h" |
| 12 #include "ui/gfx/image/image_skia_operations.h" | |
| 13 | |
| 14 namespace wm { | |
| 12 | 15 |
| 13 namespace { | 16 namespace { |
| 14 | 17 |
| 15 // The opacity used for active shadow when animating between | 18 // The opacity used for active shadow when animating between |
| 16 // inactive/active shadow. | 19 // inactive/active shadow. |
| 17 const float kInactiveShadowAnimationOpacity = 0.2f; | 20 const float kInactiveShadowAnimationOpacity = 0.2f; |
| 18 | 21 |
| 19 // Shadow aperture for different styles. | |
| 20 // Note that this may be greater than interior inset to allow shadows with | |
| 21 // curved corners that extend inwards beyond a window's borders. | |
| 22 const int kActiveInteriorAperture = 134; | |
| 23 const int kInactiveInteriorAperture = 134; | |
| 24 const int kSmallInteriorAperture = 9; | |
| 25 | |
| 26 // Interior inset for different styles. | |
| 27 const int kActiveInteriorInset = 64; | |
| 28 const int kInactiveInteriorInset = 64; | |
| 29 const int kSmallInteriorInset = 4; | |
| 30 | |
| 31 // Rounded corners are overdrawn on top of the window's content layer, | 22 // Rounded corners are overdrawn on top of the window's content layer, |
| 32 // we need to exclude them from the occlusion area. | 23 // we need to exclude them from the occlusion area. |
| 33 const int kRoundedCornerRadius = 2; | 24 const int kRoundedCornerRadius = 2; |
| 34 | 25 |
| 35 // Duration for opacity animation in milliseconds. | 26 // Duration for opacity animation in milliseconds. |
| 36 const int kShadowAnimationDurationMs = 100; | 27 const int kShadowAnimationDurationMs = 100; |
| 37 | 28 |
| 38 int GetShadowApertureForStyle(wm::Shadow::Style style) { | 29 struct ShadowDetails { |
| 39 switch (style) { | 30 gfx::ShadowValues values; |
| 40 case wm::Shadow::STYLE_ACTIVE: | 31 gfx::ImageSkia image; |
|
James Cook
2016/12/05 23:38:35
nit: document either here or above struct what thi
Evan Stade
2016/12/06 00:53:21
Done.
| |
| 41 return kActiveInteriorAperture; | 32 }; |
| 42 case wm::Shadow::STYLE_INACTIVE: | 33 |
| 43 return kInactiveInteriorAperture; | 34 // Map from elevation to a cached shadow. |
| 44 case wm::Shadow::STYLE_SMALL: | 35 typedef std::map<int, ShadowDetails> ShadowDetailsMap; |
| 45 return kSmallInteriorAperture; | 36 base::LazyInstance<ShadowDetailsMap> g_shadow_cache = LAZY_INSTANCE_INITIALIZER; |
| 37 | |
| 38 const ShadowDetails& GetDetailsForElevation(int elevation) { | |
| 39 auto insertion = | |
| 40 g_shadow_cache.Get().insert(std::make_pair(elevation, ShadowDetails())); | |
|
James Cook
2016/12/05 23:38:35
optional: would emplace work here?
Evan Stade
2016/12/06 00:53:21
yes it would if map::emplace were allowed :~(
"st
James Cook
2016/12/06 18:17:51
I learned something new today!
| |
| 41 ShadowDetails* shadow = &insertion.first->second; | |
| 42 // If there was an insertion, initialize the new ShadowDetails. | |
| 43 if (insertion.second) { | |
|
James Cook
2016/12/05 23:38:35
I think this would be clearer if it did std::map::
Evan Stade
2016/12/06 00:53:21
Done.
| |
| 44 // To match the CSS notion of blur (spread outside the bounding box) to the | |
| 45 // Skia notion of blur (spread outside and inside the bounding box), we have | |
| 46 // to double the designer-provided blur values. | |
| 47 const int kBlurCorrection = 2; | |
| 48 // "Key shadow": y offset is elevation and blur is twice the elevation. | |
| 49 shadow->values.emplace_back(gfx::Vector2d(0, elevation), | |
| 50 kBlurCorrection * elevation * 2, | |
| 51 SkColorSetA(SK_ColorBLACK, 0x3d)); | |
| 52 // "Ambient shadow": no offset and blur matches the elevation. | |
| 53 shadow->values.emplace_back(gfx::Vector2d(), kBlurCorrection * elevation, | |
| 54 SkColorSetA(SK_ColorBLACK, 0x1f)); | |
| 55 shadow->image = gfx::ImageSkiaOperations::CreateShadowNinebox( | |
| 56 shadow->values, kRoundedCornerRadius); | |
| 46 } | 57 } |
| 47 return 0; | 58 return *shadow; |
| 48 } | |
| 49 | |
| 50 int GetInteriorInsetForStyle(wm::Shadow::Style style) { | |
| 51 switch (style) { | |
| 52 case wm::Shadow::STYLE_ACTIVE: | |
| 53 return kActiveInteriorInset; | |
| 54 case wm::Shadow::STYLE_INACTIVE: | |
| 55 return kInactiveInteriorInset; | |
| 56 case wm::Shadow::STYLE_SMALL: | |
| 57 return kSmallInteriorInset; | |
| 58 } | |
| 59 return 0; | |
| 60 } | 59 } |
| 61 | 60 |
| 62 } // namespace | 61 } // namespace |
| 63 | 62 |
| 64 namespace wm { | 63 Shadow::Shadow() : style_(STYLE_ACTIVE) {} |
|
James Cook
2016/12/05 23:38:35
optional: init in header?
Evan Stade
2016/12/06 00:53:21
Done.
| |
| 65 | 64 |
| 66 Shadow::Shadow() : style_(STYLE_ACTIVE), interior_inset_(0) { | 65 Shadow::~Shadow() {} |
| 67 } | |
| 68 | |
| 69 Shadow::~Shadow() { | |
| 70 } | |
| 71 | 66 |
| 72 void Shadow::Init(Style style) { | 67 void Shadow::Init(Style style) { |
| 73 style_ = style; | 68 style_ = style; |
| 74 | 69 |
| 75 layer_.reset(new ui::Layer(ui::LAYER_NOT_DRAWN)); | 70 layer_.reset(new ui::Layer(ui::LAYER_NOT_DRAWN)); |
| 76 shadow_layer_.reset(new ui::Layer(ui::LAYER_NINE_PATCH)); | 71 shadow_layer_.reset(new ui::Layer(ui::LAYER_NINE_PATCH)); |
| 77 layer()->Add(shadow_layer_.get()); | 72 layer()->Add(shadow_layer_.get()); |
| 78 | 73 |
| 79 UpdateImagesForStyle(); | 74 UpdateImagesForStyle(); |
| 80 shadow_layer_->set_name("Shadow"); | 75 shadow_layer_->set_name("Shadow"); |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 142 // If we just finished going inactive, switch images. This doesn't cause | 137 // If we just finished going inactive, switch images. This doesn't cause |
| 143 // a visual pop because the inactive image opacity is so low. | 138 // a visual pop because the inactive image opacity is so low. |
| 144 if (style_ == STYLE_INACTIVE) { | 139 if (style_ == STYLE_INACTIVE) { |
| 145 UpdateImagesForStyle(); | 140 UpdateImagesForStyle(); |
| 146 // Opacity is baked into inactive image, so set fully opaque. | 141 // Opacity is baked into inactive image, so set fully opaque. |
| 147 shadow_layer_->SetOpacity(1.0f); | 142 shadow_layer_->SetOpacity(1.0f); |
| 148 } | 143 } |
| 149 } | 144 } |
| 150 | 145 |
| 151 void Shadow::UpdateImagesForStyle() { | 146 void Shadow::UpdateImagesForStyle() { |
| 152 ResourceBundle& res = ResourceBundle::GetSharedInstance(); | 147 const ShadowDetails& details = GetDetailsForElevation(ElevationForStyle()); |
| 153 gfx::Image image; | 148 shadow_layer_->UpdateNinePatchLayerImage(details.image); |
| 154 switch (style_) { | |
| 155 case STYLE_ACTIVE: | |
| 156 image = res.GetImageNamed(IDR_AURA_SHADOW_ACTIVE); | |
|
James Cook
2016/12/05 23:38:35
Can you file a bug about updating Mustash to use t
Evan Stade
2016/12/06 00:53:21
Done.
| |
| 157 break; | |
| 158 case STYLE_INACTIVE: | |
| 159 image = res.GetImageNamed(IDR_AURA_SHADOW_INACTIVE); | |
| 160 break; | |
| 161 case STYLE_SMALL: | |
| 162 image = res.GetImageNamed(IDR_WINDOW_BUBBLE_SHADOW_SMALL); | |
| 163 break; | |
| 164 default: | |
| 165 NOTREACHED() << "Unhandled style " << style_; | |
| 166 break; | |
| 167 } | |
| 168 | |
| 169 shadow_layer_->UpdateNinePatchLayerImage(image.AsImageSkia()); | |
| 170 image_size_ = image.Size(); | |
| 171 interior_inset_ = GetInteriorInsetForStyle(style_); | |
| 172 | |
| 173 // Image sizes may have changed. | |
| 174 UpdateLayerBounds(); | 149 UpdateLayerBounds(); |
| 175 } | 150 } |
| 176 | 151 |
| 177 void Shadow::UpdateLayerBounds() { | 152 void Shadow::UpdateLayerBounds() { |
| 178 // Update bounds based on content bounds and interior inset. | 153 const ShadowDetails& details = GetDetailsForElevation(ElevationForStyle()); |
| 154 const gfx::Insets margins = gfx::ShadowValue::GetMargin(details.values); | |
|
James Cook
2016/12/05 23:38:35
nit: maybe comment that these insets push the boun
Evan Stade
2016/12/06 00:53:21
done
| |
| 179 gfx::Rect layer_bounds = content_bounds_; | 155 gfx::Rect layer_bounds = content_bounds_; |
| 180 layer_bounds.Inset(-interior_inset_, -interior_inset_); | 156 layer_bounds.Inset(margins); |
| 181 layer()->SetBounds(layer_bounds); | 157 layer()->SetBounds(layer_bounds); |
| 182 shadow_layer_->SetBounds(gfx::Rect(layer_bounds.size())); | 158 gfx::Rect shadow_layer_bounds(layer_bounds.size()); |
| 159 shadow_layer_->SetBounds(shadow_layer_bounds); | |
| 183 | 160 |
| 184 // Update the shadow aperture and border for style. Note that border is in | 161 // Occlude the region inside the bounding box. Occlusion uses shadow layer |
| 185 // layer space and it cannot exceed the bounds of the layer. | 162 // space. |
| 186 int aperture = GetShadowApertureForStyle(style_); | 163 gfx::Rect occlusion_bounds = shadow_layer_bounds; |
| 187 int aperture_x = std::min(aperture, layer_bounds.width() / 2); | 164 occlusion_bounds.Inset(-margins + gfx::Insets(kRoundedCornerRadius)); |
| 188 int aperture_y = std::min(aperture, layer_bounds.height() / 2); | 165 shadow_layer_->UpdateNinePatchOcclusion(occlusion_bounds); |
| 189 gfx::Rect aperture_rect(aperture_x, aperture_y, | |
| 190 image_size_.width() - aperture_x * 2, | |
| 191 image_size_.height() - aperture_y * 2); | |
| 192 | 166 |
| 193 shadow_layer_->UpdateNinePatchLayerAperture(aperture_rect); | 167 // The ninebox grid is defined in terms of the image size. We have to take |
| 194 shadow_layer_->UpdateNinePatchLayerBorder( | 168 // into account the inner blur as well as outer blur and offset. |
| 195 gfx::Rect(aperture_x, aperture_y, aperture_x * 2, aperture_y * 2)); | 169 gfx::Rect aperture(details.image.size()); |
| 170 gfx::Insets blur_region = gfx::ShadowValue::GetBlurRegion(details.values) + | |
| 171 gfx::Insets(kRoundedCornerRadius); | |
| 172 aperture.Inset(blur_region); | |
| 173 shadow_layer_->UpdateNinePatchLayerAperture(aperture); | |
| 196 | 174 |
| 197 // The content bounds in the shadow's layer space are offsetted by | 175 // The border is more or less the same inset as the aperture, but can be no |
| 198 // |interior_inset_|. The occlusion area also has to be shrunk to allow | 176 // larger than the shadow layer. |
| 199 // rounded corners overdrawing on top of the window's content. | 177 gfx::Rect border_rect(blur_region.left(), blur_region.top(), |
| 200 gfx::Rect content_bounds(interior_inset_ + kRoundedCornerRadius, | 178 blur_region.width(), blur_region.height()); |
| 201 interior_inset_ + kRoundedCornerRadius, | 179 border_rect.ClampToCenteredSize(shadow_layer_bounds.size()); |
| 202 content_bounds_.width() - 2 * kRoundedCornerRadius, | 180 shadow_layer_->UpdateNinePatchLayerBorder(border_rect); |
| 203 content_bounds_.height() - 2 * kRoundedCornerRadius); | 181 } |
|
James Cook
2016/12/05 23:38:35
I'm having a hard time following this function. Ma
Evan Stade
2016/12/06 00:53:21
no kidding. Figuring this out cost me a lot of hai
James Cook
2016/12/06 18:17:51
The new docs here help. I think adding a note abou
Evan Stade
2016/12/07 01:56:42
done, except included a CSS snippet instead of the
| |
| 204 shadow_layer_->UpdateNinePatchOcclusion(content_bounds); | 182 |
| 183 int Shadow::ElevationForStyle() { | |
| 184 switch (style_) { | |
| 185 case STYLE_ACTIVE: | |
| 186 return 24; | |
| 187 case STYLE_INACTIVE: | |
| 188 return 8; | |
| 189 case STYLE_SMALL: | |
| 190 return 6; | |
| 191 } | |
| 192 NOTREACHED(); | |
| 193 return 0; | |
| 205 } | 194 } |
| 206 | 195 |
| 207 } // namespace wm | 196 } // namespace wm |
| OLD | NEW |