Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/status_bubble_views.h" | 5 #include "chrome/browser/ui/views/status_bubble_views.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/i18n/rtl.h" | 10 #include "base/i18n/rtl.h" |
| 11 #include "base/location.h" | 11 #include "base/location.h" |
| 12 #include "base/macros.h" | 12 #include "base/macros.h" |
| 13 #include "base/single_thread_task_runner.h" | 13 #include "base/single_thread_task_runner.h" |
| 14 #include "base/strings/string_util.h" | 14 #include "base/strings/string_util.h" |
| 15 #include "base/strings/utf_string_conversions.h" | 15 #include "base/strings/utf_string_conversions.h" |
| 16 #include "base/threading/thread_task_runner_handle.h" | 16 #include "base/threading/thread_task_runner_handle.h" |
| 17 #include "build/build_config.h" | 17 #include "build/build_config.h" |
| 18 #include "chrome/browser/themes/theme_properties.h" | 18 #include "chrome/browser/themes/theme_properties.h" |
| 19 #include "components/url_formatter/elide_url.h" | 19 #include "components/url_formatter/elide_url.h" |
| 20 #include "components/url_formatter/url_formatter.h" | 20 #include "components/url_formatter/url_formatter.h" |
| 21 #include "third_party/skia/include/core/SkPaint.h" | 21 #include "third_party/skia/include/core/SkPaint.h" |
| 22 #include "third_party/skia/include/core/SkRRect.h" | 22 #include "third_party/skia/include/core/SkPath.h" |
| 23 #include "third_party/skia/include/pathops/SkPathOps.h" | |
| 23 #include "ui/base/theme_provider.h" | 24 #include "ui/base/theme_provider.h" |
| 24 #include "ui/display/display.h" | 25 #include "ui/display/display.h" |
| 25 #include "ui/display/screen.h" | 26 #include "ui/display/screen.h" |
| 26 #include "ui/gfx/animation/animation_delegate.h" | 27 #include "ui/gfx/animation/animation_delegate.h" |
| 27 #include "ui/gfx/animation/linear_animation.h" | 28 #include "ui/gfx/animation/linear_animation.h" |
| 28 #include "ui/gfx/canvas.h" | 29 #include "ui/gfx/canvas.h" |
| 29 #include "ui/gfx/font_list.h" | 30 #include "ui/gfx/font_list.h" |
| 30 #include "ui/gfx/geometry/point.h" | 31 #include "ui/gfx/geometry/point.h" |
| 31 #include "ui/gfx/geometry/rect.h" | 32 #include "ui/gfx/geometry/rect.h" |
| 32 #include "ui/gfx/skia_util.h" | 33 #include "ui/gfx/skia_util.h" |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 128 }; | 129 }; |
| 129 | 130 |
| 130 enum BubbleStyle { | 131 enum BubbleStyle { |
| 131 STYLE_BOTTOM, | 132 STYLE_BOTTOM, |
| 132 STYLE_FLOATING, | 133 STYLE_FLOATING, |
| 133 STYLE_STANDARD, | 134 STYLE_STANDARD, |
| 134 STYLE_STANDARD_RIGHT | 135 STYLE_STANDARD_RIGHT |
| 135 }; | 136 }; |
| 136 | 137 |
| 137 StatusView(views::Widget* popup, | 138 StatusView(views::Widget* popup, |
| 138 const ui::ThemeProvider* theme_provider); | 139 const gfx::Size& popup_size_, |
| 140 SkColor bubble_color, | |
| 141 SkColor bubble_text_color, | |
| 142 bool has_client_edge); | |
| 139 ~StatusView() override; | 143 ~StatusView() override; |
| 140 | 144 |
| 141 // Set the bubble text to a certain value, hides the bubble if text is | 145 // Set the bubble text to a certain value, hides the bubble if text is |
| 142 // an empty string. Trigger animation sequence to display if | 146 // an empty string. Trigger animation sequence to display if |
| 143 // |should_animate_open|. | 147 // |should_animate_open|. |
| 144 void SetText(const base::string16& text, bool should_animate_open); | 148 void SetText(const base::string16& text, bool should_animate_open); |
| 145 | 149 |
| 146 BubbleState state() const { return state_; } | 150 BubbleState state() const { return state_; } |
| 147 BubbleStyle style() const { return style_; } | 151 BubbleStyle style() const { return style_; } |
| 148 void SetStyle(BubbleStyle style); | 152 void SetStyle(BubbleStyle style); |
| 149 | 153 |
| 150 // Show the bubble instantly. | 154 // Show the bubble instantly. |
| 151 void Show(); | 155 void Show(); |
| 152 | 156 |
| 153 // Hide the bubble instantly. | 157 // Hide the bubble instantly. |
| 154 void Hide(); | 158 void Hide(); |
| 155 | 159 |
| 156 // Resets any timers we have. Typically called when the user moves a | 160 // Resets any timers we have. Typically called when the user moves a |
| 157 // mouse. | 161 // mouse. |
| 158 void ResetTimer(); | 162 void ResetTimer(); |
| 159 | 163 |
| 160 // This call backs the StatusView in order to fade the bubble in and out. | 164 // This call backs the StatusView in order to fade the bubble in and out. |
| 161 void SetOpacity(float opacity); | 165 void SetOpacity(float opacity); |
| 162 | 166 |
| 163 // Depending on the state of the bubble this will either hide the popup or | 167 // Depending on the state of the bubble this will either hide the popup or |
| 164 // not. | 168 // not. |
| 165 void OnAnimationEnded(); | 169 void OnAnimationEnded(); |
| 166 | 170 |
| 171 void SetWidth(int new_width); | |
| 172 | |
| 167 private: | 173 private: |
| 168 class InitialTimer; | 174 class InitialTimer; |
| 169 | 175 |
| 170 // Manage the timers that control the delay before a fade begins or ends. | 176 // Manage the timers that control the delay before a fade begins or ends. |
| 171 void StartTimer(base::TimeDelta time); | 177 void StartTimer(base::TimeDelta time); |
| 172 void OnTimer(); | 178 void OnTimer(); |
| 173 void CancelTimer(); | 179 void CancelTimer(); |
| 174 void RestartTimer(base::TimeDelta delay); | 180 void RestartTimer(base::TimeDelta delay); |
| 175 | 181 |
| 176 // Manage the fades and starting and stopping the animations correctly. | 182 // Manage the fades and starting and stopping the animations correctly. |
| 177 void StartFade(float start, float end, int duration); | 183 void StartFade(float start, float end, int duration); |
| 178 void StartHiding(); | 184 void StartHiding(); |
| 179 void StartShowing(); | 185 void StartShowing(); |
| 180 | 186 |
| 181 // views::View: | 187 // views::View: |
| 182 const char* GetClassName() const override; | 188 const char* GetClassName() const override; |
| 183 void OnPaint(gfx::Canvas* canvas) override; | 189 void OnPaint(gfx::Canvas* canvas) override; |
| 184 | 190 |
| 185 BubbleState state_; | 191 BubbleState state_; |
| 186 BubbleStyle style_; | 192 BubbleStyle style_; |
| 187 | 193 |
| 188 std::unique_ptr<StatusViewAnimation> animation_; | 194 std::unique_ptr<StatusViewAnimation> animation_; |
| 189 | 195 |
| 190 // Handle to the widget that contains us. | 196 // Handle to the widget that contains us. |
| 191 views::Widget* popup_; | 197 views::Widget* popup_; |
| 192 | 198 |
| 193 // The currently-displayed text. | 199 // The currently-displayed text. |
| 194 base::string16 text_; | 200 base::string16 text_; |
| 195 | 201 |
| 196 // Holds the theme provider of the frame that created us. | 202 gfx::Size popup_size_; |
| 197 const ui::ThemeProvider* theme_provider_; | 203 |
| 204 const SkColor bubble_color_; | |
| 205 const SkColor bubble_text_color_; | |
| 206 const bool has_client_edge_; | |
| 198 | 207 |
| 199 base::WeakPtrFactory<StatusBubbleViews::StatusView> timer_factory_; | 208 base::WeakPtrFactory<StatusBubbleViews::StatusView> timer_factory_; |
| 200 | 209 |
| 201 DISALLOW_COPY_AND_ASSIGN(StatusView); | 210 DISALLOW_COPY_AND_ASSIGN(StatusView); |
| 202 }; | 211 }; |
| 203 | 212 |
| 204 StatusBubbleViews::StatusView::StatusView( | 213 StatusBubbleViews::StatusView::StatusView(views::Widget* popup, |
| 205 views::Widget* popup, | 214 const gfx::Size& popup_size, |
| 206 const ui::ThemeProvider* theme_provider) | 215 SkColor bubble_color, |
| 216 SkColor bubble_text_color, | |
| 217 bool has_client_edge) | |
| 207 : state_(BUBBLE_HIDDEN), | 218 : state_(BUBBLE_HIDDEN), |
| 208 style_(STYLE_STANDARD), | 219 style_(STYLE_STANDARD), |
| 209 animation_(new StatusViewAnimation(this, 0, 0)), | 220 animation_(new StatusViewAnimation(this, 0, 0)), |
| 210 popup_(popup), | 221 popup_(popup), |
| 211 theme_provider_(theme_provider), | 222 popup_size_(popup_size), |
| 223 bubble_color_(bubble_color), | |
| 224 bubble_text_color_(bubble_text_color), | |
| 225 has_client_edge_(has_client_edge), | |
| 212 timer_factory_(this) {} | 226 timer_factory_(this) {} |
| 213 | 227 |
| 214 StatusBubbleViews::StatusView::~StatusView() { | 228 StatusBubbleViews::StatusView::~StatusView() { |
| 215 animation_->Stop(); | 229 animation_->Stop(); |
| 216 CancelTimer(); | 230 CancelTimer(); |
| 217 } | 231 } |
| 218 | 232 |
| 219 void StatusBubbleViews::StatusView::SetText(const base::string16& text, | 233 void StatusBubbleViews::StatusView::SetText(const base::string16& text, |
| 220 bool should_animate_open) { | 234 bool should_animate_open) { |
| 221 if (text.empty()) { | 235 if (text.empty()) { |
| (...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 354 | 368 |
| 355 void StatusBubbleViews::StatusView::OnAnimationEnded() { | 369 void StatusBubbleViews::StatusView::OnAnimationEnded() { |
| 356 if (state_ == BUBBLE_HIDING_FADE) { | 370 if (state_ == BUBBLE_HIDING_FADE) { |
| 357 state_ = BUBBLE_HIDDEN; | 371 state_ = BUBBLE_HIDDEN; |
| 358 popup_->Hide(); | 372 popup_->Hide(); |
| 359 } else if (state_ == BUBBLE_SHOWING_FADE) { | 373 } else if (state_ == BUBBLE_SHOWING_FADE) { |
| 360 state_ = BUBBLE_SHOWN; | 374 state_ = BUBBLE_SHOWN; |
| 361 } | 375 } |
| 362 } | 376 } |
| 363 | 377 |
| 378 void StatusBubbleViews::StatusView::SetWidth(int new_width) { | |
| 379 popup_size_.set_width(new_width); | |
| 380 } | |
| 381 | |
| 364 const char* StatusBubbleViews::StatusView::GetClassName() const { | 382 const char* StatusBubbleViews::StatusView::GetClassName() const { |
| 365 return "StatusBubbleViews::StatusView"; | 383 return "StatusBubbleViews::StatusView"; |
| 366 } | 384 } |
| 367 | 385 |
| 368 void StatusBubbleViews::StatusView::OnPaint(gfx::Canvas* canvas) { | 386 void StatusBubbleViews::StatusView::OnPaint(gfx::Canvas* canvas) { |
| 369 SkPaint paint; | 387 canvas->Save(); |
| 370 paint.setStyle(SkPaint::kFill_Style); | 388 float scale = canvas->UndoDeviceScaleFactor(); |
| 371 paint.setAntiAlias(true); | 389 const float radius = kBubbleCornerRadius * scale; |
| 372 SkColor toolbar_color = theme_provider_->GetColor( | |
| 373 ThemeProperties::COLOR_TOOLBAR); | |
| 374 paint.setColor(toolbar_color); | |
| 375 | |
| 376 gfx::Rect popup_bounds = popup_->GetWindowBoundsInScreen(); | |
| 377 | 390 |
| 378 SkScalar rad[8] = {}; | 391 SkScalar rad[8] = {}; |
| 379 | 392 |
| 380 // Top Edges - if the bubble is in its bottom position (sticking downwards), | 393 // Top Edges - if the bubble is in its bottom position (sticking downwards), |
| 381 // then we square the top edges. Otherwise, we square the edges based on the | 394 // then we square the top edges. Otherwise, we square the edges based on the |
| 382 // position of the bubble within the window (the bubble is positioned in the | 395 // position of the bubble within the window (the bubble is positioned in the |
| 383 // southeast corner in RTL and in the southwest corner in LTR). | 396 // southeast corner in RTL and in the southwest corner in LTR). |
| 384 if (style_ != STYLE_BOTTOM) { | 397 if (style_ != STYLE_BOTTOM) { |
| 385 if (base::i18n::IsRTL() != (style_ == STYLE_STANDARD_RIGHT)) { | 398 if (base::i18n::IsRTL() != (style_ == STYLE_STANDARD_RIGHT)) { |
| 386 // The text is RtL or the bubble is on the right side (but not both). | 399 // The text is RtL or the bubble is on the right side (but not both). |
| 387 | 400 |
| 388 // Top Left corner. | 401 // Top Left corner. |
| 389 rad[0] = kBubbleCornerRadius; | 402 rad[0] = radius; |
| 390 rad[1] = kBubbleCornerRadius; | 403 rad[1] = radius; |
| 391 } else { | 404 } else { |
| 392 // Top Right corner. | 405 // Top Right corner. |
| 393 rad[2] = kBubbleCornerRadius; | 406 rad[2] = radius; |
| 394 rad[3] = kBubbleCornerRadius; | 407 rad[3] = radius; |
| 395 } | 408 } |
| 396 } | 409 } |
| 397 | 410 |
| 398 // Bottom edges - Keep these squared off if the bubble is in its standard | 411 // Bottom edges - Keep these squared off if the bubble is in its standard |
| 399 // position (sticking upward). | 412 // position (sticking upward). |
| 400 if (style_ != STYLE_STANDARD && style_ != STYLE_STANDARD_RIGHT) { | 413 if (style_ != STYLE_STANDARD && style_ != STYLE_STANDARD_RIGHT) { |
| 401 // Bottom Right Corner. | 414 // Bottom Right Corner. |
| 402 rad[4] = kBubbleCornerRadius; | 415 rad[4] = radius; |
| 403 rad[5] = kBubbleCornerRadius; | 416 rad[5] = radius; |
| 404 | 417 |
| 405 // Bottom Left Corner. | 418 // Bottom Left Corner. |
| 406 rad[6] = kBubbleCornerRadius; | 419 rad[6] = radius; |
| 407 rad[7] = kBubbleCornerRadius; | 420 rad[7] = radius; |
| 408 } | 421 } |
| 409 | 422 |
| 410 // Draw the bubble's shadow. | 423 // Snap to pixels to avoid shadow blurriness. |
| 411 int width = popup_bounds.width(); | 424 const float width = std::round(popup_size_.width() * scale); |
| 412 int height = popup_bounds.height(); | 425 const float height = std::round(popup_size_.height() * scale); |
|
Peter Kasting
2016/08/24 22:53:24
Why are we rounding if we're storing in floats? I
Bret
2016/08/25 18:05:38
The types are just an oversight. I didn't think th
| |
| 413 gfx::Rect rect(gfx::Rect(popup_bounds.size())); | |
| 414 SkPaint shadow_paint; | |
| 415 shadow_paint.setAntiAlias(true); | |
| 416 shadow_paint.setColor(kShadowColor); | |
| 417 | 426 |
| 418 SkRRect rrect; | 427 #if defined(OS_WIN) |
| 419 rrect.setRectRadii(RectToSkRect(rect), (const SkVector*)rad); | 428 // In Reposition() below we move the bubble 1 dip to the bottom/left so that |
| 420 canvas->sk_canvas()->drawRRect(rrect, shadow_paint); | 429 // the bubble shadow will overlap the client edge/window frame. But we draw |
| 430 // the shadow 1 pixel thick, which means we need to draw at the inner-most | |
| 431 // pixel of that dip for a proper overlap. | |
| 432 // | |
| 433 // Unfortunately the bubble's position relative to the window is dependent on | |
| 434 // the bubble's absolute screen position we can't position the bubble | |
| 435 // precisely enough to guarantee exactly what we want. Having the bubble "pull | |
|
Peter Kasting
2016/08/24 22:53:24
I think you meant to divide this first sentence in
Bret
2016/08/25 18:05:37
Done.
| |
| 436 // away" from the frame (leaving a gap where the web content shows through) | |
| 437 // looks a lot worse than allowing the bubble to hang off the edge of the | |
| 438 // window. Plus the possible positioning imprecision increases at higher dsfs. | |
|
Peter Kasting
2016/08/24 22:53:24
Are you saying that sometimes (for example) the bu
Bret
2016/08/25 18:05:37
To your first question: you have the basic idea ri
| |
| 439 // So these values are very conservative but still look better than not | |
| 440 // compensating at all. | |
| 441 const int subdip_layout_inset = scale > 1.25 ? (scale > 2 ? 2 : 1) : 0; | |
|
Peter Kasting
2016/08/24 22:53:24
It clearly isn't right to just use "2" for all sca
Bret
2016/08/25 18:05:37
I'm not claiming this isn't a hack, basically, but
| |
| 442 #else | |
| 443 // FIXME: Since the dip error is dependent on platform-specific code we need | |
|
Peter Kasting
2016/08/24 22:53:24
Which platform-specific code? The DIP-vs.px posit
Bret
2016/08/25 18:05:38
ScreenWin::DIPToScreenRect is what I was thinking
| |
| 444 // to figure out appropriate values for non-Windows platforms. | |
| 445 const int subdip_layout_inset = 0; | |
| 446 #endif | |
| 421 | 447 |
| 422 const int shadow_size = 2 * kShadowThickness; | 448 if (!has_client_edge_) { |
| 423 // Draw the bubble. | 449 const int clip_size = subdip_layout_inset + 1; |
| 424 rect.SetRect(SkIntToScalar(kShadowThickness), SkIntToScalar(kShadowThickness), | 450 // Clip out the edges when the bubble is docked so that it doesn't draw over |
| 425 SkIntToScalar(width - shadow_size), | 451 // the window border, since there's no client edge. But we do want the |
| 426 SkIntToScalar(height - shadow_size)); | 452 // border when the bubble is floating so it looks complete. |
| 427 rrect.setRectRadii(RectToSkRect(rect), (const SkVector*)rad); | 453 const int clip_left = style_ == STYLE_STANDARD ? clip_size : 0; |
| 428 canvas->sk_canvas()->drawRRect(rrect, paint); | 454 const int clip_right = style_ == STYLE_STANDARD_RIGHT ? clip_size : 0; |
| 455 const int clip_bottom = clip_left || clip_right ? clip_size : 0; | |
| 456 gfx::Rect clip_rect(clip_left, 0, width - clip_right, height - clip_bottom); | |
| 457 canvas->ClipRect(clip_rect); | |
| 458 } | |
| 459 | |
| 460 gfx::RectF bubble_rect(width, height); | |
| 461 const int error_left = | |
| 462 style_ != STYLE_STANDARD_RIGHT ? subdip_layout_inset : 0; | |
| 463 const int error_right = | |
| 464 style_ == STYLE_STANDARD_RIGHT ? subdip_layout_inset : 0; | |
| 465 // The bottom edge is very close to the top of the client edge, so trying to | |
| 466 // inset it at all causes it to pull away from the frame. | |
|
Peter Kasting
2016/08/24 22:53:24
I don't understand why this is different than the
Bret
2016/08/25 18:05:38
I'm not sure either, tbh. It might have something
| |
| 467 const int error_bottom = has_client_edge_ ? 0 : subdip_layout_inset; | |
| 468 bubble_rect.Inset(error_left + 0.5, 0.5, error_right + 0.5, | |
| 469 error_bottom + 0.5); | |
| 470 | |
| 471 SkPath path; | |
| 472 path.addRoundRect(gfx::RectFToSkRect(bubble_rect), rad); | |
| 473 | |
| 474 SkPaint paint; | |
| 475 paint.setStyle(SkPaint::kStroke_Style); | |
| 476 paint.setStrokeWidth(1); | |
| 477 paint.setAntiAlias(true); | |
| 478 | |
| 479 SkPath stroke_path; | |
| 480 paint.getFillPath(path, &stroke_path); | |
| 481 | |
| 482 // Get the fill path by subtracting the shadow so they algin neatly. | |
|
Peter Kasting
2016/08/24 22:53:24
Nit: align
Bret
2016/08/25 18:05:38
Done.
| |
| 483 SkPath fill_path; | |
| 484 Op(path, stroke_path, kDifference_SkPathOp, &fill_path); | |
| 485 paint.setStyle(SkPaint::kFill_Style); | |
| 486 paint.setColor(bubble_color_); | |
| 487 canvas->sk_canvas()->drawPath(fill_path, paint); | |
| 488 | |
| 489 paint.setColor(kShadowColor); | |
| 490 canvas->sk_canvas()->drawPath(stroke_path, paint); | |
| 491 | |
| 492 canvas->Restore(); | |
| 429 | 493 |
| 430 // Compute text bounds. | 494 // Compute text bounds. |
| 431 const gfx::FontList font_list; | 495 gfx::Rect text_rect(kTextPositionX, 0, |
| 432 int text_width = | 496 popup_size_.width() - kTextHorizPadding, |
| 433 std::min(gfx::GetStringWidth(text_, font_list), | 497 popup_size_.height()); |
| 434 width - shadow_size - kTextPositionX - kTextHorizPadding); | 498 text_rect.Inset(kShadowThickness, kShadowThickness); |
| 435 int text_height = height - shadow_size; | |
| 436 gfx::Rect text_bounds(kShadowThickness + kTextPositionX, | |
| 437 kShadowThickness, | |
| 438 std::max(0, text_width), | |
| 439 std::max(0, text_height)); | |
| 440 // Make sure the text is aligned to the right on RTL UIs. | 499 // Make sure the text is aligned to the right on RTL UIs. |
| 441 text_bounds.set_x(GetMirroredXForRect(text_bounds)); | 500 text_rect.set_x(GetMirroredXForRect(text_rect)); |
| 442 | 501 |
| 443 // Text color is the foreground tab text color at 60% alpha. | 502 // Text color is the foreground tab text color at 60% alpha. |
| 444 SkColor text_color = color_utils::AlphaBlend( | 503 SkColor blended_text_color = |
| 445 theme_provider_->GetColor(ThemeProperties::COLOR_TAB_TEXT), toolbar_color, | 504 color_utils::AlphaBlend(bubble_text_color_, bubble_color_, 0x99); |
| 446 0x99); | |
| 447 canvas->DrawStringRect( | 505 canvas->DrawStringRect( |
| 448 text_, font_list, | 506 text_, gfx::FontList(), |
| 449 color_utils::GetReadableColor(text_color, toolbar_color), text_bounds); | 507 color_utils::GetReadableColor(blended_text_color, bubble_color_), |
| 508 text_rect); | |
| 450 } | 509 } |
| 451 | 510 |
| 452 | 511 |
| 453 // StatusBubbleViews::StatusViewAnimation -------------------------------------- | 512 // StatusBubbleViews::StatusViewAnimation -------------------------------------- |
| 454 | 513 |
| 455 StatusBubbleViews::StatusViewAnimation::StatusViewAnimation( | 514 StatusBubbleViews::StatusViewAnimation::StatusViewAnimation( |
| 456 StatusView* status_view, | 515 StatusView* status_view, |
| 457 float opacity_start, | 516 float opacity_start, |
| 458 float opacity_end) | 517 float opacity_end) |
| 459 : gfx::LinearAnimation(kFramerate, this), | 518 : gfx::LinearAnimation(kFramerate, this), |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 498 status_view_(status_view), | 557 status_view_(status_view), |
| 499 expansion_start_(0), | 558 expansion_start_(0), |
| 500 expansion_end_(0) { | 559 expansion_end_(0) { |
| 501 } | 560 } |
| 502 | 561 |
| 503 // Manage the expansion of the bubble. | 562 // Manage the expansion of the bubble. |
| 504 void StartExpansion(const base::string16& expanded_text, | 563 void StartExpansion(const base::string16& expanded_text, |
| 505 int current_width, | 564 int current_width, |
| 506 int expansion_end); | 565 int expansion_end); |
| 507 | 566 |
| 508 // Set width of fully expanded bubble. | |
| 509 void SetExpandedWidth(int expanded_width); | |
| 510 | |
| 511 private: | 567 private: |
| 512 // Animation functions. | 568 // Animation functions. |
| 513 int GetCurrentBubbleWidth(); | 569 int GetCurrentBubbleWidth(); |
| 514 void SetBubbleWidth(int width); | 570 void SetBubbleWidth(int width); |
| 515 void AnimateToState(double state) override; | 571 void AnimateToState(double state) override; |
| 516 void AnimationEnded(const gfx::Animation* animation) override; | 572 void AnimationEnded(const gfx::Animation* animation) override; |
| 517 | 573 |
| 518 // Manager that owns us. | 574 // Manager that owns us. |
| 519 StatusBubbleViews* status_bubble_; | 575 StatusBubbleViews* status_bubble_; |
| 520 | 576 |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 562 void StatusBubbleViews::StatusViewExpander::SetBubbleWidth(int width) { | 618 void StatusBubbleViews::StatusViewExpander::SetBubbleWidth(int width) { |
| 563 status_bubble_->SetBubbleWidth(width); | 619 status_bubble_->SetBubbleWidth(width); |
| 564 status_view_->SchedulePaint(); | 620 status_view_->SchedulePaint(); |
| 565 } | 621 } |
| 566 | 622 |
| 567 | 623 |
| 568 // StatusBubbleViews ----------------------------------------------------------- | 624 // StatusBubbleViews ----------------------------------------------------------- |
| 569 | 625 |
| 570 const int StatusBubbleViews::kShadowThickness = 1; | 626 const int StatusBubbleViews::kShadowThickness = 1; |
| 571 | 627 |
| 572 StatusBubbleViews::StatusBubbleViews(views::View* base_view) | 628 StatusBubbleViews::StatusBubbleViews(views::View* base_view, |
| 629 bool has_client_edge) | |
| 573 : contains_mouse_(false), | 630 : contains_mouse_(false), |
| 574 offset_(0), | 631 offset_(0), |
| 575 base_view_(base_view), | 632 base_view_(base_view), |
| 576 view_(NULL), | 633 view_(NULL), |
| 577 download_shelf_is_visible_(false), | 634 download_shelf_is_visible_(false), |
| 578 is_expanded_(false), | 635 is_expanded_(false), |
| 636 has_client_edge_(has_client_edge), | |
| 579 expand_timer_factory_(this) { | 637 expand_timer_factory_(this) { |
| 580 expand_view_.reset(); | 638 expand_view_.reset(); |
| 581 } | 639 } |
| 582 | 640 |
| 583 StatusBubbleViews::~StatusBubbleViews() { | 641 StatusBubbleViews::~StatusBubbleViews() { |
| 584 CancelExpandTimer(); | 642 CancelExpandTimer(); |
| 585 if (popup_.get()) | 643 if (popup_.get()) |
| 586 popup_->CloseNow(); | 644 popup_->CloseNow(); |
| 587 } | 645 } |
| 588 | 646 |
| 589 void StatusBubbleViews::Init() { | 647 void StatusBubbleViews::Init() { |
| 590 if (!popup_.get()) { | 648 if (!popup_.get()) { |
| 591 popup_.reset(new views::Widget); | 649 popup_.reset(new views::Widget); |
| 592 views::Widget* frame = base_view_->GetWidget(); | 650 views::Widget* frame = base_view_->GetWidget(); |
| 593 if (!view_) | 651 if (!view_) { |
| 594 view_ = new StatusView(popup_.get(), frame->GetThemeProvider()); | 652 const ui::ThemeProvider* theme_provider = frame->GetThemeProvider(); |
| 653 view_ = new StatusView( | |
| 654 popup_.get(), size_, | |
| 655 theme_provider->GetColor(ThemeProperties::COLOR_TOOLBAR), | |
| 656 theme_provider->GetColor(ThemeProperties::COLOR_TAB_TEXT), | |
| 657 has_client_edge_); | |
| 658 } | |
| 595 if (!expand_view_.get()) | 659 if (!expand_view_.get()) |
| 596 expand_view_.reset(new StatusViewExpander(this, view_)); | 660 expand_view_.reset(new StatusViewExpander(this, view_)); |
| 597 | 661 |
| 598 views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP); | 662 views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP); |
| 599 #if defined(OS_WIN) | 663 #if defined(OS_WIN) |
| 600 // On Windows use the software compositor to ensure that we don't block | 664 // On Windows use the software compositor to ensure that we don't block |
| 601 // the UI thread blocking issue during command buffer creation. We can | 665 // the UI thread blocking issue during command buffer creation. We can |
| 602 // revert this change once http://crbug.com/125248 is fixed. | 666 // revert this change once http://crbug.com/125248 is fixed. |
| 603 params.force_software_compositing = true; | 667 params.force_software_compositing = true; |
| 604 #endif | 668 #endif |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 619 popup_->SetContentsView(view_); | 683 popup_->SetContentsView(view_); |
| 620 #if defined(USE_ASH) | 684 #if defined(USE_ASH) |
| 621 ash::wm::GetWindowState(popup_->GetNativeWindow())-> | 685 ash::wm::GetWindowState(popup_->GetNativeWindow())-> |
| 622 set_ignored_by_shelf(true); | 686 set_ignored_by_shelf(true); |
| 623 #endif | 687 #endif |
| 624 RepositionPopup(); | 688 RepositionPopup(); |
| 625 } | 689 } |
| 626 } | 690 } |
| 627 | 691 |
| 628 void StatusBubbleViews::Reposition() { | 692 void StatusBubbleViews::Reposition() { |
| 629 // In restored mode, the client area has a client edge between it and the | 693 // Overlap the client edge that's shown in restored mode, or when there is no |
| 630 // frame. | 694 // client edge this makes the bubble snug with the corner of the window. |
| 631 int overlap = kShadowThickness; | 695 int overlap = kShadowThickness; |
| 632 int height = GetPreferredSize().height(); | 696 int height = GetPreferredSize().height(); |
| 633 int base_view_height = base_view()->bounds().height(); | 697 int base_view_height = base_view()->bounds().height(); |
| 634 gfx::Point origin(-overlap, base_view_height - height + overlap); | 698 gfx::Point origin(-overlap, base_view_height - height + overlap); |
| 635 SetBounds(origin.x(), origin.y(), base_view()->bounds().width() / 3, height); | 699 SetBounds(origin.x(), origin.y(), base_view()->bounds().width() / 3, height); |
| 636 } | 700 } |
| 637 | 701 |
| 638 void StatusBubbleViews::RepositionPopup() { | 702 void StatusBubbleViews::RepositionPopup() { |
| 639 if (popup_.get()) { | 703 if (popup_.get()) { |
| 640 gfx::Point top_left; | 704 gfx::Point top_left; |
| 641 // TODO(flackr): Get the non-transformed point so that the status bubble | 705 // TODO(flackr): Get the non-transformed point so that the status bubble |
| 642 // popup window's position is consistent with the base_view_'s window. | 706 // popup window's position is consistent with the base_view_'s window. |
| 643 views::View::ConvertPointToScreen(base_view_, &top_left); | 707 views::View::ConvertPointToScreen(base_view_, &top_left); |
| 644 | 708 |
| 709 view_->SetWidth(size_.width()); | |
| 645 popup_->SetBounds(gfx::Rect(top_left.x() + position_.x(), | 710 popup_->SetBounds(gfx::Rect(top_left.x() + position_.x(), |
| 646 top_left.y() + position_.y(), | 711 top_left.y() + position_.y(), |
| 647 size_.width(), size_.height())); | 712 size_.width(), size_.height())); |
| 648 } | 713 } |
| 649 } | 714 } |
| 650 | 715 |
| 651 gfx::Size StatusBubbleViews::GetPreferredSize() { | 716 gfx::Size StatusBubbleViews::GetPreferredSize() { |
| 652 return gfx::Size(0, gfx::FontList().GetHeight() + kTotalVerticalPadding); | 717 return gfx::Size(0, gfx::FontList().GetHeight() + kTotalVerticalPadding); |
| 653 } | 718 } |
| 654 | 719 |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 699 return; | 764 return; |
| 700 } | 765 } |
| 701 | 766 |
| 702 // Reset expansion state only when bubble is completely hidden. | 767 // Reset expansion state only when bubble is completely hidden. |
| 703 if (view_->state() == StatusView::BUBBLE_HIDDEN) { | 768 if (view_->state() == StatusView::BUBBLE_HIDDEN) { |
| 704 is_expanded_ = false; | 769 is_expanded_ = false; |
| 705 SetBubbleWidth(GetStandardStatusBubbleWidth()); | 770 SetBubbleWidth(GetStandardStatusBubbleWidth()); |
| 706 } | 771 } |
| 707 | 772 |
| 708 // Set Elided Text corresponding to the GURL object. | 773 // Set Elided Text corresponding to the GURL object. |
| 709 gfx::Rect popup_bounds = popup_->GetWindowBoundsInScreen(); | 774 int text_width = static_cast<int>(size_.width() - (kShadowThickness * 2) - |
| 710 int text_width = static_cast<int>(popup_bounds.width() - | 775 kTextPositionX - kTextHorizPadding - 1); |
| 711 (kShadowThickness * 2) - kTextPositionX - kTextHorizPadding - 1); | |
| 712 url_text_ = | 776 url_text_ = |
| 713 url_formatter::ElideUrl(url, gfx::FontList(), text_width); | 777 url_formatter::ElideUrl(url, gfx::FontList(), text_width); |
| 714 | 778 |
| 715 // An URL is always treated as a left-to-right string. On right-to-left UIs | 779 // An URL is always treated as a left-to-right string. On right-to-left UIs |
| 716 // we need to explicitly mark the URL as LTR to make sure it is displayed | 780 // we need to explicitly mark the URL as LTR to make sure it is displayed |
| 717 // correctly. | 781 // correctly. |
| 718 url_text_ = base::i18n::GetDisplayStringInLTRDirectionality(url_text_); | 782 url_text_ = base::i18n::GetDisplayStringInLTRDirectionality(url_text_); |
| 719 | 783 |
| 720 if (IsFrameVisible()) { | 784 if (IsFrameVisible()) { |
| 721 view_->SetText(url_text_, true); | 785 view_->SetText(url_text_, true); |
| (...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 865 | 929 |
| 866 bool StatusBubbleViews::IsFrameMaximized() { | 930 bool StatusBubbleViews::IsFrameMaximized() { |
| 867 views::Widget* frame = base_view_->GetWidget(); | 931 views::Widget* frame = base_view_->GetWidget(); |
| 868 views::Widget* window = frame->GetTopLevelWidget(); | 932 views::Widget* window = frame->GetTopLevelWidget(); |
| 869 return window && window->IsMaximized(); | 933 return window && window->IsMaximized(); |
| 870 } | 934 } |
| 871 | 935 |
| 872 void StatusBubbleViews::ExpandBubble() { | 936 void StatusBubbleViews::ExpandBubble() { |
| 873 // Elide URL to maximum possible size, then check actual length (it may | 937 // Elide URL to maximum possible size, then check actual length (it may |
| 874 // still be too long to fit) before expanding bubble. | 938 // still be too long to fit) before expanding bubble. |
| 875 gfx::Rect popup_bounds = popup_->GetWindowBoundsInScreen(); | |
| 876 int max_status_bubble_width = GetMaxStatusBubbleWidth(); | 939 int max_status_bubble_width = GetMaxStatusBubbleWidth(); |
| 877 const gfx::FontList font_list; | 940 const gfx::FontList font_list; |
| 878 url_text_ = url_formatter::ElideUrl(url_, font_list, max_status_bubble_width); | 941 url_text_ = url_formatter::ElideUrl(url_, font_list, max_status_bubble_width); |
| 879 int expanded_bubble_width = | 942 int expanded_bubble_width = |
| 880 std::max(GetStandardStatusBubbleWidth(), | 943 std::max(GetStandardStatusBubbleWidth(), |
| 881 std::min(gfx::GetStringWidth(url_text_, font_list) + | 944 std::min(gfx::GetStringWidth(url_text_, font_list) + |
| 882 (kShadowThickness * 2) + kTextPositionX + | 945 (kShadowThickness * 2) + kTextPositionX + |
| 883 kTextHorizPadding + 1, | 946 kTextHorizPadding + 1, |
| 884 max_status_bubble_width)); | 947 max_status_bubble_width)); |
| 885 is_expanded_ = true; | 948 is_expanded_ = true; |
| 886 expand_view_->StartExpansion(url_text_, popup_bounds.width(), | 949 expand_view_->StartExpansion(url_text_, size_.width(), expanded_bubble_width); |
| 887 expanded_bubble_width); | |
| 888 } | 950 } |
| 889 | 951 |
| 890 int StatusBubbleViews::GetStandardStatusBubbleWidth() { | 952 int StatusBubbleViews::GetStandardStatusBubbleWidth() { |
| 891 return base_view_->bounds().width() / 3; | 953 return base_view_->bounds().width() / 3; |
| 892 } | 954 } |
| 893 | 955 |
| 894 int StatusBubbleViews::GetMaxStatusBubbleWidth() { | 956 int StatusBubbleViews::GetMaxStatusBubbleWidth() { |
| 895 const ui::NativeTheme* theme = base_view_->GetNativeTheme(); | 957 const ui::NativeTheme* theme = base_view_->GetNativeTheme(); |
| 896 return static_cast<int>(std::max(0, base_view_->bounds().width() - | 958 return static_cast<int>(std::max(0, base_view_->bounds().width() - |
| 897 (kShadowThickness * 2) - kTextPositionX - kTextHorizPadding - 1 - | 959 (kShadowThickness * 2) - kTextPositionX - kTextHorizPadding - 1 - |
| 898 views::NativeScrollBar::GetVerticalScrollBarWidth(theme))); | 960 views::NativeScrollBar::GetVerticalScrollBarWidth(theme))); |
| 899 } | 961 } |
| 900 | 962 |
| 901 void StatusBubbleViews::SetBubbleWidth(int width) { | 963 void StatusBubbleViews::SetBubbleWidth(int width) { |
| 902 size_.set_width(width); | 964 size_.set_width(width); |
| 903 SetBounds(original_position_.x(), original_position_.y(), | 965 SetBounds(original_position_.x(), original_position_.y(), |
| 904 size_.width(), size_.height()); | 966 size_.width(), size_.height()); |
| 905 } | 967 } |
| 906 | 968 |
| 907 void StatusBubbleViews::CancelExpandTimer() { | 969 void StatusBubbleViews::CancelExpandTimer() { |
| 908 if (expand_timer_factory_.HasWeakPtrs()) | 970 if (expand_timer_factory_.HasWeakPtrs()) |
| 909 expand_timer_factory_.InvalidateWeakPtrs(); | 971 expand_timer_factory_.InvalidateWeakPtrs(); |
| 910 } | 972 } |
| OLD | NEW |