Home | History | Annotate | Download | only in win
      1 /*
      2  * Copyright (C) 2006, 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 "Pasteboard.h"
     28 
     29 #include "BitmapInfo.h"
     30 #include "CString.h"
     31 #include "ClipboardUtilitiesWin.h"
     32 #include "Document.h"
     33 #include "DocumentFragment.h"
     34 #include "Element.h"
     35 #include "Frame.h"
     36 #include "HitTestResult.h"
     37 #include "Image.h"
     38 #include "KURL.h"
     39 #include "Page.h"
     40 #include "Range.h"
     41 #include "RenderImage.h"
     42 #include "TextEncoding.h"
     43 #include "markup.h"
     44 
     45 namespace WebCore {
     46 
     47 static UINT HTMLClipboardFormat = 0;
     48 static UINT BookmarkClipboardFormat = 0;
     49 static UINT WebSmartPasteFormat = 0;
     50 
     51 static LRESULT CALLBACK PasteboardOwnerWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
     52 {
     53     LRESULT lresult = 0;
     54     LONG_PTR longPtr = GetWindowLongPtr(hWnd, 0);
     55 
     56     switch(message) {
     57     case WM_RENDERFORMAT:
     58         // This message comes when SetClipboardData was sent a null data handle
     59         // and now it's come time to put the data on the clipboard.
     60         break;
     61     case WM_RENDERALLFORMATS:
     62         // This message comes when SetClipboardData was sent a null data handle
     63         // and now this application is about to quit, so it must put data on
     64         // the clipboard before it exits.
     65         break;
     66     case WM_DRAWCLIPBOARD:
     67         break;
     68     case WM_DESTROY:
     69         break;
     70     case WM_CHANGECBCHAIN:
     71         break;
     72     default:
     73         lresult = DefWindowProc(hWnd, message, wParam, lParam);
     74         break;
     75     }
     76     return lresult;
     77 }
     78 
     79 Pasteboard* Pasteboard::generalPasteboard()
     80 {
     81     static Pasteboard* pasteboard = new Pasteboard;
     82     return pasteboard;
     83 }
     84 
     85 Pasteboard::Pasteboard()
     86 {
     87     // make a dummy HWND to be the Windows clipboard's owner
     88     WNDCLASSEX wcex = {0};
     89     wcex.cbSize = sizeof(WNDCLASSEX);
     90     wcex.lpfnWndProc    = PasteboardOwnerWndProc;
     91     wcex.hInstance      = Page::instanceHandle();
     92     wcex.lpszClassName  = L"PasteboardOwnerWindowClass";
     93     ::RegisterClassEx(&wcex);
     94 
     95     m_owner = ::CreateWindow(L"PasteboardOwnerWindowClass", L"PasteboardOwnerWindow", 0, 0, 0, 0, 0,
     96         HWND_MESSAGE, 0, 0, 0);
     97 
     98     HTMLClipboardFormat = ::RegisterClipboardFormat(L"HTML Format");
     99     BookmarkClipboardFormat = ::RegisterClipboardFormat(L"UniformResourceLocatorW");
    100     WebSmartPasteFormat = ::RegisterClipboardFormat(L"WebKit Smart Paste Format");
    101 }
    102 
    103 void Pasteboard::clear()
    104 {
    105     if (::OpenClipboard(m_owner)) {
    106         ::EmptyClipboard();
    107         ::CloseClipboard();
    108     }
    109 }
    110 
    111 void Pasteboard::writeSelection(Range* selectedRange, bool canSmartCopyOrDelete, Frame* frame)
    112 {
    113     clear();
    114 
    115     // Put CF_HTML format on the pasteboard
    116     if (::OpenClipboard(m_owner)) {
    117         ExceptionCode ec = 0;
    118         Vector<char> data;
    119         markupToCF_HTML(createMarkup(selectedRange, 0, AnnotateForInterchange),
    120             selectedRange->startContainer(ec)->document()->url().string(), data);
    121         HGLOBAL cbData = createGlobalData(data);
    122         if (!::SetClipboardData(HTMLClipboardFormat, cbData))
    123             ::GlobalFree(cbData);
    124         ::CloseClipboard();
    125     }
    126 
    127     // Put plain string on the pasteboard. CF_UNICODETEXT covers CF_TEXT as well
    128     String str = frame->selectedText();
    129     replaceNewlinesWithWindowsStyleNewlines(str);
    130     replaceNBSPWithSpace(str);
    131     if (::OpenClipboard(m_owner)) {
    132         HGLOBAL cbData = createGlobalData(str);
    133         if (!::SetClipboardData(CF_UNICODETEXT, cbData))
    134             ::GlobalFree(cbData);
    135         ::CloseClipboard();
    136     }
    137 
    138     // enable smart-replacing later on by putting dummy data on the pasteboard
    139     if (canSmartCopyOrDelete) {
    140         if (::OpenClipboard(m_owner)) {
    141             ::SetClipboardData(WebSmartPasteFormat, NULL);
    142             ::CloseClipboard();
    143         }
    144 
    145     }
    146 }
    147 
    148 void Pasteboard::writePlainText(const String& text)
    149 {
    150     clear();
    151 
    152     // Put plain string on the pasteboard. CF_UNICODETEXT covers CF_TEXT as well
    153     String str = text;
    154     replaceNewlinesWithWindowsStyleNewlines(str);
    155     if (::OpenClipboard(m_owner)) {
    156         HGLOBAL cbData = createGlobalData(str);
    157         if (!::SetClipboardData(CF_UNICODETEXT, cbData))
    158             ::GlobalFree(cbData);
    159         ::CloseClipboard();
    160     }
    161 }
    162 
    163 void Pasteboard::writeURL(const KURL& url, const String& titleStr, Frame* frame)
    164 {
    165     ASSERT(!url.isEmpty());
    166 
    167     clear();
    168 
    169     String title(titleStr);
    170     if (title.isEmpty()) {
    171         title = url.lastPathComponent();
    172         if (title.isEmpty())
    173             title = url.host();
    174     }
    175 
    176     // write to clipboard in format com.apple.safari.bookmarkdata to be able to paste into the bookmarks view with appropriate title
    177     if (::OpenClipboard(m_owner)) {
    178         HGLOBAL cbData = createGlobalData(url, title);
    179         if (!::SetClipboardData(BookmarkClipboardFormat, cbData))
    180             ::GlobalFree(cbData);
    181         ::CloseClipboard();
    182     }
    183 
    184     // write to clipboard in format CF_HTML to be able to paste into contenteditable areas as a link
    185     if (::OpenClipboard(m_owner)) {
    186         Vector<char> data;
    187         markupToCF_HTML(urlToMarkup(url, title), "", data);
    188         HGLOBAL cbData = createGlobalData(data);
    189         if (!::SetClipboardData(HTMLClipboardFormat, cbData))
    190             ::GlobalFree(cbData);
    191         ::CloseClipboard();
    192     }
    193 
    194     // bare-bones CF_UNICODETEXT support
    195     if (::OpenClipboard(m_owner)) {
    196         HGLOBAL cbData = createGlobalData(url.string());
    197         if (!::SetClipboardData(CF_UNICODETEXT, cbData))
    198             ::GlobalFree(cbData);
    199         ::CloseClipboard();
    200     }
    201 }
    202 
    203 void Pasteboard::writeImage(Node* node, const KURL&, const String&)
    204 {
    205     ASSERT(node && node->renderer() && node->renderer()->isImage());
    206     RenderImage* renderer = toRenderImage(node->renderer());
    207     CachedImage* cachedImage = renderer->cachedImage();
    208     ASSERT(cachedImage);
    209     Image* image = cachedImage->image();
    210     ASSERT(image);
    211 
    212     clear();
    213 
    214     HDC dc = GetDC(0);
    215     HDC compatibleDC = CreateCompatibleDC(0);
    216     HDC sourceDC = CreateCompatibleDC(0);
    217     HBITMAP resultBitmap = CreateCompatibleBitmap(dc, image->width(), image->height());
    218     HBITMAP oldBitmap = (HBITMAP)SelectObject(compatibleDC, resultBitmap);
    219 
    220     BitmapInfo bmInfo = BitmapInfo::create(image->size());
    221 
    222     HBITMAP coreBitmap = CreateDIBSection(dc, &bmInfo, DIB_RGB_COLORS, 0, 0, 0);
    223     HBITMAP oldSource = (HBITMAP)SelectObject(sourceDC, coreBitmap);
    224     image->getHBITMAP(coreBitmap);
    225 
    226     BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA};
    227     AlphaBlend(compatibleDC, 0, 0, image->width(), image->height(),
    228         sourceDC, 0, 0, image->width(), image->height(), bf);
    229 
    230     SelectObject(compatibleDC, oldBitmap);
    231     SelectObject(sourceDC, oldSource);
    232 
    233     DeleteObject(oldBitmap);
    234     DeleteObject(oldSource);
    235     DeleteObject(coreBitmap);
    236     ReleaseDC(0, dc);
    237     DeleteDC(compatibleDC);
    238     DeleteDC(sourceDC);
    239 
    240     if (::OpenClipboard(m_owner)) {
    241         ::SetClipboardData(CF_BITMAP, resultBitmap);
    242         ::CloseClipboard();
    243     }
    244 }
    245 
    246 bool Pasteboard::canSmartReplace()
    247 {
    248     return ::IsClipboardFormatAvailable(WebSmartPasteFormat);
    249 }
    250 
    251 String Pasteboard::plainText(Frame* frame)
    252 {
    253     if (::IsClipboardFormatAvailable(CF_UNICODETEXT) && ::OpenClipboard(m_owner)) {
    254         HANDLE cbData = ::GetClipboardData(CF_UNICODETEXT);
    255         if (cbData) {
    256             UChar* buffer = (UChar*)::GlobalLock(cbData);
    257             String fromClipboard(buffer);
    258             ::GlobalUnlock(cbData);
    259             ::CloseClipboard();
    260             return fromClipboard;
    261         } else
    262             ::CloseClipboard();
    263     }
    264 
    265     if (::IsClipboardFormatAvailable(CF_TEXT) && ::OpenClipboard(m_owner)) {
    266         HANDLE cbData = ::GetClipboardData(CF_TEXT);
    267         if (cbData) {
    268             char* buffer = (char*)::GlobalLock(cbData);
    269             String fromClipboard(buffer);
    270             ::GlobalUnlock(cbData);
    271             ::CloseClipboard();
    272             return fromClipboard;
    273         } else
    274             ::CloseClipboard();
    275     }
    276 
    277     return String();
    278 }
    279 
    280 PassRefPtr<DocumentFragment> Pasteboard::documentFragment(Frame* frame, PassRefPtr<Range> context, bool allowPlainText, bool& chosePlainText)
    281 {
    282     chosePlainText = false;
    283 
    284     if (::IsClipboardFormatAvailable(HTMLClipboardFormat) && ::OpenClipboard(m_owner)) {
    285         // get data off of clipboard
    286         HANDLE cbData = ::GetClipboardData(HTMLClipboardFormat);
    287         if (cbData) {
    288             SIZE_T dataSize = ::GlobalSize(cbData);
    289             String cf_html(UTF8Encoding().decode((char*)::GlobalLock(cbData), dataSize));
    290             ::GlobalUnlock(cbData);
    291             ::CloseClipboard();
    292 
    293             PassRefPtr<DocumentFragment> fragment = fragmentFromCF_HTML(frame->document(), cf_html);
    294             if (fragment)
    295                 return fragment;
    296         } else
    297             ::CloseClipboard();
    298     }
    299 
    300     if (allowPlainText && ::IsClipboardFormatAvailable(CF_UNICODETEXT)) {
    301         chosePlainText = true;
    302         if (::OpenClipboard(m_owner)) {
    303             HANDLE cbData = ::GetClipboardData(CF_UNICODETEXT);
    304             if (cbData) {
    305                 UChar* buffer = (UChar*)GlobalLock(cbData);
    306                 String str(buffer);
    307                 ::GlobalUnlock( cbData );
    308                 ::CloseClipboard();
    309                 RefPtr<DocumentFragment> fragment = createFragmentFromText(context.get(), str);
    310                 if (fragment)
    311                     return fragment.release();
    312             } else
    313                 ::CloseClipboard();
    314         }
    315     }
    316 
    317     if (allowPlainText && ::IsClipboardFormatAvailable(CF_TEXT)) {
    318         chosePlainText = true;
    319         if (::OpenClipboard(m_owner)) {
    320             HANDLE cbData = ::GetClipboardData(CF_TEXT);
    321             if (cbData) {
    322                 char* buffer = (char*)GlobalLock(cbData);
    323                 String str(buffer);
    324                 ::GlobalUnlock( cbData );
    325                 ::CloseClipboard();
    326                 RefPtr<DocumentFragment> fragment = createFragmentFromText(context.get(), str);
    327                 if (fragment)
    328                     return fragment.release();
    329             } else
    330                 ::CloseClipboard();
    331         }
    332     }
    333 
    334     return 0;
    335 }
    336 
    337 } // namespace WebCore
    338