2 * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "ClipboardUtilitiesWin.h"
29 #include "DocumentFragment.h"
31 #include "PlatformString.h"
32 #include "TextEncoding.h"
36 #include <wininet.h> // for INTERNET_MAX_URL_LENGTH
37 #include <wtf/StringExtras.h>
38 #include <wtf/text/CString.h>
39 #include <wtf/text/StringConcatenate.h>
42 #include <CoreFoundation/CoreFoundation.h>
43 #include <wtf/RetainPtr.h>
49 FORMATETC* cfHDropFormat()
51 static FORMATETC urlFormat = {CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
55 static bool urlFromPath(CFStringRef path, String& url)
60 RetainPtr<CFURLRef> cfURL(AdoptCF, CFURLCreateWithFileSystemPath(0, path, kCFURLWindowsPathStyle, false));
64 url = CFURLGetString(cfURL.get());
66 // Work around <rdar://problem/6708300>, where CFURLCreateWithFileSystemPath makes URLs with "localhost".
67 if (url.startsWith("file://localhost/"))
74 static bool getDataMapItem(const DragDataMap* dataObject, FORMATETC* format, String& item)
76 DragDataMap::const_iterator found = dataObject->find(format->cfFormat);
77 if (found == dataObject->end())
79 item = found->second[0];
83 static bool getWebLocData(IDataObject* dataObject, String& url, String* title)
85 bool succeeded = false;
87 WCHAR filename[MAX_PATH];
88 WCHAR urlBuffer[INTERNET_MAX_URL_LENGTH];
91 if (FAILED(dataObject->GetData(cfHDropFormat(), &medium)))
94 HDROP hdrop = static_cast<HDROP>(GlobalLock(medium.hGlobal));
99 if (!DragQueryFileW(hdrop, 0, filename, WTF_ARRAY_LENGTH(filename)))
102 if (_wcsicmp(PathFindExtensionW(filename), L".url"))
105 if (!GetPrivateProfileStringW(L"InternetShortcut", L"url", 0, urlBuffer, WTF_ARRAY_LENGTH(urlBuffer), filename))
109 PathRemoveExtension(filename);
110 *title = String((UChar*)filename);
113 url = String((UChar*)urlBuffer);
119 GlobalUnlock(medium.hGlobal);
124 static bool getWebLocData(const DragDataMap* dataObject, String& url, String* title)
127 WCHAR filename[MAX_PATH];
128 WCHAR urlBuffer[INTERNET_MAX_URL_LENGTH];
130 if (!dataObject->contains(cfHDropFormat()->cfFormat))
133 wcscpy(filename, dataObject->get(cfHDropFormat()->cfFormat)[0].characters());
134 if (_wcsicmp(PathFindExtensionW(filename), L".url"))
137 if (!GetPrivateProfileStringW(L"InternetShortcut", L"url", 0, urlBuffer, WTF_ARRAY_LENGTH(urlBuffer), filename))
141 PathRemoveExtension(filename);
152 static String extractURL(const String &inURL, String* title)
155 int splitLoc = url.find('\n');
158 *title = url.substring(splitLoc+1);
159 url.truncate(splitLoc);
166 static FORMATETC* texthtmlFormat()
168 static UINT cf = RegisterClipboardFormat(L"text/html");
169 static FORMATETC texthtmlFormat = {cf, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
170 return &texthtmlFormat;
173 HGLOBAL createGlobalData(const KURL& url, const String& title)
175 String mutableURL(url.string());
176 String mutableTitle(title);
177 SIZE_T size = mutableURL.length() + mutableTitle.length() + 2; // +1 for "\n" and +1 for null terminator
178 HGLOBAL cbData = ::GlobalAlloc(GPTR, size * sizeof(UChar));
181 PWSTR buffer = static_cast<PWSTR>(GlobalLock(cbData));
182 _snwprintf(buffer, size, L"%s\n%s", mutableURL.charactersWithNullTermination(), mutableTitle.charactersWithNullTermination());
183 GlobalUnlock(cbData);
188 HGLOBAL createGlobalData(const String& str)
190 HGLOBAL globalData = ::GlobalAlloc(GPTR, (str.length() + 1) * sizeof(UChar));
193 UChar* buffer = static_cast<UChar*>(GlobalLock(globalData));
194 memcpy(buffer, str.characters(), str.length() * sizeof(UChar));
195 buffer[str.length()] = 0;
196 GlobalUnlock(globalData);
200 HGLOBAL createGlobalData(const Vector<char>& vector)
202 HGLOBAL globalData = ::GlobalAlloc(GPTR, vector.size() + 1);
205 char* buffer = static_cast<char*>(GlobalLock(globalData));
206 memcpy(buffer, vector.data(), vector.size());
207 buffer[vector.size()] = 0;
208 GlobalUnlock(globalData);
212 static String getFullCFHTML(IDataObject* data, bool& success)
215 if (SUCCEEDED(data->GetData(htmlFormat(), &store))) {
216 // MS HTML Format parsing
217 char* data = static_cast<char*>(GlobalLock(store.hGlobal));
218 SIZE_T dataSize = ::GlobalSize(store.hGlobal);
219 String cfhtml(UTF8Encoding().decode(data, dataSize));
220 GlobalUnlock(store.hGlobal);
221 ReleaseStgMedium(&store);
229 static void append(Vector<char>& vector, const char* string)
231 vector.append(string, strlen(string));
234 static void append(Vector<char>& vector, const CString& string)
236 vector.append(string.data(), string.length());
239 // Find the markup between "<!--StartFragment -->" and "<!--EndFragment -->", accounting for browser quirks.
240 static String extractMarkupFromCFHTML(const String& cfhtml)
242 unsigned markupStart = cfhtml.find("<html", 0, false);
243 unsigned tagStart = cfhtml.find("startfragment", markupStart, false);
244 unsigned fragmentStart = cfhtml.find('>', tagStart) + 1;
245 unsigned tagEnd = cfhtml.find("endfragment", fragmentStart, false);
246 unsigned fragmentEnd = cfhtml.reverseFind('<', tagEnd);
247 return cfhtml.substring(fragmentStart, fragmentEnd - fragmentStart).stripWhiteSpace();
250 // Documentation for the CF_HTML format is available at http://msdn.microsoft.com/workshop/networking/clipboard/htmlclipboard.asp
251 void markupToCFHTML(const String& markup, const String& srcURL, Vector<char>& result)
253 if (markup.isEmpty())
256 #define MAX_DIGITS 10
257 #define MAKE_NUMBER_FORMAT_1(digits) MAKE_NUMBER_FORMAT_2(digits)
258 #define MAKE_NUMBER_FORMAT_2(digits) "%0" #digits "u"
259 #define NUMBER_FORMAT MAKE_NUMBER_FORMAT_1(MAX_DIGITS)
261 const char* header = "Version:0.9\n"
262 "StartHTML:" NUMBER_FORMAT "\n"
263 "EndHTML:" NUMBER_FORMAT "\n"
264 "StartFragment:" NUMBER_FORMAT "\n"
265 "EndFragment:" NUMBER_FORMAT "\n";
266 const char* sourceURLPrefix = "SourceURL:";
268 const char* startMarkup = "<HTML>\n<BODY>\n<!--StartFragment-->\n";
269 const char* endMarkup = "\n<!--EndFragment-->\n</BODY>\n</HTML>";
271 CString sourceURLUTF8 = srcURL == blankURL() ? "" : srcURL.utf8();
272 CString markupUTF8 = markup.utf8();
275 unsigned startHTMLOffset = strlen(header) - strlen(NUMBER_FORMAT) * 4 + MAX_DIGITS * 4;
276 if (sourceURLUTF8.length())
277 startHTMLOffset += strlen(sourceURLPrefix) + sourceURLUTF8.length() + 1;
278 unsigned startFragmentOffset = startHTMLOffset + strlen(startMarkup);
279 unsigned endFragmentOffset = startFragmentOffset + markupUTF8.length();
280 unsigned endHTMLOffset = endFragmentOffset + strlen(endMarkup);
282 unsigned headerBufferLength = startHTMLOffset + 1; // + 1 for '\0' terminator.
283 char* headerBuffer = (char*)malloc(headerBufferLength);
284 snprintf(headerBuffer, headerBufferLength, header, startHTMLOffset, endHTMLOffset, startFragmentOffset, endFragmentOffset);
285 append(result, CString(headerBuffer));
287 if (sourceURLUTF8.length()) {
288 append(result, sourceURLPrefix);
289 append(result, sourceURLUTF8);
292 append(result, startMarkup);
293 append(result, markupUTF8);
294 append(result, endMarkup);
297 #undef MAKE_NUMBER_FORMAT_1
298 #undef MAKE_NUMBER_FORMAT_2
302 void replaceNewlinesWithWindowsStyleNewlines(String& str)
304 static const UChar Newline = '\n';
305 static const char* const WindowsNewline("\r\n");
306 str.replace(Newline, WindowsNewline);
309 void replaceNBSPWithSpace(String& str)
311 static const UChar NonBreakingSpaceCharacter = 0xA0;
312 static const UChar SpaceCharacter = ' ';
313 str.replace(NonBreakingSpaceCharacter, SpaceCharacter);
316 FORMATETC* urlWFormat()
318 static UINT cf = RegisterClipboardFormat(L"UniformResourceLocatorW");
319 static FORMATETC urlFormat = {cf, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
323 FORMATETC* urlFormat()
325 static UINT cf = RegisterClipboardFormat(L"UniformResourceLocator");
326 static FORMATETC urlFormat = {cf, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
330 FORMATETC* plainTextFormat()
332 static FORMATETC textFormat = {CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
336 FORMATETC* plainTextWFormat()
338 static FORMATETC textFormat = {CF_UNICODETEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
342 FORMATETC* filenameWFormat()
344 static UINT cf = RegisterClipboardFormat(L"FileNameW");
345 static FORMATETC urlFormat = {cf, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
349 FORMATETC* filenameFormat()
351 static UINT cf = RegisterClipboardFormat(L"FileName");
352 static FORMATETC urlFormat = {cf, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
357 FORMATETC* htmlFormat()
359 static UINT cf = RegisterClipboardFormat(L"HTML Format");
360 static FORMATETC htmlFormat = {cf, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
364 FORMATETC* smartPasteFormat()
366 static UINT cf = RegisterClipboardFormat(L"WebKit Smart Paste Format");
367 static FORMATETC htmlFormat = {cf, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
371 String getURL(IDataObject* dataObject, DragData::FilenameConversionPolicy filenamePolicy, bool& success, String* title)
376 if (getWebLocData(dataObject, url, title))
378 else if (SUCCEEDED(dataObject->GetData(urlWFormat(), &store))) {
380 UChar* data = static_cast<UChar*>(GlobalLock(store.hGlobal));
381 url = extractURL(String(data), title);
382 GlobalUnlock(store.hGlobal);
383 ReleaseStgMedium(&store);
385 } else if (SUCCEEDED(dataObject->GetData(urlFormat(), &store))) {
387 char* data = static_cast<char*>(GlobalLock(store.hGlobal));
388 url = extractURL(String(data), title);
389 GlobalUnlock(store.hGlobal);
390 ReleaseStgMedium(&store);
394 else if (filenamePolicy == DragData::ConvertFilenames) {
395 if (SUCCEEDED(dataObject->GetData(filenameWFormat(), &store))) {
396 // file using unicode
397 wchar_t* data = static_cast<wchar_t*>(GlobalLock(store.hGlobal));
398 if (data && data[0] && (PathFileExists(data) || PathIsUNC(data))) {
399 RetainPtr<CFStringRef> pathAsCFString(AdoptCF, CFStringCreateWithCharacters(kCFAllocatorDefault, (const UniChar*)data, wcslen(data)));
400 if (urlFromPath(pathAsCFString.get(), url)) {
406 GlobalUnlock(store.hGlobal);
407 ReleaseStgMedium(&store);
408 } else if (SUCCEEDED(dataObject->GetData(filenameFormat(), &store))) {
409 // filename using ascii
410 char* data = static_cast<char*>(GlobalLock(store.hGlobal));
411 if (data && data[0] && (PathFileExistsA(data) || PathIsUNCA(data))) {
412 RetainPtr<CFStringRef> pathAsCFString(AdoptCF, CFStringCreateWithCString(kCFAllocatorDefault, data, kCFStringEncodingASCII));
413 if (urlFromPath(pathAsCFString.get(), url)) {
419 GlobalUnlock(store.hGlobal);
420 ReleaseStgMedium(&store);
427 String getURL(const DragDataMap* data, DragData::FilenameConversionPolicy filenamePolicy, String* title)
431 if (getWebLocData(data, url, title))
433 if (getDataMapItem(data, urlWFormat(), url))
434 return extractURL(url, title);
435 if (getDataMapItem(data, urlFormat(), url))
436 return extractURL(url, title);
438 if (filenamePolicy != DragData::ConvertFilenames)
442 if (!getDataMapItem(data, filenameWFormat(), stringData))
443 getDataMapItem(data, filenameFormat(), stringData);
445 if (stringData.isEmpty() || (!PathFileExists(stringData.charactersWithNullTermination()) && !PathIsUNC(stringData.charactersWithNullTermination())))
447 RetainPtr<CFStringRef> pathAsCFString(AdoptCF, CFStringCreateWithCharacters(kCFAllocatorDefault, (const UniChar *)stringData.charactersWithNullTermination(), stringData.length()));
448 if (urlFromPath(pathAsCFString.get(), url) && title)
454 String getPlainText(IDataObject* dataObject, bool& success)
459 if (SUCCEEDED(dataObject->GetData(plainTextWFormat(), &store))) {
461 UChar* data = static_cast<UChar*>(GlobalLock(store.hGlobal));
463 GlobalUnlock(store.hGlobal);
464 ReleaseStgMedium(&store);
466 } else if (SUCCEEDED(dataObject->GetData(plainTextFormat(), &store))) {
468 char* data = static_cast<char*>(GlobalLock(store.hGlobal));
470 GlobalUnlock(store.hGlobal);
471 ReleaseStgMedium(&store);
474 // FIXME: Originally, we called getURL() here because dragging and dropping files doesn't
475 // populate the drag with text data. Per https://bugs.webkit.org/show_bug.cgi?id=38826, this
476 // is undesirable, so maybe this line can be removed.
477 text = getURL(dataObject, DragData::DoNotConvertFilenames, success);
483 String getPlainText(const DragDataMap* data)
487 if (getDataMapItem(data, plainTextWFormat(), text))
489 if (getDataMapItem(data, plainTextFormat(), text))
491 return getURL(data, DragData::DoNotConvertFilenames);
494 String getTextHTML(IDataObject* data, bool& success)
499 if (SUCCEEDED(data->GetData(texthtmlFormat(), &store))) {
500 UChar* data = static_cast<UChar*>(GlobalLock(store.hGlobal));
502 GlobalUnlock(store.hGlobal);
503 ReleaseStgMedium(&store);
509 String getTextHTML(const DragDataMap* data)
512 getDataMapItem(data, texthtmlFormat(), text);
516 String getCFHTML(IDataObject* data, bool& success)
518 String cfhtml = getFullCFHTML(data, success);
520 return extractMarkupFromCFHTML(cfhtml);
524 String getCFHTML(const DragDataMap* dataMap)
527 getDataMapItem(dataMap, htmlFormat(), cfhtml);
528 return extractMarkupFromCFHTML(cfhtml);
531 PassRefPtr<DocumentFragment> fragmentFromFilenames(Document*, const IDataObject*)
533 // FIXME: We should be able to create fragments from files
537 PassRefPtr<DocumentFragment> fragmentFromFilenames(Document*, const DragDataMap*)
539 // FIXME: We should be able to create fragments from files
543 bool containsFilenames(const IDataObject*)
545 // FIXME: We'll want to update this once we can produce fragments from files
549 bool containsFilenames(const DragDataMap*)
551 // FIXME: We'll want to update this once we can produce fragments from files
555 // Convert a String containing CF_HTML formatted text to a DocumentFragment
556 PassRefPtr<DocumentFragment> fragmentFromCFHTML(Document* doc, const String& cfhtml)
558 // obtain baseURL if present
559 String srcURLStr("sourceURL:");
561 unsigned lineStart = cfhtml.find(srcURLStr, 0, false);
562 if (lineStart != -1) {
563 unsigned srcEnd = cfhtml.find("\n", lineStart, false);
564 unsigned srcStart = lineStart+srcURLStr.length();
565 String rawSrcURL = cfhtml.substring(srcStart, srcEnd-srcStart);
566 replaceNBSPWithSpace(rawSrcURL);
567 srcURL = rawSrcURL.stripWhiteSpace();
570 String markup = extractMarkupFromCFHTML(cfhtml);
571 return createFragmentFromMarkup(doc, markup, srcURL, FragmentScriptingNotAllowed);
574 PassRefPtr<DocumentFragment> fragmentFromHTML(Document* doc, IDataObject* data)
579 bool success = false;
580 String cfhtml = getFullCFHTML(data, success);
582 if (RefPtr<DocumentFragment> fragment = fragmentFromCFHTML(doc, cfhtml))
583 return fragment.release();
586 String html = getTextHTML(data, success);
589 return createFragmentFromMarkup(doc, html, srcURL, FragmentScriptingNotAllowed);
594 PassRefPtr<DocumentFragment> fragmentFromHTML(Document* document, const DragDataMap* data)
596 if (!document || !data || data->isEmpty())
600 if (getDataMapItem(data, htmlFormat(), stringData)) {
601 if (RefPtr<DocumentFragment> fragment = fragmentFromCFHTML(document, stringData))
602 return fragment.release();
606 if (getDataMapItem(data, texthtmlFormat(), stringData))
607 return createFragmentFromMarkup(document, stringData, srcURL, FragmentScriptingNotAllowed);
612 bool containsHTML(IDataObject* data)
614 return SUCCEEDED(data->QueryGetData(texthtmlFormat())) || SUCCEEDED(data->QueryGetData(htmlFormat()));
617 bool containsHTML(const DragDataMap* data)
619 return data->contains(texthtmlFormat()->cfFormat) || data->contains(htmlFormat()->cfFormat);
622 typedef void (*GetStringFunction)(IDataObject*, FORMATETC*, Vector<String>&);
623 typedef void (*SetStringFunction)(IDataObject*, FORMATETC*, const Vector<String>&);
625 struct ClipboardDataItem {
626 GetStringFunction getString;
627 SetStringFunction setString;
630 ClipboardDataItem(FORMATETC* format, GetStringFunction getString, SetStringFunction setString): format(format), getString(getString), setString(setString) { }
633 typedef HashMap<UINT, ClipboardDataItem*> ClipboardFormatMap;
637 template<typename T> void getStringData(IDataObject* data, FORMATETC* format, Vector<String>& dataStrings)
640 if (FAILED(data->GetData(format, &store)))
642 dataStrings.append(String(static_cast<T*>(GlobalLock(store.hGlobal)), ::GlobalSize(store.hGlobal) / sizeof(T)));
643 GlobalUnlock(store.hGlobal);
644 ReleaseStgMedium(&store);
647 void getUtf8Data(IDataObject* data, FORMATETC* format, Vector<String>& dataStrings)
650 if (FAILED(data->GetData(format, &store)))
652 dataStrings.append(String(UTF8Encoding().decode(static_cast<char*>(GlobalLock(store.hGlobal)), GlobalSize(store.hGlobal))));
653 GlobalUnlock(store.hGlobal);
654 ReleaseStgMedium(&store);
658 void getCFData(IDataObject* data, FORMATETC* format, Vector<String>& dataStrings)
661 if (FAILED(data->GetData(format, &store)))
664 HDROP hdrop = reinterpret_cast<HDROP>(GlobalLock(store.hGlobal));
668 WCHAR filename[MAX_PATH];
669 UINT fileCount = DragQueryFileW(hdrop, 0xFFFFFFFF, 0, 0);
670 for (UINT i = 0; i < fileCount; i++) {
671 if (!DragQueryFileW(hdrop, i, filename, WTF_ARRAY_LENGTH(filename)))
673 dataStrings.append(static_cast<UChar*>(filename));
676 GlobalUnlock(store.hGlobal);
677 ReleaseStgMedium(&store);
683 void setUCharData(IDataObject* data, FORMATETC* format, const Vector<String>& dataStrings)
685 STGMEDIUM medium = {0};
686 medium.tymed = TYMED_HGLOBAL;
688 medium.hGlobal = createGlobalData(dataStrings.first());
691 data->SetData(format, &medium, FALSE);
692 ::GlobalFree(medium.hGlobal);
695 void setUtf8Data(IDataObject* data, FORMATETC* format, const Vector<String>& dataStrings)
697 STGMEDIUM medium = {0};
698 medium.tymed = TYMED_HGLOBAL;
700 CString charString = dataStrings.first().utf8();
701 size_t stringLength = charString.length();
702 medium.hGlobal = ::GlobalAlloc(GPTR, stringLength + 1);
705 char* buffer = static_cast<char*>(GlobalLock(medium.hGlobal));
706 memcpy(buffer, charString.data(), stringLength);
707 buffer[stringLength] = 0;
708 GlobalUnlock(medium.hGlobal);
709 data->SetData(format, &medium, FALSE);
710 ::GlobalFree(medium.hGlobal);
714 void setCFData(IDataObject* data, FORMATETC* format, const Vector<String>& dataStrings)
716 STGMEDIUM medium = {0};
717 SIZE_T dropFilesSize = sizeof(DROPFILES) + (sizeof(WCHAR) * (dataStrings.first().length() + 2));
718 medium.hGlobal = ::GlobalAlloc(GHND | GMEM_SHARE, dropFilesSize);
722 DROPFILES* dropFiles = reinterpret_cast<DROPFILES *>(GlobalLock(medium.hGlobal));
723 dropFiles->pFiles = sizeof(DROPFILES);
724 dropFiles->fWide = TRUE;
725 String filename = dataStrings.first();
726 wcscpy(reinterpret_cast<LPWSTR>(dropFiles + 1), filename.charactersWithNullTermination());
727 GlobalUnlock(medium.hGlobal);
728 data->SetData(format, &medium, FALSE);
729 ::GlobalFree(medium.hGlobal);
733 static const ClipboardFormatMap& getClipboardMap()
735 static ClipboardFormatMap formatMap;
736 if (formatMap.isEmpty()) {
737 formatMap.add(htmlFormat()->cfFormat, new ClipboardDataItem(htmlFormat(), getUtf8Data, setUtf8Data));
738 formatMap.add(texthtmlFormat()->cfFormat, new ClipboardDataItem(texthtmlFormat(), getStringData<UChar>, setUCharData));
739 formatMap.add(plainTextFormat()->cfFormat, new ClipboardDataItem(plainTextFormat(), getStringData<char>, setUtf8Data));
740 formatMap.add(plainTextWFormat()->cfFormat, new ClipboardDataItem(plainTextWFormat(), getStringData<UChar>, setUCharData));
742 formatMap.add(cfHDropFormat()->cfFormat, new ClipboardDataItem(cfHDropFormat(), getCFData, setCFData));
744 formatMap.add(filenameFormat()->cfFormat, new ClipboardDataItem(filenameFormat(), getStringData<char>, setUtf8Data));
745 formatMap.add(filenameWFormat()->cfFormat, new ClipboardDataItem(filenameWFormat(), getStringData<UChar>, setUCharData));
746 formatMap.add(urlFormat()->cfFormat, new ClipboardDataItem(urlFormat(), getStringData<char>, setUtf8Data));
747 formatMap.add(urlWFormat()->cfFormat, new ClipboardDataItem(urlWFormat(), getStringData<UChar>, setUCharData));
752 void getClipboardData(IDataObject* dataObject, FORMATETC* format, Vector<String>& dataStrings)
754 const ClipboardFormatMap& formatMap = getClipboardMap();
755 ClipboardFormatMap::const_iterator found = formatMap.find(format->cfFormat);
756 if (found == formatMap.end())
758 found->second->getString(dataObject, found->second->format, dataStrings);
761 void setClipboardData(IDataObject* dataObject, UINT format, const Vector<String>& dataStrings)
763 const ClipboardFormatMap& formatMap = getClipboardMap();
764 ClipboardFormatMap::const_iterator found = formatMap.find(format);
765 if (found == formatMap.end())
767 found->second->setString(dataObject, found->second->format, dataStrings);
770 } // namespace WebCore