Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(55)

Side by Side Diff: ui/wm/core/shadow.cc

Issue 2550593002: Update WM shadows for MD. (Closed)
Patch Set: fix corners Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698