1 // Copyright (c) 2012 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.
5 #include "ui/base/dragdrop/drag_utils.h"
11 #include "base/win/scoped_comptr.h"
12 #include "base/win/scoped_hdc.h"
13 #include "third_party/skia/include/core/SkBitmap.h"
14 #include "ui/base/dragdrop/os_exchange_data.h"
15 #include "ui/base/dragdrop/os_exchange_data_provider_win.h"
16 #include "ui/gfx/canvas.h"
17 #include "ui/gfx/gdi_util.h"
18 #include "ui/gfx/geometry/size.h"
19 #include "ui/gfx/image/image_skia.h"
20 #include "ui/gfx/skbitmap_operations.h"
22 namespace drag_utils
{
24 static void SetDragImageOnDataObject(HBITMAP hbitmap
,
25 const gfx::Size
& size_in_pixels
,
26 const gfx::Vector2d
& cursor_offset
,
27 IDataObject
* data_object
) {
28 base::win::ScopedComPtr
<IDragSourceHelper
> helper
;
29 HRESULT rv
= CoCreateInstance(CLSID_DragDropHelper
, 0, CLSCTX_INPROC_SERVER
,
30 IID_IDragSourceHelper
, helper
.ReceiveVoid());
33 sdi
.sizeDragImage
= size_in_pixels
.ToSIZE();
34 sdi
.crColorKey
= 0xFFFFFFFF;
35 sdi
.hbmpDragImage
= hbitmap
;
36 sdi
.ptOffset
= gfx::PointAtOffsetFromOrigin(cursor_offset
).ToPOINT();
37 helper
->InitializeFromBitmap(&sdi
, data_object
);
41 // Blit the contents of the canvas to a new HBITMAP. It is the caller's
42 // responsibility to release the |bits| buffer.
43 static HBITMAP
CreateHBITMAPFromSkBitmap(const SkBitmap
& sk_bitmap
) {
44 base::win::ScopedGetDC
screen_dc(NULL
);
45 BITMAPINFOHEADER header
;
46 gfx::CreateBitmapHeader(sk_bitmap
.width(), sk_bitmap
.height(), &header
);
49 CreateDIBSection(screen_dc
, reinterpret_cast<BITMAPINFO
*>(&header
),
50 DIB_RGB_COLORS
, &bits
, NULL
, 0);
53 DCHECK_EQ(sk_bitmap
.rowBytes(), static_cast<size_t>(sk_bitmap
.width() * 4));
54 SkAutoLockPixels
lock(sk_bitmap
);
56 bits
, sk_bitmap
.getPixels(), sk_bitmap
.height() * sk_bitmap
.rowBytes());
60 void SetDragImageOnDataObject(const gfx::ImageSkia
& image_skia
,
61 const gfx::Vector2d
& cursor_offset
,
62 ui::OSExchangeData
* data_object
) {
63 DCHECK(data_object
&& !image_skia
.size().IsEmpty());
64 // InitializeFromBitmap() doesn't expect an alpha channel and is confused
65 // by premultiplied colors, so unpremultiply the bitmap.
66 // SetDragImageOnDataObject(HBITMAP) takes ownership of the bitmap.
67 HBITMAP bitmap
= CreateHBITMAPFromSkBitmap(
68 SkBitmapOperations::UnPreMultiply(*image_skia
.bitmap()));
70 // Attach 'bitmap' to the data_object.
71 SetDragImageOnDataObject(
73 gfx::Size(image_skia
.bitmap()->width(), image_skia
.bitmap()->height()),
75 ui::OSExchangeDataProviderWin::GetIDataObject(*data_object
));
78 // TODO: the above code is used in non-Ash, while below is used in Ash. If we
79 // could figure this context out then we wouldn't do unnecessary work. However
80 // as it stands getting this information in ui/base would be a layering
82 data_object
->provider().SetDragImage(image_skia
, cursor_offset
);
85 } // namespace drag_utils