// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/drag_utils.h" #include #include #include #include "base/file_util.h" #include "base/gfx/gdi_util.h" #include "base/gfx/point.h" #include "base/string_util.h" #include "chrome/app/theme/theme_resources.h" #include "chrome/browser/views/bookmark_bar_view.h" #include "chrome/common/gfx/chrome_canvas.h" #include "chrome/common/gfx/chrome_font.h" #include "chrome/common/os_exchange_data.h" #include "chrome/common/resource_bundle.h" #include "chrome/common/win_util.h" #include "chrome/views/text_button.h" #include "googleurl/src/gurl.h" namespace drag_utils { // Maximum width of the link drag image in pixels. static const int kLinkDragImageMaxWidth = 200; static const int kLinkDragImageVPadding = 3; static const int kLinkDragImageVSpacing = 2; static const int kLinkDragImageHPadding = 4; static const SkColor kLinkDragImageBGColor = SkColorSetRGB(131, 146, 171); //static const SkColor kLinkDragImageBGColor = SkColorSetRGB(195, 217, 255); static const SkColor kLinkDragImageTextColor = SK_ColorBLACK; // File dragging pixel measurements static const int kFileDragImageMaxWidth = 200; static const SkColor kFileDragImageTextColor = SK_ColorBLACK; static void SetDragImageOnDataObject(HBITMAP hbitmap, int width, int height, int cursor_offset_x, int cursor_offset_y, IDataObject* data_object) { IDragSourceHelper* helper = NULL; HRESULT rv = CoCreateInstance(CLSID_DragDropHelper, 0, CLSCTX_INPROC_SERVER, IID_IDragSourceHelper, reinterpret_cast(&helper)); if (SUCCEEDED(rv)) { SHDRAGIMAGE sdi; sdi.sizeDragImage.cx = width; sdi.sizeDragImage.cy = height; sdi.crColorKey = 0xFFFFFFFF; sdi.hbmpDragImage = hbitmap; sdi.ptOffset.x = cursor_offset_x; sdi.ptOffset.y = cursor_offset_y; helper->InitializeFromBitmap(&sdi, data_object); } }; // Blit the contents of the canvas to a new HBITMAP. It is the caller's // responsibility to release the |bits| buffer. static HBITMAP CreateBitmapFromCanvas(const ChromeCanvas& canvas, int width, int height) { HDC screen_dc = GetDC(NULL); BITMAPINFOHEADER header; gfx::CreateBitmapHeader(width, height, &header); void* bits; HBITMAP bitmap = CreateDIBSection(screen_dc, reinterpret_cast(&header), DIB_RGB_COLORS, &bits, NULL, 0); HDC compatible_dc = CreateCompatibleDC(screen_dc); HGDIOBJ old_object = SelectObject(compatible_dc, bitmap); BitBlt(compatible_dc, 0, 0, width, height, canvas.getTopPlatformDevice().getBitmapDC(), 0, 0, SRCCOPY); SelectObject(compatible_dc, old_object); ReleaseDC(NULL, compatible_dc); ReleaseDC(NULL, screen_dc); return bitmap; } void CreateDragImageForLink(const GURL& url, const std::wstring& title, IDataObject* data_object) { // First calculate our dimensions. ChromeFont title_font = ResourceBundle::GetSharedInstance().GetFont(ResourceBundle::BaseFont). DeriveFont(0, ChromeFont::BOLD); ChromeFont url_font = ResourceBundle::GetSharedInstance().GetFont(ResourceBundle::SmallFont); const int title_height = title_font.height(); const int url_height = url_font.height(); const int width = kLinkDragImageMaxWidth; const int height = kLinkDragImageVPadding * 2 + kLinkDragImageVSpacing + title_height + url_height; // Now create a canvas and render the dragged representation into it. ChromeCanvas canvas(width, height, true); // Paint the alpha layer canvas.FillRectInt(SK_ColorWHITE, 0, 0, kLinkDragImageMaxWidth, height); // kLinkDragImageTransparentColor // Paint the background SkPaint paint; paint.setFlags(SkPaint::kAntiAlias_Flag); paint.setStyle(SkPaint::kFill_Style); paint.setColor(kLinkDragImageBGColor); SkRect bounds_rect; bounds_rect.set(0, 0, SkIntToScalar(width), SkIntToScalar(height)); canvas.drawRoundRect(bounds_rect, 3, 3, paint); // Paint the link title canvas.DrawStringInt(title, title_font, kLinkDragImageTextColor, kLinkDragImageHPadding, kLinkDragImageVPadding, kLinkDragImageMaxWidth - 2 * kLinkDragImageHPadding, title_height); // Paint the link URL canvas.DrawStringInt(UTF8ToWide(url.spec()), url_font, kLinkDragImageTextColor, kLinkDragImageHPadding, kLinkDragImageVPadding + title_height + kLinkDragImageVSpacing, kLinkDragImageMaxWidth - 2 * kLinkDragImageHPadding, url_height); SetDragImageOnDataObject(canvas, kLinkDragImageMaxWidth, height, kLinkDragImageMaxWidth / 2, height - kLinkDragImageVPadding, data_object); } void SetURLAndDragImage(const GURL& url, const std::wstring& title, const SkBitmap& icon, OSExchangeData* data) { DCHECK(url.is_valid() && data); data->SetURL(url, title); // Create a button to render the drag image for us. views::TextButton button(title.empty() ? UTF8ToWide(url.spec()) : title); button.set_max_width(BookmarkBarView::kMaxButtonWidth); if (icon.isNull()) { button.SetIcon(*ResourceBundle::GetSharedInstance().GetBitmapNamed( IDR_DEFAULT_FAVICON)); } else { button.SetIcon(icon); } gfx::Size prefsize = button.GetPreferredSize(); button.SetBounds(0, 0, prefsize.width(), prefsize.height()); // Render the image. ChromeCanvas canvas(prefsize.width(), prefsize.height(), false); button.Paint(&canvas, true); SetDragImageOnDataObject(canvas, prefsize.width(), prefsize.height(), prefsize.width() / 2, prefsize.height() / 2, data); } void CreateDragImageForFile(const std::wstring& file_name, SkBitmap* icon, IDataObject* data_object) { DCHECK(icon); DCHECK(data_object); // Set up our text portion const std::wstring& name = file_util::GetFilenameFromPath(file_name); ResourceBundle& rb = ResourceBundle::GetSharedInstance(); ChromeFont font = rb.GetFont(ResourceBundle::BaseFont); const int width = kFileDragImageMaxWidth; const int height = font.height() + icon->height() + kLinkDragImageVPadding; ChromeCanvas canvas(width, height, false /* translucent */); // Paint the icon. canvas.DrawBitmapInt(*icon, (width - icon->width()) / 2, 0); // Paint the file name. canvas.DrawStringInt(name, font, kFileDragImageTextColor, 0, icon->height() + kLinkDragImageVPadding, width, font.height(), ChromeCanvas::TEXT_ALIGN_CENTER); SetDragImageOnDataObject(canvas, width, height, width / 2, kLinkDragImageVPadding, data_object); } void SetDragImageOnDataObject(const ChromeCanvas& canvas, int width, int height, int cursor_x_offset, int cursor_y_offset, IDataObject* data_object) { DCHECK(data_object && width > 0 && height > 0); // SetDragImageOnDataObject(HBITMAP) takes ownership of the bitmap. HBITMAP bitmap = CreateBitmapFromCanvas(canvas, width, height); // Attach 'bitmap' to the data_object. SetDragImageOnDataObject(bitmap, width, height, cursor_x_offset, cursor_y_offset, data_object); } } // namespace drag_utils