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 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 64 DraggedTabView::~DraggedTabView() { 65 parent()->RemoveChildView(this); 66 container_->CloseNow(); 67 STLDeleteElements(&renderers_); 68 } 69 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 96 void DraggedTabView::Update() { 97 SchedulePaint(); 98 } 99 100 /////////////////////////////////////////////////////////////////////////////// 101 // DraggedTabView, views::View overrides: 102 103 void DraggedTabView::OnPaint(gfx::Canvas* canvas) { 104 if (show_contents_on_drag_) 105 PaintDetachedView(canvas); 106 else 107 PaintFocusRect(canvas); 108 } 109 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 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 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 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 189 gfx::Size DraggedTabView::PreferredContainerSize() { 190 gfx::Size ps = GetPreferredSize(); 191 return gfx::Size(ScaleValue(ps.width()), ScaleValue(ps.height())); 192 } 193 194 int DraggedTabView::ScaleValue(int value) { 195 return static_cast<int>(value * kScalingFactor); 196 } 197