cc8d18eeb645b89288c1957983d42620474ef184
[WebKit-https.git] / Source / WebCore / platform / wince / PasteboardWinCE.cpp
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 "NotImplemented.h"
40 #include "Page.h"
41 #include "Range.h"
42 #include "RenderImage.h"
43 #include "TextEncoding.h"
44 #include "WebCoreInstanceHandle.h"
45 #include "markup.h"
46 #include <wtf/text/CString.h>
47
48 namespace WebCore {
49
50 static UINT HTMLClipboardFormat = 0;
51 static UINT BookmarkClipboardFormat = 0;
52 static UINT WebSmartPasteFormat = 0;
53
54 extern HDC hScreenDC;
55
56 static LRESULT CALLBACK PasteboardOwnerWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
57 {
58     LRESULT lresult = 0;
59     LONG longPtr = GetWindowLong(hWnd, 0);
60
61     switch (message) {
62     case WM_RENDERFORMAT:
63         // This message comes when SetClipboardData was sent a null data handle
64         // and now it's come time to put the data on the clipboard.
65         break;
66     case WM_RENDERALLFORMATS:
67         // This message comes when SetClipboardData was sent a null data handle
68         // and now this application is about to quit, so it must put data on
69         // the clipboard before it exits.
70         break;
71     case WM_DESTROY:
72         break;
73     default:
74         lresult = DefWindowProc(hWnd, message, wParam, lParam);
75         break;
76     }
77     return lresult;
78 }
79
80 Pasteboard* Pasteboard::generalPasteboard()
81 {
82     static Pasteboard* pasteboard = new Pasteboard;
83     return pasteboard;
84 }
85
86 Pasteboard::Pasteboard()
87 {
88     // make a dummy HWND to be the Windows clipboard's owner
89     WNDCLASS wc = {0};
90     memset(&wc, 0, sizeof(wc));
91     wc.lpfnWndProc    = PasteboardOwnerWndProc;
92     wc.hInstance      = WebCore::instanceHandle();
93     wc.lpszClassName  = L"PasteboardOwnerWindowClass";
94     ::RegisterClass(&wc);
95
96     m_owner = ::CreateWindow(L"PasteboardOwnerWindowClass", L"PasteboardOwnerWindow", 0, 0, 0, 0, 0,
97         HWND_MESSAGE, 0, 0, 0);
98
99     HTMLClipboardFormat = ::RegisterClipboardFormat(L"HTML Format");
100     BookmarkClipboardFormat = ::RegisterClipboardFormat(L"UniformResourceLocatorW");
101     WebSmartPasteFormat = ::RegisterClipboardFormat(L"WebKit Smart Paste Format");
102 }
103
104 void Pasteboard::clear()
105 {
106     if (::OpenClipboard(m_owner)) {
107         ::EmptyClipboard();
108         ::CloseClipboard();
109     }
110 }
111
112 void Pasteboard::writeSelection(Range* selectedRange, bool canSmartCopyOrDelete, Frame* frame)
113 {
114     clear();
115
116     // Put CF_HTML format on the pasteboard
117     if (::OpenClipboard(m_owner)) {
118         ExceptionCode ec = 0;
119         Vector<char> data;
120         markupToCF_HTML(createMarkup(selectedRange, 0, AnnotateForInterchange), selectedRange->startContainer(ec)->document()->url(), 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, 0);
142             ::CloseClipboard();
143         }
144     }
145 }
146
147 void Pasteboard::writePlainText(const String& text, SmartReplaceOption smartReplaceOption)
148 {
149     clear();
150
151     // Put plain string on the pasteboard. CF_UNICODETEXT covers CF_TEXT as well
152     String str = text;
153     replaceNewlinesWithWindowsStyleNewlines(str);
154     if (::OpenClipboard(m_owner)) {
155         HGLOBAL cbData = createGlobalData(str);
156         if (!::SetClipboardData(CF_UNICODETEXT, cbData))
157             ::GlobalFree(cbData);
158         ::CloseClipboard();
159     }
160
161     // enable smart-replacing later on by putting dummy data on the pasteboard
162     if (smartReplaceOption == CanSmartReplace) {
163         if (::OpenClipboard(m_owner)) {
164             ::SetClipboardData(WebSmartPasteFormat, 0);
165             ::CloseClipboard();
166         }
167     }
168 }
169
170 void Pasteboard::writeURL(const KURL& url, const String& titleStr, Frame* frame)
171 {
172     ASSERT(!url.isEmpty());
173
174     clear();
175
176     String title(titleStr);
177     if (title.isEmpty()) {
178         title = url.lastPathComponent();
179         if (title.isEmpty())
180             title = url.host();
181     }
182
183     // write to clipboard in format com.apple.safari.bookmarkdata to be able to paste into the bookmarks view with appropriate title
184     if (::OpenClipboard(m_owner)) {
185         HGLOBAL cbData = createGlobalData(url, title);
186         if (!::SetClipboardData(BookmarkClipboardFormat, cbData))
187             ::GlobalFree(cbData);
188         ::CloseClipboard();
189     }
190
191     // write to clipboard in format CF_HTML to be able to paste into contenteditable areas as a link
192     if (::OpenClipboard(m_owner)) {
193         Vector<char> data;
194         markupToCF_HTML(urlToMarkup(url, title), "", data);
195         HGLOBAL cbData = createGlobalData(data);
196         if (!::SetClipboardData(HTMLClipboardFormat, cbData))
197             ::GlobalFree(cbData);
198         ::CloseClipboard();
199     }
200
201     // bare-bones CF_UNICODETEXT support
202     if (::OpenClipboard(m_owner)) {
203         HGLOBAL cbData = createGlobalData(url.string());
204         if (!::SetClipboardData(CF_UNICODETEXT, cbData))
205             ::GlobalFree(cbData);
206         ::CloseClipboard();
207     }
208 }
209
210 void Pasteboard::writeImage(Node* node, const KURL&, const String&)
211 {
212     ASSERT(node);
213
214     if (!(node->renderer() && node->renderer()->isImage()))
215         return;
216
217     RenderImage* renderer = static_cast<RenderImage*>(node->renderer());
218     CachedImage* cachedImage = static_cast<CachedImage*>(renderer->cachedImage());
219     ASSERT(cachedImage);
220     Image* image = cachedImage->imageForRenderer(renderer);
221     ASSERT(image);
222
223     clear();
224
225     RefPtr<SharedBitmap> sourceBmp = image->nativeImageForCurrentFrame();
226     if (!sourceBmp)
227         return;
228
229     IntRect rect(0, 0, sourceBmp->width(), sourceBmp->height());
230     BitmapInfo bmpInfo;
231     void* pixels;
232     HBITMAP resultBitmap = sourceBmp->clipBitmap(rect, true, bmpInfo, pixels);
233     if (!resultBitmap)
234         return;
235
236     if (::OpenClipboard(m_owner)) {
237         ::SetClipboardData(CF_BITMAP, resultBitmap);
238         ::CloseClipboard();
239     } else
240         DeleteObject(resultBitmap);
241 }
242
243 void Pasteboard::writeClipboard(Clipboard*)
244 {
245     notImplemented();
246 }
247
248 bool Pasteboard::canSmartReplace()
249 {
250     return ::IsClipboardFormatAvailable(WebSmartPasteFormat);
251 }
252
253 String Pasteboard::plainText(Frame* frame)
254 {
255     if (::IsClipboardFormatAvailable(CF_UNICODETEXT) && ::OpenClipboard(m_owner)) {
256         HANDLE cbData = ::GetClipboardData(CF_UNICODETEXT);
257         if (cbData) {
258             UChar* buffer = (UChar*)GlobalLock(cbData);
259             String fromClipboard(buffer);
260             GlobalUnlock(cbData);
261             CloseClipboard();
262             return fromClipboard;
263         } else
264             CloseClipboard();
265     }
266
267     if (::IsClipboardFormatAvailable(CF_TEXT) && ::OpenClipboard(m_owner)) {
268         HANDLE cbData = ::GetClipboardData(CF_TEXT);
269         if (cbData) {
270             char* buffer = (char*)GlobalLock(cbData);
271             String fromClipboard(buffer);
272             GlobalUnlock(cbData);
273             CloseClipboard();
274             return fromClipboard;
275         } else
276             CloseClipboard();
277     }
278
279     return String();
280 }
281
282 PassRefPtr<DocumentFragment> Pasteboard::documentFragment(Frame* frame, PassRefPtr<Range> context, bool allowPlainText, bool& chosePlainText)
283 {
284     chosePlainText = false;
285
286     if (::IsClipboardFormatAvailable(HTMLClipboardFormat) && ::OpenClipboard(m_owner)) {
287         // get data off of clipboard
288         HANDLE cbData = ::GetClipboardData(HTMLClipboardFormat);
289         if (cbData) {
290             SIZE_T dataSize = ::GlobalSize(cbData);
291             String cf_html(UTF8Encoding().decode((char*)GlobalLock(cbData), dataSize));
292             GlobalUnlock(cbData);
293             CloseClipboard();
294
295             PassRefPtr<DocumentFragment> fragment = fragmentFromCF_HTML(frame->document(), cf_html);
296             if (fragment)
297                 return fragment;
298         } else
299             CloseClipboard();
300     }
301
302     if (allowPlainText && IsClipboardFormatAvailable(CF_UNICODETEXT)) {
303         chosePlainText = true;
304         if (OpenClipboard(m_owner)) {
305             HANDLE cbData = GetClipboardData(CF_UNICODETEXT);
306             if (cbData) {
307                 UChar* buffer = (UChar*)GlobalLock(cbData);
308                 String str(buffer);
309                 GlobalUnlock(cbData);
310                 CloseClipboard();
311                 RefPtr<DocumentFragment> fragment = createFragmentFromText(context.get(), str);
312                 if (fragment)
313                     return fragment.release();
314             } else
315                 CloseClipboard();
316         }
317     }
318
319     if (allowPlainText && ::IsClipboardFormatAvailable(CF_TEXT)) {
320         chosePlainText = true;
321         if (::OpenClipboard(m_owner)) {
322             HANDLE cbData = ::GetClipboardData(CF_TEXT);
323             if (cbData) {
324                 char* buffer = (char*)GlobalLock(cbData);
325                 String str(buffer);
326                 GlobalUnlock(cbData);
327                 CloseClipboard();
328                 RefPtr<DocumentFragment> fragment = createFragmentFromText(context.get(), str);
329                 if (fragment)
330                     return fragment.release();
331             } else
332                 CloseClipboard();
333         }
334     }
335
336     return 0;
337 }
338
339 bool Pasteboard::hasData()
340 {
341     return hasDataInFormat(CF_UNICODETEXT) || hasDataInFormat(CF_TEXT);
342 }
343
344 bool Pasteboard::hasDataInFormat(unsigned int format)
345 {
346     return ::IsClipboardFormatAvailable(format);
347 }
348
349 } // namespace WebCore