diff -r 000000000000 -r dd21522fd290 webengine/osswebengine/WebKit/win/WebDragClient.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/webengine/osswebengine/WebKit/win/WebDragClient.cpp Mon Mar 30 12:54:55 2009 +0300 @@ -0,0 +1,268 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "WebDragClient.h" +#include "WebDropSource.h" +#include "WebKitGraphics.h" +#include "WebView.h" + +#include +#include + +#pragma warning(push, 0) +#include +#include +#include +#include +#include +#include +#include +#include +#include +#pragma warning(pop) + +namespace WebCore { + HBITMAP allocImage(HDC dc, IntSize size, CGContextRef *targetRef); +} + + +#define DRAG_LABEL_BORDER_X 4 +// Keep border_y in synch with DragController::LinkDragBorderInset +#define DRAG_LABEL_BORDER_Y 2 +#define DRAG_LABEL_RADIUS 5 +#define DRAG_LABEL_BORDER_Y_OFFSET 2 + +#define MIN_DRAG_LABEL_WIDTH_BEFORE_CLIP 120 + +// Observation says max size is 200x200 +#define MAX_DRAG_LABEL_WIDTH 200 +#define MAX_DRAG_LABEL_STRING_WIDTH (MAX_DRAG_LABEL_WIDTH - 2 * DRAG_LABEL_BORDER_X) + +#define DRAG_LINK_LABEL_FONT_SIZE 11 +#define DRAG_LINK_URL_FONT_SIZE 10 + +using namespace WebCore; + +WebDragClient::WebDragClient(WebView* webView) + : m_webView(webView) +{ + ASSERT(webView); +} + +DragDestinationAction WebDragClient::actionMaskForDrag(DragData* dragData) +{ + COMPtr delegateRef = 0; + //Default behaviour (eg. no delegate, or callback not implemented) is to allow + //any action + WebDragDestinationAction mask = WebDragDestinationActionAny; + if (SUCCEEDED(m_webView->uiDelegate(&delegateRef))) + delegateRef->dragDestinationActionMaskForDraggingInfo(m_webView, dragData->platformData(), &mask); + + return (DragDestinationAction)mask; +} + +void WebDragClient::willPerformDragDestinationAction(DragDestinationAction action, DragData* dragData) +{ + //Default delegate for willPerformDragDestinationAction has no side effects + //so we just call the delegate, and don't worry about whether it's implemented + COMPtr delegateRef = 0; + if (SUCCEEDED(m_webView->uiDelegate(&delegateRef))) + delegateRef->willPerformDragDestinationAction(m_webView, (WebDragDestinationAction)action, dragData->platformData()); +} + +DragSourceAction WebDragClient::dragSourceActionMaskForPoint(const IntPoint& windowPoint) +{ + COMPtr delegateRef = 0; + WebDragSourceAction action = WebDragSourceActionAny; + POINT localpt = core(m_webView)->mainFrame()->view()->windowToContents(windowPoint); + if (SUCCEEDED(m_webView->uiDelegate(&delegateRef))) + delegateRef->dragSourceActionMaskForPoint(m_webView, &localpt, &action); + return (DragSourceAction)action; +} + +void WebDragClient::willPerformDragSourceAction(DragSourceAction, const IntPoint&, Clipboard*) +{ +} + +void WebDragClient::startDrag(DragImageRef image, const IntPoint& imageOrigin, const IntPoint& dragPoint, Clipboard* clipboard, Frame* frame, bool isLink) +{ + //FIXME: Allow UIDelegate to override behaviour + + //We liberally protect everything, to protect against a load occurring mid-drag + RefPtr frameProtector = frame; + COMPtr helper; + COMPtr dataObject; + COMPtr viewProtector = m_webView; + COMPtr source; + if (FAILED(WebDropSource::createInstance(m_webView, &source))) + return; + + dataObject = static_cast(clipboard)->dataObject(); + if (source && (image || dataObject)) { + if (image) { + if(SUCCEEDED(CoCreateInstance(CLSID_DragDropHelper, 0, CLSCTX_INPROC_SERVER, + IID_IDragSourceHelper,(LPVOID*)&helper))) { + BITMAP b; + GetObject(image, sizeof(BITMAP), &b); + SHDRAGIMAGE sdi; + sdi.sizeDragImage.cx = b.bmWidth; + sdi.sizeDragImage.cy = b.bmHeight; + sdi.crColorKey = 0xffffffff; + sdi.hbmpDragImage = image; + sdi.ptOffset.x = dragPoint.x() - imageOrigin.x(); + sdi.ptOffset.y = dragPoint.y() - imageOrigin.y(); + if (isLink) + sdi.ptOffset.y = b.bmHeight - sdi.ptOffset.y; + + helper->InitializeFromBitmap(&sdi, dataObject.get()); + } + } + + //FIXME: Ensure correct drag ops are available + DWORD okEffect = DROPEFFECT_COPY | DROPEFFECT_LINK | DROPEFFECT_MOVE; + DWORD effect; + COMPtr ui; + if (SUCCEEDED(m_webView->uiDelegate(&ui))) { + COMPtr uiPrivate; + if (SUCCEEDED(ui->QueryInterface(IID_IWebUIDelegatePrivate, (void**)&uiPrivate))) + if (SUCCEEDED(uiPrivate->doDragDrop(m_webView, dataObject.get(), source.get(), okEffect, &effect))) + return; + } + + DoDragDrop(dataObject.get(), source.get(), okEffect, &effect); + } +} + +static Font dragLabelFont(int size, bool bold) +{ + FontDescription desc; + desc.setBold(bold); + FontFamily family; + family.setFamily("Lucida Grande"); + desc.setFamily(family); + desc.setSpecifiedSize((float)size); + desc.setComputedSize((float)size); + Font result = Font(desc, 0, 0); + result.update(); + return result; +} + +DragImageRef WebDragClient::createDragImageForLink(KURL& url, const String& inLabel, Frame*) +{ + //This is more or less an exact match for the MacOS code + static const Font labelFont = dragLabelFont(DRAG_LINK_LABEL_FONT_SIZE, true); + static const Font urlFont = dragLabelFont(DRAG_LINK_URL_FONT_SIZE, false); + bool drawURLString = true; + bool clipURLString = false; + bool clipLabelString = false; + + String urlString = url.url(); + String label = inLabel; + if (label.isEmpty()) { + drawURLString = false; + label = urlString; + } + + //First step in drawing the link drag image width + TextRun labelRun(label.impl()); + TextRun urlRun(urlString.impl()); + IntSize labelSize(labelFont.width(labelRun), labelFont.ascent() + labelFont.descent()); + + if (labelSize.width() > MAX_DRAG_LABEL_STRING_WIDTH){ + labelSize.setWidth(MAX_DRAG_LABEL_STRING_WIDTH); + clipLabelString = true; + } + + IntSize urlStringSize; + IntSize imageSize(labelSize.width() + DRAG_LABEL_BORDER_X * 2, + labelSize.height() + DRAG_LABEL_BORDER_Y * 2); + + if (drawURLString) { + urlStringSize.setWidth(urlFont.width(urlRun)); + urlStringSize.setHeight(urlFont.ascent() + urlFont.descent()); + imageSize.setHeight(imageSize.height() + urlStringSize.height()); + if (urlStringSize.width() > MAX_DRAG_LABEL_STRING_WIDTH) { + imageSize.setWidth(MAX_DRAG_LABEL_WIDTH); + clipURLString = true; + } else { + imageSize.setWidth(std::max(labelSize.width(), urlStringSize.width()) + DRAG_LABEL_BORDER_X * 2); + } + } + + // We now know how big the image needs to be, so we create and + // fill the background + HBITMAP image = 0; + HDC dc = GetDC(0); + HDC workingDC = CreateCompatibleDC(dc); + if (!workingDC) { + ReleaseDC(0, dc); + return 0; + } + + CGContextRef contextRef; + image = allocImage(workingDC, imageSize, &contextRef); + if (!image) { + DeleteDC(workingDC); + ReleaseDC(0, dc); + return 0; + } + + ::SelectObject(workingDC, image); + GraphicsContext context(contextRef); + // On Mac alpha is {0.7, 0.7, 0.7, 0.8}, however we can't control alpha + // for drag images on win, so we use 1 + static const Color backgroundColor(140, 140, 140); + static const IntSize radii(DRAG_LABEL_RADIUS, DRAG_LABEL_RADIUS); + context.setFont(labelFont); + IntRect rect(0, 0, imageSize.width(), imageSize.height()); + context.fillRoundedRect(rect, radii, radii, radii, radii, backgroundColor); + + // Draw the text + static const Color topColor(0, 0, 0, 255); //original alpha = 0.75 + static const Color bottomColor(255, 255, 255, 127); //original alpha = 0.5 + if (drawURLString) { + if (clipURLString) + urlString = StringTruncator::rightTruncate(urlString, imageSize.width() - (DRAG_LABEL_BORDER_X * 2.0f), urlFont, false); + IntPoint textPos(DRAG_LABEL_BORDER_X, imageSize.height() - (DRAG_LABEL_BORDER_Y_OFFSET + urlFont.descent())); + WebCoreDrawDoubledTextAtPoint(context, urlString, textPos, urlFont, topColor, bottomColor); + } + + if (clipLabelString) + label = StringTruncator::rightTruncate(label, imageSize.width() - (DRAG_LABEL_BORDER_X * 2.0f), labelFont, false); + + IntPoint textPos(DRAG_LABEL_BORDER_X, DRAG_LABEL_BORDER_Y + labelFont.pixelSize()); + WebCoreDrawDoubledTextAtPoint(context, label, textPos, labelFont, topColor, bottomColor); + + CGContextRelease(contextRef); + DeleteDC(workingDC); + ReleaseDC(0, dc); + return image; +} + +void WebDragClient::dragControllerDestroyed() +{ + delete this; +}