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