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