summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorfinnur@chromium.org <finnur@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-04-19 23:09:07 +0000
committerfinnur@chromium.org <finnur@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-04-19 23:09:07 +0000
commitf98903ef56ce35144860be0d69df5207ae9ace32 (patch)
tree7d874ef4188dcabf4138f976dfc1bd99ba1e6985
parent1b882f5c0f0c50d9eefc9cb421a1157e6e1e45d4 (diff)
downloadchromium_src-f98903ef56ce35144860be0d69df5207ae9ace32.zip
chromium_src-f98903ef56ce35144860be0d69df5207ae9ace32.tar.gz
chromium_src-f98903ef56ce35144860be0d69df5207ae9ace32.tar.bz2
Subclassing the InfoBubble to handle anchoring bubbles basedon their content, not what they point to, like the one we wantto show for the extension apps.
BUG=41270 TEST=Run Chrome with --enable-extension-apps --app-launcher-new-tab and press the NewTab button. A panel should open that has a mini omnibox which should be situated right on top of the underlying omnibox. Review URL: http://codereview.chromium.org/1572045 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@44979 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/chromeos/frame/browser_view.cc2
-rw-r--r--chrome/browser/views/app_launcher.cc30
-rw-r--r--chrome/browser/views/app_launcher.h16
-rw-r--r--chrome/browser/views/bubble_border.cc12
-rw-r--r--chrome/browser/views/bubble_border.h13
-rw-r--r--chrome/browser/views/info_bubble.cc72
-rw-r--r--chrome/browser/views/info_bubble.h77
-rw-r--r--chrome/browser/views/pinned_contents_info_bubble.cc74
-rw-r--r--chrome/browser/views/pinned_contents_info_bubble.h89
-rw-r--r--chrome/chrome_browser.gypi4
10 files changed, 300 insertions, 89 deletions
diff --git a/chrome/browser/chromeos/frame/browser_view.cc b/chrome/browser/chromeos/frame/browser_view.cc
index bf822aa..63804a0 100644
--- a/chrome/browser/chromeos/frame/browser_view.cc
+++ b/chrome/browser/chromeos/frame/browser_view.cc
@@ -450,7 +450,7 @@ void BrowserView::ButtonPressed(views::Button* sender,
origin.Offset(kAppLauncherLeftPadding, 0);
views::RootView::ConvertPointToScreen(this, &origin);
bounds.set_origin(origin);
- ::AppLauncher::Show(browser(), bounds);
+ ::AppLauncher::Show(browser(), bounds, gfx::Point());
}
// views::ContextMenuController overrides.
diff --git a/chrome/browser/views/app_launcher.cc b/chrome/browser/views/app_launcher.cc
index 489a8e6..a074f84 100644
--- a/chrome/browser/views/app_launcher.cc
+++ b/chrome/browser/views/app_launcher.cc
@@ -18,9 +18,11 @@
#include "chrome/browser/browser_window.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/view_ids.h"
#include "chrome/browser/views/dom_view.h"
#include "chrome/browser/views/info_bubble.h"
#include "chrome/browser/views/frame/browser_view.h"
+#include "chrome/browser/views/toolbar_view.h"
#include "chrome/common/url_constants.h"
#include "views/widget/root_view.h"
#include "views/widget/widget.h"
@@ -45,10 +47,10 @@ const int kNavigationEntryYMargin = 1;
const int kNavigationBarBottomPadding = 3;
// NavigationBar constants.
-const int kNavigationBarHeight = 25;
+const int kNavigationBarHeight = 23;
const int kNavigationBarBorderThickness = 1;
-// The delta applied to the default font size for the omnibox.
+// The delta applied to the default font size for the Omnibox.
const int kAutocompleteEditFontDelta = 3;
// Command line switch for specifying url of the page.
@@ -237,6 +239,7 @@ InfoBubbleContentsView::InfoBubbleContentsView(AppLauncher* app_launcher)
: app_launcher_(app_launcher),
navigation_bar_(NULL),
dom_view_(NULL) {
+ DCHECK(app_launcher);
}
InfoBubbleContentsView::~InfoBubbleContentsView() {
@@ -299,6 +302,7 @@ void InfoBubbleContentsView::Layout() {
AppLauncher::AppLauncher(Browser* browser)
: browser_(browser),
info_bubble_(NULL) {
+ DCHECK(browser);
info_bubble_content_ = new InfoBubbleContentsView(this);
}
@@ -306,12 +310,15 @@ AppLauncher::~AppLauncher() {
}
// static
-AppLauncher* AppLauncher::Show(Browser* browser, const gfx::Rect& bounds) {
+AppLauncher* AppLauncher::Show(Browser* browser,
+ const gfx::Rect& bounds,
+ const gfx::Point& bubble_anchor) {
AppLauncher* app_launcher = new AppLauncher(browser);
BrowserView* browser_view = static_cast<BrowserView*>(browser->window());
app_launcher->info_bubble_ =
- InfoBubble::Show(browser_view->frame()->GetWindow(), bounds,
- app_launcher->info_bubble_content_, app_launcher);
+ PinnedContentsInfoBubble::Show(browser_view->frame()->GetWindow(),
+ bounds, bubble_anchor, app_launcher->info_bubble_content_,
+ app_launcher);
app_launcher->info_bubble_content_->BubbleShown();
return app_launcher;
}
@@ -326,7 +333,17 @@ AppLauncher* AppLauncher::ShowForNewTab(Browser* browser) {
gfx::Point origin = bounds.origin();
views::RootView::ConvertPointToScreen(tabstrip, &origin);
bounds.set_origin(origin);
- return Show(browser, bounds);
+
+ // Figure out where the location bar is, so we can pin the bubble to
+ // make our url bar appear exactly over it.
+ views::RootView* root_view = views::Widget::GetWidgetFromNativeWindow(
+ browser_view->GetNativeHandle())->GetRootView();
+ views::View* location_bar = root_view->GetViewByID(VIEW_ID_LOCATION_BAR);
+ gfx::Point location_bar_origin = location_bar->bounds().origin();
+ views::RootView::ConvertPointToScreen(location_bar->GetParent(),
+ &location_bar_origin);
+
+ return Show(browser, bounds, location_bar_origin);
}
void AppLauncher::Hide() {
@@ -352,7 +369,6 @@ void AppLauncher::InfoBubbleClosing(InfoBubble* info_bubble,
new DeleteTask<AppLauncher>(this));
}
-
void AppLauncher::AddTabWithURL(const GURL& url,
PageTransition::Type transition) {
#if defined(OS_CHROMEOS)
diff --git a/chrome/browser/views/app_launcher.h b/chrome/browser/views/app_launcher.h
index 229f265..fa5cc03 100644
--- a/chrome/browser/views/app_launcher.h
+++ b/chrome/browser/views/app_launcher.h
@@ -7,7 +7,7 @@
#include "base/scoped_ptr.h"
#include "chrome/browser/tab_contents/tab_contents_delegate.h"
-#include "chrome/browser/views/info_bubble.h"
+#include "chrome/browser/views/pinned_contents_info_bubble.h"
#include "views/view.h"
class Browser;
@@ -49,13 +49,17 @@ class TabContentsDelegateImpl;
// When a new url is opened, or the user clicks outsides the bounds of the
// widget the app launcher is closed.
class AppLauncher : public InfoBubbleDelegate,
- public TabContentsDelegate {
+ public TabContentsDelegate {
public:
// Shows an application launcher bubble pointing to the |bounds| (which should
- // be in screen coordinates).
+ // be in screen coordinates). |bubble_anchor| specifies at which coordinates
+ // the bubble contents should appear (in screen coordinates). The bubble will
+ // be moved accordingly.
// The caller DOES NOT OWN the AppLauncher returned. It is deleted
// automatically when the AppLauncher is closed.
- static AppLauncher* Show(Browser* browser, const gfx::Rect& bounds);
+ static AppLauncher* Show(Browser* browser,
+ const gfx::Rect& bounds,
+ const gfx::Point& bubble_anchor);
// Shows an application launcher bubble pointing to the new tab button.
// The caller DOES NOT OWN the AppLauncher returned. It is deleted
@@ -107,8 +111,8 @@ class AppLauncher : public InfoBubbleDelegate,
// The currently active browser. We use this to open urls.
Browser* browser_;
- // The InfoBubble displaying the omnibox and app contents.
- InfoBubble* info_bubble_;
+ // The InfoBubble displaying the Omnibox and app contents.
+ PinnedContentsInfoBubble* info_bubble_;
// The view with the navigation bar and render view, shown in the info-bubble.
InfoBubbleContentsView* info_bubble_content_;
diff --git a/chrome/browser/views/bubble_border.cc b/chrome/browser/views/bubble_border.cc
index d7bd07f..3548286 100644
--- a/chrome/browser/views/bubble_border.cc
+++ b/chrome/browser/views/bubble_border.cc
@@ -44,12 +44,14 @@ gfx::Rect BubbleBorder::GetBounds(const gfx::Rect& position_relative_to,
// of padding.
const int kArrowOverlap = 3;
int x = position_relative_to.x() + (position_relative_to.width() / 2);
+ int arrow_offset = override_arrow_x_offset_ ? override_arrow_x_offset_ :
+ arrow_x_offset_;
if (arrow_is_left())
- x -= arrow_x_offset_;
+ x -= arrow_offset;
else if (arrow_location_ == NONE)
x -= ((contents_size.width() / 2) + insets.left());
else
- x += (arrow_x_offset_ - border_size.width() + 1);
+ x += (arrow_offset - border_size.width() + 1);
int y = position_relative_to.y();
if (arrow_is_bottom())
y += (kArrowOverlap - border_size.height());
@@ -103,7 +105,7 @@ void BubbleBorder::InitClass() {
}
void BubbleBorder::Paint(const views::View& view, gfx::Canvas* canvas) const {
- // Convenience shorthand variables
+ // Convenience shorthand variables.
int width = view.width();
int tl_width = top_left_->width();
int tl_height = top_left_->height();
@@ -223,9 +225,11 @@ void BubbleBorder::Paint(const views::View& view, gfx::Canvas* canvas) const {
border_y = SkIntToScalar(top);
tip_y = SkIntToScalar(top - kArrowInteriorHeight);
}
+ int arrow_offset = override_arrow_x_offset_ ? override_arrow_x_offset_ :
+ arrow_x_offset_;
int arrow_width = arrow->width();
int arrow_center = arrow_is_left() ?
- arrow_x_offset_ : width - arrow_x_offset_ - 1;
+ arrow_offset : width - arrow_offset - 1;
int arrow_x = arrow_center - (arrow_width / 2);
SkScalar arrow_interior_x =
SkIntToScalar(arrow_center - kArrowInteriorHeight);
diff --git a/chrome/browser/views/bubble_border.h b/chrome/browser/views/bubble_border.h
index e2d5de3..3670503 100644
--- a/chrome/browser/views/bubble_border.h
+++ b/chrome/browser/views/bubble_border.h
@@ -27,7 +27,9 @@ class BubbleBorder : public views::Border {
BOTTOM_RIGHT
};
- BubbleBorder() : arrow_location_(NONE), background_color_(SK_ColorWHITE) {
+ BubbleBorder() : override_arrow_x_offset_(0),
+ arrow_location_(NONE),
+ background_color_(SK_ColorWHITE) {
InitClass();
}
@@ -45,6 +47,12 @@ class BubbleBorder : public views::Border {
arrow_location_ = arrow_location;
}
+ // Sets a fixed x offset for the arrow. The arrow will still point to the
+ // same location but the bubble will shift horizontally to make that happen.
+ void set_arrow_offset(int offset) {
+ override_arrow_x_offset_ = offset;
+ }
+
// Sets the background color for the arrow body. This is irrelevant if you do
// not also set the arrow location to something other than NONE.
void set_background_color(SkColor background_color) {
@@ -99,6 +107,9 @@ class BubbleBorder : public views::Border {
static int arrow_x_offset_;
+ // If specified, overrides the pre-calculated |arrow_x_offset_| of the arrow.
+ int override_arrow_x_offset_;
+
ArrowLocation arrow_location_;
SkColor background_color_;
diff --git a/chrome/browser/views/info_bubble.cc b/chrome/browser/views/info_bubble.cc
index 218decd..8150db9 100644
--- a/chrome/browser/views/info_bubble.cc
+++ b/chrome/browser/views/info_bubble.cc
@@ -29,55 +29,17 @@ const SkColor InfoBubble::kBackgroundColor =
const SkColor InfoBubble::kBackgroundColor = SK_ColorWHITE;
#endif
-// BorderContents -------------------------------------------------------------
-
-// This is used to paint the border of the InfoBubble. Windows uses this via
-// BorderWidget (see below), while others can use it directly in the bubble.
-class BorderContents : public views::View {
- public:
- BorderContents() { }
-
- // Given the size of the contents and the rect to point at, initializes the
- // bubble and returns the bounds of both the border
- // and the contents inside the bubble.
- // |prefer_arrow_on_right| specifies the preferred location for the arrow
- // anchor. If the bubble does not fit on the monitor, the arrow location may
- // changed so it can.
- //
- // TODO(pkasting): Maybe this should use mirroring transformations instead,
- // which would hopefully simplify this code.
- void InitAndGetBounds(
- const gfx::Rect& position_relative_to, // In screen coordinates
- const gfx::Size& contents_size,
- bool prefer_arrow_on_right,
- gfx::Rect* contents_bounds, // Returned in window coordinates
- gfx::Rect* window_bounds); // Returned in screen coordinates
-
- private:
- virtual ~BorderContents() { }
-
- // Overridden from View:
- virtual void Paint(gfx::Canvas* canvas);
-
- DISALLOW_COPY_AND_ASSIGN(BorderContents);
-};
-
void BorderContents::InitAndGetBounds(
const gfx::Rect& position_relative_to,
const gfx::Size& contents_size,
bool prefer_arrow_on_right,
gfx::Rect* contents_bounds,
gfx::Rect* window_bounds) {
- // Margins between the contents and the inside of the border, in pixels.
- const int kLeftMargin = 6;
- const int kTopMargin = 6;
- const int kRightMargin = 6;
- const int kBottomMargin = 9;
-
// Set the border.
- BubbleBorder* bubble_border = new BubbleBorder;
- set_border(bubble_border);
- bubble_border->set_background_color(InfoBubble::kBackgroundColor);
+ if (!bubble_border_)
+ bubble_border_ = new BubbleBorder;
+ set_border(bubble_border_);
+ bubble_border_->set_background_color(InfoBubble::kBackgroundColor);
// Give the contents a margin.
gfx::Size local_contents_size(contents_size);
@@ -88,9 +50,9 @@ void BorderContents::InitAndGetBounds(
// bounds.
BubbleBorder::ArrowLocation arrow_location(prefer_arrow_on_right ?
BubbleBorder::TOP_RIGHT : BubbleBorder::TOP_LEFT);
- bubble_border->set_arrow_location(arrow_location);
+ bubble_border_->set_arrow_location(arrow_location);
*window_bounds =
- bubble_border->GetBounds(position_relative_to, local_contents_size);
+ bubble_border_->GetBounds(position_relative_to, local_contents_size);
// See if those bounds will fit on the monitor.
scoped_ptr<WindowSizer::MonitorInfoProvider> monitor_provider(
@@ -109,10 +71,10 @@ void BorderContents::InitAndGetBounds(
arrow_location = arrow_on_left ?
BubbleBorder::TOP_LEFT : BubbleBorder::TOP_RIGHT;
}
- bubble_border->set_arrow_location(arrow_location);
+ bubble_border_->set_arrow_location(arrow_location);
// Now get the recalculated bounds.
- *window_bounds = bubble_border->GetBounds(position_relative_to,
+ *window_bounds = bubble_border_->GetBounds(position_relative_to,
local_contents_size);
}
@@ -120,7 +82,7 @@ void BorderContents::InitAndGetBounds(
// subtracting the border dimensions and margin amounts.
*contents_bounds = gfx::Rect(gfx::Point(), window_bounds->size());
gfx::Insets insets;
- bubble_border->GetInsets(&insets);
+ bubble_border_->GetInsets(&insets);
contents_bounds->Inset(insets.left() + kLeftMargin, insets.top() + kTopMargin,
insets.right() + kRightMargin, insets.bottom() + kBottomMargin);
}
@@ -152,7 +114,7 @@ void BorderContents::Paint(gfx::Canvas* canvas) {
#if defined(OS_WIN)
// BorderWidget ---------------------------------------------------------------
-BorderWidget::BorderWidget() {
+BorderWidget::BorderWidget() : border_contents_(NULL) {
set_delete_on_destroy(false); // Our owner will free us manually.
set_window_style(WS_POPUP);
set_window_ex_style(WS_EX_TOOLWINDOW | WS_EX_LAYERED);
@@ -165,15 +127,16 @@ gfx::Rect BorderWidget::InitAndGetBounds(
bool prefer_arrow_on_right) {
// Set up the border view and ask it to calculate our bounds (and our
// contents').
- BorderContents* border_contents = new BorderContents;
+ if (!border_contents_)
+ border_contents_ = new BorderContents;
gfx::Rect contents_bounds, window_bounds;
- border_contents->InitAndGetBounds(position_relative_to, contents_size,
- prefer_arrow_on_right, &contents_bounds,
- &window_bounds);
+ border_contents_->InitAndGetBounds(position_relative_to, contents_size,
+ prefer_arrow_on_right, &contents_bounds,
+ &window_bounds);
// Initialize ourselves.
WidgetWin::Init(GetAncestor(owner, GA_ROOT), window_bounds);
- SetContentsView(border_contents);
+ SetContentsView(border_contents_);
SetWindowPos(owner, 0, 0, 0, 0,
SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOREDRAW);
@@ -270,7 +233,8 @@ void InfoBubble::Init(views::Window* parent,
(contents->UILayoutIsRightToLeft() == delegate->PreferOriginSideAnchor());
#if defined(OS_WIN)
- border_.reset(new BorderWidget);
+ if (!border_.get())
+ border_.reset(new BorderWidget);
// Initialize and position the border window.
window_bounds = border_->InitAndGetBounds(GetNativeView(),
position_relative_to, contents->GetPreferredSize(),
diff --git a/chrome/browser/views/info_bubble.h b/chrome/browser/views/info_bubble.h
index 90911b5..ea80b0f 100644
--- a/chrome/browser/views/info_bubble.h
+++ b/chrome/browser/views/info_bubble.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// 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.
@@ -7,6 +7,7 @@
#include "third_party/skia/include/core/SkColor.h"
#include "views/accelerator.h"
+#include "views/view.h"
#if defined(OS_WIN)
#include "views/widget/widget_win.h"
#elif defined(OS_LINUX)
@@ -23,6 +24,7 @@
// have any additional margins.
class BorderWidget;
+class BubbleBorder;
class InfoBubble;
namespace views {
@@ -33,6 +35,46 @@ namespace gfx {
class Path;
}
+// This is used to paint the border of the InfoBubble. Windows uses this via
+// BorderWidget (see below), while others can use it directly in the bubble.
+class BorderContents : public views::View {
+ public:
+ BorderContents() : bubble_border_(NULL) { }
+
+ // Given the size of the contents and the rect to point at, initializes the
+ // bubble and returns the bounds of both the border
+ // and the contents inside the bubble.
+ // |prefer_arrow_on_right| specifies the preferred location for the arrow
+ // anchor. If the bubble does not fit on the monitor, the arrow location may
+ // changed so it can.
+ //
+ // TODO(pkasting): Maybe this should use mirroring transformations instead,
+ // which would hopefully simplify this code.
+ virtual void InitAndGetBounds(
+ const gfx::Rect& position_relative_to, // In screen coordinates
+ const gfx::Size& contents_size,
+ bool prefer_arrow_on_right,
+ gfx::Rect* contents_bounds, // Returned in window coordinates
+ gfx::Rect* window_bounds); // Returned in screen coordinates
+
+ protected:
+ virtual ~BorderContents() { }
+
+ // Margins between the contents and the inside of the border, in pixels.
+ static const int kLeftMargin = 6;
+ static const int kTopMargin = 6;
+ static const int kRightMargin = 6;
+ static const int kBottomMargin = 9;
+
+ BubbleBorder* bubble_border_;
+
+ private:
+ // Overridden from View:
+ virtual void Paint(gfx::Canvas* canvas);
+
+ DISALLOW_COPY_AND_ASSIGN(BorderContents);
+};
+
#if defined(OS_WIN)
// This is a window that surrounds the info bubble and paints the margin and
// border. It is a separate window so that it can be a layered window, so that
@@ -47,12 +89,15 @@ class BorderWidget : public views::WidgetWin {
// Given the owning (parent) window, the size of the contained contents
// (without margins), and the rect (in screen coordinates) to point to,
// initializes the window and returns the bounds (in screen coordinates) the
- // contents should use. |is_rtl| is supplied to
+ // contents should use. |is_rtl| is supplied to
// BorderContents::InitAndGetBounds(), see its declaration for details.
- gfx::Rect InitAndGetBounds(HWND owner,
- const gfx::Rect& position_relative_to,
- const gfx::Size& contents_size,
- bool is_rtl);
+ virtual gfx::Rect InitAndGetBounds(HWND owner,
+ const gfx::Rect& position_relative_to,
+ const gfx::Size& contents_size,
+ bool is_rtl);
+
+ protected:
+ BorderContents* border_contents_;
private:
// Overridden from WidgetWin:
@@ -82,7 +127,7 @@ class InfoBubbleDelegate {
virtual bool PreferOriginSideAnchor() { return true; }
};
-// TODO: this code is ifdef-tastic. It might be cleaner to refactor the
+// TODO(sky): this code is ifdef-tastic. It might be cleaner to refactor the
// WidgetFoo subclass into a separate class that calls into InfoBubble.
// That way InfoBubble has no (or very few) ifdefs.
class InfoBubble
@@ -120,10 +165,10 @@ class InfoBubble
virtual ~InfoBubble() {}
// Creates the InfoBubble.
- void Init(views::Window* parent,
- const gfx::Rect& position_relative_to,
- views::View* contents,
- InfoBubbleDelegate* delegate);
+ virtual void Init(views::Window* parent,
+ const gfx::Rect& position_relative_to,
+ views::View* contents,
+ InfoBubbleDelegate* delegate);
#if defined(OS_WIN)
// Overridden from WidgetWin:
@@ -133,6 +178,11 @@ class InfoBubble
virtual void IsActiveChanged();
#endif
+#if defined(OS_WIN)
+ // The window used to render the padding, border and arrow.
+ scoped_ptr<BorderWidget> border_;
+#endif
+
private:
// Closes the window notifying the delegate. |closed_by_escape| is true if
// the close is the result of pressing escape.
@@ -147,11 +197,6 @@ class InfoBubble
// The window that this InfoBubble is parented to.
views::Window* parent_;
-#if defined(OS_WIN)
- // The window used to render the padding, border and arrow.
- scoped_ptr<BorderWidget> border_;
-#endif
-
// Have we been closed?
bool closed_;
diff --git a/chrome/browser/views/pinned_contents_info_bubble.cc b/chrome/browser/views/pinned_contents_info_bubble.cc
new file mode 100644
index 0000000..8331db1
--- /dev/null
+++ b/chrome/browser/views/pinned_contents_info_bubble.cc
@@ -0,0 +1,74 @@
+// 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/pinned_contents_info_bubble.h"
+
+#include "chrome/browser/views/bubble_border.h"
+
+#if defined(OS_WIN)
+// BorderWidget ---------------------------------------------------------------
+
+void PinnedContentsBorderContents::InitAndGetBounds(
+ const gfx::Rect& position_relative_to,
+ const gfx::Size& contents_size,
+ bool prefer_arrow_on_right,
+ gfx::Rect* contents_bounds,
+ gfx::Rect* window_bounds) {
+ bubble_border_ = new BubbleBorder;
+
+ // Arrow offset is calculated from the middle of the |position_relative_to|.
+ int offset = position_relative_to.x() + (position_relative_to.width() / 2);
+ offset -= bubble_anchor_.x();
+
+ gfx::Insets insets;
+ bubble_border_->GetInsets(&insets);
+ offset += kLeftMargin + insets.left() + 1;
+ bubble_border_->set_arrow_offset(offset);
+
+ BorderContents::InitAndGetBounds(
+ position_relative_to, contents_size, prefer_arrow_on_right,
+ contents_bounds, window_bounds);
+
+ // Now move the y position to make sure the bubble contents overlap the view.
+ window_bounds->Offset(0, -(kTopMargin + 1));
+}
+
+gfx::Rect PinnedContentsBorderWidget::InitAndGetBounds(
+ HWND owner,
+ const gfx::Rect& position_relative_to,
+ const gfx::Size& contents_size,
+ bool prefer_arrow_on_right) {
+ border_contents_ = new PinnedContentsBorderContents(bubble_anchor_);
+ return BorderWidget::InitAndGetBounds(
+ owner, position_relative_to, contents_size,
+ prefer_arrow_on_right);
+}
+#endif
+
+// InfoBubble -----------------------------------------------------------------
+
+// static
+PinnedContentsInfoBubble* PinnedContentsInfoBubble::Show(
+ views::Window* parent,
+ const gfx::Rect& position_relative_to,
+ const gfx::Point& bubble_anchor,
+ views::View* contents,
+ InfoBubbleDelegate* delegate) {
+ PinnedContentsInfoBubble* window =
+ new PinnedContentsInfoBubble(bubble_anchor);
+ window->Init(parent, position_relative_to, contents, delegate);
+ return window;
+}
+
+void PinnedContentsInfoBubble::Init(views::Window* parent,
+ const gfx::Rect& position_relative_to,
+ views::View* contents,
+ InfoBubbleDelegate* delegate) {
+// TODO(finnur): This needs to be implemented for other platforms once we
+// decide this is the way to go.
+#if defined(OS_WIN)
+ border_.reset(new PinnedContentsBorderWidget(bubble_anchor_));
+#endif
+ InfoBubble::Init(parent, position_relative_to, contents, delegate);
+}
diff --git a/chrome/browser/views/pinned_contents_info_bubble.h b/chrome/browser/views/pinned_contents_info_bubble.h
new file mode 100644
index 0000000..92477c0
--- /dev/null
+++ b/chrome/browser/views/pinned_contents_info_bubble.h
@@ -0,0 +1,89 @@
+// 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.
+
+#ifndef CHROME_BROWSER_VIEWS_PINNED_CONTENTS_INFO_BUBBLE_H_
+#define CHROME_BROWSER_VIEWS_PINNED_CONTENTS_INFO_BUBBLE_H_
+
+#include "chrome/browser/views/info_bubble.h"
+
+// This is a specialization of BorderContents, used to draw a border around
+// an InfoBubble that has its contents pinned to a specific location. See
+// base class for details.
+class PinnedContentsBorderContents : public BorderContents {
+ public:
+ explicit PinnedContentsBorderContents(const gfx::Point& bubble_anchor)
+ : bubble_anchor_(bubble_anchor) {}
+
+ // BorderContents overrides:
+ virtual void InitAndGetBounds(
+ const gfx::Rect& position_relative_to, // In screen coordinates
+ const gfx::Size& contents_size,
+ bool prefer_arrow_on_right,
+ gfx::Rect* contents_bounds, // Returned in window coordinates
+ gfx::Rect* window_bounds); // Returned in screen coordinates
+
+ private:
+ // The location of the pinned contents (in screen coordinates).
+ const gfx::Point bubble_anchor_;
+
+ DISALLOW_COPY_AND_ASSIGN(PinnedContentsBorderContents);
+};
+
+#if defined(OS_WIN)
+// The window that surrounds the info bubble. See base class for details.
+class PinnedContentsBorderWidget : public BorderWidget {
+ public:
+ explicit PinnedContentsBorderWidget(const gfx::Point& bubble_anchor)
+ : bubble_anchor_(bubble_anchor) {}
+ virtual ~PinnedContentsBorderWidget() {}
+
+ // BorderWidget overrides:
+ virtual gfx::Rect InitAndGetBounds(HWND owner,
+ const gfx::Rect& position_relative_to,
+ const gfx::Size& contents_size,
+ bool is_rtl);
+
+ private:
+ // The location of the pinned contents (in screen coordinates).
+ const gfx::Point bubble_anchor_;
+
+ DISALLOW_COPY_AND_ASSIGN(PinnedContentsBorderWidget);
+};
+#endif
+
+// A specialization of the InfoBubble. Used to draw an InfoBubble which, in
+// addition to having an arrow pointing to where the user clicked, also shifts
+// the bubble horizontally to fix it to a specific location. See base class
+// for details.
+class PinnedContentsInfoBubble : public InfoBubble {
+ public:
+ // Shows the InfoBubble (see base class function for details).
+ // |bubble_anchor| specifies how far horizontally to shift the bubble in
+ // order to anchor its contents. Once the InfoBubble has been anchored its
+ // arrow may be pointing to a slightly different |y| location than specified
+ // in |position_relative_to|.
+ static PinnedContentsInfoBubble* Show(views::Window* parent,
+ const gfx::Rect& position_relative_to,
+ const gfx::Point& bubble_anchor_,
+ views::View* contents,
+ InfoBubbleDelegate* delegate);
+
+ private:
+ explicit PinnedContentsInfoBubble(const gfx::Point& bubble_anchor)
+ : bubble_anchor_(bubble_anchor) {}
+ virtual ~PinnedContentsInfoBubble() {}
+
+ // InfoBubble overrides:
+ virtual void Init(views::Window* parent,
+ const gfx::Rect& position_relative_to,
+ views::View* contents,
+ InfoBubbleDelegate* delegate);
+
+ // The location of the pinned contents (in screen coordinates).
+ const gfx::Point bubble_anchor_;
+
+ DISALLOW_COPY_AND_ASSIGN(PinnedContentsInfoBubble);
+};
+
+#endif // CHROME_BROWSER_VIEWS_PINNED_CONTENTS_INFO_BUBBLE_H_
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 3f84b65..55a856a 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -2353,6 +2353,8 @@
'browser/views/options/plugin_filter_page_view.cc',
'browser/views/options/plugin_filter_page_view.h',
'browser/views/page_info_window_view.cc',
+ 'browser/views/pinned_contents_info_bubble.cc',
+ 'browser/views/pinned_contents_info_bubble.h',
'browser/views/repost_form_warning_view.cc',
'browser/views/repost_form_warning_view.h',
'browser/views/restart_message_box.cc',
@@ -2912,6 +2914,8 @@
#['include', '^browser/views/panels/panel_scroller_container.h'],
#['include', '^browser/views/panels/panel_scroller_header.cc'],
#['include', '^browser/views/panels/panel_scroller_header.h'],
+ ['include', '^browser/views/pinned_contents_info_bubble.cc'],
+ ['include', '^browser/views/pinned_contents_info_bubble.h'],
['include', '^browser/views/restart_message_box.cc'],
['include', '^browser/views/restart_message_box.h'],
['include', '^browser/views/sad_tab_view.cc'],