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. 4 5#include "ui/base/dragdrop/drag_utils.h" 6 7#include <objidl.h> 8#include <shlobj.h> 9#include <shobjidl.h> 10 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/image/image_skia.h" 19#include "ui/gfx/skbitmap_operations.h" 20 21namespace drag_utils { 22 23static void SetDragImageOnDataObject(HBITMAP hbitmap, 24 const gfx::Size& size, 25 const gfx::Vector2d& cursor_offset, 26 IDataObject* data_object) { 27 base::win::ScopedComPtr<IDragSourceHelper> helper; 28 HRESULT rv = CoCreateInstance(CLSID_DragDropHelper, 0, CLSCTX_INPROC_SERVER, 29 IID_IDragSourceHelper, helper.ReceiveVoid()); 30 if (SUCCEEDED(rv)) { 31 SHDRAGIMAGE sdi; 32 sdi.sizeDragImage = size.ToSIZE(); 33 sdi.crColorKey = 0xFFFFFFFF; 34 sdi.hbmpDragImage = hbitmap; 35 sdi.ptOffset = gfx::PointAtOffsetFromOrigin(cursor_offset).ToPOINT(); 36 helper->InitializeFromBitmap(&sdi, data_object); 37 } 38} 39 40// Blit the contents of the canvas to a new HBITMAP. It is the caller's 41// responsibility to release the |bits| buffer. 42static HBITMAP CreateHBITMAPFromSkBitmap(const SkBitmap& sk_bitmap) { 43 base::win::ScopedGetDC screen_dc(NULL); 44 BITMAPINFOHEADER header; 45 gfx::CreateBitmapHeader(sk_bitmap.width(), sk_bitmap.height(), &header); 46 void* bits; 47 HBITMAP bitmap = 48 CreateDIBSection(screen_dc, reinterpret_cast<BITMAPINFO*>(&header), 49 DIB_RGB_COLORS, &bits, NULL, 0); 50 if (!bitmap || !bits) 51 return NULL; 52 DCHECK_EQ(sk_bitmap.rowBytes(), static_cast<size_t>(sk_bitmap.width() * 4)); 53 SkAutoLockPixels lock(sk_bitmap); 54 memcpy( 55 bits, sk_bitmap.getPixels(), sk_bitmap.height() * sk_bitmap.rowBytes()); 56 return bitmap; 57} 58 59void SetDragImageOnDataObject(const gfx::ImageSkia& image_skia, 60 const gfx::Size& size, 61 const gfx::Vector2d& cursor_offset, 62 ui::OSExchangeData* data_object) { 63 DCHECK(data_object && !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())); 69 if (bitmap) { 70 // Attach 'bitmap' to the data_object. 71 SetDragImageOnDataObject(bitmap, size, cursor_offset, 72 ui::OSExchangeDataProviderWin::GetIDataObject(*data_object)); 73 } 74 75#if defined(USE_AURA) 76 // TODO: the above code is used in non-Ash, while below is used in Ash. If we 77 // could figure this context out then we wouldn't do unnecessary work. However 78 // as it stands getting this information in ui/base would be a layering 79 // violation. 80 data_object->provider().SetDragImage(image_skia, cursor_offset); 81#endif 82} 83 84} // namespace drag_utils 85