diff options
author | pkotwicz@chromium.org <pkotwicz@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-03-17 21:18:53 +0000 |
---|---|---|
committer | pkotwicz@chromium.org <pkotwicz@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-03-17 21:18:53 +0000 |
commit | 8f9a4f94342c5da809f4976c81bc8e9bd84cde41 (patch) | |
tree | 199be3f2b3030105ca22ff01ca1153a94d5b2917 /chrome/browser/ui/views | |
parent | be6d25abdc7019ac2d12cc0b76e709de83a444ef (diff) | |
download | chromium_src-8f9a4f94342c5da809f4976c81bc8e9bd84cde41.zip chromium_src-8f9a4f94342c5da809f4976c81bc8e9bd84cde41.tar.gz chromium_src-8f9a4f94342c5da809f4976c81bc8e9bd84cde41.tar.bz2 |
[Refactor] Move code for painting the window header for browser windows out of ash
BUG=340143
TEST=None
Review URL: https://codereview.chromium.org/189463013
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@257494 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/ui/views')
5 files changed, 641 insertions, 138 deletions
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) |