| OLD | NEW | 
 | (Empty) | 
|    1 /* |  | 
|    2  * Copyright (C) 2007, 2008 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 "ClipboardUtilitiesWin.h" |  | 
|   28  |  | 
|   29 #include "DocumentFragment.h" |  | 
|   30 #include "KURL.h" |  | 
|   31 #include "TextEncoding.h" |  | 
|   32 #include "markup.h" |  | 
|   33 #include <shlobj.h> |  | 
|   34 #include <wininet.h> // for INTERNET_MAX_URL_LENGTH |  | 
|   35 #include <wtf/StringExtras.h> |  | 
|   36 #include <wtf/text/CString.h> |  | 
|   37 #include <wtf/text/StringBuilder.h> |  | 
|   38 #include <wtf/text/WTFString.h> |  | 
|   39  |  | 
|   40 #if !OS(WINCE) |  | 
|   41 #include <shlwapi.h> |  | 
|   42 #endif |  | 
|   43  |  | 
|   44 #if USE(CF) |  | 
|   45 #include <CoreFoundation/CoreFoundation.h> |  | 
|   46 #include <wtf/RetainPtr.h> |  | 
|   47 #endif |  | 
|   48  |  | 
|   49 namespace WebCore { |  | 
|   50  |  | 
|   51 #if USE(CF) |  | 
|   52 FORMATETC* cfHDropFormat() |  | 
|   53 { |  | 
|   54     static FORMATETC urlFormat = {CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOB
     AL}; |  | 
|   55     return &urlFormat; |  | 
|   56 } |  | 
|   57  |  | 
|   58 static bool urlFromPath(CFStringRef path, String& url) |  | 
|   59 { |  | 
|   60     if (!path) |  | 
|   61         return false; |  | 
|   62  |  | 
|   63     RetainPtr<CFURLRef> cfURL(AdoptCF, CFURLCreateWithFileSystemPath(0, path, kC
     FURLWindowsPathStyle, false)); |  | 
|   64     if (!cfURL) |  | 
|   65         return false; |  | 
|   66  |  | 
|   67     url = CFURLGetString(cfURL.get()); |  | 
|   68  |  | 
|   69     // Work around <rdar://problem/6708300>, where CFURLCreateWithFileSystemPath
      makes URLs with "localhost". |  | 
|   70     if (url.startsWith("file://localhost/")) |  | 
|   71         url.remove(7, 9); |  | 
|   72  |  | 
|   73     return true; |  | 
|   74 } |  | 
|   75 #endif |  | 
|   76  |  | 
|   77 static bool getDataMapItem(const DragDataMap* dataObject, FORMATETC* format, Str
     ing& item) |  | 
|   78 { |  | 
|   79     DragDataMap::const_iterator found = dataObject->find(format->cfFormat); |  | 
|   80     if (found == dataObject->end()) |  | 
|   81         return false; |  | 
|   82     item = found->value[0]; |  | 
|   83     return true; |  | 
|   84 } |  | 
|   85  |  | 
|   86 static bool getWebLocData(IDataObject* dataObject, String& url, String* title)  |  | 
|   87 { |  | 
|   88     bool succeeded = false; |  | 
|   89 #if USE(CF) |  | 
|   90     WCHAR filename[MAX_PATH]; |  | 
|   91     WCHAR urlBuffer[INTERNET_MAX_URL_LENGTH]; |  | 
|   92  |  | 
|   93     STGMEDIUM medium; |  | 
|   94     if (FAILED(dataObject->GetData(cfHDropFormat(), &medium))) |  | 
|   95         return false; |  | 
|   96  |  | 
|   97     HDROP hdrop = static_cast<HDROP>(GlobalLock(medium.hGlobal)); |  | 
|   98  |  | 
|   99     if (!hdrop) |  | 
|  100         return false; |  | 
|  101  |  | 
|  102     if (!DragQueryFileW(hdrop, 0, filename, WTF_ARRAY_LENGTH(filename))) |  | 
|  103         goto exit; |  | 
|  104  |  | 
|  105     if (_wcsicmp(PathFindExtensionW(filename), L".url")) |  | 
|  106         goto exit;     |  | 
|  107      |  | 
|  108     if (!GetPrivateProfileStringW(L"InternetShortcut", L"url", 0, urlBuffer, WTF
     _ARRAY_LENGTH(urlBuffer), filename)) |  | 
|  109         goto exit; |  | 
|  110      |  | 
|  111     if (title) { |  | 
|  112         PathRemoveExtension(filename); |  | 
|  113         *title = String((UChar*)filename); |  | 
|  114     } |  | 
|  115      |  | 
|  116     url = String((UChar*)urlBuffer); |  | 
|  117     succeeded = true; |  | 
|  118  |  | 
|  119 exit: |  | 
|  120     // Free up memory. |  | 
|  121     DragFinish(hdrop); |  | 
|  122     GlobalUnlock(medium.hGlobal); |  | 
|  123 #endif |  | 
|  124     return succeeded; |  | 
|  125 } |  | 
|  126  |  | 
|  127 static bool getWebLocData(const DragDataMap* dataObject, String& url, String* ti
     tle)  |  | 
|  128 { |  | 
|  129 #if USE(CF) |  | 
|  130     WCHAR filename[MAX_PATH]; |  | 
|  131     WCHAR urlBuffer[INTERNET_MAX_URL_LENGTH]; |  | 
|  132  |  | 
|  133     if (!dataObject->contains(cfHDropFormat()->cfFormat)) |  | 
|  134         return false; |  | 
|  135  |  | 
|  136     wcscpy(filename, dataObject->get(cfHDropFormat()->cfFormat)[0].charactersWit
     hNullTermination()); |  | 
|  137     if (_wcsicmp(PathFindExtensionW(filename), L".url")) |  | 
|  138         return false;     |  | 
|  139  |  | 
|  140     if (!GetPrivateProfileStringW(L"InternetShortcut", L"url", 0, urlBuffer, WTF
     _ARRAY_LENGTH(urlBuffer), filename)) |  | 
|  141         return false; |  | 
|  142  |  | 
|  143     if (title) { |  | 
|  144         PathRemoveExtension(filename); |  | 
|  145         *title = filename; |  | 
|  146     } |  | 
|  147      |  | 
|  148     url = urlBuffer; |  | 
|  149     return true; |  | 
|  150 #else |  | 
|  151     return false; |  | 
|  152 #endif |  | 
|  153 } |  | 
|  154  |  | 
|  155 static String extractURL(const String &inURL, String* title) |  | 
|  156 { |  | 
|  157     String url = inURL; |  | 
|  158     int splitLoc = url.find('\n'); |  | 
|  159     if (splitLoc > 0) { |  | 
|  160         if (title) |  | 
|  161             *title = url.substring(splitLoc+1); |  | 
|  162         url.truncate(splitLoc); |  | 
|  163     } else if (title) |  | 
|  164         *title = url; |  | 
|  165     return url; |  | 
|  166 } |  | 
|  167  |  | 
|  168 // Firefox text/html |  | 
|  169 static FORMATETC* texthtmlFormat()  |  | 
|  170 { |  | 
|  171     static UINT cf = RegisterClipboardFormat(L"text/html"); |  | 
|  172     static FORMATETC texthtmlFormat = {cf, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBA
     L}; |  | 
|  173     return &texthtmlFormat; |  | 
|  174 } |  | 
|  175  |  | 
|  176 HGLOBAL createGlobalData(const KURL& url, const String& title) |  | 
|  177 { |  | 
|  178     String mutableURL(url.string()); |  | 
|  179     String mutableTitle(title); |  | 
|  180     SIZE_T size = mutableURL.length() + mutableTitle.length() + 2; // +1 for "\n
     " and +1 for null terminator |  | 
|  181     HGLOBAL cbData = ::GlobalAlloc(GPTR, size * sizeof(UChar)); |  | 
|  182  |  | 
|  183     if (cbData) { |  | 
|  184         PWSTR buffer = static_cast<PWSTR>(GlobalLock(cbData)); |  | 
|  185         _snwprintf(buffer, size, L"%s\n%s", mutableURL.charactersWithNullTermina
     tion(), mutableTitle.charactersWithNullTermination()); |  | 
|  186         GlobalUnlock(cbData); |  | 
|  187     } |  | 
|  188     return cbData; |  | 
|  189 } |  | 
|  190  |  | 
|  191 HGLOBAL createGlobalData(const String& str) |  | 
|  192 { |  | 
|  193     HGLOBAL globalData = ::GlobalAlloc(GPTR, (str.length() + 1) * sizeof(UChar))
     ; |  | 
|  194     if (!globalData) |  | 
|  195         return 0; |  | 
|  196     UChar* buffer = static_cast<UChar*>(GlobalLock(globalData)); |  | 
|  197     memcpy(buffer, str.characters(), str.length() * sizeof(UChar)); |  | 
|  198     buffer[str.length()] = 0; |  | 
|  199     GlobalUnlock(globalData); |  | 
|  200     return globalData; |  | 
|  201 } |  | 
|  202  |  | 
|  203 HGLOBAL createGlobalData(const Vector<char>& vector) |  | 
|  204 { |  | 
|  205     HGLOBAL globalData = ::GlobalAlloc(GPTR, vector.size() + 1); |  | 
|  206     if (!globalData) |  | 
|  207         return 0; |  | 
|  208     char* buffer = static_cast<char*>(GlobalLock(globalData)); |  | 
|  209     memcpy(buffer, vector.data(), vector.size()); |  | 
|  210     buffer[vector.size()] = 0; |  | 
|  211     GlobalUnlock(globalData); |  | 
|  212     return globalData; |  | 
|  213 } |  | 
|  214  |  | 
|  215 static String getFullCFHTML(IDataObject* data) |  | 
|  216 { |  | 
|  217     STGMEDIUM store; |  | 
|  218     if (SUCCEEDED(data->GetData(htmlFormat(), &store))) { |  | 
|  219         // MS HTML Format parsing |  | 
|  220         char* data = static_cast<char*>(GlobalLock(store.hGlobal)); |  | 
|  221         SIZE_T dataSize = ::GlobalSize(store.hGlobal); |  | 
|  222         String cfhtml(UTF8Encoding().decode(data, dataSize)); |  | 
|  223         GlobalUnlock(store.hGlobal); |  | 
|  224         ReleaseStgMedium(&store); |  | 
|  225         return cfhtml; |  | 
|  226     } |  | 
|  227     return String(); |  | 
|  228 } |  | 
|  229  |  | 
|  230 static void append(Vector<char>& vector, const char* string) |  | 
|  231 { |  | 
|  232     vector.append(string, strlen(string)); |  | 
|  233 } |  | 
|  234  |  | 
|  235 static void append(Vector<char>& vector, const CString& string) |  | 
|  236 { |  | 
|  237     vector.append(string.data(), string.length()); |  | 
|  238 } |  | 
|  239  |  | 
|  240 // Find the markup between "<!--StartFragment -->" and "<!--EndFragment -->", ac
     counting for browser quirks. |  | 
|  241 static String extractMarkupFromCFHTML(const String& cfhtml) |  | 
|  242 { |  | 
|  243     unsigned markupStart = cfhtml.find("<html", 0, false); |  | 
|  244     unsigned tagStart = cfhtml.find("startfragment", markupStart, false); |  | 
|  245     unsigned fragmentStart = cfhtml.find('>', tagStart) + 1; |  | 
|  246     unsigned tagEnd = cfhtml.find("endfragment", fragmentStart, false); |  | 
|  247     unsigned fragmentEnd = cfhtml.reverseFind('<', tagEnd); |  | 
|  248     return cfhtml.substring(fragmentStart, fragmentEnd - fragmentStart).stripWhi
     teSpace(); |  | 
|  249 } |  | 
|  250  |  | 
|  251 // Documentation for the CF_HTML format is available at http://msdn.microsoft.co
     m/workshop/networking/clipboard/htmlclipboard.asp |  | 
|  252 void markupToCFHTML(const String& markup, const String& srcURL, Vector<char>& re
     sult) |  | 
|  253 { |  | 
|  254     if (markup.isEmpty()) |  | 
|  255         return; |  | 
|  256  |  | 
|  257     #define MAX_DIGITS 10 |  | 
|  258     #define MAKE_NUMBER_FORMAT_1(digits) MAKE_NUMBER_FORMAT_2(digits) |  | 
|  259     #define MAKE_NUMBER_FORMAT_2(digits) "%0" #digits "u" |  | 
|  260     #define NUMBER_FORMAT MAKE_NUMBER_FORMAT_1(MAX_DIGITS) |  | 
|  261  |  | 
|  262     const char* header = "Version:0.9\n" |  | 
|  263         "StartHTML:" NUMBER_FORMAT "\n" |  | 
|  264         "EndHTML:" NUMBER_FORMAT "\n" |  | 
|  265         "StartFragment:" NUMBER_FORMAT "\n" |  | 
|  266         "EndFragment:" NUMBER_FORMAT "\n"; |  | 
|  267     const char* sourceURLPrefix = "SourceURL:"; |  | 
|  268  |  | 
|  269     const char* startMarkup = "<HTML>\n<BODY>\n<!--StartFragment-->\n"; |  | 
|  270     const char* endMarkup = "\n<!--EndFragment-->\n</BODY>\n</HTML>"; |  | 
|  271  |  | 
|  272     CString sourceURLUTF8 = srcURL == blankURL() ? "" : srcURL.utf8(); |  | 
|  273     CString markupUTF8 = markup.utf8(); |  | 
|  274  |  | 
|  275     // calculate offsets |  | 
|  276     unsigned startHTMLOffset = strlen(header) - strlen(NUMBER_FORMAT) * 4 + MAX_
     DIGITS * 4; |  | 
|  277     if (sourceURLUTF8.length()) |  | 
|  278         startHTMLOffset += strlen(sourceURLPrefix) + sourceURLUTF8.length() + 1; |  | 
|  279     unsigned startFragmentOffset = startHTMLOffset + strlen(startMarkup); |  | 
|  280     unsigned endFragmentOffset = startFragmentOffset + markupUTF8.length(); |  | 
|  281     unsigned endHTMLOffset = endFragmentOffset + strlen(endMarkup); |  | 
|  282  |  | 
|  283     unsigned headerBufferLength = startHTMLOffset + 1; // + 1 for '\0' terminato
     r. |  | 
|  284     char* headerBuffer = (char*)malloc(headerBufferLength); |  | 
|  285     snprintf(headerBuffer, headerBufferLength, header, startHTMLOffset, endHTMLO
     ffset, startFragmentOffset, endFragmentOffset); |  | 
|  286     append(result, CString(headerBuffer)); |  | 
|  287     free(headerBuffer); |  | 
|  288     if (sourceURLUTF8.length()) { |  | 
|  289         append(result, sourceURLPrefix); |  | 
|  290         append(result, sourceURLUTF8); |  | 
|  291         result.append('\n'); |  | 
|  292     } |  | 
|  293     append(result, startMarkup); |  | 
|  294     append(result, markupUTF8); |  | 
|  295     append(result, endMarkup); |  | 
|  296  |  | 
|  297     #undef MAX_DIGITS |  | 
|  298     #undef MAKE_NUMBER_FORMAT_1 |  | 
|  299     #undef MAKE_NUMBER_FORMAT_2 |  | 
|  300     #undef NUMBER_FORMAT |  | 
|  301 } |  | 
|  302  |  | 
|  303 void replaceNewlinesWithWindowsStyleNewlines(String& str) |  | 
|  304 { |  | 
|  305     DEFINE_STATIC_LOCAL(String, windowsNewline, (ASCIILiteral("\r\n"))); |  | 
|  306     StringBuilder result; |  | 
|  307     for (unsigned index = 0; index < str.length(); ++index) { |  | 
|  308         if (str[index] != '\n' || (index > 0 && str[index - 1] == '\r')) |  | 
|  309             result.append(str[index]); |  | 
|  310         else |  | 
|  311             result.append(windowsNewline); |  | 
|  312     } |  | 
|  313     str = result.toString(); |  | 
|  314 } |  | 
|  315  |  | 
|  316 void replaceNBSPWithSpace(String& str) |  | 
|  317 { |  | 
|  318     static const UChar NonBreakingSpaceCharacter = 0xA0; |  | 
|  319     static const UChar SpaceCharacter = ' '; |  | 
|  320     str.replace(NonBreakingSpaceCharacter, SpaceCharacter); |  | 
|  321 } |  | 
|  322  |  | 
|  323 FORMATETC* urlWFormat() |  | 
|  324 { |  | 
|  325     static UINT cf = RegisterClipboardFormat(L"UniformResourceLocatorW"); |  | 
|  326     static FORMATETC urlFormat = {cf, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; |  | 
|  327     return &urlFormat; |  | 
|  328 } |  | 
|  329  |  | 
|  330 FORMATETC* urlFormat() |  | 
|  331 { |  | 
|  332     static UINT cf = RegisterClipboardFormat(L"UniformResourceLocator"); |  | 
|  333     static FORMATETC urlFormat = {cf, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; |  | 
|  334     return &urlFormat; |  | 
|  335 } |  | 
|  336  |  | 
|  337 FORMATETC* plainTextFormat() |  | 
|  338 { |  | 
|  339     static FORMATETC textFormat = {CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOB
     AL}; |  | 
|  340     return &textFormat; |  | 
|  341 } |  | 
|  342  |  | 
|  343 FORMATETC* plainTextWFormat() |  | 
|  344 { |  | 
|  345     static FORMATETC textFormat = {CF_UNICODETEXT, 0, DVASPECT_CONTENT, -1, TYME
     D_HGLOBAL}; |  | 
|  346     return &textFormat; |  | 
|  347 } |  | 
|  348  |  | 
|  349 FORMATETC* filenameWFormat() |  | 
|  350 { |  | 
|  351     static UINT cf = RegisterClipboardFormat(L"FileNameW"); |  | 
|  352     static FORMATETC urlFormat = {cf, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; |  | 
|  353     return &urlFormat; |  | 
|  354 } |  | 
|  355  |  | 
|  356 FORMATETC* filenameFormat() |  | 
|  357 { |  | 
|  358     static UINT cf = RegisterClipboardFormat(L"FileName"); |  | 
|  359     static FORMATETC urlFormat = {cf, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; |  | 
|  360     return &urlFormat; |  | 
|  361 } |  | 
|  362  |  | 
|  363 // MSIE HTML Format |  | 
|  364 FORMATETC* htmlFormat()  |  | 
|  365 { |  | 
|  366     static UINT cf = RegisterClipboardFormat(L"HTML Format"); |  | 
|  367     static FORMATETC htmlFormat = {cf, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; |  | 
|  368     return &htmlFormat; |  | 
|  369 } |  | 
|  370  |  | 
|  371 FORMATETC* smartPasteFormat() |  | 
|  372 { |  | 
|  373     static UINT cf = RegisterClipboardFormat(L"WebKit Smart Paste Format"); |  | 
|  374     static FORMATETC htmlFormat = {cf, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; |  | 
|  375     return &htmlFormat; |  | 
|  376 } |  | 
|  377  |  | 
|  378 FORMATETC* fileDescriptorFormat() |  | 
|  379 { |  | 
|  380     static UINT cf = RegisterClipboardFormat(CFSTR_FILEDESCRIPTOR); |  | 
|  381     static FORMATETC fileDescriptorFormat = { cf, 0, DVASPECT_CONTENT, -1, TYMED
     _HGLOBAL }; |  | 
|  382     return &fileDescriptorFormat; |  | 
|  383 } |  | 
|  384  |  | 
|  385 FORMATETC* fileContentFormatZero() |  | 
|  386 { |  | 
|  387     static UINT cf = RegisterClipboardFormat(CFSTR_FILECONTENTS); |  | 
|  388     static FORMATETC fileContentFormat = { cf, 0, DVASPECT_CONTENT, 0, TYMED_HGL
     OBAL }; |  | 
|  389     return &fileContentFormat; |  | 
|  390 } |  | 
|  391  |  | 
|  392 void getFileDescriptorData(IDataObject* dataObject, int& size, String& pathname) |  | 
|  393 { |  | 
|  394     STGMEDIUM store; |  | 
|  395     size = 0; |  | 
|  396     if (FAILED(dataObject->GetData(fileDescriptorFormat(), &store))) |  | 
|  397         return; |  | 
|  398  |  | 
|  399     FILEGROUPDESCRIPTOR* fgd = static_cast<FILEGROUPDESCRIPTOR*>(GlobalLock(stor
     e.hGlobal)); |  | 
|  400     size = fgd->fgd[0].nFileSizeLow; |  | 
|  401     pathname = fgd->fgd[0].cFileName; |  | 
|  402  |  | 
|  403     GlobalUnlock(store.hGlobal); |  | 
|  404     ::ReleaseStgMedium(&store); |  | 
|  405 } |  | 
|  406  |  | 
|  407 void getFileContentData(IDataObject* dataObject, int size, void* dataBlob) |  | 
|  408 { |  | 
|  409     STGMEDIUM store; |  | 
|  410     if (FAILED(dataObject->GetData(fileContentFormatZero(), &store))) |  | 
|  411         return; |  | 
|  412     void* data = GlobalLock(store.hGlobal); |  | 
|  413     ::CopyMemory(dataBlob, data, size); |  | 
|  414  |  | 
|  415     GlobalUnlock(store.hGlobal); |  | 
|  416     ::ReleaseStgMedium(&store); |  | 
|  417 } |  | 
|  418  |  | 
|  419 void setFileDescriptorData(IDataObject* dataObject, int size, const String& pass
     edPathname) |  | 
|  420 { |  | 
|  421     String pathname = passedPathname; |  | 
|  422  |  | 
|  423     STGMEDIUM medium = { 0 }; |  | 
|  424     medium.tymed = TYMED_HGLOBAL; |  | 
|  425  |  | 
|  426     medium.hGlobal = ::GlobalAlloc(GPTR, sizeof(FILEGROUPDESCRIPTOR)); |  | 
|  427     if (!medium.hGlobal) |  | 
|  428         return; |  | 
|  429  |  | 
|  430     FILEGROUPDESCRIPTOR* fgd = static_cast<FILEGROUPDESCRIPTOR*>(GlobalLock(medi
     um.hGlobal)); |  | 
|  431     ::ZeroMemory(fgd, sizeof(FILEGROUPDESCRIPTOR)); |  | 
|  432     fgd->cItems = 1; |  | 
|  433     fgd->fgd[0].dwFlags = FD_FILESIZE; |  | 
|  434     fgd->fgd[0].nFileSizeLow = size; |  | 
|  435  |  | 
|  436     int maxSize = std::min<int>(pathname.length(), WTF_ARRAY_LENGTH(fgd->fgd[0].
     cFileName)); |  | 
|  437     CopyMemory(fgd->fgd[0].cFileName, pathname.charactersWithNullTermination(), 
     maxSize * sizeof(UChar)); |  | 
|  438     GlobalUnlock(medium.hGlobal); |  | 
|  439  |  | 
|  440     dataObject->SetData(fileDescriptorFormat(), &medium, TRUE); |  | 
|  441 } |  | 
|  442  |  | 
|  443 void setFileContentData(IDataObject* dataObject, int size, void* dataBlob) |  | 
|  444 { |  | 
|  445     STGMEDIUM medium = { 0 }; |  | 
|  446     medium.tymed = TYMED_HGLOBAL; |  | 
|  447  |  | 
|  448     medium.hGlobal = ::GlobalAlloc(GPTR, size); |  | 
|  449     if (!medium.hGlobal) |  | 
|  450         return; |  | 
|  451     void* fileContents = GlobalLock(medium.hGlobal); |  | 
|  452     ::CopyMemory(fileContents, dataBlob, size); |  | 
|  453     GlobalUnlock(medium.hGlobal); |  | 
|  454  |  | 
|  455     dataObject->SetData(fileContentFormatZero(), &medium, TRUE); |  | 
|  456 } |  | 
|  457  |  | 
|  458 String getURL(IDataObject* dataObject, DragData::FilenameConversionPolicy filena
     mePolicy, String* title) |  | 
|  459 { |  | 
|  460     STGMEDIUM store; |  | 
|  461     String url; |  | 
|  462     if (getWebLocData(dataObject, url, title)) |  | 
|  463         return url; |  | 
|  464  |  | 
|  465     if (SUCCEEDED(dataObject->GetData(urlWFormat(), &store))) { |  | 
|  466         // URL using Unicode |  | 
|  467         UChar* data = static_cast<UChar*>(GlobalLock(store.hGlobal)); |  | 
|  468         url = extractURL(String(data), title); |  | 
|  469         GlobalUnlock(store.hGlobal); |  | 
|  470         ReleaseStgMedium(&store); |  | 
|  471     } else if (SUCCEEDED(dataObject->GetData(urlFormat(), &store))) { |  | 
|  472         // URL using ASCII |  | 
|  473         char* data = static_cast<char*>(GlobalLock(store.hGlobal)); |  | 
|  474         url = extractURL(String(data), title); |  | 
|  475         GlobalUnlock(store.hGlobal); |  | 
|  476         ReleaseStgMedium(&store); |  | 
|  477     } |  | 
|  478 #if USE(CF) |  | 
|  479     else if (filenamePolicy == DragData::ConvertFilenames) { |  | 
|  480         if (SUCCEEDED(dataObject->GetData(filenameWFormat(), &store))) { |  | 
|  481             // file using unicode |  | 
|  482             wchar_t* data = static_cast<wchar_t*>(GlobalLock(store.hGlobal)); |  | 
|  483             if (data && data[0] && (PathFileExists(data) || PathIsUNC(data))) { |  | 
|  484                 RetainPtr<CFStringRef> pathAsCFString(AdoptCF, CFStringCreateWit
     hCharacters(kCFAllocatorDefault, (const UniChar*)data, wcslen(data))); |  | 
|  485                 if (urlFromPath(pathAsCFString.get(), url) && title) |  | 
|  486                     *title = url; |  | 
|  487             } |  | 
|  488             GlobalUnlock(store.hGlobal); |  | 
|  489             ReleaseStgMedium(&store); |  | 
|  490         } else if (SUCCEEDED(dataObject->GetData(filenameFormat(), &store))) { |  | 
|  491             // filename using ascii |  | 
|  492             char* data = static_cast<char*>(GlobalLock(store.hGlobal)); |  | 
|  493             if (data && data[0] && (PathFileExistsA(data) || PathIsUNCA(data))) 
     { |  | 
|  494                 RetainPtr<CFStringRef> pathAsCFString(AdoptCF, CFStringCreateWit
     hCString(kCFAllocatorDefault, data, kCFStringEncodingASCII)); |  | 
|  495                 if (urlFromPath(pathAsCFString.get(), url) && title) |  | 
|  496                     *title = url; |  | 
|  497             } |  | 
|  498             GlobalUnlock(store.hGlobal); |  | 
|  499             ReleaseStgMedium(&store); |  | 
|  500         } |  | 
|  501     } |  | 
|  502 #endif |  | 
|  503     return url; |  | 
|  504 } |  | 
|  505  |  | 
|  506 String getURL(const DragDataMap* data, DragData::FilenameConversionPolicy filena
     mePolicy, String* title) |  | 
|  507 { |  | 
|  508     String url; |  | 
|  509  |  | 
|  510     if (getWebLocData(data, url, title)) |  | 
|  511         return url; |  | 
|  512     if (getDataMapItem(data, urlWFormat(), url)) |  | 
|  513         return extractURL(url, title); |  | 
|  514     if (getDataMapItem(data, urlFormat(), url)) |  | 
|  515         return extractURL(url, title); |  | 
|  516 #if USE(CF) |  | 
|  517     if (filenamePolicy != DragData::ConvertFilenames) |  | 
|  518         return url; |  | 
|  519  |  | 
|  520     String stringData; |  | 
|  521     if (!getDataMapItem(data, filenameWFormat(), stringData)) |  | 
|  522         getDataMapItem(data, filenameFormat(), stringData); |  | 
|  523  |  | 
|  524     if (stringData.isEmpty() || (!PathFileExists(stringData.charactersWithNullTe
     rmination()) && !PathIsUNC(stringData.charactersWithNullTermination()))) |  | 
|  525         return url; |  | 
|  526     RetainPtr<CFStringRef> pathAsCFString(AdoptCF, CFStringCreateWithCharacters(
     kCFAllocatorDefault, (const UniChar *)stringData.charactersWithNullTermination()
     , wcslen(stringData.charactersWithNullTermination()))); |  | 
|  527     if (urlFromPath(pathAsCFString.get(), url) && title) |  | 
|  528         *title = url; |  | 
|  529 #endif |  | 
|  530     return url; |  | 
|  531 } |  | 
|  532  |  | 
|  533 String getPlainText(IDataObject* dataObject) |  | 
|  534 { |  | 
|  535     STGMEDIUM store; |  | 
|  536     String text; |  | 
|  537     if (SUCCEEDED(dataObject->GetData(plainTextWFormat(), &store))) { |  | 
|  538         // Unicode text |  | 
|  539         UChar* data = static_cast<UChar*>(GlobalLock(store.hGlobal)); |  | 
|  540         text = String(data); |  | 
|  541         GlobalUnlock(store.hGlobal); |  | 
|  542         ReleaseStgMedium(&store); |  | 
|  543     } else if (SUCCEEDED(dataObject->GetData(plainTextFormat(), &store))) { |  | 
|  544         // ASCII text |  | 
|  545         char* data = static_cast<char*>(GlobalLock(store.hGlobal)); |  | 
|  546         text = String(data); |  | 
|  547         GlobalUnlock(store.hGlobal); |  | 
|  548         ReleaseStgMedium(&store); |  | 
|  549     } else { |  | 
|  550         // FIXME: Originally, we called getURL() here because dragging and dropp
     ing files doesn't |  | 
|  551         // populate the drag with text data. Per https://bugs.webkit.org/show_bu
     g.cgi?id=38826, this |  | 
|  552         // is undesirable, so maybe this line can be removed. |  | 
|  553         text = getURL(dataObject, DragData::DoNotConvertFilenames); |  | 
|  554     } |  | 
|  555     return text; |  | 
|  556 } |  | 
|  557  |  | 
|  558 String getPlainText(const DragDataMap* data) |  | 
|  559 { |  | 
|  560     String text; |  | 
|  561      |  | 
|  562     if (getDataMapItem(data, plainTextWFormat(), text)) |  | 
|  563         return text; |  | 
|  564     if (getDataMapItem(data, plainTextFormat(), text)) |  | 
|  565         return text; |  | 
|  566     return getURL(data, DragData::DoNotConvertFilenames); |  | 
|  567 } |  | 
|  568  |  | 
|  569 String getTextHTML(IDataObject* data) |  | 
|  570 { |  | 
|  571     STGMEDIUM store; |  | 
|  572     String html; |  | 
|  573     if (SUCCEEDED(data->GetData(texthtmlFormat(), &store))) { |  | 
|  574         UChar* data = static_cast<UChar*>(GlobalLock(store.hGlobal)); |  | 
|  575         html = String(data); |  | 
|  576         GlobalUnlock(store.hGlobal); |  | 
|  577         ReleaseStgMedium(&store); |  | 
|  578     } |  | 
|  579     return html; |  | 
|  580 } |  | 
|  581  |  | 
|  582 String getTextHTML(const DragDataMap* data) |  | 
|  583 { |  | 
|  584     String text; |  | 
|  585     getDataMapItem(data, texthtmlFormat(), text); |  | 
|  586     return text; |  | 
|  587 } |  | 
|  588  |  | 
|  589 String getCFHTML(IDataObject* data) |  | 
|  590 { |  | 
|  591     String cfhtml = getFullCFHTML(data); |  | 
|  592     if (!cfhtml.isEmpty()) |  | 
|  593         return extractMarkupFromCFHTML(cfhtml); |  | 
|  594     return String(); |  | 
|  595 } |  | 
|  596  |  | 
|  597 String getCFHTML(const DragDataMap* dataMap) |  | 
|  598 { |  | 
|  599     String cfhtml; |  | 
|  600     getDataMapItem(dataMap, htmlFormat(), cfhtml); |  | 
|  601     return extractMarkupFromCFHTML(cfhtml); |  | 
|  602 } |  | 
|  603  |  | 
|  604 PassRefPtr<DocumentFragment> fragmentFromFilenames(Document*, const IDataObject*
     ) |  | 
|  605 { |  | 
|  606     // FIXME: We should be able to create fragments from files |  | 
|  607     return 0; |  | 
|  608 } |  | 
|  609  |  | 
|  610 PassRefPtr<DocumentFragment> fragmentFromFilenames(Document*, const DragDataMap*
     ) |  | 
|  611 { |  | 
|  612     // FIXME: We should be able to create fragments from files |  | 
|  613     return 0; |  | 
|  614 } |  | 
|  615  |  | 
|  616 bool containsFilenames(const IDataObject*) |  | 
|  617 { |  | 
|  618     // FIXME: We'll want to update this once we can produce fragments from files |  | 
|  619     return false; |  | 
|  620 } |  | 
|  621  |  | 
|  622 bool containsFilenames(const DragDataMap*) |  | 
|  623 { |  | 
|  624     // FIXME: We'll want to update this once we can produce fragments from files |  | 
|  625     return false; |  | 
|  626 } |  | 
|  627  |  | 
|  628 // Convert a String containing CF_HTML formatted text to a DocumentFragment |  | 
|  629 PassRefPtr<DocumentFragment> fragmentFromCFHTML(Document* doc, const String& cfh
     tml) |  | 
|  630 { |  | 
|  631     // obtain baseURL if present |  | 
|  632     String srcURLStr("sourceURL:"); |  | 
|  633     String srcURL; |  | 
|  634     unsigned lineStart = cfhtml.find(srcURLStr, 0, false); |  | 
|  635     if (lineStart != -1) { |  | 
|  636         unsigned srcEnd = cfhtml.find("\n", lineStart, false); |  | 
|  637         unsigned srcStart = lineStart+srcURLStr.length(); |  | 
|  638         String rawSrcURL = cfhtml.substring(srcStart, srcEnd-srcStart); |  | 
|  639         replaceNBSPWithSpace(rawSrcURL); |  | 
|  640         srcURL = rawSrcURL.stripWhiteSpace(); |  | 
|  641     } |  | 
|  642  |  | 
|  643     String markup = extractMarkupFromCFHTML(cfhtml); |  | 
|  644     return createFragmentFromMarkup(doc, markup, srcURL, DisallowScriptingAndPlu
     ginContent); |  | 
|  645 } |  | 
|  646  |  | 
|  647 PassRefPtr<DocumentFragment> fragmentFromHTML(Document* doc, IDataObject* data)  |  | 
|  648 { |  | 
|  649     if (!doc || !data) |  | 
|  650         return 0; |  | 
|  651  |  | 
|  652     String cfhtml = getFullCFHTML(data); |  | 
|  653     if (!cfhtml.isEmpty()) { |  | 
|  654         if (RefPtr<DocumentFragment> fragment = fragmentFromCFHTML(doc, cfhtml)) |  | 
|  655             return fragment.release(); |  | 
|  656     } |  | 
|  657  |  | 
|  658     String html = getTextHTML(data); |  | 
|  659     String srcURL; |  | 
|  660     if (!html.isEmpty()) |  | 
|  661         return createFragmentFromMarkup(doc, html, srcURL, DisallowScriptingAndP
     luginContent); |  | 
|  662  |  | 
|  663     return 0; |  | 
|  664 } |  | 
|  665  |  | 
|  666 PassRefPtr<DocumentFragment> fragmentFromHTML(Document* document, const DragData
     Map* data)  |  | 
|  667 { |  | 
|  668     if (!document || !data || data->isEmpty()) |  | 
|  669         return 0; |  | 
|  670  |  | 
|  671     String stringData; |  | 
|  672     if (getDataMapItem(data, htmlFormat(), stringData)) { |  | 
|  673         if (RefPtr<DocumentFragment> fragment = fragmentFromCFHTML(document, str
     ingData)) |  | 
|  674             return fragment.release(); |  | 
|  675     } |  | 
|  676  |  | 
|  677     String srcURL; |  | 
|  678     if (getDataMapItem(data, texthtmlFormat(), stringData)) |  | 
|  679         return createFragmentFromMarkup(document, stringData, srcURL, DisallowSc
     riptingAndPluginContent); |  | 
|  680  |  | 
|  681     return 0; |  | 
|  682 } |  | 
|  683  |  | 
|  684 bool containsHTML(IDataObject* data) |  | 
|  685 { |  | 
|  686     return SUCCEEDED(data->QueryGetData(texthtmlFormat())) || SUCCEEDED(data->Qu
     eryGetData(htmlFormat())); |  | 
|  687 } |  | 
|  688  |  | 
|  689 bool containsHTML(const DragDataMap* data) |  | 
|  690 { |  | 
|  691     return data->contains(texthtmlFormat()->cfFormat) || data->contains(htmlForm
     at()->cfFormat); |  | 
|  692 } |  | 
|  693  |  | 
|  694 typedef void (*GetStringFunction)(IDataObject*, FORMATETC*, Vector<String>&); |  | 
|  695 typedef void (*SetStringFunction)(IDataObject*, FORMATETC*, const Vector<String>
     &); |  | 
|  696  |  | 
|  697 struct ClipboardDataItem { |  | 
|  698     GetStringFunction getString; |  | 
|  699     SetStringFunction setString; |  | 
|  700     FORMATETC* format; |  | 
|  701  |  | 
|  702     ClipboardDataItem(FORMATETC* format, GetStringFunction getString, SetStringF
     unction setString): format(format), getString(getString), setString(setString) {
      } |  | 
|  703 }; |  | 
|  704  |  | 
|  705 typedef HashMap<UINT, ClipboardDataItem*> ClipboardFormatMap; |  | 
|  706  |  | 
|  707 // Getter functions. |  | 
|  708  |  | 
|  709 template<typename T> void getStringData(IDataObject* data, FORMATETC* format, Ve
     ctor<String>& dataStrings) |  | 
|  710 { |  | 
|  711     STGMEDIUM store; |  | 
|  712     if (FAILED(data->GetData(format, &store))) |  | 
|  713         return; |  | 
|  714     dataStrings.append(String(static_cast<T*>(GlobalLock(store.hGlobal)), ::Glob
     alSize(store.hGlobal) / sizeof(T))); |  | 
|  715     GlobalUnlock(store.hGlobal); |  | 
|  716     ReleaseStgMedium(&store); |  | 
|  717 } |  | 
|  718  |  | 
|  719 void getUtf8Data(IDataObject* data, FORMATETC* format, Vector<String>& dataStrin
     gs) |  | 
|  720 { |  | 
|  721     STGMEDIUM store; |  | 
|  722     if (FAILED(data->GetData(format, &store))) |  | 
|  723         return; |  | 
|  724     dataStrings.append(String(UTF8Encoding().decode(static_cast<char*>(GlobalLoc
     k(store.hGlobal)), GlobalSize(store.hGlobal)))); |  | 
|  725     GlobalUnlock(store.hGlobal); |  | 
|  726     ReleaseStgMedium(&store); |  | 
|  727 } |  | 
|  728  |  | 
|  729 #if USE(CF) |  | 
|  730 void getCFData(IDataObject* data, FORMATETC* format, Vector<String>& dataStrings
     ) |  | 
|  731 { |  | 
|  732     STGMEDIUM store; |  | 
|  733     if (FAILED(data->GetData(format, &store))) |  | 
|  734         return; |  | 
|  735  |  | 
|  736     HDROP hdrop = reinterpret_cast<HDROP>(GlobalLock(store.hGlobal)); |  | 
|  737     if (!hdrop) |  | 
|  738         return; |  | 
|  739  |  | 
|  740     WCHAR filename[MAX_PATH]; |  | 
|  741     UINT fileCount = DragQueryFileW(hdrop, 0xFFFFFFFF, 0, 0); |  | 
|  742     for (UINT i = 0; i < fileCount; i++) { |  | 
|  743         if (!DragQueryFileW(hdrop, i, filename, WTF_ARRAY_LENGTH(filename))) |  | 
|  744             continue; |  | 
|  745         dataStrings.append(static_cast<UChar*>(filename)); |  | 
|  746     } |  | 
|  747  |  | 
|  748     GlobalUnlock(store.hGlobal); |  | 
|  749     ReleaseStgMedium(&store); |  | 
|  750 } |  | 
|  751 #endif |  | 
|  752  |  | 
|  753 // Setter functions. |  | 
|  754  |  | 
|  755 void setUCharData(IDataObject* data, FORMATETC* format, const Vector<String>& da
     taStrings) |  | 
|  756 { |  | 
|  757     STGMEDIUM medium = {0}; |  | 
|  758     medium.tymed = TYMED_HGLOBAL; |  | 
|  759  |  | 
|  760     medium.hGlobal = createGlobalData(dataStrings.first()); |  | 
|  761     if (!medium.hGlobal) |  | 
|  762         return; |  | 
|  763     data->SetData(format, &medium, FALSE); |  | 
|  764     ::GlobalFree(medium.hGlobal); |  | 
|  765 } |  | 
|  766  |  | 
|  767 void setUtf8Data(IDataObject* data, FORMATETC* format, const Vector<String>& dat
     aStrings) |  | 
|  768 { |  | 
|  769     STGMEDIUM medium = {0}; |  | 
|  770     medium.tymed = TYMED_HGLOBAL; |  | 
|  771  |  | 
|  772     CString charString = dataStrings.first().utf8(); |  | 
|  773     size_t stringLength = charString.length(); |  | 
|  774     medium.hGlobal = ::GlobalAlloc(GPTR, stringLength + 1); |  | 
|  775     if (!medium.hGlobal) |  | 
|  776         return; |  | 
|  777     char* buffer = static_cast<char*>(GlobalLock(medium.hGlobal)); |  | 
|  778     memcpy(buffer, charString.data(), stringLength); |  | 
|  779     buffer[stringLength] = 0; |  | 
|  780     GlobalUnlock(medium.hGlobal); |  | 
|  781     data->SetData(format, &medium, FALSE); |  | 
|  782     ::GlobalFree(medium.hGlobal); |  | 
|  783 } |  | 
|  784  |  | 
|  785 #if USE(CF) |  | 
|  786 void setCFData(IDataObject* data, FORMATETC* format, const Vector<String>& dataS
     trings) |  | 
|  787 { |  | 
|  788     STGMEDIUM medium = {0}; |  | 
|  789     medium.tymed = TYMED_HGLOBAL; |  | 
|  790  |  | 
|  791     SIZE_T dropFilesSize = sizeof(DROPFILES) + (sizeof(WCHAR) * (dataStrings.fir
     st().length() + 2)); |  | 
|  792     medium.hGlobal = ::GlobalAlloc(GHND | GMEM_SHARE, dropFilesSize); |  | 
|  793     if (!medium.hGlobal)  |  | 
|  794         return; |  | 
|  795  |  | 
|  796     DROPFILES* dropFiles = reinterpret_cast<DROPFILES *>(GlobalLock(medium.hGlob
     al)); |  | 
|  797     dropFiles->pFiles = sizeof(DROPFILES); |  | 
|  798     dropFiles->fWide = TRUE; |  | 
|  799     String filename = dataStrings.first(); |  | 
|  800     wcscpy(reinterpret_cast<LPWSTR>(dropFiles + 1), filename.charactersWithNullT
     ermination());     |  | 
|  801     GlobalUnlock(medium.hGlobal); |  | 
|  802     data->SetData(format, &medium, FALSE); |  | 
|  803     ::GlobalFree(medium.hGlobal); |  | 
|  804 } |  | 
|  805 #endif |  | 
|  806  |  | 
|  807 static const ClipboardFormatMap& getClipboardMap() |  | 
|  808 { |  | 
|  809     static ClipboardFormatMap formatMap; |  | 
|  810     if (formatMap.isEmpty()) { |  | 
|  811         formatMap.add(htmlFormat()->cfFormat, new ClipboardDataItem(htmlFormat()
     , getUtf8Data, setUtf8Data)); |  | 
|  812         formatMap.add(texthtmlFormat()->cfFormat, new ClipboardDataItem(texthtml
     Format(), getStringData<UChar>, setUCharData)); |  | 
|  813         formatMap.add(plainTextFormat()->cfFormat,  new ClipboardDataItem(plainT
     extFormat(), getStringData<char>, setUtf8Data)); |  | 
|  814         formatMap.add(plainTextWFormat()->cfFormat,  new ClipboardDataItem(plain
     TextWFormat(), getStringData<UChar>, setUCharData)); |  | 
|  815 #if USE(CF) |  | 
|  816         formatMap.add(cfHDropFormat()->cfFormat,  new ClipboardDataItem(cfHDropF
     ormat(), getCFData, setCFData)); |  | 
|  817 #endif |  | 
|  818         formatMap.add(filenameFormat()->cfFormat,  new ClipboardDataItem(filenam
     eFormat(), getStringData<char>, setUtf8Data)); |  | 
|  819         formatMap.add(filenameWFormat()->cfFormat,  new ClipboardDataItem(filena
     meWFormat(), getStringData<UChar>, setUCharData)); |  | 
|  820         formatMap.add(urlFormat()->cfFormat,  new ClipboardDataItem(urlFormat(),
      getStringData<char>, setUtf8Data)); |  | 
|  821         formatMap.add(urlWFormat()->cfFormat,  new ClipboardDataItem(urlWFormat(
     ), getStringData<UChar>, setUCharData)); |  | 
|  822     } |  | 
|  823     return formatMap; |  | 
|  824 } |  | 
|  825  |  | 
|  826 void getClipboardData(IDataObject* dataObject, FORMATETC* format, Vector<String>
     & dataStrings) |  | 
|  827 { |  | 
|  828     const ClipboardFormatMap& formatMap = getClipboardMap(); |  | 
|  829     ClipboardFormatMap::const_iterator found = formatMap.find(format->cfFormat); |  | 
|  830     if (found == formatMap.end()) |  | 
|  831         return; |  | 
|  832     found->value->getString(dataObject, found->value->format, dataStrings); |  | 
|  833 } |  | 
|  834  |  | 
|  835 void setClipboardData(IDataObject* dataObject, UINT format, const Vector<String>
     & dataStrings) |  | 
|  836 { |  | 
|  837     const ClipboardFormatMap& formatMap = getClipboardMap(); |  | 
|  838     ClipboardFormatMap::const_iterator found = formatMap.find(format); |  | 
|  839     if (found == formatMap.end()) |  | 
|  840         return; |  | 
|  841     found->value->setString(dataObject, found->value->format, dataStrings); |  | 
|  842 } |  | 
|  843  |  | 
|  844 } // namespace WebCore |  | 
| OLD | NEW |