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

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

Issue 2550593002: Update WM shadows for MD. (Closed)
Patch Set: improve legibility 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 // Description of the shadows.
40 case wm::Shadow::STYLE_ACTIVE: 31 gfx::ShadowValues values;
41 return kActiveInteriorAperture; 32 // Cached ninebox image based on |values|.
42 case wm::Shadow::STYLE_INACTIVE: 33 gfx::ImageSkia ninebox_image;
43 return kInactiveInteriorAperture; 34 };
44 case wm::Shadow::STYLE_SMALL:
45 return kSmallInteriorAperture;
46 }
47 return 0;
48 }
49 35
50 int GetInteriorInsetForStyle(wm::Shadow::Style style) { 36 // Map from elevation to a cached shadow.
51 switch (style) { 37 typedef std::map<int, ShadowDetails> ShadowDetailsMap;
sky 2016/12/07 16:39:32 using
Evan Stade 2016/12/07 18:55:00 Done.
52 case wm::Shadow::STYLE_ACTIVE: 38 base::LazyInstance<ShadowDetailsMap> g_shadow_cache = LAZY_INSTANCE_INITIALIZER;
53 return kActiveInteriorInset; 39
54 case wm::Shadow::STYLE_INACTIVE: 40 const ShadowDetails& GetDetailsForElevation(int elevation) {
55 return kInactiveInteriorInset; 41 auto iter = g_shadow_cache.Get().find(elevation);
56 case wm::Shadow::STYLE_SMALL: 42 if (iter != g_shadow_cache.Get().end())
57 return kSmallInteriorInset; 43 return iter->second;
58 } 44
59 return 0; 45 auto insertion =
46 g_shadow_cache.Get().insert(std::make_pair(elevation, ShadowDetails()));
47 DCHECK(insertion.second);
48 ShadowDetails* shadow = &insertion.first->second;
49 // To match the CSS notion of blur (spread outside the bounding box) to the
50 // Skia notion of blur (spread outside and inside the bounding box), we have
51 // to double the designer-provided blur values.
52 const int kBlurCorrection = 2;
53 // "Key shadow": y offset is elevation and blur is twice the elevation.
54 shadow->values.emplace_back(gfx::Vector2d(0, elevation),
55 kBlurCorrection * elevation * 2,
56 SkColorSetA(SK_ColorBLACK, 0x3d));
57 // "Ambient shadow": no offset and blur matches the elevation.
58 shadow->values.emplace_back(gfx::Vector2d(), kBlurCorrection * elevation,
59 SkColorSetA(SK_ColorBLACK, 0x1f));
60 // To see what this looks like for elevation 24, try this CSS:
61 // box-shadow: 0 24px 48px rgba(0, 0, 0, .24),
62 // 0 0 24px rgba(0, 0, 0, .12);
63 shadow->ninebox_image = gfx::ImageSkiaOperations::CreateShadowNinebox(
64 shadow->values, kRoundedCornerRadius);
65 return *shadow;
60 } 66 }
61 67
62 } // namespace 68 } // namespace
63 69
64 namespace wm { 70 Shadow::Shadow() {}
65 71
66 Shadow::Shadow() : style_(STYLE_ACTIVE), interior_inset_(0) { 72 Shadow::~Shadow() {}
67 }
68
69 Shadow::~Shadow() {
70 }
71 73
72 void Shadow::Init(Style style) { 74 void Shadow::Init(Style style) {
73 style_ = style; 75 style_ = style;
74 76
75 layer_.reset(new ui::Layer(ui::LAYER_NOT_DRAWN)); 77 layer_.reset(new ui::Layer(ui::LAYER_NOT_DRAWN));
76 shadow_layer_.reset(new ui::Layer(ui::LAYER_NINE_PATCH)); 78 shadow_layer_.reset(new ui::Layer(ui::LAYER_NINE_PATCH));
77 layer()->Add(shadow_layer_.get()); 79 layer()->Add(shadow_layer_.get());
78 80
79 UpdateImagesForStyle(); 81 UpdateImagesForStyle();
80 shadow_layer_->set_name("Shadow"); 82 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 144 // If we just finished going inactive, switch images. This doesn't cause
143 // a visual pop because the inactive image opacity is so low. 145 // a visual pop because the inactive image opacity is so low.
144 if (style_ == STYLE_INACTIVE) { 146 if (style_ == STYLE_INACTIVE) {
145 UpdateImagesForStyle(); 147 UpdateImagesForStyle();
146 // Opacity is baked into inactive image, so set fully opaque. 148 // Opacity is baked into inactive image, so set fully opaque.
147 shadow_layer_->SetOpacity(1.0f); 149 shadow_layer_->SetOpacity(1.0f);
148 } 150 }
149 } 151 }
150 152
151 void Shadow::UpdateImagesForStyle() { 153 void Shadow::UpdateImagesForStyle() {
152 ResourceBundle& res = ResourceBundle::GetSharedInstance(); 154 const ShadowDetails& details = GetDetailsForElevation(ElevationForStyle());
153 gfx::Image image; 155 shadow_layer_->UpdateNinePatchLayerImage(details.ninebox_image);
154 switch (style_) {
155 case STYLE_ACTIVE:
156 image = res.GetImageNamed(IDR_AURA_SHADOW_ACTIVE);
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(); 156 UpdateLayerBounds();
175 } 157 }
176 158
177 void Shadow::UpdateLayerBounds() { 159 void Shadow::UpdateLayerBounds() {
178 // Update bounds based on content bounds and interior inset. 160 const ShadowDetails& details = GetDetailsForElevation(ElevationForStyle());
161 // Shadow margins are negative, so this expands outwards from
162 // |content_bounds_|.
163 const gfx::Insets margins = gfx::ShadowValue::GetMargin(details.values);
179 gfx::Rect layer_bounds = content_bounds_; 164 gfx::Rect layer_bounds = content_bounds_;
180 layer_bounds.Inset(-interior_inset_, -interior_inset_); 165 layer_bounds.Inset(margins);
181 layer()->SetBounds(layer_bounds); 166 layer()->SetBounds(layer_bounds);
182 shadow_layer_->SetBounds(gfx::Rect(layer_bounds.size())); 167 gfx::Rect shadow_layer_bounds(layer_bounds.size());
168 shadow_layer_->SetBounds(shadow_layer_bounds);
183 169
184 // Update the shadow aperture and border for style. Note that border is in 170 // Occlude the region inside the bounding box. Occlusion uses shadow layer
185 // layer space and it cannot exceed the bounds of the layer. 171 // space. See nine_patch_layer.h for more context on what's going on here.
186 int aperture = GetShadowApertureForStyle(style_); 172 gfx::Rect occlusion_bounds = shadow_layer_bounds;
187 int aperture_x = std::min(aperture, layer_bounds.width() / 2); 173 occlusion_bounds.Inset(-margins + gfx::Insets(kRoundedCornerRadius));
188 int aperture_y = std::min(aperture, layer_bounds.height() / 2); 174 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 175
193 shadow_layer_->UpdateNinePatchLayerAperture(aperture_rect); 176 // The ninebox grid is defined in terms of the image size. The shadow blurs in
194 shadow_layer_->UpdateNinePatchLayerBorder( 177 // both inward and outward directions from the edge of the contents, so the
195 gfx::Rect(aperture_x, aperture_y, aperture_x * 2, aperture_y * 2)); 178 // aperture goes further inside the image than the shadow margins (which
179 // represent exterior blur).
180 gfx::Rect aperture(details.ninebox_image.size());
181 gfx::Insets blur_region = gfx::ShadowValue::GetBlurRegion(details.values) +
182 gfx::Insets(kRoundedCornerRadius);
183 aperture.Inset(blur_region);
184 shadow_layer_->UpdateNinePatchLayerAperture(aperture);
196 185
197 // The content bounds in the shadow's layer space are offsetted by 186 // 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 187 // larger than the shadow layer.
199 // rounded corners overdrawing on top of the window's content. 188 gfx::Rect border_rect(blur_region.left(), blur_region.top(),
200 gfx::Rect content_bounds(interior_inset_ + kRoundedCornerRadius, 189 blur_region.width(), blur_region.height());
201 interior_inset_ + kRoundedCornerRadius, 190 border_rect.ClampToCenteredSize(shadow_layer_bounds.size());
202 content_bounds_.width() - 2 * kRoundedCornerRadius, 191 shadow_layer_->UpdateNinePatchLayerBorder(border_rect);
203 content_bounds_.height() - 2 * kRoundedCornerRadius); 192 }
204 shadow_layer_->UpdateNinePatchOcclusion(content_bounds); 193
194 int Shadow::ElevationForStyle() {
195 switch (style_) {
196 case STYLE_ACTIVE:
197 return 24;
198 case STYLE_INACTIVE:
199 return 8;
200 case STYLE_SMALL:
201 return 6;
202 }
203 NOTREACHED();
204 return 0;
205 } 205 }
206 206
207 } // namespace wm 207 } // namespace wm
OLDNEW
« ui/wm/core/shadow.h ('K') | « ui/wm/core/shadow.h ('k') | ui/wm/core/shadow_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698