Home | History | Annotate | Download | only in wince
      1 /*
      2  * Copyright (C) 2006, 2007 Apple Inc.  All rights reserved.
      3  * Copyright (C) 2007-2009 Torch Mobile, Inc.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  * 2. Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  *
     14  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
     15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
     18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     25  */
     26 
     27 
     28 #include "config.h"
     29 #include "Pasteboard.h"
     30 
     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 "WebCoreInstanceHandle.h"
     44 #include "markup.h"
     45 #include <wtf/text/CString.h>
     46 
     47 namespace WebCore {
     48 
     49 static UINT HTMLClipboardFormat = 0;
     50 static UINT BookmarkClipboardFormat = 0;
     51 static UINT WebSmartPasteFormat = 0;
     52 
     53 extern HDC hScreenDC;
     54 
     55 static LRESULT CALLBACK PasteboardOwnerWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
     56 {
     57     LRESULT lresult = 0;
     58     LONG longPtr = GetWindowLong(hWnd, 0);
     59 
     60     switch (message) {
     61     case WM_RENDERFORMAT:
     62         // This message comes when SetClipboardData was sent a null data handle
     63         // and now it's come time to put the data on the clipboard.
     64         break;
     65     case WM_RENDERALLFORMATS:
     66         // This message comes when SetClipboardData was sent a null data handle
     67         // and now this application is about to quit, so it must put data on
     68         // the clipboard before it exits.
     69         break;
     70     case WM_DESTROY:
     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     WNDCLASS wc = {0};
     89     memset(&wc, 0, sizeof(wc));
     90     wc.lpfnWndProc    = PasteboardOwnerWndProc;
     91     wc.hInstance      = WebCore::instanceHandle();
     92     wc.lpszClassName  = L"PasteboardOwnerWindowClass";
     93     ::RegisterClass(&wc);
     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), selectedRange->startContainer(ec)->document()->url(), data);
    120         HGLOBAL cbData = createGlobalData(data);
    121         if (!::SetClipboardData(HTMLClipboardFormat, cbData))
    122             ::GlobalFree(cbData);
    123         ::CloseClipboard();
    124     }
    125 
    126     // Put plain string on the pasteboard. CF_UNICODETEXT covers CF_TEXT as well
    127     String str = frame->selectedText();
    128     replaceNewlinesWithWindowsStyleNewlines(str);
    129     replaceNBSPWithSpace(str);
    130     if (::OpenClipboard(m_owner)) {
    131         HGLOBAL cbData = createGlobalData(str);
    132         if (!::SetClipboardData(CF_UNICODETEXT, cbData))
    133             ::GlobalFree(cbData);
    134         ::CloseClipboard();
    135     }
    136 
    137     // enable smart-replacing later on by putting dummy data on the pasteboard
    138     if (canSmartCopyOrDelete) {
    139         if (::OpenClipboard(m_owner)) {
    140             ::SetClipboardData(WebSmartPasteFormat, 0);
    141             ::CloseClipboard();
    142         }
    143     }
    144 }
    145 
    146 void Pasteboard::writePlainText(const String& text)
    147 {
    148     clear();
    149 
    150     // Put plain string on the pasteboard. CF_UNICODETEXT covers CF_TEXT as well
    151     String str = text;
    152     replaceNewlinesWithWindowsStyleNewlines(str);
    153     if (::OpenClipboard(m_owner)) {
    154         HGLOBAL cbData = createGlobalData(str);
    155         if (!::SetClipboardData(CF_UNICODETEXT, cbData))
    156             ::GlobalFree(cbData);
    157         ::CloseClipboard();
    158     }
    159 }
    160 
    161 void Pasteboard::writeURL(const KURL& url, const String& titleStr, Frame* frame)
    162 {
    163     ASSERT(!url.isEmpty());
    164 
    165     clear();
    166 
    167     String title(titleStr);
    168     if (title.isEmpty()) {
    169         title = url.lastPathComponent();
    170         if (title.isEmpty())
    171             title = url.host();
    172     }
    173 
    174     // write to clipboard in format com.apple.safari.bookmarkdata to be able to paste into the bookmarks view with appropriate title
    175     if (::OpenClipboard(m_owner)) {
    176         HGLOBAL cbData = createGlobalData(url, title);
    177         if (!::SetClipboardData(BookmarkClipboardFormat, cbData))
    178             ::GlobalFree(cbData);
    179         ::CloseClipboard();
    180     }
    181 
    182     // write to clipboard in format CF_HTML to be able to paste into contenteditable areas as a link
    183     if (::OpenClipboard(m_owner)) {
    184         Vector<char> data;
    185         markupToCF_HTML(urlToMarkup(url, title), "", data);
    186         HGLOBAL cbData = createGlobalData(data);
    187         if (!::SetClipboardData(HTMLClipboardFormat, cbData))
    188             ::GlobalFree(cbData);
    189         ::CloseClipboard();
    190     }
    191 
    192     // bare-bones CF_UNICODETEXT support
    193     if (::OpenClipboard(m_owner)) {
    194         HGLOBAL cbData = createGlobalData(url.string());
    195         if (!::SetClipboardData(CF_UNICODETEXT, cbData))
    196             ::GlobalFree(cbData);
    197         ::CloseClipboard();
    198     }
    199 }
    200 
    201 void Pasteboard::writeImage(Node* node, const KURL&, const String&)
    202 {
    203     ASSERT(node && node->renderer() && node->renderer()->isImage());
    204     RenderImage* renderer = static_cast<RenderImage*>(node->renderer());
    205     CachedImage* cachedImage = static_cast<CachedImage*>(renderer->cachedImage());
    206     ASSERT(cachedImage);
    207     Image* image = cachedImage->image();
    208     ASSERT(image);
    209 
    210     clear();
    211 
    212     RefPtr<SharedBitmap> sourceBmp = image->nativeImageForCurrentFrame();
    213     if (!sourceBmp)
    214         return;
    215 
    216     IntRect rect(0, 0, sourceBmp->width(), sourceBmp->height());
    217     BitmapInfo bmpInfo;
    218     void* pixels;
    219     HBITMAP resultBitmap = sourceBmp->clipBitmap(rect, true, bmpInfo, pixels);
    220     if (!resultBitmap)
    221         return;
    222 
    223     if (::OpenClipboard(m_owner)) {
    224         ::SetClipboardData(CF_BITMAP, resultBitmap);
    225         ::CloseClipboard();
    226     } else
    227         DeleteObject(resultBitmap);
    228 }
    229 
    230 bool Pasteboard::canSmartReplace()
    231 {
    232     return ::IsClipboardFormatAvailable(WebSmartPasteFormat);
    233 }
    234 
    235 String Pasteboard::plainText(Frame* frame)
    236 {
    237     if (::IsClipboardFormatAvailable(CF_UNICODETEXT) && ::OpenClipboard(m_owner)) {
    238         HANDLE cbData = ::GetClipboardData(CF_UNICODETEXT);
    239         if (cbData) {
    240             UChar* buffer = (UChar*)GlobalLock(cbData);
    241             String fromClipboard(buffer);
    242             GlobalUnlock(cbData);
    243             CloseClipboard();
    244             return fromClipboard;
    245         } else
    246             CloseClipboard();
    247     }
    248 
    249     if (::IsClipboardFormatAvailable(CF_TEXT) && ::OpenClipboard(m_owner)) {
    250         HANDLE cbData = ::GetClipboardData(CF_TEXT);
    251         if (cbData) {
    252             char* buffer = (char*)GlobalLock(cbData);
    253             String fromClipboard(buffer);
    254             GlobalUnlock(cbData);
    255             CloseClipboard();
    256             return fromClipboard;
    257         } else
    258             CloseClipboard();
    259     }
    260 
    261     return String();
    262 }
    263 
    264 PassRefPtr<DocumentFragment> Pasteboard::documentFragment(Frame* frame, PassRefPtr<Range> context, bool allowPlainText, bool& chosePlainText)
    265 {
    266     chosePlainText = false;
    267 
    268     if (::IsClipboardFormatAvailable(HTMLClipboardFormat) && ::OpenClipboard(m_owner)) {
    269         // get data off of clipboard
    270         HANDLE cbData = ::GetClipboardData(HTMLClipboardFormat);
    271         if (cbData) {
    272             SIZE_T dataSize = ::GlobalSize(cbData);
    273             String cf_html(UTF8Encoding().decode((char*)GlobalLock(cbData), dataSize));
    274             GlobalUnlock(cbData);
    275             CloseClipboard();
    276 
    277             PassRefPtr<DocumentFragment> fragment = fragmentFromCF_HTML(frame->document(), cf_html);
    278             if (fragment)
    279                 return fragment;
    280         } else
    281             CloseClipboard();
    282     }
    283 
    284     if (allowPlainText && IsClipboardFormatAvailable(CF_UNICODETEXT)) {
    285         chosePlainText = true;
    286         if (OpenClipboard(m_owner)) {
    287             HANDLE cbData = GetClipboardData(CF_UNICODETEXT);
    288             if (cbData) {
    289                 UChar* buffer = (UChar*)GlobalLock(cbData);
    290                 String str(buffer);
    291                 GlobalUnlock(cbData);
    292                 CloseClipboard();
    293                 RefPtr<DocumentFragment> fragment = createFragmentFromText(context.get(), str);
    294                 if (fragment)
    295                     return fragment.release();
    296             } else
    297                 CloseClipboard();
    298         }
    299     }
    300 
    301     if (allowPlainText && ::IsClipboardFormatAvailable(CF_TEXT)) {
    302         chosePlainText = true;
    303         if (::OpenClipboard(m_owner)) {
    304             HANDLE cbData = ::GetClipboardData(CF_TEXT);
    305             if (cbData) {
    306                 char* buffer = (char*)GlobalLock(cbData);
    307                 String str(buffer);
    308                 GlobalUnlock(cbData);
    309                 CloseClipboard();
    310                 RefPtr<DocumentFragment> fragment = createFragmentFromText(context.get(), str);
    311                 if (fragment)
    312                     return fragment.release();
    313             } else
    314                 CloseClipboard();
    315         }
    316     }
    317 
    318     return 0;
    319 }
    320 
    321 bool Pasteboard::hasData()
    322 {
    323     return hasDataInFormat(CF_UNICODETEXT) || hasDataInFormat(CF_TEXT);
    324 }
    325 
    326 bool Pasteboard::hasDataInFormat(unsigned int format)
    327 {
    328     return ::IsClipboardFormatAvailable(format);
    329 }
    330 
    331 } // namespace WebCore
    332