Skip to content

Commit

Permalink
Ash: Special header transparency for single open windows
Browse files Browse the repository at this point in the history
Added a special transparency setting for when a single large window is open.
Made window transparency values based on constants, rather than baked into assets.
Added chrome://transparency so designers can fiddle with the values without waiting for an engineer to make a change and the builds to cycle.  We'll take this out when we have final values.

BUG=120275,120454
TEST=manual
R=sky@chromium.org

Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=129266

Reverted: http://src.chromium.org/viewvc/chrome?view=rev&revision=129272

Review URL: https://chromiumcodereview.appspot.com/9864010

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@129280 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
jamescook@chromium.org committed Mar 27, 2012
1 parent f3da4c6 commit 15b1fa3
Show file tree
Hide file tree
Showing 10 changed files with 234 additions and 15 deletions.
10 changes: 8 additions & 2 deletions ash/wm/custom_frame_view_ash.cc
Original file line number Diff line number Diff line change
Expand Up @@ -120,10 +120,16 @@ void CustomFrameViewAsh::Layout() {

void CustomFrameViewAsh::OnPaint(gfx::Canvas* canvas) {
ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
const SkBitmap* theme_bitmap = ShouldPaintAsActive() ?
bool paint_as_active = ShouldPaintAsActive();
const SkBitmap* theme_bitmap = paint_as_active ?
rb.GetImageNamed(IDR_AURA_WINDOW_HEADER_BASE_ACTIVE).ToSkBitmap() :
rb.GetImageNamed(IDR_AURA_WINDOW_HEADER_BASE_INACTIVE).ToSkBitmap();
frame_painter_->PaintHeader(this, canvas, theme_bitmap, NULL);
frame_painter_->PaintHeader(
this,
canvas,
paint_as_active ? FramePainter::ACTIVE : FramePainter::INACTIVE,
theme_bitmap,
NULL);
frame_painter_->PaintTitleBar(this, canvas, GetTitleFont());
frame_painter_->PaintHeaderContentSeparator(this, canvas);
}
Expand Down
75 changes: 68 additions & 7 deletions ash/wm/frame_painter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

#include "ash/wm/frame_painter.h"

#include "ash/shell.h"
#include "ash/shell_window_ids.h"
#include "ash/wm/window_util.h"
#include "base/logging.h" // DCHECK
#include "grit/ui_resources.h"
Expand Down Expand Up @@ -73,6 +75,7 @@ const int kThemeFrameBitmapOffsetX = 5;
// starting |bitmap_offset_x| pixels from the left of the image.
void TileRoundRect(gfx::Canvas* canvas,
int x, int y, int w, int h,
SkPaint* paint,
const SkBitmap& bitmap,
int corner_radius,
int bitmap_offset_x) {
Expand All @@ -90,26 +93,37 @@ void TileRoundRect(gfx::Canvas* canvas,
SkPath path;
path.addRoundRect(rect, radii, SkPath::kCW_Direction);

SkPaint paint;
SkShader* shader = SkShader::CreateBitmapShader(bitmap,
SkShader::kRepeat_TileMode,
SkShader::kRepeat_TileMode);
paint.setShader(shader);
paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
paint->setShader(shader);
// CreateBitmapShader returns a Shader with a reference count of one, we
// need to unref after paint takes ownership of the shader.
shader->unref();
// Adjust canvas to compensate for image sampling offset, draw, then adjust
// back. This is cheaper than pushing/popping the entire canvas state.
canvas->sk_canvas()->translate(SkIntToScalar(-bitmap_offset_x), 0);
canvas->sk_canvas()->drawPath(path, paint);
canvas->sk_canvas()->drawPath(path, *paint);
canvas->sk_canvas()->translate(SkIntToScalar(bitmap_offset_x), 0);
}

// Returns true if |window| is a visible, normal window.
bool IsVisibleNormalWindow(aura::Window* window) {
return window &&
window->IsVisible() &&
window->type() == aura::client::WINDOW_TYPE_NORMAL;
}

} // namespace

namespace ash {

// static
int FramePainter::kActiveWindowOpacity = 255;
int FramePainter::kInactiveWindowOpacity = 166;
int FramePainter::kSoloWindowOpacity = 230;
std::set<FramePainter*>* FramePainter::instances_ = NULL;

///////////////////////////////////////////////////////////////////////////////
// FramePainter, public:

Expand All @@ -125,12 +139,16 @@ FramePainter::FramePainter()
top_right_corner_(NULL),
header_left_edge_(NULL),
header_right_edge_(NULL) {
if (!instances_)
instances_ = new std::set<FramePainter*>();
instances_->insert(this);
}

FramePainter::~FramePainter() {
// Sometimes we are destroyed before the window closes, so ensure we clean up.
if (window_)
window_->RemoveObserver(this);

instances_->erase(this);
}

void FramePainter::Init(views::Widget* frame,
Expand Down Expand Up @@ -258,13 +276,20 @@ gfx::Size FramePainter::GetMinimumSize(views::NonClientFrameView* view) {

void FramePainter::PaintHeader(views::NonClientFrameView* view,
gfx::Canvas* canvas,
HeaderMode header_mode,
const SkBitmap* theme_frame,
const SkBitmap* theme_frame_overlay) {
int opacity = UseSoloWindowHeader(NULL) ?
kSoloWindowOpacity :
(header_mode == ACTIVE ? kActiveWindowOpacity : kInactiveWindowOpacity);

SkPaint paint;
paint.setAlpha(opacity);
// Draw the header background, clipping the corners to be rounded.
const int kCornerRadius = 2;
TileRoundRect(canvas,
0, 0, view->width(), theme_frame->height(),
&paint,
*theme_frame,
kCornerRadius,
kThemeFrameBitmapOffsetX);
Expand Down Expand Up @@ -421,12 +446,28 @@ void FramePainter::OnWindowPropertyChanged(aura::Window* window,
}
}

void FramePainter::OnWindowDestroying(aura::Window* window) {
DCHECK_EQ(window_, window);
void FramePainter::OnWindowDestroying(aura::Window* destroying) {
DCHECK_EQ(window_, destroying);
// Must be removed here and not in the destructor, as the aura::Window is
// already destroyed when our destructor runs.
window_->RemoveObserver(this);
window_ = NULL;

// For purposes of painting and solo window computation, we're done.
instances_->erase(this);

// If we have two or more windows open and we close this one, we might trigger
// the solo window appearance. If so, find the window that is becoming solo
// and schedule it to paint.
if (UseSoloWindowHeader(destroying)) {
for (std::set<FramePainter*>::const_iterator it = instances_->begin();
it != instances_->end();
++it) {
FramePainter* painter = *it;
if (IsVisibleNormalWindow(painter->window_) && painter->frame_)
painter->frame_->non_client_view()->SchedulePaint();
}
}
}

///////////////////////////////////////////////////////////////////////////////
Expand All @@ -451,4 +492,24 @@ int FramePainter::GetTitleOffsetX() const {
kTitleNoIconOffsetX;
}

bool FramePainter::UseSoloWindowHeader(aura::Window* ignore) const {
// In unit tests this can be called after the shell is destroyed.
if (!Shell::HasInstance())
return false;
const aura::Window* default_container = Shell::GetInstance()->GetContainer(
internal::kShellWindowId_DefaultContainer);
int normal_window_count = 0;
const aura::Window::Windows& windows = default_container->children();
for (aura::Window::Windows::const_iterator it = windows.begin();
it != windows.end();
++it) {
if (*it != ignore && IsVisibleNormalWindow(*it)) {
normal_window_count++;
if (normal_window_count > 1)
return false;
}
}
return normal_window_count == 1;
}

} // namespace ash
21 changes: 21 additions & 0 deletions ash/wm/frame_painter.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
#define ASH_WM_FRAME_PAINTER_H_
#pragma once

#include <set>

#include "ash/ash_export.h"
#include "base/basictypes.h"
#include "base/compiler_specific.h" // OVERRIDE
Expand Down Expand Up @@ -36,6 +38,16 @@ namespace ash {
// layout constants for Ash window frames.
class ASH_EXPORT FramePainter : public aura::WindowObserver {
public:
// Opacity values for the window header in various states, from 0 to 255.
static int kActiveWindowOpacity;
static int kInactiveWindowOpacity;
static int kSoloWindowOpacity;

enum HeaderMode {
ACTIVE,
INACTIVE
};

FramePainter();
virtual ~FramePainter();

Expand All @@ -58,6 +70,7 @@ class ASH_EXPORT FramePainter : public aura::WindowObserver {
// Paints the frame header.
void PaintHeader(views::NonClientFrameView* view,
gfx::Canvas* canvas,
HeaderMode header_mode,
const SkBitmap* theme_frame,
const SkBitmap* theme_frame_overlay);

Expand Down Expand Up @@ -95,6 +108,14 @@ class ASH_EXPORT FramePainter : public aura::WindowObserver {
// Returns the offset between window left edge and title string.
int GetTitleOffsetX() const;

// Returns true if there is exactly one visible, normal-type window in the
// default window container, in which case we should paint a transparent
// window header. Does not count window |ignore|. Pass NULL for |ignore|
// to check all windows.
bool UseSoloWindowHeader(aura::Window* ignore) const;

static std::set<FramePainter*>* instances_;

// Not owned
views::Widget* frame_;
views::View* window_icon_; // May be NULL.
Expand Down
10 changes: 8 additions & 2 deletions ash/wm/panel_frame_view.cc
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,16 @@ int PanelFrameView::NonClientHitTest(const gfx::Point& point) {

void PanelFrameView::OnPaint(gfx::Canvas* canvas) {
ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
const SkBitmap* theme_bitmap = ShouldPaintAsActive() ?
bool paint_as_active = ShouldPaintAsActive();
const SkBitmap* theme_bitmap = paint_as_active ?
rb.GetImageNamed(IDR_AURA_WINDOW_HEADER_BASE_ACTIVE).ToSkBitmap() :
rb.GetImageNamed(IDR_AURA_WINDOW_HEADER_BASE_INACTIVE).ToSkBitmap();
frame_painter_->PaintHeader(this, canvas, theme_bitmap, NULL);
frame_painter_->PaintHeader(
this,
canvas,
paint_as_active ? FramePainter::ACTIVE : FramePainter::INACTIVE,
theme_bitmap,
NULL);
frame_painter_->PaintHeaderContentSeparator(this, canvas);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,10 +189,13 @@ void BrowserNonClientFrameViewAura::OnPaint(gfx::Canvas* canvas) {
return; // Nothing visible, don't paint.
// The primary header image changes based on window activation state and
// theme, so we look it up for each paint.
frame_painter_->PaintHeader(this,
canvas,
GetThemeFrameBitmap(),
GetThemeFrameOverlayBitmap());
frame_painter_->PaintHeader(
this,
canvas,
ShouldPaintAsActive() ?
ash::FramePainter::ACTIVE : ash::FramePainter::INACTIVE,
GetThemeFrameBitmap(),
GetThemeFrameOverlayBitmap());
if (browser_view()->ShouldShowWindowTitle())
frame_painter_->PaintTitleBar(this, canvas, BrowserFrame::GetTitleFont());
if (browser_view()->IsToolbarVisible())
Expand Down
105 changes: 105 additions & 0 deletions chrome/browser/ui/webui/about_ui.cc
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,11 @@
#include "content/public/browser/zygote_host_linux.h"
#endif

#if defined(USE_ASH)
#include "ash/wm/frame_painter.h"
#include "base/string_split.h"
#endif

#if defined(USE_TCMALLOC)
#include "third_party/tcmalloc/chromium/src/gperftools/malloc_extension.h"
#endif
Expand Down Expand Up @@ -631,6 +636,102 @@ std::string AboutDiscards(const std::string& path) {

#endif // OS_CHROMEOS

#if defined(USE_ASH)

// Adds an entry to the chrome://transparency page, with the format:
// |label|:
// -- - |value|% + ++
// where --, -, +, and ++ are links to change the appropriate |key|.
// TODO(jamescook): Remove this temporary tool when we decide what the window
// header opacity should be for Ash.
std::string TransparencyLink(const std::string& label,
int value,
const std::string& key) {
return StringPrintf("<p>%s</p>"
"<p>"
"<a href='%s%s=%d'>--</a> "
"<a href='%s%s=%d'>-</a> "
"%d%% "
"<a href='%s%s=%d'>+</a> "
"<a href='%s%s=%d'>++</a>"
"</p>",
label.c_str(),
chrome::kChromeUITransparencyURL, key.c_str(), value - 5,
chrome::kChromeUITransparencyURL, key.c_str(), value - 1,
value,
chrome::kChromeUITransparencyURL, key.c_str(), value + 1,
chrome::kChromeUITransparencyURL, key.c_str(), value + 5);
}

// Returns a transparency percent from an opacity value.
int TransparencyFromOpacity(int opacity) {
return (255 - opacity) * 100 / 255;
}

// Displays a tweaking page for window header transparency, as we're iterating
// rapidly on how transparent we want the headers to be.
// TODO(jamescook): Remove this temporary tool when we decide what the window
// header opacity should be for Ash.
std::string AboutTransparency(const std::string& path) {
const char kActive[] = "active";
const char kInactive[] = "inactive";
const char kSolo[] = "solo";
// Apply transparency based on a path like "active=10&inactive=25".
std::vector<std::pair<std::string, std::string> > kv_pairs;
if (!path.empty() &&
base::SplitStringIntoKeyValuePairs(path, '=', '&', &kv_pairs)) {
for (std::vector<std::pair<std::string, std::string> >::const_iterator it =
kv_pairs.begin();
it != kv_pairs.end();
++it) {
int* opacity = NULL;
if (it->first == kActive)
opacity = &ash::FramePainter::kActiveWindowOpacity;
else if (it->first == kInactive)
opacity = &ash::FramePainter::kInactiveWindowOpacity;
else if (it->first == kSolo)
opacity = &ash::FramePainter::kSoloWindowOpacity;
if (opacity) {
int transparent = 0;
base::StringToInt(it->second, &transparent);
transparent = std::max(0, std::min(100, transparent));
*opacity = (100 - transparent) * 255 / 100;
}
}
}

// Display current settings. Do everything in transparency-percent instead of
// opacity-value.
std::string output;
AppendHeader(&output, 0, "About transparency");
AppendFooter(&output);
AppendBody(&output);
output.append("<h3>Window header transparency</h3>");
output.append(TransparencyLink("Active window:",
TransparencyFromOpacity(ash::FramePainter::kActiveWindowOpacity),
kActive));
output.append(TransparencyLink("Inactive window:",
TransparencyFromOpacity(ash::FramePainter::kInactiveWindowOpacity),
kInactive));
output.append(TransparencyLink("Solo window:",
TransparencyFromOpacity(ash::FramePainter::kSoloWindowOpacity),
kSolo));
output.append(StringPrintf(
"<p>Share: %s%s=%d&%s=%d&%s=%d</p>",
chrome::kChromeUITransparencyURL,
kActive,
TransparencyFromOpacity(ash::FramePainter::kActiveWindowOpacity),
kInactive,
TransparencyFromOpacity(ash::FramePainter::kInactiveWindowOpacity),
kSolo,
TransparencyFromOpacity(ash::FramePainter::kSoloWindowOpacity)));
output.append("<p>Reshape window to force a redraw.</p>");
AppendFooter(&output);
return output;
}

#endif // USE_ASH

// AboutDnsHandler bounces the request back to the IO thread to collect
// the DNS information.
class AboutDnsHandler : public base::RefCountedThreadSafe<AboutDnsHandler> {
Expand Down Expand Up @@ -1327,6 +1428,10 @@ void AboutUIHTMLSource::StartDataRequest(const std::string& path,
return;
} else if (host == chrome::kChromeUIDiscardsHost) {
response = AboutDiscards(path);
#endif
#if defined(USE_ASH)
} else if (host == chrome::kChromeUITransparencyHost) {
response = AboutTransparency(path);
#endif
} else if (host == chrome::kChromeUIDNSHost) {
AboutDnsHandler::Start(this, request_id);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,7 @@ WebUIFactoryFunction GetWebUIFactoryFunction(content::WebUI* web_ui,
|| url.host() == chrome::kChromeUIDiscardsHost
|| url.host() == chrome::kChromeUINetworkHost
|| url.host() == chrome::kChromeUIOSCreditsHost
|| url.host() == chrome::kChromeUITransparencyHost
#endif
) {
return &NewWebUI<AboutUI>;
Expand Down
Loading

0 comments on commit 15b1fa3

Please sign in to comment.