Commit 0aef1fc3 authored by sadrul@chromium.org's avatar sadrul@chromium.org

overscroll: Show a shadow for the sliding window during nav gesture.

BUG=174219

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

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@182388 0039d316-1c4b-4281-b951-d872f2087c98
parent 043de5eb
......@@ -27,6 +27,7 @@
#include "content/public/browser/web_contents_view_delegate.h"
#include "content/public/browser/web_drag_dest_delegate.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h"
#include "third_party/skia/include/effects/SkGradientShader.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/client/drag_drop_client.h"
#include "ui/aura/client/drag_drop_delegate.h"
......@@ -48,6 +49,7 @@
#include "ui/gfx/image/image_png_rep.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/screen.h"
#include "ui/gfx/skia_util.h"
#include "webkit/glue/webdropdata.h"
#if defined(OS_WIN)
......@@ -66,6 +68,18 @@ WebContentsView* CreateWebContentsView(
namespace {
const SkColor kShadowLightColor = SkColorSetARGB(0x0, 0, 0, 0);
const SkColor kShadowDarkColor = SkColorSetARGB(0x70, 0, 0, 0);
const int kShadowThick = 7;
enum ShadowEdge {
SHADOW_NONE,
SHADOW_LEFT,
SHADOW_RIGHT,
SHADOW_TOP,
SHADOW_BOTTOM
};
bool ShouldNavigateForward(const NavigationController& controller,
OverscrollMode mode) {
return mode == (base::i18n::IsRTL() ? OVERSCROLL_EAST : OVERSCROLL_WEST) &&
......@@ -85,7 +99,8 @@ class OverscrollWindowDelegate : public aura::WindowDelegate {
public:
OverscrollWindowDelegate(WebContentsImpl* web_contents,
OverscrollMode overscroll_mode)
: web_contents_(web_contents) {
: web_contents_(web_contents),
show_shadow_(false) {
const NavigationControllerImpl& controller = web_contents->GetController();
const NavigationEntryImpl* entry = NULL;
if (ShouldNavigateForward(controller, overscroll_mode)) {
......@@ -106,6 +121,10 @@ class OverscrollWindowDelegate : public aura::WindowDelegate {
bool has_screenshot() const { return !image_.IsEmpty(); }
void set_show_shadow(bool show) {
show_shadow_ = show;
}
private:
virtual ~OverscrollWindowDelegate() {}
......@@ -148,10 +167,33 @@ class OverscrollWindowDelegate : public aura::WindowDelegate {
}
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
if (show_shadow_) {
canvas->Save();
canvas->Translate(gfx::Vector2d(kShadowThick, 0));
}
if (image_.IsEmpty())
canvas->DrawColor(SK_ColorGRAY);
else
canvas->DrawImageInt(image_.AsImageSkia(), 0, 0);
if (show_shadow_) {
canvas->Restore();
SkPoint points[2];
points[0].iset(0, 0);
points[1].iset(kShadowThick, 0);
SkColor colors[2] = { kShadowLightColor, kShadowDarkColor };
skia::RefPtr<SkShader> shader = skia::AdoptRef(
SkGradientShader::CreateLinear(points, colors, NULL,
arraysize(points), SkShader::kRepeat_TileMode, NULL));
SkRect rect = { SkIntToScalar(0),
SkIntToScalar(0),
SkIntToScalar(kShadowThick),
SkIntToScalar(web_contents_window()->bounds().height()) };
SkPaint paint;
paint.setShader(shader.get());
canvas->sk_canvas()->drawRect(rect, paint);
}
}
virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE {
......@@ -191,6 +233,7 @@ class OverscrollWindowDelegate : public aura::WindowDelegate {
WebContents* web_contents_;
gfx::Image image_;
bool show_shadow_;
DISALLOW_COPY_AND_ASSIGN(OverscrollWindowDelegate);
};
......@@ -403,6 +446,142 @@ int GetResistedScrollAmount(int scroll, int threshold) {
} // namespace
// ShadowWindow is used to paint shadows around a content window.
// A ShadowWindow destroys itself when the content window is destroyed, and
// updates its bounds to make sure the shadows are painted in the correct size.
class ShadowWindow : public aura::Window,
public aura::WindowObserver {
public:
explicit ShadowWindow(aura::Window* window)
: aura::Window(NULL),
window_(window),
edge_(SHADOW_NONE) {
SetType(aura::client::WINDOW_TYPE_CONTROL);
SetTransparent(true);
set_owned_by_parent(false);
Init(ui::LAYER_NOT_DRAWN);
layer()->SetMasksToBounds(false);
AddChild(window);
window_->AddObserver(this);
SetBounds(gfx::Rect(window->bounds().size()));
Show();
}
void SetShadowEdge(ShadowEdge edge) {
edge_ = edge;
if (edge_ == SHADOW_NONE) {
shadow_.reset();
return;
}
shadow_.reset(new ui::Layer(ui::LAYER_TEXTURED));
shadow_->set_delegate(this);
shadow_->SetFillsBoundsOpaquely(false);
layer()->Add(shadow_.get());
layer()->StackBelow(shadow_.get(), window_->layer());
UpdateShadowBounds();
}
private:
friend class base::DeleteHelper<content::ShadowWindow>;
virtual ~ShadowWindow() {
}
void UpdateShadowBounds() {
if (!shadow_.get())
return;
gfx::Rect bound;
switch (edge_) {
case SHADOW_LEFT:
bound.SetRect(-kShadowThick, 0, kShadowThick, bounds().height());
break;
case SHADOW_RIGHT:
bound.SetRect(bounds().right(), 0, kShadowThick, bounds().height());
break;
case SHADOW_TOP:
bound.SetRect(0, -kShadowThick, bounds().width(), kShadowThick);
break;
case SHADOW_BOTTOM:
bound.SetRect(0, bounds().bottom(), bounds().width(), kShadowThick);
break;
case SHADOW_NONE:
NOTREACHED();
}
shadow_->SetBounds(bound);
}
// Overridden from aura::WindowObserver:
virtual void OnWindowBoundsChanged(Window* window,
const gfx::Rect& old_bounds,
const gfx::Rect& new_bounds) OVERRIDE {
SetBounds(gfx::Rect(new_bounds.size()));
UpdateShadowBounds();
}
virtual void OnWindowDestroying(aura::Window* window) OVERRIDE {
DCHECK_EQ(window, window_);
window_->RemoveObserver(this);
window_ = NULL;
MessageLoop::current()->DeleteSoon(FROM_HERE, this);
}
// Overridden from ui::LayerDelegate:
virtual void OnPaintLayer(gfx::Canvas* canvas) OVERRIDE {
SkPoint points[2];
SkColor colors[2];
points[0].iset(0, 0);
switch (edge_) {
case SHADOW_LEFT:
case SHADOW_RIGHT:
points[1].iset(shadow_->bounds().width(), 0);
break;
case SHADOW_TOP:
case SHADOW_BOTTOM:
points[1].iset(0, shadow_->bounds().height());
break;
default:
NOTREACHED();
}
switch (edge_) {
case SHADOW_LEFT:
case SHADOW_TOP:
colors[0] = kShadowLightColor;
colors[1] = kShadowDarkColor;
break;
case SHADOW_RIGHT:
case SHADOW_BOTTOM:
colors[0] = kShadowDarkColor;
colors[1] = kShadowLightColor;
break;
default:
NOTREACHED();
}
skia::RefPtr<SkShader> shader = skia::AdoptRef(
SkGradientShader::CreateLinear(points, colors, NULL,
arraysize(points), SkShader::kRepeat_TileMode, NULL));
SkPaint paint;
paint.setShader(shader.get());
canvas->sk_canvas()->drawRect(gfx::RectToSkRect(bounds()), paint);
}
aura::Window* window_;
scoped_ptr<ui::Layer> shadow_;
ShadowEdge edge_;
DISALLOW_COPY_AND_ASSIGN(ShadowWindow);
};
// When a history navigation is triggered at the end of an overscroll
// navigation, it is necessary to show the history-screenshot until the page is
// done navigating and painting. This class accomplishes this by showing the
......@@ -573,6 +752,7 @@ WebContentsViewAura::WebContentsViewAura(
current_drag_op_(WebKit::WebDragOperationNone),
drag_dest_delegate_(NULL),
current_rvh_for_drag_(NULL),
content_container_(NULL),
overscroll_change_brightness_(false),
current_overscroll_gesture_(OVERSCROLL_NONE),
completed_overscroll_gesture_(OVERSCROLL_NONE) {
......@@ -629,7 +809,7 @@ void WebContentsViewAura::PrepareOverscrollWindow() {
current_overscroll_gesture_);
overscroll_window_.reset(new aura::Window(overscroll_delegate));
overscroll_window_->SetType(aura::client::WINDOW_TYPE_CONTROL);
overscroll_window_->SetTransparent(false);
overscroll_window_->SetTransparent(true);
overscroll_window_->Init(ui::LAYER_TEXTURED);
overscroll_window_->layer()->SetMasksToBounds(true);
overscroll_window_->SetName("OverscrollOverlay");
......@@ -646,10 +826,34 @@ void WebContentsViewAura::PrepareOverscrollWindow() {
bounds.Offset(base::i18n::IsRTL() ? -bounds.width() : bounds.width(), 0);
}
if (GetWindowToAnimateForOverscroll() == overscroll_window_.get())
window_->StackChildAbove(overscroll_window_.get(), GetContentNativeView());
else
window_->StackChildBelow(overscroll_window_.get(), GetContentNativeView());
if (GetWindowToAnimateForOverscroll() == overscroll_window_.get()) {
overscroll_delegate->set_show_shadow(true);
window_->StackChildAbove(overscroll_window_.get(), content_container_);
} else {
window_->StackChildBelow(overscroll_window_.get(), content_container_);
switch (current_overscroll_gesture_) {
case OVERSCROLL_EAST:
content_container_->SetShadowEdge(SHADOW_LEFT);
break;
case OVERSCROLL_WEST:
content_container_->SetShadowEdge(SHADOW_RIGHT);
break;
case OVERSCROLL_NORTH:
content_container_->SetShadowEdge(SHADOW_BOTTOM);
break;
case OVERSCROLL_SOUTH:
content_container_->SetShadowEdge(SHADOW_TOP);
break;
case OVERSCROLL_NONE:
case OVERSCROLL_COUNT:
NOTREACHED();
}
}
UpdateOverscrollWindowBrightness(0.f);
......@@ -658,7 +862,7 @@ void WebContentsViewAura::PrepareOverscrollWindow() {
}
void WebContentsViewAura::PrepareContentWindowForOverscroll() {
aura::Window* content = GetContentNativeView();
aura::Window* content = content_container_;
if (!content)
return;
......@@ -725,7 +929,7 @@ aura::Window* WebContentsViewAura::GetWindowToAnimateForOverscroll() {
return ShouldNavigateForward(web_contents_->GetController(),
current_overscroll_gesture_) ?
overscroll_window_.get() : GetContentNativeView();
overscroll_window_.get() : content_container_;
}
gfx::Vector2d WebContentsViewAura::GetTranslationForOverscroll(int delta_x,
......@@ -757,6 +961,11 @@ gfx::Vector2d WebContentsViewAura::GetTranslationForOverscroll(int delta_x,
}
void WebContentsViewAura::PrepareOverscrollNavigationOverlay() {
OverscrollWindowDelegate* delegate = static_cast<OverscrollWindowDelegate*>(
overscroll_window_->delegate());
delegate->set_show_shadow(false);
overscroll_window_->SchedulePaintInRect(
gfx::Rect(overscroll_window_->bounds().size()));
navigation_overlay_->SetOverlayWindow(overscroll_window_.Pass());
navigation_overlay_->StartObservingView(static_cast<
RenderWidgetHostViewAura*>(web_contents_->GetRenderWidgetHostView()));
......@@ -835,7 +1044,8 @@ RenderWidgetHostView* WebContentsViewAura::CreateViewForWidget(
RenderWidgetHostView* view =
RenderWidgetHostView::CreateViewForWidget(render_widget_host);
view->InitAsChild(NULL);
GetNativeView()->AddChild(view->GetNativeView());
content_container_ = new ShadowWindow(view->GetNativeView());
GetNativeView()->AddChild(content_container_);
if (navigation_overlay_.get() && navigation_overlay_->has_window()) {
navigation_overlay_->StartObservingView(static_cast<
......@@ -1105,8 +1315,9 @@ void WebContentsViewAura::OnImplicitAnimationsCompleted() {
}
if (GetContentNativeView()) {
GetContentNativeView()->SetTransform(gfx::Transform());
GetContentNativeView()->layer()->SetLayerBrightness(0.f);
content_container_->SetTransform(gfx::Transform());
content_container_->layer()->SetLayerBrightness(0.f);
content_container_->SetShadowEdge(SHADOW_NONE);
}
current_overscroll_gesture_ = OVERSCROLL_NONE;
completed_overscroll_gesture_ = OVERSCROLL_NONE;
......
......@@ -27,6 +27,7 @@ class DropTargetEvent;
namespace content {
class OverscrollNavigationOverlay;
class ShadowWindow;
class WebContentsViewDelegate;
class WebContentsImpl;
class WebDragDestDelegate;
......@@ -172,6 +173,9 @@ class CONTENT_EXPORT WebContentsViewAura
virtual int OnPerformDrop(const ui::DropTargetEvent& event) OVERRIDE;
scoped_ptr<aura::Window> window_;
// The window that shows the screenshot of the history page during an
// overscroll navigation gesture.
scoped_ptr<aura::Window> overscroll_window_;
scoped_ptr<WindowObserver> window_observer_;
......@@ -193,6 +197,10 @@ class CONTENT_EXPORT WebContentsViewAura
// pointers.
void* current_rvh_for_drag_;
// The container for the content-window. The doc for ShadowWindow explains its
// lifetime and ownership.
ShadowWindow* content_container_;
bool overscroll_change_brightness_;
// The overscroll gesture currently in progress.
......
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