1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/ui/views/tabs/dragged_tab_view.h"
6
7 #include "base/stl_util-inl.h"
8 #include "chrome/browser/ui/views/tabs/native_view_photobooth.h"
9 #include "third_party/skia/include/core/SkShader.h"
10 #include "ui/gfx/canvas_skia.h"
11 #include "views/widget/widget.h"
12
13 #if defined(OS_WIN)
14 #include "views/widget/widget_win.h"
15 #elif defined(OS_LINUX)
16 #include "views/widget/widget_gtk.h"
17 #endif
18
19 static const int kTransparentAlpha = 200;
20 static const int kOpaqueAlpha = 255;
21 static const int kDragFrameBorderSize = 2;
22 static const int kTwiceDragFrameBorderSize = 2 * kDragFrameBorderSize;
23 static const float kScalingFactor = 0.5;
24 static const SkColor kDraggedTabBorderColor = SkColorSetRGB(103, 129, 162);
25
26 ////////////////////////////////////////////////////////////////////////////////
27 // DraggedTabView, public:
28
DraggedTabView(const std::vector<views::View * > & renderers,const std::vector<gfx::Rect> & renderer_bounds,const gfx::Point & mouse_tab_offset,const gfx::Size & contents_size,NativeViewPhotobooth * photobooth)29 DraggedTabView::DraggedTabView(const std::vector<views::View*>& renderers,
30 const std::vector<gfx::Rect>& renderer_bounds,
31 const gfx::Point& mouse_tab_offset,
32 const gfx::Size& contents_size,
33 NativeViewPhotobooth* photobooth)
34 : renderers_(renderers),
35 renderer_bounds_(renderer_bounds),
36 show_contents_on_drag_(true),
37 mouse_tab_offset_(mouse_tab_offset),
38 photobooth_(photobooth),
39 contents_size_(contents_size) {
40 set_parent_owned(false);
41
42 views::Widget::CreateParams params(views::Widget::CreateParams::TYPE_POPUP);
43 params.transparent = true;
44 params.keep_on_top = true;
45 params.delete_on_destroy = false;
46 container_.reset(views::Widget::CreateWidget(params));
47 #if defined(OS_WIN)
48 static_cast<views::WidgetWin*>(container_.get())->
49 set_can_update_layered_window(false);
50
51 BOOL drag;
52 if ((::SystemParametersInfo(SPI_GETDRAGFULLWINDOWS, 0, &drag, 0) != 0) &&
53 (drag == FALSE)) {
54 show_contents_on_drag_ = false;
55 }
56 #endif
57 gfx::Size container_size(PreferredContainerSize());
58 container_->Init(NULL, gfx::Rect(gfx::Point(), container_size));
59 container_->SetContentsView(this);
60 container_->SetOpacity(kTransparentAlpha);
61 container_->SetBounds(gfx::Rect(gfx::Point(), container_size));
62 }
63
~DraggedTabView()64 DraggedTabView::~DraggedTabView() {
65 parent()->RemoveChildView(this);
66 container_->CloseNow();
67 STLDeleteElements(&renderers_);
68 }
69
MoveTo(const gfx::Point & screen_point)70 void DraggedTabView::MoveTo(const gfx::Point& screen_point) {
71 int x;
72 if (base::i18n::IsRTL()) {
73 // On RTL locales, a dragged tab (when it is not attached to a tab strip)
74 // is rendered using a right-to-left orientation so we should calculate the
75 // window position differently.
76 gfx::Size ps = GetPreferredSize();
77 x = screen_point.x() + ScaleValue(mouse_tab_offset_.x() - ps.width());
78 } else {
79 x = screen_point.x() - ScaleValue(mouse_tab_offset_.x());
80 }
81 int y = screen_point.y() - ScaleValue(mouse_tab_offset_.y());
82
83 #if defined(OS_WIN)
84 // TODO(beng): make this cross-platform
85 int show_flags = container_->IsVisible() ? SWP_NOZORDER : SWP_SHOWWINDOW;
86 SetWindowPos(container_->GetNativeView(), HWND_TOP, x, y, 0, 0,
87 SWP_NOSIZE | SWP_NOACTIVATE | show_flags);
88 #else
89 gfx::Rect bounds = container_->GetWindowScreenBounds();
90 container_->SetBounds(gfx::Rect(x, y, bounds.width(), bounds.height()));
91 if (!container_->IsVisible())
92 container_->Show();
93 #endif
94 }
95
Update()96 void DraggedTabView::Update() {
97 SchedulePaint();
98 }
99
100 ///////////////////////////////////////////////////////////////////////////////
101 // DraggedTabView, views::View overrides:
102
OnPaint(gfx::Canvas * canvas)103 void DraggedTabView::OnPaint(gfx::Canvas* canvas) {
104 if (show_contents_on_drag_)
105 PaintDetachedView(canvas);
106 else
107 PaintFocusRect(canvas);
108 }
109
Layout()110 void DraggedTabView::Layout() {
111 int max_width = GetPreferredSize().width();
112 for (size_t i = 0; i < renderers_.size(); ++i) {
113 gfx::Rect bounds = renderer_bounds_[i];
114 bounds.set_y(0);
115 if (base::i18n::IsRTL())
116 bounds.set_x(max_width - bounds.x() - bounds.width());
117 renderers_[i]->SetBoundsRect(bounds);
118 }
119 }
120
GetPreferredSize()121 gfx::Size DraggedTabView::GetPreferredSize() {
122 DCHECK(!renderer_bounds_.empty());
123 int max_renderer_x = renderer_bounds_.back().right();
124 int width = std::max(max_renderer_x, contents_size_.width()) +
125 kTwiceDragFrameBorderSize;
126 int height = renderer_bounds_.back().height() + kDragFrameBorderSize +
127 contents_size_.height();
128 return gfx::Size(width, height);
129 }
130
131 ////////////////////////////////////////////////////////////////////////////////
132 // DraggedTabView, private:
133
PaintDetachedView(gfx::Canvas * canvas)134 void DraggedTabView::PaintDetachedView(gfx::Canvas* canvas) {
135 gfx::Size ps = GetPreferredSize();
136 gfx::CanvasSkia scale_canvas(ps.width(), ps.height(), false);
137 SkBitmap& bitmap_device = const_cast<SkBitmap&>(
138 scale_canvas.getTopPlatformDevice().accessBitmap(true));
139 bitmap_device.eraseARGB(0, 0, 0, 0);
140
141 int tab_height = renderer_bounds_.back().height();
142 scale_canvas.FillRectInt(kDraggedTabBorderColor, 0,
143 tab_height - kDragFrameBorderSize,
144 ps.width(), ps.height() - tab_height);
145 int image_x = kDragFrameBorderSize;
146 int image_y = tab_height;
147 int image_w = ps.width() - kTwiceDragFrameBorderSize;
148 int image_h = contents_size_.height();
149 scale_canvas.FillRectInt(SK_ColorBLACK, image_x, image_y, image_w, image_h);
150 photobooth_->PaintScreenshotIntoCanvas(
151 &scale_canvas,
152 gfx::Rect(image_x, image_y, image_w, image_h));
153 for (size_t i = 0; i < renderers_.size(); ++i)
154 renderers_[i]->Paint(&scale_canvas);
155
156 SkIRect subset;
157 subset.set(0, 0, ps.width(), ps.height());
158 SkBitmap mipmap = scale_canvas.ExtractBitmap();
159 mipmap.buildMipMap(true);
160
161 SkShader* bitmap_shader =
162 SkShader::CreateBitmapShader(mipmap, SkShader::kClamp_TileMode,
163 SkShader::kClamp_TileMode);
164
165 SkMatrix shader_scale;
166 shader_scale.setScale(kScalingFactor, kScalingFactor);
167 bitmap_shader->setLocalMatrix(shader_scale);
168
169 SkPaint paint;
170 paint.setShader(bitmap_shader);
171 paint.setAntiAlias(true);
172 bitmap_shader->unref();
173
174 SkRect rc;
175 rc.fLeft = 0;
176 rc.fTop = 0;
177 rc.fRight = SkIntToScalar(ps.width());
178 rc.fBottom = SkIntToScalar(ps.height());
179 canvas->AsCanvasSkia()->drawRect(rc, paint);
180 }
181
PaintFocusRect(gfx::Canvas * canvas)182 void DraggedTabView::PaintFocusRect(gfx::Canvas* canvas) {
183 gfx::Size ps = GetPreferredSize();
184 canvas->DrawFocusRect(0, 0,
185 static_cast<int>(ps.width() * kScalingFactor),
186 static_cast<int>(ps.height() * kScalingFactor));
187 }
188
PreferredContainerSize()189 gfx::Size DraggedTabView::PreferredContainerSize() {
190 gfx::Size ps = GetPreferredSize();
191 return gfx::Size(ScaleValue(ps.width()), ScaleValue(ps.height()));
192 }
193
ScaleValue(int value)194 int DraggedTabView::ScaleValue(int value) {
195 return static_cast<int>(value * kScalingFactor);
196 }
197