Index: content/browser/web_contents/web_contents_view_aura.cc |
diff --git a/content/browser/web_contents/web_contents_view_aura.cc b/content/browser/web_contents/web_contents_view_aura.cc |
index 83362893595a346a6ebd0406de641e10d746c366..bee2a646967ade63fa9efc2bbacdeae3d4a21783 100644 |
--- a/content/browser/web_contents/web_contents_view_aura.cc |
+++ b/content/browser/web_contents/web_contents_view_aura.cc |
@@ -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; |