| Index: ui/wm/core/shadow.cc
|
| diff --git a/ui/wm/core/shadow.cc b/ui/wm/core/shadow.cc
|
| index 78853435c6cc81720b66c08c0bf0c2268b8b885b..83190954208d81601426d32d89684697b7b71fb6 100644
|
| --- a/ui/wm/core/shadow.cc
|
| +++ b/ui/wm/core/shadow.cc
|
| @@ -4,11 +4,14 @@
|
|
|
| #include "ui/wm/core/shadow.h"
|
|
|
| -#include "third_party/skia/include/core/SkBitmap.h"
|
| +#include "base/lazy_instance.h"
|
| #include "ui/base/resource/resource_bundle.h"
|
| #include "ui/compositor/layer.h"
|
| #include "ui/compositor/scoped_layer_animation_settings.h"
|
| -#include "ui/resources/grit/ui_resources.h"
|
| +#include "ui/gfx/geometry/insets.h"
|
| +#include "ui/gfx/image/image_skia_operations.h"
|
| +
|
| +namespace wm {
|
|
|
| namespace {
|
|
|
| @@ -16,18 +19,6 @@ namespace {
|
| // inactive/active shadow.
|
| const float kInactiveShadowAnimationOpacity = 0.2f;
|
|
|
| -// Shadow aperture for different styles.
|
| -// Note that this may be greater than interior inset to allow shadows with
|
| -// curved corners that extend inwards beyond a window's borders.
|
| -const int kActiveInteriorAperture = 134;
|
| -const int kInactiveInteriorAperture = 134;
|
| -const int kSmallInteriorAperture = 9;
|
| -
|
| -// Interior inset for different styles.
|
| -const int kActiveInteriorInset = 64;
|
| -const int kInactiveInteriorInset = 64;
|
| -const int kSmallInteriorInset = 4;
|
| -
|
| // Rounded corners are overdrawn on top of the window's content layer,
|
| // we need to exclude them from the occlusion area.
|
| const int kRoundedCornerRadius = 2;
|
| @@ -35,39 +26,50 @@ const int kRoundedCornerRadius = 2;
|
| // Duration for opacity animation in milliseconds.
|
| const int kShadowAnimationDurationMs = 100;
|
|
|
| -int GetShadowApertureForStyle(wm::Shadow::Style style) {
|
| - switch (style) {
|
| - case wm::Shadow::STYLE_ACTIVE:
|
| - return kActiveInteriorAperture;
|
| - case wm::Shadow::STYLE_INACTIVE:
|
| - return kInactiveInteriorAperture;
|
| - case wm::Shadow::STYLE_SMALL:
|
| - return kSmallInteriorAperture;
|
| - }
|
| - return 0;
|
| -}
|
| -
|
| -int GetInteriorInsetForStyle(wm::Shadow::Style style) {
|
| - switch (style) {
|
| - case wm::Shadow::STYLE_ACTIVE:
|
| - return kActiveInteriorInset;
|
| - case wm::Shadow::STYLE_INACTIVE:
|
| - return kInactiveInteriorInset;
|
| - case wm::Shadow::STYLE_SMALL:
|
| - return kSmallInteriorInset;
|
| - }
|
| - return 0;
|
| +struct ShadowDetails {
|
| + // Description of the shadows.
|
| + gfx::ShadowValues values;
|
| + // Cached ninebox image based on |values|.
|
| + gfx::ImageSkia ninebox_image;
|
| +};
|
| +
|
| +// Map from elevation to a cached shadow.
|
| +using ShadowDetailsMap = std::map<int, ShadowDetails>;
|
| +base::LazyInstance<ShadowDetailsMap> g_shadow_cache = LAZY_INSTANCE_INITIALIZER;
|
| +
|
| +const ShadowDetails& GetDetailsForElevation(int elevation) {
|
| + auto iter = g_shadow_cache.Get().find(elevation);
|
| + if (iter != g_shadow_cache.Get().end())
|
| + return iter->second;
|
| +
|
| + auto insertion =
|
| + g_shadow_cache.Get().insert(std::make_pair(elevation, ShadowDetails()));
|
| + DCHECK(insertion.second);
|
| + ShadowDetails* shadow = &insertion.first->second;
|
| + // To match the CSS notion of blur (spread outside the bounding box) to the
|
| + // Skia notion of blur (spread outside and inside the bounding box), we have
|
| + // to double the designer-provided blur values.
|
| + const int kBlurCorrection = 2;
|
| + // "Key shadow": y offset is elevation and blur is twice the elevation.
|
| + shadow->values.emplace_back(gfx::Vector2d(0, elevation),
|
| + kBlurCorrection * elevation * 2,
|
| + SkColorSetA(SK_ColorBLACK, 0x3d));
|
| + // "Ambient shadow": no offset and blur matches the elevation.
|
| + shadow->values.emplace_back(gfx::Vector2d(), kBlurCorrection * elevation,
|
| + SkColorSetA(SK_ColorBLACK, 0x1f));
|
| + // To see what this looks like for elevation 24, try this CSS:
|
| + // box-shadow: 0 24px 48px rgba(0, 0, 0, .24),
|
| + // 0 0 24px rgba(0, 0, 0, .12);
|
| + shadow->ninebox_image = gfx::ImageSkiaOperations::CreateShadowNinebox(
|
| + shadow->values, kRoundedCornerRadius);
|
| + return *shadow;
|
| }
|
|
|
| } // namespace
|
|
|
| -namespace wm {
|
| +Shadow::Shadow() {}
|
|
|
| -Shadow::Shadow() : style_(STYLE_ACTIVE), interior_inset_(0) {
|
| -}
|
| -
|
| -Shadow::~Shadow() {
|
| -}
|
| +Shadow::~Shadow() {}
|
|
|
| void Shadow::Init(Style style) {
|
| style_ = style;
|
| @@ -149,59 +151,61 @@ void Shadow::OnImplicitAnimationsCompleted() {
|
| }
|
|
|
| void Shadow::UpdateImagesForStyle() {
|
| - ResourceBundle& res = ResourceBundle::GetSharedInstance();
|
| - gfx::Image image;
|
| - switch (style_) {
|
| - case STYLE_ACTIVE:
|
| - image = res.GetImageNamed(IDR_AURA_SHADOW_ACTIVE);
|
| - break;
|
| - case STYLE_INACTIVE:
|
| - image = res.GetImageNamed(IDR_AURA_SHADOW_INACTIVE);
|
| - break;
|
| - case STYLE_SMALL:
|
| - image = res.GetImageNamed(IDR_WINDOW_BUBBLE_SHADOW_SMALL);
|
| - break;
|
| - default:
|
| - NOTREACHED() << "Unhandled style " << style_;
|
| - break;
|
| - }
|
| -
|
| - shadow_layer_->UpdateNinePatchLayerImage(image.AsImageSkia());
|
| - image_size_ = image.Size();
|
| - interior_inset_ = GetInteriorInsetForStyle(style_);
|
| -
|
| - // Image sizes may have changed.
|
| + const ShadowDetails& details = GetDetailsForElevation(ElevationForStyle());
|
| + shadow_layer_->UpdateNinePatchLayerImage(details.ninebox_image);
|
| + // The ninebox grid is defined in terms of the image size. The shadow blurs in
|
| + // both inward and outward directions from the edge of the contents, so the
|
| + // aperture goes further inside the image than the shadow margins (which
|
| + // represent exterior blur).
|
| + gfx::Rect aperture(details.ninebox_image.size());
|
| + gfx::Insets blur_region = gfx::ShadowValue::GetBlurRegion(details.values) +
|
| + gfx::Insets(kRoundedCornerRadius);
|
| + aperture.Inset(blur_region);
|
| + shadow_layer_->UpdateNinePatchLayerAperture(aperture);
|
| UpdateLayerBounds();
|
| }
|
|
|
| void Shadow::UpdateLayerBounds() {
|
| - // Update bounds based on content bounds and interior inset.
|
| + const ShadowDetails& details = GetDetailsForElevation(ElevationForStyle());
|
| + // Shadow margins are negative, so this expands outwards from
|
| + // |content_bounds_|.
|
| + const gfx::Insets margins = gfx::ShadowValue::GetMargin(details.values);
|
| gfx::Rect layer_bounds = content_bounds_;
|
| - layer_bounds.Inset(-interior_inset_, -interior_inset_);
|
| + layer_bounds.Inset(margins);
|
| layer()->SetBounds(layer_bounds);
|
| - shadow_layer_->SetBounds(gfx::Rect(layer_bounds.size()));
|
| -
|
| - // Update the shadow aperture and border for style. Note that border is in
|
| - // layer space and it cannot exceed the bounds of the layer.
|
| - int aperture = GetShadowApertureForStyle(style_);
|
| - int aperture_x = std::min(aperture, layer_bounds.width() / 2);
|
| - int aperture_y = std::min(aperture, layer_bounds.height() / 2);
|
| - gfx::Rect aperture_rect(aperture_x, aperture_y,
|
| - image_size_.width() - aperture_x * 2,
|
| - image_size_.height() - aperture_y * 2);
|
| -
|
| - shadow_layer_->UpdateNinePatchLayerAperture(aperture_rect);
|
| + const gfx::Rect shadow_layer_bounds(layer_bounds.size());
|
| + shadow_layer_->SetBounds(shadow_layer_bounds);
|
| +
|
| + // Occlude the region inside the bounding box. Occlusion uses shadow layer
|
| + // space. See nine_patch_layer.h for more context on what's going on here.
|
| + gfx::Rect occlusion_bounds = shadow_layer_bounds;
|
| + occlusion_bounds.Inset(-margins + gfx::Insets(kRoundedCornerRadius));
|
| + shadow_layer_->UpdateNinePatchOcclusion(occlusion_bounds);
|
| +
|
| + // The border is more or less the same inset as the aperture, but can be no
|
| + // larger than the shadow layer. When the shadow layer is too small, shrink
|
| + // the dimensions proportionally.
|
| + gfx::Insets blur_region = gfx::ShadowValue::GetBlurRegion(details.values) +
|
| + gfx::Insets(kRoundedCornerRadius);
|
| + int border_w = std::min(blur_region.width(), shadow_layer_bounds.width());
|
| + int border_x = border_w * blur_region.left() / blur_region.width();
|
| + int border_h = std::min(blur_region.height(), shadow_layer_bounds.height());
|
| + int border_y = border_h * blur_region.top() / blur_region.height();
|
| shadow_layer_->UpdateNinePatchLayerBorder(
|
| - gfx::Rect(aperture_x, aperture_y, aperture_x * 2, aperture_y * 2));
|
| -
|
| - // The content bounds in the shadow's layer space are offsetted by
|
| - // |interior_inset_|. The occlusion area also has to be shrunk to allow
|
| - // rounded corners overdrawing on top of the window's content.
|
| - gfx::Rect content_bounds(interior_inset_ + kRoundedCornerRadius,
|
| - interior_inset_ + kRoundedCornerRadius,
|
| - content_bounds_.width() - 2 * kRoundedCornerRadius,
|
| - content_bounds_.height() - 2 * kRoundedCornerRadius);
|
| - shadow_layer_->UpdateNinePatchOcclusion(content_bounds);
|
| + gfx::Rect(border_x, border_y, border_w, border_h));
|
| +}
|
| +
|
| +int Shadow::ElevationForStyle() {
|
| + switch (style_) {
|
| + case STYLE_ACTIVE:
|
| + return 24;
|
| + case STYLE_INACTIVE:
|
| + return 8;
|
| + case STYLE_SMALL:
|
| + return 6;
|
| + }
|
| + NOTREACHED();
|
| + return 0;
|
| }
|
|
|
| } // namespace wm
|
|
|