initial import
[vuplus_webkit] / Source / WebCore / platform / win / PasteboardWin.cpp
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);
212
213     if (!(node->renderer() && node->renderer()->isImage()))
214         return;
215
216     RenderImage* renderer = toRenderImage(node->renderer());
217     CachedImage* cachedImage = renderer->cachedImage();
218     if (!cachedImage || cachedImage->errorOccurred())
219         return;
220     Image* image = cachedImage->image();
221     ASSERT(image);
222
223     clear();
224
225     HDC dc = GetDC(0);
226     HDC compatibleDC = CreateCompatibleDC(0);
227     HDC sourceDC = CreateCompatibleDC(0);
228     OwnPtr<HBITMAP> resultBitmap = adoptPtr(CreateCompatibleBitmap(dc, image->width(), image->height()));
229     HGDIOBJ oldBitmap = SelectObject(compatibleDC, resultBitmap.get());
230
231     BitmapInfo bmInfo = BitmapInfo::create(image->size());
232
233     HBITMAP coreBitmap = CreateDIBSection(dc, &bmInfo, DIB_RGB_COLORS, 0, 0, 0);
234     HGDIOBJ oldSource = SelectObject(sourceDC, coreBitmap);
235     image->getHBITMAP(coreBitmap);
236
237     BitBlt(compatibleDC, 0, 0, image->width(), image->height(), sourceDC, 0, 0, SRCCOPY);
238
239     SelectObject(sourceDC, oldSource);
240     DeleteObject(coreBitmap);
241
242     SelectObject(compatibleDC, oldBitmap);
243     DeleteDC(sourceDC);
244     DeleteDC(compatibleDC);
245     ReleaseDC(0, dc);
246
247     if (::OpenClipboard(m_owner)) {
248         ::SetClipboardData(CF_BITMAP, resultBitmap.leakPtr());
249         ::CloseClipboard();
250     }
251 }
252
253 bool Pasteboard::canSmartReplace()
254
255     return ::IsClipboardFormatAvailable(WebSmartPasteFormat);
256 }
257
258 String Pasteboard::plainText(Frame* frame)
259 {
260     if (::IsClipboardFormatAvailable(CF_UNICODETEXT) && ::OpenClipboard(m_owner)) {
261         HANDLE cbData = ::GetClipboardData(CF_UNICODETEXT);
262         if (cbData) {
263             UChar* buffer = static_cast<UChar*>(GlobalLock(cbData));
264             String fromClipboard(buffer);
265             GlobalUnlock(cbData);
266             ::CloseClipboard();
267             return fromClipboard;
268         }
269         ::CloseClipboard();
270     }
271
272     if (::IsClipboardFormatAvailable(CF_TEXT) && ::OpenClipboard(m_owner)) {
273         HANDLE cbData = ::GetClipboardData(CF_TEXT);
274         if (cbData) {
275             char* buffer = static_cast<char*>(GlobalLock(cbData));
276             String fromClipboard(buffer);
277             GlobalUnlock(cbData);
278             ::CloseClipboard();
279             return fromClipboard;
280         }
281         ::CloseClipboard();
282     }
283
284     return String();
285 }
286
287 PassRefPtr<DocumentFragment> Pasteboard::documentFragment(Frame* frame, PassRefPtr<Range> context, bool allowPlainText, bool& chosePlainText)
288 {
289     chosePlainText = false;
290     
291     if (::IsClipboardFormatAvailable(HTMLClipboardFormat) && ::OpenClipboard(m_owner)) {
292         // get data off of clipboard
293         HANDLE cbData = ::GetClipboardData(HTMLClipboardFormat);
294         if (cbData) {
295             SIZE_T dataSize = ::GlobalSize(cbData);
296             String cfhtml(UTF8Encoding().decode(static_cast<char*>(GlobalLock(cbData)), dataSize));
297             GlobalUnlock(cbData);
298             ::CloseClipboard();
299
300             PassRefPtr<DocumentFragment> fragment = fragmentFromCFHTML(frame->document(), cfhtml);
301             if (fragment)
302                 return fragment;
303         } else 
304             ::CloseClipboard();
305     }
306      
307     if (allowPlainText && ::IsClipboardFormatAvailable(CF_UNICODETEXT)) {
308         chosePlainText = true;
309         if (::OpenClipboard(m_owner)) {
310             HANDLE cbData = ::GetClipboardData(CF_UNICODETEXT);
311             if (cbData) {
312                 UChar* buffer = static_cast<UChar*>(GlobalLock(cbData));
313                 String str(buffer);
314                 GlobalUnlock(cbData);
315                 ::CloseClipboard();
316                 RefPtr<DocumentFragment> fragment = createFragmentFromText(context.get(), str);
317                 if (fragment)
318                     return fragment.release();
319             } else 
320                 ::CloseClipboard();
321         }
322     }
323
324     if (allowPlainText && ::IsClipboardFormatAvailable(CF_TEXT)) {
325         chosePlainText = true;
326         if (::OpenClipboard(m_owner)) {
327             HANDLE cbData = ::GetClipboardData(CF_TEXT);
328             if (cbData) {
329                 char* buffer = static_cast<char*>(GlobalLock(cbData));
330                 String str(buffer);
331                 GlobalUnlock(cbData);
332                 ::CloseClipboard();
333                 RefPtr<DocumentFragment> fragment = createFragmentFromText(context.get(), str);
334                 if (fragment)
335                     return fragment.release();
336             } else
337                 ::CloseClipboard();
338         }
339     }
340     
341     return 0;
342 }
343
344 } // namespace WebCore