summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorpkasting@chromium.org <pkasting@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-04-20 06:25:10 +0000
committerpkasting@chromium.org <pkasting@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-04-20 06:25:10 +0000
commit2a28dc24c68f8cf3cee1b9667f5e51342cc5df04 (patch)
tree2817ae41fb74d22662a88a21d304dd739082a2e3
parent4e62446f597ada42213a573ccc1a683adb41eff6 (diff)
downloadchromium_src-2a28dc24c68f8cf3cee1b9667f5e51342cc5df04.zip
chromium_src-2a28dc24c68f8cf3cee1b9667f5e51342cc5df04.tar.gz
chromium_src-2a28dc24c68f8cf3cee1b9667f5e51342cc5df04.tar.bz2
Adjust infobar arrow height when the toolbar height changes. This also fixes infobars having thewrong top arrow height in popups.
BUG=76388 TEST=open and close the bookmark bar with an infobar open. The infobar arrow should adjust per the mocks in the bug. Review URL: http://codereview.chromium.org/6880059 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@82251 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc44
-rw-r--r--chrome/browser/ui/views/frame/browser_view.cc54
-rw-r--r--chrome/browser/ui/views/frame/browser_view_layout.cc14
-rw-r--r--chrome/browser/ui/views/infobars/extension_infobar.cc3
-rw-r--r--chrome/browser/ui/views/infobars/infobar.cc62
-rw-r--r--chrome/browser/ui/views/infobars/infobar.h37
-rw-r--r--chrome/browser/ui/views/infobars/infobar_background.cc14
-rw-r--r--chrome/browser/ui/views/infobars/infobar_background.h2
-rw-r--r--chrome/browser/ui/views/infobars/infobar_container.cc35
-rw-r--r--chrome/browser/ui/views/infobars/infobar_container.h21
-rw-r--r--chrome/browser/ui/views/infobars/infobar_view.cc60
-rw-r--r--chrome/browser/ui/views/infobars/infobar_view.h2
12 files changed, 241 insertions, 107 deletions
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc
index 657a169..e7d78a5 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc
@@ -439,8 +439,7 @@ gfx::Size BookmarkBarView::GetMinimumSize() {
if (OnNewTabPage()) {
double current_state = 1 - size_animation_->GetCurrentValue();
- width += 2 * static_cast<int>(static_cast<double>
- (kNewtabHorizontalPadding) * current_state);
+ width += 2 * static_cast<int>(kNewtabHorizontalPadding * current_state);
}
int sync_error_total_width = 0;
@@ -740,8 +739,7 @@ int BookmarkBarView::GetToolbarOverlap(bool return_max) const {
return 0;
// When on the New Tab Page with no infobar, animate the overlap between the
// attached and detached states.
- return static_cast<int>(static_cast<double>(kToolbarOverlap) *
- size_animation_->GetCurrentValue());
+ return static_cast<int>(kToolbarOverlap * size_animation_->GetCurrentValue());
}
bool BookmarkBarView::is_animating() {
@@ -1639,21 +1637,23 @@ gfx::Size BookmarkBarView::LayoutItems(bool compute_bounds_only) {
int top_margin = IsDetached() ? kDetachedTopMargin : 0;
int y = top_margin;
int width = View::width() - kRightMargin - kLeftMargin;
- int height = View::height() - top_margin - kBottomMargin;
+ int height = -top_margin - kBottomMargin;
int separator_margin = kSeparatorMargin;
if (OnNewTabPage()) {
double current_state = 1 - size_animation_->GetCurrentValue();
- x += static_cast<int>(static_cast<double>
- (kNewtabHorizontalPadding) * current_state);
- y += static_cast<int>(static_cast<double>
- (kNewtabVerticalPadding) * current_state);
- width -= static_cast<int>(static_cast<double>
- (kNewtabHorizontalPadding) * current_state);
- height -= static_cast<int>(static_cast<double>
- (kNewtabVerticalPadding * 2) * current_state);
- separator_margin -= static_cast<int>(static_cast<double>
- (kSeparatorMargin) * current_state);
+ x += static_cast<int>(kNewtabHorizontalPadding * current_state);
+ y += static_cast<int>(kNewtabVerticalPadding * current_state);
+ width -= static_cast<int>(kNewtabHorizontalPadding * current_state);
+ height += View::height() -
+ static_cast<int>(kNewtabVerticalPadding * 2 * current_state);
+ separator_margin -= static_cast<int>(kSeparatorMargin * current_state);
+ } else {
+ // For the attached appearance, pin the content to the bottom of the bar
+ // when animating in/out, as shrinking its height instead looks weird. This
+ // also matches how we layout infobars.
+ y += View::height() - kBarHeight;
+ height += kBarHeight;
}
gfx::Size other_bookmarked_pref =
@@ -1761,14 +1761,14 @@ gfx::Size BookmarkBarView::LayoutItems(bool compute_bounds_only) {
x += kRightMargin;
prefsize.set_width(x);
if (OnNewTabPage()) {
- x += static_cast<int>(static_cast<double>(kNewtabHorizontalPadding) *
- (1 - size_animation_->GetCurrentValue()));
- prefsize.set_height(kBarHeight + static_cast<int>(static_cast<double>
- (kNewtabBarHeight - kBarHeight) *
- (1 - size_animation_->GetCurrentValue())));
+ x += static_cast<int>(
+ kNewtabHorizontalPadding * (1 - size_animation_->GetCurrentValue()));
+ prefsize.set_height(kBarHeight +
+ static_cast<int>((kNewtabBarHeight - kBarHeight) *
+ (1 - size_animation_->GetCurrentValue())));
} else {
- prefsize.set_height(static_cast<int>(static_cast<double>(kBarHeight) *
- size_animation_->GetCurrentValue()));
+ prefsize.set_height(
+ static_cast<int>(kBarHeight * size_animation_->GetCurrentValue()));
}
}
return prefsize;
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc
index 08c035b..e52e0c1 100644
--- a/chrome/browser/ui/views/frame/browser_view.cc
+++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -8,6 +8,7 @@
#include <gtk/gtk.h>
#endif
+#include "base/auto_reset.h"
#include "base/command_line.h"
#include "base/i18n/rtl.h"
#include "base/metrics/histogram.h"
@@ -614,17 +615,51 @@ StatusBubble* BrowserView::GetStatusBubble() {
return status_bubble_.get();
}
+namespace {
+ // Only used by ToolbarSizeChanged() below, but placed here because template
+ // arguments (to AutoReset<>) must have external linkage.
+ enum CallState { NORMAL, REENTRANT, REENTRANT_FORCE_FAST_RESIZE };
+}
+
void BrowserView::ToolbarSizeChanged(bool is_animating) {
- if (is_animating) {
+ // The call to InfoBarContainer::SetMaxTopArrowHeight() below can result in
+ // reentrancy; |call_state| tracks whether we're reentrant. We can't just
+ // early-return in this case because we need to layout again so the infobar
+ // container's bounds are set correctly.
+ static CallState call_state = NORMAL;
+
+ // A reentrant call can (and should) use the fast resize path unless both it
+ // and the normal call are both non-animating.
+ bool use_fast_resize =
+ is_animating || (call_state == REENTRANT_FORCE_FAST_RESIZE);
+ if (use_fast_resize)
contents_container_->SetFastResize(true);
- UpdateUIForContents(browser_->GetSelectedTabContentsWrapper());
+ UpdateUIForContents(browser_->GetSelectedTabContentsWrapper());
+ if (use_fast_resize)
contents_container_->SetFastResize(false);
- } else {
- UpdateUIForContents(browser_->GetSelectedTabContentsWrapper());
- // When transitioning from animating to not animating we need to make sure
- // the contents_container_ gets layed out. If we don't do this and the
- // bounds haven't changed contents_container_ won't get a Layout out and
- // we'll end up with a gray rect because the clip wasn't updated.
+
+ // Inform the InfoBarContainer that the distance to the location icon may have
+ // changed. We have to do this after the block above so that the toolbars are
+ // laid out correctly for calculating the maximum arrow height below.
+ AutoReset<CallState> resetter(&call_state,
+ is_animating ? REENTRANT : REENTRANT_FORCE_FAST_RESIZE);
+ const LocationIconView* location_icon_view =
+ toolbar_->location_bar()->location_icon_view();
+ // The +1 in the next line creates a 1-px gap between icon and arrow tip.
+ gfx::Point icon_bottom(0, location_icon_view->GetImageBounds().bottom() -
+ LocationBarView::kIconInternalPadding + 1);
+ ConvertPointToView(location_icon_view, this, &icon_bottom);
+ gfx::Point infobar_top(0, infobar_container_->GetVerticalOverlap(NULL));
+ ConvertPointToView(infobar_container_, this, &infobar_top);
+ infobar_container_->SetMaxTopArrowHeight(infobar_top.y() - icon_bottom.y());
+
+ // When transitioning from animating to not animating we need to make sure the
+ // contents_container_ gets layed out. If we don't do this and the bounds
+ // haven't changed contents_container_ won't get a Layout out and we'll end up
+ // with a gray rect because the clip wasn't updated. Note that a reentrant
+ // call never needs to do this, because after it returns, the normal call
+ // wrapping it will do it.
+ if ((call_state == NORMAL) && !is_animating) {
contents_container_->InvalidateLayout();
contents_split_->Layout();
}
@@ -1667,8 +1702,7 @@ void BrowserView::InfoBarContainerHeightChanged(bool is_animating) {
bool BrowserView::DrawInfoBarArrows(int* x) const {
const LocationIconView* location_icon_view =
toolbar_->location_bar()->location_icon_view();
- gfx::Rect icon_bounds = location_icon_view->GetLocalBounds();
- gfx::Point icon_center = icon_bounds.CenterPoint();
+ gfx::Point icon_center(location_icon_view->GetImageBounds().CenterPoint());
ConvertPointToView(location_icon_view, this, &icon_center);
*x = icon_center.x();
return true;
diff --git a/chrome/browser/ui/views/frame/browser_view_layout.cc b/chrome/browser/ui/views/frame/browser_view_layout.cc
index 4308939..eae56ab 100644
--- a/chrome/browser/ui/views/frame/browser_view_layout.cc
+++ b/chrome/browser/ui/views/frame/browser_view_layout.cc
@@ -34,9 +34,6 @@ namespace {
const int kTabShadowSize = 2;
// The vertical overlap between the TabStrip and the Toolbar.
const int kToolbarTabStripVerticalOverlap = 3;
-// An offset distance between certain toolbars and the toolbar that preceded
-// them in layout.
-const int kSeparationLineHeight = 1;
} // namespace
@@ -74,8 +71,9 @@ gfx::Size BrowserViewLayout::GetMinimumSize() {
if (active_bookmark_bar_ &&
browser()->SupportsWindowFeature(Browser::FEATURE_BOOKMARKBAR)) {
bookmark_bar_size = active_bookmark_bar_->GetMinimumSize();
- bookmark_bar_size.Enlarge(0, -(kSeparationLineHeight +
- active_bookmark_bar_->GetToolbarOverlap(true)));
+ bookmark_bar_size.Enlarge(0,
+ -(views::NonClientFrameView::kClientEdgeThickness +
+ active_bookmark_bar_->GetToolbarOverlap(true)));
}
gfx::Size contents_size(contents_split_->GetMinimumSize());
@@ -353,7 +351,8 @@ int BrowserViewLayout::LayoutBookmarkBar(int top) {
active_bookmark_bar_->set_infobar_visible(InfobarVisible());
int bookmark_bar_height = active_bookmark_bar_->GetPreferredSize().height();
- y -= kSeparationLineHeight + active_bookmark_bar_->GetToolbarOverlap(false);
+ y -= views::NonClientFrameView::kClientEdgeThickness +
+ active_bookmark_bar_->GetToolbarOverlap(false);
active_bookmark_bar_->SetVisible(true);
active_bookmark_bar_->SetBounds(vertical_layout_rect_.x(), y,
vertical_layout_rect_.width(),
@@ -501,7 +500,8 @@ int BrowserViewLayout::GetTopMarginForActiveContent() {
}
// Adjust for separator.
- return active_bookmark_bar_->height() - kSeparationLineHeight;
+ return active_bookmark_bar_->height() -
+ views::NonClientFrameView::kClientEdgeThickness;
}
int BrowserViewLayout::LayoutDownloadShelf(int bottom) {
diff --git a/chrome/browser/ui/views/infobars/extension_infobar.cc b/chrome/browser/ui/views/infobars/extension_infobar.cc
index 1966636..6892509 100644
--- a/chrome/browser/ui/views/infobars/extension_infobar.cc
+++ b/chrome/browser/ui/views/infobars/extension_infobar.cc
@@ -43,8 +43,7 @@ ExtensionInfoBar::ExtensionInfoBar(ExtensionInfoBarDelegate* delegate)
ExtensionView* extension_view = delegate->extension_host()->view();
int height = extension_view->GetPreferredSize().height();
- SetBarTargetHeight((height > 0) ?
- (height + InfoBarBackground::kSeparatorLineHeight) : height);
+ SetBarTargetHeight((height > 0) ? (height + kSeparatorLineHeight) : 0);
// Get notified of resize events for the ExtensionView.
extension_view->SetContainer(this);
diff --git a/chrome/browser/ui/views/infobars/infobar.cc b/chrome/browser/ui/views/infobars/infobar.cc
index 1d32362..49ca2bc 100644
--- a/chrome/browser/ui/views/infobars/infobar.cc
+++ b/chrome/browser/ui/views/infobars/infobar.cc
@@ -14,9 +14,11 @@ InfoBar::InfoBar(InfoBarDelegate* delegate)
: delegate_(delegate),
container_(NULL),
ALLOW_THIS_IN_INITIALIZER_LIST(animation_(new ui::SlideAnimation(this))),
- bar_target_height_(kDefaultBarTargetHeight),
arrow_height_(0),
- bar_height_(0) {
+ arrow_target_height_(kDefaultArrowTargetHeight),
+ arrow_half_width_(0),
+ bar_height_(0),
+ bar_target_height_(kDefaultBarTargetHeight) {
DCHECK(delegate != NULL);
animation_->SetTweenType(ui::Tween::LINEAR);
}
@@ -43,8 +45,18 @@ void InfoBar::Hide(bool animate) {
}
}
+void InfoBar::SetArrowTargetHeight(int height) {
+ DCHECK_LE(height, kMaximumArrowTargetHeight);
+ // Once the closing animation starts, we ignore further requests to change the
+ // target height.
+ if ((arrow_target_height_ != height) && !animation()->IsClosing()) {
+ arrow_target_height_ = height;
+ RecalculateHeights();
+ }
+}
+
void InfoBar::AnimationProgressed(const ui::Animation* animation) {
- RecalculateHeight();
+ RecalculateHeights();
}
void InfoBar::RemoveInfoBar() {
@@ -55,7 +67,7 @@ void InfoBar::RemoveInfoBar() {
void InfoBar::SetBarTargetHeight(int height) {
if (bar_target_height_ != height) {
bar_target_height_ = height;
- RecalculateHeight();
+ RecalculateHeights();
}
}
@@ -66,31 +78,47 @@ int InfoBar::OffsetY(const gfx::Size& prefsize) const {
}
void InfoBar::AnimationEnded(const ui::Animation* animation) {
- RecalculateHeight();
+ RecalculateHeights();
MaybeDelete();
}
-void InfoBar::RecalculateHeight() {
+void InfoBar::RecalculateHeights() {
int old_arrow_height = arrow_height_;
int old_bar_height = bar_height_;
- // The arrow area is |arrow_size| ^ 2. By taking the square root of the
- // animation value, we cause a linear animation of the area, which matches the
- // perception of the animation of the InfoBar.
- arrow_height_ = static_cast<int>(kArrowTargetHeight *
- sqrt(animation()->GetCurrentValue()));
- // Add one more pixel for the stroke, if the arrow is to be visible at all.
- // Without this, changing the arrow height from 0 to 1 would produce no
- // visible effect, because the single pixel of stroke would paint atop the
- // divider line above the infobar.
+
+ // Find the desired arrow height/half-width. The arrow area is
+ // |arrow_height_| * |arrow_half_width_|. When the bar is opening or closing,
+ // scaling each of these with the square root of the animation value causes a
+ // linear animation of the area, which matches the perception of the animation
+ // of the bar portion.
+ double scale_factor = sqrt(animation()->GetCurrentValue());
+ arrow_height_ = static_cast<int>(arrow_target_height_ * scale_factor);
+ if (animation_->is_animating()) {
+ arrow_half_width_ = static_cast<int>(std::min(arrow_target_height_,
+ kMaximumArrowTargetHalfWidth) * scale_factor);
+ } else {
+ // When the infobar is not animating (i.e. fully open), we set the
+ // half-width to be proportionally the same distance between its default and
+ // maximum values as the height is between its.
+ arrow_half_width_ = kDefaultArrowTargetHalfWidth +
+ ((kMaximumArrowTargetHalfWidth - kDefaultArrowTargetHalfWidth) *
+ ((arrow_height_ - kDefaultArrowTargetHeight) /
+ (kMaximumArrowTargetHeight - kDefaultArrowTargetHeight)));
+ }
+ // Add pixels for the stroke, if the arrow is to be visible at all. Without
+ // this, changing the arrow height from 0 to kSeparatorLineHeight would
+ // produce no visible effect, because the stroke would paint atop the divider
+ // line above the infobar.
if (arrow_height_)
- ++arrow_height_;
+ arrow_height_ += kSeparatorLineHeight;
+
bar_height_ =
static_cast<int>(bar_target_height_ * animation()->GetCurrentValue());
// Don't re-layout if nothing has changed, e.g. because the animation step was
// not large enough to actually change the heights by at least a pixel.
if ((old_arrow_height != arrow_height_) || (old_bar_height != bar_height_)) {
- PlatformSpecificOnHeightRecalculated();
+ PlatformSpecificOnHeightsRecalculated();
if (container_)
container_->OnInfoBarHeightChanged(animation_->is_animating());
}
diff --git a/chrome/browser/ui/views/infobars/infobar.h b/chrome/browser/ui/views/infobars/infobar.h
index ed9250e..c863ce9 100644
--- a/chrome/browser/ui/views/infobars/infobar.h
+++ b/chrome/browser/ui/views/infobars/infobar.h
@@ -23,6 +23,15 @@ class InfoBar : public ui::AnimationDelegate {
explicit InfoBar(InfoBarDelegate* delegate);
virtual ~InfoBar();
+ // Platforms must define these.
+ static const int kSeparatorLineHeight;
+ static const int kDefaultArrowTargetHeight;
+ static const int kMaximumArrowTargetHeight;
+ // The half-width (see comments on |arrow_half_width_| below) scales to its
+ // default and maximum values proportionally to how the height scales to its.
+ static const int kDefaultArrowTargetHalfWidth;
+ static const int kMaximumArrowTargetHalfWidth;
+
InfoBarDelegate* delegate() { return delegate_; }
void set_container(InfoBarContainer* container) { container_ = container; }
@@ -35,14 +44,16 @@ class InfoBar : public ui::AnimationDelegate {
// container (triggering its deletion), and its delegate is closed.
void Hide(bool animate);
+ // Changes the target height of the arrow portion of the infobar. This has no
+ // effect once the infobar is animating closed.
+ void SetArrowTargetHeight(int height);
+
+ const ui::SlideAnimation* animation() const { return animation_.get(); }
int arrow_height() const { return arrow_height_; }
int total_height() const { return arrow_height_ + bar_height_; }
protected:
- // The target heights of the InfoBar arrow and bar portions, regardless of
- // what their current heights are (due to animation). Platforms must define
- // these!
- static const int kArrowTargetHeight;
+ // Platforms must define this.
static const int kDefaultBarTargetHeight;
// ui::AnimationDelegate:
@@ -62,13 +73,13 @@ class InfoBar : public ui::AnimationDelegate {
const InfoBarContainer* container() const { return container_; }
ui::SlideAnimation* animation() { return animation_.get(); }
- const ui::SlideAnimation* animation() const { return animation_.get(); }
+ int arrow_half_width() const { return arrow_half_width_; }
int bar_height() const { return bar_height_; }
// Platforms may optionally override these if they need to do work during
// processing of the given calls.
virtual void PlatformSpecificHide(bool animate) {}
- virtual void PlatformSpecificOnHeightRecalculated() {}
+ virtual void PlatformSpecificOnHeightsRecalculated() {}
private:
// ui::AnimationDelegate:
@@ -77,7 +88,7 @@ class InfoBar : public ui::AnimationDelegate {
// Finds the new desired arrow and bar heights, and if they differ from the
// current ones, calls PlatformSpecificOnHeightRecalculated() and informs our
// container our height has changed.
- void RecalculateHeight();
+ void RecalculateHeights();
// Checks whether we're closed. If so, notifies the container that it should
// remove us (which will cause the platform-specific code to asynchronously
@@ -88,13 +99,15 @@ class InfoBar : public ui::AnimationDelegate {
InfoBarContainer* container_;
scoped_ptr<ui::SlideAnimation> animation_;
- // The target height for the bar portion of the InfoBarView.
+ // The current and target heights of the arrow and bar portions, and half the
+ // current arrow width. (It's easier to work in half-widths as we draw the
+ // arrow as two halves on either side of a center point.)
+ int arrow_height_; // Includes both fill and top stroke.
+ int arrow_target_height_;
+ int arrow_half_width_; // Includes only fill.
+ int bar_height_; // Includes both fill and bottom separator.
int bar_target_height_;
- // The current heights of the arrow and bar portions.
- int arrow_height_;
- int bar_height_;
-
DISALLOW_COPY_AND_ASSIGN(InfoBar);
};
diff --git a/chrome/browser/ui/views/infobars/infobar_background.cc b/chrome/browser/ui/views/infobars/infobar_background.cc
index b6f94f8..fa74322 100644
--- a/chrome/browser/ui/views/infobars/infobar_background.cc
+++ b/chrome/browser/ui/views/infobars/infobar_background.cc
@@ -10,9 +10,6 @@
#include "third_party/skia/include/effects/SkGradientShader.h"
#include "views/view.h"
-// static
-const int InfoBarBackground::kSeparatorLineHeight = 1;
-
InfoBarBackground::InfoBarBackground(InfoBarDelegate::Type infobar_type)
: separator_color_(SK_ColorBLACK),
top_color_(GetTopColor(infobar_type)),
@@ -54,7 +51,7 @@ void InfoBarBackground::Paint(gfx::Canvas* canvas, views::View* view) const {
SkShader* gradient_shader = SkGradientShader::CreateLinear(
gradient_points, gradient_colors, NULL, 2, SkShader::kClamp_TileMode);
SkPaint paint;
- paint.setStrokeWidth(1.0);
+ paint.setStrokeWidth(SkIntToScalar(InfoBar::kSeparatorLineHeight));
paint.setStyle(SkPaint::kFill_Style);
paint.setStrokeCap(SkPaint::kRound_Cap);
paint.setShader(gradient_shader);
@@ -68,10 +65,15 @@ void InfoBarBackground::Paint(gfx::Canvas* canvas, views::View* view) const {
paint.setColor(SkColorSetA(separator_color_,
SkColorGetA(gradient_colors[0])));
paint.setStyle(SkPaint::kStroke_Style);
+ // Anti-alias the path so it doesn't look goofy when the edges are not at 45
+ // degree angles, but don't anti-alias anything else, especially not the fill,
+ // lest we get weird color bleeding problems.
+ paint.setAntiAlias(true);
canvas_skia->drawPath(*infobar->stroke_path(), paint);
+ paint.setAntiAlias(false);
// Now draw the separator at the bottom.
canvas->FillRectInt(separator_color_, 0,
- view->height() - kSeparatorLineHeight, view->width(),
- kSeparatorLineHeight);
+ view->height() - InfoBar::kSeparatorLineHeight,
+ view->width(), InfoBar::kSeparatorLineHeight);
}
diff --git a/chrome/browser/ui/views/infobars/infobar_background.h b/chrome/browser/ui/views/infobars/infobar_background.h
index f948129..50bcce1 100644
--- a/chrome/browser/ui/views/infobars/infobar_background.h
+++ b/chrome/browser/ui/views/infobars/infobar_background.h
@@ -11,8 +11,6 @@
class InfoBarBackground : public views::Background {
public:
- static const int kSeparatorLineHeight;
-
explicit InfoBarBackground(InfoBarDelegate::Type infobar_type);
virtual ~InfoBarBackground();
diff --git a/chrome/browser/ui/views/infobars/infobar_container.cc b/chrome/browser/ui/views/infobars/infobar_container.cc
index 3f0b3f9..b451ae7 100644
--- a/chrome/browser/ui/views/infobars/infobar_container.cc
+++ b/chrome/browser/ui/views/infobars/infobar_container.cc
@@ -9,13 +9,15 @@
#include "content/browser/tab_contents/tab_contents.h"
#include "content/common/notification_details.h"
#include "content/common/notification_source.h"
+#include "ui/base/animation/slide_animation.h"
InfoBarContainer::Delegate::~Delegate() {
}
InfoBarContainer::InfoBarContainer(Delegate* delegate)
: delegate_(delegate),
- tab_contents_(NULL) {
+ tab_contents_(NULL),
+ top_arrow_target_height_(InfoBar::kDefaultArrowTargetHeight) {
}
InfoBarContainer::~InfoBarContainer() {
@@ -77,6 +79,15 @@ int InfoBarContainer::GetVerticalOverlap(int* total_height) {
return vertical_overlap;
}
+void InfoBarContainer::SetMaxTopArrowHeight(int height) {
+ // Decrease the height by the arrow stroke thickness, which is the separator
+ // line height, because the infobar arrow target heights are without-stroke.
+ top_arrow_target_height_ = std::min(
+ std::max(height - InfoBar::kSeparatorLineHeight, 0),
+ InfoBar::kMaximumArrowTargetHeight);
+ UpdateInfoBarArrowTargetHeights();
+}
+
void InfoBarContainer::OnInfoBarHeightChanged(bool is_animating) {
if (delegate_)
delegate_->InfoBarContainerHeightChanged(is_animating);
@@ -143,6 +154,7 @@ void InfoBarContainer::RemoveInfoBar(InfoBarDelegate* delegate,
// We merely need hide the infobar; it will call back to RemoveInfoBar()
// itself once it's hidden.
infobar->Hide(use_animation);
+ UpdateInfoBarArrowTargetHeights();
break;
}
}
@@ -154,6 +166,7 @@ void InfoBarContainer::AddInfoBar(InfoBar* infobar,
DCHECK(std::find(infobars_.begin(), infobars_.end(), infobar) ==
infobars_.end());
infobars_.push_back(infobar);
+ UpdateInfoBarArrowTargetHeights();
PlatformSpecificAddInfoBar(infobar);
if (callback_status == WANT_CALLBACK)
infobar->set_container(this);
@@ -161,3 +174,23 @@ void InfoBarContainer::AddInfoBar(InfoBar* infobar,
if (callback_status == NO_CALLBACK)
infobar->set_container(this);
}
+
+void InfoBarContainer::UpdateInfoBarArrowTargetHeights() {
+ for (size_t i = 0; i < infobars_.size(); ++i)
+ infobars_[i]->SetArrowTargetHeight(ArrowTargetHeightForInfoBar(i));
+}
+
+int InfoBarContainer::ArrowTargetHeightForInfoBar(size_t infobar_index) const {
+ if (infobar_index == 0)
+ return top_arrow_target_height_;
+ const ui::SlideAnimation* first_infobar_animation =
+ const_cast<const InfoBar*>(infobars_.front())->animation();
+ if ((infobar_index > 1) || first_infobar_animation->IsShowing())
+ return InfoBar::kDefaultArrowTargetHeight;
+ // When the first infobar is animating closed, we animate the second infobar's
+ // arrow target height from the default to the top target height. Note that
+ // the animation values here are going from 1.0 -> 0.0 as the top bar closes.
+ return top_arrow_target_height_ + static_cast<int>(
+ (InfoBar::kDefaultArrowTargetHeight - top_arrow_target_height_) *
+ first_infobar_animation->GetCurrentValue());
+}
diff --git a/chrome/browser/ui/views/infobars/infobar_container.h b/chrome/browser/ui/views/infobars/infobar_container.h
index 0c0a129..35c789d 100644
--- a/chrome/browser/ui/views/infobars/infobar_container.h
+++ b/chrome/browser/ui/views/infobars/infobar_container.h
@@ -50,17 +50,28 @@ class InfoBarContainer : public NotificationObserver {
// |contents|, and show them all. |contents| may be NULL.
void ChangeTabContents(TabContents* contents);
- // Return the amount by which to overlap the toolbar above, and, when
+ // Returns the amount by which to overlap the toolbar above, and, when
// |total_height| is non-NULL, set it to the height of the InfoBarContainer
// (including overlap).
int GetVerticalOverlap(int* total_height);
+ // Called by the delegate when the distance between what the top infobar's
+ // "unspoofable" arrow would point to and the top infobar itself changes.
+ // This enables the top infobar to show a longer arrow (e.g. because of a
+ // visible bookmark bar) or shorter (e.g. due to being in a popup window) if
+ // desired.
+ //
+ // IMPORTANT: This MUST NOT result in a call back to
+ // Delegate::InfoBarContainerHeightChanged() unless it causes an actual
+ // change, lest we infinitely recurse.
+ void SetMaxTopArrowHeight(int height);
+
// Called when a contained infobar has animated or by some other means changed
// its height. The container is expected to do anything necessary to respond,
// e.g. re-layout.
void OnInfoBarHeightChanged(bool is_animating);
- // Remove the specified InfoBarDelegate from the selected TabContents. This
+ // Removes the specified InfoBarDelegate from the selected TabContents. This
// will notify us back and cause us to close the InfoBar. This is called from
// the InfoBar's close button handler.
void RemoveDelegate(InfoBarDelegate* delegate);
@@ -106,11 +117,17 @@ class InfoBarContainer : public NotificationObserver {
bool animate,
CallbackStatus callback_status);
+ void UpdateInfoBarArrowTargetHeights();
+ int ArrowTargetHeightForInfoBar(size_t infobar_index) const;
+
NotificationRegistrar registrar_;
Delegate* delegate_;
TabContents* tab_contents_;
InfoBars infobars_;
+ // Calculated in SetMaxTopArrowHeight().
+ int top_arrow_target_height_;
+
DISALLOW_COPY_AND_ASSIGN(InfoBarContainer);
};
diff --git a/chrome/browser/ui/views/infobars/infobar_view.cc b/chrome/browser/ui/views/infobars/infobar_view.cc
index 4a8af9320..d10bb36 100644
--- a/chrome/browser/ui/views/infobars/infobar_view.cc
+++ b/chrome/browser/ui/views/infobars/infobar_view.cc
@@ -25,6 +25,7 @@
#include "views/controls/link.h"
#include "views/focus/external_focus_tracker.h"
#include "views/widget/widget.h"
+#include "views/window/non_client_view.h"
#if defined(OS_WIN)
#include <shellapi.h>
@@ -36,7 +37,12 @@
#endif
// static
-const int InfoBar::kArrowTargetHeight = 9;
+const int InfoBar::kSeparatorLineHeight =
+ views::NonClientFrameView::kClientEdgeThickness;
+const int InfoBar::kDefaultArrowTargetHeight = 9;
+const int InfoBar::kMaximumArrowTargetHeight = 24;
+const int InfoBar::kDefaultArrowTargetHalfWidth = kDefaultArrowTargetHeight;
+const int InfoBar::kMaximumArrowTargetHalfWidth = 14;
const int InfoBar::kDefaultBarTargetHeight = 36;
const int InfoBarView::kButtonButtonSpacing = 10;
@@ -144,39 +150,43 @@ void InfoBarView::Layout() {
// width is changed, which affects both paths.
stroke_path_->rewind();
fill_path_->rewind();
- int arrow_bottom = std::max(arrow_height() - 1, 0);
- SkScalar arrow_bottom_scalar = SkIntToScalar(arrow_bottom);
const InfoBarContainer::Delegate* delegate = container_delegate();
- int arrow_x;
if (delegate) {
static_cast<InfoBarBackground*>(background())->set_separator_color(
delegate->GetInfoBarSeparatorColor());
- if (delegate->DrawInfoBarArrows(&arrow_x) && arrow_bottom) {
- stroke_path_->moveTo(SkIntToScalar(arrow_x - arrow_bottom),
- arrow_bottom_scalar);
- stroke_path_->rLineTo(arrow_bottom_scalar, -arrow_bottom_scalar);
- stroke_path_->rLineTo(arrow_bottom_scalar, arrow_bottom_scalar);
-
- // Without extending the fill downward by a pixel, Skia doesn't seem to
- // want to fill over the divider above the bar portion.
+ int arrow_x;
+ SkScalar arrow_fill_height =
+ SkIntToScalar(std::max(arrow_height() - kSeparatorLineHeight, 0));
+ SkScalar arrow_fill_half_width = SkIntToScalar(arrow_half_width());
+ SkScalar separator_height = SkIntToScalar(kSeparatorLineHeight);
+ if (delegate->DrawInfoBarArrows(&arrow_x) && arrow_fill_height) {
+ // Skia pixel centers are at the half-values, so the arrow is horizontally
+ // centered at |arrow_x| + 0.5. Vertically, the stroke path is the center
+ // of the separator, while the fill path is a closed path that extends up
+ // through the entire height of the separator and down to the bottom of
+ // the arrow where it joins the bar.
+ stroke_path_->moveTo(
+ SkIntToScalar(arrow_x) + SK_ScalarHalf - arrow_fill_half_width,
+ SkIntToScalar(arrow_height()) - (separator_height * SK_ScalarHalf));
+ stroke_path_->rLineTo(arrow_fill_half_width, -arrow_fill_height);
+ stroke_path_->rLineTo(arrow_fill_half_width, arrow_fill_height);
+
*fill_path_ = *stroke_path_;
- fill_path_->rLineTo(0.0, 1.0);
- fill_path_->rLineTo(-arrow_bottom_scalar * 2, 0.0);
+ // Move the top of the fill path up to the top of the separator and then
+ // extend it down all the way through.
+ fill_path_->offset(0, -separator_height * SK_ScalarHalf);
+ // This 0.01 hack prevents the fill from filling more pixels on the right
+ // edge of the arrow than on the left.
+ const SkScalar epsilon = 0.01f;
+ fill_path_->rLineTo(-epsilon, 0);
+ fill_path_->rLineTo(0, separator_height);
+ fill_path_->rLineTo(epsilon - (arrow_fill_half_width * 2), 0);
fill_path_->close();
-
- // Fill and stroke have different opinions about how to treat paths.
- // Because in Skia integral coordinates represent pixel boundaries,
- // offsetting the path makes it go exactly through pixel centers; this
- // results in lines that are exactly where we expect, instead of having
- // odd "off by one" issues. Were we to do this for |fill_path|, however,
- // which tries to fill "inside" the path (using some questionable math),
- // we'd get a fill at a very different place than we'd want.
- stroke_path_->offset(SK_ScalarHalf, SK_ScalarHalf);
}
}
if (bar_height()) {
fill_path_->addRect(0.0, SkIntToScalar(arrow_height()),
- SkIntToScalar(width()), SkIntToScalar(height()));
+ SkIntToScalar(width()), SkIntToScalar(height() - kSeparatorLineHeight));
}
int start_x = kHorizontalPadding;
@@ -318,7 +328,7 @@ void InfoBarView::PlatformSpecificHide(bool animate) {
DestroyFocusTracker(restore_focus);
}
-void InfoBarView::PlatformSpecificOnHeightRecalculated() {
+void InfoBarView::PlatformSpecificOnHeightsRecalculated() {
// Ensure that notifying our container of our size change will result in a
// re-layout.
InvalidateLayout();
diff --git a/chrome/browser/ui/views/infobars/infobar_view.h b/chrome/browser/ui/views/infobars/infobar_view.h
index 56bebc8..ec32051 100644
--- a/chrome/browser/ui/views/infobars/infobar_view.h
+++ b/chrome/browser/ui/views/infobars/infobar_view.h
@@ -90,7 +90,7 @@ class InfoBarView : public InfoBar,
// InfoBar:
virtual void PlatformSpecificHide(bool animate) OVERRIDE;
- virtual void PlatformSpecificOnHeightRecalculated() OVERRIDE;
+ virtual void PlatformSpecificOnHeightsRecalculated() OVERRIDE;
// views::View:
virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;