• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
PasteboardOwnerWndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)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 
generalPasteboard()81 Pasteboard* Pasteboard::generalPasteboard()
82 {
83     static Pasteboard* pasteboard = new Pasteboard;
84     return pasteboard;
85 }
86 
Pasteboard()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 
clear()109 void Pasteboard::clear()
110 {
111     if (::OpenClipboard(m_owner)) {
112         ::EmptyClipboard();
113         ::CloseClipboard();
114     }
115 }
116 
writeSelection(Range * selectedRange,bool canSmartCopyOrDelete,Frame * frame)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 
writePlainText(const String & text)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 
writeURL(const KURL & url,const String & titleStr,Frame * frame)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 
writeImage(Node * node,const KURL &,const String &)209 void Pasteboard::writeImage(Node* node, const KURL&, const String&)
210 {
211     ASSERT(node && node->renderer() && node->renderer()->isImage());
212     RenderImage* renderer = toRenderImage(node->renderer());
213     CachedImage* cachedImage = renderer->cachedImage();
214     if (!cachedImage || cachedImage->errorOccurred())
215         return;
216     Image* image = cachedImage->image();
217     ASSERT(image);
218 
219     clear();
220 
221     HDC dc = GetDC(0);
222     HDC compatibleDC = CreateCompatibleDC(0);
223     HDC sourceDC = CreateCompatibleDC(0);
224     OwnPtr<HBITMAP> resultBitmap(CreateCompatibleBitmap(dc, image->width(), image->height()));
225     HGDIOBJ oldBitmap = SelectObject(compatibleDC, resultBitmap.get());
226 
227     BitmapInfo bmInfo = BitmapInfo::create(image->size());
228 
229     HBITMAP coreBitmap = CreateDIBSection(dc, &bmInfo, DIB_RGB_COLORS, 0, 0, 0);
230     HGDIOBJ oldSource = SelectObject(sourceDC, coreBitmap);
231     image->getHBITMAP(coreBitmap);
232 
233     BitBlt(compatibleDC, 0, 0, image->width(), image->height(), sourceDC, 0, 0, SRCCOPY);
234 
235     SelectObject(sourceDC, oldSource);
236     DeleteObject(coreBitmap);
237 
238     SelectObject(compatibleDC, oldBitmap);
239     DeleteDC(sourceDC);
240     DeleteDC(compatibleDC);
241     ReleaseDC(0, dc);
242 
243     if (::OpenClipboard(m_owner)) {
244         ::SetClipboardData(CF_BITMAP, resultBitmap.leakPtr());
245         ::CloseClipboard();
246     }
247 }
248 
canSmartReplace()249 bool Pasteboard::canSmartReplace()
250 {
251     return ::IsClipboardFormatAvailable(WebSmartPasteFormat);
252 }
253 
plainText(Frame * frame)254 String Pasteboard::plainText(Frame* frame)
255 {
256     if (::IsClipboardFormatAvailable(CF_UNICODETEXT) && ::OpenClipboard(m_owner)) {
257         HANDLE cbData = ::GetClipboardData(CF_UNICODETEXT);
258         if (cbData) {
259             UChar* buffer = static_cast<UChar*>(GlobalLock(cbData));
260             String fromClipboard(buffer);
261             GlobalUnlock(cbData);
262             ::CloseClipboard();
263             return fromClipboard;
264         }
265         ::CloseClipboard();
266     }
267 
268     if (::IsClipboardFormatAvailable(CF_TEXT) && ::OpenClipboard(m_owner)) {
269         HANDLE cbData = ::GetClipboardData(CF_TEXT);
270         if (cbData) {
271             char* buffer = static_cast<char*>(GlobalLock(cbData));
272             String fromClipboard(buffer);
273             GlobalUnlock(cbData);
274             ::CloseClipboard();
275             return fromClipboard;
276         }
277         ::CloseClipboard();
278     }
279 
280     return String();
281 }
282 
documentFragment(Frame * frame,PassRefPtr<Range> context,bool allowPlainText,bool & chosePlainText)283 PassRefPtr<DocumentFragment> Pasteboard::documentFragment(Frame* frame, PassRefPtr<Range> context, bool allowPlainText, bool& chosePlainText)
284 {
285     chosePlainText = false;
286 
287     if (::IsClipboardFormatAvailable(HTMLClipboardFormat) && ::OpenClipboard(m_owner)) {
288         // get data off of clipboard
289         HANDLE cbData = ::GetClipboardData(HTMLClipboardFormat);
290         if (cbData) {
291             SIZE_T dataSize = ::GlobalSize(cbData);
292             String cfhtml(UTF8Encoding().decode(static_cast<char*>(GlobalLock(cbData)), dataSize));
293             GlobalUnlock(cbData);
294             ::CloseClipboard();
295 
296             PassRefPtr<DocumentFragment> fragment = fragmentFromCFHTML(frame->document(), cfhtml);
297             if (fragment)
298                 return fragment;
299         } else
300             ::CloseClipboard();
301     }
302 
303     if (allowPlainText && ::IsClipboardFormatAvailable(CF_UNICODETEXT)) {
304         chosePlainText = true;
305         if (::OpenClipboard(m_owner)) {
306             HANDLE cbData = ::GetClipboardData(CF_UNICODETEXT);
307             if (cbData) {
308                 UChar* buffer = static_cast<UChar*>(GlobalLock(cbData));
309                 String str(buffer);
310                 GlobalUnlock(cbData);
311                 ::CloseClipboard();
312                 RefPtr<DocumentFragment> fragment = createFragmentFromText(context.get(), str);
313                 if (fragment)
314                     return fragment.release();
315             } else
316                 ::CloseClipboard();
317         }
318     }
319 
320     if (allowPlainText && ::IsClipboardFormatAvailable(CF_TEXT)) {
321         chosePlainText = true;
322         if (::OpenClipboard(m_owner)) {
323             HANDLE cbData = ::GetClipboardData(CF_TEXT);
324             if (cbData) {
325                 char* buffer = static_cast<char*>(GlobalLock(cbData));
326                 String str(buffer);
327                 GlobalUnlock(cbData);
328                 ::CloseClipboard();
329                 RefPtr<DocumentFragment> fragment = createFragmentFromText(context.get(), str);
330                 if (fragment)
331                     return fragment.release();
332             } else
333                 ::CloseClipboard();
334         }
335     }
336 
337     return 0;
338 }
339 
340 } // namespace WebCore
341