Home | History | Annotate | Download | only in tabs
      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