diff options
Diffstat (limited to 'chrome/browser/views/status_bubble_views.cc')
-rw-r--r-- | chrome/browser/views/status_bubble_views.cc | 835 |
1 files changed, 0 insertions, 835 deletions
diff --git a/chrome/browser/views/status_bubble_views.cc b/chrome/browser/views/status_bubble_views.cc deleted file mode 100644 index 234b6f0..0000000 --- a/chrome/browser/views/status_bubble_views.cc +++ /dev/null @@ -1,835 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/views/status_bubble_views.h" - -#include <algorithm> - -#include "app/linear_animation.h" -#include "app/resource_bundle.h" -#include "app/text_elider.h" -#include "base/i18n/rtl.h" -#include "base/message_loop.h" -#include "base/string_util.h" -#include "base/utf_string_conversions.h" -#include "chrome/browser/themes/browser_theme_provider.h" -#include "gfx/canvas_skia.h" -#include "gfx/point.h" -#include "googleurl/src/gurl.h" -#include "grit/generated_resources.h" -#include "grit/theme_resources.h" -#include "net/base/net_util.h" -#include "third_party/skia/include/core/SkPaint.h" -#include "third_party/skia/include/core/SkPath.h" -#include "third_party/skia/include/core/SkRect.h" -#include "views/controls/label.h" -#include "views/controls/scrollbar/native_scroll_bar.h" -#include "views/screen.h" -#include "views/widget/root_view.h" -#include "views/widget/widget.h" -#include "views/window/window.h" - -using views::Widget; - -// The alpha and color of the bubble's shadow. -static const SkColor kShadowColor = SkColorSetARGB(30, 0, 0, 0); - -// The roundedness of the edges of our bubble. -static const int kBubbleCornerRadius = 4; - -// How close the mouse can get to the infobubble before it starts sliding -// off-screen. -static const int kMousePadding = 20; - -// The horizontal offset of the text within the status bubble, not including the -// outer shadow ring. -static const int kTextPositionX = 3; - -// The minimum horizontal space between the (right) end of the text and the edge -// of the status bubble, not including the outer shadow ring. -static const int kTextHorizPadding = 1; - -// Delays before we start hiding or showing the bubble after we receive a -// show or hide request. -static const int kShowDelay = 80; -static const int kHideDelay = 250; - -// How long each fade should last for. -static const int kShowFadeDurationMS = 120; -static const int kHideFadeDurationMS = 200; -static const int kFramerate = 25; - -// How long each expansion step should take. -static const int kMinExpansionStepDurationMS = 20; -static const int kMaxExpansionStepDurationMS = 150; - -// View ----------------------------------------------------------------------- -// StatusView manages the display of the bubble, applying text changes and -// fading in or out the bubble as required. -class StatusBubbleViews::StatusView : public views::Label, - public LinearAnimation, - public AnimationDelegate { - public: - StatusView(StatusBubble* status_bubble, views::Widget* popup, - ThemeProvider* theme_provider) - : ALLOW_THIS_IN_INITIALIZER_LIST(LinearAnimation(kFramerate, this)), - stage_(BUBBLE_HIDDEN), - style_(STYLE_STANDARD), - ALLOW_THIS_IN_INITIALIZER_LIST(timer_factory_(this)), - status_bubble_(status_bubble), - popup_(popup), - opacity_start_(0), - opacity_end_(0), - theme_provider_(theme_provider) { - ResourceBundle& rb = ResourceBundle::GetSharedInstance(); - gfx::Font font(rb.GetFont(ResourceBundle::BaseFont)); - SetFont(font); - } - - virtual ~StatusView() { - Stop(); - CancelTimer(); - } - - // The bubble can be in one of many stages: - enum BubbleStage { - BUBBLE_HIDDEN, // Entirely BUBBLE_HIDDEN. - BUBBLE_HIDING_FADE, // In a fade-out transition. - BUBBLE_HIDING_TIMER, // Waiting before a fade-out. - BUBBLE_SHOWING_TIMER, // Waiting before a fade-in. - BUBBLE_SHOWING_FADE, // In a fade-in transition. - BUBBLE_SHOWN // Fully visible. - }; - - enum BubbleStyle { - STYLE_BOTTOM, - STYLE_FLOATING, - STYLE_STANDARD, - STYLE_STANDARD_RIGHT - }; - - // Set the bubble text to a certain value, hides the bubble if text is - // an empty string. Trigger animation sequence to display if - // |should_animate_open|. - void SetText(const string16& text, bool should_animate_open); - - BubbleStage GetState() const { return stage_; } - - void SetStyle(BubbleStyle style); - - BubbleStyle GetStyle() const { return style_; } - - // Show the bubble instantly. - void Show(); - - // Hide the bubble instantly. - void Hide(); - - // Resets any timers we have. Typically called when the user moves a - // mouse. - void ResetTimer(); - - private: - class InitialTimer; - - // Manage the timers that control the delay before a fade begins or ends. - void StartTimer(int time); - void OnTimer(); - void CancelTimer(); - void RestartTimer(int delay); - - // Manage the fades and starting and stopping the animations correctly. - void StartFade(double start, double end, int duration); - void StartHiding(); - void StartShowing(); - - // Animation functions. - double GetCurrentOpacity(); - void SetOpacity(double opacity); - void AnimateToState(double state); - void AnimationEnded(const Animation* animation); - - virtual void Paint(gfx::Canvas* canvas); - - BubbleStage stage_; - BubbleStyle style_; - - ScopedRunnableMethodFactory<StatusBubbleViews::StatusView> timer_factory_; - - // Manager, owns us. - StatusBubble* status_bubble_; - - // Handle to the widget that contains us. - views::Widget* popup_; - - // The currently-displayed text. - string16 text_; - - // Start and end opacities for the current transition - note that as a - // fade-in can easily turn into a fade out, opacity_start_ is sometimes - // a value between 0 and 1. - double opacity_start_; - double opacity_end_; - - // Holds the theme provider of the frame that created us. - ThemeProvider* theme_provider_; -}; - -void StatusBubbleViews::StatusView::SetText(const string16& text, - bool should_animate_open) { - if (text.empty()) { - // The string was empty. - StartHiding(); - } else { - // We want to show the string. - text_ = text; - if (should_animate_open) - StartShowing(); - } - - SchedulePaint(); -} - -void StatusBubbleViews::StatusView::Show() { - Stop(); - CancelTimer(); - SetOpacity(1.0); - popup_->Show(); - stage_ = BUBBLE_SHOWN; - PaintNow(); -} - -void StatusBubbleViews::StatusView::Hide() { - Stop(); - CancelTimer(); - SetOpacity(0.0); - text_.clear(); - popup_->Hide(); - stage_ = BUBBLE_HIDDEN; -} - -void StatusBubbleViews::StatusView::StartTimer(int time) { - if (!timer_factory_.empty()) - timer_factory_.RevokeAll(); - - MessageLoop::current()->PostDelayedTask(FROM_HERE, - timer_factory_.NewRunnableMethod(&StatusBubbleViews::StatusView::OnTimer), - time); -} - -void StatusBubbleViews::StatusView::OnTimer() { - if (stage_ == BUBBLE_HIDING_TIMER) { - stage_ = BUBBLE_HIDING_FADE; - StartFade(1.0, 0.0, kHideFadeDurationMS); - } else if (stage_ == BUBBLE_SHOWING_TIMER) { - stage_ = BUBBLE_SHOWING_FADE; - StartFade(0.0, 1.0, kShowFadeDurationMS); - } -} - -void StatusBubbleViews::StatusView::CancelTimer() { - if (!timer_factory_.empty()) - timer_factory_.RevokeAll(); -} - -void StatusBubbleViews::StatusView::RestartTimer(int delay) { - CancelTimer(); - StartTimer(delay); -} - -void StatusBubbleViews::StatusView::ResetTimer() { - if (stage_ == BUBBLE_SHOWING_TIMER) { - // We hadn't yet begun showing anything when we received a new request - // for something to show, so we start from scratch. - RestartTimer(kShowDelay); - } -} - -void StatusBubbleViews::StatusView::StartFade(double start, - double end, - int duration) { - opacity_start_ = start; - opacity_end_ = end; - - // This will also reset the currently-occurring animation. - SetDuration(duration); - Start(); -} - -void StatusBubbleViews::StatusView::StartHiding() { - if (stage_ == BUBBLE_SHOWN) { - stage_ = BUBBLE_HIDING_TIMER; - StartTimer(kHideDelay); - } else if (stage_ == BUBBLE_SHOWING_TIMER) { - stage_ = BUBBLE_HIDDEN; - CancelTimer(); - } else if (stage_ == BUBBLE_SHOWING_FADE) { - stage_ = BUBBLE_HIDING_FADE; - // Figure out where we are in the current fade. - double current_opacity = GetCurrentOpacity(); - - // Start a fade in the opposite direction. - StartFade(current_opacity, 0.0, - static_cast<int>(kHideFadeDurationMS * current_opacity)); - } -} - -void StatusBubbleViews::StatusView::StartShowing() { - if (stage_ == BUBBLE_HIDDEN) { - popup_->Show(); - stage_ = BUBBLE_SHOWING_TIMER; - StartTimer(kShowDelay); - } else if (stage_ == BUBBLE_HIDING_TIMER) { - stage_ = BUBBLE_SHOWN; - CancelTimer(); - } else if (stage_ == BUBBLE_HIDING_FADE) { - // We're partway through a fade. - stage_ = BUBBLE_SHOWING_FADE; - - // Figure out where we are in the current fade. - double current_opacity = GetCurrentOpacity(); - - // Start a fade in the opposite direction. - StartFade(current_opacity, 1.0, - static_cast<int>(kShowFadeDurationMS * current_opacity)); - } else if (stage_ == BUBBLE_SHOWING_TIMER) { - // We hadn't yet begun showing anything when we received a new request - // for something to show, so we start from scratch. - ResetTimer(); - } -} - -// Animation functions. -double StatusBubbleViews::StatusView::GetCurrentOpacity() { - return opacity_start_ + (opacity_end_ - opacity_start_) * - LinearAnimation::GetCurrentValue(); -} - -void StatusBubbleViews::StatusView::SetOpacity(double opacity) { - popup_->SetOpacity(static_cast<unsigned char>(opacity * 255)); - SchedulePaint(); -} - -void StatusBubbleViews::StatusView::AnimateToState(double state) { - SetOpacity(GetCurrentOpacity()); -} - -void StatusBubbleViews::StatusView::AnimationEnded( - const Animation* animation) { - SetOpacity(opacity_end_); - - if (stage_ == BUBBLE_HIDING_FADE) { - stage_ = BUBBLE_HIDDEN; - popup_->Hide(); - } else if (stage_ == BUBBLE_SHOWING_FADE) { - stage_ = BUBBLE_SHOWN; - } -} - -void StatusBubbleViews::StatusView::SetStyle(BubbleStyle style) { - if (style_ != style) { - style_ = style; - SchedulePaint(); - } -} - -void StatusBubbleViews::StatusView::Paint(gfx::Canvas* canvas) { - SkPaint paint; - paint.setStyle(SkPaint::kFill_Style); - paint.setFlags(SkPaint::kAntiAlias_Flag); - SkColor toolbar_color = - theme_provider_->GetColor(BrowserThemeProvider::COLOR_TOOLBAR); - paint.setColor(toolbar_color); - - gfx::Rect popup_bounds; - popup_->GetBounds(&popup_bounds, true); - - // Figure out how to round the bubble's four corners. - SkScalar rad[8]; - - // Top Edges - if the bubble is in its bottom position (sticking downwards), - // then we square the top edges. Otherwise, we square the edges based on the - // position of the bubble within the window (the bubble is positioned in the - // southeast corner in RTL and in the southwest corner in LTR). - if (style_ == STYLE_BOTTOM) { - // Top Left corner. - rad[0] = 0; - rad[1] = 0; - - // Top Right corner. - rad[2] = 0; - rad[3] = 0; - } else { - if (base::i18n::IsRTL() != (style_ == STYLE_STANDARD_RIGHT)) { - // The text is RtL or the bubble is on the right side (but not both). - - // Top Left corner. - rad[0] = SkIntToScalar(kBubbleCornerRadius); - rad[1] = SkIntToScalar(kBubbleCornerRadius); - - // Top Right corner. - rad[2] = 0; - rad[3] = 0; - } else { - // Top Left corner. - rad[0] = 0; - rad[1] = 0; - - // Top Right corner. - rad[2] = SkIntToScalar(kBubbleCornerRadius); - rad[3] = SkIntToScalar(kBubbleCornerRadius); - } - } - - // Bottom edges - square these off if the bubble is in its standard position - // (sticking upward). - if (style_ == STYLE_STANDARD || style_ == STYLE_STANDARD_RIGHT) { - // Bottom Right Corner. - rad[4] = 0; - rad[5] = 0; - - // Bottom Left Corner. - rad[6] = 0; - rad[7] = 0; - } else { - // Bottom Right Corner. - rad[4] = SkIntToScalar(kBubbleCornerRadius); - rad[5] = SkIntToScalar(kBubbleCornerRadius); - - // Bottom Left Corner. - rad[6] = SkIntToScalar(kBubbleCornerRadius); - rad[7] = SkIntToScalar(kBubbleCornerRadius); - } - - // Draw the bubble's shadow. - int width = popup_bounds.width(); - int height = popup_bounds.height(); - SkRect rect; - rect.set(0, 0, - SkIntToScalar(width), - SkIntToScalar(height)); - SkPath shadow_path; - shadow_path.addRoundRect(rect, rad, SkPath::kCW_Direction); - SkPaint shadow_paint; - shadow_paint.setFlags(SkPaint::kAntiAlias_Flag); - shadow_paint.setColor(kShadowColor); - canvas->AsCanvasSkia()->drawPath(shadow_path, shadow_paint); - - // Draw the bubble. - rect.set(SkIntToScalar(kShadowThickness), - SkIntToScalar(kShadowThickness), - SkIntToScalar(width - kShadowThickness), - SkIntToScalar(height - kShadowThickness)); - SkPath path; - path.addRoundRect(rect, rad, SkPath::kCW_Direction); - canvas->AsCanvasSkia()->drawPath(path, paint); - - // Draw highlight text and then the text body. In order to make sure the text - // is aligned to the right on RTL UIs, we mirror the text bounds if the - // locale is RTL. - int text_width = std::min( - views::Label::font().GetStringWidth(UTF16ToWide(text_)), - width - (kShadowThickness * 2) - kTextPositionX - kTextHorizPadding); - int text_height = height - (kShadowThickness * 2); - gfx::Rect body_bounds(kShadowThickness + kTextPositionX, - kShadowThickness, - std::max(0, text_width), - std::max(0, text_height)); - body_bounds.set_x(MirroredLeftPointForRect(body_bounds)); - SkColor text_color = - theme_provider_->GetColor(BrowserThemeProvider::COLOR_TAB_TEXT); - - // DrawStringInt doesn't handle alpha, so we'll do the blending ourselves. - text_color = SkColorSetARGB( - SkColorGetA(text_color), - (SkColorGetR(text_color) + SkColorGetR(toolbar_color)) / 2, - (SkColorGetG(text_color) + SkColorGetR(toolbar_color)) / 2, - (SkColorGetB(text_color) + SkColorGetR(toolbar_color)) / 2); - canvas->DrawStringInt(UTF16ToWide(text_), - views::Label::font(), - text_color, - body_bounds.x(), - body_bounds.y(), - body_bounds.width(), - body_bounds.height()); -} - -// StatusViewExpander --------------------------------------------------------- -// Manages the expansion and contraction of the status bubble as it accommodates -// URLs too long to fit in the standard bubble. Changes are passed through the -// StatusView to paint. -class StatusBubbleViews::StatusViewExpander : public LinearAnimation, - public AnimationDelegate { - public: - StatusViewExpander(StatusBubbleViews* status_bubble, - StatusView* status_view) - : ALLOW_THIS_IN_INITIALIZER_LIST(LinearAnimation(kFramerate, this)), - status_bubble_(status_bubble), - status_view_(status_view), - expansion_start_(0), - expansion_end_(0) { - } - - // Manage the expansion of the bubble. - void StartExpansion(string16 expanded_text, int current_width, - int expansion_end); - - // Set width of fully expanded bubble. - void SetExpandedWidth(int expanded_width); - - private: - // Animation functions. - int GetCurrentBubbleWidth(); - void SetBubbleWidth(int width); - void AnimateToState(double state); - void AnimationEnded(const Animation* animation); - - // Manager that owns us. - StatusBubbleViews* status_bubble_; - - // Change the bounds and text of this view. - StatusView* status_view_; - - // Text elided (if needed) to fit maximum status bar width. - string16 expanded_text_; - - // Widths at expansion start and end. - int expansion_start_; - int expansion_end_; -}; - -void StatusBubbleViews::StatusViewExpander::AnimateToState(double state) { - SetBubbleWidth(GetCurrentBubbleWidth()); -} - -void StatusBubbleViews::StatusViewExpander::AnimationEnded( - const Animation* animation) { - SetBubbleWidth(expansion_end_); - status_view_->SetText(expanded_text_, false); -} - -void StatusBubbleViews::StatusViewExpander::StartExpansion( - string16 expanded_text, int expansion_start, - int expansion_end) { - expanded_text_ = expanded_text; - expansion_start_ = expansion_start; - expansion_end_ = expansion_end; - int min_duration = std::max(kMinExpansionStepDurationMS, - static_cast<int>(kMaxExpansionStepDurationMS * - (expansion_end - expansion_start) / 100.0)); - SetDuration(std::min(kMaxExpansionStepDurationMS, min_duration)); - Start(); -} - -int StatusBubbleViews::StatusViewExpander::GetCurrentBubbleWidth() { - return static_cast<int>(expansion_start_ + - (expansion_end_ - expansion_start_) * LinearAnimation::GetCurrentValue()); -} - -void StatusBubbleViews::StatusViewExpander::SetBubbleWidth(int width) { - status_bubble_->SetBubbleWidth(width); - status_view_->SchedulePaint(); -} - -// StatusBubble --------------------------------------------------------------- - -const int StatusBubbleViews::kShadowThickness = 1; - -StatusBubbleViews::StatusBubbleViews(views::View* base_view) - : offset_(0), - popup_(NULL), - opacity_(0), - base_view_(base_view), - view_(NULL), - download_shelf_is_visible_(false), - is_expanded_(false), - ALLOW_THIS_IN_INITIALIZER_LIST(expand_timer_factory_(this)) { - expand_view_.reset(); -} - -StatusBubbleViews::~StatusBubbleViews() { - CancelExpandTimer(); - if (popup_.get()) - popup_->CloseNow(); -} - -void StatusBubbleViews::Init() { - if (!popup_.get()) { - popup_.reset(Widget::CreatePopupWidget(Widget::Transparent, - Widget::NotAcceptEvents, - Widget::NotDeleteOnDestroy, - Widget::MirrorOriginInRTL)); - views::Widget* frame = base_view_->GetWidget(); - if (!view_) - view_ = new StatusView(this, popup_.get(), frame->GetThemeProvider()); - if (!expand_view_.get()) - expand_view_.reset(new StatusViewExpander(this, view_)); - popup_->SetOpacity(0x00); - popup_->Init(frame->GetNativeView(), gfx::Rect()); - popup_->SetContentsView(view_); - Reposition(); - popup_->Show(); - } -} - -void StatusBubbleViews::Reposition() { - if (popup_.get()) { - gfx::Point top_left; - views::View::ConvertPointToScreen(base_view_, &top_left); - - popup_->SetBounds(gfx::Rect(top_left.x() + position_.x(), - top_left.y() + position_.y(), - size_.width(), size_.height())); - } -} - -gfx::Size StatusBubbleViews::GetPreferredSize() { - return gfx::Size(0, ResourceBundle::GetSharedInstance().GetFont( - ResourceBundle::BaseFont).GetHeight() + kTotalVerticalPadding); -} - -void StatusBubbleViews::SetBounds(int x, int y, int w, int h) { - original_position_.SetPoint(x, y); - position_.SetPoint(base_view_->MirroredXWithWidthInsideView(x, w), y); - size_.SetSize(w, h); - Reposition(); -} - -void StatusBubbleViews::SetStatus(const string16& status_text) { - if (size_.IsEmpty()) - return; // We have no bounds, don't attempt to show the popup. - - if (status_text_ == status_text && !status_text.empty()) - return; - - if (!IsFrameVisible()) - return; // Don't show anything if the parent isn't visible. - - Init(); - status_text_ = status_text; - if (!status_text_.empty()) { - view_->SetText(status_text, true); - view_->Show(); - } else if (!url_text_.empty()) { - view_->SetText(url_text_, true); - } else { - view_->SetText(string16(), true); - } -} - -void StatusBubbleViews::SetURL(const GURL& url, const string16& languages) { - languages_ = languages; - url_ = url; - if (size_.IsEmpty()) - return; // We have no bounds, don't attempt to show the popup. - - Init(); - - // If we want to clear a displayed URL but there is a status still to - // display, display that status instead. - if (url.is_empty() && !status_text_.empty()) { - url_text_ = string16(); - if (IsFrameVisible()) - view_->SetText(status_text_, true); - return; - } - - // Reset expansion state only when bubble is completely hidden. - if (view_->GetState() == StatusView::BUBBLE_HIDDEN) { - is_expanded_ = false; - SetBubbleWidth(GetStandardStatusBubbleWidth()); - } - - // Set Elided Text corresponding to the GURL object. - gfx::Rect popup_bounds; - popup_->GetBounds(&popup_bounds, true); - int text_width = static_cast<int>(popup_bounds.width() - - (kShadowThickness * 2) - kTextPositionX - kTextHorizPadding - 1); - url_text_ = gfx::ElideUrl(url, view_->Label::font(), - text_width, UTF16ToWideHack(languages)); - - std::wstring original_url_text = - UTF16ToWideHack(net::FormatUrl(url, UTF16ToUTF8(languages))); - - // An URL is always treated as a left-to-right string. On right-to-left UIs - // we need to explicitly mark the URL as LTR to make sure it is displayed - // correctly. - url_text_ = base::i18n::GetDisplayStringInLTRDirectionality(url_text_); - - if (IsFrameVisible()) { - view_->SetText(url_text_, true); - - CancelExpandTimer(); - - // If bubble is already in expanded state, shift to adjust to new text - // size (shrinking or expanding). Otherwise delay. - if (is_expanded_ && !url.is_empty()) - ExpandBubble(); - else if (original_url_text.length() > url_text_.length()) - MessageLoop::current()->PostDelayedTask(FROM_HERE, - expand_timer_factory_.NewRunnableMethod( - &StatusBubbleViews::ExpandBubble), kExpandHoverDelay); - } -} - -void StatusBubbleViews::Hide() { - status_text_ = string16(); - url_text_ = string16(); - if (view_) - view_->Hide(); -} - -void StatusBubbleViews::MouseMoved(const gfx::Point& location, - bool left_content) { - if (left_content) - return; - - if (view_) { - view_->ResetTimer(); - - if (view_->GetState() != StatusView::BUBBLE_HIDDEN && - view_->GetState() != StatusView::BUBBLE_HIDING_FADE && - view_->GetState() != StatusView::BUBBLE_HIDING_TIMER) { - AvoidMouse(location); - } - } -} - -void StatusBubbleViews::UpdateDownloadShelfVisibility(bool visible) { - download_shelf_is_visible_ = visible; -} - -void StatusBubbleViews::AvoidMouse(const gfx::Point& location) { - // Get the position of the frame. - gfx::Point top_left; - views::View::ConvertPointToScreen(base_view_, &top_left); - // Border included. - int window_width = base_view_->GetLocalBounds(true).width(); - - // Get the cursor position relative to the popup. - gfx::Point relative_location = location; - if (base::i18n::IsRTL()) { - int top_right_x = top_left.x() + window_width; - relative_location.set_x(top_right_x - relative_location.x()); - } else { - relative_location.set_x( - relative_location.x() - (top_left.x() + position_.x())); - } - relative_location.set_y( - relative_location.y() - (top_left.y() + position_.y())); - - // If the mouse is in a position where we think it would move the - // status bubble, figure out where and how the bubble should be moved. - if (relative_location.y() > -kMousePadding && - relative_location.x() < size_.width() + kMousePadding) { - int offset = kMousePadding + relative_location.y(); - - // Make the movement non-linear. - offset = offset * offset / kMousePadding; - - // When the mouse is entering from the right, we want the offset to be - // scaled by how horizontally far away the cursor is from the bubble. - if (relative_location.x() > size_.width()) { - offset = static_cast<int>(static_cast<float>(offset) * ( - static_cast<float>(kMousePadding - - (relative_location.x() - size_.width())) / - static_cast<float>(kMousePadding))); - } - - // Cap the offset and change the visual presentation of the bubble - // depending on where it ends up (so that rounded corners square off - // and mate to the edges of the tab content). - if (offset >= size_.height() - kShadowThickness * 2) { - offset = size_.height() - kShadowThickness * 2; - view_->SetStyle(StatusView::STYLE_BOTTOM); - } else if (offset > kBubbleCornerRadius / 2 - kShadowThickness) { - view_->SetStyle(StatusView::STYLE_FLOATING); - } else { - view_->SetStyle(StatusView::STYLE_STANDARD); - } - - // Check if the bubble sticks out from the monitor or will obscure - // download shelf. - gfx::NativeView widget = base_view_->GetWidget()->GetNativeView(); - gfx::Rect monitor_rect = - views::Screen::GetMonitorWorkAreaNearestWindow(widget); - const int bubble_bottom_y = top_left.y() + position_.y() + size_.height(); - - if (bubble_bottom_y + offset > monitor_rect.height() || - (download_shelf_is_visible_ && - (view_->GetStyle() == StatusView::STYLE_FLOATING || - view_->GetStyle() == StatusView::STYLE_BOTTOM))) { - // The offset is still too large. Move the bubble to the right and reset - // Y offset_ to zero. - view_->SetStyle(StatusView::STYLE_STANDARD_RIGHT); - offset_ = 0; - - // Subtract border width + bubble width. - int right_position_x = window_width - (position_.x() + size_.width()); - popup_->SetBounds(gfx::Rect(top_left.x() + right_position_x, - top_left.y() + position_.y(), - size_.width(), size_.height())); - } else { - offset_ = offset; - popup_->SetBounds(gfx::Rect(top_left.x() + position_.x(), - top_left.y() + position_.y() + offset_, - size_.width(), size_.height())); - } - } else if (offset_ != 0 || - view_->GetStyle() == StatusView::STYLE_STANDARD_RIGHT) { - offset_ = 0; - view_->SetStyle(StatusView::STYLE_STANDARD); - popup_->SetBounds(gfx::Rect(top_left.x() + position_.x(), - top_left.y() + position_.y(), - size_.width(), size_.height())); - } -} - -bool StatusBubbleViews::IsFrameVisible() { - views::Widget* frame = base_view_->GetWidget(); - if (!frame->IsVisible()) - return false; - - views::Window* window = frame->GetWindow(); - return !window || !window->IsMinimized(); -} - -void StatusBubbleViews::ExpandBubble() { - // Elide URL to maximum possible size, then check actual length (it may - // still be too long to fit) before expanding bubble. - gfx::Rect popup_bounds; - popup_->GetBounds(&popup_bounds, true); - int max_status_bubble_width = GetMaxStatusBubbleWidth(); - url_text_ = gfx::ElideUrl(url_, view_->Label::font(), - max_status_bubble_width, UTF16ToWideHack(languages_)); - int expanded_bubble_width =std::max(GetStandardStatusBubbleWidth(), - std::min(view_->Label::font().GetStringWidth(UTF16ToWide(url_text_)) + - (kShadowThickness * 2) + kTextPositionX + - kTextHorizPadding + 1, - max_status_bubble_width)); - is_expanded_ = true; - expand_view_->StartExpansion(url_text_, popup_bounds.width(), - expanded_bubble_width); -} - -int StatusBubbleViews::GetStandardStatusBubbleWidth() { - return base_view_->bounds().width() / 3; -} - -int StatusBubbleViews::GetMaxStatusBubbleWidth() { - return static_cast<int>(std::max(0, base_view_->bounds().width() - - (kShadowThickness * 2) - kTextPositionX - kTextHorizPadding - 1 - - views::NativeScrollBar::GetVerticalScrollBarWidth())); -} - -void StatusBubbleViews::SetBubbleWidth(int width) { - size_.set_width(width); - SetBounds(original_position_.x(), original_position_.y(), - size_.width(), size_.height()); -} - -void StatusBubbleViews::CancelExpandTimer() { - if (!expand_timer_factory_.empty()) - expand_timer_factory_.RevokeAll(); -} |