diff options
30 files changed, 883 insertions, 875 deletions
diff --git a/ash/launcher/launcher_tooltip_manager.cc b/ash/launcher/launcher_tooltip_manager.cc index d7c07a6..c817e8f 100644 --- a/ash/launcher/launcher_tooltip_manager.cc +++ b/ash/launcher/launcher_tooltip_manager.cc @@ -17,7 +17,6 @@ #include "ui/base/events/event.h" #include "ui/base/events/event_constants.h" #include "ui/gfx/insets.h" -#include "ui/views/bubble/bubble_border_2.h" #include "ui/views/bubble/bubble_delegate.h" #include "ui/views/bubble/bubble_frame_view.h" #include "ui/views/controls/label.h" @@ -37,21 +36,17 @@ const SkColor kTooltipTextColor = SkColorSetRGB(0x22, 0x22, 0x22); // ash/tooltip/tooltip_controller.cc const int kTooltipMaxWidth = 250; -// Bubble border metrics -const int kArrowHeight = 7; -const int kArrowWidth = 15; -const int kShadowWidth = 8; // The distance between the arrow tip and edge of the anchor view. const int kArrowOffset = 10; views::BubbleBorder::ArrowLocation GetArrowLocation(ShelfAlignment alignment) { switch (alignment) { case SHELF_ALIGNMENT_LEFT: - return views::BubbleBorder::LEFT_BOTTOM; + return views::BubbleBorder::LEFT_CENTER; case SHELF_ALIGNMENT_RIGHT: - return views::BubbleBorder::RIGHT_BOTTOM; + return views::BubbleBorder::RIGHT_CENTER; case SHELF_ALIGNMENT_BOTTOM: - return views::BubbleBorder::BOTTOM_RIGHT; + return views::BubbleBorder::BOTTOM_CENTER; } return views::BubbleBorder::NONE; @@ -70,9 +65,6 @@ class LauncherTooltipManager::LauncherTooltipBubble void Close(); private: - // Overridden from views::BubbleDelegateView: - virtual gfx::Rect GetBubbleBounds() OVERRIDE; - // views::WidgetDelegate overrides: virtual void WindowClosing() OVERRIDE; @@ -81,7 +73,6 @@ class LauncherTooltipManager::LauncherTooltipBubble LauncherTooltipManager* host_; views::Label* label_; - views::BubbleBorder2* bubble_border_; DISALLOW_COPY_AND_ASSIGN(LauncherTooltipBubble); }; @@ -91,14 +82,16 @@ LauncherTooltipManager::LauncherTooltipBubble::LauncherTooltipBubble( views::BubbleBorder::ArrowLocation arrow_location, LauncherTooltipManager* host) : views::BubbleDelegateView(anchor, arrow_location), - host_(host), - bubble_border_(NULL) { + host_(host) { + set_anchor_insets(gfx::Insets(kArrowOffset, kArrowOffset, kArrowOffset, + kArrowOffset)); set_close_on_esc(false); set_close_on_deactivate(false); set_use_focusless(true); set_accept_events(false); set_margins(gfx::Insets(kTooltipTopBottomMargin, kTooltipLeftRightMargin, kTooltipTopBottomMargin, kTooltipLeftRightMargin)); + set_shadow(views::BubbleBorder::SMALL_SHADOW); SetLayoutManager(new views::FillLayout()); // The anchor may not have the widget in tests. if (anchor->GetWidget() && anchor->GetWidget()->GetNativeView()) { @@ -113,17 +106,6 @@ LauncherTooltipManager::LauncherTooltipBubble::LauncherTooltipBubble( label_->SetElideBehavior(views::Label::ELIDE_AT_END); AddChildView(label_); views::BubbleDelegateView::CreateBubble(this); - bubble_border_ = new views::BubbleBorder2(views::BubbleBorder::BOTTOM_RIGHT); - bubble_border_->SetShadow(gfx::ShadowValue( - gfx::Point(0, 5), kShadowWidth, SkColorSetARGB(0x72, 0, 0, 0))); - bubble_border_->set_arrow_width(kArrowWidth); - bubble_border_->set_arrow_height(kArrowHeight); - set_anchor_insets(gfx::Insets(kArrowOffset, kArrowOffset, kArrowOffset, - kArrowOffset)); - GetBubbleFrameView()->SetBubbleBorder(bubble_border_); - - // BubbleBorder2 paints its own background. - GetBubbleFrameView()->set_background(NULL); } void LauncherTooltipManager::LauncherTooltipBubble::SetText( @@ -139,28 +121,6 @@ void LauncherTooltipManager::LauncherTooltipBubble::Close() { } } -gfx::Rect LauncherTooltipManager::LauncherTooltipBubble::GetBubbleBounds() { - // This happens before replacing the default border. - if (!bubble_border_) - return views::BubbleDelegateView::GetBubbleBounds(); - - const gfx::Rect anchor_rect = GetAnchorRect(); - gfx::Rect bubble_rect = GetBubbleFrameView()->GetUpdatedWindowBounds( - anchor_rect, - GetPreferredSize(), - false /* try_mirroring_arrow */); - - const gfx::Point old_offset = bubble_border_->offset(); - bubble_rect = bubble_border_->ComputeOffsetAndUpdateBubbleRect(bubble_rect, - anchor_rect); - - // Repaints border if arrow offset is changed. - if (bubble_border_->offset() != old_offset) - GetBubbleFrameView()->SchedulePaint(); - - return bubble_rect; -} - void LauncherTooltipManager::LauncherTooltipBubble::WindowClosing() { views::BubbleDelegateView::WindowClosing(); if (host_) @@ -204,9 +164,9 @@ LauncherTooltipManager::~LauncherTooltipManager() { void LauncherTooltipManager::ShowDelayed(views::View* anchor, const string16& text) { if (view_) { - if (timer_.get() && timer_->IsRunning()) + if (timer_.get() && timer_->IsRunning()) { return; - else { + } else { CancelHidingAnimation(); Close(); } diff --git a/ash/launcher/overflow_bubble.cc b/ash/launcher/overflow_bubble.cc index 0daf312..6489583 100644 --- a/ash/launcher/overflow_bubble.cc +++ b/ash/launcher/overflow_bubble.cc @@ -207,7 +207,7 @@ gfx::Rect OverflowBubbleView::GetBubbleBounds() { kLauncherPreferredSize / 2; const gfx::Size content_size = GetPreferredSize(); - border->SetArrowOffset(arrow_offset, content_size); + border->set_arrow_offset(arrow_offset); const gfx::Rect anchor_rect = GetAnchorRect(); gfx::Rect bubble_rect = GetBubbleFrameView()->GetUpdatedWindowBounds( @@ -226,8 +226,7 @@ gfx::Rect OverflowBubbleView::GetBubbleBounds() { offset = monitor_rect.right() - bubble_rect.right(); bubble_rect.Offset(offset, 0); - border->SetArrowOffset(anchor_rect.CenterPoint().x() - bubble_rect.x(), - content_size); + border->set_arrow_offset(anchor_rect.CenterPoint().x() - bubble_rect.x()); } else { if (bubble_rect.y() < monitor_rect.y()) offset = monitor_rect.y() - bubble_rect.y(); @@ -235,8 +234,7 @@ gfx::Rect OverflowBubbleView::GetBubbleBounds() { offset = monitor_rect.bottom() - bubble_rect.bottom(); bubble_rect.Offset(0, offset); - border->SetArrowOffset(anchor_rect.CenterPoint().y() - bubble_rect.y(), - content_size); + border->set_arrow_offset(anchor_rect.CenterPoint().y() - bubble_rect.y()); } GetBubbleFrameView()->SchedulePaint(); diff --git a/ash/wm/app_list_controller.cc b/ash/wm/app_list_controller.cc index 262f91f..f6f9cdd 100644 --- a/ash/wm/app_list_controller.cc +++ b/ash/wm/app_list_controller.cc @@ -49,14 +49,14 @@ views::BubbleBorder::ArrowLocation GetBubbleArrowLocation() { ShelfAlignment shelf_alignment = Shell::GetInstance()->GetShelfAlignment(); switch (shelf_alignment) { case ash::SHELF_ALIGNMENT_BOTTOM: - return views::BubbleBorder::BOTTOM_RIGHT; + return views::BubbleBorder::BOTTOM_CENTER; case ash::SHELF_ALIGNMENT_LEFT: - return views::BubbleBorder::LEFT_BOTTOM; + return views::BubbleBorder::LEFT_CENTER; case ash::SHELF_ALIGNMENT_RIGHT: - return views::BubbleBorder::RIGHT_BOTTOM; + return views::BubbleBorder::RIGHT_CENTER; default: NOTREACHED() << "Unknown shelf alignment " << shelf_alignment; - return views::BubbleBorder::BOTTOM_RIGHT; + return views::BubbleBorder::BOTTOM_CENTER; } } diff --git a/ash/wm/maximize_bubble_controller.cc b/ash/wm/maximize_bubble_controller.cc index 1395d70..b26d903 100644 --- a/ash/wm/maximize_bubble_controller.cc +++ b/ash/wm/maximize_bubble_controller.cc @@ -86,7 +86,7 @@ MaximizeBubbleBorder::MaximizeBubbleBorder(views::View* content_view, : views::BubbleBorder(views::BubbleBorder::TOP_RIGHT, views::BubbleBorder::NO_SHADOW), anchor_size_(anchor->size()), - anchor_screen_origin_(0,0), + anchor_screen_origin_(0, 0), content_view_(content_view) { views::View::ConvertPointToScreen(anchor, &anchor_screen_origin_); set_alignment(views::BubbleBorder::ALIGN_EDGE_TO_ANCHOR_EDGE); @@ -399,7 +399,7 @@ MaximizeBubbleController::Bubble::Bubble( set_parent_window(parent); set_notify_enter_exit_on_child(true); - set_try_mirroring_arrow(false); + set_adjust_if_offscreen(false); SetPaintToLayer(true); SetFillsBoundsOpaquely(false); set_color(kBubbleBackgroundColor); diff --git a/ui/app_list/app_list.gyp b/ui/app_list/app_list.gyp index 75c78e7..d364eff 100644 --- a/ui/app_list/app_list.gyp +++ b/ui/app_list/app_list.gyp @@ -22,8 +22,8 @@ 'APP_LIST_IMPLEMENTATION', ], 'sources': [ - 'app_list_bubble_border.cc', - 'app_list_bubble_border.h', + 'app_list_background.cc', + 'app_list_background.h', 'app_list_constants.cc', 'app_list_constants.h', 'app_list_export.h', diff --git a/ui/app_list/app_list_bubble_border.cc b/ui/app_list/app_list_background.cc index bfd134c..eef7f04 100644 --- a/ui/app_list/app_list_bubble_border.cc +++ b/ui/app_list/app_list_background.cc @@ -2,15 +2,15 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ui/app_list/app_list_bubble_border.h" +#include "ui/app_list/app_list_background.h" -#include "third_party/skia/include/core/SkPath.h" #include "third_party/skia/include/core/SkPaint.h" -#include "third_party/skia/include/effects/SkGradientShader.h" +#include "third_party/skia/include/core/SkPath.h" #include "ui/app_list/app_list_constants.h" #include "ui/gfx/canvas.h" -#include "ui/gfx/path.h" +#include "ui/gfx/rect.h" #include "ui/gfx/skia_util.h" +#include "ui/views/view.h" namespace { @@ -24,25 +24,33 @@ const int kTopSeparatorSize = 1; namespace app_list { -AppListBubbleBorder::AppListBubbleBorder(views::View* app_list_view, - views::View* search_box_view) - : views::BubbleBorder2(views::BubbleBorder::BOTTOM_RIGHT), - app_list_view_(app_list_view), +AppListBackground::AppListBackground(int corner_radius, + views::View* search_box_view) + : corner_radius_(corner_radius), search_box_view_(search_box_view) { } -AppListBubbleBorder::~AppListBubbleBorder() { +AppListBackground::~AppListBackground() { } -void AppListBubbleBorder::PaintBackground(gfx::Canvas* canvas, - const gfx::Rect& bounds) const { +void AppListBackground::Paint(gfx::Canvas* canvas, + views::View* view) const { + gfx::Rect bounds = view->GetContentsBounds(); + + canvas->Save(); + SkPath path; + // Contents corner radius is 1px smaller than border corner radius. + SkScalar radius = SkIntToScalar(corner_radius_ - 1); + path.addRoundRect(gfx::RectToSkRect(bounds), radius, radius); + canvas->ClipPath(path); + SkPaint paint; paint.setStyle(SkPaint::kFill_Style); // TODO(benwells): Get these details painting on Windows. #if !defined(OS_WIN) const gfx::Rect search_box_view_bounds = - app_list_view_->ConvertRectToWidget(search_box_view_->bounds()); + search_box_view_->ConvertRectToWidget(search_box_view_->GetLocalBounds()); gfx::Rect search_box_rect(bounds.x(), bounds.y(), bounds.width(), @@ -66,6 +74,7 @@ void AppListBubbleBorder::PaintBackground(gfx::Canvas* canvas, paint.setColor(kContentsBackgroundColor); canvas->DrawRect(contents_rect, paint); + canvas->Restore(); } } // namespace app_list diff --git a/ui/app_list/app_list_background.h b/ui/app_list/app_list_background.h new file mode 100644 index 0000000..66be878 --- /dev/null +++ b/ui/app_list/app_list_background.h @@ -0,0 +1,37 @@ +// Copyright (c) 2012 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 UI_APP_LIST_APP_LIST_BACKGROUND_H_ +#define UI_APP_LIST_APP_LIST_BACKGROUND_H_ + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "ui/views/background.h" + +namespace views { +class View; +} + +namespace app_list { + +// A class to paint bubble background. +class AppListBackground : public views::Background { + public: + AppListBackground(int corner_radius, + views::View* search_box_view); + virtual ~AppListBackground(); + + private: + // views::Background overrides: + virtual void Paint(gfx::Canvas* canvas, views::View* view) const OVERRIDE; + + const int corner_radius_; + const views::View* search_box_view_; // Owned by views hierarchy. + + DISALLOW_COPY_AND_ASSIGN(AppListBackground); +}; + +} // namespace app_list + +#endif // UI_APP_LIST_APP_LIST_BACKGROUND_H_ diff --git a/ui/app_list/app_list_bubble_border.h b/ui/app_list/app_list_bubble_border.h deleted file mode 100644 index 901afd9..0000000 --- a/ui/app_list/app_list_bubble_border.h +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) 2012 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 UI_APP_LIST_APP_LIST_BUBBLE_BORDER_H_ -#define UI_APP_LIST_APP_LIST_BUBBLE_BORDER_H_ - -#include "base/basictypes.h" -#include "ui/gfx/shadow_value.h" -#include "ui/views/bubble/bubble_border_2.h" - -namespace app_list { - -// A class to paint bubble border and background. -class AppListBubbleBorder : public views::BubbleBorder2 { - public: - AppListBubbleBorder(views::View* app_list_view, - views::View* search_box_view); - virtual ~AppListBubbleBorder(); - - private: - // views::BubbleBorder2 overrides: - virtual void PaintBackground(gfx::Canvas* canvas, - const gfx::Rect& bounds) const OVERRIDE; - - // AppListView hosted inside this bubble. - const views::View* app_list_view_; // Owned by views hierarchy. - - // Children view of AppListView that needs to paint background. - const views::View* search_box_view_; // Owned by views hierarchy. - - DISALLOW_COPY_AND_ASSIGN(AppListBubbleBorder); -}; - -} // namespace app_list - -#endif // UI_APP_LIST_APP_LIST_BUBBLE_BORDER_H_ diff --git a/ui/app_list/app_list_view.cc b/ui/app_list/app_list_view.cc index 0cbd42b..8098b7d 100644 --- a/ui/app_list/app_list_view.cc +++ b/ui/app_list/app_list_view.cc @@ -5,7 +5,7 @@ #include "ui/app_list/app_list_view.h" #include "base/string_util.h" -#include "ui/app_list/app_list_bubble_border.h" +#include "ui/app_list/app_list_background.h" #include "ui/app_list/app_list_constants.h" #include "ui/app_list/app_list_item_view.h" #include "ui/app_list/app_list_model.h" @@ -16,6 +16,8 @@ #include "ui/app_list/search_box_view.h" #include "ui/base/events/event.h" #include "ui/gfx/insets.h" +#include "ui/gfx/path.h" +#include "ui/gfx/skia_util.h" #include "ui/views/bubble/bubble_frame_view.h" #include "ui/views/controls/textfield/textfield.h" #include "ui/views/layout/box_layout.h" @@ -38,7 +40,6 @@ const int kArrowOffset = 10; AppListView::AppListView(AppListViewDelegate* delegate) : delegate_(delegate), - bubble_border_(NULL), search_box_view_(NULL), contents_view_(NULL) { } @@ -76,22 +77,23 @@ void AppListView::InitAsBubble( set_anchor_view(anchor); set_anchor_point(anchor_point); + set_color(kContentsBackgroundColor); set_margins(gfx::Insets()); set_move_with_anchor(true); set_parent_window(parent); set_close_on_deactivate(false); - set_anchor_insets(gfx::Insets(kArrowOffset, kArrowOffset, kArrowOffset, - kArrowOffset)); + // Shift anchor rect up 1px because app menu icon center is 1px above anchor + // rect center when shelf is on left/right. + set_anchor_insets(gfx::Insets(kArrowOffset - 1, kArrowOffset, + kArrowOffset + 1, kArrowOffset)); + set_shadow(views::BubbleBorder::BIG_SHADOW); views::BubbleDelegateView::CreateBubble(this); - - // Overrides border with AppListBubbleBorder. - bubble_border_ = new AppListBubbleBorder(this, search_box_view_); - GetBubbleFrameView()->SetBubbleBorder(bubble_border_); SetBubbleArrowLocation(arrow_location); #if !defined(OS_WIN) - // Resets default background since AppListBubbleBorder paints background. - GetBubbleFrameView()->set_background(NULL); + GetBubbleFrameView()->set_background(new AppListBackground( + GetBubbleFrameView()->bubble_border()->GetBorderCornerRadius(), + search_box_view_)); contents_view_->SetPaintToLayer(true); contents_view_->SetFillsBoundsOpaquely(false); @@ -103,9 +105,9 @@ void AppListView::InitAsBubble( void AppListView::SetBubbleArrowLocation( views::BubbleBorder::ArrowLocation arrow_location) { - DCHECK(bubble_border_); - bubble_border_->set_arrow_location(arrow_location); + GetBubbleFrameView()->bubble_border()->set_arrow_location(arrow_location); SizeToContents(); // Recalcuates with new border. + GetBubbleFrameView()->SchedulePaint(); } void AppListView::Close() { @@ -149,7 +151,8 @@ bool AppListView::HasHitTestMask() const { void AppListView::GetHitTestMask(gfx::Path* mask) const { DCHECK(mask); - bubble_border_->GetMask(GetBubbleFrameView()->bounds(), mask); + mask->addRect(gfx::RectToSkRect( + GetBubbleFrameView()->GetContentsBounds())); } bool AppListView::OnKeyPressed(const ui::KeyEvent& event) { @@ -173,28 +176,6 @@ void AppListView::ButtonPressed(views::Button* sender, const ui::Event& event) { Close(); } -gfx::Rect AppListView::GetBubbleBounds() { - // This happens before replacing the default border. - if (!bubble_border_) - return views::BubbleDelegateView::GetBubbleBounds(); - - const gfx::Rect anchor_rect = GetAnchorRect(); - gfx::Rect bubble_rect = GetBubbleFrameView()->GetUpdatedWindowBounds( - anchor_rect, - GetPreferredSize(), - false /* try_mirroring_arrow */); - - const gfx::Point old_offset = bubble_border_->offset(); - bubble_rect = bubble_border_->ComputeOffsetAndUpdateBubbleRect(bubble_rect, - anchor_rect); - - // Repaints border if arrow offset is changed. - if (bubble_border_->offset() != old_offset) - GetBubbleFrameView()->SchedulePaint(); - - return bubble_rect; -} - void AppListView::QueryChanged(SearchBoxView* sender) { string16 query; TrimWhitespace(model_->search_box()->text(), TRIM_ALL, &query); diff --git a/ui/app_list/app_list_view.h b/ui/app_list/app_list_view.h index a4d5c67..8ffecb9 100644 --- a/ui/app_list/app_list_view.h +++ b/ui/app_list/app_list_view.h @@ -14,7 +14,6 @@ namespace app_list { -class AppListBubbleBorder; class AppListModel; class AppListViewDelegate; class ContentsView; @@ -63,9 +62,6 @@ class APP_LIST_EXPORT AppListView : public views::BubbleDelegateView, virtual void ButtonPressed(views::Button* sender, const ui::Event& event) OVERRIDE; - // Overridden from views::BubbleDelegate: - virtual gfx::Rect GetBubbleBounds() OVERRIDE; - // Overridden from SearchBoxViewDelegate: virtual void QueryChanged(SearchBoxView* sender) OVERRIDE; @@ -79,7 +75,6 @@ class APP_LIST_EXPORT AppListView : public views::BubbleDelegateView, scoped_ptr<AppListModel> model_; scoped_ptr<AppListViewDelegate> delegate_; - AppListBubbleBorder* bubble_border_; // Owned by views hierarchy. SearchBoxView* search_box_view_; // Owned by views hierarchy. ContentsView* contents_view_; // Owned by views hierarchy. diff --git a/ui/resources/default_100_percent/common/window_bubble_shadow_spike_big_left.png b/ui/resources/default_100_percent/common/window_bubble_shadow_spike_big_left.png Binary files differindex 982b20f..30dde27 100644 --- a/ui/resources/default_100_percent/common/window_bubble_shadow_spike_big_left.png +++ b/ui/resources/default_100_percent/common/window_bubble_shadow_spike_big_left.png diff --git a/ui/resources/default_100_percent/common/window_bubble_shadow_spike_big_right.png b/ui/resources/default_100_percent/common/window_bubble_shadow_spike_big_right.png Binary files differindex ff62e11..cf33fae 100644 --- a/ui/resources/default_100_percent/common/window_bubble_shadow_spike_big_right.png +++ b/ui/resources/default_100_percent/common/window_bubble_shadow_spike_big_right.png diff --git a/ui/resources/default_100_percent/common/window_bubble_shadow_spike_small_left.png b/ui/resources/default_100_percent/common/window_bubble_shadow_spike_small_left.png Binary files differindex 6e0c319..6fe7e0e 100644 --- a/ui/resources/default_100_percent/common/window_bubble_shadow_spike_small_left.png +++ b/ui/resources/default_100_percent/common/window_bubble_shadow_spike_small_left.png diff --git a/ui/resources/default_100_percent/common/window_bubble_shadow_spike_small_right.png b/ui/resources/default_100_percent/common/window_bubble_shadow_spike_small_right.png Binary files differindex 6d4f9dc..39f8e7b 100644 --- a/ui/resources/default_100_percent/common/window_bubble_shadow_spike_small_right.png +++ b/ui/resources/default_100_percent/common/window_bubble_shadow_spike_small_right.png diff --git a/ui/resources/default_200_percent/common/window_bubble_shadow_spike_big_left.png b/ui/resources/default_200_percent/common/window_bubble_shadow_spike_big_left.png Binary files differindex 65498b4..708f8e6 100644 --- a/ui/resources/default_200_percent/common/window_bubble_shadow_spike_big_left.png +++ b/ui/resources/default_200_percent/common/window_bubble_shadow_spike_big_left.png diff --git a/ui/resources/default_200_percent/common/window_bubble_shadow_spike_big_right.png b/ui/resources/default_200_percent/common/window_bubble_shadow_spike_big_right.png Binary files differindex 7f1e3cb..a781810 100644 --- a/ui/resources/default_200_percent/common/window_bubble_shadow_spike_big_right.png +++ b/ui/resources/default_200_percent/common/window_bubble_shadow_spike_big_right.png diff --git a/ui/resources/default_200_percent/common/window_bubble_shadow_spike_small_left.png b/ui/resources/default_200_percent/common/window_bubble_shadow_spike_small_left.png Binary files differindex daec7b0..08a4219 100644 --- a/ui/resources/default_200_percent/common/window_bubble_shadow_spike_small_left.png +++ b/ui/resources/default_200_percent/common/window_bubble_shadow_spike_small_left.png diff --git a/ui/resources/default_200_percent/common/window_bubble_shadow_spike_small_right.png b/ui/resources/default_200_percent/common/window_bubble_shadow_spike_small_right.png Binary files differindex d571618..65b7620 100644 --- a/ui/resources/default_200_percent/common/window_bubble_shadow_spike_small_right.png +++ b/ui/resources/default_200_percent/common/window_bubble_shadow_spike_small_right.png diff --git a/ui/resources/ui_resources.grd b/ui/resources/ui_resources.grd index c6c952f..102c9610 100644 --- a/ui/resources/ui_resources.grd +++ b/ui/resources/ui_resources.grd @@ -222,6 +222,30 @@ <structure type="chrome_scaled_image" name="IDR_WINDOW_TOP_CENTER" file="window_top_center.png" /> <structure type="chrome_scaled_image" name="IDR_WINDOW_TOP_LEFT_CORNER" file="window_top_left_corner.png" /> <structure type="chrome_scaled_image" name="IDR_WINDOW_TOP_RIGHT_CORNER" file="window_top_right_corner.png" /> + <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_BIG_BOTTOM" file="common/window_bubble_shadow_big_bottom.png" /> + <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_BIG_BOTTOM_LEFT" file="common/window_bubble_shadow_big_bottom_left.png" /> + <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_BIG_BOTTOM_RIGHT" file="common/window_bubble_shadow_big_bottom_right.png" /> + <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_BIG_LEFT" file="common/window_bubble_shadow_big_left.png" /> + <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_BIG_RIGHT" file="common/window_bubble_shadow_big_right.png" /> + <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_BIG_TOP" file="common/window_bubble_shadow_big_top.png" /> + <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_BIG_TOP_LEFT" file="common/window_bubble_shadow_big_top_left.png" /> + <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_BIG_TOP_RIGHT" file="common/window_bubble_shadow_big_top_right.png" /> + <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SPIKE_BIG_BOTTOM" file="common/window_bubble_shadow_spike_big_bottom.png" /> + <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SPIKE_BIG_LEFT" file="common/window_bubble_shadow_spike_big_left.png" /> + <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SPIKE_BIG_RIGHT" file="common/window_bubble_shadow_spike_big_right.png" /> + <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SPIKE_BIG_TOP" file="common/window_bubble_shadow_spike_big_top.png" /> + <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SMALL_BOTTOM" file="common/window_bubble_shadow_small_bottom.png" /> + <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SMALL_BOTTOM_LEFT" file="common/window_bubble_shadow_small_bottom_left.png" /> + <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SMALL_BOTTOM_RIGHT" file="common/window_bubble_shadow_small_bottom_right.png" /> + <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SMALL_LEFT" file="common/window_bubble_shadow_small_left.png" /> + <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SMALL_RIGHT" file="common/window_bubble_shadow_small_right.png" /> + <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SMALL_TOP" file="common/window_bubble_shadow_small_top.png" /> + <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SMALL_TOP_LEFT" file="common/window_bubble_shadow_small_top_left.png" /> + <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SMALL_TOP_RIGHT" file="common/window_bubble_shadow_small_top_right.png" /> + <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SPIKE_SMALL_BOTTOM" file="common/window_bubble_shadow_spike_small_bottom.png" /> + <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SPIKE_SMALL_LEFT" file="common/window_bubble_shadow_spike_small_left.png" /> + <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SPIKE_SMALL_RIGHT" file="common/window_bubble_shadow_spike_small_right.png" /> + <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SPIKE_SMALL_TOP" file="common/window_bubble_shadow_spike_small_top.png" /> </structures> </release> </grit> diff --git a/ui/views/bubble/bubble_border.cc b/ui/views/bubble/bubble_border.cc index 881f082..4a5547c 100644 --- a/ui/views/bubble/bubble_border.cc +++ b/ui/views/bubble/bubble_border.cc @@ -13,70 +13,150 @@ #include "ui/gfx/image/image_skia.h" #include "ui/gfx/skia_util.h" +namespace { + +// Stroke size in pixels of borders in image assets. +const int kBorderStrokeSize = 1; + +// Border image resource ids. +const int kShadowImages[] = { + IDR_BUBBLE_SHADOW_L, + IDR_BUBBLE_SHADOW_TL, + IDR_BUBBLE_SHADOW_T, + IDR_BUBBLE_SHADOW_TR, + IDR_BUBBLE_SHADOW_R, + IDR_BUBBLE_SHADOW_BR, + IDR_BUBBLE_SHADOW_B, + IDR_BUBBLE_SHADOW_BL, +}; + +const int kNoShadowImages[] = { + IDR_BUBBLE_L, + IDR_BUBBLE_TL, + IDR_BUBBLE_T, + IDR_BUBBLE_TR, + IDR_BUBBLE_R, + IDR_BUBBLE_BR, + IDR_BUBBLE_B, + IDR_BUBBLE_BL, + IDR_BUBBLE_L_ARROW, + IDR_BUBBLE_T_ARROW, + IDR_BUBBLE_R_ARROW, + IDR_BUBBLE_B_ARROW, +}; + +const int kBigShadowImages[] = { + IDR_WINDOW_BUBBLE_SHADOW_BIG_LEFT, + IDR_WINDOW_BUBBLE_SHADOW_BIG_TOP_LEFT, + IDR_WINDOW_BUBBLE_SHADOW_BIG_TOP, + IDR_WINDOW_BUBBLE_SHADOW_BIG_TOP_RIGHT, + IDR_WINDOW_BUBBLE_SHADOW_BIG_RIGHT, + IDR_WINDOW_BUBBLE_SHADOW_BIG_BOTTOM_RIGHT, + IDR_WINDOW_BUBBLE_SHADOW_BIG_BOTTOM, + IDR_WINDOW_BUBBLE_SHADOW_BIG_BOTTOM_LEFT, + IDR_WINDOW_BUBBLE_SHADOW_SPIKE_BIG_LEFT, + IDR_WINDOW_BUBBLE_SHADOW_SPIKE_BIG_TOP, + IDR_WINDOW_BUBBLE_SHADOW_SPIKE_BIG_RIGHT, + IDR_WINDOW_BUBBLE_SHADOW_SPIKE_BIG_BOTTOM, +}; + +const int kSmallShadowImages[] = { + IDR_WINDOW_BUBBLE_SHADOW_SMALL_LEFT, + IDR_WINDOW_BUBBLE_SHADOW_SMALL_TOP_LEFT, + IDR_WINDOW_BUBBLE_SHADOW_SMALL_TOP, + IDR_WINDOW_BUBBLE_SHADOW_SMALL_TOP_RIGHT, + IDR_WINDOW_BUBBLE_SHADOW_SMALL_RIGHT, + IDR_WINDOW_BUBBLE_SHADOW_SMALL_BOTTOM_RIGHT, + IDR_WINDOW_BUBBLE_SHADOW_SMALL_BOTTOM, + IDR_WINDOW_BUBBLE_SHADOW_SMALL_BOTTOM_LEFT, + IDR_WINDOW_BUBBLE_SHADOW_SPIKE_SMALL_LEFT, + IDR_WINDOW_BUBBLE_SHADOW_SPIKE_SMALL_TOP, + IDR_WINDOW_BUBBLE_SHADOW_SPIKE_SMALL_RIGHT, + IDR_WINDOW_BUBBLE_SHADOW_SPIKE_SMALL_BOTTOM, +}; + +} // namespace + namespace views { struct BubbleBorder::BorderImages { - BorderImages() - : left(NULL), - top_left(NULL), - top(NULL), - top_right(NULL), - right(NULL), - bottom_right(NULL), - bottom(NULL), - bottom_left(NULL), - left_arrow(NULL), - top_arrow(NULL), - right_arrow(NULL), - bottom_arrow(NULL), - border_thickness(0) { + BorderImages(const int image_ids[], + size_t image_ids_size, + int arrow_interior_height, + int border_thickness, + int corner_radius) + : arrow_interior_height(arrow_interior_height), + border_thickness(border_thickness), + corner_radius(corner_radius) { + // Only two possible sizes of image ids array. + DCHECK(image_ids_size == 12 || image_ids_size == 8); + + ResourceBundle& rb = ResourceBundle::GetSharedInstance(); + + left = *rb.GetImageSkiaNamed(image_ids[0]); + top_left = *rb.GetImageSkiaNamed(image_ids[1]); + top = *rb.GetImageSkiaNamed(image_ids[2]); + top_right = *rb.GetImageSkiaNamed(image_ids[3]); + right = *rb.GetImageSkiaNamed(image_ids[4]); + bottom_right = *rb.GetImageSkiaNamed(image_ids[5]); + bottom = *rb.GetImageSkiaNamed(image_ids[6]); + bottom_left = *rb.GetImageSkiaNamed(image_ids[7]); + + if (image_ids_size > 8) { + left_arrow = *rb.GetImageSkiaNamed(image_ids[8]); + top_arrow = *rb.GetImageSkiaNamed(image_ids[9]); + right_arrow = *rb.GetImageSkiaNamed(image_ids[10]); + bottom_arrow = *rb.GetImageSkiaNamed(image_ids[11]); + } } - gfx::ImageSkia* left; - gfx::ImageSkia* top_left; - gfx::ImageSkia* top; - gfx::ImageSkia* top_right; - gfx::ImageSkia* right; - gfx::ImageSkia* bottom_right; - gfx::ImageSkia* bottom; - gfx::ImageSkia* bottom_left; - gfx::ImageSkia* left_arrow; - gfx::ImageSkia* top_arrow; - gfx::ImageSkia* right_arrow; - gfx::ImageSkia* bottom_arrow; + gfx::ImageSkia left; + gfx::ImageSkia top_left; + gfx::ImageSkia top; + gfx::ImageSkia top_right; + gfx::ImageSkia right; + gfx::ImageSkia bottom_right; + gfx::ImageSkia bottom; + gfx::ImageSkia bottom_left; + + gfx::ImageSkia left_arrow; + gfx::ImageSkia top_arrow; + gfx::ImageSkia right_arrow; + gfx::ImageSkia bottom_arrow; + + int arrow_interior_height; // The height inside the arrow image, in pixels. int border_thickness; + int corner_radius; }; // static -struct BubbleBorder::BorderImages* BubbleBorder::normal_images_ = NULL; -struct BubbleBorder::BorderImages* BubbleBorder::shadow_images_ = NULL; - -// The height inside the arrow image, in pixels. -static const int kArrowInteriorHeight = 7; +struct BubbleBorder::BorderImages* + BubbleBorder::border_images_[SHADOW_COUNT] = { NULL }; BubbleBorder::BubbleBorder(ArrowLocation arrow_location, Shadow shadow) : override_arrow_offset_(0), arrow_location_(arrow_location), alignment_(ALIGN_ARROW_TO_MID_ANCHOR), background_color_(SK_ColorWHITE) { + DCHECK(shadow < SHADOW_COUNT); images_ = GetBorderImages(shadow); // Calculate horizontal and vertical insets for arrow by ensuring that // the widest arrow and corner images will have enough room to avoid overlap int offset_x = - (std::max(images_->top_arrow->width(), - images_->bottom_arrow->width()) / 2) + - std::max(std::max(images_->top_left->width(), - images_->top_right->width()), - std::max(images_->bottom_left->width(), - images_->bottom_right->width())); + (std::max(images_->top_arrow.width(), + images_->bottom_arrow.width()) / 2) + + std::max(std::max(images_->top_left.width(), + images_->top_right.width()), + std::max(images_->bottom_left.width(), + images_->bottom_right.width())); int offset_y = - (std::max(images_->left_arrow->height(), - images_->right_arrow->height()) / 2) + - std::max(std::max(images_->top_left->height(), - images_->top_right->height()), - std::max(images_->bottom_left->height(), - images_->bottom_right->height())); + (std::max(images_->left_arrow.height(), + images_->right_arrow.height()) / 2) + + std::max(std::max(images_->top_left.height(), + images_->top_right.height()), + std::max(images_->bottom_left.height(), + images_->bottom_right.height())); arrow_offset_ = std::max(offset_x, offset_y); } @@ -95,39 +175,46 @@ gfx::Rect BubbleBorder::GetBounds(const gfx::Rect& position_relative_to, border_size.set_height(std::max(border_size.height(), 2 * arrow_offset_)); // Screen position depends on the arrow location. - // The arrow should overlap the target by some amount since there is space - // for shadow between arrow tip and image bounds. - const int kArrowOverlap = 3; + // The bubble should overlap the target by some amount since there is space + // for shadow between arrow tip/bubble border and image bounds. int x = position_relative_to.x(); int y = position_relative_to.y(); int w = position_relative_to.width(); int h = position_relative_to.height(); - int arrow_offset = override_arrow_offset_ ? override_arrow_offset_ : - arrow_offset_; + + const int arrow_size = images_->arrow_interior_height + kBorderStrokeSize; + const int arrow_offset = GetArrowOffset(border_size); // Calculate bubble x coordinate. switch (arrow_location_) { case TOP_LEFT: case BOTTOM_LEFT: x += alignment_ == ALIGN_ARROW_TO_MID_ANCHOR ? w / 2 - arrow_offset : - -kArrowOverlap; + -(images_->left.width() - kBorderStrokeSize); break; case TOP_RIGHT: case BOTTOM_RIGHT: x += alignment_ == ALIGN_ARROW_TO_MID_ANCHOR ? w / 2 + arrow_offset - border_size.width() + 1 : - w - border_size.width() + kArrowOverlap; + w - border_size.width() + images_->right.width() - kBorderStrokeSize; break; case LEFT_TOP: + case LEFT_CENTER: case LEFT_BOTTOM: - x += w - kArrowOverlap; + x += w - (images_->left_arrow.width() - arrow_size); break; case RIGHT_TOP: + case RIGHT_CENTER: case RIGHT_BOTTOM: - x += kArrowOverlap - border_size.width(); + x += images_->right_arrow.width() - arrow_size - border_size.width(); + break; + + case TOP_CENTER: + case BOTTOM_CENTER: + x += w / 2 - arrow_offset; break; case NONE: @@ -139,26 +226,35 @@ gfx::Rect BubbleBorder::GetBounds(const gfx::Rect& position_relative_to, // Calculate bubble y coordinate. switch (arrow_location_) { case TOP_LEFT: + case TOP_CENTER: case TOP_RIGHT: - y += h - kArrowOverlap; + y += h - (images_->top_arrow.height() - arrow_size); break; case BOTTOM_LEFT: + case BOTTOM_CENTER: case BOTTOM_RIGHT: - y += kArrowOverlap - border_size.height(); + y += images_->bottom_arrow.height() - arrow_size - + border_size.height(); break; case LEFT_TOP: case RIGHT_TOP: y += alignment_ == ALIGN_ARROW_TO_MID_ANCHOR ? h / 2 - arrow_offset : - -kArrowOverlap; + -(images_->top.height() - kBorderStrokeSize); break; case LEFT_BOTTOM: case RIGHT_BOTTOM: y += alignment_ == ALIGN_ARROW_TO_MID_ANCHOR ? h / 2 + arrow_offset - border_size.height() + 1 : - h - border_size.height() + kArrowOverlap; + h - border_size.height() + images_->bottom.height() - + kBorderStrokeSize; + break; + + case LEFT_CENTER: + case RIGHT_CENTER: + y += h / 2 - arrow_offset; break; case NONE: @@ -179,29 +275,33 @@ void BubbleBorder::GetInsets(gfx::Insets* insets) const { void BubbleBorder::GetInsetsForArrowLocation(gfx::Insets* insets, ArrowLocation arrow_loc) const { - int top = images_->top->height(); - int bottom = images_->bottom->height(); - int left = images_->left->width(); - int right = images_->right->width(); + int top = images_->top.height(); + int bottom = images_->bottom.height(); + int left = images_->left.width(); + int right = images_->right.width(); switch (arrow_loc) { case TOP_LEFT: + case TOP_CENTER: case TOP_RIGHT: - top = std::max(top, images_->top_arrow->height()); + top = std::max(top, images_->top_arrow.height()); break; case BOTTOM_LEFT: + case BOTTOM_CENTER: case BOTTOM_RIGHT: - bottom = std::max(bottom, images_->bottom_arrow->height()); + bottom = std::max(bottom, images_->bottom_arrow.height()); break; case LEFT_TOP: + case LEFT_CENTER: case LEFT_BOTTOM: - left = std::max(left, images_->left_arrow->width()); + left = std::max(left, images_->left_arrow.width()); break; case RIGHT_TOP: + case RIGHT_CENTER: case RIGHT_BOTTOM: - right = std::max(right, images_->right_arrow->width()); + right = std::max(right, images_->right_arrow.width()); break; case NONE: @@ -216,73 +316,83 @@ int BubbleBorder::GetBorderThickness() const { return images_->border_thickness; } -int BubbleBorder::SetArrowOffset(int offset, const gfx::Size& contents_size) { - gfx::Size border_size(contents_size); - gfx::Insets insets; - GetInsets(&insets); - border_size.Enlarge(insets.left() + insets.right(), - insets.top() + insets.bottom()); - offset = std::max(arrow_offset_, - std::min(offset, (is_arrow_on_horizontal(arrow_location_) ? +int BubbleBorder::GetBorderCornerRadius() const { + return images_->corner_radius; +} + +int BubbleBorder::GetArrowOffset(const gfx::Size& border_size) const { + int arrow_offset = arrow_offset_; + if (override_arrow_offset_) { + arrow_offset = override_arrow_offset_; + } else if (is_arrow_at_center(arrow_location_)) { + if (is_arrow_on_horizontal(arrow_location_)) + arrow_offset = border_size.width() / 2; + else + arrow_offset = border_size.height() / 2; + } + + // |arrow_offset_| contains the minimum offset required to draw border images + // correctly. It's defined in terms of number of pixels from the beginning of + // the edge. The maximum arrow offset is the edge size - |arrow_offset_|. The + // following statement clamps the calculated arrow offset within that range. + return std::max(arrow_offset_, + std::min(arrow_offset, (is_arrow_on_horizontal(arrow_location_) ? border_size.width() : border_size.height()) - arrow_offset_)); - override_arrow_offset_ = offset; - return override_arrow_offset_; } // static BubbleBorder::BorderImages* BubbleBorder::GetBorderImages(Shadow shadow) { - if (shadow == SHADOW && shadow_images_ == NULL) { - ResourceBundle& rb = ResourceBundle::GetSharedInstance(); - shadow_images_ = new BorderImages(); - shadow_images_->left = rb.GetImageSkiaNamed(IDR_BUBBLE_SHADOW_L); - shadow_images_->top_left = rb.GetImageSkiaNamed(IDR_BUBBLE_SHADOW_TL); - shadow_images_->top = rb.GetImageSkiaNamed(IDR_BUBBLE_SHADOW_T); - shadow_images_->top_right = rb.GetImageSkiaNamed(IDR_BUBBLE_SHADOW_TR); - shadow_images_->right = rb.GetImageSkiaNamed(IDR_BUBBLE_SHADOW_R); - shadow_images_->bottom_right = rb.GetImageSkiaNamed(IDR_BUBBLE_SHADOW_BR); - shadow_images_->bottom = rb.GetImageSkiaNamed(IDR_BUBBLE_SHADOW_B); - shadow_images_->bottom_left = rb.GetImageSkiaNamed(IDR_BUBBLE_SHADOW_BL); - shadow_images_->left_arrow = new gfx::ImageSkia(); - shadow_images_->top_arrow = new gfx::ImageSkia(); - shadow_images_->right_arrow = new gfx::ImageSkia(); - shadow_images_->bottom_arrow = new gfx::ImageSkia(); - shadow_images_->border_thickness = 10; - } else if (shadow == NO_SHADOW && normal_images_ == NULL) { - ResourceBundle& rb = ResourceBundle::GetSharedInstance(); - normal_images_ = new BorderImages(); - normal_images_->left = rb.GetImageSkiaNamed(IDR_BUBBLE_L); - normal_images_->top_left = rb.GetImageSkiaNamed(IDR_BUBBLE_TL); - normal_images_->top = rb.GetImageSkiaNamed(IDR_BUBBLE_T); - normal_images_->top_right = rb.GetImageSkiaNamed(IDR_BUBBLE_TR); - normal_images_->right = rb.GetImageSkiaNamed(IDR_BUBBLE_R); - normal_images_->bottom_right = rb.GetImageSkiaNamed(IDR_BUBBLE_BR); - normal_images_->bottom = rb.GetImageSkiaNamed(IDR_BUBBLE_B); - normal_images_->bottom_left = rb.GetImageSkiaNamed(IDR_BUBBLE_BL); - normal_images_->left_arrow = rb.GetImageSkiaNamed(IDR_BUBBLE_L_ARROW); - normal_images_->top_arrow = rb.GetImageSkiaNamed(IDR_BUBBLE_T_ARROW); - normal_images_->right_arrow = rb.GetImageSkiaNamed(IDR_BUBBLE_R_ARROW); - normal_images_->bottom_arrow = rb.GetImageSkiaNamed(IDR_BUBBLE_B_ARROW); - normal_images_->border_thickness = 0; + CHECK_LT(shadow, SHADOW_COUNT); + + struct BorderImages*& images = border_images_[shadow]; + if (images) + return images; + + switch (shadow) { + case SHADOW: + images = new BorderImages(kShadowImages, + arraysize(kShadowImages), + 0, 10, 4); + break; + case NO_SHADOW: + images = new BorderImages(kNoShadowImages, + arraysize(kNoShadowImages), + 7, 0, 4); + break; + case BIG_SHADOW: + images = new BorderImages(kBigShadowImages, + arraysize(kBigShadowImages), + 9, 0, 3); + break; + case SMALL_SHADOW: + images = new BorderImages(kSmallShadowImages, + arraysize(kSmallShadowImages), + 9, 0, 3); + break; + case SHADOW_COUNT: + NOTREACHED(); + break; } - return shadow == SHADOW ? shadow_images_ : normal_images_; + + return images; } BubbleBorder::~BubbleBorder() {} void BubbleBorder::Paint(const views::View& view, gfx::Canvas* canvas) const { // Convenience shorthand variables. - const int tl_width = images_->top_left->width(); - const int tl_height = images_->top_left->height(); - const int t_height = images_->top->height(); - const int tr_width = images_->top_right->width(); - const int tr_height = images_->top_right->height(); - const int l_width = images_->left->width(); - const int r_width = images_->right->width(); - const int br_width = images_->bottom_right->width(); - const int br_height = images_->bottom_right->height(); - const int b_height = images_->bottom->height(); - const int bl_width = images_->bottom_left->width(); - const int bl_height = images_->bottom_left->height(); + const int tl_width = images_->top_left.width(); + const int tl_height = images_->top_left.height(); + const int t_height = images_->top.height(); + const int tr_width = images_->top_right.width(); + const int tr_height = images_->top_right.height(); + const int l_width = images_->left.width(); + const int r_width = images_->right.width(); + const int br_width = images_->bottom_right.width(); + const int br_height = images_->bottom_right.height(); + const int b_height = images_->bottom.height(); + const int bl_width = images_->bottom_left.width(); + const int bl_height = images_->bottom_left.height(); gfx::Insets insets; GetInsets(&insets); @@ -293,29 +403,31 @@ void BubbleBorder::Paint(const views::View& view, gfx::Canvas* canvas) const { const int height = bottom - top; const int width = right - left; - // |arrow_offset| is offset of arrow from the begining of the edge. - int arrow_offset = arrow_offset_; - if (override_arrow_offset_) - arrow_offset = override_arrow_offset_; - else if (is_arrow_on_horizontal(arrow_location_) && - !is_arrow_on_left(arrow_location_)) { - arrow_offset = view.width() - arrow_offset - 1; - } else if (!is_arrow_on_horizontal(arrow_location_) && - !is_arrow_on_top(arrow_location_)) { - arrow_offset = view.height() - arrow_offset - 1; + // |arrow_offset| is offset of arrow from the beginning of the edge. + int arrow_offset = GetArrowOffset(view.size()); + if (!is_arrow_at_center(arrow_location_)) { + if (is_arrow_on_horizontal(arrow_location_) && + !is_arrow_on_left(arrow_location_)) { + arrow_offset = view.width() - arrow_offset - 1; + } else if (!is_arrow_on_horizontal(arrow_location_) && + !is_arrow_on_top(arrow_location_)) { + arrow_offset = view.height() - arrow_offset - 1; + } } // Left edge. - if (arrow_location_ == LEFT_TOP || arrow_location_ == LEFT_BOTTOM) { + if (arrow_location_ == LEFT_TOP || + arrow_location_ == LEFT_CENTER || + arrow_location_ == LEFT_BOTTOM) { int start_y = top + tl_height; int before_arrow = - arrow_offset - start_y - images_->left_arrow->height() / 2; + arrow_offset - start_y - images_->left_arrow.height() / 2; int after_arrow = height - tl_height - bl_height - - images_->left_arrow->height() - before_arrow; + images_->left_arrow.height() - before_arrow; // Shift tip coordinates half pixel so that skia draws the tip correctly. DrawArrowInterior(canvas, - images_->left_arrow->width() - kArrowInteriorHeight - 0.5f, - start_y + before_arrow + images_->left_arrow->height() / 2 - 0.5f); + images_->left_arrow.width() - images_->arrow_interior_height - 0.5f, + start_y + before_arrow + images_->left_arrow.height() / 2 - 0.5f); DrawEdgeWithArrow(canvas, false, images_->left, @@ -324,24 +436,26 @@ void BubbleBorder::Paint(const views::View& view, gfx::Canvas* canvas) const { start_y, before_arrow, after_arrow, - images_->left->width() - images_->left_arrow->width()); + images_->left.width() - images_->left_arrow.width()); } else { - canvas->TileImageInt(*images_->left, left, top + tl_height, l_width, + canvas->TileImageInt(images_->left, left, top + tl_height, l_width, height - tl_height - bl_height); } // Top left corner. - canvas->DrawImageInt(*images_->top_left, left, top); + canvas->DrawImageInt(images_->top_left, left, top); // Top edge. - if (arrow_location_ == TOP_LEFT || arrow_location_ == TOP_RIGHT) { + if (arrow_location_ == TOP_LEFT || + arrow_location_ == TOP_CENTER || + arrow_location_ == TOP_RIGHT) { int start_x = left + tl_width; - int before_arrow = arrow_offset - start_x - images_->top_arrow->width() / 2; + int before_arrow = arrow_offset - start_x - images_->top_arrow.width() / 2; int after_arrow = width - tl_width - tr_width - - images_->top_arrow->width() - before_arrow; + images_->top_arrow.width() - before_arrow; DrawArrowInterior(canvas, - start_x + before_arrow + images_->top_arrow->width() / 2, - images_->top_arrow->height() - kArrowInteriorHeight); + start_x + before_arrow + images_->top_arrow.width() / 2, + images_->top_arrow.height() - images_->arrow_interior_height); DrawEdgeWithArrow(canvas, true, images_->top, @@ -350,26 +464,28 @@ void BubbleBorder::Paint(const views::View& view, gfx::Canvas* canvas) const { top, before_arrow, after_arrow, - images_->top->height() - images_->top_arrow->height()); + images_->top.height() - images_->top_arrow.height()); } else { - canvas->TileImageInt(*images_->top, left + tl_width, top, + canvas->TileImageInt(images_->top, left + tl_width, top, width - tl_width - tr_width, t_height); } // Top right corner. - canvas->DrawImageInt(*images_->top_right, right - tr_width, top); + canvas->DrawImageInt(images_->top_right, right - tr_width, top); // Right edge. - if (arrow_location_ == RIGHT_TOP || arrow_location_ == RIGHT_BOTTOM) { + if (arrow_location_ == RIGHT_TOP || + arrow_location_ == RIGHT_CENTER || + arrow_location_ == RIGHT_BOTTOM) { int start_y = top + tr_height; int before_arrow = - arrow_offset - start_y - images_->right_arrow->height() / 2; + arrow_offset - start_y - images_->right_arrow.height() / 2; int after_arrow = height - tl_height - bl_height - - images_->right_arrow->height() - before_arrow; + images_->right_arrow.height() - before_arrow; // Shift tip coordinates half pixel so that skia draws the tip correctly. DrawArrowInterior(canvas, - right - r_width + kArrowInteriorHeight - 0.5f, - start_y + before_arrow + images_->right_arrow->height() / 2 - 0.5f); + right - r_width + images_->arrow_interior_height - 0.5f, + start_y + before_arrow + images_->right_arrow.height() / 2 - 0.5f); DrawEdgeWithArrow(canvas, false, images_->right, @@ -380,25 +496,27 @@ void BubbleBorder::Paint(const views::View& view, gfx::Canvas* canvas) const { after_arrow, 0); } else { - canvas->TileImageInt(*images_->right, right - r_width, top + tr_height, + canvas->TileImageInt(images_->right, right - r_width, top + tr_height, r_width, height - tr_height - br_height); } // Bottom right corner. - canvas->DrawImageInt(*images_->bottom_right, + canvas->DrawImageInt(images_->bottom_right, right - br_width, bottom - br_height); // Bottom edge. - if (arrow_location_ == BOTTOM_LEFT || arrow_location_ == BOTTOM_RIGHT) { + if (arrow_location_ == BOTTOM_LEFT || + arrow_location_ == BOTTOM_CENTER || + arrow_location_ == BOTTOM_RIGHT) { int start_x = left + bl_width; int before_arrow = - arrow_offset - start_x - images_->bottom_arrow->width() / 2; + arrow_offset - start_x - images_->bottom_arrow.width() / 2; int after_arrow = width - bl_width - br_width - - images_->bottom_arrow->width() - before_arrow; + images_->bottom_arrow.width() - before_arrow; DrawArrowInterior(canvas, - start_x + before_arrow + images_->bottom_arrow->width() / 2, - bottom - b_height + kArrowInteriorHeight); + start_x + before_arrow + images_->bottom_arrow.width() / 2, + bottom - b_height + images_->arrow_interior_height); DrawEdgeWithArrow(canvas, true, images_->bottom, @@ -409,18 +527,18 @@ void BubbleBorder::Paint(const views::View& view, gfx::Canvas* canvas) const { after_arrow, 0); } else { - canvas->TileImageInt(*images_->bottom, left + bl_width, bottom - b_height, + canvas->TileImageInt(images_->bottom, left + bl_width, bottom - b_height, width - bl_width - br_width, b_height); } // Bottom left corner. - canvas->DrawImageInt(*images_->bottom_left, left, bottom - bl_height); + canvas->DrawImageInt(images_->bottom_left, left, bottom - bl_height); } void BubbleBorder::DrawEdgeWithArrow(gfx::Canvas* canvas, bool is_horizontal, - gfx::ImageSkia* edge, - gfx::ImageSkia* arrow, + const gfx::ImageSkia& edge, + const gfx::ImageSkia& arrow, int start_x, int start_y, int before_arrow, @@ -438,21 +556,21 @@ void BubbleBorder::DrawEdgeWithArrow(gfx::Canvas* canvas, * before_arrow ─┘ └─ after_arrow */ if (before_arrow) { - canvas->TileImageInt(*edge, start_x, start_y, - is_horizontal ? before_arrow : edge->width(), - is_horizontal ? edge->height() : before_arrow); + canvas->TileImageInt(edge, start_x, start_y, + is_horizontal ? before_arrow : edge.width(), + is_horizontal ? edge.height() : before_arrow); } - canvas->DrawImageInt(*arrow, + canvas->DrawImageInt(arrow, start_x + (is_horizontal ? before_arrow : offset), start_y + (is_horizontal ? offset : before_arrow)); if (after_arrow) { - start_x += (is_horizontal ? before_arrow + arrow->width() : 0); - start_y += (is_horizontal ? 0 : before_arrow + arrow->height()); - canvas->TileImageInt(*edge, start_x, start_y, - is_horizontal ? after_arrow : edge->width(), - is_horizontal ? edge->height() : after_arrow); + start_x += (is_horizontal ? before_arrow + arrow.width() : 0); + start_y += (is_horizontal ? 0 : before_arrow + arrow.height()); + canvas->TileImageInt(edge, start_x, start_y, + is_horizontal ? after_arrow : edge.width(), + is_horizontal ? edge.height() : after_arrow); } } @@ -463,7 +581,7 @@ void BubbleBorder::DrawArrowInterior(gfx::Canvas* canvas, const bool positive_offset = is_horizontal ? is_arrow_on_top(arrow_location_) : is_arrow_on_left(arrow_location_); const int offset_to_next_vertex = positive_offset ? - kArrowInteriorHeight : -kArrowInteriorHeight; + images_->arrow_interior_height : -images_->arrow_interior_height; SkPath path; path.incReserve(4); @@ -506,7 +624,7 @@ void BubbleBackground::Paint(gfx::Canvas* canvas, views::View* view) const { SkPath path; gfx::Rect bounds(view->GetContentsBounds()); bounds.Inset(-border_->GetBorderThickness(), -border_->GetBorderThickness()); - SkScalar radius = SkIntToScalar(BubbleBorder::GetCornerRadius()); + SkScalar radius = SkIntToScalar(border_->GetBorderCornerRadius()); path.addRoundRect(gfx::RectToSkRect(bounds), radius, radius); canvas->DrawPath(path, paint); } diff --git a/ui/views/bubble/bubble_border.h b/ui/views/bubble/bubble_border.h index 17d1de7..d883ca7 100644 --- a/ui/views/bubble/bubble_border.h +++ b/ui/views/bubble/bubble_border.h @@ -24,22 +24,37 @@ class VIEWS_EXPORT BubbleBorder : public Border { // 0 bit specifies left or right. // 1 bit specifies top or bottom. // 2 bit specifies horizontal or vertical. + // 3 bit specifies whether the arrow at the center of its residing edge. + enum ArrowLocationMask { + RIGHT = 0x01, + BOTTOM = 0x02, + VERTICAL = 0x04, + CENTER = 0x08, + }; + enum ArrowLocation { - TOP_LEFT = 0, - TOP_RIGHT = 1, - BOTTOM_LEFT = 2, - BOTTOM_RIGHT = 3, - LEFT_TOP = 4, - RIGHT_TOP = 5, - LEFT_BOTTOM = 6, - RIGHT_BOTTOM = 7, - NONE = 8, // No arrow. Positioned under the supplied rect. - FLOAT = 9 // No arrow. Centered over the supplied rect. + TOP_LEFT = 0, + TOP_RIGHT = RIGHT, + BOTTOM_LEFT = BOTTOM, + BOTTOM_RIGHT = BOTTOM | RIGHT, + LEFT_TOP = VERTICAL, + RIGHT_TOP = VERTICAL | RIGHT, + LEFT_BOTTOM = VERTICAL | BOTTOM, + RIGHT_BOTTOM = VERTICAL | BOTTOM | RIGHT, + TOP_CENTER = CENTER, + BOTTOM_CENTER = CENTER | BOTTOM, + LEFT_CENTER = CENTER | VERTICAL, + RIGHT_CENTER = CENTER | VERTICAL | RIGHT, + NONE = 16, // No arrow. Positioned under the supplied rect. + FLOAT = 17, // No arrow. Centered over the supplied rect. }; enum Shadow { SHADOW = 0, - NO_SHADOW = 1 + NO_SHADOW, + BIG_SHADOW, + SMALL_SHADOW, + SHADOW_COUNT, }; // The position of the bubble in relation to the anchor. @@ -53,6 +68,7 @@ class VIEWS_EXPORT BubbleBorder : public Border { BubbleBorder(ArrowLocation arrow_location, Shadow shadow); // Returns the radius of the corner of the border. + // TODO(xiyuan): Get rid of this since it's part of BorderImages now? static int GetCornerRadius() { // We can't safely calculate a border radius by comparing the sizes of the // side and corner images, because either may have been extended in various @@ -70,11 +86,13 @@ class VIEWS_EXPORT BubbleBorder : public Border { BubbleAlignment alignment() const { return alignment_; } static ArrowLocation horizontal_mirror(ArrowLocation loc) { - return loc >= NONE ? loc : static_cast<ArrowLocation>(loc ^ 1); + return (loc == TOP_CENTER || loc == BOTTOM_CENTER || loc >= NONE) ? + loc : static_cast<ArrowLocation>(loc ^ RIGHT); } static ArrowLocation vertical_mirror(ArrowLocation loc) { - return loc >= NONE ? loc : static_cast<ArrowLocation>(loc ^ 2); + return (loc == LEFT_CENTER || loc == RIGHT_CENTER || loc >= NONE) ? + loc : static_cast<ArrowLocation>(loc ^ BOTTOM); } static bool has_arrow(ArrowLocation loc) { @@ -82,15 +100,21 @@ class VIEWS_EXPORT BubbleBorder : public Border { } static bool is_arrow_on_left(ArrowLocation loc) { - return loc >= NONE ? false : !(loc & 1); + return (loc == TOP_CENTER || loc == BOTTOM_CENTER || loc >= NONE) ? + false : !(loc & RIGHT); } static bool is_arrow_on_top(ArrowLocation loc) { - return loc >= NONE ? false : !(loc & 2); + return (loc == LEFT_CENTER || loc == RIGHT_CENTER || loc >= NONE) ? + false : !(loc & BOTTOM); } static bool is_arrow_on_horizontal(ArrowLocation loc) { - return loc >= NONE ? false : !(loc & 4); + return loc >= NONE ? false : !(loc & VERTICAL); + } + + static bool is_arrow_at_center(ArrowLocation loc) { + return has_arrow(loc) && !!(loc & CENTER); } // Sets the background color for the arrow body. This is irrelevant if you do @@ -101,6 +125,11 @@ class VIEWS_EXPORT BubbleBorder : public Border { void set_client_bounds(const gfx::Rect& bounds) { client_bounds_ = bounds; } const gfx::Rect& client_bounds() const { return client_bounds_; } + // Sets a fixed offset for the arrow from the beginning of corresponding edge. + // The arrow will still point to the same location but the bubble will shift + // location to make that happen. + void set_arrow_offset(int offset) { override_arrow_offset_ = offset; } + // For borders with an arrow, gives the desired bounds (in screen coordinates) // given the rect to point to and the size of the contained contents. This // depends on the arrow location, so if you change that, you should call this @@ -108,11 +137,11 @@ class VIEWS_EXPORT BubbleBorder : public Border { virtual gfx::Rect GetBounds(const gfx::Rect& position_relative_to, const gfx::Size& contents_size) const; - // Sets a fixed offset for the arrow from the beginning of corresponding edge. - // The arrow will still point to the same location but the bubble will shift - // location to make that happen. Returns actuall arrow offset, in case of - // overflow it differ from desired. - int SetArrowOffset(int offset, const gfx::Size& contents_size); + // Returns the corner radius of the current image set. + int GetBorderCornerRadius() const; + + // Gets the arrow offset to use. + int GetArrowOffset(const gfx::Size& border_size) const; // Overridden from Border: virtual void GetInsets(gfx::Insets* insets) const OVERRIDE; @@ -141,8 +170,8 @@ class VIEWS_EXPORT BubbleBorder : public Border { void DrawEdgeWithArrow(gfx::Canvas* canvas, bool is_horizontal, - gfx::ImageSkia* edge, - gfx::ImageSkia* arrow, + const gfx::ImageSkia& edge, + const gfx::ImageSkia& arrow, int start_x, int start_y, int before_arrow, @@ -155,8 +184,7 @@ class VIEWS_EXPORT BubbleBorder : public Border { struct BorderImages* images_; // Image bundles. - static struct BorderImages* normal_images_; - static struct BorderImages* shadow_images_; + static struct BorderImages* border_images_[SHADOW_COUNT]; // Minimal offset of the arrow from the closet edge of bounding rect. int arrow_offset_; diff --git a/ui/views/bubble/bubble_border_2.cc b/ui/views/bubble/bubble_border_2.cc deleted file mode 100644 index 0f909d1..0000000 --- a/ui/views/bubble/bubble_border_2.cc +++ /dev/null @@ -1,399 +0,0 @@ -// Copyright (c) 2012 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 "ui/views/bubble/bubble_border_2.h" - -#include <algorithm> // for std::max - -#include "base/logging.h" -#include "ui/gfx/canvas.h" -#include "ui/gfx/path.h" -#include "ui/gfx/rect.h" -#include "ui/gfx/screen.h" -#include "ui/gfx/skia_util.h" - -namespace { - -// Bubble border corner radius. -const int kCornerRadius = 2; - -// Arrow width and height. -const int kArrowHeight = 10; -const int kArrowWidth = 20; - -const int kBorderSize = 1; -const SkColor kBorderColor = SkColorSetARGB(0x26, 0, 0, 0); -const SkColor kBackgroundColor = SK_ColorWHITE; - -const int kShadowOffsetX = 0; -const int kShadowOffsetY = 5; -const double kShadowBlur = 30; -const SkColor kShadowColor = SkColorSetARGB(0x72, 0, 0, 0); - -// Builds a bubble shape for given |bounds|. -void BuildShape(const gfx::Rect& bounds, - views::BubbleBorder::ArrowLocation arrow_location, - SkScalar arrow_offset, - SkScalar padding, - SkPath* path, - int corner_radius_int, - int arrow_height_int, - int arrow_width_int) { - const SkScalar corner_radius = SkIntToScalar(corner_radius_int); - - const SkScalar left = SkIntToScalar(bounds.x()) + padding; - const SkScalar top = SkIntToScalar(bounds.y()) + padding; - const SkScalar right = SkIntToScalar(bounds.right()) - padding; - const SkScalar bottom = SkIntToScalar(bounds.bottom()) - padding; - - const SkScalar center_x = SkIntToScalar((bounds.x() + bounds.right()) / 2); - const SkScalar center_y = SkIntToScalar((bounds.y() + bounds.bottom()) / 2); - - const SkScalar half_arrow_width = - (SkIntToScalar(arrow_width_int) - padding) / 2; - const SkScalar arrow_height = SkIntToScalar(arrow_height_int) - padding; - - path->reset(); - path->incReserve(12); - - switch (arrow_location) { - case views::BubbleBorder::TOP_LEFT: - case views::BubbleBorder::TOP_RIGHT: - path->moveTo(center_x, bottom); - path->arcTo(right, bottom, right, center_y, corner_radius); - path->arcTo(right, top, center_x - half_arrow_width, top, - corner_radius); - path->lineTo(center_x + arrow_offset + half_arrow_width, top); - path->lineTo(center_x + arrow_offset, top - arrow_height); - path->lineTo(center_x + arrow_offset - half_arrow_width, top); - path->arcTo(left, top, left, center_y, corner_radius); - path->arcTo(left, bottom, center_x, bottom, corner_radius); - break; - case views::BubbleBorder::BOTTOM_LEFT: - case views::BubbleBorder::BOTTOM_RIGHT: - path->moveTo(center_x, top); - path->arcTo(left, top, left, center_y, corner_radius); - path->arcTo(left, bottom, center_x - half_arrow_width, bottom, - corner_radius); - path->lineTo(center_x + arrow_offset - half_arrow_width, bottom); - path->lineTo(center_x + arrow_offset, bottom + arrow_height); - path->lineTo(center_x + arrow_offset + half_arrow_width, bottom); - path->arcTo(right, bottom, right, center_y, corner_radius); - path->arcTo(right, top, center_x, top, corner_radius); - break; - case views::BubbleBorder::LEFT_TOP: - case views::BubbleBorder::LEFT_BOTTOM: - path->moveTo(right, center_y); - path->arcTo(right, top, center_x, top, corner_radius); - path->arcTo(left, top, left, center_y + arrow_offset - half_arrow_width, - corner_radius); - path->lineTo(left, center_y + arrow_offset - half_arrow_width); - path->lineTo(left - arrow_height, center_y + arrow_offset); - path->lineTo(left, center_y + arrow_offset + half_arrow_width); - path->arcTo(left, bottom, center_x, bottom, corner_radius); - path->arcTo(right, bottom, right, center_y, corner_radius); - break; - case views::BubbleBorder::RIGHT_TOP: - case views::BubbleBorder::RIGHT_BOTTOM: - path->moveTo(left, center_y); - path->arcTo(left, bottom, center_x, bottom, corner_radius); - path->arcTo(right, bottom, - right, center_y + arrow_offset + half_arrow_width, - corner_radius); - path->lineTo(right, center_y + arrow_offset + half_arrow_width); - path->lineTo(right + arrow_height, center_y + arrow_offset); - path->lineTo(right, center_y + arrow_offset - half_arrow_width); - path->arcTo(right, top, center_x, top, corner_radius); - path->arcTo(left, top, left, center_y, corner_radius); - break; - default: - // No arrows. - path->addRoundRect(gfx::RectToSkRect(bounds), - corner_radius, - corner_radius); - break; - } - - path->close(); -} - -} // namespace - -namespace views { - -BubbleBorder2::BubbleBorder2(ArrowLocation arrow_location) - : BubbleBorder(arrow_location, views::BubbleBorder::NO_SHADOW), - corner_radius_(kCornerRadius), - border_size_(kBorderSize), - arrow_height_(kArrowHeight), - arrow_width_(kArrowWidth), - background_color_(kBackgroundColor), - border_color_(kBorderColor) { - SetShadow(gfx::ShadowValue(gfx::Point(kShadowOffsetX, kShadowOffsetY), - kShadowBlur, kShadowColor)); -} - -BubbleBorder2::~BubbleBorder2() {} - -gfx::Rect BubbleBorder2::ComputeOffsetAndUpdateBubbleRect( - gfx::Rect bubble_rect, - const gfx::Rect& anchor_view_rect) { - offset_ = gfx::Point(); - - gfx::Rect monitor_rect = gfx::Screen::GetDisplayNearestPoint( - anchor_view_rect.CenterPoint()).bounds(); - if (monitor_rect.IsEmpty() || monitor_rect.Contains(bubble_rect)) - return bubble_rect; - - gfx::Point offset; - - if (has_arrow(arrow_location())) { - if (is_arrow_on_horizontal(arrow_location())) { - if (bubble_rect.x() < monitor_rect.x()) - offset.set_x(monitor_rect.x() - bubble_rect.x()); - else if (bubble_rect.right() > monitor_rect.right()) - offset.set_x(monitor_rect.right() - bubble_rect.right()); - } else { - if (bubble_rect.y() < monitor_rect.y()) - offset.set_y(monitor_rect.y() - bubble_rect.y()); - else if (bubble_rect.bottom() > monitor_rect.bottom()) - offset.set_y(monitor_rect.bottom() - bubble_rect.bottom()); - } - } - - bubble_rect.Offset(offset); - set_offset(offset); - - return bubble_rect; -} - -void BubbleBorder2::GetMask(const gfx::Rect& bounds, - gfx::Path* mask) const { - gfx::Insets insets; - GetInsets(&insets); - - gfx::Rect content_bounds(bounds); - content_bounds.Inset(insets); - - BuildShape(content_bounds, - arrow_location(), - SkIntToScalar(GetArrowOffset()), - SkIntToScalar(kBorderSize), - mask, - corner_radius_, - arrow_height_, - arrow_width_); -} - -void BubbleBorder2::SetShadow(gfx::ShadowValue shadow) { - shadows_.clear(); - shadows_.push_back(shadow); -} - -int BubbleBorder2::GetBorderThickness() const { - return border_size_; -} - -void BubbleBorder2::PaintBackground(gfx::Canvas* canvas, - const gfx::Rect& bounds) const { - canvas->FillRect(bounds, background_color_); -} - -int BubbleBorder2::GetArrowOffset() const { - if (has_arrow(arrow_location())) { - if (is_arrow_on_horizontal(arrow_location())) { - // Picks x offset and moves bubble arrow in the opposite direction. - // i.e. If bubble bounds is moved to right (positive offset), we need to - // move arrow to left so that it points to the same position. - return -offset_.x(); - } else { - // Picks y offset and moves bubble arrow in the opposite direction. - return -offset_.y(); - } - } - - // Other style does not have an arrow, so return 0. - return 0; -} - -void BubbleBorder2::GetInsets(gfx::Insets* insets) const { - // Negate to change from outer margin to inner padding. - gfx::Insets shadow_padding(-gfx::ShadowValue::GetMargin(shadows_)); - - if (arrow_location() == views::BubbleBorder::TOP_LEFT || - arrow_location() == views::BubbleBorder::TOP_RIGHT) { - // Arrow at top. - insets->Set(shadow_padding.top() + arrow_height_, - shadow_padding.left(), - shadow_padding.bottom(), - shadow_padding.right()); - } else if (arrow_location() == views::BubbleBorder::BOTTOM_LEFT || - arrow_location() == views::BubbleBorder::BOTTOM_RIGHT) { - // Arrow at bottom. - insets->Set(shadow_padding.top(), - shadow_padding.left(), - shadow_padding.bottom() + arrow_height_, - shadow_padding.right()); - } else if (arrow_location() == views::BubbleBorder::LEFT_TOP || - arrow_location() == views::BubbleBorder::LEFT_BOTTOM) { - // Arrow on left. - insets->Set(shadow_padding.top(), - shadow_padding.left() + arrow_height_, - shadow_padding.bottom(), - shadow_padding.right()); - } else if (arrow_location() == views::BubbleBorder::RIGHT_TOP || - arrow_location() == views::BubbleBorder::RIGHT_BOTTOM) { - // Arrow on right. - insets->Set(shadow_padding.top(), - shadow_padding.left(), - shadow_padding.bottom(), - shadow_padding.right() + arrow_height_); - } -} - -gfx::Rect BubbleBorder2::GetBounds(const gfx::Rect& position_relative_to, - const gfx::Size& contents_size) const { - gfx::Size border_size(contents_size); - gfx::Insets insets; - GetInsets(&insets); - border_size.Enlarge(insets.width(), insets.height()); - - // Negate to change from outer margin to inner padding. - gfx::Insets shadow_padding(-gfx::ShadowValue::GetMargin(shadows_)); - - // Anchor center that arrow aligns with. - const int anchor_center_x = - (position_relative_to.x() + position_relative_to.right()) / 2; - const int anchor_center_y = - (position_relative_to.y() + position_relative_to.bottom()) / 2; - - // Arrow position relative to top-left of bubble. |arrow_tip_x| is used for - // arrow at the top or bottom and |arrow_tip_y| is used for arrow on left or - // right. The 1px offset for |arrow_tip_y| is needed because the app list grid - // icon start at a different position (1px earlier) compared with bottom - // launcher bar. - // TODO(xiyuan): Remove 1px offset when app list icon image asset is updated. - int arrow_tip_x = insets.left() + contents_size.width() / 2 + - GetArrowOffset(); - int arrow_tip_y = insets.top() + contents_size.height() / 2 + - GetArrowOffset() + 1; - - if (arrow_location() == views::BubbleBorder::TOP_LEFT || - arrow_location() == views::BubbleBorder::TOP_RIGHT) { - // Arrow at top. - return gfx::Rect( - gfx::Point(anchor_center_x - arrow_tip_x, - position_relative_to.bottom() - shadow_padding.top()), - border_size); - } else if (arrow_location() == views::BubbleBorder::BOTTOM_LEFT || - arrow_location() == views::BubbleBorder::BOTTOM_RIGHT) { - // Arrow at bottom. - return gfx::Rect( - gfx::Point(anchor_center_x - arrow_tip_x, - position_relative_to.y() - border_size.height() + - shadow_padding.bottom()), - border_size); - } else if (arrow_location() == views::BubbleBorder::LEFT_TOP || - arrow_location() == views::BubbleBorder::LEFT_BOTTOM) { - // Arrow on left. - return gfx::Rect( - gfx::Point(position_relative_to.right() - shadow_padding.left(), - anchor_center_y - arrow_tip_y), - border_size); - } else if (arrow_location() == views::BubbleBorder::RIGHT_TOP || - arrow_location() == views::BubbleBorder::RIGHT_BOTTOM) { - // Arrow on right. - return gfx::Rect( - gfx::Point(position_relative_to.x() - border_size.width() + - shadow_padding.right(), - anchor_center_y - arrow_tip_y), - border_size); - } - - // No arrow bubble, center align with anchor. - return position_relative_to.Center(border_size); -} - -void BubbleBorder2::GetInsetsForArrowLocation(gfx::Insets* insets, - ArrowLocation arrow_loc) const { - int top = border_size_; - int bottom = border_size_; - int left = border_size_; - int right = border_size_; - switch (arrow_loc) { - case TOP_LEFT: - case TOP_RIGHT: - top = std::max(top, arrow_height_); - break; - - case BOTTOM_LEFT: - case BOTTOM_RIGHT: - bottom = std::max(bottom, arrow_height_); - break; - - case LEFT_TOP: - case LEFT_BOTTOM: - left = std::max(left, arrow_height_); - break; - - case RIGHT_TOP: - case RIGHT_BOTTOM: - right = std::max(right, arrow_height_); - break; - - case NONE: - case FLOAT: - // Nothing to do. - break; - } - insets->Set(top, left, bottom, right); -} - -void BubbleBorder2::Paint(const views::View& view, gfx::Canvas* canvas) const { - gfx::Insets insets; - GetInsets(&insets); - - gfx::Rect content_bounds = view.bounds(); - content_bounds.Inset(insets); - - SkPath path; - // Pads with 0.5 pixel since anti alias is used. - BuildShape(content_bounds, - arrow_location(), - SkIntToScalar(GetArrowOffset()), - SkDoubleToScalar(0.5), - &path, - corner_radius_, - arrow_height_, - arrow_width_); - - // Draw border and shadow. Note fill is needed to generate enough shadow. - SkPaint paint; - paint.setAntiAlias(true); - paint.setStyle(SkPaint::kStrokeAndFill_Style); - paint.setStrokeWidth(SkIntToScalar(border_size_)); - paint.setColor(border_color_); - SkSafeUnref(paint.setLooper(gfx::CreateShadowDrawLooper(shadows_))); - canvas->DrawPath(path, paint); - - // Pads with |border_size_| pixels to leave space for border lines. - BuildShape(content_bounds, - arrow_location(), - SkIntToScalar(GetArrowOffset()), - SkIntToScalar(border_size_), - &path, - corner_radius_, - arrow_height_, - arrow_width_); - canvas->Save(); - canvas->ClipPath(path); - - // Use full bounds so that arrow is also painted. - const gfx::Rect& bounds = view.bounds(); - PaintBackground(canvas, bounds); - - canvas->Restore(); -} - -} // namespace views diff --git a/ui/views/bubble/bubble_border_2.h b/ui/views/bubble/bubble_border_2.h deleted file mode 100644 index 46eafbc..0000000 --- a/ui/views/bubble/bubble_border_2.h +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright (c) 2012 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 UI_VIEWS_BUBBLE_BUBBLE_BORDER_2_H_ -#define UI_VIEWS_BUBBLE_BUBBLE_BORDER_2_H_ - -#include "base/basictypes.h" -#include "base/compiler_specific.h" -#include "ui/gfx/shadow_value.h" -#include "ui/views/bubble/bubble_border.h" - -namespace views { - -// A BubbleBorder rendered with Skia drawing commands instead of images. -class VIEWS_EXPORT BubbleBorder2 : public BubbleBorder { - public: - explicit BubbleBorder2(ArrowLocation arrow_location); - virtual ~BubbleBorder2(); - - // Given the |bubble_rect| that this border encloses, and the bounds of the - // anchor view |anchor_view_rect|, compute the right offset to place the - // arrow at shifting the |bubble_rect| to fit inside the display area if - // needed. Returns the shifted |bubble_rect|. - gfx::Rect ComputeOffsetAndUpdateBubbleRect(gfx::Rect bubble_rect, - const gfx::Rect& anchor_view_rect); - - // Returns the path in |mask| that would be created if this border were to be - // applied to the rect specified by |bounds|. - void GetMask(const gfx::Rect& bounds, gfx::Path* mask) const; - - void set_offset(const gfx::Point& offset) { offset_ = offset; } - const gfx::Point& offset() const { return offset_; } - - void set_corner_radius(int corner_radius) { corner_radius_ = corner_radius; } - int corner_radius() const { return corner_radius_; } - - void set_border_size(int border_size) { border_size_ = border_size; } - int border_size() const { return border_size_; } - - void set_arrow_height(int arrow_height) { arrow_height_ = arrow_height; } - int arrow_height() const { return arrow_height_; } - - void set_arrow_width(int arrow_width) { arrow_width_ = arrow_width; } - int arrow_width() const { return arrow_width_; } - - void SetShadow(gfx::ShadowValue shadow); - - // views::BubbleBorder overrides: - virtual int GetBorderThickness() const OVERRIDE; - - protected: - virtual void PaintBackground(gfx::Canvas* canvas, - const gfx::Rect& bounds) const; - - private: - // Gets arrow offset based on arrow location and |offset_|. - int GetArrowOffset() const; - - // views::BubbleBorder overrides: - virtual void GetInsets(gfx::Insets* insets) const OVERRIDE; - virtual gfx::Rect GetBounds(const gfx::Rect& position_relative_to, - const gfx::Size& contents_size) const OVERRIDE; - virtual void GetInsetsForArrowLocation( - gfx::Insets* insets, - ArrowLocation arrow_loc) const OVERRIDE; - - // views::Border overrides: - virtual void Paint(const View& view, - gfx::Canvas* canvas) const OVERRIDE; - - int corner_radius_; - int border_size_; - int arrow_height_; - int arrow_width_; - SkColor background_color_; - SkColor border_color_; - - // Offset in pixels by which the arrow is shifted relative the default middle - // position. If the arrow is placed horizontally (at top or bottom), the |x_| - // component of |offset_| specifies the offset, else, the |y_| component. - gfx::Point offset_; - - gfx::ShadowValues shadows_; - - DISALLOW_COPY_AND_ASSIGN(BubbleBorder2); -}; - -} // namespace views - -#endif // UI_VIEWS_BUBBLE_BUBBLE_BORDER_2_H_ diff --git a/ui/views/bubble/bubble_border_unittest.cc b/ui/views/bubble/bubble_border_unittest.cc new file mode 100644 index 0000000..cb49030 --- /dev/null +++ b/ui/views/bubble/bubble_border_unittest.cc @@ -0,0 +1,205 @@ +// Copyright (c) 2012 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 "ui/views/bubble/bubble_border.h" + +#include "ui/views/test/views_test_base.h" + +namespace views { + +typedef ViewsTestBase BubbleBorderTest; + +TEST_F(BubbleBorderTest, GetMirroredArrow) { + // Horizontal mirroring. + EXPECT_EQ(BubbleBorder::TOP_RIGHT, + BubbleBorder::horizontal_mirror(BubbleBorder::TOP_LEFT)); + EXPECT_EQ(BubbleBorder::TOP_LEFT, + BubbleBorder::horizontal_mirror(BubbleBorder::TOP_RIGHT)); + + EXPECT_EQ(BubbleBorder::BOTTOM_RIGHT, + BubbleBorder::horizontal_mirror(BubbleBorder::BOTTOM_LEFT)); + EXPECT_EQ(BubbleBorder::BOTTOM_LEFT, + BubbleBorder::horizontal_mirror(BubbleBorder::BOTTOM_RIGHT)); + + EXPECT_EQ(BubbleBorder::RIGHT_TOP, + BubbleBorder::horizontal_mirror(BubbleBorder::LEFT_TOP)); + EXPECT_EQ(BubbleBorder::LEFT_TOP, + BubbleBorder::horizontal_mirror(BubbleBorder::RIGHT_TOP)); + + EXPECT_EQ(BubbleBorder::RIGHT_BOTTOM, + BubbleBorder::horizontal_mirror(BubbleBorder::LEFT_BOTTOM)); + EXPECT_EQ(BubbleBorder::LEFT_BOTTOM, + BubbleBorder::horizontal_mirror(BubbleBorder::RIGHT_BOTTOM)); + + EXPECT_EQ(BubbleBorder::TOP_CENTER, + BubbleBorder::horizontal_mirror(BubbleBorder::TOP_CENTER)); + EXPECT_EQ(BubbleBorder::BOTTOM_CENTER, + BubbleBorder::horizontal_mirror(BubbleBorder::BOTTOM_CENTER)); + + EXPECT_EQ(BubbleBorder::RIGHT_CENTER, + BubbleBorder::horizontal_mirror(BubbleBorder::LEFT_CENTER)); + EXPECT_EQ(BubbleBorder::LEFT_CENTER, + BubbleBorder::horizontal_mirror(BubbleBorder::RIGHT_CENTER)); + + EXPECT_EQ(BubbleBorder::NONE, + BubbleBorder::horizontal_mirror(BubbleBorder::NONE)); + EXPECT_EQ(BubbleBorder::FLOAT, + BubbleBorder::horizontal_mirror(BubbleBorder::FLOAT)); + + // Vertical mirroring. + EXPECT_EQ(BubbleBorder::BOTTOM_LEFT, + BubbleBorder::vertical_mirror(BubbleBorder::TOP_LEFT)); + EXPECT_EQ(BubbleBorder::BOTTOM_RIGHT, + BubbleBorder::vertical_mirror(BubbleBorder::TOP_RIGHT)); + + EXPECT_EQ(BubbleBorder::TOP_LEFT, + BubbleBorder::vertical_mirror(BubbleBorder::BOTTOM_LEFT)); + EXPECT_EQ(BubbleBorder::TOP_RIGHT, + BubbleBorder::vertical_mirror(BubbleBorder::BOTTOM_RIGHT)); + + EXPECT_EQ(BubbleBorder::LEFT_BOTTOM, + BubbleBorder::vertical_mirror(BubbleBorder::LEFT_TOP)); + EXPECT_EQ(BubbleBorder::RIGHT_BOTTOM, + BubbleBorder::vertical_mirror(BubbleBorder::RIGHT_TOP)); + + EXPECT_EQ(BubbleBorder::LEFT_TOP, + BubbleBorder::vertical_mirror(BubbleBorder::LEFT_BOTTOM)); + EXPECT_EQ(BubbleBorder::RIGHT_TOP, + BubbleBorder::vertical_mirror(BubbleBorder::RIGHT_BOTTOM)); + + EXPECT_EQ(BubbleBorder::BOTTOM_CENTER, + BubbleBorder::vertical_mirror(BubbleBorder::TOP_CENTER)); + EXPECT_EQ(BubbleBorder::TOP_CENTER, + BubbleBorder::vertical_mirror(BubbleBorder::BOTTOM_CENTER)); + + EXPECT_EQ(BubbleBorder::LEFT_CENTER, + BubbleBorder::vertical_mirror(BubbleBorder::LEFT_CENTER)); + EXPECT_EQ(BubbleBorder::RIGHT_CENTER, + BubbleBorder::vertical_mirror(BubbleBorder::RIGHT_CENTER)); + + EXPECT_EQ(BubbleBorder::NONE, + BubbleBorder::vertical_mirror(BubbleBorder::NONE)); + EXPECT_EQ(BubbleBorder::FLOAT, + BubbleBorder::vertical_mirror(BubbleBorder::FLOAT)); +} + +TEST_F(BubbleBorderTest, HasArrow) { + EXPECT_TRUE(BubbleBorder::has_arrow(BubbleBorder::TOP_LEFT)); + EXPECT_TRUE(BubbleBorder::has_arrow(BubbleBorder::TOP_RIGHT)); + + EXPECT_TRUE(BubbleBorder::has_arrow(BubbleBorder::BOTTOM_LEFT)); + EXPECT_TRUE(BubbleBorder::has_arrow(BubbleBorder::BOTTOM_RIGHT)); + + EXPECT_TRUE(BubbleBorder::has_arrow(BubbleBorder::LEFT_TOP)); + EXPECT_TRUE(BubbleBorder::has_arrow(BubbleBorder::RIGHT_TOP)); + + EXPECT_TRUE(BubbleBorder::has_arrow(BubbleBorder::LEFT_BOTTOM)); + EXPECT_TRUE(BubbleBorder::has_arrow(BubbleBorder::RIGHT_BOTTOM)); + + EXPECT_TRUE(BubbleBorder::has_arrow(BubbleBorder::TOP_CENTER)); + EXPECT_TRUE(BubbleBorder::has_arrow(BubbleBorder::BOTTOM_CENTER)); + + EXPECT_TRUE(BubbleBorder::has_arrow(BubbleBorder::LEFT_CENTER)); + EXPECT_TRUE(BubbleBorder::has_arrow(BubbleBorder::RIGHT_CENTER)); + + EXPECT_FALSE(BubbleBorder::has_arrow(BubbleBorder::NONE)); + EXPECT_FALSE(BubbleBorder::has_arrow(BubbleBorder::FLOAT)); +} + +TEST_F(BubbleBorderTest, IsArrowOnLeft) { + EXPECT_TRUE(BubbleBorder::is_arrow_on_left(BubbleBorder::TOP_LEFT)); + EXPECT_FALSE(BubbleBorder::is_arrow_on_left(BubbleBorder::TOP_RIGHT)); + + EXPECT_TRUE(BubbleBorder::is_arrow_on_left(BubbleBorder::BOTTOM_LEFT)); + EXPECT_FALSE(BubbleBorder::is_arrow_on_left(BubbleBorder::BOTTOM_RIGHT)); + + EXPECT_TRUE(BubbleBorder::is_arrow_on_left(BubbleBorder::LEFT_TOP)); + EXPECT_FALSE(BubbleBorder::is_arrow_on_left(BubbleBorder::RIGHT_TOP)); + + EXPECT_TRUE(BubbleBorder::is_arrow_on_left(BubbleBorder::LEFT_BOTTOM)); + EXPECT_FALSE(BubbleBorder::is_arrow_on_left(BubbleBorder::RIGHT_BOTTOM)); + + EXPECT_FALSE(BubbleBorder::is_arrow_on_left(BubbleBorder::TOP_CENTER)); + EXPECT_FALSE(BubbleBorder::is_arrow_on_left(BubbleBorder::BOTTOM_CENTER)); + + EXPECT_TRUE(BubbleBorder::is_arrow_on_left(BubbleBorder::LEFT_CENTER)); + EXPECT_FALSE(BubbleBorder::is_arrow_on_left(BubbleBorder::RIGHT_CENTER)); + + EXPECT_FALSE(BubbleBorder::is_arrow_on_left(BubbleBorder::NONE)); + EXPECT_FALSE(BubbleBorder::is_arrow_on_left(BubbleBorder::FLOAT)); +} + +TEST_F(BubbleBorderTest, IsArrowOnTop) { + EXPECT_TRUE(BubbleBorder::is_arrow_on_top(BubbleBorder::TOP_LEFT)); + EXPECT_TRUE(BubbleBorder::is_arrow_on_top(BubbleBorder::TOP_RIGHT)); + + EXPECT_FALSE(BubbleBorder::is_arrow_on_top(BubbleBorder::BOTTOM_LEFT)); + EXPECT_FALSE(BubbleBorder::is_arrow_on_top(BubbleBorder::BOTTOM_RIGHT)); + + EXPECT_TRUE(BubbleBorder::is_arrow_on_top(BubbleBorder::LEFT_TOP)); + EXPECT_TRUE(BubbleBorder::is_arrow_on_top(BubbleBorder::RIGHT_TOP)); + + EXPECT_FALSE(BubbleBorder::is_arrow_on_top(BubbleBorder::LEFT_BOTTOM)); + EXPECT_FALSE(BubbleBorder::is_arrow_on_top(BubbleBorder::RIGHT_BOTTOM)); + + EXPECT_TRUE(BubbleBorder::is_arrow_on_top(BubbleBorder::TOP_CENTER)); + EXPECT_FALSE(BubbleBorder::is_arrow_on_top(BubbleBorder::BOTTOM_CENTER)); + + EXPECT_FALSE(BubbleBorder::is_arrow_on_top(BubbleBorder::LEFT_CENTER)); + EXPECT_FALSE(BubbleBorder::is_arrow_on_top(BubbleBorder::RIGHT_CENTER)); + + EXPECT_FALSE(BubbleBorder::is_arrow_on_top(BubbleBorder::NONE)); + EXPECT_FALSE(BubbleBorder::is_arrow_on_top(BubbleBorder::FLOAT)); +} + +TEST_F(BubbleBorderTest, IsArrowOnHorizontal) { + EXPECT_TRUE(BubbleBorder::is_arrow_on_horizontal(BubbleBorder::TOP_LEFT)); + EXPECT_TRUE(BubbleBorder::is_arrow_on_horizontal(BubbleBorder::TOP_RIGHT)); + + EXPECT_TRUE(BubbleBorder::is_arrow_on_horizontal(BubbleBorder::BOTTOM_LEFT)); + EXPECT_TRUE(BubbleBorder::is_arrow_on_horizontal(BubbleBorder::BOTTOM_RIGHT)); + + EXPECT_FALSE(BubbleBorder::is_arrow_on_horizontal(BubbleBorder::LEFT_TOP)); + EXPECT_FALSE(BubbleBorder::is_arrow_on_horizontal(BubbleBorder::RIGHT_TOP)); + + EXPECT_FALSE(BubbleBorder::is_arrow_on_horizontal(BubbleBorder::LEFT_BOTTOM)); + EXPECT_FALSE( + BubbleBorder::is_arrow_on_horizontal(BubbleBorder::RIGHT_BOTTOM)); + + EXPECT_TRUE(BubbleBorder::is_arrow_on_horizontal(BubbleBorder::TOP_CENTER)); + EXPECT_TRUE( + BubbleBorder::is_arrow_on_horizontal(BubbleBorder::BOTTOM_CENTER)); + + EXPECT_FALSE(BubbleBorder::is_arrow_on_horizontal(BubbleBorder::LEFT_CENTER)); + EXPECT_FALSE( + BubbleBorder::is_arrow_on_horizontal(BubbleBorder::RIGHT_CENTER)); + + EXPECT_FALSE(BubbleBorder::is_arrow_on_horizontal(BubbleBorder::NONE)); + EXPECT_FALSE(BubbleBorder::is_arrow_on_horizontal(BubbleBorder::FLOAT)); +} + +TEST_F(BubbleBorderTest, IsArrowAtCenter) { + EXPECT_FALSE(BubbleBorder::is_arrow_at_center(BubbleBorder::TOP_LEFT)); + EXPECT_FALSE(BubbleBorder::is_arrow_at_center(BubbleBorder::TOP_RIGHT)); + + EXPECT_FALSE(BubbleBorder::is_arrow_at_center(BubbleBorder::BOTTOM_LEFT)); + EXPECT_FALSE(BubbleBorder::is_arrow_at_center(BubbleBorder::BOTTOM_RIGHT)); + + EXPECT_FALSE(BubbleBorder::is_arrow_at_center(BubbleBorder::LEFT_TOP)); + EXPECT_FALSE(BubbleBorder::is_arrow_at_center(BubbleBorder::RIGHT_TOP)); + + EXPECT_FALSE(BubbleBorder::is_arrow_at_center(BubbleBorder::LEFT_BOTTOM)); + EXPECT_FALSE(BubbleBorder::is_arrow_at_center(BubbleBorder::RIGHT_BOTTOM)); + + EXPECT_TRUE(BubbleBorder::is_arrow_at_center(BubbleBorder::TOP_CENTER)); + EXPECT_TRUE(BubbleBorder::is_arrow_at_center(BubbleBorder::BOTTOM_CENTER)); + + EXPECT_TRUE(BubbleBorder::is_arrow_at_center(BubbleBorder::LEFT_CENTER)); + EXPECT_TRUE(BubbleBorder::is_arrow_at_center(BubbleBorder::RIGHT_CENTER)); + + EXPECT_FALSE(BubbleBorder::is_arrow_at_center(BubbleBorder::NONE)); + EXPECT_FALSE(BubbleBorder::is_arrow_at_center(BubbleBorder::FLOAT)); +} + +} // namespace views diff --git a/ui/views/bubble/bubble_delegate.cc b/ui/views/bubble/bubble_delegate.cc index fa3a7b9..12c3798 100644 --- a/ui/views/bubble/bubble_delegate.cc +++ b/ui/views/bubble/bubble_delegate.cc @@ -111,13 +111,14 @@ BubbleDelegateView::BubbleDelegateView() anchor_widget_(NULL), move_with_anchor_(false), arrow_location_(BubbleBorder::TOP_LEFT), + shadow_(BubbleBorder::NO_SHADOW), color_(kBackgroundColor), margins_(kDefaultMargin, kDefaultMargin, kDefaultMargin, kDefaultMargin), original_opacity_(255), border_widget_(NULL), use_focusless_(false), accept_events_(true), - try_mirroring_arrow_(true), + adjust_if_offscreen_(true), parent_window_(NULL) { set_background(Background::CreateSolidBackground(color_)); AddAccelerator(ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE)); @@ -132,13 +133,14 @@ BubbleDelegateView::BubbleDelegateView( anchor_widget_(NULL), move_with_anchor_(false), arrow_location_(arrow_location), + shadow_(BubbleBorder::NO_SHADOW), color_(kBackgroundColor), margins_(kDefaultMargin, kDefaultMargin, kDefaultMargin, kDefaultMargin), original_opacity_(255), border_widget_(NULL), use_focusless_(false), accept_events_(true), - try_mirroring_arrow_(true), + adjust_if_offscreen_(true), parent_window_(NULL) { set_background(Background::CreateSolidBackground(color_)); AddAccelerator(ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE)); @@ -194,9 +196,7 @@ NonClientFrameView* BubbleDelegateView::CreateNonClientFrameView( BubbleBorder::ArrowLocation arrow_loc = arrow_location(); if (base::i18n::IsRTL()) arrow_loc = BubbleBorder::horizontal_mirror(arrow_loc); - // TODO(alicet): Expose the shadow option in BorderContentsView when we make - // the fullscreen exit bubble use the new bubble code. - BubbleBorder* border = new BubbleBorder(arrow_loc, BubbleBorder::NO_SHADOW); + BubbleBorder* border = new BubbleBorder(arrow_loc, shadow_); border->set_background_color(color()); BubbleFrameView* frame_view = new BubbleFrameView(margins(), border); frame_view->set_background(new BubbleBackground(border)); @@ -350,7 +350,7 @@ gfx::Rect BubbleDelegateView::GetBubbleBounds() { // The argument rect has its origin at the bubble's arrow anchor point; // its size is the preferred size of the bubble's client view (this view). return GetBubbleFrameView()->GetUpdatedWindowBounds(GetAnchorRect(), - GetPreferredSize(), try_mirroring_arrow_); + GetPreferredSize(), adjust_if_offscreen_); } #if defined(OS_WIN) && !defined(USE_AURA) diff --git a/ui/views/bubble/bubble_delegate.h b/ui/views/bubble/bubble_delegate.h index dd29da7..247202d 100644 --- a/ui/views/bubble/bubble_delegate.h +++ b/ui/views/bubble/bubble_delegate.h @@ -67,6 +67,9 @@ class VIEWS_EXPORT BubbleDelegateView : public WidgetDelegateView, arrow_location_ = arrow_location; } + BubbleBorder::Shadow shadow() const { return shadow_; } + void set_shadow(BubbleBorder::Shadow shadow) { shadow_ = shadow; } + SkColor color() const { return color_; } void set_color(SkColor color) { color_ = color; } @@ -87,10 +90,8 @@ class VIEWS_EXPORT BubbleDelegateView : public WidgetDelegateView, bool accept_events() const { return accept_events_; } void set_accept_events(bool accept_events) { accept_events_ = accept_events; } - bool try_mirroring_arrow() const { return try_mirroring_arrow_; } - void set_try_mirroring_arrow(bool try_mirroring_arrow) { - try_mirroring_arrow_ = try_mirroring_arrow; - } + bool adjust_if_offscreen() const { return adjust_if_offscreen_; } + void set_adjust_if_offscreen(bool adjust) { adjust_if_offscreen_ = adjust; } // Get the arrow's anchor rect in screen space. virtual gfx::Rect GetAnchorRect(); @@ -173,6 +174,9 @@ class VIEWS_EXPORT BubbleDelegateView : public WidgetDelegateView, // The arrow's location on the bubble. BubbleBorder::ArrowLocation arrow_location_; + // Bubble border shadow to use. + BubbleBorder::Shadow shadow_; + // The background color of the bubble. SkColor color_; @@ -195,9 +199,9 @@ class VIEWS_EXPORT BubbleDelegateView : public WidgetDelegateView, // Specifies whether the popup accepts events or lets them pass through. bool accept_events_; - // If true (defaults to true), the arrow may be mirrored to fit the - // bubble on screen better. - bool try_mirroring_arrow_; + // If true (defaults to true), the arrow may be mirrored and moved to fit the + // bubble on screen better. It would be a no-op if the bubble has no arrow. + bool adjust_if_offscreen_; // Parent native window of the bubble. gfx::NativeView parent_window_; diff --git a/ui/views/bubble/bubble_frame_view.cc b/ui/views/bubble/bubble_frame_view.cc index 9ae1f8d..d164194 100644 --- a/ui/views/bubble/bubble_frame_view.cc +++ b/ui/views/bubble/bubble_frame_view.cc @@ -74,17 +74,22 @@ gfx::Size BubbleFrameView::GetPreferredSize() { gfx::Rect BubbleFrameView::GetUpdatedWindowBounds(const gfx::Rect& anchor_rect, gfx::Size client_size, - bool try_mirroring_arrow) { + bool adjust_if_offscreen) { // Give the contents a margin. client_size.Enlarge(content_margins_.width(), content_margins_.height()); - if (try_mirroring_arrow) { - // Try to mirror the anchoring if the bubble does not fit on the screen. - MirrorArrowIfOffScreen(true, anchor_rect, client_size); - MirrorArrowIfOffScreen(false, anchor_rect, client_size); + const BubbleBorder::ArrowLocation arrow = bubble_border_->arrow_location(); + if (adjust_if_offscreen && BubbleBorder::has_arrow(arrow)) { + if (!bubble_border_->is_arrow_at_center(arrow)) { + // Try to mirror the anchoring if the bubble does not fit on the screen. + MirrorArrowIfOffScreen(true, anchor_rect, client_size); + MirrorArrowIfOffScreen(false, anchor_rect, client_size); + } else { + OffsetArrowIfOffScreen(anchor_rect, client_size); + } } - // Calculate the bounds with the arrow in its updated location. + // Calculate the bounds with the arrow in its updated location and offset. return bubble_border_->GetBounds(anchor_rect, client_size); } @@ -124,4 +129,42 @@ void BubbleFrameView::MirrorArrowIfOffScreen( } } +void BubbleFrameView::OffsetArrowIfOffScreen(const gfx::Rect& anchor_rect, + const gfx::Size& client_size) { + BubbleBorder::ArrowLocation arrow = bubble_border()->arrow_location(); + DCHECK(BubbleBorder::is_arrow_at_center(arrow)); + + // Get the desired bubble bounds without adjustment. + bubble_border_->set_arrow_offset(0); + gfx::Rect window_bounds(bubble_border_->GetBounds(anchor_rect, client_size)); + + gfx::Rect monitor_rect(GetMonitorBounds(anchor_rect)); + if (monitor_rect.IsEmpty() || monitor_rect.Contains(window_bounds)) + return; + + // Calculate off-screen adjustment. + const bool is_horizontal = BubbleBorder::is_arrow_on_horizontal(arrow); + int offscreen_adjust = 0; + if (is_horizontal) { + if (window_bounds.x() < monitor_rect.x()) + offscreen_adjust = monitor_rect.x() - window_bounds.x(); + else if (window_bounds.right() > monitor_rect.right()) + offscreen_adjust = monitor_rect.right() - window_bounds.right(); + } else { + if (window_bounds.y() < monitor_rect.y()) + offscreen_adjust = monitor_rect.y() - window_bounds.y(); + else if (window_bounds.bottom() > monitor_rect.bottom()) + offscreen_adjust = monitor_rect.bottom() - window_bounds.bottom(); + } + + // For center arrows, arrows are moved in the opposite direction of + // |offscreen_adjust|, e.g. positive |offscreen_adjust| means bubble + // window needs to be moved to the right and that means we need to move arrow + // to the left, and that means negative offset. + bubble_border_->set_arrow_offset( + bubble_border_->GetArrowOffset(window_bounds.size()) - offscreen_adjust); + if (offscreen_adjust) + SchedulePaint(); +} + } // namespace views diff --git a/ui/views/bubble/bubble_frame_view.h b/ui/views/bubble/bubble_frame_view.h index 0f01428..b82fe8e 100644 --- a/ui/views/bubble/bubble_frame_view.h +++ b/ui/views/bubble/bubble_frame_view.h @@ -42,10 +42,10 @@ class VIEWS_EXPORT BubbleFrameView : public NonClientFrameView { // Given the size of the contents and the rect to point at, returns the bounds // of the bubble window. The bubble's arrow location may change if the bubble - // does not fit on the monitor and |try_mirroring_arrow| is true. + // does not fit on the monitor and |adjust_if_offscreen| is true. gfx::Rect GetUpdatedWindowBounds(const gfx::Rect& anchor_rect, gfx::Size client_size, - bool try_mirroring_arrow); + bool adjust_if_offscreen); void SetBubbleBorder(BubbleBorder* border); @@ -63,6 +63,11 @@ class VIEWS_EXPORT BubbleFrameView : public NonClientFrameView { const gfx::Rect& anchor_rect, const gfx::Size& client_size); + // Adjust the bubble's arrow offsets if the generated window bounds don't fit + // in the monitor bounds. + void OffsetArrowIfOffScreen(const gfx::Rect& anchor_rect, + const gfx::Size& client_size); + // The bubble border. BubbleBorder* bubble_border_; diff --git a/ui/views/bubble/bubble_frame_view_unittest.cc b/ui/views/bubble/bubble_frame_view_unittest.cc index c6f1a5b..042e7ce 100644 --- a/ui/views/bubble/bubble_frame_view_unittest.cc +++ b/ui/views/bubble/bubble_frame_view_unittest.cc @@ -14,14 +14,14 @@ namespace views { typedef ViewsTestBase BubbleFrameViewTest; +namespace { + const BubbleBorder::ArrowLocation kArrow = BubbleBorder::TOP_LEFT; const int kBubbleWidth = 200; const int kBubbleHeight = 200; const SkColor kBackgroundColor = SK_ColorRED; const int kDefaultMargin = 6; -namespace { - class SizedBubbleDelegateView : public BubbleDelegateView { public: SizedBubbleDelegateView(); @@ -114,7 +114,7 @@ TEST_F(BubbleFrameViewTest, GetUpdatedWindowBounds) { window_bounds = frame.GetUpdatedWindowBounds( gfx::Rect(100, 100, 50, 50), // |anchor_rect| gfx::Size(500, 500), // |client_size| - true); // |try_mirroring_arrow| + true); // |adjust_if_offscreen| EXPECT_EQ(BubbleBorder::TOP_LEFT, frame.bubble_border()->arrow_location()); EXPECT_GT(window_bounds.x(), xposition); EXPECT_GT(window_bounds.y(), 100 + 50 - 10); // -10 to roughly compensate for @@ -125,7 +125,7 @@ TEST_F(BubbleFrameViewTest, GetUpdatedWindowBounds) { window_bounds = frame.GetUpdatedWindowBounds( gfx::Rect(100, 100, 50, 50), // |anchor_rect| gfx::Size(500, 500), // |client_size| - true); // |try_mirroring_arrow| + true); // |adjust_if_offscreen| EXPECT_EQ(BubbleBorder::TOP_LEFT, frame.bubble_border()->arrow_location()); EXPECT_GT(window_bounds.x(), xposition); EXPECT_GT(window_bounds.y(), 100 + 50 - 10); // -10 to roughly compensate for @@ -136,7 +136,7 @@ TEST_F(BubbleFrameViewTest, GetUpdatedWindowBounds) { window_bounds = frame.GetUpdatedWindowBounds( gfx::Rect(100, 100, 50, 50), // |anchor_rect| gfx::Size(500, 500), // |client_size| - true); // |try_mirroring_arrow| + true); // |adjust_if_offscreen| EXPECT_EQ(BubbleBorder::TOP_LEFT, frame.bubble_border()->arrow_location()); EXPECT_GT(window_bounds.x(), xposition); EXPECT_GT(window_bounds.y(), 100 + 50 - 10); // -10 to roughly compensate for @@ -147,7 +147,7 @@ TEST_F(BubbleFrameViewTest, GetUpdatedWindowBounds) { window_bounds = frame.GetUpdatedWindowBounds( gfx::Rect(100, 100, 50, 50), // |anchor_rect| gfx::Size(500, 500), // |client_size| - true); // |try_mirroring_arrow| + true); // |adjust_if_offscreen| EXPECT_EQ(BubbleBorder::TOP_LEFT, frame.bubble_border()->arrow_location()); EXPECT_GT(window_bounds.x(), xposition); EXPECT_GT(window_bounds.y(), 100 + 50 - 10); // -10 to roughly compensate for @@ -158,7 +158,7 @@ TEST_F(BubbleFrameViewTest, GetUpdatedWindowBounds) { window_bounds = frame.GetUpdatedWindowBounds( gfx::Rect(900, 100, 50, 50), // |anchor_rect| gfx::Size(500, 500), // |client_size| - true); // |try_mirroring_arrow| + true); // |adjust_if_offscreen| EXPECT_EQ(BubbleBorder::TOP_RIGHT, frame.bubble_border()->arrow_location()); EXPECT_LT(window_bounds.x(), 900 + 50 - 500); EXPECT_GT(window_bounds.y(), 100 + 50 - 10); // -10 to roughly compensate for @@ -169,7 +169,7 @@ TEST_F(BubbleFrameViewTest, GetUpdatedWindowBounds) { window_bounds = frame.GetUpdatedWindowBounds( gfx::Rect(900, 100, 50, 50), // |anchor_rect| gfx::Size(500, 500), // |client_size| - true); // |try_mirroring_arrow| + true); // |adjust_if_offscreen| EXPECT_EQ(BubbleBorder::TOP_RIGHT, frame.bubble_border()->arrow_location()); EXPECT_LT(window_bounds.x(), 900 + 50 - 500); EXPECT_GT(window_bounds.y(), 100 + 50 - 10); // -10 to roughly compensate for @@ -180,7 +180,7 @@ TEST_F(BubbleFrameViewTest, GetUpdatedWindowBounds) { window_bounds = frame.GetUpdatedWindowBounds( gfx::Rect(900, 900, 50, 50), // |anchor_rect| gfx::Size(500, 500), // |client_size| - true); // |try_mirroring_arrow| + true); // |adjust_if_offscreen| EXPECT_EQ(BubbleBorder::BOTTOM_RIGHT, frame.bubble_border()->arrow_location()); EXPECT_LT(window_bounds.x(), 900 + 50 - 500); @@ -192,7 +192,7 @@ TEST_F(BubbleFrameViewTest, GetUpdatedWindowBounds) { window_bounds = frame.GetUpdatedWindowBounds( gfx::Rect(100, 900, 50, 50), // |anchor_rect| gfx::Size(500, 500), // |client_size| - true); // |try_mirroring_arrow| + true); // |adjust_if_offscreen| EXPECT_EQ(BubbleBorder::BOTTOM_LEFT, frame.bubble_border()->arrow_location()); // The window should be right aligned with the anchor_rect. EXPECT_LT(window_bounds.x(), 900 + 50 - 500); @@ -204,7 +204,7 @@ TEST_F(BubbleFrameViewTest, GetUpdatedWindowBounds) { window_bounds = frame.GetUpdatedWindowBounds( gfx::Rect(100, 900, 50, 50), // |anchor_rect| gfx::Size(500, 500), // |client_size| - true); // |try_mirroring_arrow| + true); // |adjust_if_offscreen| EXPECT_EQ(BubbleBorder::BOTTOM_LEFT, frame.bubble_border()->arrow_location()); // The window should be right aligned with the anchor_rect. EXPECT_LT(window_bounds.x(), 900 + 50 - 500); @@ -220,18 +220,18 @@ TEST_F(BubbleFrameViewTest, GetUpdatedWindowBoundsMirroringFails) { gfx::Rect window_bounds = frame.GetUpdatedWindowBounds( gfx::Rect(400, 100, 50, 50), // |anchor_rect| gfx::Size(500, 700), // |client_size| - true); // |try_mirroring_arrow| + true); // |adjust_if_offscreen| EXPECT_EQ(BubbleBorder::TOP_LEFT, frame.bubble_border()->arrow_location()); } -// Test that the arrow will not be mirrored when |try_mirroring_arrow| is false. +// Test that the arrow will not be mirrored when |adjust_if_offscreen| is false. TEST_F(BubbleFrameViewTest, GetUpdatedWindowBoundsDontTryMirror) { TestBubbleFrameView frame; frame.bubble_border()->set_arrow_location(BubbleBorder::TOP_RIGHT); gfx::Rect window_bounds = frame.GetUpdatedWindowBounds( gfx::Rect(100, 900, 50, 50), // |anchor_rect| gfx::Size(500, 500), // |client_size| - false); // |try_mirroring_arrow| + false); // |adjust_if_offscreen| EXPECT_EQ(BubbleBorder::TOP_RIGHT, frame.bubble_border()->arrow_location()); // The coordinates should be pointing to anchor_rect from TOP_RIGHT. EXPECT_LT(window_bounds.x(), 100 + 50 - 500); @@ -239,4 +239,133 @@ TEST_F(BubbleFrameViewTest, GetUpdatedWindowBoundsDontTryMirror) { // arrow overlap. } +// Test that the center arrow is moved as needed to fit the screen. +TEST_F(BubbleFrameViewTest, GetUpdatedWindowBoundsCenterArrows) { + TestBubbleFrameView frame; + gfx::Rect window_bounds; + + // Test that the bubble displays normally when it fits. + frame.bubble_border()->set_arrow_location(BubbleBorder::TOP_CENTER); + window_bounds = frame.GetUpdatedWindowBounds( + gfx::Rect(500, 100, 50, 50), // |anchor_rect| + gfx::Size(500, 500), // |client_size| + true); // |adjust_if_offscreen| + EXPECT_EQ(BubbleBorder::TOP_CENTER, frame.bubble_border()->arrow_location()); + EXPECT_EQ(window_bounds.x() + window_bounds.width() / 2, 525); + + frame.bubble_border()->set_arrow_location(BubbleBorder::BOTTOM_CENTER); + window_bounds = frame.GetUpdatedWindowBounds( + gfx::Rect(500, 900, 50, 50), // |anchor_rect| + gfx::Size(500, 500), // |client_size| + true); // |adjust_if_offscreen| + EXPECT_EQ(BubbleBorder::BOTTOM_CENTER, + frame.bubble_border()->arrow_location()); + EXPECT_EQ(window_bounds.x() + window_bounds.width() / 2, 525); + + frame.bubble_border()->set_arrow_location(BubbleBorder::LEFT_CENTER); + window_bounds = frame.GetUpdatedWindowBounds( + gfx::Rect(100, 400, 50, 50), // |anchor_rect| + gfx::Size(500, 500), // |client_size| + true); // |adjust_if_offscreen| + EXPECT_EQ(BubbleBorder::LEFT_CENTER, frame.bubble_border()->arrow_location()); + EXPECT_EQ(window_bounds.y() + window_bounds.height() / 2, 425); + + frame.bubble_border()->set_arrow_location(BubbleBorder::RIGHT_CENTER); + window_bounds = frame.GetUpdatedWindowBounds( + gfx::Rect(900, 400, 50, 50), // |anchor_rect| + gfx::Size(500, 500), // |client_size| + true); // |adjust_if_offscreen| + EXPECT_EQ(BubbleBorder::RIGHT_CENTER, + frame.bubble_border()->arrow_location()); + EXPECT_EQ(window_bounds.y() + window_bounds.height() / 2, 425); + + // Test bubble not fitting left screen edge. + frame.bubble_border()->set_arrow_location(BubbleBorder::TOP_CENTER); + window_bounds = frame.GetUpdatedWindowBounds( + gfx::Rect(100, 100, 50, 50), // |anchor_rect| + gfx::Size(500, 500), // |client_size| + true); // |adjust_if_offscreen| + EXPECT_EQ(BubbleBorder::TOP_CENTER, frame.bubble_border()->arrow_location()); + EXPECT_EQ(window_bounds.x(), 0); + EXPECT_EQ(window_bounds.x() + + frame.bubble_border()->GetArrowOffset(window_bounds.size()), 125); + + frame.bubble_border()->set_arrow_location(BubbleBorder::BOTTOM_CENTER); + window_bounds = frame.GetUpdatedWindowBounds( + gfx::Rect(100, 900, 50, 50), // |anchor_rect| + gfx::Size(500, 500), // |client_size| + true); // |adjust_if_offscreen| + EXPECT_EQ(BubbleBorder::BOTTOM_CENTER, + frame.bubble_border()->arrow_location()); + EXPECT_EQ(window_bounds.x(), 0); + EXPECT_EQ(window_bounds.x() + + frame.bubble_border()->GetArrowOffset(window_bounds.size()), 125); + + // Test bubble not fitting right screen edge. + frame.bubble_border()->set_arrow_location(BubbleBorder::TOP_CENTER); + window_bounds = frame.GetUpdatedWindowBounds( + gfx::Rect(900, 100, 50, 50), // |anchor_rect| + gfx::Size(500, 500), // |client_size| + true); // |adjust_if_offscreen| + EXPECT_EQ(BubbleBorder::TOP_CENTER, frame.bubble_border()->arrow_location()); + EXPECT_EQ(window_bounds.right(), 1000); + EXPECT_EQ(window_bounds.x() + + frame.bubble_border()->GetArrowOffset(window_bounds.size()), 925); + + frame.bubble_border()->set_arrow_location(BubbleBorder::BOTTOM_CENTER); + window_bounds = frame.GetUpdatedWindowBounds( + gfx::Rect(900, 900, 50, 50), // |anchor_rect| + gfx::Size(500, 500), // |client_size| + true); // |adjust_if_offscreen| + EXPECT_EQ(BubbleBorder::BOTTOM_CENTER, + frame.bubble_border()->arrow_location()); + EXPECT_EQ(window_bounds.right(), 1000); + EXPECT_EQ(window_bounds.x() + + frame.bubble_border()->GetArrowOffset(window_bounds.size()), 925); + + // Test bubble not fitting top screen edge. + frame.bubble_border()->set_arrow_location(BubbleBorder::LEFT_CENTER); + window_bounds = frame.GetUpdatedWindowBounds( + gfx::Rect(100, 100, 50, 50), // |anchor_rect| + gfx::Size(500, 500), // |client_size| + true); // |adjust_if_offscreen| + EXPECT_EQ(BubbleBorder::LEFT_CENTER, frame.bubble_border()->arrow_location()); + EXPECT_EQ(window_bounds.y(), 0); + EXPECT_EQ(window_bounds.y() + + frame.bubble_border()->GetArrowOffset(window_bounds.size()), 125); + + frame.bubble_border()->set_arrow_location(BubbleBorder::RIGHT_CENTER); + window_bounds = frame.GetUpdatedWindowBounds( + gfx::Rect(900, 100, 50, 50), // |anchor_rect| + gfx::Size(500, 500), // |client_size| + true); // |adjust_if_offscreen| + EXPECT_EQ(BubbleBorder::RIGHT_CENTER, + frame.bubble_border()->arrow_location()); + EXPECT_EQ(window_bounds.y(), 0); + EXPECT_EQ(window_bounds.y() + + frame.bubble_border()->GetArrowOffset(window_bounds.size()), 125); + + // Test bubble not fitting bottom screen edge. + frame.bubble_border()->set_arrow_location(BubbleBorder::LEFT_CENTER); + window_bounds = frame.GetUpdatedWindowBounds( + gfx::Rect(100, 900, 50, 50), // |anchor_rect| + gfx::Size(500, 500), // |client_size| + true); // |adjust_if_offscreen| + EXPECT_EQ(BubbleBorder::LEFT_CENTER, frame.bubble_border()->arrow_location()); + EXPECT_EQ(window_bounds.bottom(), 1000); + EXPECT_EQ(window_bounds.y() + + frame.bubble_border()->GetArrowOffset(window_bounds.size()), 925); + + frame.bubble_border()->set_arrow_location(BubbleBorder::RIGHT_CENTER); + window_bounds = frame.GetUpdatedWindowBounds( + gfx::Rect(900, 900, 50, 50), // |anchor_rect| + gfx::Size(500, 500), // |client_size| + true); // |adjust_if_offscreen| + EXPECT_EQ(BubbleBorder::RIGHT_CENTER, + frame.bubble_border()->arrow_location()); + EXPECT_EQ(window_bounds.bottom(), 1000); + EXPECT_EQ(window_bounds.y() + + frame.bubble_border()->GetArrowOffset(window_bounds.size()), 925); +} + } // namespace views diff --git a/ui/views/views.gyp b/ui/views/views.gyp index 131cfac..2e30ab4 100644 --- a/ui/views/views.gyp +++ b/ui/views/views.gyp @@ -58,8 +58,6 @@ 'bubble/bubble_delegate.h', 'bubble/bubble_frame_view.cc', 'bubble/bubble_frame_view.h', - 'bubble/bubble_border_2.cc', - 'bubble/bubble_border_2.h', 'button_drag_utils.cc', 'button_drag_utils.h', 'color_chooser/color_chooser_listener.h', @@ -541,6 +539,7 @@ 'sources': [ 'accessible_pane_view_unittest.cc', 'animation/bounds_animator_unittest.cc', + 'bubble/bubble_border_unittest.cc', 'bubble/bubble_delegate_unittest.cc', 'bubble/bubble_frame_view_unittest.cc', 'controls/button/image_button_unittest.cc', |