Commit d89c83ac authored by hshi's avatar hshi Committed by Commit bot

Shadows: crop corner tiles instead of hiding.

When the shadow layer bounds is smaller than the full shadow image size,
we should crop the corner tiles by reducing aperture values instead of making
the shadow layer invisible.

This allows shadow to draw correctly when window size is very small.

BUG=415514
TEST=visually verify that window shadows are drawn correctly with very small windows.

Review URL: https://codereview.chromium.org/581273002

Cr-Commit-Position: refs/heads/master@{#295728}
parent a907aee7
...@@ -598,8 +598,7 @@ void Layer::SetShowPaintedContent() { ...@@ -598,8 +598,7 @@ void Layer::SetShowPaintedContent() {
RecomputeDrawsContentAndUVRect(); RecomputeDrawsContentAndUVRect();
} }
void Layer::UpdateNinePatchLayerBitmap(const SkBitmap& bitmap, void Layer::UpdateNinePatchLayerBitmap(const SkBitmap& bitmap) {
const gfx::Rect& aperture) {
DCHECK(type_ == LAYER_NINE_PATCH && nine_patch_layer_.get()); DCHECK(type_ == LAYER_NINE_PATCH && nine_patch_layer_.get());
SkBitmap bitmap_copy; SkBitmap bitmap_copy;
if (bitmap.isImmutable()) { if (bitmap.isImmutable()) {
...@@ -610,6 +609,10 @@ void Layer::UpdateNinePatchLayerBitmap(const SkBitmap& bitmap, ...@@ -610,6 +609,10 @@ void Layer::UpdateNinePatchLayerBitmap(const SkBitmap& bitmap,
bitmap_copy.setImmutable(); bitmap_copy.setImmutable();
} }
nine_patch_layer_->SetBitmap(bitmap_copy); nine_patch_layer_->SetBitmap(bitmap_copy);
}
void Layer::UpdateNinePatchLayerAperture(const gfx::Rect& aperture) {
DCHECK(type_ == LAYER_NINE_PATCH && nine_patch_layer_.get());
nine_patch_layer_->SetAperture(aperture); nine_patch_layer_->SetAperture(aperture);
} }
......
...@@ -287,13 +287,10 @@ class COMPOSITOR_EXPORT Layer ...@@ -287,13 +287,10 @@ class COMPOSITOR_EXPORT Layer
// Sets the layer's fill color. May only be called for LAYER_SOLID_COLOR. // Sets the layer's fill color. May only be called for LAYER_SOLID_COLOR.
void SetColor(SkColor color); void SetColor(SkColor color);
// Updates the nine patch layer's bitmap and aperture. May only be called for // Updates the nine patch layer's bitmap, aperture and border. May only be
// LAYER_NINE_PATCH. // called for LAYER_NINE_PATCH.
void UpdateNinePatchLayerBitmap(const SkBitmap& bitmap, void UpdateNinePatchLayerBitmap(const SkBitmap& bitmap);
const gfx::Rect& aperture); void UpdateNinePatchLayerAperture(const gfx::Rect& aperture);
// Updates the nine patch layer's border. May only be called for
// LAYER_NINE_PATCH.
void UpdateNinePatchLayerBorder(const gfx::Rect& border); void UpdateNinePatchLayerBorder(const gfx::Rect& border);
// Adds |invalid_rect| to the Layer's pending invalid rect and calls // Adds |invalid_rect| to the Layer's pending invalid rect and calls
......
...@@ -7,6 +7,7 @@ include_rules = [ ...@@ -7,6 +7,7 @@ include_rules = [
"+ui/base/ime", "+ui/base/ime",
"+ui/base/resource", "+ui/base/resource",
"+ui/base/ui_base_switches_util.h", "+ui/base/ui_base_switches_util.h",
"+ui/base/ui_base_paths.h",
"+ui/base/ui_base_types.h", "+ui/base/ui_base_types.h",
"+ui/compositor", "+ui/compositor",
"+ui/events", "+ui/events",
......
...@@ -172,17 +172,8 @@ void Shadow::UpdateImagesForStyle() { ...@@ -172,17 +172,8 @@ void Shadow::UpdateImagesForStyle() {
break; break;
} }
// Calculate shadow aperture for style. shadow_layer_->UpdateNinePatchLayerBitmap(image.AsBitmap());
int shadow_aperture = GetShadowApertureForStyle(style_); image_size_ = image.Size();
gfx::Rect aperture(shadow_aperture,
shadow_aperture,
image.Width() - shadow_aperture * 2,
image.Height() - shadow_aperture * 2);
// Update nine-patch layer with new bitmap and aperture.
shadow_layer_->UpdateNinePatchLayerBitmap(image.AsBitmap(), aperture);
// Update interior inset for style.
interior_inset_ = GetInteriorInsetForStyle(style_); interior_inset_ = GetInteriorInsetForStyle(style_);
// Image sizes may have changed. // Image sizes may have changed.
...@@ -196,18 +187,17 @@ void Shadow::UpdateLayerBounds() { ...@@ -196,18 +187,17 @@ void Shadow::UpdateLayerBounds() {
layer()->SetBounds(layer_bounds); layer()->SetBounds(layer_bounds);
shadow_layer_->SetBounds(gfx::Rect(layer_bounds.size())); shadow_layer_->SetBounds(gfx::Rect(layer_bounds.size()));
// Calculate shadow border for style. Note that border is in layer space // Update the shadow aperture and border for style. Note that border is in
// and it cannot exceed the bounds of the layer. // layer space and it cannot exceed the bounds of the layer.
int shadow_aperture = GetShadowApertureForStyle(style_); int aperture = GetShadowApertureForStyle(style_);
gfx::Rect border(shadow_aperture, shadow_aperture, int aperture_x = std::min(aperture, layer_bounds.width() / 2);
shadow_aperture * 2, shadow_aperture * 2); int aperture_y = std::min(aperture, layer_bounds.height() / 2);
if (layer_bounds.width() < border.width() || shadow_layer_->UpdateNinePatchLayerAperture(
layer_bounds.height() < border.height()) { gfx::Rect(aperture_x, aperture_y,
shadow_layer_->SetVisible(false); image_size_.width() - aperture_x * 2,
} else { image_size_.height() - aperture_y * 2));
shadow_layer_->SetVisible(true); shadow_layer_->UpdateNinePatchLayerBorder(
shadow_layer_->UpdateNinePatchLayerBorder(border); gfx::Rect(aperture_x, aperture_y, aperture_x * 2, aperture_y * 2));
}
} }
} // namespace wm } // namespace wm
...@@ -74,6 +74,9 @@ class WM_EXPORT Shadow : public ui::ImplicitAnimationObserver { ...@@ -74,6 +74,9 @@ class WM_EXPORT Shadow : public ui::ImplicitAnimationObserver {
// The actual shadow layer corresponding to a cc::NinePatchLayer. // The actual shadow layer corresponding to a cc::NinePatchLayer.
scoped_ptr<ui::Layer> shadow_layer_; scoped_ptr<ui::Layer> shadow_layer_;
// Size of the current shadow image.
gfx::Size image_size_;
// Bounds of the content that the shadow encloses. // Bounds of the content that the shadow encloses.
gfx::Rect content_bounds_; gfx::Rect content_bounds_;
......
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/wm/core/shadow.h"
#include "base/memory/scoped_ptr.h"
#include "base/path_service.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/aura/test/aura_test_base.h"
#include "ui/aura/test/test_windows.h"
#include "ui/aura/window.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/base/ui_base_paths.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/layer_tree_owner.h"
#include "ui/resources/grit/ui_resources.h"
namespace wm {
namespace {
const int kSmallBitmapSize = 129;
const int kLargeBitmapSize = 269;
// Mock for the ResourceBundle::Delegate class.
class MockResourceBundleDelegate : public ui::ResourceBundle::Delegate {
public:
MockResourceBundleDelegate() : last_resource_id_(0) {
SkBitmap bitmap_small, bitmap_large;
bitmap_small.allocPixels(
SkImageInfo::MakeN32Premul(kSmallBitmapSize, kSmallBitmapSize));
bitmap_large.allocPixels(
SkImageInfo::MakeN32Premul(kLargeBitmapSize, kLargeBitmapSize));
image_small_ = gfx::Image::CreateFrom1xBitmap(bitmap_small);
image_large_ = gfx::Image::CreateFrom1xBitmap(bitmap_large);
}
virtual ~MockResourceBundleDelegate() {}
// ResourceBundle::Delegate:
virtual base::FilePath GetPathForResourcePack(
const base::FilePath& pack_path,
ui::ScaleFactor scale_factor) OVERRIDE {
return base::FilePath();
}
virtual base::FilePath GetPathForLocalePack(
const base::FilePath& pack_path,
const std::string& locale) OVERRIDE {
return base::FilePath();
}
virtual gfx::Image GetImageNamed(int resource_id) OVERRIDE {
last_resource_id_ = resource_id;
switch (resource_id) {
case IDR_WINDOW_BUBBLE_SHADOW_SMALL:
return image_small_;
case IDR_AURA_SHADOW_ACTIVE:
case IDR_AURA_SHADOW_INACTIVE:
return image_large_;
default:
NOTREACHED();
return gfx::Image();
}
}
virtual gfx::Image GetNativeImageNamed(
int resource_id, ui::ResourceBundle::ImageRTL rtl) OVERRIDE {
return gfx::Image();
}
virtual base::RefCountedStaticMemory* LoadDataResourceBytes(
int resource_id, ui::ScaleFactor scale_factor) OVERRIDE {
return NULL;
}
virtual bool GetRawDataResource(
int resource_id, ui::ScaleFactor scale_factor,
base::StringPiece* value) OVERRIDE {
return false;
}
virtual bool GetLocalizedString(
int message_id, base::string16* value) OVERRIDE {
return false;
}
virtual scoped_ptr<gfx::Font> GetFont(
ui::ResourceBundle::FontStyle style) OVERRIDE {
return scoped_ptr<gfx::Font>();
}
int last_resource_id() const { return last_resource_id_; }
private:
gfx::Image image_small_;
gfx::Image image_large_;
int last_resource_id_;
DISALLOW_COPY_AND_ASSIGN(MockResourceBundleDelegate);
};
} // namespace
class ShadowTest: public aura::test::AuraTestBase {
public:
ShadowTest() {}
virtual ~ShadowTest() {}
MockResourceBundleDelegate* delegate() { return delegate_.get(); }
// aura::testAuraBase:
virtual void SetUp() OVERRIDE {
aura::test::AuraTestBase::SetUp();
delegate_.reset(new MockResourceBundleDelegate());
if (ResourceBundle::HasSharedInstance())
ui::ResourceBundle::CleanupSharedInstance();
ui::ResourceBundle::InitSharedInstanceWithLocale(
"en-US", delegate(), ui::ResourceBundle::LOAD_COMMON_RESOURCES);
}
virtual void TearDown() OVERRIDE {
ui::ResourceBundle::CleanupSharedInstance();
base::FilePath ui_test_pak_path;
ASSERT_TRUE(PathService::Get(ui::UI_TEST_PAK, &ui_test_pak_path));
ui::ResourceBundle::InitSharedInstanceWithPakPath(ui_test_pak_path);
aura::test::AuraTestBase::TearDown();
}
private:
scoped_ptr<MockResourceBundleDelegate> delegate_;
DISALLOW_COPY_AND_ASSIGN(ShadowTest);
};
// Test if the proper image is set for the specified style.
TEST_F(ShadowTest, UpdateImagesForStyle) {
Shadow shadow;
shadow.Init(Shadow::STYLE_SMALL);
EXPECT_EQ(delegate()->last_resource_id(), IDR_WINDOW_BUBBLE_SHADOW_SMALL);
shadow.SetStyle(Shadow::STYLE_ACTIVE);
EXPECT_EQ(delegate()->last_resource_id(), IDR_AURA_SHADOW_ACTIVE);
shadow.SetStyle(Shadow::STYLE_INACTIVE);
EXPECT_EQ(delegate()->last_resource_id(), IDR_AURA_SHADOW_INACTIVE);
}
// Test if the proper content bounds is calculated based on the current style.
TEST_F(ShadowTest, SetContentBounds) {
Shadow shadow;
// Verify that layer bounds are inset from content bounds.
shadow.Init(Shadow::STYLE_ACTIVE);
gfx::Rect content_bounds(100, 100, 300, 300);
shadow.SetContentBounds(content_bounds);
EXPECT_EQ(shadow.content_bounds(), content_bounds);
EXPECT_EQ(shadow.layer()->bounds(), gfx::Rect(36, 36, 428, 428));
shadow.SetStyle(Shadow::STYLE_SMALL);
EXPECT_EQ(shadow.content_bounds(), content_bounds);
EXPECT_EQ(shadow.layer()->bounds(), gfx::Rect(96, 96, 308, 308));
}
} // namespace wm
...@@ -142,6 +142,7 @@ ...@@ -142,6 +142,7 @@
'core/image_grid_unittest.cc', 'core/image_grid_unittest.cc',
'core/nested_accelerator_controller_unittest.cc', 'core/nested_accelerator_controller_unittest.cc',
'core/shadow_controller_unittest.cc', 'core/shadow_controller_unittest.cc',
'core/shadow_unittest.cc',
'core/transient_window_manager_unittest.cc', 'core/transient_window_manager_unittest.cc',
'core/transient_window_stacking_client_unittest.cc', 'core/transient_window_stacking_client_unittest.cc',
'core/user_activity_detector_unittest.cc', 'core/user_activity_detector_unittest.cc',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment