e11ab45ddcb0c0c7526214d75143a450c3d548ac
[WebKit-https.git] / 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 "ClipboardUtilitiesWin.h"
30 #include "CString.h"
31 #include "DeprecatedString.h"
32 #include "DocumentFragment.h"
33 #include "Document.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 "markup.h"
45
46 namespace WebCore {
47
48 static UINT HTMLClipboardFormat = 0;
49 static UINT BookmarkClipboardFormat = 0;
50
51 static LRESULT CALLBACK PasteboardOwnerWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
52 {
53     LRESULT lresult = 0;
54     LONG_PTR longPtr = GetWindowLongPtr(hWnd, 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_DRAWCLIPBOARD:
67         break;
68     case WM_DESTROY:
69         break;
70     case WM_CHANGECBCHAIN:
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     WNDCLASSEX wcex = {0};
89     wcex.cbSize = sizeof(WNDCLASSEX);
90     wcex.lpfnWndProc    = PasteboardOwnerWndProc;
91     wcex.hInstance      = Page::instanceHandle();
92     wcex.lpszClassName  = L"PasteboardOwnerWindowClass";
93     ::RegisterClassEx(&wcex);
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 }
101
102 void Pasteboard::clear()
103 {
104     if (::OpenClipboard(m_owner)) {
105         ::EmptyClipboard();
106         ::CloseClipboard();
107     }
108 }
109
110 void Pasteboard::writeSelection(Range* selectedRange, bool canSmartCopyOrDelete, Frame* frame)
111 {
112     clear();
113     
114     // Put CF_HTML format on the pasteboard 
115     if (::OpenClipboard(m_owner)) {
116         ExceptionCode ec = 0;
117         HGLOBAL cbData = createGlobalData(markupToCF_HTML(createMarkup(selectedRange, 0, AnnotateForInterchange), selectedRange->startContainer(ec)->document()->URL()));
118         if (!::SetClipboardData(HTMLClipboardFormat, cbData))
119             ::GlobalFree(cbData);
120         ::CloseClipboard();
121     }
122     
123     // Put plain string on the pasteboard. CF_UNICODETEXT covers CF_TEXT as well
124     String str = frame->selectedText();
125     replaceNewlinesWithWindowsStyleNewlines(str);
126     replaceNBSPWithSpace(str);
127     if (::OpenClipboard(m_owner)) {
128         HGLOBAL cbData = createGlobalData(str);
129         if (!::SetClipboardData(CF_UNICODETEXT, cbData))
130             ::GlobalFree(cbData);
131         ::CloseClipboard();
132     }
133 }
134
135 void Pasteboard::writeURL(const KURL& url, const String& titleStr, Frame* frame)
136 {
137     ASSERT(!url.isEmpty());
138
139     clear();
140
141     String title(titleStr);
142     if (title.isEmpty()) {
143         title = url.lastPathComponent();
144         if (title.isEmpty())
145             title = url.host();
146     }
147
148     // write to clipboard in format com.apple.safari.bookmarkdata to be able to paste into the bookmarks view with appropriate title
149     if (::OpenClipboard(m_owner)) {
150         HGLOBAL cbData = createGlobalData(url, title);
151         if (!::SetClipboardData(BookmarkClipboardFormat, cbData))
152             ::GlobalFree(cbData);
153         ::CloseClipboard();
154     }
155
156     // write to clipboard in format CF_HTML to be able to paste into contenteditable areas as a link
157     if (::OpenClipboard(m_owner)) {
158         HGLOBAL cbData = createGlobalData(markupToCF_HTML(urlToMarkup(url, title), ""));
159         if (!::SetClipboardData(HTMLClipboardFormat, cbData))
160             ::GlobalFree(cbData);
161         ::CloseClipboard();
162     }
163
164     // bare-bones CF_UNICODETEXT support
165     if (::OpenClipboard(m_owner)) {
166         HGLOBAL cbData = createGlobalData(url.url());
167         if (!::SetClipboardData(CF_UNICODETEXT, cbData))
168             ::GlobalFree(cbData);
169         ::CloseClipboard();
170     }
171 }
172
173 void Pasteboard::writeImage(Node* node, const KURL&, const String&)
174 {
175     ASSERT(node && node->renderer() && node->renderer()->isImage());
176     RenderImage* renderer = static_cast<RenderImage*>(node->renderer());
177     CachedImage* cachedImage = static_cast<CachedImage*>(renderer->cachedImage());
178     ASSERT(cachedImage);
179     Image* image = cachedImage->image();
180     ASSERT(image);
181
182     clear();
183
184     HDC dc = GetDC(0);
185     HDC compatibleDC = CreateCompatibleDC(0);
186     HDC sourceDC = CreateCompatibleDC(0);
187     HBITMAP resultBitmap = CreateCompatibleBitmap(dc, image->width(), image->height());
188     HBITMAP oldBitmap = (HBITMAP)SelectObject(compatibleDC, resultBitmap);
189
190     BITMAPINFO bmInfo = {0};
191     bmInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
192     bmInfo.bmiHeader.biWidth = image->width();
193     bmInfo.bmiHeader.biHeight = image->height();
194     bmInfo.bmiHeader.biPlanes = 1;
195     bmInfo.bmiHeader.biBitCount = 32;
196     bmInfo.bmiHeader.biCompression = BI_RGB;
197     HBITMAP coreBitmap = CreateDIBSection(dc, &bmInfo, DIB_RGB_COLORS, 0, 0, 0);
198     HBITMAP oldSource = (HBITMAP)SelectObject(sourceDC, coreBitmap);
199     image->getHBITMAP(coreBitmap);
200
201     BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA};
202     AlphaBlend(compatibleDC, 0, 0, image->width(), image->height(),
203         sourceDC, 0, 0, image->width(), image->height(), bf);
204
205     SelectObject(compatibleDC, oldBitmap);
206     SelectObject(sourceDC, oldSource);
207
208     DeleteObject(oldBitmap);
209     DeleteObject(oldSource);
210     DeleteObject(coreBitmap);
211     ReleaseDC(0, dc);
212     DeleteDC(compatibleDC);
213     DeleteDC(sourceDC);
214
215     if (::OpenClipboard(m_owner)) {
216         ::SetClipboardData(CF_BITMAP, resultBitmap);
217         ::CloseClipboard();
218     }
219 }
220
221 bool Pasteboard::canSmartReplace()
222
223     // WebSmartPastePboardType is unavailable
224     return false; 
225 }
226
227 String Pasteboard::plainText(Frame* frame)
228 {
229     if (::IsClipboardFormatAvailable(CF_UNICODETEXT) && ::OpenClipboard(m_owner)) {
230         HANDLE cbData = ::GetClipboardData(CF_UNICODETEXT);
231         if (cbData) {
232             UChar* buffer = (UChar*)::GlobalLock(cbData);
233             String fromClipboard(buffer);
234             ::GlobalUnlock(cbData);
235             ::CloseClipboard();
236             return fromClipboard;
237         } else
238             ::CloseClipboard();
239     }
240
241     if (::IsClipboardFormatAvailable(CF_TEXT) && ::OpenClipboard(m_owner)) {
242         HANDLE cbData = ::GetClipboardData(CF_TEXT);
243         if (cbData) {
244             char* buffer = (char*)::GlobalLock(cbData);
245             String fromClipboard(buffer);
246             ::GlobalUnlock(cbData);
247             ::CloseClipboard();
248             return fromClipboard;
249         } else
250             ::CloseClipboard();
251     }
252
253     return String();
254 }
255
256 PassRefPtr<DocumentFragment> Pasteboard::documentFragment(Frame* frame, PassRefPtr<Range> context, bool allowPlainText, bool& chosePlainText)
257 {
258     chosePlainText = false;
259     
260     if (::IsClipboardFormatAvailable(HTMLClipboardFormat) && ::OpenClipboard(m_owner)) {
261         // get data off of clipboard
262         HANDLE cbData = ::GetClipboardData(HTMLClipboardFormat);
263         if (cbData) {
264             SIZE_T dataSize = ::GlobalSize(cbData);
265             String cf_html(UTF8Encoding().decode((char*)::GlobalLock(cbData), dataSize));
266             ::GlobalUnlock(cbData);
267             ::CloseClipboard();
268
269             PassRefPtr<DocumentFragment> fragment = fragmentFromCF_HTML(frame->document(), cf_html);
270             if (fragment)
271                 return fragment;
272         } else 
273             ::CloseClipboard();
274     }
275      
276     if (allowPlainText && ::IsClipboardFormatAvailable(CF_UNICODETEXT)) {
277         chosePlainText = true;
278         if (::OpenClipboard(m_owner)) {
279             HANDLE cbData = ::GetClipboardData(CF_UNICODETEXT);
280             if (cbData) {
281                 UChar* buffer = (UChar*)GlobalLock(cbData);
282                 String str(buffer);
283                 ::GlobalUnlock( cbData );
284                 ::CloseClipboard();
285                 RefPtr<DocumentFragment> fragment = createFragmentFromText(context.get(), str);
286                 if (fragment)
287                     return fragment.release();
288             } else 
289                 ::CloseClipboard();
290         }
291     }
292
293     if (allowPlainText && ::IsClipboardFormatAvailable(CF_TEXT)) {
294         chosePlainText = true;
295         if (::OpenClipboard(m_owner)) {
296             HANDLE cbData = ::GetClipboardData(CF_TEXT);
297             if (cbData) {
298                 char* buffer = (char*)GlobalLock(cbData);
299                 String str(buffer);
300                 ::GlobalUnlock( cbData );
301                 ::CloseClipboard();
302                 RefPtr<DocumentFragment> fragment = createFragmentFromText(context.get(), str);
303                 if (fragment)
304                     return fragment.release();
305             } else
306                 ::CloseClipboard();
307         }
308     }
309     
310     return 0;
311 }
312
313 } // namespace WebCore