Commit b43a8979 authored by derat@chromium.org's avatar derat@chromium.org

aura: Draw shadows around tooltip windows.

Also, add padding around the tooltip text and disable the
border when shadows are enabled.

I'm also updating the existing shadow code in aura_shell to
clip corner images as needed when they're too large to fit
within the requested size.

BUG=106507
TEST=added


Review URL: http://codereview.chromium.org/8821028

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@113294 0039d316-1c4b-4281-b951-d872f2087c98
parent 33ade1db
......@@ -13,6 +13,7 @@
#include "third_party/skia/include/core/SkXfermode.h"
using std::max;
using std::min;
namespace aura_shell {
namespace internal {
......@@ -92,45 +93,81 @@ void ImageGrid::SetSize(const gfx::Size& size) {
float center_height = size.height() - top_row_height_ - bottom_row_height_;
if (top_layer_.get()) {
ui::Transform transform;
transform.SetScaleX(center_width / top_layer_->bounds().width());
transform.ConcatTranslate(left_column_width_, 0);
top_layer_->SetTransform(transform);
if (center_width > 0) {
ui::Transform transform;
transform.SetScaleX(center_width / top_layer_->bounds().width());
transform.ConcatTranslate(left_column_width_, 0);
top_layer_->SetTransform(transform);
}
top_layer_->SetVisible(center_width > 0);
}
if (bottom_layer_.get()) {
ui::Transform transform;
transform.SetScaleX(center_width / bottom_layer_->bounds().width());
transform.ConcatTranslate(
left_column_width_, size.height() - bottom_layer_->bounds().height());
bottom_layer_->SetTransform(transform);
if (center_width > 0) {
ui::Transform transform;
transform.SetScaleX(center_width / bottom_layer_->bounds().width());
transform.ConcatTranslate(
left_column_width_, size.height() - bottom_layer_->bounds().height());
bottom_layer_->SetTransform(transform);
}
bottom_layer_->SetVisible(center_width > 0);
}
if (left_layer_.get()) {
ui::Transform transform;
transform.SetScaleY(center_height / left_layer_->bounds().height());
transform.ConcatTranslate(0, top_row_height_);
left_layer_->SetTransform(transform);
if (center_height > 0) {
ui::Transform transform;
transform.SetScaleY(center_height / left_layer_->bounds().height());
transform.ConcatTranslate(0, top_row_height_);
left_layer_->SetTransform(transform);
}
left_layer_->SetVisible(center_height > 0);
}
if (right_layer_.get()) {
ui::Transform transform;
transform.SetScaleY(center_height / right_layer_->bounds().height());
transform.ConcatTranslate(
size.width() - right_layer_->bounds().width(), top_row_height_);
right_layer_->SetTransform(transform);
if (center_height > 0) {
ui::Transform transform;
transform.SetScaleY(center_height / right_layer_->bounds().height());
transform.ConcatTranslate(
size.width() - right_layer_->bounds().width(), top_row_height_);
right_layer_->SetTransform(transform);
}
right_layer_->SetVisible(center_height > 0);
}
// Calculate the available amount of space for corner images on all sides of
// the grid. If the images don't fit, we need to clip them.
const int left = min(left_column_width_, size_.width() / 2);
const int right = min(right_column_width_, size_.width() - left);
const int top = min(top_row_height_, size_.height() / 2);
const int bottom = min(bottom_row_height_, size_.height() - top);
if (top_left_layer_.get()) {
// No transformation needed; it should be at (0, 0) and unscaled.
top_left_painter_->SetClipRect(
LayerExceedsSize(top_left_layer_.get(), gfx::Size(left, top)) ?
gfx::Rect(gfx::Rect(0, 0, left, top)) :
gfx::Rect(),
top_left_layer_.get());
}
if (top_right_layer_.get()) {
ui::Transform transform;
transform.SetTranslateX(size.width() - top_right_layer_->bounds().width());
top_right_layer_->SetTransform(transform);
top_right_painter_->SetClipRect(
LayerExceedsSize(top_right_layer_.get(), gfx::Size(right, top)) ?
gfx::Rect(top_right_layer_->bounds().width() - right, 0,
right, top) :
gfx::Rect(),
top_right_layer_.get());
}
if (bottom_left_layer_.get()) {
ui::Transform transform;
transform.SetTranslateY(
size.height() - bottom_left_layer_->bounds().height());
bottom_left_layer_->SetTransform(transform);
bottom_left_painter_->SetClipRect(
LayerExceedsSize(bottom_left_layer_.get(), gfx::Size(left, bottom)) ?
gfx::Rect(0, bottom_left_layer_->bounds().height() - bottom,
left, bottom) :
gfx::Rect(),
bottom_left_layer_.get());
}
if (bottom_right_layer_.get()) {
ui::Transform transform;
......@@ -138,18 +175,38 @@ void ImageGrid::SetSize(const gfx::Size& size) {
size.width() - bottom_right_layer_->bounds().width(),
size.height() - bottom_right_layer_->bounds().height());
bottom_right_layer_->SetTransform(transform);
bottom_right_painter_->SetClipRect(
LayerExceedsSize(bottom_right_layer_.get(), gfx::Size(right, bottom)) ?
gfx::Rect(bottom_right_layer_->bounds().width() - right,
bottom_right_layer_->bounds().height() - bottom,
right, bottom) :
gfx::Rect(),
bottom_right_layer_.get());
}
if (center_layer_.get()) {
ui::Transform transform;
transform.SetScale(center_width / center_layer_->bounds().width(),
center_height / center_layer_->bounds().height());
transform.ConcatTranslate(left_column_width_, top_row_height_);
center_layer_->SetTransform(transform);
if (center_width > 0 && center_height > 0) {
ui::Transform transform;
transform.SetScale(center_width / center_layer_->bounds().width(),
center_height / center_layer_->bounds().height());
transform.ConcatTranslate(left_column_width_, top_row_height_);
center_layer_->SetTransform(transform);
}
center_layer_->SetVisible(center_width > 0 && center_height > 0);
}
}
void ImageGrid::ImagePainter::SetClipRect(const gfx::Rect& clip_rect,
ui::Layer* layer) {
if (clip_rect != clip_rect_) {
clip_rect_ = clip_rect;
layer->ScheduleDraw();
}
}
void ImageGrid::ImagePainter::OnPaintLayer(gfx::Canvas* canvas) {
if (!clip_rect_.IsEmpty())
canvas->ClipRect(clip_rect_);
canvas->DrawBitmapInt(*(image_->ToSkBitmap()), 0, 0);
}
......@@ -160,6 +217,13 @@ gfx::Size ImageGrid::GetImageSize(const gfx::Image* image) {
gfx::Size();
}
// static
bool ImageGrid::LayerExceedsSize(const ui::Layer* layer,
const gfx::Size& size) {
return layer->bounds().width() > size.width() ||
layer->bounds().height() > size.height();
}
void ImageGrid::InitImage(const gfx::Image* image,
scoped_ptr<ui::Layer>* layer_ptr,
scoped_ptr<ImagePainter>* painter_ptr) {
......
......@@ -78,6 +78,19 @@ class AURA_SHELL_EXPORT ImageGrid {
return grid_->bottom_right_layer_.get();
}
gfx::Rect top_left_clip_rect() const {
return grid_->top_left_painter_->clip_rect_;
}
gfx::Rect top_right_clip_rect() const {
return grid_->top_right_painter_->clip_rect_;
}
gfx::Rect bottom_left_clip_rect() const {
return grid_->bottom_left_painter_->clip_rect_;
}
gfx::Rect bottom_right_clip_rect() const {
return grid_->bottom_right_painter_->clip_rect_;
}
// Returns |layer|'s bounds after applying the layer's current transform.
gfx::Rect GetTransformedLayerBounds(const ui::Layer& layer);
......@@ -117,18 +130,29 @@ class AURA_SHELL_EXPORT ImageGrid {
ImagePainter(const gfx::Image* image) : image_(image) {}
virtual ~ImagePainter() {}
// Clips |layer| to |clip_rect|. Triggers a repaint if the clipping
// rectangle has changed. An empty rectangle disables clipping.
void SetClipRect(const gfx::Rect& clip_rect, ui::Layer* layer);
// ui::LayerDelegate implementation:
virtual void OnPaintLayer(gfx::Canvas* canvas) OVERRIDE;
private:
friend class TestAPI;
const gfx::Image* image_; // not owned
gfx::Rect clip_rect_;
DISALLOW_COPY_AND_ASSIGN(ImagePainter);
};
// Returns the dimensions of |image| if non-NULL or gfx::Size(0, 0) otherwise.
static gfx::Size GetImageSize(const gfx::Image* image);
// Returns true if |layer|'s bounds don't fit within |size|.
static bool LayerExceedsSize(const ui::Layer* layer, const gfx::Size& size);
// Initializes |layer_ptr| and |painter_ptr| to display |image|.
// Also adds the passed-in layer to |layer_|.
void InitImage(const gfx::Image* image,
......
......@@ -180,7 +180,6 @@ TEST_F(ImageGridTest, SmallerSides) {
test_api.GetTransformedLayerBounds(
*test_api.top_layer()).ToString());
// The left layer should be flush with the left edge and stretched vertically
// between the top left corner and the bottom.
EXPECT_EQ(gfx::Rect(
......@@ -197,5 +196,77 @@ TEST_F(ImageGridTest, SmallerSides) {
*test_api.right_layer()).ToString());
}
// Test that we hide or clip layers as needed when the grid is assigned a small
// size.
TEST_F(ImageGridTest, TooSmall) {
const int kCorner = 5;
const int kCenter = 3;
const int kEdge = 3;
scoped_ptr<gfx::Image> top_left_image(
CreateImage(gfx::Size(kCorner, kCorner)));
scoped_ptr<gfx::Image> top_image(CreateImage(gfx::Size(kEdge, kEdge)));
scoped_ptr<gfx::Image> top_right_image(
CreateImage(gfx::Size(kCorner, kCorner)));
scoped_ptr<gfx::Image> left_image(CreateImage(gfx::Size(kEdge, kEdge)));
scoped_ptr<gfx::Image> center_image(CreateImage(gfx::Size(kCenter, kCenter)));
scoped_ptr<gfx::Image> right_image(CreateImage(gfx::Size(kEdge, kEdge)));
scoped_ptr<gfx::Image> bottom_left_image(
CreateImage(gfx::Size(kCorner, kCorner)));
scoped_ptr<gfx::Image> bottom_image(CreateImage(gfx::Size(kEdge, kEdge)));
scoped_ptr<gfx::Image> bottom_right_image(
CreateImage(gfx::Size(kCorner, kCorner)));
ImageGrid grid;
grid.Init(
top_left_image.get(), top_image.get(), top_right_image.get(),
left_image.get(), center_image.get(), right_image.get(),
bottom_left_image.get(), bottom_image.get(), bottom_right_image.get());
ImageGrid::TestAPI test_api(&grid);
// Set a size that's smaller than the combined (unscaled) corner images.
const gfx::Size kSmallSize(kCorner + kCorner - 3, kCorner + kCorner - 5);
grid.SetSize(kSmallSize);
// The scalable images around the sides and in the center should be hidden.
EXPECT_FALSE(test_api.top_layer()->visible());
EXPECT_FALSE(test_api.bottom_layer()->visible());
EXPECT_FALSE(test_api.left_layer()->visible());
EXPECT_FALSE(test_api.right_layer()->visible());
EXPECT_FALSE(test_api.center_layer()->visible());
// The corner images' clip rects should sum to the expected size.
EXPECT_EQ(kSmallSize.width(),
test_api.top_left_clip_rect().width() +
test_api.top_right_clip_rect().width());
EXPECT_EQ(kSmallSize.width(),
test_api.bottom_left_clip_rect().width() +
test_api.bottom_right_clip_rect().width());
EXPECT_EQ(kSmallSize.height(),
test_api.top_left_clip_rect().height() +
test_api.bottom_left_clip_rect().height());
EXPECT_EQ(kSmallSize.height(),
test_api.top_right_clip_rect().height() +
test_api.bottom_right_clip_rect().height());
// Resize the grid to be large enough to show all images.
const gfx::Size kLargeSize(kCorner + kCorner + kCenter,
kCorner + kCorner + kCenter);
grid.SetSize(kLargeSize);
// The scalable images should be visible now.
EXPECT_TRUE(test_api.top_layer()->visible());
EXPECT_TRUE(test_api.bottom_layer()->visible());
EXPECT_TRUE(test_api.left_layer()->visible());
EXPECT_TRUE(test_api.right_layer()->visible());
EXPECT_TRUE(test_api.center_layer()->visible());
// We shouldn't be clipping the corner images anymore.
EXPECT_TRUE(test_api.top_left_clip_rect().IsEmpty());
EXPECT_TRUE(test_api.top_right_clip_rect().IsEmpty());
EXPECT_TRUE(test_api.bottom_left_clip_rect().IsEmpty());
EXPECT_TRUE(test_api.bottom_right_clip_rect().IsEmpty());
}
} // namespace test
} // namespace aura_shell
......@@ -6,9 +6,11 @@
#include <vector>
#include "base/command_line.h"
#include "base/location.h"
#include "base/string_split.h"
#include "base/time.h"
#include "ui/aura/aura_switches.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/event.h"
#include "ui/aura/window.h"
......@@ -26,14 +28,19 @@
namespace {
SkColor kTooltipBackground = 0xFFFFFFCC;
SkColor kTooltipBorder = 0xFF000000;
int kTooltipBorderWidth = 1;
int kTooltipTimeoutMs = 500;
const SkColor kTooltipBackground = 0xFFFFFFCC;
const SkColor kTooltipBorder = 0xFF646450;
const int kTooltipBorderWidth = 1;
const int kTooltipHorizontalPadding = 3;
// TODO(derat): This padding is needed on Chrome OS devices but seems excessive
// when running the same binary on a Linux workstation; presumably there's a
// difference in font metrics. Rationalize this.
const int kTooltipVerticalPadding = 2;
const int kTooltipTimeoutMs = 500;
// FIXME: get cursor offset from actual cursor size.
int kCursorOffsetX = 10;
int kCursorOffsetY = 15;
const int kCursorOffsetX = 10;
const int kCursorOffsetY = 15;
// Maximum number of characters we allow in a tooltip.
const size_t kMaxTooltipLength = 1024;
......@@ -107,8 +114,11 @@ class ShellTooltipManager::Tooltip {
Tooltip() {
label_.set_background(
views::Background::CreateSolidBackground(kTooltipBackground));
label_.set_border(
views::Border::CreateSolidBorder(kTooltipBorderWidth, kTooltipBorder));
if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAuraNoShadows)) {
label_.set_border(
views::Border::CreateSolidBorder(kTooltipBorderWidth,
kTooltipBorder));
}
label_.set_parent_owned(false);
widget_.reset(CreateTooltip());
widget_->SetContentsView(&label_);
......@@ -126,8 +136,14 @@ class ShellTooltipManager::Tooltip {
location.x(), location.y());
label_.SetText(tooltip_text);
SetTooltipBounds(location, max_width + 2 * kTooltipBorderWidth,
label_.GetPreferredSize().height());
int width = max_width + 2 * kTooltipHorizontalPadding;
int height = label_.GetPreferredSize().height() +
2 * kTooltipVerticalPadding;
if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAuraNoShadows)) {
width += 2 * kTooltipBorderWidth;
height += 2 * kTooltipBorderWidth;
}
SetTooltipBounds(location, width, height);
}
// Shows the tooltip.
......@@ -167,9 +183,10 @@ class ShellTooltipManager::Tooltip {
////////////////////////////////////////////////////////////////////////////////
// ShellTooltipManager public:
ShellTooltipManager::ShellTooltipManager() : aura::EventFilter(NULL),
tooltip_window_(NULL),
tooltip_(new Tooltip) {
ShellTooltipManager::ShellTooltipManager()
: aura::EventFilter(NULL),
tooltip_window_(NULL),
tooltip_(new Tooltip) {
tooltip_timer_.Start(FROM_HERE,
base::TimeDelta::FromMilliseconds(kTooltipTimeoutMs),
this, &ShellTooltipManager::TooltipTimerFired);
......
......@@ -168,7 +168,8 @@ void NativeWidgetAura::InitNativeWidget(const Widget::InitParams& params) {
static_cast<aura::WindowDragDropDelegate*>(this));
}
if (window_type == Widget::InitParams::TYPE_MENU)
if (window_type == Widget::InitParams::TYPE_MENU ||
window_type == Widget::InitParams::TYPE_TOOLTIP)
window_->SetIntProperty(aura::kShadowTypeKey,
aura::SHADOW_TYPE_RECTANGULAR);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment