source: webkit/trunk/WebCore/platform/win/ClipboardWin.cpp @ 30621

Last change on this file since 30621 was 30621, checked in by Adam Roben, 16 years ago

Windows build fix after r30613

  • platform/win/ClipboardWin.cpp:
  • Property svn:eol-style set to native
File size: 23.8 KB
Line 
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 "ClipboardWin.h"
28
29#include "CString.h"
30#include "CachedImage.h"
31#include "ClipboardUtilitiesWin.h"
32#include "Document.h"
33#include "DragData.h"
34#include "Editor.h"
35#include "Element.h"
36#include "EventHandler.h"
37#include "Frame.h"
38#include "FrameLoader.h"
39#include "FrameView.h"
40#include "HTMLNames.h"
41#include "Image.h"
42#include "MIMETypeRegistry.h"
43#include "Page.h"
44#include "Pasteboard.h"
45#include "PlatformMouseEvent.h"
46#include "PlatformString.h"
47#include "Range.h"
48#include "RenderImage.h"
49#include "ResourceResponse.h"
50#include "StringHash.h"
51#include "WCDataObject.h"
52#include "csshelper.h"
53#include "markup.h"
54
55#include <shlwapi.h>
56#include <wininet.h>
57
58#include <wtf/RefPtr.h>
59
60using namespace std;
61
62namespace WebCore {
63
64using namespace HTMLNames;
65
66// format string for
67static const char szShellDotUrlTemplate[] = "[InternetShortcut]\r\nURL=%s\r\n";
68
69// We provide the IE clipboard types (URL and Text), and the clipboard types specified in the WHATWG Web Applications 1.0 draft
70// see http://www.whatwg.org/specs/web-apps/current-work/ Section 6.3.5.3
71
72enum ClipboardDataType { ClipboardDataTypeNone, ClipboardDataTypeURL, ClipboardDataTypeText };
73
74static ClipboardDataType clipboardTypeFromMIMEType(const String& type)
75{
76    String qType = type.stripWhiteSpace().lower();
77
78    // two special cases for IE compatibility
79    if (qType == "text" || qType == "text/plain" || qType.startsWith("text/plain;"))
80        return ClipboardDataTypeText;
81    if (qType == "url" || qType == "text/uri-list")
82        return ClipboardDataTypeURL;
83
84    return ClipboardDataTypeNone;
85}
86
87static inline FORMATETC* fileDescriptorFormat()
88{
89    static UINT cf = RegisterClipboardFormat(CFSTR_FILEDESCRIPTOR);
90    static FORMATETC fileDescriptorFormat = {cf, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
91    return &fileDescriptorFormat;
92}
93
94static inline FORMATETC* fileContentFormatZero()
95{
96    static UINT cf = RegisterClipboardFormat(CFSTR_FILECONTENTS);
97    static FORMATETC fileContentFormat = {cf, 0, DVASPECT_CONTENT, 0, TYMED_HGLOBAL};
98    return &fileContentFormat;
99}
100
101static inline void pathRemoveBadFSCharacters(PWSTR psz, size_t length)
102{
103    size_t writeTo = 0;
104    size_t readFrom = 0;
105    while (readFrom < length) {
106        UINT type = PathGetCharType(psz[readFrom]);
107        if (psz[readFrom] == 0 || type & (GCT_LFNCHAR | GCT_SHORTCHAR)) {
108            psz[writeTo++] = psz[readFrom];
109        }
110
111        readFrom++;
112    }
113    psz[writeTo] = 0;
114}
115
116static String filesystemPathFromUrlOrTitle(const String& url, const String& title, TCHAR* extension, bool isLink)
117{
118    bool usedURL = false;
119    WCHAR fsPathBuffer[MAX_PATH + 1];
120    fsPathBuffer[0] = 0;
121    int extensionLen = extension ? lstrlen(extension) : 0;
122
123    if (!title.isEmpty()) {
124        size_t len = min<size_t>(title.length(), MAX_PATH - extensionLen);
125        CopyMemory(fsPathBuffer, title.characters(), len * sizeof(UChar));
126        fsPathBuffer[len] = 0;
127        pathRemoveBadFSCharacters(fsPathBuffer, len);
128    }
129
130    if (!lstrlen(fsPathBuffer)) {
131        DWORD len = MAX_PATH;
132        String nullTermURL = url;
133        usedURL = true;
134        if (UrlIsFileUrl((LPCWSTR)nullTermURL.charactersWithNullTermination())
135            && SUCCEEDED(PathCreateFromUrl((LPCWSTR)nullTermURL.charactersWithNullTermination(), fsPathBuffer, &len, 0))) {
136            // When linking to a file URL we can trivially find the file name
137            PWSTR fn = PathFindFileName(fsPathBuffer);
138            if (fn && fn != fsPathBuffer)
139                lstrcpyn(fsPathBuffer, fn, lstrlen(fn) + 1);
140        } else {
141            // The filename for any content based drag should be the last element of
142            // the path.  If we can't find it, or we're coming up with the name for a link
143            // we just use the entire url.
144            KURL kurl(url);
145            String lastComponent;
146            if (!isLink && !(lastComponent = kurl.lastPathComponent()).isEmpty()) {
147                len = min<DWORD>(MAX_PATH, lastComponent.length());
148                CopyMemory(fsPathBuffer, lastComponent.characters(), len * sizeof(UChar));
149            } else {
150                len = min<DWORD>(MAX_PATH, nullTermURL.length());
151                CopyMemory(fsPathBuffer, nullTermURL.characters(), len * sizeof(UChar));
152            }
153            fsPathBuffer[len] = 0;
154            pathRemoveBadFSCharacters(fsPathBuffer, len);
155        }
156    }
157
158    if (!extension)
159        return String((UChar*)fsPathBuffer);
160
161    if (!isLink && usedURL) {
162        PathRenameExtension(fsPathBuffer, extension);
163        return String((UChar*)fsPathBuffer);
164    }
165
166    String result((UChar*)fsPathBuffer);
167    result += String((UChar*)extension);
168    return result;
169}
170
171static HGLOBAL createGlobalURLContent(const String& url, int estimatedFileSize)
172{
173    HRESULT hr = S_OK;
174    HGLOBAL memObj = 0;
175
176    char* fileContents;
177    char ansiUrl[INTERNET_MAX_URL_LENGTH + 1];
178    // Used to generate the buffer. This is null terminated whereas the fileContents won't be.
179    char contentGenerationBuffer[INTERNET_MAX_URL_LENGTH + ARRAYSIZE(szShellDotUrlTemplate) + 1];
180   
181    if (estimatedFileSize > 0 && estimatedFileSize > ARRAYSIZE(contentGenerationBuffer))
182        return 0;
183
184    int ansiUrlSize = ::WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)url.characters(), url.length(), ansiUrl, ARRAYSIZE(ansiUrl) - 1, 0, 0);
185    if (!ansiUrlSize)
186        return 0;
187
188    ansiUrl[ansiUrlSize] = 0;
189   
190    int fileSize = (int) (ansiUrlSize+strlen(szShellDotUrlTemplate)-2); // -2 to remove the %s
191    ASSERT(estimatedFileSize < 0 || fileSize == estimatedFileSize);
192
193    memObj = GlobalAlloc(GPTR, fileSize);
194    if (!memObj)
195        return 0;
196
197    fileContents = (PSTR)GlobalLock(memObj);
198
199    sprintf_s(contentGenerationBuffer, ARRAYSIZE(contentGenerationBuffer), szShellDotUrlTemplate, ansiUrl);
200    CopyMemory(fileContents, contentGenerationBuffer, fileSize);
201   
202    GlobalUnlock(memObj);
203   
204    return memObj;
205}
206
207static HGLOBAL createGlobalImageFileContent(SharedBuffer* data)
208{
209    HGLOBAL memObj = GlobalAlloc(GPTR, data->size());
210    if (!memObj)
211        return 0;
212
213    char* fileContents = (PSTR)GlobalLock(memObj);
214
215    CopyMemory(fileContents, data->data(), data->size());
216   
217    GlobalUnlock(memObj);
218   
219    return memObj;
220}
221
222static HGLOBAL createGlobalHDropContent(const KURL& url, String& fileName, SharedBuffer* data)
223{
224    if (fileName.isEmpty() || !data )
225        return 0;
226
227    WCHAR filePath[MAX_PATH];
228
229    if (url.isLocalFile()) {
230        String localPath = url.path();
231        // windows does not enjoy a leading slash on paths
232        if (localPath[0] == '/')
233            localPath = localPath.substring(1);
234        LPCTSTR localPathStr = localPath.charactersWithNullTermination();
235        if (wcslen(localPathStr) + 1 < MAX_PATH)
236            wcscpy_s(filePath, MAX_PATH, localPathStr);
237        else
238            return 0;
239    } else {
240        WCHAR tempPath[MAX_PATH];
241        WCHAR extension[MAX_PATH];
242        if (!::GetTempPath(ARRAYSIZE(tempPath), tempPath))
243            return 0;
244        if (!::PathAppend(tempPath, fileName.charactersWithNullTermination()))
245            return 0;
246        LPCWSTR foundExtension = ::PathFindExtension(tempPath);
247        if (foundExtension) {
248            if (wcscpy_s(extension, MAX_PATH, foundExtension))
249                return 0;
250        } else
251            *extension = 0;
252        ::PathRemoveExtension(tempPath);
253        for (int i = 1; i < 10000; i++) {
254            if (swprintf_s(filePath, MAX_PATH, TEXT("%s-%d%s"), tempPath, i, extension) == -1)
255                return 0;
256            if (!::PathFileExists(filePath))
257                break;
258        }
259        HANDLE tempFileHandle = CreateFile(filePath, GENERIC_READ | GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
260        if (tempFileHandle == INVALID_HANDLE_VALUE)
261            return 0;
262
263        // Write the data to this temp file.
264        DWORD written;
265        BOOL tempWriteSucceeded = WriteFile(tempFileHandle, data->data(), data->size(), &written, 0);
266        CloseHandle(tempFileHandle);
267        if (!tempWriteSucceeded)
268            return 0;
269    }
270
271    SIZE_T dropFilesSize = sizeof(DROPFILES) + (sizeof(WCHAR) * (wcslen(filePath) + 2));
272    HGLOBAL memObj = GlobalAlloc(GHND | GMEM_SHARE, dropFilesSize);
273    if (!memObj)
274        return 0;
275
276    DROPFILES* dropFiles = (DROPFILES*) GlobalLock(memObj);
277    dropFiles->pFiles = sizeof(DROPFILES);
278    dropFiles->fWide = TRUE;
279    wcscpy((LPWSTR)(dropFiles + 1), filePath);   
280    GlobalUnlock(memObj);
281   
282    return memObj;
283}
284
285static HGLOBAL createGlobalUrlFileDescriptor(const String& url, const String& title, int& /*out*/ estimatedSize)
286{
287    HRESULT hr = S_OK;
288    HGLOBAL memObj = 0;
289    String fsPath;
290    memObj = GlobalAlloc(GPTR, sizeof(FILEGROUPDESCRIPTOR));
291    if (!memObj)
292        return 0;
293
294    FILEGROUPDESCRIPTOR* fgd = (FILEGROUPDESCRIPTOR*)GlobalLock(memObj);
295    memset(fgd, 0, sizeof(FILEGROUPDESCRIPTOR));
296    fgd->cItems = 1;
297    fgd->fgd[0].dwFlags = FD_FILESIZE;
298    int fileSize = ::WideCharToMultiByte(CP_ACP, 0, url.characters(), url.length(), 0, 0, 0, 0);
299    fileSize += strlen(szShellDotUrlTemplate) - 2;  // -2 is for getting rid of %s in the template string
300    fgd->fgd[0].nFileSizeLow = fileSize;
301    estimatedSize = fileSize;
302    fsPath = filesystemPathFromUrlOrTitle(url, title, L".URL", true);
303
304    if (fsPath.length() <= 0) {
305        GlobalUnlock(memObj);
306        GlobalFree(memObj);
307        return 0;
308    }
309
310    int maxSize = min(fsPath.length(), ARRAYSIZE(fgd->fgd[0].cFileName));
311    CopyMemory(fgd->fgd[0].cFileName, (LPCWSTR)fsPath.characters(), maxSize * sizeof(UChar));
312    GlobalUnlock(memObj);
313   
314    return memObj;
315}
316
317
318static HGLOBAL createGlobalImageFileDescriptor(const String& url, const String& title, CachedImage* image)
319{
320    ASSERT_ARG(image, image);
321    ASSERT(image->image()->data());
322
323    HRESULT hr = S_OK;
324    HGLOBAL memObj = 0;
325    String fsPath;
326    memObj = GlobalAlloc(GPTR, sizeof(FILEGROUPDESCRIPTOR));
327    if (!memObj)
328        return 0;
329
330    FILEGROUPDESCRIPTOR* fgd = (FILEGROUPDESCRIPTOR*)GlobalLock(memObj);
331    memset(fgd, 0, sizeof(FILEGROUPDESCRIPTOR));
332    fgd->cItems = 1;
333    fgd->fgd[0].dwFlags = FD_FILESIZE;
334    fgd->fgd[0].nFileSizeLow = image->image()->data()->size();
335   
336    String extension(".");
337    extension += WebCore::MIMETypeRegistry::getPreferredExtensionForMIMEType(image->response().mimeType());
338    const String& preferredTitle = title.isEmpty() ? image->response().suggestedFilename() : title;
339    fsPath = filesystemPathFromUrlOrTitle(url, preferredTitle, extension.length() ? (TCHAR*)extension.charactersWithNullTermination() : 0, false);
340
341    if (fsPath.length() <= 0) {
342        GlobalUnlock(memObj);
343        GlobalFree(memObj);
344        return 0;
345    }
346
347    int maxSize = min(fsPath.length(), ARRAYSIZE(fgd->fgd[0].cFileName));
348    CopyMemory(fgd->fgd[0].cFileName, (LPCWSTR)fsPath.characters(), maxSize * sizeof(UChar));
349    GlobalUnlock(memObj);
350   
351    return memObj;
352}
353
354
355// writeFileToDataObject takes ownership of fileDescriptor and fileContent
356static HRESULT writeFileToDataObject(IDataObject* dataObject, HGLOBAL fileDescriptor, HGLOBAL fileContent, HGLOBAL hDropContent)
357{
358    HRESULT hr = S_OK;
359    FORMATETC* fe;
360    STGMEDIUM medium = {0};
361    medium.tymed = TYMED_HGLOBAL;
362
363    if (!fileDescriptor || !fileContent)
364        goto exit;
365
366    // Descriptor
367    fe = fileDescriptorFormat();
368
369    medium.hGlobal = fileDescriptor;
370
371    if (FAILED(hr = dataObject->SetData(fe, &medium, TRUE)))
372        goto exit;
373
374    // Contents
375    fe = fileContentFormatZero();
376    medium.hGlobal = fileContent;
377    if (FAILED(hr = dataObject->SetData(fe, &medium, TRUE)))
378        goto exit;
379
380    // HDROP
381    if (hDropContent) {
382        medium.hGlobal = hDropContent;
383        hr = dataObject->SetData(cfHDropFormat(), &medium, TRUE);
384    }
385
386exit:
387    if (FAILED(hr)) {
388        if (fileDescriptor)
389            GlobalFree(fileDescriptor);
390        if (fileContent)
391            GlobalFree(fileContent);
392        if (hDropContent)
393            GlobalFree(hDropContent);
394    }
395    return hr;
396}
397
398ClipboardWin::ClipboardWin(bool isForDragging, IDataObject* dataObject, ClipboardAccessPolicy policy)
399    : Clipboard(policy, isForDragging)
400    , m_dataObject(dataObject)
401    , m_writableDataObject(0)
402{
403}
404
405ClipboardWin::ClipboardWin(bool isForDragging, WCDataObject* dataObject, ClipboardAccessPolicy policy)
406    : Clipboard(policy, isForDragging)
407    , m_dataObject(dataObject)
408    , m_writableDataObject(dataObject)
409{
410}
411
412ClipboardWin::~ClipboardWin()
413{
414}
415
416static bool writeURL(WCDataObject *data, const KURL& url, String title, bool withPlainText, bool withHTML)
417{
418    ASSERT(data);
419
420    if (url.isEmpty())
421        return false;
422   
423    if (title.isEmpty()) {
424        title = url.lastPathComponent();
425        if (title.isEmpty())
426            title = url.host();
427    }
428
429    STGMEDIUM medium = {0};
430    medium.tymed = TYMED_HGLOBAL;
431
432    medium.hGlobal = createGlobalData(url, title);
433    bool success = false;
434    if (medium.hGlobal && FAILED(data->SetData(urlWFormat(), &medium, TRUE)))
435        ::GlobalFree(medium.hGlobal);
436    else
437        success = true;
438
439    if (withHTML) {
440        Vector<char> cfhtmlData;
441        markupToCF_HTML(urlToMarkup(url, title), "", cfhtmlData);
442        medium.hGlobal = createGlobalData(cfhtmlData);
443        if (medium.hGlobal && FAILED(data->SetData(htmlFormat(), &medium, TRUE)))
444            ::GlobalFree(medium.hGlobal);
445        else
446            success = true;
447    }
448
449    if (withPlainText) {
450        medium.hGlobal = createGlobalData(url.string());
451        if (medium.hGlobal && FAILED(data->SetData(plainTextWFormat(), &medium, TRUE)))
452            ::GlobalFree(medium.hGlobal);
453        else
454            success = true;
455    }
456
457    return success;
458}
459
460void ClipboardWin::clearData(const String& type)
461{
462    //FIXME: Need to be able to write to the system clipboard <rdar://problem/5015941>
463    ASSERT(isForDragging());
464    if (policy() != ClipboardWritable || !m_writableDataObject)
465        return;
466
467    ClipboardDataType dataType = clipboardTypeFromMIMEType(type);
468
469    if (dataType == ClipboardDataTypeURL) {
470        m_writableDataObject->clearData(urlWFormat()->cfFormat);
471        m_writableDataObject->clearData(urlFormat()->cfFormat);
472    }
473    if (dataType == ClipboardDataTypeText) {
474        m_writableDataObject->clearData(plainTextFormat()->cfFormat);
475        m_writableDataObject->clearData(plainTextWFormat()->cfFormat);
476    }
477
478}
479
480void ClipboardWin::clearAllData()
481{
482    //FIXME: Need to be able to write to the system clipboard <rdar://problem/5015941>
483    ASSERT(isForDragging());
484    if (policy() != ClipboardWritable)
485        return;
486   
487    m_writableDataObject = 0;
488    WCDataObject::createInstance(&m_writableDataObject);
489    m_dataObject = m_writableDataObject;
490}
491
492String ClipboardWin::getData(const String& type, bool& success) const
493{     
494    success = false;
495    if (policy() != ClipboardReadable || !m_dataObject) {
496        return "";
497    }
498
499    ClipboardDataType dataType = clipboardTypeFromMIMEType(type);
500    if (dataType == ClipboardDataTypeText)
501        return getPlainText(m_dataObject.get(), success);
502    else if (dataType == ClipboardDataTypeURL)
503        return getURL(m_dataObject.get(), success);
504   
505    return "";
506}
507
508bool ClipboardWin::setData(const String& type, const String& data)
509{
510    // FIXME: Need to be able to write to the system clipboard <rdar://problem/5015941>
511    ASSERT(isForDragging());
512    if (policy() != ClipboardWritable || !m_writableDataObject)
513        return false;
514
515    ClipboardDataType winType = clipboardTypeFromMIMEType(type);
516
517    if (winType == ClipboardDataTypeURL)
518        return WebCore::writeURL(m_writableDataObject.get(), KURL(data), String(), false, true);
519
520    if (winType == ClipboardDataTypeText) {
521        STGMEDIUM medium = {0};
522        medium.tymed = TYMED_HGLOBAL;
523        medium.hGlobal = createGlobalData(data);
524        if (!medium.hGlobal)
525            return false;
526
527        if (FAILED(m_writableDataObject->SetData(plainTextWFormat(), &medium, TRUE))) {
528            ::GlobalFree(medium.hGlobal);
529            return false;
530        }
531        return true;
532    }
533
534    return false;
535}
536
537static void addMimeTypesForFormat(HashSet<String>& results, FORMATETC& format)
538{
539    // URL and Text are provided for compatibility with IE's model
540    if (format.cfFormat == urlFormat()->cfFormat || format.cfFormat == urlWFormat()->cfFormat) {
541        results.add("URL");
542        results.add("text/uri-list");
543    }
544
545    if (format.cfFormat == plainTextWFormat()->cfFormat || format.cfFormat == plainTextFormat()->cfFormat) {
546        results.add("Text");
547        results.add("text/plain");
548    }
549}
550
551// extensions beyond IE's API
552HashSet<String> ClipboardWin::types() const
553{
554    HashSet<String> results;
555    if (policy() != ClipboardReadable && policy() != ClipboardTypesReadable)
556        return results;
557
558    if (!m_dataObject)
559        return results;
560
561    COMPtr<IEnumFORMATETC> itr;
562
563    if (FAILED(m_dataObject->EnumFormatEtc(0, &itr)))
564        return results;
565
566    if (!itr)
567        return results;
568
569    FORMATETC data;
570
571    while (SUCCEEDED(itr->Next(1, &data, 0))) {
572        addMimeTypesForFormat(results, data);
573    }
574
575    return results;
576}
577
578void ClipboardWin::setDragImage(CachedImage* image, Node *node, const IntPoint &loc)
579{
580    if (policy() != ClipboardImageWritable && policy() != ClipboardWritable)
581        return;
582       
583    if (m_dragImage)
584        m_dragImage->deref(this);
585    m_dragImage = image;
586    if (m_dragImage)
587        m_dragImage->ref(this);
588
589    m_dragLoc = loc;
590    m_dragImageElement = node;
591}
592
593void ClipboardWin::setDragImage(CachedImage* img, const IntPoint &loc)
594{
595    setDragImage(img, 0, loc);
596}
597
598void ClipboardWin::setDragImageElement(Node *node, const IntPoint &loc)
599{
600    setDragImage(0, node, loc);
601}
602
603DragImageRef ClipboardWin::createDragImage(IntPoint& loc) const
604{
605    HBITMAP result = 0;
606    //FIXME: Need to be able to draw element <rdar://problem/5015942>
607    if (m_dragImage) {
608        result = createDragImageFromImage(m_dragImage->image());       
609        loc = m_dragLoc;
610    }
611    return result;
612}
613
614static String imageToMarkup(const String& url)
615{
616    String markup("<img src=\"");
617    markup.append(url);
618    markup.append("\"/>");
619    return markup;
620}
621
622static CachedImage* getCachedImage(Element* element)
623{
624    // Attempt to pull CachedImage from element
625    ASSERT(element);
626    RenderObject* renderer = element->renderer();
627    if (!renderer || !renderer->isImage())
628        return 0;
629   
630    RenderImage* image = static_cast<RenderImage*>(renderer);
631    if (image->cachedImage() && !image->cachedImage()->errorOccurred())
632        return image->cachedImage();
633
634    return 0;
635}
636
637static void writeImageToDataObject(IDataObject* dataObject, Element* element, const KURL& url)
638{
639    // Shove image data into a DataObject for use as a file
640    CachedImage* cachedImage = getCachedImage(element);
641    if (!cachedImage || !cachedImage->image() || !cachedImage->isLoaded())
642        return;
643
644    SharedBuffer* imageBuffer = cachedImage->image()->data();
645    if (!imageBuffer || !imageBuffer->size())
646        return;
647
648    HGLOBAL imageFileDescriptor = createGlobalImageFileDescriptor(url.string(), element->getAttribute(altAttr), cachedImage);
649    if (!imageFileDescriptor)
650        return;
651
652    HGLOBAL imageFileContent = createGlobalImageFileContent(imageBuffer);
653    if (!imageFileContent) {
654        GlobalFree(imageFileDescriptor);
655        return;
656    }
657
658    String fileName = cachedImage->response().suggestedFilename();
659    HGLOBAL hDropContent = createGlobalHDropContent(url, fileName, imageBuffer);
660    if (!hDropContent) {
661        GlobalFree(hDropContent);
662        return;
663    }
664
665    writeFileToDataObject(dataObject, imageFileDescriptor, imageFileContent, hDropContent);
666}
667
668void ClipboardWin::declareAndWriteDragImage(Element* element, const KURL& url, const String& title, Frame* frame)
669{
670    // Order is important here for Explorer's sake
671    if (!m_writableDataObject)
672         return;
673    WebCore::writeURL(m_writableDataObject.get(), url, title, true, false);
674
675    writeImageToDataObject(m_writableDataObject.get(), element, url);
676
677    AtomicString imageURL = element->getAttribute(srcAttr);
678    if (imageURL.isEmpty())
679        return;
680
681    String fullURL = frame->document()->completeURL(parseURL(imageURL)).string();
682    if (fullURL.isEmpty())
683        return;
684    STGMEDIUM medium = {0};
685    medium.tymed = TYMED_HGLOBAL;
686    ExceptionCode ec = 0;
687
688    // Put img tag on the clipboard referencing the image
689    Vector<char> data;
690    markupToCF_HTML(imageToMarkup(fullURL), "", data);
691    medium.hGlobal = createGlobalData(data);
692    if (medium.hGlobal && FAILED(m_writableDataObject->SetData(htmlFormat(), &medium, TRUE)))
693        ::GlobalFree(medium.hGlobal);
694}
695
696void ClipboardWin::writeURL(const KURL& kurl, const String& titleStr, Frame*)
697{
698    if (!m_writableDataObject)
699         return;
700    WebCore::writeURL(m_writableDataObject.get(), kurl, titleStr, true, true);
701
702    int estimatedSize = 0;
703    String url = kurl.string();
704
705    HGLOBAL urlFileDescriptor = createGlobalUrlFileDescriptor(url, titleStr, estimatedSize);
706    if (!urlFileDescriptor)
707        return;
708    HGLOBAL urlFileContent = createGlobalURLContent(url, estimatedSize);
709    if (!urlFileContent) {
710        GlobalFree(urlFileDescriptor);
711        return;
712    }
713    writeFileToDataObject(m_writableDataObject.get(), urlFileDescriptor, urlFileContent, 0);
714}
715
716void ClipboardWin::writeRange(Range* selectedRange, Frame* frame)
717{
718    ASSERT(selectedRange);
719    if (!m_writableDataObject)
720         return;
721
722    STGMEDIUM medium = {0};
723    medium.tymed = TYMED_HGLOBAL;
724    ExceptionCode ec = 0;
725
726    Vector<char> data;
727    markupToCF_HTML(createMarkup(selectedRange, 0, AnnotateForInterchange),
728        selectedRange->startContainer(ec)->document()->url().string(), data);
729    medium.hGlobal = createGlobalData(data);
730    if (medium.hGlobal && FAILED(m_writableDataObject->SetData(htmlFormat(), &medium, TRUE)))
731        ::GlobalFree(medium.hGlobal);
732
733    String str = frame->selectedText();
734    replaceNewlinesWithWindowsStyleNewlines(str);
735    replaceNBSPWithSpace(str);
736    medium.hGlobal = createGlobalData(str);
737    if (medium.hGlobal && FAILED(m_writableDataObject->SetData(plainTextWFormat(), &medium, TRUE)))
738        ::GlobalFree(medium.hGlobal);
739
740    medium.hGlobal = 0;
741    if (frame->editor()->canSmartCopyOrDelete())
742        m_writableDataObject->SetData(smartPasteFormat(), &medium, TRUE);
743}
744
745bool ClipboardWin::hasData()
746{
747    if (!m_dataObject)
748        return false;
749
750    COMPtr<IEnumFORMATETC> itr;
751    if (FAILED(m_dataObject->EnumFormatEtc(0, &itr)))
752        return false;
753
754    if (!itr)
755        return false;
756
757    FORMATETC data;
758
759    if (SUCCEEDED(itr->Next(1, &data, 0))) {
760        // There is at least one item in the IDataObject
761        return true;
762    }
763
764    return false;
765}
766
767} // namespace WebCore
Note: See TracBrowser for help on using the repository browser.