15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/views/tabs/dragged_tab_view.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/stl_util.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/views/tabs/native_view_photobooth.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/skia/include/core/SkShader.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/canvas.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/widget/widget.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(USE_AURA)
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/widget/native_widget_aura.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(OS_WIN)
167d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "ui/base/win/dpi.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/widget/native_widget_win.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kTransparentAlpha = 200;
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kOpaqueAlpha = 255;
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kDragFrameBorderSize = 2;
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kTwiceDragFrameBorderSize = 2 * kDragFrameBorderSize;
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const float kScalingFactor = 0.5;
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const SkColor kDraggedTabBorderColor = SkColorSetRGB(103, 129, 162);
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// DraggedTabView, public:
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DraggedTabView::DraggedTabView(const std::vector<views::View*>& renderers,
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               const std::vector<gfx::Rect>& renderer_bounds,
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               const gfx::Point& mouse_tab_offset,
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               const gfx::Size& contents_size,
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               NativeViewPhotobooth* photobooth)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : renderers_(renderers),
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      renderer_bounds_(renderer_bounds),
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      show_contents_on_drag_(true),
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      mouse_tab_offset_(mouse_tab_offset),
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      photobooth_(photobooth),
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      contents_size_(contents_size) {
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  set_owned_by_client();
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  container_.reset(new views::Widget);
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP);
45eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  params.keep_on_top = true;
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  params.bounds = gfx::Rect(PreferredContainerSize());
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  container_->Init(params);
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  container_->SetContentsView(this);
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN) && !defined(USE_AURA)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static_cast<views::NativeWidgetWin*>(container_->native_widget())->
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SetCanUpdateLayeredWindow(false);
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BOOL drag;
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((::SystemParametersInfo(SPI_GETDRAGFULLWINDOWS, 0, &drag, 0) != 0) &&
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (drag == FALSE)) {
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    show_contents_on_drag_ = false;
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  container_->SetOpacity(kTransparentAlpha);
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  container_->SetBounds(gfx::Rect(params.bounds.size()));
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DraggedTabView::~DraggedTabView() {
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  parent()->RemoveChildView(this);
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  container_->CloseNow();
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STLDeleteElements(&renderers_);
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DraggedTabView::MoveTo(const gfx::Point& screen_point) {
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int x;
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (base::i18n::IsRTL()) {
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // On RTL locales, a dragged tab (when it is not attached to a tab strip)
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // is rendered using a right-to-left orientation so we should calculate the
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // window position differently.
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gfx::Size ps = GetPreferredSize();
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    x = screen_point.x() + ScaleValue(mouse_tab_offset_.x() - ps.width());
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    x = screen_point.x() - ScaleValue(mouse_tab_offset_.x());
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int y = screen_point.y() - ScaleValue(mouse_tab_offset_.y());
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN) && !defined(USE_AURA)
857d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  double scale = ui::win::GetDeviceScaleFactor();
867d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  x = static_cast<int>(scale * screen_point.x());
877d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  y = static_cast<int>(scale * screen_point.y());
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(beng): make this cross-platform
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int show_flags = container_->IsVisible() ? SWP_NOZORDER : SWP_SHOWWINDOW;
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetWindowPos(container_->GetNativeView(), HWND_TOP, x, y, 0, 0,
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               SWP_NOSIZE | SWP_NOACTIVATE | show_flags);
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Rect bounds = container_->GetWindowBoundsInScreen();
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  container_->SetBounds(gfx::Rect(x, y, bounds.width(), bounds.height()));
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!container_->IsVisible())
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    container_->Show();
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DraggedTabView::Update() {
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SchedulePaint();
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)///////////////////////////////////////////////////////////////////////////////
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// DraggedTabView, views::View overrides:
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DraggedTabView::OnPaint(gfx::Canvas* canvas) {
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (show_contents_on_drag_)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PaintDetachedView(canvas);
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PaintFocusRect(canvas);
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DraggedTabView::Layout() {
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int max_width = GetPreferredSize().width();
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < renderers_.size(); ++i) {
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gfx::Rect bounds = renderer_bounds_[i];
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bounds.set_y(0);
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (base::i18n::IsRTL())
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bounds.set_x(max_width - bounds.x() - bounds.width());
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    renderers_[i]->SetBoundsRect(bounds);
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::Size DraggedTabView::GetPreferredSize() {
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!renderer_bounds_.empty());
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int max_renderer_x = renderer_bounds_.back().right();
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int width = std::max(max_renderer_x, contents_size_.width()) +
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      kTwiceDragFrameBorderSize;
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int height = renderer_bounds_.back().height() + kDragFrameBorderSize +
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      contents_size_.height();
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return gfx::Size(width, height);
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// DraggedTabView, private:
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DraggedTabView::PaintDetachedView(gfx::Canvas* canvas) {
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Size ps = GetPreferredSize();
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(pkotwicz): DIP enable this class.
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Canvas scale_canvas(ps, ui::SCALE_FACTOR_100P, false);
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SkBitmap& bitmap_device = const_cast<SkBitmap&>(
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      skia::GetTopDevice(*scale_canvas.sk_canvas())->accessBitmap(true));
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bitmap_device.eraseARGB(0, 0, 0, 0);
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int tab_height = renderer_bounds_.back().height();
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scale_canvas.FillRect(gfx::Rect(0, tab_height - kDragFrameBorderSize,
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  ps.width(), ps.height() - tab_height),
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        kDraggedTabBorderColor);
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Rect image_rect(kDragFrameBorderSize,
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       tab_height,
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       ps.width() - kTwiceDragFrameBorderSize,
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       contents_size_.height());
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scale_canvas.FillRect(image_rect, SK_ColorBLACK);
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  photobooth_->PaintScreenshotIntoCanvas(&scale_canvas, image_rect);
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < renderers_.size(); ++i)
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    renderers_[i]->Paint(&scale_canvas);
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SkBitmap mipmap = scale_canvas.ExtractImageRep().sk_bitmap();
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mipmap.buildMipMap(true);
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  skia::RefPtr<SkShader> bitmap_shader = skia::AdoptRef(
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SkShader::CreateBitmapShader(mipmap, SkShader::kClamp_TileMode,
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                   SkShader::kClamp_TileMode));
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SkMatrix shader_scale;
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  shader_scale.setScale(kScalingFactor, kScalingFactor);
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bitmap_shader->setLocalMatrix(shader_scale);
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SkPaint paint;
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  paint.setShader(bitmap_shader.get());
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  paint.setAntiAlias(true);
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  canvas->DrawRect(gfx::Rect(ps), paint);
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DraggedTabView::PaintFocusRect(gfx::Canvas* canvas) {
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Size ps = GetPreferredSize();
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  canvas->DrawFocusRect(
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gfx::Rect(0, 0,
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                static_cast<int>(ps.width() * kScalingFactor),
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                static_cast<int>(ps.height() * kScalingFactor)));
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::Size DraggedTabView::PreferredContainerSize() {
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Size ps = GetPreferredSize();
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return gfx::Size(ScaleValue(ps.width()), ScaleValue(ps.height()));
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int DraggedTabView::ScaleValue(int value) {
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return static_cast<int>(value * kScalingFactor);
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
193