OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/ui/views/infobars/infobar_view.h" | 5 #include "chrome/browser/ui/views/infobars/infobar_view.h" |
6 | 6 |
7 #include "base/message_loop.h" | 7 #include "base/message_loop.h" |
8 #include "base/utf_string_conversions.h" | 8 #include "base/utf_string_conversions.h" |
9 #include "chrome/browser/tab_contents/infobar_delegate.h" | 9 #include "chrome/browser/tab_contents/infobar_delegate.h" |
10 #include "chrome/browser/ui/views/infobars/infobar_background.h" | 10 #include "chrome/browser/ui/views/infobars/infobar_background.h" |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
49 | 49 |
50 const int InfoBarView::kTabWidth = (kCurveWidth + kTabIconPadding) * 2 + | 50 const int InfoBarView::kTabWidth = (kCurveWidth + kTabIconPadding) * 2 + |
51 kMaxIconWidth; | 51 kMaxIconWidth; |
52 | 52 |
53 InfoBarView::InfoBarView(InfoBarDelegate* delegate) | 53 InfoBarView::InfoBarView(InfoBarDelegate* delegate) |
54 : InfoBar(delegate), | 54 : InfoBar(delegate), |
55 icon_(NULL), | 55 icon_(NULL), |
56 close_button_(NULL), | 56 close_button_(NULL), |
57 ALLOW_THIS_IN_INITIALIZER_LIST(delete_factory_(this)), | 57 ALLOW_THIS_IN_INITIALIZER_LIST(delete_factory_(this)), |
58 target_height_(kDefaultTargetHeight), | 58 target_height_(kDefaultTargetHeight), |
| 59 tab_height_(0), |
| 60 bar_height_(0), |
59 fill_path_(new SkPath), | 61 fill_path_(new SkPath), |
60 stroke_path_(new SkPath) { | 62 stroke_path_(new SkPath) { |
61 set_parent_owned(false); // InfoBar deletes itself at the appropriate time. | 63 set_parent_owned(false); // InfoBar deletes itself at the appropriate time. |
62 | 64 |
63 InfoBarDelegate::Type infobar_type = delegate->GetInfoBarType(); | 65 InfoBarDelegate::Type infobar_type = delegate->GetInfoBarType(); |
64 set_background(new InfoBarBackground(infobar_type)); | 66 set_background(new InfoBarBackground(infobar_type)); |
65 } | 67 } |
66 | 68 |
67 InfoBarView::~InfoBarView() { | 69 InfoBarView::~InfoBarView() { |
68 } | 70 } |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
142 (*func)(SIID_SHIELD, SHGSI_ICON | SHGSI_SMALLICON, &icon_info); | 144 (*func)(SIID_SHIELD, SHGSI_ICON | SHGSI_SMALLICON, &icon_info); |
143 text_button->SetIcon(*IconUtil::CreateSkBitmapFromHICON(icon_info.hIcon, | 145 text_button->SetIcon(*IconUtil::CreateSkBitmapFromHICON(icon_info.hIcon, |
144 gfx::Size(GetSystemMetrics(SM_CXSMICON), | 146 gfx::Size(GetSystemMetrics(SM_CXSMICON), |
145 GetSystemMetrics(SM_CYSMICON)))); | 147 GetSystemMetrics(SM_CYSMICON)))); |
146 } | 148 } |
147 #endif | 149 #endif |
148 return text_button; | 150 return text_button; |
149 } | 151 } |
150 | 152 |
151 void InfoBarView::Layout() { | 153 void InfoBarView::Layout() { |
| 154 // Calculate the fill and stroke paths. We do this here, rather than in |
| 155 // PlatformSpecificRecalculateHeight(), because this is also reached when our |
| 156 // width is changed, which affects both paths. |
| 157 stroke_path_->rewind(); |
| 158 fill_path_->rewind(); |
| 159 if (tab_height_) { |
| 160 int divider_y = tab_height_ - 1; |
| 161 stroke_path_->moveTo( |
| 162 SkIntToScalar(GetMirroredXWithWidthInView(0, kTabWidth)), |
| 163 SkIntToScalar(divider_y)); |
| 164 stroke_path_->rCubicTo( |
| 165 SkScalarDiv(kCurveWidth, 2), 0.0, |
| 166 SkScalarDiv(kCurveWidth, 2), |
| 167 SkIntToScalar(-divider_y), |
| 168 SkIntToScalar(kCurveWidth), |
| 169 SkIntToScalar(-divider_y)); |
| 170 stroke_path_->rLineTo(SkScalarMulAdd(kTabIconPadding, 2, kMaxIconWidth), |
| 171 0.0); |
| 172 stroke_path_->rCubicTo( |
| 173 SkScalarDiv(kCurveWidth, 2), 0.0, |
| 174 SkScalarDiv(kCurveWidth, 2), |
| 175 SkIntToScalar(divider_y), |
| 176 SkIntToScalar(kCurveWidth), |
| 177 SkIntToScalar(divider_y)); |
| 178 |
| 179 // Create the fill portion of the tab. Because the fill is inside the |
| 180 // bounds and will not cover the separator, we need to extend downward by a |
| 181 // pixel before closing. |
| 182 *fill_path_ = *stroke_path_; |
| 183 fill_path_->rLineTo(0.0, 1.0); |
| 184 fill_path_->rLineTo(-SkIntToScalar(kTabWidth), 0.0); |
| 185 fill_path_->close(); |
| 186 |
| 187 // Fill and stroke have different opinions about how to treat paths. |
| 188 // Because in Skia integral coordinates represent pixel boundaries, |
| 189 // offsetting the path makes it go exactly through pixel centers; this |
| 190 // results in lines that are exactly where we expect, instead of having odd |
| 191 // "off by one" issues. Were we to do this for |fill_path|, however, which |
| 192 // tries to fill "inside" the path (using some questionable math), we'd get |
| 193 // a fill at a very different place than we'd want. |
| 194 stroke_path_->offset(SK_ScalarHalf, SK_ScalarHalf); |
| 195 } |
| 196 if (bar_height_) { |
| 197 fill_path_->addRect(0.0, SkIntToScalar(tab_height_), SkIntToScalar(width()), |
| 198 SkIntToScalar(height())); |
| 199 } |
| 200 |
152 int start_x = kHorizontalPadding; | 201 int start_x = kHorizontalPadding; |
153 if (icon_ != NULL) { | 202 if (icon_ != NULL) { |
154 // Center the icon horizontally within the tab, and vertically between the | 203 // Center the icon horizontally within the tab, and vertically between the |
155 // entire height (tab + bar). | 204 // entire height (tab + bar). |
156 gfx::Size icon_size = icon_->GetPreferredSize(); | 205 gfx::Size icon_size = icon_->GetPreferredSize(); |
157 int center_x = std::max((kTabWidth - icon_size.width()) / 2, 0); | 206 int center_x = std::max((kTabWidth - icon_size.width()) / 2, 0); |
158 int full_height = target_height_ + kTabHeight; | 207 int full_height = target_height_ + kTabHeight; |
159 | 208 |
160 // This duplicates OffsetY except centered within the entire height (tab + | 209 // This duplicates OffsetY except centered within the entire height (tab + |
161 // bar) instead of just within the bar. | 210 // bar) instead of just within the bar. |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
238 | 287 |
239 void InfoBarView::PaintChildren(gfx::Canvas* canvas) { | 288 void InfoBarView::PaintChildren(gfx::Canvas* canvas) { |
240 canvas->Save(); | 289 canvas->Save(); |
241 | 290 |
242 // TODO(scr): This really should be the |fill_path_|, but the clipPath seems | 291 // TODO(scr): This really should be the |fill_path_|, but the clipPath seems |
243 // broken on non-Windows platforms (crbug.com/75154). For now, just clip to | 292 // broken on non-Windows platforms (crbug.com/75154). For now, just clip to |
244 // the bar bounds. | 293 // the bar bounds. |
245 // | 294 // |
246 // gfx::CanvasSkia* canvas_skia = canvas->AsCanvasSkia(); | 295 // gfx::CanvasSkia* canvas_skia = canvas->AsCanvasSkia(); |
247 // canvas_skia->clipPath(*fill_path_); | 296 // canvas_skia->clipPath(*fill_path_); |
248 int tab_height = AnimatedTabHeight(); | 297 DCHECK_EQ(tab_height_ + bar_height_, height()) |
249 int bar_height = AnimatedBarHeight(); | 298 << "Infobar piecewise heights do not match overall height"; |
250 DCHECK_EQ(tab_height + bar_height, height()) | 299 canvas->ClipRectInt(0, tab_height_, width(), bar_height_); |
251 << "Animation progressed between OnBoundsChanged & PaintChildren."; | |
252 canvas->ClipRectInt(0, tab_height, width(), bar_height); | |
253 | |
254 views::View::PaintChildren(canvas); | 300 views::View::PaintChildren(canvas); |
255 canvas->Restore(); | 301 canvas->Restore(); |
256 } | 302 } |
257 | 303 |
258 void InfoBarView::ButtonPressed(views::Button* sender, | 304 void InfoBarView::ButtonPressed(views::Button* sender, |
259 const views::Event& event) { | 305 const views::Event& event) { |
260 if (sender == close_button_) { | 306 if (sender == close_button_) { |
261 if (delegate()) | 307 if (delegate()) |
262 delegate()->InfoBarDismissed(); | 308 delegate()->InfoBarDismissed(); |
263 RemoveInfoBar(); | 309 RemoveInfoBar(); |
264 } | 310 } |
265 } | 311 } |
266 | 312 |
267 int InfoBarView::ContentMinimumWidth() const { | 313 int InfoBarView::ContentMinimumWidth() const { |
268 return 0; | 314 return 0; |
269 } | 315 } |
270 | 316 |
| 317 void InfoBarView::SetTargetHeight(int height) { |
| 318 if (target_height_ != height) { |
| 319 target_height_ = height; |
| 320 RecalculateHeight(); |
| 321 } |
| 322 } |
| 323 |
271 int InfoBarView::StartX() const { | 324 int InfoBarView::StartX() const { |
272 // Ensure we don't return a value greater than EndX(), so children can safely | 325 // Ensure we don't return a value greater than EndX(), so children can safely |
273 // set something's width to "EndX() - StartX()" without risking that being | 326 // set something's width to "EndX() - StartX()" without risking that being |
274 // negative. | 327 // negative. |
275 return std::min(EndX(), | 328 return std::min(EndX(), |
276 ((icon_ != NULL) ? icon_->bounds().right() : 0) + kHorizontalPadding); | 329 ((icon_ != NULL) ? icon_->bounds().right() : 0) + kHorizontalPadding); |
277 } | 330 } |
278 | 331 |
279 int InfoBarView::EndX() const { | 332 int InfoBarView::EndX() const { |
280 const int kCloseButtonSpacing = 12; | 333 const int kCloseButtonSpacing = 12; |
281 return close_button_->x() - kCloseButtonSpacing; | 334 return close_button_->x() - kCloseButtonSpacing; |
282 } | 335 } |
283 | 336 |
284 int InfoBarView::CenterY(const gfx::Size prefsize) const { | 337 int InfoBarView::CenterY(const gfx::Size prefsize) const { |
285 return std::max((target_height_ - prefsize.height()) / 2, 0); | 338 return std::max((target_height_ - prefsize.height()) / 2, 0); |
286 } | 339 } |
287 | 340 |
288 int InfoBarView::OffsetY(const gfx::Size prefsize) const { | 341 int InfoBarView::OffsetY(const gfx::Size prefsize) const { |
289 return CenterY(prefsize) + AnimatedTabHeight() - | 342 return CenterY(prefsize) + tab_height_ - (target_height_ - bar_height_); |
290 (target_height_ - AnimatedBarHeight()); | |
291 } | 343 } |
292 | 344 |
293 void InfoBarView::PlatformSpecificHide(bool animate) { | 345 void InfoBarView::PlatformSpecificHide(bool animate) { |
294 if (!animate) | 346 if (!animate) |
295 return; | 347 return; |
296 | 348 |
297 bool restore_focus = true; | 349 bool restore_focus = true; |
298 #if defined(OS_WIN) | 350 #if defined(OS_WIN) |
299 // Do not restore focus (and active state with it) on Windows if some other | 351 // Do not restore focus (and active state with it) on Windows if some other |
300 // top-level window became active. | 352 // top-level window became active. |
301 if (GetWidget() && | 353 if (GetWidget() && |
302 !ui::DoesWindowBelongToActiveWindow(GetWidget()->GetNativeView())) | 354 !ui::DoesWindowBelongToActiveWindow(GetWidget()->GetNativeView())) |
303 restore_focus = false; | 355 restore_focus = false; |
304 #endif // defined(OS_WIN) | 356 #endif // defined(OS_WIN) |
305 DestroyFocusTracker(restore_focus); | 357 DestroyFocusTracker(restore_focus); |
306 } | 358 } |
307 | 359 |
| 360 void InfoBarView::PlatformSpecificRecalculateHeight() { |
| 361 int old_tab_height = tab_height_; |
| 362 int old_bar_height = bar_height_; |
| 363 tab_height_ = static_cast<int>(kTabHeight * animation()->GetCurrentValue()); |
| 364 bar_height_ = |
| 365 static_cast<int>(target_height_ * animation()->GetCurrentValue()); |
| 366 |
| 367 // Don't re-layout if nothing has changed, e.g. because the animation step was |
| 368 // not large enough to actually change the heights by at least a pixel. |
| 369 if ((old_tab_height != tab_height_) || (old_bar_height != bar_height_)) { |
| 370 // Ensure that notifying our container of our size change will result in a |
| 371 // re-layout. |
| 372 InvalidateLayout(); |
| 373 } |
| 374 } |
| 375 |
308 void InfoBarView::GetAccessibleState(ui::AccessibleViewState* state) { | 376 void InfoBarView::GetAccessibleState(ui::AccessibleViewState* state) { |
309 if (delegate()) { | 377 if (delegate()) { |
310 state->name = l10n_util::GetStringUTF16( | 378 state->name = l10n_util::GetStringUTF16( |
311 (delegate()->GetInfoBarType() == InfoBarDelegate::WARNING_TYPE) ? | 379 (delegate()->GetInfoBarType() == InfoBarDelegate::WARNING_TYPE) ? |
312 IDS_ACCNAME_INFOBAR_WARNING : IDS_ACCNAME_INFOBAR_PAGE_ACTION); | 380 IDS_ACCNAME_INFOBAR_WARNING : IDS_ACCNAME_INFOBAR_PAGE_ACTION); |
313 } | 381 } |
314 state->role = ui::AccessibilityTypes::ROLE_ALERT; | 382 state->role = ui::AccessibilityTypes::ROLE_ALERT; |
315 } | 383 } |
316 | 384 |
317 int InfoBarView::AnimatedTabHeight() const { | |
318 return static_cast<int>(kTabHeight * animation()->GetCurrentValue()); | |
319 } | |
320 | |
321 int InfoBarView::AnimatedBarHeight() const { | |
322 return static_cast<int>(target_height_ * animation()->GetCurrentValue()); | |
323 } | |
324 | |
325 gfx::Size InfoBarView::GetPreferredSize() { | 385 gfx::Size InfoBarView::GetPreferredSize() { |
326 return gfx::Size(0, AnimatedTabHeight() + AnimatedBarHeight()); | 386 return gfx::Size(0, tab_height_ + bar_height_); |
327 } | |
328 | |
329 void InfoBarView::OnBoundsChanged(const gfx::Rect& previous_bounds) { | |
330 int tab_height = AnimatedTabHeight(); | |
331 int bar_height = AnimatedBarHeight(); | |
332 int divider_y = tab_height - 1; | |
333 DCHECK_EQ(tab_height + bar_height, height()) | |
334 << "Animation progressed between Layout & OnBoundsChanged."; | |
335 | |
336 int mirrored_x = GetMirroredXWithWidthInView(0, kTabWidth); | |
337 stroke_path_->rewind(); | |
338 fill_path_->rewind(); | |
339 | |
340 if (tab_height) { | |
341 stroke_path_->moveTo(SkIntToScalar(mirrored_x), | |
342 SkIntToScalar(divider_y)); | |
343 stroke_path_->rCubicTo( | |
344 SkScalarDiv(kCurveWidth, 2), 0.0, | |
345 SkScalarDiv(kCurveWidth, 2), | |
346 SkIntToScalar(-divider_y), | |
347 SkIntToScalar(kCurveWidth), | |
348 SkIntToScalar(-divider_y)); | |
349 stroke_path_->rLineTo(SkScalarMulAdd(kTabIconPadding, 2, kMaxIconWidth), | |
350 0.0); | |
351 stroke_path_->rCubicTo( | |
352 SkScalarDiv(kCurveWidth, 2), 0.0, | |
353 SkScalarDiv(kCurveWidth, 2), | |
354 SkIntToScalar(divider_y), | |
355 SkIntToScalar(kCurveWidth), | |
356 SkIntToScalar(divider_y)); | |
357 | |
358 // Create the fill portion of the tab. Because the fill is inside the | |
359 // bounds and will not cover the separator, we need to extend downward by a | |
360 // pixel before closing. | |
361 *fill_path_ = *stroke_path_; | |
362 fill_path_->rLineTo(0.0, 1.0); | |
363 fill_path_->rLineTo(-SkIntToScalar(kTabWidth), 0.0); | |
364 fill_path_->close(); | |
365 | |
366 // Fill and stroke have different opinions about how to treat paths. | |
367 // Because in Skia integral coordinates represent pixel boundaries, | |
368 // offsetting the path makes it go exactly through pixel centers; this | |
369 // results in lines that are exactly where we expect, instead of having odd | |
370 // "off by one" issues. Were we to do this for |fill_path|, however, which | |
371 // tries to fill "inside" the path (using some questionable math), we'd get | |
372 // a fill at a very different place than we'd want. | |
373 stroke_path_->offset(SK_ScalarHalf, SK_ScalarHalf); | |
374 } | |
375 if (bar_height) { | |
376 fill_path_->addRect(0.0, SkIntToScalar(tab_height), | |
377 SkIntToScalar(width()), SkIntToScalar(height())); | |
378 } | |
379 } | 387 } |
380 | 388 |
381 void InfoBarView::FocusWillChange(View* focused_before, View* focused_now) { | 389 void InfoBarView::FocusWillChange(View* focused_before, View* focused_now) { |
382 // This will trigger some screen readers to read the entire contents of this | 390 // This will trigger some screen readers to read the entire contents of this |
383 // infobar. | 391 // infobar. |
384 if (focused_before && focused_now && !this->Contains(focused_before) && | 392 if (focused_before && focused_now && !this->Contains(focused_before) && |
385 this->Contains(focused_now) && GetWidget()) { | 393 this->Contains(focused_now) && GetWidget()) { |
386 GetWidget()->NotifyAccessibilityEvent( | 394 GetWidget()->NotifyAccessibilityEvent( |
387 this, ui::AccessibilityTypes::EVENT_ALERT, true); | 395 this, ui::AccessibilityTypes::EVENT_ALERT, true); |
388 } | 396 } |
389 } | 397 } |
390 | 398 |
391 void InfoBarView::DestroyFocusTracker(bool restore_focus) { | 399 void InfoBarView::DestroyFocusTracker(bool restore_focus) { |
392 if (focus_tracker_ != NULL) { | 400 if (focus_tracker_ != NULL) { |
393 if (restore_focus) | 401 if (restore_focus) |
394 focus_tracker_->FocusLastFocusedExternalView(); | 402 focus_tracker_->FocusLastFocusedExternalView(); |
395 focus_tracker_->SetFocusManager(NULL); | 403 focus_tracker_->SetFocusManager(NULL); |
396 focus_tracker_.reset(); | 404 focus_tracker_.reset(); |
397 } | 405 } |
398 } | 406 } |
399 | 407 |
400 void InfoBarView::DeleteSelf() { | 408 void InfoBarView::DeleteSelf() { |
401 delete this; | 409 delete this; |
402 } | 410 } |
OLD | NEW |