1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/ui/views/frame/contents_container.h"
6
7 #include "base/logging.h"
8 #include "third_party/skia/include/core/SkColor.h"
9 #include "ui/base/animation/slide_animation.h"
10 #include "views/background.h"
11 #include "views/widget/root_view.h"
12 #include "views/widget/widget.h"
13
14 // Min/max opacity of the overlay.
15 static const int kMinOpacity = 0;
16 static const int kMaxOpacity = 192;
17
18 // View used to track when the overlay widget is destroyed. If the
19 // ContentsContainer is still valid when the destructor is invoked this invokes
20 // |OverlayViewDestroyed| on the ContentsContainer.
21 class ContentsContainer::OverlayContentView : public views::View {
22 public:
OverlayContentView(ContentsContainer * container)23 explicit OverlayContentView(ContentsContainer* container)
24 : container_(container) {
25 }
~OverlayContentView()26 ~OverlayContentView() {
27 if (container_)
28 container_->OverlayViewDestroyed();
29 }
30
Detach()31 void Detach() {
32 container_ = NULL;
33 }
34
35 private:
36 ContentsContainer* container_;
37
38 DISALLOW_COPY_AND_ASSIGN(OverlayContentView);
39 };
40
ContentsContainer(views::View * active)41 ContentsContainer::ContentsContainer(views::View* active)
42 : active_(active),
43 preview_(NULL),
44 preview_tab_contents_(NULL),
45 active_overlay_(NULL),
46 overlay_view_(NULL),
47 active_top_margin_(0) {
48 AddChildView(active_);
49 }
50
~ContentsContainer()51 ContentsContainer::~ContentsContainer() {
52 // We don't need to explicitly delete active_overlay_ as it'll be deleted by
53 // virtue of being a child window.
54 if (overlay_view_)
55 overlay_view_->Detach();
56 }
57
MakePreviewContentsActiveContents()58 void ContentsContainer::MakePreviewContentsActiveContents() {
59 DCHECK(preview_);
60 RemoveFade();
61
62 active_ = preview_;
63 preview_ = NULL;
64 Layout();
65 }
66
SetPreview(views::View * preview,TabContents * preview_tab_contents)67 void ContentsContainer::SetPreview(views::View* preview,
68 TabContents* preview_tab_contents) {
69 if (preview == preview_)
70 return;
71
72 if (preview_)
73 RemoveChildView(preview_);
74 preview_ = preview;
75 preview_tab_contents_ = preview_tab_contents;
76 if (preview_)
77 AddChildView(preview_);
78
79 Layout();
80 }
81
SetActiveTopMargin(int margin)82 void ContentsContainer::SetActiveTopMargin(int margin) {
83 if (active_top_margin_ == margin)
84 return;
85
86 active_top_margin_ = margin;
87 // Make sure we layout next time around. We need this in case our bounds
88 // haven't changed.
89 InvalidateLayout();
90 }
91
GetPreviewBounds()92 gfx::Rect ContentsContainer::GetPreviewBounds() {
93 gfx::Point screen_loc;
94 ConvertPointToScreen(this, &screen_loc);
95 return gfx::Rect(screen_loc, size());
96 }
97
FadeActiveContents()98 void ContentsContainer::FadeActiveContents() {
99 if (active_overlay_ || !ui::Animation::ShouldRenderRichAnimation())
100 return;
101
102 #if !defined(OS_WIN)
103 // TODO: fix this. I'm disabling as z-order isn't right on linux so that
104 // overlay ends up obscuring the omnibox.
105 return;
106 #endif
107
108 overlay_animation_.reset(new ui::SlideAnimation(this));
109 overlay_animation_->SetDuration(300);
110 overlay_animation_->SetSlideDuration(300);
111 overlay_animation_->Show();
112
113 CreateOverlay(kMinOpacity);
114 }
115
ShowFade()116 void ContentsContainer::ShowFade() {
117 if (active_overlay_ || !ui::Animation::ShouldRenderRichAnimation())
118 return;
119
120 CreateOverlay(kMaxOpacity);
121 }
122
RemoveFade()123 void ContentsContainer::RemoveFade() {
124 overlay_animation_.reset();
125 if (active_overlay_) {
126 overlay_view_->Detach();
127 overlay_view_ = NULL;
128 active_overlay_->Close();
129 active_overlay_ = NULL;
130 }
131 }
132
AnimationProgressed(const ui::Animation * animation)133 void ContentsContainer::AnimationProgressed(const ui::Animation* animation) {
134 active_overlay_->SetOpacity(
135 ui::Tween::ValueBetween(animation->GetCurrentValue(), kMinOpacity,
136 kMaxOpacity));
137 active_overlay_->GetRootView()->SchedulePaint();
138 }
139
Layout()140 void ContentsContainer::Layout() {
141 // The active view always gets the full bounds.
142 active_->SetBounds(0, active_top_margin_, width(),
143 std::max(0, height() - active_top_margin_));
144
145 if (preview_)
146 preview_->SetBounds(0, 0, width(), height());
147
148 // Need to invoke views::View in case any views whose bounds didn't change
149 // still need a layout.
150 views::View::Layout();
151 }
152
CreateOverlay(int initial_opacity)153 void ContentsContainer::CreateOverlay(int initial_opacity) {
154 DCHECK(!active_overlay_);
155 views::Widget::CreateParams params(views::Widget::CreateParams::TYPE_POPUP);
156 params.transparent = true;
157 params.accept_events = false;
158 active_overlay_ = views::Widget::CreateWidget(params);
159 active_overlay_->SetOpacity(initial_opacity);
160 gfx::Point screen_origin;
161 views::View::ConvertPointToScreen(active_, &screen_origin);
162 gfx::Rect overlay_bounds(screen_origin, active_->size());
163 active_overlay_->Init(active_->GetWidget()->GetNativeView(), overlay_bounds);
164 overlay_view_ = new OverlayContentView(this);
165 overlay_view_->set_background(
166 views::Background::CreateSolidBackground(SK_ColorWHITE));
167 active_overlay_->SetContentsView(overlay_view_);
168 active_overlay_->Show();
169 active_overlay_->MoveAboveWidget(active_->GetWidget());
170 }
171
OverlayViewDestroyed()172 void ContentsContainer::OverlayViewDestroyed() {
173 active_overlay_ = NULL;
174 overlay_view_ = NULL;
175 }
176