Cleanup: Use exceptionless Range::* methods rather than ignoring exceptions.
[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         Vector<char> data;
119         markupToCF_HTML(createMarkup(selectedRange, 0, AnnotateForInterchange), selectedRange->startContainer()->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, SmartReplaceOption smartReplaceOption)
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     // enable smart-replacing later on by putting dummy data on the pasteboard
161     if (smartReplaceOption == CanSmartReplace) {
162         if (::OpenClipboard(m_owner)) {
163             ::SetClipboardData(WebSmartPasteFormat, 0);
164             ::CloseClipboard();
165         }
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         markupToCF_HTML(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 = static_cast<RenderImage*>(node->renderer());
217     CachedImage* cachedImage = static_cast<CachedImage*>(renderer->cachedImage());
218     ASSERT(cachedImage);
219     Image* image = cachedImage->imageForRenderer(renderer);
220     ASSERT(image);
221
222     clear();
223
224     RefPtr<SharedBitmap> sourceBmp = image->nativeImageForCurrentFrame();
225     if (!sourceBmp)
226         return;
227
228     IntRect rect(0, 0, sourceBmp->width(), sourceBmp->height());
229     BitmapInfo bmpInfo;
230     void* pixels;
231     HBITMAP resultBitmap = sourceBmp->clipBitmap(rect, true, bmpInfo, pixels);
232     if (!resultBitmap)
233         return;
234
235     if (::OpenClipboard(m_owner)) {
236         ::SetClipboardData(CF_BITMAP, resultBitmap);
237         ::CloseClipboard();
238     } else
239         DeleteObject(resultBitmap);
240 }
241
242 void Pasteboard::writeClipboard(Clipboard*)
243 {
244     notImplemented();
245 }
246
247 bool Pasteboard::canSmartReplace()
248 {
249     return ::IsClipboardFormatAvailable(WebSmartPasteFormat);
250 }
251
252 String Pasteboard::plainText(Frame* frame)
253 {
254     if (::IsClipboardFormatAvailable(CF_UNICODETEXT) && ::OpenClipboard(m_owner)) {
255         HANDLE cbData = ::GetClipboardData(CF_UNICODETEXT);
256         if (cbData) {
257             UChar* buffer = (UChar*)GlobalLock(cbData);
258             String fromClipboard(buffer);
259             GlobalUnlock(cbData);
260             CloseClipboard();
261             return fromClipboard;
262         } else
263             CloseClipboard();
264     }
265
266     if (::IsClipboardFormatAvailable(CF_TEXT) && ::OpenClipboard(m_owner)) {
267         HANDLE cbData = ::GetClipboardData(CF_TEXT);
268         if (cbData) {
269             char* buffer = (char*)GlobalLock(cbData);
270             String fromClipboard(buffer);
271             GlobalUnlock(cbData);
272             CloseClipboard();
273             return fromClipboard;
274         } else
275             CloseClipboard();
276     }
277
278     return String();
279 }
280
281 PassRefPtr<DocumentFragment> Pasteboard::documentFragment(Frame* frame, PassRefPtr<Range> context, bool allowPlainText, bool& chosePlainText)
282 {
283     chosePlainText = false;
284
285     if (::IsClipboardFormatAvailable(HTMLClipboardFormat) && ::OpenClipboard(m_owner)) {
286         // get data off of clipboard
287         HANDLE cbData = ::GetClipboardData(HTMLClipboardFormat);
288         if (cbData) {
289             SIZE_T dataSize = ::GlobalSize(cbData);
290             String cf_html(UTF8Encoding().decode((char*)GlobalLock(cbData), dataSize));
291             GlobalUnlock(cbData);
292             CloseClipboard();
293
294             PassRefPtr<DocumentFragment> fragment = fragmentFromCF_HTML(frame->document(), cf_html);
295             if (fragment)
296                 return fragment;
297         } else
298             CloseClipboard();
299     }
300
301     if (allowPlainText && IsClipboardFormatAvailable(CF_UNICODETEXT)) {
302         chosePlainText = true;
303         if (OpenClipboard(m_owner)) {
304             HANDLE cbData = GetClipboardData(CF_UNICODETEXT);
305             if (cbData) {
306                 UChar* buffer = (UChar*)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     if (allowPlainText && ::IsClipboardFormatAvailable(CF_TEXT)) {
319         chosePlainText = true;
320         if (::OpenClipboard(m_owner)) {
321             HANDLE cbData = ::GetClipboardData(CF_TEXT);
322             if (cbData) {
323                 char* buffer = (char*)GlobalLock(cbData);
324                 String str(buffer);
325                 GlobalUnlock(cbData);
326                 CloseClipboard();
327                 RefPtr<DocumentFragment> fragment = createFragmentFromText(context.get(), str);
328                 if (fragment)
329                     return fragment.release();
330             } else
331                 CloseClipboard();
332         }
333     }
334
335     return 0;
336 }
337
338 bool Pasteboard::hasData()
339 {
340     return hasDataInFormat(CF_UNICODETEXT) || hasDataInFormat(CF_TEXT);
341 }
342
343 bool Pasteboard::hasDataInFormat(unsigned int format)
344 {
345     return ::IsClipboardFormatAvailable(format);
346 }
347
348 } // namespace WebCore