- add sources.
[platform/framework/web/crosswalk.git] / src / chrome_frame / infobars / internal / infobar_window.cc
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 // Implementation of the manager for infobar windows.
6
7 #include "chrome_frame/infobars/internal/infobar_window.h"
8
9 #include <algorithm>
10
11 #include "base/compiler_specific.h"
12 #include "base/logging.h"
13 #include "chrome_frame/function_stub.h"
14
15 namespace {
16
17 // length of each step when opening or closing
18 const UINT kInfobarSlidingTimerIntervalMs = 50U;
19 // pixels per step, when opening or closing
20 const int kInfobarSlideOpenStep = 2;
21 const int kInfobarSlideCloseStep = 6;
22
23 }  // namespace
24
25 VOID CALLBACK OnSliderTimer(InfobarWindow::Host* host,
26                             HWND /*hwnd*/, UINT /*uMsg*/,
27                             UINT_PTR /*idEvent*/, DWORD /*dwTime*/) {
28   if (host)
29     host->UpdateLayout();
30 }
31
32 InfobarWindow::InfobarWindow(InfobarType type)
33     : type_(type),
34       host_(NULL),
35       target_height_(0),
36       initial_height_(0),
37       current_height_(0),
38       current_width_(0),
39       timer_id_(0),
40       timer_stub_(NULL),
41       frame_impl_(this) {
42   DCHECK(type_ >= FIRST_INFOBAR_TYPE);
43   DCHECK(type_ < END_OF_INFOBAR_TYPE);
44 }
45
46 InfobarWindow::~InfobarWindow() {
47   if (StopTimer() && timer_stub_ != NULL)
48     FunctionStub::Destroy(timer_stub_);
49   else if (timer_stub_ != NULL)
50     timer_stub_->set_argument(NULL);  // Couldn't stop it, so orphan and disable
51 }
52
53 void InfobarWindow::SetHost(Host* host) {
54   DCHECK(host_ == NULL);
55   DCHECK(timer_stub_ == NULL);
56   DCHECK(host != NULL);
57   host_ = host;
58   timer_stub_ = FunctionStub::Create(reinterpret_cast<uintptr_t>(host),
59                                      OnSliderTimer);
60 }
61
62 bool InfobarWindow::Show(InfobarContent* content) {
63   DCHECK(host_ != NULL);
64   if (host_ == NULL)
65     return false;
66
67   scoped_ptr<InfobarContent> new_content(content);
68   content_.reset();
69
70   if (!new_content->InstallInFrame(&frame_impl_))
71     return false;
72
73   // Force a call to ReserveSpace, which will capture the width of the displaced
74   // window.
75   if (current_width_ == 0)
76     host_->UpdateLayout();
77   if (current_width_ == 0)
78     return false;  // Might not be any displaced window.. then we can't display.
79
80   content_.swap(new_content);
81   StartSlidingTowards(content_->GetDesiredSize(current_width_, 0));
82
83   return true;
84 }
85
86 void InfobarWindow::Hide() {
87   DCHECK(host_ != NULL);
88   if (host_ == NULL)
89     return;
90
91   StartSlidingTowards(0);
92 }
93
94 void InfobarWindow::ReserveSpace(RECT* rect) {
95   DCHECK(rect);
96   DCHECK(host_ != NULL);
97   if (rect == NULL || host_ == NULL)
98     return;
99
100   current_width_ = rect->right - rect->left;
101   current_height_ = CalculateHeight();
102
103   RECT infobar_rect = *rect;
104
105   switch (type_) {
106     case TOP_INFOBAR:
107       infobar_rect.bottom = rect->top + current_height_;
108       rect->top = std::min(rect->bottom, infobar_rect.bottom);
109       break;
110     case BOTTOM_INFOBAR:
111       infobar_rect.top = rect->bottom - current_height_;
112       rect->bottom = std::max(rect->top, infobar_rect.top);
113       break;
114     default:
115       NOTREACHED() << "Unknown InfobarType value.";
116       break;
117   }
118
119   if (content_ != NULL)
120     content_->SetDimensions(infobar_rect);
121
122   // Done sliding?
123   if (current_height_ == target_height_) {
124     StopTimer();
125     if (current_height_ == 0)
126       content_.reset();
127   }
128 }
129
130 void InfobarWindow::StartSlidingTowards(int target_height) {
131   initial_height_ = current_height_;
132   target_height_ = target_height;
133
134   if (StartTimer())
135     slide_start_ = base::Time::Now();
136   else
137     slide_start_ = base::Time();  // NULL time means don't slide, resize now
138
139   // Trigger an immediate re-laying out. The timer will handle remaining steps.
140   host_->UpdateLayout();
141 }
142
143 bool InfobarWindow::StartTimer() {
144   if (timer_id_ != 0)
145     return true;
146
147   DCHECK(timer_stub_ != NULL);
148   if (timer_stub_ == NULL)
149     return false;
150
151   timer_id_ = ::SetTimer(NULL,
152                          timer_id_,
153                          kInfobarSlidingTimerIntervalMs,
154                          reinterpret_cast<TIMERPROC>(timer_stub_->code()));
155
156   DPLOG_IF(ERROR, timer_id_ == 0) << "Failure in SetTimer.";
157
158   return timer_id_ != 0;
159 }
160
161 bool InfobarWindow::StopTimer() {
162   if (timer_id_ == 0)
163     return true;
164
165   if (::KillTimer(NULL, timer_id_)) {
166     timer_id_ = 0;
167     return true;
168   }
169
170   DPLOG(ERROR) << "Failure in KillTimer.";
171   return false;
172 }
173
174 int InfobarWindow::CalculateHeight() {
175   if (slide_start_.is_null())
176     return target_height_;
177
178   base::TimeDelta elapsed = base::Time::Now() - slide_start_;
179   int elapsed_steps = static_cast<int>(elapsed.InMilliseconds()) /
180                       kInfobarSlidingTimerIntervalMs;
181
182   if (initial_height_ < target_height_) {
183     return std::min(initial_height_ + elapsed_steps * kInfobarSlideOpenStep,
184                     target_height_);
185   } else if (initial_height_ > target_height_) {
186     return std::max(initial_height_ - elapsed_steps * kInfobarSlideCloseStep,
187                     target_height_);
188   } else {
189     return target_height_;
190   }
191 }
192
193 InfobarWindow::FrameImpl::FrameImpl(InfobarWindow* infobar_window)
194     : infobar_window_(infobar_window) {
195 }
196
197 HWND InfobarWindow::FrameImpl::GetFrameWindow() {
198   return infobar_window_->host_->GetContainerWindow();
199 }
200
201 void InfobarWindow::FrameImpl::CloseInfobar() {
202   infobar_window_->Hide();
203 }