diff options
22 files changed, 1353 insertions, 1100 deletions
diff --git a/ash/ash.gyp b/ash/ash.gyp index f8d48ba..4fe16d6 100644 --- a/ash/ash.gyp +++ b/ash/ash.gyp @@ -175,10 +175,13 @@ 'frame/custom_frame_view_ash.h', 'frame/frame_border_hit_test_controller.cc', 'frame/frame_border_hit_test_controller.h', + 'frame/default_header_painter.cc', + 'frame/default_header_painter.h', 'frame/frame_util.cc', 'frame/frame_util.h', - 'frame/header_painter.cc', 'frame/header_painter.h', + 'frame/header_painter_util.cc', + 'frame/header_painter_util.h', 'gpu_support.h', 'gpu_support_stub.cc', 'gpu_support_stub.h', @@ -887,7 +890,7 @@ 'frame/caption_buttons/frame_caption_button_container_view_unittest.cc', 'frame/caption_buttons/frame_maximize_button_unittest.cc', 'frame/custom_frame_view_ash_unittest.cc', - 'frame/header_painter_unittest.cc', + 'frame/default_header_painter_unittest.cc', 'ime/candidate_window_view_unittest.cc', 'ime/input_method_menu_item_unittest.cc', 'ime/input_method_menu_manager_unittest.cc', diff --git a/ash/frame/custom_frame_view_ash.cc b/ash/frame/custom_frame_view_ash.cc index 964020b..615bc40 100644 --- a/ash/frame/custom_frame_view_ash.cc +++ b/ash/frame/custom_frame_view_ash.cc @@ -8,6 +8,7 @@ #include "ash/frame/caption_buttons/frame_caption_button_container_view.h" #include "ash/frame/caption_buttons/frame_maximize_button.h" #include "ash/frame/caption_buttons/frame_maximize_button_observer.h" +#include "ash/frame/default_header_painter.h" #include "ash/frame/frame_border_hit_test_controller.h" #include "ash/frame/header_painter.h" #include "ash/wm/immersive_fullscreen_controller.h" @@ -15,31 +16,20 @@ #include "ash/wm/window_state_delegate.h" #include "ash/wm/window_state_observer.h" #include "base/command_line.h" -#include "base/debug/leak_annotations.h" -#include "grit/ash_resources.h" #include "ui/aura/client/aura_constants.h" #include "ui/aura/window.h" #include "ui/aura/window_observer.h" #include "ui/gfx/canvas.h" -#include "ui/gfx/font_list.h" #include "ui/gfx/rect.h" #include "ui/gfx/rect_conversions.h" #include "ui/gfx/size.h" #include "ui/views/view.h" -#include "ui/views/widget/native_widget_aura.h" #include "ui/views/widget/widget.h" #include "ui/views/widget/widget_delegate.h" #include "ui/views/widget/widget_deletion_observer.h" namespace { -const gfx::FontList& GetTitleFontList() { - static const gfx::FontList* title_font_list = - new gfx::FontList(views::NativeWidgetAura::GetWindowTitleFontList()); - ANNOTATE_LEAKING_OBJECT_PTR(title_font_list); - return *title_font_list; -} - /////////////////////////////////////////////////////////////////////////////// // CustomFrameViewAshWindowStateDelegate @@ -160,8 +150,8 @@ class CustomFrameViewAsh::HeaderView virtual void Layout() OVERRIDE; virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE; - HeaderPainter* header_painter() { - return header_painter_.get(); + FrameCaptionButtonContainerView* caption_button_container() { + return caption_button_container_; } private: @@ -179,7 +169,7 @@ class CustomFrameViewAsh::HeaderView views::Widget* frame_; // Helper for painting the header. - scoped_ptr<HeaderPainter> header_painter_; + scoped_ptr<DefaultHeaderPainter> header_painter_; // View which contains the window caption buttons. FrameCaptionButtonContainerView* caption_button_container_; @@ -200,7 +190,7 @@ class CustomFrameViewAsh::HeaderView CustomFrameViewAsh::HeaderView::HeaderView(views::Widget* frame) : frame_(frame), - header_painter_(new ash::HeaderPainter), + header_painter_(new ash::DefaultHeaderPainter), caption_button_container_(NULL), maximize_bubble_(NULL), fullscreen_visible_fraction_(0) { @@ -218,8 +208,7 @@ CustomFrameViewAsh::HeaderView::HeaderView(views::Widget* frame) if (frame_maximize_button) frame_maximize_button->AddObserver(this); - header_painter_->Init(HeaderPainter::STYLE_OTHER, frame_, this, NULL, - caption_button_container_); + header_painter_->Init(frame_, this, NULL, caption_button_container_); } CustomFrameViewAsh::HeaderView::~HeaderView() { @@ -230,7 +219,7 @@ CustomFrameViewAsh::HeaderView::~HeaderView() { } void CustomFrameViewAsh::HeaderView::SchedulePaintForTitle() { - header_painter_->SchedulePaintForTitle(GetTitleFontList()); + header_painter_->SchedulePaintForTitle(); } void CustomFrameViewAsh::HeaderView::ResetWindowControls() { @@ -246,9 +235,7 @@ int CustomFrameViewAsh::HeaderView::GetPreferredOnScreenHeight() const { } int CustomFrameViewAsh::HeaderView::GetPreferredHeight() const { - // Reserve enough space to see the buttons and the separator line. - return caption_button_container_->bounds().bottom() + - header_painter_->HeaderContentSeparatorSize(); + return header_painter_->GetHeaderHeightForPainting(); } int CustomFrameViewAsh::HeaderView::GetMinimumWidth() const { @@ -257,7 +244,6 @@ int CustomFrameViewAsh::HeaderView::GetMinimumWidth() const { void CustomFrameViewAsh::HeaderView::Layout() { header_painter_->LayoutHeader(); - header_painter_->set_header_height(GetPreferredHeight()); } void CustomFrameViewAsh::HeaderView::OnPaint(gfx::Canvas* canvas) { @@ -265,21 +251,9 @@ void CustomFrameViewAsh::HeaderView::OnPaint(gfx::Canvas* canvas) { frame_->non_client_view()->frame_view()->ShouldPaintAsActive(); caption_button_container_->SetPaintAsActive(paint_as_active); - int theme_image_id = 0; - if (paint_as_active) - theme_image_id = IDR_AURA_WINDOW_HEADER_BASE_ACTIVE; - else - theme_image_id = IDR_AURA_WINDOW_HEADER_BASE_INACTIVE; - HeaderPainter::Mode header_mode = paint_as_active ? HeaderPainter::MODE_ACTIVE : HeaderPainter::MODE_INACTIVE; - header_painter_->PaintHeader( - canvas, - header_mode, - theme_image_id, - 0); - header_painter_->PaintTitleBar(canvas, GetTitleFontList()); - header_painter_->PaintHeaderContentSeparator(canvas, header_mode); + header_painter_->PaintHeader(canvas, header_mode); } void CustomFrameViewAsh::HeaderView::OnImmersiveRevealStarted() { @@ -419,20 +393,21 @@ void CustomFrameViewAsh::InitImmersiveFullscreenControllerForView( // CustomFrameViewAsh, views::NonClientFrameView overrides: gfx::Rect CustomFrameViewAsh::GetBoundsForClientView() const { - int top_height = NonClientTopBorderHeight(); - return HeaderPainter::GetBoundsForClientView(top_height, bounds()); + gfx::Rect client_bounds = bounds(); + client_bounds.Inset(0, NonClientTopBorderHeight(), 0, 0); + return client_bounds; } gfx::Rect CustomFrameViewAsh::GetWindowBoundsForClientBounds( const gfx::Rect& client_bounds) const { - int top_height = NonClientTopBorderHeight(); - return HeaderPainter::GetWindowBoundsForClientBounds(top_height, - client_bounds); + gfx::Rect window_bounds = client_bounds; + window_bounds.Inset(0, -NonClientTopBorderHeight(), 0, 0); + return window_bounds; } int CustomFrameViewAsh::NonClientHitTest(const gfx::Point& point) { return FrameBorderHitTestController::NonClientHitTest(this, - header_view_->header_painter(), point); + header_view_->caption_button_container(), point); } void CustomFrameViewAsh::GetWindowMask(const gfx::Size& size, diff --git a/ash/frame/custom_frame_view_ash.h b/ash/frame/custom_frame_view_ash.h index 9a87e71..6fd9bdf 100644 --- a/ash/frame/custom_frame_view_ash.h +++ b/ash/frame/custom_frame_view_ash.h @@ -11,7 +11,6 @@ namespace ash { class FrameBorderHitTestController; -class HeaderPainter; class ImmersiveFullscreenController; } namespace views { diff --git a/ash/frame/custom_frame_view_ash_unittest.cc b/ash/frame/custom_frame_view_ash_unittest.cc index 014f586..299b983 100644 --- a/ash/frame/custom_frame_view_ash_unittest.cc +++ b/ash/frame/custom_frame_view_ash_unittest.cc @@ -114,7 +114,7 @@ TEST_F(CustomFrameViewAshTest, HeaderHeight) { rb.GetImageSkiaNamed(IDR_AURA_WINDOW_CONTROL_BACKGROUND_H); // |kSeparatorSize| should match |kHeaderContentSeparatorSize| in - // header_painter.cc + // default_header_painter.cc // TODO(pkotwicz): Clean this test up once the separator overlays the window // controls. const int kSeparatorSize = 1; diff --git a/ash/frame/default_header_painter.cc b/ash/frame/default_header_painter.cc new file mode 100644 index 0000000..d760961 --- /dev/null +++ b/ash/frame/default_header_painter.cc @@ -0,0 +1,319 @@ +// Copyright 2014 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 "ash/frame/default_header_painter.h" + +#include "ash/frame/caption_buttons/frame_caption_button_container_view.h" +#include "ash/frame/header_painter_util.h" +#include "base/debug/leak_annotations.h" +#include "base/logging.h" // DCHECK +#include "grit/ash_resources.h" +#include "third_party/skia/include/core/SkColor.h" +#include "third_party/skia/include/core/SkPaint.h" +#include "third_party/skia/include/core/SkPath.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/gfx/animation/slide_animation.h" +#include "ui/gfx/canvas.h" +#include "ui/gfx/font_list.h" +#include "ui/gfx/image/image.h" +#include "ui/gfx/rect.h" +#include "ui/gfx/skia_util.h" +#include "ui/views/view.h" +#include "ui/views/widget/native_widget_aura.h" +#include "ui/views/widget/widget.h" +#include "ui/views/widget/widget_delegate.h" + +using views::Widget; + +namespace { + +// Color for the window title text. +const SkColor kTitleTextColor = SkColorSetRGB(40, 40, 40); +// Size of header/content separator line. +const int kHeaderContentSeparatorSize = 1; +// Color of the active window header/content separator line. +const SkColor kHeaderContentSeparatorColor = SkColorSetRGB(180, 180, 182); +// Color of the inactive window header/content separator line. +const SkColor kHeaderContentSeparatorInactiveColor = + SkColorSetRGB(150, 150, 152); +// Duration of crossfade animation for activating and deactivating frame. +const int kActivationCrossfadeDurationMs = 200; + +// Tiles an image into an area, rounding the top corners. +void TileRoundRect(gfx::Canvas* canvas, + const gfx::ImageSkia& image, + const SkPaint& paint, + const gfx::Rect& bounds, + int corner_radius) { + SkRect rect = gfx::RectToSkRect(bounds); + const SkScalar corner_radius_scalar = SkIntToScalar(corner_radius); + SkScalar radii[8] = { + corner_radius_scalar, corner_radius_scalar, // top-left + corner_radius_scalar, corner_radius_scalar, // top-right + 0, 0, // bottom-right + 0, 0}; // bottom-left + SkPath path; + path.addRoundRect(rect, radii, SkPath::kCW_Direction); + canvas->DrawImageInPath(image, 0, 0, path, paint); +} + +// Returns the FontList to use for the title. +const gfx::FontList& GetTitleFontList() { + static const gfx::FontList* title_font_list = + new gfx::FontList(views::NativeWidgetAura::GetWindowTitleFontList()); + ANNOTATE_LEAKING_OBJECT_PTR(title_font_list); + return *title_font_list; +} + +} // namespace + +namespace ash { + +/////////////////////////////////////////////////////////////////////////////// +// DefaultHeaderPainter, public: + +DefaultHeaderPainter::DefaultHeaderPainter() + : frame_(NULL), + view_(NULL), + window_icon_(NULL), + caption_button_container_(NULL), + height_(0), + mode_(MODE_INACTIVE), + initial_paint_(true), + activation_animation_(new gfx::SlideAnimation(this)) { +} + +DefaultHeaderPainter::~DefaultHeaderPainter() { +} + +void DefaultHeaderPainter::Init( + views::Widget* frame, + views::View* header_view, + views::View* window_icon, + FrameCaptionButtonContainerView* caption_button_container) { + DCHECK(frame); + DCHECK(header_view); + // window_icon may be NULL. + DCHECK(caption_button_container); + frame_ = frame; + view_ = header_view; + window_icon_ = window_icon; + caption_button_container_ = caption_button_container; + + caption_button_container_->SetButtonImages( + CAPTION_BUTTON_ICON_MINIMIZE, + IDR_AURA_WINDOW_CONTROL_ICON_MINIMIZE, + IDR_AURA_WINDOW_CONTROL_ICON_MINIMIZE_I, + IDR_AURA_WINDOW_CONTROL_BACKGROUND_H, + IDR_AURA_WINDOW_CONTROL_BACKGROUND_P); + caption_button_container_->SetButtonImages( + CAPTION_BUTTON_ICON_MAXIMIZE_RESTORE, + IDR_AURA_WINDOW_CONTROL_ICON_SIZE, + IDR_AURA_WINDOW_CONTROL_ICON_SIZE_I, + IDR_AURA_WINDOW_CONTROL_BACKGROUND_H, + IDR_AURA_WINDOW_CONTROL_BACKGROUND_P); + caption_button_container_->SetButtonImages( + CAPTION_BUTTON_ICON_CLOSE, + IDR_AURA_WINDOW_CONTROL_ICON_CLOSE, + IDR_AURA_WINDOW_CONTROL_ICON_CLOSE_I, + IDR_AURA_WINDOW_CONTROL_BACKGROUND_H, + IDR_AURA_WINDOW_CONTROL_BACKGROUND_P); + + // There is no dedicated icon for the snap-left and snap-right buttons + // when |frame_| is inactive because they should never be visible while + // |frame_| is inactive. + caption_button_container_->SetButtonImages( + CAPTION_BUTTON_ICON_LEFT_SNAPPED, + IDR_AURA_WINDOW_CONTROL_ICON_LEFT_SNAPPED, + IDR_AURA_WINDOW_CONTROL_ICON_LEFT_SNAPPED, + IDR_AURA_WINDOW_CONTROL_BACKGROUND_H, + IDR_AURA_WINDOW_CONTROL_BACKGROUND_P); + caption_button_container_->SetButtonImages( + CAPTION_BUTTON_ICON_RIGHT_SNAPPED, + IDR_AURA_WINDOW_CONTROL_ICON_RIGHT_SNAPPED, + IDR_AURA_WINDOW_CONTROL_ICON_RIGHT_SNAPPED, + IDR_AURA_WINDOW_CONTROL_BACKGROUND_H, + IDR_AURA_WINDOW_CONTROL_BACKGROUND_P); +} + +int DefaultHeaderPainter::GetMinimumHeaderWidth() const { + // Ensure we have enough space for the window icon and buttons. We allow + // the title string to collapse to zero width. + return GetTitleBounds().x() + + caption_button_container_->GetMinimumSize().width(); +} + +void DefaultHeaderPainter::PaintHeader(gfx::Canvas* canvas, Mode mode) { + Mode old_mode = mode_; + mode_ = mode; + + if (mode_ != old_mode) { + if (!initial_paint_ && HeaderPainterUtil::CanAnimateActivation(frame_)) { + activation_animation_->SetSlideDuration(kActivationCrossfadeDurationMs); + if (mode_ == MODE_ACTIVE) + activation_animation_->Show(); + else + activation_animation_->Hide(); + } else { + if (mode_ == MODE_ACTIVE) + activation_animation_->Reset(1); + else + activation_animation_->Reset(0); + } + initial_paint_ = false; + } + + int corner_radius = (frame_->IsMaximized() || frame_->IsFullscreen()) ? + 0 : HeaderPainterUtil::GetTopCornerRadiusWhenRestored(); + + int active_alpha = activation_animation_->CurrentValueBetween(0, 255); + int inactive_alpha = 255 - active_alpha; + + ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); + SkPaint paint; + if (inactive_alpha > 0) { + if (active_alpha > 0) + paint.setXfermodeMode(SkXfermode::kPlus_Mode); + + paint.setAlpha(inactive_alpha); + gfx::ImageSkia inactive_frame = + *rb.GetImageSkiaNamed(IDR_AURA_WINDOW_HEADER_BASE_INACTIVE); + TileRoundRect(canvas, inactive_frame, paint, GetLocalBounds(), + corner_radius); + } + + if (active_alpha > 0) { + paint.setAlpha(active_alpha); + gfx::ImageSkia active_frame = + *rb.GetImageSkiaNamed(IDR_AURA_WINDOW_HEADER_BASE_ACTIVE); + TileRoundRect(canvas, active_frame, paint, GetLocalBounds(), + corner_radius); + } + + if (!frame_->IsMaximized() && + !frame_->IsFullscreen() && + mode_ == MODE_INACTIVE) { + PaintHighlightForInactiveRestoredWindow(canvas); + } + if (frame_->widget_delegate() && + frame_->widget_delegate()->ShouldShowWindowTitle()) { + PaintTitleBar(canvas); + } + PaintHeaderContentSeparator(canvas); +} + +void DefaultHeaderPainter::LayoutHeader() { + caption_button_container_->Layout(); + + gfx::Size caption_button_container_size = + caption_button_container_->GetPreferredSize(); + caption_button_container_->SetBounds( + view_->width() - caption_button_container_size.width(), + 0, + caption_button_container_size.width(), + caption_button_container_size.height()); + + if (window_icon_) { + // Vertically center the window icon with respect to the caption button + // container. + int icon_size = HeaderPainterUtil::GetIconSize(); + int icon_offset_y = (caption_button_container_->height() - icon_size) / 2; + window_icon_->SetBounds(HeaderPainterUtil::GetIconXOffset(), icon_offset_y, + icon_size, icon_size); + } + + SetHeaderHeightForPainting(caption_button_container_->height() + + kHeaderContentSeparatorSize); +} + +int DefaultHeaderPainter::GetHeaderHeightForPainting() const { + return height_; +} + +void DefaultHeaderPainter::SetHeaderHeightForPainting(int height) { + height_ = height; +} + +void DefaultHeaderPainter::SchedulePaintForTitle() { + view_->SchedulePaintInRect(GetTitleBounds()); +} + +/////////////////////////////////////////////////////////////////////////////// +// gfx::AnimationDelegate overrides: + +void DefaultHeaderPainter::AnimationProgressed( + const gfx::Animation* animation) { + view_->SchedulePaintInRect(GetLocalBounds()); +} + +/////////////////////////////////////////////////////////////////////////////// +// DefaultHeaderPainter, private: + +void DefaultHeaderPainter::PaintHighlightForInactiveRestoredWindow( + gfx::Canvas* canvas) { + ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); + gfx::ImageSkia top_edge = *rb.GetImageSkiaNamed( + IDR_AURA_WINDOW_HEADER_SHADE_INACTIVE_TOP); + gfx::ImageSkia left_edge = *rb.GetImageSkiaNamed( + IDR_AURA_WINDOW_HEADER_SHADE_INACTIVE_LEFT); + gfx::ImageSkia right_edge = *rb.GetImageSkiaNamed( + IDR_AURA_WINDOW_HEADER_SHADE_INACTIVE_RIGHT); + gfx::ImageSkia bottom_edge = *rb.GetImageSkiaNamed( + IDR_AURA_WINDOW_HEADER_SHADE_INACTIVE_BOTTOM); + + int left_edge_width = left_edge.width(); + int right_edge_width = right_edge.width(); + canvas->DrawImageInt(left_edge, 0, 0); + canvas->DrawImageInt(right_edge, view_->width() - right_edge_width, 0); + canvas->TileImageInt( + top_edge, + left_edge_width, + 0, + view_->width() - left_edge_width - right_edge_width, + top_edge.height()); + + DCHECK_EQ(left_edge.height(), right_edge.height()); + int bottom = left_edge.height(); + int bottom_height = bottom_edge.height(); + canvas->TileImageInt( + bottom_edge, + left_edge_width, + bottom - bottom_height, + view_->width() - left_edge_width - right_edge_width, + bottom_height); +} + +void DefaultHeaderPainter::PaintTitleBar(gfx::Canvas* canvas) { + // The window icon is painted by its own views::View. + gfx::Rect title_bounds = GetTitleBounds(); + title_bounds.set_x(view_->GetMirroredXForRect(title_bounds)); + canvas->DrawStringRectWithFlags(frame_->widget_delegate()->GetWindowTitle(), + GetTitleFontList(), + kTitleTextColor, + title_bounds, + gfx::Canvas::NO_SUBPIXEL_RENDERING); +} + +void DefaultHeaderPainter::PaintHeaderContentSeparator(gfx::Canvas* canvas) { + SkColor color = (mode_ == MODE_ACTIVE) ? + kHeaderContentSeparatorColor : + kHeaderContentSeparatorInactiveColor; + + canvas->FillRect(gfx::Rect(0, + height_ - kHeaderContentSeparatorSize, + view_->width(), + kHeaderContentSeparatorSize), + color); +} + +gfx::Rect DefaultHeaderPainter::GetLocalBounds() const { + return gfx::Rect(view_->width(), height_); +} + +gfx::Rect DefaultHeaderPainter::GetTitleBounds() const { + return HeaderPainterUtil::GetTitleBounds( + window_icon_, caption_button_container_, GetTitleFontList()); +} + +} // namespace ash diff --git a/ash/frame/default_header_painter.h b/ash/frame/default_header_painter.h new file mode 100644 index 0000000..80990c1 --- /dev/null +++ b/ash/frame/default_header_painter.h @@ -0,0 +1,94 @@ +// Copyright 2014 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 ASH_FRAME_DEFAULT_HEADER_PAINTER_H_ +#define ASH_FRAME_DEFAULT_HEADER_PAINTER_H_ + +#include "ash/ash_export.h" +#include "ash/frame/header_painter.h" +#include "base/basictypes.h" +#include "base/compiler_specific.h" // OVERRIDE +#include "base/gtest_prod_util.h" +#include "base/memory/scoped_ptr.h" +#include "ui/gfx/animation/animation_delegate.h" + +namespace gfx { +class Rect; +class SlideAnimation; +} +namespace views { +class View; +class Widget; +} + +namespace ash { +class FrameCaptionButtonContainerView; + +// Helper class for painting the default window header. +class ASH_EXPORT DefaultHeaderPainter : public HeaderPainter, + public gfx::AnimationDelegate { + public: + DefaultHeaderPainter(); + virtual ~DefaultHeaderPainter(); + + // DefaultHeaderPainter does not take ownership of any of the parameters. + void Init(views::Widget* frame, + views::View* header_view, + views::View* window_icon, + FrameCaptionButtonContainerView* caption_button_container); + + // HeaderPainter overrides: + virtual int GetMinimumHeaderWidth() const OVERRIDE; + virtual void PaintHeader(gfx::Canvas* canvas, Mode mode) OVERRIDE; + virtual void LayoutHeader() OVERRIDE; + virtual int GetHeaderHeightForPainting() const OVERRIDE; + virtual void SetHeaderHeightForPainting(int height) OVERRIDE; + virtual void SchedulePaintForTitle() OVERRIDE; + + private: + FRIEND_TEST_ALL_PREFIXES(DefaultHeaderPainterTest, TitleIconAlignment); + + // gfx::AnimationDelegate override: + virtual void AnimationProgressed(const gfx::Animation* animation) OVERRIDE; + + // Paints highlight around the edge of the header for inactive restored + // windows. + void PaintHighlightForInactiveRestoredWindow(gfx::Canvas* canvas); + + // Paints the title bar, primarily the title string. + void PaintTitleBar(gfx::Canvas* canvas); + + // Paints the header/content separator. + void PaintHeaderContentSeparator(gfx::Canvas* canvas); + + // Returns the header bounds in the coordinates of |view_|. The header is + // assumed to be positioned at the top left corner of |view_| and to have the + // same width as |view_|. + gfx::Rect GetLocalBounds() const; + + // Returns the bounds for the title. + gfx::Rect GetTitleBounds() const; + + views::Widget* frame_; + views::View* view_; + views::View* window_icon_; // May be NULL. + FrameCaptionButtonContainerView* caption_button_container_; + + // The height of the header including the header/content separator. + int height_; + + // Whether the header should be painted as active. + Mode mode_; + + // Whether the header is painted for the first time. + bool initial_paint_; + + scoped_ptr<gfx::SlideAnimation> activation_animation_; + + DISALLOW_COPY_AND_ASSIGN(DefaultHeaderPainter); +}; + +} // namespace ash + +#endif // ASH_FRAME_DEFAULT_HEADER_PAINTER_H_ diff --git a/ash/frame/default_header_painter_unittest.cc b/ash/frame/default_header_painter_unittest.cc new file mode 100644 index 0000000..282baab --- /dev/null +++ b/ash/frame/default_header_painter_unittest.cc @@ -0,0 +1,57 @@ +// Copyright 2014 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 "ash/frame/default_header_painter.h" + +#include "ash/frame/caption_buttons/frame_caption_button_container_view.h" +#include "ash/shell.h" +#include "ash/test/ash_test_base.h" +#include "ash/wm/window_state.h" +#include "base/memory/scoped_ptr.h" +#include "grit/ash_resources.h" +#include "ui/gfx/font_list.h" +#include "ui/views/widget/widget.h" +#include "ui/views/window/non_client_view.h" + +using ash::HeaderPainter; +using views::NonClientFrameView; +using views::Widget; + +namespace ash { + +class DefaultHeaderPainterTest : public ash::test::AshTestBase { + public: + // Creates a test widget that owns its native widget. + Widget* CreateTestWidget() { + Widget* widget = new Widget; + Widget::InitParams params; + params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + params.context = CurrentContext(); + widget->Init(params); + return widget; + } +}; + +// Ensure the title text is vertically aligned with the window icon. +TEST_F(DefaultHeaderPainterTest, TitleIconAlignment) { + scoped_ptr<Widget> w(CreateTestWidget()); + ash::FrameCaptionButtonContainerView container(w.get(), + ash::FrameCaptionButtonContainerView::MINIMIZE_ALLOWED); + views::View window_icon; + window_icon.SetBounds(0, 0, 16, 16); + w->SetBounds(gfx::Rect(0, 0, 500, 500)); + w->Show(); + + DefaultHeaderPainter painter; + painter.Init(w.get(), + w->non_client_view()->frame_view(), + &window_icon, + &container); + painter.LayoutHeader(); + gfx::Rect title_bounds = painter.GetTitleBounds(); + EXPECT_EQ(window_icon.bounds().CenterPoint().y(), + title_bounds.CenterPoint().y()); +} + +} // namespace ash diff --git a/ash/frame/frame_border_hit_test_controller.cc b/ash/frame/frame_border_hit_test_controller.cc index 228db6b..1ce114d 100644 --- a/ash/frame/frame_border_hit_test_controller.cc +++ b/ash/frame/frame_border_hit_test_controller.cc @@ -5,7 +5,7 @@ #include "ash/frame/frame_border_hit_test_controller.h" #include "ash/ash_constants.h" -#include "ash/frame/header_painter.h" +#include "ash/frame/caption_buttons/frame_caption_button_container_view.h" #include "ash/wm/resize_handle_window_targeter.h" #include "ash/wm/window_state_observer.h" #include "ui/aura/env.h" @@ -31,8 +31,8 @@ FrameBorderHitTestController::~FrameBorderHitTestController() { // static int FrameBorderHitTestController::NonClientHitTest( views::NonClientFrameView* view, - HeaderPainter* header_painter, - const gfx::Point& point) { + FrameCaptionButtonContainerView* caption_button_container, + const gfx::Point& point_in_widget) { gfx::Rect expanded_bounds = view->bounds(); int outside_bounds = kResizeOutsideBoundsSize; @@ -40,7 +40,7 @@ int FrameBorderHitTestController::NonClientHitTest( outside_bounds *= kResizeOutsideBoundsScaleForTouch; expanded_bounds.Inset(-outside_bounds, -outside_bounds); - if (!expanded_bounds.Contains(point)) + if (!expanded_bounds.Contains(point_in_widget)) return HTNOWHERE; // Check the frame first, as we allow a small area overlapping the contents @@ -52,7 +52,7 @@ int FrameBorderHitTestController::NonClientHitTest( int resize_border = frame->IsMaximized() || frame->IsFullscreen() ? 0 : kResizeInsideBoundsSize; - int frame_component = view->GetHTComponentForFrame(point, + int frame_component = view->GetHTComponentForFrame(point_in_widget, resize_border, resize_border, kResizeAreaCornerSize, @@ -61,11 +61,23 @@ int FrameBorderHitTestController::NonClientHitTest( if (frame_component != HTNOWHERE) return frame_component; - int client_component = frame->client_view()->NonClientHitTest(point); + int client_component = frame->client_view()->NonClientHitTest( + point_in_widget); if (client_component != HTNOWHERE) return client_component; - return header_painter->NonClientHitTest(point); + if (caption_button_container->visible()) { + gfx::Point point_in_caption_button_container(point_in_widget); + views::View::ConvertPointFromWidget(caption_button_container, + &point_in_caption_button_container); + int caption_button_component = caption_button_container->NonClientHitTest( + point_in_caption_button_container); + if (caption_button_component != HTNOWHERE) + return caption_button_component; + } + + // Caption is a safe default. + return HTCAPTION; } } // namespace ash diff --git a/ash/frame/frame_border_hit_test_controller.h b/ash/frame/frame_border_hit_test_controller.h index 1fef389..9d50b0f 100644 --- a/ash/frame/frame_border_hit_test_controller.h +++ b/ash/frame/frame_border_hit_test_controller.h @@ -23,7 +23,7 @@ class Widget; } namespace ash { -class HeaderPainter; +class FrameCaptionButtonContainerView; // Class which manages the hittest override bounds for |frame|. class ASH_EXPORT FrameBorderHitTestController { @@ -31,11 +31,12 @@ class ASH_EXPORT FrameBorderHitTestController { explicit FrameBorderHitTestController(views::Widget* frame); virtual ~FrameBorderHitTestController(); - // Does the non client hit test on behalf of |view|. |point| must be in the - // coordinates of |view|'s widget. - static int NonClientHitTest(views::NonClientFrameView* view, - HeaderPainter* header_painter, - const gfx::Point& point); + // Does the non client hit test on behalf of |view|. |point_in_widget| must be + // in the coordinates of |view|'s widget. + static int NonClientHitTest( + views::NonClientFrameView* view, + FrameCaptionButtonContainerView* caption_button_container, + const gfx::Point& point_in_widget); private: // The window whose hittest override bounds are being managed. diff --git a/ash/frame/header_painter.cc b/ash/frame/header_painter.cc deleted file mode 100644 index 4a9195f..0000000 --- a/ash/frame/header_painter.cc +++ /dev/null @@ -1,634 +0,0 @@ -// Copyright 2013 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 "ash/frame/header_painter.h" - -#include <vector> - -#include "ash/frame/caption_buttons/frame_caption_button_container_view.h" -#include "base/logging.h" // DCHECK -#include "grit/ash_resources.h" -#include "third_party/skia/include/core/SkCanvas.h" -#include "third_party/skia/include/core/SkColor.h" -#include "third_party/skia/include/core/SkPaint.h" -#include "third_party/skia/include/core/SkPath.h" -#include "ui/aura/window.h" -#include "ui/base/hit_test.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/base/theme_provider.h" -#include "ui/gfx/animation/slide_animation.h" -#include "ui/gfx/canvas.h" -#include "ui/gfx/font_list.h" -#include "ui/gfx/image/image.h" -#include "ui/gfx/skia_util.h" -#include "ui/views/widget/widget.h" -#include "ui/views/widget/widget_delegate.h" - -using aura::Window; -using views::Widget; - -namespace { -// Space between left edge of window and popup window icon. -const int kIconOffsetX = 9; -// Height and width of window icon. -const int kIconSize = 16; -// Space between the title text and the caption buttons. -const int kTitleLogoSpacing = 5; -// Space between window icon and title text. -const int kTitleIconOffsetX = 5; -// Space between window edge and title text, when there is no icon. -const int kTitleNoIconOffsetX = 8; -// Color for the non-browser window title text. -const SkColor kWindowTitleTextColor = SkColorSetRGB(40, 40, 40); -// Color for the restored browser window title text. -const SkColor kRestoredBrowserWindowTitleTextColor = SkColorSetRGB(40, 40, 40); -// Color for the maximized browser window title text. -const SkColor kMaximizedBrowserWindowTitleTextColor = SK_ColorWHITE; -// Size of header/content separator line below the header image for non-browser -// windows. -const int kHeaderContentSeparatorSize = 1; -// Color of the active window header/content separator line for non-browser -// windows. -const SkColor kHeaderContentSeparatorColor = SkColorSetRGB(180, 180, 182); -// Color of the inactive window header/content separator line for non-browser -// windows. -const SkColor kHeaderContentSeparatorInactiveColor = - SkColorSetRGB(150, 150, 152); -// In the pre-Ash era the web content area had a frame along the left edge, so -// user-generated theme images for the new tab page assume they are shifted -// right relative to the header. Now that we have removed the left edge frame -// we need to copy the theme image for the window header from a few pixels -// inset to preserve alignment with the NTP image, or else we'll break a bunch -// of existing themes. We do something similar on OS X for the same reason. -const int kThemeFrameImageInsetX = 5; -// Duration of crossfade animation for activating and deactivating frame. -const int kActivationCrossfadeDurationMs = 200; - -// Tiles an image into an area, rounding the top corners. Samples |image| -// starting |image_inset_x| pixels from the left of the image. -void TileRoundRect(gfx::Canvas* canvas, - const gfx::ImageSkia& image, - const SkPaint& paint, - const gfx::Rect& bounds, - int top_left_corner_radius, - int top_right_corner_radius, - int image_inset_x) { - SkRect rect = gfx::RectToSkRect(bounds); - const SkScalar kTopLeftRadius = SkIntToScalar(top_left_corner_radius); - const SkScalar kTopRightRadius = SkIntToScalar(top_right_corner_radius); - SkScalar radii[8] = { - kTopLeftRadius, kTopLeftRadius, // top-left - kTopRightRadius, kTopRightRadius, // top-right - 0, 0, // bottom-right - 0, 0}; // bottom-left - SkPath path; - path.addRoundRect(rect, radii, SkPath::kCW_Direction); - canvas->DrawImageInPath(image, -image_inset_x, 0, path, paint); -} - -// Tiles |frame_image| and |frame_overlay_image| into an area, rounding the top -// corners. -void PaintFrameImagesInRoundRect(gfx::Canvas* canvas, - const gfx::ImageSkia* frame_image, - const gfx::ImageSkia* frame_overlay_image, - const SkPaint& paint, - const gfx::Rect& bounds, - int corner_radius, - int image_inset_x) { - SkXfermode::Mode normal_mode; - SkXfermode::AsMode(NULL, &normal_mode); - - // If |paint| is using an unusual SkXfermode::Mode (this is the case while - // crossfading), we must create a new canvas to overlay |frame_image| and - // |frame_overlay_image| using |normal_mode| and then paint the result - // using the unusual mode. We try to avoid this because creating a new - // browser-width canvas is expensive. - bool fast_path = (!frame_overlay_image || - SkXfermode::IsMode(paint.getXfermode(), normal_mode)); - if (fast_path) { - TileRoundRect(canvas, *frame_image, paint, bounds, corner_radius, - corner_radius, image_inset_x); - - if (frame_overlay_image) { - // Adjust |bounds| such that |frame_overlay_image| is not tiled. - gfx::Rect overlay_bounds = bounds; - overlay_bounds.Intersect( - gfx::Rect(bounds.origin(), frame_overlay_image->size())); - int top_left_corner_radius = corner_radius; - int top_right_corner_radius = corner_radius; - if (overlay_bounds.width() < bounds.width() - corner_radius) - top_right_corner_radius = 0; - TileRoundRect(canvas, *frame_overlay_image, paint, overlay_bounds, - top_left_corner_radius, top_right_corner_radius, 0); - } - } else { - gfx::Canvas temporary_canvas(bounds.size(), canvas->image_scale(), false); - temporary_canvas.TileImageInt(*frame_image, - image_inset_x, 0, - 0, 0, - bounds.width(), bounds.height()); - temporary_canvas.DrawImageInt(*frame_overlay_image, 0, 0); - TileRoundRect(canvas, gfx::ImageSkia(temporary_canvas.ExtractImageRep()), - paint, bounds, corner_radius, corner_radius, 0); - } -} - -} // namespace - -namespace ash { - -/////////////////////////////////////////////////////////////////////////////// -// HeaderPainter, public: - -HeaderPainter::HeaderPainter() - : frame_(NULL), - header_view_(NULL), - window_icon_(NULL), - caption_button_container_(NULL), - header_height_(0), - previous_theme_frame_id_(0), - previous_theme_frame_overlay_id_(0), - crossfade_theme_frame_id_(0), - crossfade_theme_frame_overlay_id_(0) {} - -HeaderPainter::~HeaderPainter() { -} - -void HeaderPainter::Init( - Style style, - views::Widget* frame, - views::View* header_view, - views::View* window_icon, - FrameCaptionButtonContainerView* caption_button_container) { - DCHECK(frame); - DCHECK(header_view); - // window_icon may be NULL. - DCHECK(caption_button_container); - style_ = style; - frame_ = frame; - header_view_ = header_view; - window_icon_ = window_icon; - caption_button_container_ = caption_button_container; -} - -// static -gfx::Rect HeaderPainter::GetBoundsForClientView( - int header_height, - const gfx::Rect& window_bounds) { - gfx::Rect client_bounds(window_bounds); - client_bounds.Inset(0, header_height, 0, 0); - return client_bounds; -} - -// static -gfx::Rect HeaderPainter::GetWindowBoundsForClientBounds( - int header_height, - const gfx::Rect& client_bounds) { - gfx::Rect window_bounds(client_bounds); - window_bounds.Inset(0, -header_height, 0, 0); - return window_bounds; -} - -int HeaderPainter::NonClientHitTest(const gfx::Point& point) const { - gfx::Point point_in_header_view(point); - views::View::ConvertPointFromWidget(header_view_, &point_in_header_view); - if (!GetHeaderLocalBounds().Contains(point_in_header_view)) - return HTNOWHERE; - if (caption_button_container_->visible()) { - gfx::Point point_in_caption_button_container(point); - views::View::ConvertPointFromWidget(caption_button_container_, - &point_in_caption_button_container); - int component = caption_button_container_->NonClientHitTest( - point_in_caption_button_container); - if (component != HTNOWHERE) - return component; - } - // Caption is a safe default. - return HTCAPTION; -} - -int HeaderPainter::GetMinimumHeaderWidth() const { - // Ensure we have enough space for the window icon and buttons. We allow - // the title string to collapse to zero width. - return GetTitleOffsetX() + - caption_button_container_->GetMinimumSize().width(); -} - -int HeaderPainter::GetRightInset() const { - return caption_button_container_->GetPreferredSize().width(); -} - -int HeaderPainter::GetThemeBackgroundXInset() const { - return kThemeFrameImageInsetX; -} - -void HeaderPainter::PaintHeader(gfx::Canvas* canvas, - Mode mode, - int theme_frame_id, - int theme_frame_overlay_id) { - bool initial_paint = (previous_theme_frame_id_ == 0); - if (!initial_paint && - (previous_theme_frame_id_ != theme_frame_id || - previous_theme_frame_overlay_id_ != theme_frame_overlay_id)) { - aura::Window* parent = frame_->GetNativeWindow()->parent(); - // Don't animate the header if the parent (a workspace) is already - // animating. Doing so results in continually painting during the animation - // and gives a slower frame rate. - // TODO(sky): expose a better way to determine this rather than assuming - // the parent is a workspace. - bool parent_animating = parent && - (parent->layer()->GetAnimator()->IsAnimatingProperty( - ui::LayerAnimationElement::OPACITY) || - parent->layer()->GetAnimator()->IsAnimatingProperty( - ui::LayerAnimationElement::VISIBILITY)); - if (!parent_animating) { - crossfade_animation_.reset(new gfx::SlideAnimation(this)); - crossfade_theme_frame_id_ = previous_theme_frame_id_; - crossfade_theme_frame_overlay_id_ = previous_theme_frame_overlay_id_; - crossfade_animation_->SetSlideDuration(kActivationCrossfadeDurationMs); - crossfade_animation_->Show(); - } else { - crossfade_animation_.reset(); - } - } - - ui::ThemeProvider* theme_provider = frame_->GetThemeProvider(); - gfx::ImageSkia* theme_frame = theme_provider->GetImageSkiaNamed( - theme_frame_id); - gfx::ImageSkia* theme_frame_overlay = NULL; - if (theme_frame_overlay_id != 0) { - theme_frame_overlay = theme_provider->GetImageSkiaNamed( - theme_frame_overlay_id); - } - - int corner_radius = GetHeaderCornerRadius(); - SkPaint paint; - - if (crossfade_animation_.get() && crossfade_animation_->is_animating()) { - gfx::ImageSkia* crossfade_theme_frame = - theme_provider->GetImageSkiaNamed(crossfade_theme_frame_id_); - gfx::ImageSkia* crossfade_theme_frame_overlay = NULL; - if (crossfade_theme_frame_overlay_id_ != 0) { - crossfade_theme_frame_overlay = theme_provider->GetImageSkiaNamed( - crossfade_theme_frame_overlay_id_); - } - if (!crossfade_theme_frame || - (crossfade_theme_frame_overlay_id_ != 0 && - !crossfade_theme_frame_overlay)) { - // Reset the animation. This case occurs when the user switches the theme - // that they are using. - crossfade_animation_.reset(); - } else { - int old_alpha = crossfade_animation_->CurrentValueBetween(255, 0); - int new_alpha = 255 - old_alpha; - - // Draw the old header background, clipping the corners to be rounded. - paint.setAlpha(old_alpha); - paint.setXfermodeMode(SkXfermode::kPlus_Mode); - PaintFrameImagesInRoundRect(canvas, - crossfade_theme_frame, - crossfade_theme_frame_overlay, - paint, - GetHeaderLocalBounds(), - corner_radius, - GetThemeBackgroundXInset()); - - paint.setAlpha(new_alpha); - } - } - - // Draw the header background, clipping the corners to be rounded. - PaintFrameImagesInRoundRect(canvas, - theme_frame, - theme_frame_overlay, - paint, - GetHeaderLocalBounds(), - corner_radius, - GetThemeBackgroundXInset()); - - previous_theme_frame_id_ = theme_frame_id; - previous_theme_frame_overlay_id_ = theme_frame_overlay_id; - - if (!frame_->IsMaximized() && !frame_->IsFullscreen()) { - if (style_ == STYLE_BROWSER) { - PaintHighlightForRestoredBrowserWindow(canvas); - } else { - if (mode == MODE_INACTIVE) - PaintHighlightForInactiveRestoredWindow(canvas); - } - } -} - -void HeaderPainter::PaintHeaderContentSeparator(gfx::Canvas* canvas, - Mode mode) { - DCHECK_EQ(style_, STYLE_OTHER); - SkColor color = (mode == MODE_ACTIVE) ? - kHeaderContentSeparatorColor : - kHeaderContentSeparatorInactiveColor; - - canvas->FillRect(gfx::Rect(0, - header_height_ - kHeaderContentSeparatorSize, - header_view_->width(), - kHeaderContentSeparatorSize), - color); -} - -int HeaderPainter::HeaderContentSeparatorSize() const { - return kHeaderContentSeparatorSize; -} - -void HeaderPainter::PaintTitleBar(gfx::Canvas* canvas, - const gfx::FontList& title_font_list) { - // The window icon is painted by its own views::View. - views::WidgetDelegate* delegate = frame_->widget_delegate(); - if (delegate && delegate->ShouldShowWindowTitle()) { - gfx::Rect title_bounds = GetTitleBounds(title_font_list); - title_bounds.set_x(header_view_->GetMirroredXForRect(title_bounds)); - SkColor title_color = kWindowTitleTextColor; - if (style_ == STYLE_BROWSER) { - title_color = (frame_->IsMaximized() || frame_->IsFullscreen()) ? - kMaximizedBrowserWindowTitleTextColor : - kRestoredBrowserWindowTitleTextColor; - } - canvas->DrawStringRectWithFlags(delegate->GetWindowTitle(), - title_font_list, - title_color, - title_bounds, - gfx::Canvas::NO_SUBPIXEL_RENDERING); - } -} - -void HeaderPainter::LayoutHeader() { - // Purposefully set |header_height_| to an invalid value. We cannot use - // |header_height_| because the computation of |header_height_| may depend - // on having laid out the window controls. - header_height_ = -1; - - UpdateCaptionButtonImages(); - caption_button_container_->Layout(); - - gfx::Size caption_button_container_size = - caption_button_container_->GetPreferredSize(); - caption_button_container_->SetBounds( - header_view_->width() - caption_button_container_size.width(), - 0, - caption_button_container_size.width(), - caption_button_container_size.height()); - - if (window_icon_) { - // Vertically center the window icon with respect to the caption button - // container. - int icon_offset_y = - GetCaptionButtonContainerCenterY() - window_icon_->height() / 2; - window_icon_->SetBounds(kIconOffsetX, icon_offset_y, kIconSize, kIconSize); - } -} - -void HeaderPainter::SchedulePaintForTitle( - const gfx::FontList& title_font_list) { - header_view_->SchedulePaintInRect(GetTitleBounds(title_font_list)); -} - -void HeaderPainter::OnThemeChanged() { - // We do not cache the images for |previous_theme_frame_id_| and - // |previous_theme_frame_overlay_id_|. Changing the theme changes the images - // returned from ui::ThemeProvider for |previous_theme_frame_id_| - // and |previous_theme_frame_overlay_id_|. Reset the image ids to prevent - // starting a crossfade animation with these images. - previous_theme_frame_id_ = 0; - previous_theme_frame_overlay_id_ = 0; - - if (crossfade_animation_.get() && crossfade_animation_->is_animating()) { - crossfade_animation_.reset(); - header_view_->SchedulePaintInRect(GetHeaderLocalBounds()); - } -} - -/////////////////////////////////////////////////////////////////////////////// -// gfx::AnimationDelegate overrides: - -void HeaderPainter::AnimationProgressed(const gfx::Animation* animation) { - header_view_->SchedulePaintInRect(GetHeaderLocalBounds()); -} - -/////////////////////////////////////////////////////////////////////////////// -// HeaderPainter, private: - -void HeaderPainter::PaintHighlightForRestoredBrowserWindow( - gfx::Canvas* canvas) { - ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); - gfx::ImageSkia top_left_corner = *rb.GetImageSkiaNamed( - IDR_AURA_BROWSER_WINDOW_HEADER_SHADE_TOP_LEFT); - gfx::ImageSkia top_right_corner = *rb.GetImageSkiaNamed( - IDR_AURA_BROWSER_WINDOW_HEADER_SHADE_TOP_RIGHT); - gfx::ImageSkia top_edge = *rb.GetImageSkiaNamed( - IDR_AURA_BROWSER_WINDOW_HEADER_SHADE_TOP); - gfx::ImageSkia left_edge = *rb.GetImageSkiaNamed( - IDR_AURA_BROWSER_WINDOW_HEADER_SHADE_LEFT); - gfx::ImageSkia right_edge = *rb.GetImageSkiaNamed( - IDR_AURA_BROWSER_WINDOW_HEADER_SHADE_RIGHT); - - int top_left_width = top_left_corner.width(); - int top_left_height = top_left_corner.height(); - canvas->DrawImageInt(top_left_corner, 0, 0); - - int top_right_width = top_right_corner.width(); - int top_right_height = top_right_corner.height(); - canvas->DrawImageInt(top_right_corner, - header_view_->width() - top_right_width, - 0); - - canvas->TileImageInt( - top_edge, - top_left_width, - 0, - header_view_->width() - top_left_width - top_right_width, - top_edge.height()); - - canvas->TileImageInt(left_edge, - 0, - top_left_height, - left_edge.width(), - header_height_ - top_left_height); - - canvas->TileImageInt(right_edge, - header_view_->width() - right_edge.width(), - top_right_height, - right_edge.width(), - header_height_ - top_right_height); -} - -void HeaderPainter::PaintHighlightForInactiveRestoredWindow( - gfx::Canvas* canvas) { - ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); - gfx::ImageSkia top_edge = *rb.GetImageSkiaNamed( - IDR_AURA_WINDOW_HEADER_SHADE_INACTIVE_TOP); - gfx::ImageSkia left_edge = *rb.GetImageSkiaNamed( - IDR_AURA_WINDOW_HEADER_SHADE_INACTIVE_LEFT); - gfx::ImageSkia right_edge = *rb.GetImageSkiaNamed( - IDR_AURA_WINDOW_HEADER_SHADE_INACTIVE_RIGHT); - gfx::ImageSkia bottom_edge = *rb.GetImageSkiaNamed( - IDR_AURA_WINDOW_HEADER_SHADE_INACTIVE_BOTTOM); - - int left_edge_width = left_edge.width(); - int right_edge_width = right_edge.width(); - canvas->DrawImageInt(left_edge, 0, 0); - canvas->DrawImageInt(right_edge, header_view_->width() - right_edge_width, 0); - canvas->TileImageInt( - top_edge, - left_edge_width, - 0, - header_view_->width() - left_edge_width - right_edge_width, - top_edge.height()); - - DCHECK_EQ(left_edge.height(), right_edge.height()); - int bottom = left_edge.height(); - int bottom_height = bottom_edge.height(); - canvas->TileImageInt( - bottom_edge, - left_edge_width, - bottom - bottom_height, - header_view_->width() - left_edge_width - right_edge_width, - bottom_height); -} - -void HeaderPainter::UpdateCaptionButtonImages() { - if (style_ == STYLE_BROWSER) { - if (frame_->IsMaximized() || frame_->IsFullscreen()) { - caption_button_container_->SetButtonImages( - CAPTION_BUTTON_ICON_MINIMIZE, - IDR_AURA_BROWSER_WINDOW_CONTROL_ICON_MAXIMIZED_MINIMIZE, - IDR_AURA_BROWSER_WINDOW_CONTROL_ICON_MAXIMIZED_MINIMIZE, - IDR_AURA_BROWSER_WINDOW_CONTROL_BACKGROUND_MAXIMIZED_H, - IDR_AURA_BROWSER_WINDOW_CONTROL_BACKGROUND_MAXIMIZED_P); - caption_button_container_->SetButtonImages( - CAPTION_BUTTON_ICON_MAXIMIZE_RESTORE, - IDR_AURA_BROWSER_WINDOW_CONTROL_ICON_MAXIMIZED_SIZE, - IDR_AURA_BROWSER_WINDOW_CONTROL_ICON_MAXIMIZED_SIZE, - IDR_AURA_BROWSER_WINDOW_CONTROL_BACKGROUND_MAXIMIZED_H, - IDR_AURA_BROWSER_WINDOW_CONTROL_BACKGROUND_MAXIMIZED_P); - caption_button_container_->SetButtonImages( - CAPTION_BUTTON_ICON_CLOSE, - IDR_AURA_BROWSER_WINDOW_CONTROL_ICON_MAXIMIZED_CLOSE, - IDR_AURA_BROWSER_WINDOW_CONTROL_ICON_MAXIMIZED_CLOSE, - IDR_AURA_BROWSER_WINDOW_CONTROL_BACKGROUND_MAXIMIZED_H, - IDR_AURA_BROWSER_WINDOW_CONTROL_BACKGROUND_MAXIMIZED_P); - caption_button_container_->SetButtonImages( - CAPTION_BUTTON_ICON_LEFT_SNAPPED, - IDR_AURA_BROWSER_WINDOW_CONTROL_ICON_MAXIMIZED_LEFT_SNAPPED, - IDR_AURA_BROWSER_WINDOW_CONTROL_ICON_MAXIMIZED_LEFT_SNAPPED, - IDR_AURA_BROWSER_WINDOW_CONTROL_BACKGROUND_MAXIMIZED_H, - IDR_AURA_BROWSER_WINDOW_CONTROL_BACKGROUND_MAXIMIZED_P); - caption_button_container_->SetButtonImages( - CAPTION_BUTTON_ICON_RIGHT_SNAPPED, - IDR_AURA_BROWSER_WINDOW_CONTROL_ICON_MAXIMIZED_RIGHT_SNAPPED, - IDR_AURA_BROWSER_WINDOW_CONTROL_ICON_MAXIMIZED_RIGHT_SNAPPED, - IDR_AURA_BROWSER_WINDOW_CONTROL_BACKGROUND_MAXIMIZED_H, - IDR_AURA_BROWSER_WINDOW_CONTROL_BACKGROUND_MAXIMIZED_P); - } else { - caption_button_container_->SetButtonImages( - CAPTION_BUTTON_ICON_MINIMIZE, - IDR_AURA_BROWSER_WINDOW_CONTROL_ICON_RESTORED_MINIMIZE, - IDR_AURA_BROWSER_WINDOW_CONTROL_ICON_RESTORED_MINIMIZE, - IDR_AURA_BROWSER_WINDOW_CONTROL_BACKGROUND_RESTORED_H, - IDR_AURA_BROWSER_WINDOW_CONTROL_BACKGROUND_RESTORED_P); - caption_button_container_->SetButtonImages( - CAPTION_BUTTON_ICON_MAXIMIZE_RESTORE, - IDR_AURA_BROWSER_WINDOW_CONTROL_ICON_RESTORED_SIZE, - IDR_AURA_BROWSER_WINDOW_CONTROL_ICON_RESTORED_SIZE, - IDR_AURA_BROWSER_WINDOW_CONTROL_BACKGROUND_RESTORED_H, - IDR_AURA_BROWSER_WINDOW_CONTROL_BACKGROUND_RESTORED_P); - caption_button_container_->SetButtonImages( - CAPTION_BUTTON_ICON_CLOSE, - IDR_AURA_BROWSER_WINDOW_CONTROL_ICON_RESTORED_CLOSE, - IDR_AURA_BROWSER_WINDOW_CONTROL_ICON_RESTORED_CLOSE, - IDR_AURA_BROWSER_WINDOW_CONTROL_BACKGROUND_RESTORED_H, - IDR_AURA_BROWSER_WINDOW_CONTROL_BACKGROUND_RESTORED_P); - caption_button_container_->SetButtonImages( - CAPTION_BUTTON_ICON_LEFT_SNAPPED, - IDR_AURA_BROWSER_WINDOW_CONTROL_ICON_RESTORED_LEFT_SNAPPED, - IDR_AURA_BROWSER_WINDOW_CONTROL_ICON_RESTORED_LEFT_SNAPPED, - IDR_AURA_BROWSER_WINDOW_CONTROL_BACKGROUND_RESTORED_H, - IDR_AURA_BROWSER_WINDOW_CONTROL_BACKGROUND_RESTORED_P); - caption_button_container_->SetButtonImages( - CAPTION_BUTTON_ICON_RIGHT_SNAPPED, - IDR_AURA_BROWSER_WINDOW_CONTROL_ICON_RESTORED_RIGHT_SNAPPED, - IDR_AURA_BROWSER_WINDOW_CONTROL_ICON_RESTORED_RIGHT_SNAPPED, - IDR_AURA_BROWSER_WINDOW_CONTROL_BACKGROUND_RESTORED_H, - IDR_AURA_BROWSER_WINDOW_CONTROL_BACKGROUND_RESTORED_P); - } - } else { - caption_button_container_->SetButtonImages( - CAPTION_BUTTON_ICON_MINIMIZE, - IDR_AURA_WINDOW_CONTROL_ICON_MINIMIZE, - IDR_AURA_WINDOW_CONTROL_ICON_MINIMIZE_I, - IDR_AURA_WINDOW_CONTROL_BACKGROUND_H, - IDR_AURA_WINDOW_CONTROL_BACKGROUND_P); - caption_button_container_->SetButtonImages( - CAPTION_BUTTON_ICON_MAXIMIZE_RESTORE, - IDR_AURA_WINDOW_CONTROL_ICON_SIZE, - IDR_AURA_WINDOW_CONTROL_ICON_SIZE_I, - IDR_AURA_WINDOW_CONTROL_BACKGROUND_H, - IDR_AURA_WINDOW_CONTROL_BACKGROUND_P); - caption_button_container_->SetButtonImages( - CAPTION_BUTTON_ICON_CLOSE, - IDR_AURA_WINDOW_CONTROL_ICON_CLOSE, - IDR_AURA_WINDOW_CONTROL_ICON_CLOSE_I, - IDR_AURA_WINDOW_CONTROL_BACKGROUND_H, - IDR_AURA_WINDOW_CONTROL_BACKGROUND_P); - - // There is no dedicated icon for the snap-left and snap-right buttons - // when |frame_| is inactive because they should never be visible while - // |frame_| is inactive. - caption_button_container_->SetButtonImages( - CAPTION_BUTTON_ICON_LEFT_SNAPPED, - IDR_AURA_WINDOW_CONTROL_ICON_LEFT_SNAPPED, - IDR_AURA_WINDOW_CONTROL_ICON_LEFT_SNAPPED, - IDR_AURA_WINDOW_CONTROL_BACKGROUND_H, - IDR_AURA_WINDOW_CONTROL_BACKGROUND_P); - caption_button_container_->SetButtonImages( - CAPTION_BUTTON_ICON_RIGHT_SNAPPED, - IDR_AURA_WINDOW_CONTROL_ICON_RIGHT_SNAPPED, - IDR_AURA_WINDOW_CONTROL_ICON_RIGHT_SNAPPED, - IDR_AURA_WINDOW_CONTROL_BACKGROUND_H, - IDR_AURA_WINDOW_CONTROL_BACKGROUND_P); - } -} - -gfx::Rect HeaderPainter::GetHeaderLocalBounds() const { - return gfx::Rect(header_view_->width(), header_height_); -} - -int HeaderPainter::GetTitleOffsetX() const { - return window_icon_ ? - window_icon_->bounds().right() + kTitleIconOffsetX : - kTitleNoIconOffsetX; -} - -int HeaderPainter::GetCaptionButtonContainerCenterY() const { - return caption_button_container_->y() + - caption_button_container_->height() / 2; -} - -int HeaderPainter::GetHeaderCornerRadius() const { - bool square_corners = (frame_->IsMaximized() || frame_->IsFullscreen()); - const int kCornerRadius = 2; - return square_corners ? 0 : kCornerRadius; -} - -gfx::Rect HeaderPainter::GetTitleBounds(const gfx::FontList& title_font_list) { - int title_x = GetTitleOffsetX(); - // Center the text with respect to the caption button container. This way it - // adapts to the caption button height and aligns exactly with the window - // icon. Don't use |window_icon_| for this computation as it may be NULL. - int title_y = - GetCaptionButtonContainerCenterY() - title_font_list.GetHeight() / 2; - return gfx::Rect( - title_x, - std::max(0, title_y), - std::max(0, caption_button_container_->x() - kTitleLogoSpacing - title_x), - title_font_list.GetHeight()); -} - -} // namespace ash diff --git a/ash/frame/header_painter.h b/ash/frame/header_painter.h index f4f8d36..c8c8015 100644 --- a/ash/frame/header_painter.h +++ b/ash/frame/header_painter.h @@ -6,181 +6,40 @@ #define ASH_FRAME_HEADER_PAINTER_H_ #include "ash/ash_export.h" -#include "base/basictypes.h" -#include "base/compiler_specific.h" // OVERRIDE -#include "base/gtest_prod_util.h" -#include "base/memory/scoped_ptr.h" -#include "ui/gfx/animation/animation_delegate.h" -#include "ui/gfx/geometry/rect.h" namespace gfx { class Canvas; -class FontList; -class ImageSkia; -class Point; -class Size; -class SlideAnimation; -} -namespace views { -class View; -class Widget; } namespace ash { -class FrameCaptionButtonContainerView; // Helper class for painting the window header. -class ASH_EXPORT HeaderPainter : public gfx::AnimationDelegate { +class ASH_EXPORT HeaderPainter { public: enum Mode { MODE_ACTIVE, MODE_INACTIVE }; - // TODO(pkotwicz): Move code related to "browser" windows out of ash. - enum Style { - // Header style used for browser windows. - STYLE_BROWSER, - - // Header style used for apps and miscellaneous windows (e.g. task manager). - STYLE_OTHER - }; - - HeaderPainter(); - virtual ~HeaderPainter(); - - // None of the parameters are owned. - void Init(Style style, - views::Widget* frame, - views::View* header_view, - views::View* window_icon, - FrameCaptionButtonContainerView* caption_button_container); - - // Returns the bounds of the client view for a window with |header_height| - // and |window_bounds|. The return value and |window_bounds| are in the - // views::NonClientView's coordinates. - static gfx::Rect GetBoundsForClientView(int header_height, - const gfx::Rect& window_bounds); - - // Returns the bounds of the window given |header_height| and |client_bounds|. - // The return value and |client_bounds| are in the views::NonClientView's - // coordinates. - static gfx::Rect GetWindowBoundsForClientBounds( - int header_height, - const gfx::Rect& client_bounds); - - // Determines the window HT* code at |point|. Returns HTNOWHERE if |point| is - // not within the top |header_height_| of |header_view_|. |point| is in the - // coordinates of |header_view_|'s widget. The client view must be hittested - // before calling this method because a browser's tabs are in the top - // |header_height_| of |header_view_|. - int NonClientHitTest(const gfx::Point& point) const; + virtual ~HeaderPainter() { + } // Returns the header's minimum width. - int GetMinimumHeaderWidth() const; - - // Returns the inset from the right edge. - int GetRightInset() const; - - // Returns the amount that the theme background should be inset. - int GetThemeBackgroundXInset() const; + virtual int GetMinimumHeaderWidth() const = 0; // Paints the header. - // |theme_frame_overlay_id| is 0 if no overlay image should be used. - // |mode| indicates whether the window should be painted as active. - void PaintHeader(gfx::Canvas* canvas, - Mode mode, - int theme_frame_id, - int theme_frame_overlay_id); - - // Paints the header/content separator line for non-browser windows. - void PaintHeaderContentSeparator(gfx::Canvas* canvas, Mode mode); + virtual void PaintHeader(gfx::Canvas* canvas, Mode mode) = 0; - // Returns size of the header/content separator line for non-browser windows - // in pixels. - int HeaderContentSeparatorSize() const; + // Performs layout for the header. + virtual void LayoutHeader() = 0; - // Paint the title bar, primarily the title string. - void PaintTitleBar(gfx::Canvas* canvas, const gfx::FontList& title_font_list); - - // Performs layout for the header based on |frame_|'s show state. - void LayoutHeader(); - - // Sets the height of the header. The height of the header affects painting, - // and non client hit tests. It does not affect layout. - void set_header_height(int header_height) { - header_height_ = header_height; - } - - // Returns the header height. - int header_height() const { - return header_height_; - } + // Gets / sets how much of the header is painted. This allows the tabstrip to + // affect the header height. This height does not affect LayoutHeader(). + virtual int GetHeaderHeightForPainting() const = 0; + virtual void SetHeaderHeightForPainting(int height_for_painting) = 0; // Schedule a re-paint of the entire title. - void SchedulePaintForTitle(const gfx::FontList& title_font_list); - - // Called when the browser theme changes. - void OnThemeChanged(); - - // Overridden from gfx::AnimationDelegate - virtual void AnimationProgressed(const gfx::Animation* animation) OVERRIDE; - - private: - FRIEND_TEST_ALL_PREFIXES(HeaderPainterTest, TitleIconAlignment); - - // Paints highlight around the edge of the header for restored browser - // windows. - void PaintHighlightForRestoredBrowserWindow(gfx::Canvas* canvas); - - // Paints highlight around the edge of the header for inactive restored - // non-browser windows. - void PaintHighlightForInactiveRestoredWindow(gfx::Canvas* canvas); - - // Updates the images used for the minimize, restore and close buttons. - void UpdateCaptionButtonImages(); - - // Returns the header bounds in the coordinates of |header_view_|. The header - // is assumed to be positioned at the top left corner of |header_view_| and to - // have the same width as |header_view_|. - gfx::Rect GetHeaderLocalBounds() const; - - // Returns the offset between window left edge and title string. - int GetTitleOffsetX() const; - - // Returns the vertical center of the caption button container in window - // coordinates. - int GetCaptionButtonContainerCenterY() const; - - // Returns the radius of the header's top corners. - int GetHeaderCornerRadius() const; - - // Get the bounds for the title. The provided |title_font_list| is used to - // determine the correct dimensions. - gfx::Rect GetTitleBounds(const gfx::FontList& title_font_list); - - Style style_; - - // Not owned - views::Widget* frame_; - views::View* header_view_; - views::View* window_icon_; // May be NULL. - FrameCaptionButtonContainerView* caption_button_container_; - - // The height of the header. - int header_height_; - - // Image ids and opacity last used for painting header. - int previous_theme_frame_id_; - int previous_theme_frame_overlay_id_; - - // Image ids and opacity we are crossfading from. - int crossfade_theme_frame_id_; - int crossfade_theme_frame_overlay_id_; - - scoped_ptr<gfx::SlideAnimation> crossfade_animation_; - - DISALLOW_COPY_AND_ASSIGN(HeaderPainter); + virtual void SchedulePaintForTitle() = 0; }; } // namespace ash diff --git a/ash/frame/header_painter_unittest.cc b/ash/frame/header_painter_unittest.cc deleted file mode 100644 index 91523d63..0000000 --- a/ash/frame/header_painter_unittest.cc +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 2013 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 "ash/frame/header_painter.h" - -#include "ash/frame/caption_buttons/frame_caption_button_container_view.h" -#include "ash/shell.h" -#include "ash/test/ash_test_base.h" -#include "ash/wm/window_state.h" -#include "base/memory/scoped_ptr.h" -#include "grit/ash_resources.h" -#include "ui/gfx/font_list.h" -#include "ui/views/widget/widget.h" -#include "ui/views/window/non_client_view.h" - -using ash::HeaderPainter; -using views::NonClientFrameView; -using views::Widget; - -namespace ash { - -class HeaderPainterTest : public ash::test::AshTestBase { - public: - // Creates a test widget that owns its native widget. - Widget* CreateTestWidget() { - Widget* widget = new Widget; - Widget::InitParams params; - params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; - params.context = CurrentContext(); - widget->Init(params); - return widget; - } -}; - -// Ensure the title text is vertically aligned with the window icon. -TEST_F(HeaderPainterTest, TitleIconAlignment) { - scoped_ptr<Widget> w(CreateTestWidget()); - ash::FrameCaptionButtonContainerView container(w.get(), - ash::FrameCaptionButtonContainerView::MINIMIZE_ALLOWED); - views::View window_icon; - window_icon.SetBounds(0, 0, 16, 16); - w->SetBounds(gfx::Rect(0, 0, 500, 500)); - w->Show(); - - gfx::FontList default_font_list; - - // 1) Non-browser windows. - HeaderPainter non_browser_painter; - non_browser_painter.Init(HeaderPainter::STYLE_OTHER, - w.get(), - w->non_client_view()->frame_view(), - &window_icon, - &container); - non_browser_painter.LayoutHeader(); - gfx::Rect non_browser_header_title_bounds = - non_browser_painter.GetTitleBounds(default_font_list); - EXPECT_EQ(window_icon.bounds().CenterPoint().y(), - non_browser_header_title_bounds.CenterPoint().y()); - - // 2) Non-maximized browser windows. - HeaderPainter browser_painter; - browser_painter.Init(HeaderPainter::STYLE_BROWSER, - w.get(), - w->non_client_view()->frame_view(), - &window_icon, - &container); - browser_painter.LayoutHeader(); - gfx::Rect browser_header_title_bounds = - browser_painter.GetTitleBounds(default_font_list); - EXPECT_EQ(window_icon.bounds().CenterPoint().y(), - browser_header_title_bounds.CenterPoint().y()); - - // 3) Maximized browser windows. - w->Maximize(); - browser_painter.LayoutHeader(); - gfx::Rect maximized_browser_header_title_bounds = - browser_painter.GetTitleBounds(default_font_list); - EXPECT_EQ(window_icon.bounds().CenterPoint().y(), - maximized_browser_header_title_bounds.CenterPoint().y()); -} - -} // namespace ash diff --git a/ash/frame/header_painter_util.cc b/ash/frame/header_painter_util.cc new file mode 100644 index 0000000..77123e6 --- /dev/null +++ b/ash/frame/header_painter_util.cc @@ -0,0 +1,107 @@ +// Copyright 2014 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 "ash/frame/header_painter_util.h" + +#include <algorithm> + +#include "ui/aura/window.h" +#include "ui/compositor/layer.h" +#include "ui/compositor/layer_animator.h" +#include "ui/gfx/font_list.h" +#include "ui/gfx/rect.h" +#include "ui/views/view.h" +#include "ui/views/widget/widget.h" + +namespace { + +// Radius of the header's top corners when the window is restored. +const int kTopCornerRadiusWhenRestored = 2; + +// Distance between left edge of the window and the header icon. +const int kIconXOffset = 9; + +// Height and width of header icon. +const int kIconSize = 16; + +// Space between the title text and the caption buttons. +const int kTitleCaptionButtonSpacing = 5; + +// Space between window icon and title text. +const int kTitleIconOffsetX = 5; + +// Space between window edge and title text, when there is no icon. +const int kTitleNoIconOffsetX = 8; + +// In the pre-Ash era the web content area had a frame along the left edge, so +// user-generated theme images for the new tab page assume they are shifted +// right relative to the header. Now that we have removed the left edge frame +// we need to copy the theme image for the window header from a few pixels +// inset to preserve alignment with the NTP image, or else we'll break a bunch +// of existing themes. We do something similar on OS X for the same reason. +const int kThemeFrameImageInsetX = 5; + +} // namespace + +namespace ash { + +// static +int HeaderPainterUtil::GetTopCornerRadiusWhenRestored() { + return kTopCornerRadiusWhenRestored; +} + +// static +int HeaderPainterUtil::GetIconXOffset() { + return kIconXOffset; +} + +// static +int HeaderPainterUtil::GetIconSize() { + return kIconSize; +} + +// static +int HeaderPainterUtil::GetThemeBackgroundXInset() { + return kThemeFrameImageInsetX; +} + +// static +gfx::Rect HeaderPainterUtil::GetTitleBounds( + const views::View* icon, + const views::View* caption_button_container, + const gfx::FontList& title_font_list) { + int x = icon ? + icon->bounds().right() + kTitleIconOffsetX : kTitleNoIconOffsetX; + int height = title_font_list.GetHeight(); + int y = std::max( + 0, + static_cast<int>(std::ceil( + (caption_button_container->height() - height) / 2.0f))); + int width = std::max( + 0, caption_button_container->x() - kTitleCaptionButtonSpacing - x); + return gfx::Rect(x, y, width, height); +} + +// static +bool HeaderPainterUtil::CanAnimateActivation(views::Widget* widget) { + // Do not animate the header if the parent (e.g. + // kShellWindowId_DefaultContainer) is already animating. All of the + // implementers of HeaderPainter animate activation by continuously painting + // during the animation. This gives the parent's animation a slower frame + // rate. + // TODO(sky): Expose a better way to determine this rather than assuming the + // parent is a toplevel container. + aura::Window* window = widget->GetNativeWindow(); + if (!window->parent()) + return true; + + ui::LayerAnimator* parent_layer_animator = + window->parent()->layer()->GetAnimator(); + return !parent_layer_animator->IsAnimatingProperty( + ui::LayerAnimationElement::OPACITY) && + !parent_layer_animator->IsAnimatingProperty( + ui::LayerAnimationElement::VISIBILITY); +} + +} // namespace ash diff --git a/ash/frame/header_painter_util.h b/ash/frame/header_painter_util.h new file mode 100644 index 0000000..468184a --- /dev/null +++ b/ash/frame/header_painter_util.h @@ -0,0 +1,58 @@ +// Copyright 2014 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 ASH_FRAME_HEADER_PAINTER_UTIL_H_ +#define ASH_FRAME_HEADER_PAINTER_UTIL_H_ + +#include "ash/ash_export.h" +#include "base/macros.h" + +namespace gfx { +class FontList; +class Rect; +} +namespace views { +class View; +class Widget; +} + +namespace ash { + +// Static-only helper class for functionality used accross multiple +// implementations of HeaderPainter. +class ASH_EXPORT HeaderPainterUtil { + public: + // Returns the radius of the header's corners when the window is restored. + static int GetTopCornerRadiusWhenRestored(); + + // Returns the distance between the left edge of the window and the header + // icon. + static int GetIconXOffset(); + + // Returns the size of the header icon. + static int GetIconSize(); + + // Returns the amount that the frame background is inset from the left edge of + // the window. + static int GetThemeBackgroundXInset(); + + // Returns the bounds for the header's title given the header icon, the + // caption button container and the font used. + // |icon| should be NULL if the header does not use an icon. + static gfx::Rect GetTitleBounds(const views::View* icon, + const views::View* caption_button_container, + const gfx::FontList& title_font_list); + + // Returns true if the header for |widget| can animate to new visuals when the + // widget's activation changes. Returns false if the header should switch to + // new visuals instantaneously. + static bool CanAnimateActivation(views::Widget* widget); + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(HeaderPainterUtil); +}; + +} // namespace ash + +#endif // ASH_FRAME_HEADER_PAINTER_UTIL_H_ diff --git a/ash/wm/panels/panel_frame_view.cc b/ash/wm/panels/panel_frame_view.cc index 9188dc8..210435e 100644 --- a/ash/wm/panels/panel_frame_view.cc +++ b/ash/wm/panels/panel_frame_view.cc @@ -5,14 +5,13 @@ #include "ash/wm/panels/panel_frame_view.h" #include "ash/frame/caption_buttons/frame_caption_button_container_view.h" +#include "ash/frame/default_header_painter.h" #include "ash/frame/frame_border_hit_test_controller.h" -#include "ash/frame/header_painter.h" #include "grit/ash_resources.h" #include "ui/base/hit_test.h" #include "ui/base/l10n/l10n_util.h" #include "ui/gfx/canvas.h" #include "ui/views/controls/image_view.h" -#include "ui/views/widget/native_widget_aura.h" #include "ui/views/widget/widget.h" #include "ui/views/widget/widget_delegate.h" @@ -25,7 +24,6 @@ PanelFrameView::PanelFrameView(views::Widget* frame, FrameType frame_type) : frame_(frame), caption_button_container_(NULL), window_icon_(NULL), - title_font_list_(views::NativeWidgetAura::GetWindowTitleFontList()), frame_border_hit_test_controller_( new FrameBorderHitTestController(frame_)) { DCHECK(!frame_->widget_delegate()->CanMaximize()); @@ -41,7 +39,7 @@ const char* PanelFrameView::GetClassName() const { } void PanelFrameView::InitHeaderPainter() { - header_painter_.reset(new HeaderPainter); + header_painter_.reset(new DefaultHeaderPainter); caption_button_container_ = new FrameCaptionButtonContainerView(frame_, FrameCaptionButtonContainerView::MINIMIZE_ALLOWED); @@ -52,16 +50,13 @@ void PanelFrameView::InitHeaderPainter() { AddChildView(window_icon_); } - header_painter_->Init(HeaderPainter::STYLE_OTHER, frame_, this, window_icon_, - caption_button_container_); + header_painter_->Init(frame_, this, window_icon_, caption_button_container_); } int PanelFrameView::NonClientTopBorderHeight() const { if (!header_painter_) return 0; - // Reserve enough space to see the buttons and the separator line. - return caption_button_container_->bounds().bottom() + - header_painter_->HeaderContentSeparatorSize(); + return header_painter_->GetHeaderHeightForPainting(); } gfx::Size PanelFrameView::GetMinimumSize() { @@ -78,7 +73,6 @@ void PanelFrameView::Layout() { if (!header_painter_) return; header_painter_->LayoutHeader(); - header_painter_->set_header_height(NonClientTopBorderHeight()); } void PanelFrameView::GetWindowMask(const gfx::Size&, gfx::Path*) { @@ -101,14 +95,14 @@ void PanelFrameView::UpdateWindowIcon() { void PanelFrameView::UpdateWindowTitle() { if (!header_painter_) return; - header_painter_->SchedulePaintForTitle(title_font_list_); + header_painter_->SchedulePaintForTitle(); } int PanelFrameView::NonClientHitTest(const gfx::Point& point) { if (!header_painter_) return HTNOWHERE; return FrameBorderHitTestController::NonClientHitTest(this, - header_painter_.get(), point); + caption_button_container_, point); } void PanelFrameView::OnPaint(gfx::Canvas* canvas) { @@ -117,32 +111,22 @@ void PanelFrameView::OnPaint(gfx::Canvas* canvas) { bool paint_as_active = ShouldPaintAsActive(); caption_button_container_->SetPaintAsActive(paint_as_active); - int theme_frame_id = 0; - if (paint_as_active) - theme_frame_id = IDR_AURA_WINDOW_HEADER_BASE_ACTIVE; - else - theme_frame_id = IDR_AURA_WINDOW_HEADER_BASE_INACTIVE; - HeaderPainter::Mode header_mode = paint_as_active ? HeaderPainter::MODE_ACTIVE : HeaderPainter::MODE_INACTIVE; - header_painter_->PaintHeader(canvas, header_mode, theme_frame_id, 0); - header_painter_->PaintTitleBar(canvas, title_font_list_); - header_painter_->PaintHeaderContentSeparator(canvas, header_mode); + header_painter_->PaintHeader(canvas, header_mode); } gfx::Rect PanelFrameView::GetBoundsForClientView() const { - if (!header_painter_) - return bounds(); - return HeaderPainter::GetBoundsForClientView( - NonClientTopBorderHeight(), bounds()); + gfx::Rect client_bounds = bounds(); + client_bounds.Inset(0, NonClientTopBorderHeight(), 0, 0); + return client_bounds; } gfx::Rect PanelFrameView::GetWindowBoundsForClientBounds( const gfx::Rect& client_bounds) const { - if (!header_painter_) - return client_bounds; - return HeaderPainter::GetWindowBoundsForClientBounds( - NonClientTopBorderHeight(), client_bounds); + gfx::Rect window_bounds = client_bounds; + window_bounds.Inset(0, -NonClientTopBorderHeight(), 0, 0); + return window_bounds; } } // namespace ash diff --git a/ash/wm/panels/panel_frame_view.h b/ash/wm/panels/panel_frame_view.h index 3bad676..6ab0cba 100644 --- a/ash/wm/panels/panel_frame_view.h +++ b/ash/wm/panels/panel_frame_view.h @@ -7,7 +7,6 @@ #include "ash/ash_export.h" #include "base/basictypes.h" -#include "ui/gfx/font_list.h" #include "ui/views/window/non_client_view.h" namespace views { @@ -15,10 +14,9 @@ class ImageView; } namespace ash { - +class DefaultHeaderPainter; class FrameCaptionButtonContainerView; class FrameBorderHitTestController; -class HeaderPainter; class ASH_EXPORT PanelFrameView : public views::NonClientFrameView { public: @@ -64,10 +62,9 @@ class ASH_EXPORT PanelFrameView : public views::NonClientFrameView { FrameCaptionButtonContainerView* caption_button_container_; views::ImageView* window_icon_; gfx::Rect client_view_bounds_; - const gfx::FontList title_font_list_; // Helper class for painting the header. - scoped_ptr<HeaderPainter> header_painter_; + scoped_ptr<DefaultHeaderPainter> header_painter_; // Updates the hittest bounds overrides based on the window state type. scoped_ptr<FrameBorderHitTestController> frame_border_hit_test_controller_; diff --git a/chrome/browser/ui/views/frame/browser_header_painter_ash.cc b/chrome/browser/ui/views/frame/browser_header_painter_ash.cc new file mode 100644 index 0000000..34ee202 --- /dev/null +++ b/chrome/browser/ui/views/frame/browser_header_painter_ash.cc @@ -0,0 +1,474 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/views/frame/browser_header_painter_ash.h" + +#include "ash/frame/caption_buttons/frame_caption_button_container_view.h" +#include "ash/frame/header_painter_util.h" +#include "base/logging.h" // DCHECK +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/views/frame/browser_frame.h" +#include "chrome/browser/ui/views/frame/browser_view.h" +#include "grit/ash_resources.h" +#include "grit/theme_resources.h" +#include "third_party/skia/include/core/SkCanvas.h" +#include "third_party/skia/include/core/SkColor.h" +#include "third_party/skia/include/core/SkPaint.h" +#include "third_party/skia/include/core/SkPath.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/base/theme_provider.h" +#include "ui/gfx/animation/slide_animation.h" +#include "ui/gfx/canvas.h" +#include "ui/gfx/image/image_skia.h" +#include "ui/gfx/rect.h" +#include "ui/gfx/skia_util.h" +#include "ui/views/view.h" +#include "ui/views/widget/widget.h" +#include "ui/views/widget/widget_delegate.h" + +using views::Widget; + +namespace { +// Color for the restored window title text. +const SkColor kRestoredWindowTitleTextColor = SkColorSetRGB(40, 40, 40); +// Color for the maximized window title text. +const SkColor kMaximizedWindowTitleTextColor = SK_ColorWHITE; +// Duration of crossfade animation for activating and deactivating frame. +const int kActivationCrossfadeDurationMs = 200; + +// Tiles an image into an area, rounding the top corners. Samples |image| +// starting |image_inset_x| pixels from the left of the image. +void TileRoundRect(gfx::Canvas* canvas, + const gfx::ImageSkia& image, + const SkPaint& paint, + const gfx::Rect& bounds, + int top_left_corner_radius, + int top_right_corner_radius, + int image_inset_x) { + SkRect rect = gfx::RectToSkRect(bounds); + const SkScalar kTopLeftRadius = SkIntToScalar(top_left_corner_radius); + const SkScalar kTopRightRadius = SkIntToScalar(top_right_corner_radius); + SkScalar radii[8] = { + kTopLeftRadius, kTopLeftRadius, // top-left + kTopRightRadius, kTopRightRadius, // top-right + 0, 0, // bottom-right + 0, 0}; // bottom-left + SkPath path; + path.addRoundRect(rect, radii, SkPath::kCW_Direction); + canvas->DrawImageInPath(image, -image_inset_x, 0, path, paint); +} + +// Tiles |frame_image| and |frame_overlay_image| into an area, rounding the top +// corners. +void PaintFrameImagesInRoundRect(gfx::Canvas* canvas, + const gfx::ImageSkia& frame_image, + const gfx::ImageSkia& frame_overlay_image, + const SkPaint& paint, + const gfx::Rect& bounds, + int corner_radius, + int image_inset_x) { + SkXfermode::Mode normal_mode; + SkXfermode::AsMode(NULL, &normal_mode); + + // If |paint| is using an unusual SkXfermode::Mode (this is the case while + // crossfading), we must create a new canvas to overlay |frame_image| and + // |frame_overlay_image| using |normal_mode| and then paint the result + // using the unusual mode. We try to avoid this because creating a new + // browser-width canvas is expensive. + bool fast_path = (frame_overlay_image.isNull() || + SkXfermode::IsMode(paint.getXfermode(), normal_mode)); + if (fast_path) { + TileRoundRect(canvas, frame_image, paint, bounds, corner_radius, + corner_radius, image_inset_x); + + if (!frame_overlay_image.isNull()) { + // Adjust |bounds| such that |frame_overlay_image| is not tiled. + gfx::Rect overlay_bounds = bounds; + overlay_bounds.Intersect( + gfx::Rect(bounds.origin(), frame_overlay_image.size())); + int top_left_corner_radius = corner_radius; + int top_right_corner_radius = corner_radius; + if (overlay_bounds.width() < bounds.width() - corner_radius) + top_right_corner_radius = 0; + TileRoundRect(canvas, frame_overlay_image, paint, overlay_bounds, + top_left_corner_radius, top_right_corner_radius, 0); + } + } else { + gfx::Canvas temporary_canvas(bounds.size(), canvas->image_scale(), false); + temporary_canvas.TileImageInt(frame_image, + image_inset_x, 0, + 0, 0, + bounds.width(), bounds.height()); + temporary_canvas.DrawImageInt(frame_overlay_image, 0, 0); + TileRoundRect(canvas, gfx::ImageSkia(temporary_canvas.ExtractImageRep()), + paint, bounds, corner_radius, corner_radius, 0); + } +} + +} // namespace + +/////////////////////////////////////////////////////////////////////////////// +// BrowserHeaderPainterAsh, public: + +BrowserHeaderPainterAsh::BrowserHeaderPainterAsh() + : frame_(NULL), + is_tabbed_(false), + is_incognito_(false), + view_(NULL), + window_icon_(NULL), + caption_button_container_(NULL), + painted_height_(0), + initial_paint_(true), + mode_(MODE_INACTIVE), + activation_animation_(new gfx::SlideAnimation(this)) { +} + +BrowserHeaderPainterAsh::~BrowserHeaderPainterAsh() { +} + +void BrowserHeaderPainterAsh::Init( + views::Widget* frame, + BrowserView* browser_view, + views::View* header_view, + views::View* window_icon, + ash::FrameCaptionButtonContainerView* caption_button_container) { + DCHECK(frame); + DCHECK(browser_view); + DCHECK(header_view); + // window_icon may be NULL. + DCHECK(caption_button_container); + frame_ = frame; + + is_tabbed_ = browser_view->browser()->is_type_tabbed(); + is_incognito_ = !browser_view->IsRegularOrGuestSession(); + + view_ = header_view; + window_icon_ = window_icon; + caption_button_container_ = caption_button_container; +} + +int BrowserHeaderPainterAsh::GetMinimumHeaderWidth() const { + // Ensure we have enough space for the window icon and buttons. We allow + // the title string to collapse to zero width. + return GetTitleBounds().x() + + caption_button_container_->GetMinimumSize().width(); +} + +void BrowserHeaderPainterAsh::PaintHeader(gfx::Canvas* canvas, Mode mode) { + Mode old_mode = mode_; + mode_ = mode; + + if (mode_ != old_mode) { + if (!initial_paint_ && + ash::HeaderPainterUtil::CanAnimateActivation(frame_)) { + activation_animation_->SetSlideDuration(kActivationCrossfadeDurationMs); + if (mode_ == MODE_ACTIVE) + activation_animation_->Show(); + else + activation_animation_->Hide(); + } else { + if (mode_ == MODE_ACTIVE) + activation_animation_->Reset(1); + else + activation_animation_->Reset(0); + } + initial_paint_ = false; + } + + int corner_radius = (frame_->IsMaximized() || frame_->IsFullscreen()) ? + 0 : ash::HeaderPainterUtil::GetTopCornerRadiusWhenRestored(); + + int active_alpha = activation_animation_->CurrentValueBetween(0, 255); + int inactive_alpha = 255 - active_alpha; + + SkPaint paint; + if (inactive_alpha > 0) { + if (active_alpha > 0) + paint.setXfermodeMode(SkXfermode::kPlus_Mode); + + gfx::ImageSkia inactive_frame_image; + gfx::ImageSkia inactive_frame_overlay_image; + GetFrameImages(MODE_INACTIVE, &inactive_frame_image, + &inactive_frame_overlay_image); + + paint.setAlpha(inactive_alpha); + PaintFrameImagesInRoundRect( + canvas, + inactive_frame_image, + inactive_frame_overlay_image, + paint, + GetPaintedBounds(), + corner_radius, + ash::HeaderPainterUtil::GetThemeBackgroundXInset()); + } + + if (active_alpha > 0) { + gfx::ImageSkia active_frame_image; + gfx::ImageSkia active_frame_overlay_image; + GetFrameImages(MODE_ACTIVE, &active_frame_image, + &active_frame_overlay_image); + + paint.setAlpha(active_alpha); + PaintFrameImagesInRoundRect( + canvas, + active_frame_image, + active_frame_overlay_image, + paint, + GetPaintedBounds(), + corner_radius, + ash::HeaderPainterUtil::GetThemeBackgroundXInset()); + } + + if (!frame_->IsMaximized() && !frame_->IsFullscreen()) + PaintHighlightForRestoredWindow(canvas); + if (frame_->widget_delegate() && + frame_->widget_delegate()->ShouldShowWindowTitle()) { + PaintTitleBar(canvas); + } +} + +void BrowserHeaderPainterAsh::LayoutHeader() { + // Purposefully set |painted_height_| to an invalid value. We cannot use + // |painted_height_| because the computation of |painted_height_| may depend + // on having laid out the window controls. + painted_height_ = -1; + + UpdateCaptionButtonImages(); + caption_button_container_->Layout(); + + gfx::Size caption_button_container_size = + caption_button_container_->GetPreferredSize(); + caption_button_container_->SetBounds( + view_->width() - caption_button_container_size.width(), + 0, + caption_button_container_size.width(), + caption_button_container_size.height()); + + if (window_icon_) { + // Vertically center the window icon with respect to the caption button + // container. + int icon_size = ash::HeaderPainterUtil::GetIconSize(); + int icon_offset_y = (caption_button_container_->height() - icon_size) / 2; + window_icon_->SetBounds(ash::HeaderPainterUtil::GetIconXOffset(), + icon_offset_y, icon_size, icon_size); + } +} + +int BrowserHeaderPainterAsh::GetHeaderHeightForPainting() const { + return painted_height_; +} + +void BrowserHeaderPainterAsh::SetHeaderHeightForPainting(int height) { + painted_height_ = height; +} + +void BrowserHeaderPainterAsh::SchedulePaintForTitle() { + view_->SchedulePaintInRect(GetTitleBounds()); +} + +/////////////////////////////////////////////////////////////////////////////// +// gfx::AnimationDelegate overrides: + +void BrowserHeaderPainterAsh::AnimationProgressed( + const gfx::Animation* animation) { + view_->SchedulePaintInRect(GetPaintedBounds()); +} + +/////////////////////////////////////////////////////////////////////////////// +// BrowserHeaderPainterAsh, private: + +void BrowserHeaderPainterAsh::PaintHighlightForRestoredWindow( + gfx::Canvas* canvas) { + ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); + gfx::ImageSkia top_left_corner = *rb.GetImageSkiaNamed( + IDR_AURA_BROWSER_WINDOW_HEADER_SHADE_TOP_LEFT); + gfx::ImageSkia top_right_corner = *rb.GetImageSkiaNamed( + IDR_AURA_BROWSER_WINDOW_HEADER_SHADE_TOP_RIGHT); + gfx::ImageSkia top_edge = *rb.GetImageSkiaNamed( + IDR_AURA_BROWSER_WINDOW_HEADER_SHADE_TOP); + gfx::ImageSkia left_edge = *rb.GetImageSkiaNamed( + IDR_AURA_BROWSER_WINDOW_HEADER_SHADE_LEFT); + gfx::ImageSkia right_edge = *rb.GetImageSkiaNamed( + IDR_AURA_BROWSER_WINDOW_HEADER_SHADE_RIGHT); + + int top_left_width = top_left_corner.width(); + int top_left_height = top_left_corner.height(); + canvas->DrawImageInt(top_left_corner, 0, 0); + + int top_right_width = top_right_corner.width(); + int top_right_height = top_right_corner.height(); + canvas->DrawImageInt(top_right_corner, + view_->width() - top_right_width, + 0); + + canvas->TileImageInt( + top_edge, + top_left_width, + 0, + view_->width() - top_left_width - top_right_width, + top_edge.height()); + + canvas->TileImageInt(left_edge, + 0, + top_left_height, + left_edge.width(), + painted_height_ - top_left_height); + + canvas->TileImageInt(right_edge, + view_->width() - right_edge.width(), + top_right_height, + right_edge.width(), + painted_height_ - top_right_height); +} + +void BrowserHeaderPainterAsh::PaintTitleBar(gfx::Canvas* canvas) { + // The window icon is painted by its own views::View. + gfx::Rect title_bounds = GetTitleBounds(); + title_bounds.set_x(view_->GetMirroredXForRect(title_bounds)); + SkColor title_color = (frame_->IsMaximized() || frame_->IsFullscreen()) ? + kMaximizedWindowTitleTextColor : kRestoredWindowTitleTextColor; + canvas->DrawStringRectWithFlags(frame_->widget_delegate()->GetWindowTitle(), + BrowserFrame::GetTitleFontList(), + title_color, + title_bounds, + gfx::Canvas::NO_SUBPIXEL_RENDERING); +} + +void BrowserHeaderPainterAsh::GetFrameImages( + Mode mode, + gfx::ImageSkia* frame_image, + gfx::ImageSkia* frame_overlay_image) const { + if (is_tabbed_) { + GetFrameImagesForTabbedBrowser(mode, frame_image, frame_overlay_image); + } else { + *frame_image = GetFrameImageForNonTabbedBrowser(mode); + *frame_overlay_image = gfx::ImageSkia(); + } +} + +void BrowserHeaderPainterAsh::GetFrameImagesForTabbedBrowser( + Mode mode, + gfx::ImageSkia* frame_image, + gfx::ImageSkia* frame_overlay_image) const { + int frame_image_id = 0; + int frame_overlay_image_id = 0; + + ui::ThemeProvider* tp = frame_->GetThemeProvider(); + if (tp->HasCustomImage(IDR_THEME_FRAME_OVERLAY) && !is_incognito_) { + frame_overlay_image_id = (mode == MODE_ACTIVE) ? + IDR_THEME_FRAME_OVERLAY : IDR_THEME_FRAME_OVERLAY_INACTIVE; + } + + if (mode == MODE_ACTIVE) { + frame_image_id = is_incognito_ ? + IDR_THEME_FRAME_INCOGNITO : IDR_THEME_FRAME; + } else { + frame_image_id = is_incognito_ ? + IDR_THEME_FRAME_INCOGNITO_INACTIVE : IDR_THEME_FRAME_INACTIVE; + } + + if ((frame_->IsMaximized() || frame_->IsFullscreen()) && + !tp->HasCustomImage(IDR_THEME_FRAME) && + !tp->HasCustomImage(frame_image_id) && + frame_overlay_image_id == 0) { + *frame_image = *tp->GetImageSkiaNamed( + IDR_AURA_BROWSER_WINDOW_HEADER_BASE_MAXIMIZED); + } else { + *frame_image = *tp->GetImageSkiaNamed(frame_image_id); + } + + *frame_overlay_image = (frame_overlay_image_id == 0) ? + gfx::ImageSkia() : *tp->GetImageSkiaNamed(frame_overlay_image_id); +} + +gfx::ImageSkia BrowserHeaderPainterAsh::GetFrameImageForNonTabbedBrowser( + Mode mode) const { + ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); + if (frame_->IsMaximized() || frame_->IsFullscreen()) + return *rb.GetImageSkiaNamed(IDR_AURA_BROWSER_WINDOW_HEADER_BASE_MAXIMIZED); + + if (mode == MODE_ACTIVE) { + return *rb.GetImageSkiaNamed(is_incognito_ ? + IDR_AURA_BROWSER_WINDOW_HEADER_BASE_RESTORED_INCOGNITO_ACTIVE : + IDR_AURA_BROWSER_WINDOW_HEADER_BASE_RESTORED_ACTIVE); + } + return *rb.GetImageSkiaNamed(is_incognito_ ? + IDR_AURA_BROWSER_WINDOW_HEADER_BASE_RESTORED_INCOGNITO_INACTIVE : + IDR_AURA_BROWSER_WINDOW_HEADER_BASE_RESTORED_INACTIVE); +} + +void BrowserHeaderPainterAsh::UpdateCaptionButtonImages() { + if (frame_->IsMaximized() || frame_->IsFullscreen()) { + caption_button_container_->SetButtonImages( + ash::CAPTION_BUTTON_ICON_MINIMIZE, + IDR_AURA_BROWSER_WINDOW_CONTROL_ICON_MAXIMIZED_MINIMIZE, + IDR_AURA_BROWSER_WINDOW_CONTROL_ICON_MAXIMIZED_MINIMIZE, + IDR_AURA_BROWSER_WINDOW_CONTROL_BACKGROUND_MAXIMIZED_H, + IDR_AURA_BROWSER_WINDOW_CONTROL_BACKGROUND_MAXIMIZED_P); + caption_button_container_->SetButtonImages( + ash::CAPTION_BUTTON_ICON_MAXIMIZE_RESTORE, + IDR_AURA_BROWSER_WINDOW_CONTROL_ICON_MAXIMIZED_SIZE, + IDR_AURA_BROWSER_WINDOW_CONTROL_ICON_MAXIMIZED_SIZE, + IDR_AURA_BROWSER_WINDOW_CONTROL_BACKGROUND_MAXIMIZED_H, + IDR_AURA_BROWSER_WINDOW_CONTROL_BACKGROUND_MAXIMIZED_P); + caption_button_container_->SetButtonImages( + ash::CAPTION_BUTTON_ICON_CLOSE, + IDR_AURA_BROWSER_WINDOW_CONTROL_ICON_MAXIMIZED_CLOSE, + IDR_AURA_BROWSER_WINDOW_CONTROL_ICON_MAXIMIZED_CLOSE, + IDR_AURA_BROWSER_WINDOW_CONTROL_BACKGROUND_MAXIMIZED_H, + IDR_AURA_BROWSER_WINDOW_CONTROL_BACKGROUND_MAXIMIZED_P); + caption_button_container_->SetButtonImages( + ash::CAPTION_BUTTON_ICON_LEFT_SNAPPED, + IDR_AURA_BROWSER_WINDOW_CONTROL_ICON_MAXIMIZED_LEFT_SNAPPED, + IDR_AURA_BROWSER_WINDOW_CONTROL_ICON_MAXIMIZED_LEFT_SNAPPED, + IDR_AURA_BROWSER_WINDOW_CONTROL_BACKGROUND_MAXIMIZED_H, + IDR_AURA_BROWSER_WINDOW_CONTROL_BACKGROUND_MAXIMIZED_P); + caption_button_container_->SetButtonImages( + ash::CAPTION_BUTTON_ICON_RIGHT_SNAPPED, + IDR_AURA_BROWSER_WINDOW_CONTROL_ICON_MAXIMIZED_RIGHT_SNAPPED, + IDR_AURA_BROWSER_WINDOW_CONTROL_ICON_MAXIMIZED_RIGHT_SNAPPED, + IDR_AURA_BROWSER_WINDOW_CONTROL_BACKGROUND_MAXIMIZED_H, + IDR_AURA_BROWSER_WINDOW_CONTROL_BACKGROUND_MAXIMIZED_P); + } else { + caption_button_container_->SetButtonImages( + ash::CAPTION_BUTTON_ICON_MINIMIZE, + IDR_AURA_BROWSER_WINDOW_CONTROL_ICON_RESTORED_MINIMIZE, + IDR_AURA_BROWSER_WINDOW_CONTROL_ICON_RESTORED_MINIMIZE, + IDR_AURA_BROWSER_WINDOW_CONTROL_BACKGROUND_RESTORED_H, + IDR_AURA_BROWSER_WINDOW_CONTROL_BACKGROUND_RESTORED_P); + caption_button_container_->SetButtonImages( + ash::CAPTION_BUTTON_ICON_MAXIMIZE_RESTORE, + IDR_AURA_BROWSER_WINDOW_CONTROL_ICON_RESTORED_SIZE, + IDR_AURA_BROWSER_WINDOW_CONTROL_ICON_RESTORED_SIZE, + IDR_AURA_BROWSER_WINDOW_CONTROL_BACKGROUND_RESTORED_H, + IDR_AURA_BROWSER_WINDOW_CONTROL_BACKGROUND_RESTORED_P); + caption_button_container_->SetButtonImages( + ash::CAPTION_BUTTON_ICON_CLOSE, + IDR_AURA_BROWSER_WINDOW_CONTROL_ICON_RESTORED_CLOSE, + IDR_AURA_BROWSER_WINDOW_CONTROL_ICON_RESTORED_CLOSE, + IDR_AURA_BROWSER_WINDOW_CONTROL_BACKGROUND_RESTORED_H, + IDR_AURA_BROWSER_WINDOW_CONTROL_BACKGROUND_RESTORED_P); + caption_button_container_->SetButtonImages( + ash::CAPTION_BUTTON_ICON_LEFT_SNAPPED, + IDR_AURA_BROWSER_WINDOW_CONTROL_ICON_RESTORED_LEFT_SNAPPED, + IDR_AURA_BROWSER_WINDOW_CONTROL_ICON_RESTORED_LEFT_SNAPPED, + IDR_AURA_BROWSER_WINDOW_CONTROL_BACKGROUND_RESTORED_H, + IDR_AURA_BROWSER_WINDOW_CONTROL_BACKGROUND_RESTORED_P); + caption_button_container_->SetButtonImages( + ash::CAPTION_BUTTON_ICON_RIGHT_SNAPPED, + IDR_AURA_BROWSER_WINDOW_CONTROL_ICON_RESTORED_RIGHT_SNAPPED, + IDR_AURA_BROWSER_WINDOW_CONTROL_ICON_RESTORED_RIGHT_SNAPPED, + IDR_AURA_BROWSER_WINDOW_CONTROL_BACKGROUND_RESTORED_H, + IDR_AURA_BROWSER_WINDOW_CONTROL_BACKGROUND_RESTORED_P); + } +} + +gfx::Rect BrowserHeaderPainterAsh::GetPaintedBounds() const { + return gfx::Rect(view_->width(), painted_height_); +} + +gfx::Rect BrowserHeaderPainterAsh::GetTitleBounds() const { + return ash::HeaderPainterUtil::GetTitleBounds(window_icon_, + caption_button_container_, BrowserFrame::GetTitleFontList()); +} diff --git a/chrome/browser/ui/views/frame/browser_header_painter_ash.h b/chrome/browser/ui/views/frame/browser_header_painter_ash.h new file mode 100644 index 0000000..fbc4302 --- /dev/null +++ b/chrome/browser/ui/views/frame/browser_header_painter_ash.h @@ -0,0 +1,119 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_VIEWS_FRAME_BROWSER_HEADER_PAINTER_ASH_H_ +#define CHROME_BROWSER_UI_VIEWS_FRAME_BROWSER_HEADER_PAINTER_ASH_H_ + +#include "ash/frame/header_painter.h" +#include "base/basictypes.h" +#include "base/compiler_specific.h" // OVERRIDE +#include "base/memory/scoped_ptr.h" +#include "ui/gfx/animation/animation_delegate.h" + +class BrowserView; + +namespace ash { +class FrameCaptionButtonContainerView; +} + +namespace gfx { +class ImageSkia; +class Rect; +class SlideAnimation; +} +namespace views { +class View; +class Widget; +} + +// Helper class for painting the browser window header. +class BrowserHeaderPainterAsh : public ash::HeaderPainter, + public gfx::AnimationDelegate { + public: + BrowserHeaderPainterAsh(); + virtual ~BrowserHeaderPainterAsh(); + + // BrowserHeaderPainterAsh does not take ownership of any of the parameters. + void Init( + views::Widget* frame, + BrowserView* browser_view, + views::View* header_view, + views::View* window_icon, + ash::FrameCaptionButtonContainerView* caption_button_container); + + // ash::HeaderPainter overrides: + virtual int GetMinimumHeaderWidth() const OVERRIDE; + virtual void PaintHeader(gfx::Canvas* canvas, Mode mode) OVERRIDE; + virtual void LayoutHeader() OVERRIDE; + virtual int GetHeaderHeightForPainting() const OVERRIDE; + virtual void SetHeaderHeightForPainting(int height) OVERRIDE; + virtual void SchedulePaintForTitle() OVERRIDE; + + private: + // gfx::AnimationDelegate override: + virtual void AnimationProgressed(const gfx::Animation* animation) OVERRIDE; + + // Paints highlight around the edge of the header for restored windows. + void PaintHighlightForRestoredWindow(gfx::Canvas* canvas); + + // Paints the title bar, primarily the title string. + void PaintTitleBar(gfx::Canvas* canvas); + + // Sets |frame_image| and |frame_overlay_image| to the frame image and the + // frame overlay image respectivately which should be used to paint the + // header. + void GetFrameImages(Mode mode, + gfx::ImageSkia* frame_image, + gfx::ImageSkia* frame_overlay_image) const; + + // Sets |frame_image| and |frame_overlay_image| to the frame image and the + // frame overlay image respectively that should be used to paint the header + // for tabbed browser windows. + void GetFrameImagesForTabbedBrowser( + Mode mode, + gfx::ImageSkia* frame_image, + gfx::ImageSkia* frame_overlay_image) const; + + // Returns the frame image which should be used to paint the header for popup + // browser windows and for hosted app windows which show the toolbar. + gfx::ImageSkia GetFrameImageForNonTabbedBrowser(Mode mode) const; + + // Updates the images used for the minimize, restore and close buttons. + void UpdateCaptionButtonImages(); + + // Returns bounds of the region in |view_| which is painted with the header + // images. The region is assumed to start at the top left corner of |view_| + // and to have the same width as |view_|. + gfx::Rect GetPaintedBounds() const; + + // Returns the bounds for the title. + gfx::Rect GetTitleBounds() const; + + views::Widget* frame_; + + // Whether the header is for a tabbed browser window. + bool is_tabbed_; + + // Whether the header is for an incognito browser window. + bool is_incognito_; + + // The header view. + views::View* view_; + + views::View* window_icon_; + ash::FrameCaptionButtonContainerView* caption_button_container_; + int painted_height_; + + // Whether the header is painted for the first time. + bool initial_paint_; + + // Whether the header should be painted as active. + Mode mode_; + + scoped_ptr<gfx::SlideAnimation> activation_animation_; + + DISALLOW_COPY_AND_ASSIGN(BrowserHeaderPainterAsh); +}; + +#endif // CHROME_BROWSER_UI_VIEWS_FRAME_BROWSER_HEADER_PAINTER_ASH_H_ diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc index c4fc2e8..0a42acb 100644 --- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc +++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc @@ -6,14 +6,16 @@ #include "ash/ash_switches.h" #include "ash/frame/caption_buttons/frame_caption_button_container_view.h" +#include "ash/frame/default_header_painter.h" #include "ash/frame/frame_border_hit_test_controller.h" -#include "ash/frame/header_painter.h" +#include "ash/frame/header_painter_util.h" #include "base/command_line.h" #include "chrome/browser/themes/theme_properties.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/views/avatar_label.h" #include "chrome/browser/ui/views/avatar_menu_button.h" #include "chrome/browser/ui/views/frame/browser_frame.h" +#include "chrome/browser/ui/views/frame/browser_header_painter_ash.h" #include "chrome/browser/ui/views/frame/browser_view.h" #include "chrome/browser/ui/views/frame/immersive_mode_controller.h" #include "chrome/browser/ui/views/tab_icon_view.h" @@ -79,7 +81,6 @@ BrowserNonClientFrameViewAsh::BrowserNonClientFrameViewAsh( : BrowserNonClientFrameView(frame, browser_view), caption_button_container_(NULL), window_icon_(NULL), - header_painter_(new ash::HeaderPainter), frame_border_hit_test_controller_( new ash::FrameBorderHitTestController(frame)) { } @@ -104,10 +105,17 @@ void BrowserNonClientFrameViewAsh::Init() { UpdateAvatarInfo(); // HeaderPainter handles layout. - ash::HeaderPainter::Style header_style = UsePackagedAppHeaderStyle() ? - ash::HeaderPainter::STYLE_OTHER : ash::HeaderPainter::STYLE_BROWSER; - header_painter_->Init(header_style, frame(), this, window_icon_, - caption_button_container_); + if (UsePackagedAppHeaderStyle()) { + ash::DefaultHeaderPainter* header_painter = new ash::DefaultHeaderPainter; + header_painter_.reset(header_painter); + header_painter->Init(frame(), this, window_icon_, + caption_button_container_); + } else { + BrowserHeaderPainterAsh* header_painter = new BrowserHeaderPainterAsh; + header_painter_.reset(header_painter); + header_painter->Init(frame(), browser_view(), this, window_icon_, + caption_button_container_); + } } /////////////////////////////////////////////////////////////////////////////// @@ -142,19 +150,20 @@ int BrowserNonClientFrameViewAsh::GetTopInset() const { return kTabstripTopSpacingTall; } + if (UsePackagedAppHeaderStyle()) + return header_painter_->GetHeaderHeightForPainting(); + int caption_buttons_bottom = caption_button_container_->bounds().bottom(); // The toolbar partially overlaps the caption buttons. if (browser_view()->IsToolbarVisible()) return caption_buttons_bottom - kContentShadowHeight; - int separator_thickness = UsePackagedAppHeaderStyle() ? - header_painter_->HeaderContentSeparatorSize() : kClientEdgeThickness; - return caption_buttons_bottom + separator_thickness; + return caption_buttons_bottom + kClientEdgeThickness; } int BrowserNonClientFrameViewAsh::GetThemeBackgroundXInset() const { - return header_painter_->GetThemeBackgroundXInset(); + return ash::HeaderPainterUtil::GetThemeBackgroundXInset(); } void BrowserNonClientFrameViewAsh::UpdateThrobber(bool running) { @@ -172,17 +181,17 @@ gfx::Rect BrowserNonClientFrameViewAsh::GetBoundsForClientView() const { // and the top-of-window views are revealed, the TopContainerView paints the // window header by redirecting paints from its background to // BrowserNonClientFrameViewAsh. - return ash::HeaderPainter::GetBoundsForClientView(0, bounds()); + return bounds(); } gfx::Rect BrowserNonClientFrameViewAsh::GetWindowBoundsForClientBounds( const gfx::Rect& client_bounds) const { - return ash::HeaderPainter::GetWindowBoundsForClientBounds(0, client_bounds); + return client_bounds; } int BrowserNonClientFrameViewAsh::NonClientHitTest(const gfx::Point& point) { int hit_test = ash::FrameBorderHitTestController::NonClientHitTest(this, - header_painter_.get(), point); + caption_button_container_, point); // See if the point is actually within the avatar menu button or within // the avatar label. @@ -228,7 +237,7 @@ void BrowserNonClientFrameViewAsh::UpdateWindowIcon() { void BrowserNonClientFrameViewAsh::UpdateWindowTitle() { if (!frame()->IsFullscreen()) - header_painter_->SchedulePaintForTitle(BrowserFrame::GetTitleFontList()); + header_painter_->SchedulePaintForTitle(); } /////////////////////////////////////////////////////////////////////////////// @@ -245,52 +254,33 @@ void BrowserNonClientFrameViewAsh::OnPaint(gfx::Canvas* canvas) { caption_button_container_->SetPaintAsActive(ShouldPaintAsActive()); - // The primary header image changes based on window activation state and - // theme, so we look it up for each paint. - int theme_frame_image_id = 0; - int theme_frame_overlay_image_id = 0; - if (browser_view()->IsTabStripVisible()) { - GetFrameImageIdsForTabbedBrowser(&theme_frame_image_id, - &theme_frame_overlay_image_id); - } else if (browser_view()->browser()->is_app()) { - theme_frame_image_id = GetFrameImageIdForHostedApp(); - } else { - theme_frame_image_id = GetFrameImageIdForBrowserPopup(); - } - ash::HeaderPainter::Mode header_mode = ShouldPaintAsActive() ? ash::HeaderPainter::MODE_ACTIVE : ash::HeaderPainter::MODE_INACTIVE; - header_painter_->PaintHeader( - canvas, - header_mode, - theme_frame_image_id, - theme_frame_overlay_image_id); - if (browser_view()->ShouldShowWindowTitle()) - header_painter_->PaintTitleBar(canvas, BrowserFrame::GetTitleFontList()); + header_painter_->PaintHeader(canvas, header_mode); if (browser_view()->IsToolbarVisible()) PaintToolbarBackground(canvas); - else + else if (!UsePackagedAppHeaderStyle()) PaintContentEdge(canvas); } void BrowserNonClientFrameViewAsh::Layout() { - // The header must be laid out before computing |header_height| because the - // computation of |header_height| for app and popup windows depends on the + // The header must be laid out before computing |painted_height| because the + // computation of |painted_height| for app and popup windows depends on the // position of the window controls. header_painter_->LayoutHeader(); - int header_height = 0; + int painted_height = 0; if (browser_view()->IsTabStripVisible()) { - header_height = GetTopInset() + + painted_height = GetTopInset() + browser_view()->tabstrip()->GetPreferredSize().height(); } else if (browser_view()->IsToolbarVisible()) { - // Set the header's height so that it overlaps with the toolbar because the - // top few pixels of the toolbar are not opaque. - header_height = GetTopInset() + kFrameShadowThickness * 2; + // Paint the header so that it overlaps with the top few pixels of the + // toolbar because the top few pixels of the toolbar are not opaque. + painted_height = GetTopInset() + kFrameShadowThickness * 2; } else { - header_height = GetTopInset(); + painted_height = GetTopInset(); } - header_painter_->set_header_height(header_height); + header_painter_->SetHeaderHeightForPainting(painted_height); if (avatar_button()) LayoutAvatar(); BrowserNonClientFrameView::Layout(); @@ -346,11 +336,6 @@ gfx::Size BrowserNonClientFrameViewAsh::GetMinimumSize() { return gfx::Size(min_width, min_client_view_size.height()); } -void BrowserNonClientFrameViewAsh::OnThemeChanged() { - BrowserNonClientFrameView::OnThemeChanged(); - header_painter_->OnThemeChanged(); -} - /////////////////////////////////////////////////////////////////////////////// // chrome::TabIconViewModel overrides: @@ -379,7 +364,8 @@ int BrowserNonClientFrameViewAsh::GetTabStripLeftInset() const { } int BrowserNonClientFrameViewAsh::GetTabStripRightInset() const { - return header_painter_->GetRightInset() + kTabstripRightSpacing; + return caption_button_container_->GetPreferredSize().width() + + kTabstripRightSpacing; } bool BrowserNonClientFrameViewAsh::UseImmersiveLightbarHeaderStyle() const { @@ -521,68 +507,9 @@ void BrowserNonClientFrameViewAsh::PaintToolbarBackground(gfx::Canvas* canvas) { } void BrowserNonClientFrameViewAsh::PaintContentEdge(gfx::Canvas* canvas) { - if (UsePackagedAppHeaderStyle()) { - ash::HeaderPainter::Mode header_mode = ShouldPaintAsActive() ? - ash::HeaderPainter::MODE_ACTIVE : ash::HeaderPainter::MODE_INACTIVE; - header_painter_->PaintHeaderContentSeparator(canvas, header_mode); - } else { - canvas->FillRect(gfx::Rect(0, caption_button_container_->bounds().bottom(), - width(), kClientEdgeThickness), - ThemeProperties::GetDefaultColor( - ThemeProperties::COLOR_TOOLBAR_SEPARATOR)); - } -} - -void BrowserNonClientFrameViewAsh::GetFrameImageIdsForTabbedBrowser( - int* frame_image_id, - int* frame_overlay_image_id) const { - *frame_overlay_image_id = 0; - - bool is_incognito = !browser_view()->IsRegularOrGuestSession(); - ui::ThemeProvider* tp = GetThemeProvider(); - if (tp->HasCustomImage(IDR_THEME_FRAME_OVERLAY) && - !is_incognito) { - *frame_overlay_image_id = ShouldPaintAsActive() ? - IDR_THEME_FRAME_OVERLAY : IDR_THEME_FRAME_OVERLAY_INACTIVE; - } - - if (ShouldPaintAsActive()) { - *frame_image_id = is_incognito ? - IDR_THEME_FRAME_INCOGNITO : IDR_THEME_FRAME; - } else { - *frame_image_id = is_incognito ? - IDR_THEME_FRAME_INCOGNITO_INACTIVE : IDR_THEME_FRAME_INACTIVE; - } - - if ((frame()->IsMaximized() || frame()->IsFullscreen()) && - !tp->HasCustomImage(IDR_THEME_FRAME) && - !tp->HasCustomImage(*frame_image_id) && - *frame_overlay_image_id == 0) { - *frame_image_id = IDR_AURA_BROWSER_WINDOW_HEADER_BASE_MAXIMIZED; - } -} - -int BrowserNonClientFrameViewAsh::GetFrameImageIdForBrowserPopup() const { - // Browser popups are not themeable. - if (frame()->IsMaximized() || frame()->IsFullscreen()) - return IDR_AURA_BROWSER_WINDOW_HEADER_BASE_MAXIMIZED; - - bool is_incognito = !browser_view()->IsRegularOrGuestSession(); - if (ShouldPaintAsActive()) { - return is_incognito ? - IDR_AURA_BROWSER_WINDOW_HEADER_BASE_RESTORED_INCOGNITO_ACTIVE : - IDR_AURA_BROWSER_WINDOW_HEADER_BASE_RESTORED_ACTIVE; - } - return is_incognito ? - IDR_AURA_BROWSER_WINDOW_HEADER_BASE_RESTORED_INCOGNITO_INACTIVE : - IDR_AURA_BROWSER_WINDOW_HEADER_BASE_RESTORED_INACTIVE; -} - -int BrowserNonClientFrameViewAsh::GetFrameImageIdForHostedApp() const { - if (UsePackagedAppHeaderStyle()) { - return ShouldPaintAsActive() ? - IDR_AURA_WINDOW_HEADER_BASE_ACTIVE : - IDR_AURA_WINDOW_HEADER_BASE_INACTIVE; - } - return GetFrameImageIdForBrowserPopup(); + DCHECK(!UsePackagedAppHeaderStyle()); + canvas->FillRect(gfx::Rect(0, caption_button_container_->bounds().bottom(), + width(), kClientEdgeThickness), + ThemeProperties::GetDefaultColor( + ThemeProperties::COLOR_TOOLBAR_SEPARATOR)); } diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.h b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.h index acc71a1..7acbb0c 100644 --- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.h +++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.h @@ -57,7 +57,6 @@ class BrowserNonClientFrameViewAsh virtual bool HitTestRect(const gfx::Rect& rect) const OVERRIDE; virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE; virtual gfx::Size GetMinimumSize() OVERRIDE; - virtual void OnThemeChanged() OVERRIDE; // Overridden from chrome::TabIconViewModel: virtual bool ShouldTabIconViewAnimate() const OVERRIDE; @@ -100,26 +99,10 @@ class BrowserNonClientFrameViewAsh void PaintToolbarBackground(gfx::Canvas* canvas); - // Windows without a toolbar need to draw their own line under the header, - // above the content area. + // Draws the line under the header for windows without a toolbar and not using + // the packaged app header style. void PaintContentEdge(gfx::Canvas* canvas); - // Sets |frame_image_id| and |frame_image_overlay_id| to the ids of the header - // frame image and the header frame overlay image respectively which should be - // used for tabbed browser windows. |frame_overlay_image_id| is set to 0 if no - // overlay image should be used. - void GetFrameImageIdsForTabbedBrowser(int* frame_image_id, - int* frame_overlay_image_id) const; - - - // Returns the id of the header frame image which should be used for browser - // popups. Browser popups are not themed and do not use a frame overlay image. - int GetFrameImageIdForBrowserPopup() const; - - // Returns the id of the header frame image which should be used for hosted - // apps. Hosted apps are not themed and do not use a frame overlay image. - int GetFrameImageIdForHostedApp() const; - // View which contains the window controls. ash::FrameCaptionButtonContainerView* caption_button_container_; diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc index 961cc34..9f3fcda 100644 --- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc +++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc @@ -118,7 +118,7 @@ IN_PROC_BROWSER_TEST_F(BrowserNonClientFrameViewAshTest, ImmersiveFullscreen) { // Frame paints by default. EXPECT_TRUE(frame_view->ShouldPaint()); EXPECT_LT(Tab::GetImmersiveHeight(), - frame_view->header_painter_->header_height()); + frame_view->header_painter_->GetHeaderHeightForPainting()); // Enter both browser fullscreen and tab fullscreen. Entering browser // fullscreen should enable immersive fullscreen. @@ -152,7 +152,7 @@ IN_PROC_BROWSER_TEST_F(BrowserNonClientFrameViewAshTest, ImmersiveFullscreen) { revealed_lock.reset(); EXPECT_FALSE(immersive_mode_controller->IsRevealed()); EXPECT_FALSE(frame_view->ShouldPaint()); - EXPECT_EQ(0, frame_view->header_painter_->header_height()); + EXPECT_EQ(0, frame_view->header_painter_->GetHeaderHeightForPainting()); // Repeat test but without tab fullscreen. The tab lightbars should now show // when the top-of-window views are not revealed. @@ -172,7 +172,7 @@ IN_PROC_BROWSER_TEST_F(BrowserNonClientFrameViewAshTest, ImmersiveFullscreen) { EXPECT_TRUE(frame_view->caption_button_container_->visible()); EXPECT_FALSE(frame_view->UseImmersiveLightbarHeaderStyle()); EXPECT_LT(Tab::GetImmersiveHeight(), - frame_view->header_painter_->header_height()); + frame_view->header_painter_->GetHeaderHeightForPainting()); // Ending the reveal should hide the caption buttons and the header should // be in the lightbar style. @@ -181,7 +181,7 @@ IN_PROC_BROWSER_TEST_F(BrowserNonClientFrameViewAshTest, ImmersiveFullscreen) { EXPECT_FALSE(frame_view->caption_button_container_->visible()); EXPECT_TRUE(frame_view->UseImmersiveLightbarHeaderStyle()); EXPECT_EQ(Tab::GetImmersiveHeight(), - frame_view->header_painter_->header_height()); + frame_view->header_painter_->GetHeaderHeightForPainting()); // Exiting immersive fullscreen should make the caption buttons and the frame // visible again. @@ -196,6 +196,6 @@ IN_PROC_BROWSER_TEST_F(BrowserNonClientFrameViewAshTest, ImmersiveFullscreen) { EXPECT_TRUE(frame_view->caption_button_container_->visible()); EXPECT_FALSE(frame_view->UseImmersiveLightbarHeaderStyle()); EXPECT_LT(Tab::GetImmersiveHeight(), - frame_view->header_painter_->header_height()); + frame_view->header_painter_->GetHeaderHeightForPainting()); } #endif // defined(OS_CHROMEOS) diff --git a/chrome/chrome_browser_ui.gypi b/chrome/chrome_browser_ui.gypi index 08adf22..aae8f0d 100644 --- a/chrome/chrome_browser_ui.gypi +++ b/chrome/chrome_browser_ui.gypi @@ -1892,6 +1892,8 @@ 'browser/ui/views/frame/browser_frame_ashwin.h', 'browser/ui/views/frame/browser_frame_common_win.cc', 'browser/ui/views/frame/browser_frame_common_win.h', + 'browser/ui/views/frame/browser_header_painter_ash.cc', + 'browser/ui/views/frame/browser_header_painter_ash.h', 'browser/ui/views/frame/browser_non_client_frame_view.cc', 'browser/ui/views/frame/browser_non_client_frame_view.h', 'browser/ui/views/frame/browser_non_client_frame_view_ash.h', |