webengine/osswebengine/WebKit/win/WebDragClient.cpp
changeset 0 dd21522fd290
equal deleted inserted replaced
-1:000000000000 0:dd21522fd290
       
     1 /*
       
     2  * Copyright (C) 2007 Apple Inc.  All rights reserved.
       
     3  *
       
     4  * Redistribution and use in source and binary forms, with or without
       
     5  * modification, are permitted provided that the following conditions
       
     6  * are met:
       
     7  * 1. Redistributions of source code must retain the above copyright
       
     8  *    notice, this list of conditions and the following disclaimer.
       
     9  * 2. Redistributions in binary form must reproduce the above copyright
       
    10  *    notice, this list of conditions and the following disclaimer in the
       
    11  *    documentation and/or other materials provided with the distribution.
       
    12  *
       
    13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
       
    14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
       
    15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
       
    16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
       
    17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
       
    18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
       
    19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
       
    20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
       
    21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
       
    22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
       
    23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
       
    24  */
       
    25 
       
    26 #include "config.h"
       
    27 #include "WebDragClient.h"
       
    28 #include "WebDropSource.h"
       
    29 #include "WebKitGraphics.h"
       
    30 #include "WebView.h"
       
    31 
       
    32 #include <shlobj.h>
       
    33 #include <CoreGraphics/CoreGraphics.h>
       
    34 
       
    35 #pragma warning(push, 0) 
       
    36 #include <WebCore/ClipboardWin.h>
       
    37 #include <WebCore/DragData.h>
       
    38 #include <WebCore/Font.h>
       
    39 #include <WebCore/FontDescription.h>
       
    40 #include <WebCore/FrameView.h>
       
    41 #include <WebCore/GraphicsContext.h>
       
    42 #include <WebCore/Page.h>
       
    43 #include <WebCore/StringTruncator.h>
       
    44 #include <WebCore/WebCoreTextRenderer.h>
       
    45 #pragma warning(pop) 
       
    46 
       
    47 namespace WebCore {
       
    48     HBITMAP allocImage(HDC dc, IntSize size, CGContextRef *targetRef);
       
    49 }
       
    50 
       
    51 
       
    52 #define DRAG_LABEL_BORDER_X             4
       
    53 // Keep border_y in synch with DragController::LinkDragBorderInset
       
    54 #define DRAG_LABEL_BORDER_Y             2
       
    55 #define DRAG_LABEL_RADIUS               5
       
    56 #define DRAG_LABEL_BORDER_Y_OFFSET              2
       
    57 
       
    58 #define MIN_DRAG_LABEL_WIDTH_BEFORE_CLIP        120
       
    59 
       
    60 // Observation says max size is 200x200
       
    61 #define MAX_DRAG_LABEL_WIDTH                    200
       
    62 #define MAX_DRAG_LABEL_STRING_WIDTH             (MAX_DRAG_LABEL_WIDTH - 2 * DRAG_LABEL_BORDER_X)
       
    63 
       
    64 #define DRAG_LINK_LABEL_FONT_SIZE   11
       
    65 #define DRAG_LINK_URL_FONT_SIZE   10
       
    66 
       
    67 using namespace WebCore;
       
    68 
       
    69 WebDragClient::WebDragClient(WebView* webView)
       
    70     : m_webView(webView) 
       
    71 {
       
    72     ASSERT(webView);
       
    73 }
       
    74 
       
    75 DragDestinationAction WebDragClient::actionMaskForDrag(DragData* dragData)
       
    76 {
       
    77     COMPtr<IWebUIDelegate> delegateRef = 0;
       
    78     //Default behaviour (eg. no delegate, or callback not implemented) is to allow
       
    79     //any action
       
    80     WebDragDestinationAction mask = WebDragDestinationActionAny;
       
    81     if (SUCCEEDED(m_webView->uiDelegate(&delegateRef)))
       
    82         delegateRef->dragDestinationActionMaskForDraggingInfo(m_webView, dragData->platformData(), &mask);
       
    83 
       
    84     return (DragDestinationAction)mask;
       
    85 }
       
    86 
       
    87 void WebDragClient::willPerformDragDestinationAction(DragDestinationAction action, DragData* dragData)
       
    88 {
       
    89     //Default delegate for willPerformDragDestinationAction has no side effects
       
    90     //so we just call the delegate, and don't worry about whether it's implemented
       
    91     COMPtr<IWebUIDelegate> delegateRef = 0;
       
    92     if (SUCCEEDED(m_webView->uiDelegate(&delegateRef)))
       
    93         delegateRef->willPerformDragDestinationAction(m_webView, (WebDragDestinationAction)action, dragData->platformData());
       
    94 }
       
    95 
       
    96 DragSourceAction WebDragClient::dragSourceActionMaskForPoint(const IntPoint& windowPoint)
       
    97 {
       
    98    COMPtr<IWebUIDelegate> delegateRef = 0;
       
    99    WebDragSourceAction action = WebDragSourceActionAny;
       
   100    POINT localpt = core(m_webView)->mainFrame()->view()->windowToContents(windowPoint);
       
   101    if (SUCCEEDED(m_webView->uiDelegate(&delegateRef)))
       
   102        delegateRef->dragSourceActionMaskForPoint(m_webView, &localpt, &action);
       
   103    return (DragSourceAction)action;
       
   104 }
       
   105 
       
   106 void WebDragClient::willPerformDragSourceAction(DragSourceAction, const IntPoint&, Clipboard*)
       
   107 {
       
   108 }
       
   109 
       
   110 void WebDragClient::startDrag(DragImageRef image, const IntPoint& imageOrigin, const IntPoint& dragPoint, Clipboard* clipboard, Frame* frame, bool isLink)
       
   111 {
       
   112     //FIXME: Allow UIDelegate to override behaviour <rdar://problem/5015953>
       
   113 
       
   114     //We liberally protect everything, to protect against a load occurring mid-drag
       
   115     RefPtr<Frame> frameProtector = frame;
       
   116     COMPtr<IDragSourceHelper> helper;
       
   117     COMPtr<IDataObject> dataObject;
       
   118     COMPtr<WebView> viewProtector = m_webView;
       
   119     COMPtr<IDropSource> source;
       
   120     if (FAILED(WebDropSource::createInstance(m_webView, &source)))
       
   121         return;
       
   122 
       
   123     dataObject = static_cast<ClipboardWin*>(clipboard)->dataObject();
       
   124     if (source && (image || dataObject)) {
       
   125         if (image) {
       
   126             if(SUCCEEDED(CoCreateInstance(CLSID_DragDropHelper, 0, CLSCTX_INPROC_SERVER,
       
   127                 IID_IDragSourceHelper,(LPVOID*)&helper))) {
       
   128                 BITMAP b;
       
   129                 GetObject(image, sizeof(BITMAP), &b);
       
   130                 SHDRAGIMAGE sdi;
       
   131                 sdi.sizeDragImage.cx = b.bmWidth;
       
   132                 sdi.sizeDragImage.cy = b.bmHeight;
       
   133                 sdi.crColorKey = 0xffffffff;
       
   134                 sdi.hbmpDragImage = image;
       
   135                 sdi.ptOffset.x = dragPoint.x() - imageOrigin.x();
       
   136                 sdi.ptOffset.y = dragPoint.y() - imageOrigin.y();
       
   137                 if (isLink)
       
   138                     sdi.ptOffset.y = b.bmHeight - sdi.ptOffset.y;
       
   139 
       
   140                 helper->InitializeFromBitmap(&sdi, dataObject.get());
       
   141             }
       
   142         }
       
   143 
       
   144         //FIXME: Ensure correct drag ops are available <rdar://problem/5015957>
       
   145         DWORD okEffect = DROPEFFECT_COPY | DROPEFFECT_LINK | DROPEFFECT_MOVE;
       
   146         DWORD effect;
       
   147         COMPtr<IWebUIDelegate> ui;
       
   148         if (SUCCEEDED(m_webView->uiDelegate(&ui))) {
       
   149             COMPtr<IWebUIDelegatePrivate> uiPrivate;
       
   150             if (SUCCEEDED(ui->QueryInterface(IID_IWebUIDelegatePrivate, (void**)&uiPrivate)))
       
   151                 if (SUCCEEDED(uiPrivate->doDragDrop(m_webView, dataObject.get(), source.get(), okEffect, &effect)))
       
   152                     return;
       
   153         }
       
   154 
       
   155         DoDragDrop(dataObject.get(), source.get(), okEffect, &effect);
       
   156     }
       
   157 }
       
   158 
       
   159 static Font dragLabelFont(int size, bool bold)
       
   160 {
       
   161     FontDescription desc;
       
   162     desc.setBold(bold);
       
   163     FontFamily family;
       
   164     family.setFamily("Lucida Grande");
       
   165     desc.setFamily(family);
       
   166     desc.setSpecifiedSize((float)size);
       
   167     desc.setComputedSize((float)size);
       
   168     Font result = Font(desc, 0, 0); 
       
   169     result.update();
       
   170     return result;
       
   171 }
       
   172 
       
   173 DragImageRef WebDragClient::createDragImageForLink(KURL& url, const String& inLabel, Frame*)
       
   174 {
       
   175     //This is more or less an exact match for the MacOS code
       
   176     static const Font labelFont = dragLabelFont(DRAG_LINK_LABEL_FONT_SIZE, true);
       
   177     static const Font urlFont = dragLabelFont(DRAG_LINK_URL_FONT_SIZE, false);
       
   178     bool drawURLString = true;
       
   179     bool clipURLString = false;
       
   180     bool clipLabelString = false;
       
   181 
       
   182     String urlString = url.url(); 
       
   183     String label = inLabel;
       
   184     if (label.isEmpty()) {
       
   185         drawURLString = false;
       
   186         label = urlString;
       
   187     }
       
   188 
       
   189     //First step in drawing the link drag image width
       
   190     TextRun labelRun(label.impl());
       
   191     TextRun urlRun(urlString.impl());
       
   192     IntSize labelSize(labelFont.width(labelRun), labelFont.ascent() + labelFont.descent());
       
   193 
       
   194     if (labelSize.width() > MAX_DRAG_LABEL_STRING_WIDTH){
       
   195         labelSize.setWidth(MAX_DRAG_LABEL_STRING_WIDTH);
       
   196         clipLabelString = true;
       
   197     }
       
   198     
       
   199     IntSize urlStringSize;
       
   200     IntSize imageSize(labelSize.width() + DRAG_LABEL_BORDER_X * 2, 
       
   201                       labelSize.height() + DRAG_LABEL_BORDER_Y * 2);
       
   202 
       
   203     if (drawURLString) {
       
   204         urlStringSize.setWidth(urlFont.width(urlRun));
       
   205         urlStringSize.setHeight(urlFont.ascent() + urlFont.descent()); 
       
   206         imageSize.setHeight(imageSize.height() + urlStringSize.height());
       
   207         if (urlStringSize.width() > MAX_DRAG_LABEL_STRING_WIDTH) {
       
   208             imageSize.setWidth(MAX_DRAG_LABEL_WIDTH);
       
   209             clipURLString = true;
       
   210         } else {
       
   211             imageSize.setWidth(std::max(labelSize.width(), urlStringSize.width()) + DRAG_LABEL_BORDER_X * 2);
       
   212         }
       
   213     }
       
   214 
       
   215     // We now know how big the image needs to be, so we create and
       
   216     // fill the background
       
   217     HBITMAP image = 0;
       
   218     HDC dc = GetDC(0);
       
   219     HDC workingDC = CreateCompatibleDC(dc);
       
   220     if (!workingDC) {
       
   221         ReleaseDC(0, dc);
       
   222         return 0;
       
   223     }
       
   224 
       
   225     CGContextRef contextRef;
       
   226     image = allocImage(workingDC, imageSize, &contextRef);
       
   227     if (!image) {
       
   228         DeleteDC(workingDC);
       
   229         ReleaseDC(0, dc);
       
   230         return 0;
       
   231     }
       
   232         
       
   233     ::SelectObject(workingDC, image);
       
   234     GraphicsContext context(contextRef);
       
   235     // On Mac alpha is {0.7, 0.7, 0.7, 0.8}, however we can't control alpha
       
   236     // for drag images on win, so we use 1
       
   237     static const Color backgroundColor(140, 140, 140);
       
   238     static const IntSize radii(DRAG_LABEL_RADIUS, DRAG_LABEL_RADIUS);
       
   239     context.setFont(labelFont);
       
   240     IntRect rect(0, 0, imageSize.width(), imageSize.height());
       
   241     context.fillRoundedRect(rect, radii, radii, radii, radii, backgroundColor);
       
   242  
       
   243     // Draw the text
       
   244     static const Color topColor(0, 0, 0, 255); //original alpha = 0.75
       
   245     static const Color bottomColor(255, 255, 255, 127); //original alpha = 0.5
       
   246     if (drawURLString) {
       
   247         if (clipURLString)
       
   248             urlString = StringTruncator::rightTruncate(urlString, imageSize.width() - (DRAG_LABEL_BORDER_X * 2.0f), urlFont, false);
       
   249         IntPoint textPos(DRAG_LABEL_BORDER_X, imageSize.height() - (DRAG_LABEL_BORDER_Y_OFFSET + urlFont.descent()));
       
   250         WebCoreDrawDoubledTextAtPoint(context, urlString, textPos, urlFont, topColor, bottomColor);
       
   251     }
       
   252     
       
   253     if (clipLabelString)
       
   254         label = StringTruncator::rightTruncate(label, imageSize.width() - (DRAG_LABEL_BORDER_X * 2.0f), labelFont, false);
       
   255 
       
   256     IntPoint textPos(DRAG_LABEL_BORDER_X, DRAG_LABEL_BORDER_Y + labelFont.pixelSize());
       
   257     WebCoreDrawDoubledTextAtPoint(context, label, textPos, labelFont, topColor, bottomColor);
       
   258 
       
   259     CGContextRelease(contextRef);
       
   260     DeleteDC(workingDC);
       
   261     ReleaseDC(0, dc);
       
   262     return image;
       
   263 }
       
   264 
       
   265 void WebDragClient::dragControllerDestroyed()
       
   266 {
       
   267     delete this;
       
   268 }