summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ash/wm/custom_frame_view_ash.cc2
-rw-r--r--ash/wm/frame_painter.cc148
-rw-r--r--ash/wm/frame_painter.h15
-rw-r--r--ash/wm/frame_painter_unittest.cc21
-rw-r--r--ash/wm/panels/panel_frame_view.cc2
-rw-r--r--chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc19
-rw-r--r--chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.h10
7 files changed, 141 insertions, 76 deletions
diff --git a/ash/wm/custom_frame_view_ash.cc b/ash/wm/custom_frame_view_ash.cc
index 3fb5b24..8c66eb8 100644
--- a/ash/wm/custom_frame_view_ash.cc
+++ b/ash/wm/custom_frame_view_ash.cc
@@ -150,7 +150,7 @@ void CustomFrameViewAsh::OnPaint(gfx::Canvas* canvas) {
canvas,
paint_as_active ? FramePainter::ACTIVE : FramePainter::INACTIVE,
theme_image_id,
- NULL);
+ 0);
frame_painter_->PaintTitleBar(this, canvas, GetTitleFont());
frame_painter_->PaintHeaderContentSeparator(this, canvas);
canvas->Restore();
diff --git a/ash/wm/frame_painter.cc b/ash/wm/frame_painter.cc
index f94bf12..5aeb714 100644
--- a/ash/wm/frame_painter.cc
+++ b/ash/wm/frame_painter.cc
@@ -33,6 +33,7 @@
#include "ui/gfx/font.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/screen.h"
+#include "ui/gfx/skia_util.h"
#include "ui/views/controls/button/image_button.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
@@ -82,23 +83,21 @@ const int kActivationCrossfadeDurationMs = 200;
// Alpha/opacity value for fully-opaque headers.
const int kFullyOpaque = 255;
-// Tiles an image into an area, rounding the top corners. Samples the |bitmap|
-// starting |bitmap_offset_x| pixels from the left of the image.
+// 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,
- int x, int y, int w, int h,
- const SkPaint& paint,
const gfx::ImageSkia& image,
- int corner_radius,
+ const SkPaint& paint,
+ const gfx::Rect& bounds,
+ int top_left_corner_radius,
+ int top_right_corner_radius,
int image_inset_x) {
- // To get the shader to sample the image |inset_y| pixels in but tile across
- // the whole image, we adjust the target rectangle for the shader to the right
- // and translate the canvas left to compensate.
- SkRect rect;
- rect.iset(x, y, x + w, y + h);
- const SkScalar kRadius = SkIntToScalar(corner_radius);
+ SkRect rect = gfx::RectToSkRect(bounds);
+ const SkScalar kTopLeftRadius = SkIntToScalar(top_left_corner_radius);
+ const SkScalar kTopRightRadius = SkIntToScalar(top_right_corner_radius);
SkScalar radii[8] = {
- kRadius, kRadius, // top-left
- kRadius, kRadius, // top-right
+ kTopLeftRadius, kTopLeftRadius, // top-left
+ kTopRightRadius, kTopRightRadius, // top-right
0, 0, // bottom-right
0, 0}; // bottom-left
SkPath path;
@@ -106,6 +105,53 @@ void TileRoundRect(gfx::Canvas* canvas,
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->scale_factor(), 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);
+ }
+}
+
// Returns true if |child| and all ancestors are visible. Useful to ensure that
// a window is individually visible and is not part of a hidden workspace.
bool IsVisibleToRoot(Window* child) {
@@ -179,8 +225,10 @@ FramePainter::FramePainter()
header_left_edge_(NULL),
header_right_edge_(NULL),
previous_theme_frame_id_(0),
+ previous_theme_frame_overlay_id_(0),
previous_opacity_(0),
crossfade_theme_frame_id_(0),
+ crossfade_theme_frame_overlay_id_(0),
crossfade_opacity_(0),
crossfade_animation_(NULL),
size_button_behavior_(SIZE_BUTTON_MAXIMIZES) {
@@ -373,9 +421,11 @@ void FramePainter::PaintHeader(views::NonClientFrameView* view,
gfx::Canvas* canvas,
HeaderMode header_mode,
int theme_frame_id,
- const gfx::ImageSkia* theme_frame_overlay) {
- if (previous_theme_frame_id_ != 0 &&
- previous_theme_frame_id_ != 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
@@ -390,6 +440,7 @@ void FramePainter::PaintHeader(views::NonClientFrameView* view,
if (!parent_animating) {
crossfade_animation_.reset(new ui::SlideAnimation(this));
crossfade_theme_frame_id_ = previous_theme_frame_id_;
+ crossfade_theme_frame_overlay_id_ = previous_theme_frame_overlay_id_;
crossfade_opacity_ = previous_opacity_;
crossfade_animation_->SetSlideDuration(kActivationCrossfadeDurationMs);
crossfade_animation_->Show();
@@ -399,10 +450,15 @@ void FramePainter::PaintHeader(views::NonClientFrameView* view,
}
int opacity =
- GetHeaderOpacity(header_mode, theme_frame_id, theme_frame_overlay);
+ GetHeaderOpacity(header_mode, theme_frame_id, theme_frame_overlay_id);
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);
+ }
header_frame_bounds_ = gfx::Rect(0, 0, view->width(), theme_frame->height());
const int kCornerRadius = 2;
@@ -411,7 +467,19 @@ void FramePainter::PaintHeader(views::NonClientFrameView* view,
if (crossfade_animation_.get() && crossfade_animation_->is_animating()) {
gfx::ImageSkia* crossfade_theme_frame =
theme_provider->GetImageSkiaNamed(crossfade_theme_frame_id_);
- if (crossfade_theme_frame) {
+ 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();
+ paint.setAlpha(opacity);
+ } else {
double current_value = crossfade_animation_->GetCurrentValue();
int old_alpha = (1 - current_value) * crossfade_opacity_;
int new_alpha = current_value * opacity;
@@ -419,37 +487,33 @@ void FramePainter::PaintHeader(views::NonClientFrameView* view,
// Draw the old header background, clipping the corners to be rounded.
paint.setAlpha(old_alpha);
paint.setXfermodeMode(SkXfermode::kPlus_Mode);
- TileRoundRect(canvas,
- 0, 0, view->width(), theme_frame->height(),
- paint,
- *crossfade_theme_frame,
- kCornerRadius,
- GetThemeBackgroundXInset());
+ PaintFrameImagesInRoundRect(canvas,
+ crossfade_theme_frame,
+ crossfade_theme_frame_overlay,
+ paint,
+ header_frame_bounds_,
+ kCornerRadius,
+ GetThemeBackgroundXInset());
paint.setAlpha(new_alpha);
- } else {
- crossfade_animation_.reset();
- paint.setAlpha(opacity);
}
} else {
paint.setAlpha(opacity);
}
// Draw the header background, clipping the corners to be rounded.
- TileRoundRect(canvas,
- 0, 0, view->width(), theme_frame->height(),
- paint,
- *theme_frame,
- kCornerRadius,
- GetThemeBackgroundXInset());
+ PaintFrameImagesInRoundRect(canvas,
+ theme_frame,
+ theme_frame_overlay,
+ paint,
+ header_frame_bounds_,
+ kCornerRadius,
+ GetThemeBackgroundXInset());
previous_theme_frame_id_ = theme_frame_id;
+ previous_theme_frame_overlay_id_ = theme_frame_overlay_id;
previous_opacity_ = opacity;
- // Draw the theme frame overlay, if available.
- if (theme_frame_overlay)
- canvas->DrawImageInt(*theme_frame_overlay, 0, 0);
-
// Separator between the maximize and close buttons. It overlaps the left
// edge of the close button.
gfx::Rect divider(close_button_->x(), close_button_->y(),
@@ -759,12 +823,14 @@ int FramePainter::GetTitleOffsetX() const {
int FramePainter::GetHeaderOpacity(
HeaderMode header_mode,
int theme_frame_id,
- const gfx::ImageSkia* theme_frame_overlay) const {
+ int theme_frame_overlay_id) const {
// User-provided themes are painted fully opaque.
- if (frame_->GetThemeProvider()->HasCustomImage(theme_frame_id))
- return kFullyOpaque;
- if (theme_frame_overlay)
+ ui::ThemeProvider* theme_provider = frame_->GetThemeProvider();
+ if (theme_provider->HasCustomImage(theme_frame_id) ||
+ (theme_frame_overlay_id != 0 &&
+ theme_provider->HasCustomImage(theme_frame_overlay_id))) {
return kFullyOpaque;
+ }
// The header is fully opaque when using the minimalistic header style.
if (ShouldUseMinimalHeaderStyle(THEMED_NO))
diff --git a/ash/wm/frame_painter.h b/ash/wm/frame_painter.h
index a46aa17..e288166 100644
--- a/ash/wm/frame_painter.h
+++ b/ash/wm/frame_painter.h
@@ -100,11 +100,12 @@ class ASH_EXPORT FramePainter : public aura::WindowObserver,
bool ShouldUseMinimalHeaderStyle(Themed header_themed) const;
// Paints the frame header.
+ // |theme_frame_overlay_id| is 0 if no overlay image should be used.
void PaintHeader(views::NonClientFrameView* view,
gfx::Canvas* canvas,
HeaderMode header_mode,
int theme_frame_id,
- const gfx::ImageSkia* theme_frame_overlay);
+ int theme_frame_overlay_id);
// Paints the header/content separator line. Exists as a separate function
// because some windows with complex headers (e.g. browsers with tab strips)
@@ -172,9 +173,13 @@ class ASH_EXPORT FramePainter : public aura::WindowObserver,
int GetTitleOffsetX() const;
// Returns the opacity value used to paint the header.
+ // |theme_frame_overlay_id| is 0 if no overlay image is used.
int GetHeaderOpacity(HeaderMode header_mode,
int theme_frame_id,
- const gfx::ImageSkia* theme_frame_overlay) const;
+ int theme_frame_overlay_id) const;
+
+ // Adjust frame operations for left / right maximized modes.
+ int AdjustFrameHitCodeForMaximizedModes(int hit_code);
// Returns true if the user is cycling through workspaces.
bool IsCyclingThroughWorkspaces() const;
@@ -221,12 +226,14 @@ class ASH_EXPORT FramePainter : public aura::WindowObserver,
const gfx::ImageSkia* header_left_edge_;
const gfx::ImageSkia* header_right_edge_;
- // Image id and opacity last used for painting header.
+ // Image ids and opacity last used for painting header.
int previous_theme_frame_id_;
+ int previous_theme_frame_overlay_id_;
int previous_opacity_;
- // Image id and opacity we are crossfading from.
+ // Image ids and opacity we are crossfading from.
int crossfade_theme_frame_id_;
+ int crossfade_theme_frame_overlay_id_;
int crossfade_opacity_;
gfx::Rect header_frame_bounds_;
diff --git a/ash/wm/frame_painter_unittest.cc b/ash/wm/frame_painter_unittest.cc
index 8108320..3c9d55c 100644
--- a/ash/wm/frame_painter_unittest.cc
+++ b/ash/wm/frame_painter_unittest.cc
@@ -594,7 +594,7 @@ TEST_F(FramePainterTest, GetHeaderOpacity) {
EXPECT_EQ(FramePainter::kSoloWindowOpacity,
p1.GetHeaderOpacity(FramePainter::ACTIVE,
IDR_AURA_WINDOW_HEADER_BASE_ACTIVE,
- NULL));
+ 0));
// Create a second widget and painter.
scoped_ptr<Widget> w2(CreateTestWidget());
@@ -608,33 +608,20 @@ TEST_F(FramePainterTest, GetHeaderOpacity) {
EXPECT_EQ(FramePainter::kActiveWindowOpacity,
p2.GetHeaderOpacity(FramePainter::ACTIVE,
IDR_AURA_WINDOW_HEADER_BASE_ACTIVE,
- NULL));
+ 0));
// Inactive window has inactive window opacity.
EXPECT_EQ(FramePainter::kInactiveWindowOpacity,
p2.GetHeaderOpacity(FramePainter::INACTIVE,
IDR_AURA_WINDOW_HEADER_BASE_INACTIVE,
- NULL));
-
- // Custom overlay image is drawn completely opaque.
- gfx::ImageSkia custom_overlay;
- EXPECT_EQ(255,
- p1.GetHeaderOpacity(FramePainter::ACTIVE,
- IDR_AURA_WINDOW_HEADER_BASE_ACTIVE,
- &custom_overlay));
+ 0));
// Regular maximized windows are fully opaque.
ash::wm::MaximizeWindow(w1->GetNativeWindow());
EXPECT_EQ(255,
p1.GetHeaderOpacity(FramePainter::ACTIVE,
IDR_AURA_WINDOW_HEADER_BASE_ACTIVE,
- NULL));
-
- // Windows with custom overlays are fully opaque when maximized.
- EXPECT_EQ(255,
- p1.GetHeaderOpacity(FramePainter::ACTIVE,
- IDR_AURA_WINDOW_HEADER_BASE_ACTIVE,
- &custom_overlay));
+ 0));
}
// Test that the minimal header style is used in the proper situations.
diff --git a/ash/wm/panels/panel_frame_view.cc b/ash/wm/panels/panel_frame_view.cc
index 59bab64..36b6950 100644
--- a/ash/wm/panels/panel_frame_view.cc
+++ b/ash/wm/panels/panel_frame_view.cc
@@ -118,7 +118,7 @@ void PanelFrameView::OnPaint(gfx::Canvas* canvas) {
canvas,
paint_as_active ? FramePainter::ACTIVE : FramePainter::INACTIVE,
theme_frame_id,
- NULL);
+ 0);
frame_painter_->PaintTitleBar(this, canvas, title_font_);
frame_painter_->PaintHeaderContentSeparator(this, canvas);
}
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 36fbdf2..d658b84 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
@@ -221,11 +221,13 @@ void BrowserNonClientFrameViewAsh::OnPaint(gfx::Canvas* canvas) {
// 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 = GetThemeFrameImageId();
- const gfx::ImageSkia* theme_frame_overlay_image = GetThemeFrameOverlayImage();
+ int theme_frame_overlay_image_id = GetThemeFrameOverlayImageId();
+ ui::ThemeProvider* theme_provider = GetThemeProvider();
ash::FramePainter::Themed header_themed = ash::FramePainter::THEMED_NO;
- if (GetThemeProvider()->HasCustomImage(theme_frame_image_id) ||
- theme_frame_overlay_image) {
+ if (theme_provider->HasCustomImage(theme_frame_image_id) ||
+ (theme_frame_overlay_image_id != 0 &&
+ theme_provider->HasCustomImage(theme_frame_overlay_image_id))) {
header_themed = ash::FramePainter::THEMED_YES;
}
@@ -238,7 +240,7 @@ void BrowserNonClientFrameViewAsh::OnPaint(gfx::Canvas* canvas) {
ShouldPaintAsActive() ?
ash::FramePainter::ACTIVE : ash::FramePainter::INACTIVE,
theme_frame_image_id,
- theme_frame_overlay_image);
+ theme_frame_overlay_image_id);
if (browser_view()->ShouldShowWindowTitle())
frame_painter_->PaintTitleBar(this, canvas, BrowserFrame::GetTitleFont());
if (browser_view()->IsToolbarVisible())
@@ -530,14 +532,13 @@ int BrowserNonClientFrameViewAsh::GetThemeFrameImageId() const {
IDR_AURA_WINDOW_HEADER_BASE_INACTIVE;
}
-const gfx::ImageSkia*
-BrowserNonClientFrameViewAsh::GetThemeFrameOverlayImage() const {
+int BrowserNonClientFrameViewAsh::GetThemeFrameOverlayImageId() const {
ui::ThemeProvider* tp = GetThemeProvider();
if (tp->HasCustomImage(IDR_THEME_FRAME_OVERLAY) &&
browser_view()->IsBrowserTypeNormal() &&
!browser_view()->IsOffTheRecord()) {
- return tp->GetImageSkiaNamed(ShouldPaintAsActive() ?
- IDR_THEME_FRAME_OVERLAY : IDR_THEME_FRAME_OVERLAY_INACTIVE);
+ return ShouldPaintAsActive() ?
+ IDR_THEME_FRAME_OVERLAY : IDR_THEME_FRAME_OVERLAY_INACTIVE;
}
- return NULL;
+ return 0;
}
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 140a7c7..eea274d 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
@@ -89,10 +89,14 @@ class BrowserNonClientFrameViewAsh
// above the content area.
void PaintContentEdge(gfx::Canvas* canvas);
- // Returns the correct image id for the frame header based on activation
- // state and incognito mode.
+ // Returns the id of the header frame image based on the browser type,
+ // activation state and incognito mode.
int GetThemeFrameImageId() const;
- const gfx::ImageSkia* GetThemeFrameOverlayImage() const;
+
+ // Returns the id of the header frame overlay image based on the activation
+ // state and incognito mode.
+ // Returns 0 if no overlay image should be used.
+ int GetThemeFrameOverlayImageId() const;
// Window controls. The |size_button_| either toggles maximized or toggles
// minimized. The exact behavior is determined by |size_button_minimizes_|.