summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorestade@chromium.org <estade@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-10-26 22:00:37 +0000
committerestade@chromium.org <estade@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-10-26 22:00:37 +0000
commitdcb3070302b8ee07a3d1dbfc290a84d325c7a6e3 (patch)
treec4f5942b02cb09f2a37dc96298bbb32d1858d421
parenta314ee5ab5322b95a861e38fdc377ec156b0add9 (diff)
downloadchromium_src-dcb3070302b8ee07a3d1dbfc290a84d325c7a6e3.zip
chromium_src-dcb3070302b8ee07a3d1dbfc290a84d325c7a6e3.tar.gz
chromium_src-dcb3070302b8ee07a3d1dbfc290a84d325c7a6e3.tar.bz2
[gtk] spoof proof infobars, take 2
This looks like a big review, but a lot of it is just shuffling code around: - rip out dropshadow code - move arrow state and drawing to a model class, to allow sharing between BrowserWindow and Infobar - get rid of InfoBar's border_bin_ and slightly simplify baseclasses by no longer requiring them to call show() on the toplevel widget Added stuff: - transition between arrow colors (previous_color_ vs. target_color_ business) - arrows protruding on neighboring infobars BUG=48996 TEST=manual, with animations slowed down 100x Review URL: http://codereview.chromium.org/3919004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@63956 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/gtk/browser_window_gtk.cc181
-rw-r--r--chrome/browser/gtk/browser_window_gtk.h35
-rw-r--r--chrome/browser/gtk/extension_infobar_gtk.cc1
-rw-r--r--chrome/browser/gtk/gtk_util.cc21
-rw-r--r--chrome/browser/gtk/gtk_util.h8
-rw-r--r--chrome/browser/gtk/infobar_arrow_model.cc124
-rw-r--r--chrome/browser/gtk/infobar_arrow_model.h77
-rw-r--r--chrome/browser/gtk/infobar_container_gtk.cc72
-rw-r--r--chrome/browser/gtk/infobar_container_gtk.h4
-rw-r--r--chrome/browser/gtk/infobar_gtk.cc82
-rw-r--r--chrome/browser/gtk/infobar_gtk.h26
-rw-r--r--chrome/browser/gtk/translate/after_translate_infobar_gtk.cc2
-rw-r--r--chrome/browser/gtk/translate/before_translate_infobar_gtk.cc2
-rw-r--r--chrome/browser/gtk/translate/translate_message_infobar_gtk.cc2
-rw-r--r--chrome/browser/renderer_host/render_view_host_delegate.cc4
-rw-r--r--chrome/browser/renderer_host/render_view_host_delegate.h4
-rw-r--r--chrome/browser/renderer_host/render_widget_host_view_gtk.cc21
-rw-r--r--chrome/browser/tab_contents/tab_contents_view.cc4
-rw-r--r--chrome/browser/tab_contents/tab_contents_view.h2
-rw-r--r--chrome/browser/tab_contents/tab_contents_view_gtk.cc13
-rw-r--r--chrome/browser/tab_contents/tab_contents_view_gtk.h1
-rw-r--r--chrome/chrome_browser.gypi2
-rw-r--r--gfx/color_utils.cc31
-rw-r--r--gfx/color_utils.h6
-rw-r--r--gfx/color_utils_unittest.cc18
25 files changed, 426 insertions, 317 deletions
diff --git a/chrome/browser/gtk/browser_window_gtk.cc b/chrome/browser/gtk/browser_window_gtk.cc
index 1dfc8f3..16c0f1a 100644
--- a/chrome/browser/gtk/browser_window_gtk.cc
+++ b/chrome/browser/gtk/browser_window_gtk.cc
@@ -81,8 +81,6 @@
#include "chrome/common/native_web_keyboard_event.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/pref_names.h"
-#include "gfx/canvas_skia_paint.h"
-#include "gfx/color_utils.h"
#include "gfx/gtk_util.h"
#include "gfx/rect.h"
#include "gfx/skia_utils_gtk.h"
@@ -90,7 +88,6 @@
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
-#include "third_party/skia/include/effects/SkGradientShader.h"
namespace {
@@ -261,10 +258,6 @@ GdkCursorType GdkWindowEdgeToGdkCursorType(GdkWindowEdge edge) {
return GDK_LAST_CURSOR;
}
-GdkColor SkColorToGdkColor(const SkColor& color) {
- return gfx::SkColorToGdkColor(color);
-}
-
// A helper method for setting the GtkWindow size that should be used in place
// of calling gtk_window_resize directly. This is done to avoid a WM "feature"
// where setting the window size to the monitor size causes the WM to set the
@@ -345,7 +338,7 @@ BrowserWindowGtk::BrowserWindowGtk(Browser* browser)
maximize_after_show_(false),
suppress_window_raise_(false),
accel_group_(NULL),
- infobar_animation_(this) {
+ infobar_arrow_model_(this) {
// We register first so that other views like the toolbar can use the
// is_active() function in their ActiveWindowChanged() handlers.
ActiveWindowWatcherX::AddObserver(this);
@@ -389,8 +382,6 @@ BrowserWindowGtk::BrowserWindowGtk(Browser* browser)
SetBackgroundColor();
HideUnsupportedWindowFeatures();
- infobar_animation_.SetTweenType(Tween::LINEAR);
-
registrar_.Add(this, NotificationType::BOOKMARK_BAR_VISIBILITY_PREF_CHANGED,
NotificationService::AllSources());
}
@@ -1680,7 +1671,7 @@ void BrowserWindowGtk::SetBackgroundColor() {
SkColor frame_color = theme_provider->GetColor(frame_color_id);
// Paint the frame color on the left, right and bottom.
- GdkColor frame_color_gdk = SkColorToGdkColor(frame_color);
+ GdkColor frame_color_gdk = gfx::SkColorToGdkColor(frame_color);
gtk_widget_modify_bg(GTK_WIDGET(window_), GTK_STATE_NORMAL,
&frame_color_gdk);
@@ -1692,7 +1683,8 @@ void BrowserWindowGtk::SetBackgroundColor() {
// color, override the prelight also.
color_utils::HSL hsl = { -1, 0.5, 0.65 };
SkColor frame_prelight_color = color_utils::HSLShift(frame_color, hsl);
- GdkColor frame_prelight_color_gdk = SkColorToGdkColor(frame_prelight_color);
+ GdkColor frame_prelight_color_gdk =
+ gfx::SkColorToGdkColor(frame_prelight_color);
gtk_widget_modify_bg(contents_split_, GTK_STATE_PRELIGHT,
&frame_prelight_color_gdk);
@@ -1798,179 +1790,74 @@ void BrowserWindowGtk::SaveWindowPosition() {
window_preferences->SetInteger("work_area_bottom", work_area.bottom());
}
-void BrowserWindowGtk::AnimationEnded(const Animation* animation) {
- InvalidateInfoBarBits();
-}
-
-void BrowserWindowGtk::AnimationProgressed(const Animation* animation) {
- InvalidateInfoBarBits();
-}
-
-void BrowserWindowGtk::AnimationCanceled(const Animation* animation) {
- InvalidateInfoBarBits();
+void BrowserWindowGtk::SetInfoBarShowing(InfoBar* bar, bool animate) {
+ infobar_arrow_model_.ShowArrowFor(bar, animate);
}
-void BrowserWindowGtk::SetInfoBarShowing(
- const std::pair<SkColor, SkColor>* colors,
- bool animate) {
- if (colors) {
- infobar_colors_ = *colors;
-
- if (animate)
- infobar_animation_.Show();
- else
- infobar_animation_.Reset(1.0);
- } else {
- if (animate)
- infobar_animation_.Hide();
- else
- infobar_animation_.Reset();
- }
-
+void BrowserWindowGtk::PaintStateChanged() {
InvalidateInfoBarBits();
}
-bool BrowserWindowGtk::ShouldDrawInfobarDropShadowOnRenderView() {
- return infobar_animation_.GetCurrentValue() != 0.0 &&
- !(bookmark_bar_.get() && bookmark_bar_is_floating_);
-}
-
void BrowserWindowGtk::InvalidateInfoBarBits() {
gtk_widget_queue_draw(toolbar_border_);
gtk_widget_queue_draw(toolbar_->widget());
- if (bookmark_bar_.get())
+ if (bookmark_bar_.get() && !bookmark_bar_is_floating_)
gtk_widget_queue_draw(bookmark_bar_->widget());
+}
- // Redraw the top bit of the render view area.
- int width = contents_container_->widget()->allocation.width;
- int height = gtk_util::kInfoBarDropShadowHeight;
- gtk_widget_queue_draw_area(contents_container_->widget(),
- 0, 0, width, height);
+int BrowserWindowGtk::GetXPositionOfLocationIcon(GtkWidget* relative_to) {
+ GtkWidget* location_icon = toolbar_->GetLocationBarView()->
+ location_icon_widget();
+ int x = 0;
+ gtk_widget_translate_coordinates(
+ location_icon, relative_to,
+ (location_icon->allocation.width + 1) / 2,
+ 0, &x, NULL);
+
+ if (GTK_WIDGET_NO_WINDOW(relative_to))
+ x += relative_to->allocation.x;
+
+ return x;
}
gboolean BrowserWindowGtk::OnExposeDrawInfobarBits(GtkWidget* sender,
GdkEventExpose* expose) {
- double alpha = infobar_animation_.GetCurrentValue();
- if (alpha == 0.0)
+ if (!infobar_arrow_model_.NeedToDrawInfoBarArrow())
return FALSE;
- GtkWidget* location_icon = toolbar_->GetLocationBarView()->
- location_icon_widget();
- int x = 0;
- int top_y = 0;
- // The offset between the vertical center of the location icon and the top
- // of the arrow.
- const int kArrowVerticalOffset = 4;
- gtk_widget_translate_coordinates(
- location_icon, sender,
- location_icon->allocation.width / 2,
- location_icon->allocation.height / 2 + kArrowVerticalOffset,
- &x, &top_y);
+ int x = GetXPositionOfLocationIcon(sender);
gfx::Rect toolbar_border(toolbar_border_->allocation);
int y = 0;
gtk_widget_translate_coordinates(toolbar_border_, sender,
0, toolbar_border.bottom(),
NULL, &y);
-
- int arrow_height = y - top_y;
- // The width of half the arrow.
- const int kArrowWidth = 15;
-
- if (GTK_WIDGET_NO_WINDOW(sender)) {
- x += sender->allocation.x;
+ if (GTK_WIDGET_NO_WINDOW(sender))
y += sender->allocation.y;
- }
-
- SkPath path;
- path.moveTo(SkPoint::Make(x - kArrowWidth, y));
- path.lineTo(SkPoint::Make(x, y - arrow_height));
- path.lineTo(SkPoint::Make(x + kArrowWidth, y));
- path.close();
-
- SkPaint paint;
- paint.setStyle(SkPaint::kFill_Style);
-
- SkPoint grad_points[2];
- grad_points[0].set(SkIntToScalar(0), SkIntToScalar(y));
- grad_points[1].set(SkIntToScalar(0),
- SkIntToScalar(y + InfoBar::kInfoBarHeight));
-
- SkColor grad_colors[2];
- grad_colors[0] = SkColorSetA(infobar_colors_.first, alpha * 0xff);
- grad_colors[1] = SkColorSetA(infobar_colors_.second, alpha * 0xff);
-
- SkShader* gradient_shader = SkGradientShader::CreateLinear(
- grad_points, grad_colors, NULL, 2, SkShader::kMirror_TileMode);
- paint.setShader(gradient_shader);
- gradient_shader->unref();
-
- gfx::CanvasSkiaPaint canvas(expose, false);
- canvas.drawPath(path, paint);
-
- paint.setShader(NULL);
- paint.setStyle(SkPaint::kStroke_Style);
- // Smooth out the shadow.
- paint.setAntiAlias(true);
-
- const int kMaxShading = 100;
- const int kShadingPixels = 5;
-
- // The goal of all this mathematical trickery is to create a shadow for the
- // arrow that looks decent. We want a shadow of a set width, and the thickest
- // direction of that shadow needs to be perpendicular to the sides of the
- // arrow.
- double scale_factor = sqrt(static_cast<double>(
- (arrow_height * arrow_height + kArrowWidth * kArrowWidth))) /
- kShadingPixels;
- double x_scale = arrow_height / scale_factor / kShadingPixels;
- double y_scale = kArrowWidth / scale_factor / kShadingPixels;
- for (int i = 1; i <= kShadingPixels; ++i) {
- double x_backoff = x_scale * i;
- double y_backoff = y_scale * i;
- SkPath shadow_path;
- shadow_path.moveTo(0, y - i);
- // The +1 below makes sure the shadow hugs the left side of the arrow.
- shadow_path.rLineTo(x - kArrowWidth - x_backoff + 1, 0);
- shadow_path.rMoveTo(0, i - y_backoff);
- shadow_path.rLineTo(kArrowWidth, -arrow_height);
- // The -1.5 below makes sure the shadow hugs the right side of the arrow.
- shadow_path.rLineTo(2 * x_backoff - 1.5, 0);
- shadow_path.rLineTo(kArrowWidth, arrow_height);
- shadow_path.rMoveTo(0, y_backoff - i);
- shadow_path.rLineTo(sender->allocation.width, 0);
-
- int shading = (kShadingPixels - i + 1) * kMaxShading / kShadingPixels;
- paint.setColor(SkColorSetARGB(alpha * shading, 0, 0, 0));
- canvas.drawPath(shadow_path, paint);
- }
+ Profile* profile = browser()->profile();
+ infobar_arrow_model_.Paint(
+ sender, expose, gfx::Point(x, y),
+ GtkThemeProvider::GetFrom(profile)->GetBorderColor());
return FALSE;
}
gboolean BrowserWindowGtk::OnBookmarkBarExpose(GtkWidget* sender,
GdkEventExpose* expose) {
- if (infobar_animation_.GetCurrentValue() == 0.0)
+ if (!infobar_arrow_model_.NeedToDrawInfoBarArrow())
return FALSE;
- // This shares the same draw path as the other widgets when it's not floating.
- if (!bookmark_bar_is_floating_)
- return OnExposeDrawInfobarBits(sender, expose);
+ if (bookmark_bar_is_floating_)
+ return FALSE;
- gfx::Point origin;
- if (GTK_WIDGET_NO_WINDOW(sender))
- origin = gfx::Point(sender->allocation.x, sender->allocation.y);
- cairo_t* cr = gdk_cairo_create(GDK_DRAWABLE(expose->window));
- gtk_util::DrawTopDropShadowForRenderView(cr, origin, gfx::Rect(expose->area));
- cairo_destroy(cr);
- return FALSE;
+ return OnExposeDrawInfobarBits(sender, expose);
}
void BrowserWindowGtk::OnBookmarkBarSizeAllocate(GtkWidget* sender,
GtkAllocation* allocation) {
// The size of the bookmark bar affects how the infobar arrow is drawn on
// the toolbar.
- if (infobar_animation_.GetCurrentValue() != 0.0)
+ if (infobar_arrow_model_.NeedToDrawInfoBarArrow())
gtk_widget_queue_draw(toolbar_->widget());
}
diff --git a/chrome/browser/gtk/browser_window_gtk.h b/chrome/browser/gtk/browser_window_gtk.h
index ce6fd20..ce8e582 100644
--- a/chrome/browser/gtk/browser_window_gtk.h
+++ b/chrome/browser/gtk/browser_window_gtk.h
@@ -12,12 +12,12 @@
#include "app/active_window_watcher_x.h"
#include "app/gtk_signal.h"
-#include "app/slide_animation.h"
#include "app/x11_util.h"
#include "base/scoped_ptr.h"
#include "base/timer.h"
#include "build/build_config.h"
#include "chrome/browser/browser_window.h"
+#include "chrome/browser/gtk/infobar_arrow_model.h"
#include "chrome/browser/prefs/pref_member.h"
#include "chrome/browser/tabs/tab_strip_model_observer.h"
#include "chrome/common/notification_registrar.h"
@@ -45,7 +45,7 @@ class BrowserWindowGtk : public BrowserWindow,
public NotificationObserver,
public TabStripModelObserver,
public ActiveWindowWatcherX::Observer,
- public AnimationDelegate {
+ public InfoBarArrowModel::Observer {
public:
explicit BrowserWindowGtk(Browser* browser);
virtual ~BrowserWindowGtk();
@@ -145,10 +145,8 @@ class BrowserWindowGtk : public BrowserWindow,
// Overridden from ActiveWindowWatcher::Observer.
virtual void ActiveWindowChanged(GdkWindow* active_window);
- // Overridden from AnimationDelegate.
- virtual void AnimationEnded(const Animation* animation);
- virtual void AnimationProgressed(const Animation* animation);
- virtual void AnimationCanceled(const Animation* animation);
+ // Overridden from InfoBarArrowModel::Observer.
+ virtual void PaintStateChanged();
// Accessor for the tab strip.
TabStripGtk* tabstrip() const { return tabstrip_.get(); }
@@ -178,16 +176,9 @@ class BrowserWindowGtk : public BrowserWindow,
// else for the custom frame.
void ResetCustomFrameCursor();
- // Toggles whether an infobar is showing. If |colors| is NULL, then no infobar
- // is showing. When non-NULL, |colors| describes the gradient stop colors for
- // the showing infobar.
- // |animate| controls whether we animate to the new state set by |colors|.
- void SetInfoBarShowing(const std::pair<SkColor, SkColor>* colors,
- bool animate);
-
- // Called by the RenderViewHostDelegate::View (TabContentsViewGtk in our case)
- // to decide whether to draw a drop shadow on the render view.
- bool ShouldDrawInfobarDropShadowOnRenderView();
+ // Toggles whether an infobar is showing.
+ // |animate| controls whether we animate to the new state set by |bar|.
+ void SetInfoBarShowing(InfoBar* bar, bool animate);
// Returns the BrowserWindowGtk registered with |window|.
static BrowserWindowGtk* GetBrowserWindowForNativeWindow(
@@ -221,6 +212,10 @@ class BrowserWindowGtk : public BrowserWindow,
// redraw when it should.
void QueueToolbarRedraw();
+ // Get the position where the infobar arrow should be anchored in
+ // |relative_to| coordinates. This is the middle of the omnibox location icon.
+ int GetXPositionOfLocationIcon(GtkWidget* relative_to);
+
protected:
virtual void DestroyBrowser();
// Top level window.
@@ -480,11 +475,9 @@ class BrowserWindowGtk : public BrowserWindow,
scoped_ptr<FullscreenExitBubbleGtk> fullscreen_exit_bubble_;
- // The top and bottom colors for the infobar gradient, if there is an
- // infobar showing.
- std::pair<SkColor, SkColor> infobar_colors_;
-
- SlideAnimation infobar_animation_;
+ // The model that tracks the paint state of the arrow for the infobar
+ // directly below the toolbar.
+ InfoBarArrowModel infobar_arrow_model_;
DISALLOW_COPY_AND_ASSIGN(BrowserWindowGtk);
};
diff --git a/chrome/browser/gtk/extension_infobar_gtk.cc b/chrome/browser/gtk/extension_infobar_gtk.cc
index 7140afc..b7355b1 100644
--- a/chrome/browser/gtk/extension_infobar_gtk.cc
+++ b/chrome/browser/gtk/extension_infobar_gtk.cc
@@ -66,7 +66,6 @@ void ExtensionInfoBarGtk::BuildWidgets() {
g_signal_connect(view_->native_view(), "size_allocate",
G_CALLBACK(&OnSizeAllocateThunk), this);
- gtk_widget_show_all(border_bin_.get());
}
void ExtensionInfoBarGtk::OnSizeAllocate(GtkWidget* widget,
diff --git a/chrome/browser/gtk/gtk_util.cc b/chrome/browser/gtk/gtk_util.cc
index babed07..005c3b9 100644
--- a/chrome/browser/gtk/gtk_util.cc
+++ b/chrome/browser/gtk/gtk_util.cc
@@ -1136,25 +1136,4 @@ WebDragOperationsMask GdkDragActionToWebDragOp(GdkDragAction action) {
return op;
}
-void DrawTopDropShadowForRenderView(cairo_t* cr, const gfx::Point& origin,
- const gfx::Rect& paint_rect) {
- gfx::Rect shadow_rect(paint_rect.x(), origin.y(),
- paint_rect.width(), kInfoBarDropShadowHeight);
-
- // Avoid this extra work if we can.
- if (!shadow_rect.Intersects(paint_rect))
- return;
-
- cairo_pattern_t* shadow =
- cairo_pattern_create_linear(0.0, shadow_rect.y(),
- 0.0, shadow_rect.bottom());
- cairo_pattern_add_color_stop_rgba(shadow, 0, 0, 0, 0, 0.6);
- cairo_pattern_add_color_stop_rgba(shadow, 1, 0, 0, 0, 0.1);
- cairo_rectangle(cr, shadow_rect.x(), shadow_rect.y(),
- shadow_rect.width(), shadow_rect.height());
- cairo_set_source(cr, shadow);
- cairo_fill(cr);
- cairo_pattern_destroy(shadow);
-}
-
} // namespace gtk_util
diff --git a/chrome/browser/gtk/gtk_util.h b/chrome/browser/gtk/gtk_util.h
index 466ba7e..0ecafee 100644
--- a/chrome/browser/gtk/gtk_util.h
+++ b/chrome/browser/gtk/gtk_util.h
@@ -57,9 +57,6 @@ const int kContentAreaSpacing = 18;
// Horizontal Spacing between controls in a form.
const int kFormControlSpacing = 10;
-// Height for the infobar drop shadow.
-const int kInfoBarDropShadowHeight = 6;
-
// Create a table of labeled controls, using proper spacing and alignment.
// Arguments should be pairs of const char*, GtkWidget*, concluding with a
// NULL. The first argument is a vector in which to place all labels
@@ -344,11 +341,6 @@ void InitLabelSizeRequestAndEllipsizeMode(GtkWidget* label);
GdkDragAction WebDragOpToGdkDragAction(WebKit::WebDragOperationsMask op);
WebKit::WebDragOperationsMask GdkDragActionToWebDragOp(GdkDragAction action);
-// Code to draw the drop shadow below an infobar (at the top of the render
-// view).
-void DrawTopDropShadowForRenderView(cairo_t* cr, const gfx::Point& origin,
- const gfx::Rect& paint_rect);
-
} // namespace gtk_util
#endif // CHROME_BROWSER_GTK_GTK_UTIL_H_
diff --git a/chrome/browser/gtk/infobar_arrow_model.cc b/chrome/browser/gtk/infobar_arrow_model.cc
new file mode 100644
index 0000000..e66bb02
--- /dev/null
+++ b/chrome/browser/gtk/infobar_arrow_model.cc
@@ -0,0 +1,124 @@
+// 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/gtk/infobar_arrow_model.h"
+
+#include "chrome/browser/gtk/infobar_gtk.h"
+#include "gfx/canvas_skia_paint.h"
+#include "gfx/color_utils.h"
+#include "gfx/point.h"
+#include "gfx/skia_utils_gtk.h"
+#include "third_party/skia/include/effects/SkGradientShader.h"
+
+InfoBarArrowModel::InfoBarArrowModel(Observer* observer)
+ : observer_(observer),
+ animation_(this) {
+ animation_.SetTweenType(Tween::LINEAR);
+ animation_.Reset(1.0);
+ target_colors_.top = target_colors_.bottom = SkColorSetARGB(0, 0, 0, 0);
+ previous_colors_ = target_colors_;
+}
+
+InfoBarArrowModel::~InfoBarArrowModel() {
+}
+
+InfoBarArrowModel::InfoBarColors InfoBarArrowModel::CurrentInfoBarColors() {
+ double alpha = animation_.GetCurrentValue();
+ InfoBarColors colors = {
+ color_utils::AlphaBlend(target_colors_.top,
+ previous_colors_.top,
+ alpha * 0xff),
+ color_utils::AlphaBlend(target_colors_.bottom,
+ previous_colors_.bottom,
+ alpha * 0xff)};
+ return colors;
+}
+
+bool InfoBarArrowModel::NeedToDrawInfoBarArrow() {
+ return SkColorGetA(CurrentInfoBarColors().top) != 0;
+}
+
+void InfoBarArrowModel::ShowArrowFor(InfoBar* bar, bool animate) {
+ scoped_ptr<std::pair<SkColor, SkColor> > colors;
+
+ previous_colors_ = CurrentInfoBarColors();
+
+ if (bar) {
+ double r, g, b;
+ bar->GetTopColor(bar->delegate()->GetInfoBarType(), &r, &g, &b);
+ target_colors_.top = SkColorSetRGB(r * 0xff, g * 0xff, b * 0xff);
+ bar->GetBottomColor(bar->delegate()->GetInfoBarType(), &r, &g, &b);
+ target_colors_.bottom = SkColorSetRGB(r * 0xff, g * 0xff, b * 0xff);
+ } else {
+ target_colors_.bottom = target_colors_.top = SkColorSetARGB(0, 0, 0, 0);
+ }
+
+ if (animate) {
+ // Fade from the current color to the target color.
+ animation_.Reset();
+ animation_.Show();
+ } else {
+ // Skip straight to showing the target color.
+ animation_.Reset(1.0);
+ }
+
+ observer_->PaintStateChanged();
+}
+
+void InfoBarArrowModel::Paint(GtkWidget* widget,
+ GdkEventExpose* expose,
+ const gfx::Point& origin,
+ const GdkColor& border_color) {
+ if (!NeedToDrawInfoBarArrow())
+ return;
+
+ // The size of the arrow (its height; also half its width).
+ const int kArrowSize = 10;
+
+ SkPath path;
+ path.moveTo(SkPoint::Make(origin.x() - kArrowSize, origin.y()));
+ path.rLineTo(kArrowSize, -kArrowSize);
+ path.rLineTo(kArrowSize, kArrowSize);
+ path.close();
+
+ SkPaint paint;
+ paint.setStrokeWidth(1);
+ paint.setStyle(SkPaint::kFill_Style);
+
+ SkPoint grad_points[2];
+ grad_points[0].set(SkIntToScalar(0), SkIntToScalar(origin.y()));
+ grad_points[1].set(SkIntToScalar(0),
+ SkIntToScalar(origin.y() + InfoBar::kInfoBarHeight));
+
+ InfoBarColors colors = CurrentInfoBarColors();
+ SkColor grad_colors[2];
+ grad_colors[0] = colors.top;
+ grad_colors[1] = colors.bottom;
+
+ SkShader* gradient_shader = SkGradientShader::CreateLinear(
+ grad_points, grad_colors, NULL, 2, SkShader::kMirror_TileMode);
+ paint.setShader(gradient_shader);
+ gradient_shader->unref();
+
+ gfx::CanvasSkiaPaint canvas(expose, false);
+ canvas.drawPath(path, paint);
+
+ paint.setShader(NULL);
+ paint.setColor(SkColorSetA(gfx::GdkColorToSkColor(border_color),
+ SkColorGetA(colors.top)));
+ paint.setStyle(SkPaint::kStroke_Style);
+ canvas.drawPath(path, paint);
+}
+
+void InfoBarArrowModel::AnimationEnded(const Animation* animation) {
+ observer_->PaintStateChanged();
+}
+
+void InfoBarArrowModel::AnimationProgressed(const Animation* animation) {
+ observer_->PaintStateChanged();
+}
+
+void InfoBarArrowModel::AnimationCanceled(const Animation* animation) {
+ observer_->PaintStateChanged();
+}
diff --git a/chrome/browser/gtk/infobar_arrow_model.h b/chrome/browser/gtk/infobar_arrow_model.h
new file mode 100644
index 0000000..369e586
--- /dev/null
+++ b/chrome/browser/gtk/infobar_arrow_model.h
@@ -0,0 +1,77 @@
+// 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_GTK_INFOBAR_ARROW_MODEL_H_
+#define CHROME_BROWSER_GTK_INFOBAR_ARROW_MODEL_H_
+
+#include <gtk/gtk.h>
+
+#include "app/slide_animation.h"
+#include "third_party/skia/include/core/SkPaint.h"
+
+namespace gfx {
+class Point;
+}
+
+class InfoBar;
+
+// A helper class that tracks the state of an infobar arrow and provides a
+// utility to draw it.
+class InfoBarArrowModel : public AnimationDelegate {
+ public:
+ class Observer {
+ public:
+ // The arrow has changed states; relevant widgets need to be repainted.
+ virtual void PaintStateChanged() = 0;
+ };
+
+ explicit InfoBarArrowModel(Observer* observer);
+ virtual ~InfoBarArrowModel();
+
+ // An infobar has been added or removed that will affect the state of this
+ // arrow.
+ void ShowArrowFor(InfoBar* bar, bool animate);
+
+ // Returns true if the arrow is showing at all.
+ bool NeedToDrawInfoBarArrow();
+
+ // Paints the arrow on |widget|, in response to |expose|, with the bottom
+ // center of the arrow at |origin|, drawing a border with |border_color|.
+ void Paint(GtkWidget* widget,
+ GdkEventExpose* expose,
+ const gfx::Point& origin,
+ const GdkColor& border_color);
+
+ // Overridden from AnimationDelegate.
+ virtual void AnimationEnded(const Animation* animation);
+ virtual void AnimationProgressed(const Animation* animation);
+ virtual void AnimationCanceled(const Animation* animation);
+
+ private:
+ // A pair of colors used to draw a gradient for an arrow.
+ struct InfoBarColors {
+ SkColor top;
+ SkColor bottom;
+ };
+
+ // Calculates the currently showing arrow color, which is a blend of the new
+ // arrow color and the old arrow color.
+ InfoBarColors CurrentInfoBarColors();
+
+ // The view that owns us.
+ Observer* observer_;
+
+ // An animation that tracks the progress of the transition from the last color
+ // to the new color.
+ SlideAnimation animation_;
+
+ // The color we are animating towards.
+ InfoBarColors target_colors_;
+ // The last color we showed (the one we are animating away from).
+ InfoBarColors previous_colors_;
+
+ DISALLOW_COPY_AND_ASSIGN(InfoBarArrowModel);
+};
+
+#endif // CHROME_BROWSER_GTK_INFOBAR_ARROW_MODEL_H_
diff --git a/chrome/browser/gtk/infobar_container_gtk.cc b/chrome/browser/gtk/infobar_container_gtk.cc
index 01c6ccc..b53a995 100644
--- a/chrome/browser/gtk/infobar_container_gtk.cc
+++ b/chrome/browser/gtk/infobar_container_gtk.cc
@@ -143,6 +143,41 @@ void InfoBarContainerGtk::UpdateInfoBars() {
}
}
+void InfoBarContainerGtk::ShowArrowForDelegate(InfoBarDelegate* delegate,
+ bool animate) {
+ if (!CommandLine::ForCurrentProcess()->
+ HasSwitch(switches::kEnableSecureInfoBars)) {
+ return;
+ }
+
+ GList* children = gtk_container_get_children(GTK_CONTAINER(widget()));
+ if (!children)
+ return;
+
+ // Iterate through the infobars and find the last one that isn't closing.
+ InfoBar* last_bar = NULL;
+ InfoBar* this_bar = NULL;
+ for (GList* iter = children; iter != NULL; iter = iter->next) {
+ this_bar = reinterpret_cast<InfoBar*>(
+ g_object_get_data(G_OBJECT(iter->data), kInfoBar));
+
+ if (this_bar->delegate() == delegate)
+ break;
+
+ if (!this_bar->IsClosing())
+ last_bar = this_bar;
+
+ this_bar = NULL;
+ }
+
+ if (last_bar)
+ last_bar->ShowArrowFor(this_bar, animate);
+ else
+ UpdateToolbarInfoBarState(this_bar, animate);
+
+ g_list_free(children);
+}
+
void InfoBarContainerGtk::AddInfoBar(InfoBarDelegate* delegate, bool animate) {
InfoBar* infobar = delegate->CreateInfoBar();
infobar->set_container(this);
@@ -155,8 +190,7 @@ void InfoBarContainerGtk::AddInfoBar(InfoBarDelegate* delegate, bool animate) {
else
infobar->Open();
- if (tab_contents_->GetInfoBarDelegateAt(0) == delegate)
- UpdateToolbarInfoBarState(infobar, animate);
+ ShowArrowForDelegate(delegate, animate);
}
void InfoBarContainerGtk::RemoveInfoBar(InfoBarDelegate* delegate,
@@ -169,21 +203,15 @@ void InfoBarContainerGtk::RemoveInfoBar(InfoBarDelegate* delegate,
delegate);
}
- if (tab_contents_->GetInfoBarDelegateAt(0) == delegate) {
- InfoBar* bar = NULL;
- // Get the next infobar, if it exists, so we can change the color of the
- // arrow to it.
- GList* children = gtk_container_get_children(GTK_CONTAINER(widget()));
- if (children) {
- if (children->next) {
- bar = reinterpret_cast<InfoBar*>(
- g_object_get_data(G_OBJECT(children->next->data), kInfoBar));
- }
- g_list_free(children);
+ InfoBarDelegate* next_delegate = NULL;
+ for (int i = 1; i < tab_contents_->infobar_delegate_count(); ++i) {
+ if (tab_contents_->GetInfoBarDelegateAt(i - 1) == delegate) {
+ next_delegate = tab_contents_->GetInfoBarDelegateAt(i);
+ break;
}
-
- UpdateToolbarInfoBarState(bar, animate);
}
+
+ ShowArrowForDelegate(next_delegate, animate);
}
void InfoBarContainerGtk::UpdateToolbarInfoBarState(
@@ -193,21 +221,9 @@ void InfoBarContainerGtk::UpdateToolbarInfoBarState(
return;
}
- scoped_ptr<std::pair<SkColor, SkColor> > colors;
-
- if (infobar) {
- double r, g, b;
- infobar->GetTopColor(infobar->delegate()->GetInfoBarType(), &r, &g, &b);
- SkColor top = SkColorSetRGB(r * 0xff, g * 0xff, b * 0xff);
- infobar->GetBottomColor(infobar->delegate()->GetInfoBarType(), &r, &g, &b);
- SkColor bottom = SkColorSetRGB(r * 0xff, g * 0xff, b * 0xff);
-
- colors.reset(new std::pair<SkColor, SkColor>(top, bottom));
- }
-
GtkWindow* parent = platform_util::GetTopLevel(widget());
BrowserWindowGtk* browser_window =
BrowserWindowGtk::GetBrowserWindowForNativeWindow(parent);
if (browser_window)
- browser_window->SetInfoBarShowing(colors.get(), animate);
+ browser_window->SetInfoBarShowing(infobar, animate);
}
diff --git a/chrome/browser/gtk/infobar_container_gtk.h b/chrome/browser/gtk/infobar_container_gtk.h
index cb81580..ba676a9 100644
--- a/chrome/browser/gtk/infobar_container_gtk.h
+++ b/chrome/browser/gtk/infobar_container_gtk.h
@@ -51,6 +51,10 @@ class InfoBarContainerGtk : public NotificationObserver {
// this process.
void UpdateInfoBars();
+ // Makes the calls to show an arrow for |delegate| (either on the browser
+ // toolbar or on the next infobar up).
+ void ShowArrowForDelegate(InfoBarDelegate* delegate, bool animate);
+
// Adds an InfoBar for the specified delegate, in response to a notification
// from the selected TabContents.
void AddInfoBar(InfoBarDelegate* delegate, bool animate);
diff --git a/chrome/browser/gtk/infobar_gtk.cc b/chrome/browser/gtk/infobar_gtk.cc
index ce420ac..a512237 100644
--- a/chrome/browser/gtk/infobar_gtk.cc
+++ b/chrome/browser/gtk/infobar_gtk.cc
@@ -7,12 +7,14 @@
#include <gtk/gtk.h>
#include "base/utf_string_conversions.h"
+#include "chrome/browser/gtk/browser_window_gtk.h"
#include "chrome/browser/gtk/custom_button.h"
#include "chrome/browser/gtk/gtk_chrome_link_button.h"
#include "chrome/browser/gtk/gtk_chrome_shrinkable_hbox.h"
#include "chrome/browser/gtk/gtk_theme_provider.h"
#include "chrome/browser/gtk/gtk_util.h"
#include "chrome/browser/gtk/infobar_container_gtk.h"
+#include "chrome/browser/platform_util.h"
#include "chrome/common/notification_service.h"
#include "gfx/gtk_util.h"
@@ -37,7 +39,8 @@ const int kRightPadding = 5;
InfoBar::InfoBar(InfoBarDelegate* delegate)
: container_(NULL),
delegate_(delegate),
- theme_provider_(NULL) {
+ theme_provider_(NULL),
+ arrow_model_(this) {
// Create |hbox_| and pad the sides.
hbox_ = gtk_hbox_new(FALSE, kElementPadding);
@@ -48,17 +51,13 @@ InfoBar::InfoBar(InfoBarDelegate* delegate)
gtk_alignment_set_padding(GTK_ALIGNMENT(padding),
0, 0, kLeftPadding, kRightPadding);
- GtkWidget* bg_box = gtk_event_box_new();
- gtk_widget_set_app_paintable(bg_box, TRUE);
- g_signal_connect(bg_box, "expose-event",
+ bg_box_ = gtk_event_box_new();
+ gtk_widget_set_app_paintable(bg_box_, TRUE);
+ g_signal_connect(bg_box_, "expose-event",
G_CALLBACK(OnBackgroundExposeThunk), this);
gtk_container_add(GTK_CONTAINER(padding), hbox_);
- gtk_container_add(GTK_CONTAINER(bg_box), padding);
- // The -1 on the kInfoBarHeight is to account for the border.
- gtk_widget_set_size_request(bg_box, -1, kInfoBarHeight - 1);
-
- border_bin_.Own(gtk_util::CreateGtkBorderBin(bg_box, NULL,
- 0, 1, 0, 0));
+ gtk_container_add(GTK_CONTAINER(bg_box_), padding);
+ gtk_widget_set_size_request(bg_box_, -1, kInfoBarHeight);
// Add the icon on the left, if any.
SkBitmap* icon = delegate->GetIcon();
@@ -69,13 +68,12 @@ InfoBar::InfoBar(InfoBarDelegate* delegate)
gtk_box_pack_start(GTK_BOX(hbox_), image, FALSE, FALSE, 0);
}
- // TODO(erg): GTK theme the info bar.
close_button_.reset(CustomDrawButton::CloseButton(NULL));
gtk_util::CenterWidgetInHBox(hbox_, close_button_->widget(), true, 0);
g_signal_connect(close_button_->widget(), "clicked",
G_CALLBACK(OnCloseButtonThunk), this);
- slide_widget_.reset(new SlideAnimatorGtk(border_bin_.get(),
+ slide_widget_.reset(new SlideAnimatorGtk(bg_box_,
SlideAnimatorGtk::DOWN,
0, true, true, this));
// We store a pointer back to |this| so we can refer to it from the infobar
@@ -84,7 +82,6 @@ InfoBar::InfoBar(InfoBarDelegate* delegate)
}
InfoBar::~InfoBar() {
- border_bin_.Destroy();
}
GtkWidget* InfoBar::widget() {
@@ -93,14 +90,18 @@ GtkWidget* InfoBar::widget() {
void InfoBar::AnimateOpen() {
slide_widget_->Open();
- if (border_bin_->window)
- gdk_window_lower(border_bin_->window);
+
+ gtk_widget_show_all(bg_box_);
+ if (bg_box_->window)
+ gdk_window_lower(bg_box_->window);
}
void InfoBar::Open() {
slide_widget_->OpenWithoutAnimation();
- if (border_bin_->window)
- gdk_window_lower(border_bin_->window);
+
+ gtk_widget_show_all(bg_box_);
+ if (bg_box_->window)
+ gdk_window_lower(bg_box_->window);
}
void InfoBar::AnimateClose() {
@@ -119,6 +120,18 @@ bool InfoBar::IsAnimating() {
return slide_widget_->IsAnimating();
}
+bool InfoBar::IsClosing() {
+ return slide_widget_->IsClosing();
+}
+
+void InfoBar::ShowArrowFor(InfoBar* other, bool animate) {
+ arrow_model_.ShowArrowFor(other, animate);
+}
+
+void InfoBar::PaintStateChanged() {
+ gtk_widget_queue_draw(widget());
+}
+
void InfoBar::RemoveInfoBar() const {
container_->RemoveDelegate(delegate_);
}
@@ -253,8 +266,7 @@ void InfoBar::GetBottomColor(InfoBarDelegate::Type type,
}
void InfoBar::UpdateBorderColor() {
- GdkColor border_color = theme_provider_->GetBorderColor();
- gtk_widget_modify_bg(border_bin_.get(), GTK_STATE_NORMAL, &border_color);
+ gtk_widget_queue_draw(widget());
}
void InfoBar::OnCloseButton(GtkWidget* button) {
@@ -263,11 +275,11 @@ void InfoBar::OnCloseButton(GtkWidget* button) {
RemoveInfoBar();
}
-gboolean InfoBar::OnBackgroundExpose(GtkWidget* widget,
+gboolean InfoBar::OnBackgroundExpose(GtkWidget* sender,
GdkEventExpose* event) {
- const int height = widget->allocation.height;
+ const int height = sender->allocation.height;
- cairo_t* cr = gdk_cairo_create(GDK_DRAWABLE(widget->window));
+ cairo_t* cr = gdk_cairo_create(GDK_DRAWABLE(sender->window));
gdk_cairo_rectangle(cr, &event->area);
cairo_clip(cr);
@@ -285,8 +297,30 @@ gboolean InfoBar::OnBackgroundExpose(GtkWidget* widget,
cairo_paint(cr);
cairo_pattern_destroy(pattern);
+ // Draw the bottom border.
+ GdkColor border_color = theme_provider_->GetBorderColor();
+ cairo_set_source_rgb(cr, border_color.red / 65535.0,
+ border_color.green / 65535.0,
+ border_color.blue / 65535.0);
+ cairo_set_line_width(cr, 1.0);
+ int y = sender->allocation.height;
+ cairo_move_to(cr, 0, y - 0.5);
+ cairo_rel_line_to(cr, sender->allocation.width, 0);
+ cairo_stroke(cr);
+
cairo_destroy(cr);
+ if (!arrow_model_.NeedToDrawInfoBarArrow())
+ return FALSE;
+
+ GtkWindow* parent = platform_util::GetTopLevel(widget());
+ BrowserWindowGtk* browser_window =
+ BrowserWindowGtk::GetBrowserWindowForNativeWindow(parent);
+ int x = browser_window ?
+ browser_window->GetXPositionOfLocationIcon(sender) : 0;
+
+ arrow_model_.Paint(sender, event, gfx::Point(x, y), border_color);
+
return FALSE;
}
@@ -297,7 +331,6 @@ class AlertInfoBar : public InfoBar {
explicit AlertInfoBar(AlertInfoBarDelegate* delegate)
: InfoBar(delegate) {
AddLabelAndLink(delegate->GetMessageText(), string16(), NULL);
- gtk_widget_show_all(border_bin_.get());
}
};
@@ -312,7 +345,6 @@ class LinkInfoBar : public InfoBar {
string16 link_text = delegate->GetLinkText();
AddLabelWithInlineLink(display_text, link_text, link_offset,
G_CALLBACK(OnLinkClick));
- gtk_widget_show_all(border_bin_.get());
}
private:
@@ -371,8 +403,6 @@ ConfirmInfoBar::ConfirmInfoBar(ConfirmInfoBarDelegate* delegate)
// 13.4px == 10pt @ 96dpi
gtk_util::ForceFontSizePixels(GTK_CHROME_LINK_BUTTON(link)->label, 13.4);
gtk_util::CenterWidgetInHBox(hbox_, link, true, kEndOfLabelSpacing);
-
- gtk_widget_show_all(border_bin_.get());
}
void ConfirmInfoBar::AddButton(ConfirmInfoBarDelegate::InfoBarButton type) {
diff --git a/chrome/browser/gtk/infobar_gtk.h b/chrome/browser/gtk/infobar_gtk.h
index 5589f9e..4293ea8 100644
--- a/chrome/browser/gtk/infobar_gtk.h
+++ b/chrome/browser/gtk/infobar_gtk.h
@@ -7,13 +7,16 @@
#pragma once
#include "app/gtk_signal.h"
+#include "app/slide_animation.h"
#include "base/basictypes.h"
#include "base/scoped_ptr.h"
+#include "chrome/browser/gtk/infobar_arrow_model.h"
#include "chrome/browser/gtk/owned_widget_gtk.h"
#include "chrome/browser/gtk/slide_animator_gtk.h"
#include "chrome/browser/tab_contents/infobar_delegate.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
+#include "third_party/skia/include/core/SkPaint.h"
class CustomDrawButton;
class GtkThemeProvider;
@@ -21,7 +24,8 @@ class InfoBarContainerGtk;
class InfoBarDelegate;
class InfoBar : public SlideAnimatorGtk::Delegate,
- public NotificationObserver {
+ public NotificationObserver,
+ public InfoBarArrowModel::Observer {
public:
explicit InfoBar(InfoBarDelegate* delegate);
virtual ~InfoBar();
@@ -53,12 +57,22 @@ class InfoBar : public SlideAnimatorGtk::Delegate,
// Returns true if the infobar is showing the its open or close animation.
bool IsAnimating();
+ // Returns true if the infobar is showing the close animation.
+ bool IsClosing();
+
void SetThemeProvider(GtkThemeProvider* theme_provider);
+ // Show an arrow that originates from another infobar (i.e. a bar was added
+ // below this one). If |other| is NULL, stop showing the arrow.
+ void ShowArrowFor(InfoBar* other, bool animate);
+
+ // InfoBarArrowModel::Observer implementation.
+ virtual void PaintStateChanged();
+
// SlideAnimatorGtk::Delegate implementation.
virtual void Closed();
- // NotificationOPbserver implementation.
+ // NotificationObserver implementation.
virtual void Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details);
@@ -95,8 +109,8 @@ class InfoBar : public SlideAnimatorGtk::Delegate,
// The top level widget of the infobar.
scoped_ptr<SlideAnimatorGtk> slide_widget_;
- // The second highest level widget of the infobar.
- OwnedWidgetGtk border_bin_;
+ // The second highest widget in the hierarchy (after the slide widget).
+ GtkWidget* bg_box_;
// The hbox that holds infobar elements (button, text, icon, etc.).
GtkWidget* hbox_;
@@ -113,6 +127,10 @@ class InfoBar : public SlideAnimatorGtk::Delegate,
// The theme provider, used for getting border colors.
GtkThemeProvider* theme_provider_;
+ // The model that tracks the paint state of the arrow for the infobar
+ // below this one (if it exists).
+ InfoBarArrowModel arrow_model_;
+
NotificationRegistrar registrar_;
private:
diff --git a/chrome/browser/gtk/translate/after_translate_infobar_gtk.cc b/chrome/browser/gtk/translate/after_translate_infobar_gtk.cc
index 6fefadd..914f2ca 100644
--- a/chrome/browser/gtk/translate/after_translate_infobar_gtk.cc
+++ b/chrome/browser/gtk/translate/after_translate_infobar_gtk.cc
@@ -62,8 +62,6 @@ void AfterTranslateInfoBar::Init() {
l10n_util::GetStringUTF8(IDS_TRANSLATE_INFOBAR_REVERT).c_str());
g_signal_connect(button, "clicked",G_CALLBACK(&OnRevertPressedThunk), this);
gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
-
- gtk_widget_show_all(border_bin_.get());
}
void AfterTranslateInfoBar::OnOriginalLanguageModified(GtkWidget* sender) {
diff --git a/chrome/browser/gtk/translate/before_translate_infobar_gtk.cc b/chrome/browser/gtk/translate/before_translate_infobar_gtk.cc
index c3a9b8a..75c668e 100644
--- a/chrome/browser/gtk/translate/before_translate_infobar_gtk.cc
+++ b/chrome/browser/gtk/translate/before_translate_infobar_gtk.cc
@@ -73,8 +73,6 @@ void BeforeTranslateInfoBar::Init() {
G_CALLBACK(&OnAlwaysTranslatePressedThunk), this);
gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
}
-
- gtk_widget_show_all(border_bin_.get());
}
void BeforeTranslateInfoBar::OnLanguageModified(GtkWidget* sender) {
diff --git a/chrome/browser/gtk/translate/translate_message_infobar_gtk.cc b/chrome/browser/gtk/translate/translate_message_infobar_gtk.cc
index 22e800d..0f61bca 100644
--- a/chrome/browser/gtk/translate/translate_message_infobar_gtk.cc
+++ b/chrome/browser/gtk/translate/translate_message_infobar_gtk.cc
@@ -31,8 +31,6 @@ void TranslateMessageInfoBar::Init() {
g_signal_connect(button, "clicked",G_CALLBACK(&OnButtonPressedThunk), this);
gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
}
-
- gtk_widget_show_all(border_bin_.get());
}
void TranslateMessageInfoBar::OnButtonPressed(GtkWidget* sender) {
diff --git a/chrome/browser/renderer_host/render_view_host_delegate.cc b/chrome/browser/renderer_host/render_view_host_delegate.cc
index 19722a1..523fd8f 100644
--- a/chrome/browser/renderer_host/render_view_host_delegate.cc
+++ b/chrome/browser/renderer_host/render_view_host_delegate.cc
@@ -112,7 +112,3 @@ gfx::Rect RenderViewHostDelegate::GetRootWindowResizerRect() const {
bool RenderViewHostDelegate::IsExternalTabContainer() const {
return false;
}
-
-bool RenderViewHostDelegate::View::ShouldDrawDropShadow() {
- return false;
-}
diff --git a/chrome/browser/renderer_host/render_view_host_delegate.h b/chrome/browser/renderer_host/render_view_host_delegate.h
index 5332a83..93aabb0 100644
--- a/chrome/browser/renderer_host/render_view_host_delegate.h
+++ b/chrome/browser/renderer_host/render_view_host_delegate.h
@@ -209,10 +209,6 @@ class RenderViewHostDelegate {
// The contents' preferred size changed.
virtual void UpdatePreferredSize(const gfx::Size& pref_size) = 0;
- // Called to determine whether the render view needs to draw a drop shadow
- // at the top (currently used for infobars).
- virtual bool ShouldDrawDropShadow();
-
protected:
virtual ~View() {}
};
diff --git a/chrome/browser/renderer_host/render_widget_host_view_gtk.cc b/chrome/browser/renderer_host/render_widget_host_view_gtk.cc
index 2f5a7e9..cc8ef50 100644
--- a/chrome/browser/renderer_host/render_widget_host_view_gtk.cc
+++ b/chrome/browser/renderer_host/render_widget_host_view_gtk.cc
@@ -876,14 +876,7 @@ void RenderWidgetHostViewGtk::Paint(const gfx::Rect& damage_rect) {
// period where this object isn't attached to a window but hasn't been
// Destroy()ed yet and it receives paint messages...
if (window) {
- gfx::Rect drop_shadow_area(0, 0, kMaxWindowWidth,
- gtk_util::kInfoBarDropShadowHeight);
- bool drop_shadow = host_->IsRenderView() &&
- static_cast<RenderViewHost*>(host_)->delegate()->GetViewDelegate()->
- ShouldDrawDropShadow() &&
- drop_shadow_area.Intersects(paint_rect);
-
- if (!visually_deemphasized_ && !drop_shadow) {
+ if (!visually_deemphasized_) {
// In the common case, use XCopyArea. We don't draw more than once, so
// we don't need to double buffer.
backing_store->XShowRect(
@@ -915,15 +908,9 @@ void RenderWidgetHostViewGtk::Paint(const gfx::Rect& damage_rect) {
backing_store->CairoShowRect(damage_rect, GDK_DRAWABLE(window));
cairo_t* cr = gdk_cairo_create(window);
- if (visually_deemphasized_) {
- gdk_cairo_rectangle(cr, &rect);
- cairo_set_source_rgba(cr, 0, 0, 0, 0.7);
- cairo_fill(cr);
- }
- if (drop_shadow) {
- gtk_util::DrawTopDropShadowForRenderView(
- cr, gfx::Point(), damage_rect);
- }
+ gdk_cairo_rectangle(cr, &rect);
+ cairo_set_source_rgba(cr, 0, 0, 0, 0.7);
+ cairo_fill(cr);
cairo_destroy(cr);
gdk_window_end_paint(window);
diff --git a/chrome/browser/tab_contents/tab_contents_view.cc b/chrome/browser/tab_contents/tab_contents_view.cc
index 83eb7a4..47e71f2 100644
--- a/chrome/browser/tab_contents/tab_contents_view.cc
+++ b/chrome/browser/tab_contents/tab_contents_view.cc
@@ -113,10 +113,6 @@ bool TabContentsView::IsEventTracking() const {
return false;
}
-bool TabContentsView::ShouldDrawDropShadow() {
- return false;
-}
-
TabContentsView::TabContentsView() : tab_contents_(NULL) {}
void TabContentsView::HandleKeyboardEvent(const NativeWebKeyboardEvent& event) {
diff --git a/chrome/browser/tab_contents/tab_contents_view.h b/chrome/browser/tab_contents/tab_contents_view.h
index 4550781..c6b9a61 100644
--- a/chrome/browser/tab_contents/tab_contents_view.h
+++ b/chrome/browser/tab_contents/tab_contents_view.h
@@ -153,8 +153,6 @@ class TabContentsView : public RenderViewHostDelegate::View {
virtual bool IsEventTracking() const;
virtual void CloseTabAfterEventTracking() {}
- virtual bool ShouldDrawDropShadow();
-
protected:
TabContentsView(); // Abstract interface.
diff --git a/chrome/browser/tab_contents/tab_contents_view_gtk.cc b/chrome/browser/tab_contents/tab_contents_view_gtk.cc
index 2c8a276..7ec34e4 100644
--- a/chrome/browser/tab_contents/tab_contents_view_gtk.cc
+++ b/chrome/browser/tab_contents/tab_contents_view_gtk.cc
@@ -247,19 +247,6 @@ void TabContentsViewGtk::RestoreFocus() {
SetInitialFocus();
}
-bool TabContentsViewGtk::ShouldDrawDropShadow() {
- GtkWindow* window = GetTopLevelNativeWindow();
- if (!window)
- return false;
-
- BrowserWindowGtk* browser_window =
- BrowserWindowGtk::GetBrowserWindowForNativeWindow(window);
- if (!browser_window)
- return false;
-
- return browser_window->ShouldDrawInfobarDropShadowOnRenderView();
-}
-
void TabContentsViewGtk::SetFocusedWidget(GtkWidget* widget) {
focus_store_.SetWidget(widget);
}
diff --git a/chrome/browser/tab_contents/tab_contents_view_gtk.h b/chrome/browser/tab_contents/tab_contents_view_gtk.h
index 2ea02ca..9a016a1 100644
--- a/chrome/browser/tab_contents/tab_contents_view_gtk.h
+++ b/chrome/browser/tab_contents/tab_contents_view_gtk.h
@@ -59,7 +59,6 @@ class TabContentsViewGtk : public TabContentsView,
virtual void SetInitialFocus();
virtual void StoreFocus();
virtual void RestoreFocus();
- virtual bool ShouldDrawDropShadow();
// Backend implementation of RenderViewHostDelegate::View.
virtual void ShowContextMenu(const ContextMenuParams& params);
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 6c92179..aa3c47c 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -1845,6 +1845,8 @@
'browser/gtk/info_bubble_gtk.h',
'browser/gtk/info_bubble_accelerators_gtk.cc',
'browser/gtk/info_bubble_accelerators_gtk.h',
+ 'browser/gtk/infobar_arrow_model.cc',
+ 'browser/gtk/infobar_arrow_model.h',
'browser/gtk/infobar_container_gtk.cc',
'browser/gtk/infobar_container_gtk.h',
'browser/gtk/infobar_gtk.cc',
diff --git a/gfx/color_utils.cc b/gfx/color_utils.cc
index 268f556..73c585b 100644
--- a/gfx/color_utils.cc
+++ b/gfx/color_utils.cc
@@ -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.
@@ -256,13 +256,28 @@ SkColor AlphaBlend(SkColor foreground, SkColor background, SkAlpha alpha) {
return background;
if (alpha == 255)
return foreground;
- return SkColorSetRGB(
- ((SkColorGetR(foreground) * alpha) +
- (SkColorGetR(background) * (255 - alpha))) / 255,
- ((SkColorGetG(foreground) * alpha) +
- (SkColorGetG(background) * (255 - alpha))) / 255,
- ((SkColorGetB(foreground) * alpha) +
- (SkColorGetB(background) * (255 - alpha))) / 255);
+
+ int f_alpha = SkColorGetA(foreground);
+ int b_alpha = SkColorGetA(background);
+
+ double normalizer = (f_alpha * alpha + b_alpha * (255 - alpha)) / 255.0;
+ if (normalizer == 0.0)
+ return SkColorSetARGB(0, 0, 0, 0);
+
+ double f_weight = f_alpha * alpha / normalizer;
+ double b_weight = b_alpha * (255 - alpha) / normalizer;
+
+ double r = (SkColorGetR(foreground) * f_weight +
+ SkColorGetR(background) * b_weight) / 255.0;
+ double g = (SkColorGetG(foreground) * f_weight +
+ SkColorGetG(background) * b_weight) / 255.0;
+ double b = (SkColorGetB(foreground) * f_weight +
+ SkColorGetB(background) * b_weight) / 255.0;
+
+ return SkColorSetARGB(static_cast<int>(normalizer),
+ static_cast<int>(r),
+ static_cast<int>(g),
+ static_cast<int>(b));
}
SkColor GetReadableColor(SkColor foreground, SkColor background) {
diff --git a/gfx/color_utils.h b/gfx/color_utils.h
index f511168..b6eb2da 100644
--- a/gfx/color_utils.h
+++ b/gfx/color_utils.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.
@@ -58,7 +58,9 @@ SkColor GetAverageColorOfFavicon(SkBitmap* bitmap, SkAlpha alpha);
void BuildLumaHistogram(SkBitmap* bitmap, int histogram[256]);
// Returns a blend of the supplied colors, ranging from |background| (for
-// |alpha| == 0) to |foreground| (for |alpha| == 255).
+// |alpha| == 0) to |foreground| (for |alpha| == 255). The alpha channels of
+// the supplied colors are also taken into account, so the returned color may
+// be partially transparent.
SkColor AlphaBlend(SkColor foreground, SkColor background, SkAlpha alpha);
// Given a foreground and background color, try to return a foreground color
diff --git a/gfx/color_utils_unittest.cc b/gfx/color_utils_unittest.cc
index 363d700..30cf514 100644
--- a/gfx/color_utils_unittest.cc
+++ b/gfx/color_utils_unittest.cc
@@ -47,3 +47,21 @@ TEST(ColorUtils, ColorToHSLRegisterSpill) {
EXPECT_EQ(153U, SkColorGetG(result));
EXPECT_EQ(88U, SkColorGetB(result));
}
+
+TEST(ColorUtils, AlphaBlend) {
+ SkColor fore = SkColorSetARGB(255, 200, 200, 200);
+ SkColor back = SkColorSetARGB(255, 100, 100, 100);
+
+ EXPECT_TRUE(color_utils::AlphaBlend(fore, back, 255) ==
+ fore);
+ EXPECT_TRUE(color_utils::AlphaBlend(fore, back, 0) ==
+ back);
+
+ // One is fully transparent, result is partially transparent.
+ back = SkColorSetA(back, 0);
+ EXPECT_EQ(136U, SkColorGetA(color_utils::AlphaBlend(fore, back, 136)));
+
+ // Both are fully transparent, result is fully transparent.
+ fore = SkColorSetA(fore, 0);
+ EXPECT_EQ(0U, SkColorGetA(color_utils::AlphaBlend(fore, back, 255)));
+}