1a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved. 2a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 3a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// found in the LICENSE file. 4a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 5a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "content/browser/web_contents/aura/gesture_nav_simple.h" 6a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 7a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "cc/layers/layer.h" 8a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "content/browser/frame_host/navigation_controller_impl.h" 9a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "content/browser/renderer_host/overscroll_controller.h" 10a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "content/browser/web_contents/web_contents_impl.h" 11010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "content/browser/web_contents/web_contents_view.h" 12cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "content/public/browser/browser_thread.h" 13a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "content/public/browser/overscroll_configuration.h" 14a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "content/public/common/content_client.h" 15a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "grit/ui_resources.h" 16a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/aura/window.h" 17a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/compositor/layer.h" 18a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/compositor/layer_animation_observer.h" 19a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/compositor/layer_delegate.h" 20a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/compositor/scoped_layer_animation_settings.h" 21a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/gfx/animation/tween.h" 22a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/gfx/canvas.h" 23a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/gfx/image/image.h" 24a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 25a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)namespace content { 26a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 27a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)namespace { 28a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 29a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)const int kArrowHeight = 280; 30a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)const int kArrowWidth = 140; 31a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)const float kMinOpacity = 0.25f; 32a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 33a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool ShouldNavigateForward(const NavigationController& controller, 34a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) OverscrollMode mode) { 35a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return mode == (base::i18n::IsRTL() ? OVERSCROLL_EAST : OVERSCROLL_WEST) && 36a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) controller.CanGoForward(); 37a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 38a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 39a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool ShouldNavigateBack(const NavigationController& controller, 40a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) OverscrollMode mode) { 41a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return mode == (base::i18n::IsRTL() ? OVERSCROLL_WEST : OVERSCROLL_EAST) && 42a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) controller.CanGoBack(); 43a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 44a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 45a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// An animation observers that deletes itself and a pointer after the end of the 46a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// animation. 47a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)template <class T> 48a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)class DeleteAfterAnimation : public ui::ImplicitAnimationObserver { 49a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) public: 50a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) explicit DeleteAfterAnimation(scoped_ptr<T> object) 51a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) : object_(object.Pass()) {} 52a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 53a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) private: 54a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) friend class base::DeleteHelper<DeleteAfterAnimation<T> >; 55a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 56a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) virtual ~DeleteAfterAnimation() {} 57a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 58a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // ui::ImplicitAnimationObserver: 59a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) virtual void OnImplicitAnimationsCompleted() OVERRIDE { 60a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Deleting an observer when a ScopedLayerAnimationSettings is iterating 61a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // over them can cause a crash (which can happen during tests). So instead, 62a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // schedule this observer to be deleted soon. 63a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE, this); 64a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 65a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 66a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) scoped_ptr<T> object_; 67a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(DeleteAfterAnimation); 68a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}; 69a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 70a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} // namespace 71a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 72a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// A layer delegate that paints the shield with the arrow in it. 73a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)class ArrowLayerDelegate : public ui::LayerDelegate { 74a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) public: 75a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) explicit ArrowLayerDelegate(int resource_id) 76a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) : image_(GetContentClient()->GetNativeImageNamed(resource_id)), 77a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) left_arrow_(resource_id == IDR_BACK_ARROW) { 78a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) CHECK(!image_.IsEmpty()); 79a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 80a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 81a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) virtual ~ArrowLayerDelegate() {} 82a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 83a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) bool left() const { return left_arrow_; } 84a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 85a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) private: 86a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // ui::LayerDelegate: 87a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) virtual void OnPaintLayer(gfx::Canvas* canvas) OVERRIDE { 88a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) SkPaint paint; 89a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) paint.setColor(SkColorSetARGB(0xa0, 0, 0, 0)); 90a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) paint.setStyle(SkPaint::kFill_Style); 91a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) paint.setAntiAlias(true); 92a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 93a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) canvas->DrawCircle( 94a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) gfx::Point(left_arrow_ ? 0 : kArrowWidth, kArrowHeight / 2), 95a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) kArrowWidth, 96a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) paint); 97a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) canvas->DrawImageInt(*image_.ToImageSkia(), 98a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) left_arrow_ ? 0 : kArrowWidth - image_.Width(), 99a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) (kArrowHeight - image_.Height()) / 2); 100a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 101a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 102a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE {} 103a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 104a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) virtual base::Closure PrepareForLayerBoundsChange() OVERRIDE { 105a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return base::Closure(); 106a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 107a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 108a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) const gfx::Image& image_; 109a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) const bool left_arrow_; 110a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 111a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(ArrowLayerDelegate); 112a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}; 113a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 114a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)GestureNavSimple::GestureNavSimple(WebContentsImpl* web_contents) 115a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) : web_contents_(web_contents), 116a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) completion_threshold_(0.f) {} 117a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 118a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)GestureNavSimple::~GestureNavSimple() {} 119a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 120a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void GestureNavSimple::ApplyEffectsAndDestroy(const gfx::Transform& transform, 121a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) float opacity) { 122a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) ui::Layer* layer = arrow_.get(); 123a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) ui::ScopedLayerAnimationSettings settings(arrow_->GetAnimator()); 124a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) settings.AddObserver( 125a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) new DeleteAfterAnimation<ArrowLayerDelegate>(arrow_delegate_.Pass())); 126a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) settings.AddObserver(new DeleteAfterAnimation<ui::Layer>(arrow_.Pass())); 127a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) settings.AddObserver(new DeleteAfterAnimation<ui::Layer>(clip_layer_.Pass())); 128a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) layer->SetTransform(transform); 129a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) layer->SetOpacity(opacity); 130a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 131a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 132a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void GestureNavSimple::AbortGestureAnimation() { 133a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!arrow_) 134a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return; 135a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) gfx::Transform transform; 136a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) transform.Translate(arrow_delegate_->left() ? -kArrowWidth : kArrowWidth, 0); 137a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) ApplyEffectsAndDestroy(transform, kMinOpacity); 138a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 139a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 140a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void GestureNavSimple::CompleteGestureAnimation() { 141a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!arrow_) 142a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return; 143a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Make sure the fade-out starts from the complete state. 144a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) ApplyEffectsForDelta(completion_threshold_); 145a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) ApplyEffectsAndDestroy(arrow_->transform(), 0.f); 146a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 147a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 148a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void GestureNavSimple::ApplyEffectsForDelta(float delta_x) { 149a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!arrow_) 150a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return; 151a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) CHECK_GT(completion_threshold_, 0.f); 152a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) CHECK_GE(delta_x, 0.f); 153a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) double complete = std::min(1.f, delta_x / completion_threshold_); 154a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) float translate_x = gfx::Tween::FloatValueBetween(complete, -kArrowWidth, 0); 155a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) gfx::Transform transform; 156a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) transform.Translate(arrow_delegate_->left() ? translate_x : -translate_x, 157a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 0.f); 158a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) arrow_->SetTransform(transform); 159a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) arrow_->SetOpacity(gfx::Tween::FloatValueBetween(complete, kMinOpacity, 1.f)); 160a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 161a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 162a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)gfx::Rect GestureNavSimple::GetVisibleBounds() const { 163010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) return web_contents_->GetNativeView()->bounds(); 164a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 165a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 166a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void GestureNavSimple::OnOverscrollUpdate(float delta_x, float delta_y) { 167a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) ApplyEffectsForDelta(std::abs(delta_x) + 50.f); 168a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 169a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 170a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void GestureNavSimple::OnOverscrollComplete(OverscrollMode overscroll_mode) { 171a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) CompleteGestureAnimation(); 172a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 173a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) NavigationControllerImpl& controller = web_contents_->GetController(); 174a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (ShouldNavigateForward(controller, overscroll_mode)) 175a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) controller.GoForward(); 176a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) else if (ShouldNavigateBack(controller, overscroll_mode)) 177a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) controller.GoBack(); 178a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 179a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 180a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void GestureNavSimple::OnOverscrollModeChange(OverscrollMode old_mode, 181a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) OverscrollMode new_mode) { 182a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) NavigationControllerImpl& controller = web_contents_->GetController(); 183a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!ShouldNavigateForward(controller, new_mode) && 184a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) !ShouldNavigateBack(controller, new_mode)) { 185a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) AbortGestureAnimation(); 186a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return; 187a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 188a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 189a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) arrow_.reset(new ui::Layer(ui::LAYER_TEXTURED)); 190a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Note that RTL doesn't affect the arrow that should be displayed. 191a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) int resource_id = 0; 192a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (new_mode == OVERSCROLL_WEST) 193a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) resource_id = IDR_FORWARD_ARROW; 194a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) else if (new_mode == OVERSCROLL_EAST) 195a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) resource_id = IDR_BACK_ARROW; 196a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) else 197a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) NOTREACHED(); 198a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 199a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) arrow_delegate_.reset(new ArrowLayerDelegate(resource_id)); 200a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) arrow_->set_delegate(arrow_delegate_.get()); 201a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) arrow_->SetFillsBoundsOpaquely(false); 202a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 203010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) aura::Window* window = web_contents_->GetNativeView(); 204a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) const gfx::Rect& window_bounds = window->bounds(); 205a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) completion_threshold_ = window_bounds.width() * 206a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) GetOverscrollConfig(OVERSCROLL_CONFIG_HORIZ_THRESHOLD_COMPLETE); 207a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 208a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Align on the left or right edge. 209a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) int x = (resource_id == IDR_BACK_ARROW) ? 0 : 210a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) (window_bounds.width() - kArrowWidth); 211a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Align in the center vertically. 212a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) int y = std::max(0, (window_bounds.height() - kArrowHeight) / 2); 213a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) arrow_->SetBounds(gfx::Rect(x, y, kArrowWidth, kArrowHeight)); 214a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) ApplyEffectsForDelta(0.f); 215a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 216a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Adding the arrow as a child of the content window is not sufficient, 217a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // because it is possible for a new layer to be parented on top of the arrow 218a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // layer (e.g. when the navigated-to page is displayed while the completion 219a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // animation is in progress). So instead, a clip layer (that doesn't paint) is 220a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // installed on top of the content window as its sibling, and the arrow layer 221a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // is added to that clip layer. 222a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) clip_layer_.reset(new ui::Layer(ui::LAYER_NOT_DRAWN)); 223a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) clip_layer_->SetBounds(window->layer()->bounds()); 224a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) clip_layer_->SetMasksToBounds(true); 225a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) clip_layer_->Add(arrow_.get()); 226a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 227a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) ui::Layer* parent = window->layer()->parent(); 228a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) parent->Add(clip_layer_.get()); 229a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) parent->StackAtTop(clip_layer_.get()); 230a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 231a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 232a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} // namespace content 233